diff options
Diffstat (limited to 'framework/source/fwe/classes')
-rw-r--r-- | framework/source/fwe/classes/actiontriggercontainer.cxx | 134 | ||||
-rw-r--r-- | framework/source/fwe/classes/actiontriggerpropertyset.cxx | 371 | ||||
-rw-r--r-- | framework/source/fwe/classes/actiontriggerseparatorpropertyset.cxx | 245 | ||||
-rw-r--r-- | framework/source/fwe/classes/addonmenu.cxx | 299 | ||||
-rw-r--r-- | framework/source/fwe/classes/addonsoptions.cxx | 1958 | ||||
-rw-r--r-- | framework/source/fwe/classes/framelistanalyzer.cxx | 260 | ||||
-rw-r--r-- | framework/source/fwe/classes/fwkresid.cxx | 24 | ||||
-rw-r--r-- | framework/source/fwe/classes/rootactiontriggercontainer.cxx | 251 | ||||
-rw-r--r-- | framework/source/fwe/classes/sfxhelperfunctions.cxx | 181 |
9 files changed, 3723 insertions, 0 deletions
diff --git a/framework/source/fwe/classes/actiontriggercontainer.cxx b/framework/source/fwe/classes/actiontriggercontainer.cxx new file mode 100644 index 000000000..360223e6e --- /dev/null +++ b/framework/source/fwe/classes/actiontriggercontainer.cxx @@ -0,0 +1,134 @@ +/* -*- 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 <classes/actiontriggercontainer.hxx> +#include <classes/actiontriggerpropertyset.hxx> +#include <classes/actiontriggerseparatorpropertyset.hxx> +#include <cppuhelper/queryinterface.hxx> +#include <cppuhelper/supportsservice.hxx> +#include <cppuhelper/typeprovider.hxx> + +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() +{ +} + +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() noexcept +{ + PropertySetContainer::acquire(); +} + +void ActionTriggerContainer::release() noexcept +{ + PropertySetContainer::release(); +} + +// XMultiServiceFactory +Reference< XInterface > SAL_CALL ActionTriggerContainer::createInstance( const OUString& aServiceSpecifier ) +{ + if ( aServiceSpecifier == SERVICENAME_ACTIONTRIGGER ) + return static_cast<OWeakObject *>( new ActionTriggerPropertySet()); + else if ( aServiceSpecifier == SERVICENAME_ACTIONTRIGGERCONTAINER ) + return static_cast<OWeakObject *>( new ActionTriggerContainer()); + else if ( aServiceSpecifier == SERVICENAME_ACTIONTRIGGERSEPARATOR ) + return static_cast<OWeakObject *>( new ActionTriggerSeparatorPropertySet()); + else + throw css::uno::RuntimeException("Unknown service specifier!", static_cast<OWeakObject *>(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{ SERVICENAME_ACTIONTRIGGER, + SERVICENAME_ACTIONTRIGGERCONTAINER, + 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<XMultiServiceFactory>::get(), + cppu::UnoType<XIndexContainer>::get(), + cppu::UnoType<XServiceInfo>::get(), + cppu::UnoType<XTypeProvider>::get()); + + return ourTypeCollection.getTypes(); +} + +Sequence< sal_Int8 > SAL_CALL ActionTriggerContainer::getImplementationId() +{ + return css::uno::Sequence<sal_Int8>(); +} + +} + +/* 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..4592174df --- /dev/null +++ b/framework/source/fwe/classes/actiontriggerpropertyset.cxx @@ -0,0 +1,371 @@ +/* -*- 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 <classes/actiontriggerpropertyset.hxx> +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <cppuhelper/proptypehlp.hxx> +#include <cppuhelper/queryinterface.hxx> +#include <cppuhelper/supportsservice.hxx> +#include <cppuhelper/typeprovider.hxx> +#include <vcl/svapp.hxx> + +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) ) +{ +} + +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() noexcept +{ + OWeakObject::acquire(); +} + +void SAL_CALL ActionTriggerPropertySet::release() noexcept +{ + 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<OUString> seqServiceNames { SERVICENAME_ACTIONTRIGGER }; + return seqServiceNames; +} + +// XTypeProvider +Sequence< Type > SAL_CALL ActionTriggerPropertySet::getTypes() +{ + // Create a static typecollection ... + static ::cppu::OTypeCollection ourTypeCollection( + cppu::UnoType<XPropertySet>::get(), + cppu::UnoType<XFastPropertySet>::get(), + cppu::UnoType<XMultiPropertySet>::get(), + cppu::UnoType<XServiceInfo>::get(), + cppu::UnoType<XTypeProvider>::get()); + + + return ourTypeCollection.getTypes(); +} + +Sequence< sal_Int8 > SAL_CALL ActionTriggerPropertySet::getImplementationId() +{ + return css::uno::Sequence<sal_Int8>(); +} + +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<OUString>::get(), PropertyAttribute::TRANSIENT ), + Property( "HelpURL" , HANDLE_HELPURL , cppu::UnoType<OUString>::get(), PropertyAttribute::TRANSIENT ), + Property( "Image" , HANDLE_IMAGE , cppu::UnoType<XBitmap>::get(), PropertyAttribute::TRANSIENT ), + Property( "SubContainer" , HANDLE_SUBCONTAINER , cppu::UnoType<OUString>::get(), PropertyAttribute::TRANSIENT ), + Property( "Text" , HANDLE_TEXT , cppu::UnoType<XInterface>::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..104d765f5 --- /dev/null +++ b/framework/source/fwe/classes/actiontriggerseparatorpropertyset.cxx @@ -0,0 +1,245 @@ +/* -*- 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 <classes/actiontriggerseparatorpropertyset.hxx> +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <cppuhelper/proptypehlp.hxx> +#include <cppuhelper/supportsservice.hxx> +#include <cppuhelper/queryinterface.hxx> +#include <cppuhelper/typeprovider.hxx> +#include <vcl/svapp.hxx> + +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) ) + , 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() noexcept +{ + OWeakObject::acquire(); +} + +void ActionTriggerSeparatorPropertySet::release() noexcept +{ + 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<OUString> seqServiceNames { SERVICENAME_ACTIONTRIGGERSEPARATOR }; + return seqServiceNames; +} + +// XTypeProvider +Sequence< Type > SAL_CALL ActionTriggerSeparatorPropertySet::getTypes() +{ + // Create a static typecollection ... + static ::cppu::OTypeCollection ourTypeCollection( + cppu::UnoType<XPropertySet>::get(), + cppu::UnoType<XFastPropertySet>::get(), + cppu::UnoType<XMultiPropertySet>::get(), + cppu::UnoType<XServiceInfo>::get(), + cppu::UnoType<XTypeProvider>::get()); + + return ourTypeCollection.getTypes(); +} + +Sequence< sal_Int8 > SAL_CALL ActionTriggerSeparatorPropertySet::getImplementationId() +{ + return css::uno::Sequence<sal_Int8>(); +} + +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<sal_Int16>::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..423a157f8 --- /dev/null +++ b/framework/source/fwe/classes/addonmenu.cxx @@ -0,0 +1,299 @@ +/* -*- 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 <addonmenu.hxx> +#include <framework/addonsoptions.hxx> +#include <menuconfiguration.hxx> + +#include <com/sun/star/uno/Reference.hxx> +#include <com/sun/star/uno/Sequence.hxx> +#include <com/sun/star/beans/PropertyValue.hpp> + +#include <vcl/commandinfoprovider.hxx> +#include <vcl/menu.hxx> + +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<PopupMenu> AddonMenuManager::CreateAddonMenu( const Reference< XFrame >& rFrame ) +{ + AddonsOptions aOptions; + VclPtr<PopupMenu> pAddonMenu; + + const Sequence< Sequence< PropertyValue > >& rAddonMenuEntries = aOptions.GetAddonsMenu(); + if ( rAddonMenuEntries.hasElements() ) + { + sal_uInt16 nUniqueMenuId = ADDONMENU_ITEMID_START; + pAddonMenu = VclPtr<PopupMenu>::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, std::u16string_view 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, u".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, u".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 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, + aContext, + aAddonSubMenu ); + if ( !aTitle.isEmpty() && + !aURL.isEmpty() && + aAddonSubMenu.hasElements() && + AddonMenuManager::IsCorrectContext( aModuleIdentifier, aContext )) + { + sal_uInt16 nId = nUniqueMenuId++; + VclPtrInstance<PopupMenu> 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 aContext; + + for ( i = 0; i < nCount; ++i ) + { + GetMenuEntry( aAddonMenuDefinition[i], aTitle, aURL, aTarget, aContext, aAddonSubMenu ); + + if ( !IsCorrectContext( rModuleIdentifier, aContext ) || ( aTitle.isEmpty() && aURL.isEmpty() )) + continue; + + if ( aURL == "private:separator" ) + bInsertSeparator = true; + else + { + VclPtr<PopupMenu> pSubMenu; + if ( aAddonSubMenu.hasElements() ) + { + pSubMenu = VclPtr<PopupMenu>::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; + + void* nAttributePtr = MenuAttributes::CreateAttribute(aTarget, OUString()); + 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& 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_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( std::u16string_view rModuleIdentifier, std::u16string_view rContext ) +{ + if ( rContext.empty() ) + return true; + + if ( !rModuleIdentifier.empty() ) + { + return rContext.find( rModuleIdentifier ) != std::u16string_view::npos; + } + + 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..b97a7eac6 --- /dev/null +++ b/framework/source/fwe/classes/addonsoptions.cxx @@ -0,0 +1,1958 @@ +/* -*- 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 <com/sun/star/beans/PropertyValue.hpp> +#include <framework/addonsoptions.hxx> +#include <o3tl/safeint.hxx> +#include <unotools/configmgr.hxx> +#include <unotools/configitem.hxx> +#include <unotools/ucbstreamhelper.hxx> +#include <tools/stream.hxx> +#include <com/sun/star/uno/Any.hxx> +#include <com/sun/star/uno/Sequence.hxx> +#include <rtl/ustrbuf.hxx> +#include <sal/log.hxx> +#include <comphelper/getexpandeduri.hxx> +#include <comphelper/processfactory.hxx> +#include <vcl/dibtools.hxx> +#include <vcl/graph.hxx> +#include <vcl/graphicfilter.hxx> +#include <vcl/toolbox.hxx> +#include <vcl/svapp.hxx> + +#include <algorithm> +#include <string_view> +#include <unordered_map> +#include <vector> + +// 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; + +constexpr OUStringLiteral ROOTNODE_ADDONMENU = u"Office.Addons"; +constexpr OUStringLiteral PATHDELIMITER = u"/"; +constexpr OUStringLiteral SEPARATOR_URL = u"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 + +constexpr OUStringLiteral IMAGES_NODENAME = u"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 2 +#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;} + BitmapEx 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 + { + BitmapEx aScaled; ///< cached scaled image + BitmapEx 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 BitmapEx &rImage); + void addImage(ImageSize eSize, 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( std::u16string_view aMergeAddonInstructionBase, Sequence< Sequence< PropertyValue > >& rMergeMenu ); + void ReadMergeToolbarData( std::u16string_view aMergeAddonInstructionBase, Sequence< Sequence< PropertyValue > >& rMergeToolbarItems ); + void ReadMergeNotebookBarData( std::u16string_view aMergeAddonInstructionBase, Sequence< Sequence< PropertyValue > >& rMergeNotebookBarItems ); + void ReadMergeStatusbarData( std::u16string_view aMergeAddonInstructionBase, Sequence< Sequence< PropertyValue > >& rMergeStatusbar ); + bool ReadMenuItem( std::u16string_view aMenuItemNodeName, Sequence< PropertyValue >& aMenuItem, bool bIgnoreSubMenu = false ); + bool ReadPopupMenu( std::u16string_view aPopupMenuNodeName, Sequence< PropertyValue >& aPopupMenu ); + void AppendPopupMenu( Sequence< PropertyValue >& aTargetPopupMenu, const Sequence< PropertyValue >& rSourcePopupMenu ); + bool ReadToolBarItem( std::u16string_view aToolBarItemNodeName, Sequence< PropertyValue >& aToolBarItem ); + bool ReadNotebookBarItem( std::u16string_view aNotebookBarItemNodeName, Sequence< PropertyValue >& aNotebookBarItem ); + + bool ReadStatusBarItem( std::u16string_view aStatusbarItemNodeName, Sequence< PropertyValue >& aStatusbarItem ); + std::unique_ptr<ImageEntry> ReadImageData( std::u16string_view aImagesNodeName ); + void ReadAndAssociateImages( const OUString& aURL, const OUString& aImageId ); + BitmapEx 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( std::u16string_view aPropertyRootNode ) + const; + Sequence< OUString > GetPropertyNamesPopupMenu( std::u16string_view aPropertyRootNode ) + const; + Sequence< OUString > GetPropertyNamesToolBarItem( std::u16string_view aPropertyRootNode ) + const; + Sequence< OUString > GetPropertyNamesNotebookBarItem( std::u16string_view aPropertyRootNode ) const; + + Sequence< OUString > GetPropertyNamesStatusbarItem( std::u16string_view aPropertyRootNode ) const; + Sequence< OUString > GetPropertyNamesImages( std::u16string_view aPropertyRootNode ) const; + bool CreateImageFromSequence( BitmapEx& 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 BitmapEx& rImage) +{ + aSizeEntry[static_cast<int>(eSize)].aImage = rImage; +} + +void AddonsOptions_Impl::ImageEntry::addImage(ImageSize eSize, const OUString &rURL) +{ + aSizeEntry[static_cast<int>(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<OUString> 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 BitmapEx ScaleImage( const BitmapEx &rImage, bool bBig ) +{ + Size aSize = ToolBox::GetDefaultImageSize(bBig ? ToolBoxButtonSize::Large : ToolBoxButtonSize::Small); + BitmapEx aScaleBmp(rImage); + SAL_INFO("fwk", "Addons: expensive scale image from " + << aScaleBmp.GetSizePixel() << " to " << aSize); + aScaleBmp.Scale(aSize, BmpScaleFlag::BestQuality); + return aScaleBmp; +} + +BitmapEx AddonsOptions_Impl::GetImageFromURL( const OUString& aURL, bool bBig, bool bNoScale ) +{ + BitmapEx 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<int>(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.IsEmpty()) + rSizeEntry.aImage = ReadImageFromURL(rSizeEntry.aURL); + + if (rSizeEntry.aImage.IsEmpty()) + { // try the other size and scale it + aImage = ScaleImage(ReadImageFromURL(rOtherEntry.aURL), bBig); + rSizeEntry.aImage = aImage; + if (rSizeEntry.aImage.IsEmpty()) + SAL_WARN("fwk", "failed to load addons image " << aURL); + } + + // FIXME: bNoScale is not terribly meaningful or useful + + if (aImage.IsEmpty() && bNoScale) + aImage = rSizeEntry.aImage; + + if (aImage.IsEmpty() && !rSizeEntry.aScaled.IsEmpty()) + aImage = rSizeEntry.aScaled; + + else // scale to the correct size for the theme / toolbox + { + aImage = rSizeEntry.aImage; + if (aImage.IsEmpty()) // 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 ); + auto pMenuItem = aMenuItem.getArray(); + // Init the property value sequence + pMenuItem[ OFFSET_MENUITEM_URL ].Name = m_aPropNames[ INDEX_URL ]; + pMenuItem[ OFFSET_MENUITEM_TITLE ].Name = m_aPropNames[ INDEX_TITLE ]; + pMenuItem[ OFFSET_MENUITEM_TARGET ].Name = m_aPropNames[ INDEX_TARGET ]; + pMenuItem[ OFFSET_MENUITEM_IMAGEIDENTIFIER ].Name = m_aPropNames[ INDEX_IMAGEIDENTIFIER]; + pMenuItem[ OFFSET_MENUITEM_CONTEXT ].Name = m_aPropNames[ INDEX_CONTEXT ]; + pMenuItem[ 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.getArray()[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 ); + auto pMenuItem = aMenuItem.getArray(); + // Init the property value sequence + pMenuItem[ OFFSET_MENUITEM_URL ].Name = m_aPropNames[ INDEX_URL ]; + pMenuItem[ OFFSET_MENUITEM_TITLE ].Name = m_aPropNames[ INDEX_TITLE ]; + pMenuItem[ OFFSET_MENUITEM_TARGET ].Name = m_aPropNames[ INDEX_TARGET ]; + pMenuItem[ OFFSET_MENUITEM_IMAGEIDENTIFIER ].Name = m_aPropNames[ INDEX_IMAGEIDENTIFIER]; + pMenuItem[ OFFSET_MENUITEM_CONTEXT ].Name = m_aPropNames[ INDEX_CONTEXT ]; + pMenuItem[ 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.getArray()[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 ); + auto pPopupMenu = aPopupMenu.getArray(); + // Init the property value sequence + pPopupMenu[ OFFSET_POPUPMENU_TITLE ].Name = m_aPropNames[ INDEX_TITLE ]; + pPopupMenu[ OFFSET_POPUPMENU_CONTEXT ].Name = m_aPropNames[ INDEX_CONTEXT]; + pPopupMenu[ OFFSET_POPUPMENU_SUBMENU ].Name = m_aPropNames[ INDEX_SUBMENU]; + pPopupMenu[ OFFSET_POPUPMENU_URL ].Name = m_aPropNames[ INDEX_URL ]; + + StringToIndexMap aTitleToIndexMap; + auto pAddonOfficeMenuBarSeq = rAddonOfficeMenuBarSeq.getArray(); + 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 = pAddonOfficeMenuBarSeq[pIter->second]; + AppendPopupMenu( rOldPopupMenu, aPopupMenu ); + } + else + { + // not found + sal_uInt32 nMenuItemCount = rAddonOfficeMenuBarSeq.getLength() + 1; + rAddonOfficeMenuBarSeq.realloc( nMenuItemCount ); + pAddonOfficeMenuBarSeq = rAddonOfficeMenuBarSeq.getArray(); + pAddonOfficeMenuBarSeq[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 ); + auto pToolBarItem = aToolBarItem.getArray(); + // Init the property value sequence + pToolBarItem[ OFFSET_TOOLBARITEM_URL ].Name = m_aPropNames[ INDEX_URL ]; + pToolBarItem[ OFFSET_TOOLBARITEM_TITLE ].Name = m_aPropNames[ INDEX_TITLE ]; + pToolBarItem[ OFFSET_TOOLBARITEM_IMAGEIDENTIFIER ].Name = m_aPropNames[ INDEX_IMAGEIDENTIFIER]; + pToolBarItem[ OFFSET_TOOLBARITEM_TARGET ].Name = m_aPropNames[ INDEX_TARGET ]; + pToolBarItem[ OFFSET_TOOLBARITEM_CONTEXT ].Name = m_aPropNames[ INDEX_CONTEXT ]; + pToolBarItem[ OFFSET_TOOLBARITEM_CONTROLTYPE ].Name = m_aPropNames[ INDEX_CONTROLTYPE ]; + pToolBarItem[ 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.getArray()[nAddonCount] = aToolBarItem; + } + } + + return ( o3tl::make_unsigned(rAddonOfficeToolBarSeq.getLength()) > nToolBarItemCount ); +} + +void AddonsOptions_Impl::ReadOfficeNotebookBarSet( + AddonNotebookBars& rAddonOfficeNotebookBars, + std::vector<OUString>& rAddonOfficeNotebookBarResNames) +{ + // Read the OfficeToolBar set and fill property sequences + OUString aAddonNotebookBarNodeName("AddonUI/OfficeNotebookBar"); + Sequence<OUString> 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<Sequence<PropertyValue>>& rAddonOfficeNotebookBarSeq) +{ + sal_uInt32 nNotebookBarItemCount = rAddonOfficeNotebookBarSeq.getLength(); + OUString aAddonNotebookBarItemSetNode(rNotebookBarItemSetNodeName + m_aPathDelimiter); + Sequence<OUString> aAddonNotebookBarItemSetNodeSeq = GetNodeNames(rNotebookBarItemSetNodeName); + Sequence<PropertyValue> aNotebookBarItem(PROPERTYCOUNT_NOTEBOOKBARITEM); + auto pNotebookBarItem = aNotebookBarItem.getArray(); + // Init the property value sequence + pNotebookBarItem[OFFSET_NOTEBOOKBARITEM_URL].Name = m_aPropNames[INDEX_URL]; + pNotebookBarItem[OFFSET_NOTEBOOKBARITEM_TITLE].Name = m_aPropNames[INDEX_TITLE]; + pNotebookBarItem[OFFSET_NOTEBOOKBARITEM_IMAGEIDENTIFIER].Name + = m_aPropNames[INDEX_IMAGEIDENTIFIER]; + pNotebookBarItem[OFFSET_NOTEBOOKBARITEM_TARGET].Name = m_aPropNames[INDEX_TARGET]; + pNotebookBarItem[OFFSET_NOTEBOOKBARITEM_CONTEXT].Name = m_aPropNames[INDEX_CONTEXT]; + pNotebookBarItem[OFFSET_NOTEBOOKBARITEM_CONTROLTYPE].Name = m_aPropNames[INDEX_CONTROLTYPE]; + pNotebookBarItem[OFFSET_NOTEBOOKBARITEM_WIDTH].Name = m_aPropNames[INDEX_WIDTH]; + pNotebookBarItem[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.getArray()[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 + OUString aURL; + + for ( sal_uInt32 n = 0; n < nCount; n++ ) + { + OUString aImagesItemNode( aAddonImagesNode + aAddonImagesNodeSeq[n] ); + + // Create sequence for data access + Sequence< OUString > aAddonImageItemNodePropNames = { 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<ImageEntry> 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. + OUString aPopupMenuURL; + OUStringBuffer aBuf( m_aRootAddonPopupMenuURLPrexfix.getLength() + 3 ); + aBuf.append( m_aRootAddonPopupMenuURLPrexfix ); + aBuf.append( ++m_nRootAddonPopupMenuId ); + aPopupMenuURL = aBuf.makeStringAndClear(); + return aPopupMenuURL; +} + +void AddonsOptions_Impl::ReadMenuMergeInstructions( MergeMenuInstructionContainer& aContainer ) +{ + static const OUStringLiteral aMenuMergeRootName( u"AddonUI/OfficeMenuBarMerging/" ); + + Sequence< OUString > aAddonMergeNodesSeq = GetNodeNames( aMenuMergeRootName ); + + sal_uInt32 nCount = aAddonMergeNodesSeq.getLength(); + + // Init the property value sequence + Sequence< OUString > aNodePropNames( 5 ); + auto pNodePropNames = aNodePropNames.getArray(); + + 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++ ) + { + OUString aMergeAddonInstructionBase = aMergeAddonInstructions + + m_aPathDelimiter + + aAddonInstMergeNodesSeq[j] + + m_aPathDelimiter; + + // Create sequence for data access + pNodePropNames[0] = aMergeAddonInstructionBase + + m_aPropMergeMenuNames[ OFFSET_MERGEMENU_MERGEPOINT ]; + + pNodePropNames[1] = aMergeAddonInstructionBase + + m_aPropMergeMenuNames[ OFFSET_MERGEMENU_MERGECOMMAND ]; + + pNodePropNames[2] = aMergeAddonInstructionBase + + m_aPropMergeMenuNames[ OFFSET_MERGEMENU_MERGECOMMANDPARAMETER ]; + + pNodePropNames[3] = aMergeAddonInstructionBase + + m_aPropMergeMenuNames[ OFFSET_MERGEMENU_MERGEFALLBACK ]; + + pNodePropNames[4] = aMergeAddonInstructionBase + + m_aPropMergeMenuNames[ OFFSET_MERGEMENU_MERGECONTEXT ]; + + 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; + + ReadMergeMenuData( aMergeAddonInstructionBase, aMergeMenuInstruction.aMergeMenu ); + + aContainer.push_back( aMergeMenuInstruction ); + } + } +} + +void AddonsOptions_Impl::ReadMergeMenuData( std::u16string_view 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 : asNonConstRange(aSubMenuNodeNames) ) + rName = aMergeMenuBaseNode + rName; + + ReadSubMenuEntries( aSubMenuNodeNames, rMergeMenu ); +} + +void AddonsOptions_Impl::ReadToolbarMergeInstructions( ToolbarMergingInstructions& rCachedToolbarMergingInstructions ) +{ + static const OUStringLiteral aToolbarMergeRootName( u"AddonUI/OfficeToolbarMerging/" ); + + Sequence< OUString > aAddonMergeNodesSeq = GetNodeNames( aToolbarMergeRootName ); + sal_uInt32 nCount = aAddonMergeNodesSeq.getLength(); + + // Init the property value sequence + Sequence< OUString > aNodePropNames( 6 ); + auto pNodePropNames = aNodePropNames.getArray(); + + 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++ ) + { + OUString aMergeAddonInstructionBase = aMergeAddonInstructions + + m_aPathDelimiter + + aAddonInstMergeNodesSeq[j] + + m_aPathDelimiter; + + // Create sequence for data access + pNodePropNames[0] = aMergeAddonInstructionBase + + m_aPropMergeToolbarNames[ OFFSET_MERGETOOLBAR_TOOLBAR ]; + + pNodePropNames[1] = aMergeAddonInstructionBase + + m_aPropMergeToolbarNames[ OFFSET_MERGETOOLBAR_MERGEPOINT ]; + + pNodePropNames[2] = aMergeAddonInstructionBase + + m_aPropMergeToolbarNames[ OFFSET_MERGETOOLBAR_MERGECOMMAND ]; + + pNodePropNames[3] = aMergeAddonInstructionBase + + m_aPropMergeToolbarNames[ OFFSET_MERGETOOLBAR_MERGECOMMANDPARAMETER ]; + + pNodePropNames[4] = aMergeAddonInstructionBase + + m_aPropMergeToolbarNames[ OFFSET_MERGETOOLBAR_MERGEFALLBACK ]; + + pNodePropNames[5] = aMergeAddonInstructionBase + + m_aPropMergeToolbarNames[ OFFSET_MERGETOOLBAR_MERGECONTEXT ]; + + 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, + aMergeToolbarInstruction.aMergeToolbarItems ); + + MergeToolbarInstructionContainer& rVector = rCachedToolbarMergingInstructions[ aMergeToolbarInstruction.aMergeToolbar ]; + rVector.push_back( aMergeToolbarInstruction ); + } + } +} + +void AddonsOptions_Impl::ReadMergeToolbarData( std::u16string_view aMergeAddonInstructionBase, Sequence< Sequence< PropertyValue > >& rMergeToolbarItems ) +{ + OUString aMergeToolbarBaseNode = aMergeAddonInstructionBase + + m_aPropMergeToolbarNames[ OFFSET_MERGETOOLBAR_TOOLBARITEMS ]; + + ReadToolBarItemSet( aMergeToolbarBaseNode, rMergeToolbarItems ); +} + +void AddonsOptions_Impl::ReadNotebookBarMergeInstructions( + NotebookBarMergingInstructions& rCachedNotebookBarMergingInstructions) +{ + static const OUStringLiteral aNotebookBarMergeRootName(u"AddonUI/OfficeNotebookBarMerging/"); + + Sequence<OUString> aAddonMergeNodesSeq = GetNodeNames(aNotebookBarMergeRootName); + sal_uInt32 nCount = aAddonMergeNodesSeq.getLength(); + + // Init the property value sequence + Sequence<OUString> aNodePropNames(6); + auto pNodePropNames = aNodePropNames.getArray(); + + for (sal_uInt32 i = 0; i < nCount; i++) + { + OUString aMergeAddonInstructions(aNotebookBarMergeRootName + aAddonMergeNodesSeq[i]); + + Sequence<OUString> aAddonInstMergeNodesSeq = GetNodeNames(aMergeAddonInstructions); + sal_uInt32 nCountAddons = aAddonInstMergeNodesSeq.getLength(); + + for (sal_uInt32 j = 0; j < nCountAddons; j++) + { + OUString aMergeAddonInstructionBase = aMergeAddonInstructions + + m_aPathDelimiter + + aAddonInstMergeNodesSeq[j] + + m_aPathDelimiter; + + // Create sequence for data access + pNodePropNames[0] = aMergeAddonInstructionBase + + m_aPropMergeNotebookBarNames[OFFSET_MERGENOTEBOOKBAR_NOTEBOOKBAR]; + + pNodePropNames[1] = aMergeAddonInstructionBase + + m_aPropMergeNotebookBarNames[OFFSET_MERGENOTEBOOKBAR_MERGEPOINT]; + + pNodePropNames[2] = aMergeAddonInstructionBase + + m_aPropMergeNotebookBarNames[OFFSET_MERGENOTEBOOKBAR_MERGECOMMAND]; + + pNodePropNames[3] = aMergeAddonInstructionBase + + m_aPropMergeNotebookBarNames[OFFSET_MERGENOTEBOOKBAR_MERGECOMMANDPARAMETER]; + + pNodePropNames[4] = aMergeAddonInstructionBase + + m_aPropMergeNotebookBarNames[OFFSET_MERGENOTEBOOKBAR_MERGEFALLBACK]; + + pNodePropNames[5] = aMergeAddonInstructionBase + + m_aPropMergeNotebookBarNames[OFFSET_MERGENOTEBOOKBAR_MERGECONTEXT]; + + Sequence<Any> 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, + aMergeNotebookBarInstruction.aMergeNotebookBarItems); + + MergeNotebookBarInstructionContainer& rVector + = rCachedNotebookBarMergingInstructions[aMergeNotebookBarInstruction + .aMergeNotebookBar]; + rVector.push_back(aMergeNotebookBarInstruction); + } + } +} + +void AddonsOptions_Impl::ReadMergeNotebookBarData( + std::u16string_view aMergeAddonInstructionBase, + Sequence<Sequence<PropertyValue>>& rMergeNotebookBarItems) +{ + OUString aMergeNotebookBarBaseNode = aMergeAddonInstructionBase + + m_aPropMergeNotebookBarNames[OFFSET_MERGENOTEBOOKBAR_NOTEBOOKBARITEMS]; + + ReadNotebookBarItemSet(aMergeNotebookBarBaseNode, rMergeNotebookBarItems); +} + +void AddonsOptions_Impl::ReadStatusbarMergeInstructions( MergeStatusbarInstructionContainer& aContainer ) +{ + static const OUStringLiteral aStatusbarMergeRootName( u"AddonUI/OfficeStatusbarMerging/" ); + + Sequence< OUString > aAddonMergeNodesSeq = GetNodeNames( aStatusbarMergeRootName ); + sal_uInt32 nCount = aAddonMergeNodesSeq.getLength(); + + Sequence< OUString > aNodePropNames( 5 ); + auto pNodePropNames = aNodePropNames.getArray(); + + 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++ ) + { + OUString aMergeAddonInstructionBase = aMergeAddonInstructions + + m_aPathDelimiter + + aAddonInstMergeNodesSeq[j] + + m_aPathDelimiter; + + // Create sequence for data access + pNodePropNames[0] = aMergeAddonInstructionBase + + m_aPropMergeMenuNames[ OFFSET_MERGESTATUSBAR_MERGEPOINT ]; + + pNodePropNames[1] = aMergeAddonInstructionBase + + m_aPropMergeMenuNames[ OFFSET_MERGESTATUSBAR_MERGECOMMAND ]; + + pNodePropNames[2] = aMergeAddonInstructionBase + + m_aPropMergeMenuNames[ OFFSET_MERGESTATUSBAR_MERGECOMMANDPARAMETER ]; + + pNodePropNames[3] = aMergeAddonInstructionBase + + m_aPropMergeMenuNames[ OFFSET_MERGESTATUSBAR_MERGEFALLBACK ]; + + pNodePropNames[4] = aMergeAddonInstructionBase + + m_aPropMergeMenuNames[ OFFSET_MERGESTATUSBAR_MERGECONTEXT ]; + + 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, + aMergeStatusbarInstruction.aMergeStatusbarItems ); + + aContainer.push_back( aMergeStatusbarInstruction ); + } + } +} + +void AddonsOptions_Impl::ReadMergeStatusbarData( + std::u16string_view aMergeAddonInstructionBase, + Sequence< Sequence< PropertyValue > >& rMergeStatusbarItems ) +{ + OUString aMergeStatusbarBaseNode = aMergeAddonInstructionBase + + m_aPropMergeStatusbarNames[ OFFSET_MERGESTATUSBAR_STATUSBARITEMS ]; + + OUString aAddonStatusbarItemSetNode( aMergeStatusbarBaseNode + m_aPathDelimiter ); + Sequence< OUString > aAddonStatusbarItemSetNodeSeq = GetNodeNames( aMergeStatusbarBaseNode ); + + Sequence< PropertyValue > aStatusbarItem( PROPERTYCOUNT_STATUSBARITEM ); + auto pStatusbarItem = aStatusbarItem.getArray(); + pStatusbarItem[ OFFSET_STATUSBARITEM_URL ].Name = m_aPropNames[ INDEX_URL ]; + pStatusbarItem[ OFFSET_STATUSBARITEM_TITLE ].Name = m_aPropNames[ INDEX_TITLE ]; + pStatusbarItem[ OFFSET_STATUSBARITEM_CONTEXT ].Name = m_aPropNames[ INDEX_CONTEXT ]; + pStatusbarItem[ OFFSET_STATUSBARITEM_ALIGN ].Name = m_aPropNames[ INDEX_ALIGN ]; + pStatusbarItem[ OFFSET_STATUSBARITEM_AUTOSIZE ].Name = m_aPropNames[ INDEX_AUTOSIZE ]; + pStatusbarItem[ OFFSET_STATUSBARITEM_OWNERDRAW ].Name = m_aPropNames[ INDEX_OWNERDRAW ]; + pStatusbarItem[ OFFSET_STATUSBARITEM_MANDATORY ].Name = m_aPropNames[ INDEX_MANDATORY ]; + pStatusbarItem[ 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.getArray()[nAddonCount] = aStatusbarItem; + } + } +} + +bool AddonsOptions_Impl::ReadStatusBarItem( + std::u16string_view 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 ) + { + auto pStatusbarItem = aStatusbarItem.getArray(); + pStatusbarItem[ OFFSET_STATUSBARITEM_URL ].Value <<= aURL; + pStatusbarItem[ OFFSET_STATUSBARITEM_TITLE ].Value = aStatusbarItemNodePropValues[ OFFSET_STATUSBARITEM_TITLE ]; + pStatusbarItem[ OFFSET_STATUSBARITEM_CONTEXT ].Value = aStatusbarItemNodePropValues[ OFFSET_STATUSBARITEM_CONTEXT ]; + pStatusbarItem[ OFFSET_STATUSBARITEM_ALIGN ].Value = aStatusbarItemNodePropValues[ OFFSET_STATUSBARITEM_ALIGN ]; + pStatusbarItem[ OFFSET_STATUSBARITEM_AUTOSIZE ].Value = aStatusbarItemNodePropValues[ OFFSET_STATUSBARITEM_AUTOSIZE ]; + pStatusbarItem[ OFFSET_STATUSBARITEM_OWNERDRAW ].Value = aStatusbarItemNodePropValues[ OFFSET_STATUSBARITEM_OWNERDRAW ]; + pStatusbarItem[ 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; + pStatusbarItem[ OFFSET_STATUSBARITEM_WIDTH ].Value <<= sal_Int32( nValue ); + + bResult = true; + } + + return bResult; +} + +bool AddonsOptions_Impl::ReadMenuItem( std::u16string_view 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() ) + { + auto pMenuItem = aMenuItem.getArray(); + pMenuItem[ 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 + pMenuItem[ OFFSET_MENUITEM_URL ].Value <<= aPopupMenuURL; + pMenuItem[ OFFSET_MENUITEM_TARGET ].Value <<= OUString(); + pMenuItem[ OFFSET_MENUITEM_IMAGEIDENTIFIER ].Value <<= aPopupMenuImageId; + pMenuItem[ 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 : asNonConstRange(aRootSubMenuNodeNames) ) + rName = aSubMenuRootNodeName + rName; + ReadSubMenuEntries( aRootSubMenuNodeNames, aSubMenuSeq ); + pMenuItem[ 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 ); + + pMenuItem[ OFFSET_MENUITEM_URL ].Value <<= aStrValue; + pMenuItem[ OFFSET_MENUITEM_TARGET ].Value = aMenuItemNodePropValues[ OFFSET_MENUITEM_TARGET ]; + pMenuItem[ OFFSET_MENUITEM_IMAGEIDENTIFIER ].Value <<= aMenuImageId; + pMenuItem[ OFFSET_MENUITEM_CONTEXT ].Value = aMenuItemNodePropValues[ OFFSET_MENUITEM_CONTEXT ]; + pMenuItem[ OFFSET_MENUITEM_SUBMENU ].Value <<= Sequence< Sequence< PropertyValue > >(); // Submenu set! + + bResult = true; + } + } + else if (( aMenuItemNodePropValues[ OFFSET_MENUITEM_URL ] >>= aStrValue ) && + aStrValue == SEPARATOR_URL ) + { + auto pMenuItem = aMenuItem.getArray(); + + // Separator + pMenuItem[ OFFSET_MENUITEM_URL ].Value <<= aStrValue; + pMenuItem[ OFFSET_MENUITEM_TARGET ].Value <<= OUString(); + pMenuItem[ OFFSET_MENUITEM_IMAGEIDENTIFIER ].Value <<= OUString(); + pMenuItem[ OFFSET_MENUITEM_CONTEXT ].Value <<= OUString(); + pMenuItem[ OFFSET_MENUITEM_SUBMENU ].Value <<= Sequence< Sequence< PropertyValue > >(); // Submenu set! + bResult = true; + } + + return bResult; +} + +bool AddonsOptions_Impl::ReadPopupMenu( std::u16string_view 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() ) + { + auto pPopupMenu = aPopupMenu.getArray(); + pPopupMenu[ 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(); + + pPopupMenu[ OFFSET_POPUPMENU_URL ].Value <<= aPopupMenuURL; + pPopupMenu[ 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 : asNonConstRange(aRootSubMenuNodeNames) ) + rName = aSubMenuRootNodeName + rName; + ReadSubMenuEntries( aRootSubMenuNodeNames, aSubMenuSeq ); + pPopupMenu[ 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() ); + auto pTargetSubMenuSeq = aTargetSubMenuSeq.getArray(); + for ( Sequence<PropertyValue> const & rSeq : std::as_const(aSourceSubMenuSeq) ) + pTargetSubMenuSeq[nIndex++] = rSeq; + rTargetPopupMenu.getArray()[ OFFSET_POPUPMENU_SUBMENU ].Value <<= aTargetSubMenuSeq; + } +} + +bool AddonsOptions_Impl::ReadToolBarItem( std::u16string_view aToolBarItemNodeName, Sequence< PropertyValue >& aToolBarItem ) +{ + bool bResult = false; + 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() ) + { + OUString aTitle; + if ( aURL == SEPARATOR_URL ) + { + auto pToolBarItem = aToolBarItem.getArray(); + + // A separator toolbar item only needs a URL + pToolBarItem[ OFFSET_TOOLBARITEM_URL ].Value <<= aURL; + pToolBarItem[ OFFSET_TOOLBARITEM_TITLE ].Value <<= OUString(); + pToolBarItem[ OFFSET_TOOLBARITEM_TARGET ].Value <<= OUString(); + pToolBarItem[ OFFSET_TOOLBARITEM_IMAGEIDENTIFIER ].Value <<= OUString(); + pToolBarItem[ OFFSET_TOOLBARITEM_CONTEXT ].Value <<= OUString(); + pToolBarItem[ OFFSET_TOOLBARITEM_CONTROLTYPE ].Value <<= OUString(); + pToolBarItem[ OFFSET_TOOLBARITEM_WIDTH ].Value <<= sal_Int32( 0 ); + + bResult = true; + } + else if (( aToolBarItemNodePropValues[ OFFSET_TOOLBARITEM_TITLE ] >>= aTitle ) && !aTitle.isEmpty() ) + { + auto pToolBarItem = aToolBarItem.getArray(); + + // 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 ); + + pToolBarItem[ OFFSET_TOOLBARITEM_URL ].Value <<= aURL; + pToolBarItem[ OFFSET_TOOLBARITEM_TITLE ].Value <<= aTitle; + pToolBarItem[ OFFSET_TOOLBARITEM_TARGET ].Value = aToolBarItemNodePropValues[ OFFSET_TOOLBARITEM_TARGET ]; + pToolBarItem[ OFFSET_TOOLBARITEM_IMAGEIDENTIFIER ].Value <<= aImageId; + pToolBarItem[ OFFSET_TOOLBARITEM_CONTEXT ].Value = aToolBarItemNodePropValues[ OFFSET_TOOLBARITEM_CONTEXT ]; + pToolBarItem[ 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; + pToolBarItem[ OFFSET_TOOLBARITEM_WIDTH ].Value <<= sal_Int32( nValue ); + + bResult = true; + } + } + + return bResult; +} + +bool AddonsOptions_Impl::ReadNotebookBarItem( std::u16string_view aNotebookBarItemNodeName, Sequence< PropertyValue >& aNotebookBarItem ) +{ + bool bResult = false; + 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() ) + { + OUString aTitle; + if ( aURL == SEPARATOR_URL ) + { + auto pNotebookBarItem = aNotebookBarItem.getArray(); + + // A separator toolbar item only needs a URL + pNotebookBarItem[ OFFSET_NOTEBOOKBARITEM_URL ].Value <<= aURL; + pNotebookBarItem[ OFFSET_NOTEBOOKBARITEM_TITLE ].Value <<= OUString(); + pNotebookBarItem[ OFFSET_NOTEBOOKBARITEM_TARGET ].Value <<= OUString(); + pNotebookBarItem[ OFFSET_NOTEBOOKBARITEM_IMAGEIDENTIFIER ].Value <<= OUString(); + pNotebookBarItem[ OFFSET_NOTEBOOKBARITEM_CONTEXT ].Value <<= OUString(); + pNotebookBarItem[ OFFSET_NOTEBOOKBARITEM_CONTROLTYPE ].Value <<= OUString(); + pNotebookBarItem[ OFFSET_NOTEBOOKBARITEM_WIDTH ].Value <<= sal_Int32( 0 ); + pNotebookBarItem[ OFFSET_NOTEBOOKBARITEM_STYLE ].Value <<= OUString(); + + bResult = true; + } + else if (( aNotebookBarItemNodePropValues[ OFFSET_NOTEBOOKBARITEM_TITLE ] >>= aTitle ) && !aTitle.isEmpty() ) + { + auto pNotebookBarItem = aNotebookBarItem.getArray(); + + // 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 ); + + pNotebookBarItem[ OFFSET_NOTEBOOKBARITEM_URL ].Value <<= aURL; + pNotebookBarItem[ OFFSET_NOTEBOOKBARITEM_TITLE ].Value <<= aTitle; + pNotebookBarItem[ OFFSET_NOTEBOOKBARITEM_TARGET ].Value = aNotebookBarItemNodePropValues[ OFFSET_NOTEBOOKBARITEM_TARGET ]; + pNotebookBarItem[ OFFSET_NOTEBOOKBARITEM_IMAGEIDENTIFIER ].Value <<= aImageId; + pNotebookBarItem[ OFFSET_NOTEBOOKBARITEM_CONTEXT ].Value = aNotebookBarItemNodePropValues[ OFFSET_NOTEBOOKBARITEM_CONTEXT ]; + pNotebookBarItem[ 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; + pNotebookBarItem[ OFFSET_NOTEBOOKBARITEM_WIDTH ].Value <<= sal_Int32( nValue ); + pNotebookBarItem[ 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 ); + auto pMenuItem = aMenuItem.getArray(); + + // Init the property value sequence + pMenuItem[ OFFSET_MENUITEM_URL ].Name = PROPERTYNAME_URL; + pMenuItem[ OFFSET_MENUITEM_TITLE ].Name = PROPERTYNAME_TITLE; + pMenuItem[ OFFSET_MENUITEM_TARGET ].Name = PROPERTYNAME_TARGET; + pMenuItem[ OFFSET_MENUITEM_IMAGEIDENTIFIER ].Name = PROPERTYNAME_IMAGEIDENTIFIER; + pMenuItem[ OFFSET_MENUITEM_CONTEXT ].Name = PROPERTYNAME_CONTEXT; + pMenuItem[ 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.getArray()[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); +} + +BitmapEx AddonsOptions_Impl::ReadImageFromURL(const OUString& aImageURL) +{ + BitmapEx aImage; + + std::unique_ptr<SvStream> 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, u"", *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.IsAlpha() ) + aBitmapEx = BitmapEx( aBitmapEx.GetBitmap(), COL_LIGHTMAGENTA ); + + aImage = 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, aFileURL.makeStringAndClear() ); + } + + m_aImageManager.emplace( aURL, aImageEntry ); +} + +std::unique_ptr<AddonsOptions_Impl::ImageEntry> AddonsOptions_Impl::ReadImageData( std::u16string_view aImagesNodeName ) +{ + Sequence< OUString > aImageDataNodeNames = GetPropertyNamesImages( aImagesNodeName ); + Sequence< Any > aPropertyData; + Sequence< sal_Int8 > aImageDataSeq; + OUString aImageURL; + + std::unique_ptr<ImageEntry> 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 + BitmapEx 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 ( i == OFFSET_IMAGES_SMALL_URL || i == OFFSET_IMAGES_BIG_URL ) + { + if(!pEntry) + pEntry.reset(new ImageEntry()); + + // Retrieve image data from an external bitmap file. Make sure that embedded image data + // has a higher priority. + if (aPropertyData[i] >>= aImageURL) + { + SubstituteVariables(aImageURL); + pEntry->addImage(i == OFFSET_IMAGES_SMALL_URL ? IMGSIZE_SMALL : IMGSIZE_BIG, aImageURL); + } + } + } + + return pEntry; +} + +bool AddonsOptions_Impl::CreateImageFromSequence( BitmapEx& rImage, Sequence< sal_Int8 >& rBitmapDataSeq ) const +{ + bool bResult = false; + + if ( rBitmapDataSeq.hasElements() ) + { + SvMemoryStream aMemStream( rBitmapDataSeq.getArray(), rBitmapDataSeq.getLength(), StreamMode::STD_READ ); + + ReadDIBBitmapEx(rImage, aMemStream); + + if( !rImage.IsAlpha() ) + { + // Support non-transparent bitmaps to be downward compatible with OOo 1.1.x addons + rImage = BitmapEx( rImage.GetBitmap(), COL_LIGHTMAGENTA ); + } + + bResult = true; + } + + return bResult; +} + +Sequence< OUString > AddonsOptions_Impl::GetPropertyNamesMenuItem( std::u16string_view aPropertyRootNode ) const +{ + Sequence< OUString > lResult( PROPERTYCOUNT_MENUITEM ); + auto plResult = lResult.getArray(); + + // Create property names dependent from the root node name + plResult[OFFSET_MENUITEM_URL] = aPropertyRootNode + m_aPropNames[ INDEX_URL ]; + plResult[OFFSET_MENUITEM_TITLE] = aPropertyRootNode + m_aPropNames[ INDEX_TITLE ]; + plResult[OFFSET_MENUITEM_IMAGEIDENTIFIER] = aPropertyRootNode + m_aPropNames[ INDEX_IMAGEIDENTIFIER ]; + plResult[OFFSET_MENUITEM_TARGET] = aPropertyRootNode + m_aPropNames[ INDEX_TARGET ]; + plResult[OFFSET_MENUITEM_CONTEXT] = aPropertyRootNode + m_aPropNames[ INDEX_CONTEXT ]; + plResult[OFFSET_MENUITEM_SUBMENU] = aPropertyRootNode + m_aPropNames[ INDEX_SUBMENU ]; + + return lResult; +} + +Sequence< OUString > AddonsOptions_Impl::GetPropertyNamesPopupMenu( std::u16string_view aPropertyRootNode ) const +{ + // The URL is automatically set and not read from the configuration. + Sequence< OUString > lResult( PROPERTYCOUNT_POPUPMENU-1 ); + auto plResult = lResult.getArray(); + + // Create property names dependent from the root node name + plResult[OFFSET_POPUPMENU_TITLE] = aPropertyRootNode + m_aPropNames[ INDEX_TITLE ]; + plResult[OFFSET_POPUPMENU_CONTEXT] = aPropertyRootNode + m_aPropNames[ INDEX_CONTEXT ]; + plResult[OFFSET_POPUPMENU_SUBMENU] = aPropertyRootNode + m_aPropNames[ INDEX_SUBMENU ]; + + return lResult; +} + +Sequence< OUString > AddonsOptions_Impl::GetPropertyNamesToolBarItem( std::u16string_view aPropertyRootNode ) const +{ + Sequence< OUString > lResult( PROPERTYCOUNT_TOOLBARITEM ); + auto plResult = lResult.getArray(); + + // Create property names dependent from the root node name + plResult[0] = aPropertyRootNode + m_aPropNames[ INDEX_URL ]; + plResult[1] = aPropertyRootNode + m_aPropNames[ INDEX_TITLE ]; + plResult[2] = aPropertyRootNode + m_aPropNames[ INDEX_IMAGEIDENTIFIER]; + plResult[3] = aPropertyRootNode + m_aPropNames[ INDEX_TARGET ]; + plResult[4] = aPropertyRootNode + m_aPropNames[ INDEX_CONTEXT ]; + plResult[5] = aPropertyRootNode + m_aPropNames[ INDEX_CONTROLTYPE ]; + plResult[6] = aPropertyRootNode + m_aPropNames[ INDEX_WIDTH ]; + + return lResult; +} + +Sequence< OUString > AddonsOptions_Impl::GetPropertyNamesNotebookBarItem( std::u16string_view aPropertyRootNode ) const +{ + Sequence< OUString > lResult( PROPERTYCOUNT_NOTEBOOKBARITEM ); + auto plResult = lResult.getArray(); + + // Create property names dependent from the root node name + plResult[0] = aPropertyRootNode + m_aPropNames[ INDEX_URL ]; + plResult[1] = aPropertyRootNode + m_aPropNames[ INDEX_TITLE ]; + plResult[2] = aPropertyRootNode + m_aPropNames[ INDEX_IMAGEIDENTIFIER]; + plResult[3] = aPropertyRootNode + m_aPropNames[ INDEX_TARGET ]; + plResult[4] = aPropertyRootNode + m_aPropNames[ INDEX_CONTEXT ]; + plResult[5] = aPropertyRootNode + m_aPropNames[ INDEX_CONTROLTYPE ]; + plResult[6] = aPropertyRootNode + m_aPropNames[ INDEX_WIDTH ]; + plResult[7] = aPropertyRootNode + m_aPropNames[ INDEX_STYLE ]; + + return lResult; +} + +Sequence< OUString > AddonsOptions_Impl::GetPropertyNamesStatusbarItem( + std::u16string_view aPropertyRootNode ) const +{ + Sequence< OUString > lResult( PROPERTYCOUNT_STATUSBARITEM ); + auto plResult = lResult.getArray(); + + plResult[0] = OUString( aPropertyRootNode + m_aPropNames[ INDEX_URL ] ); + plResult[1] = OUString( aPropertyRootNode + m_aPropNames[ INDEX_TITLE ] ); + plResult[2] = OUString( aPropertyRootNode + m_aPropNames[ INDEX_CONTEXT ] ); + plResult[3] = OUString( aPropertyRootNode + m_aPropNames[ INDEX_ALIGN ] ); + plResult[4] = OUString( aPropertyRootNode + m_aPropNames[ INDEX_AUTOSIZE ] ); + plResult[5] = OUString( aPropertyRootNode + m_aPropNames[ INDEX_OWNERDRAW ] ); + plResult[6] = OUString( aPropertyRootNode + m_aPropNames[ INDEX_MANDATORY ] ); + plResult[7] = OUString( aPropertyRootNode + m_aPropNames[ INDEX_WIDTH ] ); + + return lResult; +} + +Sequence< OUString > AddonsOptions_Impl::GetPropertyNamesImages( std::u16string_view aPropertyRootNode ) const +{ + Sequence< OUString > lResult( PROPERTYCOUNT_IMAGES ); + auto plResult = lResult.getArray(); + + // Create property names dependent from the root node name + plResult[0] = aPropertyRootNode + m_aPropImagesNames[ OFFSET_IMAGES_SMALL ]; + plResult[1] = aPropertyRootNode + m_aPropImagesNames[ OFFSET_IMAGES_BIG ]; + plResult[2] = aPropertyRootNode + m_aPropImagesNames[ OFFSET_IMAGES_SMALLHC ]; + plResult[3] = aPropertyRootNode + m_aPropImagesNames[ OFFSET_IMAGES_BIGHC ]; + plResult[4] = aPropertyRootNode + m_aPropImagesNames[ OFFSET_IMAGES_SMALL_URL ]; + plResult[5] = aPropertyRootNode + m_aPropImagesNames[ OFFSET_IMAGES_BIG_URL ]; + plResult[6] = aPropertyRootNode + m_aPropImagesNames[ OFFSET_IMAGES_SMALLHC_URL]; + plResult[7] = aPropertyRootNode + m_aPropImagesNames[ OFFSET_IMAGES_BIGHC_URL ]; + + return lResult; +} + +namespace{ + //global + std::weak_ptr<AddonsOptions_Impl> 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<AddonsOptions_Impl>(); + 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 + +BitmapEx AddonsOptions::GetImageFromURL( const OUString& aURL, bool bBig, bool bNoScale ) const +{ + MutexGuard aGuard( GetOwnStaticMutex() ); + return m_pImpl->GetImageFromURL( aURL, bBig, bNoScale ); +} + +// public method + +BitmapEx 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 <framework/framelistanalyzer.hxx> + +#include <targets.h> +#include <properties.h> + +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/lang/IndexOutOfBoundsException.hpp> +#include <com/sun/star/frame/ModuleManager.hpp> +#include <com/sun/star/frame/UnknownModuleException.hpp> +#include <com/sun/star/frame/XFrame.hpp> + +#include <comphelper/processfactory.hxx> +#include <tools/diagnose_ex.h> +#include <sal/log.hxx> + +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<nCount; ++i) + { + // Ignore invalid items ... and of course the reference frame. + // It will be a member of the given frame list too - but it was already + // analyzed before! + css::uno::Reference< css::frame::XFrame > 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..e9a1d639d --- /dev/null +++ b/framework/source/fwe/classes/fwkresid.cxx @@ -0,0 +1,24 @@ +/* -*- 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 <classes/fwkresid.hxx> + +OUString FwkResId(TranslateId aId) { return Translate::get(aId, Translate::Create("fwk")); } + +/* 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..02fa9d2df --- /dev/null +++ b/framework/source/fwe/classes/rootactiontriggercontainer.cxx @@ -0,0 +1,251 @@ +/* -*- 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 <classes/rootactiontriggercontainer.hxx> +#include <classes/actiontriggercontainer.hxx> +#include <classes/actiontriggerpropertyset.hxx> +#include <classes/actiontriggerseparatorpropertyset.hxx> +#include <comphelper/servicehelper.hxx> +#include <cppuhelper/supportsservice.hxx> +#include <cppuhelper/queryinterface.hxx> +#include <cppuhelper/typeprovider.hxx> +#include <framework/actiontriggerhelper.hxx> +#include <utility> +#include <vcl/svapp.hxx> + +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 +{ + +const css::uno::Sequence<sal_Int8>& RootActionTriggerContainer::getUnoTunnelId() noexcept +{ + 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<const sal_Int8*>(pGUID), 16); + return seqID; +} + +RootActionTriggerContainer::RootActionTriggerContainer(css::uno::Reference<css::awt::XPopupMenu> xMenu, + const OUString* pMenuIdentifier) + : m_bContainerCreated(false) + , m_xMenu(std::move(xMenu)) + , 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() noexcept +{ + PropertySetContainer::acquire(); +} + +void SAL_CALL RootActionTriggerContainer::release() noexcept +{ + PropertySetContainer::release(); +} + +// XMultiServiceFactory +Reference< XInterface > SAL_CALL RootActionTriggerContainer::createInstance( const OUString& aServiceSpecifier ) +{ + if ( aServiceSpecifier == SERVICENAME_ACTIONTRIGGER ) + return static_cast<OWeakObject *>( new ActionTriggerPropertySet()); + else if ( aServiceSpecifier == SERVICENAME_ACTIONTRIGGERCONTAINER ) + return static_cast<OWeakObject *>( new ActionTriggerContainer()); + else if ( aServiceSpecifier == SERVICENAME_ACTIONTRIGGERSEPARATOR ) + return static_cast<OWeakObject *>( new ActionTriggerSeparatorPropertySet()); + else + throw css::uno::RuntimeException("Unknown service specifier!", static_cast<OWeakObject *>(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{ SERVICENAME_ACTIONTRIGGER, + SERVICENAME_ACTIONTRIGGERCONTAINER, + 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_xMenu ) + return m_xMenu->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<XPropertySet>::get(); +} + +sal_Bool SAL_CALL RootActionTriggerContainer::hasElements() +{ + if (m_xMenu) + return m_xMenu->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() +{ + return { SERVICENAME_ACTIONTRIGGERCONTAINER }; +} + +// XUnoTunnel +sal_Int64 SAL_CALL RootActionTriggerContainer::getSomething( const Sequence< sal_Int8 >& aIdentifier ) +{ + return comphelper::getSomethingImpl(aIdentifier, this); +} + +// XTypeProvider +Sequence< Type > SAL_CALL RootActionTriggerContainer::getTypes() +{ + // Create a static typecollection ... + static ::cppu::OTypeCollection ourTypeCollection( + cppu::UnoType<XMultiServiceFactory>::get(), + cppu::UnoType<XIndexContainer>::get(), + cppu::UnoType<XServiceInfo>::get(), + cppu::UnoType<XTypeProvider>::get(), + cppu::UnoType<XUnoTunnel>::get(), + cppu::UnoType<XNamed>::get()); + + return ourTypeCollection.getTypes(); +} + +Sequence< sal_Int8 > SAL_CALL RootActionTriggerContainer::getImplementationId() +{ + return css::uno::Sequence<sal_Int8>(); +} + +// private implementation helper +void RootActionTriggerContainer::FillContainer() +{ + m_bContainerCreated = true; + ActionTriggerHelper::FillActionTriggerContainerFromMenu( + this, m_xMenu); +} +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..170f3e715 --- /dev/null +++ b/framework/source/fwe/classes/sfxhelperfunctions.cxx @@ -0,0 +1,181 @@ +/* -*- 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 <framework/sfxhelperfunctions.hxx> +#include <framework/ContextChangeEventMultiplexerTunnel.hxx> +#include <helper/mischelper.hxx> +#include <svtools/toolboxcontroller.hxx> +#include <svtools/statusbarcontroller.hxx> + +static pfunc_setToolBoxControllerCreator pToolBoxControllerCreator = nullptr; +static pfunc_setWeldToolBoxControllerCreator pWeldToolBoxControllerCreator = 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; +} + +rtl::Reference<svt::ToolboxController> CreateToolBoxController( const Reference< XFrame >& rFrame, ToolBox* pToolbox, ToolBoxItemId 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_setWeldToolBoxControllerCreator SetWeldToolBoxControllerCreator( pfunc_setWeldToolBoxControllerCreator pSetWeldToolBoxControllerCreator ) +{ + ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() ); + pfunc_setWeldToolBoxControllerCreator pOldSetToolBoxControllerCreator = pWeldToolBoxControllerCreator; + pWeldToolBoxControllerCreator = pSetWeldToolBoxControllerCreator; + return pOldSetToolBoxControllerCreator; +} + +css::uno::Reference<css::frame::XToolbarController> CreateWeldToolBoxController( const Reference< XFrame >& rFrame, weld::Toolbar* pToolbar, weld::Builder* pBuilder, const OUString& aCommandURL ) +{ + pfunc_setWeldToolBoxControllerCreator pFactory = nullptr; + { + ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() ); + pFactory = pWeldToolBoxControllerCreator; + } + + if ( pFactory ) + return (*pFactory)( rFrame, pToolbar, pBuilder, aCommandURL ); + else + return nullptr; +} + +pfunc_setStatusBarControllerCreator SetStatusBarControllerCreator( pfunc_setStatusBarControllerCreator pSetStatusBarControllerCreator ) +{ + ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() ); + pfunc_setStatusBarControllerCreator pOldSetStatusBarControllerCreator = pSetStatusBarControllerCreator; + pStatusBarControllerCreator = pSetStatusBarControllerCreator; + return pOldSetStatusBarControllerCreator; +} + +rtl::Reference<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, std::u16string_view 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, std::u16string_view 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<ui::XContextChangeEventListener> GetFirstListenerWith( + css::uno::Reference<css::uno::XComponentContext> const & xComponentContext, + uno::Reference<uno::XInterface> const& xEventFocus, + std::function<bool (uno::Reference<ui::XContextChangeEventListener> const&)> const& rPredicate) +{ + return GetFirstListenerWith_Impl(xComponentContext, xEventFocus, rPredicate); +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |