bump product version to 5.0.4.1
[LibreOffice.git] / configmgr / source / access.cxx
blob41d86e78228bceba98e40b51115c0c8f98aed8a9
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 <vector>
25 #include <com/sun/star/beans/Property.hpp>
26 #include <com/sun/star/beans/PropertyAttribute.hpp>
27 #include <com/sun/star/beans/PropertyChangeEvent.hpp>
28 #include <com/sun/star/beans/PropertyVetoException.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/NoSupportException.hpp>
56 #include <com/sun/star/lang/WrappedTargetException.hpp>
57 #include <com/sun/star/lang/XComponent.hpp>
58 #include <com/sun/star/lang/XEventListener.hpp>
59 #include <com/sun/star/lang/XServiceInfo.hpp>
60 #include <com/sun/star/lang/XSingleServiceFactory.hpp>
61 #include <com/sun/star/lang/XTypeProvider.hpp>
62 #include <com/sun/star/lang/XUnoTunnel.hpp>
63 #include <com/sun/star/uno/Any.hxx>
64 #include <com/sun/star/uno/Reference.hxx>
65 #include <com/sun/star/uno/RuntimeException.hpp>
66 #include <com/sun/star/uno/Sequence.hxx>
67 #include <com/sun/star/uno/Type.hxx>
68 #include <com/sun/star/uno/TypeClass.hpp>
69 #include <com/sun/star/uno/XInterface.hpp>
70 #include <com/sun/star/uno/XWeak.hpp>
71 #include <com/sun/star/util/ElementChange.hpp>
72 #include <comphelper/sequence.hxx>
73 #include <cppu/unotype.hxx>
74 #include <cppuhelper/queryinterface.hxx>
75 #include <cppuhelper/supportsservice.hxx>
76 #include <cppuhelper/weak.hxx>
77 #include <osl/interlck.h>
78 #include <osl/mutex.hxx>
79 #include <rtl/ref.hxx>
80 #include <rtl/ustrbuf.hxx>
81 #include <rtl/ustring.h>
82 #include <rtl/ustring.hxx>
83 #include <sal/log.hxx>
84 #include <sal/types.h>
86 #include "access.hxx"
87 #include "broadcaster.hxx"
88 #include "childaccess.hxx"
89 #include "components.hxx"
90 #include "data.hxx"
91 #include "groupnode.hxx"
92 #include "localizedpropertynode.hxx"
93 #include "localizedvaluenode.hxx"
94 #include "lock.hxx"
95 #include "modifications.hxx"
96 #include "node.hxx"
97 #include "nodemap.hxx"
98 #include "path.hxx"
99 #include "propertynode.hxx"
100 #include "rootaccess.hxx"
101 #include "setnode.hxx"
102 #include "type.hxx"
104 namespace configmgr {
106 oslInterlockedCount Access::acquireCounting() {
107 return osl_atomic_increment(&m_refCount);
110 void Access::releaseNondeleting() {
111 osl_atomic_decrement(&m_refCount);
114 bool Access::isValue() {
115 rtl::Reference< Node > p(getNode());
116 switch (p->kind()) {
117 case Node::KIND_PROPERTY:
118 case Node::KIND_LOCALIZED_VALUE:
119 return true;
120 case Node::KIND_LOCALIZED_PROPERTY:
121 return !Components::allLocales(getRootAccess()->getLocale());
122 default:
123 return false;
127 void Access::markChildAsModified(rtl::Reference< ChildAccess > const & child) {
128 assert(child.is() && child->getParentAccess() == this);
129 modifiedChildren_[child->getNameInternal()] = ModifiedChild(child, true);
130 for (rtl::Reference< Access > p(this);;) {
131 rtl::Reference< Access > parent(p->getParentAccess());
132 if (!parent.is()) {
133 break;
135 assert(dynamic_cast< ChildAccess * >(p.get()) != 0);
136 parent->modifiedChildren_.insert(
137 ModifiedChildren::value_type(
138 p->getNameInternal(),
139 ModifiedChild(static_cast< ChildAccess * >(p.get()), false)));
140 p = parent;
144 void Access::releaseChild(OUString const & name) {
145 cachedChildren_.erase(name);
148 void Access::initBroadcaster(
149 Modifications::Node const & modifications, Broadcaster * broadcaster)
151 initBroadcasterAndChanges(modifications, broadcaster, 0);
154 css::uno::Sequence< css::uno::Type > Access::getTypes()
155 throw (css::uno::RuntimeException, std::exception)
157 assert(thisIs(IS_ANY));
158 osl::MutexGuard g(*lock_);
159 checkLocalizedPropertyAccess();
160 std::vector< css::uno::Type > types;
161 types.push_back(cppu::UnoType< css::uno::XInterface >::get());
162 types.push_back(cppu::UnoType< css::uno::XWeak >::get());
163 types.push_back(cppu::UnoType< css::lang::XTypeProvider >::get());
164 types.push_back(cppu::UnoType< css::lang::XServiceInfo >::get());
165 types.push_back(cppu::UnoType< css::lang::XComponent >::get());
166 types.push_back(cppu::UnoType< css::container::XContainer >::get());
167 types.push_back(cppu::UnoType< css::beans::XExactName >::get());
168 types.push_back(cppu::UnoType< css::container::XHierarchicalName >::get());
169 types.push_back(cppu::UnoType< css::container::XNamed >::get());
170 types.push_back(cppu::UnoType< css::beans::XProperty >::get());
171 types.push_back(cppu::UnoType< css::container::XElementAccess >::get());
172 types.push_back(cppu::UnoType< css::container::XNameAccess >::get());
173 if (getNode()->kind() == Node::KIND_GROUP) {
174 types.push_back(cppu::UnoType< css::beans::XPropertySetInfo >::get());
175 types.push_back(cppu::UnoType< css::beans::XPropertySet >::get());
176 types.push_back(cppu::UnoType< css::beans::XMultiPropertySet >::get());
177 types.push_back(
178 cppu::UnoType< css::beans::XHierarchicalPropertySet >::get());
179 types.push_back(
180 cppu::UnoType< css::beans::XMultiHierarchicalPropertySet >::get());
181 types.push_back(
182 cppu::UnoType< css::beans::XHierarchicalPropertySetInfo >::get());
184 if (getRootAccess()->isUpdate()) {
185 types.push_back(cppu::UnoType< css::container::XNameReplace >::get());
186 types.push_back(
187 cppu::UnoType< css::container::XHierarchicalNameReplace >::get());
188 if (getNode()->kind() != Node::KIND_GROUP ||
189 static_cast< GroupNode * >(getNode().get())->isExtensible())
191 types.push_back(
192 cppu::UnoType< css::container::XNameContainer >::get());
194 if (getNode()->kind() == Node::KIND_SET) {
195 types.push_back(
196 cppu::UnoType< css::lang::XSingleServiceFactory >::get());
198 } else {
199 types.push_back(
200 cppu::UnoType< css::container::XHierarchicalNameAccess >::get());
202 addTypes(&types);
203 return comphelper::containerToSequence(types);
206 css::uno::Sequence< sal_Int8 > Access::getImplementationId()
207 throw (css::uno::RuntimeException, std::exception)
209 assert(thisIs(IS_ANY));
210 osl::MutexGuard g(*lock_);
211 checkLocalizedPropertyAccess();
212 return css::uno::Sequence< sal_Int8 >();
215 OUString Access::getImplementationName() throw (css::uno::RuntimeException, std::exception)
217 assert(thisIs(IS_ANY));
218 osl::MutexGuard g(*lock_);
219 checkLocalizedPropertyAccess();
220 return OUString("org.openoffice-configmgr::Access");
223 sal_Bool Access::supportsService(OUString const & ServiceName)
224 throw (css::uno::RuntimeException, std::exception)
226 return cppu::supportsService(this, ServiceName);
229 css::uno::Sequence< OUString > Access::getSupportedServiceNames()
230 throw (css::uno::RuntimeException, std::exception)
232 assert(thisIs(IS_ANY));
233 osl::MutexGuard g(*lock_);
234 checkLocalizedPropertyAccess();
235 std::vector< OUString > services;
236 services.push_back("com.sun.star.configuration.ConfigurationAccess");
237 if (getRootAccess()->isUpdate()) {
238 services.push_back(
239 "com.sun.star.configuration.ConfigurationUpdateAccess");
241 services.push_back("com.sun.star.configuration.HierarchyAccess");
242 services.push_back("com.sun.star.configuration.HierarchyElement");
243 if (getNode()->kind() == Node::KIND_GROUP) {
244 services.push_back("com.sun.star.configuration.GroupAccess");
245 services.push_back("com.sun.star.configuration.PropertyHierarchy");
246 if (getRootAccess()->isUpdate()) {
247 services.push_back("com.sun.star.configuration.GroupUpdate");
249 } else {
250 services.push_back("com.sun.star.configuration.SetAccess");
251 services.push_back("com.sun.star.configuration.SimpleSetAccess");
252 if (getRootAccess()->isUpdate()) {
253 services.push_back("com.sun.star.configuration.SetUpdate");
254 services.push_back("com.sun.star.configuration.SimpleSetUpdate");
257 addSupportedServiceNames(&services);
258 return comphelper::containerToSequence(services);
261 void Access::dispose() throw (css::uno::RuntimeException, std::exception) {
262 assert(thisIs(IS_ANY));
263 Broadcaster bc;
265 osl::MutexGuard g(*lock_);
266 checkLocalizedPropertyAccess();
267 if (getParentAccess().is()) {
268 throw css::uno::RuntimeException(
269 "configmgr dispose inappropriate Access",
270 static_cast< cppu::OWeakObject * >(this));
272 if (disposed_) {
273 return;
275 initDisposeBroadcaster(&bc);
276 clearListeners();
277 disposed_ = true;
279 bc.send();
282 void Access::addEventListener(
283 css::uno::Reference< css::lang::XEventListener > const & xListener)
284 throw (css::uno::RuntimeException, std::exception)
286 assert(thisIs(IS_ANY));
288 osl::MutexGuard g(*lock_);
289 checkLocalizedPropertyAccess();
290 if (!xListener.is()) {
291 throw css::uno::RuntimeException(
292 "null listener", static_cast< cppu::OWeakObject * >(this));
294 if (!disposed_) {
295 disposeListeners_.insert(xListener);
296 return;
299 try {
300 xListener->disposing(
301 css::lang::EventObject(static_cast< cppu::OWeakObject * >(this)));
302 } catch (css::lang::DisposedException &) {}
305 void Access::removeEventListener(
306 css::uno::Reference< css::lang::XEventListener > const & aListener)
307 throw (css::uno::RuntimeException, std::exception)
309 assert(thisIs(IS_ANY));
310 osl::MutexGuard g(*lock_);
311 checkLocalizedPropertyAccess();
312 DisposeListeners::iterator i(disposeListeners_.find(aListener));
313 if (i != disposeListeners_.end()) {
314 disposeListeners_.erase(i);
318 css::uno::Type Access::getElementType() throw (css::uno::RuntimeException, std::exception) {
319 assert(thisIs(IS_ANY));
320 osl::MutexGuard g(*lock_);
321 checkLocalizedPropertyAccess();
322 rtl::Reference< Node > p(getNode());
323 switch (p->kind()) {
324 case Node::KIND_LOCALIZED_PROPERTY:
325 return mapType(
326 static_cast< LocalizedPropertyNode * >(p.get())->getStaticType());
327 case Node::KIND_GROUP:
328 //TODO: Should a specific type be returned for a non-extensible group
329 // with homogeneous members or for an extensible group that currently
330 // has only homegeneous members?
331 return cppu::UnoType<void>::get();
332 case Node::KIND_SET:
333 return cppu::UnoType<void>::get(); //TODO: correct?
334 default:
335 assert(false);
336 throw css::uno::RuntimeException(
337 "this cannot happen", static_cast< cppu::OWeakObject * >(this));
341 sal_Bool Access::hasElements() throw (css::uno::RuntimeException, std::exception) {
342 assert(thisIs(IS_ANY));
343 osl::MutexGuard g(*lock_);
344 checkLocalizedPropertyAccess();
345 return !getAllChildren().empty(); //TODO: optimize
348 bool Access::getByNameFast(const OUString & name, css::uno::Any & value)
350 bool bGotValue = false;
351 rtl::Reference< ChildAccess > child;
353 if (getNode()->kind() != Node::KIND_LOCALIZED_PROPERTY)
354 { // try to get it directly
355 ModifiedChildren::iterator i(modifiedChildren_.find(name));
356 if (i != modifiedChildren_.end())
358 child = getModifiedChild(i);
359 if (child.is())
361 value = child->asValue();
362 bGotValue = true;
365 else
367 rtl::Reference< Node > node(getNode()->getMember(name));
368 if (!node.is())
369 return false;
370 bGotValue = ChildAccess::asSimpleValue(node, value, components_);
374 if (!bGotValue)
376 child = getChild(name);
377 if (!child.is())
378 return false;
379 value = child->asValue();
381 return true;
384 css::uno::Any Access::getByName(OUString const & aName)
385 throw (
386 css::container::NoSuchElementException,
387 css::lang::WrappedTargetException, css::uno::RuntimeException, std::exception)
389 assert(thisIs(IS_ANY));
390 osl::MutexGuard g(*lock_);
391 checkLocalizedPropertyAccess();
392 css::uno::Any value;
393 if (!getByNameFast(aName, value))
394 throw css::container::NoSuchElementException(
395 aName, static_cast< cppu::OWeakObject * >(this));
396 return value;
399 css::uno::Sequence< OUString > Access::getElementNames()
400 throw (css::uno::RuntimeException, std::exception)
402 assert(thisIs(IS_ANY));
403 osl::MutexGuard g(*lock_);
404 checkLocalizedPropertyAccess();
405 std::vector< rtl::Reference< ChildAccess > > children(getAllChildren());
406 std::vector< OUString > names;
407 for (std::vector< rtl::Reference< ChildAccess > >::iterator i(
408 children.begin());
409 i != children.end(); ++i)
411 names.push_back((*i)->getNameInternal());
413 return comphelper::containerToSequence(names);
416 sal_Bool Access::hasByName(OUString const & aName)
417 throw (css::uno::RuntimeException, std::exception)
419 assert(thisIs(IS_ANY));
420 osl::MutexGuard g(*lock_);
421 checkLocalizedPropertyAccess();
422 return getChild(aName).is();
425 css::uno::Any Access::getByHierarchicalName(OUString const & aName)
426 throw (css::container::NoSuchElementException, css::uno::RuntimeException, std::exception)
428 assert(thisIs(IS_ANY));
429 osl::MutexGuard g(*lock_);
430 checkLocalizedPropertyAccess();
431 rtl::Reference< ChildAccess > child(getSubChild(aName));
432 if (!child.is()) {
433 throw css::container::NoSuchElementException(
434 aName, static_cast< cppu::OWeakObject * >(this));
436 return child->asValue();
439 sal_Bool Access::hasByHierarchicalName(OUString const & aName)
440 throw (css::uno::RuntimeException, std::exception)
442 assert(thisIs(IS_ANY));
443 osl::MutexGuard g(*lock_);
444 checkLocalizedPropertyAccess();
445 return getSubChild(aName).is();
448 void Access::replaceByHierarchicalName(
449 OUString const & aName, css::uno::Any const & aElement)
450 throw (
451 css::lang::IllegalArgumentException,
452 css::container::NoSuchElementException,
453 css::lang::WrappedTargetException, css::uno::RuntimeException, std::exception)
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)
496 throw (css::uno::RuntimeException, std::exception)
498 assert(thisIs(IS_ANY));
500 osl::MutexGuard g(*lock_);
501 checkLocalizedPropertyAccess();
502 if (!xListener.is()) {
503 throw css::uno::RuntimeException(
504 "null listener", static_cast< cppu::OWeakObject * >(this));
506 if (!disposed_) {
507 containerListeners_.insert(xListener);
508 return;
511 try {
512 xListener->disposing(
513 css::lang::EventObject(static_cast< cppu::OWeakObject * >(this)));
514 } catch (css::lang::DisposedException &) {}
517 void Access::removeContainerListener(
518 css::uno::Reference< css::container::XContainerListener > const & xListener)
519 throw (css::uno::RuntimeException, std::exception)
521 assert(thisIs(IS_ANY));
522 osl::MutexGuard g(*lock_);
523 checkLocalizedPropertyAccess();
524 ContainerListeners::iterator i(containerListeners_.find(xListener));
525 if (i != containerListeners_.end()) {
526 containerListeners_.erase(i);
530 OUString Access::getExactName(OUString const & aApproximateName)
531 throw (css::uno::RuntimeException, std::exception)
533 assert(thisIs(IS_ANY));
534 osl::MutexGuard g(*lock_);
535 checkLocalizedPropertyAccess();
536 return aApproximateName;
539 css::uno::Sequence< css::beans::Property > Access::getProperties()
540 throw (css::uno::RuntimeException, std::exception)
542 assert(thisIs(IS_GROUP));
543 osl::MutexGuard g(*lock_);
544 std::vector< rtl::Reference< ChildAccess > > children(getAllChildren());
545 std::vector< css::beans::Property > properties;
546 for (std::vector< rtl::Reference< ChildAccess > >::iterator i(
547 children.begin());
548 i != children.end(); ++i)
550 properties.push_back((*i)->asProperty());
552 return comphelper::containerToSequence(properties);
555 css::beans::Property Access::getPropertyByName(OUString const & aName)
556 throw (css::beans::UnknownPropertyException, css::uno::RuntimeException, std::exception)
558 assert(thisIs(IS_GROUP));
559 osl::MutexGuard g(*lock_);
560 rtl::Reference< ChildAccess > child(getChild(aName));
561 if (!child.is()) {
562 throw css::beans::UnknownPropertyException(
563 aName, static_cast< cppu::OWeakObject * >(this));
565 return child->asProperty();
568 sal_Bool Access::hasPropertyByName(OUString const & Name)
569 throw (css::uno::RuntimeException, std::exception)
571 assert(thisIs(IS_GROUP));
572 osl::MutexGuard g(*lock_);
573 return getChild(Name).is();
576 OUString Access::getHierarchicalName() throw (css::uno::RuntimeException, std::exception) {
577 assert(thisIs(IS_ANY));
578 osl::MutexGuard g(*lock_);
579 checkLocalizedPropertyAccess();
580 // For backwards compatibility, return an absolute path representation where
581 // available:
582 OUString rootPath;
583 rtl::Reference< RootAccess > root(getRootAccess());
584 if (root.is()) {
585 rootPath = root->getAbsolutePathRepresentation();
587 OUString rel(getRelativePathRepresentation());
588 OUStringBuffer path(rootPath);
589 if (!rootPath.isEmpty() && rootPath != "/" && !rel.isEmpty()) {
590 path.append('/');
592 path.append(rel);
593 return path.makeStringAndClear();
596 OUString Access::composeHierarchicalName(
597 OUString const & aRelativeName)
598 throw (
599 css::lang::IllegalArgumentException, css::lang::NoSupportException,
600 css::uno::RuntimeException, std::exception)
602 assert(thisIs(IS_ANY));
603 osl::MutexGuard g(*lock_);
604 checkLocalizedPropertyAccess();
605 if (aRelativeName.isEmpty() || aRelativeName[0] == '/') {
606 throw css::lang::IllegalArgumentException(
607 "configmgr composeHierarchicalName inappropriate relative name",
608 static_cast< cppu::OWeakObject * >(this), -1);
610 OUStringBuffer path(getRelativePathRepresentation());
611 if (!path.isEmpty()) {
612 path.append('/');
614 path.append(aRelativeName);
615 return path.makeStringAndClear();
618 OUString Access::getName() throw (css::uno::RuntimeException, std::exception) {
619 assert(thisIs(IS_ANY));
620 osl::MutexGuard g(*lock_);
621 checkLocalizedPropertyAccess();
622 return getNameInternal();
625 void Access::setName(OUString const & aName)
626 throw (css::uno::RuntimeException, std::exception)
628 assert(thisIs(IS_ANY));
629 Broadcaster bc;
631 osl::MutexGuard g(*lock_);
632 checkLocalizedPropertyAccess();
633 checkFinalized();
634 Modifications localMods;
635 switch (getNode()->kind()) {
636 case Node::KIND_GROUP:
637 case Node::KIND_SET:
639 rtl::Reference< Access > parent(getParentAccess());
640 if (parent.is()) {
641 rtl::Reference< Node > node(getNode());
642 if (! node->getTemplateName().isEmpty()) {
643 rtl::Reference< ChildAccess > other(
644 parent->getChild(aName));
645 if (other.get() == this) {
646 break;
648 if (node->getMandatory() == Data::NO_LAYER &&
649 !(other.is() && other->isFinalized()))
651 rtl::Reference< RootAccess > root(getRootAccess());
652 rtl::Reference< ChildAccess > childAccess(
653 static_cast< ChildAccess * >(this));
654 localMods.add(getRelativePath());
655 // unbind() modifies the parent chain that
656 // markChildAsModified() walks, so order is
657 // important:
658 parent->markChildAsModified(childAccess);
659 //TODO: must not throw
660 childAccess->unbind(); // must not throw
661 if (other.is()) {
662 other->unbind(); // must not throw
664 childAccess->bind(root, parent, aName);
665 // must not throw
666 parent->markChildAsModified(childAccess);
667 //TODO: must not throw
668 localMods.add(getRelativePath());
669 break;
674 // fall through
675 case Node::KIND_LOCALIZED_PROPERTY:
676 // renaming a property could only work for an extension property,
677 // but a localized property is never an extension property
678 throw css::uno::RuntimeException(
679 "configmgr setName inappropriate node",
680 static_cast< cppu::OWeakObject * >(this));
681 default:
682 assert(false); // this cannot happen
683 break;
685 getNotificationRoot()->initBroadcaster(localMods.getRoot(), &bc);
687 bc.send();
690 css::beans::Property Access::getAsProperty() throw (css::uno::RuntimeException, std::exception)
692 assert(thisIs(IS_ANY));
693 osl::MutexGuard g(*lock_);
694 checkLocalizedPropertyAccess();
695 return asProperty();
698 css::uno::Reference< css::beans::XPropertySetInfo > Access::getPropertySetInfo()
699 throw (css::uno::RuntimeException, std::exception)
701 assert(thisIs(IS_GROUP));
702 return this;
705 void Access::setPropertyValue(
706 OUString const & aPropertyName, css::uno::Any const & aValue)
707 throw (
708 css::beans::UnknownPropertyException, css::beans::PropertyVetoException,
709 css::lang::IllegalArgumentException, css::lang::WrappedTargetException,
710 css::uno::RuntimeException, std::exception)
712 assert(thisIs(IS_GROUP));
713 Broadcaster bc;
715 osl::MutexGuard g(*lock_);
716 if (!getRootAccess()->isUpdate()) {
717 throw css::uno::RuntimeException(
718 "configmgr setPropertyValue on non-update access",
719 static_cast< cppu::OWeakObject * >(this));
721 Modifications localMods;
722 if (!setChildProperty(aPropertyName, aValue, &localMods)) {
723 throw css::beans::UnknownPropertyException(
724 aPropertyName, static_cast< cppu::OWeakObject * >(this));
726 getNotificationRoot()->initBroadcaster(localMods.getRoot(), &bc);
728 bc.send();
731 css::uno::Any Access::getPropertyValue(OUString const & PropertyName)
732 throw (
733 css::beans::UnknownPropertyException, css::lang::WrappedTargetException,
734 css::uno::RuntimeException, std::exception)
736 assert(thisIs(IS_GROUP));
737 osl::MutexGuard g(*lock_);
739 css::uno::Any value;
740 if (!getByNameFast(PropertyName, value))
741 throw css::beans::UnknownPropertyException(
742 PropertyName, static_cast< cppu::OWeakObject * >(this));
743 return value;
746 void Access::addPropertyChangeListener(
747 OUString const & aPropertyName,
748 css::uno::Reference< css::beans::XPropertyChangeListener > const &
749 xListener)
750 throw (
751 css::beans::UnknownPropertyException, css::lang::WrappedTargetException,
752 css::uno::RuntimeException, std::exception)
754 assert(thisIs(IS_GROUP));
756 osl::MutexGuard g(*lock_);
757 if (!xListener.is()) {
758 throw css::uno::RuntimeException(
759 "null listener", static_cast< cppu::OWeakObject * >(this));
761 checkKnownProperty(aPropertyName);
762 if (!disposed_) {
763 propertyChangeListeners_[aPropertyName].insert(xListener);
764 return;
767 try {
768 xListener->disposing(
769 css::lang::EventObject(static_cast< cppu::OWeakObject * >(this)));
770 } catch (css::lang::DisposedException &) {}
773 void Access::removePropertyChangeListener(
774 OUString const & aPropertyName,
775 css::uno::Reference< css::beans::XPropertyChangeListener > const &
776 aListener)
777 throw (
778 css::beans::UnknownPropertyException, css::lang::WrappedTargetException,
779 css::uno::RuntimeException, std::exception)
781 assert(thisIs(IS_GROUP));
782 osl::MutexGuard g(*lock_);
783 checkKnownProperty(aPropertyName);
784 PropertyChangeListeners::iterator i(
785 propertyChangeListeners_.find(aPropertyName));
786 if (i != propertyChangeListeners_.end()) {
787 PropertyChangeListenersElement::iterator j(i->second.find(aListener));
788 if (j != i->second.end()) {
789 i->second.erase(j);
790 if (i->second.empty()) {
791 propertyChangeListeners_.erase(i);
797 void Access::addVetoableChangeListener(
798 OUString const & PropertyName,
799 css::uno::Reference< css::beans::XVetoableChangeListener > const &
800 aListener)
801 throw (
802 css::beans::UnknownPropertyException, css::lang::WrappedTargetException,
803 css::uno::RuntimeException, std::exception)
805 assert(thisIs(IS_GROUP));
807 osl::MutexGuard g(*lock_);
808 if (!aListener.is()) {
809 throw css::uno::RuntimeException(
810 "null listener", static_cast< cppu::OWeakObject * >(this));
812 checkKnownProperty(PropertyName);
813 if (!disposed_) {
814 vetoableChangeListeners_[PropertyName].insert(aListener);
815 //TODO: actually call vetoableChangeListeners_
816 return;
819 try {
820 aListener->disposing(
821 css::lang::EventObject(static_cast< cppu::OWeakObject * >(this)));
822 } catch (css::lang::DisposedException &) {}
825 void Access::removeVetoableChangeListener(
826 OUString const & PropertyName,
827 css::uno::Reference< css::beans::XVetoableChangeListener > const &
828 aListener)
829 throw (
830 css::beans::UnknownPropertyException, css::lang::WrappedTargetException,
831 css::uno::RuntimeException, std::exception)
833 assert(thisIs(IS_GROUP));
834 osl::MutexGuard g(*lock_);
835 checkKnownProperty(PropertyName);
836 VetoableChangeListeners::iterator i(
837 vetoableChangeListeners_.find(PropertyName));
838 if (i != vetoableChangeListeners_.end()) {
839 VetoableChangeListenersElement::iterator j(i->second.find(aListener));
840 if (j != i->second.end()) {
841 i->second.erase(j);
842 if (i->second.empty()) {
843 vetoableChangeListeners_.erase(i);
849 void Access::setPropertyValues(
850 css::uno::Sequence< OUString > const & aPropertyNames,
851 css::uno::Sequence< css::uno::Any > const & aValues)
852 throw (
853 css::beans::PropertyVetoException, css::lang::IllegalArgumentException,
854 css::lang::WrappedTargetException, css::uno::RuntimeException, std::exception)
856 assert(thisIs(IS_GROUP));
857 Broadcaster bc;
859 osl::MutexGuard g(*lock_);
860 if (!getRootAccess()->isUpdate()) {
861 throw css::uno::RuntimeException(
862 "configmgr setPropertyValues on non-update access",
863 static_cast< cppu::OWeakObject * >(this));
865 if (aPropertyNames.getLength() != aValues.getLength()) {
866 throw css::lang::IllegalArgumentException(
867 ("configmgr setPropertyValues: aPropertyNames/aValues of"
868 " different length"),
869 static_cast< cppu::OWeakObject * >(this), -1);
871 Modifications localMods;
872 for (sal_Int32 i = 0; i < aPropertyNames.getLength(); ++i) {
873 if (!setChildProperty(aPropertyNames[i], aValues[i], &localMods)) {
874 throw css::lang::IllegalArgumentException(
875 "configmgr setPropertyValues inappropriate property name",
876 static_cast< cppu::OWeakObject * >(this), -1);
879 getNotificationRoot()->initBroadcaster(localMods.getRoot(), &bc);
881 bc.send();
884 css::uno::Sequence< css::uno::Any > Access::getPropertyValues(
885 css::uno::Sequence< OUString > const & aPropertyNames)
886 throw (css::uno::RuntimeException, std::exception)
888 assert(thisIs(IS_GROUP));
889 osl::MutexGuard g(*lock_);
890 css::uno::Sequence< css::uno::Any > vals(aPropertyNames.getLength());
892 for (sal_Int32 i = 0; i < aPropertyNames.getLength(); ++i)
894 if (!getByNameFast(aPropertyNames[i], vals[i]))
895 throw css::uno::RuntimeException(
896 "configmgr getPropertyValues inappropriate property name",
897 static_cast< cppu::OWeakObject * >(this));
900 return vals;
903 void Access::addPropertiesChangeListener(
904 css::uno::Sequence< OUString > const &,
905 css::uno::Reference< css::beans::XPropertiesChangeListener > const &
906 xListener)
907 throw (css::uno::RuntimeException, std::exception)
909 assert(thisIs(IS_GROUP));
911 osl::MutexGuard g(*lock_);
912 if (!xListener.is()) {
913 throw css::uno::RuntimeException(
914 "null listener", static_cast< cppu::OWeakObject * >(this));
916 if (!disposed_) {
917 propertiesChangeListeners_.insert(xListener);
918 return;
921 try {
922 xListener->disposing(
923 css::lang::EventObject(static_cast< cppu::OWeakObject * >(this)));
924 } catch (css::lang::DisposedException &) {}
927 void Access::removePropertiesChangeListener(
928 css::uno::Reference< css::beans::XPropertiesChangeListener > const &
929 xListener)
930 throw (css::uno::RuntimeException, std::exception)
932 assert(thisIs(IS_GROUP));
933 osl::MutexGuard g(*lock_);
934 PropertiesChangeListeners::iterator i(
935 propertiesChangeListeners_.find(xListener));
936 if (i != propertiesChangeListeners_.end()) {
937 propertiesChangeListeners_.erase(i);
941 void Access::firePropertiesChangeEvent(
942 css::uno::Sequence< OUString > const & aPropertyNames,
943 css::uno::Reference< css::beans::XPropertiesChangeListener > const &
944 xListener)
945 throw (css::uno::RuntimeException, std::exception)
947 assert(thisIs(IS_GROUP));
948 css::uno::Sequence< css::beans::PropertyChangeEvent > events(
949 aPropertyNames.getLength());
950 for (sal_Int32 i = 0; i < events.getLength(); ++i) {
951 events[i].Source = static_cast< cppu::OWeakObject * >(this);
952 events[i].PropertyName = aPropertyNames[i];
953 events[i].Further = false;
954 events[i].PropertyHandle = -1;
956 xListener->propertiesChange(events);
959 css::uno::Reference< css::beans::XHierarchicalPropertySetInfo >
960 Access::getHierarchicalPropertySetInfo() throw (css::uno::RuntimeException, std::exception) {
961 assert(thisIs(IS_GROUP));
962 return this;
965 void Access::setHierarchicalPropertyValue(
966 OUString const & aHierarchicalPropertyName,
967 css::uno::Any const & aValue)
968 throw (
969 css::beans::UnknownPropertyException, css::beans::PropertyVetoException,
970 css::lang::IllegalArgumentException, css::lang::WrappedTargetException,
971 css::uno::RuntimeException, std::exception)
973 assert(thisIs(IS_GROUP));
974 Broadcaster bc;
976 osl::MutexGuard g(*lock_);
977 if (!getRootAccess()->isUpdate()) {
978 throw css::uno::RuntimeException(
979 "configmgr setHierarchicalPropertyName on non-update access",
980 static_cast< cppu::OWeakObject * >(this));
982 rtl::Reference< ChildAccess > child(
983 getSubChild(aHierarchicalPropertyName));
984 if (!child.is()) {
985 throw css::beans::UnknownPropertyException(
986 aHierarchicalPropertyName,
987 static_cast< cppu::OWeakObject * >(this));
989 child->checkFinalized();
990 Modifications localMods;
991 child->setProperty(aValue, &localMods);
992 getNotificationRoot()->initBroadcaster(localMods.getRoot(), &bc);
994 bc.send();
997 css::uno::Any Access::getHierarchicalPropertyValue(
998 OUString const & aHierarchicalPropertyName)
999 throw (
1000 css::beans::UnknownPropertyException,
1001 css::lang::IllegalArgumentException, css::lang::WrappedTargetException,
1002 css::uno::RuntimeException, std::exception)
1004 assert(thisIs(IS_GROUP));
1005 osl::MutexGuard g(*lock_);
1006 rtl::Reference< ChildAccess > child(getSubChild(aHierarchicalPropertyName));
1007 if (!child.is()) {
1008 throw css::beans::UnknownPropertyException(
1009 aHierarchicalPropertyName,
1010 static_cast< cppu::OWeakObject * >(this));
1012 return child->asValue();
1015 void Access::setHierarchicalPropertyValues(
1016 css::uno::Sequence< OUString > const & aHierarchicalPropertyNames,
1017 css::uno::Sequence< css::uno::Any > const & Values)
1018 throw (
1019 css::beans::PropertyVetoException, css::lang::IllegalArgumentException,
1020 css::lang::WrappedTargetException, css::uno::RuntimeException, std::exception)
1022 assert(thisIs(IS_GROUP));
1023 Broadcaster bc;
1025 osl::MutexGuard g(*lock_);
1026 if (!getRootAccess()->isUpdate()) {
1027 throw css::uno::RuntimeException(
1028 "configmgr setPropertyValues on non-update access",
1029 static_cast< cppu::OWeakObject * >(this));
1031 if (aHierarchicalPropertyNames.getLength() != Values.getLength()) {
1032 throw css::lang::IllegalArgumentException(
1033 ("configmgr setHierarchicalPropertyValues:"
1034 " aHierarchicalPropertyNames/Values of different length"),
1035 static_cast< cppu::OWeakObject * >(this), -1);
1037 Modifications localMods;
1038 for (sal_Int32 i = 0; i < aHierarchicalPropertyNames.getLength(); ++i) {
1039 rtl::Reference< ChildAccess > child(
1040 getSubChild(aHierarchicalPropertyNames[i]));
1041 if (!child.is()) {
1042 throw css::lang::IllegalArgumentException(
1043 ("configmgr setHierarchicalPropertyValues inappropriate"
1044 " property name"),
1045 static_cast< cppu::OWeakObject * >(this), -1);
1047 child->checkFinalized();
1048 child->setProperty(Values[i], &localMods);
1050 getNotificationRoot()->initBroadcaster(localMods.getRoot(), &bc);
1052 bc.send();
1055 css::uno::Sequence< css::uno::Any > Access::getHierarchicalPropertyValues(
1056 css::uno::Sequence< OUString > const & aHierarchicalPropertyNames)
1057 throw (
1058 css::lang::IllegalArgumentException, css::lang::WrappedTargetException,
1059 css::uno::RuntimeException, std::exception)
1061 assert(thisIs(IS_GROUP));
1062 osl::MutexGuard g(*lock_);
1063 css::uno::Sequence< css::uno::Any > vals(
1064 aHierarchicalPropertyNames.getLength());
1065 for (sal_Int32 i = 0; i < aHierarchicalPropertyNames.getLength(); ++i) {
1066 rtl::Reference< ChildAccess > child(
1067 getSubChild(aHierarchicalPropertyNames[i]));
1068 if (!child.is()) {
1069 throw css::lang::IllegalArgumentException(
1070 ("configmgr getHierarchicalPropertyValues inappropriate"
1071 " hierarchical property name"),
1072 static_cast< cppu::OWeakObject * >(this), -1);
1074 vals[i] = child->asValue();
1076 return vals;
1079 css::beans::Property Access::getPropertyByHierarchicalName(
1080 OUString const & aHierarchicalName)
1081 throw (css::beans::UnknownPropertyException, css::uno::RuntimeException, std::exception)
1083 assert(thisIs(IS_GROUP));
1084 osl::MutexGuard g(*lock_);
1085 rtl::Reference< ChildAccess > child(getSubChild(aHierarchicalName));
1086 if (!child.is()) {
1087 throw css::beans::UnknownPropertyException(
1088 aHierarchicalName, static_cast< cppu::OWeakObject * >(this));
1090 return child->asProperty();
1093 sal_Bool Access::hasPropertyByHierarchicalName(
1094 OUString const & aHierarchicalName)
1095 throw (css::uno::RuntimeException, std::exception)
1097 assert(thisIs(IS_GROUP));
1098 osl::MutexGuard g(*lock_);
1099 return getSubChild(aHierarchicalName).is();
1102 void Access::replaceByName(
1103 OUString const & aName, css::uno::Any const & aElement)
1104 throw (
1105 css::lang::IllegalArgumentException,
1106 css::container::NoSuchElementException,
1107 css::lang::WrappedTargetException, css::uno::RuntimeException, std::exception)
1109 assert(thisIs(IS_UPDATE));
1110 Broadcaster bc;
1112 osl::MutexGuard g(*lock_);
1113 checkLocalizedPropertyAccess();
1114 rtl::Reference< ChildAccess > child(getChild(aName));
1115 if (!child.is()) {
1116 throw css::container::NoSuchElementException(
1117 aName, static_cast< cppu::OWeakObject * >(this));
1119 child->checkFinalized();
1120 Modifications localMods;
1121 switch (getNode()->kind()) {
1122 case Node::KIND_LOCALIZED_PROPERTY:
1123 case Node::KIND_GROUP:
1124 child->setProperty(aElement, &localMods);
1125 break;
1126 case Node::KIND_SET:
1128 rtl::Reference< ChildAccess > freeAcc(
1129 getFreeSetMember(aElement));
1130 rtl::Reference< RootAccess > root(getRootAccess());
1131 localMods.add(child->getRelativePath());
1132 child->unbind(); // must not throw
1133 freeAcc->bind(root, this, aName); // must not throw
1134 markChildAsModified(freeAcc); //TODO: must not throw
1136 break;
1137 default:
1138 assert(false); // this cannot happen
1139 break;
1141 getNotificationRoot()->initBroadcaster(localMods.getRoot(), &bc);
1143 bc.send();
1146 void Access::insertByName(
1147 OUString const & aName, css::uno::Any const & aElement)
1148 throw (
1149 css::lang::IllegalArgumentException,
1150 css::container::ElementExistException,
1151 css::lang::WrappedTargetException, css::uno::RuntimeException, std::exception)
1153 assert(thisIs(IS_EXTENSIBLE|IS_UPDATE));
1154 Broadcaster bc;
1156 osl::MutexGuard g(*lock_);
1157 checkLocalizedPropertyAccess();
1158 checkFinalized();
1159 if (getChild(aName).is()) {
1160 throw css::container::ElementExistException(
1161 aName, static_cast< cppu::OWeakObject * >(this));
1163 Modifications localMods;
1164 switch (getNode()->kind()) {
1165 case Node::KIND_LOCALIZED_PROPERTY:
1166 insertLocalizedValueChild(aName, aElement, &localMods);
1167 break;
1168 case Node::KIND_GROUP:
1170 checkValue(aElement, TYPE_ANY, true);
1171 rtl::Reference< ChildAccess > child(
1172 new ChildAccess(
1173 components_, getRootAccess(), this, aName,
1174 new PropertyNode(
1175 Data::NO_LAYER, TYPE_ANY, true, aElement, true)));
1176 markChildAsModified(child);
1177 localMods.add(child->getRelativePath());
1179 break;
1180 case Node::KIND_SET:
1182 rtl::Reference< ChildAccess > freeAcc(
1183 getFreeSetMember(aElement));
1184 freeAcc->bind(getRootAccess(), this, aName); // must not throw
1185 markChildAsModified(freeAcc); //TODO: must not throw
1186 localMods.add(freeAcc->getRelativePath());
1188 break;
1189 default:
1190 assert(false); // this cannot happen
1191 break;
1193 getNotificationRoot()->initBroadcaster(localMods.getRoot(), &bc);
1195 bc.send();
1198 void Access::removeByName(OUString const & aName)
1199 throw (
1200 css::container::NoSuchElementException,
1201 css::lang::WrappedTargetException, css::uno::RuntimeException, std::exception)
1203 assert(thisIs(IS_EXTENSIBLE|IS_UPDATE));
1204 Broadcaster bc;
1206 osl::MutexGuard g(*lock_);
1207 checkLocalizedPropertyAccess();
1208 rtl::Reference< ChildAccess > child(getChild(aName));
1209 if (!child.is() || child->isFinalized() ||
1210 child->getNode()->getMandatory() != Data::NO_LAYER)
1212 throw css::container::NoSuchElementException(
1213 aName, static_cast< cppu::OWeakObject * >(this));
1215 if (getNode()->kind() == Node::KIND_GROUP) {
1216 rtl::Reference< Node > p(child->getNode());
1217 if (p->kind() != Node::KIND_PROPERTY ||
1218 !static_cast< PropertyNode * >(p.get())->isExtension())
1220 throw css::container::NoSuchElementException(
1221 aName, static_cast< cppu::OWeakObject * >(this));
1224 Modifications localMods;
1225 localMods.add(child->getRelativePath());
1226 // unbind() modifies the parent chain that markChildAsModified() walks,
1227 // so order is important:
1228 markChildAsModified(child); //TODO: must not throw
1229 child->unbind();
1230 getNotificationRoot()->initBroadcaster(localMods.getRoot(), &bc);
1232 bc.send();
1235 css::uno::Reference< css::uno::XInterface > Access::createInstance()
1236 throw (css::uno::Exception, css::uno::RuntimeException, std::exception)
1238 assert(thisIs(IS_SET|IS_UPDATE));
1239 OUString tmplName(
1240 static_cast< SetNode * >(getNode().get())->getDefaultTemplateName());
1241 rtl::Reference< Node > tmpl(
1242 components_.getTemplate(Data::NO_LAYER, tmplName));
1243 if (!tmpl.is()) {
1244 throw css::uno::Exception(
1245 "unknown template " + tmplName,
1246 static_cast< cppu::OWeakObject * >(this));
1248 rtl::Reference< Node > node(tmpl->clone(true));
1249 node->setLayer(Data::NO_LAYER);
1250 return static_cast< cppu::OWeakObject * >(
1251 new ChildAccess(components_, getRootAccess(), node));
1254 css::uno::Reference< css::uno::XInterface > Access::createInstanceWithArguments(
1255 css::uno::Sequence< css::uno::Any > const & aArguments)
1256 throw (css::uno::Exception, css::uno::RuntimeException, std::exception)
1258 assert(thisIs(IS_SET|IS_UPDATE));
1259 if (aArguments.getLength() != 0) {
1260 throw css::uno::Exception(
1261 ("configuration SimpleSetUpdate createInstanceWithArguments"
1262 " must not specify any arguments"),
1263 static_cast< cppu::OWeakObject * >(this));
1265 return createInstance();
1268 Access::Access(Components & components):
1269 components_(components), disposed_(false)
1271 lock_ = lock();
1274 Access::~Access() {}
1276 void Access::initDisposeBroadcaster(Broadcaster * broadcaster) {
1277 assert(broadcaster != 0);
1278 for (DisposeListeners::iterator i(disposeListeners_.begin());
1279 i != disposeListeners_.end(); ++i)
1281 broadcaster->addDisposeNotification(
1283 css::lang::EventObject(static_cast< cppu::OWeakObject * >(this)));
1285 for (ContainerListeners::iterator i(containerListeners_.begin());
1286 i != containerListeners_.end(); ++i)
1288 broadcaster->addDisposeNotification(
1289 i->get(),
1290 css::lang::EventObject(static_cast< cppu::OWeakObject * >(this)));
1292 for (PropertyChangeListeners::iterator i(propertyChangeListeners_.begin());
1293 i != propertyChangeListeners_.end(); ++i)
1295 for (PropertyChangeListenersElement::iterator j(i->second.begin());
1296 j != i->second.end(); ++j)
1298 broadcaster->addDisposeNotification(
1299 j->get(),
1300 css::lang::EventObject(
1301 static_cast< cppu::OWeakObject * >(this)));
1304 for (VetoableChangeListeners::iterator i(vetoableChangeListeners_.begin());
1305 i != vetoableChangeListeners_.end(); ++i)
1307 for (VetoableChangeListenersElement::iterator j(i->second.begin());
1308 j != i->second.end(); ++j)
1310 broadcaster->addDisposeNotification(
1311 j->get(),
1312 css::lang::EventObject(
1313 static_cast< cppu::OWeakObject * >(this)));
1316 for (PropertiesChangeListeners::iterator i(
1317 propertiesChangeListeners_.begin());
1318 i != propertiesChangeListeners_.end(); ++i)
1320 broadcaster->addDisposeNotification(
1321 i->get(),
1322 css::lang::EventObject(static_cast< cppu::OWeakObject * >(this)));
1324 //TODO: iterate over children w/ listeners (incl. unmodified ones):
1325 for (ModifiedChildren::iterator i(modifiedChildren_.begin());
1326 i != modifiedChildren_.end(); ++i)
1328 rtl::Reference< ChildAccess > child(getModifiedChild(i));
1329 if (child.is()) {
1330 child->initDisposeBroadcaster(broadcaster);
1335 void Access::clearListeners() throw() {
1336 disposeListeners_.clear();
1337 containerListeners_.clear();
1338 propertyChangeListeners_.clear();
1339 vetoableChangeListeners_.clear();
1340 propertiesChangeListeners_.clear();
1341 //TODO: iterate over children w/ listeners (incl. unmodified ones):
1342 for (ModifiedChildren::iterator i(modifiedChildren_.begin());
1343 i != modifiedChildren_.end(); ++i)
1345 rtl::Reference< ChildAccess > child(getModifiedChild(i));
1346 if (child.is()) {
1347 child->clearListeners();
1352 css::uno::Any Access::queryInterface(css::uno::Type const & aType)
1353 throw (css::uno::RuntimeException, std::exception)
1355 css::uno::Any res(OWeakObject::queryInterface(aType));
1356 if (res.hasValue()) {
1357 return res;
1359 res = cppu::queryInterface(
1360 aType, static_cast< css::lang::XTypeProvider * >(this),
1361 static_cast< css::lang::XServiceInfo * >(this),
1362 static_cast< css::lang::XComponent * >(this),
1363 static_cast< css::container::XHierarchicalNameAccess * >(this),
1364 static_cast< css::container::XContainer * >(this),
1365 static_cast< css::beans::XExactName * >(this),
1366 static_cast< css::container::XHierarchicalName * >(this),
1367 static_cast< css::container::XNamed * >(this),
1368 static_cast< css::beans::XProperty * >(this),
1369 static_cast< css::container::XElementAccess * >(this),
1370 static_cast< css::container::XNameAccess * >(this));
1371 if (res.hasValue()) {
1372 return res;
1374 if (getNode()->kind() == Node::KIND_GROUP) {
1375 res = cppu::queryInterface(
1376 aType, static_cast< css::beans::XPropertySetInfo * >(this),
1377 static_cast< css::beans::XPropertySet * >(this),
1378 static_cast< css::beans::XMultiPropertySet * >(this),
1379 static_cast< css::beans::XHierarchicalPropertySet * >(this),
1380 static_cast< css::beans::XMultiHierarchicalPropertySet * >(this),
1381 static_cast< css::beans::XHierarchicalPropertySetInfo * >(this));
1382 if (res.hasValue()) {
1383 return res;
1386 if (getRootAccess()->isUpdate()) {
1387 res = cppu::queryInterface(
1388 aType, static_cast< css::container::XNameReplace * >(this),
1389 static_cast< css::container::XHierarchicalNameReplace * >(this));
1390 if (res.hasValue()) {
1391 return res;
1393 if (getNode()->kind() != Node::KIND_GROUP ||
1394 static_cast< GroupNode * >(getNode().get())->isExtensible())
1396 res = cppu::queryInterface(
1397 aType, static_cast< css::container::XNameContainer * >(this));
1398 if (res.hasValue()) {
1399 return res;
1402 if (getNode()->kind() == Node::KIND_SET) {
1403 res = cppu::queryInterface(
1404 aType, static_cast< css::lang::XSingleServiceFactory * >(this));
1407 return res;
1411 void Access::checkLocalizedPropertyAccess() {
1412 if (getNode()->kind() == Node::KIND_LOCALIZED_PROPERTY &&
1413 !Components::allLocales(getRootAccess()->getLocale()))
1415 throw css::uno::RuntimeException(
1416 "configmgr Access to specialized LocalizedPropertyNode",
1417 static_cast< cppu::OWeakObject * >(this));
1421 rtl::Reference< Node > Access::getParentNode() {
1422 rtl::Reference< Access > parent(getParentAccess());
1423 return parent.is() ? parent->getNode() : rtl::Reference< Node >();
1426 rtl::Reference< ChildAccess > Access::getChild(OUString const & name) {
1427 OUString locale;
1428 if (getNode()->kind() == Node::KIND_LOCALIZED_PROPERTY
1429 && name.startsWith("*", &locale))
1431 if (locale.startsWith("*")) {
1432 SAL_WARN(
1433 "configmgr",
1434 ("access best-matching localized property value via"
1435 " \"*<locale>\" with <locale> \"")
1436 << locale << "\" recursively starting with \"*\"");
1437 return getChild(locale);
1439 SAL_WARN_IF(
1440 locale.isEmpty(), "configmgr",
1441 ("access best-matching localized property value via \"*<locale>\""
1442 " with empty <locale>; falling back to defaults"));
1443 if (!locale.isEmpty()) {
1444 // Find best match using an adaption of RFC 4647 lookup matching
1445 // rules, removing "-" or "_" delimited segments from the end:
1446 for (;;) {
1447 rtl::Reference< ChildAccess > child(getChild(locale));
1448 if (child.is()) {
1449 return child;
1451 sal_Int32 i = locale.getLength() - 1;
1452 while (i > 0 && locale[i] != '-' && locale[i] != '_') {
1453 --i;
1455 if (i <= 0) {
1456 break;
1458 locale = locale.copy(0, i);
1460 // As a workaround for broken xcu data that does not use shortest
1461 // xml:lang attributes, look for the first entry with the same first
1462 // segment as the requested language tag before falling back to
1463 // defaults (see fdo#33638):
1464 assert(
1465 !locale.isEmpty() && locale.indexOf('-') == -1 &&
1466 locale.indexOf('_') == -1);
1467 std::vector< rtl::Reference< ChildAccess > > children(
1468 getAllChildren());
1469 for (std::vector< rtl::Reference< ChildAccess > >::iterator i(
1470 children.begin());
1471 i != children.end(); ++i)
1473 OUString name2((*i)->getNameInternal());
1474 if (name2.startsWith(locale) &&
1475 (name2.getLength() == locale.getLength() ||
1476 name2[locale.getLength()] == '-' ||
1477 name2[locale.getLength()] == '_'))
1479 return *i;
1483 // Defaults are the "en-US" locale, the "en" locale, the empty string
1484 // locale, the first child (if any), or a null ChildAccess, in that
1485 // order:
1486 rtl::Reference< ChildAccess > child(getChild("en-US"));
1487 if (child.is()) {
1488 return child;
1490 child = getChild("en");
1491 if (child.is()) {
1492 return child;
1494 child = getChild("");
1495 if (child.is()) {
1496 return child;
1498 std::vector< rtl::Reference< ChildAccess > > children(getAllChildren());
1499 if (!children.empty()) {
1500 return children.front();
1502 return rtl::Reference< ChildAccess >();
1504 ModifiedChildren::iterator i(modifiedChildren_.find(name));
1505 return i == modifiedChildren_.end()
1506 ? getUnmodifiedChild(name) : getModifiedChild(i);
1509 std::vector< rtl::Reference< ChildAccess > > Access::getAllChildren() {
1510 std::vector< rtl::Reference< ChildAccess > > vec;
1511 NodeMap const & members = getNode()->getMembers();
1512 for (NodeMap::const_iterator i(members.begin()); i != members.end(); ++i) {
1513 if (modifiedChildren_.find(i->first) == modifiedChildren_.end()) {
1514 vec.push_back(getUnmodifiedChild(i->first));
1515 assert(vec.back().is());
1518 for (ModifiedChildren::iterator i(modifiedChildren_.begin());
1519 i != modifiedChildren_.end(); ++i)
1521 rtl::Reference< ChildAccess > child(getModifiedChild(i));
1522 if (child.is()) {
1523 vec.push_back(child);
1526 return vec;
1529 void Access::checkValue(css::uno::Any const & value, Type type, bool nillable) {
1530 bool ok;
1531 switch (type) {
1532 case TYPE_NIL:
1533 assert(false);
1534 // fall through (cannot happen)
1535 case TYPE_ERROR:
1536 ok = false;
1537 break;
1538 case TYPE_ANY:
1539 switch (getDynamicType(value)) {
1540 case TYPE_ANY:
1541 assert(false);
1542 // fall through (cannot happen)
1543 case TYPE_ERROR:
1544 ok = false;
1545 break;
1546 case TYPE_NIL:
1547 ok = nillable;
1548 break;
1549 default:
1550 ok = true;
1551 break;
1553 break;
1554 default:
1555 ok = value.hasValue() ? value.isExtractableTo(mapType(type)) : nillable;
1556 break;
1558 if (!ok) {
1559 throw css::lang::IllegalArgumentException(
1560 "configmgr inappropriate property value",
1561 static_cast< cppu::OWeakObject * >(this), -1);
1565 void Access::insertLocalizedValueChild(
1566 OUString const & name, css::uno::Any const & value,
1567 Modifications * localModifications)
1569 assert(localModifications != 0);
1570 LocalizedPropertyNode * locprop = static_cast< LocalizedPropertyNode * >(
1571 getNode().get());
1572 checkValue(value, locprop->getStaticType(), locprop->isNillable());
1573 rtl::Reference< ChildAccess > child(
1574 new ChildAccess(
1575 components_, getRootAccess(), this, name,
1576 new LocalizedValueNode(Data::NO_LAYER, value)));
1577 markChildAsModified(child);
1578 localModifications->add(child->getRelativePath());
1581 void Access::reportChildChanges(
1582 std::vector< css::util::ElementChange > * changes)
1584 assert(changes != 0);
1585 for (ModifiedChildren::iterator i(modifiedChildren_.begin());
1586 i != modifiedChildren_.end(); ++i)
1588 rtl::Reference< ChildAccess > child(getModifiedChild(i));
1589 if (child.is()) {
1590 child->reportChildChanges(changes);
1591 changes->push_back(css::util::ElementChange());
1592 //TODO: changed value and/or inserted node
1593 } else {
1594 changes->push_back(css::util::ElementChange()); //TODO: removed node
1599 void Access::commitChildChanges(
1600 bool valid, Modifications * globalModifications)
1602 assert(globalModifications != 0);
1603 while (!modifiedChildren_.empty()) {
1604 bool childValid = valid;
1605 ModifiedChildren::iterator i(modifiedChildren_.begin());
1606 rtl::Reference< ChildAccess > child(getModifiedChild(i));
1607 if (child.is()) {
1608 childValid = childValid && !child->isFinalized();
1609 child->commitChanges(childValid, globalModifications);
1610 //TODO: currently, this is called here for directly inserted
1611 // children as well as for children whose sub-children were
1612 // modified (and should never be called for directly removed
1613 // children); clarify what exactly should happen here for
1614 // directly inserted children
1616 NodeMap & members = getNode()->getMembers();
1617 NodeMap::iterator j(members.find(i->first));
1618 if (child.is()) {
1619 // Inserted:
1620 if (j != members.end()) {
1621 childValid = childValid &&
1622 j->second->getFinalized() == Data::NO_LAYER;
1623 if (childValid) {
1624 child->getNode()->setMandatory(j->second->getMandatory());
1627 if (childValid) {
1628 members[i->first] = child->getNode();
1630 } else {
1631 // Removed:
1632 childValid = childValid && j != members.end() &&
1633 j->second->getFinalized() == Data::NO_LAYER &&
1634 j->second->getMandatory() == Data::NO_LAYER;
1635 if (childValid) {
1636 members.erase(j);
1639 if (childValid && i->second.directlyModified) {
1640 Path path(getAbsolutePath());
1641 path.push_back(i->first);
1642 components_.addModification(path);
1643 globalModifications->add(path);
1645 i->second.child->committed();
1646 modifiedChildren_.erase(i);
1650 void Access::initBroadcasterAndChanges(
1651 Modifications::Node const & modifications, Broadcaster * broadcaster,
1652 std::vector< css::util::ElementChange > * allChanges)
1654 assert(broadcaster != 0);
1655 std::vector< css::beans::PropertyChangeEvent > propChanges;
1656 bool collectPropChanges = !propertiesChangeListeners_.empty();
1657 for (Modifications::Node::Children::const_iterator i(
1658 modifications.children.begin());
1659 i != modifications.children.end(); ++i)
1661 rtl::Reference< ChildAccess > child(getChild(i->first));
1662 if (child.is()) {
1663 switch (child->getNode()->kind()) {
1664 case Node::KIND_LOCALIZED_PROPERTY:
1665 if (!i->second.children.empty()) {
1666 if (Components::allLocales(getRootAccess()->getLocale())) {
1667 child->initBroadcasterAndChanges(
1668 i->second, broadcaster, allChanges);
1669 //TODO: if allChanges==0, recurse only into children
1670 // w/ listeners
1671 } else {
1672 //TODO: filter child mods that are irrelevant for
1673 // locale:
1674 for (ContainerListeners::iterator j(
1675 containerListeners_.begin());
1676 j != containerListeners_.end(); ++j)
1678 broadcaster->
1679 addContainerElementReplacedNotification(
1681 css::container::ContainerEvent(
1682 static_cast< cppu::OWeakObject * >(
1683 this),
1684 css::uno::makeAny(i->first),
1685 css::uno::Any(), css::uno::Any()));
1686 //TODO: non-void Element, ReplacedElement
1688 PropertyChangeListeners::iterator j(
1689 propertyChangeListeners_.find(i->first));
1690 if (j != propertyChangeListeners_.end()) {
1691 for (PropertyChangeListenersElement::iterator k(
1692 j->second.begin());
1693 k != j->second.end(); ++k)
1695 broadcaster->addPropertyChangeNotification(
1697 css::beans::PropertyChangeEvent(
1698 static_cast< cppu::OWeakObject * >(
1699 this),
1700 i->first, false, -1, css::uno::Any(),
1701 css::uno::Any()));
1704 j = propertyChangeListeners_.find("");
1705 if (j != propertyChangeListeners_.end()) {
1706 for (PropertyChangeListenersElement::iterator k(
1707 j->second.begin());
1708 k != j->second.end(); ++k)
1710 broadcaster->addPropertyChangeNotification(
1712 css::beans::PropertyChangeEvent(
1713 static_cast< cppu::OWeakObject * >(
1714 this),
1715 i->first, false, -1, css::uno::Any(),
1716 css::uno::Any()));
1719 if (allChanges != 0) {
1720 allChanges->push_back(
1721 css::util::ElementChange(
1722 css::uno::makeAny(
1723 child->getRelativePathRepresentation()),
1724 css::uno::Any(), css::uno::Any()));
1725 //TODO: non-void Element, ReplacedElement
1727 if (collectPropChanges) {
1728 propChanges.push_back(
1729 css::beans::PropertyChangeEvent(
1730 static_cast< cppu::OWeakObject * >(this),
1731 i->first, false, -1, css::uno::Any(),
1732 css::uno::Any()));
1736 // else: spurious Modifications::Node not representing a change
1737 break;
1738 case Node::KIND_LOCALIZED_VALUE:
1739 assert(Components::allLocales(getRootAccess()->getLocale()));
1740 for (ContainerListeners::iterator j(
1741 containerListeners_.begin());
1742 j != containerListeners_.end(); ++j)
1744 broadcaster->addContainerElementReplacedNotification(
1746 css::container::ContainerEvent(
1747 static_cast< cppu::OWeakObject * >(this),
1748 css::uno::makeAny(i->first), child->asValue(),
1749 css::uno::Any()));
1750 //TODO: distinguish add/modify; non-void ReplacedElement
1752 if (allChanges != 0) {
1753 allChanges->push_back(
1754 css::util::ElementChange(
1755 css::uno::makeAny(
1756 child->getRelativePathRepresentation()),
1757 child->asValue(), css::uno::Any()));
1758 //TODO: non-void ReplacedElement
1760 assert(!collectPropChanges);
1761 break;
1762 case Node::KIND_PROPERTY:
1764 for (ContainerListeners::iterator j(
1765 containerListeners_.begin());
1766 j != containerListeners_.end(); ++j)
1768 broadcaster->addContainerElementReplacedNotification(
1770 css::container::ContainerEvent(
1771 static_cast< cppu::OWeakObject * >(this),
1772 css::uno::makeAny(i->first), child->asValue(),
1773 css::uno::Any()));
1774 //TODO: distinguish add/remove/modify; non-void
1775 // ReplacedElement
1777 PropertyChangeListeners::iterator j(
1778 propertyChangeListeners_.find(i->first));
1779 if (j != propertyChangeListeners_.end()) {
1780 for (PropertyChangeListenersElement::iterator k(
1781 j->second.begin());
1782 k != j->second.end(); ++k)
1784 broadcaster->addPropertyChangeNotification(
1786 css::beans::PropertyChangeEvent(
1787 static_cast< cppu::OWeakObject * >(this),
1788 i->first, false, -1, css::uno::Any(),
1789 css::uno::Any()));
1792 j = propertyChangeListeners_.find("");
1793 if (j != propertyChangeListeners_.end()) {
1794 for (PropertyChangeListenersElement::iterator k(
1795 j->second.begin());
1796 k != j->second.end(); ++k)
1798 broadcaster->addPropertyChangeNotification(
1800 css::beans::PropertyChangeEvent(
1801 static_cast< cppu::OWeakObject * >(this),
1802 i->first, false, -1, css::uno::Any(),
1803 css::uno::Any()));
1806 if (allChanges != 0) {
1807 allChanges->push_back(
1808 css::util::ElementChange(
1809 css::uno::makeAny(
1810 child->getRelativePathRepresentation()),
1811 child->asValue(), css::uno::Any()));
1812 //TODO: non-void ReplacedElement
1814 if (collectPropChanges) {
1815 propChanges.push_back(
1816 css::beans::PropertyChangeEvent(
1817 static_cast< cppu::OWeakObject * >(this),
1818 i->first, false, -1, css::uno::Any(),
1819 css::uno::Any()));
1822 break;
1823 case Node::KIND_GROUP:
1824 case Node::KIND_SET:
1825 if (i->second.children.empty()) {
1826 if (!child->getNode()->getTemplateName().isEmpty()) {
1827 for (ContainerListeners::iterator j(
1828 containerListeners_.begin());
1829 j != containerListeners_.end(); ++j)
1831 broadcaster->
1832 addContainerElementInsertedNotification(
1834 css::container::ContainerEvent(
1835 static_cast< cppu::OWeakObject * >(
1836 this),
1837 css::uno::makeAny(i->first),
1838 child->asValue(), css::uno::Any()));
1840 if (allChanges != 0) {
1841 allChanges->push_back(
1842 css::util::ElementChange(
1843 css::uno::makeAny(
1844 child->getRelativePathRepresentation()),
1845 css::uno::Any(), css::uno::Any()));
1846 //TODO: non-void Element, ReplacedElement
1849 // else: spurious Modifications::Node not representing a
1850 // change
1851 } else {
1852 child->initBroadcasterAndChanges(
1853 i->second, broadcaster, allChanges);
1854 //TODO: if allChanges==0, recurse only into children w/
1855 // listeners
1857 break;
1858 case Node::KIND_ROOT:
1859 assert(false); // this cannot happen
1860 break;
1862 } else {
1863 switch (getNode()->kind()) {
1864 case Node::KIND_LOCALIZED_PROPERTY:
1865 // Removed localized property value:
1866 assert(Components::allLocales(getRootAccess()->getLocale()));
1867 for (ContainerListeners::iterator j(
1868 containerListeners_.begin());
1869 j != containerListeners_.end(); ++j)
1871 broadcaster->addContainerElementRemovedNotification(
1873 css::container::ContainerEvent(
1874 static_cast< cppu::OWeakObject * >(this),
1875 css::uno::makeAny(i->first), css::uno::Any(),
1876 css::uno::Any()));
1877 //TODO: non-void ReplacedElement
1879 if (allChanges != 0) {
1880 OUStringBuffer path(getRelativePathRepresentation());
1881 if (!path.isEmpty()) {
1882 path.append('/');
1884 path.append(Data::createSegment("*", i->first));
1885 allChanges->push_back(
1886 css::util::ElementChange(
1887 css::uno::makeAny(path.makeStringAndClear()),
1888 css::uno::Any(), css::uno::Any()));
1889 //TODO: non-void ReplacedElement
1891 assert(!collectPropChanges);
1892 break;
1893 case Node::KIND_GROUP:
1895 // Removed (non-localized) extension property:
1896 for (ContainerListeners::iterator j(
1897 containerListeners_.begin());
1898 j != containerListeners_.end(); ++j)
1900 broadcaster->addContainerElementRemovedNotification(
1902 css::container::ContainerEvent(
1903 static_cast< cppu::OWeakObject * >(this),
1904 css::uno::makeAny(i->first), css::uno::Any(),
1905 css::uno::Any()));
1906 //TODO: non-void ReplacedElement
1908 PropertyChangeListeners::iterator j(
1909 propertyChangeListeners_.find(i->first));
1910 if (j != propertyChangeListeners_.end()) {
1911 for (PropertyChangeListenersElement::iterator k(
1912 j->second.begin());
1913 k != j->second.end(); ++k)
1915 broadcaster->addPropertyChangeNotification(
1917 css::beans::PropertyChangeEvent(
1918 static_cast< cppu::OWeakObject * >(this),
1919 i->first, false, -1, css::uno::Any(),
1920 css::uno::Any()));
1923 j = propertyChangeListeners_.find("");
1924 if (j != propertyChangeListeners_.end()) {
1925 for (PropertyChangeListenersElement::iterator k(
1926 j->second.begin());
1927 k != j->second.end(); ++k)
1929 broadcaster->addPropertyChangeNotification(
1931 css::beans::PropertyChangeEvent(
1932 static_cast< cppu::OWeakObject * >(this),
1933 i->first, false, -1, css::uno::Any(),
1934 css::uno::Any()));
1937 if (allChanges != 0) {
1938 OUStringBuffer path(
1939 getRelativePathRepresentation());
1940 if (!path.isEmpty()) {
1941 path.append('/');
1943 path.append(i->first);
1944 allChanges->push_back(
1945 css::util::ElementChange(
1946 css::uno::makeAny(path.makeStringAndClear()),
1947 css::uno::Any(), css::uno::Any()));
1948 //TODO: non-void ReplacedElement
1950 if (collectPropChanges) {
1951 propChanges.push_back(
1952 css::beans::PropertyChangeEvent(
1953 static_cast< cppu::OWeakObject * >(this),
1954 i->first, false, -1, css::uno::Any(),
1955 css::uno::Any()));
1958 break;
1959 case Node::KIND_SET:
1960 // Removed set member:
1961 if (i->second.children.empty()) {
1962 for (ContainerListeners::iterator j(
1963 containerListeners_.begin());
1964 j != containerListeners_.end(); ++j)
1966 broadcaster->addContainerElementRemovedNotification(
1968 css::container::ContainerEvent(
1969 static_cast< cppu::OWeakObject * >(this),
1970 css::uno::makeAny(i->first),
1971 css::uno::Any(), css::uno::Any()));
1972 //TODO: non-void ReplacedElement
1974 if (allChanges != 0) {
1975 OUStringBuffer path(
1976 getRelativePathRepresentation());
1977 if (!path.isEmpty()) {
1978 path.append('/');
1980 path.append(Data::createSegment("*", i->first));
1981 allChanges->push_back(
1982 css::util::ElementChange(
1983 css::uno::makeAny(path.makeStringAndClear()),
1984 css::uno::Any(), css::uno::Any()));
1985 //TODO: non-void ReplacedElement
1988 // else: spurious Modifications::Node not representing a change
1989 break;
1990 default:
1991 assert(false); // this cannot happen
1992 break;
1996 if (!propChanges.empty()) {
1997 css::uno::Sequence< css::beans::PropertyChangeEvent > seq(
1998 comphelper::containerToSequence(propChanges));
1999 for (PropertiesChangeListeners::iterator i(
2000 propertiesChangeListeners_.begin());
2001 i != propertiesChangeListeners_.end(); ++i)
2003 broadcaster->addPropertiesChangeNotification(*i, seq);
2009 Access::ModifiedChild::ModifiedChild():
2010 directlyModified(false)
2013 Access::ModifiedChild::ModifiedChild(
2014 rtl::Reference< ChildAccess > const & theChild, bool theDirectlyModified):
2015 child(theChild), directlyModified(theDirectlyModified)
2018 rtl::Reference< ChildAccess > Access::getModifiedChild(
2019 ModifiedChildren::iterator const & childIterator)
2021 return (childIterator->second.child->getParentAccess() == this &&
2022 (childIterator->second.child->getNameInternal() ==
2023 childIterator->first))
2024 ? childIterator->second.child : rtl::Reference< ChildAccess >();
2027 rtl::Reference< ChildAccess > Access::createUnmodifiedChild(
2028 const OUString &name, const rtl::Reference< Node > &node)
2030 rtl::Reference< ChildAccess > child(
2031 new ChildAccess(components_, getRootAccess(), this, name, node));
2032 cachedChildren_[name] = child.get();
2033 return child;
2036 rtl::Reference< ChildAccess > Access::getUnmodifiedChild(
2037 OUString const & name)
2039 assert(modifiedChildren_.find(name) == modifiedChildren_.end());
2040 rtl::Reference< Node > node(getNode()->getMember(name));
2041 if (!node.is()) {
2042 return rtl::Reference< ChildAccess >();
2044 WeakChildMap::iterator i(cachedChildren_.find(name));
2045 if (i != cachedChildren_.end()) {
2046 rtl::Reference< ChildAccess > child;
2047 if (i->second->acquireCounting() > 1) {
2048 child.set(i->second); // must not throw
2050 i->second->releaseNondeleting();
2051 if (child.is()) {
2052 child->setNode(node);
2053 return child;
2056 return createUnmodifiedChild(name,node);
2059 rtl::Reference< ChildAccess > Access::getSubChild(OUString const & path) {
2060 sal_Int32 i = 0;
2061 // For backwards compatibility, allow absolute paths where meaningful:
2062 if( path.startsWith("/") ) {
2063 ++i;
2064 if (!getRootAccess().is()) {
2065 return rtl::Reference< ChildAccess >();
2067 Path abs(getAbsolutePath());
2068 for (Path::iterator j(abs.begin()); j != abs.end(); ++j) {
2069 OUString name1;
2070 bool setElement1;
2071 OUString templateName1;
2072 i = Data::parseSegment(
2073 path, i, &name1, &setElement1, &templateName1);
2074 if (i == -1 || (i != path.getLength() && path[i] != '/')) {
2075 return rtl::Reference< ChildAccess >();
2077 OUString name2;
2078 bool setElement2;
2079 OUString templateName2;
2080 Data::parseSegment(*j, 0, &name2, &setElement2, &templateName2);
2081 if (name1 != name2 || setElement1 != setElement2 ||
2082 (setElement1 &&
2083 !Data::equalTemplateNames(templateName1, templateName2)))
2085 return rtl::Reference< ChildAccess >();
2087 if (i != path.getLength()) {
2088 ++i;
2092 for (rtl::Reference< Access > parent(this);;) {
2093 OUString name;
2094 bool setElement;
2095 OUString templateName;
2096 i = Data::parseSegment(path, i, &name, &setElement, &templateName);
2097 if (i == -1 || (i != path.getLength() && path[i] != '/')) {
2098 return rtl::Reference< ChildAccess >();
2100 rtl::Reference< ChildAccess > child(parent->getChild(name));
2101 if (!child.is()) {
2102 return rtl::Reference< ChildAccess >();
2104 if (setElement) {
2105 rtl::Reference< Node > p(parent->getNode());
2106 switch (p->kind()) {
2107 case Node::KIND_LOCALIZED_PROPERTY:
2108 if (!Components::allLocales(getRootAccess()->getLocale()) ||
2109 !templateName.isEmpty())
2111 return rtl::Reference< ChildAccess >();
2113 break;
2114 case Node::KIND_SET:
2115 if (!templateName.isEmpty() &&
2116 !static_cast< SetNode * >(p.get())->isValidTemplate(
2117 templateName))
2119 return rtl::Reference< ChildAccess >();
2121 break;
2122 default:
2123 return rtl::Reference< ChildAccess >();
2126 // For backwards compatibility, ignore a final slash after non-value
2127 // nodes:
2128 if (child->isValue()) {
2129 return i == path.getLength()
2130 ? child : rtl::Reference< ChildAccess >();
2131 } else if (i >= path.getLength() - 1) {
2132 return child;
2134 ++i;
2135 parent = child.get();
2139 bool Access::setChildProperty(
2140 OUString const & name, css::uno::Any const & value,
2141 Modifications * localModifications)
2143 assert(localModifications != 0);
2144 rtl::Reference< ChildAccess > child(getChild(name));
2145 if (!child.is()) {
2146 return false;
2148 child->checkFinalized();
2149 child->setProperty(value, localModifications);
2150 return true;
2153 css::beans::Property Access::asProperty() {
2154 css::uno::Type type;
2155 bool nillable;
2156 bool removable;
2157 rtl::Reference< Node > p(getNode());
2158 switch (p->kind()) {
2159 case Node::KIND_PROPERTY:
2161 PropertyNode * prop = static_cast< PropertyNode * >(p.get());
2162 type = mapType(prop->getStaticType());
2163 nillable = prop->isNillable();
2164 removable = prop->isExtension();
2166 break;
2167 case Node::KIND_LOCALIZED_PROPERTY:
2169 LocalizedPropertyNode * locprop =
2170 static_cast< LocalizedPropertyNode *>(p.get());
2171 if (Components::allLocales(getRootAccess()->getLocale())) {
2172 type = cppu::UnoType< css::uno::XInterface >::get();
2173 //TODO: correct?
2174 removable = false;
2175 } else {
2176 type = mapType(locprop->getStaticType());
2177 removable = false; //TODO ???
2179 nillable = locprop->isNillable();
2181 break;
2182 case Node::KIND_LOCALIZED_VALUE:
2184 LocalizedPropertyNode * locprop =
2185 static_cast< LocalizedPropertyNode * >(getParentNode().get());
2186 type = mapType(locprop->getStaticType());
2187 nillable = locprop->isNillable();
2188 removable = false; //TODO ???
2190 break;
2191 default:
2192 type = cppu::UnoType< css::uno::XInterface >::get(); //TODO: correct?
2193 nillable = false;
2194 rtl::Reference< Node > parent(getParentNode());
2195 removable = parent.is() && parent->kind() == Node::KIND_SET;
2196 break;
2198 return css::beans::Property(
2199 getNameInternal(), -1, type,
2200 (css::beans::PropertyAttribute::BOUND | //TODO: correct for group/set?
2201 css::beans::PropertyAttribute::CONSTRAINED |
2202 (nillable ? css::beans::PropertyAttribute::MAYBEVOID : 0) |
2203 (getRootAccess()->isUpdate() && removable
2204 ? css::beans::PropertyAttribute::REMOVABLE : 0) |
2205 (!getRootAccess()->isUpdate() || p->getFinalized() != Data::NO_LAYER
2206 ? css::beans::PropertyAttribute::READONLY : 0))); //TODO: MAYBEDEFAULT
2209 void Access::checkFinalized() {
2210 if (isFinalized()) {
2211 throw css::lang::IllegalArgumentException(
2212 "configmgr modification of finalized item",
2213 static_cast< cppu::OWeakObject * >(this), -1);
2217 void Access::checkKnownProperty(OUString const & descriptor) {
2218 if (descriptor.isEmpty()) {
2219 return;
2221 rtl::Reference< ChildAccess > child(getChild(descriptor));
2222 if (child.is()) {
2223 switch (child->getNode()->kind()) {
2224 case Node::KIND_PROPERTY:
2225 return;
2226 case Node::KIND_LOCALIZED_PROPERTY:
2227 if (!Components::allLocales(getRootAccess()->getLocale())) {
2228 return;
2230 break;
2231 case Node::KIND_LOCALIZED_VALUE:
2232 if (Components::allLocales(getRootAccess()->getLocale())) {
2233 return;
2235 break;
2236 default:
2237 break;
2240 throw css::beans::UnknownPropertyException(
2241 descriptor, static_cast< cppu::OWeakObject * >(this));
2244 rtl::Reference< ChildAccess > Access::getFreeSetMember(
2245 css::uno::Any const & value)
2247 rtl::Reference< ChildAccess > freeAcc;
2248 css::uno::Reference< css::lang::XUnoTunnel > tunnel;
2249 value >>= tunnel;
2250 if (tunnel.is()) {
2251 freeAcc.set(
2252 reinterpret_cast< ChildAccess * >(
2253 tunnel->getSomething(ChildAccess::getTunnelId())));
2255 if (!freeAcc.is() || freeAcc->getParentAccess().is() ||
2256 (freeAcc->isInTransaction() &&
2257 freeAcc->getRootAccess() != getRootAccess()))
2259 throw css::lang::IllegalArgumentException(
2260 "configmgr inappropriate set element",
2261 static_cast< cppu::OWeakObject * >(this), 1);
2263 assert(dynamic_cast< SetNode * >(getNode().get()) != 0);
2264 if (!static_cast< SetNode * >(getNode().get())->isValidTemplate(
2265 freeAcc->getNode()->getTemplateName()))
2267 throw css::lang::IllegalArgumentException(
2268 "configmgr inappropriate set element",
2269 static_cast< cppu::OWeakObject * >(this), 1);
2271 return freeAcc;
2274 rtl::Reference< Access > Access::getNotificationRoot() {
2275 for (rtl::Reference< Access > p(this);;) {
2276 rtl::Reference< Access > parent(p->getParentAccess());
2277 if (!parent.is()) {
2278 return p;
2280 p = parent;
2284 #if !defined NDEBUG
2285 bool Access::thisIs(int what) {
2286 osl::MutexGuard g(*lock_);
2287 rtl::Reference< Node > p(getNode());
2288 Node::Kind k(p->kind());
2289 return (k != Node::KIND_PROPERTY && k != Node::KIND_LOCALIZED_VALUE &&
2290 ((what & IS_GROUP) == 0 || k == Node::KIND_GROUP) &&
2291 ((what & IS_SET) == 0 || k == Node::KIND_SET) &&
2292 ((what & IS_EXTENSIBLE) == 0 || k != Node::KIND_GROUP ||
2293 static_cast< GroupNode * >(p.get())->isExtensible()) &&
2294 ((what & IS_GROUP_MEMBER) == 0 ||
2295 getParentNode()->kind() == Node::KIND_GROUP)) ||
2296 ((what & IS_SET_MEMBER) == 0 ||
2297 getParentNode()->kind() == Node::KIND_SET) ||
2298 ((what & IS_UPDATE) == 0 || getRootAccess()->isUpdate());
2300 #endif
2304 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */