/src/libreoffice/unotools/source/config/configitem.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 <sal/config.h> |
21 | | |
22 | | #include <sal/log.hxx> |
23 | | #include <unotools/configitem.hxx> |
24 | | #include <unotools/configmgr.hxx> |
25 | | #include <unotools/configpaths.hxx> |
26 | | #include <com/sun/star/beans/XPropertySet.hpp> |
27 | | #include <com/sun/star/util/XChangesListener.hpp> |
28 | | #include <com/sun/star/util/XChangesNotifier.hpp> |
29 | | #include <com/sun/star/container/XHierarchicalNameAccess.hpp> |
30 | | #include <com/sun/star/configuration/XTemplateContainer.hpp> |
31 | | #include <com/sun/star/container/XNameContainer.hpp> |
32 | | #include <com/sun/star/lang/XSingleServiceFactory.hpp> |
33 | | #include <com/sun/star/lang/XServiceInfo.hpp> |
34 | | #include <com/sun/star/beans/PropertyValue.hpp> |
35 | | #include <com/sun/star/beans/PropertyAttribute.hpp> |
36 | | #include <com/sun/star/util/XChangesBatch.hpp> |
37 | | #include <o3tl/deleter.hxx> |
38 | | #include <osl/diagnose.h> |
39 | | #include <comphelper/configuration.hxx> |
40 | | #include <comphelper/sequence.hxx> |
41 | | #include <comphelper/solarmutex.hxx> |
42 | | #include <comphelper/diagnose_ex.hxx> |
43 | | #include <comphelper/propertyvalue.hxx> |
44 | | #include <cppuhelper/implbase.hxx> |
45 | | #include <utility> |
46 | | |
47 | | using namespace utl; |
48 | | using namespace com::sun::star::uno; |
49 | | using namespace com::sun::star::util; |
50 | | using namespace com::sun::star::lang; |
51 | | using namespace com::sun::star::beans; |
52 | | using namespace com::sun::star::container; |
53 | | using namespace com::sun::star::configuration; |
54 | | |
55 | | /* |
56 | | The ConfigChangeListener_Impl receives notifications from the configuration about changes that |
57 | | have happened. It forwards this notification to the ConfigItem it knows a pParent by calling its |
58 | | "CallNotify" method. As ConfigItems are most probably not thread safe, the SolarMutex is acquired |
59 | | before doing so. |
60 | | */ |
61 | | |
62 | | namespace utl{ |
63 | | class ConfigChangeListener_Impl : public cppu::WeakImplHelper |
64 | | < |
65 | | css::util::XChangesListener |
66 | | > |
67 | | { |
68 | | public: |
69 | | ConfigItem* pParent; |
70 | | const Sequence< OUString > aPropertyNames; |
71 | | ConfigChangeListener_Impl(ConfigItem& rItem, const Sequence< OUString >& rNames); |
72 | | |
73 | | //XChangesListener |
74 | | virtual void SAL_CALL changesOccurred( const ChangesEvent& Event ) override; |
75 | | |
76 | | //XEventListener |
77 | | virtual void SAL_CALL disposing( const EventObject& Source ) override; |
78 | | }; |
79 | | } |
80 | | |
81 | | namespace { |
82 | | |
83 | | class ValueCounter_Impl |
84 | | { |
85 | | sal_Int16& rCnt; |
86 | | public: |
87 | | explicit ValueCounter_Impl(sal_Int16& rCounter) |
88 | 0 | : rCnt(rCounter) |
89 | 0 | { |
90 | 0 | rCnt++; |
91 | 0 | } |
92 | | ~ValueCounter_Impl() |
93 | 0 | { |
94 | 0 | OSL_ENSURE(rCnt>0, "RefCount < 0 ??"); |
95 | 0 | rCnt--; |
96 | 0 | } |
97 | | }; |
98 | | |
99 | | } |
100 | | |
101 | | ConfigChangeListener_Impl::ConfigChangeListener_Impl( |
102 | | ConfigItem& rItem, const Sequence< OUString >& rNames) : |
103 | 0 | pParent(&rItem), |
104 | 0 | aPropertyNames(rNames) |
105 | 0 | { |
106 | 0 | } |
107 | | |
108 | | void ConfigChangeListener_Impl::changesOccurred( const ChangesEvent& rEvent ) |
109 | 0 | { |
110 | 0 | Sequence<OUString> aChangedNames(rEvent.Changes.getLength()); |
111 | 0 | OUString* pNames = aChangedNames.getArray(); |
112 | |
|
113 | 0 | sal_Int32 nNotify = 0; |
114 | 0 | for(const auto& rElementChange : rEvent.Changes) |
115 | 0 | { |
116 | 0 | OUString sTemp; |
117 | 0 | rElementChange.Accessor >>= sTemp; |
118 | | //true if the path is completely correct or if it is longer |
119 | | //i.e ...Print/Content/Graphic and .../Print |
120 | 0 | bool bFound = std::any_of(aPropertyNames.begin(), aPropertyNames.end(), |
121 | 0 | [&sTemp](const OUString& rCheckPropertyName) { return isPrefixOfConfigurationPath(sTemp, rCheckPropertyName); }); |
122 | 0 | if(bFound) |
123 | 0 | pNames[nNotify++] = sTemp; |
124 | 0 | } |
125 | 0 | if( nNotify ) |
126 | 0 | { |
127 | 0 | ::comphelper::SolarMutex *pMutex = ::comphelper::SolarMutex::get(); |
128 | 0 | if ( pMutex ) |
129 | 0 | { |
130 | 0 | osl::Guard<comphelper::SolarMutex> aMutexGuard( pMutex ); |
131 | 0 | aChangedNames.realloc(nNotify); |
132 | 0 | pParent->CallNotify(aChangedNames); |
133 | 0 | } |
134 | 0 | } |
135 | 0 | } |
136 | | |
137 | | void ConfigChangeListener_Impl::disposing( const EventObject& /*rSource*/ ) |
138 | 0 | { |
139 | 0 | pParent->RemoveChangesListener(); |
140 | 0 | } |
141 | | |
142 | | ConfigItem::ConfigItem(OUString aSubTree, ConfigItemMode nSetMode ) : |
143 | 45.8k | sSubTree(std::move(aSubTree)), |
144 | 45.8k | m_nMode(nSetMode), |
145 | 45.8k | m_bIsModified(false), |
146 | 45.8k | m_bEnableInternalNotification(false), |
147 | 45.8k | m_nInValueChange(0) |
148 | 45.8k | { |
149 | 45.8k | if (comphelper::IsFuzzing()) |
150 | 45.8k | return; |
151 | | |
152 | 0 | if (nSetMode & ConfigItemMode::ReleaseTree) |
153 | 0 | ConfigManager::getConfigManager().addConfigItem(*this); |
154 | 0 | else |
155 | 0 | m_xHierarchyAccess = ConfigManager::getConfigManager().addConfigItem(*this); |
156 | 0 | } |
157 | | |
158 | 0 | ConfigItem::ConfigItem(ConfigItem const &) = default; |
159 | 0 | ConfigItem::ConfigItem(ConfigItem &&) = default; |
160 | | |
161 | | ConfigItem::~ConfigItem() |
162 | 45.4k | { |
163 | 45.4k | suppress_fun_call_w_exception(RemoveChangesListener()); |
164 | 45.4k | ConfigManager::getConfigManager().removeConfigItem(*this); |
165 | 45.4k | } |
166 | | |
167 | | void ConfigItem::CallNotify( const css::uno::Sequence<OUString>& rPropertyNames ) |
168 | 0 | { |
169 | | // the call is forwarded to the virtual Notify() method |
170 | | // it is pure virtual, so all classes deriving from ConfigItem have to decide how they |
171 | | // want to notify listeners |
172 | 0 | if(m_nInValueChange <= 0 || m_bEnableInternalNotification) |
173 | 0 | Notify(rPropertyNames); |
174 | 0 | } |
175 | | |
176 | | // In special mode ALL_LOCALES we must support reading/writing of localized cfg entries as Sequence< PropertyValue >. |
177 | | // These methods are helper to convert given lists of names and Any-values. |
178 | | // format: PropertyValue.Name = <locale as ISO string> |
179 | | // PropertyValue.Value = <value; type depends from cfg entry!> |
180 | | // e.g. |
181 | | // LOCALIZED NODE |
182 | | // "UIName" |
183 | | // LOCALE VALUE |
184 | | // "de" "Mein Name" |
185 | | // "en-US" "my name" |
186 | | |
187 | | static void impl_packLocalizedProperties( const Sequence< OUString >& lInNames , |
188 | | const Sequence< Any >& lInValues , |
189 | | Sequence< Any >& lOutValues ) |
190 | 0 | { |
191 | | // This method should be called for special AllLocales ConfigItem-mode only! |
192 | | |
193 | | // Optimise follow algorithm ... A LITTLE BIT :-) |
194 | | // There exist two different possibilities: |
195 | | // i ) There exist no localized entries ... => size of lOutValues will be the same like lInNames/lInValues! |
196 | | // ii) There exist some (mostly one or two) localized entries ... => size of lOutValues will be the same like lInNames/lInValues! |
197 | | // ... Why? If a localized value exist - the any is filled with an XInterface object (is a SetNode-service). |
198 | | // We read all his child nodes and pack it into Sequence< PropertyValue >. |
199 | | // The result list we pack into the return any. We never change size of lists! |
200 | 0 | lOutValues.realloc(lInNames.getLength()); |
201 | | |
202 | | // Algorithm: |
203 | | // Copy all names and values from in to out lists. |
204 | | // Look for special localized entries ... You can detect it as "XInterface" packed into an Any. |
205 | | // Use this XInterface-object to read all localized values and pack it into Sequence< PropertyValue >. |
206 | | // Add this list to out lists then. |
207 | |
|
208 | 0 | std::transform(lInValues.begin(), lInValues.end(), lOutValues.getArray(), [](const Any& value) |
209 | 0 | { |
210 | | // If item is a special localized one ... convert and pack it ... |
211 | 0 | if (value.getValueTypeName() == "com.sun.star.uno.XInterface") |
212 | 0 | { |
213 | 0 | if (auto xSetAccess = value.query<XNameContainer>()) |
214 | 0 | { |
215 | | // list of all locales for localized entry |
216 | 0 | Sequence<OUString> locales = xSetAccess->getElementNames(); |
217 | | // localized values of a configuration entry packed for return |
218 | 0 | Sequence<PropertyValue> lProperties(locales.getLength()); |
219 | |
|
220 | 0 | std::transform( |
221 | 0 | locales.begin(), locales.end(), lProperties.getArray(), |
222 | 0 | [&xSetAccess](const OUString& s) |
223 | 0 | { return comphelper::makePropertyValue(s, xSetAccess->getByName(s)); }); |
224 | |
|
225 | 0 | return Any(lProperties); |
226 | 0 | } |
227 | 0 | } |
228 | | // ... or copy normal items to return lists directly. |
229 | 0 | return value; |
230 | 0 | }); |
231 | 0 | } |
232 | | |
233 | | static void impl_unpackLocalizedProperties( const Sequence< OUString >& lInNames , |
234 | | const Sequence< Any >& lInValues , |
235 | | Sequence< OUString >& lOutNames , |
236 | | Sequence< Any >& lOutValues) |
237 | 0 | { |
238 | | // This method should be called for special AllLocales ConfigItem-mode only! |
239 | |
|
240 | 0 | sal_Int32 nSourceSize; // marks end of loop over input lists |
241 | 0 | sal_Int32 nDestinationCounter; // actual position in output lists |
242 | 0 | sal_Int32 nPropertiesSize; // marks end of inner loop |
243 | 0 | OUString sNodeName; // base name of node ( e.g. "UIName/" ) ... expand to locale ( e.g. "UIName/de" ) |
244 | 0 | Sequence< PropertyValue > lProperties; // localized values of a configuration entry gotten from lInValues-Any |
245 | | |
246 | | // Optimise follow algorithm ... A LITTLE BIT :-) |
247 | | // There exist two different possibilities: |
248 | | // i ) There exist no localized entries ... => size of lOutNames/lOutValues will be the same like lInNames/lInValues! |
249 | | // ii) There exist some (mostly one or two) localized entries ... => size of lOutNames/lOutValues will be some bytes greater than lInNames/lInValues. |
250 | | // => I think we should make it fast for i). ii) is a special case and mustn't be SOOOO... fast. |
251 | | // We should reserve same space for output list like input ones first. |
252 | | // Follow algorithm looks for these borders and change it for ii) only! |
253 | | // It will be faster then a "realloc()" call in every loop ... |
254 | 0 | nSourceSize = lInNames.getLength(); |
255 | |
|
256 | 0 | lOutNames.realloc ( nSourceSize ); |
257 | 0 | auto plOutNames = lOutNames.getArray(); |
258 | 0 | lOutValues.realloc ( nSourceSize ); |
259 | 0 | auto plOutValues = lOutValues.getArray(); |
260 | | |
261 | | // Algorithm: |
262 | | // Copy all names and values from const to return lists. |
263 | | // Look for special localized entries ... You can detect it as Sequence< PropertyValue > packed into an Any. |
264 | | // Split it ... insert PropertyValue.Name to lOutNames and PropertyValue.Value to lOutValues. |
265 | |
|
266 | 0 | nDestinationCounter = 0; |
267 | 0 | for( sal_Int32 nSourceCounter=0; nSourceCounter<nSourceSize; ++nSourceCounter ) |
268 | 0 | { |
269 | | // If item a special localized one ... split it and insert his parts to output lists ... |
270 | 0 | if( lInValues[nSourceCounter].getValueType() == cppu::UnoType<Sequence<PropertyValue>>::get() ) |
271 | 0 | { |
272 | 0 | lInValues[nSourceCounter] >>= lProperties; |
273 | 0 | nPropertiesSize = lProperties.getLength(); |
274 | |
|
275 | 0 | sNodeName = lInNames[nSourceCounter] + "/"; |
276 | |
|
277 | 0 | if( (nDestinationCounter+nPropertiesSize) > lOutNames.getLength() ) |
278 | 0 | { |
279 | 0 | lOutNames.realloc ( nDestinationCounter+nPropertiesSize ); |
280 | 0 | plOutNames = lOutNames.getArray(); |
281 | 0 | lOutValues.realloc ( nDestinationCounter+nPropertiesSize ); |
282 | 0 | plOutValues = lOutValues.getArray(); |
283 | 0 | } |
284 | |
|
285 | 0 | for (const auto& rProperty : lProperties) |
286 | 0 | { |
287 | 0 | plOutNames [nDestinationCounter] = sNodeName + rProperty.Name; |
288 | 0 | plOutValues[nDestinationCounter] = rProperty.Value; |
289 | 0 | ++nDestinationCounter; |
290 | 0 | } |
291 | 0 | } |
292 | | // ... or copy normal items to return lists directly. |
293 | 0 | else |
294 | 0 | { |
295 | 0 | if( (nDestinationCounter+1) > lOutNames.getLength() ) |
296 | 0 | { |
297 | 0 | lOutNames.realloc ( nDestinationCounter+1 ); |
298 | 0 | plOutNames = lOutNames.getArray(); |
299 | 0 | lOutValues.realloc ( nDestinationCounter+1 ); |
300 | 0 | plOutValues = lOutValues.getArray(); |
301 | 0 | } |
302 | |
|
303 | 0 | plOutNames [nDestinationCounter] = lInNames [nSourceCounter]; |
304 | 0 | plOutValues[nDestinationCounter] = lInValues[nSourceCounter]; |
305 | 0 | ++nDestinationCounter; |
306 | 0 | } |
307 | 0 | } |
308 | 0 | } |
309 | | |
310 | | Sequence< sal_Bool > ConfigItem::GetReadOnlyStates(const css::uno::Sequence< OUString >& rNames) |
311 | 1.56k | { |
312 | 1.56k | sal_Int32 i; |
313 | | |
314 | | // size of return list is fix! |
315 | | // Every item must match to length of incoming name list. |
316 | 1.56k | sal_Int32 nCount = rNames.getLength(); |
317 | 1.56k | Sequence< sal_Bool > lStates(nCount); |
318 | 1.56k | sal_Bool* plStates = lStates.getArray(); |
319 | | |
320 | | // We must be sure to return a valid information every time! |
321 | | // Set default to non readonly... similar to the configuration handling of this property. |
322 | 1.56k | std::fill_n(plStates, lStates.getLength(), false); |
323 | | |
324 | | // no access - no information... |
325 | 1.56k | Reference< XHierarchicalNameAccess > xHierarchyAccess = GetTree(); |
326 | 1.56k | if (!xHierarchyAccess.is()) |
327 | 1.56k | return lStates; |
328 | | |
329 | 0 | for (i=0; i<nCount; ++i) |
330 | 0 | { |
331 | 0 | try |
332 | 0 | { |
333 | 0 | const OUString& sName = rNames[i]; |
334 | 0 | OUString sPath; |
335 | 0 | OUString sProperty; |
336 | |
|
337 | 0 | (void)::utl::splitLastFromConfigurationPath(sName,sPath,sProperty); |
338 | 0 | if (sPath.isEmpty() && sProperty.isEmpty()) |
339 | 0 | { |
340 | 0 | OSL_FAIL("ConfigItem::IsReadonly() split failed"); |
341 | 0 | continue; |
342 | 0 | } |
343 | | |
344 | 0 | Reference< XInterface > xNode; |
345 | 0 | Reference< XPropertySet > xSet; |
346 | 0 | Reference< XPropertySetInfo > xInfo; |
347 | 0 | if (!sPath.isEmpty()) |
348 | 0 | { |
349 | 0 | Any aNode = xHierarchyAccess->getByHierarchicalName(sPath); |
350 | 0 | if (!(aNode >>= xNode) || !xNode.is()) |
351 | 0 | { |
352 | 0 | OSL_FAIL("ConfigItem::IsReadonly() no set available"); |
353 | 0 | continue; |
354 | 0 | } |
355 | 0 | } |
356 | 0 | else |
357 | 0 | { |
358 | 0 | xNode = xHierarchyAccess; |
359 | 0 | } |
360 | | |
361 | 0 | xSet.set(xNode, UNO_QUERY); |
362 | 0 | if (xSet.is()) |
363 | 0 | { |
364 | 0 | xInfo = xSet->getPropertySetInfo(); |
365 | 0 | OSL_ENSURE(xInfo.is(), "ConfigItem::IsReadonly() getPropertySetInfo failed ..."); |
366 | 0 | } |
367 | 0 | else |
368 | 0 | { |
369 | 0 | xInfo.set(xNode, UNO_QUERY); |
370 | 0 | OSL_ENSURE(xInfo.is(), "ConfigItem::IsReadonly() UNO_QUERY failed ..."); |
371 | 0 | } |
372 | |
|
373 | 0 | if (!xInfo.is()) |
374 | 0 | { |
375 | 0 | OSL_FAIL("ConfigItem::IsReadonly() no prop info available"); |
376 | 0 | continue; |
377 | 0 | } |
378 | | |
379 | 0 | Property aProp = xInfo->getPropertyByName(sProperty); |
380 | 0 | plStates[i] = (aProp.Attributes & PropertyAttribute::READONLY) == PropertyAttribute::READONLY; |
381 | 0 | } |
382 | 0 | catch (const Exception&) |
383 | 0 | { |
384 | 0 | } |
385 | 0 | } |
386 | | |
387 | 0 | return lStates; |
388 | 0 | } |
389 | | |
390 | | Sequence< Any > ConfigItem::GetProperties(const Sequence< OUString >& rNames) |
391 | 41.2k | { |
392 | 41.2k | Reference<XHierarchicalNameAccess> xHierarchyAccess = GetTree(); |
393 | 41.2k | if(xHierarchyAccess.is()) |
394 | 0 | return GetProperties(xHierarchyAccess, rNames, |
395 | 0 | (m_nMode & ConfigItemMode::AllLocales ) == ConfigItemMode::AllLocales); |
396 | 41.2k | return Sequence< Any >(rNames.getLength()); |
397 | 41.2k | } |
398 | | |
399 | | Sequence< Any > ConfigItem::GetProperties( |
400 | | css::uno::Reference<css::container::XHierarchicalNameAccess> const & xHierarchyAccess, |
401 | | const Sequence< OUString >& rNames, |
402 | | bool bAllLocales) |
403 | 0 | { |
404 | 0 | Sequence< Any > aRet(rNames.getLength()); |
405 | 0 | const OUString* pNames = rNames.getConstArray(); |
406 | 0 | Any* pRet = aRet.getArray(); |
407 | 0 | for(int i = 0; i < rNames.getLength(); i++) |
408 | 0 | { |
409 | 0 | try |
410 | 0 | { |
411 | 0 | pRet[i] = xHierarchyAccess->getByHierarchicalName(pNames[i]); |
412 | 0 | } |
413 | 0 | catch (const Exception&) |
414 | 0 | { |
415 | 0 | TOOLS_WARN_EXCEPTION( |
416 | 0 | "unotools.config", |
417 | 0 | "ignoring XHierarchicalNameAccess " << pNames[i]); |
418 | 0 | } |
419 | 0 | } |
420 | | |
421 | | // In special mode "ALL_LOCALES" we must convert localized values to Sequence< PropertyValue >. |
422 | 0 | if(bAllLocales) |
423 | 0 | { |
424 | 0 | Sequence< Any > lValues; |
425 | 0 | impl_packLocalizedProperties( rNames, aRet, lValues ); |
426 | 0 | aRet = std::move(lValues); |
427 | 0 | } |
428 | 0 | return aRet; |
429 | 0 | } |
430 | | |
431 | | bool ConfigItem::PutProperties( const Sequence< OUString >& rNames, |
432 | | const Sequence< Any>& rValues) |
433 | 0 | { |
434 | 0 | ValueCounter_Impl aCounter(m_nInValueChange); |
435 | 0 | Reference<XHierarchicalNameAccess> xHierarchyAccess = GetTree(); |
436 | 0 | Reference<XNameReplace> xTopNodeReplace(xHierarchyAccess, UNO_QUERY); |
437 | 0 | bool bRet = xHierarchyAccess.is() && xTopNodeReplace.is(); |
438 | 0 | if(bRet) |
439 | 0 | { |
440 | 0 | Sequence< OUString > lNames; |
441 | 0 | Sequence< Any > lValues; |
442 | 0 | const OUString* pNames = nullptr; |
443 | 0 | const Any* pValues = nullptr; |
444 | 0 | sal_Int32 nNameCount; |
445 | 0 | if(( m_nMode & ConfigItemMode::AllLocales ) == ConfigItemMode::AllLocales ) |
446 | 0 | { |
447 | | // If ConfigItem works in "ALL_LOCALES"-mode ... we must support a Sequence< PropertyValue > |
448 | | // as value of a localized configuration entry! |
449 | | // How we can do that? |
450 | | // We must split all PropertyValues to "Sequence< OUString >" AND "Sequence< Any >"! |
451 | 0 | impl_unpackLocalizedProperties( rNames, rValues, lNames, lValues ); |
452 | 0 | pNames = lNames.getConstArray (); |
453 | 0 | pValues = lValues.getConstArray (); |
454 | 0 | nNameCount = lNames.getLength (); |
455 | 0 | } |
456 | 0 | else |
457 | 0 | { |
458 | | // This is the normal mode ... |
459 | | // Use given input lists directly. |
460 | 0 | pNames = rNames.getConstArray (); |
461 | 0 | pValues = rValues.getConstArray (); |
462 | 0 | nNameCount = rNames.getLength (); |
463 | 0 | } |
464 | 0 | for(int i = 0; i < nNameCount; i++) |
465 | 0 | { |
466 | 0 | try |
467 | 0 | { |
468 | 0 | OUString sNode, sProperty; |
469 | 0 | if (splitLastFromConfigurationPath(pNames[i],sNode, sProperty)) |
470 | 0 | { |
471 | 0 | Any aNode = xHierarchyAccess->getByHierarchicalName(sNode); |
472 | |
|
473 | 0 | Reference<XNameAccess> xNodeAcc; |
474 | 0 | aNode >>= xNodeAcc; |
475 | 0 | Reference<XNameReplace> xNodeReplace(xNodeAcc, UNO_QUERY); |
476 | 0 | Reference<XNameContainer> xNodeCont (xNodeAcc, UNO_QUERY); |
477 | |
|
478 | 0 | bool bExist = (xNodeAcc.is() && xNodeAcc->hasByName(sProperty)); |
479 | 0 | if (bExist && xNodeReplace.is()) |
480 | 0 | xNodeReplace->replaceByName(sProperty, pValues[i]); |
481 | 0 | else |
482 | 0 | if (!bExist && xNodeCont.is()) |
483 | 0 | xNodeCont->insertByName(sProperty, pValues[i]); |
484 | 0 | else |
485 | 0 | bRet = false; |
486 | 0 | } |
487 | 0 | else //direct value |
488 | 0 | { |
489 | 0 | xTopNodeReplace->replaceByName(sProperty, pValues[i]); |
490 | 0 | } |
491 | 0 | } |
492 | 0 | catch (css::uno::Exception &) |
493 | 0 | { |
494 | 0 | TOOLS_WARN_EXCEPTION("unotools.config", "Exception from PutProperties"); |
495 | 0 | } |
496 | 0 | } |
497 | 0 | try |
498 | 0 | { |
499 | 0 | Reference<XChangesBatch> xBatch(xHierarchyAccess, UNO_QUERY); |
500 | 0 | xBatch->commitChanges(); |
501 | 0 | } |
502 | 0 | catch (css::uno::Exception &) |
503 | 0 | { |
504 | 0 | TOOLS_WARN_EXCEPTION("unotools.config", "Exception from commitChanges"); |
505 | 0 | } |
506 | 0 | } |
507 | | |
508 | 0 | return bRet; |
509 | 0 | } |
510 | | |
511 | | bool ConfigItem::PutProperties( |
512 | | css::uno::Reference<css::container::XHierarchicalNameAccess> const & xHierarchyAccess, |
513 | | const Sequence< OUString >& rNames, |
514 | | const Sequence< Any>& rValues, |
515 | | bool bAllLocales) |
516 | 0 | { |
517 | 0 | Reference<XNameReplace> xTopNodeReplace(xHierarchyAccess, UNO_QUERY); |
518 | 0 | bool bRet = xTopNodeReplace.is(); |
519 | 0 | if(bRet) |
520 | 0 | { |
521 | 0 | Sequence< OUString > lNames; |
522 | 0 | Sequence< Any > lValues; |
523 | 0 | const OUString* pNames = nullptr; |
524 | 0 | const Any* pValues = nullptr; |
525 | 0 | sal_Int32 nNameCount; |
526 | 0 | if(bAllLocales) |
527 | 0 | { |
528 | | // If ConfigItem works in "ALL_LOCALES"-mode ... we must support a Sequence< PropertyValue > |
529 | | // as value of a localized configuration entry! |
530 | | // How we can do that? |
531 | | // We must split all PropertyValues to "Sequence< OUString >" AND "Sequence< Any >"! |
532 | 0 | impl_unpackLocalizedProperties( rNames, rValues, lNames, lValues ); |
533 | 0 | pNames = lNames.getConstArray (); |
534 | 0 | pValues = lValues.getConstArray (); |
535 | 0 | nNameCount = lNames.getLength (); |
536 | 0 | } |
537 | 0 | else |
538 | 0 | { |
539 | | // This is the normal mode ... |
540 | | // Use given input lists directly. |
541 | 0 | pNames = rNames.getConstArray (); |
542 | 0 | pValues = rValues.getConstArray (); |
543 | 0 | nNameCount = rNames.getLength (); |
544 | 0 | } |
545 | 0 | for(int i = 0; i < nNameCount; i++) |
546 | 0 | { |
547 | 0 | try |
548 | 0 | { |
549 | 0 | OUString sNode, sProperty; |
550 | 0 | if (splitLastFromConfigurationPath(pNames[i],sNode, sProperty)) |
551 | 0 | { |
552 | 0 | Any aNode = xHierarchyAccess->getByHierarchicalName(sNode); |
553 | |
|
554 | 0 | Reference<XNameAccess> xNodeAcc; |
555 | 0 | aNode >>= xNodeAcc; |
556 | 0 | Reference<XNameReplace> xNodeReplace(xNodeAcc, UNO_QUERY); |
557 | 0 | Reference<XNameContainer> xNodeCont (xNodeAcc, UNO_QUERY); |
558 | |
|
559 | 0 | bool bExist = (xNodeAcc.is() && xNodeAcc->hasByName(sProperty)); |
560 | 0 | if (bExist && xNodeReplace.is()) |
561 | 0 | xNodeReplace->replaceByName(sProperty, pValues[i]); |
562 | 0 | else |
563 | 0 | if (!bExist && xNodeCont.is()) |
564 | 0 | xNodeCont->insertByName(sProperty, pValues[i]); |
565 | 0 | else |
566 | 0 | bRet = false; |
567 | 0 | } |
568 | 0 | else //direct value |
569 | 0 | { |
570 | 0 | xTopNodeReplace->replaceByName(sProperty, pValues[i]); |
571 | 0 | } |
572 | 0 | } |
573 | 0 | catch (css::uno::Exception &) |
574 | 0 | { |
575 | 0 | TOOLS_WARN_EXCEPTION("unotools.config", "Exception from PutProperties"); |
576 | 0 | } |
577 | 0 | } |
578 | 0 | try |
579 | 0 | { |
580 | 0 | Reference<XChangesBatch> xBatch(xHierarchyAccess, UNO_QUERY); |
581 | 0 | xBatch->commitChanges(); |
582 | 0 | } |
583 | 0 | catch (css::uno::Exception &) |
584 | 0 | { |
585 | 0 | TOOLS_WARN_EXCEPTION("unotools.config", "Exception from commitChanges"); |
586 | 0 | } |
587 | 0 | } |
588 | | |
589 | 0 | return bRet; |
590 | 0 | } |
591 | | |
592 | | void ConfigItem::DisableNotification() |
593 | 4.57k | { |
594 | 4.57k | OSL_ENSURE( xChangeLstnr.is(), "ConfigItem::DisableNotification: notifications not enabled currently!" ); |
595 | 4.57k | RemoveChangesListener(); |
596 | 4.57k | } |
597 | | |
598 | | bool ConfigItem::EnableNotification(const Sequence< OUString >& rNames, |
599 | | bool bEnableInternalNotification ) |
600 | 6.46k | { |
601 | 6.46k | OSL_ENSURE(!(m_nMode & ConfigItemMode::ReleaseTree), "notification in ConfigItemMode::ReleaseTree mode not possible"); |
602 | 6.46k | m_bEnableInternalNotification = bEnableInternalNotification; |
603 | 6.46k | Reference<XHierarchicalNameAccess> xHierarchyAccess = GetTree(); |
604 | 6.46k | Reference<XChangesNotifier> xChgNot(xHierarchyAccess, UNO_QUERY); |
605 | 6.46k | if(!xChgNot.is()) |
606 | 6.46k | return false; |
607 | | |
608 | 0 | OSL_ENSURE(!xChangeLstnr.is(), "EnableNotification already called"); |
609 | 0 | if(xChangeLstnr.is()) |
610 | 0 | xChgNot->removeChangesListener( xChangeLstnr ); |
611 | 0 | bool bRet = true; |
612 | |
|
613 | 0 | try |
614 | 0 | { |
615 | 0 | xChangeLstnr = new ConfigChangeListener_Impl(*this, rNames); |
616 | 0 | xChgNot->addChangesListener( xChangeLstnr ); |
617 | 0 | } |
618 | 0 | catch (const RuntimeException&) |
619 | 0 | { |
620 | 0 | bRet = false; |
621 | 0 | } |
622 | 0 | return bRet; |
623 | 0 | } |
624 | | |
625 | | void ConfigItem::RemoveChangesListener() |
626 | 50.0k | { |
627 | 50.0k | Reference<XHierarchicalNameAccess> xHierarchyAccess = GetTree(); |
628 | 50.0k | if(!xHierarchyAccess.is()) |
629 | 50.0k | return; |
630 | | |
631 | 0 | Reference<XChangesNotifier> xChgNot(xHierarchyAccess, UNO_QUERY); |
632 | 0 | if(xChgNot.is() && xChangeLstnr.is()) |
633 | 0 | { |
634 | 0 | try |
635 | 0 | { |
636 | 0 | xChgNot->removeChangesListener( xChangeLstnr ); |
637 | 0 | xChangeLstnr = nullptr; |
638 | 0 | } |
639 | 0 | catch (const Exception&) |
640 | 0 | { |
641 | 0 | } |
642 | 0 | } |
643 | 0 | } |
644 | | |
645 | | static void lcl_normalizeLocalNames(Sequence< OUString >& _rNames, ConfigNameFormat _eFormat, Reference<XInterface> const& _xParentNode) |
646 | 0 | { |
647 | 0 | switch (_eFormat) |
648 | 0 | { |
649 | 0 | case ConfigNameFormat::LocalNode: |
650 | | // unaltered - this is our input format |
651 | 0 | break; |
652 | | |
653 | 0 | case ConfigNameFormat::LocalPath: |
654 | 0 | { |
655 | 0 | Reference<XTemplateContainer> xTypeContainer(_xParentNode, UNO_QUERY); |
656 | 0 | if (xTypeContainer.is()) |
657 | 0 | { |
658 | 0 | OUString sTypeName = xTypeContainer->getElementTemplateName(); |
659 | 0 | sTypeName = sTypeName.copy(sTypeName.lastIndexOf('/')+1); |
660 | |
|
661 | 0 | std::transform(std::cbegin(_rNames), std::cend(_rNames), _rNames.getArray(), |
662 | 0 | [&sTypeName](const OUString& rName) -> OUString { return wrapConfigurationElementName(rName,sTypeName); }); |
663 | 0 | } |
664 | 0 | else |
665 | 0 | { |
666 | 0 | Reference<XServiceInfo> xSVI(_xParentNode, UNO_QUERY); |
667 | 0 | if (xSVI.is() && xSVI->supportsService(u"com.sun.star.configuration.SetAccess"_ustr)) |
668 | 0 | { |
669 | 0 | std::transform(std::cbegin(_rNames), std::cend(_rNames), _rNames.getArray(), |
670 | 0 | [](const OUString& rName) -> OUString { return wrapConfigurationElementName(rName); }); |
671 | 0 | } |
672 | 0 | } |
673 | 0 | } |
674 | 0 | break; |
675 | |
|
676 | 0 | } |
677 | 0 | } |
678 | | |
679 | | Sequence< OUString > ConfigItem::GetNodeNames(const OUString& rNode) |
680 | 19 | { |
681 | 19 | ConfigNameFormat const eDefaultFormat = ConfigNameFormat::LocalNode; // CONFIG_NAME_DEFAULT; |
682 | | |
683 | 19 | return GetNodeNames(rNode, eDefaultFormat); |
684 | 19 | } |
685 | | |
686 | | Sequence< OUString > ConfigItem::GetNodeNames(const OUString& rNode, ConfigNameFormat eFormat) |
687 | 55 | { |
688 | 55 | Reference<XHierarchicalNameAccess> xHierarchyAccess = GetTree(); |
689 | 55 | if(xHierarchyAccess.is()) |
690 | 0 | return GetNodeNames(xHierarchyAccess, rNode, eFormat); |
691 | 55 | return Sequence< OUString >(); |
692 | 55 | } |
693 | | |
694 | | Sequence< OUString > ConfigItem::GetNodeNames( |
695 | | css::uno::Reference<css::container::XHierarchicalNameAccess> const & xHierarchyAccess, |
696 | | const OUString& rNode, |
697 | | ConfigNameFormat eFormat) |
698 | 0 | { |
699 | 0 | Sequence< OUString > aRet; |
700 | 0 | try |
701 | 0 | { |
702 | 0 | Reference<XNameAccess> xCont; |
703 | 0 | if(!rNode.isEmpty()) |
704 | 0 | { |
705 | 0 | Any aNode = xHierarchyAccess->getByHierarchicalName(rNode); |
706 | 0 | aNode >>= xCont; |
707 | 0 | } |
708 | 0 | else |
709 | 0 | xCont.set(xHierarchyAccess, UNO_QUERY); |
710 | 0 | if(xCont.is()) |
711 | 0 | { |
712 | 0 | aRet = xCont->getElementNames(); |
713 | 0 | lcl_normalizeLocalNames(aRet,eFormat,xCont); |
714 | 0 | } |
715 | |
|
716 | 0 | } |
717 | 0 | catch (css::uno::Exception &) |
718 | 0 | { |
719 | 0 | TOOLS_WARN_EXCEPTION("unotools.config", "Exception from GetNodeNames"); |
720 | 0 | } |
721 | 0 | return aRet; |
722 | 0 | } |
723 | | |
724 | | bool ConfigItem::ClearNodeSet(const OUString& rNode) |
725 | 0 | { |
726 | 0 | ValueCounter_Impl aCounter(m_nInValueChange); |
727 | 0 | bool bRet = false; |
728 | 0 | Reference<XHierarchicalNameAccess> xHierarchyAccess = GetTree(); |
729 | 0 | if(xHierarchyAccess.is()) |
730 | 0 | bRet = ClearNodeSet(xHierarchyAccess, rNode); |
731 | 0 | return bRet; |
732 | 0 | } |
733 | | |
734 | | bool ConfigItem::ClearNodeSet( |
735 | | css::uno::Reference<css::container::XHierarchicalNameAccess> const & xHierarchyAccess, |
736 | | const OUString& rNode) |
737 | 0 | { |
738 | 0 | bool bRet = false; |
739 | 0 | try |
740 | 0 | { |
741 | 0 | Reference<XNameContainer> xCont; |
742 | 0 | if(!rNode.isEmpty()) |
743 | 0 | { |
744 | 0 | Any aNode = xHierarchyAccess->getByHierarchicalName(rNode); |
745 | 0 | aNode >>= xCont; |
746 | 0 | } |
747 | 0 | else |
748 | 0 | xCont.set(xHierarchyAccess, UNO_QUERY); |
749 | 0 | if(!xCont.is()) |
750 | 0 | return false; |
751 | 0 | const Sequence< OUString > aNames = xCont->getElementNames(); |
752 | 0 | Reference<XChangesBatch> xBatch(xHierarchyAccess, UNO_QUERY); |
753 | 0 | for(const OUString& rName : aNames) |
754 | 0 | { |
755 | 0 | try |
756 | 0 | { |
757 | 0 | xCont->removeByName(rName); |
758 | 0 | } |
759 | 0 | catch (css::uno::Exception &) |
760 | 0 | { |
761 | 0 | TOOLS_WARN_EXCEPTION("unotools.config", "Exception from removeByName"); |
762 | 0 | } |
763 | 0 | } |
764 | 0 | xBatch->commitChanges(); |
765 | 0 | bRet = true; |
766 | 0 | } |
767 | 0 | catch (css::uno::Exception &) |
768 | 0 | { |
769 | 0 | TOOLS_WARN_EXCEPTION("unotools.config", "Exception from ClearNodeSet"); |
770 | 0 | } |
771 | 0 | return bRet; |
772 | 0 | } |
773 | | |
774 | | bool ConfigItem::ClearNodeElements(const OUString& rNode, Sequence< OUString > const & rElements) |
775 | 0 | { |
776 | 0 | ValueCounter_Impl aCounter(m_nInValueChange); |
777 | 0 | bool bRet = false; |
778 | 0 | Reference<XHierarchicalNameAccess> xHierarchyAccess = GetTree(); |
779 | 0 | if(xHierarchyAccess.is()) |
780 | 0 | { |
781 | 0 | try |
782 | 0 | { |
783 | 0 | Reference<XNameContainer> xCont; |
784 | 0 | if(!rNode.isEmpty()) |
785 | 0 | { |
786 | 0 | Any aNode = xHierarchyAccess->getByHierarchicalName(rNode); |
787 | 0 | aNode >>= xCont; |
788 | 0 | } |
789 | 0 | else |
790 | 0 | xCont.set(xHierarchyAccess, UNO_QUERY); |
791 | 0 | if(!xCont.is()) |
792 | 0 | return false; |
793 | 0 | try |
794 | 0 | { |
795 | 0 | for(const OUString& rElement : rElements) |
796 | 0 | { |
797 | 0 | xCont->removeByName(rElement); |
798 | 0 | } |
799 | 0 | Reference<XChangesBatch> xBatch(xHierarchyAccess, UNO_QUERY); |
800 | 0 | xBatch->commitChanges(); |
801 | 0 | } |
802 | 0 | catch (css::uno::Exception &) |
803 | 0 | { |
804 | 0 | TOOLS_WARN_EXCEPTION("unotools.config", "Exception from commitChanges()"); |
805 | 0 | } |
806 | 0 | bRet = true; |
807 | 0 | } |
808 | 0 | catch (css::uno::Exception &) |
809 | 0 | { |
810 | 0 | TOOLS_WARN_EXCEPTION("unotools.config", "Exception from GetNodeNames()"); |
811 | 0 | } |
812 | 0 | } |
813 | 0 | return bRet; |
814 | 0 | } |
815 | | |
816 | | static OUString lcl_extractSetPropertyName( const OUString& rInPath, std::u16string_view rPrefix ) |
817 | 0 | { |
818 | 0 | OUString const sSubPath = dropPrefixFromConfigurationPath( rInPath, rPrefix); |
819 | 0 | return extractFirstFromConfigurationPath( sSubPath ); |
820 | 0 | } |
821 | | |
822 | | static |
823 | | Sequence< OUString > lcl_extractSetPropertyNames( const Sequence< PropertyValue >& rValues, std::u16string_view rPrefix ) |
824 | 0 | { |
825 | 0 | Sequence< OUString > aSubNodeNames(rValues.getLength()); |
826 | 0 | OUString* pSubNodeNames = aSubNodeNames.getArray(); |
827 | |
|
828 | 0 | OUString sLastSubNode; |
829 | 0 | sal_Int32 nSubIndex = 0; |
830 | |
|
831 | 0 | for(const PropertyValue& rProperty : rValues) |
832 | 0 | { |
833 | 0 | OUString const sSubPath = dropPrefixFromConfigurationPath( rProperty.Name, rPrefix); |
834 | 0 | OUString const sSubNode = extractFirstFromConfigurationPath( sSubPath ); |
835 | |
|
836 | 0 | if(sLastSubNode != sSubNode) |
837 | 0 | { |
838 | 0 | pSubNodeNames[nSubIndex++] = sSubNode; |
839 | 0 | } |
840 | |
|
841 | 0 | sLastSubNode = sSubNode; |
842 | 0 | } |
843 | 0 | aSubNodeNames.realloc(nSubIndex); |
844 | |
|
845 | 0 | return aSubNodeNames; |
846 | 0 | } |
847 | | |
848 | | // Add or change properties |
849 | | bool ConfigItem::SetSetProperties( |
850 | | const OUString& rNode, const Sequence< PropertyValue >& rValues) |
851 | 0 | { |
852 | 0 | ValueCounter_Impl aCounter(m_nInValueChange); |
853 | 0 | Reference<XHierarchicalNameAccess> xHierarchyAccess = GetTree(); |
854 | 0 | if(!xHierarchyAccess.is()) |
855 | 0 | return true; |
856 | 0 | return SetSetProperties(xHierarchyAccess, rNode, rValues); |
857 | 0 | } |
858 | | |
859 | | // Add or change properties |
860 | | bool ConfigItem::SetSetProperties( |
861 | | css::uno::Reference<css::container::XHierarchicalNameAccess> const & xHierarchyAccess, |
862 | | const OUString& rNode, const Sequence< PropertyValue >& rValues) |
863 | 0 | { |
864 | 0 | bool bRet = true; |
865 | 0 | Reference<XChangesBatch> xBatch(xHierarchyAccess, UNO_QUERY); |
866 | 0 | try |
867 | 0 | { |
868 | 0 | Reference<XNameContainer> xCont; |
869 | 0 | if(!rNode.isEmpty()) |
870 | 0 | { |
871 | 0 | Any aNode = xHierarchyAccess->getByHierarchicalName(rNode); |
872 | 0 | aNode >>= xCont; |
873 | 0 | } |
874 | 0 | else |
875 | 0 | xCont.set(xHierarchyAccess, UNO_QUERY); |
876 | 0 | if(!xCont.is()) |
877 | 0 | return false; |
878 | | |
879 | 0 | Reference<XSingleServiceFactory> xFac(xCont, UNO_QUERY); |
880 | |
|
881 | 0 | if(xFac.is()) |
882 | 0 | { |
883 | 0 | const Sequence< OUString > aSubNodeNames = lcl_extractSetPropertyNames(rValues, rNode); |
884 | |
|
885 | 0 | for(const auto& rSubNodeName : aSubNodeNames) |
886 | 0 | { |
887 | 0 | if(!xCont->hasByName(rSubNodeName)) |
888 | 0 | { |
889 | 0 | Reference<XInterface> xInst = xFac->createInstance(); |
890 | 0 | Any aVal; aVal <<= xInst; |
891 | 0 | xCont->insertByName(rSubNodeName, aVal); |
892 | 0 | } |
893 | | //set values |
894 | 0 | } |
895 | 0 | try |
896 | 0 | { |
897 | 0 | xBatch->commitChanges(); |
898 | 0 | } |
899 | 0 | catch (css::uno::Exception &) |
900 | 0 | { |
901 | 0 | TOOLS_WARN_EXCEPTION("unotools.config", "Exception from commitChanges()"); |
902 | 0 | } |
903 | | |
904 | 0 | const PropertyValue* pProperties = rValues.getConstArray(); |
905 | |
|
906 | 0 | Sequence< OUString > aSetNames(rValues.getLength()); |
907 | 0 | OUString* pSetNames = aSetNames.getArray(); |
908 | |
|
909 | 0 | Sequence< Any> aSetValues(rValues.getLength()); |
910 | 0 | Any* pSetValues = aSetValues.getArray(); |
911 | |
|
912 | 0 | bool bEmptyNode = rNode.isEmpty(); |
913 | 0 | for(sal_Int32 k = 0; k < rValues.getLength(); k++) |
914 | 0 | { |
915 | 0 | pSetNames[k] = pProperties[k].Name.copy( bEmptyNode ? 1 : 0); |
916 | 0 | pSetValues[k] = pProperties[k].Value; |
917 | 0 | } |
918 | 0 | bRet = PutProperties(xHierarchyAccess, aSetNames, aSetValues, /*bAllLocales*/false); |
919 | 0 | } |
920 | 0 | else |
921 | 0 | { |
922 | | //if no factory is available then the node contains basic data elements |
923 | 0 | for(const PropertyValue& rValue : rValues) |
924 | 0 | { |
925 | 0 | try |
926 | 0 | { |
927 | 0 | OUString sSubNode = lcl_extractSetPropertyName( rValue.Name, rNode ); |
928 | |
|
929 | 0 | if(xCont->hasByName(sSubNode)) |
930 | 0 | xCont->replaceByName(sSubNode, rValue.Value); |
931 | 0 | else |
932 | 0 | xCont->insertByName(sSubNode, rValue.Value); |
933 | |
|
934 | 0 | OSL_ENSURE( xHierarchyAccess->hasByHierarchicalName(rValue.Name), |
935 | 0 | "Invalid config path" ); |
936 | 0 | } |
937 | 0 | catch (css::uno::Exception &) |
938 | 0 | { |
939 | 0 | TOOLS_WARN_EXCEPTION("unotools.config", "Exception from insert/replaceByName()"); |
940 | 0 | } |
941 | 0 | } |
942 | 0 | xBatch->commitChanges(); |
943 | 0 | } |
944 | 0 | } |
945 | 0 | catch (const Exception&) |
946 | 0 | { |
947 | 0 | TOOLS_WARN_EXCEPTION("unotools.config", "Exception from SetSetProperties"); |
948 | 0 | bRet = false; |
949 | 0 | } |
950 | 0 | return bRet; |
951 | 0 | } |
952 | | |
953 | | bool ConfigItem::ReplaceSetProperties( |
954 | | const OUString& rNode, const Sequence< PropertyValue >& rValues) |
955 | 0 | { |
956 | 0 | ValueCounter_Impl aCounter(m_nInValueChange); |
957 | 0 | bool bRet = true; |
958 | 0 | Reference<XHierarchicalNameAccess> xHierarchyAccess = GetTree(); |
959 | 0 | if(xHierarchyAccess.is()) |
960 | 0 | bRet = ReplaceSetProperties(xHierarchyAccess, rNode, rValues, |
961 | 0 | ( m_nMode & ConfigItemMode::AllLocales ) == ConfigItemMode::AllLocales); |
962 | 0 | return bRet; |
963 | 0 | } |
964 | | |
965 | | bool ConfigItem::ReplaceSetProperties( |
966 | | css::uno::Reference<css::container::XHierarchicalNameAccess> const & xHierarchyAccess, |
967 | | const OUString& rNode, |
968 | | const Sequence< PropertyValue >& rValues, |
969 | | bool bAllLocales) |
970 | 0 | { |
971 | 0 | bool bRet = true; |
972 | 0 | Reference<XChangesBatch> xBatch(xHierarchyAccess, UNO_QUERY); |
973 | 0 | try |
974 | 0 | { |
975 | 0 | Reference<XNameContainer> xCont; |
976 | 0 | if(!rNode.isEmpty()) |
977 | 0 | { |
978 | 0 | Any aNode = xHierarchyAccess->getByHierarchicalName(rNode); |
979 | 0 | aNode >>= xCont; |
980 | 0 | } |
981 | 0 | else |
982 | 0 | xCont.set(xHierarchyAccess, UNO_QUERY); |
983 | 0 | if(!xCont.is()) |
984 | 0 | return false; |
985 | | |
986 | | // JB: Change: now the same name handling for sets of simple values |
987 | 0 | const Sequence< OUString > aSubNodeNames = lcl_extractSetPropertyNames(rValues, rNode); |
988 | |
|
989 | 0 | Reference<XSingleServiceFactory> xFac(xCont, UNO_QUERY); |
990 | 0 | const bool isSimpleValueSet = !xFac.is(); |
991 | | |
992 | | //remove unknown members first |
993 | 0 | { |
994 | 0 | const Sequence<OUString> aContainerSubNodes = xCont->getElementNames(); |
995 | |
|
996 | 0 | for(const OUString& rContainerSubNode : aContainerSubNodes) |
997 | 0 | { |
998 | 0 | bool bFound = comphelper::findValue(aSubNodeNames, rContainerSubNode) != -1; |
999 | 0 | if(!bFound) |
1000 | 0 | try |
1001 | 0 | { |
1002 | 0 | xCont->removeByName(rContainerSubNode); |
1003 | 0 | } |
1004 | 0 | catch (const Exception&) |
1005 | 0 | { |
1006 | 0 | if (isSimpleValueSet) |
1007 | 0 | { |
1008 | 0 | try |
1009 | 0 | { |
1010 | | // #i37322#: fallback action: replace with <void/> |
1011 | 0 | xCont->replaceByName(rContainerSubNode, Any()); |
1012 | | // fallback successful: continue looping |
1013 | 0 | continue; |
1014 | 0 | } |
1015 | 0 | catch (Exception &) |
1016 | 0 | {} // propagate original exception, if fallback fails |
1017 | 0 | } |
1018 | 0 | throw; |
1019 | 0 | } |
1020 | 0 | } |
1021 | 0 | try { xBatch->commitChanges(); } |
1022 | 0 | catch (css::uno::Exception &) |
1023 | 0 | { |
1024 | 0 | TOOLS_WARN_EXCEPTION("unotools.config", "Exception from commitChanges"); |
1025 | 0 | } |
1026 | 0 | } |
1027 | | |
1028 | 0 | if(xFac.is()) // !isSimpleValueSet |
1029 | 0 | { |
1030 | 0 | for(const OUString& rSubNodeName : aSubNodeNames) |
1031 | 0 | { |
1032 | 0 | if(!xCont->hasByName(rSubNodeName)) |
1033 | 0 | { |
1034 | | //create if not available |
1035 | 0 | Reference<XInterface> xInst = xFac->createInstance(); |
1036 | 0 | Any aVal; aVal <<= xInst; |
1037 | 0 | xCont->insertByName(rSubNodeName, aVal); |
1038 | 0 | } |
1039 | 0 | } |
1040 | 0 | try { xBatch->commitChanges(); } |
1041 | 0 | catch (css::uno::Exception &) |
1042 | 0 | { |
1043 | 0 | TOOLS_WARN_EXCEPTION("unotools.config", "Exception from commitChanges"); |
1044 | 0 | } |
1045 | | |
1046 | 0 | const PropertyValue* pProperties = rValues.getConstArray(); |
1047 | |
|
1048 | 0 | Sequence< OUString > aSetNames(rValues.getLength()); |
1049 | 0 | OUString* pSetNames = aSetNames.getArray(); |
1050 | |
|
1051 | 0 | Sequence< Any> aSetValues(rValues.getLength()); |
1052 | 0 | Any* pSetValues = aSetValues.getArray(); |
1053 | |
|
1054 | 0 | bool bEmptyNode = rNode.isEmpty(); |
1055 | 0 | for(sal_Int32 k = 0; k < rValues.getLength(); k++) |
1056 | 0 | { |
1057 | 0 | pSetNames[k] = pProperties[k].Name.copy( bEmptyNode ? 1 : 0); |
1058 | 0 | pSetValues[k] = pProperties[k].Value; |
1059 | 0 | } |
1060 | 0 | bRet = PutProperties(xHierarchyAccess, aSetNames, aSetValues, bAllLocales); |
1061 | 0 | } |
1062 | 0 | else |
1063 | 0 | { |
1064 | | //if no factory is available then the node contains basic data elements |
1065 | 0 | for(const PropertyValue& rValue : rValues) |
1066 | 0 | { |
1067 | 0 | try |
1068 | 0 | { |
1069 | 0 | OUString sSubNode = lcl_extractSetPropertyName( rValue.Name, rNode ); |
1070 | |
|
1071 | 0 | if(xCont->hasByName(sSubNode)) |
1072 | 0 | xCont->replaceByName(sSubNode, rValue.Value); |
1073 | 0 | else |
1074 | 0 | xCont->insertByName(sSubNode, rValue.Value); |
1075 | 0 | } |
1076 | 0 | catch (css::uno::Exception &) |
1077 | 0 | { |
1078 | 0 | TOOLS_WARN_EXCEPTION("unotools.config", "Exception from insert/replaceByName"); |
1079 | 0 | } |
1080 | 0 | } |
1081 | 0 | xBatch->commitChanges(); |
1082 | 0 | } |
1083 | 0 | } |
1084 | 0 | catch (const Exception& ) |
1085 | 0 | { |
1086 | 0 | TOOLS_WARN_EXCEPTION("unotools.config", "Exception from ReplaceSetProperties"); |
1087 | 0 | bRet = false; |
1088 | 0 | } |
1089 | 0 | return bRet; |
1090 | 0 | } |
1091 | | |
1092 | | bool ConfigItem::AddNode(const OUString& rNode, const OUString& rNewNode) |
1093 | 0 | { |
1094 | 0 | ValueCounter_Impl aCounter(m_nInValueChange); |
1095 | 0 | bool bRet = true; |
1096 | 0 | Reference<XHierarchicalNameAccess> xHierarchyAccess = GetTree(); |
1097 | 0 | if(xHierarchyAccess.is()) |
1098 | 0 | { |
1099 | 0 | Reference<XChangesBatch> xBatch(xHierarchyAccess, UNO_QUERY); |
1100 | 0 | try |
1101 | 0 | { |
1102 | 0 | Reference<XNameContainer> xCont; |
1103 | 0 | if(!rNode.isEmpty()) |
1104 | 0 | { |
1105 | 0 | Any aNode = xHierarchyAccess->getByHierarchicalName(rNode); |
1106 | 0 | aNode >>= xCont; |
1107 | 0 | } |
1108 | 0 | else |
1109 | 0 | xCont.set(xHierarchyAccess, UNO_QUERY); |
1110 | 0 | if(!xCont.is()) |
1111 | 0 | return false; |
1112 | | |
1113 | 0 | Reference<XSingleServiceFactory> xFac(xCont, UNO_QUERY); |
1114 | |
|
1115 | 0 | if(xFac.is()) |
1116 | 0 | { |
1117 | 0 | if(!xCont->hasByName(rNewNode)) |
1118 | 0 | { |
1119 | 0 | Reference<XInterface> xInst = xFac->createInstance(); |
1120 | 0 | Any aVal; aVal <<= xInst; |
1121 | 0 | xCont->insertByName(rNewNode, aVal); |
1122 | 0 | } |
1123 | 0 | try |
1124 | 0 | { |
1125 | 0 | xBatch->commitChanges(); |
1126 | 0 | } |
1127 | 0 | catch (css::uno::Exception &) |
1128 | 0 | { |
1129 | 0 | TOOLS_WARN_EXCEPTION("unotools.config", "Exception from commitChanges"); |
1130 | 0 | } |
1131 | 0 | } |
1132 | 0 | else |
1133 | 0 | { |
1134 | | //if no factory is available then the node contains basic data elements |
1135 | 0 | try |
1136 | 0 | { |
1137 | 0 | if(!xCont->hasByName(rNewNode)) |
1138 | 0 | xCont->insertByName(rNewNode, Any()); |
1139 | 0 | } |
1140 | 0 | catch (css::uno::Exception &) |
1141 | 0 | { |
1142 | 0 | TOOLS_WARN_EXCEPTION("unotools.config", "Exception from AddNode"); |
1143 | 0 | } |
1144 | 0 | } |
1145 | 0 | xBatch->commitChanges(); |
1146 | 0 | } |
1147 | 0 | catch (const Exception&) |
1148 | 0 | { |
1149 | 0 | DBG_UNHANDLED_EXCEPTION("unotools.config"); |
1150 | 0 | bRet = false; |
1151 | 0 | } |
1152 | 0 | } |
1153 | 0 | return bRet; |
1154 | 0 | } |
1155 | | |
1156 | | |
1157 | | void ConfigItem::SetModified() |
1158 | 2 | { |
1159 | 2 | m_bIsModified = true; |
1160 | 2 | } |
1161 | | |
1162 | | void ConfigItem::ClearModified() |
1163 | 14 | { |
1164 | 14 | m_bIsModified = false; |
1165 | 14 | } |
1166 | | |
1167 | | Reference< XHierarchicalNameAccess> ConfigItem::GetTree() |
1168 | 99.4k | { |
1169 | 99.4k | Reference< XHierarchicalNameAccess> xRet; |
1170 | 99.4k | if (comphelper::IsFuzzing()) |
1171 | 99.4k | return xRet; |
1172 | 0 | if(!m_xHierarchyAccess.is()) |
1173 | 0 | xRet = ConfigManager::acquireTree(*this); |
1174 | 0 | else |
1175 | 0 | xRet = m_xHierarchyAccess; |
1176 | 0 | return xRet; |
1177 | 99.4k | } |
1178 | | |
1179 | | void ConfigItem::Commit() |
1180 | 0 | { |
1181 | 0 | ImplCommit(); |
1182 | 0 | ClearModified(); |
1183 | 0 | } |
1184 | | |
1185 | | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |