1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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
;
71 class UIConfigurationManager
: public ::cppu::WeakImplHelper
<
72 css::lang::XServiceInfo
,
73 css::ui::XUIConfigurationManager2
>
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
);
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
;
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
;
127 // private data types
137 UIElementInfo( const OUString
& rResourceURL
, const OUString
& rUIName
) :
138 aResourceURL( rResourceURL
), aUIName( rUIName
) {}
139 OUString aResourceURL
;
145 UIElementData() : bModified( false ), bDefault( true ) {};
147 OUString aResourceURL
;
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
;
160 UIElementType() : bModified( false ),
162 nElementType( css::ui::UIElementType::UNKNOWN
) {}
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
;
190 OUString m_aPropUIName
;
191 css::uno::Reference
< css::uno::XComponentContext
> m_xContext
;
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 );
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
264 Reference
< XPropertySet
> xPropSet( pDataSettings
->xSettings
, UNO_QUERY
);
267 Any a
= xPropSet
->getPropertyValue( m_aPropUIName
);
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
=
288 UIELEMENTTYPENAMES
[ nElementType
] +
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
:
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
);
354 aUIElementData
.xSettings
.set( static_cast< OWeakObject
* >( new ConstItemContainer( xContainer
, true ) ), UNO_QUERY
);
357 catch ( const css::lang::WrappedTargetException
& )
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
);
373 catch ( const css::lang::WrappedTargetException
& )
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
);
390 catch ( const css::lang::WrappedTargetException
& )
397 case css::ui::UIElementType::FLOATINGWINDOW
:
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
);
437 if ( !pIter
->second
.xSettings
.is() && bLoad
)
438 impl_requestUIElementData( nElementType
, pIter
->second
);
439 return &(pIter
->second
);
443 // Nothing has been found!
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
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
& )
485 case css::ui::UIElementType::TOOLBAR
:
489 ToolBoxConfiguration::StoreToolBox( m_xContext
, xOutputStream
, rElement
.xSettings
);
491 catch ( const css::lang::WrappedTargetException
& )
497 case css::ui::UIElementType::STATUSBAR
:
501 StatusBarConfiguration::StoreStatusBar( m_xContext
, xOutputStream
, rElement
.xSettings
);
503 catch ( const css::lang::WrappedTargetException
& )
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
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;
561 rElement
.bModified
= false;
564 // Remove all settings from our user interface elements
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;
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
;
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
;
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
) :
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
);
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
);
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();
710 void SAL_CALL
UIConfigurationManager::addEventListener( const Reference
< XEventListener
>& xListener
)
715 /* SAFE AREA ----------------------------------------------------------------------------------------------- */
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
)
735 /* SAFE AREA ----------------------------------------------------------------------------------------------- */
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 ----------------------------------------------------------------------------------------------- */
755 throw DisposedException();
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;
781 if ( bCommitSubStorage
)
783 Reference
< XTransactedObject
> xTransactedObject( rElementType
.xStorage
, UNO_QUERY
);
784 if ( xTransactedObject
.is() )
785 xTransactedObject
->commit();
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;
811 // Unlock mutex before notify our listeners
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();
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
);
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() );
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()
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
)
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();
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.
912 return Reference
< XIndexAccess
>( static_cast< OWeakObject
* >( new RootItemContainer( pDataSettings
->xSettings
) ), UNO_QUERY
);
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();
931 SolarMutexClearableGuard aGuard
;
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
);
945 pDataSettings
->xSettings
.set( static_cast< OWeakObject
* >( new ConstItemContainer( aNewData
) ), UNO_QUERY
);
947 pDataSettings
->xSettings
= aNewData
;
949 pDataSettings
->bDefault
= false;
950 pDataSettings
->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
;
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 );
989 SolarMutexClearableGuard aGuard
;
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
)
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
;
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();
1046 SolarMutexClearableGuard aGuard
;
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
;
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
);
1073 pDataSettings
->xSettings
= aNewData
;
1077 UIElementType
& rElementType
= m_aUIElements
[nElementType
];
1078 rElementType
.bModified
= true;
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
;
1103 implts_notifyContainerListener( aEvent
, NotifyOp_Insert
);
1108 Reference
< XInterface
> SAL_CALL
UIConfigurationManager::getImageManager()
1111 throw DisposedException();
1113 if ( !m_xImageManager
.is() )
1115 m_xImageManager
.set( static_cast< cppu::OWeakObject
*>( new ImageManager( m_xContext
)),
1117 Reference
< XInitialization
> xInit( m_xImageManager
, UNO_QUERY
);
1119 Sequence
<Any
> aPropSeq(comphelper::InitAnyPropertySequence(
1121 {"UserConfigStorage", Any(m_xDocConfigStorage
)},
1122 {"ModuleIdentifier", Any(OUString())},
1125 xInit
->initialize( aPropSeq
);
1128 return Reference
< XInterface
>( m_xImageManager
, UNO_QUERY
);
1131 Reference
< XAcceleratorConfiguration
> SAL_CALL
UIConfigurationManager::getShortCutManager()
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
)
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
;
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() )
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
& )
1213 sal_Bool SAL_CALL
UIConfigurationManager::hasStorage()
1218 throw DisposedException();
1220 return m_xDocConfigStorage
.is();
1223 // XUIConfigurationPersistence
1224 void SAL_CALL
UIConfigurationManager::reload()
1226 SolarMutexClearableGuard aGuard
;
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
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()
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
)
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()
1335 sal_Bool SAL_CALL
UIConfigurationManager::isReadOnly()
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() )
1354 case NotifyOp_Replace
:
1355 static_cast< css::ui::XUIConfigurationListener
*>(pIterator
.next())->elementReplaced( aEvent
);
1357 case NotifyOp_Insert
:
1358 static_cast< css::ui::XUIConfigurationListener
*>(pIterator
.next())->elementInserted( aEvent
);
1360 case NotifyOp_Remove
:
1361 static_cast< css::ui::XUIConfigurationListener
*>(pIterator
.next())->elementRemoved( aEvent
);
1365 catch( const css::uno::RuntimeException
& )
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: */