Coverage Report

Created: 2025-12-31 10:39

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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: */