tdf#130857 qt weld: Implement QtInstanceWidget::get_text_height
[LibreOffice.git] / framework / source / uiconfiguration / moduleuiconfigurationmanager.cxx
blobeeebdfc73730b434cd0b0772cd876d6198e8700a
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <accelerators/presethandler.hxx>
21 #include <uiconfiguration/imagemanager.hxx>
22 #include <uielement/constitemcontainer.hxx>
23 #include <uielement/rootitemcontainer.hxx>
24 #include <uielement/uielementtypenames.hxx>
25 #include <menuconfiguration.hxx>
26 #include <toolboxconfiguration.hxx>
28 #include <statusbarconfiguration.hxx>
30 #include <com/sun/star/ui/UIElementType.hpp>
31 #include <com/sun/star/ui/ConfigurationEvent.hpp>
32 #include <com/sun/star/ui/ModuleAcceleratorConfiguration.hpp>
33 #include <com/sun/star/ui/XModuleUIConfigurationManager2.hpp>
34 #include <com/sun/star/lang/DisposedException.hpp>
35 #include <com/sun/star/lang/IllegalAccessException.hpp>
36 #include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
37 #include <com/sun/star/beans/XPropertySet.hpp>
38 #include <com/sun/star/embed/ElementModes.hpp>
39 #include <com/sun/star/embed/InvalidStorageException.hpp>
40 #include <com/sun/star/embed/StorageWrappedTargetException.hpp>
41 #include <com/sun/star/embed/XTransactedObject.hpp>
42 #include <com/sun/star/container/ElementExistException.hpp>
43 #include <com/sun/star/container/XNameAccess.hpp>
44 #include <com/sun/star/container/XIndexContainer.hpp>
45 #include <com/sun/star/io/IOException.hpp>
46 #include <com/sun/star/io/XStream.hpp>
47 #include <com/sun/star/lang/XServiceInfo.hpp>
48 #include <com/sun/star/lang/XComponent.hpp>
50 #include <comphelper/propertysequence.hxx>
51 #include <comphelper/sequence.hxx>
52 #include <cppuhelper/exc_hlp.hxx>
53 #include <cppuhelper/implbase.hxx>
54 #include <cppuhelper/supportsservice.hxx>
55 #include <utility>
56 #include <vcl/svapp.hxx>
57 #include <sal/log.hxx>
58 #include <comphelper/interfacecontainer4.hxx>
59 #include <comphelper/propertyvalue.hxx>
60 #include <comphelper/sequenceashashmap.hxx>
61 #include <comphelper/servicehelper.hxx>
62 #include <o3tl/string_view.hxx>
63 #include <memory>
64 #include <mutex>
65 #include <string_view>
67 using namespace css;
68 using namespace com::sun::star::uno;
69 using namespace com::sun::star::io;
70 using namespace com::sun::star::embed;
71 using namespace com::sun::star::lang;
72 using namespace com::sun::star::container;
73 using namespace com::sun::star::beans;
74 using namespace framework;
76 constexpr OUStringLiteral RESOURCETYPE_MENUBAR = u"menubar";
77 constexpr OUStringLiteral RESOURCETYPE_TOOLBAR = u"toolbar";
78 constexpr OUStringLiteral RESOURCETYPE_STATUSBAR = u"statusbar";
79 constexpr OUStringLiteral RESOURCETYPE_POPUPMENU = u"popupmenu";
81 namespace {
83 class ModuleUIConfigurationManager : public cppu::WeakImplHelper<
84 css::lang::XServiceInfo,
85 css::lang::XComponent,
86 css::ui::XModuleUIConfigurationManager2 >
88 public:
89 ModuleUIConfigurationManager(
90 const css::uno::Reference< css::uno::XComponentContext >& xServiceManager,
91 const css::uno::Sequence< css::uno::Any >& aArguments);
93 virtual OUString SAL_CALL getImplementationName() override
95 return u"com.sun.star.comp.framework.ModuleUIConfigurationManager"_ustr;
98 virtual sal_Bool SAL_CALL supportsService(OUString const & ServiceName) override
100 return cppu::supportsService(this, ServiceName);
103 virtual css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override
105 return {u"com.sun.star.ui.ModuleUIConfigurationManager"_ustr};
108 // XComponent
109 virtual void SAL_CALL dispose() override;
110 virtual void SAL_CALL addEventListener( const css::uno::Reference< css::lang::XEventListener >& xListener ) override;
111 virtual void SAL_CALL removeEventListener( const css::uno::Reference< css::lang::XEventListener >& aListener ) override;
113 // XUIConfiguration
114 virtual void SAL_CALL addConfigurationListener( const css::uno::Reference< css::ui::XUIConfigurationListener >& Listener ) override;
115 virtual void SAL_CALL removeConfigurationListener( const css::uno::Reference< css::ui::XUIConfigurationListener >& Listener ) override;
117 // XUIConfigurationManager
118 virtual void SAL_CALL reset() override;
119 virtual css::uno::Sequence< css::uno::Sequence< css::beans::PropertyValue > > SAL_CALL getUIElementsInfo( sal_Int16 ElementType ) override;
120 virtual css::uno::Reference< css::container::XIndexContainer > SAL_CALL createSettings( ) override;
121 virtual sal_Bool SAL_CALL hasSettings( const OUString& ResourceURL ) override;
122 virtual css::uno::Reference< css::container::XIndexAccess > SAL_CALL getSettings( const OUString& ResourceURL, sal_Bool bWriteable ) override;
123 virtual void SAL_CALL replaceSettings( const OUString& ResourceURL, const css::uno::Reference< css::container::XIndexAccess >& aNewData ) override;
124 virtual void SAL_CALL removeSettings( const OUString& ResourceURL ) override;
125 virtual void SAL_CALL insertSettings( const OUString& NewResourceURL, const css::uno::Reference< css::container::XIndexAccess >& aNewData ) override;
126 virtual css::uno::Reference< css::uno::XInterface > SAL_CALL getImageManager() override;
127 virtual css::uno::Reference< css::ui::XAcceleratorConfiguration > SAL_CALL getShortCutManager() override;
128 virtual css::uno::Reference< css::ui::XAcceleratorConfiguration > SAL_CALL createShortCutManager() override;
129 virtual css::uno::Reference< css::uno::XInterface > SAL_CALL getEventsManager() override;
131 // XModuleUIConfigurationManager
132 virtual sal_Bool SAL_CALL isDefaultSettings( const OUString& ResourceURL ) override;
133 virtual css::uno::Reference< css::container::XIndexAccess > SAL_CALL getDefaultSettings( const OUString& ResourceURL ) override;
135 // XUIConfigurationPersistence
136 virtual void SAL_CALL reload() override;
137 virtual void SAL_CALL store() override;
138 virtual void SAL_CALL storeToStorage( const css::uno::Reference< css::embed::XStorage >& Storage ) override;
139 virtual sal_Bool SAL_CALL isModified() override;
140 virtual sal_Bool SAL_CALL isReadOnly() override;
142 private:
143 // private data types
144 enum Layer
146 LAYER_DEFAULT,
147 LAYER_USERDEFINED,
148 LAYER_COUNT
151 enum NotifyOp
153 NotifyOp_Remove,
154 NotifyOp_Insert,
155 NotifyOp_Replace
158 struct UIElementInfo
160 UIElementInfo( OUString _aResourceURL, OUString _aUIName ) :
161 aResourceURL(std::move( _aResourceURL)), aUIName(std::move( _aUIName )) {}
162 OUString aResourceURL;
163 OUString aUIName;
166 struct UIElementData
168 UIElementData() : bModified( false ), bDefault( true ), bDefaultNode( true ) {};
170 OUString aResourceURL;
171 OUString aName;
172 bool bModified; // has been changed since last storing
173 bool bDefault; // default settings
174 bool bDefaultNode; // this is a default layer element data
175 css::uno::Reference< css::container::XIndexAccess > xSettings;
178 typedef std::unordered_map< OUString, UIElementData > UIElementDataHashMap;
180 struct UIElementType
182 UIElementType() : bModified( false ),
183 bLoaded( false ),
184 nElementType( css::ui::UIElementType::UNKNOWN ) {}
186 bool bModified;
187 bool bLoaded;
188 sal_Int16 nElementType;
189 UIElementDataHashMap aElementsHashMap;
190 css::uno::Reference< css::embed::XStorage > xStorage;
193 typedef std::vector< UIElementType > UIElementTypesVector;
194 typedef std::vector< css::ui::ConfigurationEvent > ConfigEventNotifyContainer;
195 typedef std::unordered_map< OUString, UIElementInfo > UIElementInfoHashMap;
197 void impl_Initialize();
198 void implts_notifyContainerListener( const css::ui::ConfigurationEvent& aEvent, NotifyOp eOp );
199 void impl_fillSequenceWithElementTypeInfo( UIElementInfoHashMap& aUIElementInfoCollection, sal_Int16 nElementType );
200 void impl_preloadUIElementTypeList( Layer eLayer, sal_Int16 nElementType );
201 UIElementData* impl_findUIElementData( const OUString& aResourceURL, sal_Int16 nElementType, bool bLoad = true );
202 void impl_requestUIElementData( sal_Int16 nElementType, Layer eLayer, UIElementData& aUIElementData );
203 void impl_storeElementTypeData( const css::uno::Reference< css::embed::XStorage >& xStorage, UIElementType& rElementType, bool bResetModifyState = true );
204 void impl_resetElementTypeData( UIElementType& rUserElementType, UIElementType const & rDefaultElementType, ConfigEventNotifyContainer& rRemoveNotifyContainer, ConfigEventNotifyContainer& rReplaceNotifyContainer );
205 void impl_reloadElementTypeData( UIElementType& rUserElementType, UIElementType const & rDefaultElementType, ConfigEventNotifyContainer& rRemoveNotifyContainer, ConfigEventNotifyContainer& rReplaceNotifyContainer );
207 UIElementTypesVector m_aUIElements[LAYER_COUNT];
208 std::unique_ptr<PresetHandler> m_pStorageHandler[css::ui::UIElementType::COUNT];
209 css::uno::Reference< css::embed::XStorage > m_xDefaultConfigStorage;
210 css::uno::Reference< css::embed::XStorage > m_xUserConfigStorage;
211 bool m_bReadOnly;
212 bool m_bModified;
213 bool m_bDisposed;
214 OUString m_aXMLPostfix;
215 OUString m_aPropUIName;
216 OUString m_aModuleIdentifier;
217 css::uno::Reference< css::embed::XTransactedObject > m_xUserRootCommit;
218 css::uno::Reference< css::uno::XComponentContext > m_xContext;
219 std::mutex m_mutex;
220 comphelper::OInterfaceContainerHelper4<css::lang::XEventListener> m_aEventListeners;
221 comphelper::OInterfaceContainerHelper4<css::ui::XUIConfigurationListener> m_aConfigListeners;
222 rtl::Reference< ImageManager > m_xModuleImageManager;
223 css::uno::Reference< css::ui::XAcceleratorConfiguration > m_xModuleAcceleratorManager;
226 // important: The order and position of the elements must match the constant
227 // definition of "css::ui::UIElementType"
228 std::u16string_view UIELEMENTTYPENAMES[] =
230 u"", // Dummy value for unknown!
231 u"" UIELEMENTTYPE_MENUBAR_NAME,
232 u"" UIELEMENTTYPE_POPUPMENU_NAME,
233 u"" UIELEMENTTYPE_TOOLBAR_NAME,
234 u"" UIELEMENTTYPE_STATUSBAR_NAME,
235 u"" UIELEMENTTYPE_FLOATINGWINDOW_NAME,
236 u"" UIELEMENTTYPE_PROGRESSBAR_NAME,
237 u"" UIELEMENTTYPE_TOOLPANEL_NAME
240 constexpr std::u16string_view RESOURCEURL_PREFIX = u"private:resource/";
242 sal_Int16 RetrieveTypeFromResourceURL( std::u16string_view aResourceURL )
245 if (( o3tl::starts_with(aResourceURL, RESOURCEURL_PREFIX ) ) &&
246 ( aResourceURL.size() > RESOURCEURL_PREFIX.size() ))
248 std::u16string_view aTmpStr = aResourceURL.substr( RESOURCEURL_PREFIX.size() );
249 size_t nIndex = aTmpStr.find( '/' );
250 if (( nIndex > 0 ) && ( aTmpStr.size() > nIndex ))
252 std::u16string_view aTypeStr( aTmpStr.substr( 0, nIndex ));
253 for ( int i = 0; i < ui::UIElementType::COUNT; i++ )
255 if ( aTypeStr == UIELEMENTTYPENAMES[i] )
256 return sal_Int16( i );
261 return ui::UIElementType::UNKNOWN;
264 OUString RetrieveNameFromResourceURL( std::u16string_view aResourceURL )
266 if (( o3tl::starts_with(aResourceURL, RESOURCEURL_PREFIX ) ) &&
267 ( aResourceURL.size() > RESOURCEURL_PREFIX.size() ))
269 size_t nIndex = aResourceURL.rfind( '/' );
271 if ( nIndex > 0 && nIndex != std::u16string_view::npos && (( nIndex+1 ) < aResourceURL.size()) )
272 return OUString(aResourceURL.substr( nIndex+1 ));
275 return OUString();
278 void ModuleUIConfigurationManager::impl_fillSequenceWithElementTypeInfo( UIElementInfoHashMap& aUIElementInfoCollection, sal_Int16 nElementType )
280 // preload list of element types on demand
281 impl_preloadUIElementTypeList( LAYER_USERDEFINED, nElementType );
282 impl_preloadUIElementTypeList( LAYER_DEFAULT, nElementType );
284 UIElementDataHashMap& rUserElements = m_aUIElements[LAYER_USERDEFINED][nElementType].aElementsHashMap;
286 OUString aCustomUrlPrefix( u"custom_"_ustr );
287 for (auto const& userElement : rUserElements)
289 sal_Int32 nIndex = userElement.second.aResourceURL.indexOf( aCustomUrlPrefix, RESOURCEURL_PREFIX.size() );
290 if ( nIndex > static_cast<sal_Int32>(RESOURCEURL_PREFIX.size()) )
292 // Performance: Retrieve user interface name only for custom user interface elements.
293 // It's only used by them!
294 UIElementData* pDataSettings = impl_findUIElementData( userElement.second.aResourceURL, nElementType );
295 if ( pDataSettings )
297 // Retrieve user interface name from XPropertySet interface
298 OUString aUIName;
299 Reference< XPropertySet > xPropSet( pDataSettings->xSettings, UNO_QUERY );
300 if ( xPropSet.is() )
302 Any a = xPropSet->getPropertyValue( m_aPropUIName );
303 a >>= aUIName;
306 UIElementInfo aInfo( userElement.second.aResourceURL, aUIName );
307 aUIElementInfoCollection.emplace( userElement.second.aResourceURL, aInfo );
310 else
312 // The user interface name for standard user interface elements is stored in the WindowState.xcu file
313 UIElementInfo aInfo( userElement.second.aResourceURL, OUString() );
314 aUIElementInfoCollection.emplace( userElement.second.aResourceURL, aInfo );
318 UIElementDataHashMap& rDefaultElements = m_aUIElements[LAYER_DEFAULT][nElementType].aElementsHashMap;
320 for (auto const& defaultElement : rDefaultElements)
322 UIElementInfoHashMap::const_iterator pIterInfo = aUIElementInfoCollection.find( defaultElement.second.aResourceURL );
323 if ( pIterInfo == aUIElementInfoCollection.end() )
325 sal_Int32 nIndex = defaultElement.second.aResourceURL.indexOf( aCustomUrlPrefix, RESOURCEURL_PREFIX.size() );
326 if ( nIndex > static_cast<sal_Int32>(RESOURCEURL_PREFIX.size()) )
328 // Performance: Retrieve user interface name only for custom user interface elements.
329 // It's only used by them!
330 UIElementData* pDataSettings = impl_findUIElementData( defaultElement.second.aResourceURL, nElementType );
331 if ( pDataSettings )
333 // Retrieve user interface name from XPropertySet interface
334 OUString aUIName;
335 Reference< XPropertySet > xPropSet( pDataSettings->xSettings, UNO_QUERY );
336 if ( xPropSet.is() )
338 Any a = xPropSet->getPropertyValue( m_aPropUIName );
339 a >>= aUIName;
341 UIElementInfo aInfo( defaultElement.second.aResourceURL, aUIName );
342 aUIElementInfoCollection.emplace( defaultElement.second.aResourceURL, aInfo );
345 else
347 // The user interface name for standard user interface elements is stored in the WindowState.xcu file
348 UIElementInfo aInfo( defaultElement.second.aResourceURL, OUString() );
349 aUIElementInfoCollection.emplace( defaultElement.second.aResourceURL, aInfo );
355 void ModuleUIConfigurationManager::impl_preloadUIElementTypeList( Layer eLayer, sal_Int16 nElementType )
357 UIElementType& rElementTypeData = m_aUIElements[eLayer][nElementType];
359 if ( rElementTypeData.bLoaded )
360 return;
362 Reference< XStorage > xElementTypeStorage = rElementTypeData.xStorage;
363 if ( !xElementTypeStorage.is() )
364 return;
366 OUString aResURLPrefix =
367 OUString::Concat(RESOURCEURL_PREFIX) +
368 UIELEMENTTYPENAMES[ nElementType ] +
369 "/";
371 UIElementDataHashMap& rHashMap = rElementTypeData.aElementsHashMap;
372 const Sequence< OUString > aUIElementNames = xElementTypeStorage->getElementNames();
373 for ( OUString const & rElementName : aUIElementNames )
375 UIElementData aUIElementData;
377 // Resource name must be without ".xml"
378 sal_Int32 nIndex = rElementName.lastIndexOf( '.' );
379 if (( nIndex > 0 ) && ( nIndex < rElementName.getLength() ))
381 std::u16string_view aExtension( rElementName.subView( nIndex+1 ));
382 std::u16string_view aUIElementName( rElementName.subView( 0, nIndex ));
384 if (!aUIElementName.empty() &&
385 ( o3tl::equalsIgnoreAsciiCase(aExtension, u"xml")))
387 aUIElementData.aResourceURL = aResURLPrefix + aUIElementName;
388 aUIElementData.aName = rElementName;
390 if ( eLayer == LAYER_USERDEFINED )
392 aUIElementData.bModified = false;
393 aUIElementData.bDefault = false;
394 aUIElementData.bDefaultNode = false;
397 // Create std::unordered_map entries for all user interface elements inside the storage. We don't load the
398 // settings to speed up the process.
399 rHashMap.emplace( aUIElementData.aResourceURL, aUIElementData );
402 rElementTypeData.bLoaded = true;
407 void ModuleUIConfigurationManager::impl_requestUIElementData( sal_Int16 nElementType, Layer eLayer, UIElementData& aUIElementData )
409 UIElementType& rElementTypeData = m_aUIElements[eLayer][nElementType];
411 Reference< XStorage > xElementTypeStorage = rElementTypeData.xStorage;
412 if ( xElementTypeStorage.is() && !aUIElementData.aName.isEmpty() )
416 Reference< XStream > xStream = xElementTypeStorage->openStreamElement( aUIElementData.aName, ElementModes::READ );
417 Reference< XInputStream > xInputStream = xStream->getInputStream();
419 if ( xInputStream.is() )
421 switch ( nElementType )
423 case css::ui::UIElementType::UNKNOWN:
424 break;
426 case css::ui::UIElementType::MENUBAR:
427 case css::ui::UIElementType::POPUPMENU:
431 MenuConfiguration aMenuCfg( m_xContext );
432 Reference< XIndexAccess > xContainer( aMenuCfg.CreateMenuBarConfigurationFromXML( xInputStream ));
433 auto pRootItemContainer = dynamic_cast<RootItemContainer*>( xContainer.get() );
434 if ( pRootItemContainer )
435 aUIElementData.xSettings = new ConstItemContainer( pRootItemContainer, true );
436 else
437 aUIElementData.xSettings = new ConstItemContainer( xContainer, true );
438 return;
440 catch ( const css::lang::WrappedTargetException& )
444 break;
446 case css::ui::UIElementType::TOOLBAR:
450 Reference< XIndexContainer > xIndexContainer( new RootItemContainer() );
451 ToolBoxConfiguration::LoadToolBox( m_xContext, xInputStream, xIndexContainer );
452 auto pRootItemContainer = dynamic_cast<RootItemContainer*>( xIndexContainer.get() );
453 aUIElementData.xSettings = new ConstItemContainer( pRootItemContainer, true );
454 return;
456 catch ( const css::lang::WrappedTargetException& )
460 break;
463 case css::ui::UIElementType::STATUSBAR:
467 Reference< XIndexContainer > xIndexContainer( new RootItemContainer() );
468 StatusBarConfiguration::LoadStatusBar( m_xContext, xInputStream, xIndexContainer );
469 auto pRootItemContainer = dynamic_cast<RootItemContainer*>( xIndexContainer.get() );
470 aUIElementData.xSettings = new ConstItemContainer( pRootItemContainer, true );
471 return;
473 catch ( const css::lang::WrappedTargetException& )
477 break;
480 case css::ui::UIElementType::FLOATINGWINDOW:
482 break;
487 catch ( const css::embed::InvalidStorageException& )
490 catch ( const css::lang::IllegalArgumentException& )
493 catch ( const css::io::IOException& )
496 catch ( const css::embed::StorageWrappedTargetException& )
501 // At least we provide an empty settings container!
502 aUIElementData.xSettings = new ConstItemContainer();
505 ModuleUIConfigurationManager::UIElementData* ModuleUIConfigurationManager::impl_findUIElementData( const OUString& aResourceURL, sal_Int16 nElementType, bool bLoad )
507 // preload list of element types on demand
508 impl_preloadUIElementTypeList( LAYER_USERDEFINED, nElementType );
509 impl_preloadUIElementTypeList( LAYER_DEFAULT, nElementType );
511 // first try to look into our user-defined vector/unordered_map combination
512 UIElementDataHashMap& rUserHashMap = m_aUIElements[LAYER_USERDEFINED][nElementType].aElementsHashMap;
513 UIElementDataHashMap::iterator pIter = rUserHashMap.find( aResourceURL );
514 if ( pIter != rUserHashMap.end() )
516 // Default data settings data must be retrieved from the default layer!
517 if ( !pIter->second.bDefault )
519 if ( !pIter->second.xSettings.is() && bLoad )
520 impl_requestUIElementData( nElementType, LAYER_USERDEFINED, pIter->second );
521 return &(pIter->second);
525 // Not successful, we have to look into our default vector/unordered_map combination
526 UIElementDataHashMap& rDefaultHashMap = m_aUIElements[LAYER_DEFAULT][nElementType].aElementsHashMap;
527 pIter = rDefaultHashMap.find( aResourceURL );
528 if ( pIter != rDefaultHashMap.end() )
530 if ( !pIter->second.xSettings.is() && bLoad )
531 impl_requestUIElementData( nElementType, LAYER_DEFAULT, pIter->second );
532 return &(pIter->second);
535 // Nothing has been found!
536 return nullptr;
539 void ModuleUIConfigurationManager::impl_storeElementTypeData( const Reference< XStorage >& xStorage, UIElementType& rElementType, bool bResetModifyState )
541 UIElementDataHashMap& rHashMap = rElementType.aElementsHashMap;
543 for (auto & elem : rHashMap)
545 UIElementData& rElement = elem.second;
546 if ( rElement.bModified )
548 if ( rElement.bDefault )
550 xStorage->removeElement( rElement.aName );
551 rElement.bModified = false; // mark as not modified
553 else
555 Reference< XStream > xStream = xStorage->openStreamElement( rElement.aName, ElementModes::WRITE|ElementModes::TRUNCATE );
556 Reference< XOutputStream > xOutputStream( xStream->getOutputStream() );
558 if ( xOutputStream.is() )
560 switch( rElementType.nElementType )
562 case css::ui::UIElementType::MENUBAR:
563 case css::ui::UIElementType::POPUPMENU:
567 MenuConfiguration aMenuCfg( m_xContext );
568 aMenuCfg.StoreMenuBarConfigurationToXML(
569 rElement.xSettings, xOutputStream, rElementType.nElementType == css::ui::UIElementType::MENUBAR );
571 catch ( const css::lang::WrappedTargetException& )
575 break;
577 case css::ui::UIElementType::TOOLBAR:
581 ToolBoxConfiguration::StoreToolBox( m_xContext, xOutputStream, rElement.xSettings );
583 catch ( const css::lang::WrappedTargetException& )
587 break;
589 case css::ui::UIElementType::STATUSBAR:
593 StatusBarConfiguration::StoreStatusBar( m_xContext, xOutputStream, rElement.xSettings );
595 catch ( const css::lang::WrappedTargetException& )
599 break;
601 default:
602 break;
606 // mark as not modified if we store to our own storage
607 if ( bResetModifyState )
608 rElement.bModified = false;
613 // commit element type storage
614 Reference< XTransactedObject > xTransactedObject( xStorage, UNO_QUERY );
615 if ( xTransactedObject.is() )
616 xTransactedObject->commit();
618 // mark UIElementType as not modified if we store to our own storage
619 if ( bResetModifyState )
620 rElementType.bModified = false;
623 // This is only allowed to be called on the LAYER_USER_DEFINED!
624 void ModuleUIConfigurationManager::impl_resetElementTypeData(
625 UIElementType& rUserElementType,
626 UIElementType const & rDefaultElementType,
627 ConfigEventNotifyContainer& rRemoveNotifyContainer,
628 ConfigEventNotifyContainer& rReplaceNotifyContainer )
630 UIElementDataHashMap& rHashMap = rUserElementType.aElementsHashMap;
632 Reference< XUIConfigurationManager > xThis(this);
633 Reference< XInterface > xIfac( xThis, UNO_QUERY );
634 sal_Int16 nType = rUserElementType.nElementType;
636 // Make copies of the event structures to be thread-safe. We have to unlock our mutex before calling
637 // our listeners!
638 for (auto & elem : rHashMap)
640 UIElementData& rElement = elem.second;
641 if ( !rElement.bDefault )
643 if ( rDefaultElementType.xStorage->hasByName( rElement.aName ))
645 // Replace settings with data from default layer
646 Reference< XIndexAccess > xOldSettings( rElement.xSettings );
647 impl_requestUIElementData( nType, LAYER_DEFAULT, rElement );
649 ui::ConfigurationEvent aReplaceEvent;
650 aReplaceEvent.ResourceURL = rElement.aResourceURL;
651 aReplaceEvent.Accessor <<= xThis;
652 aReplaceEvent.Source = xIfac;
653 aReplaceEvent.ReplacedElement <<= xOldSettings;
654 aReplaceEvent.Element <<= rElement.xSettings;
656 rReplaceNotifyContainer.push_back( aReplaceEvent );
658 // Mark element as default and not modified. That means "not active"
659 // in the user layer anymore.
660 rElement.bModified = false;
661 rElement.bDefault = true;
663 else
665 // Remove user-defined settings from user layer
666 ui::ConfigurationEvent aEvent;
667 aEvent.ResourceURL = rElement.aResourceURL;
668 aEvent.Accessor <<= xThis;
669 aEvent.Source = xIfac;
670 aEvent.Element <<= rElement.xSettings;
672 rRemoveNotifyContainer.push_back( aEvent );
674 // Mark element as default and not modified. That means "not active"
675 // in the user layer anymore.
676 rElement.bModified = false;
677 rElement.bDefault = true;
682 // Remove all settings from our user interface elements
683 rHashMap.clear();
686 void ModuleUIConfigurationManager::impl_reloadElementTypeData(
687 UIElementType& rUserElementType,
688 UIElementType const & rDefaultElementType,
689 ConfigEventNotifyContainer& rRemoveNotifyContainer,
690 ConfigEventNotifyContainer& rReplaceNotifyContainer )
692 UIElementDataHashMap& rHashMap = rUserElementType.aElementsHashMap;
694 Reference< XUIConfigurationManager > xThis(this);
695 Reference< XInterface > xIfac( xThis, UNO_QUERY );
696 sal_Int16 nType = rUserElementType.nElementType;
698 for (auto & elem : rHashMap)
700 UIElementData& rElement = elem.second;
701 if ( rElement.bModified )
703 if ( rUserElementType.xStorage->hasByName( rElement.aName ))
705 // Replace settings with data from user layer
706 Reference< XIndexAccess > xOldSettings( rElement.xSettings );
708 impl_requestUIElementData( nType, LAYER_USERDEFINED, rElement );
710 ui::ConfigurationEvent aReplaceEvent;
712 aReplaceEvent.ResourceURL = rElement.aResourceURL;
713 aReplaceEvent.Accessor <<= xThis;
714 aReplaceEvent.Source = xIfac;
715 aReplaceEvent.ReplacedElement <<= xOldSettings;
716 aReplaceEvent.Element <<= rElement.xSettings;
717 rReplaceNotifyContainer.push_back( aReplaceEvent );
719 rElement.bModified = false;
721 else if ( rDefaultElementType.xStorage->hasByName( rElement.aName ))
723 // Replace settings with data from default layer
724 Reference< XIndexAccess > xOldSettings( rElement.xSettings );
726 impl_requestUIElementData( nType, LAYER_DEFAULT, rElement );
728 ui::ConfigurationEvent aReplaceEvent;
730 aReplaceEvent.ResourceURL = rElement.aResourceURL;
731 aReplaceEvent.Accessor <<= xThis;
732 aReplaceEvent.Source = xIfac;
733 aReplaceEvent.ReplacedElement <<= xOldSettings;
734 aReplaceEvent.Element <<= rElement.xSettings;
735 rReplaceNotifyContainer.push_back( aReplaceEvent );
737 // Mark element as default and not modified. That means "not active"
738 // in the user layer anymore.
739 rElement.bModified = false;
740 rElement.bDefault = true;
742 else
744 // Element settings are not in any storage => remove
745 ui::ConfigurationEvent aRemoveEvent;
747 aRemoveEvent.ResourceURL = rElement.aResourceURL;
748 aRemoveEvent.Accessor <<= xThis;
749 aRemoveEvent.Source = xIfac;
750 aRemoveEvent.Element <<= rElement.xSettings;
752 rRemoveNotifyContainer.push_back( aRemoveEvent );
754 // Mark element as default and not modified. That means "not active"
755 // in the user layer anymore.
756 rElement.bModified = false;
757 rElement.bDefault = true;
762 rUserElementType.bModified = false;
765 void ModuleUIConfigurationManager::impl_Initialize()
767 // Initialize the top-level structures with the storage data
768 if ( m_xUserConfigStorage.is() )
770 // Try to access our module sub folder
771 for ( sal_Int16 i = 1; i < css::ui::UIElementType::COUNT;
772 i++ )
774 Reference< XStorage > xElementTypeStorage;
777 if ( m_pStorageHandler[i] )
778 xElementTypeStorage = m_pStorageHandler[i]->getWorkingStorageUser();
780 catch ( const css::container::NoSuchElementException& )
783 catch ( const css::embed::InvalidStorageException& )
786 catch ( const css::lang::IllegalArgumentException& )
789 catch ( const css::io::IOException& )
792 catch ( const css::embed::StorageWrappedTargetException& )
796 m_aUIElements[LAYER_USERDEFINED][i].nElementType = i;
797 m_aUIElements[LAYER_USERDEFINED][i].bModified = false;
798 m_aUIElements[LAYER_USERDEFINED][i].xStorage = std::move(xElementTypeStorage);
802 if ( !m_xDefaultConfigStorage.is() )
803 return;
805 Reference< XNameAccess > xNameAccess( m_xDefaultConfigStorage, UNO_QUERY_THROW );
807 // Try to access our module sub folder
808 for ( sal_Int16 i = 1; i < css::ui::UIElementType::COUNT;
809 i++ )
811 Reference< XStorage > xElementTypeStorage;
814 const OUString sName( UIELEMENTTYPENAMES[i] );
815 if( xNameAccess->hasByName( sName ) )
816 xNameAccess->getByName( sName ) >>= xElementTypeStorage;
818 catch ( const css::container::NoSuchElementException& )
822 m_aUIElements[LAYER_DEFAULT][i].nElementType = i;
823 m_aUIElements[LAYER_DEFAULT][i].bModified = false;
824 m_aUIElements[LAYER_DEFAULT][i].xStorage = std::move(xElementTypeStorage);
828 ModuleUIConfigurationManager::ModuleUIConfigurationManager(
829 const Reference< XComponentContext >& xContext,
830 const css::uno::Sequence< css::uno::Any >& aArguments)
831 : m_bReadOnly( true )
832 , m_bModified( false )
833 , m_bDisposed( false )
834 , m_aXMLPostfix( u".xml"_ustr )
835 , m_aPropUIName( u"UIName"_ustr )
836 , m_xContext( xContext )
838 // Make sure we have a default initialized entry for every layer and user interface element type!
839 // The following code depends on this!
840 m_aUIElements[LAYER_DEFAULT].resize( css::ui::UIElementType::COUNT );
841 m_aUIElements[LAYER_USERDEFINED].resize( css::ui::UIElementType::COUNT );
843 SolarMutexGuard g;
845 OUString aModuleShortName;
846 if( aArguments.getLength() == 2 && (aArguments[0] >>= aModuleShortName) && (aArguments[1] >>= m_aModuleIdentifier))
849 else
851 ::comphelper::SequenceAsHashMap lArgs(aArguments);
852 aModuleShortName = lArgs.getUnpackedValueOrDefault(u"ModuleShortName"_ustr, OUString());
853 m_aModuleIdentifier = lArgs.getUnpackedValueOrDefault(u"ModuleIdentifier"_ustr, OUString());
856 for ( int i = 1; i < css::ui::UIElementType::COUNT; i++ )
858 OUString aResourceType;
859 if ( i == css::ui::UIElementType::MENUBAR )
860 aResourceType = RESOURCETYPE_MENUBAR;
861 else if ( i == css::ui::UIElementType::TOOLBAR )
862 aResourceType = RESOURCETYPE_TOOLBAR;
863 else if ( i == css::ui::UIElementType::STATUSBAR )
864 aResourceType = RESOURCETYPE_STATUSBAR;
865 else if ( i == css::ui::UIElementType::POPUPMENU )
866 aResourceType = RESOURCETYPE_POPUPMENU;
868 if ( !aResourceType.isEmpty() )
870 m_pStorageHandler[i].reset( new PresetHandler( m_xContext ) );
871 m_pStorageHandler[i]->connectToResource( PresetHandler::E_MODULES,
872 aResourceType, // this path won't be used later... see next lines!
873 aModuleShortName,
874 css::uno::Reference< css::embed::XStorage >()); // no document root used here!
878 // initialize root storages for all resource types
879 m_xUserRootCommit.set( m_pStorageHandler[css::ui::UIElementType::MENUBAR]->getOrCreateRootStorageUser(), css::uno::UNO_QUERY); // can be empty
880 m_xDefaultConfigStorage = m_pStorageHandler[css::ui::UIElementType::MENUBAR]->getParentStorageShare();
881 m_xUserConfigStorage = m_pStorageHandler[css::ui::UIElementType::MENUBAR]->getParentStorageUser();
883 if ( m_xUserConfigStorage.is() )
885 Reference< XPropertySet > xPropSet( m_xUserConfigStorage, UNO_QUERY );
886 if ( xPropSet.is() )
888 tools::Long nOpenMode = 0;
889 Any a = xPropSet->getPropertyValue(u"OpenMode"_ustr);
890 if ( a >>= nOpenMode )
891 m_bReadOnly = !( nOpenMode & ElementModes::WRITE );
895 impl_Initialize();
898 // XComponent
899 void SAL_CALL ModuleUIConfigurationManager::dispose()
901 Reference< XComponent > xThis(this);
903 css::lang::EventObject aEvent( xThis );
905 std::unique_lock aGuard(m_mutex);
906 m_aEventListeners.disposeAndClear( aGuard, aEvent );
909 std::unique_lock aGuard(m_mutex);
910 m_aConfigListeners.disposeAndClear( aGuard, aEvent );
913 /* SAFE AREA ----------------------------------------------------------------------------------------------- */
914 SolarMutexClearableGuard aGuard;
915 Reference< XComponent > xModuleImageManager( m_xModuleImageManager );
916 m_xModuleImageManager.clear();
917 m_xModuleAcceleratorManager.clear();
918 m_aUIElements[LAYER_USERDEFINED].clear();
919 m_aUIElements[LAYER_DEFAULT].clear();
920 m_xDefaultConfigStorage.clear();
921 m_xUserConfigStorage.clear();
922 m_xUserRootCommit.clear();
923 m_bModified = false;
924 m_bDisposed = true;
925 aGuard.clear();
926 /* SAFE AREA ----------------------------------------------------------------------------------------------- */
930 if ( xModuleImageManager.is() )
931 xModuleImageManager->dispose();
933 catch ( const Exception& )
938 void SAL_CALL ModuleUIConfigurationManager::addEventListener( const Reference< XEventListener >& xListener )
941 SolarMutexGuard g;
943 /* SAFE AREA ----------------------------------------------------------------------------------------------- */
944 if ( m_bDisposed )
945 throw DisposedException();
948 std::unique_lock aGuard(m_mutex);
949 m_aEventListeners.addInterface( aGuard, xListener );
952 void SAL_CALL ModuleUIConfigurationManager::removeEventListener( const Reference< XEventListener >& xListener )
954 /* SAFE AREA ----------------------------------------------------------------------------------------------- */
955 std::unique_lock aGuard(m_mutex);
956 m_aEventListeners.removeInterface( aGuard, xListener );
959 // XUIConfiguration
960 void SAL_CALL ModuleUIConfigurationManager::addConfigurationListener( const Reference< css::ui::XUIConfigurationListener >& xListener )
963 SolarMutexGuard g;
965 /* SAFE AREA ----------------------------------------------------------------------------------------------- */
966 if ( m_bDisposed )
967 throw DisposedException();
970 std::unique_lock aGuard(m_mutex);
971 m_aConfigListeners.addInterface( aGuard, xListener );
974 void SAL_CALL ModuleUIConfigurationManager::removeConfigurationListener( const Reference< css::ui::XUIConfigurationListener >& xListener )
976 /* SAFE AREA ----------------------------------------------------------------------------------------------- */
977 std::unique_lock aGuard(m_mutex);
978 m_aConfigListeners.removeInterface( aGuard, xListener );
981 // XUIConfigurationManager
982 void SAL_CALL ModuleUIConfigurationManager::reset()
984 SolarMutexClearableGuard aGuard;
986 /* SAFE AREA ----------------------------------------------------------------------------------------------- */
987 if ( m_bDisposed )
988 throw DisposedException();
990 if ( isReadOnly() )
991 return;
993 // Remove all elements from our user-defined storage!
996 for ( int i = 1; i < css::ui::UIElementType::COUNT; i++ )
998 UIElementType& rElementType = m_aUIElements[LAYER_USERDEFINED][i];
1000 if ( rElementType.xStorage.is() )
1002 bool bCommitSubStorage( false );
1003 const Sequence< OUString > aUIElementStreamNames = rElementType.xStorage->getElementNames();
1004 for ( OUString const & rName : aUIElementStreamNames )
1006 rElementType.xStorage->removeElement( rName );
1007 bCommitSubStorage = true;
1010 if ( bCommitSubStorage )
1012 Reference< XTransactedObject > xTransactedObject( rElementType.xStorage, UNO_QUERY );
1013 if ( xTransactedObject.is() )
1014 xTransactedObject->commit();
1015 m_pStorageHandler[i]->commitUserChanges();
1020 // remove settings from user defined layer and notify listener about removed settings data!
1021 ConfigEventNotifyContainer aRemoveEventNotifyContainer;
1022 ConfigEventNotifyContainer aReplaceEventNotifyContainer;
1023 for ( sal_Int16 j = 1; j < css::ui::UIElementType::COUNT; j++ )
1027 UIElementType& rUserElementType = m_aUIElements[LAYER_USERDEFINED][j];
1028 UIElementType& rDefaultElementType = m_aUIElements[LAYER_DEFAULT][j];
1030 impl_resetElementTypeData( rUserElementType, rDefaultElementType, aRemoveEventNotifyContainer, aReplaceEventNotifyContainer );
1031 rUserElementType.bModified = false;
1033 catch (const Exception&)
1035 css::uno::Any anyEx = cppu::getCaughtException();
1036 throw css::lang::WrappedTargetRuntimeException(
1037 u"ModuleUIConfigurationManager::reset exception"_ustr,
1038 css::uno::Reference<css::uno::XInterface>(*this), anyEx);
1042 m_bModified = false;
1044 // Unlock mutex before notify our listeners
1045 aGuard.clear();
1047 // Notify our listeners
1048 for ( auto const & k: aRemoveEventNotifyContainer )
1049 implts_notifyContainerListener( k, NotifyOp_Remove );
1050 for ( auto const & k: aReplaceEventNotifyContainer )
1051 implts_notifyContainerListener( k, NotifyOp_Replace );
1053 catch ( const css::lang::IllegalArgumentException& )
1056 catch ( const css::container::NoSuchElementException& )
1059 catch ( const css::embed::InvalidStorageException& )
1062 catch ( const css::embed::StorageWrappedTargetException& )
1067 Sequence< Sequence< PropertyValue > > SAL_CALL ModuleUIConfigurationManager::getUIElementsInfo( sal_Int16 ElementType )
1069 if (( ElementType < 0 ) || ( ElementType >= css::ui::UIElementType::COUNT ))
1070 throw IllegalArgumentException();
1072 SolarMutexGuard g;
1073 if ( m_bDisposed )
1074 throw DisposedException();
1076 std::vector< Sequence< PropertyValue > > aElementInfoSeq;
1077 UIElementInfoHashMap aUIElementInfoCollection;
1079 if ( ElementType == css::ui::UIElementType::UNKNOWN )
1081 for ( sal_Int16 i = 0; i < css::ui::UIElementType::COUNT; i++ )
1082 impl_fillSequenceWithElementTypeInfo( aUIElementInfoCollection, i );
1084 else
1085 impl_fillSequenceWithElementTypeInfo( aUIElementInfoCollection, ElementType );
1087 aElementInfoSeq.resize( aUIElementInfoCollection.size() );
1089 sal_Int32 n = 0;
1090 for (auto const& elem : aUIElementInfoCollection)
1092 aElementInfoSeq[n++] = Sequence<PropertyValue> {
1093 comphelper::makePropertyValue(u"ResourceURL"_ustr, elem.second.aResourceURL),
1094 comphelper::makePropertyValue(m_aPropUIName, elem.second.aUIName)
1098 return comphelper::containerToSequence(aElementInfoSeq);
1101 Reference< XIndexContainer > SAL_CALL ModuleUIConfigurationManager::createSettings()
1103 SolarMutexGuard g;
1105 if ( m_bDisposed )
1106 throw DisposedException();
1108 // Creates an empty item container which can be filled from outside
1109 return Reference< XIndexContainer >( new RootItemContainer() );
1112 sal_Bool SAL_CALL ModuleUIConfigurationManager::hasSettings( const OUString& ResourceURL )
1114 sal_Int16 nElementType = RetrieveTypeFromResourceURL( ResourceURL );
1116 if (( nElementType == css::ui::UIElementType::UNKNOWN ) ||
1117 ( nElementType >= css::ui::UIElementType::COUNT ))
1118 throw IllegalArgumentException();
1120 SolarMutexGuard g;
1122 if ( m_bDisposed )
1123 throw DisposedException();
1125 UIElementData* pDataSettings = impl_findUIElementData( ResourceURL, nElementType, false );
1126 if ( pDataSettings )
1127 return true;
1129 return false;
1132 Reference< XIndexAccess > SAL_CALL ModuleUIConfigurationManager::getSettings( const OUString& ResourceURL, sal_Bool bWriteable )
1134 sal_Int16 nElementType = RetrieveTypeFromResourceURL( ResourceURL );
1136 if (( nElementType == css::ui::UIElementType::UNKNOWN ) ||
1137 ( nElementType >= css::ui::UIElementType::COUNT ))
1138 throw IllegalArgumentException();
1140 SolarMutexGuard g;
1142 if ( m_bDisposed )
1143 throw DisposedException();
1145 UIElementData* pDataSettings = impl_findUIElementData( ResourceURL, nElementType );
1146 if ( pDataSettings )
1148 // Create a copy of our data if someone wants to change the data.
1149 if ( bWriteable )
1150 return Reference< XIndexAccess >( new RootItemContainer( pDataSettings->xSettings ) );
1151 else
1152 return pDataSettings->xSettings;
1155 throw NoSuchElementException();
1158 void SAL_CALL ModuleUIConfigurationManager::replaceSettings( const OUString& ResourceURL, const Reference< css::container::XIndexAccess >& aNewData )
1160 sal_Int16 nElementType = RetrieveTypeFromResourceURL( ResourceURL );
1162 if (( nElementType == css::ui::UIElementType::UNKNOWN ) ||
1163 ( nElementType >= css::ui::UIElementType::COUNT ))
1164 throw IllegalArgumentException();
1165 else if ( m_bReadOnly )
1166 throw IllegalAccessException();
1167 else
1169 SolarMutexClearableGuard aGuard;
1171 if ( m_bDisposed )
1172 throw DisposedException();
1174 UIElementData* pDataSettings = impl_findUIElementData( ResourceURL, nElementType );
1175 if ( !pDataSettings )
1176 throw NoSuchElementException();
1177 if ( !pDataSettings->bDefaultNode )
1179 // we have a settings entry in our user-defined layer - replace
1180 Reference< XIndexAccess > xOldSettings = pDataSettings->xSettings;
1182 // Create a copy of the data if the container is not const
1183 Reference< XIndexReplace > xReplace( aNewData, UNO_QUERY );
1184 if ( xReplace.is() )
1185 pDataSettings->xSettings = new ConstItemContainer( aNewData );
1186 else
1187 pDataSettings->xSettings = aNewData;
1188 pDataSettings->bDefault = false;
1189 pDataSettings->bModified = true;
1190 m_bModified = true;
1192 // Modify type container
1193 UIElementType& rElementType = m_aUIElements[LAYER_USERDEFINED][nElementType];
1194 rElementType.bModified = true;
1196 Reference< XUIConfigurationManager > xThis(this);
1198 // Create event to notify listener about replaced element settings
1199 ui::ConfigurationEvent aEvent;
1200 aEvent.ResourceURL = ResourceURL;
1201 aEvent.Accessor <<= xThis;
1202 aEvent.Source.set(xThis, UNO_QUERY);
1203 aEvent.ReplacedElement <<= xOldSettings;
1204 aEvent.Element <<= pDataSettings->xSettings;
1206 aGuard.clear();
1208 implts_notifyContainerListener( aEvent, NotifyOp_Replace );
1210 else
1212 // we have no settings in our user-defined layer - insert
1213 UIElementData aUIElementData;
1215 aUIElementData.bDefault = false;
1216 aUIElementData.bDefaultNode = false;
1217 aUIElementData.bModified = true;
1219 // Create a copy of the data if the container is not const
1220 Reference< XIndexReplace > xReplace( aNewData, UNO_QUERY );
1221 if ( xReplace.is() )
1222 aUIElementData.xSettings = new ConstItemContainer( aNewData );
1223 else
1224 aUIElementData.xSettings = aNewData;
1225 aUIElementData.aName = RetrieveNameFromResourceURL( ResourceURL ) + m_aXMLPostfix;
1226 aUIElementData.aResourceURL = ResourceURL;
1227 m_bModified = true;
1229 // Modify type container
1230 UIElementType& rElementType = m_aUIElements[LAYER_USERDEFINED][nElementType];
1231 rElementType.bModified = true;
1233 UIElementDataHashMap& rElements = rElementType.aElementsHashMap;
1235 // Check our user element settings hash map as it can already contain settings that have been set to default!
1236 // If no node can be found, we have to insert it.
1237 UIElementDataHashMap::iterator pIter = rElements.find( ResourceURL );
1238 if ( pIter != rElements.end() )
1239 pIter->second = aUIElementData;
1240 else
1241 rElements.emplace( ResourceURL, aUIElementData );
1243 Reference< XUIConfigurationManager > xThis(this);
1245 // Create event to notify listener about replaced element settings
1246 ui::ConfigurationEvent aEvent;
1248 aEvent.ResourceURL = ResourceURL;
1249 aEvent.Accessor <<= xThis;
1250 aEvent.Source.set(xThis, UNO_QUERY);
1251 aEvent.ReplacedElement <<= pDataSettings->xSettings;
1252 aEvent.Element <<= aUIElementData.xSettings;
1254 aGuard.clear();
1256 implts_notifyContainerListener( aEvent, NotifyOp_Replace );
1261 void SAL_CALL ModuleUIConfigurationManager::removeSettings( const OUString& ResourceURL )
1263 sal_Int16 nElementType = RetrieveTypeFromResourceURL( ResourceURL );
1265 if (( nElementType == css::ui::UIElementType::UNKNOWN ) ||
1266 ( nElementType >= css::ui::UIElementType::COUNT ))
1267 throw IllegalArgumentException( "The ResourceURL is not valid or "
1268 "describes an unknown type. "
1269 "ResourceURL: " + ResourceURL, nullptr, 0 );
1270 else if ( m_bReadOnly )
1271 throw IllegalAccessException( "The configuration manager is read-only. "
1272 "ResourceURL: " + ResourceURL, nullptr );
1273 else
1275 SolarMutexClearableGuard aGuard;
1277 if ( m_bDisposed )
1278 throw DisposedException( "The configuration manager has been disposed, "
1279 "and can't uphold its method specification anymore. "
1280 "ResourceURL: " + ResourceURL, nullptr );
1282 UIElementData* pDataSettings = impl_findUIElementData( ResourceURL, nElementType );
1283 if ( !pDataSettings )
1284 throw NoSuchElementException( "The settings data cannot be found. "
1285 "ResourceURL: " + ResourceURL, nullptr );
1286 // If element settings are default, we don't need to change anything!
1287 if ( pDataSettings->bDefault )
1288 return;
1289 else
1291 Reference< XIndexAccess > xRemovedSettings = pDataSettings->xSettings;
1292 pDataSettings->bDefault = true;
1294 // check if this is a default layer node
1295 if ( !pDataSettings->bDefaultNode )
1296 pDataSettings->bModified = true; // we have to remove this node from the user layer!
1297 pDataSettings->xSettings.clear();
1298 m_bModified = true; // user layer must be written
1300 // Modify type container
1301 UIElementType& rElementType = m_aUIElements[LAYER_USERDEFINED][nElementType];
1302 rElementType.bModified = true;
1304 Reference< XUIConfigurationManager > xThis(this);
1305 Reference< XInterface > xIfac( xThis, UNO_QUERY );
1307 // Check if we have settings in the default layer which replaces the user-defined one!
1308 UIElementData* pDefaultDataSettings = impl_findUIElementData( ResourceURL, nElementType );
1309 if ( pDefaultDataSettings )
1311 // Create event to notify listener about replaced element settings
1312 ui::ConfigurationEvent aEvent;
1314 aEvent.ResourceURL = ResourceURL;
1315 aEvent.Accessor <<= xThis;
1316 aEvent.Source = std::move(xIfac);
1317 aEvent.Element <<= xRemovedSettings;
1318 aEvent.ReplacedElement <<= pDefaultDataSettings->xSettings;
1320 aGuard.clear();
1322 implts_notifyContainerListener( aEvent, NotifyOp_Replace );
1324 else
1326 // Create event to notify listener about removed element settings
1327 ui::ConfigurationEvent aEvent;
1329 aEvent.ResourceURL = ResourceURL;
1330 aEvent.Accessor <<= xThis;
1331 aEvent.Source = std::move(xIfac);
1332 aEvent.Element <<= xRemovedSettings;
1334 aGuard.clear();
1336 implts_notifyContainerListener( aEvent, NotifyOp_Remove );
1342 void SAL_CALL ModuleUIConfigurationManager::insertSettings( const OUString& NewResourceURL, const Reference< XIndexAccess >& aNewData )
1344 sal_Int16 nElementType = RetrieveTypeFromResourceURL( NewResourceURL );
1346 if (( nElementType == css::ui::UIElementType::UNKNOWN ) ||
1347 ( nElementType >= css::ui::UIElementType::COUNT ))
1348 throw IllegalArgumentException();
1349 else if ( m_bReadOnly )
1350 throw IllegalAccessException();
1351 else
1353 SolarMutexClearableGuard aGuard;
1355 if ( m_bDisposed )
1356 throw DisposedException();
1358 UIElementData* pDataSettings = impl_findUIElementData( NewResourceURL, nElementType );
1359 if ( !(!pDataSettings) )
1360 throw ElementExistException();
1361 UIElementData aUIElementData;
1363 aUIElementData.bDefault = false;
1364 aUIElementData.bDefaultNode = false;
1365 aUIElementData.bModified = true;
1367 // Create a copy of the data if the container is not const
1368 Reference< XIndexReplace > xReplace( aNewData, UNO_QUERY );
1369 if ( xReplace.is() )
1370 aUIElementData.xSettings = new ConstItemContainer( aNewData );
1371 else
1372 aUIElementData.xSettings = aNewData;
1373 aUIElementData.aName = RetrieveNameFromResourceURL( NewResourceURL ) + m_aXMLPostfix;
1374 aUIElementData.aResourceURL = NewResourceURL;
1375 m_bModified = true;
1377 UIElementType& rElementType = m_aUIElements[LAYER_USERDEFINED][nElementType];
1378 rElementType.bModified = true;
1380 UIElementDataHashMap& rElements = rElementType.aElementsHashMap;
1381 rElements.emplace( NewResourceURL, aUIElementData );
1383 Reference< XIndexAccess > xInsertSettings( aUIElementData.xSettings );
1384 Reference< XUIConfigurationManager > xThis(this);
1386 // Create event to notify listener about removed element settings
1387 ui::ConfigurationEvent aEvent;
1389 aEvent.ResourceURL = NewResourceURL;
1390 aEvent.Accessor <<= xThis;
1391 aEvent.Source = xThis;
1392 aEvent.Element <<= xInsertSettings;
1394 aGuard.clear();
1396 implts_notifyContainerListener( aEvent, NotifyOp_Insert );
1400 Reference< XInterface > SAL_CALL ModuleUIConfigurationManager::getImageManager()
1402 SolarMutexGuard g;
1404 if ( m_bDisposed )
1405 throw DisposedException();
1407 if ( !m_xModuleImageManager.is() )
1409 m_xModuleImageManager = new ImageManager( m_xContext, /*bForModule*/true );
1411 uno::Sequence<uno::Any> aPropSeq(comphelper::InitAnyPropertySequence(
1413 {"UserConfigStorage", uno::Any(m_xUserConfigStorage)},
1414 {"ModuleIdentifier", uno::Any(m_aModuleIdentifier)},
1415 {"UserRootCommit", uno::Any(m_xUserRootCommit)},
1416 }));
1417 m_xModuleImageManager->initialize( aPropSeq );
1420 return Reference< XInterface >( static_cast<cppu::OWeakObject*>(m_xModuleImageManager.get()), UNO_QUERY );
1423 Reference< ui::XAcceleratorConfiguration > SAL_CALL ModuleUIConfigurationManager::createShortCutManager()
1425 return ui::ModuleAcceleratorConfiguration::createWithModuleIdentifier(m_xContext, m_aModuleIdentifier);
1428 Reference< ui::XAcceleratorConfiguration > SAL_CALL ModuleUIConfigurationManager::getShortCutManager()
1430 SolarMutexGuard g;
1432 if ( m_bDisposed )
1433 throw DisposedException();
1435 if ( !m_xModuleAcceleratorManager.is() ) try
1437 m_xModuleAcceleratorManager = ui::ModuleAcceleratorConfiguration::
1438 createWithModuleIdentifier(m_xContext, m_aModuleIdentifier);
1440 catch ( const css::uno::DeploymentException& )
1442 SAL_WARN("fwk.uiconfiguration", "ModuleAcceleratorConfiguration"
1443 " not available. This should happen only on mobile platforms.");
1446 return m_xModuleAcceleratorManager;
1449 Reference< XInterface > SAL_CALL ModuleUIConfigurationManager::getEventsManager()
1451 return Reference< XInterface >();
1454 // XModuleUIConfigurationManager
1455 sal_Bool SAL_CALL ModuleUIConfigurationManager::isDefaultSettings( const OUString& ResourceURL )
1457 sal_Int16 nElementType = RetrieveTypeFromResourceURL( ResourceURL );
1459 if (( nElementType == css::ui::UIElementType::UNKNOWN ) ||
1460 ( nElementType >= css::ui::UIElementType::COUNT ))
1461 throw IllegalArgumentException();
1463 SolarMutexGuard g;
1465 if ( m_bDisposed )
1466 throw DisposedException();
1468 UIElementData* pDataSettings = impl_findUIElementData( ResourceURL, nElementType, false );
1469 if ( pDataSettings && pDataSettings->bDefaultNode )
1470 return true;
1472 return false;
1475 Reference< XIndexAccess > SAL_CALL ModuleUIConfigurationManager::getDefaultSettings( const OUString& ResourceURL )
1477 sal_Int16 nElementType = RetrieveTypeFromResourceURL( ResourceURL );
1479 if (( nElementType == css::ui::UIElementType::UNKNOWN ) ||
1480 ( nElementType >= css::ui::UIElementType::COUNT ))
1481 throw IllegalArgumentException();
1483 SolarMutexGuard g;
1485 if ( m_bDisposed )
1486 throw DisposedException();
1488 // preload list of element types on demand
1489 impl_preloadUIElementTypeList( LAYER_DEFAULT, nElementType );
1491 // Look into our default vector/unordered_map combination
1492 UIElementDataHashMap& rDefaultHashMap = m_aUIElements[LAYER_DEFAULT][nElementType].aElementsHashMap;
1493 UIElementDataHashMap::iterator pIter = rDefaultHashMap.find( ResourceURL );
1494 if ( pIter != rDefaultHashMap.end() )
1496 if ( !pIter->second.xSettings.is() )
1497 impl_requestUIElementData( nElementType, LAYER_DEFAULT, pIter->second );
1498 return pIter->second.xSettings;
1501 // Nothing has been found!
1502 throw NoSuchElementException();
1505 // XUIConfigurationPersistence
1506 void SAL_CALL ModuleUIConfigurationManager::reload()
1508 SolarMutexClearableGuard aGuard;
1510 if ( m_bDisposed )
1511 throw DisposedException();
1513 if ( !m_xUserConfigStorage.is() || !m_bModified || m_bReadOnly )
1514 return;
1516 // Try to access our module sub folder
1517 ConfigEventNotifyContainer aRemoveNotifyContainer;
1518 ConfigEventNotifyContainer aReplaceNotifyContainer;
1519 for ( sal_Int16 i = 1; i < css::ui::UIElementType::COUNT; i++ )
1523 UIElementType& rUserElementType = m_aUIElements[LAYER_USERDEFINED][i];
1525 if ( rUserElementType.bModified )
1527 UIElementType& rDefaultElementType = m_aUIElements[LAYER_DEFAULT][i];
1528 impl_reloadElementTypeData( rUserElementType, rDefaultElementType, aRemoveNotifyContainer, aReplaceNotifyContainer );
1531 catch ( const Exception& )
1533 throw IOException();
1537 m_bModified = false;
1539 // Unlock mutex before notify our listeners
1540 aGuard.clear();
1542 // Notify our listeners
1543 for (const ui::ConfigurationEvent & j : aRemoveNotifyContainer)
1544 implts_notifyContainerListener( j, NotifyOp_Remove );
1545 for (const ui::ConfigurationEvent & k : aReplaceNotifyContainer)
1546 implts_notifyContainerListener( k, NotifyOp_Replace );
1549 void SAL_CALL ModuleUIConfigurationManager::store()
1551 SolarMutexGuard g;
1553 if ( m_bDisposed )
1554 throw DisposedException();
1556 if ( !m_xUserConfigStorage.is() || !m_bModified || m_bReadOnly )
1557 return;
1559 // Try to access our module sub folder
1560 for ( int i = 1; i < css::ui::UIElementType::COUNT; i++ )
1564 UIElementType& rElementType = m_aUIElements[LAYER_USERDEFINED][i];
1566 if ( rElementType.bModified && rElementType.xStorage.is() )
1568 impl_storeElementTypeData( rElementType.xStorage, rElementType );
1569 m_pStorageHandler[i]->commitUserChanges();
1572 catch ( const Exception& )
1574 throw IOException();
1578 m_bModified = false;
1581 void SAL_CALL ModuleUIConfigurationManager::storeToStorage( const Reference< XStorage >& Storage )
1583 SolarMutexGuard g;
1585 if ( m_bDisposed )
1586 throw DisposedException();
1588 if ( !m_xUserConfigStorage.is() || !m_bModified || m_bReadOnly )
1589 return;
1591 // Try to access our module sub folder
1592 for ( int i = 1; i < css::ui::UIElementType::COUNT; i++ )
1596 Reference< XStorage > xElementTypeStorage( Storage->openStorageElement(
1597 OUString(UIELEMENTTYPENAMES[i]), ElementModes::READWRITE ));
1598 UIElementType& rElementType = m_aUIElements[LAYER_USERDEFINED][i];
1600 if ( rElementType.bModified && xElementTypeStorage.is() )
1601 impl_storeElementTypeData( xElementTypeStorage, rElementType, false ); // store data to storage, but don't reset modify flag!
1603 catch ( const Exception& )
1605 throw IOException();
1609 Reference< XTransactedObject > xTransactedObject( Storage, UNO_QUERY );
1610 if ( xTransactedObject.is() )
1611 xTransactedObject->commit();
1614 sal_Bool SAL_CALL ModuleUIConfigurationManager::isModified()
1616 SolarMutexGuard g;
1618 return m_bModified;
1621 sal_Bool SAL_CALL ModuleUIConfigurationManager::isReadOnly()
1623 SolarMutexGuard g;
1625 return m_bReadOnly;
1628 void ModuleUIConfigurationManager::implts_notifyContainerListener( const ui::ConfigurationEvent& aEvent, NotifyOp eOp )
1630 std::unique_lock aGuard(m_mutex);
1631 using ListenerMethodType = void (SAL_CALL css::ui::XUIConfigurationListener::*)(const ui::ConfigurationEvent&);
1632 ListenerMethodType aListenerMethod {};
1633 switch ( eOp )
1635 case NotifyOp_Replace:
1636 aListenerMethod = &css::ui::XUIConfigurationListener::elementReplaced;
1637 break;
1638 case NotifyOp_Insert:
1639 aListenerMethod = &css::ui::XUIConfigurationListener::elementInserted;
1640 break;
1641 case NotifyOp_Remove:
1642 aListenerMethod = &css::ui::XUIConfigurationListener::elementRemoved;
1643 break;
1645 m_aConfigListeners.notifyEach(aGuard, aListenerMethod, aEvent);
1650 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
1651 com_sun_star_comp_framework_ModuleUIConfigurationManager_get_implementation(
1652 css::uno::XComponentContext *context,
1653 css::uno::Sequence<css::uno::Any> const &arguments)
1655 return cppu::acquire(new ModuleUIConfigurationManager(context, arguments));
1658 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */