Version 6.4.0.0.beta1, tag libreoffice-6.4.0.0.beta1
[LibreOffice.git] / framework / source / uiconfiguration / uiconfigurationmanager.cxx
blob778028f98d42012b500494a5b8f9c212833ab3e3
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 <uiconfiguration/imagemanager.hxx>
21 #include <uielement/rootitemcontainer.hxx>
22 #include <uielement/constitemcontainer.hxx>
23 #include <uielement/uielementtypenames.hxx>
24 #include <framework/menuconfiguration.hxx>
25 #include <framework/statusbarconfiguration.hxx>
26 #include <framework/toolboxconfiguration.hxx>
28 #include <com/sun/star/beans/XPropertySet.hpp>
29 #include <com/sun/star/container/ElementExistException.hpp>
30 #include <com/sun/star/container/XIndexContainer.hpp>
31 #include <com/sun/star/embed/ElementModes.hpp>
32 #include <com/sun/star/embed/InvalidStorageException.hpp>
33 #include <com/sun/star/embed/StorageWrappedTargetException.hpp>
34 #include <com/sun/star/embed/XTransactedObject.hpp>
35 #include <com/sun/star/lang/IllegalAccessException.hpp>
36 #include <com/sun/star/lang/XInitialization.hpp>
37 #include <com/sun/star/lang/DisposedException.hpp>
38 #include <com/sun/star/io/IOException.hpp>
39 #include <com/sun/star/io/XStream.hpp>
40 #include <com/sun/star/ui/UIElementType.hpp>
41 #include <com/sun/star/ui/ConfigurationEvent.hpp>
42 #include <com/sun/star/ui/DocumentAcceleratorConfiguration.hpp>
43 #include <com/sun/star/ui/XAcceleratorConfiguration.hpp>
44 #include <com/sun/star/ui/XUIConfigurationManager2.hpp>
45 #include <com/sun/star/lang/XComponent.hpp>
46 #include <com/sun/star/lang/XServiceInfo.hpp>
48 #include <cppuhelper/implbase.hxx>
49 #include <cppuhelper/supportsservice.hxx>
50 #include <comphelper/propertysequence.hxx>
51 #include <comphelper/sequence.hxx>
52 #include <comphelper/servicehelper.hxx>
53 #include <vcl/svapp.hxx>
54 #include <rtl/ref.hxx>
55 #include <rtl/ustrbuf.hxx>
56 #include <sal/log.hxx>
58 #include <unordered_map>
60 using namespace com::sun::star::uno;
61 using namespace com::sun::star::io;
62 using namespace com::sun::star::embed;
63 using namespace com::sun::star::lang;
64 using namespace com::sun::star::container;
65 using namespace com::sun::star::beans;
66 using namespace com::sun::star::ui;
67 using namespace framework;
69 namespace {
71 class UIConfigurationManager : public ::cppu::WeakImplHelper<
72 css::lang::XServiceInfo ,
73 css::ui::XUIConfigurationManager2 >
75 public:
76 virtual OUString SAL_CALL getImplementationName() override
78 return "com.sun.star.comp.framework.UIConfigurationManager";
81 virtual sal_Bool SAL_CALL supportsService(OUString const & ServiceName) override
83 return cppu::supportsService(this, ServiceName);
86 virtual css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override
88 return {"com.sun.star.ui.UIConfigurationManager"};
91 explicit UIConfigurationManager( const css::uno::Reference< css::uno::XComponentContext > & rxContext );
93 // XComponent
94 virtual void SAL_CALL dispose() override;
95 virtual void SAL_CALL addEventListener( const css::uno::Reference< css::lang::XEventListener >& xListener ) override;
96 virtual void SAL_CALL removeEventListener( const css::uno::Reference< css::lang::XEventListener >& aListener ) override;
98 // XUIConfiguration
99 virtual void SAL_CALL addConfigurationListener( const css::uno::Reference< css::ui::XUIConfigurationListener >& Listener ) override;
100 virtual void SAL_CALL removeConfigurationListener( const css::uno::Reference< css::ui::XUIConfigurationListener >& Listener ) override;
102 // XUIConfigurationManager
103 virtual void SAL_CALL reset() override;
104 virtual css::uno::Sequence< css::uno::Sequence< css::beans::PropertyValue > > SAL_CALL getUIElementsInfo( sal_Int16 ElementType ) override;
105 virtual css::uno::Reference< css::container::XIndexContainer > SAL_CALL createSettings( ) override;
106 virtual sal_Bool SAL_CALL hasSettings( const OUString& ResourceURL ) override;
107 virtual css::uno::Reference< css::container::XIndexAccess > SAL_CALL getSettings( const OUString& ResourceURL, sal_Bool bWriteable ) override;
108 virtual void SAL_CALL replaceSettings( const OUString& ResourceURL, const css::uno::Reference< css::container::XIndexAccess >& aNewData ) override;
109 virtual void SAL_CALL removeSettings( const OUString& ResourceURL ) override;
110 virtual void SAL_CALL insertSettings( const OUString& NewResourceURL, const css::uno::Reference< css::container::XIndexAccess >& aNewData ) override;
111 virtual css::uno::Reference< css::uno::XInterface > SAL_CALL getImageManager() override;
112 virtual css::uno::Reference< css::ui::XAcceleratorConfiguration > SAL_CALL getShortCutManager() override;
113 virtual css::uno::Reference< css::uno::XInterface > SAL_CALL getEventsManager() override;
115 // XUIConfigurationPersistence
116 virtual void SAL_CALL reload() override;
117 virtual void SAL_CALL store() override;
118 virtual void SAL_CALL storeToStorage( const css::uno::Reference< css::embed::XStorage >& Storage ) override;
119 virtual sal_Bool SAL_CALL isModified() override;
120 virtual sal_Bool SAL_CALL isReadOnly() override;
122 // XUIConfigurationStorage
123 virtual void SAL_CALL setStorage( const css::uno::Reference< css::embed::XStorage >& Storage ) override;
124 virtual sal_Bool SAL_CALL hasStorage() override;
126 private:
127 // private data types
128 enum NotifyOp
130 NotifyOp_Remove,
131 NotifyOp_Insert,
132 NotifyOp_Replace
135 struct UIElementInfo
137 UIElementInfo( const OUString& rResourceURL, const OUString& rUIName ) :
138 aResourceURL( rResourceURL), aUIName( rUIName ) {}
139 OUString aResourceURL;
140 OUString aUIName;
143 struct UIElementData
145 UIElementData() : bModified( false ), bDefault( true ) {};
147 OUString aResourceURL;
148 OUString aName;
149 bool bModified; // has been changed since last storing
150 bool bDefault; // default settings
151 css::uno::Reference< css::container::XIndexAccess > xSettings;
154 struct UIElementType;
155 friend struct UIElementType;
156 typedef std::unordered_map< OUString, UIElementData > UIElementDataHashMap;
158 struct UIElementType
160 UIElementType() : bModified( false ),
161 bLoaded( false ),
162 nElementType( css::ui::UIElementType::UNKNOWN ) {}
164 bool bModified;
165 bool bLoaded;
166 sal_Int16 nElementType;
167 UIElementDataHashMap aElementsHashMap;
168 css::uno::Reference< css::embed::XStorage > xStorage;
171 typedef std::vector< UIElementType > UIElementTypesVector;
172 typedef std::vector< css::ui::ConfigurationEvent > ConfigEventNotifyContainer;
173 typedef std::unordered_map< OUString, UIElementInfo > UIElementInfoHashMap;
175 void impl_Initialize();
176 void implts_notifyContainerListener( const css::ui::ConfigurationEvent& aEvent, NotifyOp eOp );
177 void impl_fillSequenceWithElementTypeInfo( UIElementInfoHashMap& aUIElementInfoCollection, sal_Int16 nElementType );
178 void impl_preloadUIElementTypeList( sal_Int16 nElementType );
179 UIElementData* impl_findUIElementData( const OUString& aResourceURL, sal_Int16 nElementType, bool bLoad = true );
180 void impl_requestUIElementData( sal_Int16 nElementType, UIElementData& aUIElementData );
181 void impl_storeElementTypeData( css::uno::Reference< css::embed::XStorage > const & xStorage, UIElementType& rElementType, bool bResetModifyState = true );
182 void impl_resetElementTypeData( UIElementType& rDocElementType, ConfigEventNotifyContainer& rRemoveNotifyContainer );
183 void impl_reloadElementTypeData( UIElementType& rDocElementType, ConfigEventNotifyContainer& rRemoveNotifyContainer, ConfigEventNotifyContainer& rReplaceNotifyContainer );
185 UIElementTypesVector m_aUIElements;
186 css::uno::Reference< css::embed::XStorage > m_xDocConfigStorage;
187 bool m_bReadOnly;
188 bool m_bModified;
189 bool m_bDisposed;
190 OUString m_aPropUIName;
191 css::uno::Reference< css::uno::XComponentContext > m_xContext;
192 osl::Mutex m_mutex;
193 cppu::OMultiTypeInterfaceContainerHelper m_aListenerContainer; /// container for ALL Listener
194 css::uno::Reference< css::lang::XComponent > m_xImageManager;
195 css::uno::Reference< css::ui::XAcceleratorConfiguration > m_xAccConfig;
198 // important: The order and position of the elements must match the constant
199 // definition of "css::ui::UIElementType"
200 static OUStringLiteral UIELEMENTTYPENAMES[] =
202 "", // Dummy value for unknown!
203 UIELEMENTTYPE_MENUBAR_NAME,
204 UIELEMENTTYPE_POPUPMENU_NAME,
205 UIELEMENTTYPE_TOOLBAR_NAME,
206 UIELEMENTTYPE_STATUSBAR_NAME,
207 UIELEMENTTYPE_FLOATINGWINDOW_NAME,
208 UIELEMENTTYPE_PROGRESSBAR_NAME,
209 UIELEMENTTYPE_TOOLPANEL_NAME
212 static const char RESOURCEURL_PREFIX[] = "private:resource/";
213 static const sal_Int32 RESOURCEURL_PREFIX_SIZE = 17;
215 sal_Int16 RetrieveTypeFromResourceURL( const OUString& aResourceURL )
218 if (( aResourceURL.startsWith( RESOURCEURL_PREFIX ) ) &&
219 ( aResourceURL.getLength() > RESOURCEURL_PREFIX_SIZE ))
221 OUString aTmpStr = aResourceURL.copy( RESOURCEURL_PREFIX_SIZE );
222 sal_Int32 nIndex = aTmpStr.indexOf( '/' );
223 if (( nIndex > 0 ) && ( aTmpStr.getLength() > nIndex ))
225 OUString aTypeStr( aTmpStr.copy( 0, nIndex ));
226 for ( int i = 0; i < UIElementType::COUNT; i++ )
228 if ( aTypeStr == UIELEMENTTYPENAMES[i] )
229 return sal_Int16( i );
234 return UIElementType::UNKNOWN;
237 OUString RetrieveNameFromResourceURL( const OUString& aResourceURL )
239 if (( aResourceURL.startsWith( RESOURCEURL_PREFIX ) ) &&
240 ( aResourceURL.getLength() > RESOURCEURL_PREFIX_SIZE ))
242 sal_Int32 nIndex = aResourceURL.lastIndexOf( '/' );
243 if (( nIndex > 0 ) && (( nIndex+1 ) < aResourceURL.getLength()))
244 return aResourceURL.copy( nIndex+1 );
247 return OUString();
250 void UIConfigurationManager::impl_fillSequenceWithElementTypeInfo( UIElementInfoHashMap& aUIElementInfoCollection, sal_Int16 nElementType )
252 // preload list of element types on demand
253 impl_preloadUIElementTypeList( nElementType );
255 UIElementDataHashMap& rUserElements = m_aUIElements[nElementType].aElementsHashMap;
257 for (auto const& elem : rUserElements)
259 UIElementData* pDataSettings = impl_findUIElementData( elem.second.aResourceURL, nElementType );
260 if ( pDataSettings && !pDataSettings->bDefault )
262 // Retrieve user interface name from XPropertySet interface
263 OUString aUIName;
264 Reference< XPropertySet > xPropSet( pDataSettings->xSettings, UNO_QUERY );
265 if ( xPropSet.is() )
267 Any a = xPropSet->getPropertyValue( m_aPropUIName );
268 a >>= aUIName;
271 UIElementInfo aInfo( elem.second.aResourceURL, aUIName );
272 aUIElementInfoCollection.emplace( elem.second.aResourceURL, aInfo );
277 void UIConfigurationManager::impl_preloadUIElementTypeList( sal_Int16 nElementType )
279 UIElementType& rElementTypeData = m_aUIElements[nElementType];
281 if ( !rElementTypeData.bLoaded )
283 Reference< XStorage > xElementTypeStorage = rElementTypeData.xStorage;
284 if ( xElementTypeStorage.is() )
286 OUString aResURLPrefix =
287 RESOURCEURL_PREFIX +
288 UIELEMENTTYPENAMES[ nElementType ] +
289 "/";
291 UIElementDataHashMap& rHashMap = rElementTypeData.aElementsHashMap;
292 Sequence< OUString > aUIElementNames = xElementTypeStorage->getElementNames();
293 for ( sal_Int32 n = 0; n < aUIElementNames.getLength(); n++ )
295 UIElementData aUIElementData;
297 // Resource name must be without ".xml"
298 sal_Int32 nIndex = aUIElementNames[n].lastIndexOf( '.' );
299 if (( nIndex > 0 ) && ( nIndex < aUIElementNames[n].getLength() ))
301 OUString aExtension( aUIElementNames[n].copy( nIndex+1 ));
302 OUString aUIElementName( aUIElementNames[n].copy( 0, nIndex ));
304 if (!aUIElementName.isEmpty() &&
305 ( aExtension.equalsIgnoreAsciiCase("xml")))
307 aUIElementData.aResourceURL = aResURLPrefix + aUIElementName;
308 aUIElementData.aName = aUIElementNames[n];
309 aUIElementData.bModified = false;
310 aUIElementData.bDefault = false;
312 // Create unordered_map entries for all user interface elements inside the storage. We don't load the
313 // settings to speed up the process.
314 rHashMap.emplace( aUIElementData.aResourceURL, aUIElementData );
321 rElementTypeData.bLoaded = true;
324 void UIConfigurationManager::impl_requestUIElementData( sal_Int16 nElementType, UIElementData& aUIElementData )
326 UIElementType& rElementTypeData = m_aUIElements[nElementType];
328 Reference< XStorage > xElementTypeStorage = rElementTypeData.xStorage;
329 if ( xElementTypeStorage.is() && !aUIElementData.aName.isEmpty() )
333 Reference< XStream > xStream = xElementTypeStorage->openStreamElement( aUIElementData.aName, ElementModes::READ );
334 Reference< XInputStream > xInputStream = xStream->getInputStream();
336 if ( xInputStream.is() )
338 switch ( nElementType )
340 case css::ui::UIElementType::UNKNOWN:
341 break;
343 case css::ui::UIElementType::MENUBAR:
344 case css::ui::UIElementType::POPUPMENU:
348 MenuConfiguration aMenuCfg( m_xContext );
349 Reference< XIndexAccess > xContainer( aMenuCfg.CreateMenuBarConfigurationFromXML( xInputStream ));
350 auto pRootItemContainer = comphelper::getUnoTunnelImplementation<RootItemContainer>( xContainer );
351 if ( pRootItemContainer )
352 aUIElementData.xSettings.set( static_cast< OWeakObject * >( new ConstItemContainer( pRootItemContainer, true ) ), UNO_QUERY );
353 else
354 aUIElementData.xSettings.set( static_cast< OWeakObject * >( new ConstItemContainer( xContainer, true ) ), UNO_QUERY );
355 return;
357 catch ( const css::lang::WrappedTargetException& )
361 break;
363 case css::ui::UIElementType::TOOLBAR:
367 Reference< XIndexContainer > xIndexContainer( static_cast< OWeakObject * >( new RootItemContainer() ), UNO_QUERY );
368 ToolBoxConfiguration::LoadToolBox( m_xContext, xInputStream, xIndexContainer );
369 auto pRootItemContainer = comphelper::getUnoTunnelImplementation<RootItemContainer>( xIndexContainer );
370 aUIElementData.xSettings.set( static_cast< OWeakObject * >( new ConstItemContainer( pRootItemContainer, true ) ), UNO_QUERY );
371 return;
373 catch ( const css::lang::WrappedTargetException& )
377 break;
380 case css::ui::UIElementType::STATUSBAR:
384 Reference< XIndexContainer > xIndexContainer( static_cast< OWeakObject * >( new RootItemContainer() ), UNO_QUERY );
385 StatusBarConfiguration::LoadStatusBar( m_xContext, xInputStream, xIndexContainer );
386 auto pRootItemContainer = comphelper::getUnoTunnelImplementation<RootItemContainer>( xIndexContainer );
387 aUIElementData.xSettings.set( static_cast< OWeakObject * >( new ConstItemContainer( pRootItemContainer, true ) ), UNO_QUERY );
388 return;
390 catch ( const css::lang::WrappedTargetException& )
394 break;
397 case css::ui::UIElementType::FLOATINGWINDOW:
399 break;
404 catch ( const css::embed::InvalidStorageException& )
407 catch ( const css::lang::IllegalArgumentException& )
410 catch ( const css::io::IOException& )
413 catch ( const css::embed::StorageWrappedTargetException& )
418 // At least we provide an empty settings container!
419 aUIElementData.xSettings.set( static_cast< OWeakObject * >( new ConstItemContainer()), UNO_QUERY );
422 UIConfigurationManager::UIElementData* UIConfigurationManager::impl_findUIElementData( const OUString& aResourceURL, sal_Int16 nElementType, bool bLoad )
424 // preload list of element types on demand
425 impl_preloadUIElementTypeList( nElementType );
427 // try to look into our document vector/unordered_map combination
428 UIElementDataHashMap& rUserHashMap = m_aUIElements[nElementType].aElementsHashMap;
429 UIElementDataHashMap::iterator pIter = rUserHashMap.find( aResourceURL );
430 if ( pIter != rUserHashMap.end() )
432 // Default data settings data means removed!
433 if ( pIter->second.bDefault )
434 return &(pIter->second);
435 else
437 if ( !pIter->second.xSettings.is() && bLoad )
438 impl_requestUIElementData( nElementType, pIter->second );
439 return &(pIter->second);
443 // Nothing has been found!
444 return nullptr;
447 void UIConfigurationManager::impl_storeElementTypeData( Reference< XStorage > const & xStorage, UIElementType& rElementType, bool bResetModifyState )
449 UIElementDataHashMap& rHashMap = rElementType.aElementsHashMap;
451 for (auto & elem : rHashMap)
453 UIElementData& rElement = elem.second;
454 if ( rElement.bModified )
456 if ( rElement.bDefault )
458 xStorage->removeElement( rElement.aName );
459 rElement.bModified = false; // mark as not modified
461 else
463 Reference< XStream > xStream = xStorage->openStreamElement( rElement.aName, ElementModes::WRITE|ElementModes::TRUNCATE );
464 Reference< XOutputStream > xOutputStream( xStream->getOutputStream() );
466 if ( xOutputStream.is() )
468 switch( rElementType.nElementType )
470 case css::ui::UIElementType::MENUBAR:
471 case css::ui::UIElementType::POPUPMENU:
475 MenuConfiguration aMenuCfg( m_xContext );
476 aMenuCfg.StoreMenuBarConfigurationToXML(
477 rElement.xSettings, xOutputStream, rElementType.nElementType == css::ui::UIElementType::MENUBAR );
479 catch ( const css::lang::WrappedTargetException& )
483 break;
485 case css::ui::UIElementType::TOOLBAR:
489 ToolBoxConfiguration::StoreToolBox( m_xContext, xOutputStream, rElement.xSettings );
491 catch ( const css::lang::WrappedTargetException& )
495 break;
497 case css::ui::UIElementType::STATUSBAR:
501 StatusBarConfiguration::StoreStatusBar( m_xContext, xOutputStream, rElement.xSettings );
503 catch ( const css::lang::WrappedTargetException& )
507 break;
509 default:
510 break;
514 // mark as not modified if we store to our own storage
515 if ( bResetModifyState )
516 rElement.bModified = false;
521 // commit element type storage
522 Reference< XTransactedObject > xTransactedObject( xStorage, UNO_QUERY );
523 if ( xTransactedObject.is() )
524 xTransactedObject->commit();
526 // mark UIElementType as not modified if we store to our own storage
527 if ( bResetModifyState )
528 rElementType.bModified = false;
531 void UIConfigurationManager::impl_resetElementTypeData(
532 UIElementType& rDocElementType,
533 ConfigEventNotifyContainer& rRemoveNotifyContainer )
535 UIElementDataHashMap& rHashMap = rDocElementType.aElementsHashMap;
537 Reference< XUIConfigurationManager > xThis( static_cast< OWeakObject* >( this ), UNO_QUERY );
538 Reference< XInterface > xIfac( xThis, UNO_QUERY );
540 // Make copies of the event structures to be thread-safe. We have to unlock our mutex before calling
541 // our listeners!
542 for (auto & elem : rHashMap)
544 UIElementData& rElement = elem.second;
545 if ( !rElement.bDefault )
547 // Remove user-defined settings from document
548 ConfigurationEvent aEvent;
549 aEvent.ResourceURL = rElement.aResourceURL;
550 aEvent.Accessor <<= xThis;
551 aEvent.Source = xIfac;
552 aEvent.Element <<= rElement.xSettings;
554 rRemoveNotifyContainer.push_back( aEvent );
556 // Mark element as default.
557 rElement.bModified = false;
558 rElement.bDefault = true;
560 else
561 rElement.bModified = false;
564 // Remove all settings from our user interface elements
565 rHashMap.clear();
568 void UIConfigurationManager::impl_reloadElementTypeData(
569 UIElementType& rDocElementType,
570 ConfigEventNotifyContainer& rRemoveNotifyContainer,
571 ConfigEventNotifyContainer& rReplaceNotifyContainer )
573 UIElementDataHashMap& rHashMap = rDocElementType.aElementsHashMap;
574 Reference< XStorage > xElementStorage( rDocElementType.xStorage );
576 Reference< XUIConfigurationManager > xThis( static_cast< OWeakObject* >( this ), UNO_QUERY );
577 Reference< XInterface > xIfac( xThis, UNO_QUERY );
578 sal_Int16 nType = rDocElementType.nElementType;
580 for (auto & elem : rHashMap)
582 UIElementData& rElement = elem.second;
583 if ( rElement.bModified )
585 if ( xElementStorage->hasByName( rElement.aName ))
587 // Replace settings with data from user layer
588 Reference< XIndexAccess > xOldSettings( rElement.xSettings );
590 impl_requestUIElementData( nType, rElement );
592 ConfigurationEvent aReplaceEvent;
594 aReplaceEvent.ResourceURL = rElement.aResourceURL;
595 aReplaceEvent.Accessor <<= xThis;
596 aReplaceEvent.Source = xIfac;
597 aReplaceEvent.ReplacedElement <<= xOldSettings;
598 aReplaceEvent.Element <<= rElement.xSettings;
599 rReplaceNotifyContainer.push_back( aReplaceEvent );
601 rElement.bModified = false;
603 else
605 // Element settings are not in any storage => remove
606 ConfigurationEvent aRemoveEvent;
608 aRemoveEvent.ResourceURL = rElement.aResourceURL;
609 aRemoveEvent.Accessor <<= xThis;
610 aRemoveEvent.Source = xIfac;
611 aRemoveEvent.Element <<= rElement.xSettings;
613 rRemoveNotifyContainer.push_back( aRemoveEvent );
615 // Mark element as default and not modified. That means "not active" in the document anymore
616 rElement.bModified = false;
617 rElement.bDefault = true;
622 rDocElementType.bModified = false;
625 void UIConfigurationManager::impl_Initialize()
627 // Initialize the top-level structures with the storage data
628 if ( m_xDocConfigStorage.is() )
630 long nModes = m_bReadOnly ? ElementModes::READ : ElementModes::READWRITE;
632 // Try to access our module sub folder
633 for ( sal_Int16 i = 1; i < css::ui::UIElementType::COUNT;
634 i++ )
636 Reference< XStorage > xElementTypeStorage;
639 xElementTypeStorage = m_xDocConfigStorage->openStorageElement( UIELEMENTTYPENAMES[i], nModes );
641 catch ( const css::container::NoSuchElementException& )
644 catch ( const css::embed::InvalidStorageException& )
647 catch ( const css::lang::IllegalArgumentException& )
650 catch ( const css::io::IOException& )
653 catch ( const css::embed::StorageWrappedTargetException& )
657 m_aUIElements[i].nElementType = i;
658 m_aUIElements[i].bModified = false;
659 m_aUIElements[i].xStorage = xElementTypeStorage;
662 else
664 // We have no storage, just initialize ui element types with empty storage!
665 for ( int i = 1; i < css::ui::UIElementType::COUNT; i++ )
666 m_aUIElements[i].xStorage = m_xDocConfigStorage;
670 UIConfigurationManager::UIConfigurationManager( const css::uno::Reference< css::uno::XComponentContext > & rxContext ) :
671 m_bReadOnly( true )
672 , m_bModified( false )
673 , m_bDisposed( false )
674 , m_aPropUIName( "UIName" )
675 , m_xContext( rxContext )
676 , m_aListenerContainer( m_mutex )
678 // Make sure we have a default initialized entry for every layer and user interface element type!
679 // The following code depends on this!
680 m_aUIElements.resize( css::ui::UIElementType::COUNT );
683 // XComponent
684 void SAL_CALL UIConfigurationManager::dispose()
686 Reference< XComponent > xThis( static_cast< OWeakObject* >(this), UNO_QUERY );
688 css::lang::EventObject aEvent( xThis );
689 m_aListenerContainer.disposeAndClear( aEvent );
692 SolarMutexGuard g;
695 if ( m_xImageManager.is() )
696 m_xImageManager->dispose();
698 catch ( const Exception& )
702 m_xImageManager.clear();
703 m_aUIElements.clear();
704 m_xDocConfigStorage.clear();
705 m_bModified = false;
706 m_bDisposed = true;
710 void SAL_CALL UIConfigurationManager::addEventListener( const Reference< XEventListener >& xListener )
713 SolarMutexGuard g;
715 /* SAFE AREA ----------------------------------------------------------------------------------------------- */
716 if ( m_bDisposed )
717 throw DisposedException();
720 m_aListenerContainer.addInterface( cppu::UnoType<XEventListener>::get(), xListener );
723 void SAL_CALL UIConfigurationManager::removeEventListener( const Reference< XEventListener >& xListener )
725 /* SAFE AREA ----------------------------------------------------------------------------------------------- */
726 m_aListenerContainer.removeInterface( cppu::UnoType<XEventListener>::get(), xListener );
729 // XUIConfigurationManager
730 void SAL_CALL UIConfigurationManager::addConfigurationListener( const Reference< css::ui::XUIConfigurationListener >& xListener )
733 SolarMutexGuard g;
735 /* SAFE AREA ----------------------------------------------------------------------------------------------- */
736 if ( m_bDisposed )
737 throw DisposedException();
740 m_aListenerContainer.addInterface( cppu::UnoType<XUIConfigurationListener>::get(), xListener );
743 void SAL_CALL UIConfigurationManager::removeConfigurationListener( const Reference< css::ui::XUIConfigurationListener >& xListener )
745 /* SAFE AREA ----------------------------------------------------------------------------------------------- */
746 m_aListenerContainer.removeInterface( cppu::UnoType<XUIConfigurationListener>::get(), xListener );
749 void SAL_CALL UIConfigurationManager::reset()
751 SolarMutexClearableGuard aGuard;
753 /* SAFE AREA ----------------------------------------------------------------------------------------------- */
754 if ( m_bDisposed )
755 throw DisposedException();
757 if ( isReadOnly() )
758 return;
760 if ( m_xDocConfigStorage.is() )
764 // Remove all elements from our user-defined storage!
765 bool bCommit( false );
766 for ( int i = 1; i < css::ui::UIElementType::COUNT; i++ )
768 UIElementType& rElementType = m_aUIElements[i];
770 if ( rElementType.xStorage.is() )
772 bool bCommitSubStorage( false );
773 Sequence< OUString > aUIElementStreamNames = rElementType.xStorage->getElementNames();
774 for ( sal_Int32 j = 0; j < aUIElementStreamNames.getLength(); j++ )
776 rElementType.xStorage->removeElement( aUIElementStreamNames[j] );
777 bCommitSubStorage = true;
778 bCommit = true;
781 if ( bCommitSubStorage )
783 Reference< XTransactedObject > xTransactedObject( rElementType.xStorage, UNO_QUERY );
784 if ( xTransactedObject.is() )
785 xTransactedObject->commit();
790 // Commit changes
791 if ( bCommit )
793 Reference< XTransactedObject > xTransactedObject( m_xDocConfigStorage, UNO_QUERY );
794 if ( xTransactedObject.is() )
795 xTransactedObject->commit();
798 // remove settings from user defined layer and notify listener about removed settings data!
799 // Try to access our module sub folder
800 ConfigEventNotifyContainer aRemoveEventNotifyContainer;
801 for ( sal_Int16 j = 1; j < css::ui::UIElementType::COUNT; j++ )
803 UIElementType& rDocElementType = m_aUIElements[j];
805 impl_resetElementTypeData( rDocElementType, aRemoveEventNotifyContainer );
806 rDocElementType.bModified = false;
809 m_bModified = false;
811 // Unlock mutex before notify our listeners
812 aGuard.clear();
814 // Notify our listeners
815 for (const ConfigurationEvent & k : aRemoveEventNotifyContainer)
816 implts_notifyContainerListener( k, NotifyOp_Remove );
818 catch ( const css::lang::IllegalArgumentException& )
821 catch ( const css::container::NoSuchElementException& )
824 catch ( const css::embed::InvalidStorageException& )
827 catch ( const css::embed::StorageWrappedTargetException& )
833 Sequence< Sequence< PropertyValue > > SAL_CALL UIConfigurationManager::getUIElementsInfo( sal_Int16 ElementType )
835 if (( ElementType < 0 ) || ( ElementType >= css::ui::UIElementType::COUNT ))
836 throw IllegalArgumentException();
838 SolarMutexGuard g;
839 if ( m_bDisposed )
840 throw DisposedException();
842 std::vector< Sequence< PropertyValue > > aElementInfoSeq;
843 UIElementInfoHashMap aUIElementInfoCollection;
845 if ( ElementType == css::ui::UIElementType::UNKNOWN )
847 for ( sal_Int16 i = 0; i < css::ui::UIElementType::COUNT; i++ )
848 impl_fillSequenceWithElementTypeInfo( aUIElementInfoCollection, i );
850 else
851 impl_fillSequenceWithElementTypeInfo( aUIElementInfoCollection, ElementType );
853 Sequence< PropertyValue > aUIElementInfo( 2 );
854 aUIElementInfo[0].Name = "ResourceURL";
855 aUIElementInfo[1].Name = m_aPropUIName;
857 aElementInfoSeq.resize( aUIElementInfoCollection.size() );
858 sal_Int32 n = 0;
859 for (auto const& elem : aUIElementInfoCollection)
861 aUIElementInfo[0].Value <<= elem.second.aResourceURL;
862 aUIElementInfo[1].Value <<= elem.second.aUIName;
863 aElementInfoSeq[n++] = aUIElementInfo;
866 return comphelper::containerToSequence(aElementInfoSeq);
869 Reference< XIndexContainer > SAL_CALL UIConfigurationManager::createSettings()
871 SolarMutexGuard g;
873 if ( m_bDisposed )
874 throw DisposedException();
876 // Creates an empty item container which can be filled from outside
877 return Reference< XIndexContainer >( static_cast< OWeakObject * >( new RootItemContainer()), UNO_QUERY );
880 sal_Bool SAL_CALL UIConfigurationManager::hasSettings( const OUString& ResourceURL )
882 sal_Int16 nElementType = RetrieveTypeFromResourceURL( ResourceURL );
884 if (( nElementType == css::ui::UIElementType::UNKNOWN ) ||
885 ( nElementType >= css::ui::UIElementType::COUNT ))
886 throw IllegalArgumentException();
887 UIElementData* pDataSettings = impl_findUIElementData( ResourceURL, nElementType, false );
888 if ( pDataSettings && !pDataSettings->bDefault )
889 return true;
891 return false;
894 Reference< XIndexAccess > SAL_CALL UIConfigurationManager::getSettings( const OUString& ResourceURL, sal_Bool bWriteable )
896 sal_Int16 nElementType = RetrieveTypeFromResourceURL( ResourceURL );
898 if (( nElementType == css::ui::UIElementType::UNKNOWN ) ||
899 ( nElementType >= css::ui::UIElementType::COUNT ))
900 throw IllegalArgumentException();
902 SolarMutexGuard g;
904 if ( m_bDisposed )
905 throw DisposedException();
907 UIElementData* pDataSettings = impl_findUIElementData( ResourceURL, nElementType );
908 if ( pDataSettings && !pDataSettings->bDefault )
910 // Create a copy of our data if someone wants to change the data.
911 if ( bWriteable )
912 return Reference< XIndexAccess >( static_cast< OWeakObject * >( new RootItemContainer( pDataSettings->xSettings ) ), UNO_QUERY );
913 else
914 return pDataSettings->xSettings;
917 throw NoSuchElementException();
920 void SAL_CALL UIConfigurationManager::replaceSettings( const OUString& ResourceURL, const Reference< css::container::XIndexAccess >& aNewData )
922 sal_Int16 nElementType = RetrieveTypeFromResourceURL( ResourceURL );
924 if (( nElementType == css::ui::UIElementType::UNKNOWN ) ||
925 ( nElementType >= css::ui::UIElementType::COUNT ))
926 throw IllegalArgumentException();
927 else if ( m_bReadOnly )
928 throw IllegalAccessException();
929 else
931 SolarMutexClearableGuard aGuard;
933 if ( m_bDisposed )
934 throw DisposedException();
936 UIElementData* pDataSettings = impl_findUIElementData( ResourceURL, nElementType );
937 if ( !pDataSettings || pDataSettings->bDefault )
938 throw NoSuchElementException();
939 // we have a settings entry in our user-defined layer - replace
940 Reference< XIndexAccess > xOldSettings = pDataSettings->xSettings;
942 // Create a copy of the data if the container is not const
943 Reference< XIndexReplace > xReplace( aNewData, UNO_QUERY );
944 if ( xReplace.is() )
945 pDataSettings->xSettings.set( static_cast< OWeakObject * >( new ConstItemContainer( aNewData ) ), UNO_QUERY );
946 else
947 pDataSettings->xSettings = aNewData;
949 pDataSettings->bDefault = false;
950 pDataSettings->bModified = true;
951 m_bModified = true;
953 // Modify type container
954 UIElementType& rElementType = m_aUIElements[nElementType];
955 rElementType.bModified = true;
957 Reference< XUIConfigurationManager > xThis( static_cast< OWeakObject* >( this ), UNO_QUERY );
958 Reference< XInterface > xIfac( xThis, UNO_QUERY );
960 // Create event to notify listener about replaced element settings
961 ConfigurationEvent aEvent;
963 aEvent.ResourceURL = ResourceURL;
964 aEvent.Accessor <<= xThis;
965 aEvent.Source = xIfac;
966 aEvent.ReplacedElement <<= xOldSettings;
967 aEvent.Element <<= pDataSettings->xSettings;
969 aGuard.clear();
971 implts_notifyContainerListener( aEvent, NotifyOp_Replace );
975 void SAL_CALL UIConfigurationManager::removeSettings( const OUString& ResourceURL )
977 sal_Int16 nElementType = RetrieveTypeFromResourceURL( ResourceURL );
979 if (( nElementType == css::ui::UIElementType::UNKNOWN ) ||
980 ( nElementType >= css::ui::UIElementType::COUNT ))
981 throw IllegalArgumentException( "The ResourceURL is not valid or "
982 "describes an unknown type. "
983 "ResourceURL: " + ResourceURL, nullptr, 0 );
984 else if ( m_bReadOnly )
985 throw IllegalAccessException( "The configuration manager is read-only. "
986 "ResourceURL: " + ResourceURL, nullptr );
987 else
989 SolarMutexClearableGuard aGuard;
991 if ( m_bDisposed )
992 throw DisposedException( "The configuration manager has been disposed, "
993 "and can't uphold its method specification anymore. "
994 "ResourceURL: " + ResourceURL, nullptr );
996 UIElementData* pDataSettings = impl_findUIElementData( ResourceURL, nElementType );
997 if ( !pDataSettings )
998 throw NoSuchElementException( "The settings data cannot be found. "
999 "ResourceURL: " + ResourceURL, nullptr);
1000 // If element settings are default, we don't need to change anything!
1001 if ( pDataSettings->bDefault )
1002 return;
1003 else
1005 Reference< XIndexAccess > xRemovedSettings = pDataSettings->xSettings;
1006 pDataSettings->bDefault = true;
1008 // check if this is a default layer node
1009 pDataSettings->bModified = true; // we have to remove this node from the user layer!
1010 pDataSettings->xSettings.clear();
1011 m_bModified = true; // user layer must be written
1013 // Modify type container
1014 UIElementType& rElementType = m_aUIElements[nElementType];
1015 rElementType.bModified = true;
1017 Reference< XUIConfigurationManager > xThis( static_cast< OWeakObject* >( this ), UNO_QUERY );
1018 Reference< XInterface > xIfac( xThis, UNO_QUERY );
1020 // Create event to notify listener about removed element settings
1021 ConfigurationEvent aEvent;
1023 aEvent.ResourceURL = ResourceURL;
1024 aEvent.Accessor <<= xThis;
1025 aEvent.Source = xIfac;
1026 aEvent.Element <<= xRemovedSettings;
1028 aGuard.clear();
1030 implts_notifyContainerListener( aEvent, NotifyOp_Remove );
1035 void SAL_CALL UIConfigurationManager::insertSettings( const OUString& NewResourceURL, const Reference< XIndexAccess >& aNewData )
1037 sal_Int16 nElementType = RetrieveTypeFromResourceURL( NewResourceURL );
1039 if (( nElementType == css::ui::UIElementType::UNKNOWN ) ||
1040 ( nElementType >= css::ui::UIElementType::COUNT ))
1041 throw IllegalArgumentException();
1042 else if ( m_bReadOnly )
1043 throw IllegalAccessException();
1044 else
1046 SolarMutexClearableGuard aGuard;
1048 if ( m_bDisposed )
1049 throw DisposedException();
1051 bool bInsertData( false );
1052 UIElementData aUIElementData;
1053 UIElementData* pDataSettings = impl_findUIElementData( NewResourceURL, nElementType );
1055 if ( pDataSettings && !pDataSettings->bDefault )
1056 throw ElementExistException();
1058 if ( !pDataSettings )
1060 pDataSettings = &aUIElementData;
1061 bInsertData = true;
1065 pDataSettings->bDefault = false;
1066 pDataSettings->bModified = true;
1068 // Create a copy of the data if the container is not const
1069 Reference< XIndexReplace > xReplace( aNewData, UNO_QUERY );
1070 if ( xReplace.is() )
1071 pDataSettings->xSettings.set( static_cast< OWeakObject * >( new ConstItemContainer( aNewData ) ), UNO_QUERY );
1072 else
1073 pDataSettings->xSettings = aNewData;
1075 m_bModified = true;
1077 UIElementType& rElementType = m_aUIElements[nElementType];
1078 rElementType.bModified = true;
1080 if ( bInsertData )
1082 pDataSettings->aName = RetrieveNameFromResourceURL( NewResourceURL ) + ".xml";
1083 pDataSettings->aResourceURL = NewResourceURL;
1085 UIElementDataHashMap& rElements = rElementType.aElementsHashMap;
1086 rElements.emplace( NewResourceURL, *pDataSettings );
1089 Reference< XIndexAccess > xInsertSettings( aUIElementData.xSettings );
1090 Reference< XUIConfigurationManager > xThis( static_cast< OWeakObject* >( this ), UNO_QUERY );
1091 Reference< XInterface > xIfac( xThis, UNO_QUERY );
1093 // Create event to notify listener about removed element settings
1094 ConfigurationEvent aEvent;
1096 aEvent.ResourceURL = NewResourceURL;
1097 aEvent.Accessor <<= xThis;
1098 aEvent.Source = xIfac;
1099 aEvent.Element <<= xInsertSettings;
1101 aGuard.clear();
1103 implts_notifyContainerListener( aEvent, NotifyOp_Insert );
1108 Reference< XInterface > SAL_CALL UIConfigurationManager::getImageManager()
1110 if ( m_bDisposed )
1111 throw DisposedException();
1113 if ( !m_xImageManager.is() )
1115 m_xImageManager.set( static_cast< cppu::OWeakObject *>( new ImageManager( m_xContext )),
1116 UNO_QUERY );
1117 Reference< XInitialization > xInit( m_xImageManager, UNO_QUERY );
1119 Sequence<Any> aPropSeq(comphelper::InitAnyPropertySequence(
1121 {"UserConfigStorage", Any(m_xDocConfigStorage)},
1122 {"ModuleIdentifier", Any(OUString())},
1123 }));
1125 xInit->initialize( aPropSeq );
1128 return Reference< XInterface >( m_xImageManager, UNO_QUERY );
1131 Reference< XAcceleratorConfiguration > SAL_CALL UIConfigurationManager::getShortCutManager()
1133 // SAFE ->
1134 SolarMutexGuard g;
1136 if (!m_xAccConfig.is()) try
1138 m_xAccConfig = DocumentAcceleratorConfiguration::
1139 createWithDocumentRoot(m_xContext, m_xDocConfigStorage);
1141 catch ( const css::uno::DeploymentException& )
1143 SAL_WARN("fwk.uiconfiguration", "DocumentAcceleratorConfiguration"
1144 " not available. This should happen only on mobile platforms.");
1147 return m_xAccConfig;
1150 Reference< XInterface > SAL_CALL UIConfigurationManager::getEventsManager()
1152 return Reference< XInterface >();
1155 // XUIConfigurationStorage
1156 void SAL_CALL UIConfigurationManager::setStorage( const Reference< XStorage >& Storage )
1158 SolarMutexGuard g;
1160 if ( m_bDisposed )
1161 throw DisposedException();
1163 if ( m_xDocConfigStorage.is() )
1167 // Dispose old storage to be sure that it will be closed
1168 m_xDocConfigStorage->dispose();
1170 catch ( const Exception& )
1175 // We store the new storage. Be careful it could be an empty reference!
1176 m_xDocConfigStorage = Storage;
1177 m_bReadOnly = true;
1179 if ( m_xAccConfig.is() )
1180 m_xAccConfig->setStorage( m_xDocConfigStorage );
1182 if ( m_xImageManager.is() )
1184 ImageManager* pImageManager = static_cast<ImageManager*>(m_xImageManager.get());
1185 if ( pImageManager )
1186 pImageManager->setStorage( m_xDocConfigStorage );
1189 if ( m_xDocConfigStorage.is() )
1191 Reference< XPropertySet > xPropSet( m_xDocConfigStorage, UNO_QUERY );
1192 if ( xPropSet.is() )
1196 long nOpenMode = 0;
1197 Any a = xPropSet->getPropertyValue("OpenMode");
1198 if ( a >>= nOpenMode )
1199 m_bReadOnly = !( nOpenMode & ElementModes::WRITE );
1201 catch ( const css::beans::UnknownPropertyException& )
1204 catch ( const css::lang::WrappedTargetException& )
1210 impl_Initialize();
1213 sal_Bool SAL_CALL UIConfigurationManager::hasStorage()
1215 SolarMutexGuard g;
1217 if ( m_bDisposed )
1218 throw DisposedException();
1220 return m_xDocConfigStorage.is();
1223 // XUIConfigurationPersistence
1224 void SAL_CALL UIConfigurationManager::reload()
1226 SolarMutexClearableGuard aGuard;
1228 if ( m_bDisposed )
1229 throw DisposedException();
1231 if ( m_xDocConfigStorage.is() && m_bModified && !m_bReadOnly )
1233 // Try to access our module sub folder
1234 ConfigEventNotifyContainer aRemoveNotifyContainer;
1235 ConfigEventNotifyContainer aReplaceNotifyContainer;
1236 for ( sal_Int16 i = 1; i < css::ui::UIElementType::COUNT; i++ )
1240 UIElementType& rDocElementType = m_aUIElements[i];
1241 if ( rDocElementType.bModified )
1242 impl_reloadElementTypeData( rDocElementType, aRemoveNotifyContainer, aReplaceNotifyContainer );
1244 catch ( const Exception& )
1246 throw IOException();
1250 m_bModified = false;
1252 // Unlock mutex before notify our listeners
1253 aGuard.clear();
1255 // Notify our listeners
1256 for (const ConfigurationEvent & j : aRemoveNotifyContainer)
1257 implts_notifyContainerListener( j, NotifyOp_Remove );
1258 for (const ConfigurationEvent & k : aReplaceNotifyContainer)
1259 implts_notifyContainerListener( k, NotifyOp_Replace );
1263 void SAL_CALL UIConfigurationManager::store()
1265 SolarMutexGuard g;
1267 if ( m_bDisposed )
1268 throw DisposedException();
1270 if ( m_xDocConfigStorage.is() && m_bModified && !m_bReadOnly )
1272 // Try to access our module sub folder
1273 for ( int i = 1; i < css::ui::UIElementType::COUNT; i++ )
1277 UIElementType& rElementType = m_aUIElements[i];
1279 if ( rElementType.bModified && rElementType.xStorage.is() )
1280 impl_storeElementTypeData( rElementType.xStorage, rElementType );
1282 catch ( const Exception& )
1284 throw IOException();
1288 m_bModified = false;
1289 Reference< XTransactedObject > xTransactedObject( m_xDocConfigStorage, UNO_QUERY );
1290 if ( xTransactedObject.is() )
1291 xTransactedObject->commit();
1295 void SAL_CALL UIConfigurationManager::storeToStorage( const Reference< XStorage >& Storage )
1297 SolarMutexGuard g;
1299 if ( m_bDisposed )
1300 throw DisposedException();
1302 if ( m_xDocConfigStorage.is() && m_bModified && !m_bReadOnly )
1304 // Try to access our module sub folder
1305 for ( int i = 1; i < css::ui::UIElementType::COUNT; i++ )
1309 Reference< XStorage > xElementTypeStorage( Storage->openStorageElement(
1310 UIELEMENTTYPENAMES[i], ElementModes::READWRITE ));
1311 UIElementType& rElementType = m_aUIElements[i];
1313 if ( rElementType.bModified && xElementTypeStorage.is() )
1314 impl_storeElementTypeData( xElementTypeStorage, rElementType, false ); // store data to storage, but don't reset modify flag!
1316 catch ( const Exception& )
1318 throw IOException();
1322 Reference< XTransactedObject > xTransactedObject( Storage, UNO_QUERY );
1323 if ( xTransactedObject.is() )
1324 xTransactedObject->commit();
1328 sal_Bool SAL_CALL UIConfigurationManager::isModified()
1330 SolarMutexGuard g;
1332 return m_bModified;
1335 sal_Bool SAL_CALL UIConfigurationManager::isReadOnly()
1337 SolarMutexGuard g;
1339 return m_bReadOnly;
1342 void UIConfigurationManager::implts_notifyContainerListener( const ConfigurationEvent& aEvent, NotifyOp eOp )
1344 ::cppu::OInterfaceContainerHelper* pContainer = m_aListenerContainer.getContainer( cppu::UnoType<css::ui::XUIConfigurationListener>::get());
1345 if ( pContainer != nullptr )
1347 ::cppu::OInterfaceIteratorHelper pIterator( *pContainer );
1348 while ( pIterator.hasMoreElements() )
1352 switch ( eOp )
1354 case NotifyOp_Replace:
1355 static_cast< css::ui::XUIConfigurationListener*>(pIterator.next())->elementReplaced( aEvent );
1356 break;
1357 case NotifyOp_Insert:
1358 static_cast< css::ui::XUIConfigurationListener*>(pIterator.next())->elementInserted( aEvent );
1359 break;
1360 case NotifyOp_Remove:
1361 static_cast< css::ui::XUIConfigurationListener*>(pIterator.next())->elementRemoved( aEvent );
1362 break;
1365 catch( const css::uno::RuntimeException& )
1367 pIterator.remove();
1375 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
1376 com_sun_star_comp_framework_UIConfigurationManager_get_implementation(
1377 css::uno::XComponentContext *context,
1378 css::uno::Sequence<css::uno::Any> const &)
1380 return cppu::acquire(new UIConfigurationManager(context));
1383 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */