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