Version 6.4.0.3, tag libreoffice-6.4.0.3
[LibreOffice.git] / configmgr / source / access.cxx
blob9fe7f31cc00f2204d3d68289d30ca67c1241c0e7
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 <vector>
26 #include <com/sun/star/beans/Property.hpp>
27 #include <com/sun/star/beans/PropertyAttribute.hpp>
28 #include <com/sun/star/beans/PropertyChangeEvent.hpp>
29 #include <com/sun/star/beans/UnknownPropertyException.hpp>
30 #include <com/sun/star/beans/XExactName.hpp>
31 #include <com/sun/star/beans/XHierarchicalPropertySet.hpp>
32 #include <com/sun/star/beans/XHierarchicalPropertySetInfo.hpp>
33 #include <com/sun/star/beans/XMultiHierarchicalPropertySet.hpp>
34 #include <com/sun/star/beans/XMultiPropertySet.hpp>
35 #include <com/sun/star/beans/XPropertiesChangeListener.hpp>
36 #include <com/sun/star/beans/XProperty.hpp>
37 #include <com/sun/star/beans/XPropertyChangeListener.hpp>
38 #include <com/sun/star/beans/XPropertySet.hpp>
39 #include <com/sun/star/beans/XPropertySetInfo.hpp>
40 #include <com/sun/star/beans/XVetoableChangeListener.hpp>
41 #include <com/sun/star/container/ContainerEvent.hpp>
42 #include <com/sun/star/container/NoSuchElementException.hpp>
43 #include <com/sun/star/container/XContainer.hpp>
44 #include <com/sun/star/container/XContainerListener.hpp>
45 #include <com/sun/star/container/XElementAccess.hpp>
46 #include <com/sun/star/container/XHierarchicalName.hpp>
47 #include <com/sun/star/container/XHierarchicalNameAccess.hpp>
48 #include <com/sun/star/container/XHierarchicalNameReplace.hpp>
49 #include <com/sun/star/container/XNameAccess.hpp>
50 #include <com/sun/star/container/XNameContainer.hpp>
51 #include <com/sun/star/container/XNamed.hpp>
52 #include <com/sun/star/lang/DisposedException.hpp>
53 #include <com/sun/star/lang/EventObject.hpp>
54 #include <com/sun/star/lang/IllegalArgumentException.hpp>
55 #include <com/sun/star/lang/XComponent.hpp>
56 #include <com/sun/star/lang/XEventListener.hpp>
57 #include <com/sun/star/lang/XServiceInfo.hpp>
58 #include <com/sun/star/lang/XSingleServiceFactory.hpp>
59 #include <com/sun/star/lang/XTypeProvider.hpp>
60 #include <com/sun/star/lang/XUnoTunnel.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/lok.hxx>
71 #include <i18nlangtag/languagetag.hxx>
72 #include <cppu/unotype.hxx>
73 #include <cppuhelper/queryinterface.hxx>
74 #include <cppuhelper/supportsservice.hxx>
75 #include <cppuhelper/weak.hxx>
76 #include <osl/interlck.h>
77 #include <osl/mutex.hxx>
78 #include <rtl/character.hxx>
79 #include <rtl/ref.hxx>
80 #include <rtl/ustrbuf.hxx>
81 #include <rtl/ustring.hxx>
82 #include <sal/log.hxx>
83 #include <sal/types.h>
85 #include "access.hxx"
86 #include "broadcaster.hxx"
87 #include "childaccess.hxx"
88 #include "components.hxx"
89 #include "data.hxx"
90 #include "groupnode.hxx"
91 #include "localizedpropertynode.hxx"
92 #include "localizedvaluenode.hxx"
93 #include "lock.hxx"
94 #include "modifications.hxx"
95 #include "node.hxx"
96 #include "nodemap.hxx"
97 #include "propertynode.hxx"
98 #include "rootaccess.hxx"
99 #include "setnode.hxx"
100 #include "type.hxx"
102 namespace configmgr {
104 namespace {
106 // Conservatively forbid what is either not an XML Char (including lone
107 // surrogates, even though they should not appear in well-formed UNO OUString
108 // instances anyway), or is a slash (as it causes problems in path syntax):
109 bool isValidName(OUString const & name, bool setMember) {
110 for (sal_Int32 i = 0; i != name.getLength();) {
111 sal_uInt32 c = name.iterateCodePoints(&i);
112 if ((c < 0x20 && !(c == 0x09 || c == 0x0A || c == 0x0D))
113 || rtl::isSurrogate(c) || c == 0xFFFE || c == 0xFFFF
114 || (!setMember && c == '/'))
116 return false;
119 return !name.isEmpty();
124 oslInterlockedCount Access::acquireCounting() {
125 return osl_atomic_increment(&m_refCount);
128 void Access::releaseNondeleting() {
129 osl_atomic_decrement(&m_refCount);
132 bool Access::isValue() {
133 rtl::Reference< Node > p(getNode());
134 switch (p->kind()) {
135 case Node::KIND_PROPERTY:
136 case Node::KIND_LOCALIZED_VALUE:
137 return true;
138 case Node::KIND_LOCALIZED_PROPERTY:
139 return !Components::allLocales(getRootAccess()->getLocale());
140 default:
141 return false;
145 void Access::markChildAsModified(rtl::Reference< ChildAccess > const & child) {
146 assert(child.is() && child->getParentAccess() == this);
147 modifiedChildren_[child->getNameInternal()] = ModifiedChild(child, true);
148 for (rtl::Reference< Access > p(this);;) {
149 rtl::Reference< Access > parent(p->getParentAccess());
150 if (!parent.is()) {
151 break;
153 assert(dynamic_cast< ChildAccess * >(p.get()) != nullptr);
154 parent->modifiedChildren_.emplace(
155 p->getNameInternal(),
156 ModifiedChild(static_cast< ChildAccess * >(p.get()), false));
157 p = parent;
161 void Access::releaseChild(OUString const & name) {
162 cachedChildren_.erase(name);
165 void Access::initBroadcaster(
166 Modifications::Node const & modifications, Broadcaster * broadcaster)
168 initBroadcasterAndChanges(modifications, broadcaster, nullptr);
171 css::uno::Sequence< css::uno::Type > Access::getTypes()
173 assert(thisIs(IS_ANY));
174 osl::MutexGuard g(*lock_);
175 checkLocalizedPropertyAccess();
176 std::vector< css::uno::Type > types;
177 types.push_back(cppu::UnoType< css::uno::XInterface >::get());
178 types.push_back(cppu::UnoType< css::uno::XWeak >::get());
179 types.push_back(cppu::UnoType< css::lang::XTypeProvider >::get());
180 types.push_back(cppu::UnoType< css::lang::XServiceInfo >::get());
181 types.push_back(cppu::UnoType< css::lang::XComponent >::get());
182 types.push_back(cppu::UnoType< css::container::XContainer >::get());
183 types.push_back(cppu::UnoType< css::beans::XExactName >::get());
184 types.push_back(cppu::UnoType< css::container::XHierarchicalName >::get());
185 types.push_back(cppu::UnoType< css::container::XNamed >::get());
186 types.push_back(cppu::UnoType< css::beans::XProperty >::get());
187 types.push_back(cppu::UnoType< css::container::XElementAccess >::get());
188 types.push_back(cppu::UnoType< css::container::XNameAccess >::get());
189 if (getNode()->kind() == Node::KIND_GROUP) {
190 types.push_back(cppu::UnoType< css::beans::XPropertySetInfo >::get());
191 types.push_back(cppu::UnoType< css::beans::XPropertySet >::get());
192 types.push_back(cppu::UnoType< css::beans::XMultiPropertySet >::get());
193 types.push_back(
194 cppu::UnoType< css::beans::XHierarchicalPropertySet >::get());
195 types.push_back(
196 cppu::UnoType< css::beans::XMultiHierarchicalPropertySet >::get());
197 types.push_back(
198 cppu::UnoType< css::beans::XHierarchicalPropertySetInfo >::get());
200 if (getRootAccess()->isUpdate()) {
201 types.push_back(cppu::UnoType< css::container::XNameReplace >::get());
202 types.push_back(
203 cppu::UnoType< css::container::XHierarchicalNameReplace >::get());
204 if (getNode()->kind() != Node::KIND_GROUP ||
205 static_cast< GroupNode * >(getNode().get())->isExtensible())
207 types.push_back(
208 cppu::UnoType< css::container::XNameContainer >::get());
210 if (getNode()->kind() == Node::KIND_SET) {
211 types.push_back(
212 cppu::UnoType< css::lang::XSingleServiceFactory >::get());
214 } else {
215 types.push_back(
216 cppu::UnoType< css::container::XHierarchicalNameAccess >::get());
218 addTypes(&types);
219 return comphelper::containerToSequence(types);
222 css::uno::Sequence< sal_Int8 > Access::getImplementationId()
224 assert(thisIs(IS_ANY));
225 osl::MutexGuard g(*lock_);
226 checkLocalizedPropertyAccess();
227 return css::uno::Sequence< sal_Int8 >();
230 OUString Access::getImplementationName()
232 assert(thisIs(IS_ANY));
233 osl::MutexGuard g(*lock_);
234 checkLocalizedPropertyAccess();
235 return "org.openoffice-configmgr::Access";
238 sal_Bool Access::supportsService(OUString const & ServiceName)
240 return cppu::supportsService(this, ServiceName);
243 css::uno::Sequence< OUString > Access::getSupportedServiceNames()
245 assert(thisIs(IS_ANY));
246 osl::MutexGuard g(*lock_);
247 checkLocalizedPropertyAccess();
248 std::vector<OUString> services;
249 services.emplace_back("com.sun.star.configuration.ConfigurationAccess");
250 if (getRootAccess()->isUpdate()) {
251 services.emplace_back("com.sun.star.configuration.ConfigurationUpdateAccess");
253 services.emplace_back("com.sun.star.configuration.HierarchyAccess");
254 services.emplace_back("com.sun.star.configuration.HierarchyElement");
255 if (getNode()->kind() == Node::KIND_GROUP) {
256 services.emplace_back("com.sun.star.configuration.GroupAccess");
257 services.emplace_back("com.sun.star.configuration.PropertyHierarchy");
258 if (getRootAccess()->isUpdate()) {
259 services.emplace_back("com.sun.star.configuration.GroupUpdate");
261 } else {
262 services.emplace_back("com.sun.star.configuration.SetAccess");
263 services.emplace_back("com.sun.star.configuration.SimpleSetAccess");
264 if (getRootAccess()->isUpdate()) {
265 services.emplace_back("com.sun.star.configuration.SetUpdate");
266 services.emplace_back("com.sun.star.configuration.SimpleSetUpdate");
269 addSupportedServiceNames(&services);
270 return comphelper::containerToSequence(services);
273 void Access::dispose() {
274 assert(thisIs(IS_ANY));
275 Broadcaster bc;
277 osl::MutexGuard g(*lock_);
278 checkLocalizedPropertyAccess();
279 if (getParentAccess().is()) {
280 throw css::uno::RuntimeException(
281 "configmgr dispose inappropriate Access",
282 static_cast< cppu::OWeakObject * >(this));
284 if (disposed_) {
285 return;
287 initDisposeBroadcaster(&bc);
288 clearListeners();
289 disposed_ = true;
291 bc.send();
294 void Access::addEventListener(
295 css::uno::Reference< css::lang::XEventListener > const & xListener)
297 assert(thisIs(IS_ANY));
299 osl::MutexGuard g(*lock_);
300 checkLocalizedPropertyAccess();
301 if (!xListener.is()) {
302 throw css::uno::RuntimeException(
303 "null listener", static_cast< cppu::OWeakObject * >(this));
305 if (!disposed_) {
306 disposeListeners_.insert(xListener);
307 return;
310 try {
311 xListener->disposing(
312 css::lang::EventObject(static_cast< cppu::OWeakObject * >(this)));
313 } catch (css::lang::DisposedException &) {}
316 void Access::removeEventListener(
317 css::uno::Reference< css::lang::XEventListener > const & aListener)
319 assert(thisIs(IS_ANY));
320 osl::MutexGuard g(*lock_);
321 checkLocalizedPropertyAccess();
322 DisposeListeners::iterator i(disposeListeners_.find(aListener));
323 if (i != disposeListeners_.end()) {
324 disposeListeners_.erase(i);
328 css::uno::Type Access::getElementType() {
329 assert(thisIs(IS_ANY));
330 osl::MutexGuard g(*lock_);
331 checkLocalizedPropertyAccess();
332 rtl::Reference< Node > p(getNode());
333 switch (p->kind()) {
334 case Node::KIND_LOCALIZED_PROPERTY:
335 return mapType(
336 static_cast< LocalizedPropertyNode * >(p.get())->getStaticType());
337 case Node::KIND_GROUP:
338 //TODO: Should a specific type be returned for a non-extensible group
339 // with homogeneous members or for an extensible group that currently
340 // has only homogeneous members?
341 return cppu::UnoType<void>::get();
342 case Node::KIND_SET:
343 return cppu::UnoType<void>::get(); //TODO: correct?
344 default:
345 assert(false);
346 throw css::uno::RuntimeException(
347 "this cannot happen", static_cast< cppu::OWeakObject * >(this));
351 sal_Bool Access::hasElements() {
352 assert(thisIs(IS_ANY));
353 osl::MutexGuard g(*lock_);
354 checkLocalizedPropertyAccess();
355 return !getAllChildren().empty(); //TODO: optimize
358 bool Access::getByNameFast(const OUString & name, css::uno::Any & value)
360 bool bGotValue = false;
361 rtl::Reference< ChildAccess > child;
363 if (getNode()->kind() != Node::KIND_LOCALIZED_PROPERTY)
364 { // try to get it directly
365 ModifiedChildren::iterator i(modifiedChildren_.find(name));
366 if (i != modifiedChildren_.end())
368 child = getModifiedChild(i);
369 if (child.is())
371 value = child->asValue();
372 bGotValue = true;
375 else
377 rtl::Reference< Node > node(getNode()->getMember(name));
378 if (!node.is())
379 return false;
380 bGotValue = ChildAccess::asSimpleValue(node, value, components_);
384 if (!bGotValue)
386 child = getChild(name);
387 if (!child.is())
388 return false;
389 value = child->asValue();
391 return true;
394 css::uno::Any Access::getByName(OUString const & aName)
396 assert(thisIs(IS_ANY));
397 osl::MutexGuard g(*lock_);
398 checkLocalizedPropertyAccess();
399 css::uno::Any value;
400 if (!getByNameFast(aName, value))
401 throw css::container::NoSuchElementException(
402 aName, static_cast< cppu::OWeakObject * >(this));
403 return value;
406 css::uno::Sequence< OUString > Access::getElementNames()
408 assert(thisIs(IS_ANY));
409 osl::MutexGuard g(*lock_);
410 checkLocalizedPropertyAccess();
411 std::vector< rtl::Reference< ChildAccess > > children(getAllChildren());
412 std::vector<OUString> names;
413 names.reserve(children.size());
414 for (auto const& child : children)
416 names.push_back(child->getNameInternal());
418 return comphelper::containerToSequence(names);
421 sal_Bool Access::hasByName(OUString const & aName)
423 assert(thisIs(IS_ANY));
424 osl::MutexGuard g(*lock_);
425 checkLocalizedPropertyAccess();
426 return getChild(aName).is();
429 css::uno::Any Access::getByHierarchicalName(OUString const & aName)
431 assert(thisIs(IS_ANY));
432 osl::MutexGuard g(*lock_);
433 checkLocalizedPropertyAccess();
434 rtl::Reference< ChildAccess > child(getSubChild(aName));
435 if (!child.is()) {
436 throw css::container::NoSuchElementException(
437 aName, static_cast< cppu::OWeakObject * >(this));
439 return child->asValue();
442 sal_Bool Access::hasByHierarchicalName(OUString const & aName)
444 assert(thisIs(IS_ANY));
445 osl::MutexGuard g(*lock_);
446 checkLocalizedPropertyAccess();
447 return getSubChild(aName).is();
450 void Access::replaceByHierarchicalName(
451 OUString const & aName, css::uno::Any const & aElement)
453 //TODO: Actually support sets and combine with replaceByName:
454 assert(thisIs(IS_UPDATE));
455 Broadcaster bc;
457 osl::MutexGuard g(*lock_);
458 checkLocalizedPropertyAccess();
459 rtl::Reference< ChildAccess > child(getSubChild(aName));
460 if (!child.is()) {
461 throw css::container::NoSuchElementException(
462 aName, static_cast< cppu::OWeakObject * >(this));
464 child->checkFinalized();
465 rtl::Reference< Node > parent(child->getParentNode());
466 assert(parent.is());
467 Modifications localMods;
468 switch (parent->kind()) {
469 case Node::KIND_LOCALIZED_PROPERTY:
470 case Node::KIND_GROUP:
471 child->setProperty(aElement, &localMods);
472 break;
473 case Node::KIND_SET:
474 throw css::lang::IllegalArgumentException(
475 ("configmgr::Access::replaceByHierarchicalName does not"
476 " currently support set members"),
477 static_cast< cppu::OWeakObject * >(this), 0);
478 case Node::KIND_ROOT:
479 throw css::lang::IllegalArgumentException(
480 ("configmgr::Access::replaceByHierarchicalName does not allow"
481 " changing component " + aName),
482 static_cast< cppu::OWeakObject * >(this), 0);
483 default:
484 assert(false); // this cannot happen
485 break;
487 getNotificationRoot()->initBroadcaster(localMods.getRoot(), &bc);
489 bc.send();
492 void Access::addContainerListener(
493 css::uno::Reference< css::container::XContainerListener > const & xListener)
495 assert(thisIs(IS_ANY));
497 osl::MutexGuard g(*lock_);
498 checkLocalizedPropertyAccess();
499 if (!xListener.is()) {
500 throw css::uno::RuntimeException(
501 "null listener", static_cast< cppu::OWeakObject * >(this));
503 if (!disposed_) {
504 containerListeners_.insert(xListener);
505 return;
508 try {
509 xListener->disposing(
510 css::lang::EventObject(static_cast< cppu::OWeakObject * >(this)));
511 } catch (css::lang::DisposedException &) {}
514 void Access::removeContainerListener(
515 css::uno::Reference< css::container::XContainerListener > const & xListener)
517 assert(thisIs(IS_ANY));
518 osl::MutexGuard g(*lock_);
519 checkLocalizedPropertyAccess();
520 ContainerListeners::iterator i(containerListeners_.find(xListener));
521 if (i != containerListeners_.end()) {
522 containerListeners_.erase(i);
526 OUString Access::getExactName(OUString const & aApproximateName)
528 assert(thisIs(IS_ANY));
529 osl::MutexGuard g(*lock_);
530 checkLocalizedPropertyAccess();
531 return aApproximateName;
534 css::uno::Sequence< css::beans::Property > Access::getProperties()
536 assert(thisIs(IS_GROUP));
537 osl::MutexGuard g(*lock_);
538 std::vector< rtl::Reference< ChildAccess > > children(getAllChildren());
539 std::vector< css::beans::Property > properties;
540 properties.reserve(children.size());
541 for (auto const& child : children)
543 properties.push_back(child->asProperty());
545 return comphelper::containerToSequence(properties);
548 css::beans::Property Access::getPropertyByName(OUString const & aName)
550 assert(thisIs(IS_GROUP));
551 osl::MutexGuard g(*lock_);
552 rtl::Reference< ChildAccess > child(getChild(aName));
553 if (!child.is()) {
554 throw css::beans::UnknownPropertyException(
555 aName, static_cast< cppu::OWeakObject * >(this));
557 return child->asProperty();
560 sal_Bool Access::hasPropertyByName(OUString const & Name)
562 assert(thisIs(IS_GROUP));
563 osl::MutexGuard g(*lock_);
564 return getChild(Name).is();
567 OUString Access::getHierarchicalName() {
568 assert(thisIs(IS_ANY));
569 osl::MutexGuard g(*lock_);
570 checkLocalizedPropertyAccess();
571 // For backwards compatibility, return an absolute path representation where
572 // available:
573 OUString rootPath;
574 rtl::Reference< RootAccess > root(getRootAccess());
575 if (root.is()) {
576 rootPath = root->getAbsolutePathRepresentation();
578 OUString rel(getRelativePathRepresentation());
579 OUStringBuffer path(rootPath);
580 if (!rootPath.isEmpty() && rootPath != "/" && !rel.isEmpty()) {
581 path.append('/');
583 path.append(rel);
584 return path.makeStringAndClear();
587 OUString Access::composeHierarchicalName(
588 OUString const & aRelativeName)
590 assert(thisIs(IS_ANY));
591 osl::MutexGuard g(*lock_);
592 checkLocalizedPropertyAccess();
593 if (aRelativeName.isEmpty() || aRelativeName[0] == '/') {
594 throw css::lang::IllegalArgumentException(
595 "configmgr composeHierarchicalName inappropriate relative name",
596 static_cast< cppu::OWeakObject * >(this), -1);
598 OUStringBuffer path(getRelativePathRepresentation());
599 if (!path.isEmpty()) {
600 path.append('/');
602 path.append(aRelativeName);
603 return path.makeStringAndClear();
606 OUString Access::getName() {
607 assert(thisIs(IS_ANY));
608 osl::MutexGuard g(*lock_);
609 checkLocalizedPropertyAccess();
610 return getNameInternal();
613 void Access::setName(OUString const & aName)
615 assert(thisIs(IS_ANY));
616 Broadcaster bc;
618 osl::MutexGuard g(*lock_);
619 checkLocalizedPropertyAccess();
620 checkFinalized();
621 Modifications localMods;
622 switch (getNode()->kind()) {
623 case Node::KIND_GROUP:
624 case Node::KIND_SET:
626 rtl::Reference< Access > parent(getParentAccess());
627 if (parent.is()) {
628 rtl::Reference< Node > node(getNode());
629 if (! node->getTemplateName().isEmpty()) {
630 rtl::Reference< ChildAccess > other(
631 parent->getChild(aName));
632 if (other.get() == this) {
633 break;
635 if (node->getMandatory() == Data::NO_LAYER &&
636 !(other.is() && other->isFinalized()))
638 if (!isValidName(aName, true)) {
639 throw css::uno::RuntimeException(
640 "invalid element name " + aName);
642 rtl::Reference< RootAccess > root(getRootAccess());
643 rtl::Reference< ChildAccess > childAccess(
644 static_cast< ChildAccess * >(this));
645 localMods.add(getRelativePath());
646 // unbind() modifies the parent chain that
647 // markChildAsModified() walks, so order is
648 // important:
649 parent->markChildAsModified(childAccess);
650 //TODO: must not throw
651 childAccess->unbind(); // must not throw
652 if (other.is()) {
653 other->unbind(); // must not throw
655 childAccess->bind(root, parent, aName);
656 // must not throw
657 parent->markChildAsModified(childAccess);
658 //TODO: must not throw
659 localMods.add(getRelativePath());
660 break;
665 [[fallthrough]];
666 case Node::KIND_LOCALIZED_PROPERTY:
667 // renaming a property could only work for an extension property,
668 // but a localized property is never an extension property
669 throw css::uno::RuntimeException(
670 "configmgr setName inappropriate node",
671 static_cast< cppu::OWeakObject * >(this));
672 default:
673 assert(false); // this cannot happen
674 break;
676 getNotificationRoot()->initBroadcaster(localMods.getRoot(), &bc);
678 bc.send();
681 css::beans::Property Access::getAsProperty()
683 assert(thisIs(IS_ANY));
684 osl::MutexGuard g(*lock_);
685 checkLocalizedPropertyAccess();
686 return asProperty();
689 css::uno::Reference< css::beans::XPropertySetInfo > Access::getPropertySetInfo()
691 assert(thisIs(IS_GROUP));
692 return this;
695 void Access::setPropertyValue(
696 OUString const & aPropertyName, css::uno::Any const & aValue)
698 assert(thisIs(IS_GROUP));
699 Broadcaster bc;
701 osl::MutexGuard g(*lock_);
702 if (!getRootAccess()->isUpdate()) {
703 throw css::uno::RuntimeException(
704 "configmgr setPropertyValue on non-update access",
705 static_cast< cppu::OWeakObject * >(this));
707 Modifications localMods;
708 if (!setChildProperty(aPropertyName, aValue, &localMods)) {
709 throw css::beans::UnknownPropertyException(
710 aPropertyName, static_cast< cppu::OWeakObject * >(this));
712 getNotificationRoot()->initBroadcaster(localMods.getRoot(), &bc);
714 bc.send();
717 css::uno::Any Access::getPropertyValue(OUString const & PropertyName)
719 assert(thisIs(IS_GROUP));
720 osl::MutexGuard g(*lock_);
722 css::uno::Any value;
723 if (!getByNameFast(PropertyName, value))
724 throw css::beans::UnknownPropertyException(
725 PropertyName, static_cast< cppu::OWeakObject * >(this));
726 return value;
729 void Access::addPropertyChangeListener(
730 OUString const & aPropertyName,
731 css::uno::Reference< css::beans::XPropertyChangeListener > const &
732 xListener)
734 assert(thisIs(IS_GROUP));
736 osl::MutexGuard g(*lock_);
737 if (!xListener.is()) {
738 throw css::uno::RuntimeException(
739 "null listener", static_cast< cppu::OWeakObject * >(this));
741 checkKnownProperty(aPropertyName);
742 if (!disposed_) {
743 propertyChangeListeners_[aPropertyName].insert(xListener);
744 return;
747 try {
748 xListener->disposing(
749 css::lang::EventObject(static_cast< cppu::OWeakObject * >(this)));
750 } catch (css::lang::DisposedException &) {}
753 void Access::removePropertyChangeListener(
754 OUString const & aPropertyName,
755 css::uno::Reference< css::beans::XPropertyChangeListener > const &
756 aListener)
758 assert(thisIs(IS_GROUP));
759 osl::MutexGuard g(*lock_);
760 checkKnownProperty(aPropertyName);
761 PropertyChangeListeners::iterator i(
762 propertyChangeListeners_.find(aPropertyName));
763 if (i != propertyChangeListeners_.end()) {
764 PropertyChangeListenersElement::iterator j(i->second.find(aListener));
765 if (j != i->second.end()) {
766 i->second.erase(j);
767 if (i->second.empty()) {
768 propertyChangeListeners_.erase(i);
774 void Access::addVetoableChangeListener(
775 OUString const & PropertyName,
776 css::uno::Reference< css::beans::XVetoableChangeListener > const &
777 aListener)
779 assert(thisIs(IS_GROUP));
781 osl::MutexGuard g(*lock_);
782 if (!aListener.is()) {
783 throw css::uno::RuntimeException(
784 "null listener", static_cast< cppu::OWeakObject * >(this));
786 checkKnownProperty(PropertyName);
787 if (!disposed_) {
788 vetoableChangeListeners_[PropertyName].insert(aListener);
789 //TODO: actually call vetoableChangeListeners_
790 return;
793 try {
794 aListener->disposing(
795 css::lang::EventObject(static_cast< cppu::OWeakObject * >(this)));
796 } catch (css::lang::DisposedException &) {}
799 void Access::removeVetoableChangeListener(
800 OUString const & PropertyName,
801 css::uno::Reference< css::beans::XVetoableChangeListener > const &
802 aListener)
804 assert(thisIs(IS_GROUP));
805 osl::MutexGuard g(*lock_);
806 checkKnownProperty(PropertyName);
807 VetoableChangeListeners::iterator i(
808 vetoableChangeListeners_.find(PropertyName));
809 if (i != vetoableChangeListeners_.end()) {
810 VetoableChangeListenersElement::iterator j(i->second.find(aListener));
811 if (j != i->second.end()) {
812 i->second.erase(j);
813 if (i->second.empty()) {
814 vetoableChangeListeners_.erase(i);
820 void Access::setPropertyValues(
821 css::uno::Sequence< OUString > const & aPropertyNames,
822 css::uno::Sequence< css::uno::Any > const & aValues)
824 assert(thisIs(IS_GROUP));
825 Broadcaster bc;
827 osl::MutexGuard g(*lock_);
828 if (!getRootAccess()->isUpdate()) {
829 throw css::uno::RuntimeException(
830 "configmgr setPropertyValues on non-update access",
831 static_cast< cppu::OWeakObject * >(this));
833 if (aPropertyNames.getLength() != aValues.getLength()) {
834 throw css::lang::IllegalArgumentException(
835 ("configmgr setPropertyValues: aPropertyNames/aValues of"
836 " different length"),
837 static_cast< cppu::OWeakObject * >(this), -1);
839 Modifications localMods;
840 for (sal_Int32 i = 0; i < aPropertyNames.getLength(); ++i) {
841 if (!setChildProperty(aPropertyNames[i], aValues[i], &localMods)) {
842 throw css::lang::IllegalArgumentException(
843 "configmgr setPropertyValues inappropriate property name",
844 static_cast< cppu::OWeakObject * >(this), -1);
847 getNotificationRoot()->initBroadcaster(localMods.getRoot(), &bc);
849 bc.send();
852 css::uno::Sequence< css::uno::Any > Access::getPropertyValues(
853 css::uno::Sequence< OUString > const & aPropertyNames)
855 assert(thisIs(IS_GROUP));
856 osl::MutexGuard g(*lock_);
857 css::uno::Sequence< css::uno::Any > vals(aPropertyNames.getLength());
859 for (sal_Int32 i = 0; i < aPropertyNames.getLength(); ++i)
861 if (!getByNameFast(aPropertyNames[i], vals[i]))
862 throw css::uno::RuntimeException(
863 "configmgr getPropertyValues inappropriate property name",
864 static_cast< cppu::OWeakObject * >(this));
867 return vals;
870 void Access::addPropertiesChangeListener(
871 css::uno::Sequence< OUString > const &,
872 css::uno::Reference< css::beans::XPropertiesChangeListener > const &
873 xListener)
875 assert(thisIs(IS_GROUP));
877 osl::MutexGuard g(*lock_);
878 if (!xListener.is()) {
879 throw css::uno::RuntimeException(
880 "null listener", static_cast< cppu::OWeakObject * >(this));
882 if (!disposed_) {
883 propertiesChangeListeners_.insert(xListener);
884 return;
887 try {
888 xListener->disposing(
889 css::lang::EventObject(static_cast< cppu::OWeakObject * >(this)));
890 } catch (css::lang::DisposedException &) {}
893 void Access::removePropertiesChangeListener(
894 css::uno::Reference< css::beans::XPropertiesChangeListener > const &
895 xListener)
897 assert(thisIs(IS_GROUP));
898 osl::MutexGuard g(*lock_);
899 PropertiesChangeListeners::iterator i(
900 propertiesChangeListeners_.find(xListener));
901 if (i != propertiesChangeListeners_.end()) {
902 propertiesChangeListeners_.erase(i);
906 void Access::firePropertiesChangeEvent(
907 css::uno::Sequence< OUString > const & aPropertyNames,
908 css::uno::Reference< css::beans::XPropertiesChangeListener > const &
909 xListener)
911 assert(thisIs(IS_GROUP));
912 css::uno::Sequence< css::beans::PropertyChangeEvent > events(
913 aPropertyNames.getLength());
914 for (sal_Int32 i = 0; i < events.getLength(); ++i) {
915 events[i].Source = static_cast< cppu::OWeakObject * >(this);
916 events[i].PropertyName = aPropertyNames[i];
917 events[i].Further = false;
918 events[i].PropertyHandle = -1;
920 xListener->propertiesChange(events);
923 css::uno::Reference< css::beans::XHierarchicalPropertySetInfo >
924 Access::getHierarchicalPropertySetInfo() {
925 assert(thisIs(IS_GROUP));
926 return this;
929 void Access::setHierarchicalPropertyValue(
930 OUString const & aHierarchicalPropertyName,
931 css::uno::Any const & aValue)
933 assert(thisIs(IS_GROUP));
934 Broadcaster bc;
936 osl::MutexGuard g(*lock_);
937 if (!getRootAccess()->isUpdate()) {
938 throw css::uno::RuntimeException(
939 "configmgr setHierarchicalPropertyName on non-update access",
940 static_cast< cppu::OWeakObject * >(this));
942 rtl::Reference< ChildAccess > child(
943 getSubChild(aHierarchicalPropertyName));
944 if (!child.is()) {
945 throw css::beans::UnknownPropertyException(
946 aHierarchicalPropertyName,
947 static_cast< cppu::OWeakObject * >(this));
949 child->checkFinalized();
950 Modifications localMods;
951 child->setProperty(aValue, &localMods);
952 getNotificationRoot()->initBroadcaster(localMods.getRoot(), &bc);
954 bc.send();
957 css::uno::Any Access::getHierarchicalPropertyValue(
958 OUString const & aHierarchicalPropertyName)
960 assert(thisIs(IS_GROUP));
961 osl::MutexGuard g(*lock_);
962 rtl::Reference< ChildAccess > child(getSubChild(aHierarchicalPropertyName));
963 if (!child.is()) {
964 throw css::beans::UnknownPropertyException(
965 aHierarchicalPropertyName,
966 static_cast< cppu::OWeakObject * >(this));
968 return child->asValue();
971 void Access::setHierarchicalPropertyValues(
972 css::uno::Sequence< OUString > const & aHierarchicalPropertyNames,
973 css::uno::Sequence< css::uno::Any > const & Values)
975 assert(thisIs(IS_GROUP));
976 Broadcaster bc;
978 osl::MutexGuard g(*lock_);
979 if (!getRootAccess()->isUpdate()) {
980 throw css::uno::RuntimeException(
981 "configmgr setPropertyValues on non-update access",
982 static_cast< cppu::OWeakObject * >(this));
984 if (aHierarchicalPropertyNames.getLength() != Values.getLength()) {
985 throw css::lang::IllegalArgumentException(
986 ("configmgr setHierarchicalPropertyValues:"
987 " aHierarchicalPropertyNames/Values of different length"),
988 static_cast< cppu::OWeakObject * >(this), -1);
990 Modifications localMods;
991 for (sal_Int32 i = 0; i < aHierarchicalPropertyNames.getLength(); ++i) {
992 rtl::Reference< ChildAccess > child(
993 getSubChild(aHierarchicalPropertyNames[i]));
994 if (!child.is()) {
995 throw css::lang::IllegalArgumentException(
996 ("configmgr setHierarchicalPropertyValues inappropriate"
997 " property name"),
998 static_cast< cppu::OWeakObject * >(this), -1);
1000 child->checkFinalized();
1001 child->setProperty(Values[i], &localMods);
1003 getNotificationRoot()->initBroadcaster(localMods.getRoot(), &bc);
1005 bc.send();
1008 css::uno::Sequence< css::uno::Any > Access::getHierarchicalPropertyValues(
1009 css::uno::Sequence< OUString > const & aHierarchicalPropertyNames)
1011 assert(thisIs(IS_GROUP));
1012 osl::MutexGuard g(*lock_);
1013 css::uno::Sequence< css::uno::Any > vals(
1014 aHierarchicalPropertyNames.getLength());
1015 for (sal_Int32 i = 0; i < aHierarchicalPropertyNames.getLength(); ++i) {
1016 rtl::Reference< ChildAccess > child(
1017 getSubChild(aHierarchicalPropertyNames[i]));
1018 if (!child.is()) {
1019 throw css::lang::IllegalArgumentException(
1020 ("configmgr getHierarchicalPropertyValues inappropriate"
1021 " hierarchical property name"),
1022 static_cast< cppu::OWeakObject * >(this), -1);
1024 vals[i] = child->asValue();
1026 return vals;
1029 css::beans::Property Access::getPropertyByHierarchicalName(
1030 OUString const & aHierarchicalName)
1032 assert(thisIs(IS_GROUP));
1033 osl::MutexGuard g(*lock_);
1034 rtl::Reference< ChildAccess > child(getSubChild(aHierarchicalName));
1035 if (!child.is()) {
1036 throw css::beans::UnknownPropertyException(
1037 aHierarchicalName, static_cast< cppu::OWeakObject * >(this));
1039 return child->asProperty();
1042 sal_Bool Access::hasPropertyByHierarchicalName(
1043 OUString const & aHierarchicalName)
1045 assert(thisIs(IS_GROUP));
1046 osl::MutexGuard g(*lock_);
1047 return getSubChild(aHierarchicalName).is();
1050 void Access::replaceByName(
1051 OUString const & aName, css::uno::Any const & aElement)
1053 assert(thisIs(IS_UPDATE));
1054 Broadcaster bc;
1056 osl::MutexGuard g(*lock_);
1057 checkLocalizedPropertyAccess();
1058 rtl::Reference< ChildAccess > child(getChild(aName));
1059 if (!child.is()) {
1060 throw css::container::NoSuchElementException(
1061 aName, static_cast< cppu::OWeakObject * >(this));
1063 child->checkFinalized();
1064 Modifications localMods;
1065 switch (getNode()->kind()) {
1066 case Node::KIND_LOCALIZED_PROPERTY:
1067 case Node::KIND_GROUP:
1068 child->setProperty(aElement, &localMods);
1069 break;
1070 case Node::KIND_SET:
1072 rtl::Reference< ChildAccess > freeAcc(
1073 getFreeSetMember(aElement));
1074 rtl::Reference< RootAccess > root(getRootAccess());
1075 localMods.add(child->getRelativePath());
1076 child->unbind(); // must not throw
1077 freeAcc->bind(root, this, aName); // must not throw
1078 markChildAsModified(freeAcc); //TODO: must not throw
1080 break;
1081 default:
1082 assert(false); // this cannot happen
1083 break;
1085 getNotificationRoot()->initBroadcaster(localMods.getRoot(), &bc);
1087 bc.send();
1090 void Access::insertByName(
1091 OUString const & aName, css::uno::Any const & aElement)
1093 assert(thisIs(IS_EXTENSIBLE|IS_UPDATE));
1094 Broadcaster bc;
1096 osl::MutexGuard g(*lock_);
1097 checkLocalizedPropertyAccess();
1098 checkFinalized();
1099 if (getChild(aName).is()) {
1100 throw css::container::ElementExistException(
1101 aName, static_cast< cppu::OWeakObject * >(this));
1103 Modifications localMods;
1104 switch (getNode()->kind()) {
1105 case Node::KIND_LOCALIZED_PROPERTY:
1106 if (!isValidName(aName, false)) {
1107 throw css::lang::IllegalArgumentException(
1108 aName, static_cast<cppu::OWeakObject *>(this), 0);
1110 insertLocalizedValueChild(aName, aElement, &localMods);
1111 break;
1112 case Node::KIND_GROUP:
1114 if (!isValidName(aName, false)) {
1115 throw css::lang::IllegalArgumentException(
1116 aName, static_cast<cppu::OWeakObject *>(this), 0);
1118 checkValue(aElement, TYPE_ANY, true);
1119 rtl::Reference child(
1120 new ChildAccess(
1121 components_, getRootAccess(), this, aName,
1122 new PropertyNode(
1123 Data::NO_LAYER, TYPE_ANY, true, aElement, true)));
1124 markChildAsModified(child);
1125 localMods.add(child->getRelativePath());
1127 break;
1128 case Node::KIND_SET:
1130 if (!isValidName(aName, true)) {
1131 throw css::lang::IllegalArgumentException(
1132 aName, static_cast<cppu::OWeakObject *>(this), 0);
1134 rtl::Reference< ChildAccess > freeAcc(
1135 getFreeSetMember(aElement));
1136 freeAcc->bind(getRootAccess(), this, aName); // must not throw
1137 markChildAsModified(freeAcc); //TODO: must not throw
1138 localMods.add(freeAcc->getRelativePath());
1140 break;
1141 default:
1142 assert(false); // this cannot happen
1143 break;
1145 getNotificationRoot()->initBroadcaster(localMods.getRoot(), &bc);
1147 bc.send();
1150 void Access::removeByName(OUString const & aName)
1152 assert(thisIs(IS_EXTENSIBLE|IS_UPDATE));
1153 Broadcaster bc;
1155 osl::MutexGuard g(*lock_);
1156 checkLocalizedPropertyAccess();
1157 rtl::Reference< ChildAccess > child(getChild(aName));
1158 if (!child.is() || child->isFinalized() ||
1159 child->getNode()->getMandatory() != Data::NO_LAYER)
1161 throw css::container::NoSuchElementException(
1162 aName, static_cast< cppu::OWeakObject * >(this));
1164 if (getNode()->kind() == Node::KIND_GROUP) {
1165 rtl::Reference< Node > p(child->getNode());
1166 if (p->kind() != Node::KIND_PROPERTY ||
1167 !static_cast< PropertyNode * >(p.get())->isExtension())
1169 throw css::container::NoSuchElementException(
1170 aName, static_cast< cppu::OWeakObject * >(this));
1173 Modifications localMods;
1174 localMods.add(child->getRelativePath());
1175 // unbind() modifies the parent chain that markChildAsModified() walks,
1176 // so order is important:
1177 markChildAsModified(child); //TODO: must not throw
1178 child->unbind();
1179 getNotificationRoot()->initBroadcaster(localMods.getRoot(), &bc);
1181 bc.send();
1184 css::uno::Reference< css::uno::XInterface > Access::createInstance()
1186 assert(thisIs(IS_SET|IS_UPDATE));
1187 OUString tmplName(
1188 static_cast< SetNode * >(getNode().get())->getDefaultTemplateName());
1189 rtl::Reference< Node > tmpl(
1190 components_.getTemplate(tmplName));
1191 if (!tmpl.is()) {
1192 throw css::uno::Exception(
1193 "unknown template " + tmplName,
1194 static_cast< cppu::OWeakObject * >(this));
1196 rtl::Reference< Node > node(tmpl->clone(true));
1197 node->setLayer(Data::NO_LAYER);
1198 return static_cast< cppu::OWeakObject * >(
1199 new ChildAccess(components_, getRootAccess(), node));
1202 css::uno::Reference< css::uno::XInterface > Access::createInstanceWithArguments(
1203 css::uno::Sequence< css::uno::Any > const & aArguments)
1205 assert(thisIs(IS_SET|IS_UPDATE));
1206 if (aArguments.hasElements()) {
1207 throw css::uno::Exception(
1208 ("configuration SimpleSetUpdate createInstanceWithArguments"
1209 " must not specify any arguments"),
1210 static_cast< cppu::OWeakObject * >(this));
1212 return createInstance();
1215 Access::Access(Components & components):
1216 components_(components), disposed_(false), lock_( lock() )
1220 Access::~Access() {}
1222 void Access::initDisposeBroadcaster(Broadcaster * broadcaster) {
1223 assert(broadcaster != nullptr);
1224 for (auto const& disposeListener : disposeListeners_)
1226 broadcaster->addDisposeNotification(
1227 disposeListener,
1228 css::lang::EventObject(static_cast< cppu::OWeakObject * >(this)));
1230 for (auto const& containerListener : containerListeners_)
1232 broadcaster->addDisposeNotification(
1233 containerListener.get(),
1234 css::lang::EventObject(static_cast< cppu::OWeakObject * >(this)));
1236 for (auto const& propertyChangeListener : propertyChangeListeners_)
1238 for (auto const& propertyChangeListenerElement : propertyChangeListener.second)
1240 broadcaster->addDisposeNotification(
1241 propertyChangeListenerElement.get(),
1242 css::lang::EventObject(
1243 static_cast< cppu::OWeakObject * >(this)));
1246 for (auto const& vetoableChangeListener : vetoableChangeListeners_)
1248 for (auto const& vetoableChangeListenerElement : vetoableChangeListener.second)
1250 broadcaster->addDisposeNotification(
1251 vetoableChangeListenerElement.get(),
1252 css::lang::EventObject(
1253 static_cast< cppu::OWeakObject * >(this)));
1256 for (auto const& propertiesChangeListener : propertiesChangeListeners_)
1258 broadcaster->addDisposeNotification(
1259 propertiesChangeListener.get(),
1260 css::lang::EventObject(static_cast< cppu::OWeakObject * >(this)));
1262 //TODO: iterate over children w/ listeners (incl. unmodified ones):
1263 for (ModifiedChildren::iterator i(modifiedChildren_.begin());
1264 i != modifiedChildren_.end(); ++i)
1266 rtl::Reference< ChildAccess > child(getModifiedChild(i));
1267 if (child.is()) {
1268 child->initDisposeBroadcaster(broadcaster);
1273 void Access::clearListeners() throw() {
1274 disposeListeners_.clear();
1275 containerListeners_.clear();
1276 propertyChangeListeners_.clear();
1277 vetoableChangeListeners_.clear();
1278 propertiesChangeListeners_.clear();
1279 //TODO: iterate over children w/ listeners (incl. unmodified ones):
1280 for (ModifiedChildren::iterator i(modifiedChildren_.begin());
1281 i != modifiedChildren_.end(); ++i)
1283 rtl::Reference< ChildAccess > child(getModifiedChild(i));
1284 if (child.is()) {
1285 child->clearListeners();
1290 css::uno::Any Access::queryInterface(css::uno::Type const & aType)
1292 css::uno::Any res(OWeakObject::queryInterface(aType));
1293 if (res.hasValue()) {
1294 return res;
1296 res = cppu::queryInterface(
1297 aType, static_cast< css::lang::XTypeProvider * >(this),
1298 static_cast< css::lang::XServiceInfo * >(this),
1299 static_cast< css::lang::XComponent * >(this),
1300 static_cast< css::container::XHierarchicalNameAccess * >(this),
1301 static_cast< css::container::XContainer * >(this),
1302 static_cast< css::beans::XExactName * >(this),
1303 static_cast< css::container::XHierarchicalName * >(this),
1304 static_cast< css::container::XNamed * >(this),
1305 static_cast< css::beans::XProperty * >(this),
1306 static_cast< css::container::XElementAccess * >(this),
1307 static_cast< css::container::XNameAccess * >(this));
1308 if (res.hasValue()) {
1309 return res;
1311 if (getNode()->kind() == Node::KIND_GROUP) {
1312 res = cppu::queryInterface(
1313 aType, static_cast< css::beans::XPropertySetInfo * >(this),
1314 static_cast< css::beans::XPropertySet * >(this),
1315 static_cast< css::beans::XMultiPropertySet * >(this),
1316 static_cast< css::beans::XHierarchicalPropertySet * >(this),
1317 static_cast< css::beans::XMultiHierarchicalPropertySet * >(this),
1318 static_cast< css::beans::XHierarchicalPropertySetInfo * >(this));
1319 if (res.hasValue()) {
1320 return res;
1323 if (getRootAccess()->isUpdate()) {
1324 res = cppu::queryInterface(
1325 aType, static_cast< css::container::XNameReplace * >(this),
1326 static_cast< css::container::XHierarchicalNameReplace * >(this));
1327 if (res.hasValue()) {
1328 return res;
1330 if (getNode()->kind() != Node::KIND_GROUP ||
1331 static_cast< GroupNode * >(getNode().get())->isExtensible())
1333 res = cppu::queryInterface(
1334 aType, static_cast< css::container::XNameContainer * >(this));
1335 if (res.hasValue()) {
1336 return res;
1339 if (getNode()->kind() == Node::KIND_SET) {
1340 res = cppu::queryInterface(
1341 aType, static_cast< css::lang::XSingleServiceFactory * >(this));
1344 return res;
1348 void Access::checkLocalizedPropertyAccess() {
1349 if (getNode()->kind() == Node::KIND_LOCALIZED_PROPERTY &&
1350 !Components::allLocales(getRootAccess()->getLocale()))
1352 throw css::uno::RuntimeException(
1353 "configmgr Access to specialized LocalizedPropertyNode",
1354 static_cast< cppu::OWeakObject * >(this));
1358 rtl::Reference< Node > Access::getParentNode() {
1359 rtl::Reference< Access > parent(getParentAccess());
1360 return parent.is() ? parent->getNode() : rtl::Reference< Node >();
1363 rtl::Reference< ChildAccess > Access::getChild(OUString const & name) {
1364 OUString locale;
1365 if (getNode()->kind() == Node::KIND_LOCALIZED_PROPERTY
1366 && name.startsWith("*", &locale))
1368 if (locale.startsWith("*")) {
1369 SAL_WARN(
1370 "configmgr",
1371 ("access best-matching localized property value via"
1372 " \"*<locale>\" with <locale> \"")
1373 << locale << "\" recursively starting with \"*\"");
1374 return getChild(locale);
1376 SAL_WARN_IF(
1377 locale.isEmpty(), "configmgr",
1378 ("access best-matching localized property value via \"*<locale>\""
1379 " with empty <locale>; falling back to defaults"));
1381 // Since the locale given to us is the one used at initialization,
1382 // here we override it with the actual current-user's language to
1383 // support per-view localization in LOK.
1384 if (comphelper::LibreOfficeKit::isActive())
1385 locale = comphelper::LibreOfficeKit::getLanguageTag().getLanguage();
1387 if (!locale.isEmpty()) {
1388 // Find best match using an adaptation of RFC 4647 lookup matching
1389 // rules, removing "-" or "_" delimited segments from the end:
1390 for (;;) {
1391 rtl::Reference< ChildAccess > child(getChild(locale));
1392 if (child.is()) {
1393 return child;
1395 sal_Int32 i = locale.getLength() - 1;
1396 while (i > 0 && locale[i] != '-' && locale[i] != '_') {
1397 --i;
1399 if (i <= 0) {
1400 break;
1402 locale = locale.copy(0, i);
1404 // As a workaround for broken xcu data that does not use shortest
1405 // xml:lang attributes, look for the first entry with the same first
1406 // segment as the requested language tag before falling back to
1407 // defaults (see fdo#33638):
1408 assert(
1409 !locale.isEmpty() && locale.indexOf('-') == -1 &&
1410 locale.indexOf('_') == -1);
1411 std::vector< rtl::Reference< ChildAccess > > children(
1412 getAllChildren());
1413 for (auto const& child : children)
1415 OUString name2(child->getNameInternal());
1416 if (name2.startsWith(locale) &&
1417 (name2.getLength() == locale.getLength() ||
1418 name2[locale.getLength()] == '-' ||
1419 name2[locale.getLength()] == '_'))
1421 return child;
1425 // Defaults are the "en-US" locale, the "en" locale, the empty string locale, the first child (if
1426 // any, and if the property is non-nillable), or a null ChildAccess, in that order:
1427 rtl::Reference< ChildAccess > child(getChild("en-US"));
1428 if (child.is()) {
1429 return child;
1431 child = getChild("en");
1432 if (child.is()) {
1433 return child;
1435 child = getChild("");
1436 if (child.is()) {
1437 return child;
1439 if (!static_cast<LocalizedPropertyNode *>(getNode().get())->isNillable()) {
1440 std::vector< rtl::Reference< ChildAccess > > children(getAllChildren());
1441 if (!children.empty()) {
1442 return children.front();
1445 return rtl::Reference< ChildAccess >();
1447 ModifiedChildren::iterator i(modifiedChildren_.find(name));
1448 return i == modifiedChildren_.end()
1449 ? getUnmodifiedChild(name) : getModifiedChild(i);
1452 std::vector< rtl::Reference< ChildAccess > > Access::getAllChildren() {
1453 std::vector< rtl::Reference< ChildAccess > > vec;
1454 NodeMap const & members = getNode()->getMembers();
1455 for (auto const& member : members)
1457 if (modifiedChildren_.find(member.first) == modifiedChildren_.end()) {
1458 vec.push_back(getUnmodifiedChild(member.first));
1459 assert(vec.back().is());
1462 for (ModifiedChildren::iterator i(modifiedChildren_.begin());
1463 i != modifiedChildren_.end(); ++i)
1465 rtl::Reference< ChildAccess > child(getModifiedChild(i));
1466 if (child.is()) {
1467 vec.push_back(child);
1470 return vec;
1473 void Access::checkValue(css::uno::Any const & value, Type type, bool nillable) {
1474 bool ok;
1475 switch (type) {
1476 case TYPE_ERROR:
1477 ok = false;
1478 break;
1479 case TYPE_ANY:
1480 switch (getDynamicType(value)) {
1481 case TYPE_ERROR:
1482 ok = false;
1483 break;
1484 case TYPE_NIL:
1485 ok = nillable;
1486 break;
1487 default:
1488 ok = true;
1489 break;
1490 case TYPE_ANY:
1491 for (;;) std::abort(); // cannot happen
1493 break;
1494 default:
1495 ok = value.hasValue() ? value.isExtractableTo(mapType(type)) : nillable;
1496 break;
1497 case TYPE_NIL:
1498 for (;;) std::abort(); // cannot happen
1500 if (!ok) {
1501 throw css::lang::IllegalArgumentException(
1502 "configmgr inappropriate property value",
1503 static_cast< cppu::OWeakObject * >(this), -1);
1507 void Access::insertLocalizedValueChild(
1508 OUString const & name, css::uno::Any const & value,
1509 Modifications * localModifications)
1511 assert(localModifications != nullptr);
1512 LocalizedPropertyNode * locprop = static_cast< LocalizedPropertyNode * >(
1513 getNode().get());
1514 checkValue(value, locprop->getStaticType(), locprop->isNillable());
1515 rtl::Reference child(
1516 new ChildAccess(
1517 components_, getRootAccess(), this, name,
1518 new LocalizedValueNode(Data::NO_LAYER, value)));
1519 markChildAsModified(child);
1520 localModifications->add(child->getRelativePath());
1523 void Access::reportChildChanges(
1524 std::vector< css::util::ElementChange > * changes)
1526 assert(changes != nullptr);
1527 for (ModifiedChildren::iterator i(modifiedChildren_.begin());
1528 i != modifiedChildren_.end(); ++i)
1530 rtl::Reference< ChildAccess > child(getModifiedChild(i));
1531 if (child.is()) {
1532 child->reportChildChanges(changes);
1533 changes->push_back(css::util::ElementChange());
1534 //TODO: changed value and/or inserted node
1535 } else {
1536 changes->push_back(css::util::ElementChange()); //TODO: removed node
1541 void Access::commitChildChanges(
1542 bool valid, Modifications * globalModifications)
1544 assert(globalModifications != nullptr);
1545 while (!modifiedChildren_.empty()) {
1546 bool childValid = valid;
1547 ModifiedChildren::iterator i(modifiedChildren_.begin());
1548 rtl::Reference< ChildAccess > child(getModifiedChild(i));
1549 if (child.is()) {
1550 childValid = childValid && !child->isFinalized();
1551 child->commitChanges(childValid, globalModifications);
1552 //TODO: currently, this is called here for directly inserted
1553 // children as well as for children whose sub-children were
1554 // modified (and should never be called for directly removed
1555 // children); clarify what exactly should happen here for
1556 // directly inserted children
1558 NodeMap & members = getNode()->getMembers();
1559 NodeMap::iterator j(members.find(i->first));
1560 if (child.is()) {
1561 // Inserted:
1562 if (j != members.end()) {
1563 childValid = childValid &&
1564 j->second->getFinalized() == Data::NO_LAYER;
1565 if (childValid) {
1566 child->getNode()->setMandatory(j->second->getMandatory());
1569 if (childValid) {
1570 members[i->first] = child->getNode();
1572 } else {
1573 // Removed:
1574 childValid = childValid && j != members.end() &&
1575 j->second->getFinalized() == Data::NO_LAYER &&
1576 j->second->getMandatory() == Data::NO_LAYER;
1577 if (childValid) {
1578 members.erase(j);
1581 if (childValid && i->second.directlyModified) {
1582 std::vector<OUString> path(getAbsolutePath());
1583 path.push_back(i->first);
1584 components_.addModification(path);
1585 globalModifications->add(path);
1587 i->second.child->committed();
1588 modifiedChildren_.erase(i);
1592 void Access::initBroadcasterAndChanges(
1593 Modifications::Node const & modifications, Broadcaster * broadcaster,
1594 std::vector< css::util::ElementChange > * allChanges)
1596 assert(broadcaster != nullptr);
1597 std::vector< css::beans::PropertyChangeEvent > propChanges;
1598 bool collectPropChanges = !propertiesChangeListeners_.empty();
1599 for (const auto & i : modifications.children)
1601 rtl::Reference< ChildAccess > child(getChild(i.first));
1602 if (child.is()) {
1603 switch (child->getNode()->kind()) {
1604 case Node::KIND_LOCALIZED_PROPERTY:
1605 if (!i.second.children.empty()) {
1606 if (Components::allLocales(getRootAccess()->getLocale())) {
1607 child->initBroadcasterAndChanges(
1608 i.second, broadcaster, allChanges);
1609 //TODO: if allChanges==0, recurse only into children
1610 // w/ listeners
1611 } else {
1612 //TODO: filter child mods that are irrelevant for
1613 // locale:
1614 for (auto const& containerListener : containerListeners_)
1616 broadcaster->
1617 addContainerElementReplacedNotification(
1618 containerListener,
1619 css::container::ContainerEvent(
1620 static_cast< cppu::OWeakObject * >(
1621 this),
1622 css::uno::Any(i.first),
1623 css::uno::Any(), css::uno::Any()));
1624 //TODO: non-void Element, ReplacedElement
1626 PropertyChangeListeners::iterator j(
1627 propertyChangeListeners_.find(i.first));
1628 if (j != propertyChangeListeners_.end()) {
1629 for (auto const& propertyChangeListenerElement : j->second)
1631 broadcaster->addPropertyChangeNotification(
1632 propertyChangeListenerElement,
1633 css::beans::PropertyChangeEvent(
1634 static_cast< cppu::OWeakObject * >(
1635 this),
1636 i.first, false, -1, css::uno::Any(),
1637 css::uno::Any()));
1640 j = propertyChangeListeners_.find("");
1641 if (j != propertyChangeListeners_.end()) {
1642 for (auto const& propertyChangeListenerElement : j->second)
1644 broadcaster->addPropertyChangeNotification(
1645 propertyChangeListenerElement,
1646 css::beans::PropertyChangeEvent(
1647 static_cast< cppu::OWeakObject * >(
1648 this),
1649 i.first, false, -1, css::uno::Any(),
1650 css::uno::Any()));
1653 if (allChanges != nullptr) {
1654 allChanges->push_back(
1655 css::util::ElementChange(
1656 css::uno::Any(
1657 child->getRelativePathRepresentation()),
1658 css::uno::Any(), css::uno::Any()));
1659 //TODO: non-void Element, ReplacedElement
1661 if (collectPropChanges) {
1662 propChanges.emplace_back(
1663 static_cast< cppu::OWeakObject * >(this),
1664 i.first, false, -1, css::uno::Any(),
1665 css::uno::Any());
1669 // else: spurious Modifications::Node not representing a change
1670 break;
1671 case Node::KIND_LOCALIZED_VALUE:
1672 assert(Components::allLocales(getRootAccess()->getLocale()));
1673 for (auto const& containerListener : containerListeners_)
1675 broadcaster->addContainerElementReplacedNotification(
1676 containerListener,
1677 css::container::ContainerEvent(
1678 static_cast< cppu::OWeakObject * >(this),
1679 css::uno::Any(i.first), child->asValue(),
1680 css::uno::Any()));
1681 //TODO: distinguish add/modify; non-void ReplacedElement
1683 if (allChanges != nullptr) {
1684 allChanges->push_back(
1685 css::util::ElementChange(
1686 css::uno::Any(
1687 child->getRelativePathRepresentation()),
1688 child->asValue(), css::uno::Any()));
1689 //TODO: non-void ReplacedElement
1691 assert(!collectPropChanges);
1692 break;
1693 case Node::KIND_PROPERTY:
1695 for (auto const& containerListener : containerListeners_)
1697 broadcaster->addContainerElementReplacedNotification(
1698 containerListener,
1699 css::container::ContainerEvent(
1700 static_cast< cppu::OWeakObject * >(this),
1701 css::uno::Any(i.first), child->asValue(),
1702 css::uno::Any()));
1703 //TODO: distinguish add/remove/modify; non-void
1704 // ReplacedElement
1706 PropertyChangeListeners::iterator j(
1707 propertyChangeListeners_.find(i.first));
1708 if (j != propertyChangeListeners_.end()) {
1709 for (auto const& propertyChangeListenerElement : j->second)
1711 broadcaster->addPropertyChangeNotification(
1712 propertyChangeListenerElement,
1713 css::beans::PropertyChangeEvent(
1714 static_cast< cppu::OWeakObject * >(this),
1715 i.first, false, -1, css::uno::Any(),
1716 css::uno::Any()));
1719 j = propertyChangeListeners_.find("");
1720 if (j != propertyChangeListeners_.end()) {
1721 for (auto const& propertyChangeListenerElement : j->second)
1723 broadcaster->addPropertyChangeNotification(
1724 propertyChangeListenerElement,
1725 css::beans::PropertyChangeEvent(
1726 static_cast< cppu::OWeakObject * >(this),
1727 i.first, false, -1, css::uno::Any(),
1728 css::uno::Any()));
1731 if (allChanges != nullptr) {
1732 allChanges->push_back(
1733 css::util::ElementChange(
1734 css::uno::Any(
1735 child->getRelativePathRepresentation()),
1736 child->asValue(), css::uno::Any()));
1737 //TODO: non-void ReplacedElement
1739 if (collectPropChanges) {
1740 propChanges.emplace_back(
1741 static_cast< cppu::OWeakObject * >(this),
1742 i.first, false, -1, css::uno::Any(),
1743 css::uno::Any());
1746 break;
1747 case Node::KIND_GROUP:
1748 case Node::KIND_SET:
1749 if (i.second.children.empty()) {
1750 if (!child->getNode()->getTemplateName().isEmpty()) {
1751 for (auto const& containerListener : containerListeners_)
1753 broadcaster->
1754 addContainerElementInsertedNotification(
1755 containerListener,
1756 css::container::ContainerEvent(
1757 static_cast< cppu::OWeakObject * >(
1758 this),
1759 css::uno::Any(i.first),
1760 child->asValue(), css::uno::Any()));
1762 if (allChanges != nullptr) {
1763 allChanges->push_back(
1764 css::util::ElementChange(
1765 css::uno::Any(
1766 child->getRelativePathRepresentation()),
1767 css::uno::Any(), css::uno::Any()));
1768 //TODO: non-void Element, ReplacedElement
1771 // else: spurious Modifications::Node not representing a
1772 // change
1773 } else {
1774 child->initBroadcasterAndChanges(
1775 i.second, broadcaster, allChanges);
1776 //TODO: if allChanges==0, recurse only into children w/
1777 // listeners
1779 break;
1780 case Node::KIND_ROOT:
1781 assert(false); // this cannot happen
1782 break;
1784 } else {
1785 switch (getNode()->kind()) {
1786 case Node::KIND_LOCALIZED_PROPERTY:
1787 // Removed localized property value:
1788 assert(Components::allLocales(getRootAccess()->getLocale()));
1789 for (auto const& containerListener : containerListeners_)
1791 broadcaster->addContainerElementRemovedNotification(
1792 containerListener,
1793 css::container::ContainerEvent(
1794 static_cast< cppu::OWeakObject * >(this),
1795 css::uno::Any(i.first), css::uno::Any(),
1796 css::uno::Any()));
1797 //TODO: non-void ReplacedElement
1799 if (allChanges != nullptr) {
1800 OUStringBuffer path(getRelativePathRepresentation());
1801 if (!path.isEmpty()) {
1802 path.append('/');
1804 path.append(Data::createSegment("*", i.first));
1805 allChanges->push_back(
1806 css::util::ElementChange(
1807 css::uno::Any(path.makeStringAndClear()),
1808 css::uno::Any(), css::uno::Any()));
1809 //TODO: non-void ReplacedElement
1811 assert(!collectPropChanges);
1812 break;
1813 case Node::KIND_GROUP:
1815 // Removed (non-localized) extension property:
1816 for (auto const& containerListener : containerListeners_)
1818 broadcaster->addContainerElementRemovedNotification(
1819 containerListener,
1820 css::container::ContainerEvent(
1821 static_cast< cppu::OWeakObject * >(this),
1822 css::uno::Any(i.first), css::uno::Any(),
1823 css::uno::Any()));
1824 //TODO: non-void ReplacedElement
1826 PropertyChangeListeners::iterator j(
1827 propertyChangeListeners_.find(i.first));
1828 if (j != propertyChangeListeners_.end()) {
1829 for (auto const& propertyChangeListenerElement : j->second)
1831 broadcaster->addPropertyChangeNotification(
1832 propertyChangeListenerElement,
1833 css::beans::PropertyChangeEvent(
1834 static_cast< cppu::OWeakObject * >(this),
1835 i.first, false, -1, css::uno::Any(),
1836 css::uno::Any()));
1839 j = propertyChangeListeners_.find("");
1840 if (j != propertyChangeListeners_.end()) {
1841 for (auto const& propertyChangeListenerElement : j->second)
1843 broadcaster->addPropertyChangeNotification(
1844 propertyChangeListenerElement,
1845 css::beans::PropertyChangeEvent(
1846 static_cast< cppu::OWeakObject * >(this),
1847 i.first, false, -1, css::uno::Any(),
1848 css::uno::Any()));
1851 if (allChanges != nullptr) {
1852 OUStringBuffer path(
1853 getRelativePathRepresentation());
1854 if (!path.isEmpty()) {
1855 path.append('/');
1857 path.append(i.first);
1858 allChanges->push_back(
1859 css::util::ElementChange(
1860 css::uno::Any(path.makeStringAndClear()),
1861 css::uno::Any(), css::uno::Any()));
1862 //TODO: non-void ReplacedElement
1864 if (collectPropChanges) {
1865 propChanges.emplace_back(
1866 static_cast< cppu::OWeakObject * >(this),
1867 i.first, false, -1, css::uno::Any(),
1868 css::uno::Any());
1871 break;
1872 case Node::KIND_SET:
1873 // Removed set member:
1874 if (i.second.children.empty()) {
1875 for (auto const& containerListener : containerListeners_)
1877 broadcaster->addContainerElementRemovedNotification(
1878 containerListener,
1879 css::container::ContainerEvent(
1880 static_cast< cppu::OWeakObject * >(this),
1881 css::uno::Any(i.first),
1882 css::uno::Any(), css::uno::Any()));
1883 //TODO: non-void ReplacedElement
1885 if (allChanges != nullptr) {
1886 OUStringBuffer path(
1887 getRelativePathRepresentation());
1888 if (!path.isEmpty()) {
1889 path.append('/');
1891 path.append(Data::createSegment("*", i.first));
1892 allChanges->push_back(
1893 css::util::ElementChange(
1894 css::uno::Any(path.makeStringAndClear()),
1895 css::uno::Any(), css::uno::Any()));
1896 //TODO: non-void ReplacedElement
1899 // else: spurious Modifications::Node not representing a change
1900 break;
1901 default:
1902 assert(false); // this cannot happen
1903 break;
1907 if (!propChanges.empty()) {
1908 css::uno::Sequence< css::beans::PropertyChangeEvent > seq(
1909 comphelper::containerToSequence(propChanges));
1910 for (auto const& propertyChangeListener : propertiesChangeListeners_)
1912 broadcaster->addPropertiesChangeNotification(propertyChangeListener, seq);
1918 Access::ModifiedChild::ModifiedChild():
1919 directlyModified(false)
1922 Access::ModifiedChild::ModifiedChild(
1923 rtl::Reference< ChildAccess > const & theChild, bool theDirectlyModified):
1924 child(theChild), directlyModified(theDirectlyModified)
1927 rtl::Reference< ChildAccess > Access::getModifiedChild(
1928 ModifiedChildren::iterator const & childIterator)
1930 return (childIterator->second.child->getParentAccess() == this &&
1931 (childIterator->second.child->getNameInternal() ==
1932 childIterator->first))
1933 ? childIterator->second.child : rtl::Reference< ChildAccess >();
1936 rtl::Reference< ChildAccess > Access::createUnmodifiedChild(
1937 const OUString &name, const rtl::Reference< Node > &node)
1939 rtl::Reference child(
1940 new ChildAccess(components_, getRootAccess(), this, name, node));
1941 cachedChildren_[name] = child.get();
1942 return child;
1945 rtl::Reference< ChildAccess > Access::getUnmodifiedChild(
1946 OUString const & name)
1948 assert(modifiedChildren_.find(name) == modifiedChildren_.end());
1949 rtl::Reference< Node > node(getNode()->getMember(name));
1950 if (!node.is()) {
1951 return rtl::Reference< ChildAccess >();
1953 WeakChildMap::iterator i(cachedChildren_.find(name));
1954 if (i != cachedChildren_.end()) {
1955 rtl::Reference< ChildAccess > child;
1956 if (i->second->acquireCounting() > 1) {
1957 child.set(i->second); // must not throw
1959 i->second->releaseNondeleting();
1960 if (child.is()) {
1961 child->setNode(node);
1962 return child;
1965 return createUnmodifiedChild(name,node);
1968 rtl::Reference< ChildAccess > Access::getSubChild(OUString const & path) {
1969 sal_Int32 i = 0;
1970 // For backwards compatibility, allow absolute paths where meaningful:
1971 if( path.startsWith("/") ) {
1972 ++i;
1973 if (!getRootAccess().is()) {
1974 return rtl::Reference< ChildAccess >();
1976 std::vector<OUString> abs(getAbsolutePath());
1977 for (auto const& elem : abs)
1979 OUString name1;
1980 bool setElement1;
1981 OUString templateName1;
1982 i = Data::parseSegment(
1983 path, i, &name1, &setElement1, &templateName1);
1984 if (i == -1 || (i != path.getLength() && path[i] != '/')) {
1985 return rtl::Reference< ChildAccess >();
1987 OUString name2;
1988 bool setElement2;
1989 OUString templateName2;
1990 Data::parseSegment(elem, 0, &name2, &setElement2, &templateName2);
1991 if (name1 != name2 || setElement1 != setElement2 ||
1992 (setElement1 &&
1993 !Data::equalTemplateNames(templateName1, templateName2)))
1995 return rtl::Reference< ChildAccess >();
1997 if (i != path.getLength()) {
1998 ++i;
2002 for (rtl::Reference< Access > parent(this);;) {
2003 OUString name;
2004 bool setElement;
2005 OUString templateName;
2006 i = Data::parseSegment(path, i, &name, &setElement, &templateName);
2007 if (i == -1 || (i != path.getLength() && path[i] != '/')) {
2008 return rtl::Reference< ChildAccess >();
2010 rtl::Reference< ChildAccess > child(parent->getChild(name));
2011 if (!child.is()) {
2012 return rtl::Reference< ChildAccess >();
2014 if (setElement) {
2015 rtl::Reference< Node > p(parent->getNode());
2016 switch (p->kind()) {
2017 case Node::KIND_LOCALIZED_PROPERTY:
2018 if (!Components::allLocales(getRootAccess()->getLocale()) ||
2019 !templateName.isEmpty())
2021 return rtl::Reference< ChildAccess >();
2023 break;
2024 case Node::KIND_SET:
2025 if (!templateName.isEmpty() &&
2026 !static_cast< SetNode * >(p.get())->isValidTemplate(
2027 templateName))
2029 return rtl::Reference< ChildAccess >();
2031 break;
2032 default:
2033 return rtl::Reference< ChildAccess >();
2036 // For backwards compatibility, ignore a final slash after non-value
2037 // nodes:
2038 if (child->isValue()) {
2039 return i == path.getLength()
2040 ? child : rtl::Reference< ChildAccess >();
2041 } else if (i >= path.getLength() - 1) {
2042 return child;
2044 ++i;
2045 parent = child.get();
2049 bool Access::setChildProperty(
2050 OUString const & name, css::uno::Any const & value,
2051 Modifications * localModifications)
2053 assert(localModifications != nullptr);
2054 rtl::Reference< ChildAccess > child(getChild(name));
2055 if (!child.is()) {
2056 return false;
2058 child->checkFinalized();
2059 child->setProperty(value, localModifications);
2060 return true;
2063 css::beans::Property Access::asProperty() {
2064 css::uno::Type type;
2065 bool nillable;
2066 bool removable;
2067 rtl::Reference< Node > p(getNode());
2068 switch (p->kind()) {
2069 case Node::KIND_PROPERTY:
2071 PropertyNode * prop = static_cast< PropertyNode * >(p.get());
2072 type = mapType(prop->getStaticType());
2073 nillable = prop->isNillable();
2074 removable = prop->isExtension();
2076 break;
2077 case Node::KIND_LOCALIZED_PROPERTY:
2079 LocalizedPropertyNode * locprop =
2080 static_cast< LocalizedPropertyNode *>(p.get());
2081 if (Components::allLocales(getRootAccess()->getLocale())) {
2082 type = cppu::UnoType< css::uno::XInterface >::get();
2083 //TODO: correct?
2084 removable = false;
2085 } else {
2086 type = mapType(locprop->getStaticType());
2087 removable = false; //TODO ???
2089 nillable = locprop->isNillable();
2091 break;
2092 case Node::KIND_LOCALIZED_VALUE:
2094 LocalizedPropertyNode * locprop =
2095 static_cast< LocalizedPropertyNode * >(getParentNode().get());
2096 type = mapType(locprop->getStaticType());
2097 nillable = locprop->isNillable();
2098 removable = false; //TODO ???
2100 break;
2101 default:
2102 type = cppu::UnoType< css::uno::XInterface >::get(); //TODO: correct?
2103 nillable = false;
2104 rtl::Reference< Node > parent(getParentNode());
2105 removable = parent.is() && parent->kind() == Node::KIND_SET;
2106 break;
2108 return css::beans::Property(
2109 getNameInternal(), -1, type,
2110 (css::beans::PropertyAttribute::BOUND | //TODO: correct for group/set?
2111 css::beans::PropertyAttribute::CONSTRAINED |
2112 (nillable ? css::beans::PropertyAttribute::MAYBEVOID : 0) |
2113 (getRootAccess()->isUpdate() && removable
2114 ? css::beans::PropertyAttribute::REMOVABLE : 0) |
2115 (!getRootAccess()->isUpdate() || p->getFinalized() != Data::NO_LAYER
2116 ? css::beans::PropertyAttribute::READONLY : 0))); //TODO: MAYBEDEFAULT
2119 void Access::checkFinalized() {
2120 if (isFinalized()) {
2121 throw css::lang::IllegalArgumentException(
2122 "configmgr modification of finalized item",
2123 static_cast< cppu::OWeakObject * >(this), -1);
2127 void Access::checkKnownProperty(OUString const & descriptor) {
2128 if (descriptor.isEmpty()) {
2129 return;
2131 rtl::Reference< ChildAccess > child(getChild(descriptor));
2132 if (child.is()) {
2133 switch (child->getNode()->kind()) {
2134 case Node::KIND_PROPERTY:
2135 return;
2136 case Node::KIND_LOCALIZED_PROPERTY:
2137 if (!Components::allLocales(getRootAccess()->getLocale())) {
2138 return;
2140 break;
2141 case Node::KIND_LOCALIZED_VALUE:
2142 if (Components::allLocales(getRootAccess()->getLocale())) {
2143 return;
2145 break;
2146 default:
2147 break;
2150 throw css::beans::UnknownPropertyException(
2151 descriptor, static_cast< cppu::OWeakObject * >(this));
2154 rtl::Reference< ChildAccess > Access::getFreeSetMember(
2155 css::uno::Any const & value)
2157 rtl::Reference< ChildAccess > freeAcc;
2158 css::uno::Reference< css::lang::XUnoTunnel > tunnel;
2159 value >>= tunnel;
2160 if (tunnel.is()) {
2161 freeAcc.set(
2162 reinterpret_cast< ChildAccess * >(
2163 tunnel->getSomething(ChildAccess::getTunnelId())));
2165 if (!freeAcc.is() || freeAcc->getParentAccess().is() ||
2166 (freeAcc->isInTransaction() &&
2167 freeAcc->getRootAccess() != getRootAccess()))
2169 throw css::lang::IllegalArgumentException(
2170 "configmgr inappropriate set element",
2171 static_cast< cppu::OWeakObject * >(this), 1);
2173 assert(dynamic_cast< SetNode * >(getNode().get()) != nullptr);
2174 if (!static_cast< SetNode * >(getNode().get())->isValidTemplate(
2175 freeAcc->getNode()->getTemplateName()))
2177 throw css::lang::IllegalArgumentException(
2178 "configmgr inappropriate set element",
2179 static_cast< cppu::OWeakObject * >(this), 1);
2181 return freeAcc;
2184 rtl::Reference< Access > Access::getNotificationRoot() {
2185 for (rtl::Reference< Access > p(this);;) {
2186 rtl::Reference< Access > parent(p->getParentAccess());
2187 if (!parent.is()) {
2188 return p;
2190 p = parent;
2194 #if !defined NDEBUG
2195 bool Access::thisIs(int what) {
2196 osl::MutexGuard g(*lock_);
2197 rtl::Reference< Node > p(getNode());
2198 Node::Kind k(p->kind());
2199 return (k != Node::KIND_PROPERTY && k != Node::KIND_LOCALIZED_VALUE &&
2200 ((what & IS_GROUP) == 0 || k == Node::KIND_GROUP) &&
2201 ((what & IS_SET) == 0 || k == Node::KIND_SET) &&
2202 ((what & IS_EXTENSIBLE) == 0 || k != Node::KIND_GROUP ||
2203 static_cast< GroupNode * >(p.get())->isExtensible()) &&
2204 ((what & IS_GROUP_MEMBER) == 0 ||
2205 getParentNode()->kind() == Node::KIND_GROUP)) ||
2206 ((what & IS_SET_MEMBER) == 0 ||
2207 getParentNode()->kind() == Node::KIND_SET) ||
2208 ((what & IS_UPDATE) == 0 || getRootAccess()->isUpdate());
2210 #endif
2214 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */