xref: /aoo42x/main/configmgr/source/access.cxx (revision cdf0e10c)
1 /*************************************************************************
2 *
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2000, 2010 Oracle and/or its affiliates.
6 *
7 * OpenOffice.org - a multi-platform office productivity suite
8 *
9 * This file is part of OpenOffice.org.
10 *
11 * OpenOffice.org is free software: you can redistribute it and/or modify
12 * it under the terms of the GNU Lesser General Public License version 3
13 * only, as published by the Free Software Foundation.
14 *
15 * OpenOffice.org is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18 * GNU Lesser General Public License version 3 for more details
19 * (a copy is included in the LICENSE file that accompanied this code).
20 *
21 * You should have received a copy of the GNU Lesser General Public License
22 * version 3 along with OpenOffice.org.  If not, see
23 * <http://www.openoffice.org/license.html>
24 * for a copy of the LGPLv3 License.
25 *
26 ************************************************************************/
27 
28 #include "precompiled_configmgr.hxx"
29 #include "sal/config.h"
30 
31 #include <vector>
32 
33 #include "com/sun/star/beans/Property.hpp"
34 #include "com/sun/star/beans/PropertyAttribute.hpp"
35 #include "com/sun/star/beans/PropertyChangeEvent.hpp"
36 #include "com/sun/star/beans/PropertyVetoException.hpp"
37 #include "com/sun/star/beans/UnknownPropertyException.hpp"
38 #include "com/sun/star/beans/XExactName.hpp"
39 #include "com/sun/star/beans/XHierarchicalPropertySet.hpp"
40 #include "com/sun/star/beans/XHierarchicalPropertySetInfo.hpp"
41 #include "com/sun/star/beans/XMultiHierarchicalPropertySet.hpp"
42 #include "com/sun/star/beans/XMultiPropertySet.hpp"
43 #include "com/sun/star/beans/XPropertiesChangeListener.hpp"
44 #include "com/sun/star/beans/XProperty.hpp"
45 #include "com/sun/star/beans/XPropertyChangeListener.hpp"
46 #include "com/sun/star/beans/XPropertySet.hpp"
47 #include "com/sun/star/beans/XPropertySetInfo.hpp"
48 #include "com/sun/star/beans/XVetoableChangeListener.hpp"
49 #include "com/sun/star/container/ContainerEvent.hpp"
50 #include "com/sun/star/container/NoSuchElementException.hpp"
51 #include "com/sun/star/container/XContainer.hpp"
52 #include "com/sun/star/container/XContainerListener.hpp"
53 #include "com/sun/star/container/XElementAccess.hpp"
54 #include "com/sun/star/container/XHierarchicalName.hpp"
55 #include "com/sun/star/container/XHierarchicalNameAccess.hpp"
56 #include "com/sun/star/container/XNameAccess.hpp"
57 #include "com/sun/star/container/XNameContainer.hpp"
58 #include "com/sun/star/container/XNamed.hpp"
59 #include "com/sun/star/lang/DisposedException.hpp"
60 #include "com/sun/star/lang/EventObject.hpp"
61 #include "com/sun/star/lang/IllegalArgumentException.hpp"
62 #include "com/sun/star/lang/NoSupportException.hpp"
63 #include "com/sun/star/lang/WrappedTargetException.hpp"
64 #include "com/sun/star/lang/XComponent.hpp"
65 #include "com/sun/star/lang/XEventListener.hpp"
66 #include "com/sun/star/lang/XServiceInfo.hpp"
67 #include "com/sun/star/lang/XSingleServiceFactory.hpp"
68 #include "com/sun/star/lang/XTypeProvider.hpp"
69 #include "com/sun/star/lang/XUnoTunnel.hpp"
70 #include "com/sun/star/uno/Any.hxx"
71 #include "com/sun/star/uno/Reference.hxx"
72 #include "com/sun/star/uno/RuntimeException.hpp"
73 #include "com/sun/star/uno/Sequence.hxx"
74 #include "com/sun/star/uno/Type.hxx"
75 #include "com/sun/star/uno/TypeClass.hpp"
76 #include "com/sun/star/uno/XInterface.hpp"
77 #include "com/sun/star/uno/XWeak.hpp"
78 #include "com/sun/star/util/ElementChange.hpp"
79 #include "comphelper/sequenceasvector.hxx"
80 #include "cppu/unotype.hxx"
81 #include "cppuhelper/queryinterface.hxx"
82 #include "cppuhelper/weak.hxx"
83 #include "osl/diagnose.h"
84 #include "osl/interlck.h"
85 #include "osl/mutex.hxx"
86 #include "rtl/ref.hxx"
87 #include "rtl/ustrbuf.hxx"
88 #include "rtl/ustring.h"
89 #include "rtl/ustring.hxx"
90 #include "sal/types.h"
91 
92 #include "access.hxx"
93 #include "broadcaster.hxx"
94 #include "childaccess.hxx"
95 #include "components.hxx"
96 #include "data.hxx"
97 #include "groupnode.hxx"
98 #include "localizedpropertynode.hxx"
99 #include "localizedvaluenode.hxx"
100 #include "lock.hxx"
101 #include "modifications.hxx"
102 #include "node.hxx"
103 #include "nodemap.hxx"
104 #include "path.hxx"
105 #include "propertynode.hxx"
106 #include "rootaccess.hxx"
107 #include "setnode.hxx"
108 #include "type.hxx"
109 
110 namespace configmgr {
111 
112 namespace {
113 
114 namespace css = com::sun::star;
115 
116 }
117 
118 oslInterlockedCount Access::acquireCounting() {
119     return osl_incrementInterlockedCount(&m_refCount);
120 }
121 
122 void Access::releaseNondeleting() {
123     osl_decrementInterlockedCount(&m_refCount);
124 }
125 
126 bool Access::isValue() {
127     rtl::Reference< Node > p(getNode());
128     switch (p->kind()) {
129     case Node::KIND_PROPERTY:
130     case Node::KIND_LOCALIZED_VALUE:
131         return true;
132     case Node::KIND_LOCALIZED_PROPERTY:
133         return !Components::allLocales(getRootAccess()->getLocale());
134     default:
135         return false;
136     }
137 }
138 
139 void Access::markChildAsModified(rtl::Reference< ChildAccess > const & child) {
140     OSL_ASSERT(child.is() && child->getParentAccess() == this);
141     modifiedChildren_[child->getNameInternal()] = ModifiedChild(child, true);
142     for (rtl::Reference< Access > p(this);;) {
143         rtl::Reference< Access > parent(p->getParentAccess());
144         if (!parent.is()) {
145             break;
146         }
147         OSL_ASSERT(dynamic_cast< ChildAccess * >(p.get()) != 0);
148         parent->modifiedChildren_.insert(
149             ModifiedChildren::value_type(
150                 p->getNameInternal(),
151                 ModifiedChild(dynamic_cast< ChildAccess * >(p.get()), false)));
152         p = parent;
153     }
154 }
155 
156 void Access::releaseChild(rtl::OUString const & name) {
157     cachedChildren_.erase(name);
158 }
159 
160 void Access::initBroadcaster(
161     Modifications::Node const & modifications, Broadcaster * broadcaster)
162 {
163     initBroadcasterAndChanges(modifications, broadcaster, 0);
164 }
165 
166 Access::Access(Components & components):
167     components_(components), disposed_(false)
168 {}
169 
170 Access::~Access() {}
171 
172 void Access::initDisposeBroadcaster(Broadcaster * broadcaster) {
173     OSL_ASSERT(broadcaster != 0);
174     for (DisposeListeners::iterator i(disposeListeners_.begin());
175          i != disposeListeners_.end(); ++i)
176     {
177         broadcaster->addDisposeNotification(
178             *i,
179             css::lang::EventObject(static_cast< cppu::OWeakObject * >(this)));
180     }
181     for (ContainerListeners::iterator i(containerListeners_.begin());
182          i != containerListeners_.end(); ++i)
183     {
184         broadcaster->addDisposeNotification(
185             i->get(),
186             css::lang::EventObject(static_cast< cppu::OWeakObject * >(this)));
187     }
188     for (PropertyChangeListeners::iterator i(propertyChangeListeners_.begin());
189          i != propertyChangeListeners_.end(); ++i)
190     {
191         for (PropertyChangeListenersElement::iterator j(i->second.begin());
192              j != i->second.end(); ++j)
193         {
194             broadcaster->addDisposeNotification(
195                 j->get(),
196                 css::lang::EventObject(
197                     static_cast< cppu::OWeakObject * >(this)));
198         }
199     }
200     for (VetoableChangeListeners::iterator i(vetoableChangeListeners_.begin());
201          i != vetoableChangeListeners_.end(); ++i)
202     {
203         for (VetoableChangeListenersElement::iterator j(i->second.begin());
204              j != i->second.end(); ++j)
205         {
206             broadcaster->addDisposeNotification(
207                 j->get(),
208                 css::lang::EventObject(
209                     static_cast< cppu::OWeakObject * >(this)));
210         }
211     }
212     for (PropertiesChangeListeners::iterator i(
213              propertiesChangeListeners_.begin());
214          i != propertiesChangeListeners_.end(); ++i)
215     {
216         broadcaster->addDisposeNotification(
217             i->get(),
218             css::lang::EventObject(static_cast< cppu::OWeakObject * >(this)));
219     }
220     //TODO: iterate over children w/ listeners (incl. unmodified ones):
221     for (ModifiedChildren::iterator i(modifiedChildren_.begin());
222          i != modifiedChildren_.end(); ++i)
223     {
224         rtl::Reference< ChildAccess > child(getModifiedChild(i));
225         if (child.is()) {
226             child->initDisposeBroadcaster(broadcaster);
227         }
228     }
229 }
230 
231 void Access::clearListeners() throw() {
232     disposeListeners_.clear();
233     containerListeners_.clear();
234     propertyChangeListeners_.clear();
235     vetoableChangeListeners_.clear();
236     propertiesChangeListeners_.clear();
237     //TODO: iterate over children w/ listeners (incl. unmodified ones):
238     for (ModifiedChildren::iterator i(modifiedChildren_.begin());
239          i != modifiedChildren_.end(); ++i)
240     {
241         rtl::Reference< ChildAccess > child(getModifiedChild(i));
242         if (child.is()) {
243             child->clearListeners();
244         }
245     }
246 }
247 
248 css::uno::Any Access::queryInterface(css::uno::Type const & aType)
249     throw (css::uno::RuntimeException)
250 {
251     css::uno::Any res(OWeakObject::queryInterface(aType));
252     if (res.hasValue()) {
253         return res;
254     }
255     res = cppu::queryInterface(
256         aType, static_cast< css::lang::XTypeProvider * >(this),
257         static_cast< css::lang::XServiceInfo * >(this),
258         static_cast< css::lang::XComponent * >(this),
259         static_cast< css::container::XHierarchicalNameAccess * >(this),
260         static_cast< css::container::XContainer * >(this),
261         static_cast< css::beans::XExactName * >(this),
262         static_cast< css::container::XHierarchicalName * >(this),
263         static_cast< css::container::XNamed * >(this),
264         static_cast< css::beans::XProperty * >(this),
265         static_cast< css::container::XElementAccess * >(this),
266         static_cast< css::container::XNameAccess * >(this));
267     if (res.hasValue()) {
268         return res;
269     }
270     if (getNode()->kind() == Node::KIND_GROUP) {
271         res = cppu::queryInterface(
272             aType, static_cast< css::beans::XPropertySetInfo * >(this),
273             static_cast< css::beans::XPropertySet * >(this),
274             static_cast< css::beans::XMultiPropertySet * >(this),
275             static_cast< css::beans::XHierarchicalPropertySet * >(this),
276             static_cast< css::beans::XMultiHierarchicalPropertySet * >(this),
277             static_cast< css::beans::XHierarchicalPropertySetInfo * >(this));
278         if (res.hasValue()) {
279             return res;
280         }
281     }
282     if (getRootAccess()->isUpdate()) {
283         res = cppu::queryInterface(
284             aType, static_cast< css::container::XNameReplace * >(this));
285         if (res.hasValue()) {
286             return res;
287         }
288         if (getNode()->kind() != Node::KIND_GROUP ||
289             dynamic_cast< GroupNode * >(getNode().get())->isExtensible())
290         {
291             res = cppu::queryInterface(
292                 aType, static_cast< css::container::XNameContainer * >(this));
293             if (res.hasValue()) {
294                 return res;
295             }
296         }
297         if (getNode()->kind() == Node::KIND_SET) {
298             res = cppu::queryInterface(
299                 aType, static_cast< css::lang::XSingleServiceFactory * >(this));
300         }
301     }
302     return res;
303 }
304 
305 Components & Access::getComponents() const {
306     return components_;
307 }
308 
309 void Access::checkLocalizedPropertyAccess() {
310     if (getNode()->kind() == Node::KIND_LOCALIZED_PROPERTY &&
311         !Components::allLocales(getRootAccess()->getLocale()))
312     {
313         throw css::uno::RuntimeException(
314             rtl::OUString(
315                 RTL_CONSTASCII_USTRINGPARAM(
316                     "configmgr Access to specialized LocalizedPropertyNode")),
317             static_cast< cppu::OWeakObject * >(this));
318     }
319 }
320 
321 rtl::Reference< Node > Access::getParentNode() {
322     rtl::Reference< Access > parent(getParentAccess());
323     return parent.is() ? parent->getNode() : rtl::Reference< Node >();
324 }
325 
326 rtl::Reference< ChildAccess > Access::getChild(rtl::OUString const & name) {
327     ModifiedChildren::iterator i(modifiedChildren_.find(name));
328     return i == modifiedChildren_.end()
329         ? getUnmodifiedChild(name) : getModifiedChild(i);
330 }
331 
332 std::vector< rtl::Reference< ChildAccess > > Access::getAllChildren() {
333     std::vector< rtl::Reference< ChildAccess > > vec;
334     NodeMap & members = getNode()->getMembers();
335     for (NodeMap::iterator i(members.begin()); i != members.end(); ++i) {
336         if (modifiedChildren_.find(i->first) == modifiedChildren_.end()) {
337             vec.push_back(getUnmodifiedChild(i->first));
338             OSL_ASSERT(vec.back().is());
339         }
340     }
341     for (ModifiedChildren::iterator i(modifiedChildren_.begin());
342          i != modifiedChildren_.end(); ++i)
343     {
344         rtl::Reference< ChildAccess > child(getModifiedChild(i));
345         if (child.is()) {
346             vec.push_back(child);
347         }
348     }
349     return vec;
350 }
351 
352 void Access::checkValue(css::uno::Any const & value, Type type, bool nillable) {
353     bool ok;
354     switch (type) {
355     case TYPE_NIL:
356         OSL_ASSERT(false);
357         // fall through (cannot happen)
358     case TYPE_ERROR:
359         ok = false;
360         break;
361     case TYPE_ANY:
362         switch (getDynamicType(value)) {
363         case TYPE_ANY:
364             OSL_ASSERT(false);
365             // fall through (cannot happen)
366         case TYPE_ERROR:
367             ok = false;
368             break;
369         case TYPE_NIL:
370             ok = nillable;
371             break;
372         default:
373             ok = true;
374             break;
375         }
376         break;
377     default:
378         ok = value.hasValue() ? value.isExtractableTo(mapType(type)) : nillable;
379         break;
380     }
381     if (!ok) {
382         throw css::lang::IllegalArgumentException(
383             rtl::OUString(
384                 RTL_CONSTASCII_USTRINGPARAM(
385                     "configmgr inappropriate property value")),
386             static_cast< cppu::OWeakObject * >(this), -1);
387     }
388 }
389 
390 void Access::insertLocalizedValueChild(
391     rtl::OUString const & name, css::uno::Any const & value,
392     Modifications * localModifications)
393 {
394     OSL_ASSERT(localModifications != 0);
395     LocalizedPropertyNode * locprop = dynamic_cast< LocalizedPropertyNode * >(
396         getNode().get());
397     checkValue(value, locprop->getStaticType(), locprop->isNillable());
398     rtl::Reference< ChildAccess > child(
399         new ChildAccess(
400             components_, getRootAccess(), this, name,
401             new LocalizedValueNode(Data::NO_LAYER, value)));
402     markChildAsModified(child);
403     localModifications->add(child->getRelativePath());
404 }
405 
406 void Access::reportChildChanges(
407     std::vector< css::util::ElementChange > * changes)
408 {
409     OSL_ASSERT(changes != 0);
410     for (ModifiedChildren::iterator i(modifiedChildren_.begin());
411          i != modifiedChildren_.end(); ++i)
412     {
413         rtl::Reference< ChildAccess > child(getModifiedChild(i));
414         if (child.is()) {
415             child->reportChildChanges(changes);
416             changes->push_back(css::util::ElementChange());
417                 //TODO: changed value and/or inserted node
418         } else {
419             changes->push_back(css::util::ElementChange()); //TODO: removed node
420         }
421     }
422 }
423 
424 void Access::commitChildChanges(
425     bool valid, Modifications * globalModifications)
426 {
427     OSL_ASSERT(globalModifications != 0);
428     while (!modifiedChildren_.empty()) {
429         bool childValid = valid;
430         ModifiedChildren::iterator i(modifiedChildren_.begin());
431         rtl::Reference< ChildAccess > child(getModifiedChild(i));
432         if (child.is()) {
433             childValid = childValid && !child->isFinalized();
434             child->commitChanges(childValid, globalModifications);
435                 //TODO: currently, this is called here for directly inserted
436                 // children as well as for children whose sub-children were
437                 // modified (and should never be called for directly removed
438                 // children); clarify what exactly should happen here for
439                 // directly inserted children
440         }
441         NodeMap & members = getNode()->getMembers();
442         NodeMap::iterator j(members.find(i->first));
443         if (child.is()) {
444             // Inserted:
445             if (j != members.end()) {
446                 childValid = childValid &&
447                     j->second->getFinalized() == Data::NO_LAYER;
448                 if (childValid) {
449                     child->getNode()->setMandatory(j->second->getMandatory());
450                 }
451             }
452             if (childValid) {
453                 members[i->first] = child->getNode();
454             }
455         } else {
456             // Removed:
457             childValid = childValid && j != members.end() &&
458                 j->second->getFinalized() == Data::NO_LAYER &&
459                 j->second->getMandatory() == Data::NO_LAYER;
460             if (childValid) {
461                 members.erase(j);
462             }
463         }
464         if (childValid && i->second.directlyModified) {
465             Path path(getAbsolutePath());
466             path.push_back(i->first);
467             components_.addModification(path);
468             globalModifications->add(path);
469         }
470         i->second.child->committed();
471         modifiedChildren_.erase(i);
472     }
473 }
474 
475 void Access::initBroadcasterAndChanges(
476     Modifications::Node const & modifications, Broadcaster * broadcaster,
477     std::vector< css::util::ElementChange > * allChanges)
478 {
479     OSL_ASSERT(broadcaster != 0);
480     comphelper::SequenceAsVector< css::beans::PropertyChangeEvent > propChanges;
481     bool collectPropChanges = !propertiesChangeListeners_.empty();
482     for (Modifications::Node::Children::const_iterator i(
483              modifications.children.begin());
484          i != modifications.children.end(); ++i)
485     {
486         rtl::Reference< ChildAccess > child(getChild(i->first));
487         if (child.is()) {
488             switch (child->getNode()->kind()) {
489             case Node::KIND_LOCALIZED_PROPERTY:
490                 if (!i->second.children.empty()) {
491                     if (Components::allLocales(getRootAccess()->getLocale())) {
492                         child->initBroadcasterAndChanges(
493                             i->second, broadcaster, allChanges);
494                             //TODO: if allChanges==0, recurse only into children
495                             // w/ listeners
496                     } else {
497                         //TODO: filter child mods that are irrelevant for
498                         // locale:
499                         for (ContainerListeners::iterator j(
500                                  containerListeners_.begin());
501                              j != containerListeners_.end(); ++j)
502                         {
503                             broadcaster->
504                                 addContainerElementReplacedNotification(
505                                     *j,
506                                     css::container::ContainerEvent(
507                                         static_cast< cppu::OWeakObject * >(
508                                             this),
509                                         css::uno::makeAny(i->first),
510                                         css::uno::Any(), css::uno::Any()));
511                                 //TODO: non-void Element, ReplacedElement
512                         }
513                         PropertyChangeListeners::iterator j(
514                             propertyChangeListeners_.find(i->first));
515                         if (j != propertyChangeListeners_.end()) {
516                             for (PropertyChangeListenersElement::iterator k(
517                                      j->second.begin());
518                                  k != j->second.end(); ++k)
519                             {
520                                 broadcaster->addPropertyChangeNotification(
521                                     *k,
522                                     css::beans::PropertyChangeEvent(
523                                         static_cast< cppu::OWeakObject * >(
524                                             this),
525                                         i->first, false, -1, css::uno::Any(),
526                                         css::uno::Any()));
527                             }
528                         }
529                         j = propertyChangeListeners_.find(rtl::OUString());
530                         if (j != propertyChangeListeners_.end()) {
531                             for (PropertyChangeListenersElement::iterator k(
532                                      j->second.begin());
533                                  k != j->second.end(); ++k)
534                             {
535                                 broadcaster->addPropertyChangeNotification(
536                                     *k,
537                                     css::beans::PropertyChangeEvent(
538                                         static_cast< cppu::OWeakObject * >(
539                                             this),
540                                         i->first, false, -1, css::uno::Any(),
541                                         css::uno::Any()));
542                             }
543                         }
544                         if (allChanges != 0) {
545                             allChanges->push_back(
546                                 css::util::ElementChange(
547                                     css::uno::makeAny(
548                                         child->getRelativePathRepresentation()),
549                                     css::uno::Any(), css::uno::Any()));
550                                 //TODO: non-void Element, ReplacedElement
551                         }
552                         if (collectPropChanges) {
553                             propChanges.push_back(
554                                 css::beans::PropertyChangeEvent(
555                                     static_cast< cppu::OWeakObject * >(this),
556                                     i->first, false, -1, css::uno::Any(),
557                                     css::uno::Any()));
558                         }
559                     }
560                 }
561                 // else: spurious Modifications::Node not representing a change
562                 break;
563             case Node::KIND_LOCALIZED_VALUE:
564                 OSL_ASSERT(
565                     Components::allLocales(getRootAccess()->getLocale()));
566                 for (ContainerListeners::iterator j(
567                          containerListeners_.begin());
568                      j != containerListeners_.end(); ++j)
569                 {
570                     broadcaster->addContainerElementReplacedNotification(
571                         *j,
572                         css::container::ContainerEvent(
573                             static_cast< cppu::OWeakObject * >(this),
574                             css::uno::makeAny(i->first), child->asValue(),
575                             css::uno::Any()));
576                         //TODO: distinguish add/modify; non-void ReplacedElement
577                 }
578                 if (allChanges != 0) {
579                     allChanges->push_back(
580                         css::util::ElementChange(
581                             css::uno::makeAny(
582                                 child->getRelativePathRepresentation()),
583                             child->asValue(), css::uno::Any()));
584                         //TODO: non-void ReplacedElement
585                 }
586                 OSL_ASSERT(!collectPropChanges);
587                 break;
588             case Node::KIND_PROPERTY:
589                 {
590                     for (ContainerListeners::iterator j(
591                              containerListeners_.begin());
592                          j != containerListeners_.end(); ++j)
593                     {
594                         broadcaster->addContainerElementReplacedNotification(
595                             *j,
596                             css::container::ContainerEvent(
597                                 static_cast< cppu::OWeakObject * >(this),
598                                 css::uno::makeAny(i->first), child->asValue(),
599                                 css::uno::Any()));
600                             //TODO: distinguish add/remove/modify; non-void
601                             // ReplacedElement
602                     }
603                     PropertyChangeListeners::iterator j(
604                         propertyChangeListeners_.find(i->first));
605                     if (j != propertyChangeListeners_.end()) {
606                         for (PropertyChangeListenersElement::iterator k(
607                                  j->second.begin());
608                              k != j->second.end(); ++k)
609                         {
610                             broadcaster->addPropertyChangeNotification(
611                                 *k,
612                                 css::beans::PropertyChangeEvent(
613                                     static_cast< cppu::OWeakObject * >(this),
614                                     i->first, false, -1, css::uno::Any(),
615                                     css::uno::Any()));
616                         }
617                     }
618                     j = propertyChangeListeners_.find(rtl::OUString());
619                     if (j != propertyChangeListeners_.end()) {
620                         for (PropertyChangeListenersElement::iterator k(
621                                  j->second.begin());
622                              k != j->second.end(); ++k)
623                         {
624                             broadcaster->addPropertyChangeNotification(
625                                 *k,
626                                 css::beans::PropertyChangeEvent(
627                                     static_cast< cppu::OWeakObject * >(this),
628                                     i->first, false, -1, css::uno::Any(),
629                                     css::uno::Any()));
630                         }
631                     }
632                     if (allChanges != 0) {
633                         allChanges->push_back(
634                             css::util::ElementChange(
635                                 css::uno::makeAny(
636                                     child->getRelativePathRepresentation()),
637                                 child->asValue(), css::uno::Any()));
638                             //TODO: non-void ReplacedElement
639                     }
640                     if (collectPropChanges) {
641                         propChanges.push_back(
642                             css::beans::PropertyChangeEvent(
643                                 static_cast< cppu::OWeakObject * >(this),
644                                 i->first, false, -1, css::uno::Any(),
645                                 css::uno::Any()));
646                     }
647                 }
648                 break;
649             case Node::KIND_GROUP:
650             case Node::KIND_SET:
651                 if (i->second.children.empty()) {
652                     if (child->getNode()->getTemplateName().getLength() != 0) {
653                         for (ContainerListeners::iterator j(
654                                  containerListeners_.begin());
655                              j != containerListeners_.end(); ++j)
656                         {
657                             broadcaster->
658                                 addContainerElementInsertedNotification(
659                                     *j,
660                                     css::container::ContainerEvent(
661                                         static_cast< cppu::OWeakObject * >(
662                                             this),
663                                         css::uno::makeAny(i->first),
664                                         child->asValue(), css::uno::Any()));
665                         }
666                         if (allChanges != 0) {
667                             allChanges->push_back(
668                                 css::util::ElementChange(
669                                     css::uno::makeAny(
670                                         child->getRelativePathRepresentation()),
671                                     css::uno::Any(), css::uno::Any()));
672                                 //TODO: non-void Element, ReplacedElement
673                         }
674                     }
675                     // else: spurious Modifications::Node not representing a
676                     // change
677                 } else {
678                     child->initBroadcasterAndChanges(
679                         i->second, broadcaster, allChanges);
680                         //TODO: if allChanges==0, recurse only into children w/
681                         // listeners
682                 }
683                 break;
684             }
685         } else {
686             switch (getNode()->kind()) {
687             case Node::KIND_LOCALIZED_PROPERTY:
688                 // Removed localized property value:
689                 OSL_ASSERT(
690                     Components::allLocales(getRootAccess()->getLocale()));
691                 for (ContainerListeners::iterator j(
692                          containerListeners_.begin());
693                      j != containerListeners_.end(); ++j)
694                 {
695                     broadcaster->addContainerElementRemovedNotification(
696                         *j,
697                         css::container::ContainerEvent(
698                             static_cast< cppu::OWeakObject * >(this),
699                             css::uno::makeAny(i->first), css::uno::Any(),
700                             css::uno::Any()));
701                         //TODO: non-void ReplacedElement
702                 }
703                 if (allChanges != 0) {
704                     rtl::OUStringBuffer path(getRelativePathRepresentation());
705                     if (path.getLength() != 0) {
706                         path.append(sal_Unicode('/'));
707                     }
708                     path.append(
709                         Data::createSegment(
710                             rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("*")),
711                             i->first));
712                     allChanges->push_back(
713                         css::util::ElementChange(
714                             css::uno::makeAny(path.makeStringAndClear()),
715                             css::uno::Any(), css::uno::Any()));
716                         //TODO: non-void ReplacedElement
717                 }
718                 OSL_ASSERT(!collectPropChanges);
719                 break;
720             case Node::KIND_GROUP:
721                 {
722                     // Removed (non-localized) extension property:
723                     for (ContainerListeners::iterator j(
724                              containerListeners_.begin());
725                          j != containerListeners_.end(); ++j)
726                     {
727                         broadcaster->addContainerElementRemovedNotification(
728                             *j,
729                             css::container::ContainerEvent(
730                                 static_cast< cppu::OWeakObject * >(this),
731                                 css::uno::makeAny(i->first), css::uno::Any(),
732                                 css::uno::Any()));
733                             //TODO: non-void ReplacedElement
734                     }
735                     PropertyChangeListeners::iterator j(
736                         propertyChangeListeners_.find(i->first));
737                     if (j != propertyChangeListeners_.end()) {
738                         for (PropertyChangeListenersElement::iterator k(
739                                  j->second.begin());
740                              k != j->second.end(); ++k)
741                         {
742                             broadcaster->addPropertyChangeNotification(
743                                 *k,
744                                 css::beans::PropertyChangeEvent(
745                                     static_cast< cppu::OWeakObject * >(this),
746                                     i->first, false, -1, css::uno::Any(),
747                                     css::uno::Any()));
748                         }
749                     }
750                     j = propertyChangeListeners_.find(rtl::OUString());
751                     if (j != propertyChangeListeners_.end()) {
752                         for (PropertyChangeListenersElement::iterator k(
753                                  j->second.begin());
754                              k != j->second.end(); ++k)
755                         {
756                             broadcaster->addPropertyChangeNotification(
757                                 *k,
758                                 css::beans::PropertyChangeEvent(
759                                     static_cast< cppu::OWeakObject * >(this),
760                                     i->first, false, -1, css::uno::Any(),
761                                     css::uno::Any()));
762                         }
763                     }
764                     if (allChanges != 0) {
765                         rtl::OUStringBuffer path(
766                             getRelativePathRepresentation());
767                         if (path.getLength() != 0) {
768                             path.append(sal_Unicode('/'));
769                         }
770                         path.append(i->first);
771                         allChanges->push_back(
772                             css::util::ElementChange(
773                                 css::uno::makeAny(path.makeStringAndClear()),
774                                 css::uno::Any(), css::uno::Any()));
775                             //TODO: non-void ReplacedElement
776                     }
777                     if (collectPropChanges) {
778                         propChanges.push_back(
779                             css::beans::PropertyChangeEvent(
780                                 static_cast< cppu::OWeakObject * >(this),
781                                 i->first, false, -1, css::uno::Any(),
782                                 css::uno::Any()));
783                     }
784                 }
785                 break;
786             case Node::KIND_SET:
787                 // Removed set member:
788                 if (i->second.children.empty()) {
789                     for (ContainerListeners::iterator j(
790                              containerListeners_.begin());
791                          j != containerListeners_.end(); ++j)
792                     {
793                         broadcaster->addContainerElementRemovedNotification(
794                             *j,
795                             css::container::ContainerEvent(
796                                 static_cast< cppu::OWeakObject * >(this),
797                                 css::uno::makeAny(i->first),
798                                 css::uno::Any(), css::uno::Any()));
799                             //TODO: non-void ReplacedElement
800                     }
801                     if (allChanges != 0) {
802                         rtl::OUStringBuffer path(
803                             getRelativePathRepresentation());
804                         if (path.getLength() != 0) {
805                             path.append(sal_Unicode('/'));
806                         }
807                         path.append(
808                             Data::createSegment(
809                                 rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("*")),
810                                 i->first));
811                         allChanges->push_back(
812                             css::util::ElementChange(
813                                 css::uno::makeAny(path.makeStringAndClear()),
814                                 css::uno::Any(), css::uno::Any()));
815                             //TODO: non-void ReplacedElement
816                     }
817                 }
818                 // else: spurious Modifications::Node not representing a change
819                 break;
820             default:
821                 OSL_ASSERT(false); // this cannot happen
822                 break;
823             }
824         }
825     }
826     if (!propChanges.empty()) {
827         css::uno::Sequence< css::beans::PropertyChangeEvent > seq(
828             propChanges.getAsConstList());
829         for (PropertiesChangeListeners::iterator i(
830                  propertiesChangeListeners_.begin());
831              i != propertiesChangeListeners_.end(); ++i)
832         {
833             broadcaster->addPropertiesChangeNotification(*i, seq);
834         }
835     }
836 }
837 
838 bool Access::isDisposed() const {
839     return disposed_;
840 }
841 
842 Access::ModifiedChild::ModifiedChild() {}
843 
844 Access::ModifiedChild::ModifiedChild(
845     rtl::Reference< ChildAccess > const & theChild, bool theDirectlyModified):
846     child(theChild), directlyModified(theDirectlyModified)
847 {}
848 
849 css::uno::Sequence< css::uno::Type > Access::getTypes()
850     throw (css::uno::RuntimeException)
851 {
852     OSL_ASSERT(thisIs(IS_ANY));
853     osl::MutexGuard g(lock);
854     checkLocalizedPropertyAccess();
855     comphelper::SequenceAsVector< css::uno::Type > types;
856     types.push_back(cppu::UnoType< css::uno::XInterface >::get());
857     types.push_back(cppu::UnoType< css::uno::XWeak >::get());
858     types.push_back(cppu::UnoType< css::lang::XTypeProvider >::get());
859     types.push_back(cppu::UnoType< css::lang::XServiceInfo >::get());
860     types.push_back(cppu::UnoType< css::lang::XComponent >::get());
861     types.push_back(
862         cppu::UnoType< css::container::XHierarchicalNameAccess >::get());
863     types.push_back(cppu::UnoType< css::container::XContainer >::get());
864     types.push_back(cppu::UnoType< css::beans::XExactName >::get());
865     types.push_back(cppu::UnoType< css::container::XHierarchicalName >::get());
866     types.push_back(cppu::UnoType< css::container::XNamed >::get());
867     types.push_back(cppu::UnoType< css::beans::XProperty >::get());
868     types.push_back(cppu::UnoType< css::container::XElementAccess >::get());
869     types.push_back(cppu::UnoType< css::container::XNameAccess >::get());
870     if (getNode()->kind() == Node::KIND_GROUP) {
871         types.push_back(cppu::UnoType< css::beans::XPropertySetInfo >::get());
872         types.push_back(cppu::UnoType< css::beans::XPropertySet >::get());
873         types.push_back(cppu::UnoType< css::beans::XMultiPropertySet >::get());
874         types.push_back(
875             cppu::UnoType< css::beans::XHierarchicalPropertySet >::get());
876         types.push_back(
877             cppu::UnoType< css::beans::XMultiHierarchicalPropertySet >::get());
878         types.push_back(
879             cppu::UnoType< css::beans::XHierarchicalPropertySetInfo >::get());
880     }
881     if (getRootAccess()->isUpdate()) {
882         types.push_back(cppu::UnoType< css::container::XNameReplace >::get());
883         if (getNode()->kind() != Node::KIND_GROUP ||
884             dynamic_cast< GroupNode * >(getNode().get())->isExtensible())
885         {
886             types.push_back(
887                 cppu::UnoType< css::container::XNameContainer >::get());
888         }
889         if (getNode()->kind() == Node::KIND_SET) {
890             types.push_back(
891                 cppu::UnoType< css::lang::XSingleServiceFactory >::get());
892         }
893     }
894     addTypes(&types);
895     return types.getAsConstList();
896 }
897 
898 css::uno::Sequence< sal_Int8 > Access::getImplementationId()
899     throw (css::uno::RuntimeException)
900 {
901     OSL_ASSERT(thisIs(IS_ANY));
902     osl::MutexGuard g(lock);
903     checkLocalizedPropertyAccess();
904     return css::uno::Sequence< sal_Int8 >();
905 }
906 
907 rtl::OUString Access::getImplementationName() throw (css::uno::RuntimeException)
908 {
909     OSL_ASSERT(thisIs(IS_ANY));
910     osl::MutexGuard g(lock);
911     checkLocalizedPropertyAccess();
912     return rtl::OUString(
913         RTL_CONSTASCII_USTRINGPARAM("org.openoffice-configmgr::Access"));
914 }
915 
916 sal_Bool Access::supportsService(rtl::OUString const & ServiceName)
917     throw (css::uno::RuntimeException)
918 {
919     OSL_ASSERT(thisIs(IS_ANY));
920     osl::MutexGuard g(lock);
921     checkLocalizedPropertyAccess();
922     css::uno::Sequence< rtl::OUString > names(getSupportedServiceNames());
923     for (sal_Int32 i = 0; i < names.getLength(); ++i) {
924         if (names[i] == ServiceName) {
925             return true;
926         }
927     }
928     return false;
929 }
930 
931 css::uno::Sequence< rtl::OUString > Access::getSupportedServiceNames()
932     throw (css::uno::RuntimeException)
933 {
934     OSL_ASSERT(thisIs(IS_ANY));
935     osl::MutexGuard g(lock);
936     checkLocalizedPropertyAccess();
937     comphelper::SequenceAsVector< rtl::OUString > services;
938     services.push_back(
939         rtl::OUString(
940             RTL_CONSTASCII_USTRINGPARAM(
941                 "com.sun.star.configuration.ConfigurationAccess")));
942     if (getRootAccess()->isUpdate()) {
943         services.push_back(
944             rtl::OUString(
945                 RTL_CONSTASCII_USTRINGPARAM(
946                     "com.sun.star.configuration.ConfigurationUpdateAccess")));
947     }
948     services.push_back(
949         rtl::OUString(
950             RTL_CONSTASCII_USTRINGPARAM(
951                 "com.sun.star.configuration.HierarchyAccess")));
952     services.push_back(
953         rtl::OUString(
954             RTL_CONSTASCII_USTRINGPARAM(
955                 "com.sun.star.configuration.HierarchyElement")));
956     if (getNode()->kind() == Node::KIND_GROUP) {
957         services.push_back(
958             rtl::OUString(
959                 RTL_CONSTASCII_USTRINGPARAM(
960                     "com.sun.star.configuration.GroupAccess")));
961         services.push_back(
962             rtl::OUString(
963                 RTL_CONSTASCII_USTRINGPARAM(
964                     "com.sun.star.configuration.PropertyHierarchy")));
965         if (getRootAccess()->isUpdate()) {
966             services.push_back(
967                 rtl::OUString(
968                     RTL_CONSTASCII_USTRINGPARAM(
969                         "com.sun.star.configuration.GroupUpdate")));
970         }
971     } else {
972         services.push_back(
973             rtl::OUString(
974                 RTL_CONSTASCII_USTRINGPARAM(
975                     "com.sun.star.configuration.SetAccess")));
976         services.push_back(
977             rtl::OUString(
978                 RTL_CONSTASCII_USTRINGPARAM(
979                     "com.sun.star.configuration.SimpleSetAccess")));
980         if (getRootAccess()->isUpdate()) {
981             services.push_back(
982                 rtl::OUString(
983                     RTL_CONSTASCII_USTRINGPARAM(
984                         "com.sun.star.configuration.SetUpdate")));
985             services.push_back(
986                 rtl::OUString(
987                     RTL_CONSTASCII_USTRINGPARAM(
988                         "com.sun.star.configuration.SimpleSetUpdate")));
989         }
990     }
991     addSupportedServiceNames(&services);
992     return services.getAsConstList();
993 }
994 
995 void Access::dispose() throw (css::uno::RuntimeException) {
996     OSL_ASSERT(thisIs(IS_ANY));
997     Broadcaster bc;
998     {
999         osl::MutexGuard g(lock);
1000         checkLocalizedPropertyAccess();
1001         if (getParentAccess().is()) {
1002             throw css::uno::RuntimeException(
1003                 rtl::OUString(
1004                     RTL_CONSTASCII_USTRINGPARAM(
1005                         "configmgr dispose inappropriate Access")),
1006                 static_cast< cppu::OWeakObject * >(this));
1007         }
1008         if (disposed_) {
1009             return;
1010         }
1011         initDisposeBroadcaster(&bc);
1012         clearListeners();
1013         disposed_ = true;
1014     }
1015     bc.send();
1016 }
1017 
1018 void Access::addEventListener(
1019     css::uno::Reference< css::lang::XEventListener > const & xListener)
1020     throw (css::uno::RuntimeException)
1021 {
1022     OSL_ASSERT(thisIs(IS_ANY));
1023     {
1024         osl::MutexGuard g(lock);
1025         checkLocalizedPropertyAccess();
1026         if (!xListener.is()) {
1027             throw css::uno::RuntimeException(
1028                 rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("null listener")),
1029                 static_cast< cppu::OWeakObject * >(this));
1030         }
1031         if (!disposed_) {
1032             disposeListeners_.insert(xListener);
1033             return;
1034         }
1035     }
1036     try {
1037         xListener->disposing(
1038             css::lang::EventObject(static_cast< cppu::OWeakObject * >(this)));
1039     } catch (css::lang::DisposedException &) {}
1040 }
1041 
1042 void Access::removeEventListener(
1043     css::uno::Reference< css::lang::XEventListener > const & aListener)
1044     throw (css::uno::RuntimeException)
1045 {
1046     OSL_ASSERT(thisIs(IS_ANY));
1047     osl::MutexGuard g(lock);
1048     checkLocalizedPropertyAccess();
1049     DisposeListeners::iterator i(disposeListeners_.find(aListener));
1050     if (i != disposeListeners_.end()) {
1051         disposeListeners_.erase(i);
1052     }
1053 }
1054 
1055 css::uno::Type Access::getElementType() throw (css::uno::RuntimeException) {
1056     OSL_ASSERT(thisIs(IS_ANY));
1057     osl::MutexGuard g(lock);
1058     checkLocalizedPropertyAccess();
1059     rtl::Reference< Node > p(getNode());
1060     switch (p->kind()) {
1061     case Node::KIND_LOCALIZED_PROPERTY:
1062         return mapType(
1063             dynamic_cast< LocalizedPropertyNode * >(p.get())->getStaticType());
1064     case Node::KIND_GROUP:
1065         //TODO: Should a specific type be returned for a non-extensible group
1066         // with homogeneous members or for an extensible group that currently
1067         // has only homegeneous members?
1068         return cppu::UnoType< cppu::UnoVoidType >::get();
1069     case Node::KIND_SET:
1070         return cppu::UnoType< cppu::UnoVoidType >::get(); //TODO: correct?
1071     default:
1072         OSL_ASSERT(false);
1073         throw css::uno::RuntimeException(
1074             rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("this cannot happen")),
1075             static_cast< cppu::OWeakObject * >(this));
1076     }
1077 }
1078 
1079 sal_Bool Access::hasElements() throw (css::uno::RuntimeException) {
1080     OSL_ASSERT(thisIs(IS_ANY));
1081     osl::MutexGuard g(lock);
1082     checkLocalizedPropertyAccess();
1083     return !getAllChildren().empty(); //TODO: optimize
1084 }
1085 
1086 css::uno::Any Access::getByName(rtl::OUString const & aName)
1087     throw (
1088         css::container::NoSuchElementException,
1089         css::lang::WrappedTargetException, css::uno::RuntimeException)
1090 {
1091     OSL_ASSERT(thisIs(IS_ANY));
1092     osl::MutexGuard g(lock);
1093     checkLocalizedPropertyAccess();
1094     rtl::Reference< ChildAccess > child(getChild(aName));
1095     if (!child.is()) {
1096         throw css::container::NoSuchElementException(
1097             aName, static_cast< cppu::OWeakObject * >(this));
1098     }
1099     return child->asValue();
1100 }
1101 
1102 css::uno::Sequence< rtl::OUString > Access::getElementNames()
1103     throw (css::uno::RuntimeException)
1104 {
1105     OSL_ASSERT(thisIs(IS_ANY));
1106     osl::MutexGuard g(lock);
1107     checkLocalizedPropertyAccess();
1108     std::vector< rtl::Reference< ChildAccess > > children(getAllChildren());
1109     comphelper::SequenceAsVector< rtl::OUString > names;
1110     for (std::vector< rtl::Reference< ChildAccess > >::iterator i(
1111              children.begin());
1112          i != children.end(); ++i)
1113     {
1114         names.push_back((*i)->getNameInternal());
1115     }
1116     return names.getAsConstList();
1117 }
1118 
1119 sal_Bool Access::hasByName(rtl::OUString const & aName)
1120     throw (css::uno::RuntimeException)
1121 {
1122     OSL_ASSERT(thisIs(IS_ANY));
1123     osl::MutexGuard g(lock);
1124     checkLocalizedPropertyAccess();
1125     return getChild(aName).is();
1126 }
1127 
1128 css::uno::Any Access::getByHierarchicalName(rtl::OUString const & aName)
1129     throw (css::container::NoSuchElementException, css::uno::RuntimeException)
1130 {
1131     OSL_ASSERT(thisIs(IS_ANY));
1132     osl::MutexGuard g(lock);
1133     checkLocalizedPropertyAccess();
1134     rtl::Reference< ChildAccess > child(getSubChild(aName));
1135     if (!child.is()) {
1136         throw css::container::NoSuchElementException(
1137             aName, static_cast< cppu::OWeakObject * >(this));
1138     }
1139     return child->asValue();
1140 }
1141 
1142 sal_Bool Access::hasByHierarchicalName(rtl::OUString const & aName)
1143     throw (css::uno::RuntimeException)
1144 {
1145     OSL_ASSERT(thisIs(IS_ANY));
1146     osl::MutexGuard g(lock);
1147     checkLocalizedPropertyAccess();
1148     return getSubChild(aName).is();
1149 }
1150 
1151 void Access::addContainerListener(
1152     css::uno::Reference< css::container::XContainerListener > const & xListener)
1153     throw (css::uno::RuntimeException)
1154 {
1155     OSL_ASSERT(thisIs(IS_ANY));
1156     {
1157         osl::MutexGuard g(lock);
1158         checkLocalizedPropertyAccess();
1159         if (!xListener.is()) {
1160             throw css::uno::RuntimeException(
1161                 rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("null listener")),
1162                 static_cast< cppu::OWeakObject * >(this));
1163         }
1164         if (!disposed_) {
1165             containerListeners_.insert(xListener);
1166             return;
1167         }
1168     }
1169     try {
1170         xListener->disposing(
1171             css::lang::EventObject(static_cast< cppu::OWeakObject * >(this)));
1172     } catch (css::lang::DisposedException &) {}
1173 }
1174 
1175 void Access::removeContainerListener(
1176     css::uno::Reference< css::container::XContainerListener > const & xListener)
1177     throw (css::uno::RuntimeException)
1178 {
1179     OSL_ASSERT(thisIs(IS_ANY));
1180     osl::MutexGuard g(lock);
1181     checkLocalizedPropertyAccess();
1182     ContainerListeners::iterator i(containerListeners_.find(xListener));
1183     if (i != containerListeners_.end()) {
1184         containerListeners_.erase(i);
1185     }
1186 }
1187 
1188 rtl::OUString Access::getExactName(rtl::OUString const & aApproximateName)
1189     throw (css::uno::RuntimeException)
1190 {
1191     OSL_ASSERT(thisIs(IS_ANY));
1192     osl::MutexGuard g(lock);
1193     checkLocalizedPropertyAccess();
1194     return aApproximateName;
1195 }
1196 
1197 css::uno::Sequence< css::beans::Property > Access::getProperties()
1198     throw (css::uno::RuntimeException)
1199 {
1200     OSL_ASSERT(thisIs(IS_GROUP));
1201     osl::MutexGuard g(lock);
1202     std::vector< rtl::Reference< ChildAccess > > children(getAllChildren());
1203     comphelper::SequenceAsVector< css::beans::Property > properties;
1204     for (std::vector< rtl::Reference< ChildAccess > >::iterator i(
1205              children.begin());
1206          i != children.end(); ++i)
1207     {
1208         properties.push_back((*i)->asProperty());
1209     }
1210     return properties.getAsConstList();
1211 }
1212 
1213 css::beans::Property Access::getPropertyByName(rtl::OUString const & aName)
1214     throw (css::beans::UnknownPropertyException, css::uno::RuntimeException)
1215 {
1216     OSL_ASSERT(thisIs(IS_GROUP));
1217     osl::MutexGuard g(lock);
1218     rtl::Reference< ChildAccess > child(getChild(aName));
1219     if (!child.is()) {
1220         throw css::beans::UnknownPropertyException(
1221             aName, static_cast< cppu::OWeakObject * >(this));
1222     }
1223     return child->asProperty();
1224 }
1225 
1226 sal_Bool Access::hasPropertyByName(rtl::OUString const & Name)
1227     throw (css::uno::RuntimeException)
1228 {
1229     OSL_ASSERT(thisIs(IS_GROUP));
1230     osl::MutexGuard g(lock);
1231     return getChild(Name).is();
1232 }
1233 
1234 rtl::OUString Access::getHierarchicalName() throw (css::uno::RuntimeException) {
1235     OSL_ASSERT(thisIs(IS_ANY));
1236     osl::MutexGuard g(lock);
1237     checkLocalizedPropertyAccess();
1238     // For backwards compatibility, return an absolute path representation where
1239     // available:
1240     rtl::OUStringBuffer path;
1241     rtl::Reference< RootAccess > root(getRootAccess());
1242     if (root.is()) {
1243         path.append(root->getAbsolutePathRepresentation());
1244     }
1245     rtl::OUString rel(getRelativePathRepresentation());
1246     if (path.getLength() != 0 && rel.getLength() != 0) {
1247         path.append(sal_Unicode('/'));
1248     }
1249     path.append(rel);
1250     return path.makeStringAndClear();
1251 }
1252 
1253 rtl::OUString Access::composeHierarchicalName(
1254     rtl::OUString const & aRelativeName)
1255     throw (
1256         css::lang::IllegalArgumentException, css::lang::NoSupportException,
1257         css::uno::RuntimeException)
1258 {
1259     OSL_ASSERT(thisIs(IS_ANY));
1260     osl::MutexGuard g(lock);
1261     checkLocalizedPropertyAccess();
1262     if (aRelativeName.getLength() == 0 || aRelativeName[0] == '/') {
1263         throw css::lang::IllegalArgumentException(
1264             rtl::OUString(
1265                 RTL_CONSTASCII_USTRINGPARAM(
1266                     "configmgr composeHierarchicalName inappropriate relative"
1267                     " name")),
1268             static_cast< cppu::OWeakObject * >(this), -1);
1269     }
1270     rtl::OUStringBuffer path(getRelativePathRepresentation());
1271     if (path.getLength() != 0) {
1272         path.append(sal_Unicode('/'));
1273     }
1274     path.append(aRelativeName);
1275     return path.makeStringAndClear();
1276 }
1277 
1278 rtl::OUString Access::getName() throw (css::uno::RuntimeException) {
1279     OSL_ASSERT(thisIs(IS_ANY));
1280     osl::MutexGuard g(lock);
1281     checkLocalizedPropertyAccess();
1282     return getNameInternal();
1283 }
1284 
1285 void Access::setName(rtl::OUString const & aName)
1286     throw (css::uno::RuntimeException)
1287 {
1288     OSL_ASSERT(thisIs(IS_ANY));
1289     Broadcaster bc;
1290     {
1291         osl::MutexGuard g(lock);
1292         checkLocalizedPropertyAccess();
1293         checkFinalized();
1294         Modifications localMods;
1295         switch (getNode()->kind()) {
1296         case Node::KIND_GROUP:
1297         case Node::KIND_SET:
1298             {
1299                 rtl::Reference< Access > parent(getParentAccess());
1300                 if (parent.is()) {
1301                     rtl::Reference< Node > node(getNode());
1302                     if (node->getTemplateName().getLength() != 0) {
1303                         rtl::Reference< ChildAccess > other(
1304                             parent->getChild(aName));
1305                         if (other.get() == this) {
1306                             break;
1307                         }
1308                         if (node->getMandatory() == Data::NO_LAYER &&
1309                             !(other.is() && other->isFinalized()))
1310                         {
1311                             rtl::Reference< RootAccess > root(getRootAccess());
1312                             rtl::Reference< ChildAccess > childAccess(
1313                                 dynamic_cast< ChildAccess * >(this));
1314                             localMods.add(getRelativePath());
1315                             // unbind() modifies the parent chain that
1316                             // markChildAsModified() walks, so order is
1317                             // important:
1318                             parent->markChildAsModified(childAccess);
1319                                 //TODO: must not throw
1320                             childAccess->unbind(); // must not throw
1321                             if (other.is()) {
1322                                 other->unbind(); // must not throw
1323                             }
1324                             childAccess->bind(root, parent, aName);
1325                                 // must not throw
1326                             parent->markChildAsModified(childAccess);
1327                                 //TODO: must not throw
1328                             localMods.add(getRelativePath());
1329                             break;
1330                         }
1331                     }
1332                 }
1333             }
1334             // fall through
1335         case Node::KIND_LOCALIZED_PROPERTY:
1336             // renaming a property could only work for an extension property,
1337             // but a localized property is never an extension property
1338             throw css::uno::RuntimeException(
1339                 rtl::OUString(
1340                     RTL_CONSTASCII_USTRINGPARAM(
1341                         "configmgr setName inappropriate node")),
1342                 static_cast< cppu::OWeakObject * >(this));
1343         default:
1344             OSL_ASSERT(false); // this cannot happen
1345             break;
1346         }
1347         getNotificationRoot()->initBroadcaster(localMods.getRoot(), &bc);
1348     }
1349     bc.send();
1350 }
1351 
1352 css::beans::Property Access::getAsProperty() throw (css::uno::RuntimeException)
1353 {
1354     OSL_ASSERT(thisIs(IS_ANY));
1355     osl::MutexGuard g(lock);
1356     checkLocalizedPropertyAccess();
1357     return asProperty();
1358 }
1359 
1360 css::uno::Reference< css::beans::XPropertySetInfo > Access::getPropertySetInfo()
1361     throw (css::uno::RuntimeException)
1362 {
1363     OSL_ASSERT(thisIs(IS_GROUP));
1364     return this;
1365 }
1366 
1367 void Access::setPropertyValue(
1368     rtl::OUString const & aPropertyName, css::uno::Any const & aValue)
1369     throw (
1370         css::beans::UnknownPropertyException, css::beans::PropertyVetoException,
1371         css::lang::IllegalArgumentException, css::lang::WrappedTargetException,
1372         css::uno::RuntimeException)
1373 {
1374     OSL_ASSERT(thisIs(IS_GROUP));
1375     Broadcaster bc;
1376     {
1377         osl::MutexGuard g(lock);
1378         if (!getRootAccess()->isUpdate()) {
1379             throw css::uno::RuntimeException(
1380                 rtl::OUString(
1381                     RTL_CONSTASCII_USTRINGPARAM(
1382                         "configmgr setPropertyValue on non-update access")),
1383                 static_cast< cppu::OWeakObject * >(this));
1384         }
1385         Modifications localMods;
1386         if (!setChildProperty(aPropertyName, aValue, &localMods)) {
1387             throw css::beans::UnknownPropertyException(
1388                 aPropertyName, static_cast< cppu::OWeakObject * >(this));
1389         }
1390         getNotificationRoot()->initBroadcaster(localMods.getRoot(), &bc);
1391     }
1392     bc.send();
1393 }
1394 
1395 css::uno::Any Access::getPropertyValue(rtl::OUString const & PropertyName)
1396     throw (
1397         css::beans::UnknownPropertyException, css::lang::WrappedTargetException,
1398         css::uno::RuntimeException)
1399 {
1400     OSL_ASSERT(thisIs(IS_GROUP));
1401     osl::MutexGuard g(lock);
1402     rtl::Reference< ChildAccess > child(getChild(PropertyName));
1403     if (!child.is()) {
1404         throw css::beans::UnknownPropertyException(
1405             PropertyName, static_cast< cppu::OWeakObject * >(this));
1406     }
1407     return child->asValue();
1408 }
1409 
1410 void Access::addPropertyChangeListener(
1411     rtl::OUString const & aPropertyName,
1412     css::uno::Reference< css::beans::XPropertyChangeListener > const &
1413         xListener)
1414     throw (
1415         css::beans::UnknownPropertyException, css::lang::WrappedTargetException,
1416         css::uno::RuntimeException)
1417 {
1418     OSL_ASSERT(thisIs(IS_GROUP));
1419     {
1420         osl::MutexGuard g(lock);
1421         if (!xListener.is()) {
1422             throw css::uno::RuntimeException(
1423                 rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("null listener")),
1424                 static_cast< cppu::OWeakObject * >(this));
1425         }
1426         checkKnownProperty(aPropertyName);
1427         if (!disposed_) {
1428             propertyChangeListeners_[aPropertyName].insert(xListener);
1429             return;
1430         }
1431     }
1432     try {
1433         xListener->disposing(
1434             css::lang::EventObject(static_cast< cppu::OWeakObject * >(this)));
1435     } catch (css::lang::DisposedException &) {}
1436 }
1437 
1438 void Access::removePropertyChangeListener(
1439     rtl::OUString const & aPropertyName,
1440     css::uno::Reference< css::beans::XPropertyChangeListener > const &
1441         aListener)
1442     throw (
1443         css::beans::UnknownPropertyException, css::lang::WrappedTargetException,
1444         css::uno::RuntimeException)
1445 {
1446     OSL_ASSERT(thisIs(IS_GROUP));
1447     osl::MutexGuard g(lock);
1448     checkKnownProperty(aPropertyName);
1449     PropertyChangeListeners::iterator i(
1450         propertyChangeListeners_.find(aPropertyName));
1451     if (i != propertyChangeListeners_.end()) {
1452         PropertyChangeListenersElement::iterator j(i->second.find(aListener));
1453         if (j != i->second.end()) {
1454             i->second.erase(j);
1455             if (i->second.empty()) {
1456                 propertyChangeListeners_.erase(i);
1457             }
1458         }
1459     }
1460 }
1461 
1462 void Access::addVetoableChangeListener(
1463     rtl::OUString const & PropertyName,
1464     css::uno::Reference< css::beans::XVetoableChangeListener > const &
1465         aListener)
1466     throw (
1467         css::beans::UnknownPropertyException, css::lang::WrappedTargetException,
1468         css::uno::RuntimeException)
1469 {
1470     OSL_ASSERT(thisIs(IS_GROUP));
1471     {
1472         osl::MutexGuard g(lock);
1473         if (!aListener.is()) {
1474             throw css::uno::RuntimeException(
1475                 rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("null listener")),
1476                 static_cast< cppu::OWeakObject * >(this));
1477         }
1478         checkKnownProperty(PropertyName);
1479         if (!disposed_) {
1480             vetoableChangeListeners_[PropertyName].insert(aListener);
1481             //TODO: actually call vetoableChangeListeners_
1482             return;
1483         }
1484     }
1485     try {
1486         aListener->disposing(
1487             css::lang::EventObject(static_cast< cppu::OWeakObject * >(this)));
1488     } catch (css::lang::DisposedException &) {}
1489 }
1490 
1491 void Access::removeVetoableChangeListener(
1492     rtl::OUString const & PropertyName,
1493     css::uno::Reference< css::beans::XVetoableChangeListener > const &
1494         aListener)
1495     throw (
1496         css::beans::UnknownPropertyException, css::lang::WrappedTargetException,
1497         css::uno::RuntimeException)
1498 {
1499     OSL_ASSERT(thisIs(IS_GROUP));
1500     osl::MutexGuard g(lock);
1501     checkKnownProperty(PropertyName);
1502     VetoableChangeListeners::iterator i(
1503         vetoableChangeListeners_.find(PropertyName));
1504     if (i != vetoableChangeListeners_.end()) {
1505         VetoableChangeListenersElement::iterator j(i->second.find(aListener));
1506         if (j != i->second.end()) {
1507             i->second.erase(j);
1508             if (i->second.empty()) {
1509                 vetoableChangeListeners_.erase(i);
1510             }
1511         }
1512     }
1513 }
1514 
1515 void Access::setPropertyValues(
1516     css::uno::Sequence< rtl::OUString > const & aPropertyNames,
1517     css::uno::Sequence< css::uno::Any > const & aValues)
1518     throw (
1519         css::beans::PropertyVetoException, css::lang::IllegalArgumentException,
1520         css::lang::WrappedTargetException, css::uno::RuntimeException)
1521 {
1522     OSL_ASSERT(thisIs(IS_GROUP));
1523     Broadcaster bc;
1524     {
1525         osl::MutexGuard g(lock);
1526         if (!getRootAccess()->isUpdate()) {
1527             throw css::uno::RuntimeException(
1528                 rtl::OUString(
1529                     RTL_CONSTASCII_USTRINGPARAM(
1530                         "configmgr setPropertyValues on non-update access")),
1531                 static_cast< cppu::OWeakObject * >(this));
1532         }
1533         if (aPropertyNames.getLength() != aValues.getLength()) {
1534             throw css::lang::IllegalArgumentException(
1535                 rtl::OUString(
1536                     RTL_CONSTASCII_USTRINGPARAM(
1537                         "configmgr setPropertyValues: aPropertyNames/aValues of"
1538                         " different length")),
1539                 static_cast< cppu::OWeakObject * >(this), -1);
1540         }
1541         Modifications localMods;
1542         for (sal_Int32 i = 0; i < aPropertyNames.getLength(); ++i) {
1543             if (!setChildProperty(aPropertyNames[i], aValues[i], &localMods)) {
1544                 throw css::lang::IllegalArgumentException(
1545                     rtl::OUString(
1546                         RTL_CONSTASCII_USTRINGPARAM(
1547                             "configmgr setPropertyValues inappropriate property"
1548                             " name")),
1549                     static_cast< cppu::OWeakObject * >(this), -1);
1550             }
1551         }
1552         getNotificationRoot()->initBroadcaster(localMods.getRoot(), &bc);
1553     }
1554     bc.send();
1555 }
1556 
1557 css::uno::Sequence< css::uno::Any > Access::getPropertyValues(
1558     css::uno::Sequence< rtl::OUString > const & aPropertyNames)
1559     throw (css::uno::RuntimeException)
1560 {
1561     OSL_ASSERT(thisIs(IS_GROUP));
1562     osl::MutexGuard g(lock);
1563     css::uno::Sequence< css::uno::Any > vals(aPropertyNames.getLength());
1564     for (sal_Int32 i = 0; i < aPropertyNames.getLength(); ++i) {
1565         rtl::Reference< ChildAccess > child(getChild(aPropertyNames[i]));
1566         if (!child.is()) {
1567             throw css::uno::RuntimeException(
1568                 rtl::OUString(
1569                     RTL_CONSTASCII_USTRINGPARAM(
1570                         "configmgr getPropertyValues inappropriate property"
1571                         " name")),
1572                 static_cast< cppu::OWeakObject * >(this));
1573         }
1574         vals[i] = child->asValue();
1575     }
1576     return vals;
1577 }
1578 
1579 void Access::addPropertiesChangeListener(
1580     css::uno::Sequence< rtl::OUString > const &,
1581     css::uno::Reference< css::beans::XPropertiesChangeListener > const &
1582         xListener)
1583     throw (css::uno::RuntimeException)
1584 {
1585     OSL_ASSERT(thisIs(IS_GROUP));
1586     {
1587         osl::MutexGuard g(lock);
1588         if (!xListener.is()) {
1589             throw css::uno::RuntimeException(
1590                 rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("null listener")),
1591                 static_cast< cppu::OWeakObject * >(this));
1592         }
1593         if (!disposed_) {
1594             propertiesChangeListeners_.insert(xListener);
1595             return;
1596         }
1597     }
1598     try {
1599         xListener->disposing(
1600             css::lang::EventObject(static_cast< cppu::OWeakObject * >(this)));
1601     } catch (css::lang::DisposedException &) {}
1602 }
1603 
1604 void Access::removePropertiesChangeListener(
1605     css::uno::Reference< css::beans::XPropertiesChangeListener > const &
1606         xListener)
1607     throw (css::uno::RuntimeException)
1608 {
1609     OSL_ASSERT(thisIs(IS_GROUP));
1610     osl::MutexGuard g(lock);
1611     PropertiesChangeListeners::iterator i(
1612         propertiesChangeListeners_.find(xListener));
1613     if (i != propertiesChangeListeners_.end()) {
1614         propertiesChangeListeners_.erase(i);
1615     }
1616 }
1617 
1618 void Access::firePropertiesChangeEvent(
1619     css::uno::Sequence< rtl::OUString > const & aPropertyNames,
1620     css::uno::Reference< css::beans::XPropertiesChangeListener > const &
1621         xListener)
1622     throw (css::uno::RuntimeException)
1623 {
1624     OSL_ASSERT(thisIs(IS_GROUP));
1625     css::uno::Sequence< css::beans::PropertyChangeEvent > events(
1626         aPropertyNames.getLength());
1627     for (sal_Int32 i = 0; i < events.getLength(); ++i) {
1628         events[i].Source = static_cast< cppu::OWeakObject * >(this);
1629         events[i].PropertyName = aPropertyNames[i];
1630         events[i].Further = false;
1631         events[i].PropertyHandle = -1;
1632     }
1633     xListener->propertiesChange(events);
1634 }
1635 
1636 css::uno::Reference< css::beans::XHierarchicalPropertySetInfo >
1637 Access::getHierarchicalPropertySetInfo() throw (css::uno::RuntimeException) {
1638     OSL_ASSERT(thisIs(IS_GROUP));
1639     return this;
1640 }
1641 
1642 void Access::setHierarchicalPropertyValue(
1643     rtl::OUString const & aHierarchicalPropertyName,
1644     css::uno::Any const & aValue)
1645     throw (
1646         css::beans::UnknownPropertyException, css::beans::PropertyVetoException,
1647         css::lang::IllegalArgumentException, css::lang::WrappedTargetException,
1648         css::uno::RuntimeException)
1649 {
1650     OSL_ASSERT(thisIs(IS_GROUP));
1651     Broadcaster bc;
1652     {
1653         osl::MutexGuard g(lock);
1654         if (!getRootAccess()->isUpdate()) {
1655             throw css::uno::RuntimeException(
1656                 rtl::OUString(
1657                     RTL_CONSTASCII_USTRINGPARAM(
1658                         "configmgr setHierarchicalPropertyName on non-update"
1659                         " access")),
1660                 static_cast< cppu::OWeakObject * >(this));
1661         }
1662         rtl::Reference< ChildAccess > child(
1663             getSubChild(aHierarchicalPropertyName));
1664         if (!child.is()) {
1665             throw css::beans::UnknownPropertyException(
1666                 aHierarchicalPropertyName,
1667                 static_cast< cppu::OWeakObject * >(this));
1668         }
1669         child->checkFinalized();
1670         Modifications localMods;
1671         child->setProperty(aValue, &localMods);
1672         getNotificationRoot()->initBroadcaster(localMods.getRoot(), &bc);
1673     }
1674     bc.send();
1675 }
1676 
1677 css::uno::Any Access::getHierarchicalPropertyValue(
1678     rtl::OUString const & aHierarchicalPropertyName)
1679     throw (
1680         css::beans::UnknownPropertyException,
1681         css::lang::IllegalArgumentException, css::lang::WrappedTargetException,
1682         css::uno::RuntimeException)
1683 {
1684     OSL_ASSERT(thisIs(IS_GROUP));
1685     osl::MutexGuard g(lock);
1686     rtl::Reference< ChildAccess > child(getSubChild(aHierarchicalPropertyName));
1687     if (!child.is()) {
1688         throw css::beans::UnknownPropertyException(
1689             aHierarchicalPropertyName,
1690             static_cast< cppu::OWeakObject * >(this));
1691     }
1692     return child->asValue();
1693 }
1694 
1695 void Access::setHierarchicalPropertyValues(
1696     css::uno::Sequence< rtl::OUString > const & aHierarchicalPropertyNames,
1697     css::uno::Sequence< css::uno::Any > const & Values)
1698     throw (
1699         css::beans::PropertyVetoException, css::lang::IllegalArgumentException,
1700         css::lang::WrappedTargetException, css::uno::RuntimeException)
1701 {
1702     OSL_ASSERT(thisIs(IS_GROUP));
1703     Broadcaster bc;
1704     {
1705         osl::MutexGuard g(lock);
1706         if (!getRootAccess()->isUpdate()) {
1707             throw css::uno::RuntimeException(
1708                 rtl::OUString(
1709                     RTL_CONSTASCII_USTRINGPARAM(
1710                         "configmgr setPropertyValues on non-update access")),
1711                 static_cast< cppu::OWeakObject * >(this));
1712         }
1713         if (aHierarchicalPropertyNames.getLength() != Values.getLength()) {
1714             throw css::lang::IllegalArgumentException(
1715                 rtl::OUString(
1716                     RTL_CONSTASCII_USTRINGPARAM(
1717                         "configmgr setHierarchicalPropertyValues:"
1718                         " aHierarchicalPropertyNames/Values of different"
1719                         " length")),
1720                 static_cast< cppu::OWeakObject * >(this), -1);
1721         }
1722         Modifications localMods;
1723         for (sal_Int32 i = 0; i < aHierarchicalPropertyNames.getLength(); ++i) {
1724             rtl::Reference< ChildAccess > child(
1725                 getSubChild(aHierarchicalPropertyNames[i]));
1726             if (!child.is()) {
1727                 throw css::lang::IllegalArgumentException(
1728                     rtl::OUString(
1729                         RTL_CONSTASCII_USTRINGPARAM(
1730                             "configmgr setHierarchicalPropertyValues"
1731                             " inappropriate property name")),
1732                     static_cast< cppu::OWeakObject * >(this), -1);
1733             }
1734             child->checkFinalized();
1735             child->setProperty(Values[i], &localMods);
1736         }
1737         getNotificationRoot()->initBroadcaster(localMods.getRoot(), &bc);
1738     }
1739     bc.send();
1740 }
1741 
1742 css::uno::Sequence< css::uno::Any > Access::getHierarchicalPropertyValues(
1743     css::uno::Sequence< rtl::OUString > const & aHierarchicalPropertyNames)
1744     throw (
1745         css::lang::IllegalArgumentException, css::lang::WrappedTargetException,
1746         css::uno::RuntimeException)
1747 {
1748     OSL_ASSERT(thisIs(IS_GROUP));
1749     osl::MutexGuard g(lock);
1750     css::uno::Sequence< css::uno::Any > vals(
1751         aHierarchicalPropertyNames.getLength());
1752     for (sal_Int32 i = 0; i < aHierarchicalPropertyNames.getLength(); ++i) {
1753         rtl::Reference< ChildAccess > child(
1754             getSubChild(aHierarchicalPropertyNames[i]));
1755         if (!child.is()) {
1756             throw css::lang::IllegalArgumentException(
1757                 rtl::OUString(
1758                     RTL_CONSTASCII_USTRINGPARAM(
1759                         "configmgr getHierarchicalPropertyValues inappropriate"
1760                         " hierarchical property name")),
1761                 static_cast< cppu::OWeakObject * >(this), -1);
1762         }
1763         vals[i] = child->asValue();
1764     }
1765     return vals;
1766 }
1767 
1768 css::beans::Property Access::getPropertyByHierarchicalName(
1769     rtl::OUString const & aHierarchicalName)
1770     throw (css::beans::UnknownPropertyException, css::uno::RuntimeException)
1771 {
1772     OSL_ASSERT(thisIs(IS_GROUP));
1773     osl::MutexGuard g(lock);
1774     rtl::Reference< ChildAccess > child(getSubChild(aHierarchicalName));
1775     if (!child.is()) {
1776         throw css::beans::UnknownPropertyException(
1777             aHierarchicalName, static_cast< cppu::OWeakObject * >(this));
1778     }
1779     return child->asProperty();
1780 }
1781 
1782 sal_Bool Access::hasPropertyByHierarchicalName(
1783     rtl::OUString const & aHierarchicalName)
1784     throw (css::uno::RuntimeException)
1785 {
1786     OSL_ASSERT(thisIs(IS_GROUP));
1787     osl::MutexGuard g(lock);
1788     return getSubChild(aHierarchicalName).is();
1789 }
1790 
1791 void Access::replaceByName(
1792     rtl::OUString const & aName, css::uno::Any const & aElement)
1793     throw (
1794         css::lang::IllegalArgumentException,
1795         css::container::NoSuchElementException,
1796         css::lang::WrappedTargetException, css::uno::RuntimeException)
1797 {
1798     OSL_ASSERT(thisIs(IS_UPDATE));
1799     Broadcaster bc;
1800     {
1801         osl::MutexGuard g(lock);
1802         checkLocalizedPropertyAccess();
1803         rtl::Reference< ChildAccess > child(getChild(aName));
1804         if (!child.is()) {
1805             throw css::container::NoSuchElementException(
1806                 aName, static_cast< cppu::OWeakObject * >(this));
1807         }
1808         child->checkFinalized();
1809         Modifications localMods;
1810         switch (getNode()->kind()) {
1811         case Node::KIND_LOCALIZED_PROPERTY:
1812         case Node::KIND_GROUP:
1813             child->setProperty(aElement, &localMods);
1814             break;
1815         case Node::KIND_SET:
1816             {
1817                 rtl::Reference< ChildAccess > freeAcc(
1818                     getFreeSetMember(aElement));
1819                 rtl::Reference< RootAccess > root(getRootAccess());
1820                 localMods.add(child->getRelativePath());
1821                 child->unbind(); // must not throw
1822                 freeAcc->bind(root, this, aName); // must not throw
1823                 markChildAsModified(freeAcc); //TODO: must not throw
1824             }
1825             break;
1826         default:
1827             OSL_ASSERT(false); // this cannot happen
1828             break;
1829         }
1830         getNotificationRoot()->initBroadcaster(localMods.getRoot(), &bc);
1831     }
1832     bc.send();
1833 }
1834 
1835 void Access::insertByName(
1836     rtl::OUString const & aName, css::uno::Any const & aElement)
1837     throw (
1838         css::lang::IllegalArgumentException,
1839         css::container::ElementExistException,
1840         css::lang::WrappedTargetException, css::uno::RuntimeException)
1841 {
1842     OSL_ASSERT(thisIs(IS_EXTENSIBLE|IS_UPDATE));
1843     Broadcaster bc;
1844     {
1845         osl::MutexGuard g(lock);
1846         checkLocalizedPropertyAccess();
1847         checkFinalized();
1848         if (getChild(aName).is()) {
1849             throw css::container::ElementExistException(
1850                 aName, static_cast< cppu::OWeakObject * >(this));
1851         }
1852         Modifications localMods;
1853         switch (getNode()->kind()) {
1854         case Node::KIND_LOCALIZED_PROPERTY:
1855             insertLocalizedValueChild(aName, aElement, &localMods);
1856             break;
1857         case Node::KIND_GROUP:
1858             {
1859                 checkValue(aElement, TYPE_ANY, true);
1860                 rtl::Reference< ChildAccess > child(
1861                     new ChildAccess(
1862                         components_, getRootAccess(), this, aName,
1863                         new PropertyNode(
1864                             Data::NO_LAYER, TYPE_ANY, true, aElement, true)));
1865                 markChildAsModified(child);
1866                 localMods.add(child->getRelativePath());
1867             }
1868             break;
1869         case Node::KIND_SET:
1870             {
1871                 rtl::Reference< ChildAccess > freeAcc(
1872                     getFreeSetMember(aElement));
1873                 freeAcc->bind(getRootAccess(), this, aName); // must not throw
1874                 markChildAsModified(freeAcc); //TODO: must not throw
1875                 localMods.add(freeAcc->getRelativePath());
1876             }
1877             break;
1878         default:
1879             OSL_ASSERT(false); // this cannot happen
1880             break;
1881         }
1882         getNotificationRoot()->initBroadcaster(localMods.getRoot(), &bc);
1883     }
1884     bc.send();
1885 }
1886 
1887 void Access::removeByName(rtl::OUString const & aName)
1888     throw (
1889         css::container::NoSuchElementException,
1890         css::lang::WrappedTargetException, css::uno::RuntimeException)
1891 {
1892     OSL_ASSERT(thisIs(IS_EXTENSIBLE|IS_UPDATE));
1893     Broadcaster bc;
1894     {
1895         osl::MutexGuard g(lock);
1896         checkLocalizedPropertyAccess();
1897         rtl::Reference< ChildAccess > child(getChild(aName));
1898         if (!child.is() || child->isFinalized() ||
1899             child->getNode()->getMandatory() != Data::NO_LAYER)
1900         {
1901             throw css::container::NoSuchElementException(
1902                 aName, static_cast< cppu::OWeakObject * >(this));
1903         }
1904         if (getNode()->kind() == Node::KIND_GROUP) {
1905             rtl::Reference< Node > p(child->getNode());
1906             if (p->kind() != Node::KIND_PROPERTY ||
1907                 !dynamic_cast< PropertyNode * >(p.get())->isExtension())
1908             {
1909                 throw css::container::NoSuchElementException(
1910                     aName, static_cast< cppu::OWeakObject * >(this));
1911             }
1912         }
1913         Modifications localMods;
1914         localMods.add(child->getRelativePath());
1915         // unbind() modifies the parent chain that markChildAsModified() walks,
1916         // so order is important:
1917         markChildAsModified(child); //TODO: must not throw
1918         child->unbind();
1919         getNotificationRoot()->initBroadcaster(localMods.getRoot(), &bc);
1920     }
1921     bc.send();
1922 }
1923 
1924 css::uno::Reference< css::uno::XInterface > Access::createInstance()
1925     throw (css::uno::Exception, css::uno::RuntimeException)
1926 {
1927     OSL_ASSERT(thisIs(IS_SET|IS_UPDATE));
1928     rtl::OUString tmplName(
1929         dynamic_cast< SetNode * >(getNode().get())->getDefaultTemplateName());
1930     rtl::Reference< Node > tmpl(
1931         components_.getTemplate(Data::NO_LAYER, tmplName));
1932     if (!tmpl.is()) {
1933         throw css::uno::Exception(
1934             (rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("unknown template ")) +
1935              tmplName),
1936             static_cast< cppu::OWeakObject * >(this));
1937     }
1938     rtl::Reference< Node > node(tmpl->clone(true));
1939     node->setLayer(Data::NO_LAYER);
1940     return static_cast< cppu::OWeakObject * >(
1941         new ChildAccess(components_, getRootAccess(), node));
1942 }
1943 
1944 css::uno::Reference< css::uno::XInterface > Access::createInstanceWithArguments(
1945     css::uno::Sequence< css::uno::Any > const & aArguments)
1946     throw (css::uno::Exception, css::uno::RuntimeException)
1947 {
1948     OSL_ASSERT(thisIs(IS_SET|IS_UPDATE));
1949     if (aArguments.getLength() != 0) {
1950         throw css::uno::Exception(
1951             rtl::OUString(
1952                 RTL_CONSTASCII_USTRINGPARAM(
1953                     "configuration SimpleSetUpdate createInstanceWithArguments"
1954                     " must not specify any arguments")),
1955             static_cast< cppu::OWeakObject * >(this));
1956     }
1957     return createInstance();
1958 }
1959 
1960 rtl::Reference< ChildAccess > Access::getModifiedChild(
1961     ModifiedChildren::iterator const & childIterator)
1962 {
1963     return (childIterator->second.child->getParentAccess() == this &&
1964             (childIterator->second.child->getNameInternal() ==
1965              childIterator->first))
1966         ? childIterator->second.child : rtl::Reference< ChildAccess >();
1967 }
1968 
1969 rtl::Reference< ChildAccess > Access::getUnmodifiedChild(
1970     rtl::OUString const & name)
1971 {
1972     OSL_ASSERT(modifiedChildren_.find(name) == modifiedChildren_.end());
1973     rtl::Reference< Node > node(getNode()->getMember(name));
1974     if (!node.is()) {
1975         return rtl::Reference< ChildAccess >();
1976     }
1977     WeakChildMap::iterator i(cachedChildren_.find(name));
1978     if (i != cachedChildren_.end()) {
1979         rtl::Reference< ChildAccess > child;
1980         if (i->second->acquireCounting() > 1) {
1981             child.set(i->second); // must not throw
1982         }
1983         i->second->releaseNondeleting();
1984         if (child.is()) {
1985             child->setNode(node);
1986             return child;
1987         }
1988     }
1989     rtl::Reference< ChildAccess > child(
1990         new ChildAccess(components_, getRootAccess(), this, name, node));
1991     cachedChildren_[name] = child.get();
1992     return child;
1993 }
1994 
1995 rtl::Reference< ChildAccess > Access::getSubChild(rtl::OUString const & path) {
1996     sal_Int32 i = 0;
1997     // For backwards compatibility, allow absolute paths where meaningful:
1998     if (path.getLength() != 0 && path[0] == '/') {
1999         ++i;
2000         if (!getRootAccess().is()) {
2001             return rtl::Reference< ChildAccess >();
2002         }
2003         Path abs(getAbsolutePath());
2004         for (Path::iterator j(abs.begin()); j != abs.end(); ++j) {
2005             rtl::OUString name1;
2006             bool setElement1;
2007             rtl::OUString templateName1;
2008             i = Data::parseSegment(
2009                 path, i, &name1, &setElement1, &templateName1);
2010             if (i == -1 || (i != path.getLength() && path[i] != '/')) {
2011                 return rtl::Reference< ChildAccess >();
2012             }
2013             rtl::OUString name2;
2014             bool setElement2;
2015             rtl::OUString templateName2;
2016             Data::parseSegment(*j, 0, &name2, &setElement2, &templateName2);
2017             if (name1 != name2 || setElement1 != setElement2 ||
2018                 (setElement1 &&
2019                  !Data::equalTemplateNames(templateName1, templateName2)))
2020             {
2021                 return rtl::Reference< ChildAccess >();
2022             }
2023             if (i != path.getLength()) {
2024                 ++i;
2025             }
2026         }
2027     }
2028     for (rtl::Reference< Access > parent(this);;) {
2029         rtl::OUString name;
2030         bool setElement;
2031         rtl::OUString templateName;
2032         i = Data::parseSegment(path, i, &name, &setElement, &templateName);
2033         if (i == -1 || (i != path.getLength() && path[i] != '/')) {
2034             return rtl::Reference< ChildAccess >();
2035         }
2036         rtl::Reference< ChildAccess > child(parent->getChild(name));
2037         if (!child.is()) {
2038             return rtl::Reference< ChildAccess >();
2039         }
2040         if (setElement) {
2041             rtl::Reference< Node > p(parent->getNode());
2042             switch (p->kind()) {
2043             case Node::KIND_LOCALIZED_PROPERTY:
2044                 if (!Components::allLocales(getRootAccess()->getLocale()) ||
2045                     templateName.getLength() != 0)
2046                 {
2047                     return rtl::Reference< ChildAccess >();
2048                 }
2049                 break;
2050             case Node::KIND_SET:
2051                 if (templateName.getLength() != 0 &&
2052                     !dynamic_cast< SetNode * >(p.get())->isValidTemplate(
2053                         templateName))
2054                 {
2055                     return rtl::Reference< ChildAccess >();
2056                 }
2057                 break;
2058             default:
2059                 return rtl::Reference< ChildAccess >();
2060             }
2061         }
2062         // For backwards compatibility, ignore a final slash after non-value
2063         // nodes:
2064         if (child->isValue()) {
2065             return i == path.getLength()
2066                 ? child : rtl::Reference< ChildAccess >();
2067         } else if (i >= path.getLength() - 1) {
2068             return child;
2069         }
2070         ++i;
2071         parent = child.get();
2072     }
2073 }
2074 
2075 bool Access::setChildProperty(
2076     rtl::OUString const & name, css::uno::Any const & value,
2077     Modifications * localModifications)
2078 {
2079     OSL_ASSERT(localModifications != 0);
2080     rtl::Reference< ChildAccess > child(getChild(name));
2081     if (!child.is()) {
2082         return false;
2083     }
2084     child->checkFinalized();
2085     child->setProperty(value, localModifications);
2086     return true;
2087 }
2088 
2089 css::beans::Property Access::asProperty() {
2090     css::uno::Type type;
2091     bool nillable;
2092     bool removable;
2093     rtl::Reference< Node > p(getNode());
2094     switch (p->kind()) {
2095     case Node::KIND_PROPERTY:
2096         {
2097             PropertyNode * prop = dynamic_cast< PropertyNode * >(p.get());
2098             type = mapType(prop->getStaticType());
2099             nillable = prop->isNillable();
2100             removable = prop->isExtension();
2101         }
2102         break;
2103     case Node::KIND_LOCALIZED_PROPERTY:
2104         {
2105             LocalizedPropertyNode * locprop =
2106                 dynamic_cast< LocalizedPropertyNode *>(p.get());
2107             if (Components::allLocales(getRootAccess()->getLocale())) {
2108                 type = cppu::UnoType< css::uno::XInterface >::get();
2109                     //TODO: correct?
2110                 removable = false;
2111             } else {
2112                 type = mapType(locprop->getStaticType());
2113                 removable = false; //TODO ???
2114             }
2115             nillable = locprop->isNillable();
2116         }
2117         break;
2118     case Node::KIND_LOCALIZED_VALUE:
2119         {
2120             LocalizedPropertyNode * locprop =
2121                 dynamic_cast< LocalizedPropertyNode * >(getParentNode().get());
2122             type = mapType(locprop->getStaticType());
2123             nillable = locprop->isNillable();
2124             removable = false; //TODO ???
2125         }
2126         break;
2127     default:
2128         type = cppu::UnoType< css::uno::XInterface >::get(); //TODO: correct?
2129         nillable = false;
2130         rtl::Reference< Node > parent(getParentNode());
2131         removable = parent.is() && parent->kind() == Node::KIND_SET;
2132         break;
2133     }
2134     return css::beans::Property(
2135         getNameInternal(), -1, type,
2136         (css::beans::PropertyAttribute::BOUND | //TODO: correct for group/set?
2137          css::beans::PropertyAttribute::CONSTRAINED |
2138          (nillable ? css::beans::PropertyAttribute::MAYBEVOID : 0) |
2139          (getRootAccess()->isUpdate()
2140           ? (removable ? css::beans::PropertyAttribute::REMOVEABLE : 0)
2141           : css::beans::PropertyAttribute::READONLY))); //TODO: MAYBEDEFAULT
2142 }
2143 
2144 void Access::checkFinalized() {
2145     if (isFinalized()) {
2146         throw css::lang::IllegalArgumentException(
2147             rtl::OUString(
2148                 RTL_CONSTASCII_USTRINGPARAM(
2149                     "configmgr modification of finalized item")),
2150             static_cast< cppu::OWeakObject * >(this), -1);
2151     }
2152 }
2153 
2154 void Access::checkKnownProperty(rtl::OUString const & descriptor) {
2155     if (descriptor.getLength() == 0) {
2156         return;
2157     }
2158     rtl::Reference< ChildAccess > child(getChild(descriptor));
2159     if (child.is()) {
2160         switch (child->getNode()->kind()) {
2161         case Node::KIND_PROPERTY:
2162             return;
2163         case Node::KIND_LOCALIZED_PROPERTY:
2164             if (!Components::allLocales(getRootAccess()->getLocale())) {
2165                 return;
2166             }
2167             break;
2168         case Node::KIND_LOCALIZED_VALUE:
2169             if (Components::allLocales(getRootAccess()->getLocale())) {
2170                 return;
2171             }
2172             break;
2173         default:
2174             break;
2175         }
2176     }
2177     throw css::beans::UnknownPropertyException(
2178         descriptor, static_cast< cppu::OWeakObject * >(this));
2179 }
2180 
2181 rtl::Reference< ChildAccess > Access::getFreeSetMember(
2182     css::uno::Any const & value)
2183 {
2184     rtl::Reference< ChildAccess > freeAcc;
2185     css::uno::Reference< css::lang::XUnoTunnel > tunnel;
2186     value >>= tunnel;
2187     if (tunnel.is()) {
2188         freeAcc.set(
2189             reinterpret_cast< ChildAccess * >(
2190                 tunnel->getSomething(ChildAccess::getTunnelId())));
2191     }
2192     if (!freeAcc.is() || freeAcc->getParentAccess().is() ||
2193         (freeAcc->isInTransaction() &&
2194          freeAcc->getRootAccess() != getRootAccess()))
2195     {
2196         throw css::lang::IllegalArgumentException(
2197             rtl::OUString(
2198                 RTL_CONSTASCII_USTRINGPARAM(
2199                     "configmgr inappropriate set element")),
2200             static_cast< cppu::OWeakObject * >(this), 1);
2201     }
2202     OSL_ASSERT(dynamic_cast< SetNode * >(getNode().get()) != 0);
2203     if (!dynamic_cast< SetNode * >(getNode().get())->isValidTemplate(
2204             freeAcc->getNode()->getTemplateName()))
2205     {
2206         throw css::lang::IllegalArgumentException(
2207             rtl::OUString(
2208                 RTL_CONSTASCII_USTRINGPARAM(
2209                     "configmgr inappropriate set element")),
2210             static_cast< cppu::OWeakObject * >(this), 1);
2211     }
2212     return freeAcc;
2213 }
2214 
2215 rtl::Reference< Access > Access::getNotificationRoot() {
2216     for (rtl::Reference< Access > p(this);;) {
2217         rtl::Reference< Access > parent(p->getParentAccess());
2218         if (!parent.is()) {
2219             return p;
2220         }
2221         p = parent;
2222     }
2223 }
2224 
2225 #if OSL_DEBUG_LEVEL > 0
2226 bool Access::thisIs(int what) {
2227     osl::MutexGuard g(lock);
2228     rtl::Reference< Node > p(getNode());
2229     Node::Kind k(p->kind());
2230     return k != Node::KIND_PROPERTY && k != Node::KIND_LOCALIZED_VALUE &&
2231         ((what & IS_GROUP) == 0 || k == Node::KIND_GROUP) &&
2232         ((what & IS_SET) == 0 || k == Node::KIND_SET) &&
2233         ((what & IS_EXTENSIBLE) == 0 || k != Node::KIND_GROUP ||
2234          dynamic_cast< GroupNode * >(p.get())->isExtensible()) &&
2235         ((what & IS_GROUP_MEMBER) == 0 ||
2236          getParentNode()->kind() == Node::KIND_GROUP) ||
2237         ((what & IS_SET_MEMBER) == 0 ||
2238          getParentNode()->kind() == Node::KIND_SET) ||
2239         ((what & IS_UPDATE) == 0 || getRootAccess()->isUpdate());
2240 }
2241 #endif
2242 
2243 }
2244