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