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