1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <sal/config.h>
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/servicehelper.hxx>
72 #include <comphelper/string.hxx>
73 #include <comphelper/lok.hxx>
74 #include <i18nlangtag/languagetag.hxx>
75 #include <cppu/unotype.hxx>
76 #include <cppuhelper/queryinterface.hxx>
77 #include <cppuhelper/supportsservice.hxx>
78 #include <cppuhelper/weak.hxx>
79 #include <osl/interlck.h>
80 #include <osl/mutex.hxx>
81 #include <rtl/character.hxx>
82 #include <rtl/ref.hxx>
83 #include <rtl/ustrbuf.hxx>
84 #include <rtl/ustring.hxx>
85 #include <sal/log.hxx>
86 #include <sal/types.h>
89 #include "broadcaster.hxx"
90 #include "childaccess.hxx"
91 #include "components.hxx"
93 #include "groupnode.hxx"
94 #include "localizedpropertynode.hxx"
95 #include "localizedvaluenode.hxx"
97 #include "modifications.hxx"
99 #include "nodemap.hxx"
100 #include "propertynode.hxx"
101 #include "rootaccess.hxx"
102 #include "setnode.hxx"
105 namespace configmgr
{
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 bool isValidName(OUString
const & name
, bool setMember
) {
113 for (sal_Int32 i
= 0; i
!= name
.getLength();) {
114 sal_uInt32 c
= name
.iterateCodePoints(&i
);
115 if ((c
< 0x20 && !(c
== 0x09 || c
== 0x0A || c
== 0x0D))
116 || rtl::isSurrogate(c
) || c
== 0xFFFE || c
== 0xFFFF
117 || (!setMember
&& c
== '/'))
122 return !name
.isEmpty();
127 oslInterlockedCount
Access::acquireCounting() {
128 return osl_atomic_increment(&m_refCount
);
131 void Access::releaseNondeleting() {
132 osl_atomic_decrement(&m_refCount
);
135 bool Access::isValue() {
136 const rtl::Reference
< Node
> & p(getNode());
138 case Node::KIND_PROPERTY
:
139 case Node::KIND_LOCALIZED_VALUE
:
141 case Node::KIND_LOCALIZED_PROPERTY
:
142 return !Components::allLocales(getRootAccess()->getLocale());
148 void Access::markChildAsModified(rtl::Reference
< ChildAccess
> const & child
) {
149 assert(child
.is() && child
->getParentAccess() == this);
150 modifiedChildren_
[child
->getNameInternal()] = ModifiedChild(child
, true);
151 for (rtl::Reference
< Access
> p(this);;) {
152 rtl::Reference
< Access
> parent(p
->getParentAccess());
156 assert(dynamic_cast< ChildAccess
* >(p
.get()) != nullptr);
157 parent
->modifiedChildren_
.emplace(
158 p
->getNameInternal(),
159 ModifiedChild(static_cast< ChildAccess
* >(p
.get()), false));
164 void Access::releaseChild(OUString
const & name
) {
165 cachedChildren_
.erase(name
);
168 void Access::initBroadcaster(
169 Modifications::Node
const & modifications
, Broadcaster
* broadcaster
)
171 initBroadcasterAndChanges(modifications
, broadcaster
, nullptr);
174 css::uno::Sequence
< css::uno::Type
> Access::getTypes()
176 assert(thisIs(IS_ANY
));
177 osl::MutexGuard
g(*lock_
);
178 checkLocalizedPropertyAccess();
179 std::vector
< css::uno::Type
> types
{ cppu::UnoType
< css::uno::XInterface
>::get(),
180 cppu::UnoType
< css::uno::XWeak
>::get(),
181 cppu::UnoType
< css::lang::XTypeProvider
>::get(),
182 cppu::UnoType
< css::lang::XServiceInfo
>::get(),
183 cppu::UnoType
< css::lang::XComponent
>::get(),
184 cppu::UnoType
< css::container::XContainer
>::get(),
185 cppu::UnoType
< css::beans::XExactName
>::get(),
186 cppu::UnoType
< css::container::XHierarchicalName
>::get(),
187 cppu::UnoType
< css::container::XNamed
>::get(),
188 cppu::UnoType
< css::beans::XProperty
>::get(),
189 cppu::UnoType
< css::container::XElementAccess
>::get(),
190 cppu::UnoType
< css::container::XNameAccess
>::get()
192 if (getNode()->kind() == Node::KIND_GROUP
) {
193 types
.push_back(cppu::UnoType
< css::beans::XPropertySetInfo
>::get());
194 types
.push_back(cppu::UnoType
< css::beans::XPropertySet
>::get());
195 types
.push_back(cppu::UnoType
< css::beans::XMultiPropertySet
>::get());
197 cppu::UnoType
< css::beans::XHierarchicalPropertySet
>::get());
199 cppu::UnoType
< css::beans::XMultiHierarchicalPropertySet
>::get());
201 cppu::UnoType
< css::beans::XHierarchicalPropertySetInfo
>::get());
203 if (getRootAccess()->isUpdate()) {
204 types
.push_back(cppu::UnoType
< css::container::XNameReplace
>::get());
206 cppu::UnoType
< css::container::XHierarchicalNameReplace
>::get());
207 if (getNode()->kind() != Node::KIND_GROUP
||
208 static_cast< GroupNode
* >(getNode().get())->isExtensible())
211 cppu::UnoType
< css::container::XNameContainer
>::get());
213 if (getNode()->kind() == Node::KIND_SET
) {
215 cppu::UnoType
< css::lang::XSingleServiceFactory
>::get());
219 cppu::UnoType
< css::container::XHierarchicalNameAccess
>::get());
221 cppu::UnoType
< css::configuration::XDocumentation
>::get());
224 return comphelper::containerToSequence(types
);
227 css::uno::Sequence
< sal_Int8
> Access::getImplementationId()
229 assert(thisIs(IS_ANY
));
230 osl::MutexGuard
g(*lock_
);
231 checkLocalizedPropertyAccess();
232 return css::uno::Sequence
< sal_Int8
>();
235 OUString
Access::getImplementationName()
237 assert(thisIs(IS_ANY
));
238 osl::MutexGuard
g(*lock_
);
239 checkLocalizedPropertyAccess();
240 return "org.openoffice-configmgr::Access";
243 sal_Bool
Access::supportsService(OUString
const & ServiceName
)
245 return cppu::supportsService(this, ServiceName
);
248 css::uno::Sequence
< OUString
> Access::getSupportedServiceNames()
250 assert(thisIs(IS_ANY
));
251 osl::MutexGuard
g(*lock_
);
252 checkLocalizedPropertyAccess();
253 std::vector
<OUString
> services
;
254 services
.emplace_back("com.sun.star.configuration.ConfigurationAccess");
255 if (getRootAccess()->isUpdate()) {
256 services
.emplace_back("com.sun.star.configuration.ConfigurationUpdateAccess");
258 services
.emplace_back("com.sun.star.configuration.HierarchyAccess");
259 services
.emplace_back("com.sun.star.configuration.HierarchyElement");
260 if (getNode()->kind() == Node::KIND_GROUP
) {
261 services
.emplace_back("com.sun.star.configuration.GroupAccess");
262 services
.emplace_back("com.sun.star.configuration.PropertyHierarchy");
263 if (getRootAccess()->isUpdate()) {
264 services
.emplace_back("com.sun.star.configuration.GroupUpdate");
267 services
.emplace_back("com.sun.star.configuration.SetAccess");
268 services
.emplace_back("com.sun.star.configuration.SimpleSetAccess");
269 if (getRootAccess()->isUpdate()) {
270 services
.emplace_back("com.sun.star.configuration.SetUpdate");
271 services
.emplace_back("com.sun.star.configuration.SimpleSetUpdate");
274 addSupportedServiceNames(&services
);
275 return comphelper::containerToSequence(services
);
278 void Access::dispose() {
279 assert(thisIs(IS_ANY
));
282 osl::MutexGuard
g(*lock_
);
283 checkLocalizedPropertyAccess();
284 if (getParentAccess().is()) {
285 throw css::uno::RuntimeException(
286 "configmgr dispose inappropriate Access",
292 initDisposeBroadcaster(&bc
);
299 void Access::addEventListener(
300 css::uno::Reference
< css::lang::XEventListener
> const & xListener
)
302 assert(thisIs(IS_ANY
));
304 osl::MutexGuard
g(*lock_
);
305 checkLocalizedPropertyAccess();
306 if (!xListener
.is()) {
307 throw css::uno::RuntimeException(
308 "null listener", getXWeak());
311 disposeListeners_
.insert(xListener
);
316 xListener
->disposing(
317 css::lang::EventObject(getXWeak()));
318 } catch (css::lang::DisposedException
&) {}
321 void Access::removeEventListener(
322 css::uno::Reference
< css::lang::XEventListener
> const & aListener
)
324 assert(thisIs(IS_ANY
));
325 osl::MutexGuard
g(*lock_
);
326 checkLocalizedPropertyAccess();
327 DisposeListeners::iterator
i(disposeListeners_
.find(aListener
));
328 if (i
!= disposeListeners_
.end()) {
329 disposeListeners_
.erase(i
);
333 css::uno::Type
Access::getElementType() {
334 assert(thisIs(IS_ANY
));
335 osl::MutexGuard
g(*lock_
);
336 checkLocalizedPropertyAccess();
337 const rtl::Reference
< Node
> & p(getNode());
339 case Node::KIND_LOCALIZED_PROPERTY
:
341 static_cast< LocalizedPropertyNode
* >(p
.get())->getStaticType());
342 case Node::KIND_GROUP
:
343 //TODO: Should a specific type be returned for a non-extensible group
344 // with homogeneous members or for an extensible group that currently
345 // has only homogeneous members?
346 return cppu::UnoType
<void>::get();
348 return cppu::UnoType
<void>::get(); //TODO: correct?
351 throw css::uno::RuntimeException(
352 "this cannot happen", getXWeak());
356 sal_Bool
Access::hasElements() {
357 assert(thisIs(IS_ANY
));
358 osl::MutexGuard
g(*lock_
);
359 checkLocalizedPropertyAccess();
360 return !isAllChildrenEmpty();
363 bool Access::getByNameFast(const OUString
& name
, css::uno::Any
& value
)
365 bool bGotValue
= false;
366 rtl::Reference
< ChildAccess
> child
;
368 if (getNode()->kind() != Node::KIND_LOCALIZED_PROPERTY
)
369 { // try to get it directly
370 ModifiedChildren::iterator
i(modifiedChildren_
.find(name
));
371 if (i
!= modifiedChildren_
.end())
373 child
= getModifiedChild(i
);
376 value
= child
->asValue();
382 rtl::Reference
< Node
> node(getNode()->getMember(name
));
385 bGotValue
= ChildAccess::asSimpleValue(node
, value
, components_
);
391 child
= getChild(name
);
394 value
= child
->asValue();
399 css::uno::Any
Access::getByName(OUString
const & aName
)
401 assert(thisIs(IS_ANY
));
402 osl::MutexGuard
g(*lock_
);
403 checkLocalizedPropertyAccess();
405 if (!getByNameFast(aName
, value
))
406 throw css::container::NoSuchElementException(
411 css::uno::Sequence
< OUString
> Access::getElementNames()
413 assert(thisIs(IS_ANY
));
414 osl::MutexGuard
g(*lock_
);
415 checkLocalizedPropertyAccess();
416 std::vector
<OUString
> childNames
;
417 forAllChildren([&childNames
] (ChildAccess
& rChild
)
419 childNames
.push_back(rChild
.getNameInternal());
422 return comphelper::containerToSequence(childNames
);
425 sal_Bool
Access::hasByName(OUString
const & aName
)
427 assert(thisIs(IS_ANY
));
428 osl::MutexGuard
g(*lock_
);
429 checkLocalizedPropertyAccess();
430 return getChild(aName
).is();
433 css::uno::Any
Access::getByHierarchicalName(OUString
const & aName
)
435 assert(thisIs(IS_ANY
));
436 osl::MutexGuard
g(*lock_
);
437 checkLocalizedPropertyAccess();
438 rtl::Reference
< ChildAccess
> child(getSubChild(aName
));
440 throw css::container::NoSuchElementException(
443 return child
->asValue();
446 OUString
Access::getDescriptionByHierarchicalName(OUString
const & aName
)
448 assert(thisIs(IS_ANY
));
449 osl::MutexGuard
g(*lock_
);
450 checkLocalizedPropertyAccess();
451 rtl::Reference
< ChildAccess
> child(getSubChild(aName
));
453 throw css::container::NoSuchElementException(
456 return child
->getNode()->getDescription();
459 css::uno::Type
Access::getTypeByHierarchicalName(OUString
const & aName
)
461 assert(thisIs(IS_ANY
));
462 osl::MutexGuard
g(*lock_
);
463 checkLocalizedPropertyAccess();
464 rtl::Reference
< ChildAccess
> child(getSubChild(aName
));
466 throw css::container::NoSuchElementException(
469 auto const & p
= child
->getNode();
471 case Node::KIND_PROPERTY
:
472 return mapType(static_cast<PropertyNode
*>(p
.get())->getStaticType());
473 case Node::KIND_LOCALIZED_PROPERTY
:
474 return mapType(static_cast<LocalizedPropertyNode
*>(p
.get())->getStaticType());
476 throw css::util::InvalidStateException(
481 sal_Bool
Access::getModifiedByHierarchicalName(OUString
const & aName
)
483 assert(thisIs(IS_ANY
));
484 osl::MutexGuard
g(*lock_
);
485 checkLocalizedPropertyAccess();
486 rtl::Reference
< ChildAccess
> child(getSubChild(aName
));
488 throw css::container::NoSuchElementException(
491 auto const & p
= child
->getNode();
493 case Node::KIND_PROPERTY
:
494 return static_cast<PropertyNode
*>(p
.get())->isModified();
495 case Node::KIND_LOCALIZED_VALUE
:
496 return static_cast<LocalizedValueNode
*>(p
.get())->isModified();
498 throw css::util::InvalidStateException(
503 sal_Bool
Access::hasByHierarchicalName(OUString
const & aName
)
505 assert(thisIs(IS_ANY
));
506 osl::MutexGuard
g(*lock_
);
507 checkLocalizedPropertyAccess();
508 return getSubChild(aName
).is();
511 void Access::replaceByHierarchicalName(
512 OUString
const & aName
, css::uno::Any
const & aElement
)
514 //TODO: Actually support sets and combine with replaceByName:
515 assert(thisIs(IS_UPDATE
));
518 osl::MutexGuard
g(*lock_
);
519 checkLocalizedPropertyAccess();
520 rtl::Reference
< ChildAccess
> child(getSubChild(aName
));
522 throw css::container::NoSuchElementException(
525 child
->checkFinalized();
526 rtl::Reference
< Node
> parent(child
->getParentNode());
528 Modifications localMods
;
529 switch (parent
->kind()) {
530 case Node::KIND_LOCALIZED_PROPERTY
:
531 case Node::KIND_GROUP
:
532 child
->setProperty(aElement
, &localMods
);
535 throw css::lang::IllegalArgumentException(
536 ("configmgr::Access::replaceByHierarchicalName does not"
537 " currently support set members"),
539 case Node::KIND_ROOT
:
540 throw css::lang::IllegalArgumentException(
541 ("configmgr::Access::replaceByHierarchicalName does not allow"
542 " changing component " + aName
),
545 assert(false); // this cannot happen
548 getNotificationRoot()->initBroadcaster(localMods
.getRoot(), &bc
);
553 void Access::addContainerListener(
554 css::uno::Reference
< css::container::XContainerListener
> const & xListener
)
556 assert(thisIs(IS_ANY
));
558 osl::MutexGuard
g(*lock_
);
559 checkLocalizedPropertyAccess();
560 if (!xListener
.is()) {
561 throw css::uno::RuntimeException(
562 "null listener", getXWeak());
565 containerListeners_
.insert(xListener
);
570 xListener
->disposing(
571 css::lang::EventObject(getXWeak()));
572 } catch (css::lang::DisposedException
&) {}
575 void Access::removeContainerListener(
576 css::uno::Reference
< css::container::XContainerListener
> const & xListener
)
578 assert(thisIs(IS_ANY
));
579 osl::MutexGuard
g(*lock_
);
580 checkLocalizedPropertyAccess();
581 ContainerListeners::iterator
i(containerListeners_
.find(xListener
));
582 if (i
!= containerListeners_
.end()) {
583 containerListeners_
.erase(i
);
587 OUString
Access::getExactName(OUString
const & aApproximateName
)
589 assert(thisIs(IS_ANY
));
590 osl::MutexGuard
g(*lock_
);
591 checkLocalizedPropertyAccess();
592 return aApproximateName
;
595 css::uno::Sequence
< css::beans::Property
> Access::getProperties()
597 assert(thisIs(IS_GROUP
));
598 osl::MutexGuard
g(*lock_
);
599 std::vector
< css::beans::Property
> properties
;
600 forAllChildren([&properties
] (ChildAccess
& rChild
)
602 properties
.push_back(rChild
.asProperty());
605 return comphelper::containerToSequence(properties
);
608 css::beans::Property
Access::getPropertyByName(OUString
const & aName
)
610 assert(thisIs(IS_GROUP
));
611 osl::MutexGuard
g(*lock_
);
612 rtl::Reference
< ChildAccess
> child(getChild(aName
));
614 throw css::beans::UnknownPropertyException(
617 return child
->asProperty();
620 sal_Bool
Access::hasPropertyByName(OUString
const & Name
)
622 assert(thisIs(IS_GROUP
));
623 osl::MutexGuard
g(*lock_
);
624 return getChild(Name
).is();
627 OUString
Access::getHierarchicalName() {
628 assert(thisIs(IS_ANY
));
629 osl::MutexGuard
g(*lock_
);
630 checkLocalizedPropertyAccess();
631 // For backwards compatibility, return an absolute path representation where
634 rtl::Reference
< RootAccess
> root(getRootAccess());
636 rootPath
= root
->getAbsolutePathRepresentation();
638 OUString
rel(getRelativePathRepresentation());
639 OUStringBuffer
path(rootPath
);
640 if (!rootPath
.isEmpty() && rootPath
!= "/" && !rel
.isEmpty()) {
644 return path
.makeStringAndClear();
647 OUString
Access::composeHierarchicalName(
648 OUString
const & aRelativeName
)
650 assert(thisIs(IS_ANY
));
651 osl::MutexGuard
g(*lock_
);
652 checkLocalizedPropertyAccess();
653 if (aRelativeName
.isEmpty() || aRelativeName
[0] == '/') {
654 throw css::lang::IllegalArgumentException(
655 "configmgr composeHierarchicalName inappropriate relative name",
658 OUStringBuffer
path(getRelativePathRepresentation());
659 if (!path
.isEmpty()) {
662 path
.append(aRelativeName
);
663 return path
.makeStringAndClear();
666 OUString
Access::getName() {
667 assert(thisIs(IS_ANY
));
668 osl::MutexGuard
g(*lock_
);
669 checkLocalizedPropertyAccess();
670 return getNameInternal();
673 void Access::setName(OUString
const & aName
)
675 assert(thisIs(IS_ANY
));
678 osl::MutexGuard
g(*lock_
);
679 checkLocalizedPropertyAccess();
681 Modifications localMods
;
682 switch (getNode()->kind()) {
683 case Node::KIND_GROUP
:
686 rtl::Reference
< Access
> parent(getParentAccess());
688 const rtl::Reference
< Node
> & node(getNode());
689 if (! node
->getTemplateName().isEmpty()) {
690 rtl::Reference
< ChildAccess
> other(
691 parent
->getChild(aName
));
692 if (other
.get() == this) {
695 if (node
->getMandatory() == Data::NO_LAYER
&&
696 !(other
.is() && other
->isFinalized()))
698 if (!isValidName(aName
, true)) {
699 throw css::uno::RuntimeException(
700 "invalid element name " + aName
);
702 rtl::Reference
< RootAccess
> root(getRootAccess());
703 rtl::Reference
< ChildAccess
> childAccess(
704 static_cast< ChildAccess
* >(this));
705 localMods
.add(getRelativePath());
706 // unbind() modifies the parent chain that
707 // markChildAsModified() walks, so order is
709 parent
->markChildAsModified(childAccess
);
710 //TODO: must not throw
711 childAccess
->unbind(); // must not throw
713 other
->unbind(); // must not throw
715 childAccess
->bind(root
, parent
, aName
);
717 parent
->markChildAsModified(childAccess
);
718 //TODO: must not throw
719 localMods
.add(getRelativePath());
726 case Node::KIND_LOCALIZED_PROPERTY
:
727 // renaming a property could only work for an extension property,
728 // but a localized property is never an extension property
729 throw css::uno::RuntimeException(
730 "configmgr setName inappropriate node",
733 assert(false); // this cannot happen
736 getNotificationRoot()->initBroadcaster(localMods
.getRoot(), &bc
);
741 css::beans::Property
Access::getAsProperty()
743 assert(thisIs(IS_ANY
));
744 osl::MutexGuard
g(*lock_
);
745 checkLocalizedPropertyAccess();
749 css::uno::Reference
< css::beans::XPropertySetInfo
> Access::getPropertySetInfo()
751 assert(thisIs(IS_GROUP
));
755 void Access::setPropertyValue(
756 OUString
const & aPropertyName
, css::uno::Any
const & aValue
)
758 assert(thisIs(IS_GROUP
));
761 osl::MutexGuard
g(*lock_
);
762 if (!getRootAccess()->isUpdate()) {
763 throw css::uno::RuntimeException(
764 "configmgr setPropertyValue on non-update access",
767 Modifications localMods
;
768 if (!setChildProperty(aPropertyName
, aValue
, &localMods
)) {
769 throw css::beans::UnknownPropertyException(
770 aPropertyName
, getXWeak());
772 getNotificationRoot()->initBroadcaster(localMods
.getRoot(), &bc
);
777 css::uno::Any
Access::getPropertyValue(OUString
const & PropertyName
)
779 assert(thisIs(IS_GROUP
));
780 osl::MutexGuard
g(*lock_
);
783 if (!getByNameFast(PropertyName
, value
))
784 throw css::beans::UnknownPropertyException(
785 PropertyName
, getXWeak());
789 void Access::addPropertyChangeListener(
790 OUString
const & aPropertyName
,
791 css::uno::Reference
< css::beans::XPropertyChangeListener
> const &
794 assert(thisIs(IS_GROUP
));
796 osl::MutexGuard
g(*lock_
);
797 if (!xListener
.is()) {
798 throw css::uno::RuntimeException(
799 "null listener", getXWeak());
801 checkKnownProperty(aPropertyName
);
803 propertyChangeListeners_
[aPropertyName
].insert(xListener
);
808 xListener
->disposing(
809 css::lang::EventObject(getXWeak()));
810 } catch (css::lang::DisposedException
&) {}
813 void Access::removePropertyChangeListener(
814 OUString
const & aPropertyName
,
815 css::uno::Reference
< css::beans::XPropertyChangeListener
> const &
818 assert(thisIs(IS_GROUP
));
819 osl::MutexGuard
g(*lock_
);
820 checkKnownProperty(aPropertyName
);
821 PropertyChangeListeners::iterator
i(
822 propertyChangeListeners_
.find(aPropertyName
));
823 if (i
!= propertyChangeListeners_
.end()) {
824 PropertyChangeListenersElement::iterator
j(i
->second
.find(aListener
));
825 if (j
!= i
->second
.end()) {
827 if (i
->second
.empty()) {
828 propertyChangeListeners_
.erase(i
);
834 void Access::addVetoableChangeListener(
835 OUString
const & PropertyName
,
836 css::uno::Reference
< css::beans::XVetoableChangeListener
> const &
839 assert(thisIs(IS_GROUP
));
841 osl::MutexGuard
g(*lock_
);
842 if (!aListener
.is()) {
843 throw css::uno::RuntimeException(
844 "null listener", getXWeak());
846 checkKnownProperty(PropertyName
);
848 vetoableChangeListeners_
[PropertyName
].insert(aListener
);
849 //TODO: actually call vetoableChangeListeners_
854 aListener
->disposing(
855 css::lang::EventObject(getXWeak()));
856 } catch (css::lang::DisposedException
&) {}
859 void Access::removeVetoableChangeListener(
860 OUString
const & PropertyName
,
861 css::uno::Reference
< css::beans::XVetoableChangeListener
> const &
864 assert(thisIs(IS_GROUP
));
865 osl::MutexGuard
g(*lock_
);
866 checkKnownProperty(PropertyName
);
867 VetoableChangeListeners::iterator
i(
868 vetoableChangeListeners_
.find(PropertyName
));
869 if (i
!= vetoableChangeListeners_
.end()) {
870 VetoableChangeListenersElement::iterator
j(i
->second
.find(aListener
));
871 if (j
!= i
->second
.end()) {
873 if (i
->second
.empty()) {
874 vetoableChangeListeners_
.erase(i
);
880 void Access::setPropertyValues(
881 css::uno::Sequence
< OUString
> const & aPropertyNames
,
882 css::uno::Sequence
< css::uno::Any
> const & aValues
)
884 assert(thisIs(IS_GROUP
));
887 osl::MutexGuard
g(*lock_
);
888 if (!getRootAccess()->isUpdate()) {
889 throw css::uno::RuntimeException(
890 "configmgr setPropertyValues on non-update access",
893 if (aPropertyNames
.getLength() != aValues
.getLength()) {
894 throw css::lang::IllegalArgumentException(
895 ("configmgr setPropertyValues: aPropertyNames/aValues of"
896 " different length"),
899 Modifications localMods
;
900 for (sal_Int32 i
= 0; i
< aPropertyNames
.getLength(); ++i
) {
901 if (!setChildProperty(aPropertyNames
[i
], aValues
[i
], &localMods
)) {
902 throw css::lang::IllegalArgumentException(
903 "configmgr setPropertyValues inappropriate property name",
907 getNotificationRoot()->initBroadcaster(localMods
.getRoot(), &bc
);
912 css::uno::Sequence
< css::uno::Any
> Access::getPropertyValues(
913 css::uno::Sequence
< OUString
> const & aPropertyNames
)
915 assert(thisIs(IS_GROUP
));
916 osl::MutexGuard
g(*lock_
);
917 css::uno::Sequence
< css::uno::Any
> vals(aPropertyNames
.getLength());
918 auto aValsRange
= asNonConstRange(vals
);
919 for (sal_Int32 i
= 0; i
< aPropertyNames
.getLength(); ++i
)
921 if (!getByNameFast(aPropertyNames
[i
], aValsRange
[i
]))
922 throw css::uno::RuntimeException(
923 "configmgr getPropertyValues inappropriate property name",
930 void Access::addPropertiesChangeListener(
931 css::uno::Sequence
< OUString
> const &,
932 css::uno::Reference
< css::beans::XPropertiesChangeListener
> const &
935 assert(thisIs(IS_GROUP
));
937 osl::MutexGuard
g(*lock_
);
938 if (!xListener
.is()) {
939 throw css::uno::RuntimeException(
940 "null listener", getXWeak());
943 propertiesChangeListeners_
.insert(xListener
);
948 xListener
->disposing(
949 css::lang::EventObject(getXWeak()));
950 } catch (css::lang::DisposedException
&) {}
953 void Access::removePropertiesChangeListener(
954 css::uno::Reference
< css::beans::XPropertiesChangeListener
> const &
957 assert(thisIs(IS_GROUP
));
958 osl::MutexGuard
g(*lock_
);
959 PropertiesChangeListeners::iterator
i(
960 propertiesChangeListeners_
.find(xListener
));
961 if (i
!= propertiesChangeListeners_
.end()) {
962 propertiesChangeListeners_
.erase(i
);
966 void Access::firePropertiesChangeEvent(
967 css::uno::Sequence
< OUString
> const & aPropertyNames
,
968 css::uno::Reference
< css::beans::XPropertiesChangeListener
> const &
971 assert(thisIs(IS_GROUP
));
972 css::uno::Sequence
< css::beans::PropertyChangeEvent
> events(
973 aPropertyNames
.getLength());
974 auto aEventsRange
= asNonConstRange(events
);
975 for (sal_Int32 i
= 0; i
< events
.getLength(); ++i
) {
976 aEventsRange
[i
].Source
= getXWeak();
977 aEventsRange
[i
].PropertyName
= aPropertyNames
[i
];
978 aEventsRange
[i
].Further
= false;
979 aEventsRange
[i
].PropertyHandle
= -1;
981 xListener
->propertiesChange(events
);
984 css::uno::Reference
< css::beans::XHierarchicalPropertySetInfo
>
985 Access::getHierarchicalPropertySetInfo() {
986 assert(thisIs(IS_GROUP
));
990 void Access::setHierarchicalPropertyValue(
991 OUString
const & aHierarchicalPropertyName
,
992 css::uno::Any
const & aValue
)
994 assert(thisIs(IS_GROUP
));
997 osl::MutexGuard
g(*lock_
);
998 if (!getRootAccess()->isUpdate()) {
999 throw css::uno::RuntimeException(
1000 "configmgr setHierarchicalPropertyName on non-update access",
1003 rtl::Reference
< ChildAccess
> child(
1004 getSubChild(aHierarchicalPropertyName
));
1006 throw css::beans::UnknownPropertyException(
1007 aHierarchicalPropertyName
,
1010 child
->checkFinalized();
1011 Modifications localMods
;
1012 child
->setProperty(aValue
, &localMods
);
1013 getNotificationRoot()->initBroadcaster(localMods
.getRoot(), &bc
);
1018 css::uno::Any
Access::getHierarchicalPropertyValue(
1019 OUString
const & aHierarchicalPropertyName
)
1021 assert(thisIs(IS_GROUP
));
1022 osl::MutexGuard
g(*lock_
);
1023 rtl::Reference
< ChildAccess
> child(getSubChild(aHierarchicalPropertyName
));
1025 throw css::beans::UnknownPropertyException(
1026 aHierarchicalPropertyName
,
1029 return child
->asValue();
1032 void Access::setHierarchicalPropertyValues(
1033 css::uno::Sequence
< OUString
> const & aHierarchicalPropertyNames
,
1034 css::uno::Sequence
< css::uno::Any
> const & Values
)
1036 assert(thisIs(IS_GROUP
));
1039 osl::MutexGuard
g(*lock_
);
1040 if (!getRootAccess()->isUpdate()) {
1041 throw css::uno::RuntimeException(
1042 "configmgr setPropertyValues on non-update access",
1045 if (aHierarchicalPropertyNames
.getLength() != Values
.getLength()) {
1046 throw css::lang::IllegalArgumentException(
1047 ("configmgr setHierarchicalPropertyValues:"
1048 " aHierarchicalPropertyNames/Values of different length"),
1051 Modifications localMods
;
1052 for (sal_Int32 i
= 0; i
< aHierarchicalPropertyNames
.getLength(); ++i
) {
1053 rtl::Reference
< ChildAccess
> child(
1054 getSubChild(aHierarchicalPropertyNames
[i
]));
1056 throw css::lang::IllegalArgumentException(
1057 ("configmgr setHierarchicalPropertyValues inappropriate"
1061 child
->checkFinalized();
1062 child
->setProperty(Values
[i
], &localMods
);
1064 getNotificationRoot()->initBroadcaster(localMods
.getRoot(), &bc
);
1069 css::uno::Sequence
< css::uno::Any
> Access::getHierarchicalPropertyValues(
1070 css::uno::Sequence
< OUString
> const & aHierarchicalPropertyNames
)
1072 assert(thisIs(IS_GROUP
));
1073 osl::MutexGuard
g(*lock_
);
1074 css::uno::Sequence
< css::uno::Any
> vals(
1075 aHierarchicalPropertyNames
.getLength());
1076 auto aValsRange
= asNonConstRange(vals
);
1077 for (sal_Int32 i
= 0; i
< aHierarchicalPropertyNames
.getLength(); ++i
) {
1078 rtl::Reference
< ChildAccess
> child(
1079 getSubChild(aHierarchicalPropertyNames
[i
]));
1081 throw css::lang::IllegalArgumentException(
1082 ("configmgr getHierarchicalPropertyValues inappropriate"
1083 " hierarchical property name"),
1086 aValsRange
[i
] = child
->asValue();
1091 css::beans::Property
Access::getPropertyByHierarchicalName(
1092 OUString
const & aHierarchicalName
)
1094 assert(thisIs(IS_GROUP
));
1095 osl::MutexGuard
g(*lock_
);
1096 rtl::Reference
< ChildAccess
> child(getSubChild(aHierarchicalName
));
1098 throw css::beans::UnknownPropertyException(
1099 aHierarchicalName
, getXWeak());
1101 return child
->asProperty();
1104 sal_Bool
Access::hasPropertyByHierarchicalName(
1105 OUString
const & aHierarchicalName
)
1107 assert(thisIs(IS_GROUP
));
1108 osl::MutexGuard
g(*lock_
);
1109 return getSubChild(aHierarchicalName
).is();
1112 void Access::replaceByName(
1113 OUString
const & aName
, css::uno::Any
const & aElement
)
1115 assert(thisIs(IS_UPDATE
));
1118 osl::MutexGuard
g(*lock_
);
1119 checkLocalizedPropertyAccess();
1120 rtl::Reference
< ChildAccess
> child(getChild(aName
));
1122 throw css::container::NoSuchElementException(
1125 child
->checkFinalized();
1126 Modifications localMods
;
1127 switch (getNode()->kind()) {
1128 case Node::KIND_LOCALIZED_PROPERTY
:
1129 case Node::KIND_GROUP
:
1130 child
->setProperty(aElement
, &localMods
);
1132 case Node::KIND_SET
:
1134 rtl::Reference
< ChildAccess
> freeAcc(
1135 getFreeSetMember(aElement
));
1136 rtl::Reference
< RootAccess
> root(getRootAccess());
1137 localMods
.add(child
->getRelativePath());
1138 child
->unbind(); // must not throw
1139 freeAcc
->bind(root
, this, aName
); // must not throw
1140 markChildAsModified(freeAcc
); //TODO: must not throw
1144 assert(false); // this cannot happen
1147 getNotificationRoot()->initBroadcaster(localMods
.getRoot(), &bc
);
1152 void Access::insertByName(
1153 OUString
const & aName
, css::uno::Any
const & aElement
)
1155 assert(thisIs(IS_EXTENSIBLE
|IS_UPDATE
));
1158 osl::MutexGuard
g(*lock_
);
1159 checkLocalizedPropertyAccess();
1161 if (getChild(aName
).is()) {
1162 throw css::container::ElementExistException(
1165 Modifications localMods
;
1166 switch (getNode()->kind()) {
1167 case Node::KIND_LOCALIZED_PROPERTY
:
1168 if (!isValidName(aName
, false)) {
1169 throw css::lang::IllegalArgumentException(
1170 aName
, getXWeak(), 0);
1172 insertLocalizedValueChild(aName
, aElement
, &localMods
);
1174 case Node::KIND_GROUP
:
1176 if (!isValidName(aName
, false)) {
1177 throw css::lang::IllegalArgumentException(
1178 aName
, getXWeak(), 0);
1180 checkValue(aElement
, TYPE_ANY
, true);
1181 rtl::Reference
child(
1183 components_
, getRootAccess(), this, aName
,
1185 Data::NO_LAYER
, TYPE_ANY
, true, aElement
, true)));
1186 markChildAsModified(child
);
1187 localMods
.add(child
->getRelativePath());
1190 case Node::KIND_SET
:
1192 if (!isValidName(aName
, true)) {
1193 throw css::lang::IllegalArgumentException(
1194 aName
, getXWeak(), 0);
1196 rtl::Reference
< ChildAccess
> freeAcc(
1197 getFreeSetMember(aElement
));
1198 freeAcc
->bind(getRootAccess(), this, aName
); // must not throw
1199 markChildAsModified(freeAcc
); //TODO: must not throw
1200 localMods
.add(freeAcc
->getRelativePath());
1204 assert(false); // this cannot happen
1207 getNotificationRoot()->initBroadcaster(localMods
.getRoot(), &bc
);
1212 void Access::removeByName(OUString
const & aName
)
1214 assert(thisIs(IS_EXTENSIBLE
|IS_UPDATE
));
1217 osl::MutexGuard
g(*lock_
);
1218 checkLocalizedPropertyAccess();
1219 rtl::Reference
< ChildAccess
> child(getChild(aName
));
1220 if (!child
.is() || child
->isFinalized() ||
1221 child
->getNode()->getMandatory() != Data::NO_LAYER
)
1223 throw css::container::NoSuchElementException(
1226 if (getNode()->kind() == Node::KIND_GROUP
) {
1227 const rtl::Reference
< Node
>& p(child
->getNode());
1228 if (p
->kind() != Node::KIND_PROPERTY
||
1229 !static_cast< PropertyNode
* >(p
.get())->isExtension())
1231 throw css::container::NoSuchElementException(
1235 Modifications localMods
;
1236 localMods
.add(child
->getRelativePath());
1237 // unbind() modifies the parent chain that markChildAsModified() walks,
1238 // so order is important:
1239 markChildAsModified(child
); //TODO: must not throw
1241 getNotificationRoot()->initBroadcaster(localMods
.getRoot(), &bc
);
1246 css::uno::Reference
< css::uno::XInterface
> Access::createInstance()
1248 assert(thisIs(IS_SET
|IS_UPDATE
));
1250 static_cast< SetNode
* >(getNode().get())->getDefaultTemplateName());
1251 rtl::Reference
< Node
> tmpl(
1252 components_
.getTemplate(tmplName
));
1254 throw css::uno::Exception(
1255 "unknown template " + tmplName
,
1258 rtl::Reference
< Node
> node(tmpl
->clone(true));
1259 node
->setLayer(Data::NO_LAYER
);
1260 return cppu::getXWeak(
1261 new ChildAccess(components_
, getRootAccess(), node
));
1264 css::uno::Reference
< css::uno::XInterface
> Access::createInstanceWithArguments(
1265 css::uno::Sequence
< css::uno::Any
> const & aArguments
)
1267 assert(thisIs(IS_SET
|IS_UPDATE
));
1268 if (aArguments
.hasElements()) {
1269 throw css::uno::Exception(
1270 ("configuration SimpleSetUpdate createInstanceWithArguments"
1271 " must not specify any arguments"),
1274 return createInstance();
1277 Access::Access(Components
& components
):
1278 components_(components
), disposed_(false), lock_( lock() )
1282 Access::~Access() {}
1284 void Access::initDisposeBroadcaster(Broadcaster
* broadcaster
) {
1285 assert(broadcaster
!= nullptr);
1286 for (auto const& disposeListener
: disposeListeners_
)
1288 broadcaster
->addDisposeNotification(
1290 css::lang::EventObject(getXWeak()));
1292 for (auto const& containerListener
: containerListeners_
)
1294 broadcaster
->addDisposeNotification(
1296 css::lang::EventObject(getXWeak()));
1298 for (auto const& propertyChangeListener
: propertyChangeListeners_
)
1300 for (auto const& propertyChangeListenerElement
: propertyChangeListener
.second
)
1302 broadcaster
->addDisposeNotification(
1303 propertyChangeListenerElement
,
1304 css::lang::EventObject(
1308 for (auto const& vetoableChangeListener
: vetoableChangeListeners_
)
1310 for (auto const& vetoableChangeListenerElement
: vetoableChangeListener
.second
)
1312 broadcaster
->addDisposeNotification(
1313 vetoableChangeListenerElement
,
1314 css::lang::EventObject(
1318 for (auto const& propertiesChangeListener
: propertiesChangeListeners_
)
1320 broadcaster
->addDisposeNotification(
1321 propertiesChangeListener
,
1322 css::lang::EventObject(getXWeak()));
1324 //TODO: iterate over children w/ listeners (incl. unmodified ones):
1325 for (ModifiedChildren::iterator
i(modifiedChildren_
.begin());
1326 i
!= modifiedChildren_
.end(); ++i
)
1328 rtl::Reference
< ChildAccess
> child(getModifiedChild(i
));
1330 child
->initDisposeBroadcaster(broadcaster
);
1335 void Access::clearListeners() noexcept
{
1336 disposeListeners_
.clear();
1337 containerListeners_
.clear();
1338 propertyChangeListeners_
.clear();
1339 vetoableChangeListeners_
.clear();
1340 propertiesChangeListeners_
.clear();
1341 //TODO: iterate over children w/ listeners (incl. unmodified ones):
1342 for (ModifiedChildren::iterator
i(modifiedChildren_
.begin());
1343 i
!= modifiedChildren_
.end(); ++i
)
1345 rtl::Reference
< ChildAccess
> child(getModifiedChild(i
));
1347 child
->clearListeners();
1352 css::uno::Any
Access::queryInterface(css::uno::Type
const & aType
)
1354 css::uno::Any
res(OWeakObject::queryInterface(aType
));
1355 if (res
.hasValue()) {
1358 res
= cppu::queryInterface(
1359 aType
, static_cast< css::lang::XTypeProvider
* >(this),
1360 static_cast< css::lang::XServiceInfo
* >(this),
1361 static_cast< css::lang::XComponent
* >(this),
1362 static_cast< css::container::XHierarchicalNameAccess
* >(this),
1363 static_cast< css::configuration::XDocumentation
* >(this),
1364 static_cast< css::container::XContainer
* >(this),
1365 static_cast< css::beans::XExactName
* >(this),
1366 static_cast< css::container::XHierarchicalName
* >(this),
1367 static_cast< css::container::XNamed
* >(this),
1368 static_cast< css::beans::XProperty
* >(this),
1369 static_cast< css::container::XElementAccess
* >(this),
1370 static_cast< css::container::XNameAccess
* >(this));
1371 if (res
.hasValue()) {
1374 if (getNode()->kind() == Node::KIND_GROUP
) {
1375 res
= cppu::queryInterface(
1376 aType
, static_cast< css::beans::XPropertySetInfo
* >(this),
1377 static_cast< css::beans::XPropertySet
* >(this),
1378 static_cast< css::beans::XMultiPropertySet
* >(this),
1379 static_cast< css::beans::XHierarchicalPropertySet
* >(this),
1380 static_cast< css::beans::XMultiHierarchicalPropertySet
* >(this),
1381 static_cast< css::beans::XHierarchicalPropertySetInfo
* >(this));
1382 if (res
.hasValue()) {
1386 if (getRootAccess()->isUpdate()) {
1387 res
= cppu::queryInterface(
1388 aType
, static_cast< css::container::XNameReplace
* >(this),
1389 static_cast< css::container::XHierarchicalNameReplace
* >(this));
1390 if (res
.hasValue()) {
1393 if (getNode()->kind() != Node::KIND_GROUP
||
1394 static_cast< GroupNode
* >(getNode().get())->isExtensible())
1396 res
= cppu::queryInterface(
1397 aType
, static_cast< css::container::XNameContainer
* >(this));
1398 if (res
.hasValue()) {
1402 if (getNode()->kind() == Node::KIND_SET
) {
1403 res
= cppu::queryInterface(
1404 aType
, static_cast< css::lang::XSingleServiceFactory
* >(this));
1411 void Access::checkLocalizedPropertyAccess() {
1412 if (getNode()->kind() == Node::KIND_LOCALIZED_PROPERTY
&&
1413 !Components::allLocales(getRootAccess()->getLocale()))
1415 throw css::uno::RuntimeException(
1416 "configmgr Access to specialized LocalizedPropertyNode",
1421 rtl::Reference
< Node
> Access::getParentNode() {
1422 rtl::Reference
< Access
> parent(getParentAccess());
1423 return parent
.is() ? parent
->getNode() : rtl::Reference
< Node
>();
1426 rtl::Reference
< ChildAccess
> Access::getChild(OUString
const & name
) {
1428 if (getNode()->kind() == Node::KIND_LOCALIZED_PROPERTY
1429 && name
.startsWith("*", &locale
))
1431 if (locale
.startsWith("*")) {
1434 ("access best-matching localized property value via"
1435 " \"*<locale>\" with <locale> \"")
1436 << locale
<< "\" recursively starting with \"*\"");
1437 return getChild(locale
);
1440 locale
.isEmpty(), "configmgr",
1441 ("access best-matching localized property value via \"*<locale>\""
1442 " with empty <locale>; falling back to defaults"));
1444 // Since the locale given to us is the one used at initialization,
1445 // here we override it with the actual current-user's language to
1446 // support per-view localization in LOK.
1447 if (comphelper::LibreOfficeKit::isActive())
1448 locale
= comphelper::LibreOfficeKit::getLanguageTag().getBcp47();
1450 if (!locale
.isEmpty()) {
1451 // Try exact match first, avoiding all fallback overhead.
1452 rtl::Reference
<ChildAccess
> directChild(getChild(locale
));
1453 if (directChild
.is())
1456 LanguageTag
aLanguageTag(locale
, true);
1457 if (aLanguageTag
.getBcp47() != locale
)
1459 // Original may be overridden by a known locale, for example
1460 // "zh-Hant-TW" by "zh-TW".
1461 rtl::Reference
<ChildAccess
> child(getChild(aLanguageTag
.getBcp47()));
1466 // Find the best match using the LanguageTag fallback mechanism,
1467 // excluding the original tag.
1468 std::vector
<OUString
> aFallbacks
= aLanguageTag
.getFallbackStrings(false);
1469 for (const OUString
& rFallback
: aFallbacks
)
1471 rtl::Reference
<ChildAccess
> child(getChild(rFallback
));
1476 // As a workaround for broken xcu data that does not use shortest
1477 // xml:lang attributes, look for the first entry with the same first
1478 // segment as the requested language tag before falling back to
1479 // defaults (see fdo#33638):
1480 auto const i
= comphelper::string::indexOfAny(locale
, u
"-_", 1);
1482 locale
= locale
.copy(0, i
);
1484 assert(!locale
.isEmpty());
1485 rtl::Reference
< ChildAccess
> foundChild
;
1486 forAllChildren([&foundChild
, &locale
] (ChildAccess
& rChild
)
1488 const OUString
& name2(rChild
.getNameInternal());
1489 if (name2
.startsWith(locale
) &&
1490 (name2
.getLength() == locale
.getLength() ||
1491 name2
[locale
.getLength()] == '-' ||
1492 name2
[locale
.getLength()] == '_'))
1494 foundChild
= &rChild
;
1502 // Defaults are the "en-US" locale, the "en" locale, the empty string locale, the first child (if
1503 // any, and if the property is non-nillable), or a null ChildAccess, in that order:
1504 rtl::Reference
< ChildAccess
> child(getChild("en-US"));
1508 child
= getChild("en");
1512 child
= getChild("");
1516 if (!static_cast<LocalizedPropertyNode
*>(getNode().get())->isNillable()) {
1517 // look for first child in list
1518 rtl::Reference
< ChildAccess
> foundChild
;
1519 forAllChildren([&foundChild
] (ChildAccess
& rChild
)
1521 foundChild
= &rChild
;
1528 return rtl::Reference
< ChildAccess
>();
1530 ModifiedChildren::iterator
i(modifiedChildren_
.find(name
));
1531 return i
== modifiedChildren_
.end()
1532 ? getUnmodifiedChild(name
) : getModifiedChild(i
);
1535 void Access::forAllChildren(const std::function
<bool(ChildAccess
&)> & func
) {
1536 NodeMap
const & members
= getNode()->getMembers();
1537 for (auto const& member
: members
)
1539 if (modifiedChildren_
.find(member
.first
) == modifiedChildren_
.end()) {
1540 bool bContinue
= func(*getUnmodifiedChild(member
.first
));
1545 for (ModifiedChildren::iterator
i(modifiedChildren_
.begin());
1546 i
!= modifiedChildren_
.end(); ++i
)
1548 rtl::Reference
< ChildAccess
> child(getModifiedChild(i
));
1550 bool bContinue
= func(*child
);
1557 bool Access::isAllChildrenEmpty() {
1558 NodeMap
const & members
= getNode()->getMembers();
1559 for (auto const& member
: members
)
1561 if (modifiedChildren_
.find(member
.first
) == modifiedChildren_
.end())
1564 for (ModifiedChildren::iterator
i(modifiedChildren_
.begin());
1565 i
!= modifiedChildren_
.end(); ++i
)
1567 rtl::Reference
< ChildAccess
> child(getModifiedChild(i
));
1574 void Access::checkValue(css::uno::Any
const & value
, Type type
, bool nillable
) {
1581 switch (getDynamicType(value
)) {
1592 for (;;) std::abort(); // cannot happen
1596 ok
= value
.hasValue() ? value
.isExtractableTo(mapType(type
)) : nillable
;
1599 for (;;) std::abort(); // cannot happen
1602 throw css::lang::IllegalArgumentException(
1603 "configmgr inappropriate property value",
1608 void Access::insertLocalizedValueChild(
1609 OUString
const & name
, css::uno::Any
const & value
,
1610 Modifications
* localModifications
)
1612 assert(localModifications
!= nullptr);
1613 LocalizedPropertyNode
* locprop
= static_cast< LocalizedPropertyNode
* >(
1615 checkValue(value
, locprop
->getStaticType(), locprop
->isNillable());
1616 rtl::Reference
child(
1618 components_
, getRootAccess(), this, name
,
1619 new LocalizedValueNode(Data::NO_LAYER
, value
)));
1620 markChildAsModified(child
);
1621 localModifications
->add(child
->getRelativePath());
1624 void Access::reportChildChanges(
1625 std::vector
< css::util::ElementChange
> * changes
)
1627 assert(changes
!= nullptr);
1628 for (ModifiedChildren::iterator
i(modifiedChildren_
.begin());
1629 i
!= modifiedChildren_
.end(); ++i
)
1631 rtl::Reference
< ChildAccess
> child(getModifiedChild(i
));
1633 child
->reportChildChanges(changes
);
1634 changes
->push_back(css::util::ElementChange());
1635 //TODO: changed value and/or inserted node
1637 changes
->push_back(css::util::ElementChange()); //TODO: removed node
1642 void Access::commitChildChanges(
1643 bool valid
, Modifications
* globalModifications
)
1645 assert(globalModifications
!= nullptr);
1646 while (!modifiedChildren_
.empty()) {
1647 bool childValid
= valid
;
1648 ModifiedChildren::iterator
i(modifiedChildren_
.begin());
1649 rtl::Reference
< ChildAccess
> child(getModifiedChild(i
));
1651 childValid
= childValid
&& !child
->isFinalized();
1652 child
->commitChanges(childValid
, globalModifications
);
1653 //TODO: currently, this is called here for directly inserted
1654 // children as well as for children whose sub-children were
1655 // modified (and should never be called for directly removed
1656 // children); clarify what exactly should happen here for
1657 // directly inserted children
1659 NodeMap
& members
= getNode()->getMembers();
1660 NodeMap::iterator
j(members
.find(i
->first
));
1663 if (j
!= members
.end()) {
1664 childValid
= childValid
&&
1665 j
->second
->getFinalized() == Data::NO_LAYER
;
1667 child
->getNode()->setMandatory(j
->second
->getMandatory());
1671 members
[i
->first
] = child
->getNode();
1675 childValid
= childValid
&& j
!= members
.end() &&
1676 j
->second
->getFinalized() == Data::NO_LAYER
&&
1677 j
->second
->getMandatory() == Data::NO_LAYER
;
1682 if (childValid
&& i
->second
.directlyModified
) {
1683 std::vector
<OUString
> path(getAbsolutePath());
1684 path
.push_back(i
->first
);
1685 components_
.addModification(path
);
1686 globalModifications
->add(path
);
1688 i
->second
.child
->committed();
1689 modifiedChildren_
.erase(i
);
1693 void Access::initBroadcasterAndChanges(
1694 Modifications::Node
const & modifications
, Broadcaster
* broadcaster
,
1695 std::vector
< css::util::ElementChange
> * allChanges
)
1697 assert(broadcaster
!= nullptr);
1698 std::vector
< css::beans::PropertyChangeEvent
> propChanges
;
1699 bool collectPropChanges
= !propertiesChangeListeners_
.empty();
1700 for (const auto & i
: modifications
.children
)
1702 rtl::Reference
< ChildAccess
> child(getChild(i
.first
));
1704 switch (child
->getNode()->kind()) {
1705 case Node::KIND_LOCALIZED_PROPERTY
:
1706 if (!i
.second
.children
.empty()) {
1707 if (Components::allLocales(getRootAccess()->getLocale())) {
1708 child
->initBroadcasterAndChanges(
1709 i
.second
, broadcaster
, allChanges
);
1710 //TODO: if allChanges==0, recurse only into children
1713 //TODO: filter child mods that are irrelevant for
1715 for (auto const& containerListener
: containerListeners_
)
1718 addContainerElementReplacedNotification(
1720 css::container::ContainerEvent(
1722 css::uno::Any(i
.first
),
1723 css::uno::Any(), css::uno::Any()));
1724 //TODO: non-void Element, ReplacedElement
1726 PropertyChangeListeners::iterator
j(
1727 propertyChangeListeners_
.find(i
.first
));
1728 if (j
!= propertyChangeListeners_
.end()) {
1729 for (auto const& propertyChangeListenerElement
: j
->second
)
1731 broadcaster
->addPropertyChangeNotification(
1732 propertyChangeListenerElement
,
1733 css::beans::PropertyChangeEvent(
1735 i
.first
, false, -1, css::uno::Any(),
1739 j
= propertyChangeListeners_
.find("");
1740 if (j
!= propertyChangeListeners_
.end()) {
1741 for (auto const& propertyChangeListenerElement
: j
->second
)
1743 broadcaster
->addPropertyChangeNotification(
1744 propertyChangeListenerElement
,
1745 css::beans::PropertyChangeEvent(
1747 i
.first
, false, -1, css::uno::Any(),
1751 if (allChanges
!= nullptr) {
1752 allChanges
->push_back(
1753 css::util::ElementChange(
1755 child
->getRelativePathRepresentation()),
1756 css::uno::Any(), css::uno::Any()));
1757 //TODO: non-void Element, ReplacedElement
1759 if (collectPropChanges
) {
1760 propChanges
.emplace_back(
1762 i
.first
, false, -1, css::uno::Any(),
1767 // else: spurious Modifications::Node not representing a change
1769 case Node::KIND_LOCALIZED_VALUE
:
1770 assert(Components::allLocales(getRootAccess()->getLocale()));
1771 for (auto const& containerListener
: containerListeners_
)
1773 broadcaster
->addContainerElementReplacedNotification(
1775 css::container::ContainerEvent(
1777 css::uno::Any(i
.first
), child
->asValue(),
1779 //TODO: distinguish add/modify; non-void ReplacedElement
1781 if (allChanges
!= nullptr) {
1782 allChanges
->push_back(
1783 css::util::ElementChange(
1785 child
->getRelativePathRepresentation()),
1786 child
->asValue(), css::uno::Any()));
1787 //TODO: non-void ReplacedElement
1789 assert(!collectPropChanges
);
1791 case Node::KIND_PROPERTY
:
1793 for (auto const& containerListener
: containerListeners_
)
1795 broadcaster
->addContainerElementReplacedNotification(
1797 css::container::ContainerEvent(
1799 css::uno::Any(i
.first
), child
->asValue(),
1801 //TODO: distinguish add/remove/modify; non-void
1804 PropertyChangeListeners::iterator
j(
1805 propertyChangeListeners_
.find(i
.first
));
1806 if (j
!= propertyChangeListeners_
.end()) {
1807 for (auto const& propertyChangeListenerElement
: j
->second
)
1809 broadcaster
->addPropertyChangeNotification(
1810 propertyChangeListenerElement
,
1811 css::beans::PropertyChangeEvent(
1813 i
.first
, false, -1, css::uno::Any(),
1817 j
= propertyChangeListeners_
.find("");
1818 if (j
!= propertyChangeListeners_
.end()) {
1819 for (auto const& propertyChangeListenerElement
: j
->second
)
1821 broadcaster
->addPropertyChangeNotification(
1822 propertyChangeListenerElement
,
1823 css::beans::PropertyChangeEvent(
1825 i
.first
, false, -1, css::uno::Any(),
1829 if (allChanges
!= nullptr) {
1830 allChanges
->push_back(
1831 css::util::ElementChange(
1833 child
->getRelativePathRepresentation()),
1834 child
->asValue(), css::uno::Any()));
1835 //TODO: non-void ReplacedElement
1837 if (collectPropChanges
) {
1838 propChanges
.emplace_back(
1840 i
.first
, false, -1, css::uno::Any(),
1845 case Node::KIND_GROUP
:
1846 case Node::KIND_SET
:
1847 if (i
.second
.children
.empty()) {
1848 if (!child
->getNode()->getTemplateName().isEmpty()) {
1849 for (auto const& containerListener
: containerListeners_
)
1852 addContainerElementInsertedNotification(
1854 css::container::ContainerEvent(
1856 css::uno::Any(i
.first
),
1857 child
->asValue(), css::uno::Any()));
1859 if (allChanges
!= nullptr) {
1860 allChanges
->push_back(
1861 css::util::ElementChange(
1863 child
->getRelativePathRepresentation()),
1864 css::uno::Any(), css::uno::Any()));
1865 //TODO: non-void Element, ReplacedElement
1868 // else: spurious Modifications::Node not representing a
1871 child
->initBroadcasterAndChanges(
1872 i
.second
, broadcaster
, allChanges
);
1873 //TODO: if allChanges==0, recurse only into children w/
1877 case Node::KIND_ROOT
:
1878 assert(false); // this cannot happen
1882 switch (getNode()->kind()) {
1883 case Node::KIND_LOCALIZED_PROPERTY
:
1884 // Removed localized property value:
1885 assert(Components::allLocales(getRootAccess()->getLocale()));
1886 for (auto const& containerListener
: containerListeners_
)
1888 broadcaster
->addContainerElementRemovedNotification(
1890 css::container::ContainerEvent(
1892 css::uno::Any(i
.first
), css::uno::Any(),
1894 //TODO: non-void ReplacedElement
1896 if (allChanges
!= nullptr) {
1897 OUStringBuffer
path(getRelativePathRepresentation());
1898 if (!path
.isEmpty()) {
1901 path
.append(Data::createSegment(u
"*", i
.first
));
1902 allChanges
->push_back(
1903 css::util::ElementChange(
1904 css::uno::Any(path
.makeStringAndClear()),
1905 css::uno::Any(), css::uno::Any()));
1906 //TODO: non-void ReplacedElement
1908 assert(!collectPropChanges
);
1910 case Node::KIND_GROUP
:
1912 // Removed (non-localized) extension property:
1913 for (auto const& containerListener
: containerListeners_
)
1915 broadcaster
->addContainerElementRemovedNotification(
1917 css::container::ContainerEvent(
1919 css::uno::Any(i
.first
), css::uno::Any(),
1921 //TODO: non-void ReplacedElement
1923 PropertyChangeListeners::iterator
j(
1924 propertyChangeListeners_
.find(i
.first
));
1925 if (j
!= propertyChangeListeners_
.end()) {
1926 for (auto const& propertyChangeListenerElement
: j
->second
)
1928 broadcaster
->addPropertyChangeNotification(
1929 propertyChangeListenerElement
,
1930 css::beans::PropertyChangeEvent(
1932 i
.first
, false, -1, css::uno::Any(),
1936 j
= propertyChangeListeners_
.find("");
1937 if (j
!= propertyChangeListeners_
.end()) {
1938 for (auto const& propertyChangeListenerElement
: j
->second
)
1940 broadcaster
->addPropertyChangeNotification(
1941 propertyChangeListenerElement
,
1942 css::beans::PropertyChangeEvent(
1944 i
.first
, false, -1, css::uno::Any(),
1948 if (allChanges
!= nullptr) {
1949 OUStringBuffer
path(
1950 getRelativePathRepresentation());
1951 if (!path
.isEmpty()) {
1954 path
.append(i
.first
);
1955 allChanges
->push_back(
1956 css::util::ElementChange(
1957 css::uno::Any(path
.makeStringAndClear()),
1958 css::uno::Any(), css::uno::Any()));
1959 //TODO: non-void ReplacedElement
1961 if (collectPropChanges
) {
1962 propChanges
.emplace_back(
1964 i
.first
, false, -1, css::uno::Any(),
1969 case Node::KIND_SET
:
1970 // Removed set member:
1971 if (i
.second
.children
.empty()) {
1972 for (auto const& containerListener
: containerListeners_
)
1974 broadcaster
->addContainerElementRemovedNotification(
1976 css::container::ContainerEvent(
1978 css::uno::Any(i
.first
),
1979 css::uno::Any(), css::uno::Any()));
1980 //TODO: non-void ReplacedElement
1982 if (allChanges
!= nullptr) {
1983 OUStringBuffer
path(
1984 getRelativePathRepresentation());
1985 if (!path
.isEmpty()) {
1988 path
.append(Data::createSegment(u
"*", i
.first
));
1989 allChanges
->push_back(
1990 css::util::ElementChange(
1991 css::uno::Any(path
.makeStringAndClear()),
1992 css::uno::Any(), css::uno::Any()));
1993 //TODO: non-void ReplacedElement
1996 // else: spurious Modifications::Node not representing a change
1999 assert(false); // this cannot happen
2004 if (!propChanges
.empty()) {
2005 css::uno::Sequence
< css::beans::PropertyChangeEvent
> seq(
2006 comphelper::containerToSequence(propChanges
));
2007 for (auto const& propertyChangeListener
: propertiesChangeListeners_
)
2009 broadcaster
->addPropertiesChangeNotification(propertyChangeListener
, seq
);
2015 Access::ModifiedChild::ModifiedChild():
2016 directlyModified(false)
2019 Access::ModifiedChild::ModifiedChild(
2020 rtl::Reference
< ChildAccess
> theChild
, bool theDirectlyModified
):
2021 child(std::move(theChild
)), directlyModified(theDirectlyModified
)
2024 rtl::Reference
< ChildAccess
> Access::getModifiedChild(
2025 ModifiedChildren::iterator
const & childIterator
)
2027 return (childIterator
->second
.child
->getParentAccess() == this &&
2028 (childIterator
->second
.child
->getNameInternal() ==
2029 childIterator
->first
))
2030 ? childIterator
->second
.child
: rtl::Reference
< ChildAccess
>();
2033 rtl::Reference
< ChildAccess
> Access::createUnmodifiedChild(
2034 const OUString
&name
, const rtl::Reference
< Node
> &node
)
2036 rtl::Reference
child(
2037 new ChildAccess(components_
, getRootAccess(), this, name
, node
));
2038 cachedChildren_
[name
] = child
.get();
2042 rtl::Reference
< ChildAccess
> Access::getUnmodifiedChild(
2043 OUString
const & name
)
2045 assert(modifiedChildren_
.find(name
) == modifiedChildren_
.end());
2046 rtl::Reference
< Node
> node(getNode()->getMember(name
));
2048 return rtl::Reference
< ChildAccess
>();
2050 WeakChildMap::iterator
i(cachedChildren_
.find(name
));
2051 if (i
!= cachedChildren_
.end()) {
2052 rtl::Reference
< ChildAccess
> child
;
2053 if (i
->second
->acquireCounting() > 1) {
2054 child
.set(i
->second
); // must not throw
2056 i
->second
->releaseNondeleting();
2058 child
->setNode(node
);
2062 return createUnmodifiedChild(name
,node
);
2065 rtl::Reference
< ChildAccess
> Access::getSubChild(OUString
const & path
) {
2067 // For backwards compatibility, allow absolute paths where meaningful:
2068 if( path
.startsWith("/") ) {
2070 if (!getRootAccess().is()) {
2071 return rtl::Reference
< ChildAccess
>();
2073 std::vector
<OUString
> abs(getAbsolutePath());
2074 for (auto const& elem
: abs
)
2078 OUString templateName1
;
2079 i
= Data::parseSegment(
2080 path
, i
, &name1
, &setElement1
, &templateName1
);
2081 if (i
== -1 || (i
!= path
.getLength() && path
[i
] != '/')) {
2082 return rtl::Reference
< ChildAccess
>();
2086 OUString templateName2
;
2087 Data::parseSegment(elem
, 0, &name2
, &setElement2
, &templateName2
);
2088 if (name1
!= name2
|| setElement1
!= setElement2
||
2090 !Data::equalTemplateNames(templateName1
, templateName2
)))
2092 return rtl::Reference
< ChildAccess
>();
2094 if (i
!= path
.getLength()) {
2099 for (rtl::Reference
< Access
> parent(this);;) {
2102 OUString templateName
;
2103 i
= Data::parseSegment(path
, i
, &name
, &setElement
, &templateName
);
2104 if (i
== -1 || (i
!= path
.getLength() && path
[i
] != '/')) {
2105 return rtl::Reference
< ChildAccess
>();
2107 rtl::Reference
< ChildAccess
> child(parent
->getChild(name
));
2109 return rtl::Reference
< ChildAccess
>();
2112 const rtl::Reference
< Node
>& p(parent
->getNode());
2113 switch (p
->kind()) {
2114 case Node::KIND_LOCALIZED_PROPERTY
:
2115 if (!Components::allLocales(getRootAccess()->getLocale()) ||
2116 !templateName
.isEmpty())
2118 return rtl::Reference
< ChildAccess
>();
2121 case Node::KIND_SET
:
2122 if (!templateName
.isEmpty() &&
2123 !static_cast< SetNode
* >(p
.get())->isValidTemplate(
2126 return rtl::Reference
< ChildAccess
>();
2130 return rtl::Reference
< ChildAccess
>();
2133 // For backwards compatibility, ignore a final slash after non-value
2135 if (child
->isValue()) {
2136 return i
== path
.getLength()
2137 ? child
: rtl::Reference
< ChildAccess
>();
2138 } else if (i
>= path
.getLength() - 1) {
2142 parent
= child
.get();
2146 bool Access::setChildProperty(
2147 OUString
const & name
, css::uno::Any
const & value
,
2148 Modifications
* localModifications
)
2150 assert(localModifications
!= nullptr);
2151 rtl::Reference
< ChildAccess
> child(getChild(name
));
2155 child
->checkFinalized();
2156 child
->setProperty(value
, localModifications
);
2160 css::beans::Property
Access::asProperty() {
2161 css::uno::Type type
;
2164 const rtl::Reference
< Node
>& p(getNode());
2165 switch (p
->kind()) {
2166 case Node::KIND_PROPERTY
:
2168 PropertyNode
* prop
= static_cast< PropertyNode
* >(p
.get());
2169 type
= mapType(prop
->getStaticType());
2170 nillable
= prop
->isNillable();
2171 removable
= prop
->isExtension();
2174 case Node::KIND_LOCALIZED_PROPERTY
:
2176 LocalizedPropertyNode
* locprop
=
2177 static_cast< LocalizedPropertyNode
*>(p
.get());
2178 if (Components::allLocales(getRootAccess()->getLocale())) {
2179 type
= cppu::UnoType
< css::uno::XInterface
>::get();
2183 type
= mapType(locprop
->getStaticType());
2184 removable
= false; //TODO ???
2186 nillable
= locprop
->isNillable();
2189 case Node::KIND_LOCALIZED_VALUE
:
2191 LocalizedPropertyNode
* locprop
=
2192 static_cast< LocalizedPropertyNode
* >(getParentNode().get());
2193 type
= mapType(locprop
->getStaticType());
2194 nillable
= locprop
->isNillable();
2195 removable
= false; //TODO ???
2199 type
= cppu::UnoType
< css::uno::XInterface
>::get(); //TODO: correct?
2201 rtl::Reference
< Node
> parent(getParentNode());
2202 removable
= parent
.is() && parent
->kind() == Node::KIND_SET
;
2205 return css::beans::Property(
2206 getNameInternal(), -1, type
,
2207 (css::beans::PropertyAttribute::BOUND
| //TODO: correct for group/set?
2208 css::beans::PropertyAttribute::CONSTRAINED
|
2209 (nillable
? css::beans::PropertyAttribute::MAYBEVOID
: 0) |
2210 (getRootAccess()->isUpdate() && removable
2211 ? css::beans::PropertyAttribute::REMOVABLE
: 0) |
2212 (!getRootAccess()->isUpdate() || isFinalized()
2213 ? css::beans::PropertyAttribute::READONLY
: 0))); //TODO: MAYBEDEFAULT
2216 void Access::checkFinalized() {
2217 if (isFinalized()) {
2218 throw css::lang::IllegalArgumentException(
2219 "configmgr modification of finalized item",
2224 void Access::checkKnownProperty(OUString
const & descriptor
) {
2225 if (descriptor
.isEmpty()) {
2228 rtl::Reference
< ChildAccess
> child(getChild(descriptor
));
2230 switch (child
->getNode()->kind()) {
2231 case Node::KIND_PROPERTY
:
2233 case Node::KIND_LOCALIZED_PROPERTY
:
2234 if (!Components::allLocales(getRootAccess()->getLocale())) {
2238 case Node::KIND_LOCALIZED_VALUE
:
2239 if (Components::allLocales(getRootAccess()->getLocale())) {
2247 throw css::beans::UnknownPropertyException(
2248 descriptor
, getXWeak());
2251 rtl::Reference
< ChildAccess
> Access::getFreeSetMember(
2252 css::uno::Any
const & value
)
2254 css::uno::Reference
<XInterface
> xTmp
;
2256 rtl::Reference
< ChildAccess
> freeAcc
= dynamic_cast<ChildAccess
*>(xTmp
.get());
2257 if (!freeAcc
.is() || freeAcc
->getParentAccess().is() ||
2258 (freeAcc
->isInTransaction() &&
2259 freeAcc
->getRootAccess() != getRootAccess()))
2261 throw css::lang::IllegalArgumentException(
2262 "configmgr inappropriate set element",
2265 assert(dynamic_cast< SetNode
* >(getNode().get()) != nullptr);
2266 if (!static_cast< SetNode
* >(getNode().get())->isValidTemplate(
2267 freeAcc
->getNode()->getTemplateName()))
2269 throw css::lang::IllegalArgumentException(
2270 "configmgr inappropriate set element",
2276 rtl::Reference
< Access
> Access::getNotificationRoot() {
2277 for (rtl::Reference
< Access
> p(this);;) {
2278 rtl::Reference
< Access
> parent(p
->getParentAccess());
2287 bool Access::thisIs(int what
) {
2288 osl::MutexGuard
g(*lock_
);
2289 const rtl::Reference
< Node
>& p(getNode());
2290 Node::Kind
k(p
->kind());
2291 return (k
!= Node::KIND_PROPERTY
&& k
!= Node::KIND_LOCALIZED_VALUE
&&
2292 ((what
& IS_GROUP
) == 0 || k
== Node::KIND_GROUP
) &&
2293 ((what
& IS_SET
) == 0 || k
== Node::KIND_SET
) &&
2294 ((what
& IS_EXTENSIBLE
) == 0 || k
!= Node::KIND_GROUP
||
2295 static_cast< GroupNode
* >(p
.get())->isExtensible()) &&
2296 ((what
& IS_GROUP_MEMBER
) == 0 ||
2297 getParentNode()->kind() == Node::KIND_GROUP
)) ||
2298 ((what
& IS_SET_MEMBER
) == 0 ||
2299 getParentNode()->kind() == Node::KIND_SET
) ||
2300 ((what
& IS_UPDATE
) == 0 || getRootAccess()->isUpdate());
2306 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */