Avoid potential negative array index access to cached text.
[LibreOffice.git] / configmgr / source / access.cxx
blob1e2d73dafe9cf5aecea7918b51c0c61419a0e229
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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>
22 #include <cassert>
23 #include <cstdlib>
24 #include <utility>
25 #include <vector>
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>
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"
105 namespace configmgr {
107 namespace {
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 == '/'))
119 return false;
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());
137 switch (p->kind()) {
138 case Node::KIND_PROPERTY:
139 case Node::KIND_LOCALIZED_VALUE:
140 return true;
141 case Node::KIND_LOCALIZED_PROPERTY:
142 return !Components::allLocales(getRootAccess()->getLocale());
143 default:
144 return false;
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());
153 if (!parent.is()) {
154 break;
156 assert(dynamic_cast< ChildAccess * >(p.get()) != nullptr);
157 parent->modifiedChildren_.emplace(
158 p->getNameInternal(),
159 ModifiedChild(static_cast< ChildAccess * >(p.get()), false));
160 p = parent;
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());
196 types.push_back(
197 cppu::UnoType< css::beans::XHierarchicalPropertySet >::get());
198 types.push_back(
199 cppu::UnoType< css::beans::XMultiHierarchicalPropertySet >::get());
200 types.push_back(
201 cppu::UnoType< css::beans::XHierarchicalPropertySetInfo >::get());
203 if (getRootAccess()->isUpdate()) {
204 types.push_back(cppu::UnoType< css::container::XNameReplace >::get());
205 types.push_back(
206 cppu::UnoType< css::container::XHierarchicalNameReplace >::get());
207 if (getNode()->kind() != Node::KIND_GROUP ||
208 static_cast< GroupNode * >(getNode().get())->isExtensible())
210 types.push_back(
211 cppu::UnoType< css::container::XNameContainer >::get());
213 if (getNode()->kind() == Node::KIND_SET) {
214 types.push_back(
215 cppu::UnoType< css::lang::XSingleServiceFactory >::get());
217 } else {
218 types.push_back(
219 cppu::UnoType< css::container::XHierarchicalNameAccess >::get());
220 types.push_back(
221 cppu::UnoType< css::configuration::XDocumentation >::get());
223 addTypes(&types);
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");
266 } else {
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));
280 Broadcaster bc;
282 osl::MutexGuard g(*lock_);
283 checkLocalizedPropertyAccess();
284 if (getParentAccess().is()) {
285 throw css::uno::RuntimeException(
286 "configmgr dispose inappropriate Access",
287 getXWeak());
289 if (disposed_) {
290 return;
292 initDisposeBroadcaster(&bc);
293 clearListeners();
294 disposed_ = true;
296 bc.send();
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());
310 if (!disposed_) {
311 disposeListeners_.insert(xListener);
312 return;
315 try {
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());
338 switch (p->kind()) {
339 case Node::KIND_LOCALIZED_PROPERTY:
340 return mapType(
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();
347 case Node::KIND_SET:
348 return cppu::UnoType<void>::get(); //TODO: correct?
349 default:
350 assert(false);
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);
374 if (child.is())
376 value = child->asValue();
377 bGotValue = true;
380 else
382 rtl::Reference< Node > node(getNode()->getMember(name));
383 if (!node.is())
384 return false;
385 bGotValue = ChildAccess::asSimpleValue(node, value, components_);
389 if (!bGotValue)
391 child = getChild(name);
392 if (!child.is())
393 return false;
394 value = child->asValue();
396 return true;
399 css::uno::Any Access::getByName(OUString const & aName)
401 assert(thisIs(IS_ANY));
402 osl::MutexGuard g(*lock_);
403 checkLocalizedPropertyAccess();
404 css::uno::Any value;
405 if (!getByNameFast(aName, value))
406 throw css::container::NoSuchElementException(
407 aName, getXWeak());
408 return value;
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());
420 return true;
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));
439 if (!child.is()) {
440 throw css::container::NoSuchElementException(
441 aName, getXWeak());
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));
452 if (!child.is()) {
453 throw css::container::NoSuchElementException(
454 aName, getXWeak());
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));
465 if (!child.is()) {
466 throw css::container::NoSuchElementException(
467 aName, getXWeak());
469 auto const & p = child->getNode();
470 switch (p->kind()) {
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());
475 default:
476 throw css::util::InvalidStateException(
477 aName, getXWeak());
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));
487 if (!child.is()) {
488 throw css::container::NoSuchElementException(
489 aName, getXWeak());
491 auto const & p = child->getNode();
492 switch (p->kind()) {
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();
497 default:
498 throw css::util::InvalidStateException(
499 aName, getXWeak());
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));
516 Broadcaster bc;
518 osl::MutexGuard g(*lock_);
519 checkLocalizedPropertyAccess();
520 rtl::Reference< ChildAccess > child(getSubChild(aName));
521 if (!child.is()) {
522 throw css::container::NoSuchElementException(
523 aName, getXWeak());
525 child->checkFinalized();
526 rtl::Reference< Node > parent(child->getParentNode());
527 assert(parent.is());
528 Modifications localMods;
529 switch (parent->kind()) {
530 case Node::KIND_LOCALIZED_PROPERTY:
531 case Node::KIND_GROUP:
532 child->setProperty(aElement, &localMods);
533 break;
534 case Node::KIND_SET:
535 throw css::lang::IllegalArgumentException(
536 ("configmgr::Access::replaceByHierarchicalName does not"
537 " currently support set members"),
538 getXWeak(), 0);
539 case Node::KIND_ROOT:
540 throw css::lang::IllegalArgumentException(
541 ("configmgr::Access::replaceByHierarchicalName does not allow"
542 " changing component " + aName),
543 getXWeak(), 0);
544 default:
545 assert(false); // this cannot happen
546 break;
548 getNotificationRoot()->initBroadcaster(localMods.getRoot(), &bc);
550 bc.send();
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());
564 if (!disposed_) {
565 containerListeners_.insert(xListener);
566 return;
569 try {
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());
603 return true;
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));
613 if (!child.is()) {
614 throw css::beans::UnknownPropertyException(
615 aName, getXWeak());
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
632 // available:
633 OUString rootPath;
634 rtl::Reference< RootAccess > root(getRootAccess());
635 if (root.is()) {
636 rootPath = root->getAbsolutePathRepresentation();
638 OUString rel(getRelativePathRepresentation());
639 OUStringBuffer path(rootPath);
640 if (!rootPath.isEmpty() && rootPath != "/" && !rel.isEmpty()) {
641 path.append('/');
643 path.append(rel);
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",
656 getXWeak(), -1);
658 OUStringBuffer path(getRelativePathRepresentation());
659 if (!path.isEmpty()) {
660 path.append('/');
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));
676 Broadcaster bc;
678 osl::MutexGuard g(*lock_);
679 checkLocalizedPropertyAccess();
680 checkFinalized();
681 Modifications localMods;
682 switch (getNode()->kind()) {
683 case Node::KIND_GROUP:
684 case Node::KIND_SET:
686 rtl::Reference< Access > parent(getParentAccess());
687 if (parent.is()) {
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) {
693 break;
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
708 // important:
709 parent->markChildAsModified(childAccess);
710 //TODO: must not throw
711 childAccess->unbind(); // must not throw
712 if (other.is()) {
713 other->unbind(); // must not throw
715 childAccess->bind(root, parent, aName);
716 // must not throw
717 parent->markChildAsModified(childAccess);
718 //TODO: must not throw
719 localMods.add(getRelativePath());
720 break;
725 [[fallthrough]];
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",
731 getXWeak());
732 default:
733 assert(false); // this cannot happen
734 break;
736 getNotificationRoot()->initBroadcaster(localMods.getRoot(), &bc);
738 bc.send();
741 css::beans::Property Access::getAsProperty()
743 assert(thisIs(IS_ANY));
744 osl::MutexGuard g(*lock_);
745 checkLocalizedPropertyAccess();
746 return asProperty();
749 css::uno::Reference< css::beans::XPropertySetInfo > Access::getPropertySetInfo()
751 assert(thisIs(IS_GROUP));
752 return this;
755 void Access::setPropertyValue(
756 OUString const & aPropertyName, css::uno::Any const & aValue)
758 assert(thisIs(IS_GROUP));
759 Broadcaster bc;
761 osl::MutexGuard g(*lock_);
762 if (!getRootAccess()->isUpdate()) {
763 throw css::uno::RuntimeException(
764 "configmgr setPropertyValue on non-update access",
765 getXWeak());
767 Modifications localMods;
768 if (!setChildProperty(aPropertyName, aValue, &localMods)) {
769 throw css::beans::UnknownPropertyException(
770 aPropertyName, getXWeak());
772 getNotificationRoot()->initBroadcaster(localMods.getRoot(), &bc);
774 bc.send();
777 css::uno::Any Access::getPropertyValue(OUString const & PropertyName)
779 assert(thisIs(IS_GROUP));
780 osl::MutexGuard g(*lock_);
782 css::uno::Any value;
783 if (!getByNameFast(PropertyName, value))
784 throw css::beans::UnknownPropertyException(
785 PropertyName, getXWeak());
786 return value;
789 void Access::addPropertyChangeListener(
790 OUString const & aPropertyName,
791 css::uno::Reference< css::beans::XPropertyChangeListener > const &
792 xListener)
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);
802 if (!disposed_) {
803 propertyChangeListeners_[aPropertyName].insert(xListener);
804 return;
807 try {
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 &
816 aListener)
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()) {
826 i->second.erase(j);
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 &
837 aListener)
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);
847 if (!disposed_) {
848 vetoableChangeListeners_[PropertyName].insert(aListener);
849 //TODO: actually call vetoableChangeListeners_
850 return;
853 try {
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 &
862 aListener)
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()) {
872 i->second.erase(j);
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));
885 Broadcaster bc;
887 osl::MutexGuard g(*lock_);
888 if (!getRootAccess()->isUpdate()) {
889 throw css::uno::RuntimeException(
890 "configmgr setPropertyValues on non-update access",
891 getXWeak());
893 if (aPropertyNames.getLength() != aValues.getLength()) {
894 throw css::lang::IllegalArgumentException(
895 ("configmgr setPropertyValues: aPropertyNames/aValues of"
896 " different length"),
897 getXWeak(), -1);
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",
904 getXWeak(), -1);
907 getNotificationRoot()->initBroadcaster(localMods.getRoot(), &bc);
909 bc.send();
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",
924 getXWeak());
927 return vals;
930 void Access::addPropertiesChangeListener(
931 css::uno::Sequence< OUString > const &,
932 css::uno::Reference< css::beans::XPropertiesChangeListener > const &
933 xListener)
935 assert(thisIs(IS_GROUP));
937 osl::MutexGuard g(*lock_);
938 if (!xListener.is()) {
939 throw css::uno::RuntimeException(
940 "null listener", getXWeak());
942 if (!disposed_) {
943 propertiesChangeListeners_.insert(xListener);
944 return;
947 try {
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 &
955 xListener)
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 &
969 xListener)
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));
987 return this;
990 void Access::setHierarchicalPropertyValue(
991 OUString const & aHierarchicalPropertyName,
992 css::uno::Any const & aValue)
994 assert(thisIs(IS_GROUP));
995 Broadcaster bc;
997 osl::MutexGuard g(*lock_);
998 if (!getRootAccess()->isUpdate()) {
999 throw css::uno::RuntimeException(
1000 "configmgr setHierarchicalPropertyName on non-update access",
1001 getXWeak());
1003 rtl::Reference< ChildAccess > child(
1004 getSubChild(aHierarchicalPropertyName));
1005 if (!child.is()) {
1006 throw css::beans::UnknownPropertyException(
1007 aHierarchicalPropertyName,
1008 getXWeak());
1010 child->checkFinalized();
1011 Modifications localMods;
1012 child->setProperty(aValue, &localMods);
1013 getNotificationRoot()->initBroadcaster(localMods.getRoot(), &bc);
1015 bc.send();
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));
1024 if (!child.is()) {
1025 throw css::beans::UnknownPropertyException(
1026 aHierarchicalPropertyName,
1027 getXWeak());
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));
1037 Broadcaster bc;
1039 osl::MutexGuard g(*lock_);
1040 if (!getRootAccess()->isUpdate()) {
1041 throw css::uno::RuntimeException(
1042 "configmgr setPropertyValues on non-update access",
1043 getXWeak());
1045 if (aHierarchicalPropertyNames.getLength() != Values.getLength()) {
1046 throw css::lang::IllegalArgumentException(
1047 ("configmgr setHierarchicalPropertyValues:"
1048 " aHierarchicalPropertyNames/Values of different length"),
1049 getXWeak(), -1);
1051 Modifications localMods;
1052 for (sal_Int32 i = 0; i < aHierarchicalPropertyNames.getLength(); ++i) {
1053 rtl::Reference< ChildAccess > child(
1054 getSubChild(aHierarchicalPropertyNames[i]));
1055 if (!child.is()) {
1056 throw css::lang::IllegalArgumentException(
1057 ("configmgr setHierarchicalPropertyValues inappropriate"
1058 " property name"),
1059 getXWeak(), -1);
1061 child->checkFinalized();
1062 child->setProperty(Values[i], &localMods);
1064 getNotificationRoot()->initBroadcaster(localMods.getRoot(), &bc);
1066 bc.send();
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]));
1080 if (!child.is()) {
1081 throw css::lang::IllegalArgumentException(
1082 ("configmgr getHierarchicalPropertyValues inappropriate"
1083 " hierarchical property name"),
1084 getXWeak(), -1);
1086 aValsRange[i] = child->asValue();
1088 return vals;
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));
1097 if (!child.is()) {
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));
1116 Broadcaster bc;
1118 osl::MutexGuard g(*lock_);
1119 checkLocalizedPropertyAccess();
1120 rtl::Reference< ChildAccess > child(getChild(aName));
1121 if (!child.is()) {
1122 throw css::container::NoSuchElementException(
1123 aName, getXWeak());
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);
1131 break;
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
1142 break;
1143 default:
1144 assert(false); // this cannot happen
1145 break;
1147 getNotificationRoot()->initBroadcaster(localMods.getRoot(), &bc);
1149 bc.send();
1152 void Access::insertByName(
1153 OUString const & aName, css::uno::Any const & aElement)
1155 assert(thisIs(IS_EXTENSIBLE|IS_UPDATE));
1156 Broadcaster bc;
1158 osl::MutexGuard g(*lock_);
1159 checkLocalizedPropertyAccess();
1160 checkFinalized();
1161 if (getChild(aName).is()) {
1162 throw css::container::ElementExistException(
1163 aName, getXWeak());
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);
1173 break;
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(
1182 new ChildAccess(
1183 components_, getRootAccess(), this, aName,
1184 new PropertyNode(
1185 Data::NO_LAYER, TYPE_ANY, true, aElement, true)));
1186 markChildAsModified(child);
1187 localMods.add(child->getRelativePath());
1189 break;
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());
1202 break;
1203 default:
1204 assert(false); // this cannot happen
1205 break;
1207 getNotificationRoot()->initBroadcaster(localMods.getRoot(), &bc);
1209 bc.send();
1212 void Access::removeByName(OUString const & aName)
1214 assert(thisIs(IS_EXTENSIBLE|IS_UPDATE));
1215 Broadcaster bc;
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(
1224 aName, getXWeak());
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(
1232 aName, getXWeak());
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
1240 child->unbind();
1241 getNotificationRoot()->initBroadcaster(localMods.getRoot(), &bc);
1243 bc.send();
1246 css::uno::Reference< css::uno::XInterface > Access::createInstance()
1248 assert(thisIs(IS_SET|IS_UPDATE));
1249 OUString tmplName(
1250 static_cast< SetNode * >(getNode().get())->getDefaultTemplateName());
1251 rtl::Reference< Node > tmpl(
1252 components_.getTemplate(tmplName));
1253 if (!tmpl.is()) {
1254 throw css::uno::Exception(
1255 "unknown template " + tmplName,
1256 getXWeak());
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"),
1272 getXWeak());
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(
1289 disposeListener,
1290 css::lang::EventObject(getXWeak()));
1292 for (auto const& containerListener : containerListeners_)
1294 broadcaster->addDisposeNotification(
1295 containerListener,
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(
1305 getXWeak()));
1308 for (auto const& vetoableChangeListener : vetoableChangeListeners_)
1310 for (auto const& vetoableChangeListenerElement : vetoableChangeListener.second)
1312 broadcaster->addDisposeNotification(
1313 vetoableChangeListenerElement,
1314 css::lang::EventObject(
1315 getXWeak()));
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));
1329 if (child.is()) {
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));
1346 if (child.is()) {
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()) {
1356 return res;
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()) {
1372 return res;
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()) {
1383 return res;
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()) {
1391 return res;
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()) {
1399 return res;
1402 if (getNode()->kind() == Node::KIND_SET) {
1403 res = cppu::queryInterface(
1404 aType, static_cast< css::lang::XSingleServiceFactory * >(this));
1407 return res;
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",
1417 getXWeak());
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) {
1427 OUString locale;
1428 if (getNode()->kind() == Node::KIND_LOCALIZED_PROPERTY
1429 && name.startsWith("*", &locale))
1431 if (locale.startsWith("*")) {
1432 SAL_WARN(
1433 "configmgr",
1434 ("access best-matching localized property value via"
1435 " \"*<locale>\" with <locale> \"")
1436 << locale << "\" recursively starting with \"*\"");
1437 return getChild(locale);
1439 SAL_INFO_IF(
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())
1454 return directChild;
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()));
1462 if (child.is())
1463 return child;
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));
1472 if (child.is())
1473 return child;
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);
1481 if (i != -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;
1495 return false;
1497 return true;
1499 if (foundChild)
1500 return foundChild;
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"));
1505 if (child.is()) {
1506 return child;
1508 child = getChild("en");
1509 if (child.is()) {
1510 return child;
1512 child = getChild("");
1513 if (child.is()) {
1514 return child;
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;
1522 return false;
1524 if (foundChild) {
1525 return foundChild;
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));
1541 if (!bContinue)
1542 return;
1545 for (ModifiedChildren::iterator i(modifiedChildren_.begin());
1546 i != modifiedChildren_.end(); ++i)
1548 rtl::Reference< ChildAccess > child(getModifiedChild(i));
1549 if (child.is()) {
1550 bool bContinue = func(*child);
1551 if (!bContinue)
1552 return;
1557 bool Access::isAllChildrenEmpty() {
1558 NodeMap const & members = getNode()->getMembers();
1559 for (auto const& member : members)
1561 if (modifiedChildren_.find(member.first) == modifiedChildren_.end())
1562 return false;
1564 for (ModifiedChildren::iterator i(modifiedChildren_.begin());
1565 i != modifiedChildren_.end(); ++i)
1567 rtl::Reference< ChildAccess > child(getModifiedChild(i));
1568 if (child.is())
1569 return false;
1571 return true;
1574 void Access::checkValue(css::uno::Any const & value, Type type, bool nillable) {
1575 bool ok;
1576 switch (type) {
1577 case TYPE_ERROR:
1578 ok = false;
1579 break;
1580 case TYPE_ANY:
1581 switch (getDynamicType(value)) {
1582 case TYPE_ERROR:
1583 ok = false;
1584 break;
1585 case TYPE_NIL:
1586 ok = nillable;
1587 break;
1588 default:
1589 ok = true;
1590 break;
1591 case TYPE_ANY:
1592 for (;;) std::abort(); // cannot happen
1594 break;
1595 default:
1596 ok = value.hasValue() ? value.isExtractableTo(mapType(type)) : nillable;
1597 break;
1598 case TYPE_NIL:
1599 for (;;) std::abort(); // cannot happen
1601 if (!ok) {
1602 throw css::lang::IllegalArgumentException(
1603 "configmgr inappropriate property value",
1604 getXWeak(), -1);
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 * >(
1614 getNode().get());
1615 checkValue(value, locprop->getStaticType(), locprop->isNillable());
1616 rtl::Reference child(
1617 new ChildAccess(
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));
1632 if (child.is()) {
1633 child->reportChildChanges(changes);
1634 changes->push_back(css::util::ElementChange());
1635 //TODO: changed value and/or inserted node
1636 } else {
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));
1650 if (child.is()) {
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));
1661 if (child.is()) {
1662 // Inserted:
1663 if (j != members.end()) {
1664 childValid = childValid &&
1665 j->second->getFinalized() == Data::NO_LAYER;
1666 if (childValid) {
1667 child->getNode()->setMandatory(j->second->getMandatory());
1670 if (childValid) {
1671 members[i->first] = child->getNode();
1673 } else {
1674 // Removed:
1675 childValid = childValid && j != members.end() &&
1676 j->second->getFinalized() == Data::NO_LAYER &&
1677 j->second->getMandatory() == Data::NO_LAYER;
1678 if (childValid) {
1679 members.erase(j);
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));
1703 if (child.is()) {
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
1711 // w/ listeners
1712 } else {
1713 //TODO: filter child mods that are irrelevant for
1714 // locale:
1715 for (auto const& containerListener : containerListeners_)
1717 broadcaster->
1718 addContainerElementReplacedNotification(
1719 containerListener,
1720 css::container::ContainerEvent(
1721 getXWeak(),
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(
1734 getXWeak(),
1735 i.first, false, -1, css::uno::Any(),
1736 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(
1746 getXWeak(),
1747 i.first, false, -1, css::uno::Any(),
1748 css::uno::Any()));
1751 if (allChanges != nullptr) {
1752 allChanges->push_back(
1753 css::util::ElementChange(
1754 css::uno::Any(
1755 child->getRelativePathRepresentation()),
1756 css::uno::Any(), css::uno::Any()));
1757 //TODO: non-void Element, ReplacedElement
1759 if (collectPropChanges) {
1760 propChanges.emplace_back(
1761 getXWeak(),
1762 i.first, false, -1, css::uno::Any(),
1763 css::uno::Any());
1767 // else: spurious Modifications::Node not representing a change
1768 break;
1769 case Node::KIND_LOCALIZED_VALUE:
1770 assert(Components::allLocales(getRootAccess()->getLocale()));
1771 for (auto const& containerListener : containerListeners_)
1773 broadcaster->addContainerElementReplacedNotification(
1774 containerListener,
1775 css::container::ContainerEvent(
1776 getXWeak(),
1777 css::uno::Any(i.first), child->asValue(),
1778 css::uno::Any()));
1779 //TODO: distinguish add/modify; non-void ReplacedElement
1781 if (allChanges != nullptr) {
1782 allChanges->push_back(
1783 css::util::ElementChange(
1784 css::uno::Any(
1785 child->getRelativePathRepresentation()),
1786 child->asValue(), css::uno::Any()));
1787 //TODO: non-void ReplacedElement
1789 assert(!collectPropChanges);
1790 break;
1791 case Node::KIND_PROPERTY:
1793 for (auto const& containerListener : containerListeners_)
1795 broadcaster->addContainerElementReplacedNotification(
1796 containerListener,
1797 css::container::ContainerEvent(
1798 getXWeak(),
1799 css::uno::Any(i.first), child->asValue(),
1800 css::uno::Any()));
1801 //TODO: distinguish add/remove/modify; non-void
1802 // ReplacedElement
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(
1812 getXWeak(),
1813 i.first, false, -1, css::uno::Any(),
1814 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(
1824 getXWeak(),
1825 i.first, false, -1, css::uno::Any(),
1826 css::uno::Any()));
1829 if (allChanges != nullptr) {
1830 allChanges->push_back(
1831 css::util::ElementChange(
1832 css::uno::Any(
1833 child->getRelativePathRepresentation()),
1834 child->asValue(), css::uno::Any()));
1835 //TODO: non-void ReplacedElement
1837 if (collectPropChanges) {
1838 propChanges.emplace_back(
1839 getXWeak(),
1840 i.first, false, -1, css::uno::Any(),
1841 css::uno::Any());
1844 break;
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_)
1851 broadcaster->
1852 addContainerElementInsertedNotification(
1853 containerListener,
1854 css::container::ContainerEvent(
1855 getXWeak(),
1856 css::uno::Any(i.first),
1857 child->asValue(), css::uno::Any()));
1859 if (allChanges != nullptr) {
1860 allChanges->push_back(
1861 css::util::ElementChange(
1862 css::uno::Any(
1863 child->getRelativePathRepresentation()),
1864 css::uno::Any(), css::uno::Any()));
1865 //TODO: non-void Element, ReplacedElement
1868 // else: spurious Modifications::Node not representing a
1869 // change
1870 } else {
1871 child->initBroadcasterAndChanges(
1872 i.second, broadcaster, allChanges);
1873 //TODO: if allChanges==0, recurse only into children w/
1874 // listeners
1876 break;
1877 case Node::KIND_ROOT:
1878 assert(false); // this cannot happen
1879 break;
1881 } else {
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(
1889 containerListener,
1890 css::container::ContainerEvent(
1891 getXWeak(),
1892 css::uno::Any(i.first), css::uno::Any(),
1893 css::uno::Any()));
1894 //TODO: non-void ReplacedElement
1896 if (allChanges != nullptr) {
1897 OUStringBuffer path(getRelativePathRepresentation());
1898 if (!path.isEmpty()) {
1899 path.append('/');
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);
1909 break;
1910 case Node::KIND_GROUP:
1912 // Removed (non-localized) extension property:
1913 for (auto const& containerListener : containerListeners_)
1915 broadcaster->addContainerElementRemovedNotification(
1916 containerListener,
1917 css::container::ContainerEvent(
1918 getXWeak(),
1919 css::uno::Any(i.first), css::uno::Any(),
1920 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(
1931 getXWeak(),
1932 i.first, false, -1, css::uno::Any(),
1933 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(
1943 getXWeak(),
1944 i.first, false, -1, css::uno::Any(),
1945 css::uno::Any()));
1948 if (allChanges != nullptr) {
1949 OUStringBuffer path(
1950 getRelativePathRepresentation());
1951 if (!path.isEmpty()) {
1952 path.append('/');
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(
1963 getXWeak(),
1964 i.first, false, -1, css::uno::Any(),
1965 css::uno::Any());
1968 break;
1969 case Node::KIND_SET:
1970 // Removed set member:
1971 if (i.second.children.empty()) {
1972 for (auto const& containerListener : containerListeners_)
1974 broadcaster->addContainerElementRemovedNotification(
1975 containerListener,
1976 css::container::ContainerEvent(
1977 getXWeak(),
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()) {
1986 path.append('/');
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
1997 break;
1998 default:
1999 assert(false); // this cannot happen
2000 break;
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();
2039 return child;
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));
2047 if (!node.is()) {
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();
2057 if (child.is()) {
2058 child->setNode(node);
2059 return child;
2062 return createUnmodifiedChild(name,node);
2065 rtl::Reference< ChildAccess > Access::getSubChild(OUString const & path) {
2066 sal_Int32 i = 0;
2067 // For backwards compatibility, allow absolute paths where meaningful:
2068 if( path.startsWith("/") ) {
2069 ++i;
2070 if (!getRootAccess().is()) {
2071 return rtl::Reference< ChildAccess >();
2073 std::vector<OUString> abs(getAbsolutePath());
2074 for (auto const& elem : abs)
2076 OUString name1;
2077 bool setElement1;
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 >();
2084 OUString name2;
2085 bool setElement2;
2086 OUString templateName2;
2087 Data::parseSegment(elem, 0, &name2, &setElement2, &templateName2);
2088 if (name1 != name2 || setElement1 != setElement2 ||
2089 (setElement1 &&
2090 !Data::equalTemplateNames(templateName1, templateName2)))
2092 return rtl::Reference< ChildAccess >();
2094 if (i != path.getLength()) {
2095 ++i;
2099 for (rtl::Reference< Access > parent(this);;) {
2100 OUString name;
2101 bool setElement;
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));
2108 if (!child.is()) {
2109 return rtl::Reference< ChildAccess >();
2111 if (setElement) {
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 >();
2120 break;
2121 case Node::KIND_SET:
2122 if (!templateName.isEmpty() &&
2123 !static_cast< SetNode * >(p.get())->isValidTemplate(
2124 templateName))
2126 return rtl::Reference< ChildAccess >();
2128 break;
2129 default:
2130 return rtl::Reference< ChildAccess >();
2133 // For backwards compatibility, ignore a final slash after non-value
2134 // nodes:
2135 if (child->isValue()) {
2136 return i == path.getLength()
2137 ? child : rtl::Reference< ChildAccess >();
2138 } else if (i >= path.getLength() - 1) {
2139 return child;
2141 ++i;
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));
2152 if (!child.is()) {
2153 return false;
2155 child->checkFinalized();
2156 child->setProperty(value, localModifications);
2157 return true;
2160 css::beans::Property Access::asProperty() {
2161 css::uno::Type type;
2162 bool nillable;
2163 bool removable;
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();
2173 break;
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();
2180 //TODO: correct?
2181 removable = false;
2182 } else {
2183 type = mapType(locprop->getStaticType());
2184 removable = false; //TODO ???
2186 nillable = locprop->isNillable();
2188 break;
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 ???
2197 break;
2198 default:
2199 type = cppu::UnoType< css::uno::XInterface >::get(); //TODO: correct?
2200 nillable = false;
2201 rtl::Reference< Node > parent(getParentNode());
2202 removable = parent.is() && parent->kind() == Node::KIND_SET;
2203 break;
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",
2220 getXWeak(), -1);
2224 void Access::checkKnownProperty(OUString const & descriptor) {
2225 if (descriptor.isEmpty()) {
2226 return;
2228 rtl::Reference< ChildAccess > child(getChild(descriptor));
2229 if (child.is()) {
2230 switch (child->getNode()->kind()) {
2231 case Node::KIND_PROPERTY:
2232 return;
2233 case Node::KIND_LOCALIZED_PROPERTY:
2234 if (!Components::allLocales(getRootAccess()->getLocale())) {
2235 return;
2237 break;
2238 case Node::KIND_LOCALIZED_VALUE:
2239 if (Components::allLocales(getRootAccess()->getLocale())) {
2240 return;
2242 break;
2243 default:
2244 break;
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;
2255 value >>= 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",
2263 getXWeak(), 1);
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",
2271 getXWeak(), 1);
2273 return freeAcc;
2276 rtl::Reference< Access > Access::getNotificationRoot() {
2277 for (rtl::Reference< Access > p(this);;) {
2278 rtl::Reference< Access > parent(p->getParentAccess());
2279 if (!parent.is()) {
2280 return p;
2282 p = parent;
2286 #if !defined NDEBUG
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());
2302 #endif
2306 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */