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