Bump version to 4.1-6
[LibreOffice.git] / configmgr / source / access.cxx
blob5a3fd7d60aa469cfcdb21fd384b5ef82283ab915
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/sequenceasvector.hxx"
73 #include "cppu/unotype.hxx"
74 #include "cppuhelper/queryinterface.hxx"
75 #include "cppuhelper/weak.hxx"
76 #include "osl/interlck.h"
77 #include "osl/mutex.hxx"
78 #include "rtl/ref.hxx"
79 #include "rtl/ustrbuf.hxx"
80 #include "rtl/ustring.h"
81 #include "rtl/ustring.hxx"
82 #include "sal/types.h"
84 #include "access.hxx"
85 #include "broadcaster.hxx"
86 #include "childaccess.hxx"
87 #include "components.hxx"
88 #include "data.hxx"
89 #include "groupnode.hxx"
90 #include "localizedpropertynode.hxx"
91 #include "localizedvaluenode.hxx"
92 #include "lock.hxx"
93 #include "modifications.hxx"
94 #include "node.hxx"
95 #include "nodemap.hxx"
96 #include "path.hxx"
97 #include "propertynode.hxx"
98 #include "rootaccess.hxx"
99 #include "setnode.hxx"
100 #include "type.hxx"
102 namespace configmgr {
104 oslInterlockedCount Access::acquireCounting() {
105 return osl_atomic_increment(&m_refCount);
108 void Access::releaseNondeleting() {
109 osl_atomic_decrement(&m_refCount);
112 bool Access::isValue() {
113 rtl::Reference< Node > p(getNode());
114 switch (p->kind()) {
115 case Node::KIND_PROPERTY:
116 case Node::KIND_LOCALIZED_VALUE:
117 return true;
118 case Node::KIND_LOCALIZED_PROPERTY:
119 return !Components::allLocales(getRootAccess()->getLocale());
120 default:
121 return false;
125 void Access::markChildAsModified(rtl::Reference< ChildAccess > const & child) {
126 assert(child.is() && child->getParentAccess() == this);
127 modifiedChildren_[child->getNameInternal()] = ModifiedChild(child, true);
128 for (rtl::Reference< Access > p(this);;) {
129 rtl::Reference< Access > parent(p->getParentAccess());
130 if (!parent.is()) {
131 break;
133 assert(dynamic_cast< ChildAccess * >(p.get()) != 0);
134 parent->modifiedChildren_.insert(
135 ModifiedChildren::value_type(
136 p->getNameInternal(),
137 ModifiedChild(dynamic_cast< ChildAccess * >(p.get()), false)));
138 p = parent;
142 void Access::releaseChild(OUString const & name) {
143 cachedChildren_.erase(name);
146 void Access::initBroadcaster(
147 Modifications::Node const & modifications, Broadcaster * broadcaster)
149 initBroadcasterAndChanges(modifications, broadcaster, 0);
152 css::uno::Sequence< css::uno::Type > Access::getTypes()
153 throw (css::uno::RuntimeException)
155 assert(thisIs(IS_ANY));
156 osl::MutexGuard g(*lock_);
157 checkLocalizedPropertyAccess();
158 comphelper::SequenceAsVector< css::uno::Type > types;
159 types.push_back(cppu::UnoType< css::uno::XInterface >::get());
160 types.push_back(cppu::UnoType< css::uno::XWeak >::get());
161 types.push_back(cppu::UnoType< css::lang::XTypeProvider >::get());
162 types.push_back(cppu::UnoType< css::lang::XServiceInfo >::get());
163 types.push_back(cppu::UnoType< css::lang::XComponent >::get());
164 types.push_back(cppu::UnoType< css::container::XContainer >::get());
165 types.push_back(cppu::UnoType< css::beans::XExactName >::get());
166 types.push_back(cppu::UnoType< css::container::XHierarchicalName >::get());
167 types.push_back(cppu::UnoType< css::container::XNamed >::get());
168 types.push_back(cppu::UnoType< css::beans::XProperty >::get());
169 types.push_back(cppu::UnoType< css::container::XElementAccess >::get());
170 types.push_back(cppu::UnoType< css::container::XNameAccess >::get());
171 if (getNode()->kind() == Node::KIND_GROUP) {
172 types.push_back(cppu::UnoType< css::beans::XPropertySetInfo >::get());
173 types.push_back(cppu::UnoType< css::beans::XPropertySet >::get());
174 types.push_back(cppu::UnoType< css::beans::XMultiPropertySet >::get());
175 types.push_back(
176 cppu::UnoType< css::beans::XHierarchicalPropertySet >::get());
177 types.push_back(
178 cppu::UnoType< css::beans::XMultiHierarchicalPropertySet >::get());
179 types.push_back(
180 cppu::UnoType< css::beans::XHierarchicalPropertySetInfo >::get());
182 if (getRootAccess()->isUpdate()) {
183 types.push_back(cppu::UnoType< css::container::XNameReplace >::get());
184 types.push_back(
185 cppu::UnoType< css::container::XHierarchicalNameReplace >::get());
186 if (getNode()->kind() != Node::KIND_GROUP ||
187 dynamic_cast< GroupNode * >(getNode().get())->isExtensible())
189 types.push_back(
190 cppu::UnoType< css::container::XNameContainer >::get());
192 if (getNode()->kind() == Node::KIND_SET) {
193 types.push_back(
194 cppu::UnoType< css::lang::XSingleServiceFactory >::get());
196 } else {
197 types.push_back(
198 cppu::UnoType< css::container::XHierarchicalNameAccess >::get());
200 addTypes(&types);
201 return types.getAsConstList();
204 css::uno::Sequence< sal_Int8 > Access::getImplementationId()
205 throw (css::uno::RuntimeException)
207 assert(thisIs(IS_ANY));
208 osl::MutexGuard g(*lock_);
209 checkLocalizedPropertyAccess();
210 return css::uno::Sequence< sal_Int8 >();
213 OUString Access::getImplementationName() throw (css::uno::RuntimeException)
215 assert(thisIs(IS_ANY));
216 osl::MutexGuard g(*lock_);
217 checkLocalizedPropertyAccess();
218 return OUString("org.openoffice-configmgr::Access");
221 sal_Bool Access::supportsService(OUString const & ServiceName)
222 throw (css::uno::RuntimeException)
224 assert(thisIs(IS_ANY));
225 osl::MutexGuard g(*lock_);
226 checkLocalizedPropertyAccess();
227 css::uno::Sequence< OUString > names(getSupportedServiceNames());
228 for (sal_Int32 i = 0; i < names.getLength(); ++i) {
229 if (names[i] == ServiceName) {
230 return true;
233 return false;
236 css::uno::Sequence< OUString > Access::getSupportedServiceNames()
237 throw (css::uno::RuntimeException)
239 assert(thisIs(IS_ANY));
240 osl::MutexGuard g(*lock_);
241 checkLocalizedPropertyAccess();
242 comphelper::SequenceAsVector< OUString > services;
243 services.push_back(
244 OUString("com.sun.star.configuration.ConfigurationAccess"));
245 if (getRootAccess()->isUpdate()) {
246 services.push_back(
247 OUString("com.sun.star.configuration.ConfigurationUpdateAccess"));
249 services.push_back(
250 OUString("com.sun.star.configuration.HierarchyAccess"));
251 services.push_back(
252 OUString("com.sun.star.configuration.HierarchyElement"));
253 if (getNode()->kind() == Node::KIND_GROUP) {
254 services.push_back(
255 OUString("com.sun.star.configuration.GroupAccess"));
256 services.push_back(
257 OUString("com.sun.star.configuration.PropertyHierarchy"));
258 if (getRootAccess()->isUpdate()) {
259 services.push_back(
260 OUString("com.sun.star.configuration.GroupUpdate"));
262 } else {
263 services.push_back(
264 OUString("com.sun.star.configuration.SetAccess"));
265 services.push_back(
266 OUString("com.sun.star.configuration.SimpleSetAccess"));
267 if (getRootAccess()->isUpdate()) {
268 services.push_back(
269 OUString("com.sun.star.configuration.SetUpdate"));
270 services.push_back(
271 OUString("com.sun.star.configuration.SimpleSetUpdate"));
274 addSupportedServiceNames(&services);
275 return services.getAsConstList();
278 void Access::dispose() throw (css::uno::RuntimeException) {
279 assert(thisIs(IS_ANY));
280 Broadcaster bc;
282 osl::MutexGuard g(*lock_);
283 checkLocalizedPropertyAccess();
284 if (getParentAccess().is()) {
285 throw css::uno::RuntimeException(
286 OUString("configmgr dispose inappropriate Access"),
287 static_cast< cppu::OWeakObject * >(this));
289 if (disposed_) {
290 return;
292 initDisposeBroadcaster(&bc);
293 clearListeners();
294 disposed_ = true;
296 bc.send();
299 void Access::addEventListener(
300 css::uno::Reference< css::lang::XEventListener > const & xListener)
301 throw (css::uno::RuntimeException)
303 assert(thisIs(IS_ANY));
305 osl::MutexGuard g(*lock_);
306 checkLocalizedPropertyAccess();
307 if (!xListener.is()) {
308 throw css::uno::RuntimeException(
309 OUString("null listener"),
310 static_cast< cppu::OWeakObject * >(this));
312 if (!disposed_) {
313 disposeListeners_.insert(xListener);
314 return;
317 try {
318 xListener->disposing(
319 css::lang::EventObject(static_cast< cppu::OWeakObject * >(this)));
320 } catch (css::lang::DisposedException &) {}
323 void Access::removeEventListener(
324 css::uno::Reference< css::lang::XEventListener > const & aListener)
325 throw (css::uno::RuntimeException)
327 assert(thisIs(IS_ANY));
328 osl::MutexGuard g(*lock_);
329 checkLocalizedPropertyAccess();
330 DisposeListeners::iterator i(disposeListeners_.find(aListener));
331 if (i != disposeListeners_.end()) {
332 disposeListeners_.erase(i);
336 css::uno::Type Access::getElementType() throw (css::uno::RuntimeException) {
337 assert(thisIs(IS_ANY));
338 osl::MutexGuard g(*lock_);
339 checkLocalizedPropertyAccess();
340 rtl::Reference< Node > p(getNode());
341 switch (p->kind()) {
342 case Node::KIND_LOCALIZED_PROPERTY:
343 return mapType(
344 dynamic_cast< LocalizedPropertyNode * >(p.get())->getStaticType());
345 case Node::KIND_GROUP:
346 //TODO: Should a specific type be returned for a non-extensible group
347 // with homogeneous members or for an extensible group that currently
348 // has only homegeneous members?
349 return cppu::UnoType< cppu::UnoVoidType >::get();
350 case Node::KIND_SET:
351 return cppu::UnoType< cppu::UnoVoidType >::get(); //TODO: correct?
352 default:
353 assert(false);
354 throw css::uno::RuntimeException(
355 OUString("this cannot happen"),
356 static_cast< cppu::OWeakObject * >(this));
360 sal_Bool Access::hasElements() throw (css::uno::RuntimeException) {
361 assert(thisIs(IS_ANY));
362 osl::MutexGuard g(*lock_);
363 checkLocalizedPropertyAccess();
364 return !getAllChildren().empty(); //TODO: optimize
367 css::uno::Any Access::getByName(OUString const & aName)
368 throw (
369 css::container::NoSuchElementException,
370 css::lang::WrappedTargetException, css::uno::RuntimeException)
372 assert(thisIs(IS_ANY));
373 osl::MutexGuard g(*lock_);
374 checkLocalizedPropertyAccess();
375 rtl::Reference< ChildAccess > child(getChild(aName));
376 if (!child.is()) {
377 throw css::container::NoSuchElementException(
378 aName, static_cast< cppu::OWeakObject * >(this));
380 return child->asValue();
383 css::uno::Sequence< OUString > Access::getElementNames()
384 throw (css::uno::RuntimeException)
386 assert(thisIs(IS_ANY));
387 osl::MutexGuard g(*lock_);
388 checkLocalizedPropertyAccess();
389 std::vector< rtl::Reference< ChildAccess > > children(getAllChildren());
390 comphelper::SequenceAsVector< OUString > names;
391 for (std::vector< rtl::Reference< ChildAccess > >::iterator i(
392 children.begin());
393 i != children.end(); ++i)
395 names.push_back((*i)->getNameInternal());
397 return names.getAsConstList();
400 sal_Bool Access::hasByName(OUString const & aName)
401 throw (css::uno::RuntimeException)
403 assert(thisIs(IS_ANY));
404 osl::MutexGuard g(*lock_);
405 checkLocalizedPropertyAccess();
406 return getChild(aName).is();
409 css::uno::Any Access::getByHierarchicalName(OUString const & aName)
410 throw (css::container::NoSuchElementException, css::uno::RuntimeException)
412 assert(thisIs(IS_ANY));
413 osl::MutexGuard g(*lock_);
414 checkLocalizedPropertyAccess();
415 rtl::Reference< ChildAccess > child(getSubChild(aName));
416 if (!child.is()) {
417 throw css::container::NoSuchElementException(
418 aName, static_cast< cppu::OWeakObject * >(this));
420 return child->asValue();
423 sal_Bool Access::hasByHierarchicalName(OUString const & aName)
424 throw (css::uno::RuntimeException)
426 assert(thisIs(IS_ANY));
427 osl::MutexGuard g(*lock_);
428 checkLocalizedPropertyAccess();
429 return getSubChild(aName).is();
432 void Access::replaceByHierarchicalName(
433 OUString const & aName, css::uno::Any const & aElement)
434 throw (
435 css::lang::IllegalArgumentException,
436 css::container::NoSuchElementException,
437 css::lang::WrappedTargetException, css::uno::RuntimeException)
439 //TODO: Actually support sets and combine with replaceByName:
440 assert(thisIs(IS_UPDATE));
441 Broadcaster bc;
443 osl::MutexGuard g(*lock_);
444 checkLocalizedPropertyAccess();
445 rtl::Reference< ChildAccess > child(getSubChild(aName));
446 if (!child.is()) {
447 throw css::container::NoSuchElementException(
448 aName, static_cast< cppu::OWeakObject * >(this));
450 child->checkFinalized();
451 rtl::Reference< Node > parent(child->getParentNode());
452 assert(parent.is());
453 Modifications localMods;
454 switch (parent->kind()) {
455 case Node::KIND_LOCALIZED_PROPERTY:
456 case Node::KIND_GROUP:
457 child->setProperty(aElement, &localMods);
458 break;
459 case Node::KIND_SET:
460 throw css::lang::IllegalArgumentException(
461 OUString("configmgr::Access::replaceByHierarchicalName does not"
462 " currently support set members"),
463 static_cast< cppu::OWeakObject * >(this), 0);
464 case Node::KIND_ROOT:
465 throw css::lang::IllegalArgumentException(
466 (OUString("configmgr::Access::replaceByHierarchicalName does not"
467 " allow changing component ")
468 + aName),
469 static_cast< cppu::OWeakObject * >(this), 0);
470 default:
471 assert(false); // this cannot happen
472 break;
474 getNotificationRoot()->initBroadcaster(localMods.getRoot(), &bc);
476 bc.send();
479 void Access::addContainerListener(
480 css::uno::Reference< css::container::XContainerListener > const & xListener)
481 throw (css::uno::RuntimeException)
483 assert(thisIs(IS_ANY));
485 osl::MutexGuard g(*lock_);
486 checkLocalizedPropertyAccess();
487 if (!xListener.is()) {
488 throw css::uno::RuntimeException(
489 OUString("null listener"),
490 static_cast< cppu::OWeakObject * >(this));
492 if (!disposed_) {
493 containerListeners_.insert(xListener);
494 return;
497 try {
498 xListener->disposing(
499 css::lang::EventObject(static_cast< cppu::OWeakObject * >(this)));
500 } catch (css::lang::DisposedException &) {}
503 void Access::removeContainerListener(
504 css::uno::Reference< css::container::XContainerListener > const & xListener)
505 throw (css::uno::RuntimeException)
507 assert(thisIs(IS_ANY));
508 osl::MutexGuard g(*lock_);
509 checkLocalizedPropertyAccess();
510 ContainerListeners::iterator i(containerListeners_.find(xListener));
511 if (i != containerListeners_.end()) {
512 containerListeners_.erase(i);
516 OUString Access::getExactName(OUString const & aApproximateName)
517 throw (css::uno::RuntimeException)
519 assert(thisIs(IS_ANY));
520 osl::MutexGuard g(*lock_);
521 checkLocalizedPropertyAccess();
522 return aApproximateName;
525 css::uno::Sequence< css::beans::Property > Access::getProperties()
526 throw (css::uno::RuntimeException)
528 assert(thisIs(IS_GROUP));
529 osl::MutexGuard g(*lock_);
530 std::vector< rtl::Reference< ChildAccess > > children(getAllChildren());
531 comphelper::SequenceAsVector< css::beans::Property > properties;
532 for (std::vector< rtl::Reference< ChildAccess > >::iterator i(
533 children.begin());
534 i != children.end(); ++i)
536 properties.push_back((*i)->asProperty());
538 return properties.getAsConstList();
541 css::beans::Property Access::getPropertyByName(OUString const & aName)
542 throw (css::beans::UnknownPropertyException, css::uno::RuntimeException)
544 assert(thisIs(IS_GROUP));
545 osl::MutexGuard g(*lock_);
546 rtl::Reference< ChildAccess > child(getChild(aName));
547 if (!child.is()) {
548 throw css::beans::UnknownPropertyException(
549 aName, static_cast< cppu::OWeakObject * >(this));
551 return child->asProperty();
554 sal_Bool Access::hasPropertyByName(OUString const & Name)
555 throw (css::uno::RuntimeException)
557 assert(thisIs(IS_GROUP));
558 osl::MutexGuard g(*lock_);
559 return getChild(Name).is();
562 OUString Access::getHierarchicalName() throw (css::uno::RuntimeException) {
563 assert(thisIs(IS_ANY));
564 osl::MutexGuard g(*lock_);
565 checkLocalizedPropertyAccess();
566 // For backwards compatibility, return an absolute path representation where
567 // available:
568 OUString rootPath;
569 rtl::Reference< RootAccess > root(getRootAccess());
570 if (root.is()) {
571 rootPath = root->getAbsolutePathRepresentation();
573 OUString rel(getRelativePathRepresentation());
574 OUStringBuffer path(rootPath);
575 if (!rootPath.isEmpty() && rootPath != "/" && !rel.isEmpty()) {
576 path.append('/');
578 path.append(rel);
579 return path.makeStringAndClear();
582 OUString Access::composeHierarchicalName(
583 OUString const & aRelativeName)
584 throw (
585 css::lang::IllegalArgumentException, css::lang::NoSupportException,
586 css::uno::RuntimeException)
588 assert(thisIs(IS_ANY));
589 osl::MutexGuard g(*lock_);
590 checkLocalizedPropertyAccess();
591 if (aRelativeName.isEmpty() || aRelativeName[0] == '/') {
592 throw css::lang::IllegalArgumentException(
593 OUString("configmgr composeHierarchicalName inappropriate relative"
594 " name"),
595 static_cast< cppu::OWeakObject * >(this), -1);
597 OUStringBuffer path(getRelativePathRepresentation());
598 if (path.getLength() != 0) {
599 path.append(sal_Unicode('/'));
601 path.append(aRelativeName);
602 return path.makeStringAndClear();
605 OUString Access::getName() throw (css::uno::RuntimeException) {
606 assert(thisIs(IS_ANY));
607 osl::MutexGuard g(*lock_);
608 checkLocalizedPropertyAccess();
609 return getNameInternal();
612 void Access::setName(OUString const & aName)
613 throw (css::uno::RuntimeException)
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 rtl::Reference< RootAccess > root(getRootAccess());
639 rtl::Reference< ChildAccess > childAccess(
640 dynamic_cast< ChildAccess * >(this));
641 localMods.add(getRelativePath());
642 // unbind() modifies the parent chain that
643 // markChildAsModified() walks, so order is
644 // important:
645 parent->markChildAsModified(childAccess);
646 //TODO: must not throw
647 childAccess->unbind(); // must not throw
648 if (other.is()) {
649 other->unbind(); // must not throw
651 childAccess->bind(root, parent, aName);
652 // must not throw
653 parent->markChildAsModified(childAccess);
654 //TODO: must not throw
655 localMods.add(getRelativePath());
656 break;
661 // fall through
662 case Node::KIND_LOCALIZED_PROPERTY:
663 // renaming a property could only work for an extension property,
664 // but a localized property is never an extension property
665 throw css::uno::RuntimeException(
666 OUString("configmgr setName inappropriate node"),
667 static_cast< cppu::OWeakObject * >(this));
668 default:
669 assert(false); // this cannot happen
670 break;
672 getNotificationRoot()->initBroadcaster(localMods.getRoot(), &bc);
674 bc.send();
677 css::beans::Property Access::getAsProperty() throw (css::uno::RuntimeException)
679 assert(thisIs(IS_ANY));
680 osl::MutexGuard g(*lock_);
681 checkLocalizedPropertyAccess();
682 return asProperty();
685 css::uno::Reference< css::beans::XPropertySetInfo > Access::getPropertySetInfo()
686 throw (css::uno::RuntimeException)
688 assert(thisIs(IS_GROUP));
689 return this;
692 void Access::setPropertyValue(
693 OUString const & aPropertyName, css::uno::Any const & aValue)
694 throw (
695 css::beans::UnknownPropertyException, css::beans::PropertyVetoException,
696 css::lang::IllegalArgumentException, css::lang::WrappedTargetException,
697 css::uno::RuntimeException)
699 assert(thisIs(IS_GROUP));
700 Broadcaster bc;
702 osl::MutexGuard g(*lock_);
703 if (!getRootAccess()->isUpdate()) {
704 throw css::uno::RuntimeException(
705 OUString("configmgr setPropertyValue on non-update access"),
706 static_cast< cppu::OWeakObject * >(this));
708 Modifications localMods;
709 if (!setChildProperty(aPropertyName, aValue, &localMods)) {
710 throw css::beans::UnknownPropertyException(
711 aPropertyName, static_cast< cppu::OWeakObject * >(this));
713 getNotificationRoot()->initBroadcaster(localMods.getRoot(), &bc);
715 bc.send();
718 css::uno::Any Access::getPropertyValue(OUString const & PropertyName)
719 throw (
720 css::beans::UnknownPropertyException, css::lang::WrappedTargetException,
721 css::uno::RuntimeException)
723 assert(thisIs(IS_GROUP));
724 osl::MutexGuard g(*lock_);
725 rtl::Reference< ChildAccess > child(getChild(PropertyName));
726 if (!child.is()) {
727 throw css::beans::UnknownPropertyException(
728 PropertyName, static_cast< cppu::OWeakObject * >(this));
730 return child->asValue();
733 void Access::addPropertyChangeListener(
734 OUString const & aPropertyName,
735 css::uno::Reference< css::beans::XPropertyChangeListener > const &
736 xListener)
737 throw (
738 css::beans::UnknownPropertyException, css::lang::WrappedTargetException,
739 css::uno::RuntimeException)
741 assert(thisIs(IS_GROUP));
743 osl::MutexGuard g(*lock_);
744 if (!xListener.is()) {
745 throw css::uno::RuntimeException(
746 OUString("null listener"),
747 static_cast< cppu::OWeakObject * >(this));
749 checkKnownProperty(aPropertyName);
750 if (!disposed_) {
751 propertyChangeListeners_[aPropertyName].insert(xListener);
752 return;
755 try {
756 xListener->disposing(
757 css::lang::EventObject(static_cast< cppu::OWeakObject * >(this)));
758 } catch (css::lang::DisposedException &) {}
761 void Access::removePropertyChangeListener(
762 OUString const & aPropertyName,
763 css::uno::Reference< css::beans::XPropertyChangeListener > const &
764 aListener)
765 throw (
766 css::beans::UnknownPropertyException, css::lang::WrappedTargetException,
767 css::uno::RuntimeException)
769 assert(thisIs(IS_GROUP));
770 osl::MutexGuard g(*lock_);
771 checkKnownProperty(aPropertyName);
772 PropertyChangeListeners::iterator i(
773 propertyChangeListeners_.find(aPropertyName));
774 if (i != propertyChangeListeners_.end()) {
775 PropertyChangeListenersElement::iterator j(i->second.find(aListener));
776 if (j != i->second.end()) {
777 i->second.erase(j);
778 if (i->second.empty()) {
779 propertyChangeListeners_.erase(i);
785 void Access::addVetoableChangeListener(
786 OUString const & PropertyName,
787 css::uno::Reference< css::beans::XVetoableChangeListener > const &
788 aListener)
789 throw (
790 css::beans::UnknownPropertyException, css::lang::WrappedTargetException,
791 css::uno::RuntimeException)
793 assert(thisIs(IS_GROUP));
795 osl::MutexGuard g(*lock_);
796 if (!aListener.is()) {
797 throw css::uno::RuntimeException(
798 OUString("null listener"),
799 static_cast< cppu::OWeakObject * >(this));
801 checkKnownProperty(PropertyName);
802 if (!disposed_) {
803 vetoableChangeListeners_[PropertyName].insert(aListener);
804 //TODO: actually call vetoableChangeListeners_
805 return;
808 try {
809 aListener->disposing(
810 css::lang::EventObject(static_cast< cppu::OWeakObject * >(this)));
811 } catch (css::lang::DisposedException &) {}
814 void Access::removeVetoableChangeListener(
815 OUString const & PropertyName,
816 css::uno::Reference< css::beans::XVetoableChangeListener > const &
817 aListener)
818 throw (
819 css::beans::UnknownPropertyException, css::lang::WrappedTargetException,
820 css::uno::RuntimeException)
822 assert(thisIs(IS_GROUP));
823 osl::MutexGuard g(*lock_);
824 checkKnownProperty(PropertyName);
825 VetoableChangeListeners::iterator i(
826 vetoableChangeListeners_.find(PropertyName));
827 if (i != vetoableChangeListeners_.end()) {
828 VetoableChangeListenersElement::iterator j(i->second.find(aListener));
829 if (j != i->second.end()) {
830 i->second.erase(j);
831 if (i->second.empty()) {
832 vetoableChangeListeners_.erase(i);
838 void Access::setPropertyValues(
839 css::uno::Sequence< OUString > const & aPropertyNames,
840 css::uno::Sequence< css::uno::Any > const & aValues)
841 throw (
842 css::beans::PropertyVetoException, css::lang::IllegalArgumentException,
843 css::lang::WrappedTargetException, css::uno::RuntimeException)
845 assert(thisIs(IS_GROUP));
846 Broadcaster bc;
848 osl::MutexGuard g(*lock_);
849 if (!getRootAccess()->isUpdate()) {
850 throw css::uno::RuntimeException(
851 OUString("configmgr setPropertyValues on non-update access"),
852 static_cast< cppu::OWeakObject * >(this));
854 if (aPropertyNames.getLength() != aValues.getLength()) {
855 throw css::lang::IllegalArgumentException(
856 OUString("configmgr setPropertyValues: aPropertyNames/aValues of"
857 " different length"),
858 static_cast< cppu::OWeakObject * >(this), -1);
860 Modifications localMods;
861 for (sal_Int32 i = 0; i < aPropertyNames.getLength(); ++i) {
862 if (!setChildProperty(aPropertyNames[i], aValues[i], &localMods)) {
863 throw css::lang::IllegalArgumentException(
864 OUString("configmgr setPropertyValues inappropriate property"
865 " name"),
866 static_cast< cppu::OWeakObject * >(this), -1);
869 getNotificationRoot()->initBroadcaster(localMods.getRoot(), &bc);
871 bc.send();
874 css::uno::Sequence< css::uno::Any > Access::getPropertyValues(
875 css::uno::Sequence< OUString > const & aPropertyNames)
876 throw (css::uno::RuntimeException)
878 assert(thisIs(IS_GROUP));
879 osl::MutexGuard g(*lock_);
880 css::uno::Sequence< css::uno::Any > vals(aPropertyNames.getLength());
881 for (sal_Int32 i = 0; i < aPropertyNames.getLength(); ++i) {
882 rtl::Reference< ChildAccess > child(getChild(aPropertyNames[i]));
883 if (!child.is()) {
884 throw css::uno::RuntimeException(
885 OUString("configmgr getPropertyValues inappropriate property"
886 " name"),
887 static_cast< cppu::OWeakObject * >(this));
889 vals[i] = child->asValue();
891 return vals;
894 void Access::addPropertiesChangeListener(
895 css::uno::Sequence< OUString > const &,
896 css::uno::Reference< css::beans::XPropertiesChangeListener > const &
897 xListener)
898 throw (css::uno::RuntimeException)
900 assert(thisIs(IS_GROUP));
902 osl::MutexGuard g(*lock_);
903 if (!xListener.is()) {
904 throw css::uno::RuntimeException(
905 OUString("null listener"),
906 static_cast< cppu::OWeakObject * >(this));
908 if (!disposed_) {
909 propertiesChangeListeners_.insert(xListener);
910 return;
913 try {
914 xListener->disposing(
915 css::lang::EventObject(static_cast< cppu::OWeakObject * >(this)));
916 } catch (css::lang::DisposedException &) {}
919 void Access::removePropertiesChangeListener(
920 css::uno::Reference< css::beans::XPropertiesChangeListener > const &
921 xListener)
922 throw (css::uno::RuntimeException)
924 assert(thisIs(IS_GROUP));
925 osl::MutexGuard g(*lock_);
926 PropertiesChangeListeners::iterator i(
927 propertiesChangeListeners_.find(xListener));
928 if (i != propertiesChangeListeners_.end()) {
929 propertiesChangeListeners_.erase(i);
933 void Access::firePropertiesChangeEvent(
934 css::uno::Sequence< OUString > const & aPropertyNames,
935 css::uno::Reference< css::beans::XPropertiesChangeListener > const &
936 xListener)
937 throw (css::uno::RuntimeException)
939 assert(thisIs(IS_GROUP));
940 css::uno::Sequence< css::beans::PropertyChangeEvent > events(
941 aPropertyNames.getLength());
942 for (sal_Int32 i = 0; i < events.getLength(); ++i) {
943 events[i].Source = static_cast< cppu::OWeakObject * >(this);
944 events[i].PropertyName = aPropertyNames[i];
945 events[i].Further = false;
946 events[i].PropertyHandle = -1;
948 xListener->propertiesChange(events);
951 css::uno::Reference< css::beans::XHierarchicalPropertySetInfo >
952 Access::getHierarchicalPropertySetInfo() throw (css::uno::RuntimeException) {
953 assert(thisIs(IS_GROUP));
954 return this;
957 void Access::setHierarchicalPropertyValue(
958 OUString const & aHierarchicalPropertyName,
959 css::uno::Any const & aValue)
960 throw (
961 css::beans::UnknownPropertyException, css::beans::PropertyVetoException,
962 css::lang::IllegalArgumentException, css::lang::WrappedTargetException,
963 css::uno::RuntimeException)
965 assert(thisIs(IS_GROUP));
966 Broadcaster bc;
968 osl::MutexGuard g(*lock_);
969 if (!getRootAccess()->isUpdate()) {
970 throw css::uno::RuntimeException(
971 OUString("configmgr setHierarchicalPropertyName on non-update"
972 " access"),
973 static_cast< cppu::OWeakObject * >(this));
975 rtl::Reference< ChildAccess > child(
976 getSubChild(aHierarchicalPropertyName));
977 if (!child.is()) {
978 throw css::beans::UnknownPropertyException(
979 aHierarchicalPropertyName,
980 static_cast< cppu::OWeakObject * >(this));
982 child->checkFinalized();
983 Modifications localMods;
984 child->setProperty(aValue, &localMods);
985 getNotificationRoot()->initBroadcaster(localMods.getRoot(), &bc);
987 bc.send();
990 css::uno::Any Access::getHierarchicalPropertyValue(
991 OUString const & aHierarchicalPropertyName)
992 throw (
993 css::beans::UnknownPropertyException,
994 css::lang::IllegalArgumentException, css::lang::WrappedTargetException,
995 css::uno::RuntimeException)
997 assert(thisIs(IS_GROUP));
998 osl::MutexGuard g(*lock_);
999 rtl::Reference< ChildAccess > child(getSubChild(aHierarchicalPropertyName));
1000 if (!child.is()) {
1001 throw css::beans::UnknownPropertyException(
1002 aHierarchicalPropertyName,
1003 static_cast< cppu::OWeakObject * >(this));
1005 return child->asValue();
1008 void Access::setHierarchicalPropertyValues(
1009 css::uno::Sequence< OUString > const & aHierarchicalPropertyNames,
1010 css::uno::Sequence< css::uno::Any > const & Values)
1011 throw (
1012 css::beans::PropertyVetoException, css::lang::IllegalArgumentException,
1013 css::lang::WrappedTargetException, css::uno::RuntimeException)
1015 assert(thisIs(IS_GROUP));
1016 Broadcaster bc;
1018 osl::MutexGuard g(*lock_);
1019 if (!getRootAccess()->isUpdate()) {
1020 throw css::uno::RuntimeException(
1021 OUString("configmgr setPropertyValues on non-update access"),
1022 static_cast< cppu::OWeakObject * >(this));
1024 if (aHierarchicalPropertyNames.getLength() != Values.getLength()) {
1025 throw css::lang::IllegalArgumentException(
1026 OUString("configmgr setHierarchicalPropertyValues:"
1027 " aHierarchicalPropertyNames/Values of different"
1028 " length"),
1029 static_cast< cppu::OWeakObject * >(this), -1);
1031 Modifications localMods;
1032 for (sal_Int32 i = 0; i < aHierarchicalPropertyNames.getLength(); ++i) {
1033 rtl::Reference< ChildAccess > child(
1034 getSubChild(aHierarchicalPropertyNames[i]));
1035 if (!child.is()) {
1036 throw css::lang::IllegalArgumentException(
1037 OUString("configmgr setHierarchicalPropertyValues"
1038 " inappropriate property name"),
1039 static_cast< cppu::OWeakObject * >(this), -1);
1041 child->checkFinalized();
1042 child->setProperty(Values[i], &localMods);
1044 getNotificationRoot()->initBroadcaster(localMods.getRoot(), &bc);
1046 bc.send();
1049 css::uno::Sequence< css::uno::Any > Access::getHierarchicalPropertyValues(
1050 css::uno::Sequence< OUString > const & aHierarchicalPropertyNames)
1051 throw (
1052 css::lang::IllegalArgumentException, css::lang::WrappedTargetException,
1053 css::uno::RuntimeException)
1055 assert(thisIs(IS_GROUP));
1056 osl::MutexGuard g(*lock_);
1057 css::uno::Sequence< css::uno::Any > vals(
1058 aHierarchicalPropertyNames.getLength());
1059 for (sal_Int32 i = 0; i < aHierarchicalPropertyNames.getLength(); ++i) {
1060 rtl::Reference< ChildAccess > child(
1061 getSubChild(aHierarchicalPropertyNames[i]));
1062 if (!child.is()) {
1063 throw css::lang::IllegalArgumentException(
1064 OUString("configmgr getHierarchicalPropertyValues inappropriate"
1065 " hierarchical property name"),
1066 static_cast< cppu::OWeakObject * >(this), -1);
1068 vals[i] = child->asValue();
1070 return vals;
1073 css::beans::Property Access::getPropertyByHierarchicalName(
1074 OUString const & aHierarchicalName)
1075 throw (css::beans::UnknownPropertyException, css::uno::RuntimeException)
1077 assert(thisIs(IS_GROUP));
1078 osl::MutexGuard g(*lock_);
1079 rtl::Reference< ChildAccess > child(getSubChild(aHierarchicalName));
1080 if (!child.is()) {
1081 throw css::beans::UnknownPropertyException(
1082 aHierarchicalName, static_cast< cppu::OWeakObject * >(this));
1084 return child->asProperty();
1087 sal_Bool Access::hasPropertyByHierarchicalName(
1088 OUString const & aHierarchicalName)
1089 throw (css::uno::RuntimeException)
1091 assert(thisIs(IS_GROUP));
1092 osl::MutexGuard g(*lock_);
1093 return getSubChild(aHierarchicalName).is();
1096 void Access::replaceByName(
1097 OUString const & aName, css::uno::Any const & aElement)
1098 throw (
1099 css::lang::IllegalArgumentException,
1100 css::container::NoSuchElementException,
1101 css::lang::WrappedTargetException, css::uno::RuntimeException)
1103 assert(thisIs(IS_UPDATE));
1104 Broadcaster bc;
1106 osl::MutexGuard g(*lock_);
1107 checkLocalizedPropertyAccess();
1108 rtl::Reference< ChildAccess > child(getChild(aName));
1109 if (!child.is()) {
1110 throw css::container::NoSuchElementException(
1111 aName, static_cast< cppu::OWeakObject * >(this));
1113 child->checkFinalized();
1114 Modifications localMods;
1115 switch (getNode()->kind()) {
1116 case Node::KIND_LOCALIZED_PROPERTY:
1117 case Node::KIND_GROUP:
1118 child->setProperty(aElement, &localMods);
1119 break;
1120 case Node::KIND_SET:
1122 rtl::Reference< ChildAccess > freeAcc(
1123 getFreeSetMember(aElement));
1124 rtl::Reference< RootAccess > root(getRootAccess());
1125 localMods.add(child->getRelativePath());
1126 child->unbind(); // must not throw
1127 freeAcc->bind(root, this, aName); // must not throw
1128 markChildAsModified(freeAcc); //TODO: must not throw
1130 break;
1131 default:
1132 assert(false); // this cannot happen
1133 break;
1135 getNotificationRoot()->initBroadcaster(localMods.getRoot(), &bc);
1137 bc.send();
1140 void Access::insertByName(
1141 OUString const & aName, css::uno::Any const & aElement)
1142 throw (
1143 css::lang::IllegalArgumentException,
1144 css::container::ElementExistException,
1145 css::lang::WrappedTargetException, css::uno::RuntimeException)
1147 assert(thisIs(IS_EXTENSIBLE|IS_UPDATE));
1148 Broadcaster bc;
1150 osl::MutexGuard g(*lock_);
1151 checkLocalizedPropertyAccess();
1152 checkFinalized();
1153 if (getChild(aName).is()) {
1154 throw css::container::ElementExistException(
1155 aName, static_cast< cppu::OWeakObject * >(this));
1157 Modifications localMods;
1158 switch (getNode()->kind()) {
1159 case Node::KIND_LOCALIZED_PROPERTY:
1160 insertLocalizedValueChild(aName, aElement, &localMods);
1161 break;
1162 case Node::KIND_GROUP:
1164 checkValue(aElement, TYPE_ANY, true);
1165 rtl::Reference< ChildAccess > child(
1166 new ChildAccess(
1167 components_, getRootAccess(), this, aName,
1168 new PropertyNode(
1169 Data::NO_LAYER, TYPE_ANY, true, aElement, true)));
1170 markChildAsModified(child);
1171 localMods.add(child->getRelativePath());
1173 break;
1174 case Node::KIND_SET:
1176 rtl::Reference< ChildAccess > freeAcc(
1177 getFreeSetMember(aElement));
1178 freeAcc->bind(getRootAccess(), this, aName); // must not throw
1179 markChildAsModified(freeAcc); //TODO: must not throw
1180 localMods.add(freeAcc->getRelativePath());
1182 break;
1183 default:
1184 assert(false); // this cannot happen
1185 break;
1187 getNotificationRoot()->initBroadcaster(localMods.getRoot(), &bc);
1189 bc.send();
1192 void Access::removeByName(OUString const & aName)
1193 throw (
1194 css::container::NoSuchElementException,
1195 css::lang::WrappedTargetException, css::uno::RuntimeException)
1197 assert(thisIs(IS_EXTENSIBLE|IS_UPDATE));
1198 Broadcaster bc;
1200 osl::MutexGuard g(*lock_);
1201 checkLocalizedPropertyAccess();
1202 rtl::Reference< ChildAccess > child(getChild(aName));
1203 if (!child.is() || child->isFinalized() ||
1204 child->getNode()->getMandatory() != Data::NO_LAYER)
1206 throw css::container::NoSuchElementException(
1207 aName, static_cast< cppu::OWeakObject * >(this));
1209 if (getNode()->kind() == Node::KIND_GROUP) {
1210 rtl::Reference< Node > p(child->getNode());
1211 if (p->kind() != Node::KIND_PROPERTY ||
1212 !dynamic_cast< PropertyNode * >(p.get())->isExtension())
1214 throw css::container::NoSuchElementException(
1215 aName, static_cast< cppu::OWeakObject * >(this));
1218 Modifications localMods;
1219 localMods.add(child->getRelativePath());
1220 // unbind() modifies the parent chain that markChildAsModified() walks,
1221 // so order is important:
1222 markChildAsModified(child); //TODO: must not throw
1223 child->unbind();
1224 getNotificationRoot()->initBroadcaster(localMods.getRoot(), &bc);
1226 bc.send();
1229 css::uno::Reference< css::uno::XInterface > Access::createInstance()
1230 throw (css::uno::Exception, css::uno::RuntimeException)
1232 assert(thisIs(IS_SET|IS_UPDATE));
1233 OUString tmplName(
1234 dynamic_cast< SetNode * >(getNode().get())->getDefaultTemplateName());
1235 rtl::Reference< Node > tmpl(
1236 components_.getTemplate(Data::NO_LAYER, tmplName));
1237 if (!tmpl.is()) {
1238 throw css::uno::Exception(
1239 (OUString("unknown template ") +
1240 tmplName),
1241 static_cast< cppu::OWeakObject * >(this));
1243 rtl::Reference< Node > node(tmpl->clone(true));
1244 node->setLayer(Data::NO_LAYER);
1245 return static_cast< cppu::OWeakObject * >(
1246 new ChildAccess(components_, getRootAccess(), node));
1249 css::uno::Reference< css::uno::XInterface > Access::createInstanceWithArguments(
1250 css::uno::Sequence< css::uno::Any > const & aArguments)
1251 throw (css::uno::Exception, css::uno::RuntimeException)
1253 assert(thisIs(IS_SET|IS_UPDATE));
1254 if (aArguments.getLength() != 0) {
1255 throw css::uno::Exception(
1256 OUString("configuration SimpleSetUpdate createInstanceWithArguments"
1257 " must not specify any arguments"),
1258 static_cast< cppu::OWeakObject * >(this));
1260 return createInstance();
1263 Access::Access(Components & components):
1264 components_(components), disposed_(false)
1266 lock_ = lock();
1269 Access::~Access() {}
1271 void Access::initDisposeBroadcaster(Broadcaster * broadcaster) {
1272 assert(broadcaster != 0);
1273 for (DisposeListeners::iterator i(disposeListeners_.begin());
1274 i != disposeListeners_.end(); ++i)
1276 broadcaster->addDisposeNotification(
1278 css::lang::EventObject(static_cast< cppu::OWeakObject * >(this)));
1280 for (ContainerListeners::iterator i(containerListeners_.begin());
1281 i != containerListeners_.end(); ++i)
1283 broadcaster->addDisposeNotification(
1284 i->get(),
1285 css::lang::EventObject(static_cast< cppu::OWeakObject * >(this)));
1287 for (PropertyChangeListeners::iterator i(propertyChangeListeners_.begin());
1288 i != propertyChangeListeners_.end(); ++i)
1290 for (PropertyChangeListenersElement::iterator j(i->second.begin());
1291 j != i->second.end(); ++j)
1293 broadcaster->addDisposeNotification(
1294 j->get(),
1295 css::lang::EventObject(
1296 static_cast< cppu::OWeakObject * >(this)));
1299 for (VetoableChangeListeners::iterator i(vetoableChangeListeners_.begin());
1300 i != vetoableChangeListeners_.end(); ++i)
1302 for (VetoableChangeListenersElement::iterator j(i->second.begin());
1303 j != i->second.end(); ++j)
1305 broadcaster->addDisposeNotification(
1306 j->get(),
1307 css::lang::EventObject(
1308 static_cast< cppu::OWeakObject * >(this)));
1311 for (PropertiesChangeListeners::iterator i(
1312 propertiesChangeListeners_.begin());
1313 i != propertiesChangeListeners_.end(); ++i)
1315 broadcaster->addDisposeNotification(
1316 i->get(),
1317 css::lang::EventObject(static_cast< cppu::OWeakObject * >(this)));
1319 //TODO: iterate over children w/ listeners (incl. unmodified ones):
1320 for (ModifiedChildren::iterator i(modifiedChildren_.begin());
1321 i != modifiedChildren_.end(); ++i)
1323 rtl::Reference< ChildAccess > child(getModifiedChild(i));
1324 if (child.is()) {
1325 child->initDisposeBroadcaster(broadcaster);
1330 void Access::clearListeners() throw() {
1331 disposeListeners_.clear();
1332 containerListeners_.clear();
1333 propertyChangeListeners_.clear();
1334 vetoableChangeListeners_.clear();
1335 propertiesChangeListeners_.clear();
1336 //TODO: iterate over children w/ listeners (incl. unmodified ones):
1337 for (ModifiedChildren::iterator i(modifiedChildren_.begin());
1338 i != modifiedChildren_.end(); ++i)
1340 rtl::Reference< ChildAccess > child(getModifiedChild(i));
1341 if (child.is()) {
1342 child->clearListeners();
1347 css::uno::Any Access::queryInterface(css::uno::Type const & aType)
1348 throw (css::uno::RuntimeException)
1350 css::uno::Any res(OWeakObject::queryInterface(aType));
1351 if (res.hasValue()) {
1352 return res;
1354 res = cppu::queryInterface(
1355 aType, static_cast< css::lang::XTypeProvider * >(this),
1356 static_cast< css::lang::XServiceInfo * >(this),
1357 static_cast< css::lang::XComponent * >(this),
1358 static_cast< css::container::XHierarchicalNameAccess * >(this),
1359 static_cast< css::container::XContainer * >(this),
1360 static_cast< css::beans::XExactName * >(this),
1361 static_cast< css::container::XHierarchicalName * >(this),
1362 static_cast< css::container::XNamed * >(this),
1363 static_cast< css::beans::XProperty * >(this),
1364 static_cast< css::container::XElementAccess * >(this),
1365 static_cast< css::container::XNameAccess * >(this));
1366 if (res.hasValue()) {
1367 return res;
1369 if (getNode()->kind() == Node::KIND_GROUP) {
1370 res = cppu::queryInterface(
1371 aType, static_cast< css::beans::XPropertySetInfo * >(this),
1372 static_cast< css::beans::XPropertySet * >(this),
1373 static_cast< css::beans::XMultiPropertySet * >(this),
1374 static_cast< css::beans::XHierarchicalPropertySet * >(this),
1375 static_cast< css::beans::XMultiHierarchicalPropertySet * >(this),
1376 static_cast< css::beans::XHierarchicalPropertySetInfo * >(this));
1377 if (res.hasValue()) {
1378 return res;
1381 if (getRootAccess()->isUpdate()) {
1382 res = cppu::queryInterface(
1383 aType, static_cast< css::container::XNameReplace * >(this),
1384 static_cast< css::container::XHierarchicalNameReplace * >(this));
1385 if (res.hasValue()) {
1386 return res;
1388 if (getNode()->kind() != Node::KIND_GROUP ||
1389 dynamic_cast< GroupNode * >(getNode().get())->isExtensible())
1391 res = cppu::queryInterface(
1392 aType, static_cast< css::container::XNameContainer * >(this));
1393 if (res.hasValue()) {
1394 return res;
1397 if (getNode()->kind() == Node::KIND_SET) {
1398 res = cppu::queryInterface(
1399 aType, static_cast< css::lang::XSingleServiceFactory * >(this));
1402 return res;
1405 Components & Access::getComponents() const {
1406 return components_;
1409 void Access::checkLocalizedPropertyAccess() {
1410 if (getNode()->kind() == Node::KIND_LOCALIZED_PROPERTY &&
1411 !Components::allLocales(getRootAccess()->getLocale()))
1413 throw css::uno::RuntimeException(
1414 OUString("configmgr Access to specialized LocalizedPropertyNode"),
1415 static_cast< cppu::OWeakObject * >(this));
1419 rtl::Reference< Node > Access::getParentNode() {
1420 rtl::Reference< Access > parent(getParentAccess());
1421 return parent.is() ? parent->getNode() : rtl::Reference< Node >();
1424 rtl::Reference< ChildAccess > Access::getChild(OUString const & name) {
1425 if (getNode()->kind() == Node::KIND_LOCALIZED_PROPERTY && name.match("*")) {
1426 OUString locale(name.copy(1));
1427 if (locale.match("*")) {
1428 SAL_WARN(
1429 "configmgr",
1430 ("access best-matching localized property value via"
1431 " \"*<locale>\" with <locale> \"")
1432 << locale << "\" recursively starting with \"*\"");
1433 return getChild(locale);
1435 SAL_WARN_IF(
1436 locale.isEmpty(), "configmgr",
1437 ("access best-matching localized property value via \"*<locale>\""
1438 " with empty <locale>; falling back to defaults"));
1439 if (!locale.isEmpty()) {
1440 // Find best match using an adaption of RFC 4647 lookup matching
1441 // rules, removing "-" or "_" delimited segments from the end:
1442 for (;;) {
1443 rtl::Reference< ChildAccess > child(getChild(locale));
1444 if (child.is()) {
1445 return child;
1447 sal_Int32 i = locale.getLength() - 1;
1448 while (i > 0 && locale[i] != '-' && locale[i] != '_') {
1449 --i;
1451 if (i <= 0) {
1452 break;
1454 locale = locale.copy(0, i);
1456 // As a workaround for broken xcu data that does not use shortest
1457 // xml:lang attributes, look for the first entry with the same first
1458 // segment as the requested language tag before falling back to
1459 // defaults (see fdo#33638):
1460 assert(
1461 !locale.isEmpty() && locale.indexOf('-') == -1 &&
1462 locale.indexOf('_') == -1);
1463 std::vector< rtl::Reference< ChildAccess > > children(
1464 getAllChildren());
1465 for (std::vector< rtl::Reference< ChildAccess > >::iterator i(
1466 children.begin());
1467 i != children.end(); ++i)
1469 OUString name2((*i)->getNameInternal());
1470 if (name2.match(locale) &&
1471 (name2.getLength() == locale.getLength() ||
1472 name2[locale.getLength()] == '-' ||
1473 name2[locale.getLength()] == '_'))
1475 return *i;
1479 // Defaults are the "en-US" locale, the "en" locale, the empty string
1480 // locale, the first child (if any), or a null ChildAccess, in that
1481 // order:
1482 rtl::Reference< ChildAccess > child(getChild("en-US"));
1483 if (child.is()) {
1484 return child;
1486 child = getChild("en");
1487 if (child.is()) {
1488 return child;
1490 child = getChild(OUString());
1491 if (child.is()) {
1492 return child;
1494 std::vector< rtl::Reference< ChildAccess > > children(getAllChildren());
1495 if (!children.empty()) {
1496 return children.front();
1498 return rtl::Reference< ChildAccess >();
1500 ModifiedChildren::iterator i(modifiedChildren_.find(name));
1501 return i == modifiedChildren_.end()
1502 ? getUnmodifiedChild(name) : getModifiedChild(i);
1505 std::vector< rtl::Reference< ChildAccess > > Access::getAllChildren() {
1506 std::vector< rtl::Reference< ChildAccess > > vec;
1507 NodeMap const & members = getNode()->getMembers();
1508 for (NodeMap::const_iterator i(members.begin()); i != members.end(); ++i) {
1509 if (modifiedChildren_.find(i->first) == modifiedChildren_.end()) {
1510 vec.push_back(getUnmodifiedChild(i->first));
1511 assert(vec.back().is());
1514 for (ModifiedChildren::iterator i(modifiedChildren_.begin());
1515 i != modifiedChildren_.end(); ++i)
1517 rtl::Reference< ChildAccess > child(getModifiedChild(i));
1518 if (child.is()) {
1519 vec.push_back(child);
1522 return vec;
1525 void Access::checkValue(css::uno::Any const & value, Type type, bool nillable) {
1526 bool ok;
1527 switch (type) {
1528 case TYPE_NIL:
1529 assert(false);
1530 // fall through (cannot happen)
1531 case TYPE_ERROR:
1532 ok = false;
1533 break;
1534 case TYPE_ANY:
1535 switch (getDynamicType(value)) {
1536 case TYPE_ANY:
1537 assert(false);
1538 // fall through (cannot happen)
1539 case TYPE_ERROR:
1540 ok = false;
1541 break;
1542 case TYPE_NIL:
1543 ok = nillable;
1544 break;
1545 default:
1546 ok = true;
1547 break;
1549 break;
1550 default:
1551 ok = value.hasValue() ? value.isExtractableTo(mapType(type)) : nillable;
1552 break;
1554 if (!ok) {
1555 throw css::lang::IllegalArgumentException(
1556 OUString("configmgr inappropriate property value"),
1557 static_cast< cppu::OWeakObject * >(this), -1);
1561 void Access::insertLocalizedValueChild(
1562 OUString const & name, css::uno::Any const & value,
1563 Modifications * localModifications)
1565 assert(localModifications != 0);
1566 LocalizedPropertyNode * locprop = dynamic_cast< LocalizedPropertyNode * >(
1567 getNode().get());
1568 checkValue(value, locprop->getStaticType(), locprop->isNillable());
1569 rtl::Reference< ChildAccess > child(
1570 new ChildAccess(
1571 components_, getRootAccess(), this, name,
1572 new LocalizedValueNode(Data::NO_LAYER, value)));
1573 markChildAsModified(child);
1574 localModifications->add(child->getRelativePath());
1577 void Access::reportChildChanges(
1578 std::vector< css::util::ElementChange > * changes)
1580 assert(changes != 0);
1581 for (ModifiedChildren::iterator i(modifiedChildren_.begin());
1582 i != modifiedChildren_.end(); ++i)
1584 rtl::Reference< ChildAccess > child(getModifiedChild(i));
1585 if (child.is()) {
1586 child->reportChildChanges(changes);
1587 changes->push_back(css::util::ElementChange());
1588 //TODO: changed value and/or inserted node
1589 } else {
1590 changes->push_back(css::util::ElementChange()); //TODO: removed node
1595 void Access::commitChildChanges(
1596 bool valid, Modifications * globalModifications)
1598 assert(globalModifications != 0);
1599 while (!modifiedChildren_.empty()) {
1600 bool childValid = valid;
1601 ModifiedChildren::iterator i(modifiedChildren_.begin());
1602 rtl::Reference< ChildAccess > child(getModifiedChild(i));
1603 if (child.is()) {
1604 childValid = childValid && !child->isFinalized();
1605 child->commitChanges(childValid, globalModifications);
1606 //TODO: currently, this is called here for directly inserted
1607 // children as well as for children whose sub-children were
1608 // modified (and should never be called for directly removed
1609 // children); clarify what exactly should happen here for
1610 // directly inserted children
1612 NodeMap & members = getNode()->getMembers();
1613 NodeMap::iterator j(members.find(i->first));
1614 if (child.is()) {
1615 // Inserted:
1616 if (j != members.end()) {
1617 childValid = childValid &&
1618 j->second->getFinalized() == Data::NO_LAYER;
1619 if (childValid) {
1620 child->getNode()->setMandatory(j->second->getMandatory());
1623 if (childValid) {
1624 members[i->first] = child->getNode();
1626 } else {
1627 // Removed:
1628 childValid = childValid && j != members.end() &&
1629 j->second->getFinalized() == Data::NO_LAYER &&
1630 j->second->getMandatory() == Data::NO_LAYER;
1631 if (childValid) {
1632 members.erase(j);
1635 if (childValid && i->second.directlyModified) {
1636 Path path(getAbsolutePath());
1637 path.push_back(i->first);
1638 components_.addModification(path);
1639 globalModifications->add(path);
1641 i->second.child->committed();
1642 modifiedChildren_.erase(i);
1646 void Access::initBroadcasterAndChanges(
1647 Modifications::Node const & modifications, Broadcaster * broadcaster,
1648 std::vector< css::util::ElementChange > * allChanges)
1650 assert(broadcaster != 0);
1651 comphelper::SequenceAsVector< css::beans::PropertyChangeEvent > propChanges;
1652 bool collectPropChanges = !propertiesChangeListeners_.empty();
1653 for (Modifications::Node::Children::const_iterator i(
1654 modifications.children.begin());
1655 i != modifications.children.end(); ++i)
1657 rtl::Reference< ChildAccess > child(getChild(i->first));
1658 if (child.is()) {
1659 switch (child->getNode()->kind()) {
1660 case Node::KIND_LOCALIZED_PROPERTY:
1661 if (!i->second.children.empty()) {
1662 if (Components::allLocales(getRootAccess()->getLocale())) {
1663 child->initBroadcasterAndChanges(
1664 i->second, broadcaster, allChanges);
1665 //TODO: if allChanges==0, recurse only into children
1666 // w/ listeners
1667 } else {
1668 //TODO: filter child mods that are irrelevant for
1669 // locale:
1670 for (ContainerListeners::iterator j(
1671 containerListeners_.begin());
1672 j != containerListeners_.end(); ++j)
1674 broadcaster->
1675 addContainerElementReplacedNotification(
1677 css::container::ContainerEvent(
1678 static_cast< cppu::OWeakObject * >(
1679 this),
1680 css::uno::makeAny(i->first),
1681 css::uno::Any(), css::uno::Any()));
1682 //TODO: non-void Element, ReplacedElement
1684 PropertyChangeListeners::iterator j(
1685 propertyChangeListeners_.find(i->first));
1686 if (j != propertyChangeListeners_.end()) {
1687 for (PropertyChangeListenersElement::iterator k(
1688 j->second.begin());
1689 k != j->second.end(); ++k)
1691 broadcaster->addPropertyChangeNotification(
1693 css::beans::PropertyChangeEvent(
1694 static_cast< cppu::OWeakObject * >(
1695 this),
1696 i->first, false, -1, css::uno::Any(),
1697 css::uno::Any()));
1700 j = propertyChangeListeners_.find(OUString());
1701 if (j != propertyChangeListeners_.end()) {
1702 for (PropertyChangeListenersElement::iterator k(
1703 j->second.begin());
1704 k != j->second.end(); ++k)
1706 broadcaster->addPropertyChangeNotification(
1708 css::beans::PropertyChangeEvent(
1709 static_cast< cppu::OWeakObject * >(
1710 this),
1711 i->first, false, -1, css::uno::Any(),
1712 css::uno::Any()));
1715 if (allChanges != 0) {
1716 allChanges->push_back(
1717 css::util::ElementChange(
1718 css::uno::makeAny(
1719 child->getRelativePathRepresentation()),
1720 css::uno::Any(), css::uno::Any()));
1721 //TODO: non-void Element, ReplacedElement
1723 if (collectPropChanges) {
1724 propChanges.push_back(
1725 css::beans::PropertyChangeEvent(
1726 static_cast< cppu::OWeakObject * >(this),
1727 i->first, false, -1, css::uno::Any(),
1728 css::uno::Any()));
1732 // else: spurious Modifications::Node not representing a change
1733 break;
1734 case Node::KIND_LOCALIZED_VALUE:
1735 assert(Components::allLocales(getRootAccess()->getLocale()));
1736 for (ContainerListeners::iterator j(
1737 containerListeners_.begin());
1738 j != containerListeners_.end(); ++j)
1740 broadcaster->addContainerElementReplacedNotification(
1742 css::container::ContainerEvent(
1743 static_cast< cppu::OWeakObject * >(this),
1744 css::uno::makeAny(i->first), child->asValue(),
1745 css::uno::Any()));
1746 //TODO: distinguish add/modify; non-void ReplacedElement
1748 if (allChanges != 0) {
1749 allChanges->push_back(
1750 css::util::ElementChange(
1751 css::uno::makeAny(
1752 child->getRelativePathRepresentation()),
1753 child->asValue(), css::uno::Any()));
1754 //TODO: non-void ReplacedElement
1756 assert(!collectPropChanges);
1757 break;
1758 case Node::KIND_PROPERTY:
1760 for (ContainerListeners::iterator j(
1761 containerListeners_.begin());
1762 j != containerListeners_.end(); ++j)
1764 broadcaster->addContainerElementReplacedNotification(
1766 css::container::ContainerEvent(
1767 static_cast< cppu::OWeakObject * >(this),
1768 css::uno::makeAny(i->first), child->asValue(),
1769 css::uno::Any()));
1770 //TODO: distinguish add/remove/modify; non-void
1771 // ReplacedElement
1773 PropertyChangeListeners::iterator j(
1774 propertyChangeListeners_.find(i->first));
1775 if (j != propertyChangeListeners_.end()) {
1776 for (PropertyChangeListenersElement::iterator k(
1777 j->second.begin());
1778 k != j->second.end(); ++k)
1780 broadcaster->addPropertyChangeNotification(
1782 css::beans::PropertyChangeEvent(
1783 static_cast< cppu::OWeakObject * >(this),
1784 i->first, false, -1, css::uno::Any(),
1785 css::uno::Any()));
1788 j = propertyChangeListeners_.find(OUString());
1789 if (j != propertyChangeListeners_.end()) {
1790 for (PropertyChangeListenersElement::iterator k(
1791 j->second.begin());
1792 k != j->second.end(); ++k)
1794 broadcaster->addPropertyChangeNotification(
1796 css::beans::PropertyChangeEvent(
1797 static_cast< cppu::OWeakObject * >(this),
1798 i->first, false, -1, css::uno::Any(),
1799 css::uno::Any()));
1802 if (allChanges != 0) {
1803 allChanges->push_back(
1804 css::util::ElementChange(
1805 css::uno::makeAny(
1806 child->getRelativePathRepresentation()),
1807 child->asValue(), css::uno::Any()));
1808 //TODO: non-void ReplacedElement
1810 if (collectPropChanges) {
1811 propChanges.push_back(
1812 css::beans::PropertyChangeEvent(
1813 static_cast< cppu::OWeakObject * >(this),
1814 i->first, false, -1, css::uno::Any(),
1815 css::uno::Any()));
1818 break;
1819 case Node::KIND_GROUP:
1820 case Node::KIND_SET:
1821 if (i->second.children.empty()) {
1822 if (!child->getNode()->getTemplateName().isEmpty()) {
1823 for (ContainerListeners::iterator j(
1824 containerListeners_.begin());
1825 j != containerListeners_.end(); ++j)
1827 broadcaster->
1828 addContainerElementInsertedNotification(
1830 css::container::ContainerEvent(
1831 static_cast< cppu::OWeakObject * >(
1832 this),
1833 css::uno::makeAny(i->first),
1834 child->asValue(), css::uno::Any()));
1836 if (allChanges != 0) {
1837 allChanges->push_back(
1838 css::util::ElementChange(
1839 css::uno::makeAny(
1840 child->getRelativePathRepresentation()),
1841 css::uno::Any(), css::uno::Any()));
1842 //TODO: non-void Element, ReplacedElement
1845 // else: spurious Modifications::Node not representing a
1846 // change
1847 } else {
1848 child->initBroadcasterAndChanges(
1849 i->second, broadcaster, allChanges);
1850 //TODO: if allChanges==0, recurse only into children w/
1851 // listeners
1853 break;
1854 case Node::KIND_ROOT:
1855 assert(false); // this cannot happen
1856 break;
1858 } else {
1859 switch (getNode()->kind()) {
1860 case Node::KIND_LOCALIZED_PROPERTY:
1861 // Removed localized property value:
1862 assert(Components::allLocales(getRootAccess()->getLocale()));
1863 for (ContainerListeners::iterator j(
1864 containerListeners_.begin());
1865 j != containerListeners_.end(); ++j)
1867 broadcaster->addContainerElementRemovedNotification(
1869 css::container::ContainerEvent(
1870 static_cast< cppu::OWeakObject * >(this),
1871 css::uno::makeAny(i->first), css::uno::Any(),
1872 css::uno::Any()));
1873 //TODO: non-void ReplacedElement
1875 if (allChanges != 0) {
1876 OUStringBuffer path(getRelativePathRepresentation());
1877 if (path.getLength() != 0) {
1878 path.append(sal_Unicode('/'));
1880 path.append(
1881 Data::createSegment(
1882 OUString("*"),
1883 i->first));
1884 allChanges->push_back(
1885 css::util::ElementChange(
1886 css::uno::makeAny(path.makeStringAndClear()),
1887 css::uno::Any(), css::uno::Any()));
1888 //TODO: non-void ReplacedElement
1890 assert(!collectPropChanges);
1891 break;
1892 case Node::KIND_GROUP:
1894 // Removed (non-localized) extension property:
1895 for (ContainerListeners::iterator j(
1896 containerListeners_.begin());
1897 j != containerListeners_.end(); ++j)
1899 broadcaster->addContainerElementRemovedNotification(
1901 css::container::ContainerEvent(
1902 static_cast< cppu::OWeakObject * >(this),
1903 css::uno::makeAny(i->first), css::uno::Any(),
1904 css::uno::Any()));
1905 //TODO: non-void ReplacedElement
1907 PropertyChangeListeners::iterator j(
1908 propertyChangeListeners_.find(i->first));
1909 if (j != propertyChangeListeners_.end()) {
1910 for (PropertyChangeListenersElement::iterator k(
1911 j->second.begin());
1912 k != j->second.end(); ++k)
1914 broadcaster->addPropertyChangeNotification(
1916 css::beans::PropertyChangeEvent(
1917 static_cast< cppu::OWeakObject * >(this),
1918 i->first, false, -1, css::uno::Any(),
1919 css::uno::Any()));
1922 j = propertyChangeListeners_.find(OUString());
1923 if (j != propertyChangeListeners_.end()) {
1924 for (PropertyChangeListenersElement::iterator k(
1925 j->second.begin());
1926 k != j->second.end(); ++k)
1928 broadcaster->addPropertyChangeNotification(
1930 css::beans::PropertyChangeEvent(
1931 static_cast< cppu::OWeakObject * >(this),
1932 i->first, false, -1, css::uno::Any(),
1933 css::uno::Any()));
1936 if (allChanges != 0) {
1937 OUStringBuffer path(
1938 getRelativePathRepresentation());
1939 if (path.getLength() != 0) {
1940 path.append(sal_Unicode('/'));
1942 path.append(i->first);
1943 allChanges->push_back(
1944 css::util::ElementChange(
1945 css::uno::makeAny(path.makeStringAndClear()),
1946 css::uno::Any(), css::uno::Any()));
1947 //TODO: non-void ReplacedElement
1949 if (collectPropChanges) {
1950 propChanges.push_back(
1951 css::beans::PropertyChangeEvent(
1952 static_cast< cppu::OWeakObject * >(this),
1953 i->first, false, -1, css::uno::Any(),
1954 css::uno::Any()));
1957 break;
1958 case Node::KIND_SET:
1959 // Removed set member:
1960 if (i->second.children.empty()) {
1961 for (ContainerListeners::iterator j(
1962 containerListeners_.begin());
1963 j != containerListeners_.end(); ++j)
1965 broadcaster->addContainerElementRemovedNotification(
1967 css::container::ContainerEvent(
1968 static_cast< cppu::OWeakObject * >(this),
1969 css::uno::makeAny(i->first),
1970 css::uno::Any(), css::uno::Any()));
1971 //TODO: non-void ReplacedElement
1973 if (allChanges != 0) {
1974 OUStringBuffer path(
1975 getRelativePathRepresentation());
1976 if (path.getLength() != 0) {
1977 path.append(sal_Unicode('/'));
1979 path.append(
1980 Data::createSegment(
1981 OUString("*"),
1982 i->first));
1983 allChanges->push_back(
1984 css::util::ElementChange(
1985 css::uno::makeAny(path.makeStringAndClear()),
1986 css::uno::Any(), css::uno::Any()));
1987 //TODO: non-void ReplacedElement
1990 // else: spurious Modifications::Node not representing a change
1991 break;
1992 default:
1993 assert(false); // this cannot happen
1994 break;
1998 if (!propChanges.empty()) {
1999 css::uno::Sequence< css::beans::PropertyChangeEvent > seq(
2000 propChanges.getAsConstList());
2001 for (PropertiesChangeListeners::iterator i(
2002 propertiesChangeListeners_.begin());
2003 i != propertiesChangeListeners_.end(); ++i)
2005 broadcaster->addPropertiesChangeNotification(*i, seq);
2010 bool Access::isDisposed() const {
2011 return disposed_;
2014 Access::ModifiedChild::ModifiedChild() {}
2016 Access::ModifiedChild::ModifiedChild(
2017 rtl::Reference< ChildAccess > const & theChild, bool theDirectlyModified):
2018 child(theChild), directlyModified(theDirectlyModified)
2021 rtl::Reference< ChildAccess > Access::getModifiedChild(
2022 ModifiedChildren::iterator const & childIterator)
2024 return (childIterator->second.child->getParentAccess() == this &&
2025 (childIterator->second.child->getNameInternal() ==
2026 childIterator->first))
2027 ? childIterator->second.child : rtl::Reference< ChildAccess >();
2030 rtl::Reference< ChildAccess > Access::getUnmodifiedChild(
2031 OUString const & name)
2033 assert(modifiedChildren_.find(name) == modifiedChildren_.end());
2034 rtl::Reference< Node > node(getNode()->getMember(name));
2035 if (!node.is()) {
2036 return rtl::Reference< ChildAccess >();
2038 WeakChildMap::iterator i(cachedChildren_.find(name));
2039 if (i != cachedChildren_.end()) {
2040 rtl::Reference< ChildAccess > child;
2041 if (i->second->acquireCounting() > 1) {
2042 child.set(i->second); // must not throw
2044 i->second->releaseNondeleting();
2045 if (child.is()) {
2046 child->setNode(node);
2047 return child;
2050 rtl::Reference< ChildAccess > child(
2051 new ChildAccess(components_, getRootAccess(), this, name, node));
2052 cachedChildren_[name] = child.get();
2053 return child;
2056 rtl::Reference< ChildAccess > Access::getSubChild(OUString const & path) {
2057 sal_Int32 i = 0;
2058 // For backwards compatibility, allow absolute paths where meaningful:
2059 if (!path.isEmpty() && path[0] == '/') {
2060 ++i;
2061 if (!getRootAccess().is()) {
2062 return rtl::Reference< ChildAccess >();
2064 Path abs(getAbsolutePath());
2065 for (Path::iterator j(abs.begin()); j != abs.end(); ++j) {
2066 OUString name1;
2067 bool setElement1;
2068 OUString templateName1;
2069 i = Data::parseSegment(
2070 path, i, &name1, &setElement1, &templateName1);
2071 if (i == -1 || (i != path.getLength() && path[i] != '/')) {
2072 return rtl::Reference< ChildAccess >();
2074 OUString name2;
2075 bool setElement2;
2076 OUString templateName2;
2077 Data::parseSegment(*j, 0, &name2, &setElement2, &templateName2);
2078 if (name1 != name2 || setElement1 != setElement2 ||
2079 (setElement1 &&
2080 !Data::equalTemplateNames(templateName1, templateName2)))
2082 return rtl::Reference< ChildAccess >();
2084 if (i != path.getLength()) {
2085 ++i;
2089 for (rtl::Reference< Access > parent(this);;) {
2090 OUString name;
2091 bool setElement;
2092 OUString templateName;
2093 i = Data::parseSegment(path, i, &name, &setElement, &templateName);
2094 if (i == -1 || (i != path.getLength() && path[i] != '/')) {
2095 return rtl::Reference< ChildAccess >();
2097 rtl::Reference< ChildAccess > child(parent->getChild(name));
2098 if (!child.is()) {
2099 return rtl::Reference< ChildAccess >();
2101 if (setElement) {
2102 rtl::Reference< Node > p(parent->getNode());
2103 switch (p->kind()) {
2104 case Node::KIND_LOCALIZED_PROPERTY:
2105 if (!Components::allLocales(getRootAccess()->getLocale()) ||
2106 !templateName.isEmpty())
2108 return rtl::Reference< ChildAccess >();
2110 break;
2111 case Node::KIND_SET:
2112 if (!templateName.isEmpty() &&
2113 !dynamic_cast< SetNode * >(p.get())->isValidTemplate(
2114 templateName))
2116 return rtl::Reference< ChildAccess >();
2118 break;
2119 default:
2120 return rtl::Reference< ChildAccess >();
2123 // For backwards compatibility, ignore a final slash after non-value
2124 // nodes:
2125 if (child->isValue()) {
2126 return i == path.getLength()
2127 ? child : rtl::Reference< ChildAccess >();
2128 } else if (i >= path.getLength() - 1) {
2129 return child;
2131 ++i;
2132 parent = child.get();
2136 bool Access::setChildProperty(
2137 OUString const & name, css::uno::Any const & value,
2138 Modifications * localModifications)
2140 assert(localModifications != 0);
2141 rtl::Reference< ChildAccess > child(getChild(name));
2142 if (!child.is()) {
2143 return false;
2145 child->checkFinalized();
2146 child->setProperty(value, localModifications);
2147 return true;
2150 css::beans::Property Access::asProperty() {
2151 css::uno::Type type;
2152 bool nillable;
2153 bool removable;
2154 rtl::Reference< Node > p(getNode());
2155 switch (p->kind()) {
2156 case Node::KIND_PROPERTY:
2158 PropertyNode * prop = dynamic_cast< PropertyNode * >(p.get());
2159 type = mapType(prop->getStaticType());
2160 nillable = prop->isNillable();
2161 removable = prop->isExtension();
2163 break;
2164 case Node::KIND_LOCALIZED_PROPERTY:
2166 LocalizedPropertyNode * locprop =
2167 dynamic_cast< LocalizedPropertyNode *>(p.get());
2168 if (Components::allLocales(getRootAccess()->getLocale())) {
2169 type = cppu::UnoType< css::uno::XInterface >::get();
2170 //TODO: correct?
2171 removable = false;
2172 } else {
2173 type = mapType(locprop->getStaticType());
2174 removable = false; //TODO ???
2176 nillable = locprop->isNillable();
2178 break;
2179 case Node::KIND_LOCALIZED_VALUE:
2181 LocalizedPropertyNode * locprop =
2182 dynamic_cast< LocalizedPropertyNode * >(getParentNode().get());
2183 type = mapType(locprop->getStaticType());
2184 nillable = locprop->isNillable();
2185 removable = false; //TODO ???
2187 break;
2188 default:
2189 type = cppu::UnoType< css::uno::XInterface >::get(); //TODO: correct?
2190 nillable = false;
2191 rtl::Reference< Node > parent(getParentNode());
2192 removable = parent.is() && parent->kind() == Node::KIND_SET;
2193 break;
2195 return css::beans::Property(
2196 getNameInternal(), -1, type,
2197 (css::beans::PropertyAttribute::BOUND | //TODO: correct for group/set?
2198 css::beans::PropertyAttribute::CONSTRAINED |
2199 (nillable ? css::beans::PropertyAttribute::MAYBEVOID : 0) |
2200 (getRootAccess()->isUpdate() && removable
2201 ? css::beans::PropertyAttribute::REMOVABLE : 0) |
2202 (!getRootAccess()->isUpdate() || p->getFinalized() != Data::NO_LAYER
2203 ? css::beans::PropertyAttribute::READONLY : 0))); //TODO: MAYBEDEFAULT
2206 void Access::checkFinalized() {
2207 if (isFinalized()) {
2208 throw css::lang::IllegalArgumentException(
2209 OUString("configmgr modification of finalized item"),
2210 static_cast< cppu::OWeakObject * >(this), -1);
2214 void Access::checkKnownProperty(OUString const & descriptor) {
2215 if (descriptor.isEmpty()) {
2216 return;
2218 rtl::Reference< ChildAccess > child(getChild(descriptor));
2219 if (child.is()) {
2220 switch (child->getNode()->kind()) {
2221 case Node::KIND_PROPERTY:
2222 return;
2223 case Node::KIND_LOCALIZED_PROPERTY:
2224 if (!Components::allLocales(getRootAccess()->getLocale())) {
2225 return;
2227 break;
2228 case Node::KIND_LOCALIZED_VALUE:
2229 if (Components::allLocales(getRootAccess()->getLocale())) {
2230 return;
2232 break;
2233 default:
2234 break;
2237 throw css::beans::UnknownPropertyException(
2238 descriptor, static_cast< cppu::OWeakObject * >(this));
2241 rtl::Reference< ChildAccess > Access::getFreeSetMember(
2242 css::uno::Any const & value)
2244 rtl::Reference< ChildAccess > freeAcc;
2245 css::uno::Reference< css::lang::XUnoTunnel > tunnel;
2246 value >>= tunnel;
2247 if (tunnel.is()) {
2248 freeAcc.set(
2249 reinterpret_cast< ChildAccess * >(
2250 tunnel->getSomething(ChildAccess::getTunnelId())));
2252 if (!freeAcc.is() || freeAcc->getParentAccess().is() ||
2253 (freeAcc->isInTransaction() &&
2254 freeAcc->getRootAccess() != getRootAccess()))
2256 throw css::lang::IllegalArgumentException(
2257 OUString("configmgr inappropriate set element"),
2258 static_cast< cppu::OWeakObject * >(this), 1);
2260 assert(dynamic_cast< SetNode * >(getNode().get()) != 0);
2261 if (!dynamic_cast< SetNode * >(getNode().get())->isValidTemplate(
2262 freeAcc->getNode()->getTemplateName()))
2264 throw css::lang::IllegalArgumentException(
2265 OUString("configmgr inappropriate set element"),
2266 static_cast< cppu::OWeakObject * >(this), 1);
2268 return freeAcc;
2271 rtl::Reference< Access > Access::getNotificationRoot() {
2272 for (rtl::Reference< Access > p(this);;) {
2273 rtl::Reference< Access > parent(p->getParentAccess());
2274 if (!parent.is()) {
2275 return p;
2277 p = parent;
2281 #if !defined NDEBUG
2282 bool Access::thisIs(int what) {
2283 osl::MutexGuard g(*lock_);
2284 rtl::Reference< Node > p(getNode());
2285 Node::Kind k(p->kind());
2286 return (k != Node::KIND_PROPERTY && k != Node::KIND_LOCALIZED_VALUE &&
2287 ((what & IS_GROUP) == 0 || k == Node::KIND_GROUP) &&
2288 ((what & IS_SET) == 0 || k == Node::KIND_SET) &&
2289 ((what & IS_EXTENSIBLE) == 0 || k != Node::KIND_GROUP ||
2290 dynamic_cast< GroupNode * >(p.get())->isExtensible()) &&
2291 ((what & IS_GROUP_MEMBER) == 0 ||
2292 getParentNode()->kind() == Node::KIND_GROUP)) ||
2293 ((what & IS_SET_MEMBER) == 0 ||
2294 getParentNode()->kind() == Node::KIND_SET) ||
2295 ((what & IS_UPDATE) == 0 || getRootAccess()->isUpdate());
2297 #endif
2301 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */