/src/libreoffice/framework/source/uiconfiguration/moduleuiconfigurationmanager.cxx
Line | Count | Source |
1 | | /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
2 | | /* |
3 | | * This file is part of the LibreOffice project. |
4 | | * |
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/. |
8 | | * |
9 | | * This file incorporates work covered by the following license notice: |
10 | | * |
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 . |
18 | | */ |
19 | | |
20 | | #include <accelerators/presethandler.hxx> |
21 | | #include <uiconfiguration/imagemanager.hxx> |
22 | | #include <uielement/constitemcontainer.hxx> |
23 | | #include <uielement/rootitemcontainer.hxx> |
24 | | #include <uielement/uielementtypenames.hxx> |
25 | | #include <menuconfiguration.hxx> |
26 | | #include <toolboxconfiguration.hxx> |
27 | | |
28 | | #include <statusbarconfiguration.hxx> |
29 | | |
30 | | #include <com/sun/star/ui/UIElementType.hpp> |
31 | | #include <com/sun/star/ui/ConfigurationEvent.hpp> |
32 | | #include <com/sun/star/ui/ModuleAcceleratorConfiguration.hpp> |
33 | | #include <com/sun/star/ui/XModuleUIConfigurationManager2.hpp> |
34 | | #include <com/sun/star/lang/DisposedException.hpp> |
35 | | #include <com/sun/star/lang/IllegalAccessException.hpp> |
36 | | #include <com/sun/star/lang/WrappedTargetRuntimeException.hpp> |
37 | | #include <com/sun/star/beans/XPropertySet.hpp> |
38 | | #include <com/sun/star/embed/ElementModes.hpp> |
39 | | #include <com/sun/star/embed/InvalidStorageException.hpp> |
40 | | #include <com/sun/star/embed/StorageWrappedTargetException.hpp> |
41 | | #include <com/sun/star/embed/XTransactedObject.hpp> |
42 | | #include <com/sun/star/container/ElementExistException.hpp> |
43 | | #include <com/sun/star/container/XNameAccess.hpp> |
44 | | #include <com/sun/star/container/XIndexContainer.hpp> |
45 | | #include <com/sun/star/io/IOException.hpp> |
46 | | #include <com/sun/star/io/XStream.hpp> |
47 | | #include <com/sun/star/lang/XServiceInfo.hpp> |
48 | | #include <com/sun/star/lang/XComponent.hpp> |
49 | | |
50 | | #include <comphelper/propertysequence.hxx> |
51 | | #include <comphelper/sequence.hxx> |
52 | | #include <cppuhelper/exc_hlp.hxx> |
53 | | #include <cppuhelper/implbase.hxx> |
54 | | #include <cppuhelper/supportsservice.hxx> |
55 | | #include <utility> |
56 | | #include <vcl/svapp.hxx> |
57 | | #include <sal/log.hxx> |
58 | | #include <comphelper/interfacecontainer4.hxx> |
59 | | #include <comphelper/propertyvalue.hxx> |
60 | | #include <comphelper/sequenceashashmap.hxx> |
61 | | #include <comphelper/servicehelper.hxx> |
62 | | #include <o3tl/string_view.hxx> |
63 | | #include <memory> |
64 | | #include <mutex> |
65 | | #include <string_view> |
66 | | |
67 | | using namespace css; |
68 | | using namespace com::sun::star::uno; |
69 | | using namespace com::sun::star::io; |
70 | | using namespace com::sun::star::embed; |
71 | | using namespace com::sun::star::lang; |
72 | | using namespace com::sun::star::container; |
73 | | using namespace com::sun::star::beans; |
74 | | using namespace framework; |
75 | | |
76 | | constexpr OUStringLiteral RESOURCETYPE_MENUBAR = u"menubar"; |
77 | | constexpr OUStringLiteral RESOURCETYPE_TOOLBAR = u"toolbar"; |
78 | | constexpr OUStringLiteral RESOURCETYPE_STATUSBAR = u"statusbar"; |
79 | | constexpr OUStringLiteral RESOURCETYPE_POPUPMENU = u"popupmenu"; |
80 | | |
81 | | namespace { |
82 | | |
83 | | class ModuleUIConfigurationManager : public cppu::WeakImplHelper< |
84 | | css::lang::XServiceInfo, |
85 | | css::lang::XComponent, |
86 | | css::ui::XModuleUIConfigurationManager2 > |
87 | | { |
88 | | public: |
89 | | ModuleUIConfigurationManager( |
90 | | const css::uno::Reference< css::uno::XComponentContext >& xServiceManager, |
91 | | const css::uno::Sequence< css::uno::Any >& aArguments); |
92 | | |
93 | | virtual OUString SAL_CALL getImplementationName() override |
94 | 0 | { |
95 | 0 | return u"com.sun.star.comp.framework.ModuleUIConfigurationManager"_ustr; |
96 | 0 | } |
97 | | |
98 | | virtual sal_Bool SAL_CALL supportsService(OUString const & ServiceName) override |
99 | 0 | { |
100 | 0 | return cppu::supportsService(this, ServiceName); |
101 | 0 | } |
102 | | |
103 | | virtual css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override |
104 | 0 | { |
105 | 0 | return {u"com.sun.star.ui.ModuleUIConfigurationManager"_ustr}; |
106 | 0 | } |
107 | | |
108 | | // XComponent |
109 | | virtual void SAL_CALL dispose() override; |
110 | | virtual void SAL_CALL addEventListener( const css::uno::Reference< css::lang::XEventListener >& xListener ) override; |
111 | | virtual void SAL_CALL removeEventListener( const css::uno::Reference< css::lang::XEventListener >& aListener ) override; |
112 | | |
113 | | // XUIConfiguration |
114 | | virtual void SAL_CALL addConfigurationListener( const css::uno::Reference< css::ui::XUIConfigurationListener >& Listener ) override; |
115 | | virtual void SAL_CALL removeConfigurationListener( const css::uno::Reference< css::ui::XUIConfigurationListener >& Listener ) override; |
116 | | |
117 | | // XUIConfigurationManager |
118 | | virtual void SAL_CALL reset() override; |
119 | | virtual css::uno::Sequence< css::uno::Sequence< css::beans::PropertyValue > > SAL_CALL getUIElementsInfo( sal_Int16 ElementType ) override; |
120 | | virtual css::uno::Reference< css::container::XIndexContainer > SAL_CALL createSettings( ) override; |
121 | | virtual sal_Bool SAL_CALL hasSettings( const OUString& ResourceURL ) override; |
122 | | virtual css::uno::Reference< css::container::XIndexAccess > SAL_CALL getSettings( const OUString& ResourceURL, sal_Bool bWriteable ) override; |
123 | | virtual void SAL_CALL replaceSettings( const OUString& ResourceURL, const css::uno::Reference< css::container::XIndexAccess >& aNewData ) override; |
124 | | virtual void SAL_CALL removeSettings( const OUString& ResourceURL ) override; |
125 | | virtual void SAL_CALL insertSettings( const OUString& NewResourceURL, const css::uno::Reference< css::container::XIndexAccess >& aNewData ) override; |
126 | | virtual css::uno::Reference< css::uno::XInterface > SAL_CALL getImageManager() override; |
127 | | virtual css::uno::Reference< css::ui::XAcceleratorConfiguration > SAL_CALL getShortCutManager() override; |
128 | | virtual css::uno::Reference< css::ui::XAcceleratorConfiguration > SAL_CALL createShortCutManager() override; |
129 | | virtual css::uno::Reference< css::uno::XInterface > SAL_CALL getEventsManager() override; |
130 | | |
131 | | // XModuleUIConfigurationManager |
132 | | virtual sal_Bool SAL_CALL isDefaultSettings( const OUString& ResourceURL ) override; |
133 | | virtual css::uno::Reference< css::container::XIndexAccess > SAL_CALL getDefaultSettings( const OUString& ResourceURL ) override; |
134 | | |
135 | | // XUIConfigurationPersistence |
136 | | virtual void SAL_CALL reload() override; |
137 | | virtual void SAL_CALL store() override; |
138 | | virtual void SAL_CALL storeToStorage( const css::uno::Reference< css::embed::XStorage >& Storage ) override; |
139 | | virtual sal_Bool SAL_CALL isModified() override; |
140 | | virtual sal_Bool SAL_CALL isReadOnly() override; |
141 | | |
142 | | private: |
143 | | // private data types |
144 | | enum Layer |
145 | | { |
146 | | LAYER_DEFAULT, |
147 | | LAYER_USERDEFINED, |
148 | | LAYER_COUNT |
149 | | }; |
150 | | |
151 | | enum NotifyOp |
152 | | { |
153 | | NotifyOp_Remove, |
154 | | NotifyOp_Insert, |
155 | | NotifyOp_Replace |
156 | | }; |
157 | | |
158 | | struct UIElementInfo |
159 | | { |
160 | | UIElementInfo( OUString _aResourceURL, OUString _aUIName ) : |
161 | 0 | aResourceURL(std::move( _aResourceURL)), aUIName(std::move( _aUIName )) {} |
162 | | OUString aResourceURL; |
163 | | OUString aUIName; |
164 | | }; |
165 | | |
166 | | struct UIElementData |
167 | | { |
168 | 0 | UIElementData() : bModified( false ), bDefault( true ), bDefaultNode( true ) {}; |
169 | | |
170 | | OUString aResourceURL; |
171 | | OUString aName; |
172 | | bool bModified; // has been changed since last storing |
173 | | bool bDefault; // default settings |
174 | | bool bDefaultNode; // this is a default layer element data |
175 | | css::uno::Reference< css::container::XIndexAccess > xSettings; |
176 | | }; |
177 | | |
178 | | typedef std::unordered_map< OUString, UIElementData > UIElementDataHashMap; |
179 | | |
180 | | struct UIElementType |
181 | | { |
182 | 0 | UIElementType() : bModified( false ), |
183 | 0 | bLoaded( false ), |
184 | 0 | nElementType( css::ui::UIElementType::UNKNOWN ) {} |
185 | | |
186 | | bool bModified; |
187 | | bool bLoaded; |
188 | | sal_Int16 nElementType; |
189 | | UIElementDataHashMap aElementsHashMap; |
190 | | css::uno::Reference< css::embed::XStorage > xStorage; |
191 | | }; |
192 | | |
193 | | typedef std::vector< UIElementType > UIElementTypesVector; |
194 | | typedef std::vector< css::ui::ConfigurationEvent > ConfigEventNotifyContainer; |
195 | | typedef std::unordered_map< OUString, UIElementInfo > UIElementInfoHashMap; |
196 | | |
197 | | void impl_Initialize(); |
198 | | void implts_notifyContainerListener( const css::ui::ConfigurationEvent& aEvent, NotifyOp eOp ); |
199 | | void impl_fillSequenceWithElementTypeInfo( UIElementInfoHashMap& aUIElementInfoCollection, sal_Int16 nElementType ); |
200 | | void impl_preloadUIElementTypeList( Layer eLayer, sal_Int16 nElementType ); |
201 | | UIElementData* impl_findUIElementData( const OUString& aResourceURL, sal_Int16 nElementType, bool bLoad = true ); |
202 | | void impl_requestUIElementData( sal_Int16 nElementType, Layer eLayer, UIElementData& aUIElementData ); |
203 | | void impl_storeElementTypeData( const css::uno::Reference< css::embed::XStorage >& xStorage, UIElementType& rElementType, bool bResetModifyState = true ); |
204 | | void impl_resetElementTypeData( UIElementType& rUserElementType, UIElementType const & rDefaultElementType, ConfigEventNotifyContainer& rRemoveNotifyContainer, ConfigEventNotifyContainer& rReplaceNotifyContainer ); |
205 | | void impl_reloadElementTypeData( UIElementType& rUserElementType, UIElementType const & rDefaultElementType, ConfigEventNotifyContainer& rRemoveNotifyContainer, ConfigEventNotifyContainer& rReplaceNotifyContainer ); |
206 | | |
207 | | UIElementTypesVector m_aUIElements[LAYER_COUNT]; |
208 | | std::unique_ptr<PresetHandler> m_pStorageHandler[css::ui::UIElementType::COUNT]; |
209 | | css::uno::Reference< css::embed::XStorage > m_xDefaultConfigStorage; |
210 | | css::uno::Reference< css::embed::XStorage > m_xUserConfigStorage; |
211 | | bool m_bReadOnly; |
212 | | bool m_bModified; |
213 | | bool m_bDisposed; |
214 | | OUString m_aXMLPostfix; |
215 | | OUString m_aPropUIName; |
216 | | OUString m_aModuleIdentifier; |
217 | | css::uno::Reference< css::embed::XTransactedObject > m_xUserRootCommit; |
218 | | css::uno::Reference< css::uno::XComponentContext > m_xContext; |
219 | | std::mutex m_mutex; |
220 | | comphelper::OInterfaceContainerHelper4<css::lang::XEventListener> m_aEventListeners; |
221 | | comphelper::OInterfaceContainerHelper4<css::ui::XUIConfigurationListener> m_aConfigListeners; |
222 | | rtl::Reference< ImageManager > m_xModuleImageManager; |
223 | | css::uno::Reference< css::ui::XAcceleratorConfiguration > m_xModuleAcceleratorManager; |
224 | | }; |
225 | | |
226 | | // important: The order and position of the elements must match the constant |
227 | | // definition of "css::ui::UIElementType" |
228 | | constexpr std::u16string_view UIELEMENTTYPENAMES[] = |
229 | | { |
230 | | u"", // Dummy value for unknown! |
231 | | u"" UIELEMENTTYPE_MENUBAR_NAME, |
232 | | u"" UIELEMENTTYPE_POPUPMENU_NAME, |
233 | | u"" UIELEMENTTYPE_TOOLBAR_NAME, |
234 | | u"" UIELEMENTTYPE_STATUSBAR_NAME, |
235 | | u"" UIELEMENTTYPE_FLOATINGWINDOW_NAME, |
236 | | u"" UIELEMENTTYPE_PROGRESSBAR_NAME, |
237 | | u"" UIELEMENTTYPE_TOOLPANEL_NAME |
238 | | }; |
239 | | |
240 | | constexpr std::u16string_view RESOURCEURL_PREFIX = u"private:resource/"; |
241 | | |
242 | | sal_Int16 RetrieveTypeFromResourceURL( std::u16string_view aResourceURL ) |
243 | 0 | { |
244 | |
|
245 | 0 | if (( o3tl::starts_with(aResourceURL, RESOURCEURL_PREFIX ) ) && |
246 | 0 | ( aResourceURL.size() > RESOURCEURL_PREFIX.size() )) |
247 | 0 | { |
248 | 0 | std::u16string_view aTmpStr = aResourceURL.substr( RESOURCEURL_PREFIX.size() ); |
249 | 0 | size_t nIndex = aTmpStr.find( '/' ); |
250 | 0 | if (( nIndex > 0 ) && ( aTmpStr.size() > nIndex )) |
251 | 0 | { |
252 | 0 | std::u16string_view aTypeStr( aTmpStr.substr( 0, nIndex )); |
253 | 0 | for ( int i = 0; i < ui::UIElementType::COUNT; i++ ) |
254 | 0 | { |
255 | 0 | if ( aTypeStr == UIELEMENTTYPENAMES[i] ) |
256 | 0 | return sal_Int16( i ); |
257 | 0 | } |
258 | 0 | } |
259 | 0 | } |
260 | | |
261 | 0 | return ui::UIElementType::UNKNOWN; |
262 | 0 | } |
263 | | |
264 | | OUString RetrieveNameFromResourceURL( std::u16string_view aResourceURL ) |
265 | 0 | { |
266 | 0 | if (( o3tl::starts_with(aResourceURL, RESOURCEURL_PREFIX ) ) && |
267 | 0 | ( aResourceURL.size() > RESOURCEURL_PREFIX.size() )) |
268 | 0 | { |
269 | 0 | size_t nIndex = aResourceURL.rfind( '/' ); |
270 | |
|
271 | 0 | if ( nIndex > 0 && nIndex != std::u16string_view::npos && (( nIndex+1 ) < aResourceURL.size()) ) |
272 | 0 | return OUString(aResourceURL.substr( nIndex+1 )); |
273 | 0 | } |
274 | | |
275 | 0 | return OUString(); |
276 | 0 | } |
277 | | |
278 | | void ModuleUIConfigurationManager::impl_fillSequenceWithElementTypeInfo( UIElementInfoHashMap& aUIElementInfoCollection, sal_Int16 nElementType ) |
279 | 0 | { |
280 | | // preload list of element types on demand |
281 | 0 | impl_preloadUIElementTypeList( LAYER_USERDEFINED, nElementType ); |
282 | 0 | impl_preloadUIElementTypeList( LAYER_DEFAULT, nElementType ); |
283 | |
|
284 | 0 | UIElementDataHashMap& rUserElements = m_aUIElements[LAYER_USERDEFINED][nElementType].aElementsHashMap; |
285 | |
|
286 | 0 | OUString aCustomUrlPrefix( u"custom_"_ustr ); |
287 | 0 | for (auto const& userElement : rUserElements) |
288 | 0 | { |
289 | 0 | sal_Int32 nIndex = userElement.second.aResourceURL.indexOf( aCustomUrlPrefix, RESOURCEURL_PREFIX.size() ); |
290 | 0 | if ( nIndex > static_cast<sal_Int32>(RESOURCEURL_PREFIX.size()) ) |
291 | 0 | { |
292 | | // Performance: Retrieve user interface name only for custom user interface elements. |
293 | | // It's only used by them! |
294 | 0 | UIElementData* pDataSettings = impl_findUIElementData( userElement.second.aResourceURL, nElementType ); |
295 | 0 | if ( pDataSettings ) |
296 | 0 | { |
297 | | // Retrieve user interface name from XPropertySet interface |
298 | 0 | OUString aUIName; |
299 | 0 | Reference< XPropertySet > xPropSet( pDataSettings->xSettings, UNO_QUERY ); |
300 | 0 | if ( xPropSet.is() ) |
301 | 0 | { |
302 | 0 | Any a = xPropSet->getPropertyValue( m_aPropUIName ); |
303 | 0 | a >>= aUIName; |
304 | 0 | } |
305 | |
|
306 | 0 | UIElementInfo aInfo( userElement.second.aResourceURL, aUIName ); |
307 | 0 | aUIElementInfoCollection.emplace( userElement.second.aResourceURL, aInfo ); |
308 | 0 | } |
309 | 0 | } |
310 | 0 | else |
311 | 0 | { |
312 | | // The user interface name for standard user interface elements is stored in the WindowState.xcu file |
313 | 0 | UIElementInfo aInfo( userElement.second.aResourceURL, OUString() ); |
314 | 0 | aUIElementInfoCollection.emplace( userElement.second.aResourceURL, aInfo ); |
315 | 0 | } |
316 | 0 | } |
317 | |
|
318 | 0 | UIElementDataHashMap& rDefaultElements = m_aUIElements[LAYER_DEFAULT][nElementType].aElementsHashMap; |
319 | |
|
320 | 0 | for (auto const& defaultElement : rDefaultElements) |
321 | 0 | { |
322 | 0 | UIElementInfoHashMap::const_iterator pIterInfo = aUIElementInfoCollection.find( defaultElement.second.aResourceURL ); |
323 | 0 | if ( pIterInfo == aUIElementInfoCollection.end() ) |
324 | 0 | { |
325 | 0 | sal_Int32 nIndex = defaultElement.second.aResourceURL.indexOf( aCustomUrlPrefix, RESOURCEURL_PREFIX.size() ); |
326 | 0 | if ( nIndex > static_cast<sal_Int32>(RESOURCEURL_PREFIX.size()) ) |
327 | 0 | { |
328 | | // Performance: Retrieve user interface name only for custom user interface elements. |
329 | | // It's only used by them! |
330 | 0 | UIElementData* pDataSettings = impl_findUIElementData( defaultElement.second.aResourceURL, nElementType ); |
331 | 0 | if ( pDataSettings ) |
332 | 0 | { |
333 | | // Retrieve user interface name from XPropertySet interface |
334 | 0 | OUString aUIName; |
335 | 0 | Reference< XPropertySet > xPropSet( pDataSettings->xSettings, UNO_QUERY ); |
336 | 0 | if ( xPropSet.is() ) |
337 | 0 | { |
338 | 0 | Any a = xPropSet->getPropertyValue( m_aPropUIName ); |
339 | 0 | a >>= aUIName; |
340 | 0 | } |
341 | 0 | UIElementInfo aInfo( defaultElement.second.aResourceURL, aUIName ); |
342 | 0 | aUIElementInfoCollection.emplace( defaultElement.second.aResourceURL, aInfo ); |
343 | 0 | } |
344 | 0 | } |
345 | 0 | else |
346 | 0 | { |
347 | | // The user interface name for standard user interface elements is stored in the WindowState.xcu file |
348 | 0 | UIElementInfo aInfo( defaultElement.second.aResourceURL, OUString() ); |
349 | 0 | aUIElementInfoCollection.emplace( defaultElement.second.aResourceURL, aInfo ); |
350 | 0 | } |
351 | 0 | } |
352 | 0 | } |
353 | 0 | } |
354 | | |
355 | | void ModuleUIConfigurationManager::impl_preloadUIElementTypeList( Layer eLayer, sal_Int16 nElementType ) |
356 | 0 | { |
357 | 0 | UIElementType& rElementTypeData = m_aUIElements[eLayer][nElementType]; |
358 | |
|
359 | 0 | if ( rElementTypeData.bLoaded ) |
360 | 0 | return; |
361 | | |
362 | 0 | Reference< XStorage > xElementTypeStorage = rElementTypeData.xStorage; |
363 | 0 | if ( !xElementTypeStorage.is() ) |
364 | 0 | return; |
365 | | |
366 | 0 | OUString aResURLPrefix = |
367 | 0 | OUString::Concat(RESOURCEURL_PREFIX) + |
368 | 0 | UIELEMENTTYPENAMES[ nElementType ] + |
369 | 0 | "/"; |
370 | |
|
371 | 0 | UIElementDataHashMap& rHashMap = rElementTypeData.aElementsHashMap; |
372 | 0 | const Sequence< OUString > aUIElementNames = xElementTypeStorage->getElementNames(); |
373 | 0 | for ( OUString const & rElementName : aUIElementNames ) |
374 | 0 | { |
375 | 0 | UIElementData aUIElementData; |
376 | | |
377 | | // Resource name must be without ".xml" |
378 | 0 | sal_Int32 nIndex = rElementName.lastIndexOf( '.' ); |
379 | 0 | if (( nIndex > 0 ) && ( nIndex < rElementName.getLength() )) |
380 | 0 | { |
381 | 0 | std::u16string_view aExtension( rElementName.subView( nIndex+1 )); |
382 | 0 | std::u16string_view aUIElementName( rElementName.subView( 0, nIndex )); |
383 | |
|
384 | 0 | if (!aUIElementName.empty() && |
385 | 0 | ( o3tl::equalsIgnoreAsciiCase(aExtension, u"xml"))) |
386 | 0 | { |
387 | 0 | aUIElementData.aResourceURL = aResURLPrefix + aUIElementName; |
388 | 0 | aUIElementData.aName = rElementName; |
389 | |
|
390 | 0 | if ( eLayer == LAYER_USERDEFINED ) |
391 | 0 | { |
392 | 0 | aUIElementData.bModified = false; |
393 | 0 | aUIElementData.bDefault = false; |
394 | 0 | aUIElementData.bDefaultNode = false; |
395 | 0 | } |
396 | | |
397 | | // Create std::unordered_map entries for all user interface elements inside the storage. We don't load the |
398 | | // settings to speed up the process. |
399 | 0 | rHashMap.emplace( aUIElementData.aResourceURL, aUIElementData ); |
400 | 0 | } |
401 | 0 | } |
402 | 0 | rElementTypeData.bLoaded = true; |
403 | 0 | } |
404 | |
|
405 | 0 | } |
406 | | |
407 | | void ModuleUIConfigurationManager::impl_requestUIElementData( sal_Int16 nElementType, Layer eLayer, UIElementData& aUIElementData ) |
408 | 0 | { |
409 | 0 | UIElementType& rElementTypeData = m_aUIElements[eLayer][nElementType]; |
410 | |
|
411 | 0 | Reference< XStorage > xElementTypeStorage = rElementTypeData.xStorage; |
412 | 0 | if ( xElementTypeStorage.is() && !aUIElementData.aName.isEmpty() ) |
413 | 0 | { |
414 | 0 | try |
415 | 0 | { |
416 | 0 | Reference< XStream > xStream = xElementTypeStorage->openStreamElement( aUIElementData.aName, ElementModes::READ ); |
417 | 0 | Reference< XInputStream > xInputStream = xStream->getInputStream(); |
418 | |
|
419 | 0 | if ( xInputStream.is() ) |
420 | 0 | { |
421 | 0 | switch ( nElementType ) |
422 | 0 | { |
423 | 0 | case css::ui::UIElementType::UNKNOWN: |
424 | 0 | break; |
425 | | |
426 | 0 | case css::ui::UIElementType::MENUBAR: |
427 | 0 | case css::ui::UIElementType::POPUPMENU: |
428 | 0 | { |
429 | 0 | try |
430 | 0 | { |
431 | 0 | MenuConfiguration aMenuCfg( m_xContext ); |
432 | 0 | Reference< XIndexAccess > xContainer( aMenuCfg.CreateMenuBarConfigurationFromXML( xInputStream )); |
433 | 0 | auto pRootItemContainer = dynamic_cast<RootItemContainer*>( xContainer.get() ); |
434 | 0 | if ( pRootItemContainer ) |
435 | 0 | aUIElementData.xSettings = new ConstItemContainer( pRootItemContainer, true ); |
436 | 0 | else |
437 | 0 | aUIElementData.xSettings = new ConstItemContainer( xContainer, true ); |
438 | 0 | return; |
439 | 0 | } |
440 | 0 | catch ( const css::lang::WrappedTargetException& ) |
441 | 0 | { |
442 | 0 | } |
443 | 0 | } |
444 | 0 | break; |
445 | | |
446 | 0 | case css::ui::UIElementType::TOOLBAR: |
447 | 0 | { |
448 | 0 | try |
449 | 0 | { |
450 | 0 | Reference< XIndexContainer > xIndexContainer( new RootItemContainer() ); |
451 | 0 | ToolBoxConfiguration::LoadToolBox( m_xContext, xInputStream, xIndexContainer ); |
452 | 0 | auto pRootItemContainer = dynamic_cast<RootItemContainer*>( xIndexContainer.get() ); |
453 | 0 | aUIElementData.xSettings = new ConstItemContainer( pRootItemContainer, true ); |
454 | 0 | return; |
455 | 0 | } |
456 | 0 | catch ( const css::lang::WrappedTargetException& ) |
457 | 0 | { |
458 | 0 | } |
459 | | |
460 | 0 | break; |
461 | 0 | } |
462 | | |
463 | 0 | case css::ui::UIElementType::STATUSBAR: |
464 | 0 | { |
465 | 0 | try |
466 | 0 | { |
467 | 0 | Reference< XIndexContainer > xIndexContainer( new RootItemContainer() ); |
468 | 0 | StatusBarConfiguration::LoadStatusBar( m_xContext, xInputStream, xIndexContainer ); |
469 | 0 | auto pRootItemContainer = dynamic_cast<RootItemContainer*>( xIndexContainer.get() ); |
470 | 0 | aUIElementData.xSettings = new ConstItemContainer( pRootItemContainer, true ); |
471 | 0 | return; |
472 | 0 | } |
473 | 0 | catch ( const css::lang::WrappedTargetException& ) |
474 | 0 | { |
475 | 0 | } |
476 | | |
477 | 0 | break; |
478 | 0 | } |
479 | | |
480 | 0 | case css::ui::UIElementType::FLOATINGWINDOW: |
481 | 0 | { |
482 | 0 | break; |
483 | 0 | } |
484 | 0 | } |
485 | 0 | } |
486 | 0 | } |
487 | 0 | catch ( const css::embed::InvalidStorageException& ) |
488 | 0 | { |
489 | 0 | } |
490 | 0 | catch ( const css::lang::IllegalArgumentException& ) |
491 | 0 | { |
492 | 0 | } |
493 | 0 | catch ( const css::io::IOException& ) |
494 | 0 | { |
495 | 0 | } |
496 | 0 | catch ( const css::embed::StorageWrappedTargetException& ) |
497 | 0 | { |
498 | 0 | } |
499 | 0 | } |
500 | | |
501 | | // At least we provide an empty settings container! |
502 | 0 | aUIElementData.xSettings = new ConstItemContainer(); |
503 | 0 | } |
504 | | |
505 | | ModuleUIConfigurationManager::UIElementData* ModuleUIConfigurationManager::impl_findUIElementData( const OUString& aResourceURL, sal_Int16 nElementType, bool bLoad ) |
506 | 0 | { |
507 | | // preload list of element types on demand |
508 | 0 | impl_preloadUIElementTypeList( LAYER_USERDEFINED, nElementType ); |
509 | 0 | impl_preloadUIElementTypeList( LAYER_DEFAULT, nElementType ); |
510 | | |
511 | | // first try to look into our user-defined vector/unordered_map combination |
512 | 0 | UIElementDataHashMap& rUserHashMap = m_aUIElements[LAYER_USERDEFINED][nElementType].aElementsHashMap; |
513 | 0 | UIElementDataHashMap::iterator pIter = rUserHashMap.find( aResourceURL ); |
514 | 0 | if ( pIter != rUserHashMap.end() ) |
515 | 0 | { |
516 | | // Default data settings data must be retrieved from the default layer! |
517 | 0 | if ( !pIter->second.bDefault ) |
518 | 0 | { |
519 | 0 | if ( !pIter->second.xSettings.is() && bLoad ) |
520 | 0 | impl_requestUIElementData( nElementType, LAYER_USERDEFINED, pIter->second ); |
521 | 0 | return &(pIter->second); |
522 | 0 | } |
523 | 0 | } |
524 | | |
525 | | // Not successful, we have to look into our default vector/unordered_map combination |
526 | 0 | UIElementDataHashMap& rDefaultHashMap = m_aUIElements[LAYER_DEFAULT][nElementType].aElementsHashMap; |
527 | 0 | pIter = rDefaultHashMap.find( aResourceURL ); |
528 | 0 | if ( pIter != rDefaultHashMap.end() ) |
529 | 0 | { |
530 | 0 | if ( !pIter->second.xSettings.is() && bLoad ) |
531 | 0 | impl_requestUIElementData( nElementType, LAYER_DEFAULT, pIter->second ); |
532 | 0 | return &(pIter->second); |
533 | 0 | } |
534 | | |
535 | | // Nothing has been found! |
536 | 0 | return nullptr; |
537 | 0 | } |
538 | | |
539 | | void ModuleUIConfigurationManager::impl_storeElementTypeData( const Reference< XStorage >& xStorage, UIElementType& rElementType, bool bResetModifyState ) |
540 | 0 | { |
541 | 0 | UIElementDataHashMap& rHashMap = rElementType.aElementsHashMap; |
542 | |
|
543 | 0 | for (auto & elem : rHashMap) |
544 | 0 | { |
545 | 0 | UIElementData& rElement = elem.second; |
546 | 0 | if ( rElement.bModified ) |
547 | 0 | { |
548 | 0 | if ( rElement.bDefault ) |
549 | 0 | { |
550 | 0 | xStorage->removeElement( rElement.aName ); |
551 | 0 | rElement.bModified = false; // mark as not modified |
552 | 0 | } |
553 | 0 | else |
554 | 0 | { |
555 | 0 | Reference< XStream > xStream = xStorage->openStreamElement( rElement.aName, ElementModes::WRITE|ElementModes::TRUNCATE ); |
556 | 0 | Reference< XOutputStream > xOutputStream( xStream->getOutputStream() ); |
557 | |
|
558 | 0 | if ( xOutputStream.is() ) |
559 | 0 | { |
560 | 0 | switch( rElementType.nElementType ) |
561 | 0 | { |
562 | 0 | case css::ui::UIElementType::MENUBAR: |
563 | 0 | case css::ui::UIElementType::POPUPMENU: |
564 | 0 | { |
565 | 0 | try |
566 | 0 | { |
567 | 0 | MenuConfiguration aMenuCfg( m_xContext ); |
568 | 0 | aMenuCfg.StoreMenuBarConfigurationToXML( |
569 | 0 | rElement.xSettings, xOutputStream, rElementType.nElementType == css::ui::UIElementType::MENUBAR ); |
570 | 0 | } |
571 | 0 | catch ( const css::lang::WrappedTargetException& ) |
572 | 0 | { |
573 | 0 | } |
574 | 0 | } |
575 | 0 | break; |
576 | | |
577 | 0 | case css::ui::UIElementType::TOOLBAR: |
578 | 0 | { |
579 | 0 | try |
580 | 0 | { |
581 | 0 | ToolBoxConfiguration::StoreToolBox( m_xContext, xOutputStream, rElement.xSettings ); |
582 | 0 | } |
583 | 0 | catch ( const css::lang::WrappedTargetException& ) |
584 | 0 | { |
585 | 0 | } |
586 | 0 | } |
587 | 0 | break; |
588 | | |
589 | 0 | case css::ui::UIElementType::STATUSBAR: |
590 | 0 | { |
591 | 0 | try |
592 | 0 | { |
593 | 0 | StatusBarConfiguration::StoreStatusBar( m_xContext, xOutputStream, rElement.xSettings ); |
594 | 0 | } |
595 | 0 | catch ( const css::lang::WrappedTargetException& ) |
596 | 0 | { |
597 | 0 | } |
598 | 0 | } |
599 | 0 | break; |
600 | | |
601 | 0 | default: |
602 | 0 | break; |
603 | 0 | } |
604 | 0 | } |
605 | | |
606 | | // mark as not modified if we store to our own storage |
607 | 0 | if ( bResetModifyState ) |
608 | 0 | rElement.bModified = false; |
609 | 0 | } |
610 | 0 | } |
611 | 0 | } |
612 | | |
613 | | // commit element type storage |
614 | 0 | Reference< XTransactedObject > xTransactedObject( xStorage, UNO_QUERY ); |
615 | 0 | if ( xTransactedObject.is() ) |
616 | 0 | xTransactedObject->commit(); |
617 | | |
618 | | // mark UIElementType as not modified if we store to our own storage |
619 | 0 | if ( bResetModifyState ) |
620 | 0 | rElementType.bModified = false; |
621 | 0 | } |
622 | | |
623 | | // This is only allowed to be called on the LAYER_USER_DEFINED! |
624 | | void ModuleUIConfigurationManager::impl_resetElementTypeData( |
625 | | UIElementType& rUserElementType, |
626 | | UIElementType const & rDefaultElementType, |
627 | | ConfigEventNotifyContainer& rRemoveNotifyContainer, |
628 | | ConfigEventNotifyContainer& rReplaceNotifyContainer ) |
629 | 0 | { |
630 | 0 | UIElementDataHashMap& rHashMap = rUserElementType.aElementsHashMap; |
631 | |
|
632 | 0 | Reference< XUIConfigurationManager > xThis(this); |
633 | 0 | Reference< XInterface > xIfac( xThis, UNO_QUERY ); |
634 | 0 | sal_Int16 nType = rUserElementType.nElementType; |
635 | | |
636 | | // Make copies of the event structures to be thread-safe. We have to unlock our mutex before calling |
637 | | // our listeners! |
638 | 0 | for (auto & elem : rHashMap) |
639 | 0 | { |
640 | 0 | UIElementData& rElement = elem.second; |
641 | 0 | if ( !rElement.bDefault ) |
642 | 0 | { |
643 | 0 | if ( rDefaultElementType.xStorage->hasByName( rElement.aName )) |
644 | 0 | { |
645 | | // Replace settings with data from default layer |
646 | 0 | Reference< XIndexAccess > xOldSettings( rElement.xSettings ); |
647 | 0 | impl_requestUIElementData( nType, LAYER_DEFAULT, rElement ); |
648 | |
|
649 | 0 | ui::ConfigurationEvent aReplaceEvent; |
650 | 0 | aReplaceEvent.ResourceURL = rElement.aResourceURL; |
651 | 0 | aReplaceEvent.Accessor <<= xThis; |
652 | 0 | aReplaceEvent.Source = xIfac; |
653 | 0 | aReplaceEvent.ReplacedElement <<= xOldSettings; |
654 | 0 | aReplaceEvent.Element <<= rElement.xSettings; |
655 | |
|
656 | 0 | rReplaceNotifyContainer.push_back( aReplaceEvent ); |
657 | | |
658 | | // Mark element as default and not modified. That means "not active" |
659 | | // in the user layer anymore. |
660 | 0 | rElement.bModified = false; |
661 | 0 | rElement.bDefault = true; |
662 | 0 | } |
663 | 0 | else |
664 | 0 | { |
665 | | // Remove user-defined settings from user layer |
666 | 0 | ui::ConfigurationEvent aEvent; |
667 | 0 | aEvent.ResourceURL = rElement.aResourceURL; |
668 | 0 | aEvent.Accessor <<= xThis; |
669 | 0 | aEvent.Source = xIfac; |
670 | 0 | aEvent.Element <<= rElement.xSettings; |
671 | |
|
672 | 0 | rRemoveNotifyContainer.push_back( aEvent ); |
673 | | |
674 | | // Mark element as default and not modified. That means "not active" |
675 | | // in the user layer anymore. |
676 | 0 | rElement.bModified = false; |
677 | 0 | rElement.bDefault = true; |
678 | 0 | } |
679 | 0 | } |
680 | 0 | } |
681 | | |
682 | | // Remove all settings from our user interface elements |
683 | 0 | rHashMap.clear(); |
684 | 0 | } |
685 | | |
686 | | void ModuleUIConfigurationManager::impl_reloadElementTypeData( |
687 | | UIElementType& rUserElementType, |
688 | | UIElementType const & rDefaultElementType, |
689 | | ConfigEventNotifyContainer& rRemoveNotifyContainer, |
690 | | ConfigEventNotifyContainer& rReplaceNotifyContainer ) |
691 | 0 | { |
692 | 0 | UIElementDataHashMap& rHashMap = rUserElementType.aElementsHashMap; |
693 | |
|
694 | 0 | Reference< XUIConfigurationManager > xThis(this); |
695 | 0 | Reference< XInterface > xIfac( xThis, UNO_QUERY ); |
696 | 0 | sal_Int16 nType = rUserElementType.nElementType; |
697 | |
|
698 | 0 | for (auto & elem : rHashMap) |
699 | 0 | { |
700 | 0 | UIElementData& rElement = elem.second; |
701 | 0 | if ( rElement.bModified ) |
702 | 0 | { |
703 | 0 | if ( rUserElementType.xStorage->hasByName( rElement.aName )) |
704 | 0 | { |
705 | | // Replace settings with data from user layer |
706 | 0 | Reference< XIndexAccess > xOldSettings( rElement.xSettings ); |
707 | |
|
708 | 0 | impl_requestUIElementData( nType, LAYER_USERDEFINED, rElement ); |
709 | |
|
710 | 0 | ui::ConfigurationEvent aReplaceEvent; |
711 | |
|
712 | 0 | aReplaceEvent.ResourceURL = rElement.aResourceURL; |
713 | 0 | aReplaceEvent.Accessor <<= xThis; |
714 | 0 | aReplaceEvent.Source = xIfac; |
715 | 0 | aReplaceEvent.ReplacedElement <<= xOldSettings; |
716 | 0 | aReplaceEvent.Element <<= rElement.xSettings; |
717 | 0 | rReplaceNotifyContainer.push_back( aReplaceEvent ); |
718 | |
|
719 | 0 | rElement.bModified = false; |
720 | 0 | } |
721 | 0 | else if ( rDefaultElementType.xStorage->hasByName( rElement.aName )) |
722 | 0 | { |
723 | | // Replace settings with data from default layer |
724 | 0 | Reference< XIndexAccess > xOldSettings( rElement.xSettings ); |
725 | |
|
726 | 0 | impl_requestUIElementData( nType, LAYER_DEFAULT, rElement ); |
727 | |
|
728 | 0 | ui::ConfigurationEvent aReplaceEvent; |
729 | |
|
730 | 0 | aReplaceEvent.ResourceURL = rElement.aResourceURL; |
731 | 0 | aReplaceEvent.Accessor <<= xThis; |
732 | 0 | aReplaceEvent.Source = xIfac; |
733 | 0 | aReplaceEvent.ReplacedElement <<= xOldSettings; |
734 | 0 | aReplaceEvent.Element <<= rElement.xSettings; |
735 | 0 | rReplaceNotifyContainer.push_back( aReplaceEvent ); |
736 | | |
737 | | // Mark element as default and not modified. That means "not active" |
738 | | // in the user layer anymore. |
739 | 0 | rElement.bModified = false; |
740 | 0 | rElement.bDefault = true; |
741 | 0 | } |
742 | 0 | else |
743 | 0 | { |
744 | | // Element settings are not in any storage => remove |
745 | 0 | ui::ConfigurationEvent aRemoveEvent; |
746 | |
|
747 | 0 | aRemoveEvent.ResourceURL = rElement.aResourceURL; |
748 | 0 | aRemoveEvent.Accessor <<= xThis; |
749 | 0 | aRemoveEvent.Source = xIfac; |
750 | 0 | aRemoveEvent.Element <<= rElement.xSettings; |
751 | |
|
752 | 0 | rRemoveNotifyContainer.push_back( aRemoveEvent ); |
753 | | |
754 | | // Mark element as default and not modified. That means "not active" |
755 | | // in the user layer anymore. |
756 | 0 | rElement.bModified = false; |
757 | 0 | rElement.bDefault = true; |
758 | 0 | } |
759 | 0 | } |
760 | 0 | } |
761 | |
|
762 | 0 | rUserElementType.bModified = false; |
763 | 0 | } |
764 | | |
765 | | void ModuleUIConfigurationManager::impl_Initialize() |
766 | 0 | { |
767 | | // Initialize the top-level structures with the storage data |
768 | 0 | if ( m_xUserConfigStorage.is() ) |
769 | 0 | { |
770 | | // Try to access our module sub folder |
771 | 0 | for ( sal_Int16 i = 1; i < css::ui::UIElementType::COUNT; |
772 | 0 | i++ ) |
773 | 0 | { |
774 | 0 | Reference< XStorage > xElementTypeStorage; |
775 | 0 | try |
776 | 0 | { |
777 | 0 | if ( m_pStorageHandler[i] ) |
778 | 0 | xElementTypeStorage = m_pStorageHandler[i]->getWorkingStorageUser(); |
779 | 0 | } |
780 | 0 | catch ( const css::container::NoSuchElementException& ) |
781 | 0 | { |
782 | 0 | } |
783 | 0 | catch ( const css::embed::InvalidStorageException& ) |
784 | 0 | { |
785 | 0 | } |
786 | 0 | catch ( const css::lang::IllegalArgumentException& ) |
787 | 0 | { |
788 | 0 | } |
789 | 0 | catch ( const css::io::IOException& ) |
790 | 0 | { |
791 | 0 | } |
792 | 0 | catch ( const css::embed::StorageWrappedTargetException& ) |
793 | 0 | { |
794 | 0 | } |
795 | |
|
796 | 0 | m_aUIElements[LAYER_USERDEFINED][i].nElementType = i; |
797 | 0 | m_aUIElements[LAYER_USERDEFINED][i].bModified = false; |
798 | 0 | m_aUIElements[LAYER_USERDEFINED][i].xStorage = std::move(xElementTypeStorage); |
799 | 0 | } |
800 | 0 | } |
801 | |
|
802 | 0 | if ( !m_xDefaultConfigStorage.is() ) |
803 | 0 | return; |
804 | | |
805 | 0 | Reference< XNameAccess > xNameAccess( m_xDefaultConfigStorage, UNO_QUERY_THROW ); |
806 | | |
807 | | // Try to access our module sub folder |
808 | 0 | for ( sal_Int16 i = 1; i < css::ui::UIElementType::COUNT; |
809 | 0 | i++ ) |
810 | 0 | { |
811 | 0 | Reference< XStorage > xElementTypeStorage; |
812 | 0 | try |
813 | 0 | { |
814 | 0 | const OUString sName( UIELEMENTTYPENAMES[i] ); |
815 | 0 | if( xNameAccess->hasByName( sName ) ) |
816 | 0 | xNameAccess->getByName( sName ) >>= xElementTypeStorage; |
817 | 0 | } |
818 | 0 | catch ( const css::container::NoSuchElementException& ) |
819 | 0 | { |
820 | 0 | } |
821 | |
|
822 | 0 | m_aUIElements[LAYER_DEFAULT][i].nElementType = i; |
823 | 0 | m_aUIElements[LAYER_DEFAULT][i].bModified = false; |
824 | 0 | m_aUIElements[LAYER_DEFAULT][i].xStorage = std::move(xElementTypeStorage); |
825 | 0 | } |
826 | 0 | } |
827 | | |
828 | | ModuleUIConfigurationManager::ModuleUIConfigurationManager( |
829 | | const Reference< XComponentContext >& xContext, |
830 | | const css::uno::Sequence< css::uno::Any >& aArguments) |
831 | 0 | : m_bReadOnly( true ) |
832 | 0 | , m_bModified( false ) |
833 | 0 | , m_bDisposed( false ) |
834 | 0 | , m_aXMLPostfix( u".xml"_ustr ) |
835 | 0 | , m_aPropUIName( u"UIName"_ustr ) |
836 | 0 | , m_xContext( xContext ) |
837 | 0 | { |
838 | | // Make sure we have a default initialized entry for every layer and user interface element type! |
839 | | // The following code depends on this! |
840 | 0 | m_aUIElements[LAYER_DEFAULT].resize( css::ui::UIElementType::COUNT ); |
841 | 0 | m_aUIElements[LAYER_USERDEFINED].resize( css::ui::UIElementType::COUNT ); |
842 | |
|
843 | 0 | SolarMutexGuard g; |
844 | |
|
845 | 0 | OUString aModuleShortName; |
846 | 0 | if( aArguments.getLength() == 2 && (aArguments[0] >>= aModuleShortName) && (aArguments[1] >>= m_aModuleIdentifier)) |
847 | 0 | { |
848 | 0 | } |
849 | 0 | else |
850 | 0 | { |
851 | 0 | ::comphelper::SequenceAsHashMap lArgs(aArguments); |
852 | 0 | aModuleShortName = lArgs.getUnpackedValueOrDefault(u"ModuleShortName"_ustr, OUString()); |
853 | 0 | m_aModuleIdentifier = lArgs.getUnpackedValueOrDefault(u"ModuleIdentifier"_ustr, OUString()); |
854 | 0 | } |
855 | |
|
856 | 0 | for ( int i = 1; i < css::ui::UIElementType::COUNT; i++ ) |
857 | 0 | { |
858 | 0 | OUString aResourceType; |
859 | 0 | if ( i == css::ui::UIElementType::MENUBAR ) |
860 | 0 | aResourceType = RESOURCETYPE_MENUBAR; |
861 | 0 | else if ( i == css::ui::UIElementType::TOOLBAR ) |
862 | 0 | aResourceType = RESOURCETYPE_TOOLBAR; |
863 | 0 | else if ( i == css::ui::UIElementType::STATUSBAR ) |
864 | 0 | aResourceType = RESOURCETYPE_STATUSBAR; |
865 | 0 | else if ( i == css::ui::UIElementType::POPUPMENU ) |
866 | 0 | aResourceType = RESOURCETYPE_POPUPMENU; |
867 | |
|
868 | 0 | if ( !aResourceType.isEmpty() ) |
869 | 0 | { |
870 | 0 | m_pStorageHandler[i].reset( new PresetHandler( m_xContext ) ); |
871 | 0 | m_pStorageHandler[i]->connectToResource( PresetHandler::E_MODULES, |
872 | 0 | aResourceType, // this path won't be used later... see next lines! |
873 | 0 | aModuleShortName, |
874 | 0 | css::uno::Reference< css::embed::XStorage >()); // no document root used here! |
875 | 0 | } |
876 | 0 | } |
877 | | |
878 | | // initialize root storages for all resource types |
879 | 0 | m_xUserRootCommit.set( m_pStorageHandler[css::ui::UIElementType::MENUBAR]->getOrCreateRootStorageUser(), css::uno::UNO_QUERY); // can be empty |
880 | 0 | m_xDefaultConfigStorage = m_pStorageHandler[css::ui::UIElementType::MENUBAR]->getParentStorageShare(); |
881 | 0 | m_xUserConfigStorage = m_pStorageHandler[css::ui::UIElementType::MENUBAR]->getParentStorageUser(); |
882 | |
|
883 | 0 | if ( m_xUserConfigStorage.is() ) |
884 | 0 | { |
885 | 0 | Reference< XPropertySet > xPropSet( m_xUserConfigStorage, UNO_QUERY ); |
886 | 0 | if ( xPropSet.is() ) |
887 | 0 | { |
888 | 0 | tools::Long nOpenMode = 0; |
889 | 0 | Any a = xPropSet->getPropertyValue(u"OpenMode"_ustr); |
890 | 0 | if ( a >>= nOpenMode ) |
891 | 0 | m_bReadOnly = !( nOpenMode & ElementModes::WRITE ); |
892 | 0 | } |
893 | 0 | } |
894 | |
|
895 | 0 | impl_Initialize(); |
896 | 0 | } |
897 | | |
898 | | // XComponent |
899 | | void SAL_CALL ModuleUIConfigurationManager::dispose() |
900 | 0 | { |
901 | 0 | Reference< XComponent > xThis(this); |
902 | |
|
903 | 0 | css::lang::EventObject aEvent( xThis ); |
904 | 0 | { |
905 | 0 | std::unique_lock aGuard(m_mutex); |
906 | 0 | m_aEventListeners.disposeAndClear( aGuard, aEvent ); |
907 | 0 | } |
908 | 0 | { |
909 | 0 | std::unique_lock aGuard(m_mutex); |
910 | 0 | m_aConfigListeners.disposeAndClear( aGuard, aEvent ); |
911 | 0 | } |
912 | | |
913 | | /* SAFE AREA ----------------------------------------------------------------------------------------------- */ |
914 | 0 | SolarMutexClearableGuard aGuard; |
915 | 0 | rtl::Reference< ImageManager > xModuleImageManager = std::move( m_xModuleImageManager ); |
916 | 0 | m_xModuleAcceleratorManager.clear(); |
917 | 0 | m_aUIElements[LAYER_USERDEFINED].clear(); |
918 | 0 | m_aUIElements[LAYER_DEFAULT].clear(); |
919 | 0 | m_xDefaultConfigStorage.clear(); |
920 | 0 | m_xUserConfigStorage.clear(); |
921 | 0 | m_xUserRootCommit.clear(); |
922 | 0 | m_bModified = false; |
923 | 0 | m_bDisposed = true; |
924 | 0 | aGuard.clear(); |
925 | | /* SAFE AREA ----------------------------------------------------------------------------------------------- */ |
926 | |
|
927 | 0 | try |
928 | 0 | { |
929 | 0 | if ( xModuleImageManager.is() ) |
930 | 0 | xModuleImageManager->dispose(); |
931 | 0 | } |
932 | 0 | catch ( const Exception& ) |
933 | 0 | { |
934 | 0 | } |
935 | 0 | } |
936 | | |
937 | | void SAL_CALL ModuleUIConfigurationManager::addEventListener( const Reference< XEventListener >& xListener ) |
938 | 0 | { |
939 | 0 | { |
940 | 0 | SolarMutexGuard g; |
941 | | |
942 | | /* SAFE AREA ----------------------------------------------------------------------------------------------- */ |
943 | 0 | if ( m_bDisposed ) |
944 | 0 | throw DisposedException(); |
945 | 0 | } |
946 | | |
947 | 0 | std::unique_lock aGuard(m_mutex); |
948 | 0 | m_aEventListeners.addInterface( aGuard, xListener ); |
949 | 0 | } |
950 | | |
951 | | void SAL_CALL ModuleUIConfigurationManager::removeEventListener( const Reference< XEventListener >& xListener ) |
952 | 0 | { |
953 | | /* SAFE AREA ----------------------------------------------------------------------------------------------- */ |
954 | 0 | std::unique_lock aGuard(m_mutex); |
955 | 0 | m_aEventListeners.removeInterface( aGuard, xListener ); |
956 | 0 | } |
957 | | |
958 | | // XUIConfiguration |
959 | | void SAL_CALL ModuleUIConfigurationManager::addConfigurationListener( const Reference< css::ui::XUIConfigurationListener >& xListener ) |
960 | 0 | { |
961 | 0 | { |
962 | 0 | SolarMutexGuard g; |
963 | | |
964 | | /* SAFE AREA ----------------------------------------------------------------------------------------------- */ |
965 | 0 | if ( m_bDisposed ) |
966 | 0 | throw DisposedException(); |
967 | 0 | } |
968 | | |
969 | 0 | std::unique_lock aGuard(m_mutex); |
970 | 0 | m_aConfigListeners.addInterface( aGuard, xListener ); |
971 | 0 | } |
972 | | |
973 | | void SAL_CALL ModuleUIConfigurationManager::removeConfigurationListener( const Reference< css::ui::XUIConfigurationListener >& xListener ) |
974 | 0 | { |
975 | | /* SAFE AREA ----------------------------------------------------------------------------------------------- */ |
976 | 0 | std::unique_lock aGuard(m_mutex); |
977 | 0 | m_aConfigListeners.removeInterface( aGuard, xListener ); |
978 | 0 | } |
979 | | |
980 | | // XUIConfigurationManager |
981 | | void SAL_CALL ModuleUIConfigurationManager::reset() |
982 | 0 | { |
983 | 0 | SolarMutexClearableGuard aGuard; |
984 | | |
985 | | /* SAFE AREA ----------------------------------------------------------------------------------------------- */ |
986 | 0 | if ( m_bDisposed ) |
987 | 0 | throw DisposedException(); |
988 | | |
989 | 0 | if ( isReadOnly() ) |
990 | 0 | return; |
991 | | |
992 | | // Remove all elements from our user-defined storage! |
993 | 0 | try |
994 | 0 | { |
995 | 0 | for ( int i = 1; i < css::ui::UIElementType::COUNT; i++ ) |
996 | 0 | { |
997 | 0 | UIElementType& rElementType = m_aUIElements[LAYER_USERDEFINED][i]; |
998 | |
|
999 | 0 | if ( rElementType.xStorage.is() ) |
1000 | 0 | { |
1001 | 0 | bool bCommitSubStorage( false ); |
1002 | 0 | const Sequence< OUString > aUIElementStreamNames = rElementType.xStorage->getElementNames(); |
1003 | 0 | for ( OUString const & rName : aUIElementStreamNames ) |
1004 | 0 | { |
1005 | 0 | rElementType.xStorage->removeElement( rName ); |
1006 | 0 | bCommitSubStorage = true; |
1007 | 0 | } |
1008 | |
|
1009 | 0 | if ( bCommitSubStorage ) |
1010 | 0 | { |
1011 | 0 | Reference< XTransactedObject > xTransactedObject( rElementType.xStorage, UNO_QUERY ); |
1012 | 0 | if ( xTransactedObject.is() ) |
1013 | 0 | xTransactedObject->commit(); |
1014 | 0 | m_pStorageHandler[i]->commitUserChanges(); |
1015 | 0 | } |
1016 | 0 | } |
1017 | 0 | } |
1018 | | |
1019 | | // remove settings from user defined layer and notify listener about removed settings data! |
1020 | 0 | ConfigEventNotifyContainer aRemoveEventNotifyContainer; |
1021 | 0 | ConfigEventNotifyContainer aReplaceEventNotifyContainer; |
1022 | 0 | for ( sal_Int16 j = 1; j < css::ui::UIElementType::COUNT; j++ ) |
1023 | 0 | { |
1024 | 0 | try |
1025 | 0 | { |
1026 | 0 | UIElementType& rUserElementType = m_aUIElements[LAYER_USERDEFINED][j]; |
1027 | 0 | UIElementType& rDefaultElementType = m_aUIElements[LAYER_DEFAULT][j]; |
1028 | |
|
1029 | 0 | impl_resetElementTypeData( rUserElementType, rDefaultElementType, aRemoveEventNotifyContainer, aReplaceEventNotifyContainer ); |
1030 | 0 | rUserElementType.bModified = false; |
1031 | 0 | } |
1032 | 0 | catch (const Exception&) |
1033 | 0 | { |
1034 | 0 | css::uno::Any anyEx = cppu::getCaughtException(); |
1035 | 0 | throw css::lang::WrappedTargetRuntimeException( |
1036 | 0 | u"ModuleUIConfigurationManager::reset exception"_ustr, |
1037 | 0 | css::uno::Reference<css::uno::XInterface>(*this), anyEx); |
1038 | 0 | } |
1039 | 0 | } |
1040 | | |
1041 | 0 | m_bModified = false; |
1042 | | |
1043 | | // Unlock mutex before notify our listeners |
1044 | 0 | aGuard.clear(); |
1045 | | |
1046 | | // Notify our listeners |
1047 | 0 | for ( auto const & k: aRemoveEventNotifyContainer ) |
1048 | 0 | implts_notifyContainerListener( k, NotifyOp_Remove ); |
1049 | 0 | for ( auto const & k: aReplaceEventNotifyContainer ) |
1050 | 0 | implts_notifyContainerListener( k, NotifyOp_Replace ); |
1051 | 0 | } |
1052 | 0 | catch ( const css::lang::IllegalArgumentException& ) |
1053 | 0 | { |
1054 | 0 | } |
1055 | 0 | catch ( const css::container::NoSuchElementException& ) |
1056 | 0 | { |
1057 | 0 | } |
1058 | 0 | catch ( const css::embed::InvalidStorageException& ) |
1059 | 0 | { |
1060 | 0 | } |
1061 | 0 | catch ( const css::embed::StorageWrappedTargetException& ) |
1062 | 0 | { |
1063 | 0 | } |
1064 | 0 | } |
1065 | | |
1066 | | Sequence< Sequence< PropertyValue > > SAL_CALL ModuleUIConfigurationManager::getUIElementsInfo( sal_Int16 ElementType ) |
1067 | 0 | { |
1068 | 0 | if (( ElementType < 0 ) || ( ElementType >= css::ui::UIElementType::COUNT )) |
1069 | 0 | throw IllegalArgumentException(); |
1070 | | |
1071 | 0 | SolarMutexGuard g; |
1072 | 0 | if ( m_bDisposed ) |
1073 | 0 | throw DisposedException(); |
1074 | | |
1075 | 0 | std::vector< Sequence< PropertyValue > > aElementInfoSeq; |
1076 | 0 | UIElementInfoHashMap aUIElementInfoCollection; |
1077 | |
|
1078 | 0 | if ( ElementType == css::ui::UIElementType::UNKNOWN ) |
1079 | 0 | { |
1080 | 0 | for ( sal_Int16 i = 0; i < css::ui::UIElementType::COUNT; i++ ) |
1081 | 0 | impl_fillSequenceWithElementTypeInfo( aUIElementInfoCollection, i ); |
1082 | 0 | } |
1083 | 0 | else |
1084 | 0 | impl_fillSequenceWithElementTypeInfo( aUIElementInfoCollection, ElementType ); |
1085 | |
|
1086 | 0 | aElementInfoSeq.resize( aUIElementInfoCollection.size() ); |
1087 | |
|
1088 | 0 | sal_Int32 n = 0; |
1089 | 0 | for (auto const& elem : aUIElementInfoCollection) |
1090 | 0 | { |
1091 | 0 | aElementInfoSeq[n++] = Sequence<PropertyValue> { |
1092 | 0 | comphelper::makePropertyValue(u"ResourceURL"_ustr, elem.second.aResourceURL), |
1093 | 0 | comphelper::makePropertyValue(m_aPropUIName, elem.second.aUIName) |
1094 | 0 | }; |
1095 | 0 | } |
1096 | |
|
1097 | 0 | return comphelper::containerToSequence(aElementInfoSeq); |
1098 | 0 | } |
1099 | | |
1100 | | Reference< XIndexContainer > SAL_CALL ModuleUIConfigurationManager::createSettings() |
1101 | 0 | { |
1102 | 0 | SolarMutexGuard g; |
1103 | |
|
1104 | 0 | if ( m_bDisposed ) |
1105 | 0 | throw DisposedException(); |
1106 | | |
1107 | | // Creates an empty item container which can be filled from outside |
1108 | 0 | return Reference< XIndexContainer >( new RootItemContainer() ); |
1109 | 0 | } |
1110 | | |
1111 | | sal_Bool SAL_CALL ModuleUIConfigurationManager::hasSettings( const OUString& ResourceURL ) |
1112 | 0 | { |
1113 | 0 | sal_Int16 nElementType = RetrieveTypeFromResourceURL( ResourceURL ); |
1114 | |
|
1115 | 0 | if (( nElementType == css::ui::UIElementType::UNKNOWN ) || |
1116 | 0 | ( nElementType >= css::ui::UIElementType::COUNT )) |
1117 | 0 | throw IllegalArgumentException(); |
1118 | | |
1119 | 0 | SolarMutexGuard g; |
1120 | |
|
1121 | 0 | if ( m_bDisposed ) |
1122 | 0 | throw DisposedException(); |
1123 | | |
1124 | 0 | UIElementData* pDataSettings = impl_findUIElementData( ResourceURL, nElementType, false ); |
1125 | 0 | if ( pDataSettings ) |
1126 | 0 | return true; |
1127 | | |
1128 | 0 | return false; |
1129 | 0 | } |
1130 | | |
1131 | | Reference< XIndexAccess > SAL_CALL ModuleUIConfigurationManager::getSettings( const OUString& ResourceURL, sal_Bool bWriteable ) |
1132 | 0 | { |
1133 | 0 | sal_Int16 nElementType = RetrieveTypeFromResourceURL( ResourceURL ); |
1134 | |
|
1135 | 0 | if (( nElementType == css::ui::UIElementType::UNKNOWN ) || |
1136 | 0 | ( nElementType >= css::ui::UIElementType::COUNT )) |
1137 | 0 | throw IllegalArgumentException(); |
1138 | | |
1139 | 0 | SolarMutexGuard g; |
1140 | |
|
1141 | 0 | if ( m_bDisposed ) |
1142 | 0 | throw DisposedException(); |
1143 | | |
1144 | 0 | UIElementData* pDataSettings = impl_findUIElementData( ResourceURL, nElementType ); |
1145 | 0 | if ( pDataSettings ) |
1146 | 0 | { |
1147 | | // Create a copy of our data if someone wants to change the data. |
1148 | 0 | if ( bWriteable ) |
1149 | 0 | return Reference< XIndexAccess >( new RootItemContainer( pDataSettings->xSettings ) ); |
1150 | 0 | else |
1151 | 0 | return pDataSettings->xSettings; |
1152 | 0 | } |
1153 | | |
1154 | 0 | throw NoSuchElementException(); |
1155 | 0 | } |
1156 | | |
1157 | | void SAL_CALL ModuleUIConfigurationManager::replaceSettings( const OUString& ResourceURL, const Reference< css::container::XIndexAccess >& aNewData ) |
1158 | 0 | { |
1159 | 0 | sal_Int16 nElementType = RetrieveTypeFromResourceURL( ResourceURL ); |
1160 | |
|
1161 | 0 | if (( nElementType == css::ui::UIElementType::UNKNOWN ) || |
1162 | 0 | ( nElementType >= css::ui::UIElementType::COUNT )) |
1163 | 0 | throw IllegalArgumentException(); |
1164 | 0 | else if ( m_bReadOnly ) |
1165 | 0 | throw IllegalAccessException(); |
1166 | 0 | else |
1167 | 0 | { |
1168 | 0 | SolarMutexClearableGuard aGuard; |
1169 | |
|
1170 | 0 | if ( m_bDisposed ) |
1171 | 0 | throw DisposedException(); |
1172 | | |
1173 | 0 | UIElementData* pDataSettings = impl_findUIElementData( ResourceURL, nElementType ); |
1174 | 0 | if ( !pDataSettings ) |
1175 | 0 | throw NoSuchElementException(); |
1176 | 0 | if ( !pDataSettings->bDefaultNode ) |
1177 | 0 | { |
1178 | | // we have a settings entry in our user-defined layer - replace |
1179 | 0 | Reference< XIndexAccess > xOldSettings = pDataSettings->xSettings; |
1180 | | |
1181 | | // Create a copy of the data if the container is not const |
1182 | 0 | Reference< XIndexReplace > xReplace( aNewData, UNO_QUERY ); |
1183 | 0 | if ( xReplace.is() ) |
1184 | 0 | pDataSettings->xSettings = new ConstItemContainer( aNewData ); |
1185 | 0 | else |
1186 | 0 | pDataSettings->xSettings = aNewData; |
1187 | 0 | pDataSettings->bDefault = false; |
1188 | 0 | pDataSettings->bModified = true; |
1189 | 0 | m_bModified = true; |
1190 | | |
1191 | | // Modify type container |
1192 | 0 | UIElementType& rElementType = m_aUIElements[LAYER_USERDEFINED][nElementType]; |
1193 | 0 | rElementType.bModified = true; |
1194 | |
|
1195 | 0 | Reference< XUIConfigurationManager > xThis(this); |
1196 | | |
1197 | | // Create event to notify listener about replaced element settings |
1198 | 0 | ui::ConfigurationEvent aEvent; |
1199 | 0 | aEvent.ResourceURL = ResourceURL; |
1200 | 0 | aEvent.Accessor <<= xThis; |
1201 | 0 | aEvent.Source.set(xThis, UNO_QUERY); |
1202 | 0 | aEvent.ReplacedElement <<= xOldSettings; |
1203 | 0 | aEvent.Element <<= pDataSettings->xSettings; |
1204 | |
|
1205 | 0 | aGuard.clear(); |
1206 | |
|
1207 | 0 | implts_notifyContainerListener( aEvent, NotifyOp_Replace ); |
1208 | 0 | } |
1209 | 0 | else |
1210 | 0 | { |
1211 | | // we have no settings in our user-defined layer - insert |
1212 | 0 | UIElementData aUIElementData; |
1213 | |
|
1214 | 0 | aUIElementData.bDefault = false; |
1215 | 0 | aUIElementData.bDefaultNode = false; |
1216 | 0 | aUIElementData.bModified = true; |
1217 | | |
1218 | | // Create a copy of the data if the container is not const |
1219 | 0 | Reference< XIndexReplace > xReplace( aNewData, UNO_QUERY ); |
1220 | 0 | if ( xReplace.is() ) |
1221 | 0 | aUIElementData.xSettings = new ConstItemContainer( aNewData ); |
1222 | 0 | else |
1223 | 0 | aUIElementData.xSettings = aNewData; |
1224 | 0 | aUIElementData.aName = RetrieveNameFromResourceURL( ResourceURL ) + m_aXMLPostfix; |
1225 | 0 | aUIElementData.aResourceURL = ResourceURL; |
1226 | 0 | m_bModified = true; |
1227 | | |
1228 | | // Modify type container |
1229 | 0 | UIElementType& rElementType = m_aUIElements[LAYER_USERDEFINED][nElementType]; |
1230 | 0 | rElementType.bModified = true; |
1231 | |
|
1232 | 0 | UIElementDataHashMap& rElements = rElementType.aElementsHashMap; |
1233 | | |
1234 | | // Check our user element settings hash map as it can already contain settings that have been set to default! |
1235 | | // If no node can be found, we have to insert it. |
1236 | 0 | UIElementDataHashMap::iterator pIter = rElements.find( ResourceURL ); |
1237 | 0 | if ( pIter != rElements.end() ) |
1238 | 0 | pIter->second = aUIElementData; |
1239 | 0 | else |
1240 | 0 | rElements.emplace( ResourceURL, aUIElementData ); |
1241 | |
|
1242 | 0 | Reference< XUIConfigurationManager > xThis(this); |
1243 | | |
1244 | | // Create event to notify listener about replaced element settings |
1245 | 0 | ui::ConfigurationEvent aEvent; |
1246 | |
|
1247 | 0 | aEvent.ResourceURL = ResourceURL; |
1248 | 0 | aEvent.Accessor <<= xThis; |
1249 | 0 | aEvent.Source.set(xThis, UNO_QUERY); |
1250 | 0 | aEvent.ReplacedElement <<= pDataSettings->xSettings; |
1251 | 0 | aEvent.Element <<= aUIElementData.xSettings; |
1252 | |
|
1253 | 0 | aGuard.clear(); |
1254 | |
|
1255 | 0 | implts_notifyContainerListener( aEvent, NotifyOp_Replace ); |
1256 | 0 | } |
1257 | 0 | } |
1258 | 0 | } |
1259 | | |
1260 | | void SAL_CALL ModuleUIConfigurationManager::removeSettings( const OUString& ResourceURL ) |
1261 | 0 | { |
1262 | 0 | sal_Int16 nElementType = RetrieveTypeFromResourceURL( ResourceURL ); |
1263 | |
|
1264 | 0 | if (( nElementType == css::ui::UIElementType::UNKNOWN ) || |
1265 | 0 | ( nElementType >= css::ui::UIElementType::COUNT )) |
1266 | 0 | throw IllegalArgumentException( "The ResourceURL is not valid or " |
1267 | 0 | "describes an unknown type. " |
1268 | 0 | "ResourceURL: " + ResourceURL, nullptr, 0 ); |
1269 | 0 | else if ( m_bReadOnly ) |
1270 | 0 | throw IllegalAccessException( "The configuration manager is read-only. " |
1271 | 0 | "ResourceURL: " + ResourceURL, nullptr ); |
1272 | 0 | else |
1273 | 0 | { |
1274 | 0 | SolarMutexClearableGuard aGuard; |
1275 | |
|
1276 | 0 | if ( m_bDisposed ) |
1277 | 0 | throw DisposedException( "The configuration manager has been disposed, " |
1278 | 0 | "and can't uphold its method specification anymore. " |
1279 | 0 | "ResourceURL: " + ResourceURL, nullptr ); |
1280 | | |
1281 | 0 | UIElementData* pDataSettings = impl_findUIElementData( ResourceURL, nElementType ); |
1282 | 0 | if ( !pDataSettings ) |
1283 | 0 | throw NoSuchElementException( "The settings data cannot be found. " |
1284 | 0 | "ResourceURL: " + ResourceURL, nullptr ); |
1285 | | // If element settings are default, we don't need to change anything! |
1286 | 0 | if ( pDataSettings->bDefault ) |
1287 | 0 | return; |
1288 | 0 | else |
1289 | 0 | { |
1290 | 0 | Reference< XIndexAccess > xRemovedSettings = pDataSettings->xSettings; |
1291 | 0 | pDataSettings->bDefault = true; |
1292 | | |
1293 | | // check if this is a default layer node |
1294 | 0 | if ( !pDataSettings->bDefaultNode ) |
1295 | 0 | pDataSettings->bModified = true; // we have to remove this node from the user layer! |
1296 | 0 | pDataSettings->xSettings.clear(); |
1297 | 0 | m_bModified = true; // user layer must be written |
1298 | | |
1299 | | // Modify type container |
1300 | 0 | UIElementType& rElementType = m_aUIElements[LAYER_USERDEFINED][nElementType]; |
1301 | 0 | rElementType.bModified = true; |
1302 | |
|
1303 | 0 | Reference< XUIConfigurationManager > xThis(this); |
1304 | 0 | Reference< XInterface > xIfac( xThis, UNO_QUERY ); |
1305 | | |
1306 | | // Check if we have settings in the default layer which replaces the user-defined one! |
1307 | 0 | UIElementData* pDefaultDataSettings = impl_findUIElementData( ResourceURL, nElementType ); |
1308 | 0 | if ( pDefaultDataSettings ) |
1309 | 0 | { |
1310 | | // Create event to notify listener about replaced element settings |
1311 | 0 | ui::ConfigurationEvent aEvent; |
1312 | |
|
1313 | 0 | aEvent.ResourceURL = ResourceURL; |
1314 | 0 | aEvent.Accessor <<= xThis; |
1315 | 0 | aEvent.Source = std::move(xIfac); |
1316 | 0 | aEvent.Element <<= xRemovedSettings; |
1317 | 0 | aEvent.ReplacedElement <<= pDefaultDataSettings->xSettings; |
1318 | |
|
1319 | 0 | aGuard.clear(); |
1320 | |
|
1321 | 0 | implts_notifyContainerListener( aEvent, NotifyOp_Replace ); |
1322 | 0 | } |
1323 | 0 | else |
1324 | 0 | { |
1325 | | // Create event to notify listener about removed element settings |
1326 | 0 | ui::ConfigurationEvent aEvent; |
1327 | |
|
1328 | 0 | aEvent.ResourceURL = ResourceURL; |
1329 | 0 | aEvent.Accessor <<= xThis; |
1330 | 0 | aEvent.Source = std::move(xIfac); |
1331 | 0 | aEvent.Element <<= xRemovedSettings; |
1332 | |
|
1333 | 0 | aGuard.clear(); |
1334 | |
|
1335 | 0 | implts_notifyContainerListener( aEvent, NotifyOp_Remove ); |
1336 | 0 | } |
1337 | 0 | } |
1338 | 0 | } |
1339 | 0 | } |
1340 | | |
1341 | | void SAL_CALL ModuleUIConfigurationManager::insertSettings( const OUString& NewResourceURL, const Reference< XIndexAccess >& aNewData ) |
1342 | 0 | { |
1343 | 0 | sal_Int16 nElementType = RetrieveTypeFromResourceURL( NewResourceURL ); |
1344 | |
|
1345 | 0 | if (( nElementType == css::ui::UIElementType::UNKNOWN ) || |
1346 | 0 | ( nElementType >= css::ui::UIElementType::COUNT )) |
1347 | 0 | throw IllegalArgumentException(); |
1348 | 0 | else if ( m_bReadOnly ) |
1349 | 0 | throw IllegalAccessException(); |
1350 | 0 | else |
1351 | 0 | { |
1352 | 0 | SolarMutexClearableGuard aGuard; |
1353 | |
|
1354 | 0 | if ( m_bDisposed ) |
1355 | 0 | throw DisposedException(); |
1356 | | |
1357 | 0 | UIElementData* pDataSettings = impl_findUIElementData( NewResourceURL, nElementType ); |
1358 | 0 | if ( !(!pDataSettings) ) |
1359 | 0 | throw ElementExistException(); |
1360 | 0 | UIElementData aUIElementData; |
1361 | |
|
1362 | 0 | aUIElementData.bDefault = false; |
1363 | 0 | aUIElementData.bDefaultNode = false; |
1364 | 0 | aUIElementData.bModified = true; |
1365 | | |
1366 | | // Create a copy of the data if the container is not const |
1367 | 0 | Reference< XIndexReplace > xReplace( aNewData, UNO_QUERY ); |
1368 | 0 | if ( xReplace.is() ) |
1369 | 0 | aUIElementData.xSettings = new ConstItemContainer( aNewData ); |
1370 | 0 | else |
1371 | 0 | aUIElementData.xSettings = aNewData; |
1372 | 0 | aUIElementData.aName = RetrieveNameFromResourceURL( NewResourceURL ) + m_aXMLPostfix; |
1373 | 0 | aUIElementData.aResourceURL = NewResourceURL; |
1374 | 0 | m_bModified = true; |
1375 | |
|
1376 | 0 | UIElementType& rElementType = m_aUIElements[LAYER_USERDEFINED][nElementType]; |
1377 | 0 | rElementType.bModified = true; |
1378 | |
|
1379 | 0 | UIElementDataHashMap& rElements = rElementType.aElementsHashMap; |
1380 | 0 | rElements.emplace( NewResourceURL, aUIElementData ); |
1381 | |
|
1382 | 0 | Reference< XIndexAccess > xInsertSettings( aUIElementData.xSettings ); |
1383 | 0 | Reference< XUIConfigurationManager > xThis(this); |
1384 | | |
1385 | | // Create event to notify listener about removed element settings |
1386 | 0 | ui::ConfigurationEvent aEvent; |
1387 | |
|
1388 | 0 | aEvent.ResourceURL = NewResourceURL; |
1389 | 0 | aEvent.Accessor <<= xThis; |
1390 | 0 | aEvent.Source = xThis; |
1391 | 0 | aEvent.Element <<= xInsertSettings; |
1392 | |
|
1393 | 0 | aGuard.clear(); |
1394 | |
|
1395 | 0 | implts_notifyContainerListener( aEvent, NotifyOp_Insert ); |
1396 | 0 | } |
1397 | 0 | } |
1398 | | |
1399 | | Reference< XInterface > SAL_CALL ModuleUIConfigurationManager::getImageManager() |
1400 | 0 | { |
1401 | 0 | SolarMutexGuard g; |
1402 | |
|
1403 | 0 | if ( m_bDisposed ) |
1404 | 0 | throw DisposedException(); |
1405 | | |
1406 | 0 | if ( !m_xModuleImageManager.is() ) |
1407 | 0 | { |
1408 | 0 | m_xModuleImageManager = new ImageManager( m_xContext, /*bForModule*/true ); |
1409 | |
|
1410 | 0 | uno::Sequence<uno::Any> aPropSeq(comphelper::InitAnyPropertySequence( |
1411 | 0 | { |
1412 | 0 | {"UserConfigStorage", uno::Any(m_xUserConfigStorage)}, |
1413 | 0 | {"ModuleIdentifier", uno::Any(m_aModuleIdentifier)}, |
1414 | 0 | {"UserRootCommit", uno::Any(m_xUserRootCommit)}, |
1415 | 0 | })); |
1416 | 0 | m_xModuleImageManager->initialize( aPropSeq ); |
1417 | 0 | } |
1418 | |
|
1419 | 0 | return Reference< XInterface >( static_cast<cppu::OWeakObject*>(m_xModuleImageManager.get()), UNO_QUERY ); |
1420 | 0 | } |
1421 | | |
1422 | | Reference< ui::XAcceleratorConfiguration > SAL_CALL ModuleUIConfigurationManager::createShortCutManager() |
1423 | 0 | { |
1424 | 0 | return ui::ModuleAcceleratorConfiguration::createWithModuleIdentifier(m_xContext, m_aModuleIdentifier); |
1425 | 0 | } |
1426 | | |
1427 | | Reference< ui::XAcceleratorConfiguration > SAL_CALL ModuleUIConfigurationManager::getShortCutManager() |
1428 | 0 | { |
1429 | 0 | SolarMutexGuard g; |
1430 | |
|
1431 | 0 | if ( m_bDisposed ) |
1432 | 0 | throw DisposedException(); |
1433 | | |
1434 | 0 | if ( !m_xModuleAcceleratorManager.is() ) try |
1435 | 0 | { |
1436 | 0 | m_xModuleAcceleratorManager = ui::ModuleAcceleratorConfiguration:: |
1437 | 0 | createWithModuleIdentifier(m_xContext, m_aModuleIdentifier); |
1438 | 0 | } |
1439 | 0 | catch ( const css::uno::DeploymentException& ) |
1440 | 0 | { |
1441 | 0 | SAL_WARN("fwk.uiconfiguration", "ModuleAcceleratorConfiguration" |
1442 | 0 | " not available. This should happen only on mobile platforms."); |
1443 | 0 | } |
1444 | | |
1445 | 0 | return m_xModuleAcceleratorManager; |
1446 | 0 | } |
1447 | | |
1448 | | Reference< XInterface > SAL_CALL ModuleUIConfigurationManager::getEventsManager() |
1449 | 0 | { |
1450 | 0 | return Reference< XInterface >(); |
1451 | 0 | } |
1452 | | |
1453 | | // XModuleUIConfigurationManager |
1454 | | sal_Bool SAL_CALL ModuleUIConfigurationManager::isDefaultSettings( const OUString& ResourceURL ) |
1455 | 0 | { |
1456 | 0 | sal_Int16 nElementType = RetrieveTypeFromResourceURL( ResourceURL ); |
1457 | |
|
1458 | 0 | if (( nElementType == css::ui::UIElementType::UNKNOWN ) || |
1459 | 0 | ( nElementType >= css::ui::UIElementType::COUNT )) |
1460 | 0 | throw IllegalArgumentException(); |
1461 | | |
1462 | 0 | SolarMutexGuard g; |
1463 | |
|
1464 | 0 | if ( m_bDisposed ) |
1465 | 0 | throw DisposedException(); |
1466 | | |
1467 | 0 | UIElementData* pDataSettings = impl_findUIElementData( ResourceURL, nElementType, false ); |
1468 | 0 | if ( pDataSettings && pDataSettings->bDefaultNode ) |
1469 | 0 | return true; |
1470 | | |
1471 | 0 | return false; |
1472 | 0 | } |
1473 | | |
1474 | | Reference< XIndexAccess > SAL_CALL ModuleUIConfigurationManager::getDefaultSettings( const OUString& ResourceURL ) |
1475 | 0 | { |
1476 | 0 | sal_Int16 nElementType = RetrieveTypeFromResourceURL( ResourceURL ); |
1477 | |
|
1478 | 0 | if (( nElementType == css::ui::UIElementType::UNKNOWN ) || |
1479 | 0 | ( nElementType >= css::ui::UIElementType::COUNT )) |
1480 | 0 | throw IllegalArgumentException(); |
1481 | | |
1482 | 0 | SolarMutexGuard g; |
1483 | |
|
1484 | 0 | if ( m_bDisposed ) |
1485 | 0 | throw DisposedException(); |
1486 | | |
1487 | | // preload list of element types on demand |
1488 | 0 | impl_preloadUIElementTypeList( LAYER_DEFAULT, nElementType ); |
1489 | | |
1490 | | // Look into our default vector/unordered_map combination |
1491 | 0 | UIElementDataHashMap& rDefaultHashMap = m_aUIElements[LAYER_DEFAULT][nElementType].aElementsHashMap; |
1492 | 0 | UIElementDataHashMap::iterator pIter = rDefaultHashMap.find( ResourceURL ); |
1493 | 0 | if ( pIter != rDefaultHashMap.end() ) |
1494 | 0 | { |
1495 | 0 | if ( !pIter->second.xSettings.is() ) |
1496 | 0 | impl_requestUIElementData( nElementType, LAYER_DEFAULT, pIter->second ); |
1497 | 0 | return pIter->second.xSettings; |
1498 | 0 | } |
1499 | | |
1500 | | // Nothing has been found! |
1501 | 0 | throw NoSuchElementException(); |
1502 | 0 | } |
1503 | | |
1504 | | // XUIConfigurationPersistence |
1505 | | void SAL_CALL ModuleUIConfigurationManager::reload() |
1506 | 0 | { |
1507 | 0 | SolarMutexClearableGuard aGuard; |
1508 | |
|
1509 | 0 | if ( m_bDisposed ) |
1510 | 0 | throw DisposedException(); |
1511 | | |
1512 | 0 | if ( !m_xUserConfigStorage.is() || !m_bModified || m_bReadOnly ) |
1513 | 0 | return; |
1514 | | |
1515 | | // Try to access our module sub folder |
1516 | 0 | ConfigEventNotifyContainer aRemoveNotifyContainer; |
1517 | 0 | ConfigEventNotifyContainer aReplaceNotifyContainer; |
1518 | 0 | for ( sal_Int16 i = 1; i < css::ui::UIElementType::COUNT; i++ ) |
1519 | 0 | { |
1520 | 0 | try |
1521 | 0 | { |
1522 | 0 | UIElementType& rUserElementType = m_aUIElements[LAYER_USERDEFINED][i]; |
1523 | |
|
1524 | 0 | if ( rUserElementType.bModified ) |
1525 | 0 | { |
1526 | 0 | UIElementType& rDefaultElementType = m_aUIElements[LAYER_DEFAULT][i]; |
1527 | 0 | impl_reloadElementTypeData( rUserElementType, rDefaultElementType, aRemoveNotifyContainer, aReplaceNotifyContainer ); |
1528 | 0 | } |
1529 | 0 | } |
1530 | 0 | catch ( const Exception& ) |
1531 | 0 | { |
1532 | 0 | throw IOException(); |
1533 | 0 | } |
1534 | 0 | } |
1535 | | |
1536 | 0 | m_bModified = false; |
1537 | | |
1538 | | // Unlock mutex before notify our listeners |
1539 | 0 | aGuard.clear(); |
1540 | | |
1541 | | // Notify our listeners |
1542 | 0 | for (const ui::ConfigurationEvent & j : aRemoveNotifyContainer) |
1543 | 0 | implts_notifyContainerListener( j, NotifyOp_Remove ); |
1544 | 0 | for (const ui::ConfigurationEvent & k : aReplaceNotifyContainer) |
1545 | 0 | implts_notifyContainerListener( k, NotifyOp_Replace ); |
1546 | 0 | } |
1547 | | |
1548 | | void SAL_CALL ModuleUIConfigurationManager::store() |
1549 | 0 | { |
1550 | 0 | SolarMutexGuard g; |
1551 | |
|
1552 | 0 | if ( m_bDisposed ) |
1553 | 0 | throw DisposedException(); |
1554 | | |
1555 | 0 | if ( !m_xUserConfigStorage.is() || !m_bModified || m_bReadOnly ) |
1556 | 0 | return; |
1557 | | |
1558 | | // Try to access our module sub folder |
1559 | 0 | for ( int i = 1; i < css::ui::UIElementType::COUNT; i++ ) |
1560 | 0 | { |
1561 | 0 | try |
1562 | 0 | { |
1563 | 0 | UIElementType& rElementType = m_aUIElements[LAYER_USERDEFINED][i]; |
1564 | |
|
1565 | 0 | if ( rElementType.bModified && rElementType.xStorage.is() ) |
1566 | 0 | { |
1567 | 0 | impl_storeElementTypeData( rElementType.xStorage, rElementType ); |
1568 | 0 | m_pStorageHandler[i]->commitUserChanges(); |
1569 | 0 | } |
1570 | 0 | } |
1571 | 0 | catch ( const Exception& ) |
1572 | 0 | { |
1573 | 0 | throw IOException(); |
1574 | 0 | } |
1575 | 0 | } |
1576 | | |
1577 | 0 | m_bModified = false; |
1578 | 0 | } |
1579 | | |
1580 | | void SAL_CALL ModuleUIConfigurationManager::storeToStorage( const Reference< XStorage >& Storage ) |
1581 | 0 | { |
1582 | 0 | SolarMutexGuard g; |
1583 | |
|
1584 | 0 | if ( m_bDisposed ) |
1585 | 0 | throw DisposedException(); |
1586 | | |
1587 | 0 | if ( !m_xUserConfigStorage.is() || !m_bModified || m_bReadOnly ) |
1588 | 0 | return; |
1589 | | |
1590 | | // Try to access our module sub folder |
1591 | 0 | for ( int i = 1; i < css::ui::UIElementType::COUNT; i++ ) |
1592 | 0 | { |
1593 | 0 | try |
1594 | 0 | { |
1595 | 0 | Reference< XStorage > xElementTypeStorage( Storage->openStorageElement( |
1596 | 0 | OUString(UIELEMENTTYPENAMES[i]), ElementModes::READWRITE )); |
1597 | 0 | UIElementType& rElementType = m_aUIElements[LAYER_USERDEFINED][i]; |
1598 | |
|
1599 | 0 | if ( rElementType.bModified && xElementTypeStorage.is() ) |
1600 | 0 | impl_storeElementTypeData( xElementTypeStorage, rElementType, false ); // store data to storage, but don't reset modify flag! |
1601 | 0 | } |
1602 | 0 | catch ( const Exception& ) |
1603 | 0 | { |
1604 | 0 | throw IOException(); |
1605 | 0 | } |
1606 | 0 | } |
1607 | | |
1608 | 0 | Reference< XTransactedObject > xTransactedObject( Storage, UNO_QUERY ); |
1609 | 0 | if ( xTransactedObject.is() ) |
1610 | 0 | xTransactedObject->commit(); |
1611 | 0 | } |
1612 | | |
1613 | | sal_Bool SAL_CALL ModuleUIConfigurationManager::isModified() |
1614 | 0 | { |
1615 | 0 | SolarMutexGuard g; |
1616 | |
|
1617 | 0 | return m_bModified; |
1618 | 0 | } |
1619 | | |
1620 | | sal_Bool SAL_CALL ModuleUIConfigurationManager::isReadOnly() |
1621 | 0 | { |
1622 | 0 | SolarMutexGuard g; |
1623 | |
|
1624 | 0 | return m_bReadOnly; |
1625 | 0 | } |
1626 | | |
1627 | | void ModuleUIConfigurationManager::implts_notifyContainerListener( const ui::ConfigurationEvent& aEvent, NotifyOp eOp ) |
1628 | 0 | { |
1629 | 0 | std::unique_lock aGuard(m_mutex); |
1630 | 0 | using ListenerMethodType = void (SAL_CALL css::ui::XUIConfigurationListener::*)(const ui::ConfigurationEvent&); |
1631 | 0 | ListenerMethodType aListenerMethod {}; |
1632 | 0 | switch ( eOp ) |
1633 | 0 | { |
1634 | 0 | case NotifyOp_Replace: |
1635 | 0 | aListenerMethod = &css::ui::XUIConfigurationListener::elementReplaced; |
1636 | 0 | break; |
1637 | 0 | case NotifyOp_Insert: |
1638 | 0 | aListenerMethod = &css::ui::XUIConfigurationListener::elementInserted; |
1639 | 0 | break; |
1640 | 0 | case NotifyOp_Remove: |
1641 | 0 | aListenerMethod = &css::ui::XUIConfigurationListener::elementRemoved; |
1642 | 0 | break; |
1643 | 0 | } |
1644 | 0 | m_aConfigListeners.notifyEach(aGuard, aListenerMethod, aEvent); |
1645 | 0 | } |
1646 | | |
1647 | | } |
1648 | | |
1649 | | extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * |
1650 | | com_sun_star_comp_framework_ModuleUIConfigurationManager_get_implementation( |
1651 | | css::uno::XComponentContext *context, |
1652 | | css::uno::Sequence<css::uno::Any> const &arguments) |
1653 | 0 | { |
1654 | 0 | return cppu::acquire(new ModuleUIConfigurationManager(context, arguments)); |
1655 | 0 | } |
1656 | | |
1657 | | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |