Version 6.4.0.0.beta1, tag libreoffice-6.4.0.0.beta1
[LibreOffice.git] / framework / source / uiconfiguration / moduleuiconfigurationmanager.cxx
blob691c4b69a794b6260fc52c1bd9d639883175e963
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/moduleimagemanager.hxx>
22 #include <stdtypes.h>
23 #include <uielement/constitemcontainer.hxx>
24 #include <uielement/rootitemcontainer.hxx>
25 #include <uielement/uielementtypenames.hxx>
26 #include <framework/menuconfiguration.hxx>
27 #include <framework/toolboxconfiguration.hxx>
29 #include <framework/statusbarconfiguration.hxx>
31 #include <com/sun/star/ui/UIElementType.hpp>
32 #include <com/sun/star/ui/ConfigurationEvent.hpp>
33 #include <com/sun/star/ui/ModuleAcceleratorConfiguration.hpp>
34 #include <com/sun/star/ui/XUIConfigurationPersistence.hpp>
35 #include <com/sun/star/ui/XModuleUIConfigurationManager2.hpp>
36 #include <com/sun/star/lang/DisposedException.hpp>
37 #include <com/sun/star/lang/IllegalAccessException.hpp>
38 #include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
39 #include <com/sun/star/beans/XPropertySet.hpp>
40 #include <com/sun/star/embed/ElementModes.hpp>
41 #include <com/sun/star/embed/InvalidStorageException.hpp>
42 #include <com/sun/star/embed/StorageWrappedTargetException.hpp>
43 #include <com/sun/star/embed/XTransactedObject.hpp>
44 #include <com/sun/star/container/ElementExistException.hpp>
45 #include <com/sun/star/container/XNameAccess.hpp>
46 #include <com/sun/star/container/XIndexContainer.hpp>
47 #include <com/sun/star/io/IOException.hpp>
48 #include <com/sun/star/io/XStream.hpp>
49 #include <com/sun/star/lang/XServiceInfo.hpp>
50 #include <com/sun/star/lang/XComponent.hpp>
52 #include <comphelper/propertysequence.hxx>
53 #include <comphelper/sequence.hxx>
54 #include <cppuhelper/exc_hlp.hxx>
55 #include <cppuhelper/implbase.hxx>
56 #include <cppuhelper/interfacecontainer.hxx>
57 #include <cppuhelper/supportsservice.hxx>
58 #include <vcl/svapp.hxx>
59 #include <rtl/ref.hxx>
60 #include <rtl/ustrbuf.hxx>
61 #include <sal/log.hxx>
62 #include <comphelper/sequenceashashmap.hxx>
63 #include <comphelper/servicehelper.hxx>
64 #include <memory>
66 using namespace css;
67 using namespace com::sun::star::uno;
68 using namespace com::sun::star::io;
69 using namespace com::sun::star::embed;
70 using namespace com::sun::star::lang;
71 using namespace com::sun::star::container;
72 using namespace com::sun::star::beans;
73 using namespace framework;
75 #define RESOURCETYPE_MENUBAR "menubar"
76 #define RESOURCETYPE_TOOLBAR "toolbar"
77 #define RESOURCETYPE_STATUSBAR "statusbar"
78 #define RESOURCETYPE_POPUPMENU "popupmenu"
80 namespace {
82 class ModuleUIConfigurationManager : public cppu::WeakImplHelper<
83 css::lang::XServiceInfo,
84 css::lang::XComponent,
85 css::ui::XModuleUIConfigurationManager2 >
87 public:
88 ModuleUIConfigurationManager(
89 const css::uno::Reference< css::uno::XComponentContext >& xServiceManager,
90 const css::uno::Sequence< css::uno::Any >& aArguments);
92 virtual OUString SAL_CALL getImplementationName() override
94 return "com.sun.star.comp.framework.ModuleUIConfigurationManager";
97 virtual sal_Bool SAL_CALL supportsService(OUString const & ServiceName) override
99 return cppu::supportsService(this, ServiceName);
102 virtual css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override
104 return {"com.sun.star.ui.ModuleUIConfigurationManager"};
107 // XComponent
108 virtual void SAL_CALL dispose() override;
109 virtual void SAL_CALL addEventListener( const css::uno::Reference< css::lang::XEventListener >& xListener ) override;
110 virtual void SAL_CALL removeEventListener( const css::uno::Reference< css::lang::XEventListener >& aListener ) override;
112 // XUIConfiguration
113 virtual void SAL_CALL addConfigurationListener( const css::uno::Reference< css::ui::XUIConfigurationListener >& Listener ) override;
114 virtual void SAL_CALL removeConfigurationListener( const css::uno::Reference< css::ui::XUIConfigurationListener >& Listener ) override;
116 // XUIConfigurationManager
117 virtual void SAL_CALL reset() override;
118 virtual css::uno::Sequence< css::uno::Sequence< css::beans::PropertyValue > > SAL_CALL getUIElementsInfo( sal_Int16 ElementType ) override;
119 virtual css::uno::Reference< css::container::XIndexContainer > SAL_CALL createSettings( ) override;
120 virtual sal_Bool SAL_CALL hasSettings( const OUString& ResourceURL ) override;
121 virtual css::uno::Reference< css::container::XIndexAccess > SAL_CALL getSettings( const OUString& ResourceURL, sal_Bool bWriteable ) override;
122 virtual void SAL_CALL replaceSettings( const OUString& ResourceURL, const css::uno::Reference< css::container::XIndexAccess >& aNewData ) override;
123 virtual void SAL_CALL removeSettings( const OUString& ResourceURL ) override;
124 virtual void SAL_CALL insertSettings( const OUString& NewResourceURL, const css::uno::Reference< css::container::XIndexAccess >& aNewData ) override;
125 virtual css::uno::Reference< css::uno::XInterface > SAL_CALL getImageManager() override;
126 virtual css::uno::Reference< css::ui::XAcceleratorConfiguration > SAL_CALL getShortCutManager() override;
127 virtual css::uno::Reference< css::uno::XInterface > SAL_CALL getEventsManager() override;
129 // XModuleUIConfigurationManager
130 virtual sal_Bool SAL_CALL isDefaultSettings( const OUString& ResourceURL ) override;
131 virtual css::uno::Reference< css::container::XIndexAccess > SAL_CALL getDefaultSettings( const OUString& ResourceURL ) override;
133 // XUIConfigurationPersistence
134 virtual void SAL_CALL reload() override;
135 virtual void SAL_CALL store() override;
136 virtual void SAL_CALL storeToStorage( const css::uno::Reference< css::embed::XStorage >& Storage ) override;
137 virtual sal_Bool SAL_CALL isModified() override;
138 virtual sal_Bool SAL_CALL isReadOnly() override;
140 private:
141 // private data types
142 enum Layer
144 LAYER_DEFAULT,
145 LAYER_USERDEFINED,
146 LAYER_COUNT
149 enum NotifyOp
151 NotifyOp_Remove,
152 NotifyOp_Insert,
153 NotifyOp_Replace
156 struct UIElementInfo
158 UIElementInfo( const OUString& rResourceURL, const OUString& rUIName ) :
159 aResourceURL( rResourceURL), aUIName( rUIName ) {}
160 OUString aResourceURL;
161 OUString aUIName;
164 struct UIElementData
166 UIElementData() : bModified( false ), bDefault( true ), bDefaultNode( true ) {};
168 OUString aResourceURL;
169 OUString aName;
170 bool bModified; // has been changed since last storing
171 bool bDefault; // default settings
172 bool bDefaultNode; // this is a default layer element data
173 css::uno::Reference< css::container::XIndexAccess > xSettings;
176 typedef std::unordered_map< OUString, UIElementData > UIElementDataHashMap;
178 struct UIElementType
180 UIElementType() : bModified( false ),
181 bLoaded( false ),
182 nElementType( css::ui::UIElementType::UNKNOWN ) {}
184 bool bModified;
185 bool bLoaded;
186 sal_Int16 nElementType;
187 UIElementDataHashMap aElementsHashMap;
188 css::uno::Reference< css::embed::XStorage > xStorage;
191 typedef std::vector< UIElementType > UIElementTypesVector;
192 typedef std::vector< css::ui::ConfigurationEvent > ConfigEventNotifyContainer;
193 typedef std::unordered_map< OUString, UIElementInfo > UIElementInfoHashMap;
195 void impl_Initialize();
196 void implts_notifyContainerListener( const css::ui::ConfigurationEvent& aEvent, NotifyOp eOp );
197 void impl_fillSequenceWithElementTypeInfo( UIElementInfoHashMap& aUIElementInfoCollection, sal_Int16 nElementType );
198 void impl_preloadUIElementTypeList( Layer eLayer, sal_Int16 nElementType );
199 UIElementData* impl_findUIElementData( const OUString& aResourceURL, sal_Int16 nElementType, bool bLoad = true );
200 void impl_requestUIElementData( sal_Int16 nElementType, Layer eLayer, UIElementData& aUIElementData );
201 void impl_storeElementTypeData( const css::uno::Reference< css::embed::XStorage >& xStorage, UIElementType& rElementType, bool bResetModifyState = true );
202 void impl_resetElementTypeData( UIElementType& rUserElementType, UIElementType const & rDefaultElementType, ConfigEventNotifyContainer& rRemoveNotifyContainer, ConfigEventNotifyContainer& rReplaceNotifyContainer );
203 void impl_reloadElementTypeData( UIElementType& rUserElementType, UIElementType const & rDefaultElementType, ConfigEventNotifyContainer& rRemoveNotifyContainer, ConfigEventNotifyContainer& rReplaceNotifyContainer );
205 UIElementTypesVector m_aUIElements[LAYER_COUNT];
206 std::unique_ptr<PresetHandler> m_pStorageHandler[css::ui::UIElementType::COUNT];
207 css::uno::Reference< css::embed::XStorage > m_xDefaultConfigStorage;
208 css::uno::Reference< css::embed::XStorage > m_xUserConfigStorage;
209 bool m_bReadOnly;
210 bool m_bModified;
211 bool m_bDisposed;
212 OUString m_aXMLPostfix;
213 OUString m_aPropUIName;
214 OUString m_aModuleIdentifier;
215 css::uno::Reference< css::embed::XTransactedObject > m_xUserRootCommit;
216 css::uno::Reference< css::uno::XComponentContext > m_xContext;
217 osl::Mutex m_mutex;
218 ::cppu::OMultiTypeInterfaceContainerHelper m_aListenerContainer; /// container for ALL Listener
219 css::uno::Reference< css::lang::XComponent > m_xModuleImageManager;
220 css::uno::Reference< css::ui::XAcceleratorConfiguration > m_xModuleAcceleratorManager;
223 // important: The order and position of the elements must match the constant
224 // definition of "css::ui::UIElementType"
225 static OUStringLiteral UIELEMENTTYPENAMES[] =
227 "", // Dummy value for unknown!
228 UIELEMENTTYPE_MENUBAR_NAME,
229 UIELEMENTTYPE_POPUPMENU_NAME,
230 UIELEMENTTYPE_TOOLBAR_NAME,
231 UIELEMENTTYPE_STATUSBAR_NAME,
232 UIELEMENTTYPE_FLOATINGWINDOW_NAME,
233 UIELEMENTTYPE_PROGRESSBAR_NAME,
234 UIELEMENTTYPE_TOOLPANEL_NAME
237 static const char RESOURCEURL_PREFIX[] = "private:resource/";
238 static const sal_Int32 RESOURCEURL_PREFIX_SIZE = strlen(RESOURCEURL_PREFIX);
240 sal_Int16 RetrieveTypeFromResourceURL( const OUString& aResourceURL )
243 if (( aResourceURL.startsWith( RESOURCEURL_PREFIX ) ) &&
244 ( aResourceURL.getLength() > RESOURCEURL_PREFIX_SIZE ))
246 OUString aTmpStr = aResourceURL.copy( RESOURCEURL_PREFIX_SIZE );
247 sal_Int32 nIndex = aTmpStr.indexOf( '/' );
248 if (( nIndex > 0 ) && ( aTmpStr.getLength() > nIndex ))
250 OUString aTypeStr( aTmpStr.copy( 0, nIndex ));
251 for ( int i = 0; i < ui::UIElementType::COUNT; i++ )
253 if ( aTypeStr == UIELEMENTTYPENAMES[i] )
254 return sal_Int16( i );
259 return ui::UIElementType::UNKNOWN;
262 OUString RetrieveNameFromResourceURL( const OUString& aResourceURL )
264 if (( aResourceURL.startsWith( RESOURCEURL_PREFIX ) ) &&
265 ( aResourceURL.getLength() > RESOURCEURL_PREFIX_SIZE ))
267 sal_Int32 nIndex = aResourceURL.lastIndexOf( '/' );
268 if (( nIndex > 0 ) && (( nIndex+1 ) < aResourceURL.getLength()))
269 return aResourceURL.copy( nIndex+1 );
272 return OUString();
275 void ModuleUIConfigurationManager::impl_fillSequenceWithElementTypeInfo( UIElementInfoHashMap& aUIElementInfoCollection, sal_Int16 nElementType )
277 // preload list of element types on demand
278 impl_preloadUIElementTypeList( LAYER_USERDEFINED, nElementType );
279 impl_preloadUIElementTypeList( LAYER_DEFAULT, nElementType );
281 UIElementDataHashMap& rUserElements = m_aUIElements[LAYER_USERDEFINED][nElementType].aElementsHashMap;
283 OUString aCustomUrlPrefix( "custom_" );
284 for (auto const& userElement : rUserElements)
286 sal_Int32 nIndex = userElement.second.aResourceURL.indexOf( aCustomUrlPrefix, RESOURCEURL_PREFIX_SIZE );
287 if ( nIndex > RESOURCEURL_PREFIX_SIZE )
289 // Performance: Retrieve user interface name only for custom user interface elements.
290 // It's only used by them!
291 UIElementData* pDataSettings = impl_findUIElementData( userElement.second.aResourceURL, nElementType );
292 if ( pDataSettings )
294 // Retrieve user interface name from XPropertySet interface
295 OUString aUIName;
296 Reference< XPropertySet > xPropSet( pDataSettings->xSettings, UNO_QUERY );
297 if ( xPropSet.is() )
299 Any a = xPropSet->getPropertyValue( m_aPropUIName );
300 a >>= aUIName;
303 UIElementInfo aInfo( userElement.second.aResourceURL, aUIName );
304 aUIElementInfoCollection.emplace( userElement.second.aResourceURL, aInfo );
307 else
309 // The user interface name for standard user interface elements is stored in the WindowState.xcu file
310 UIElementInfo aInfo( userElement.second.aResourceURL, OUString() );
311 aUIElementInfoCollection.emplace( userElement.second.aResourceURL, aInfo );
315 UIElementDataHashMap& rDefaultElements = m_aUIElements[LAYER_DEFAULT][nElementType].aElementsHashMap;
317 for (auto const& defaultElement : rDefaultElements)
319 UIElementInfoHashMap::const_iterator pIterInfo = aUIElementInfoCollection.find( defaultElement.second.aResourceURL );
320 if ( pIterInfo == aUIElementInfoCollection.end() )
322 sal_Int32 nIndex = defaultElement.second.aResourceURL.indexOf( aCustomUrlPrefix, RESOURCEURL_PREFIX_SIZE );
323 if ( nIndex > RESOURCEURL_PREFIX_SIZE )
325 // Performance: Retrieve user interface name only for custom user interface elements.
326 // It's only used by them!
327 UIElementData* pDataSettings = impl_findUIElementData( defaultElement.second.aResourceURL, nElementType );
328 if ( pDataSettings )
330 // Retrieve user interface name from XPropertySet interface
331 OUString aUIName;
332 Reference< XPropertySet > xPropSet( pDataSettings->xSettings, UNO_QUERY );
333 if ( xPropSet.is() )
335 Any a = xPropSet->getPropertyValue( m_aPropUIName );
336 a >>= aUIName;
338 UIElementInfo aInfo( defaultElement.second.aResourceURL, aUIName );
339 aUIElementInfoCollection.emplace( defaultElement.second.aResourceURL, aInfo );
342 else
344 // The user interface name for standard user interface elements is stored in the WindowState.xcu file
345 UIElementInfo aInfo( defaultElement.second.aResourceURL, OUString() );
346 aUIElementInfoCollection.emplace( defaultElement.second.aResourceURL, aInfo );
352 void ModuleUIConfigurationManager::impl_preloadUIElementTypeList( Layer eLayer, sal_Int16 nElementType )
354 UIElementType& rElementTypeData = m_aUIElements[eLayer][nElementType];
356 if ( !rElementTypeData.bLoaded )
358 Reference< XStorage > xElementTypeStorage = rElementTypeData.xStorage;
359 if ( xElementTypeStorage.is() )
361 OUString aResURLPrefix =
362 RESOURCEURL_PREFIX +
363 UIELEMENTTYPENAMES[ nElementType ] +
364 "/";
366 UIElementDataHashMap& rHashMap = rElementTypeData.aElementsHashMap;
367 Sequence< OUString > aUIElementNames = xElementTypeStorage->getElementNames();
368 for ( sal_Int32 n = 0; n < aUIElementNames.getLength(); n++ )
370 UIElementData aUIElementData;
372 // Resource name must be without ".xml"
373 sal_Int32 nIndex = aUIElementNames[n].lastIndexOf( '.' );
374 if (( nIndex > 0 ) && ( nIndex < aUIElementNames[n].getLength() ))
376 OUString aExtension( aUIElementNames[n].copy( nIndex+1 ));
377 OUString aUIElementName( aUIElementNames[n].copy( 0, nIndex ));
379 if (!aUIElementName.isEmpty() &&
380 ( aExtension.equalsIgnoreAsciiCase("xml")))
382 aUIElementData.aResourceURL = aResURLPrefix + aUIElementName;
383 aUIElementData.aName = aUIElementNames[n];
385 if ( eLayer == LAYER_USERDEFINED )
387 aUIElementData.bModified = false;
388 aUIElementData.bDefault = false;
389 aUIElementData.bDefaultNode = false;
392 // Create std::unordered_map entries for all user interface elements inside the storage. We don't load the
393 // settings to speed up the process.
394 rHashMap.emplace( aUIElementData.aResourceURL, aUIElementData );
397 rElementTypeData.bLoaded = true;
404 void ModuleUIConfigurationManager::impl_requestUIElementData( sal_Int16 nElementType, Layer eLayer, UIElementData& aUIElementData )
406 UIElementType& rElementTypeData = m_aUIElements[eLayer][nElementType];
408 Reference< XStorage > xElementTypeStorage = rElementTypeData.xStorage;
409 if ( xElementTypeStorage.is() && !aUIElementData.aName.isEmpty() )
413 Reference< XStream > xStream = xElementTypeStorage->openStreamElement( aUIElementData.aName, ElementModes::READ );
414 Reference< XInputStream > xInputStream = xStream->getInputStream();
416 if ( xInputStream.is() )
418 switch ( nElementType )
420 case css::ui::UIElementType::UNKNOWN:
421 break;
423 case css::ui::UIElementType::MENUBAR:
424 case css::ui::UIElementType::POPUPMENU:
428 MenuConfiguration aMenuCfg( m_xContext );
429 Reference< XIndexAccess > xContainer( aMenuCfg.CreateMenuBarConfigurationFromXML( xInputStream ));
430 auto pRootItemContainer = comphelper::getUnoTunnelImplementation<RootItemContainer>( xContainer );
431 if ( pRootItemContainer )
432 aUIElementData.xSettings.set( static_cast< OWeakObject * >( new ConstItemContainer( pRootItemContainer, true ) ), UNO_QUERY );
433 else
434 aUIElementData.xSettings.set( static_cast< OWeakObject * >( new ConstItemContainer( xContainer, true ) ), UNO_QUERY );
435 return;
437 catch ( const css::lang::WrappedTargetException& )
441 break;
443 case css::ui::UIElementType::TOOLBAR:
447 Reference< XIndexContainer > xIndexContainer( static_cast< OWeakObject * >( new RootItemContainer() ), UNO_QUERY );
448 ToolBoxConfiguration::LoadToolBox( m_xContext, xInputStream, xIndexContainer );
449 auto pRootItemContainer = comphelper::getUnoTunnelImplementation<RootItemContainer>( xIndexContainer );
450 aUIElementData.xSettings.set( static_cast< OWeakObject * >( new ConstItemContainer( pRootItemContainer, true ) ), UNO_QUERY );
451 return;
453 catch ( const css::lang::WrappedTargetException& )
457 break;
460 case css::ui::UIElementType::STATUSBAR:
464 Reference< XIndexContainer > xIndexContainer( static_cast< OWeakObject * >( new RootItemContainer() ), UNO_QUERY );
465 StatusBarConfiguration::LoadStatusBar( m_xContext, xInputStream, xIndexContainer );
466 auto pRootItemContainer = comphelper::getUnoTunnelImplementation<RootItemContainer>( xIndexContainer );
467 aUIElementData.xSettings.set( static_cast< OWeakObject * >( new ConstItemContainer( pRootItemContainer, true ) ), UNO_QUERY );
468 return;
470 catch ( const css::lang::WrappedTargetException& )
474 break;
477 case css::ui::UIElementType::FLOATINGWINDOW:
479 break;
484 catch ( const css::embed::InvalidStorageException& )
487 catch ( const css::lang::IllegalArgumentException& )
490 catch ( const css::io::IOException& )
493 catch ( const css::embed::StorageWrappedTargetException& )
498 // At least we provide an empty settings container!
499 aUIElementData.xSettings.set( static_cast< OWeakObject * >( new ConstItemContainer() ), UNO_QUERY );
502 ModuleUIConfigurationManager::UIElementData* ModuleUIConfigurationManager::impl_findUIElementData( const OUString& aResourceURL, sal_Int16 nElementType, bool bLoad )
504 // preload list of element types on demand
505 impl_preloadUIElementTypeList( LAYER_USERDEFINED, nElementType );
506 impl_preloadUIElementTypeList( LAYER_DEFAULT, nElementType );
508 // first try to look into our user-defined vector/unordered_map combination
509 UIElementDataHashMap& rUserHashMap = m_aUIElements[LAYER_USERDEFINED][nElementType].aElementsHashMap;
510 UIElementDataHashMap::iterator pIter = rUserHashMap.find( aResourceURL );
511 if ( pIter != rUserHashMap.end() )
513 // Default data settings data must be retrieved from the default layer!
514 if ( !pIter->second.bDefault )
516 if ( !pIter->second.xSettings.is() && bLoad )
517 impl_requestUIElementData( nElementType, LAYER_USERDEFINED, pIter->second );
518 return &(pIter->second);
522 // Not successful, we have to look into our default vector/unordered_map combination
523 UIElementDataHashMap& rDefaultHashMap = m_aUIElements[LAYER_DEFAULT][nElementType].aElementsHashMap;
524 pIter = rDefaultHashMap.find( aResourceURL );
525 if ( pIter != rDefaultHashMap.end() )
527 if ( !pIter->second.xSettings.is() && bLoad )
528 impl_requestUIElementData( nElementType, LAYER_DEFAULT, pIter->second );
529 return &(pIter->second);
532 // Nothing has been found!
533 return nullptr;
536 void ModuleUIConfigurationManager::impl_storeElementTypeData( const Reference< XStorage >& xStorage, UIElementType& rElementType, bool bResetModifyState )
538 UIElementDataHashMap& rHashMap = rElementType.aElementsHashMap;
540 for (auto & elem : rHashMap)
542 UIElementData& rElement = elem.second;
543 if ( rElement.bModified )
545 if ( rElement.bDefault )
547 xStorage->removeElement( rElement.aName );
548 rElement.bModified = false; // mark as not modified
550 else
552 Reference< XStream > xStream = xStorage->openStreamElement( rElement.aName, ElementModes::WRITE|ElementModes::TRUNCATE );
553 Reference< XOutputStream > xOutputStream( xStream->getOutputStream() );
555 if ( xOutputStream.is() )
557 switch( rElementType.nElementType )
559 case css::ui::UIElementType::MENUBAR:
560 case css::ui::UIElementType::POPUPMENU:
564 MenuConfiguration aMenuCfg( m_xContext );
565 aMenuCfg.StoreMenuBarConfigurationToXML(
566 rElement.xSettings, xOutputStream, rElementType.nElementType == css::ui::UIElementType::MENUBAR );
568 catch ( const css::lang::WrappedTargetException& )
572 break;
574 case css::ui::UIElementType::TOOLBAR:
578 ToolBoxConfiguration::StoreToolBox( m_xContext, xOutputStream, rElement.xSettings );
580 catch ( const css::lang::WrappedTargetException& )
584 break;
586 case css::ui::UIElementType::STATUSBAR:
590 StatusBarConfiguration::StoreStatusBar( m_xContext, xOutputStream, rElement.xSettings );
592 catch ( const css::lang::WrappedTargetException& )
596 break;
598 default:
599 break;
603 // mark as not modified if we store to our own storage
604 if ( bResetModifyState )
605 rElement.bModified = false;
610 // commit element type storage
611 Reference< XTransactedObject > xTransactedObject( xStorage, UNO_QUERY );
612 if ( xTransactedObject.is() )
613 xTransactedObject->commit();
615 // mark UIElementType as not modified if we store to our own storage
616 if ( bResetModifyState )
617 rElementType.bModified = false;
620 // This is only allowed to be called on the LAYER_USER_DEFINED!
621 void ModuleUIConfigurationManager::impl_resetElementTypeData(
622 UIElementType& rUserElementType,
623 UIElementType const & rDefaultElementType,
624 ConfigEventNotifyContainer& rRemoveNotifyContainer,
625 ConfigEventNotifyContainer& rReplaceNotifyContainer )
627 UIElementDataHashMap& rHashMap = rUserElementType.aElementsHashMap;
629 Reference< XUIConfigurationManager > xThis( static_cast< OWeakObject* >( this ), UNO_QUERY );
630 Reference< XInterface > xIfac( xThis, UNO_QUERY );
631 sal_Int16 nType = rUserElementType.nElementType;
633 // Make copies of the event structures to be thread-safe. We have to unlock our mutex before calling
634 // our listeners!
635 for (auto & elem : rHashMap)
637 UIElementData& rElement = elem.second;
638 if ( !rElement.bDefault )
640 if ( rDefaultElementType.xStorage->hasByName( rElement.aName ))
642 // Replace settings with data from default layer
643 Reference< XIndexAccess > xOldSettings( rElement.xSettings );
644 impl_requestUIElementData( nType, LAYER_DEFAULT, rElement );
646 ui::ConfigurationEvent aReplaceEvent;
647 aReplaceEvent.ResourceURL = rElement.aResourceURL;
648 aReplaceEvent.Accessor <<= xThis;
649 aReplaceEvent.Source = xIfac;
650 aReplaceEvent.ReplacedElement <<= xOldSettings;
651 aReplaceEvent.Element <<= rElement.xSettings;
653 rReplaceNotifyContainer.push_back( aReplaceEvent );
655 // Mark element as default and not modified. That means "not active"
656 // in the user layer anymore.
657 rElement.bModified = false;
658 rElement.bDefault = true;
660 else
662 // Remove user-defined settings from user layer
663 ui::ConfigurationEvent aEvent;
664 aEvent.ResourceURL = rElement.aResourceURL;
665 aEvent.Accessor <<= xThis;
666 aEvent.Source = xIfac;
667 aEvent.Element <<= rElement.xSettings;
669 rRemoveNotifyContainer.push_back( aEvent );
671 // Mark element as default and not modified. That means "not active"
672 // in the user layer anymore.
673 rElement.bModified = false;
674 rElement.bDefault = true;
679 // Remove all settings from our user interface elements
680 rHashMap.clear();
683 void ModuleUIConfigurationManager::impl_reloadElementTypeData(
684 UIElementType& rUserElementType,
685 UIElementType const & rDefaultElementType,
686 ConfigEventNotifyContainer& rRemoveNotifyContainer,
687 ConfigEventNotifyContainer& rReplaceNotifyContainer )
689 UIElementDataHashMap& rHashMap = rUserElementType.aElementsHashMap;
691 Reference< XUIConfigurationManager > xThis( static_cast< OWeakObject* >( this ), UNO_QUERY );
692 Reference< XInterface > xIfac( xThis, UNO_QUERY );
693 sal_Int16 nType = rUserElementType.nElementType;
695 for (auto & elem : rHashMap)
697 UIElementData& rElement = elem.second;
698 if ( rElement.bModified )
700 if ( rUserElementType.xStorage->hasByName( rElement.aName ))
702 // Replace settings with data from user layer
703 Reference< XIndexAccess > xOldSettings( rElement.xSettings );
705 impl_requestUIElementData( nType, LAYER_USERDEFINED, rElement );
707 ui::ConfigurationEvent aReplaceEvent;
709 aReplaceEvent.ResourceURL = rElement.aResourceURL;
710 aReplaceEvent.Accessor <<= xThis;
711 aReplaceEvent.Source = xIfac;
712 aReplaceEvent.ReplacedElement <<= xOldSettings;
713 aReplaceEvent.Element <<= rElement.xSettings;
714 rReplaceNotifyContainer.push_back( aReplaceEvent );
716 rElement.bModified = false;
718 else if ( rDefaultElementType.xStorage->hasByName( rElement.aName ))
720 // Replace settings with data from default layer
721 Reference< XIndexAccess > xOldSettings( rElement.xSettings );
723 impl_requestUIElementData( nType, LAYER_DEFAULT, rElement );
725 ui::ConfigurationEvent aReplaceEvent;
727 aReplaceEvent.ResourceURL = rElement.aResourceURL;
728 aReplaceEvent.Accessor <<= xThis;
729 aReplaceEvent.Source = xIfac;
730 aReplaceEvent.ReplacedElement <<= xOldSettings;
731 aReplaceEvent.Element <<= rElement.xSettings;
732 rReplaceNotifyContainer.push_back( aReplaceEvent );
734 // Mark element as default and not modified. That means "not active"
735 // in the user layer anymore.
736 rElement.bModified = false;
737 rElement.bDefault = true;
739 else
741 // Element settings are not in any storage => remove
742 ui::ConfigurationEvent aRemoveEvent;
744 aRemoveEvent.ResourceURL = rElement.aResourceURL;
745 aRemoveEvent.Accessor <<= xThis;
746 aRemoveEvent.Source = xIfac;
747 aRemoveEvent.Element <<= rElement.xSettings;
749 rRemoveNotifyContainer.push_back( aRemoveEvent );
751 // Mark element as default and not modified. That means "not active"
752 // in the user layer anymore.
753 rElement.bModified = false;
754 rElement.bDefault = true;
759 rUserElementType.bModified = false;
762 void ModuleUIConfigurationManager::impl_Initialize()
764 // Initialize the top-level structures with the storage data
765 if ( m_xUserConfigStorage.is() )
767 // Try to access our module sub folder
768 for ( sal_Int16 i = 1; i < css::ui::UIElementType::COUNT;
769 i++ )
771 Reference< XStorage > xElementTypeStorage;
774 if ( m_pStorageHandler[i] )
775 xElementTypeStorage = m_pStorageHandler[i]->getWorkingStorageUser();
777 catch ( const css::container::NoSuchElementException& )
780 catch ( const css::embed::InvalidStorageException& )
783 catch ( const css::lang::IllegalArgumentException& )
786 catch ( const css::io::IOException& )
789 catch ( const css::embed::StorageWrappedTargetException& )
793 m_aUIElements[LAYER_USERDEFINED][i].nElementType = i;
794 m_aUIElements[LAYER_USERDEFINED][i].bModified = false;
795 m_aUIElements[LAYER_USERDEFINED][i].xStorage = xElementTypeStorage;
799 if ( m_xDefaultConfigStorage.is() )
801 Reference< XNameAccess > xNameAccess( m_xDefaultConfigStorage, UNO_QUERY_THROW );
803 // Try to access our module sub folder
804 for ( sal_Int16 i = 1; i < css::ui::UIElementType::COUNT;
805 i++ )
807 Reference< XStorage > xElementTypeStorage;
810 const OUString sName( UIELEMENTTYPENAMES[i] );
811 if( xNameAccess->hasByName( sName ) )
812 xNameAccess->getByName( sName ) >>= xElementTypeStorage;
814 catch ( const css::container::NoSuchElementException& )
818 m_aUIElements[LAYER_DEFAULT][i].nElementType = i;
819 m_aUIElements[LAYER_DEFAULT][i].bModified = false;
820 m_aUIElements[LAYER_DEFAULT][i].xStorage = xElementTypeStorage;
825 ModuleUIConfigurationManager::ModuleUIConfigurationManager(
826 const Reference< XComponentContext >& xContext,
827 const css::uno::Sequence< css::uno::Any >& aArguments)
828 : m_bReadOnly( true )
829 , m_bModified( false )
830 , m_bDisposed( false )
831 , m_aXMLPostfix( ".xml" )
832 , m_aPropUIName( "UIName" )
833 , m_xContext( xContext )
834 , m_aListenerContainer( m_mutex )
836 // Make sure we have a default initialized entry for every layer and user interface element type!
837 // The following code depends on this!
838 m_aUIElements[LAYER_DEFAULT].resize( css::ui::UIElementType::COUNT );
839 m_aUIElements[LAYER_USERDEFINED].resize( css::ui::UIElementType::COUNT );
841 SolarMutexGuard g;
843 OUString aModuleShortName;
844 if( aArguments.getLength() == 2 && (aArguments[0] >>= aModuleShortName) && (aArguments[1] >>= m_aModuleIdentifier))
847 else
849 ::comphelper::SequenceAsHashMap lArgs(aArguments);
850 aModuleShortName = lArgs.getUnpackedValueOrDefault("ModuleShortName", OUString());
851 m_aModuleIdentifier = lArgs.getUnpackedValueOrDefault("ModuleIdentifier", OUString());
854 for ( int i = 1; i < css::ui::UIElementType::COUNT; i++ )
856 OUString aResourceType;
857 if ( i == css::ui::UIElementType::MENUBAR )
858 aResourceType = RESOURCETYPE_MENUBAR;
859 else if ( i == css::ui::UIElementType::TOOLBAR )
860 aResourceType = RESOURCETYPE_TOOLBAR;
861 else if ( i == css::ui::UIElementType::STATUSBAR )
862 aResourceType = RESOURCETYPE_STATUSBAR;
863 else if ( i == css::ui::UIElementType::POPUPMENU )
864 aResourceType = RESOURCETYPE_POPUPMENU;
866 if ( !aResourceType.isEmpty() )
868 m_pStorageHandler[i].reset( new PresetHandler( m_xContext ) );
869 m_pStorageHandler[i]->connectToResource( PresetHandler::E_MODULES,
870 aResourceType, // this path won't be used later... see next lines!
871 aModuleShortName,
872 css::uno::Reference< css::embed::XStorage >()); // no document root used here!
876 // initialize root storages for all resource types
877 m_xUserRootCommit.set( m_pStorageHandler[css::ui::UIElementType::MENUBAR]->getOrCreateRootStorageUser(), css::uno::UNO_QUERY); // can be empty
878 m_xDefaultConfigStorage = m_pStorageHandler[css::ui::UIElementType::MENUBAR]->getParentStorageShare();
879 m_xUserConfigStorage = m_pStorageHandler[css::ui::UIElementType::MENUBAR]->getParentStorageUser();
881 if ( m_xUserConfigStorage.is() )
883 Reference< XPropertySet > xPropSet( m_xUserConfigStorage, UNO_QUERY );
884 if ( xPropSet.is() )
886 long nOpenMode = 0;
887 Any a = xPropSet->getPropertyValue("OpenMode");
888 if ( a >>= nOpenMode )
889 m_bReadOnly = !( nOpenMode & ElementModes::WRITE );
893 impl_Initialize();
896 // XComponent
897 void SAL_CALL ModuleUIConfigurationManager::dispose()
899 Reference< XComponent > xThis( static_cast< OWeakObject* >(this), UNO_QUERY );
901 css::lang::EventObject aEvent( xThis );
902 m_aListenerContainer.disposeAndClear( aEvent );
904 /* SAFE AREA ----------------------------------------------------------------------------------------------- */
905 SolarMutexClearableGuard aGuard;
906 Reference< XComponent > xModuleImageManager( m_xModuleImageManager );
907 m_xModuleImageManager.clear();
908 m_xModuleAcceleratorManager.clear();
909 m_aUIElements[LAYER_USERDEFINED].clear();
910 m_aUIElements[LAYER_DEFAULT].clear();
911 m_xDefaultConfigStorage.clear();
912 m_xUserConfigStorage.clear();
913 m_xUserRootCommit.clear();
914 m_bModified = false;
915 m_bDisposed = true;
916 aGuard.clear();
917 /* SAFE AREA ----------------------------------------------------------------------------------------------- */
921 if ( xModuleImageManager.is() )
922 xModuleImageManager->dispose();
924 catch ( const Exception& )
929 void SAL_CALL ModuleUIConfigurationManager::addEventListener( const Reference< XEventListener >& xListener )
932 SolarMutexGuard g;
934 /* SAFE AREA ----------------------------------------------------------------------------------------------- */
935 if ( m_bDisposed )
936 throw DisposedException();
939 m_aListenerContainer.addInterface( cppu::UnoType<XEventListener>::get(), xListener );
942 void SAL_CALL ModuleUIConfigurationManager::removeEventListener( const Reference< XEventListener >& xListener )
944 /* SAFE AREA ----------------------------------------------------------------------------------------------- */
945 m_aListenerContainer.removeInterface( cppu::UnoType<XEventListener>::get(), xListener );
948 // XUIConfiguration
949 void SAL_CALL ModuleUIConfigurationManager::addConfigurationListener( const Reference< css::ui::XUIConfigurationListener >& xListener )
952 SolarMutexGuard g;
954 /* SAFE AREA ----------------------------------------------------------------------------------------------- */
955 if ( m_bDisposed )
956 throw DisposedException();
959 m_aListenerContainer.addInterface( cppu::UnoType<ui::XUIConfigurationListener>::get(), xListener );
962 void SAL_CALL ModuleUIConfigurationManager::removeConfigurationListener( const Reference< css::ui::XUIConfigurationListener >& xListener )
964 /* SAFE AREA ----------------------------------------------------------------------------------------------- */
965 m_aListenerContainer.removeInterface( cppu::UnoType<ui::XUIConfigurationListener>::get(), xListener );
968 // XUIConfigurationManager
969 void SAL_CALL ModuleUIConfigurationManager::reset()
971 SolarMutexClearableGuard aGuard;
973 /* SAFE AREA ----------------------------------------------------------------------------------------------- */
974 if ( m_bDisposed )
975 throw DisposedException();
977 if ( !isReadOnly() )
979 // Remove all elements from our user-defined storage!
982 for ( int i = 1; i < css::ui::UIElementType::COUNT; i++ )
984 UIElementType& rElementType = m_aUIElements[LAYER_USERDEFINED][i];
986 if ( rElementType.xStorage.is() )
988 bool bCommitSubStorage( false );
989 Sequence< OUString > aUIElementStreamNames = rElementType.xStorage->getElementNames();
990 for ( sal_Int32 j = 0; j < aUIElementStreamNames.getLength(); j++ )
992 rElementType.xStorage->removeElement( aUIElementStreamNames[j] );
993 bCommitSubStorage = true;
996 if ( bCommitSubStorage )
998 Reference< XTransactedObject > xTransactedObject( rElementType.xStorage, UNO_QUERY );
999 if ( xTransactedObject.is() )
1000 xTransactedObject->commit();
1001 m_pStorageHandler[i]->commitUserChanges();
1006 // remove settings from user defined layer and notify listener about removed settings data!
1007 ConfigEventNotifyContainer aRemoveEventNotifyContainer;
1008 ConfigEventNotifyContainer aReplaceEventNotifyContainer;
1009 for ( sal_Int16 j = 1; j < css::ui::UIElementType::COUNT; j++ )
1013 UIElementType& rUserElementType = m_aUIElements[LAYER_USERDEFINED][j];
1014 UIElementType& rDefaultElementType = m_aUIElements[LAYER_DEFAULT][j];
1016 impl_resetElementTypeData( rUserElementType, rDefaultElementType, aRemoveEventNotifyContainer, aReplaceEventNotifyContainer );
1017 rUserElementType.bModified = false;
1019 catch (const Exception&)
1021 css::uno::Any anyEx = cppu::getCaughtException();
1022 throw css::lang::WrappedTargetRuntimeException(
1023 "ModuleUIConfigurationManager::reset exception",
1024 css::uno::Reference<css::uno::XInterface>(*this), anyEx);
1028 m_bModified = false;
1030 // Unlock mutex before notify our listeners
1031 aGuard.clear();
1033 // Notify our listeners
1034 for ( auto const & k: aRemoveEventNotifyContainer )
1035 implts_notifyContainerListener( k, NotifyOp_Remove );
1036 for ( auto const & k: aReplaceEventNotifyContainer )
1037 implts_notifyContainerListener( k, NotifyOp_Replace );
1039 catch ( const css::lang::IllegalArgumentException& )
1042 catch ( const css::container::NoSuchElementException& )
1045 catch ( const css::embed::InvalidStorageException& )
1048 catch ( const css::embed::StorageWrappedTargetException& )
1054 Sequence< Sequence< PropertyValue > > SAL_CALL ModuleUIConfigurationManager::getUIElementsInfo( sal_Int16 ElementType )
1056 if (( ElementType < 0 ) || ( ElementType >= css::ui::UIElementType::COUNT ))
1057 throw IllegalArgumentException();
1059 SolarMutexGuard g;
1060 if ( m_bDisposed )
1061 throw DisposedException();
1063 std::vector< Sequence< PropertyValue > > aElementInfoSeq;
1064 UIElementInfoHashMap aUIElementInfoCollection;
1066 if ( ElementType == css::ui::UIElementType::UNKNOWN )
1068 for ( sal_Int16 i = 0; i < css::ui::UIElementType::COUNT; i++ )
1069 impl_fillSequenceWithElementTypeInfo( aUIElementInfoCollection, i );
1071 else
1072 impl_fillSequenceWithElementTypeInfo( aUIElementInfoCollection, ElementType );
1074 Sequence< PropertyValue > aUIElementInfo( 2 );
1075 aUIElementInfo[0].Name = "ResourceURL";
1076 aUIElementInfo[1].Name = m_aPropUIName;
1078 aElementInfoSeq.resize( aUIElementInfoCollection.size() );
1080 sal_Int32 n = 0;
1081 for (auto const& elem : aUIElementInfoCollection)
1083 aUIElementInfo[0].Value <<= elem.second.aResourceURL;
1084 aUIElementInfo[1].Value <<= elem.second.aUIName;
1085 aElementInfoSeq[n++] = aUIElementInfo;
1088 return comphelper::containerToSequence(aElementInfoSeq);
1091 Reference< XIndexContainer > SAL_CALL ModuleUIConfigurationManager::createSettings()
1093 SolarMutexGuard g;
1095 if ( m_bDisposed )
1096 throw DisposedException();
1098 // Creates an empty item container which can be filled from outside
1099 return Reference< XIndexContainer >( static_cast< OWeakObject * >( new RootItemContainer() ), UNO_QUERY );
1102 sal_Bool SAL_CALL ModuleUIConfigurationManager::hasSettings( const OUString& ResourceURL )
1104 sal_Int16 nElementType = RetrieveTypeFromResourceURL( ResourceURL );
1106 if (( nElementType == css::ui::UIElementType::UNKNOWN ) ||
1107 ( nElementType >= css::ui::UIElementType::COUNT ))
1108 throw IllegalArgumentException();
1110 SolarMutexGuard g;
1112 if ( m_bDisposed )
1113 throw DisposedException();
1115 UIElementData* pDataSettings = impl_findUIElementData( ResourceURL, nElementType, false );
1116 if ( pDataSettings )
1117 return true;
1119 return false;
1122 Reference< XIndexAccess > SAL_CALL ModuleUIConfigurationManager::getSettings( const OUString& ResourceURL, sal_Bool bWriteable )
1124 sal_Int16 nElementType = RetrieveTypeFromResourceURL( ResourceURL );
1126 if (( nElementType == css::ui::UIElementType::UNKNOWN ) ||
1127 ( nElementType >= css::ui::UIElementType::COUNT ))
1128 throw IllegalArgumentException();
1130 SolarMutexGuard g;
1132 if ( m_bDisposed )
1133 throw DisposedException();
1135 UIElementData* pDataSettings = impl_findUIElementData( ResourceURL, nElementType );
1136 if ( pDataSettings )
1138 // Create a copy of our data if someone wants to change the data.
1139 if ( bWriteable )
1140 return Reference< XIndexAccess >( static_cast< OWeakObject * >( new RootItemContainer( pDataSettings->xSettings ) ), UNO_QUERY );
1141 else
1142 return pDataSettings->xSettings;
1145 throw NoSuchElementException();
1148 void SAL_CALL ModuleUIConfigurationManager::replaceSettings( const OUString& ResourceURL, const Reference< css::container::XIndexAccess >& aNewData )
1150 sal_Int16 nElementType = RetrieveTypeFromResourceURL( ResourceURL );
1152 if (( nElementType == css::ui::UIElementType::UNKNOWN ) ||
1153 ( nElementType >= css::ui::UIElementType::COUNT ))
1154 throw IllegalArgumentException();
1155 else if ( m_bReadOnly )
1156 throw IllegalAccessException();
1157 else
1159 SolarMutexClearableGuard aGuard;
1161 if ( m_bDisposed )
1162 throw DisposedException();
1164 UIElementData* pDataSettings = impl_findUIElementData( ResourceURL, nElementType );
1165 if ( !pDataSettings )
1166 throw NoSuchElementException();
1167 if ( !pDataSettings->bDefaultNode )
1169 // we have a settings entry in our user-defined layer - replace
1170 Reference< XIndexAccess > xOldSettings = pDataSettings->xSettings;
1172 // Create a copy of the data if the container is not const
1173 Reference< XIndexReplace > xReplace( aNewData, UNO_QUERY );
1174 if ( xReplace.is() )
1175 pDataSettings->xSettings.set( static_cast< OWeakObject * >( new ConstItemContainer( aNewData ) ), UNO_QUERY );
1176 else
1177 pDataSettings->xSettings = aNewData;
1178 pDataSettings->bDefault = false;
1179 pDataSettings->bModified = true;
1180 m_bModified = true;
1182 // Modify type container
1183 UIElementType& rElementType = m_aUIElements[LAYER_USERDEFINED][nElementType];
1184 rElementType.bModified = true;
1186 Reference< XUIConfigurationManager > xThis( static_cast< OWeakObject* >( this ), UNO_QUERY );
1187 Reference< XInterface > xIfac( xThis, UNO_QUERY );
1189 // Create event to notify listener about replaced element settings
1190 ui::ConfigurationEvent aEvent;
1191 aEvent.ResourceURL = ResourceURL;
1192 aEvent.Accessor <<= xThis;
1193 aEvent.Source = xIfac;
1194 aEvent.ReplacedElement <<= xOldSettings;
1195 aEvent.Element <<= pDataSettings->xSettings;
1197 aGuard.clear();
1199 implts_notifyContainerListener( aEvent, NotifyOp_Replace );
1201 else
1203 // we have no settings in our user-defined layer - insert
1204 UIElementData aUIElementData;
1206 aUIElementData.bDefault = false;
1207 aUIElementData.bDefaultNode = false;
1208 aUIElementData.bModified = true;
1210 // Create a copy of the data if the container is not const
1211 Reference< XIndexReplace > xReplace( aNewData, UNO_QUERY );
1212 if ( xReplace.is() )
1213 aUIElementData.xSettings.set( static_cast< OWeakObject * >( new ConstItemContainer( aNewData ) ), UNO_QUERY );
1214 else
1215 aUIElementData.xSettings = aNewData;
1216 aUIElementData.aName = RetrieveNameFromResourceURL( ResourceURL ) + m_aXMLPostfix;
1217 aUIElementData.aResourceURL = ResourceURL;
1218 m_bModified = true;
1220 // Modify type container
1221 UIElementType& rElementType = m_aUIElements[LAYER_USERDEFINED][nElementType];
1222 rElementType.bModified = true;
1224 UIElementDataHashMap& rElements = rElementType.aElementsHashMap;
1226 // Check our user element settings hash map as it can already contain settings that have been set to default!
1227 // If no node can be found, we have to insert it.
1228 UIElementDataHashMap::iterator pIter = rElements.find( ResourceURL );
1229 if ( pIter != rElements.end() )
1230 pIter->second = aUIElementData;
1231 else
1232 rElements.emplace( ResourceURL, aUIElementData );
1234 Reference< XUIConfigurationManager > xThis( static_cast< OWeakObject* >( this ), UNO_QUERY );
1235 Reference< XInterface > xIfac( xThis, UNO_QUERY );
1237 // Create event to notify listener about replaced element settings
1238 ui::ConfigurationEvent aEvent;
1240 aEvent.ResourceURL = ResourceURL;
1241 aEvent.Accessor <<= xThis;
1242 aEvent.Source = xIfac;
1243 aEvent.ReplacedElement <<= pDataSettings->xSettings;
1244 aEvent.Element <<= aUIElementData.xSettings;
1246 aGuard.clear();
1248 implts_notifyContainerListener( aEvent, NotifyOp_Replace );
1253 void SAL_CALL ModuleUIConfigurationManager::removeSettings( const OUString& ResourceURL )
1255 sal_Int16 nElementType = RetrieveTypeFromResourceURL( ResourceURL );
1257 if (( nElementType == css::ui::UIElementType::UNKNOWN ) ||
1258 ( nElementType >= css::ui::UIElementType::COUNT ))
1259 throw IllegalArgumentException( "The ResourceURL is not valid or "
1260 "describes an unknown type. "
1261 "ResourceURL: " + ResourceURL, nullptr, 0 );
1262 else if ( m_bReadOnly )
1263 throw IllegalAccessException( "The configuration manager is read-only. "
1264 "ResourceURL: " + ResourceURL, nullptr );
1265 else
1267 SolarMutexClearableGuard aGuard;
1269 if ( m_bDisposed )
1270 throw DisposedException( "The configuration manager has been disposed, "
1271 "and can't uphold its method specification anymore. "
1272 "ResourceURL: " + ResourceURL, nullptr );
1274 UIElementData* pDataSettings = impl_findUIElementData( ResourceURL, nElementType );
1275 if ( !pDataSettings )
1276 throw NoSuchElementException( "The settings data cannot be found. "
1277 "ResourceURL: " + ResourceURL, nullptr );
1278 // If element settings are default, we don't need to change anything!
1279 if ( pDataSettings->bDefault )
1280 return;
1281 else
1283 Reference< XIndexAccess > xRemovedSettings = pDataSettings->xSettings;
1284 pDataSettings->bDefault = true;
1286 // check if this is a default layer node
1287 if ( !pDataSettings->bDefaultNode )
1288 pDataSettings->bModified = true; // we have to remove this node from the user layer!
1289 pDataSettings->xSettings.clear();
1290 m_bModified = true; // user layer must be written
1292 // Modify type container
1293 UIElementType& rElementType = m_aUIElements[LAYER_USERDEFINED][nElementType];
1294 rElementType.bModified = true;
1296 Reference< XUIConfigurationManager > xThis( static_cast< OWeakObject* >( this ), UNO_QUERY );
1297 Reference< XInterface > xIfac( xThis, UNO_QUERY );
1299 // Check if we have settings in the default layer which replaces the user-defined one!
1300 UIElementData* pDefaultDataSettings = impl_findUIElementData( ResourceURL, nElementType );
1301 if ( pDefaultDataSettings )
1303 // Create event to notify listener about replaced element settings
1304 ui::ConfigurationEvent aEvent;
1306 aEvent.ResourceURL = ResourceURL;
1307 aEvent.Accessor <<= xThis;
1308 aEvent.Source = xIfac;
1309 aEvent.Element <<= xRemovedSettings;
1310 aEvent.ReplacedElement <<= pDefaultDataSettings->xSettings;
1312 aGuard.clear();
1314 implts_notifyContainerListener( aEvent, NotifyOp_Replace );
1316 else
1318 // Create event to notify listener about removed element settings
1319 ui::ConfigurationEvent aEvent;
1321 aEvent.ResourceURL = ResourceURL;
1322 aEvent.Accessor <<= xThis;
1323 aEvent.Source = xIfac;
1324 aEvent.Element <<= xRemovedSettings;
1326 aGuard.clear();
1328 implts_notifyContainerListener( aEvent, NotifyOp_Remove );
1334 void SAL_CALL ModuleUIConfigurationManager::insertSettings( const OUString& NewResourceURL, const Reference< XIndexAccess >& aNewData )
1336 sal_Int16 nElementType = RetrieveTypeFromResourceURL( NewResourceURL );
1338 if (( nElementType == css::ui::UIElementType::UNKNOWN ) ||
1339 ( nElementType >= css::ui::UIElementType::COUNT ))
1340 throw IllegalArgumentException();
1341 else if ( m_bReadOnly )
1342 throw IllegalAccessException();
1343 else
1345 SolarMutexClearableGuard aGuard;
1347 if ( m_bDisposed )
1348 throw DisposedException();
1350 UIElementData* pDataSettings = impl_findUIElementData( NewResourceURL, nElementType );
1351 if ( !(!pDataSettings) )
1352 throw ElementExistException();
1353 UIElementData aUIElementData;
1355 aUIElementData.bDefault = false;
1356 aUIElementData.bDefaultNode = false;
1357 aUIElementData.bModified = true;
1359 // Create a copy of the data if the container is not const
1360 Reference< XIndexReplace > xReplace( aNewData, UNO_QUERY );
1361 if ( xReplace.is() )
1362 aUIElementData.xSettings.set( static_cast< OWeakObject * >( new ConstItemContainer( aNewData ) ), UNO_QUERY );
1363 else
1364 aUIElementData.xSettings = aNewData;
1365 aUIElementData.aName = RetrieveNameFromResourceURL( NewResourceURL ) + m_aXMLPostfix;
1366 aUIElementData.aResourceURL = NewResourceURL;
1367 m_bModified = true;
1369 UIElementType& rElementType = m_aUIElements[LAYER_USERDEFINED][nElementType];
1370 rElementType.bModified = true;
1372 UIElementDataHashMap& rElements = rElementType.aElementsHashMap;
1373 rElements.emplace( NewResourceURL, aUIElementData );
1375 Reference< XIndexAccess > xInsertSettings( aUIElementData.xSettings );
1376 Reference< XUIConfigurationManager > xThis( static_cast< OWeakObject* >( this ), UNO_QUERY );
1378 // Create event to notify listener about removed element settings
1379 ui::ConfigurationEvent aEvent;
1381 aEvent.ResourceURL = NewResourceURL;
1382 aEvent.Accessor <<= xThis;
1383 aEvent.Source = xThis;
1384 aEvent.Element <<= xInsertSettings;
1386 aGuard.clear();
1388 implts_notifyContainerListener( aEvent, NotifyOp_Insert );
1392 Reference< XInterface > SAL_CALL ModuleUIConfigurationManager::getImageManager()
1394 SolarMutexGuard g;
1396 if ( m_bDisposed )
1397 throw DisposedException();
1399 if ( !m_xModuleImageManager.is() )
1401 m_xModuleImageManager.set( static_cast< cppu::OWeakObject *>( new ModuleImageManager( m_xContext )),
1402 UNO_QUERY );
1403 Reference< XInitialization > xInit( m_xModuleImageManager, UNO_QUERY );
1405 uno::Sequence<uno::Any> aPropSeq(comphelper::InitAnyPropertySequence(
1407 {"UserConfigStorage", uno::Any(m_xUserConfigStorage)},
1408 {"ModuleIdentifier", uno::Any(m_aModuleIdentifier)},
1409 {"UserRootCommit", uno::Any(m_xUserRootCommit)},
1410 }));
1411 xInit->initialize( aPropSeq );
1414 return Reference< XInterface >( m_xModuleImageManager, UNO_QUERY );
1417 Reference< ui::XAcceleratorConfiguration > SAL_CALL ModuleUIConfigurationManager::getShortCutManager()
1419 SolarMutexGuard g;
1421 if ( m_bDisposed )
1422 throw DisposedException();
1424 if ( !m_xModuleAcceleratorManager.is() ) try
1426 m_xModuleAcceleratorManager = ui::ModuleAcceleratorConfiguration::
1427 createWithModuleIdentifier(m_xContext, m_aModuleIdentifier);
1429 catch ( const css::uno::DeploymentException& )
1431 SAL_WARN("fwk.uiconfiguration", "ModuleAcceleratorConfiguration"
1432 " not available. This should happen only on mobile platforms.");
1435 return m_xModuleAcceleratorManager;
1438 Reference< XInterface > SAL_CALL ModuleUIConfigurationManager::getEventsManager()
1440 return Reference< XInterface >();
1443 // XModuleUIConfigurationManager
1444 sal_Bool SAL_CALL ModuleUIConfigurationManager::isDefaultSettings( const OUString& ResourceURL )
1446 sal_Int16 nElementType = RetrieveTypeFromResourceURL( ResourceURL );
1448 if (( nElementType == css::ui::UIElementType::UNKNOWN ) ||
1449 ( nElementType >= css::ui::UIElementType::COUNT ))
1450 throw IllegalArgumentException();
1452 SolarMutexGuard g;
1454 if ( m_bDisposed )
1455 throw DisposedException();
1457 UIElementData* pDataSettings = impl_findUIElementData( ResourceURL, nElementType, false );
1458 if ( pDataSettings && pDataSettings->bDefaultNode )
1459 return true;
1461 return false;
1464 Reference< XIndexAccess > SAL_CALL ModuleUIConfigurationManager::getDefaultSettings( const OUString& ResourceURL )
1466 sal_Int16 nElementType = RetrieveTypeFromResourceURL( ResourceURL );
1468 if (( nElementType == css::ui::UIElementType::UNKNOWN ) ||
1469 ( nElementType >= css::ui::UIElementType::COUNT ))
1470 throw IllegalArgumentException();
1472 SolarMutexGuard g;
1474 if ( m_bDisposed )
1475 throw DisposedException();
1477 // preload list of element types on demand
1478 impl_preloadUIElementTypeList( LAYER_DEFAULT, nElementType );
1480 // Look into our default vector/unordered_map combination
1481 UIElementDataHashMap& rDefaultHashMap = m_aUIElements[LAYER_DEFAULT][nElementType].aElementsHashMap;
1482 UIElementDataHashMap::iterator pIter = rDefaultHashMap.find( ResourceURL );
1483 if ( pIter != rDefaultHashMap.end() )
1485 if ( !pIter->second.xSettings.is() )
1486 impl_requestUIElementData( nElementType, LAYER_DEFAULT, pIter->second );
1487 return pIter->second.xSettings;
1490 // Nothing has been found!
1491 throw NoSuchElementException();
1494 // XUIConfigurationPersistence
1495 void SAL_CALL ModuleUIConfigurationManager::reload()
1497 SolarMutexClearableGuard aGuard;
1499 if ( m_bDisposed )
1500 throw DisposedException();
1502 if ( m_xUserConfigStorage.is() && m_bModified && !m_bReadOnly )
1504 // Try to access our module sub folder
1505 ConfigEventNotifyContainer aRemoveNotifyContainer;
1506 ConfigEventNotifyContainer aReplaceNotifyContainer;
1507 for ( sal_Int16 i = 1; i < css::ui::UIElementType::COUNT; i++ )
1511 UIElementType& rUserElementType = m_aUIElements[LAYER_USERDEFINED][i];
1513 if ( rUserElementType.bModified )
1515 UIElementType& rDefaultElementType = m_aUIElements[LAYER_DEFAULT][i];
1516 impl_reloadElementTypeData( rUserElementType, rDefaultElementType, aRemoveNotifyContainer, aReplaceNotifyContainer );
1519 catch ( const Exception& )
1521 throw IOException();
1525 m_bModified = false;
1527 // Unlock mutex before notify our listeners
1528 aGuard.clear();
1530 // Notify our listeners
1531 for (const ui::ConfigurationEvent & j : aRemoveNotifyContainer)
1532 implts_notifyContainerListener( j, NotifyOp_Remove );
1533 for (const ui::ConfigurationEvent & k : aReplaceNotifyContainer)
1534 implts_notifyContainerListener( k, NotifyOp_Replace );
1538 void SAL_CALL ModuleUIConfigurationManager::store()
1540 SolarMutexGuard g;
1542 if ( m_bDisposed )
1543 throw DisposedException();
1545 if ( m_xUserConfigStorage.is() && m_bModified && !m_bReadOnly )
1547 // Try to access our module sub folder
1548 for ( int i = 1; i < css::ui::UIElementType::COUNT; i++ )
1552 UIElementType& rElementType = m_aUIElements[LAYER_USERDEFINED][i];
1554 if ( rElementType.bModified && rElementType.xStorage.is() )
1556 impl_storeElementTypeData( rElementType.xStorage, rElementType );
1557 m_pStorageHandler[i]->commitUserChanges();
1560 catch ( const Exception& )
1562 throw IOException();
1566 m_bModified = false;
1570 void SAL_CALL ModuleUIConfigurationManager::storeToStorage( const Reference< XStorage >& Storage )
1572 SolarMutexGuard g;
1574 if ( m_bDisposed )
1575 throw DisposedException();
1577 if ( m_xUserConfigStorage.is() && m_bModified && !m_bReadOnly )
1579 // Try to access our module sub folder
1580 for ( int i = 1; i < css::ui::UIElementType::COUNT; i++ )
1584 Reference< XStorage > xElementTypeStorage( Storage->openStorageElement(
1585 UIELEMENTTYPENAMES[i], ElementModes::READWRITE ));
1586 UIElementType& rElementType = m_aUIElements[LAYER_USERDEFINED][i];
1588 if ( rElementType.bModified && xElementTypeStorage.is() )
1589 impl_storeElementTypeData( xElementTypeStorage, rElementType, false ); // store data to storage, but don't reset modify flag!
1591 catch ( const Exception& )
1593 throw IOException();
1597 Reference< XTransactedObject > xTransactedObject( Storage, UNO_QUERY );
1598 if ( xTransactedObject.is() )
1599 xTransactedObject->commit();
1603 sal_Bool SAL_CALL ModuleUIConfigurationManager::isModified()
1605 SolarMutexGuard g;
1607 return m_bModified;
1610 sal_Bool SAL_CALL ModuleUIConfigurationManager::isReadOnly()
1612 SolarMutexGuard g;
1614 return m_bReadOnly;
1617 void ModuleUIConfigurationManager::implts_notifyContainerListener( const ui::ConfigurationEvent& aEvent, NotifyOp eOp )
1619 ::cppu::OInterfaceContainerHelper* pContainer = m_aListenerContainer.getContainer( cppu::UnoType<css::ui::XUIConfigurationListener>::get());
1620 if ( pContainer != nullptr )
1622 ::cppu::OInterfaceIteratorHelper pIterator( *pContainer );
1623 while ( pIterator.hasMoreElements() )
1627 switch ( eOp )
1629 case NotifyOp_Replace:
1630 static_cast< css::ui::XUIConfigurationListener*>(pIterator.next())->elementReplaced( aEvent );
1631 break;
1632 case NotifyOp_Insert:
1633 static_cast< css::ui::XUIConfigurationListener*>(pIterator.next())->elementInserted( aEvent );
1634 break;
1635 case NotifyOp_Remove:
1636 static_cast< css::ui::XUIConfigurationListener*>(pIterator.next())->elementRemoved( aEvent );
1637 break;
1640 catch( const css::uno::RuntimeException& )
1642 pIterator.remove();
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: */