tdf#154546 skip dispatch when presenter controller is not set
[LibreOffice.git] / configmgr / source / access.cxx
blob047c93a5627a2e0585019947bce74744456ebf00
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 <comphelper/sequence.hxx>
70 #include <comphelper/servicehelper.hxx>
71 #include <comphelper/string.hxx>
72 #include <comphelper/lok.hxx>
73 #include <i18nlangtag/languagetag.hxx>
74 #include <cppu/unotype.hxx>
75 #include <cppuhelper/queryinterface.hxx>
76 #include <cppuhelper/supportsservice.hxx>
77 #include <cppuhelper/weak.hxx>
78 #include <osl/interlck.h>
79 #include <osl/mutex.hxx>
80 #include <rtl/character.hxx>
81 #include <rtl/ref.hxx>
82 #include <rtl/ustrbuf.hxx>
83 #include <rtl/ustring.hxx>
84 #include <sal/log.hxx>
85 #include <sal/types.h>
87 #include "access.hxx"
88 #include "broadcaster.hxx"
89 #include "childaccess.hxx"
90 #include "components.hxx"
91 #include "data.hxx"
92 #include "groupnode.hxx"
93 #include "localizedpropertynode.hxx"
94 #include "localizedvaluenode.hxx"
95 #include "lock.hxx"
96 #include "modifications.hxx"
97 #include "node.hxx"
98 #include "nodemap.hxx"
99 #include "propertynode.hxx"
100 #include "rootaccess.hxx"
101 #include "setnode.hxx"
102 #include "type.hxx"
104 namespace configmgr {
106 namespace {
108 // Conservatively forbid what is either not an XML Char (including lone
109 // surrogates, even though they should not appear in well-formed UNO OUString
110 // instances anyway), or is a slash (as it causes problems in path syntax):
111 bool isValidName(OUString const & name, bool setMember) {
112 for (sal_Int32 i = 0; i != name.getLength();) {
113 sal_uInt32 c = name.iterateCodePoints(&i);
114 if ((c < 0x20 && !(c == 0x09 || c == 0x0A || c == 0x0D))
115 || rtl::isSurrogate(c) || c == 0xFFFE || c == 0xFFFF
116 || (!setMember && c == '/'))
118 return false;
121 return !name.isEmpty();
126 oslInterlockedCount Access::acquireCounting() {
127 return osl_atomic_increment(&m_refCount);
130 void Access::releaseNondeleting() {
131 osl_atomic_decrement(&m_refCount);
134 bool Access::isValue() {
135 rtl::Reference< Node > p(getNode());
136 switch (p->kind()) {
137 case Node::KIND_PROPERTY:
138 case Node::KIND_LOCALIZED_VALUE:
139 return true;
140 case Node::KIND_LOCALIZED_PROPERTY:
141 return !Components::allLocales(getRootAccess()->getLocale());
142 default:
143 return false;
147 void Access::markChildAsModified(rtl::Reference< ChildAccess > const & child) {
148 assert(child.is() && child->getParentAccess() == this);
149 modifiedChildren_[child->getNameInternal()] = ModifiedChild(child, true);
150 for (rtl::Reference< Access > p(this);;) {
151 rtl::Reference< Access > parent(p->getParentAccess());
152 if (!parent.is()) {
153 break;
155 assert(dynamic_cast< ChildAccess * >(p.get()) != nullptr);
156 parent->modifiedChildren_.emplace(
157 p->getNameInternal(),
158 ModifiedChild(static_cast< ChildAccess * >(p.get()), false));
159 p = parent;
163 void Access::releaseChild(OUString const & name) {
164 cachedChildren_.erase(name);
167 void Access::initBroadcaster(
168 Modifications::Node const & modifications, Broadcaster * broadcaster)
170 initBroadcasterAndChanges(modifications, broadcaster, nullptr);
173 css::uno::Sequence< css::uno::Type > Access::getTypes()
175 assert(thisIs(IS_ANY));
176 osl::MutexGuard g(*lock_);
177 checkLocalizedPropertyAccess();
178 std::vector< css::uno::Type > types { cppu::UnoType< css::uno::XInterface >::get(),
179 cppu::UnoType< css::uno::XWeak >::get(),
180 cppu::UnoType< css::lang::XTypeProvider >::get(),
181 cppu::UnoType< css::lang::XServiceInfo >::get(),
182 cppu::UnoType< css::lang::XComponent >::get(),
183 cppu::UnoType< css::container::XContainer >::get(),
184 cppu::UnoType< css::beans::XExactName >::get(),
185 cppu::UnoType< css::container::XHierarchicalName >::get(),
186 cppu::UnoType< css::container::XNamed >::get(),
187 cppu::UnoType< css::beans::XProperty >::get(),
188 cppu::UnoType< css::container::XElementAccess >::get(),
189 cppu::UnoType< css::container::XNameAccess >::get()
191 if (getNode()->kind() == Node::KIND_GROUP) {
192 types.push_back(cppu::UnoType< css::beans::XPropertySetInfo >::get());
193 types.push_back(cppu::UnoType< css::beans::XPropertySet >::get());
194 types.push_back(cppu::UnoType< css::beans::XMultiPropertySet >::get());
195 types.push_back(
196 cppu::UnoType< css::beans::XHierarchicalPropertySet >::get());
197 types.push_back(
198 cppu::UnoType< css::beans::XMultiHierarchicalPropertySet >::get());
199 types.push_back(
200 cppu::UnoType< css::beans::XHierarchicalPropertySetInfo >::get());
202 if (getRootAccess()->isUpdate()) {
203 types.push_back(cppu::UnoType< css::container::XNameReplace >::get());
204 types.push_back(
205 cppu::UnoType< css::container::XHierarchicalNameReplace >::get());
206 if (getNode()->kind() != Node::KIND_GROUP ||
207 static_cast< GroupNode * >(getNode().get())->isExtensible())
209 types.push_back(
210 cppu::UnoType< css::container::XNameContainer >::get());
212 if (getNode()->kind() == Node::KIND_SET) {
213 types.push_back(
214 cppu::UnoType< css::lang::XSingleServiceFactory >::get());
216 } else {
217 types.push_back(
218 cppu::UnoType< css::container::XHierarchicalNameAccess >::get());
220 addTypes(&types);
221 return comphelper::containerToSequence(types);
224 css::uno::Sequence< sal_Int8 > Access::getImplementationId()
226 assert(thisIs(IS_ANY));
227 osl::MutexGuard g(*lock_);
228 checkLocalizedPropertyAccess();
229 return css::uno::Sequence< sal_Int8 >();
232 OUString Access::getImplementationName()
234 assert(thisIs(IS_ANY));
235 osl::MutexGuard g(*lock_);
236 checkLocalizedPropertyAccess();
237 return "org.openoffice-configmgr::Access";
240 sal_Bool Access::supportsService(OUString const & ServiceName)
242 return cppu::supportsService(this, ServiceName);
245 css::uno::Sequence< OUString > Access::getSupportedServiceNames()
247 assert(thisIs(IS_ANY));
248 osl::MutexGuard g(*lock_);
249 checkLocalizedPropertyAccess();
250 std::vector<OUString> services;
251 services.emplace_back("com.sun.star.configuration.ConfigurationAccess");
252 if (getRootAccess()->isUpdate()) {
253 services.emplace_back("com.sun.star.configuration.ConfigurationUpdateAccess");
255 services.emplace_back("com.sun.star.configuration.HierarchyAccess");
256 services.emplace_back("com.sun.star.configuration.HierarchyElement");
257 if (getNode()->kind() == Node::KIND_GROUP) {
258 services.emplace_back("com.sun.star.configuration.GroupAccess");
259 services.emplace_back("com.sun.star.configuration.PropertyHierarchy");
260 if (getRootAccess()->isUpdate()) {
261 services.emplace_back("com.sun.star.configuration.GroupUpdate");
263 } else {
264 services.emplace_back("com.sun.star.configuration.SetAccess");
265 services.emplace_back("com.sun.star.configuration.SimpleSetAccess");
266 if (getRootAccess()->isUpdate()) {
267 services.emplace_back("com.sun.star.configuration.SetUpdate");
268 services.emplace_back("com.sun.star.configuration.SimpleSetUpdate");
271 addSupportedServiceNames(&services);
272 return comphelper::containerToSequence(services);
275 void Access::dispose() {
276 assert(thisIs(IS_ANY));
277 Broadcaster bc;
279 osl::MutexGuard g(*lock_);
280 checkLocalizedPropertyAccess();
281 if (getParentAccess().is()) {
282 throw css::uno::RuntimeException(
283 "configmgr dispose inappropriate Access",
284 static_cast< cppu::OWeakObject * >(this));
286 if (disposed_) {
287 return;
289 initDisposeBroadcaster(&bc);
290 clearListeners();
291 disposed_ = true;
293 bc.send();
296 void Access::addEventListener(
297 css::uno::Reference< css::lang::XEventListener > const & xListener)
299 assert(thisIs(IS_ANY));
301 osl::MutexGuard g(*lock_);
302 checkLocalizedPropertyAccess();
303 if (!xListener.is()) {
304 throw css::uno::RuntimeException(
305 "null listener", static_cast< cppu::OWeakObject * >(this));
307 if (!disposed_) {
308 disposeListeners_.insert(xListener);
309 return;
312 try {
313 xListener->disposing(
314 css::lang::EventObject(static_cast< cppu::OWeakObject * >(this)));
315 } catch (css::lang::DisposedException &) {}
318 void Access::removeEventListener(
319 css::uno::Reference< css::lang::XEventListener > const & aListener)
321 assert(thisIs(IS_ANY));
322 osl::MutexGuard g(*lock_);
323 checkLocalizedPropertyAccess();
324 DisposeListeners::iterator i(disposeListeners_.find(aListener));
325 if (i != disposeListeners_.end()) {
326 disposeListeners_.erase(i);
330 css::uno::Type Access::getElementType() {
331 assert(thisIs(IS_ANY));
332 osl::MutexGuard g(*lock_);
333 checkLocalizedPropertyAccess();
334 rtl::Reference< Node > p(getNode());
335 switch (p->kind()) {
336 case Node::KIND_LOCALIZED_PROPERTY:
337 return mapType(
338 static_cast< LocalizedPropertyNode * >(p.get())->getStaticType());
339 case Node::KIND_GROUP:
340 //TODO: Should a specific type be returned for a non-extensible group
341 // with homogeneous members or for an extensible group that currently
342 // has only homogeneous members?
343 return cppu::UnoType<void>::get();
344 case Node::KIND_SET:
345 return cppu::UnoType<void>::get(); //TODO: correct?
346 default:
347 assert(false);
348 throw css::uno::RuntimeException(
349 "this cannot happen", static_cast< cppu::OWeakObject * >(this));
353 sal_Bool Access::hasElements() {
354 assert(thisIs(IS_ANY));
355 osl::MutexGuard g(*lock_);
356 checkLocalizedPropertyAccess();
357 return !getAllChildren().empty(); //TODO: optimize
360 bool Access::getByNameFast(const OUString & name, css::uno::Any & value)
362 bool bGotValue = false;
363 rtl::Reference< ChildAccess > child;
365 if (getNode()->kind() != Node::KIND_LOCALIZED_PROPERTY)
366 { // try to get it directly
367 ModifiedChildren::iterator i(modifiedChildren_.find(name));
368 if (i != modifiedChildren_.end())
370 child = getModifiedChild(i);
371 if (child.is())
373 value = child->asValue();
374 bGotValue = true;
377 else
379 rtl::Reference< Node > node(getNode()->getMember(name));
380 if (!node.is())
381 return false;
382 bGotValue = ChildAccess::asSimpleValue(node, value, components_);
386 if (!bGotValue)
388 child = getChild(name);
389 if (!child.is())
390 return false;
391 value = child->asValue();
393 return true;
396 css::uno::Any Access::getByName(OUString const & aName)
398 assert(thisIs(IS_ANY));
399 osl::MutexGuard g(*lock_);
400 checkLocalizedPropertyAccess();
401 css::uno::Any value;
402 if (!getByNameFast(aName, value))
403 throw css::container::NoSuchElementException(
404 aName, static_cast< cppu::OWeakObject * >(this));
405 return value;
408 css::uno::Sequence< OUString > Access::getElementNames()
410 assert(thisIs(IS_ANY));
411 osl::MutexGuard g(*lock_);
412 checkLocalizedPropertyAccess();
413 std::vector< rtl::Reference< ChildAccess > > children(getAllChildren());
414 css::uno::Sequence<OUString> names(children.size());
415 OUString* pArray = names.getArray();
416 for (auto const& child : children)
418 *pArray++ = child->getNameInternal();
420 return names;
423 sal_Bool Access::hasByName(OUString const & aName)
425 assert(thisIs(IS_ANY));
426 osl::MutexGuard g(*lock_);
427 checkLocalizedPropertyAccess();
428 return getChild(aName).is();
431 css::uno::Any Access::getByHierarchicalName(OUString const & aName)
433 assert(thisIs(IS_ANY));
434 osl::MutexGuard g(*lock_);
435 checkLocalizedPropertyAccess();
436 rtl::Reference< ChildAccess > child(getSubChild(aName));
437 if (!child.is()) {
438 throw css::container::NoSuchElementException(
439 aName, static_cast< cppu::OWeakObject * >(this));
441 return child->asValue();
444 sal_Bool Access::hasByHierarchicalName(OUString const & aName)
446 assert(thisIs(IS_ANY));
447 osl::MutexGuard g(*lock_);
448 checkLocalizedPropertyAccess();
449 return getSubChild(aName).is();
452 void Access::replaceByHierarchicalName(
453 OUString const & aName, css::uno::Any const & aElement)
455 //TODO: Actually support sets and combine with replaceByName:
456 assert(thisIs(IS_UPDATE));
457 Broadcaster bc;
459 osl::MutexGuard g(*lock_);
460 checkLocalizedPropertyAccess();
461 rtl::Reference< ChildAccess > child(getSubChild(aName));
462 if (!child.is()) {
463 throw css::container::NoSuchElementException(
464 aName, static_cast< cppu::OWeakObject * >(this));
466 child->checkFinalized();
467 rtl::Reference< Node > parent(child->getParentNode());
468 assert(parent.is());
469 Modifications localMods;
470 switch (parent->kind()) {
471 case Node::KIND_LOCALIZED_PROPERTY:
472 case Node::KIND_GROUP:
473 child->setProperty(aElement, &localMods);
474 break;
475 case Node::KIND_SET:
476 throw css::lang::IllegalArgumentException(
477 ("configmgr::Access::replaceByHierarchicalName does not"
478 " currently support set members"),
479 static_cast< cppu::OWeakObject * >(this), 0);
480 case Node::KIND_ROOT:
481 throw css::lang::IllegalArgumentException(
482 ("configmgr::Access::replaceByHierarchicalName does not allow"
483 " changing component " + aName),
484 static_cast< cppu::OWeakObject * >(this), 0);
485 default:
486 assert(false); // this cannot happen
487 break;
489 getNotificationRoot()->initBroadcaster(localMods.getRoot(), &bc);
491 bc.send();
494 void Access::addContainerListener(
495 css::uno::Reference< css::container::XContainerListener > const & xListener)
497 assert(thisIs(IS_ANY));
499 osl::MutexGuard g(*lock_);
500 checkLocalizedPropertyAccess();
501 if (!xListener.is()) {
502 throw css::uno::RuntimeException(
503 "null listener", static_cast< cppu::OWeakObject * >(this));
505 if (!disposed_) {
506 containerListeners_.insert(xListener);
507 return;
510 try {
511 xListener->disposing(
512 css::lang::EventObject(static_cast< cppu::OWeakObject * >(this)));
513 } catch (css::lang::DisposedException &) {}
516 void Access::removeContainerListener(
517 css::uno::Reference< css::container::XContainerListener > const & xListener)
519 assert(thisIs(IS_ANY));
520 osl::MutexGuard g(*lock_);
521 checkLocalizedPropertyAccess();
522 ContainerListeners::iterator i(containerListeners_.find(xListener));
523 if (i != containerListeners_.end()) {
524 containerListeners_.erase(i);
528 OUString Access::getExactName(OUString const & aApproximateName)
530 assert(thisIs(IS_ANY));
531 osl::MutexGuard g(*lock_);
532 checkLocalizedPropertyAccess();
533 return aApproximateName;
536 css::uno::Sequence< css::beans::Property > Access::getProperties()
538 assert(thisIs(IS_GROUP));
539 osl::MutexGuard g(*lock_);
540 std::vector< rtl::Reference< ChildAccess > > children(getAllChildren());
541 std::vector< css::beans::Property > properties;
542 properties.reserve(children.size());
543 for (auto const& child : children)
545 properties.push_back(child->asProperty());
547 return comphelper::containerToSequence(properties);
550 css::beans::Property Access::getPropertyByName(OUString const & aName)
552 assert(thisIs(IS_GROUP));
553 osl::MutexGuard g(*lock_);
554 rtl::Reference< ChildAccess > child(getChild(aName));
555 if (!child.is()) {
556 throw css::beans::UnknownPropertyException(
557 aName, static_cast< cppu::OWeakObject * >(this));
559 return child->asProperty();
562 sal_Bool Access::hasPropertyByName(OUString const & Name)
564 assert(thisIs(IS_GROUP));
565 osl::MutexGuard g(*lock_);
566 return getChild(Name).is();
569 OUString Access::getHierarchicalName() {
570 assert(thisIs(IS_ANY));
571 osl::MutexGuard g(*lock_);
572 checkLocalizedPropertyAccess();
573 // For backwards compatibility, return an absolute path representation where
574 // available:
575 OUString rootPath;
576 rtl::Reference< RootAccess > root(getRootAccess());
577 if (root.is()) {
578 rootPath = root->getAbsolutePathRepresentation();
580 OUString rel(getRelativePathRepresentation());
581 OUStringBuffer path(rootPath);
582 if (!rootPath.isEmpty() && rootPath != "/" && !rel.isEmpty()) {
583 path.append('/');
585 path.append(rel);
586 return path.makeStringAndClear();
589 OUString Access::composeHierarchicalName(
590 OUString const & aRelativeName)
592 assert(thisIs(IS_ANY));
593 osl::MutexGuard g(*lock_);
594 checkLocalizedPropertyAccess();
595 if (aRelativeName.isEmpty() || aRelativeName[0] == '/') {
596 throw css::lang::IllegalArgumentException(
597 "configmgr composeHierarchicalName inappropriate relative name",
598 static_cast< cppu::OWeakObject * >(this), -1);
600 OUStringBuffer path(getRelativePathRepresentation());
601 if (!path.isEmpty()) {
602 path.append('/');
604 path.append(aRelativeName);
605 return path.makeStringAndClear();
608 OUString Access::getName() {
609 assert(thisIs(IS_ANY));
610 osl::MutexGuard g(*lock_);
611 checkLocalizedPropertyAccess();
612 return getNameInternal();
615 void Access::setName(OUString const & aName)
617 assert(thisIs(IS_ANY));
618 Broadcaster bc;
620 osl::MutexGuard g(*lock_);
621 checkLocalizedPropertyAccess();
622 checkFinalized();
623 Modifications localMods;
624 switch (getNode()->kind()) {
625 case Node::KIND_GROUP:
626 case Node::KIND_SET:
628 rtl::Reference< Access > parent(getParentAccess());
629 if (parent.is()) {
630 rtl::Reference< Node > node(getNode());
631 if (! node->getTemplateName().isEmpty()) {
632 rtl::Reference< ChildAccess > other(
633 parent->getChild(aName));
634 if (other.get() == this) {
635 break;
637 if (node->getMandatory() == Data::NO_LAYER &&
638 !(other.is() && other->isFinalized()))
640 if (!isValidName(aName, true)) {
641 throw css::uno::RuntimeException(
642 "invalid element name " + aName);
644 rtl::Reference< RootAccess > root(getRootAccess());
645 rtl::Reference< ChildAccess > childAccess(
646 static_cast< ChildAccess * >(this));
647 localMods.add(getRelativePath());
648 // unbind() modifies the parent chain that
649 // markChildAsModified() walks, so order is
650 // important:
651 parent->markChildAsModified(childAccess);
652 //TODO: must not throw
653 childAccess->unbind(); // must not throw
654 if (other.is()) {
655 other->unbind(); // must not throw
657 childAccess->bind(root, parent, aName);
658 // must not throw
659 parent->markChildAsModified(childAccess);
660 //TODO: must not throw
661 localMods.add(getRelativePath());
662 break;
667 [[fallthrough]];
668 case Node::KIND_LOCALIZED_PROPERTY:
669 // renaming a property could only work for an extension property,
670 // but a localized property is never an extension property
671 throw css::uno::RuntimeException(
672 "configmgr setName inappropriate node",
673 static_cast< cppu::OWeakObject * >(this));
674 default:
675 assert(false); // this cannot happen
676 break;
678 getNotificationRoot()->initBroadcaster(localMods.getRoot(), &bc);
680 bc.send();
683 css::beans::Property Access::getAsProperty()
685 assert(thisIs(IS_ANY));
686 osl::MutexGuard g(*lock_);
687 checkLocalizedPropertyAccess();
688 return asProperty();
691 css::uno::Reference< css::beans::XPropertySetInfo > Access::getPropertySetInfo()
693 assert(thisIs(IS_GROUP));
694 return this;
697 void Access::setPropertyValue(
698 OUString const & aPropertyName, css::uno::Any const & aValue)
700 assert(thisIs(IS_GROUP));
701 Broadcaster bc;
703 osl::MutexGuard g(*lock_);
704 if (!getRootAccess()->isUpdate()) {
705 throw css::uno::RuntimeException(
706 "configmgr setPropertyValue on non-update access",
707 static_cast< cppu::OWeakObject * >(this));
709 Modifications localMods;
710 if (!setChildProperty(aPropertyName, aValue, &localMods)) {
711 throw css::beans::UnknownPropertyException(
712 aPropertyName, static_cast< cppu::OWeakObject * >(this));
714 getNotificationRoot()->initBroadcaster(localMods.getRoot(), &bc);
716 bc.send();
719 css::uno::Any Access::getPropertyValue(OUString const & PropertyName)
721 assert(thisIs(IS_GROUP));
722 osl::MutexGuard g(*lock_);
724 css::uno::Any value;
725 if (!getByNameFast(PropertyName, value))
726 throw css::beans::UnknownPropertyException(
727 PropertyName, static_cast< cppu::OWeakObject * >(this));
728 return value;
731 void Access::addPropertyChangeListener(
732 OUString const & aPropertyName,
733 css::uno::Reference< css::beans::XPropertyChangeListener > const &
734 xListener)
736 assert(thisIs(IS_GROUP));
738 osl::MutexGuard g(*lock_);
739 if (!xListener.is()) {
740 throw css::uno::RuntimeException(
741 "null listener", static_cast< cppu::OWeakObject * >(this));
743 checkKnownProperty(aPropertyName);
744 if (!disposed_) {
745 propertyChangeListeners_[aPropertyName].insert(xListener);
746 return;
749 try {
750 xListener->disposing(
751 css::lang::EventObject(static_cast< cppu::OWeakObject * >(this)));
752 } catch (css::lang::DisposedException &) {}
755 void Access::removePropertyChangeListener(
756 OUString const & aPropertyName,
757 css::uno::Reference< css::beans::XPropertyChangeListener > const &
758 aListener)
760 assert(thisIs(IS_GROUP));
761 osl::MutexGuard g(*lock_);
762 checkKnownProperty(aPropertyName);
763 PropertyChangeListeners::iterator i(
764 propertyChangeListeners_.find(aPropertyName));
765 if (i != propertyChangeListeners_.end()) {
766 PropertyChangeListenersElement::iterator j(i->second.find(aListener));
767 if (j != i->second.end()) {
768 i->second.erase(j);
769 if (i->second.empty()) {
770 propertyChangeListeners_.erase(i);
776 void Access::addVetoableChangeListener(
777 OUString const & PropertyName,
778 css::uno::Reference< css::beans::XVetoableChangeListener > const &
779 aListener)
781 assert(thisIs(IS_GROUP));
783 osl::MutexGuard g(*lock_);
784 if (!aListener.is()) {
785 throw css::uno::RuntimeException(
786 "null listener", static_cast< cppu::OWeakObject * >(this));
788 checkKnownProperty(PropertyName);
789 if (!disposed_) {
790 vetoableChangeListeners_[PropertyName].insert(aListener);
791 //TODO: actually call vetoableChangeListeners_
792 return;
795 try {
796 aListener->disposing(
797 css::lang::EventObject(static_cast< cppu::OWeakObject * >(this)));
798 } catch (css::lang::DisposedException &) {}
801 void Access::removeVetoableChangeListener(
802 OUString const & PropertyName,
803 css::uno::Reference< css::beans::XVetoableChangeListener > const &
804 aListener)
806 assert(thisIs(IS_GROUP));
807 osl::MutexGuard g(*lock_);
808 checkKnownProperty(PropertyName);
809 VetoableChangeListeners::iterator i(
810 vetoableChangeListeners_.find(PropertyName));
811 if (i != vetoableChangeListeners_.end()) {
812 VetoableChangeListenersElement::iterator j(i->second.find(aListener));
813 if (j != i->second.end()) {
814 i->second.erase(j);
815 if (i->second.empty()) {
816 vetoableChangeListeners_.erase(i);
822 void Access::setPropertyValues(
823 css::uno::Sequence< OUString > const & aPropertyNames,
824 css::uno::Sequence< css::uno::Any > const & aValues)
826 assert(thisIs(IS_GROUP));
827 Broadcaster bc;
829 osl::MutexGuard g(*lock_);
830 if (!getRootAccess()->isUpdate()) {
831 throw css::uno::RuntimeException(
832 "configmgr setPropertyValues on non-update access",
833 static_cast< cppu::OWeakObject * >(this));
835 if (aPropertyNames.getLength() != aValues.getLength()) {
836 throw css::lang::IllegalArgumentException(
837 ("configmgr setPropertyValues: aPropertyNames/aValues of"
838 " different length"),
839 static_cast< cppu::OWeakObject * >(this), -1);
841 Modifications localMods;
842 for (sal_Int32 i = 0; i < aPropertyNames.getLength(); ++i) {
843 if (!setChildProperty(aPropertyNames[i], aValues[i], &localMods)) {
844 throw css::lang::IllegalArgumentException(
845 "configmgr setPropertyValues inappropriate property name",
846 static_cast< cppu::OWeakObject * >(this), -1);
849 getNotificationRoot()->initBroadcaster(localMods.getRoot(), &bc);
851 bc.send();
854 css::uno::Sequence< css::uno::Any > Access::getPropertyValues(
855 css::uno::Sequence< OUString > const & aPropertyNames)
857 assert(thisIs(IS_GROUP));
858 osl::MutexGuard g(*lock_);
859 css::uno::Sequence< css::uno::Any > vals(aPropertyNames.getLength());
860 auto aValsRange = asNonConstRange(vals);
861 for (sal_Int32 i = 0; i < aPropertyNames.getLength(); ++i)
863 if (!getByNameFast(aPropertyNames[i], aValsRange[i]))
864 throw css::uno::RuntimeException(
865 "configmgr getPropertyValues inappropriate property name",
866 static_cast< cppu::OWeakObject * >(this));
869 return vals;
872 void Access::addPropertiesChangeListener(
873 css::uno::Sequence< OUString > const &,
874 css::uno::Reference< css::beans::XPropertiesChangeListener > const &
875 xListener)
877 assert(thisIs(IS_GROUP));
879 osl::MutexGuard g(*lock_);
880 if (!xListener.is()) {
881 throw css::uno::RuntimeException(
882 "null listener", static_cast< cppu::OWeakObject * >(this));
884 if (!disposed_) {
885 propertiesChangeListeners_.insert(xListener);
886 return;
889 try {
890 xListener->disposing(
891 css::lang::EventObject(static_cast< cppu::OWeakObject * >(this)));
892 } catch (css::lang::DisposedException &) {}
895 void Access::removePropertiesChangeListener(
896 css::uno::Reference< css::beans::XPropertiesChangeListener > const &
897 xListener)
899 assert(thisIs(IS_GROUP));
900 osl::MutexGuard g(*lock_);
901 PropertiesChangeListeners::iterator i(
902 propertiesChangeListeners_.find(xListener));
903 if (i != propertiesChangeListeners_.end()) {
904 propertiesChangeListeners_.erase(i);
908 void Access::firePropertiesChangeEvent(
909 css::uno::Sequence< OUString > const & aPropertyNames,
910 css::uno::Reference< css::beans::XPropertiesChangeListener > const &
911 xListener)
913 assert(thisIs(IS_GROUP));
914 css::uno::Sequence< css::beans::PropertyChangeEvent > events(
915 aPropertyNames.getLength());
916 auto aEventsRange = asNonConstRange(events);
917 for (sal_Int32 i = 0; i < events.getLength(); ++i) {
918 aEventsRange[i].Source = static_cast< cppu::OWeakObject * >(this);
919 aEventsRange[i].PropertyName = aPropertyNames[i];
920 aEventsRange[i].Further = false;
921 aEventsRange[i].PropertyHandle = -1;
923 xListener->propertiesChange(events);
926 css::uno::Reference< css::beans::XHierarchicalPropertySetInfo >
927 Access::getHierarchicalPropertySetInfo() {
928 assert(thisIs(IS_GROUP));
929 return this;
932 void Access::setHierarchicalPropertyValue(
933 OUString const & aHierarchicalPropertyName,
934 css::uno::Any const & aValue)
936 assert(thisIs(IS_GROUP));
937 Broadcaster bc;
939 osl::MutexGuard g(*lock_);
940 if (!getRootAccess()->isUpdate()) {
941 throw css::uno::RuntimeException(
942 "configmgr setHierarchicalPropertyName on non-update access",
943 static_cast< cppu::OWeakObject * >(this));
945 rtl::Reference< ChildAccess > child(
946 getSubChild(aHierarchicalPropertyName));
947 if (!child.is()) {
948 throw css::beans::UnknownPropertyException(
949 aHierarchicalPropertyName,
950 static_cast< cppu::OWeakObject * >(this));
952 child->checkFinalized();
953 Modifications localMods;
954 child->setProperty(aValue, &localMods);
955 getNotificationRoot()->initBroadcaster(localMods.getRoot(), &bc);
957 bc.send();
960 css::uno::Any Access::getHierarchicalPropertyValue(
961 OUString const & aHierarchicalPropertyName)
963 assert(thisIs(IS_GROUP));
964 osl::MutexGuard g(*lock_);
965 rtl::Reference< ChildAccess > child(getSubChild(aHierarchicalPropertyName));
966 if (!child.is()) {
967 throw css::beans::UnknownPropertyException(
968 aHierarchicalPropertyName,
969 static_cast< cppu::OWeakObject * >(this));
971 return child->asValue();
974 void Access::setHierarchicalPropertyValues(
975 css::uno::Sequence< OUString > const & aHierarchicalPropertyNames,
976 css::uno::Sequence< css::uno::Any > const & Values)
978 assert(thisIs(IS_GROUP));
979 Broadcaster bc;
981 osl::MutexGuard g(*lock_);
982 if (!getRootAccess()->isUpdate()) {
983 throw css::uno::RuntimeException(
984 "configmgr setPropertyValues on non-update access",
985 static_cast< cppu::OWeakObject * >(this));
987 if (aHierarchicalPropertyNames.getLength() != Values.getLength()) {
988 throw css::lang::IllegalArgumentException(
989 ("configmgr setHierarchicalPropertyValues:"
990 " aHierarchicalPropertyNames/Values of different length"),
991 static_cast< cppu::OWeakObject * >(this), -1);
993 Modifications localMods;
994 for (sal_Int32 i = 0; i < aHierarchicalPropertyNames.getLength(); ++i) {
995 rtl::Reference< ChildAccess > child(
996 getSubChild(aHierarchicalPropertyNames[i]));
997 if (!child.is()) {
998 throw css::lang::IllegalArgumentException(
999 ("configmgr setHierarchicalPropertyValues inappropriate"
1000 " property name"),
1001 static_cast< cppu::OWeakObject * >(this), -1);
1003 child->checkFinalized();
1004 child->setProperty(Values[i], &localMods);
1006 getNotificationRoot()->initBroadcaster(localMods.getRoot(), &bc);
1008 bc.send();
1011 css::uno::Sequence< css::uno::Any > Access::getHierarchicalPropertyValues(
1012 css::uno::Sequence< OUString > const & aHierarchicalPropertyNames)
1014 assert(thisIs(IS_GROUP));
1015 osl::MutexGuard g(*lock_);
1016 css::uno::Sequence< css::uno::Any > vals(
1017 aHierarchicalPropertyNames.getLength());
1018 auto aValsRange = asNonConstRange(vals);
1019 for (sal_Int32 i = 0; i < aHierarchicalPropertyNames.getLength(); ++i) {
1020 rtl::Reference< ChildAccess > child(
1021 getSubChild(aHierarchicalPropertyNames[i]));
1022 if (!child.is()) {
1023 throw css::lang::IllegalArgumentException(
1024 ("configmgr getHierarchicalPropertyValues inappropriate"
1025 " hierarchical property name"),
1026 static_cast< cppu::OWeakObject * >(this), -1);
1028 aValsRange[i] = child->asValue();
1030 return vals;
1033 css::beans::Property Access::getPropertyByHierarchicalName(
1034 OUString const & aHierarchicalName)
1036 assert(thisIs(IS_GROUP));
1037 osl::MutexGuard g(*lock_);
1038 rtl::Reference< ChildAccess > child(getSubChild(aHierarchicalName));
1039 if (!child.is()) {
1040 throw css::beans::UnknownPropertyException(
1041 aHierarchicalName, static_cast< cppu::OWeakObject * >(this));
1043 return child->asProperty();
1046 sal_Bool Access::hasPropertyByHierarchicalName(
1047 OUString const & aHierarchicalName)
1049 assert(thisIs(IS_GROUP));
1050 osl::MutexGuard g(*lock_);
1051 return getSubChild(aHierarchicalName).is();
1054 void Access::replaceByName(
1055 OUString const & aName, css::uno::Any const & aElement)
1057 assert(thisIs(IS_UPDATE));
1058 Broadcaster bc;
1060 osl::MutexGuard g(*lock_);
1061 checkLocalizedPropertyAccess();
1062 rtl::Reference< ChildAccess > child(getChild(aName));
1063 if (!child.is()) {
1064 throw css::container::NoSuchElementException(
1065 aName, static_cast< cppu::OWeakObject * >(this));
1067 child->checkFinalized();
1068 Modifications localMods;
1069 switch (getNode()->kind()) {
1070 case Node::KIND_LOCALIZED_PROPERTY:
1071 case Node::KIND_GROUP:
1072 child->setProperty(aElement, &localMods);
1073 break;
1074 case Node::KIND_SET:
1076 rtl::Reference< ChildAccess > freeAcc(
1077 getFreeSetMember(aElement));
1078 rtl::Reference< RootAccess > root(getRootAccess());
1079 localMods.add(child->getRelativePath());
1080 child->unbind(); // must not throw
1081 freeAcc->bind(root, this, aName); // must not throw
1082 markChildAsModified(freeAcc); //TODO: must not throw
1084 break;
1085 default:
1086 assert(false); // this cannot happen
1087 break;
1089 getNotificationRoot()->initBroadcaster(localMods.getRoot(), &bc);
1091 bc.send();
1094 void Access::insertByName(
1095 OUString const & aName, css::uno::Any const & aElement)
1097 assert(thisIs(IS_EXTENSIBLE|IS_UPDATE));
1098 Broadcaster bc;
1100 osl::MutexGuard g(*lock_);
1101 checkLocalizedPropertyAccess();
1102 checkFinalized();
1103 if (getChild(aName).is()) {
1104 throw css::container::ElementExistException(
1105 aName, static_cast< cppu::OWeakObject * >(this));
1107 Modifications localMods;
1108 switch (getNode()->kind()) {
1109 case Node::KIND_LOCALIZED_PROPERTY:
1110 if (!isValidName(aName, false)) {
1111 throw css::lang::IllegalArgumentException(
1112 aName, static_cast<cppu::OWeakObject *>(this), 0);
1114 insertLocalizedValueChild(aName, aElement, &localMods);
1115 break;
1116 case Node::KIND_GROUP:
1118 if (!isValidName(aName, false)) {
1119 throw css::lang::IllegalArgumentException(
1120 aName, static_cast<cppu::OWeakObject *>(this), 0);
1122 checkValue(aElement, TYPE_ANY, true);
1123 rtl::Reference child(
1124 new ChildAccess(
1125 components_, getRootAccess(), this, aName,
1126 new PropertyNode(
1127 Data::NO_LAYER, TYPE_ANY, true, aElement, true)));
1128 markChildAsModified(child);
1129 localMods.add(child->getRelativePath());
1131 break;
1132 case Node::KIND_SET:
1134 if (!isValidName(aName, true)) {
1135 throw css::lang::IllegalArgumentException(
1136 aName, static_cast<cppu::OWeakObject *>(this), 0);
1138 rtl::Reference< ChildAccess > freeAcc(
1139 getFreeSetMember(aElement));
1140 freeAcc->bind(getRootAccess(), this, aName); // must not throw
1141 markChildAsModified(freeAcc); //TODO: must not throw
1142 localMods.add(freeAcc->getRelativePath());
1144 break;
1145 default:
1146 assert(false); // this cannot happen
1147 break;
1149 getNotificationRoot()->initBroadcaster(localMods.getRoot(), &bc);
1151 bc.send();
1154 void Access::removeByName(OUString const & aName)
1156 assert(thisIs(IS_EXTENSIBLE|IS_UPDATE));
1157 Broadcaster bc;
1159 osl::MutexGuard g(*lock_);
1160 checkLocalizedPropertyAccess();
1161 rtl::Reference< ChildAccess > child(getChild(aName));
1162 if (!child.is() || child->isFinalized() ||
1163 child->getNode()->getMandatory() != Data::NO_LAYER)
1165 throw css::container::NoSuchElementException(
1166 aName, static_cast< cppu::OWeakObject * >(this));
1168 if (getNode()->kind() == Node::KIND_GROUP) {
1169 rtl::Reference< Node > p(child->getNode());
1170 if (p->kind() != Node::KIND_PROPERTY ||
1171 !static_cast< PropertyNode * >(p.get())->isExtension())
1173 throw css::container::NoSuchElementException(
1174 aName, static_cast< cppu::OWeakObject * >(this));
1177 Modifications localMods;
1178 localMods.add(child->getRelativePath());
1179 // unbind() modifies the parent chain that markChildAsModified() walks,
1180 // so order is important:
1181 markChildAsModified(child); //TODO: must not throw
1182 child->unbind();
1183 getNotificationRoot()->initBroadcaster(localMods.getRoot(), &bc);
1185 bc.send();
1188 css::uno::Reference< css::uno::XInterface > Access::createInstance()
1190 assert(thisIs(IS_SET|IS_UPDATE));
1191 OUString tmplName(
1192 static_cast< SetNode * >(getNode().get())->getDefaultTemplateName());
1193 rtl::Reference< Node > tmpl(
1194 components_.getTemplate(tmplName));
1195 if (!tmpl.is()) {
1196 throw css::uno::Exception(
1197 "unknown template " + tmplName,
1198 static_cast< cppu::OWeakObject * >(this));
1200 rtl::Reference< Node > node(tmpl->clone(true));
1201 node->setLayer(Data::NO_LAYER);
1202 return static_cast< cppu::OWeakObject * >(
1203 new ChildAccess(components_, getRootAccess(), node));
1206 css::uno::Reference< css::uno::XInterface > Access::createInstanceWithArguments(
1207 css::uno::Sequence< css::uno::Any > const & aArguments)
1209 assert(thisIs(IS_SET|IS_UPDATE));
1210 if (aArguments.hasElements()) {
1211 throw css::uno::Exception(
1212 ("configuration SimpleSetUpdate createInstanceWithArguments"
1213 " must not specify any arguments"),
1214 static_cast< cppu::OWeakObject * >(this));
1216 return createInstance();
1219 Access::Access(Components & components):
1220 components_(components), disposed_(false), lock_( lock() )
1224 Access::~Access() {}
1226 void Access::initDisposeBroadcaster(Broadcaster * broadcaster) {
1227 assert(broadcaster != nullptr);
1228 for (auto const& disposeListener : disposeListeners_)
1230 broadcaster->addDisposeNotification(
1231 disposeListener,
1232 css::lang::EventObject(static_cast< cppu::OWeakObject * >(this)));
1234 for (auto const& containerListener : containerListeners_)
1236 broadcaster->addDisposeNotification(
1237 containerListener,
1238 css::lang::EventObject(static_cast< cppu::OWeakObject * >(this)));
1240 for (auto const& propertyChangeListener : propertyChangeListeners_)
1242 for (auto const& propertyChangeListenerElement : propertyChangeListener.second)
1244 broadcaster->addDisposeNotification(
1245 propertyChangeListenerElement,
1246 css::lang::EventObject(
1247 static_cast< cppu::OWeakObject * >(this)));
1250 for (auto const& vetoableChangeListener : vetoableChangeListeners_)
1252 for (auto const& vetoableChangeListenerElement : vetoableChangeListener.second)
1254 broadcaster->addDisposeNotification(
1255 vetoableChangeListenerElement,
1256 css::lang::EventObject(
1257 static_cast< cppu::OWeakObject * >(this)));
1260 for (auto const& propertiesChangeListener : propertiesChangeListeners_)
1262 broadcaster->addDisposeNotification(
1263 propertiesChangeListener,
1264 css::lang::EventObject(static_cast< cppu::OWeakObject * >(this)));
1266 //TODO: iterate over children w/ listeners (incl. unmodified ones):
1267 for (ModifiedChildren::iterator i(modifiedChildren_.begin());
1268 i != modifiedChildren_.end(); ++i)
1270 rtl::Reference< ChildAccess > child(getModifiedChild(i));
1271 if (child.is()) {
1272 child->initDisposeBroadcaster(broadcaster);
1277 void Access::clearListeners() noexcept {
1278 disposeListeners_.clear();
1279 containerListeners_.clear();
1280 propertyChangeListeners_.clear();
1281 vetoableChangeListeners_.clear();
1282 propertiesChangeListeners_.clear();
1283 //TODO: iterate over children w/ listeners (incl. unmodified ones):
1284 for (ModifiedChildren::iterator i(modifiedChildren_.begin());
1285 i != modifiedChildren_.end(); ++i)
1287 rtl::Reference< ChildAccess > child(getModifiedChild(i));
1288 if (child.is()) {
1289 child->clearListeners();
1294 css::uno::Any Access::queryInterface(css::uno::Type const & aType)
1296 css::uno::Any res(OWeakObject::queryInterface(aType));
1297 if (res.hasValue()) {
1298 return res;
1300 res = cppu::queryInterface(
1301 aType, static_cast< css::lang::XTypeProvider * >(this),
1302 static_cast< css::lang::XServiceInfo * >(this),
1303 static_cast< css::lang::XComponent * >(this),
1304 static_cast< css::container::XHierarchicalNameAccess * >(this),
1305 static_cast< css::container::XContainer * >(this),
1306 static_cast< css::beans::XExactName * >(this),
1307 static_cast< css::container::XHierarchicalName * >(this),
1308 static_cast< css::container::XNamed * >(this),
1309 static_cast< css::beans::XProperty * >(this),
1310 static_cast< css::container::XElementAccess * >(this),
1311 static_cast< css::container::XNameAccess * >(this));
1312 if (res.hasValue()) {
1313 return res;
1315 if (getNode()->kind() == Node::KIND_GROUP) {
1316 res = cppu::queryInterface(
1317 aType, static_cast< css::beans::XPropertySetInfo * >(this),
1318 static_cast< css::beans::XPropertySet * >(this),
1319 static_cast< css::beans::XMultiPropertySet * >(this),
1320 static_cast< css::beans::XHierarchicalPropertySet * >(this),
1321 static_cast< css::beans::XMultiHierarchicalPropertySet * >(this),
1322 static_cast< css::beans::XHierarchicalPropertySetInfo * >(this));
1323 if (res.hasValue()) {
1324 return res;
1327 if (getRootAccess()->isUpdate()) {
1328 res = cppu::queryInterface(
1329 aType, static_cast< css::container::XNameReplace * >(this),
1330 static_cast< css::container::XHierarchicalNameReplace * >(this));
1331 if (res.hasValue()) {
1332 return res;
1334 if (getNode()->kind() != Node::KIND_GROUP ||
1335 static_cast< GroupNode * >(getNode().get())->isExtensible())
1337 res = cppu::queryInterface(
1338 aType, static_cast< css::container::XNameContainer * >(this));
1339 if (res.hasValue()) {
1340 return res;
1343 if (getNode()->kind() == Node::KIND_SET) {
1344 res = cppu::queryInterface(
1345 aType, static_cast< css::lang::XSingleServiceFactory * >(this));
1348 return res;
1352 void Access::checkLocalizedPropertyAccess() {
1353 if (getNode()->kind() == Node::KIND_LOCALIZED_PROPERTY &&
1354 !Components::allLocales(getRootAccess()->getLocale()))
1356 throw css::uno::RuntimeException(
1357 "configmgr Access to specialized LocalizedPropertyNode",
1358 static_cast< cppu::OWeakObject * >(this));
1362 rtl::Reference< Node > Access::getParentNode() {
1363 rtl::Reference< Access > parent(getParentAccess());
1364 return parent.is() ? parent->getNode() : rtl::Reference< Node >();
1367 rtl::Reference< ChildAccess > Access::getChild(OUString const & name) {
1368 OUString locale;
1369 if (getNode()->kind() == Node::KIND_LOCALIZED_PROPERTY
1370 && name.startsWith("*", &locale))
1372 if (locale.startsWith("*")) {
1373 SAL_WARN(
1374 "configmgr",
1375 ("access best-matching localized property value via"
1376 " \"*<locale>\" with <locale> \"")
1377 << locale << "\" recursively starting with \"*\"");
1378 return getChild(locale);
1380 SAL_WARN_IF(
1381 locale.isEmpty(), "configmgr",
1382 ("access best-matching localized property value via \"*<locale>\""
1383 " with empty <locale>; falling back to defaults"));
1385 // Since the locale given to us is the one used at initialization,
1386 // here we override it with the actual current-user's language to
1387 // support per-view localization in LOK.
1388 if (comphelper::LibreOfficeKit::isActive())
1389 locale = comphelper::LibreOfficeKit::getLanguageTag().getBcp47();
1391 if (!locale.isEmpty()) {
1392 // Try exact match first, avoiding all fallback overhead.
1393 rtl::Reference<ChildAccess> directChild(getChild(locale));
1394 if (directChild.is())
1395 return directChild;
1397 LanguageTag aLanguageTag(locale, true);
1398 if (aLanguageTag.getBcp47() != locale)
1400 // Original may be overridden by a known locale, for example
1401 // "zh-Hant-TW" by "zh-TW".
1402 rtl::Reference<ChildAccess> child(getChild(aLanguageTag.getBcp47()));
1403 if (child.is())
1404 return child;
1407 // Find the best match using the LanguageTag fallback mechanism,
1408 // excluding the original tag.
1409 std::vector<OUString> aFallbacks = aLanguageTag.getFallbackStrings(false);
1410 for (const OUString& rFallback : aFallbacks)
1412 rtl::Reference<ChildAccess> child(getChild(rFallback));
1413 if (child.is())
1414 return child;
1417 // As a workaround for broken xcu data that does not use shortest
1418 // xml:lang attributes, look for the first entry with the same first
1419 // segment as the requested language tag before falling back to
1420 // defaults (see fdo#33638):
1421 auto const i = comphelper::string::indexOfAny(locale, u"-_", 1);
1422 if (i != -1) {
1423 locale = locale.copy(0, i);
1425 assert(!locale.isEmpty());
1426 std::vector< rtl::Reference< ChildAccess > > children(
1427 getAllChildren());
1428 for (auto const& child : children)
1430 const OUString & name2(child->getNameInternal());
1431 if (name2.startsWith(locale) &&
1432 (name2.getLength() == locale.getLength() ||
1433 name2[locale.getLength()] == '-' ||
1434 name2[locale.getLength()] == '_'))
1436 return child;
1440 // Defaults are the "en-US" locale, the "en" locale, the empty string locale, the first child (if
1441 // any, and if the property is non-nillable), or a null ChildAccess, in that order:
1442 rtl::Reference< ChildAccess > child(getChild("en-US"));
1443 if (child.is()) {
1444 return child;
1446 child = getChild("en");
1447 if (child.is()) {
1448 return child;
1450 child = getChild("");
1451 if (child.is()) {
1452 return child;
1454 if (!static_cast<LocalizedPropertyNode *>(getNode().get())->isNillable()) {
1455 std::vector< rtl::Reference< ChildAccess > > children(getAllChildren());
1456 if (!children.empty()) {
1457 return children.front();
1460 return rtl::Reference< ChildAccess >();
1462 ModifiedChildren::iterator i(modifiedChildren_.find(name));
1463 return i == modifiedChildren_.end()
1464 ? getUnmodifiedChild(name) : getModifiedChild(i);
1467 std::vector< rtl::Reference< ChildAccess > > Access::getAllChildren() {
1468 std::vector< rtl::Reference< ChildAccess > > vec;
1469 NodeMap const & members = getNode()->getMembers();
1470 for (auto const& member : members)
1472 if (modifiedChildren_.find(member.first) == modifiedChildren_.end()) {
1473 vec.push_back(getUnmodifiedChild(member.first));
1474 assert(vec.back().is());
1477 for (ModifiedChildren::iterator i(modifiedChildren_.begin());
1478 i != modifiedChildren_.end(); ++i)
1480 rtl::Reference< ChildAccess > child(getModifiedChild(i));
1481 if (child.is()) {
1482 vec.push_back(child);
1485 return vec;
1488 void Access::checkValue(css::uno::Any const & value, Type type, bool nillable) {
1489 bool ok;
1490 switch (type) {
1491 case TYPE_ERROR:
1492 ok = false;
1493 break;
1494 case TYPE_ANY:
1495 switch (getDynamicType(value)) {
1496 case TYPE_ERROR:
1497 ok = false;
1498 break;
1499 case TYPE_NIL:
1500 ok = nillable;
1501 break;
1502 default:
1503 ok = true;
1504 break;
1505 case TYPE_ANY:
1506 for (;;) std::abort(); // cannot happen
1508 break;
1509 default:
1510 ok = value.hasValue() ? value.isExtractableTo(mapType(type)) : nillable;
1511 break;
1512 case TYPE_NIL:
1513 for (;;) std::abort(); // cannot happen
1515 if (!ok) {
1516 throw css::lang::IllegalArgumentException(
1517 "configmgr inappropriate property value",
1518 static_cast< cppu::OWeakObject * >(this), -1);
1522 void Access::insertLocalizedValueChild(
1523 OUString const & name, css::uno::Any const & value,
1524 Modifications * localModifications)
1526 assert(localModifications != nullptr);
1527 LocalizedPropertyNode * locprop = static_cast< LocalizedPropertyNode * >(
1528 getNode().get());
1529 checkValue(value, locprop->getStaticType(), locprop->isNillable());
1530 rtl::Reference child(
1531 new ChildAccess(
1532 components_, getRootAccess(), this, name,
1533 new LocalizedValueNode(Data::NO_LAYER, value)));
1534 markChildAsModified(child);
1535 localModifications->add(child->getRelativePath());
1538 void Access::reportChildChanges(
1539 std::vector< css::util::ElementChange > * changes)
1541 assert(changes != nullptr);
1542 for (ModifiedChildren::iterator i(modifiedChildren_.begin());
1543 i != modifiedChildren_.end(); ++i)
1545 rtl::Reference< ChildAccess > child(getModifiedChild(i));
1546 if (child.is()) {
1547 child->reportChildChanges(changes);
1548 changes->push_back(css::util::ElementChange());
1549 //TODO: changed value and/or inserted node
1550 } else {
1551 changes->push_back(css::util::ElementChange()); //TODO: removed node
1556 void Access::commitChildChanges(
1557 bool valid, Modifications * globalModifications)
1559 assert(globalModifications != nullptr);
1560 while (!modifiedChildren_.empty()) {
1561 bool childValid = valid;
1562 ModifiedChildren::iterator i(modifiedChildren_.begin());
1563 rtl::Reference< ChildAccess > child(getModifiedChild(i));
1564 if (child.is()) {
1565 childValid = childValid && !child->isFinalized();
1566 child->commitChanges(childValid, globalModifications);
1567 //TODO: currently, this is called here for directly inserted
1568 // children as well as for children whose sub-children were
1569 // modified (and should never be called for directly removed
1570 // children); clarify what exactly should happen here for
1571 // directly inserted children
1573 NodeMap & members = getNode()->getMembers();
1574 NodeMap::iterator j(members.find(i->first));
1575 if (child.is()) {
1576 // Inserted:
1577 if (j != members.end()) {
1578 childValid = childValid &&
1579 j->second->getFinalized() == Data::NO_LAYER;
1580 if (childValid) {
1581 child->getNode()->setMandatory(j->second->getMandatory());
1584 if (childValid) {
1585 members[i->first] = child->getNode();
1587 } else {
1588 // Removed:
1589 childValid = childValid && j != members.end() &&
1590 j->second->getFinalized() == Data::NO_LAYER &&
1591 j->second->getMandatory() == Data::NO_LAYER;
1592 if (childValid) {
1593 members.erase(j);
1596 if (childValid && i->second.directlyModified) {
1597 std::vector<OUString> path(getAbsolutePath());
1598 path.push_back(i->first);
1599 components_.addModification(path);
1600 globalModifications->add(path);
1602 i->second.child->committed();
1603 modifiedChildren_.erase(i);
1607 void Access::initBroadcasterAndChanges(
1608 Modifications::Node const & modifications, Broadcaster * broadcaster,
1609 std::vector< css::util::ElementChange > * allChanges)
1611 assert(broadcaster != nullptr);
1612 std::vector< css::beans::PropertyChangeEvent > propChanges;
1613 bool collectPropChanges = !propertiesChangeListeners_.empty();
1614 for (const auto & i : modifications.children)
1616 rtl::Reference< ChildAccess > child(getChild(i.first));
1617 if (child.is()) {
1618 switch (child->getNode()->kind()) {
1619 case Node::KIND_LOCALIZED_PROPERTY:
1620 if (!i.second.children.empty()) {
1621 if (Components::allLocales(getRootAccess()->getLocale())) {
1622 child->initBroadcasterAndChanges(
1623 i.second, broadcaster, allChanges);
1624 //TODO: if allChanges==0, recurse only into children
1625 // w/ listeners
1626 } else {
1627 //TODO: filter child mods that are irrelevant for
1628 // locale:
1629 for (auto const& containerListener : containerListeners_)
1631 broadcaster->
1632 addContainerElementReplacedNotification(
1633 containerListener,
1634 css::container::ContainerEvent(
1635 static_cast< cppu::OWeakObject * >(
1636 this),
1637 css::uno::Any(i.first),
1638 css::uno::Any(), css::uno::Any()));
1639 //TODO: non-void Element, ReplacedElement
1641 PropertyChangeListeners::iterator j(
1642 propertyChangeListeners_.find(i.first));
1643 if (j != propertyChangeListeners_.end()) {
1644 for (auto const& propertyChangeListenerElement : j->second)
1646 broadcaster->addPropertyChangeNotification(
1647 propertyChangeListenerElement,
1648 css::beans::PropertyChangeEvent(
1649 static_cast< cppu::OWeakObject * >(
1650 this),
1651 i.first, false, -1, css::uno::Any(),
1652 css::uno::Any()));
1655 j = propertyChangeListeners_.find("");
1656 if (j != propertyChangeListeners_.end()) {
1657 for (auto const& propertyChangeListenerElement : j->second)
1659 broadcaster->addPropertyChangeNotification(
1660 propertyChangeListenerElement,
1661 css::beans::PropertyChangeEvent(
1662 static_cast< cppu::OWeakObject * >(
1663 this),
1664 i.first, false, -1, css::uno::Any(),
1665 css::uno::Any()));
1668 if (allChanges != nullptr) {
1669 allChanges->push_back(
1670 css::util::ElementChange(
1671 css::uno::Any(
1672 child->getRelativePathRepresentation()),
1673 css::uno::Any(), css::uno::Any()));
1674 //TODO: non-void Element, ReplacedElement
1676 if (collectPropChanges) {
1677 propChanges.emplace_back(
1678 static_cast< cppu::OWeakObject * >(this),
1679 i.first, false, -1, css::uno::Any(),
1680 css::uno::Any());
1684 // else: spurious Modifications::Node not representing a change
1685 break;
1686 case Node::KIND_LOCALIZED_VALUE:
1687 assert(Components::allLocales(getRootAccess()->getLocale()));
1688 for (auto const& containerListener : containerListeners_)
1690 broadcaster->addContainerElementReplacedNotification(
1691 containerListener,
1692 css::container::ContainerEvent(
1693 static_cast< cppu::OWeakObject * >(this),
1694 css::uno::Any(i.first), child->asValue(),
1695 css::uno::Any()));
1696 //TODO: distinguish add/modify; non-void ReplacedElement
1698 if (allChanges != nullptr) {
1699 allChanges->push_back(
1700 css::util::ElementChange(
1701 css::uno::Any(
1702 child->getRelativePathRepresentation()),
1703 child->asValue(), css::uno::Any()));
1704 //TODO: non-void ReplacedElement
1706 assert(!collectPropChanges);
1707 break;
1708 case Node::KIND_PROPERTY:
1710 for (auto const& containerListener : containerListeners_)
1712 broadcaster->addContainerElementReplacedNotification(
1713 containerListener,
1714 css::container::ContainerEvent(
1715 static_cast< cppu::OWeakObject * >(this),
1716 css::uno::Any(i.first), child->asValue(),
1717 css::uno::Any()));
1718 //TODO: distinguish add/remove/modify; non-void
1719 // ReplacedElement
1721 PropertyChangeListeners::iterator j(
1722 propertyChangeListeners_.find(i.first));
1723 if (j != propertyChangeListeners_.end()) {
1724 for (auto const& propertyChangeListenerElement : j->second)
1726 broadcaster->addPropertyChangeNotification(
1727 propertyChangeListenerElement,
1728 css::beans::PropertyChangeEvent(
1729 static_cast< cppu::OWeakObject * >(this),
1730 i.first, false, -1, css::uno::Any(),
1731 css::uno::Any()));
1734 j = propertyChangeListeners_.find("");
1735 if (j != propertyChangeListeners_.end()) {
1736 for (auto const& propertyChangeListenerElement : j->second)
1738 broadcaster->addPropertyChangeNotification(
1739 propertyChangeListenerElement,
1740 css::beans::PropertyChangeEvent(
1741 static_cast< cppu::OWeakObject * >(this),
1742 i.first, false, -1, css::uno::Any(),
1743 css::uno::Any()));
1746 if (allChanges != nullptr) {
1747 allChanges->push_back(
1748 css::util::ElementChange(
1749 css::uno::Any(
1750 child->getRelativePathRepresentation()),
1751 child->asValue(), css::uno::Any()));
1752 //TODO: non-void ReplacedElement
1754 if (collectPropChanges) {
1755 propChanges.emplace_back(
1756 static_cast< cppu::OWeakObject * >(this),
1757 i.first, false, -1, css::uno::Any(),
1758 css::uno::Any());
1761 break;
1762 case Node::KIND_GROUP:
1763 case Node::KIND_SET:
1764 if (i.second.children.empty()) {
1765 if (!child->getNode()->getTemplateName().isEmpty()) {
1766 for (auto const& containerListener : containerListeners_)
1768 broadcaster->
1769 addContainerElementInsertedNotification(
1770 containerListener,
1771 css::container::ContainerEvent(
1772 static_cast< cppu::OWeakObject * >(
1773 this),
1774 css::uno::Any(i.first),
1775 child->asValue(), css::uno::Any()));
1777 if (allChanges != nullptr) {
1778 allChanges->push_back(
1779 css::util::ElementChange(
1780 css::uno::Any(
1781 child->getRelativePathRepresentation()),
1782 css::uno::Any(), css::uno::Any()));
1783 //TODO: non-void Element, ReplacedElement
1786 // else: spurious Modifications::Node not representing a
1787 // change
1788 } else {
1789 child->initBroadcasterAndChanges(
1790 i.second, broadcaster, allChanges);
1791 //TODO: if allChanges==0, recurse only into children w/
1792 // listeners
1794 break;
1795 case Node::KIND_ROOT:
1796 assert(false); // this cannot happen
1797 break;
1799 } else {
1800 switch (getNode()->kind()) {
1801 case Node::KIND_LOCALIZED_PROPERTY:
1802 // Removed localized property value:
1803 assert(Components::allLocales(getRootAccess()->getLocale()));
1804 for (auto const& containerListener : containerListeners_)
1806 broadcaster->addContainerElementRemovedNotification(
1807 containerListener,
1808 css::container::ContainerEvent(
1809 static_cast< cppu::OWeakObject * >(this),
1810 css::uno::Any(i.first), css::uno::Any(),
1811 css::uno::Any()));
1812 //TODO: non-void ReplacedElement
1814 if (allChanges != nullptr) {
1815 OUStringBuffer path(getRelativePathRepresentation());
1816 if (!path.isEmpty()) {
1817 path.append('/');
1819 path.append(Data::createSegment(u"*", i.first));
1820 allChanges->push_back(
1821 css::util::ElementChange(
1822 css::uno::Any(path.makeStringAndClear()),
1823 css::uno::Any(), css::uno::Any()));
1824 //TODO: non-void ReplacedElement
1826 assert(!collectPropChanges);
1827 break;
1828 case Node::KIND_GROUP:
1830 // Removed (non-localized) extension property:
1831 for (auto const& containerListener : containerListeners_)
1833 broadcaster->addContainerElementRemovedNotification(
1834 containerListener,
1835 css::container::ContainerEvent(
1836 static_cast< cppu::OWeakObject * >(this),
1837 css::uno::Any(i.first), css::uno::Any(),
1838 css::uno::Any()));
1839 //TODO: non-void ReplacedElement
1841 PropertyChangeListeners::iterator j(
1842 propertyChangeListeners_.find(i.first));
1843 if (j != propertyChangeListeners_.end()) {
1844 for (auto const& propertyChangeListenerElement : j->second)
1846 broadcaster->addPropertyChangeNotification(
1847 propertyChangeListenerElement,
1848 css::beans::PropertyChangeEvent(
1849 static_cast< cppu::OWeakObject * >(this),
1850 i.first, false, -1, css::uno::Any(),
1851 css::uno::Any()));
1854 j = propertyChangeListeners_.find("");
1855 if (j != propertyChangeListeners_.end()) {
1856 for (auto const& propertyChangeListenerElement : j->second)
1858 broadcaster->addPropertyChangeNotification(
1859 propertyChangeListenerElement,
1860 css::beans::PropertyChangeEvent(
1861 static_cast< cppu::OWeakObject * >(this),
1862 i.first, false, -1, css::uno::Any(),
1863 css::uno::Any()));
1866 if (allChanges != nullptr) {
1867 OUStringBuffer path(
1868 getRelativePathRepresentation());
1869 if (!path.isEmpty()) {
1870 path.append('/');
1872 path.append(i.first);
1873 allChanges->push_back(
1874 css::util::ElementChange(
1875 css::uno::Any(path.makeStringAndClear()),
1876 css::uno::Any(), css::uno::Any()));
1877 //TODO: non-void ReplacedElement
1879 if (collectPropChanges) {
1880 propChanges.emplace_back(
1881 static_cast< cppu::OWeakObject * >(this),
1882 i.first, false, -1, css::uno::Any(),
1883 css::uno::Any());
1886 break;
1887 case Node::KIND_SET:
1888 // Removed set member:
1889 if (i.second.children.empty()) {
1890 for (auto const& containerListener : containerListeners_)
1892 broadcaster->addContainerElementRemovedNotification(
1893 containerListener,
1894 css::container::ContainerEvent(
1895 static_cast< cppu::OWeakObject * >(this),
1896 css::uno::Any(i.first),
1897 css::uno::Any(), css::uno::Any()));
1898 //TODO: non-void ReplacedElement
1900 if (allChanges != nullptr) {
1901 OUStringBuffer path(
1902 getRelativePathRepresentation());
1903 if (!path.isEmpty()) {
1904 path.append('/');
1906 path.append(Data::createSegment(u"*", i.first));
1907 allChanges->push_back(
1908 css::util::ElementChange(
1909 css::uno::Any(path.makeStringAndClear()),
1910 css::uno::Any(), css::uno::Any()));
1911 //TODO: non-void ReplacedElement
1914 // else: spurious Modifications::Node not representing a change
1915 break;
1916 default:
1917 assert(false); // this cannot happen
1918 break;
1922 if (!propChanges.empty()) {
1923 css::uno::Sequence< css::beans::PropertyChangeEvent > seq(
1924 comphelper::containerToSequence(propChanges));
1925 for (auto const& propertyChangeListener : propertiesChangeListeners_)
1927 broadcaster->addPropertiesChangeNotification(propertyChangeListener, seq);
1933 Access::ModifiedChild::ModifiedChild():
1934 directlyModified(false)
1937 Access::ModifiedChild::ModifiedChild(
1938 rtl::Reference< ChildAccess > theChild, bool theDirectlyModified):
1939 child(std::move(theChild)), directlyModified(theDirectlyModified)
1942 rtl::Reference< ChildAccess > Access::getModifiedChild(
1943 ModifiedChildren::iterator const & childIterator)
1945 return (childIterator->second.child->getParentAccess() == this &&
1946 (childIterator->second.child->getNameInternal() ==
1947 childIterator->first))
1948 ? childIterator->second.child : rtl::Reference< ChildAccess >();
1951 rtl::Reference< ChildAccess > Access::createUnmodifiedChild(
1952 const OUString &name, const rtl::Reference< Node > &node)
1954 rtl::Reference child(
1955 new ChildAccess(components_, getRootAccess(), this, name, node));
1956 cachedChildren_[name] = child.get();
1957 return child;
1960 rtl::Reference< ChildAccess > Access::getUnmodifiedChild(
1961 OUString const & name)
1963 assert(modifiedChildren_.find(name) == modifiedChildren_.end());
1964 rtl::Reference< Node > node(getNode()->getMember(name));
1965 if (!node.is()) {
1966 return rtl::Reference< ChildAccess >();
1968 WeakChildMap::iterator i(cachedChildren_.find(name));
1969 if (i != cachedChildren_.end()) {
1970 rtl::Reference< ChildAccess > child;
1971 if (i->second->acquireCounting() > 1) {
1972 child.set(i->second); // must not throw
1974 i->second->releaseNondeleting();
1975 if (child.is()) {
1976 child->setNode(node);
1977 return child;
1980 return createUnmodifiedChild(name,node);
1983 rtl::Reference< ChildAccess > Access::getSubChild(OUString const & path) {
1984 sal_Int32 i = 0;
1985 // For backwards compatibility, allow absolute paths where meaningful:
1986 if( path.startsWith("/") ) {
1987 ++i;
1988 if (!getRootAccess().is()) {
1989 return rtl::Reference< ChildAccess >();
1991 std::vector<OUString> abs(getAbsolutePath());
1992 for (auto const& elem : abs)
1994 OUString name1;
1995 bool setElement1;
1996 OUString templateName1;
1997 i = Data::parseSegment(
1998 path, i, &name1, &setElement1, &templateName1);
1999 if (i == -1 || (i != path.getLength() && path[i] != '/')) {
2000 return rtl::Reference< ChildAccess >();
2002 OUString name2;
2003 bool setElement2;
2004 OUString templateName2;
2005 Data::parseSegment(elem, 0, &name2, &setElement2, &templateName2);
2006 if (name1 != name2 || setElement1 != setElement2 ||
2007 (setElement1 &&
2008 !Data::equalTemplateNames(templateName1, templateName2)))
2010 return rtl::Reference< ChildAccess >();
2012 if (i != path.getLength()) {
2013 ++i;
2017 for (rtl::Reference< Access > parent(this);;) {
2018 OUString name;
2019 bool setElement;
2020 OUString templateName;
2021 i = Data::parseSegment(path, i, &name, &setElement, &templateName);
2022 if (i == -1 || (i != path.getLength() && path[i] != '/')) {
2023 return rtl::Reference< ChildAccess >();
2025 rtl::Reference< ChildAccess > child(parent->getChild(name));
2026 if (!child.is()) {
2027 return rtl::Reference< ChildAccess >();
2029 if (setElement) {
2030 rtl::Reference< Node > p(parent->getNode());
2031 switch (p->kind()) {
2032 case Node::KIND_LOCALIZED_PROPERTY:
2033 if (!Components::allLocales(getRootAccess()->getLocale()) ||
2034 !templateName.isEmpty())
2036 return rtl::Reference< ChildAccess >();
2038 break;
2039 case Node::KIND_SET:
2040 if (!templateName.isEmpty() &&
2041 !static_cast< SetNode * >(p.get())->isValidTemplate(
2042 templateName))
2044 return rtl::Reference< ChildAccess >();
2046 break;
2047 default:
2048 return rtl::Reference< ChildAccess >();
2051 // For backwards compatibility, ignore a final slash after non-value
2052 // nodes:
2053 if (child->isValue()) {
2054 return i == path.getLength()
2055 ? child : rtl::Reference< ChildAccess >();
2056 } else if (i >= path.getLength() - 1) {
2057 return child;
2059 ++i;
2060 parent = child.get();
2064 bool Access::setChildProperty(
2065 OUString const & name, css::uno::Any const & value,
2066 Modifications * localModifications)
2068 assert(localModifications != nullptr);
2069 rtl::Reference< ChildAccess > child(getChild(name));
2070 if (!child.is()) {
2071 return false;
2073 child->checkFinalized();
2074 child->setProperty(value, localModifications);
2075 return true;
2078 css::beans::Property Access::asProperty() {
2079 css::uno::Type type;
2080 bool nillable;
2081 bool removable;
2082 rtl::Reference< Node > p(getNode());
2083 switch (p->kind()) {
2084 case Node::KIND_PROPERTY:
2086 PropertyNode * prop = static_cast< PropertyNode * >(p.get());
2087 type = mapType(prop->getStaticType());
2088 nillable = prop->isNillable();
2089 removable = prop->isExtension();
2091 break;
2092 case Node::KIND_LOCALIZED_PROPERTY:
2094 LocalizedPropertyNode * locprop =
2095 static_cast< LocalizedPropertyNode *>(p.get());
2096 if (Components::allLocales(getRootAccess()->getLocale())) {
2097 type = cppu::UnoType< css::uno::XInterface >::get();
2098 //TODO: correct?
2099 removable = false;
2100 } else {
2101 type = mapType(locprop->getStaticType());
2102 removable = false; //TODO ???
2104 nillable = locprop->isNillable();
2106 break;
2107 case Node::KIND_LOCALIZED_VALUE:
2109 LocalizedPropertyNode * locprop =
2110 static_cast< LocalizedPropertyNode * >(getParentNode().get());
2111 type = mapType(locprop->getStaticType());
2112 nillable = locprop->isNillable();
2113 removable = false; //TODO ???
2115 break;
2116 default:
2117 type = cppu::UnoType< css::uno::XInterface >::get(); //TODO: correct?
2118 nillable = false;
2119 rtl::Reference< Node > parent(getParentNode());
2120 removable = parent.is() && parent->kind() == Node::KIND_SET;
2121 break;
2123 return css::beans::Property(
2124 getNameInternal(), -1, type,
2125 (css::beans::PropertyAttribute::BOUND | //TODO: correct for group/set?
2126 css::beans::PropertyAttribute::CONSTRAINED |
2127 (nillable ? css::beans::PropertyAttribute::MAYBEVOID : 0) |
2128 (getRootAccess()->isUpdate() && removable
2129 ? css::beans::PropertyAttribute::REMOVABLE : 0) |
2130 (!getRootAccess()->isUpdate() || p->getFinalized() != Data::NO_LAYER
2131 ? css::beans::PropertyAttribute::READONLY : 0))); //TODO: MAYBEDEFAULT
2134 void Access::checkFinalized() {
2135 if (isFinalized()) {
2136 throw css::lang::IllegalArgumentException(
2137 "configmgr modification of finalized item",
2138 static_cast< cppu::OWeakObject * >(this), -1);
2142 void Access::checkKnownProperty(OUString const & descriptor) {
2143 if (descriptor.isEmpty()) {
2144 return;
2146 rtl::Reference< ChildAccess > child(getChild(descriptor));
2147 if (child.is()) {
2148 switch (child->getNode()->kind()) {
2149 case Node::KIND_PROPERTY:
2150 return;
2151 case Node::KIND_LOCALIZED_PROPERTY:
2152 if (!Components::allLocales(getRootAccess()->getLocale())) {
2153 return;
2155 break;
2156 case Node::KIND_LOCALIZED_VALUE:
2157 if (Components::allLocales(getRootAccess()->getLocale())) {
2158 return;
2160 break;
2161 default:
2162 break;
2165 throw css::beans::UnknownPropertyException(
2166 descriptor, static_cast< cppu::OWeakObject * >(this));
2169 rtl::Reference< ChildAccess > Access::getFreeSetMember(
2170 css::uno::Any const & value)
2172 css::uno::Reference<XInterface> xTmp;
2173 value >>= xTmp;
2174 rtl::Reference< ChildAccess > freeAcc = dynamic_cast<ChildAccess*>(xTmp.get());
2175 if (!freeAcc.is() || freeAcc->getParentAccess().is() ||
2176 (freeAcc->isInTransaction() &&
2177 freeAcc->getRootAccess() != getRootAccess()))
2179 throw css::lang::IllegalArgumentException(
2180 "configmgr inappropriate set element",
2181 static_cast< cppu::OWeakObject * >(this), 1);
2183 assert(dynamic_cast< SetNode * >(getNode().get()) != nullptr);
2184 if (!static_cast< SetNode * >(getNode().get())->isValidTemplate(
2185 freeAcc->getNode()->getTemplateName()))
2187 throw css::lang::IllegalArgumentException(
2188 "configmgr inappropriate set element",
2189 static_cast< cppu::OWeakObject * >(this), 1);
2191 return freeAcc;
2194 rtl::Reference< Access > Access::getNotificationRoot() {
2195 for (rtl::Reference< Access > p(this);;) {
2196 rtl::Reference< Access > parent(p->getParentAccess());
2197 if (!parent.is()) {
2198 return p;
2200 p = parent;
2204 #if !defined NDEBUG
2205 bool Access::thisIs(int what) {
2206 osl::MutexGuard g(*lock_);
2207 rtl::Reference< Node > p(getNode());
2208 Node::Kind k(p->kind());
2209 return (k != Node::KIND_PROPERTY && k != Node::KIND_LOCALIZED_VALUE &&
2210 ((what & IS_GROUP) == 0 || k == Node::KIND_GROUP) &&
2211 ((what & IS_SET) == 0 || k == Node::KIND_SET) &&
2212 ((what & IS_EXTENSIBLE) == 0 || k != Node::KIND_GROUP ||
2213 static_cast< GroupNode * >(p.get())->isExtensible()) &&
2214 ((what & IS_GROUP_MEMBER) == 0 ||
2215 getParentNode()->kind() == Node::KIND_GROUP)) ||
2216 ((what & IS_SET_MEMBER) == 0 ||
2217 getParentNode()->kind() == Node::KIND_SET) ||
2218 ((what & IS_UPDATE) == 0 || getRootAccess()->isUpdate());
2220 #endif
2224 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */