Avoid potential negative array index access to cached text.
[LibreOffice.git] / framework / source / uiconfiguration / moduleuiconfigurationmanager.cxx
blob65e12c8f8dd383f91e5092e714f89bed662bd94e
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 "com.sun.star.comp.framework.ModuleUIConfigurationManager";
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 {"com.sun.star.ui.ModuleUIConfigurationManager"};
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( "custom_" );
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 = 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 = 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( ".xml" )
835 , m_aPropUIName( "UIName" )
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("ModuleShortName", OUString());
853 m_aModuleIdentifier = lArgs.getUnpackedValueOrDefault("ModuleIdentifier", 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("OpenMode");
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 "ModuleUIConfigurationManager::reset exception",
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 Sequence< PropertyValue > aUIElementInfo{
1093 comphelper::makePropertyValue("ResourceURL", elem.second.aResourceURL),
1094 comphelper::makePropertyValue(m_aPropUIName, elem.second.aUIName)
1096 aElementInfoSeq[n++] = aUIElementInfo;
1099 return comphelper::containerToSequence(aElementInfoSeq);
1102 Reference< XIndexContainer > SAL_CALL ModuleUIConfigurationManager::createSettings()
1104 SolarMutexGuard g;
1106 if ( m_bDisposed )
1107 throw DisposedException();
1109 // Creates an empty item container which can be filled from outside
1110 return Reference< XIndexContainer >( new RootItemContainer() );
1113 sal_Bool SAL_CALL ModuleUIConfigurationManager::hasSettings( const OUString& ResourceURL )
1115 sal_Int16 nElementType = RetrieveTypeFromResourceURL( ResourceURL );
1117 if (( nElementType == css::ui::UIElementType::UNKNOWN ) ||
1118 ( nElementType >= css::ui::UIElementType::COUNT ))
1119 throw IllegalArgumentException();
1121 SolarMutexGuard g;
1123 if ( m_bDisposed )
1124 throw DisposedException();
1126 UIElementData* pDataSettings = impl_findUIElementData( ResourceURL, nElementType, false );
1127 if ( pDataSettings )
1128 return true;
1130 return false;
1133 Reference< XIndexAccess > SAL_CALL ModuleUIConfigurationManager::getSettings( const OUString& ResourceURL, sal_Bool bWriteable )
1135 sal_Int16 nElementType = RetrieveTypeFromResourceURL( ResourceURL );
1137 if (( nElementType == css::ui::UIElementType::UNKNOWN ) ||
1138 ( nElementType >= css::ui::UIElementType::COUNT ))
1139 throw IllegalArgumentException();
1141 SolarMutexGuard g;
1143 if ( m_bDisposed )
1144 throw DisposedException();
1146 UIElementData* pDataSettings = impl_findUIElementData( ResourceURL, nElementType );
1147 if ( pDataSettings )
1149 // Create a copy of our data if someone wants to change the data.
1150 if ( bWriteable )
1151 return Reference< XIndexAccess >( new RootItemContainer( pDataSettings->xSettings ) );
1152 else
1153 return pDataSettings->xSettings;
1156 throw NoSuchElementException();
1159 void SAL_CALL ModuleUIConfigurationManager::replaceSettings( const OUString& ResourceURL, const Reference< css::container::XIndexAccess >& aNewData )
1161 sal_Int16 nElementType = RetrieveTypeFromResourceURL( ResourceURL );
1163 if (( nElementType == css::ui::UIElementType::UNKNOWN ) ||
1164 ( nElementType >= css::ui::UIElementType::COUNT ))
1165 throw IllegalArgumentException();
1166 else if ( m_bReadOnly )
1167 throw IllegalAccessException();
1168 else
1170 SolarMutexClearableGuard aGuard;
1172 if ( m_bDisposed )
1173 throw DisposedException();
1175 UIElementData* pDataSettings = impl_findUIElementData( ResourceURL, nElementType );
1176 if ( !pDataSettings )
1177 throw NoSuchElementException();
1178 if ( !pDataSettings->bDefaultNode )
1180 // we have a settings entry in our user-defined layer - replace
1181 Reference< XIndexAccess > xOldSettings = pDataSettings->xSettings;
1183 // Create a copy of the data if the container is not const
1184 Reference< XIndexReplace > xReplace( aNewData, UNO_QUERY );
1185 if ( xReplace.is() )
1186 pDataSettings->xSettings = new ConstItemContainer( aNewData );
1187 else
1188 pDataSettings->xSettings = aNewData;
1189 pDataSettings->bDefault = false;
1190 pDataSettings->bModified = true;
1191 m_bModified = true;
1193 // Modify type container
1194 UIElementType& rElementType = m_aUIElements[LAYER_USERDEFINED][nElementType];
1195 rElementType.bModified = true;
1197 Reference< XUIConfigurationManager > xThis(this);
1198 Reference< XInterface > xIfac( xThis, UNO_QUERY );
1200 // Create event to notify listener about replaced element settings
1201 ui::ConfigurationEvent aEvent;
1202 aEvent.ResourceURL = ResourceURL;
1203 aEvent.Accessor <<= xThis;
1204 aEvent.Source = xIfac;
1205 aEvent.ReplacedElement <<= xOldSettings;
1206 aEvent.Element <<= pDataSettings->xSettings;
1208 aGuard.clear();
1210 implts_notifyContainerListener( aEvent, NotifyOp_Replace );
1212 else
1214 // we have no settings in our user-defined layer - insert
1215 UIElementData aUIElementData;
1217 aUIElementData.bDefault = false;
1218 aUIElementData.bDefaultNode = false;
1219 aUIElementData.bModified = true;
1221 // Create a copy of the data if the container is not const
1222 Reference< XIndexReplace > xReplace( aNewData, UNO_QUERY );
1223 if ( xReplace.is() )
1224 aUIElementData.xSettings = new ConstItemContainer( aNewData );
1225 else
1226 aUIElementData.xSettings = aNewData;
1227 aUIElementData.aName = RetrieveNameFromResourceURL( ResourceURL ) + m_aXMLPostfix;
1228 aUIElementData.aResourceURL = ResourceURL;
1229 m_bModified = true;
1231 // Modify type container
1232 UIElementType& rElementType = m_aUIElements[LAYER_USERDEFINED][nElementType];
1233 rElementType.bModified = true;
1235 UIElementDataHashMap& rElements = rElementType.aElementsHashMap;
1237 // Check our user element settings hash map as it can already contain settings that have been set to default!
1238 // If no node can be found, we have to insert it.
1239 UIElementDataHashMap::iterator pIter = rElements.find( ResourceURL );
1240 if ( pIter != rElements.end() )
1241 pIter->second = aUIElementData;
1242 else
1243 rElements.emplace( ResourceURL, aUIElementData );
1245 Reference< XUIConfigurationManager > xThis(this);
1247 // Create event to notify listener about replaced element settings
1248 ui::ConfigurationEvent aEvent;
1250 aEvent.ResourceURL = ResourceURL;
1251 aEvent.Accessor <<= xThis;
1252 aEvent.Source.set(xThis, UNO_QUERY);
1253 aEvent.ReplacedElement <<= pDataSettings->xSettings;
1254 aEvent.Element <<= aUIElementData.xSettings;
1256 aGuard.clear();
1258 implts_notifyContainerListener( aEvent, NotifyOp_Replace );
1263 void SAL_CALL ModuleUIConfigurationManager::removeSettings( const OUString& ResourceURL )
1265 sal_Int16 nElementType = RetrieveTypeFromResourceURL( ResourceURL );
1267 if (( nElementType == css::ui::UIElementType::UNKNOWN ) ||
1268 ( nElementType >= css::ui::UIElementType::COUNT ))
1269 throw IllegalArgumentException( "The ResourceURL is not valid or "
1270 "describes an unknown type. "
1271 "ResourceURL: " + ResourceURL, nullptr, 0 );
1272 else if ( m_bReadOnly )
1273 throw IllegalAccessException( "The configuration manager is read-only. "
1274 "ResourceURL: " + ResourceURL, nullptr );
1275 else
1277 SolarMutexClearableGuard aGuard;
1279 if ( m_bDisposed )
1280 throw DisposedException( "The configuration manager has been disposed, "
1281 "and can't uphold its method specification anymore. "
1282 "ResourceURL: " + ResourceURL, nullptr );
1284 UIElementData* pDataSettings = impl_findUIElementData( ResourceURL, nElementType );
1285 if ( !pDataSettings )
1286 throw NoSuchElementException( "The settings data cannot be found. "
1287 "ResourceURL: " + ResourceURL, nullptr );
1288 // If element settings are default, we don't need to change anything!
1289 if ( pDataSettings->bDefault )
1290 return;
1291 else
1293 Reference< XIndexAccess > xRemovedSettings = pDataSettings->xSettings;
1294 pDataSettings->bDefault = true;
1296 // check if this is a default layer node
1297 if ( !pDataSettings->bDefaultNode )
1298 pDataSettings->bModified = true; // we have to remove this node from the user layer!
1299 pDataSettings->xSettings.clear();
1300 m_bModified = true; // user layer must be written
1302 // Modify type container
1303 UIElementType& rElementType = m_aUIElements[LAYER_USERDEFINED][nElementType];
1304 rElementType.bModified = true;
1306 Reference< XUIConfigurationManager > xThis(this);
1307 Reference< XInterface > xIfac( xThis, UNO_QUERY );
1309 // Check if we have settings in the default layer which replaces the user-defined one!
1310 UIElementData* pDefaultDataSettings = impl_findUIElementData( ResourceURL, nElementType );
1311 if ( pDefaultDataSettings )
1313 // Create event to notify listener about replaced element settings
1314 ui::ConfigurationEvent aEvent;
1316 aEvent.ResourceURL = ResourceURL;
1317 aEvent.Accessor <<= xThis;
1318 aEvent.Source = xIfac;
1319 aEvent.Element <<= xRemovedSettings;
1320 aEvent.ReplacedElement <<= pDefaultDataSettings->xSettings;
1322 aGuard.clear();
1324 implts_notifyContainerListener( aEvent, NotifyOp_Replace );
1326 else
1328 // Create event to notify listener about removed element settings
1329 ui::ConfigurationEvent aEvent;
1331 aEvent.ResourceURL = ResourceURL;
1332 aEvent.Accessor <<= xThis;
1333 aEvent.Source = xIfac;
1334 aEvent.Element <<= xRemovedSettings;
1336 aGuard.clear();
1338 implts_notifyContainerListener( aEvent, NotifyOp_Remove );
1344 void SAL_CALL ModuleUIConfigurationManager::insertSettings( const OUString& NewResourceURL, const Reference< XIndexAccess >& aNewData )
1346 sal_Int16 nElementType = RetrieveTypeFromResourceURL( NewResourceURL );
1348 if (( nElementType == css::ui::UIElementType::UNKNOWN ) ||
1349 ( nElementType >= css::ui::UIElementType::COUNT ))
1350 throw IllegalArgumentException();
1351 else if ( m_bReadOnly )
1352 throw IllegalAccessException();
1353 else
1355 SolarMutexClearableGuard aGuard;
1357 if ( m_bDisposed )
1358 throw DisposedException();
1360 UIElementData* pDataSettings = impl_findUIElementData( NewResourceURL, nElementType );
1361 if ( !(!pDataSettings) )
1362 throw ElementExistException();
1363 UIElementData aUIElementData;
1365 aUIElementData.bDefault = false;
1366 aUIElementData.bDefaultNode = false;
1367 aUIElementData.bModified = true;
1369 // Create a copy of the data if the container is not const
1370 Reference< XIndexReplace > xReplace( aNewData, UNO_QUERY );
1371 if ( xReplace.is() )
1372 aUIElementData.xSettings = new ConstItemContainer( aNewData );
1373 else
1374 aUIElementData.xSettings = aNewData;
1375 aUIElementData.aName = RetrieveNameFromResourceURL( NewResourceURL ) + m_aXMLPostfix;
1376 aUIElementData.aResourceURL = NewResourceURL;
1377 m_bModified = true;
1379 UIElementType& rElementType = m_aUIElements[LAYER_USERDEFINED][nElementType];
1380 rElementType.bModified = true;
1382 UIElementDataHashMap& rElements = rElementType.aElementsHashMap;
1383 rElements.emplace( NewResourceURL, aUIElementData );
1385 Reference< XIndexAccess > xInsertSettings( aUIElementData.xSettings );
1386 Reference< XUIConfigurationManager > xThis(this);
1388 // Create event to notify listener about removed element settings
1389 ui::ConfigurationEvent aEvent;
1391 aEvent.ResourceURL = NewResourceURL;
1392 aEvent.Accessor <<= xThis;
1393 aEvent.Source = xThis;
1394 aEvent.Element <<= xInsertSettings;
1396 aGuard.clear();
1398 implts_notifyContainerListener( aEvent, NotifyOp_Insert );
1402 Reference< XInterface > SAL_CALL ModuleUIConfigurationManager::getImageManager()
1404 SolarMutexGuard g;
1406 if ( m_bDisposed )
1407 throw DisposedException();
1409 if ( !m_xModuleImageManager.is() )
1411 m_xModuleImageManager = new ImageManager( m_xContext, /*bForModule*/true );
1413 uno::Sequence<uno::Any> aPropSeq(comphelper::InitAnyPropertySequence(
1415 {"UserConfigStorage", uno::Any(m_xUserConfigStorage)},
1416 {"ModuleIdentifier", uno::Any(m_aModuleIdentifier)},
1417 {"UserRootCommit", uno::Any(m_xUserRootCommit)},
1418 }));
1419 m_xModuleImageManager->initialize( aPropSeq );
1422 return Reference< XInterface >( static_cast<cppu::OWeakObject*>(m_xModuleImageManager.get()), UNO_QUERY );
1425 Reference< ui::XAcceleratorConfiguration > SAL_CALL ModuleUIConfigurationManager::createShortCutManager()
1427 return ui::ModuleAcceleratorConfiguration::createWithModuleIdentifier(m_xContext, m_aModuleIdentifier);
1430 Reference< ui::XAcceleratorConfiguration > SAL_CALL ModuleUIConfigurationManager::getShortCutManager()
1432 SolarMutexGuard g;
1434 if ( m_bDisposed )
1435 throw DisposedException();
1437 if ( !m_xModuleAcceleratorManager.is() ) try
1439 m_xModuleAcceleratorManager = ui::ModuleAcceleratorConfiguration::
1440 createWithModuleIdentifier(m_xContext, m_aModuleIdentifier);
1442 catch ( const css::uno::DeploymentException& )
1444 SAL_WARN("fwk.uiconfiguration", "ModuleAcceleratorConfiguration"
1445 " not available. This should happen only on mobile platforms.");
1448 return m_xModuleAcceleratorManager;
1451 Reference< XInterface > SAL_CALL ModuleUIConfigurationManager::getEventsManager()
1453 return Reference< XInterface >();
1456 // XModuleUIConfigurationManager
1457 sal_Bool SAL_CALL ModuleUIConfigurationManager::isDefaultSettings( const OUString& ResourceURL )
1459 sal_Int16 nElementType = RetrieveTypeFromResourceURL( ResourceURL );
1461 if (( nElementType == css::ui::UIElementType::UNKNOWN ) ||
1462 ( nElementType >= css::ui::UIElementType::COUNT ))
1463 throw IllegalArgumentException();
1465 SolarMutexGuard g;
1467 if ( m_bDisposed )
1468 throw DisposedException();
1470 UIElementData* pDataSettings = impl_findUIElementData( ResourceURL, nElementType, false );
1471 if ( pDataSettings && pDataSettings->bDefaultNode )
1472 return true;
1474 return false;
1477 Reference< XIndexAccess > SAL_CALL ModuleUIConfigurationManager::getDefaultSettings( const OUString& ResourceURL )
1479 sal_Int16 nElementType = RetrieveTypeFromResourceURL( ResourceURL );
1481 if (( nElementType == css::ui::UIElementType::UNKNOWN ) ||
1482 ( nElementType >= css::ui::UIElementType::COUNT ))
1483 throw IllegalArgumentException();
1485 SolarMutexGuard g;
1487 if ( m_bDisposed )
1488 throw DisposedException();
1490 // preload list of element types on demand
1491 impl_preloadUIElementTypeList( LAYER_DEFAULT, nElementType );
1493 // Look into our default vector/unordered_map combination
1494 UIElementDataHashMap& rDefaultHashMap = m_aUIElements[LAYER_DEFAULT][nElementType].aElementsHashMap;
1495 UIElementDataHashMap::iterator pIter = rDefaultHashMap.find( ResourceURL );
1496 if ( pIter != rDefaultHashMap.end() )
1498 if ( !pIter->second.xSettings.is() )
1499 impl_requestUIElementData( nElementType, LAYER_DEFAULT, pIter->second );
1500 return pIter->second.xSettings;
1503 // Nothing has been found!
1504 throw NoSuchElementException();
1507 // XUIConfigurationPersistence
1508 void SAL_CALL ModuleUIConfigurationManager::reload()
1510 SolarMutexClearableGuard aGuard;
1512 if ( m_bDisposed )
1513 throw DisposedException();
1515 if ( !m_xUserConfigStorage.is() || !m_bModified || m_bReadOnly )
1516 return;
1518 // Try to access our module sub folder
1519 ConfigEventNotifyContainer aRemoveNotifyContainer;
1520 ConfigEventNotifyContainer aReplaceNotifyContainer;
1521 for ( sal_Int16 i = 1; i < css::ui::UIElementType::COUNT; i++ )
1525 UIElementType& rUserElementType = m_aUIElements[LAYER_USERDEFINED][i];
1527 if ( rUserElementType.bModified )
1529 UIElementType& rDefaultElementType = m_aUIElements[LAYER_DEFAULT][i];
1530 impl_reloadElementTypeData( rUserElementType, rDefaultElementType, aRemoveNotifyContainer, aReplaceNotifyContainer );
1533 catch ( const Exception& )
1535 throw IOException();
1539 m_bModified = false;
1541 // Unlock mutex before notify our listeners
1542 aGuard.clear();
1544 // Notify our listeners
1545 for (const ui::ConfigurationEvent & j : aRemoveNotifyContainer)
1546 implts_notifyContainerListener( j, NotifyOp_Remove );
1547 for (const ui::ConfigurationEvent & k : aReplaceNotifyContainer)
1548 implts_notifyContainerListener( k, NotifyOp_Replace );
1551 void SAL_CALL ModuleUIConfigurationManager::store()
1553 SolarMutexGuard g;
1555 if ( m_bDisposed )
1556 throw DisposedException();
1558 if ( !m_xUserConfigStorage.is() || !m_bModified || m_bReadOnly )
1559 return;
1561 // Try to access our module sub folder
1562 for ( int i = 1; i < css::ui::UIElementType::COUNT; i++ )
1566 UIElementType& rElementType = m_aUIElements[LAYER_USERDEFINED][i];
1568 if ( rElementType.bModified && rElementType.xStorage.is() )
1570 impl_storeElementTypeData( rElementType.xStorage, rElementType );
1571 m_pStorageHandler[i]->commitUserChanges();
1574 catch ( const Exception& )
1576 throw IOException();
1580 m_bModified = false;
1583 void SAL_CALL ModuleUIConfigurationManager::storeToStorage( const Reference< XStorage >& Storage )
1585 SolarMutexGuard g;
1587 if ( m_bDisposed )
1588 throw DisposedException();
1590 if ( !m_xUserConfigStorage.is() || !m_bModified || m_bReadOnly )
1591 return;
1593 // Try to access our module sub folder
1594 for ( int i = 1; i < css::ui::UIElementType::COUNT; i++ )
1598 Reference< XStorage > xElementTypeStorage( Storage->openStorageElement(
1599 OUString(UIELEMENTTYPENAMES[i]), ElementModes::READWRITE ));
1600 UIElementType& rElementType = m_aUIElements[LAYER_USERDEFINED][i];
1602 if ( rElementType.bModified && xElementTypeStorage.is() )
1603 impl_storeElementTypeData( xElementTypeStorage, rElementType, false ); // store data to storage, but don't reset modify flag!
1605 catch ( const Exception& )
1607 throw IOException();
1611 Reference< XTransactedObject > xTransactedObject( Storage, UNO_QUERY );
1612 if ( xTransactedObject.is() )
1613 xTransactedObject->commit();
1616 sal_Bool SAL_CALL ModuleUIConfigurationManager::isModified()
1618 SolarMutexGuard g;
1620 return m_bModified;
1623 sal_Bool SAL_CALL ModuleUIConfigurationManager::isReadOnly()
1625 SolarMutexGuard g;
1627 return m_bReadOnly;
1630 void ModuleUIConfigurationManager::implts_notifyContainerListener( const ui::ConfigurationEvent& aEvent, NotifyOp eOp )
1632 std::unique_lock aGuard(m_mutex);
1633 using ListenerMethodType = void (SAL_CALL css::ui::XUIConfigurationListener::*)(const ui::ConfigurationEvent&);
1634 ListenerMethodType aListenerMethod {};
1635 switch ( eOp )
1637 case NotifyOp_Replace:
1638 aListenerMethod = &css::ui::XUIConfigurationListener::elementReplaced;
1639 break;
1640 case NotifyOp_Insert:
1641 aListenerMethod = &css::ui::XUIConfigurationListener::elementInserted;
1642 break;
1643 case NotifyOp_Remove:
1644 aListenerMethod = &css::ui::XUIConfigurationListener::elementRemoved;
1645 break;
1647 m_aConfigListeners.notifyEach(aGuard, aListenerMethod, aEvent);
1652 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
1653 com_sun_star_comp_framework_ModuleUIConfigurationManager_get_implementation(
1654 css::uno::XComponentContext *context,
1655 css::uno::Sequence<css::uno::Any> const &arguments)
1657 return cppu::acquire(new ModuleUIConfigurationManager(context, arguments));
1660 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */