Coverage Report

Created: 2026-05-16 09:25

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/configmgr/source/access.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 <cassert>
23
#include <cstdlib>
24
#include <utility>
25
#include <vector>
26
27
#include <com/sun/star/beans/Property.hpp>
28
#include <com/sun/star/beans/PropertyAttribute.hpp>
29
#include <com/sun/star/beans/PropertyChangeEvent.hpp>
30
#include <com/sun/star/beans/UnknownPropertyException.hpp>
31
#include <com/sun/star/beans/XExactName.hpp>
32
#include <com/sun/star/beans/XHierarchicalPropertySet.hpp>
33
#include <com/sun/star/beans/XHierarchicalPropertySetInfo.hpp>
34
#include <com/sun/star/beans/XMultiHierarchicalPropertySet.hpp>
35
#include <com/sun/star/beans/XMultiPropertySet.hpp>
36
#include <com/sun/star/beans/XPropertiesChangeListener.hpp>
37
#include <com/sun/star/beans/XProperty.hpp>
38
#include <com/sun/star/beans/XPropertyChangeListener.hpp>
39
#include <com/sun/star/beans/XPropertySet.hpp>
40
#include <com/sun/star/beans/XPropertySetInfo.hpp>
41
#include <com/sun/star/beans/XVetoableChangeListener.hpp>
42
#include <com/sun/star/container/ContainerEvent.hpp>
43
#include <com/sun/star/container/NoSuchElementException.hpp>
44
#include <com/sun/star/container/XContainer.hpp>
45
#include <com/sun/star/container/XContainerListener.hpp>
46
#include <com/sun/star/container/XElementAccess.hpp>
47
#include <com/sun/star/container/XHierarchicalName.hpp>
48
#include <com/sun/star/container/XHierarchicalNameAccess.hpp>
49
#include <com/sun/star/container/XHierarchicalNameReplace.hpp>
50
#include <com/sun/star/container/XNameAccess.hpp>
51
#include <com/sun/star/container/XNameContainer.hpp>
52
#include <com/sun/star/container/XNamed.hpp>
53
#include <com/sun/star/lang/DisposedException.hpp>
54
#include <com/sun/star/lang/EventObject.hpp>
55
#include <com/sun/star/lang/IllegalArgumentException.hpp>
56
#include <com/sun/star/lang/XComponent.hpp>
57
#include <com/sun/star/lang/XEventListener.hpp>
58
#include <com/sun/star/lang/XServiceInfo.hpp>
59
#include <com/sun/star/lang/XSingleServiceFactory.hpp>
60
#include <com/sun/star/lang/XTypeProvider.hpp>
61
#include <com/sun/star/uno/Any.hxx>
62
#include <com/sun/star/uno/Reference.hxx>
63
#include <com/sun/star/uno/RuntimeException.hpp>
64
#include <com/sun/star/uno/Sequence.hxx>
65
#include <com/sun/star/uno/Type.hxx>
66
#include <com/sun/star/uno/XInterface.hpp>
67
#include <com/sun/star/uno/XWeak.hpp>
68
#include <com/sun/star/util/ElementChange.hpp>
69
#include <com/sun/star/util/InvalidStateException.hpp>
70
#include <comphelper/sequence.hxx>
71
#include <comphelper/string.hxx>
72
#include <comphelper/lok.hxx>
73
#include <i18nlangtag/languagetag.hxx>
74
#include <cppu/unotype.hxx>
75
#include <cppuhelper/queryinterface.hxx>
76
#include <cppuhelper/supportsservice.hxx>
77
#include <cppuhelper/weak.hxx>
78
#include <osl/interlck.h>
79
#include <osl/mutex.hxx>
80
#include <rtl/character.hxx>
81
#include <rtl/ref.hxx>
82
#include <rtl/ustrbuf.hxx>
83
#include <rtl/ustring.hxx>
84
#include <sal/log.hxx>
85
#include <sal/types.h>
86
#include <o3tl/string_view.hxx>
87
88
#include "access.hxx"
89
#include "broadcaster.hxx"
90
#include "childaccess.hxx"
91
#include "components.hxx"
92
#include "data.hxx"
93
#include "groupnode.hxx"
94
#include "localizedpropertynode.hxx"
95
#include "localizedvaluenode.hxx"
96
#include "lock.hxx"
97
#include "modifications.hxx"
98
#include "node.hxx"
99
#include "nodemap.hxx"
100
#include "propertynode.hxx"
101
#include "rootaccess.hxx"
102
#include "setnode.hxx"
103
#include "type.hxx"
104
105
namespace configmgr {
106
107
namespace {
108
109
// Conservatively forbid what is either not an XML Char (including lone
110
// surrogates, even though they should not appear in well-formed UNO OUString
111
// instances anyway), or is a slash (as it causes problems in path syntax):
112
0
bool isValidName(std::u16string_view name, bool setMember) {
113
0
    for (std::size_t i = 0; i != name.size();) {
114
0
        sal_uInt32 c = o3tl::iterateCodePoints(name, &i);
115
0
        if ((c < 0x20 && !(c == 0x09 || c == 0x0A || c == 0x0D))
116
0
            || rtl::isSurrogate(c) || c == 0xFFFE || c == 0xFFFF
117
0
            || (!setMember && c == '/'))
118
0
        {
119
0
            return false;
120
0
        }
121
0
    }
122
0
    return !name.empty();
123
0
}
124
125
}
126
127
0
oslInterlockedCount Access::acquireCounting() {
128
0
    return osl_atomic_increment(&m_refCount);
129
0
}
130
131
0
void Access::releaseNondeleting() {
132
#if defined __GNUC__ && !defined __clang__ && __GNUC__ == 15
133
#pragma GCC diagnostic push
134
#pragma GCC diagnostic ignored "-Wstringop-overflow"
135
#endif
136
0
    osl_atomic_decrement(&m_refCount);
137
#if defined __GNUC__ && !defined __clang__ && __GNUC__ == 15
138
#pragma GCC diagnostic pop
139
#endif
140
0
}
141
142
39.8k
bool Access::isValue() {
143
39.8k
    const rtl::Reference< Node > & p(getNode());
144
39.8k
    switch (p->kind()) {
145
0
    case Node::KIND_PROPERTY:
146
0
    case Node::KIND_LOCALIZED_VALUE:
147
0
        return true;
148
0
    case Node::KIND_LOCALIZED_PROPERTY:
149
0
        return !Components::allLocales(getRootAccess()->getLocale());
150
0
    default:
151
0
        return false;
152
39.8k
    }
153
39.8k
}
154
155
0
void Access::markChildAsModified(rtl::Reference< ChildAccess > const & child) {
156
0
    assert(child.is() && child->getParentAccess() == this);
157
0
    modifiedChildren_[child->getNameInternal()] = ModifiedChild(child, true);
158
0
    for (rtl::Reference< Access > p(this);;) {
159
0
        rtl::Reference< Access > parent(p->getParentAccess());
160
0
        if (!parent.is()) {
161
0
            break;
162
0
        }
163
0
        assert(dynamic_cast< ChildAccess * >(p.get()) != nullptr);
164
0
        parent->modifiedChildren_.emplace(
165
0
                p->getNameInternal(),
166
0
                ModifiedChild(static_cast< ChildAccess * >(p.get()), false));
167
0
        p = std::move(parent);
168
0
    }
169
0
}
170
171
0
void Access::releaseChild(OUString const & name) {
172
0
    cachedChildren_.erase(name);
173
0
}
174
175
void Access::initBroadcaster(
176
    Modifications::Node const & modifications, Broadcaster * broadcaster)
177
0
{
178
0
    initBroadcasterAndChanges(modifications, broadcaster, nullptr);
179
0
}
180
181
css::uno::Sequence< css::uno::Type > Access::getTypes()
182
0
{
183
0
    assert(thisIs(IS_ANY));
184
0
    osl::MutexGuard g(*lock_);
185
0
    checkLocalizedPropertyAccess();
186
0
    std::vector< css::uno::Type > types { cppu::UnoType< css::uno::XInterface >::get(),
187
0
                                          cppu::UnoType< css::uno::XWeak >::get(),
188
0
                                          cppu::UnoType< css::lang::XTypeProvider >::get(),
189
0
                                          cppu::UnoType< css::lang::XServiceInfo >::get(),
190
0
                                          cppu::UnoType< css::lang::XComponent >::get(),
191
0
                                          cppu::UnoType< css::container::XContainer >::get(),
192
0
                                          cppu::UnoType< css::beans::XExactName >::get(),
193
0
                                          cppu::UnoType< css::container::XHierarchicalName >::get(),
194
0
                                          cppu::UnoType< css::container::XNamed >::get(),
195
0
                                          cppu::UnoType< css::beans::XProperty >::get(),
196
0
                                          cppu::UnoType< css::container::XElementAccess >::get(),
197
0
                                          cppu::UnoType< css::container::XNameAccess >::get()
198
0
                                        };
199
0
    if (getNode()->kind() == Node::KIND_GROUP) {
200
0
        types.push_back(cppu::UnoType< css::beans::XPropertySetInfo >::get());
201
0
        types.push_back(cppu::UnoType< css::beans::XPropertySet >::get());
202
0
        types.push_back(cppu::UnoType< css::beans::XMultiPropertySet >::get());
203
0
        types.push_back(
204
0
            cppu::UnoType< css::beans::XHierarchicalPropertySet >::get());
205
0
        types.push_back(
206
0
            cppu::UnoType< css::beans::XMultiHierarchicalPropertySet >::get());
207
0
        types.push_back(
208
0
            cppu::UnoType< css::beans::XHierarchicalPropertySetInfo >::get());
209
0
    }
210
0
    if (getRootAccess()->isUpdate()) {
211
0
        types.push_back(cppu::UnoType< css::container::XNameReplace >::get());
212
0
        types.push_back(
213
0
            cppu::UnoType< css::container::XHierarchicalNameReplace >::get());
214
0
        if (getNode()->kind() != Node::KIND_GROUP ||
215
0
            static_cast< GroupNode * >(getNode().get())->isExtensible())
216
0
        {
217
0
            types.push_back(
218
0
                cppu::UnoType< css::container::XNameContainer >::get());
219
0
        }
220
0
        if (getNode()->kind() == Node::KIND_SET) {
221
0
            types.push_back(
222
0
                cppu::UnoType< css::lang::XSingleServiceFactory >::get());
223
0
        }
224
0
    } else {
225
0
        types.push_back(
226
0
            cppu::UnoType< css::container::XHierarchicalNameAccess >::get());
227
0
        types.push_back(
228
0
            cppu::UnoType< css::configuration::XDocumentation >::get());
229
0
    }
230
0
    addTypes(&types);
231
0
    return comphelper::containerToSequence(types);
232
0
}
233
234
css::uno::Sequence< sal_Int8 > Access::getImplementationId()
235
0
{
236
0
    assert(thisIs(IS_ANY));
237
0
    osl::MutexGuard g(*lock_);
238
0
    checkLocalizedPropertyAccess();
239
0
    return css::uno::Sequence< sal_Int8 >();
240
0
}
241
242
OUString Access::getImplementationName()
243
0
{
244
0
    assert(thisIs(IS_ANY));
245
0
    osl::MutexGuard g(*lock_);
246
0
    checkLocalizedPropertyAccess();
247
0
    return u"org.openoffice-configmgr::Access"_ustr;
248
0
}
249
250
sal_Bool Access::supportsService(OUString const & ServiceName)
251
0
{
252
0
    return cppu::supportsService(this, ServiceName);
253
0
}
254
255
css::uno::Sequence< OUString > Access::getSupportedServiceNames()
256
0
{
257
0
    assert(thisIs(IS_ANY));
258
0
    osl::MutexGuard g(*lock_);
259
0
    checkLocalizedPropertyAccess();
260
0
    std::vector<OUString> services;
261
0
    services.emplace_back("com.sun.star.configuration.ConfigurationAccess");
262
0
    if (getRootAccess()->isUpdate()) {
263
0
        services.emplace_back("com.sun.star.configuration.ConfigurationUpdateAccess");
264
0
    }
265
0
    services.emplace_back("com.sun.star.configuration.HierarchyAccess");
266
0
    services.emplace_back("com.sun.star.configuration.HierarchyElement");
267
0
    if (getNode()->kind() == Node::KIND_GROUP) {
268
0
        services.emplace_back("com.sun.star.configuration.GroupAccess");
269
0
        services.emplace_back("com.sun.star.configuration.PropertyHierarchy");
270
0
        if (getRootAccess()->isUpdate()) {
271
0
            services.emplace_back("com.sun.star.configuration.GroupUpdate");
272
0
        }
273
0
    } else {
274
0
        services.emplace_back("com.sun.star.configuration.SetAccess");
275
0
        services.emplace_back("com.sun.star.configuration.SimpleSetAccess");
276
0
        if (getRootAccess()->isUpdate()) {
277
0
            services.emplace_back("com.sun.star.configuration.SetUpdate");
278
0
            services.emplace_back("com.sun.star.configuration.SimpleSetUpdate");
279
0
        }
280
0
    }
281
0
    addSupportedServiceNames(&services);
282
0
    return comphelper::containerToSequence(services);
283
0
}
284
285
0
void Access::dispose() {
286
0
    assert(thisIs(IS_ANY));
287
0
    Broadcaster bc;
288
0
    {
289
0
        osl::MutexGuard g(*lock_);
290
0
        checkLocalizedPropertyAccess();
291
0
        if (getParentAccess().is()) {
292
0
            throw css::uno::RuntimeException(
293
0
                u"configmgr dispose inappropriate Access"_ustr,
294
0
                getXWeak());
295
0
        }
296
0
        if (disposed_) {
297
0
            return;
298
0
        }
299
0
        initDisposeBroadcaster(&bc);
300
0
        clearListeners();
301
0
        disposed_ = true;
302
0
    }
303
0
    bc.send();
304
0
}
305
306
void Access::addEventListener(
307
    css::uno::Reference< css::lang::XEventListener > const & xListener)
308
0
{
309
0
    assert(thisIs(IS_ANY));
310
0
    {
311
0
        osl::MutexGuard g(*lock_);
312
0
        checkLocalizedPropertyAccess();
313
0
        if (!xListener.is()) {
314
0
            throw css::uno::RuntimeException(
315
0
                u"null listener"_ustr, getXWeak());
316
0
        }
317
0
        if (!disposed_) {
318
0
            disposeListeners_.insert(xListener);
319
0
            return;
320
0
        }
321
0
    }
322
0
    try {
323
0
        xListener->disposing(
324
0
            css::lang::EventObject(getXWeak()));
325
0
    } catch (css::lang::DisposedException &) {}
326
0
}
327
328
void Access::removeEventListener(
329
    css::uno::Reference< css::lang::XEventListener > const & aListener)
330
0
{
331
0
    assert(thisIs(IS_ANY));
332
0
    osl::MutexGuard g(*lock_);
333
0
    checkLocalizedPropertyAccess();
334
0
    auto i(disposeListeners_.find(aListener));
335
0
    if (i != disposeListeners_.end()) {
336
0
        disposeListeners_.erase(i);
337
0
    }
338
0
}
339
340
0
css::uno::Type Access::getElementType() {
341
0
    assert(thisIs(IS_ANY));
342
0
    osl::MutexGuard g(*lock_);
343
0
    checkLocalizedPropertyAccess();
344
0
    const rtl::Reference< Node > & p(getNode());
345
0
    switch (p->kind()) {
346
0
    case Node::KIND_LOCALIZED_PROPERTY:
347
0
        return mapType(
348
0
            static_cast< LocalizedPropertyNode * >(p.get())->getStaticType());
349
0
    case Node::KIND_GROUP:
350
        //TODO: Should a specific type be returned for a non-extensible group
351
        // with homogeneous members or for an extensible group that currently
352
        // has only homogeneous members?
353
0
        return cppu::UnoType<void>::get();
354
0
    case Node::KIND_SET:
355
0
        return cppu::UnoType<void>::get(); //TODO: correct?
356
0
    default:
357
0
        assert(false);
358
0
        throw css::uno::RuntimeException(
359
0
            u"this cannot happen"_ustr, getXWeak());
360
0
    }
361
0
}
362
363
0
sal_Bool Access::hasElements() {
364
0
    assert(thisIs(IS_ANY));
365
0
    osl::MutexGuard g(*lock_);
366
0
    checkLocalizedPropertyAccess();
367
0
    return !isAllChildrenEmpty();
368
0
}
369
370
bool Access::getByNameFast(const OUString & name, css::uno::Any & value)
371
0
{
372
0
    bool bGotValue = false;
373
0
    rtl::Reference< ChildAccess > child;
374
375
0
    if (getNode()->kind() != Node::KIND_LOCALIZED_PROPERTY)
376
0
    { // try to get it directly
377
0
        ModifiedChildren::iterator i(modifiedChildren_.find(name));
378
0
        if (i != modifiedChildren_.end())
379
0
        {
380
0
            child = getModifiedChild(i);
381
0
            if (child.is())
382
0
            {
383
0
                value = child->asValue();
384
0
                bGotValue = true;
385
0
            }
386
0
        }
387
0
        else
388
0
        {
389
0
            rtl::Reference< Node > node(getNode()->getMember(name));
390
0
            if (!node.is())
391
0
                return false;
392
0
            bGotValue = ChildAccess::asSimpleValue(node, value, components_);
393
0
        }
394
0
    }
395
396
0
    if (!bGotValue)
397
0
    {
398
0
        child = getChild(name);
399
0
        if (!child.is())
400
0
            return false;
401
0
        value = child->asValue();
402
0
    }
403
0
    return true;
404
0
}
405
406
css::uno::Any Access::getByName(OUString const & aName)
407
0
{
408
0
    assert(thisIs(IS_ANY));
409
0
    osl::MutexGuard g(*lock_);
410
0
    checkLocalizedPropertyAccess();
411
0
    css::uno::Any value;
412
0
    if (!getByNameFast(aName, value))
413
0
        throw css::container::NoSuchElementException(
414
0
            aName, getXWeak());
415
0
    return value;
416
0
}
417
418
css::uno::Sequence< OUString > Access::getElementNames()
419
0
{
420
0
    assert(thisIs(IS_ANY));
421
0
    osl::MutexGuard g(*lock_);
422
0
    checkLocalizedPropertyAccess();
423
0
    std::vector<OUString> childNames;
424
0
    forAllChildren([&childNames] (ChildAccess& rChild)
425
0
    {
426
0
        childNames.push_back(rChild.getNameInternal());
427
0
        return true;
428
0
    });
429
0
    return comphelper::containerToSequence(childNames);
430
0
}
431
432
sal_Bool Access::hasByName(OUString const & aName)
433
0
{
434
0
    assert(thisIs(IS_ANY));
435
0
    osl::MutexGuard g(*lock_);
436
0
    checkLocalizedPropertyAccess();
437
0
    return getChild(aName).is();
438
0
}
439
440
css::uno::Any Access::getByHierarchicalName(OUString const & aName)
441
50.1k
{
442
50.1k
    assert(thisIs(IS_ANY));
443
50.1k
    osl::MutexGuard g(*lock_);
444
50.1k
    checkLocalizedPropertyAccess();
445
50.1k
    rtl::Reference< ChildAccess > child(getSubChild(aName));
446
50.1k
    if (!child.is()) {
447
50.1k
        throw css::container::NoSuchElementException(
448
50.1k
            aName, getXWeak());
449
50.1k
    }
450
0
    return child->asValue();
451
50.1k
}
452
453
OUString Access::getDescriptionByHierarchicalName(OUString const & aName)
454
0
{
455
0
    assert(thisIs(IS_ANY));
456
0
    osl::MutexGuard g(*lock_);
457
0
    checkLocalizedPropertyAccess();
458
0
    rtl::Reference< ChildAccess > child(getSubChild(aName));
459
0
    if (!child.is()) {
460
0
        throw css::container::NoSuchElementException(
461
0
            aName, getXWeak());
462
0
    }
463
0
    return child->getNode()->getDescription();
464
0
}
465
466
css::uno::Type Access::getTypeByHierarchicalName(OUString const & aName)
467
0
{
468
0
    assert(thisIs(IS_ANY));
469
0
    osl::MutexGuard g(*lock_);
470
0
    checkLocalizedPropertyAccess();
471
0
    rtl::Reference< ChildAccess > child(getSubChild(aName));
472
0
    if (!child.is()) {
473
0
        throw css::container::NoSuchElementException(
474
0
            aName, getXWeak());
475
0
    }
476
0
    auto const & p = child->getNode();
477
0
    switch (p->kind()) {
478
0
    case Node::KIND_PROPERTY:
479
0
        return mapType(static_cast<PropertyNode *>(p.get())->getStaticType());
480
0
    case Node::KIND_LOCALIZED_PROPERTY:
481
0
        return mapType(static_cast<LocalizedPropertyNode *>(p.get())->getStaticType());
482
0
    default:
483
0
        throw css::util::InvalidStateException(
484
0
            aName, getXWeak());
485
0
    }
486
0
}
487
488
sal_Bool Access::getModifiedByHierarchicalName(OUString const & aName)
489
0
{
490
0
    assert(thisIs(IS_ANY));
491
0
    osl::MutexGuard g(*lock_);
492
0
    checkLocalizedPropertyAccess();
493
0
    rtl::Reference< ChildAccess > child(getSubChild(aName));
494
0
    if (!child.is()) {
495
0
        throw css::container::NoSuchElementException(
496
0
            aName, getXWeak());
497
0
    }
498
0
    auto const & p = child->getNode();
499
0
    switch (p->kind()) {
500
0
    case Node::KIND_PROPERTY:
501
0
        return static_cast<PropertyNode *>(p.get())->isModified();
502
0
    case Node::KIND_LOCALIZED_VALUE:
503
0
        return static_cast<LocalizedValueNode *>(p.get())->isModified();
504
0
    default:
505
0
        throw css::util::InvalidStateException(
506
0
            aName, getXWeak());
507
0
    }
508
0
}
509
510
sal_Bool Access::hasByHierarchicalName(OUString const & aName)
511
0
{
512
0
    assert(thisIs(IS_ANY));
513
0
    osl::MutexGuard g(*lock_);
514
0
    checkLocalizedPropertyAccess();
515
0
    return getSubChild(aName).is();
516
0
}
517
518
void Access::replaceByHierarchicalName(
519
    OUString const & aName, css::uno::Any const & aElement)
520
0
{
521
    //TODO: Actually support sets and combine with replaceByName:
522
0
    assert(thisIs(IS_UPDATE));
523
0
    Broadcaster bc;
524
0
    {
525
0
        osl::MutexGuard g(*lock_);
526
0
        checkLocalizedPropertyAccess();
527
0
        rtl::Reference< ChildAccess > child(getSubChild(aName));
528
0
        if (!child.is()) {
529
0
            throw css::container::NoSuchElementException(
530
0
                aName, getXWeak());
531
0
        }
532
0
        child->checkFinalized();
533
0
        rtl::Reference< Node > parent(child->getParentNode());
534
0
        assert(parent.is());
535
0
        Modifications localMods;
536
0
        switch (parent->kind()) {
537
0
        case Node::KIND_LOCALIZED_PROPERTY:
538
0
        case Node::KIND_GROUP:
539
0
            child->setProperty(aElement, &localMods);
540
0
            break;
541
0
        case Node::KIND_SET:
542
0
            throw css::lang::IllegalArgumentException(
543
0
                (u"configmgr::Access::replaceByHierarchicalName does not"
544
0
                 " currently support set members"_ustr),
545
0
                getXWeak(), 0);
546
0
        case Node::KIND_ROOT:
547
0
            throw css::lang::IllegalArgumentException(
548
0
                ("configmgr::Access::replaceByHierarchicalName does not allow"
549
0
                 " changing component " + aName),
550
0
                getXWeak(), 0);
551
0
        default:
552
0
            assert(false); // this cannot happen
553
0
            break;
554
0
        }
555
0
        getNotificationRoot()->initBroadcaster(localMods.getRoot(), &bc);
556
0
    }
557
0
    bc.send();
558
0
}
559
560
void Access::addContainerListener(
561
    css::uno::Reference< css::container::XContainerListener > const & xListener)
562
0
{
563
0
    assert(thisIs(IS_ANY));
564
0
    {
565
0
        osl::MutexGuard g(*lock_);
566
0
        checkLocalizedPropertyAccess();
567
0
        if (!xListener.is()) {
568
0
            throw css::uno::RuntimeException(
569
0
                u"null listener"_ustr, getXWeak());
570
0
        }
571
0
        if (!disposed_) {
572
0
            containerListeners_.insert(xListener);
573
0
            return;
574
0
        }
575
0
    }
576
0
    try {
577
0
        xListener->disposing(
578
0
            css::lang::EventObject(getXWeak()));
579
0
    } catch (css::lang::DisposedException &) {}
580
0
}
581
582
void Access::removeContainerListener(
583
    css::uno::Reference< css::container::XContainerListener > const & xListener)
584
0
{
585
0
    assert(thisIs(IS_ANY));
586
0
    osl::MutexGuard g(*lock_);
587
0
    checkLocalizedPropertyAccess();
588
0
    auto i(containerListeners_.find(xListener));
589
0
    if (i != containerListeners_.end()) {
590
0
        containerListeners_.erase(i);
591
0
    }
592
0
}
593
594
OUString Access::getExactName(OUString const & aApproximateName)
595
0
{
596
0
    assert(thisIs(IS_ANY));
597
0
    osl::MutexGuard g(*lock_);
598
0
    checkLocalizedPropertyAccess();
599
0
    return aApproximateName;
600
0
}
601
602
css::uno::Sequence< css::beans::Property > Access::getProperties()
603
0
{
604
0
    assert(thisIs(IS_GROUP));
605
0
    osl::MutexGuard g(*lock_);
606
0
    std::vector< css::beans::Property > properties;
607
0
    forAllChildren([&properties] (ChildAccess& rChild)
608
0
    {
609
0
        properties.push_back(rChild.asProperty());
610
0
        return true;
611
0
    });
612
0
    return comphelper::containerToSequence(properties);
613
0
}
614
615
css::beans::Property Access::getPropertyByName(OUString const & aName)
616
0
{
617
0
    assert(thisIs(IS_GROUP));
618
0
    osl::MutexGuard g(*lock_);
619
0
    rtl::Reference< ChildAccess > child(getChild(aName));
620
0
    if (!child.is()) {
621
0
        throw css::beans::UnknownPropertyException(
622
0
            aName, getXWeak());
623
0
    }
624
0
    return child->asProperty();
625
0
}
626
627
sal_Bool Access::hasPropertyByName(OUString const & Name)
628
0
{
629
0
    assert(thisIs(IS_GROUP));
630
0
    osl::MutexGuard g(*lock_);
631
0
    return getChild(Name).is();
632
0
}
633
634
0
OUString Access::getHierarchicalName() {
635
0
    assert(thisIs(IS_ANY));
636
0
    osl::MutexGuard g(*lock_);
637
0
    checkLocalizedPropertyAccess();
638
    // For backwards compatibility, return an absolute path representation where
639
    // available:
640
0
    OUString rootPath;
641
0
    rtl::Reference< RootAccess > root(getRootAccess());
642
0
    if (root.is()) {
643
0
        rootPath = root->getAbsolutePathRepresentation();
644
0
    }
645
0
    OUString rel(getRelativePathRepresentation());
646
0
    OUStringBuffer path(rootPath);
647
0
    if (!rootPath.isEmpty() && rootPath != "/" && !rel.isEmpty()) {
648
0
        path.append('/');
649
0
    }
650
0
    path.append(rel);
651
0
    return path.makeStringAndClear();
652
0
}
653
654
OUString Access::composeHierarchicalName(
655
    OUString const & aRelativeName)
656
0
{
657
0
    assert(thisIs(IS_ANY));
658
0
    osl::MutexGuard g(*lock_);
659
0
    checkLocalizedPropertyAccess();
660
0
    if (aRelativeName.isEmpty() || aRelativeName[0] == '/') {
661
0
        throw css::lang::IllegalArgumentException(
662
0
            u"configmgr composeHierarchicalName inappropriate relative name"_ustr,
663
0
            getXWeak(), -1);
664
0
    }
665
0
    OUStringBuffer path(getRelativePathRepresentation());
666
0
    if (!path.isEmpty()) {
667
0
        path.append('/');
668
0
    }
669
0
    path.append(aRelativeName);
670
0
    return path.makeStringAndClear();
671
0
}
672
673
0
OUString Access::getName() {
674
0
    assert(thisIs(IS_ANY));
675
0
    osl::MutexGuard g(*lock_);
676
0
    checkLocalizedPropertyAccess();
677
0
    return getNameInternal();
678
0
}
679
680
void Access::setName(OUString const & aName)
681
0
{
682
0
    assert(thisIs(IS_ANY));
683
0
    Broadcaster bc;
684
0
    {
685
0
        osl::MutexGuard g(*lock_);
686
0
        checkLocalizedPropertyAccess();
687
0
        checkFinalized();
688
0
        Modifications localMods;
689
0
        switch (getNode()->kind()) {
690
0
        case Node::KIND_GROUP:
691
0
        case Node::KIND_SET:
692
0
            {
693
0
                rtl::Reference< Access > parent(getParentAccess());
694
0
                if (parent.is()) {
695
0
                    const rtl::Reference< Node > & node(getNode());
696
0
                    if (! node->getTemplateName().isEmpty()) {
697
0
                        rtl::Reference< ChildAccess > other(
698
0
                            parent->getChild(aName));
699
0
                        if (other.get() == this) {
700
0
                            break;
701
0
                        }
702
0
                        if (node->getMandatory() == Data::NO_LAYER &&
703
0
                            !(other.is() && other->isFinalized()))
704
0
                        {
705
0
                            if (!isValidName(aName, true)) {
706
0
                                throw css::uno::RuntimeException(
707
0
                                    "invalid element name " + aName);
708
0
                            }
709
0
                            rtl::Reference< RootAccess > root(getRootAccess());
710
0
                            rtl::Reference< ChildAccess > childAccess(
711
0
                                static_cast< ChildAccess * >(this));
712
0
                            localMods.add(getRelativePath());
713
                            // unbind() modifies the parent chain that
714
                            // markChildAsModified() walks, so order is
715
                            // important:
716
0
                            parent->markChildAsModified(childAccess);
717
                                //TODO: must not throw
718
0
                            childAccess->unbind(); // must not throw
719
0
                            if (other.is()) {
720
0
                                other->unbind(); // must not throw
721
0
                            }
722
0
                            childAccess->bind(root, parent, aName);
723
                                // must not throw
724
0
                            parent->markChildAsModified(childAccess);
725
                                //TODO: must not throw
726
0
                            localMods.add(getRelativePath());
727
0
                            break;
728
0
                        }
729
0
                    }
730
0
                }
731
0
            }
732
0
            [[fallthrough]];
733
0
        case Node::KIND_LOCALIZED_PROPERTY:
734
            // renaming a property could only work for an extension property,
735
            // but a localized property is never an extension property
736
0
            throw css::uno::RuntimeException(
737
0
                u"configmgr setName inappropriate node"_ustr,
738
0
                getXWeak());
739
0
        default:
740
0
            assert(false); // this cannot happen
741
0
            break;
742
0
        }
743
0
        getNotificationRoot()->initBroadcaster(localMods.getRoot(), &bc);
744
0
    }
745
0
    bc.send();
746
0
}
747
748
css::beans::Property Access::getAsProperty()
749
0
{
750
0
    assert(thisIs(IS_ANY));
751
0
    osl::MutexGuard g(*lock_);
752
0
    checkLocalizedPropertyAccess();
753
0
    return asProperty();
754
0
}
755
756
css::uno::Reference< css::beans::XPropertySetInfo > Access::getPropertySetInfo()
757
0
{
758
0
    assert(thisIs(IS_GROUP));
759
0
    return this;
760
0
}
761
762
void Access::setPropertyValue(
763
    OUString const & aPropertyName, css::uno::Any const & aValue)
764
0
{
765
0
    assert(thisIs(IS_GROUP));
766
0
    Broadcaster bc;
767
0
    {
768
0
        osl::MutexGuard g(*lock_);
769
0
        if (!getRootAccess()->isUpdate()) {
770
0
            throw css::uno::RuntimeException(
771
0
                u"configmgr setPropertyValue on non-update access"_ustr,
772
0
                getXWeak());
773
0
        }
774
0
        Modifications localMods;
775
0
        if (!setChildProperty(aPropertyName, aValue, &localMods)) {
776
0
            throw css::beans::UnknownPropertyException(
777
0
                aPropertyName, getXWeak());
778
0
        }
779
0
        getNotificationRoot()->initBroadcaster(localMods.getRoot(), &bc);
780
0
    }
781
0
    bc.send();
782
0
}
783
784
css::uno::Any Access::getPropertyValue(OUString const & PropertyName)
785
0
{
786
0
    assert(thisIs(IS_GROUP));
787
0
    osl::MutexGuard g(*lock_);
788
789
0
    css::uno::Any value;
790
0
    if (!getByNameFast(PropertyName, value))
791
0
        throw css::beans::UnknownPropertyException(
792
0
            PropertyName, getXWeak());
793
0
    return value;
794
0
}
795
796
void Access::addPropertyChangeListener(
797
    OUString const & aPropertyName,
798
    css::uno::Reference< css::beans::XPropertyChangeListener > const &
799
        xListener)
800
0
{
801
0
    assert(thisIs(IS_GROUP));
802
0
    {
803
0
        osl::MutexGuard g(*lock_);
804
0
        if (!xListener.is()) {
805
0
            throw css::uno::RuntimeException(
806
0
                u"null listener"_ustr, getXWeak());
807
0
        }
808
0
        checkKnownProperty(aPropertyName);
809
0
        if (!disposed_) {
810
0
            propertyChangeListeners_[aPropertyName].insert(xListener);
811
0
            return;
812
0
        }
813
0
    }
814
0
    try {
815
0
        xListener->disposing(
816
0
            css::lang::EventObject(getXWeak()));
817
0
    } catch (css::lang::DisposedException &) {}
818
0
}
819
820
void Access::removePropertyChangeListener(
821
    OUString const & aPropertyName,
822
    css::uno::Reference< css::beans::XPropertyChangeListener > const &
823
        aListener)
824
0
{
825
0
    assert(thisIs(IS_GROUP));
826
0
    osl::MutexGuard g(*lock_);
827
0
    checkKnownProperty(aPropertyName);
828
0
    PropertyChangeListeners::iterator i(
829
0
        propertyChangeListeners_.find(aPropertyName));
830
0
    if (i != propertyChangeListeners_.end()) {
831
0
        auto j(i->second.find(aListener));
832
0
        if (j != i->second.end()) {
833
0
            i->second.erase(j);
834
0
            if (i->second.empty()) {
835
0
                propertyChangeListeners_.erase(i);
836
0
            }
837
0
        }
838
0
    }
839
0
}
840
841
void Access::addVetoableChangeListener(
842
    OUString const & PropertyName,
843
    css::uno::Reference< css::beans::XVetoableChangeListener > const &
844
        aListener)
845
0
{
846
0
    assert(thisIs(IS_GROUP));
847
0
    {
848
0
        osl::MutexGuard g(*lock_);
849
0
        if (!aListener.is()) {
850
0
            throw css::uno::RuntimeException(
851
0
                u"null listener"_ustr, getXWeak());
852
0
        }
853
0
        checkKnownProperty(PropertyName);
854
0
        if (!disposed_) {
855
0
            vetoableChangeListeners_[PropertyName].insert(aListener);
856
            //TODO: actually call vetoableChangeListeners_
857
0
            return;
858
0
        }
859
0
    }
860
0
    try {
861
0
        aListener->disposing(
862
0
            css::lang::EventObject(getXWeak()));
863
0
    } catch (css::lang::DisposedException &) {}
864
0
}
865
866
void Access::removeVetoableChangeListener(
867
    OUString const & PropertyName,
868
    css::uno::Reference< css::beans::XVetoableChangeListener > const &
869
        aListener)
870
0
{
871
0
    assert(thisIs(IS_GROUP));
872
0
    osl::MutexGuard g(*lock_);
873
0
    checkKnownProperty(PropertyName);
874
0
    VetoableChangeListeners::iterator i(
875
0
        vetoableChangeListeners_.find(PropertyName));
876
0
    if (i != vetoableChangeListeners_.end()) {
877
0
        auto j(i->second.find(aListener));
878
0
        if (j != i->second.end()) {
879
0
            i->second.erase(j);
880
0
            if (i->second.empty()) {
881
0
                vetoableChangeListeners_.erase(i);
882
0
            }
883
0
        }
884
0
    }
885
0
}
886
887
void Access::setPropertyValues(
888
    css::uno::Sequence< OUString > const & aPropertyNames,
889
    css::uno::Sequence< css::uno::Any > const & aValues)
890
0
{
891
0
    assert(thisIs(IS_GROUP));
892
0
    Broadcaster bc;
893
0
    {
894
0
        osl::MutexGuard g(*lock_);
895
0
        if (!getRootAccess()->isUpdate()) {
896
0
            throw css::uno::RuntimeException(
897
0
                u"configmgr setPropertyValues on non-update access"_ustr,
898
0
                getXWeak());
899
0
        }
900
0
        if (aPropertyNames.getLength() != aValues.getLength()) {
901
0
            throw css::lang::IllegalArgumentException(
902
0
                (u"configmgr setPropertyValues: aPropertyNames/aValues of"
903
0
                 " different length"_ustr),
904
0
                getXWeak(), -1);
905
0
        }
906
0
        Modifications localMods;
907
0
        for (sal_Int32 i = 0; i < aPropertyNames.getLength(); ++i) {
908
0
            if (!setChildProperty(aPropertyNames[i], aValues[i], &localMods)) {
909
0
                throw css::lang::IllegalArgumentException(
910
0
                    u"configmgr setPropertyValues inappropriate property name"_ustr,
911
0
                    getXWeak(), -1);
912
0
            }
913
0
        }
914
0
        getNotificationRoot()->initBroadcaster(localMods.getRoot(), &bc);
915
0
    }
916
0
    bc.send();
917
0
}
918
919
css::uno::Sequence< css::uno::Any > Access::getPropertyValues(
920
    css::uno::Sequence< OUString > const & aPropertyNames)
921
0
{
922
0
    assert(thisIs(IS_GROUP));
923
0
    osl::MutexGuard g(*lock_);
924
0
    css::uno::Sequence< css::uno::Any > vals(aPropertyNames.getLength());
925
0
    auto aValsRange = asNonConstRange(vals);
926
0
    for (sal_Int32 i = 0; i < aPropertyNames.getLength(); ++i)
927
0
    {
928
0
        if (!getByNameFast(aPropertyNames[i], aValsRange[i]))
929
0
            throw css::uno::RuntimeException(
930
0
                u"configmgr getPropertyValues inappropriate property name"_ustr,
931
0
                getXWeak());
932
0
    }
933
934
0
    return vals;
935
0
}
936
937
void Access::addPropertiesChangeListener(
938
    css::uno::Sequence< OUString > const &,
939
    css::uno::Reference< css::beans::XPropertiesChangeListener > const &
940
        xListener)
941
0
{
942
0
    assert(thisIs(IS_GROUP));
943
0
    {
944
0
        osl::MutexGuard g(*lock_);
945
0
        if (!xListener.is()) {
946
0
            throw css::uno::RuntimeException(
947
0
                u"null listener"_ustr, getXWeak());
948
0
        }
949
0
        if (!disposed_) {
950
0
            propertiesChangeListeners_.insert(xListener);
951
0
            return;
952
0
        }
953
0
    }
954
0
    try {
955
0
        xListener->disposing(
956
0
            css::lang::EventObject(getXWeak()));
957
0
    } catch (css::lang::DisposedException &) {}
958
0
}
959
960
void Access::removePropertiesChangeListener(
961
    css::uno::Reference< css::beans::XPropertiesChangeListener > const &
962
        xListener)
963
0
{
964
0
    assert(thisIs(IS_GROUP));
965
0
    osl::MutexGuard g(*lock_);
966
0
    auto i(propertiesChangeListeners_.find(xListener));
967
0
    if (i != propertiesChangeListeners_.end()) {
968
0
        propertiesChangeListeners_.erase(i);
969
0
    }
970
0
}
971
972
void Access::firePropertiesChangeEvent(
973
    css::uno::Sequence< OUString > const & aPropertyNames,
974
    css::uno::Reference< css::beans::XPropertiesChangeListener > const &
975
        xListener)
976
0
{
977
0
    assert(thisIs(IS_GROUP));
978
0
    css::uno::Sequence< css::beans::PropertyChangeEvent > events(
979
0
        aPropertyNames.getLength());
980
0
    auto aEventsRange = asNonConstRange(events);
981
0
    for (sal_Int32 i = 0; i < events.getLength(); ++i) {
982
0
        aEventsRange[i].Source = getXWeak();
983
0
        aEventsRange[i].PropertyName = aPropertyNames[i];
984
0
        aEventsRange[i].Further = false;
985
0
        aEventsRange[i].PropertyHandle = -1;
986
0
    }
987
0
    xListener->propertiesChange(events);
988
0
}
989
990
css::uno::Reference< css::beans::XHierarchicalPropertySetInfo >
991
0
Access::getHierarchicalPropertySetInfo() {
992
0
    assert(thisIs(IS_GROUP));
993
0
    return this;
994
0
}
995
996
void Access::setHierarchicalPropertyValue(
997
    OUString const & aHierarchicalPropertyName,
998
    css::uno::Any const & aValue)
999
0
{
1000
0
    assert(thisIs(IS_GROUP));
1001
0
    Broadcaster bc;
1002
0
    {
1003
0
        osl::MutexGuard g(*lock_);
1004
0
        if (!getRootAccess()->isUpdate()) {
1005
0
            throw css::uno::RuntimeException(
1006
0
                u"configmgr setHierarchicalPropertyName on non-update access"_ustr,
1007
0
                getXWeak());
1008
0
        }
1009
0
        rtl::Reference< ChildAccess > child(
1010
0
            getSubChild(aHierarchicalPropertyName));
1011
0
        if (!child.is()) {
1012
0
            throw css::beans::UnknownPropertyException(
1013
0
                aHierarchicalPropertyName,
1014
0
                getXWeak());
1015
0
        }
1016
0
        child->checkFinalized();
1017
0
        Modifications localMods;
1018
0
        child->setProperty(aValue, &localMods);
1019
0
        getNotificationRoot()->initBroadcaster(localMods.getRoot(), &bc);
1020
0
    }
1021
0
    bc.send();
1022
0
}
1023
1024
css::uno::Any Access::getHierarchicalPropertyValue(
1025
    OUString const & aHierarchicalPropertyName)
1026
0
{
1027
0
    assert(thisIs(IS_GROUP));
1028
0
    osl::MutexGuard g(*lock_);
1029
0
    rtl::Reference< ChildAccess > child(getSubChild(aHierarchicalPropertyName));
1030
0
    if (!child.is()) {
1031
0
        throw css::beans::UnknownPropertyException(
1032
0
            aHierarchicalPropertyName,
1033
0
            getXWeak());
1034
0
    }
1035
0
    return child->asValue();
1036
0
}
1037
1038
void Access::setHierarchicalPropertyValues(
1039
    css::uno::Sequence< OUString > const & aHierarchicalPropertyNames,
1040
    css::uno::Sequence< css::uno::Any > const & Values)
1041
0
{
1042
0
    assert(thisIs(IS_GROUP));
1043
0
    Broadcaster bc;
1044
0
    {
1045
0
        osl::MutexGuard g(*lock_);
1046
0
        if (!getRootAccess()->isUpdate()) {
1047
0
            throw css::uno::RuntimeException(
1048
0
                u"configmgr setPropertyValues on non-update access"_ustr,
1049
0
                getXWeak());
1050
0
        }
1051
0
        if (aHierarchicalPropertyNames.getLength() != Values.getLength()) {
1052
0
            throw css::lang::IllegalArgumentException(
1053
0
                (u"configmgr setHierarchicalPropertyValues:"
1054
0
                 " aHierarchicalPropertyNames/Values of different length"_ustr),
1055
0
                getXWeak(), -1);
1056
0
        }
1057
0
        Modifications localMods;
1058
0
        for (sal_Int32 i = 0; i < aHierarchicalPropertyNames.getLength(); ++i) {
1059
0
            rtl::Reference< ChildAccess > child(
1060
0
                getSubChild(aHierarchicalPropertyNames[i]));
1061
0
            if (!child.is()) {
1062
0
                throw css::lang::IllegalArgumentException(
1063
0
                    (u"configmgr setHierarchicalPropertyValues inappropriate"
1064
0
                     " property name"_ustr),
1065
0
                    getXWeak(), -1);
1066
0
            }
1067
0
            child->checkFinalized();
1068
0
            child->setProperty(Values[i], &localMods);
1069
0
        }
1070
0
        getNotificationRoot()->initBroadcaster(localMods.getRoot(), &bc);
1071
0
    }
1072
0
    bc.send();
1073
0
}
1074
1075
css::uno::Sequence< css::uno::Any > Access::getHierarchicalPropertyValues(
1076
    css::uno::Sequence< OUString > const & aHierarchicalPropertyNames)
1077
0
{
1078
0
    assert(thisIs(IS_GROUP));
1079
0
    osl::MutexGuard g(*lock_);
1080
0
    css::uno::Sequence< css::uno::Any > vals(
1081
0
        aHierarchicalPropertyNames.getLength());
1082
0
    auto aValsRange = asNonConstRange(vals);
1083
0
    for (sal_Int32 i = 0; i < aHierarchicalPropertyNames.getLength(); ++i) {
1084
0
        rtl::Reference< ChildAccess > child(
1085
0
            getSubChild(aHierarchicalPropertyNames[i]));
1086
0
        if (!child.is()) {
1087
0
            throw css::lang::IllegalArgumentException(
1088
0
                (u"configmgr getHierarchicalPropertyValues inappropriate"
1089
0
                 " hierarchical property name"_ustr),
1090
0
                getXWeak(), -1);
1091
0
        }
1092
0
        aValsRange[i] = child->asValue();
1093
0
    }
1094
0
    return vals;
1095
0
}
1096
1097
css::beans::Property Access::getPropertyByHierarchicalName(
1098
    OUString const & aHierarchicalName)
1099
0
{
1100
0
    assert(thisIs(IS_GROUP));
1101
0
    osl::MutexGuard g(*lock_);
1102
0
    rtl::Reference< ChildAccess > child(getSubChild(aHierarchicalName));
1103
0
    if (!child.is()) {
1104
0
        throw css::beans::UnknownPropertyException(
1105
0
            aHierarchicalName, getXWeak());
1106
0
    }
1107
0
    return child->asProperty();
1108
0
}
1109
1110
sal_Bool Access::hasPropertyByHierarchicalName(
1111
    OUString const & aHierarchicalName)
1112
0
{
1113
0
    assert(thisIs(IS_GROUP));
1114
0
    osl::MutexGuard g(*lock_);
1115
0
    return getSubChild(aHierarchicalName).is();
1116
0
}
1117
1118
void Access::replaceByName(
1119
    OUString const & aName, css::uno::Any const & aElement)
1120
0
{
1121
0
    assert(thisIs(IS_UPDATE));
1122
0
    Broadcaster bc;
1123
0
    {
1124
0
        osl::MutexGuard g(*lock_);
1125
0
        checkLocalizedPropertyAccess();
1126
0
        rtl::Reference< ChildAccess > child(getChild(aName));
1127
0
        if (!child.is()) {
1128
0
            throw css::container::NoSuchElementException(
1129
0
                aName, getXWeak());
1130
0
        }
1131
0
        child->checkFinalized();
1132
0
        Modifications localMods;
1133
0
        switch (getNode()->kind()) {
1134
0
        case Node::KIND_LOCALIZED_PROPERTY:
1135
0
        case Node::KIND_GROUP:
1136
0
            child->setProperty(aElement, &localMods);
1137
0
            break;
1138
0
        case Node::KIND_SET:
1139
0
            {
1140
0
                rtl::Reference< ChildAccess > freeAcc(
1141
0
                    getFreeSetMember(aElement));
1142
0
                rtl::Reference< RootAccess > root(getRootAccess());
1143
0
                localMods.add(child->getRelativePath());
1144
0
                child->unbind(); // must not throw
1145
0
                freeAcc->bind(root, this, aName); // must not throw
1146
0
                markChildAsModified(freeAcc); //TODO: must not throw
1147
0
            }
1148
0
            break;
1149
0
        default:
1150
0
            assert(false); // this cannot happen
1151
0
            break;
1152
0
        }
1153
0
        getNotificationRoot()->initBroadcaster(localMods.getRoot(), &bc);
1154
0
    }
1155
0
    bc.send();
1156
0
}
1157
1158
void Access::insertByName(
1159
    OUString const & aName, css::uno::Any const & aElement)
1160
0
{
1161
0
    assert(thisIs(IS_EXTENSIBLE|IS_UPDATE));
1162
0
    Broadcaster bc;
1163
0
    {
1164
0
        osl::MutexGuard g(*lock_);
1165
0
        checkLocalizedPropertyAccess();
1166
0
        checkFinalized();
1167
0
        if (getChild(aName).is()) {
1168
0
            throw css::container::ElementExistException(
1169
0
                aName, getXWeak());
1170
0
        }
1171
0
        Modifications localMods;
1172
0
        switch (getNode()->kind()) {
1173
0
        case Node::KIND_LOCALIZED_PROPERTY:
1174
0
            if (!isValidName(aName, false)) {
1175
0
                throw css::lang::IllegalArgumentException(
1176
0
                    aName, getXWeak(), 0);
1177
0
            }
1178
0
            insertLocalizedValueChild(aName, aElement, &localMods);
1179
0
            break;
1180
0
        case Node::KIND_GROUP:
1181
0
            {
1182
0
                if (!isValidName(aName, false)) {
1183
0
                    throw css::lang::IllegalArgumentException(
1184
0
                        aName, getXWeak(), 0);
1185
0
                }
1186
0
                checkValue(aElement, TYPE_ANY, true);
1187
0
                rtl::Reference child(
1188
0
                    new ChildAccess(
1189
0
                        components_, getRootAccess(), this, aName,
1190
0
                        new PropertyNode(
1191
0
                            Data::NO_LAYER, TYPE_ANY, true, aElement, true)));
1192
0
                markChildAsModified(child);
1193
0
                localMods.add(child->getRelativePath());
1194
0
            }
1195
0
            break;
1196
0
        case Node::KIND_SET:
1197
0
            {
1198
0
                if (!isValidName(aName, true)) {
1199
0
                    throw css::lang::IllegalArgumentException(
1200
0
                        aName, getXWeak(), 0);
1201
0
                }
1202
0
                rtl::Reference< ChildAccess > freeAcc(
1203
0
                    getFreeSetMember(aElement));
1204
0
                freeAcc->bind(getRootAccess(), this, aName); // must not throw
1205
0
                markChildAsModified(freeAcc); //TODO: must not throw
1206
0
                localMods.add(freeAcc->getRelativePath());
1207
0
            }
1208
0
            break;
1209
0
        default:
1210
0
            assert(false); // this cannot happen
1211
0
            break;
1212
0
        }
1213
0
        getNotificationRoot()->initBroadcaster(localMods.getRoot(), &bc);
1214
0
    }
1215
0
    bc.send();
1216
0
}
1217
1218
void Access::removeByName(OUString const & aName)
1219
0
{
1220
0
    assert(thisIs(IS_EXTENSIBLE|IS_UPDATE));
1221
0
    Broadcaster bc;
1222
0
    {
1223
0
        osl::MutexGuard g(*lock_);
1224
0
        checkLocalizedPropertyAccess();
1225
0
        rtl::Reference< ChildAccess > child(getChild(aName));
1226
0
        if (!child.is() || child->isFinalized() ||
1227
0
            child->getNode()->getMandatory() != Data::NO_LAYER)
1228
0
        {
1229
0
            throw css::container::NoSuchElementException(
1230
0
                aName, getXWeak());
1231
0
        }
1232
0
        if (getNode()->kind() == Node::KIND_GROUP) {
1233
0
            const rtl::Reference< Node >& p(child->getNode());
1234
0
            if (p->kind() != Node::KIND_PROPERTY ||
1235
0
                !static_cast< PropertyNode * >(p.get())->isExtension())
1236
0
            {
1237
0
                throw css::container::NoSuchElementException(
1238
0
                    aName, getXWeak());
1239
0
            }
1240
0
        }
1241
0
        Modifications localMods;
1242
0
        localMods.add(child->getRelativePath());
1243
        // unbind() modifies the parent chain that markChildAsModified() walks,
1244
        // so order is important:
1245
0
        markChildAsModified(child); //TODO: must not throw
1246
0
        child->unbind();
1247
0
        getNotificationRoot()->initBroadcaster(localMods.getRoot(), &bc);
1248
0
    }
1249
0
    bc.send();
1250
0
}
1251
1252
css::uno::Reference< css::uno::XInterface > Access::createInstance()
1253
0
{
1254
0
    assert(thisIs(IS_SET|IS_UPDATE));
1255
0
    OUString tmplName(
1256
0
        static_cast< SetNode * >(getNode().get())->getDefaultTemplateName());
1257
0
    rtl::Reference< Node > tmpl(
1258
0
        components_.getTemplate(tmplName));
1259
0
    if (!tmpl.is()) {
1260
0
        throw css::uno::Exception(
1261
0
            "unknown template " + tmplName,
1262
0
            getXWeak());
1263
0
    }
1264
0
    rtl::Reference< Node > node(tmpl->clone(true));
1265
0
    node->setLayer(Data::NO_LAYER);
1266
0
    return cppu::getXWeak(
1267
0
        new ChildAccess(components_, getRootAccess(), node));
1268
0
}
1269
1270
css::uno::Reference< css::uno::XInterface > Access::createInstanceWithArguments(
1271
    css::uno::Sequence< css::uno::Any > const & aArguments)
1272
0
{
1273
0
    assert(thisIs(IS_SET|IS_UPDATE));
1274
0
    if (aArguments.hasElements()) {
1275
0
        throw css::uno::Exception(
1276
0
            (u"configuration SimpleSetUpdate createInstanceWithArguments"
1277
0
             " must not specify any arguments"_ustr),
1278
0
            getXWeak());
1279
0
    }
1280
0
    return createInstance();
1281
0
}
1282
1283
Access::Access(Components & components):
1284
89.9k
    components_(components), disposed_(false), lock_( lock() )
1285
89.9k
{
1286
89.9k
}
1287
1288
89.9k
Access::~Access() {}
1289
1290
0
void Access::initDisposeBroadcaster(Broadcaster * broadcaster) {
1291
0
    assert(broadcaster != nullptr);
1292
    // make copies when we fire listeners, since the vectors can
1293
    // be modified by the callees.
1294
0
    auto disposeCopy = disposeListeners_;
1295
0
    for (auto const& disposeListener : disposeCopy)
1296
0
    {
1297
0
        broadcaster->addDisposeNotification(
1298
0
            disposeListener,
1299
0
            css::lang::EventObject(getXWeak()));
1300
0
    }
1301
0
    auto containerCopy = containerListeners_;
1302
0
    for (auto const& containerListener : containerCopy)
1303
0
    {
1304
0
        broadcaster->addDisposeNotification(
1305
0
            containerListener,
1306
0
            css::lang::EventObject(getXWeak()));
1307
0
    }
1308
0
    for (auto const& propertyChangeListener : propertyChangeListeners_)
1309
0
    {
1310
0
        auto propChangeCopy = propertyChangeListener.second;
1311
0
        for (auto const& propertyChangeListenerElement : propChangeCopy)
1312
0
        {
1313
0
            broadcaster->addDisposeNotification(
1314
0
                propertyChangeListenerElement,
1315
0
                css::lang::EventObject(
1316
0
                    getXWeak()));
1317
0
        }
1318
0
    }
1319
0
    for (auto const& vetoableChangeListener : vetoableChangeListeners_)
1320
0
    {
1321
0
        auto vetoCopy = vetoableChangeListener.second;
1322
0
        for (auto const& vetoableChangeListenerElement : vetoCopy)
1323
0
        {
1324
0
            broadcaster->addDisposeNotification(
1325
0
                vetoableChangeListenerElement,
1326
0
                css::lang::EventObject(
1327
0
                    getXWeak()));
1328
0
        }
1329
0
    }
1330
0
    auto propCopy = propertiesChangeListeners_;
1331
0
    for (auto const& propertiesChangeListener : propCopy)
1332
0
    {
1333
0
        broadcaster->addDisposeNotification(
1334
0
            propertiesChangeListener,
1335
0
            css::lang::EventObject(getXWeak()));
1336
0
    }
1337
    //TODO: iterate over children w/ listeners (incl. unmodified ones):
1338
0
    for (ModifiedChildren::iterator i(modifiedChildren_.begin());
1339
0
         i != modifiedChildren_.end(); ++i)
1340
0
    {
1341
0
        rtl::Reference< ChildAccess > child(getModifiedChild(i));
1342
0
        if (child.is()) {
1343
0
            child->initDisposeBroadcaster(broadcaster);
1344
0
        }
1345
0
    }
1346
0
}
1347
1348
0
void Access::clearListeners() noexcept {
1349
0
    disposeListeners_.clear();
1350
0
    containerListeners_.clear();
1351
0
    propertyChangeListeners_.clear();
1352
0
    vetoableChangeListeners_.clear();
1353
0
    propertiesChangeListeners_.clear();
1354
    //TODO: iterate over children w/ listeners (incl. unmodified ones):
1355
0
    for (ModifiedChildren::iterator i(modifiedChildren_.begin());
1356
0
         i != modifiedChildren_.end(); ++i)
1357
0
    {
1358
0
        rtl::Reference< ChildAccess > child(getModifiedChild(i));
1359
0
        if (child.is()) {
1360
0
            child->clearListeners();
1361
0
        }
1362
0
    }
1363
0
}
1364
1365
css::uno::Any Access::queryInterface(css::uno::Type const & aType)
1366
0
{
1367
0
    css::uno::Any res(OWeakObject::queryInterface(aType));
1368
0
    if (res.hasValue()) {
1369
0
        return res;
1370
0
    }
1371
0
    res = cppu::queryInterface(
1372
0
        aType, static_cast< css::lang::XTypeProvider * >(this),
1373
0
        static_cast< css::lang::XServiceInfo * >(this),
1374
0
        static_cast< css::lang::XComponent * >(this),
1375
0
        static_cast< css::container::XHierarchicalNameAccess * >(this),
1376
0
        static_cast< css::configuration::XDocumentation * >(this),
1377
0
        static_cast< css::container::XContainer * >(this),
1378
0
        static_cast< css::beans::XExactName * >(this),
1379
0
        static_cast< css::container::XHierarchicalName * >(this),
1380
0
        static_cast< css::container::XNamed * >(this),
1381
0
        static_cast< css::beans::XProperty * >(this),
1382
0
        static_cast< css::container::XElementAccess * >(this),
1383
0
        static_cast< css::container::XNameAccess * >(this));
1384
0
    if (res.hasValue()) {
1385
0
        return res;
1386
0
    }
1387
0
    if (getNode()->kind() == Node::KIND_GROUP) {
1388
0
        res = cppu::queryInterface(
1389
0
            aType, static_cast< css::beans::XPropertySetInfo * >(this),
1390
0
            static_cast< css::beans::XPropertySet * >(this),
1391
0
            static_cast< css::beans::XMultiPropertySet * >(this),
1392
0
            static_cast< css::beans::XHierarchicalPropertySet * >(this),
1393
0
            static_cast< css::beans::XMultiHierarchicalPropertySet * >(this),
1394
0
            static_cast< css::beans::XHierarchicalPropertySetInfo * >(this));
1395
0
        if (res.hasValue()) {
1396
0
            return res;
1397
0
        }
1398
0
    }
1399
0
    if (getRootAccess()->isUpdate()) {
1400
0
        res = cppu::queryInterface(
1401
0
            aType, static_cast< css::container::XNameReplace * >(this),
1402
0
            static_cast< css::container::XHierarchicalNameReplace * >(this));
1403
0
        if (res.hasValue()) {
1404
0
            return res;
1405
0
        }
1406
0
        if (getNode()->kind() != Node::KIND_GROUP ||
1407
0
            static_cast< GroupNode * >(getNode().get())->isExtensible())
1408
0
        {
1409
0
            res = cppu::queryInterface(
1410
0
                aType, static_cast< css::container::XNameContainer * >(this));
1411
0
            if (res.hasValue()) {
1412
0
                return res;
1413
0
            }
1414
0
        }
1415
0
        if (getNode()->kind() == Node::KIND_SET) {
1416
0
            res = cppu::queryInterface(
1417
0
                aType, static_cast< css::lang::XSingleServiceFactory * >(this));
1418
0
        }
1419
0
    }
1420
0
    return res;
1421
0
}
1422
1423
1424
50.1k
void Access::checkLocalizedPropertyAccess() {
1425
50.1k
    if (getNode()->kind() == Node::KIND_LOCALIZED_PROPERTY &&
1426
0
        !Components::allLocales(getRootAccess()->getLocale()))
1427
0
    {
1428
0
        throw css::uno::RuntimeException(
1429
0
            u"configmgr Access to specialized LocalizedPropertyNode"_ustr,
1430
0
            getXWeak());
1431
0
    }
1432
50.1k
}
1433
1434
0
rtl::Reference< Node > Access::getParentNode() {
1435
0
    rtl::Reference< Access > parent(getParentAccess());
1436
0
    return parent.is() ? parent->getNode() : rtl::Reference< Node >();
1437
0
}
1438
1439
50.1k
rtl::Reference< ChildAccess > Access::getChild(OUString const & name) {
1440
50.1k
    OUString locale;
1441
50.1k
    if (getNode()->kind() == Node::KIND_LOCALIZED_PROPERTY
1442
0
        && name.startsWith("*", &locale))
1443
0
    {
1444
0
        if (locale.startsWith("*")) {
1445
0
            SAL_WARN(
1446
0
                "configmgr",
1447
0
                ("access best-matching localized property value via"
1448
0
                 " \"*<locale>\" with <locale> \"")
1449
0
                    << locale << "\" recursively starting with \"*\"");
1450
0
            return getChild(locale);
1451
0
        }
1452
0
        SAL_INFO_IF(
1453
0
            locale.isEmpty(), "configmgr",
1454
0
            ("access best-matching localized property value via \"*<locale>\""
1455
0
             " with empty <locale>; falling back to defaults"));
1456
1457
        // Since the locale given to us is the one used at initialization,
1458
        // here we override it with the actual current-user's language to
1459
        // support per-view localization in LOK.
1460
0
        if (comphelper::LibreOfficeKit::isActive())
1461
0
            locale = comphelper::LibreOfficeKit::getLanguageTag().getBcp47();
1462
1463
0
        if (!locale.isEmpty()) {
1464
            // Try exact match first, avoiding all fallback overhead.
1465
0
            rtl::Reference<ChildAccess> directChild(getChild(locale));
1466
0
            if (directChild.is())
1467
0
                return directChild;
1468
1469
0
            LanguageTag aLanguageTag(locale, true);
1470
0
            if (aLanguageTag.getBcp47() != locale)
1471
0
            {
1472
                // Original may be overridden by a known locale, for example
1473
                // "zh-Hant-TW" by "zh-TW".
1474
0
                rtl::Reference<ChildAccess> child(getChild(aLanguageTag.getBcp47()));
1475
0
                if (child.is())
1476
0
                    return child;
1477
0
            }
1478
1479
            // Find the best match using the LanguageTag fallback mechanism,
1480
            // excluding the original tag.
1481
0
            std::vector<OUString> aFallbacks = aLanguageTag.getFallbackStrings(false);
1482
0
            for (const OUString& rFallback : aFallbacks)
1483
0
            {
1484
0
                rtl::Reference<ChildAccess> child(getChild(rFallback));
1485
0
                if (child.is())
1486
0
                    return child;
1487
0
            }
1488
1489
            // As a workaround for broken xcu data that does not use shortest
1490
            // xml:lang attributes, look for the first entry with the same first
1491
            // segment as the requested language tag before falling back to
1492
            // defaults (see fdo#33638):
1493
0
            auto const i = comphelper::string::indexOfAny(locale, u"-_", 1);
1494
0
            if (i != -1) {
1495
0
                locale = locale.copy(0, i);
1496
0
            }
1497
0
            assert(!locale.isEmpty());
1498
0
            rtl::Reference< ChildAccess > foundChild;
1499
0
            forAllChildren([&foundChild, &locale] (ChildAccess& rChild)
1500
0
            {
1501
0
                const OUString & name2(rChild.getNameInternal());
1502
0
                if (name2.startsWith(locale) &&
1503
0
                    (name2.getLength() == locale.getLength() ||
1504
0
                     name2[locale.getLength()] == '-' ||
1505
0
                     name2[locale.getLength()] == '_'))
1506
0
                {
1507
0
                    foundChild = &rChild;
1508
0
                    return false;
1509
0
                }
1510
0
                return true;
1511
0
            });
1512
0
            if (foundChild)
1513
0
                return foundChild;
1514
0
        }
1515
        // Defaults are the "en-US" locale, the "en" locale, the empty string locale, the first child (if
1516
        // any, and if the property is non-nillable), or a null ChildAccess, in that order:
1517
0
        rtl::Reference< ChildAccess > child(getChild(u"en-US"_ustr));
1518
0
        if (child.is()) {
1519
0
            return child;
1520
0
        }
1521
0
        child = getChild(u"en"_ustr);
1522
0
        if (child.is()) {
1523
0
            return child;
1524
0
        }
1525
0
        child = getChild(u""_ustr);
1526
0
        if (child.is()) {
1527
0
            return child;
1528
0
        }
1529
0
        if (!static_cast<LocalizedPropertyNode *>(getNode().get())->isNillable()) {
1530
            // look for first child in list
1531
0
            rtl::Reference< ChildAccess > foundChild;
1532
0
            forAllChildren([&foundChild] (ChildAccess& rChild)
1533
0
            {
1534
0
                foundChild = &rChild;
1535
0
                return false;
1536
0
            });
1537
0
            if (foundChild) {
1538
0
                return foundChild;
1539
0
            }
1540
0
        }
1541
0
        return rtl::Reference< ChildAccess >();
1542
0
    }
1543
50.1k
    ModifiedChildren::iterator i(modifiedChildren_.find(name));
1544
50.1k
    return i == modifiedChildren_.end()
1545
50.1k
        ? getUnmodifiedChild(name) : getModifiedChild(i);
1546
50.1k
}
1547
1548
0
void Access::forAllChildren(const std::function<bool(ChildAccess&)> & func) {
1549
0
    NodeMap const & members = getNode()->getMembers();
1550
0
    for (auto const& member : members)
1551
0
    {
1552
0
        if (modifiedChildren_.find(member.first) == modifiedChildren_.end()) {
1553
0
            bool bContinue = func(*getUnmodifiedChild(member.first));
1554
0
            if (!bContinue)
1555
0
                return;
1556
0
        }
1557
0
    }
1558
0
    for (ModifiedChildren::iterator i(modifiedChildren_.begin());
1559
0
         i != modifiedChildren_.end(); ++i)
1560
0
    {
1561
0
        rtl::Reference< ChildAccess > child(getModifiedChild(i));
1562
0
        if (child.is()) {
1563
0
            bool bContinue = func(*child);
1564
0
            if (!bContinue)
1565
0
                return;
1566
0
        }
1567
0
    }
1568
0
}
1569
1570
0
bool Access::isAllChildrenEmpty() {
1571
0
    NodeMap const & members = getNode()->getMembers();
1572
0
    for (auto const& member : members)
1573
0
    {
1574
0
        if (modifiedChildren_.find(member.first) == modifiedChildren_.end())
1575
0
            return false;
1576
0
    }
1577
0
    for (ModifiedChildren::iterator i(modifiedChildren_.begin());
1578
0
         i != modifiedChildren_.end(); ++i)
1579
0
    {
1580
0
        rtl::Reference< ChildAccess > child(getModifiedChild(i));
1581
0
        if (child.is())
1582
0
            return false;
1583
0
    }
1584
0
    return true;
1585
0
}
1586
1587
0
void Access::checkValue(css::uno::Any const & value, Type type, bool nillable) {
1588
0
    bool ok;
1589
0
    switch (type) {
1590
0
    case TYPE_ERROR:
1591
0
        ok = false;
1592
0
        break;
1593
0
    case TYPE_ANY:
1594
0
        switch (getDynamicType(value)) {
1595
0
        case TYPE_ERROR:
1596
0
            ok = false;
1597
0
            break;
1598
0
        case TYPE_NIL:
1599
0
            ok = nillable;
1600
0
            break;
1601
0
        default:
1602
0
            ok = true;
1603
0
            break;
1604
0
        case TYPE_ANY:
1605
0
            for (;;) std::abort(); // cannot happen
1606
0
        }
1607
0
        break;
1608
0
    default:
1609
0
        ok = value.hasValue() ? value.isExtractableTo(mapType(type)) : nillable;
1610
0
        break;
1611
0
    case TYPE_NIL:
1612
0
        for (;;) std::abort(); // cannot happen
1613
0
    }
1614
0
    if (!ok) {
1615
0
        throw css::lang::IllegalArgumentException(
1616
0
            u"configmgr inappropriate property value"_ustr,
1617
0
            getXWeak(), -1);
1618
0
    }
1619
0
}
1620
1621
void Access::insertLocalizedValueChild(
1622
    OUString const & name, css::uno::Any const & value,
1623
    Modifications * localModifications)
1624
0
{
1625
0
    assert(localModifications != nullptr);
1626
0
    LocalizedPropertyNode * locprop = static_cast< LocalizedPropertyNode * >(
1627
0
        getNode().get());
1628
0
    checkValue(value, locprop->getStaticType(), locprop->isNillable());
1629
0
    rtl::Reference child(
1630
0
        new ChildAccess(
1631
0
            components_, getRootAccess(), this, name,
1632
0
            new LocalizedValueNode(Data::NO_LAYER, value)));
1633
0
    markChildAsModified(child);
1634
0
    localModifications->add(child->getRelativePath());
1635
0
}
1636
1637
void Access::reportChildChanges(
1638
    std::vector< css::util::ElementChange > * changes)
1639
0
{
1640
0
    assert(changes != nullptr);
1641
0
    for (ModifiedChildren::iterator i(modifiedChildren_.begin());
1642
0
         i != modifiedChildren_.end(); ++i)
1643
0
    {
1644
0
        rtl::Reference< ChildAccess > child(getModifiedChild(i));
1645
0
        if (child.is()) {
1646
0
            child->reportChildChanges(changes);
1647
0
            changes->push_back(css::util::ElementChange());
1648
                //TODO: changed value and/or inserted node
1649
0
        } else {
1650
0
            changes->push_back(css::util::ElementChange()); //TODO: removed node
1651
0
        }
1652
0
    }
1653
0
}
1654
1655
void Access::commitChildChanges(
1656
    bool valid, Modifications * globalModifications)
1657
0
{
1658
0
    assert(globalModifications != nullptr);
1659
0
    while (!modifiedChildren_.empty()) {
1660
0
        bool childValid = valid;
1661
0
        ModifiedChildren::iterator i(modifiedChildren_.begin());
1662
0
        rtl::Reference< ChildAccess > child(getModifiedChild(i));
1663
0
        if (child.is()) {
1664
0
            childValid = childValid && !child->isFinalized();
1665
0
            child->commitChanges(childValid, globalModifications);
1666
                //TODO: currently, this is called here for directly inserted
1667
                // children as well as for children whose sub-children were
1668
                // modified (and should never be called for directly removed
1669
                // children); clarify what exactly should happen here for
1670
                // directly inserted children
1671
0
        }
1672
0
        NodeMap & members = getNode()->getMembers();
1673
0
        NodeMap::iterator j(members.find(i->first));
1674
0
        if (child.is()) {
1675
            // Inserted:
1676
0
            if (j != members.end()) {
1677
0
                childValid = childValid &&
1678
0
                    j->second->getFinalized() == Data::NO_LAYER;
1679
0
                if (childValid) {
1680
0
                    child->getNode()->setMandatory(j->second->getMandatory());
1681
0
                }
1682
0
            }
1683
0
            if (childValid) {
1684
0
                members[i->first] = child->getNode();
1685
0
            }
1686
0
        } else {
1687
            // Removed:
1688
0
            childValid = childValid && j != members.end() &&
1689
0
                j->second->getFinalized() == Data::NO_LAYER &&
1690
0
                j->second->getMandatory() == Data::NO_LAYER;
1691
0
            if (childValid) {
1692
0
                members.erase(j);
1693
0
            }
1694
0
        }
1695
0
        if (childValid && i->second.directlyModified) {
1696
0
            std::vector<OUString> path(getAbsolutePath());
1697
0
            path.push_back(i->first);
1698
0
            components_.addModification(path);
1699
0
            globalModifications->add(path);
1700
0
        }
1701
0
        i->second.child->committed();
1702
0
        modifiedChildren_.erase(i);
1703
0
    }
1704
0
}
1705
1706
void Access::initBroadcasterAndChanges(
1707
    Modifications::Node const & modifications, Broadcaster * broadcaster,
1708
    std::vector< css::util::ElementChange > * allChanges)
1709
0
{
1710
0
    assert(broadcaster != nullptr);
1711
0
    std::vector< css::beans::PropertyChangeEvent > propChanges;
1712
0
    bool collectPropChanges = !propertiesChangeListeners_.empty();
1713
0
    for (const auto & i : modifications.children)
1714
0
    {
1715
0
        rtl::Reference< ChildAccess > child(getChild(i.first));
1716
0
        if (child.is()) {
1717
0
            switch (child->getNode()->kind()) {
1718
0
            case Node::KIND_LOCALIZED_PROPERTY:
1719
0
                if (!i.second.children.empty()) {
1720
0
                    if (Components::allLocales(getRootAccess()->getLocale())) {
1721
0
                        child->initBroadcasterAndChanges(
1722
0
                            i.second, broadcaster, allChanges);
1723
                            //TODO: if allChanges==0, recurse only into children
1724
                            // w/ listeners
1725
0
                    } else {
1726
                        //TODO: filter child mods that are irrelevant for
1727
                        // locale:
1728
0
                        for (auto const& containerListener : containerListeners_)
1729
0
                        {
1730
0
                            broadcaster->
1731
0
                                addContainerElementReplacedNotification(
1732
0
                                    containerListener,
1733
0
                                    css::container::ContainerEvent(
1734
0
                                        getXWeak(),
1735
0
                                        css::uno::Any(i.first),
1736
0
                                        css::uno::Any(), css::uno::Any()));
1737
                                //TODO: non-void Element, ReplacedElement
1738
0
                        }
1739
0
                        PropertyChangeListeners::iterator j(
1740
0
                            propertyChangeListeners_.find(i.first));
1741
0
                        if (j != propertyChangeListeners_.end()) {
1742
0
                            for (auto const& propertyChangeListenerElement : j->second)
1743
0
                            {
1744
0
                                broadcaster->addPropertyChangeNotification(
1745
0
                                    propertyChangeListenerElement,
1746
0
                                    css::beans::PropertyChangeEvent(
1747
0
                                        getXWeak(),
1748
0
                                        i.first, false, -1, css::uno::Any(),
1749
0
                                        css::uno::Any()));
1750
0
                            }
1751
0
                        }
1752
0
                        j = propertyChangeListeners_.find(u""_ustr);
1753
0
                        if (j != propertyChangeListeners_.end()) {
1754
0
                            for (auto const& propertyChangeListenerElement : j->second)
1755
0
                            {
1756
0
                                broadcaster->addPropertyChangeNotification(
1757
0
                                    propertyChangeListenerElement,
1758
0
                                    css::beans::PropertyChangeEvent(
1759
0
                                        getXWeak(),
1760
0
                                        i.first, false, -1, css::uno::Any(),
1761
0
                                        css::uno::Any()));
1762
0
                            }
1763
0
                        }
1764
0
                        if (allChanges != nullptr) {
1765
0
                            allChanges->push_back(
1766
0
                                css::util::ElementChange(
1767
0
                                    css::uno::Any(
1768
0
                                        child->getRelativePathRepresentation()),
1769
0
                                    css::uno::Any(), css::uno::Any()));
1770
                                //TODO: non-void Element, ReplacedElement
1771
0
                        }
1772
0
                        if (collectPropChanges) {
1773
0
                            propChanges.emplace_back(
1774
0
                                    getXWeak(),
1775
0
                                    i.first, false, -1, css::uno::Any(),
1776
0
                                    css::uno::Any());
1777
0
                        }
1778
0
                    }
1779
0
                }
1780
                // else: spurious Modifications::Node not representing a change
1781
0
                break;
1782
0
            case Node::KIND_LOCALIZED_VALUE:
1783
0
                assert(Components::allLocales(getRootAccess()->getLocale()));
1784
0
                for (auto const& containerListener : containerListeners_)
1785
0
                {
1786
0
                    broadcaster->addContainerElementReplacedNotification(
1787
0
                        containerListener,
1788
0
                        css::container::ContainerEvent(
1789
0
                            getXWeak(),
1790
0
                            css::uno::Any(i.first), child->asValue(),
1791
0
                            css::uno::Any()));
1792
                        //TODO: distinguish add/modify; non-void ReplacedElement
1793
0
                }
1794
0
                if (allChanges != nullptr) {
1795
0
                    allChanges->push_back(
1796
0
                        css::util::ElementChange(
1797
0
                            css::uno::Any(
1798
0
                                child->getRelativePathRepresentation()),
1799
0
                            child->asValue(), css::uno::Any()));
1800
                        //TODO: non-void ReplacedElement
1801
0
                }
1802
0
                assert(!collectPropChanges);
1803
0
                break;
1804
0
            case Node::KIND_PROPERTY:
1805
0
                {
1806
0
                    for (auto const& containerListener : containerListeners_)
1807
0
                    {
1808
0
                        broadcaster->addContainerElementReplacedNotification(
1809
0
                            containerListener,
1810
0
                            css::container::ContainerEvent(
1811
0
                                getXWeak(),
1812
0
                                css::uno::Any(i.first), child->asValue(),
1813
0
                                css::uno::Any()));
1814
                            //TODO: distinguish add/remove/modify; non-void
1815
                            // ReplacedElement
1816
0
                    }
1817
0
                    PropertyChangeListeners::iterator j(
1818
0
                        propertyChangeListeners_.find(i.first));
1819
0
                    if (j != propertyChangeListeners_.end()) {
1820
0
                        for (auto const& propertyChangeListenerElement : j->second)
1821
0
                        {
1822
0
                            broadcaster->addPropertyChangeNotification(
1823
0
                                propertyChangeListenerElement,
1824
0
                                css::beans::PropertyChangeEvent(
1825
0
                                    getXWeak(),
1826
0
                                    i.first, false, -1, css::uno::Any(),
1827
0
                                    css::uno::Any()));
1828
0
                        }
1829
0
                    }
1830
0
                    j = propertyChangeListeners_.find(u""_ustr);
1831
0
                    if (j != propertyChangeListeners_.end()) {
1832
0
                        for (auto const& propertyChangeListenerElement : j->second)
1833
0
                        {
1834
0
                            broadcaster->addPropertyChangeNotification(
1835
0
                                propertyChangeListenerElement,
1836
0
                                css::beans::PropertyChangeEvent(
1837
0
                                    getXWeak(),
1838
0
                                    i.first, false, -1, css::uno::Any(),
1839
0
                                    css::uno::Any()));
1840
0
                        }
1841
0
                    }
1842
0
                    if (allChanges != nullptr) {
1843
0
                        allChanges->push_back(
1844
0
                            css::util::ElementChange(
1845
0
                                css::uno::Any(
1846
0
                                    child->getRelativePathRepresentation()),
1847
0
                                child->asValue(), css::uno::Any()));
1848
                            //TODO: non-void ReplacedElement
1849
0
                    }
1850
0
                    if (collectPropChanges) {
1851
0
                        propChanges.emplace_back(
1852
0
                                getXWeak(),
1853
0
                                i.first, false, -1, css::uno::Any(),
1854
0
                                css::uno::Any());
1855
0
                    }
1856
0
                }
1857
0
                break;
1858
0
            case Node::KIND_GROUP:
1859
0
            case Node::KIND_SET:
1860
0
                if (i.second.children.empty()) {
1861
0
                    if (!child->getNode()->getTemplateName().isEmpty()) {
1862
0
                        for (auto const& containerListener : containerListeners_)
1863
0
                        {
1864
0
                            broadcaster->
1865
0
                                addContainerElementInsertedNotification(
1866
0
                                    containerListener,
1867
0
                                    css::container::ContainerEvent(
1868
0
                                        getXWeak(),
1869
0
                                        css::uno::Any(i.first),
1870
0
                                        child->asValue(), css::uno::Any()));
1871
0
                        }
1872
0
                        if (allChanges != nullptr) {
1873
0
                            allChanges->push_back(
1874
0
                                css::util::ElementChange(
1875
0
                                    css::uno::Any(
1876
0
                                        child->getRelativePathRepresentation()),
1877
0
                                    css::uno::Any(), css::uno::Any()));
1878
                                //TODO: non-void Element, ReplacedElement
1879
0
                        }
1880
0
                    }
1881
                    // else: spurious Modifications::Node not representing a
1882
                    // change
1883
0
                } else {
1884
0
                    child->initBroadcasterAndChanges(
1885
0
                        i.second, broadcaster, allChanges);
1886
                        //TODO: if allChanges==0, recurse only into children w/
1887
                        // listeners
1888
0
                }
1889
0
                break;
1890
0
            case Node::KIND_ROOT:
1891
0
                assert(false); // this cannot happen
1892
0
                break;
1893
0
            }
1894
0
        } else {
1895
0
            switch (getNode()->kind()) {
1896
0
            case Node::KIND_LOCALIZED_PROPERTY:
1897
                // Removed localized property value:
1898
0
                assert(Components::allLocales(getRootAccess()->getLocale()));
1899
0
                for (auto const& containerListener : containerListeners_)
1900
0
                {
1901
0
                    broadcaster->addContainerElementRemovedNotification(
1902
0
                        containerListener,
1903
0
                        css::container::ContainerEvent(
1904
0
                            getXWeak(),
1905
0
                            css::uno::Any(i.first), css::uno::Any(),
1906
0
                            css::uno::Any()));
1907
                        //TODO: non-void ReplacedElement
1908
0
                }
1909
0
                if (allChanges != nullptr) {
1910
0
                    OUStringBuffer path(getRelativePathRepresentation());
1911
0
                    if (!path.isEmpty()) {
1912
0
                        path.append('/');
1913
0
                    }
1914
0
                    path.append(Data::createSegment(u"*", i.first));
1915
0
                    allChanges->push_back(
1916
0
                        css::util::ElementChange(
1917
0
                            css::uno::Any(path.makeStringAndClear()),
1918
0
                            css::uno::Any(), css::uno::Any()));
1919
                        //TODO: non-void ReplacedElement
1920
0
                }
1921
0
                assert(!collectPropChanges);
1922
0
                break;
1923
0
            case Node::KIND_GROUP:
1924
0
                {
1925
                    // Removed (non-localized) extension property:
1926
0
                    for (auto const& containerListener : containerListeners_)
1927
0
                    {
1928
0
                        broadcaster->addContainerElementRemovedNotification(
1929
0
                            containerListener,
1930
0
                            css::container::ContainerEvent(
1931
0
                                getXWeak(),
1932
0
                                css::uno::Any(i.first), css::uno::Any(),
1933
0
                                css::uno::Any()));
1934
                            //TODO: non-void ReplacedElement
1935
0
                    }
1936
0
                    PropertyChangeListeners::iterator j(
1937
0
                        propertyChangeListeners_.find(i.first));
1938
0
                    if (j != propertyChangeListeners_.end()) {
1939
0
                        for (auto const& propertyChangeListenerElement : j->second)
1940
0
                        {
1941
0
                            broadcaster->addPropertyChangeNotification(
1942
0
                                propertyChangeListenerElement,
1943
0
                                css::beans::PropertyChangeEvent(
1944
0
                                    getXWeak(),
1945
0
                                    i.first, false, -1, css::uno::Any(),
1946
0
                                    css::uno::Any()));
1947
0
                        }
1948
0
                    }
1949
0
                    j = propertyChangeListeners_.find(u""_ustr);
1950
0
                    if (j != propertyChangeListeners_.end()) {
1951
0
                        for (auto const& propertyChangeListenerElement : j->second)
1952
0
                        {
1953
0
                            broadcaster->addPropertyChangeNotification(
1954
0
                                propertyChangeListenerElement,
1955
0
                                css::beans::PropertyChangeEvent(
1956
0
                                    getXWeak(),
1957
0
                                    i.first, false, -1, css::uno::Any(),
1958
0
                                    css::uno::Any()));
1959
0
                        }
1960
0
                    }
1961
0
                    if (allChanges != nullptr) {
1962
0
                        OUStringBuffer path(
1963
0
                            getRelativePathRepresentation());
1964
0
                        if (!path.isEmpty()) {
1965
0
                            path.append('/');
1966
0
                        }
1967
0
                        path.append(i.first);
1968
0
                        allChanges->push_back(
1969
0
                            css::util::ElementChange(
1970
0
                                css::uno::Any(path.makeStringAndClear()),
1971
0
                                css::uno::Any(), css::uno::Any()));
1972
                            //TODO: non-void ReplacedElement
1973
0
                    }
1974
0
                    if (collectPropChanges) {
1975
0
                        propChanges.emplace_back(
1976
0
                                getXWeak(),
1977
0
                                i.first, false, -1, css::uno::Any(),
1978
0
                                css::uno::Any());
1979
0
                    }
1980
0
                }
1981
0
                break;
1982
0
            case Node::KIND_SET:
1983
                // Removed set member:
1984
0
                if (i.second.children.empty()) {
1985
0
                    for (auto const& containerListener : containerListeners_)
1986
0
                    {
1987
0
                        broadcaster->addContainerElementRemovedNotification(
1988
0
                            containerListener,
1989
0
                            css::container::ContainerEvent(
1990
0
                                getXWeak(),
1991
0
                                css::uno::Any(i.first),
1992
0
                                css::uno::Any(), css::uno::Any()));
1993
                            //TODO: non-void ReplacedElement
1994
0
                    }
1995
0
                    if (allChanges != nullptr) {
1996
0
                        OUStringBuffer path(
1997
0
                            getRelativePathRepresentation());
1998
0
                        if (!path.isEmpty()) {
1999
0
                            path.append('/');
2000
0
                        }
2001
0
                        path.append(Data::createSegment(u"*", i.first));
2002
0
                        allChanges->push_back(
2003
0
                            css::util::ElementChange(
2004
0
                                css::uno::Any(path.makeStringAndClear()),
2005
0
                                css::uno::Any(), css::uno::Any()));
2006
                            //TODO: non-void ReplacedElement
2007
0
                    }
2008
0
                }
2009
                // else: spurious Modifications::Node not representing a change
2010
0
                break;
2011
0
            default:
2012
0
                assert(false); // this cannot happen
2013
0
                break;
2014
0
            }
2015
0
        }
2016
0
    }
2017
0
    if (!propChanges.empty()) {
2018
0
        css::uno::Sequence< css::beans::PropertyChangeEvent > seq(
2019
0
            comphelper::containerToSequence(propChanges));
2020
0
        for (auto const& propertyChangeListener : propertiesChangeListeners_)
2021
0
        {
2022
0
            broadcaster->addPropertiesChangeNotification(propertyChangeListener, seq);
2023
0
        }
2024
0
    }
2025
0
}
2026
2027
2028
Access::ModifiedChild::ModifiedChild():
2029
0
    directlyModified(false)
2030
0
{}
2031
2032
Access::ModifiedChild::ModifiedChild(
2033
    rtl::Reference< ChildAccess > theChild, bool theDirectlyModified):
2034
0
    child(std::move(theChild)), directlyModified(theDirectlyModified)
2035
0
{}
2036
2037
rtl::Reference< ChildAccess > Access::getModifiedChild(
2038
    ModifiedChildren::iterator const & childIterator)
2039
0
{
2040
0
    return (childIterator->second.child->getParentAccess() == this &&
2041
0
            (childIterator->second.child->getNameInternal() ==
2042
0
             childIterator->first))
2043
0
        ? childIterator->second.child : rtl::Reference< ChildAccess >();
2044
0
}
2045
2046
rtl::Reference< ChildAccess > Access::createUnmodifiedChild(
2047
                const OUString &name, const rtl::Reference< Node > &node)
2048
0
{
2049
0
    rtl::Reference child(
2050
0
        new ChildAccess(components_, getRootAccess(), this, name, node));
2051
0
    cachedChildren_[name] = child.get();
2052
0
    return child;
2053
0
}
2054
2055
rtl::Reference< ChildAccess > Access::getUnmodifiedChild(
2056
    OUString const & name)
2057
50.1k
{
2058
50.1k
    assert(modifiedChildren_.find(name) == modifiedChildren_.end());
2059
50.1k
    rtl::Reference< Node > node(getNode()->getMember(name));
2060
50.1k
    if (!node.is()) {
2061
50.1k
        return rtl::Reference< ChildAccess >();
2062
50.1k
    }
2063
0
    WeakChildMap::iterator i(cachedChildren_.find(name));
2064
0
    if (i != cachedChildren_.end()) {
2065
0
        rtl::Reference< ChildAccess > child;
2066
0
        if (i->second->acquireCounting() > 1) {
2067
0
            child.set(i->second); // must not throw
2068
0
        }
2069
0
        i->second->releaseNondeleting();
2070
0
        if (child.is()) {
2071
0
            child->setNode(node);
2072
0
            return child;
2073
0
        }
2074
0
    }
2075
0
    return createUnmodifiedChild(name,node);
2076
0
}
2077
2078
50.1k
rtl::Reference< ChildAccess > Access::getSubChild(OUString const & path) {
2079
50.1k
    sal_Int32 i = 0;
2080
    // For backwards compatibility, allow absolute paths where meaningful:
2081
50.1k
    if( path.startsWith("/") ) {
2082
50.1k
        ++i;
2083
50.1k
        if (!getRootAccess().is()) {
2084
0
            return rtl::Reference< ChildAccess >();
2085
0
        }
2086
50.1k
        std::vector<OUString> abs(getAbsolutePath());
2087
50.1k
        for (auto const& elem : abs)
2088
0
        {
2089
0
            OUString name1;
2090
0
            bool setElement1;
2091
0
            OUString templateName1;
2092
0
            i = Data::parseSegment(
2093
0
                path, i, &name1, &setElement1, &templateName1);
2094
0
            if (i == -1 || (i != path.getLength() && path[i] != '/')) {
2095
0
                return rtl::Reference< ChildAccess >();
2096
0
            }
2097
0
            OUString name2;
2098
0
            bool setElement2;
2099
0
            OUString templateName2;
2100
0
            Data::parseSegment(elem, 0, &name2, &setElement2, &templateName2);
2101
0
            if (name1 != name2 || setElement1 != setElement2 ||
2102
0
                (setElement1 &&
2103
0
                 !Data::equalTemplateNames(templateName1, templateName2)))
2104
0
            {
2105
0
                return rtl::Reference< ChildAccess >();
2106
0
            }
2107
0
            if (i != path.getLength()) {
2108
0
                ++i;
2109
0
            }
2110
0
        }
2111
50.1k
    }
2112
50.1k
    for (rtl::Reference< Access > parent(this);;) {
2113
50.1k
        OUString name;
2114
50.1k
        bool setElement;
2115
50.1k
        OUString templateName;
2116
50.1k
        i = Data::parseSegment(path, i, &name, &setElement, &templateName);
2117
50.1k
        if (i == -1 || (i != path.getLength() && path[i] != '/')) {
2118
0
            return rtl::Reference< ChildAccess >();
2119
0
        }
2120
50.1k
        rtl::Reference< ChildAccess > child(parent->getChild(name));
2121
50.1k
        if (!child.is()) {
2122
50.1k
            return rtl::Reference< ChildAccess >();
2123
50.1k
        }
2124
0
        if (setElement) {
2125
0
            const rtl::Reference< Node >& p(parent->getNode());
2126
0
            switch (p->kind()) {
2127
0
            case Node::KIND_LOCALIZED_PROPERTY:
2128
0
                if (!Components::allLocales(getRootAccess()->getLocale()) ||
2129
0
                    !templateName.isEmpty())
2130
0
                {
2131
0
                    return rtl::Reference< ChildAccess >();
2132
0
                }
2133
0
                break;
2134
0
            case Node::KIND_SET:
2135
0
                if (!templateName.isEmpty() &&
2136
0
                    !static_cast< SetNode * >(p.get())->isValidTemplate(
2137
0
                        templateName))
2138
0
                {
2139
0
                    return rtl::Reference< ChildAccess >();
2140
0
                }
2141
0
                break;
2142
0
            default:
2143
0
                return rtl::Reference< ChildAccess >();
2144
0
            }
2145
0
        }
2146
        // For backwards compatibility, ignore a final slash after non-value
2147
        // nodes:
2148
0
        if (child->isValue()) {
2149
0
            return i == path.getLength()
2150
0
                ? child : rtl::Reference< ChildAccess >();
2151
0
        } else if (i >= path.getLength() - 1) {
2152
0
            return child;
2153
0
        }
2154
0
        ++i;
2155
0
        parent = child.get();
2156
0
    }
2157
50.1k
}
2158
2159
bool Access::setChildProperty(
2160
    OUString const & name, css::uno::Any const & value,
2161
    Modifications * localModifications)
2162
0
{
2163
0
    assert(localModifications != nullptr);
2164
0
    rtl::Reference< ChildAccess > child(getChild(name));
2165
0
    if (!child.is()) {
2166
0
        return false;
2167
0
    }
2168
0
    child->checkFinalized();
2169
0
    child->setProperty(value, localModifications);
2170
0
    return true;
2171
0
}
2172
2173
0
css::beans::Property Access::asProperty() {
2174
0
    css::uno::Type type;
2175
0
    bool nillable;
2176
0
    bool removable;
2177
0
    const rtl::Reference< Node >& p(getNode());
2178
0
    switch (p->kind()) {
2179
0
    case Node::KIND_PROPERTY:
2180
0
        {
2181
0
            PropertyNode * prop = static_cast< PropertyNode * >(p.get());
2182
0
            type = mapType(prop->getStaticType());
2183
0
            nillable = prop->isNillable();
2184
0
            removable = prop->isExtension();
2185
0
        }
2186
0
        break;
2187
0
    case Node::KIND_LOCALIZED_PROPERTY:
2188
0
        {
2189
0
            LocalizedPropertyNode * locprop =
2190
0
                static_cast< LocalizedPropertyNode *>(p.get());
2191
0
            if (Components::allLocales(getRootAccess()->getLocale())) {
2192
0
                type = cppu::UnoType< css::uno::XInterface >::get();
2193
                    //TODO: correct?
2194
0
                removable = false;
2195
0
            } else {
2196
0
                type = mapType(locprop->getStaticType());
2197
0
                removable = false; //TODO ???
2198
0
            }
2199
0
            nillable = locprop->isNillable();
2200
0
        }
2201
0
        break;
2202
0
    case Node::KIND_LOCALIZED_VALUE:
2203
0
        {
2204
0
            LocalizedPropertyNode * locprop =
2205
0
                static_cast< LocalizedPropertyNode * >(getParentNode().get());
2206
0
            type = mapType(locprop->getStaticType());
2207
0
            nillable = locprop->isNillable();
2208
0
            removable = false; //TODO ???
2209
0
        }
2210
0
        break;
2211
0
    default:
2212
0
        type = cppu::UnoType< css::uno::XInterface >::get(); //TODO: correct?
2213
0
        nillable = false;
2214
0
        rtl::Reference< Node > parent(getParentNode());
2215
0
        removable = parent.is() && parent->kind() == Node::KIND_SET;
2216
0
        break;
2217
0
    }
2218
0
    return css::beans::Property(
2219
0
        getNameInternal(), -1, type,
2220
0
        (css::beans::PropertyAttribute::BOUND | //TODO: correct for group/set?
2221
0
         css::beans::PropertyAttribute::CONSTRAINED |
2222
0
         (nillable ? css::beans::PropertyAttribute::MAYBEVOID : 0) |
2223
0
         (getRootAccess()->isUpdate() && removable
2224
0
          ? css::beans::PropertyAttribute::REMOVABLE : 0) |
2225
0
         (!getRootAccess()->isUpdate() || isFinalized()
2226
0
          ? css::beans::PropertyAttribute::READONLY : 0))); //TODO: MAYBEDEFAULT
2227
0
}
2228
2229
0
void Access::checkFinalized() {
2230
0
    if (isFinalized()) {
2231
0
        throw css::lang::IllegalArgumentException(
2232
0
            u"configmgr modification of finalized item"_ustr,
2233
0
            getXWeak(), -1);
2234
0
    }
2235
0
}
2236
2237
0
void Access::checkKnownProperty(OUString const & descriptor) {
2238
0
    if (descriptor.isEmpty()) {
2239
0
        return;
2240
0
    }
2241
0
    rtl::Reference< ChildAccess > child(getChild(descriptor));
2242
0
    if (child.is()) {
2243
0
        switch (child->getNode()->kind()) {
2244
0
        case Node::KIND_PROPERTY:
2245
0
            return;
2246
0
        case Node::KIND_LOCALIZED_PROPERTY:
2247
0
            if (!Components::allLocales(getRootAccess()->getLocale())) {
2248
0
                return;
2249
0
            }
2250
0
            break;
2251
0
        case Node::KIND_LOCALIZED_VALUE:
2252
0
            if (Components::allLocales(getRootAccess()->getLocale())) {
2253
0
                return;
2254
0
            }
2255
0
            break;
2256
0
        default:
2257
0
            break;
2258
0
        }
2259
0
    }
2260
0
    throw css::beans::UnknownPropertyException(
2261
0
        descriptor, getXWeak());
2262
0
}
2263
2264
rtl::Reference< ChildAccess > Access::getFreeSetMember(
2265
    css::uno::Any const & value)
2266
0
{
2267
0
    css::uno::Reference<XInterface> xTmp;
2268
0
    value >>= xTmp;
2269
0
    rtl::Reference< ChildAccess > freeAcc = dynamic_cast<ChildAccess*>(xTmp.get());
2270
0
    if (!freeAcc.is() || freeAcc->getParentAccess().is() ||
2271
0
        (freeAcc->isInTransaction() &&
2272
0
         freeAcc->getRootAccess() != getRootAccess()))
2273
0
    {
2274
0
        throw css::lang::IllegalArgumentException(
2275
0
            u"configmgr inappropriate set element"_ustr,
2276
0
            getXWeak(), 1);
2277
0
    }
2278
0
    assert(dynamic_cast< SetNode * >(getNode().get()) != nullptr);
2279
0
    if (!static_cast< SetNode * >(getNode().get())->isValidTemplate(
2280
0
            freeAcc->getNode()->getTemplateName()))
2281
0
    {
2282
0
        throw css::lang::IllegalArgumentException(
2283
0
            u"configmgr inappropriate set element"_ustr,
2284
0
            getXWeak(), 1);
2285
0
    }
2286
0
    return freeAcc;
2287
0
}
2288
2289
0
rtl::Reference< Access > Access::getNotificationRoot() {
2290
0
    for (rtl::Reference< Access > p(this);;) {
2291
0
        rtl::Reference< Access > parent(p->getParentAccess());
2292
0
        if (!parent.is()) {
2293
0
            return p;
2294
0
        }
2295
0
        p = std::move(parent);
2296
0
    }
2297
0
}
2298
2299
#if !defined NDEBUG
2300
bool Access::thisIs(int what) {
2301
    osl::MutexGuard g(*lock_);
2302
    const rtl::Reference< Node >& p(getNode());
2303
    Node::Kind k(p->kind());
2304
    return (k != Node::KIND_PROPERTY && k != Node::KIND_LOCALIZED_VALUE &&
2305
        ((what & IS_GROUP) == 0 || k == Node::KIND_GROUP) &&
2306
        ((what & IS_SET) == 0 || k == Node::KIND_SET) &&
2307
        ((what & IS_EXTENSIBLE) == 0 || k != Node::KIND_GROUP ||
2308
         static_cast< GroupNode * >(p.get())->isExtensible()) &&
2309
        ((what & IS_GROUP_MEMBER) == 0 ||
2310
         getParentNode()->kind() == Node::KIND_GROUP)) ||
2311
        ((what & IS_SET_MEMBER) == 0 ||
2312
         getParentNode()->kind() == Node::KIND_SET) ||
2313
        ((what & IS_UPDATE) == 0 || getRootAccess()->isUpdate());
2314
}
2315
#endif
2316
2317
}
2318
2319
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */