Version 4.0.0.1, tag libreoffice-4.0.0.1
[LibreOffice.git] / configmgr / source / access.cxx
blob664127397cfb193cb56478df96f375b5743f0069
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include "sal/config.h"
22 #include <cassert>
23 #include <vector>
25 #include "com/sun/star/beans/Property.hpp"
26 #include "com/sun/star/beans/PropertyAttribute.hpp"
27 #include "com/sun/star/beans/PropertyChangeEvent.hpp"
28 #include "com/sun/star/beans/PropertyVetoException.hpp"
29 #include "com/sun/star/beans/UnknownPropertyException.hpp"
30 #include "com/sun/star/beans/XExactName.hpp"
31 #include "com/sun/star/beans/XHierarchicalPropertySet.hpp"
32 #include "com/sun/star/beans/XHierarchicalPropertySetInfo.hpp"
33 #include "com/sun/star/beans/XMultiHierarchicalPropertySet.hpp"
34 #include "com/sun/star/beans/XMultiPropertySet.hpp"
35 #include "com/sun/star/beans/XPropertiesChangeListener.hpp"
36 #include "com/sun/star/beans/XProperty.hpp"
37 #include "com/sun/star/beans/XPropertyChangeListener.hpp"
38 #include "com/sun/star/beans/XPropertySet.hpp"
39 #include "com/sun/star/beans/XPropertySetInfo.hpp"
40 #include "com/sun/star/beans/XVetoableChangeListener.hpp"
41 #include "com/sun/star/container/ContainerEvent.hpp"
42 #include "com/sun/star/container/NoSuchElementException.hpp"
43 #include "com/sun/star/container/XContainer.hpp"
44 #include "com/sun/star/container/XContainerListener.hpp"
45 #include "com/sun/star/container/XElementAccess.hpp"
46 #include "com/sun/star/container/XHierarchicalName.hpp"
47 #include "com/sun/star/container/XHierarchicalNameAccess.hpp"
48 #include "com/sun/star/container/XHierarchicalNameReplace.hpp"
49 #include "com/sun/star/container/XNameAccess.hpp"
50 #include "com/sun/star/container/XNameContainer.hpp"
51 #include "com/sun/star/container/XNamed.hpp"
52 #include "com/sun/star/lang/DisposedException.hpp"
53 #include "com/sun/star/lang/EventObject.hpp"
54 #include "com/sun/star/lang/IllegalArgumentException.hpp"
55 #include "com/sun/star/lang/NoSupportException.hpp"
56 #include "com/sun/star/lang/WrappedTargetException.hpp"
57 #include "com/sun/star/lang/XComponent.hpp"
58 #include "com/sun/star/lang/XEventListener.hpp"
59 #include "com/sun/star/lang/XServiceInfo.hpp"
60 #include "com/sun/star/lang/XSingleServiceFactory.hpp"
61 #include "com/sun/star/lang/XTypeProvider.hpp"
62 #include "com/sun/star/lang/XUnoTunnel.hpp"
63 #include "com/sun/star/uno/Any.hxx"
64 #include "com/sun/star/uno/Reference.hxx"
65 #include "com/sun/star/uno/RuntimeException.hpp"
66 #include "com/sun/star/uno/Sequence.hxx"
67 #include "com/sun/star/uno/Type.hxx"
68 #include "com/sun/star/uno/TypeClass.hpp"
69 #include "com/sun/star/uno/XInterface.hpp"
70 #include "com/sun/star/uno/XWeak.hpp"
71 #include "com/sun/star/util/ElementChange.hpp"
72 #include "comphelper/sequenceasvector.hxx"
73 #include "cppu/unotype.hxx"
74 #include "cppuhelper/queryinterface.hxx"
75 #include "cppuhelper/weak.hxx"
76 #include "osl/interlck.h"
77 #include "osl/mutex.hxx"
78 #include "rtl/ref.hxx"
79 #include "rtl/ustrbuf.hxx"
80 #include "rtl/ustring.h"
81 #include "rtl/ustring.hxx"
82 #include "sal/types.h"
84 #include "access.hxx"
85 #include "broadcaster.hxx"
86 #include "childaccess.hxx"
87 #include "components.hxx"
88 #include "data.hxx"
89 #include "groupnode.hxx"
90 #include "localizedpropertynode.hxx"
91 #include "localizedvaluenode.hxx"
92 #include "lock.hxx"
93 #include "modifications.hxx"
94 #include "node.hxx"
95 #include "nodemap.hxx"
96 #include "path.hxx"
97 #include "propertynode.hxx"
98 #include "rootaccess.hxx"
99 #include "setnode.hxx"
100 #include "type.hxx"
102 namespace configmgr {
104 oslInterlockedCount Access::acquireCounting() {
105 return osl_atomic_increment(&m_refCount);
108 void Access::releaseNondeleting() {
109 osl_atomic_decrement(&m_refCount);
112 bool Access::isValue() {
113 rtl::Reference< Node > p(getNode());
114 switch (p->kind()) {
115 case Node::KIND_PROPERTY:
116 case Node::KIND_LOCALIZED_VALUE:
117 return true;
118 case Node::KIND_LOCALIZED_PROPERTY:
119 return !Components::allLocales(getRootAccess()->getLocale());
120 default:
121 return false;
125 void Access::markChildAsModified(rtl::Reference< ChildAccess > const & child) {
126 assert(child.is() && child->getParentAccess() == this);
127 modifiedChildren_[child->getNameInternal()] = ModifiedChild(child, true);
128 for (rtl::Reference< Access > p(this);;) {
129 rtl::Reference< Access > parent(p->getParentAccess());
130 if (!parent.is()) {
131 break;
133 assert(dynamic_cast< ChildAccess * >(p.get()) != 0);
134 parent->modifiedChildren_.insert(
135 ModifiedChildren::value_type(
136 p->getNameInternal(),
137 ModifiedChild(dynamic_cast< ChildAccess * >(p.get()), false)));
138 p = parent;
142 void Access::releaseChild(rtl::OUString const & name) {
143 cachedChildren_.erase(name);
146 void Access::initBroadcaster(
147 Modifications::Node const & modifications, Broadcaster * broadcaster)
149 initBroadcasterAndChanges(modifications, broadcaster, 0);
152 css::uno::Sequence< css::uno::Type > Access::getTypes()
153 throw (css::uno::RuntimeException)
155 assert(thisIs(IS_ANY));
156 osl::MutexGuard g(*lock_);
157 checkLocalizedPropertyAccess();
158 comphelper::SequenceAsVector< css::uno::Type > types;
159 types.push_back(cppu::UnoType< css::uno::XInterface >::get());
160 types.push_back(cppu::UnoType< css::uno::XWeak >::get());
161 types.push_back(cppu::UnoType< css::lang::XTypeProvider >::get());
162 types.push_back(cppu::UnoType< css::lang::XServiceInfo >::get());
163 types.push_back(cppu::UnoType< css::lang::XComponent >::get());
164 types.push_back(cppu::UnoType< css::container::XContainer >::get());
165 types.push_back(cppu::UnoType< css::beans::XExactName >::get());
166 types.push_back(cppu::UnoType< css::container::XHierarchicalName >::get());
167 types.push_back(cppu::UnoType< css::container::XNamed >::get());
168 types.push_back(cppu::UnoType< css::beans::XProperty >::get());
169 types.push_back(cppu::UnoType< css::container::XElementAccess >::get());
170 types.push_back(cppu::UnoType< css::container::XNameAccess >::get());
171 if (getNode()->kind() == Node::KIND_GROUP) {
172 types.push_back(cppu::UnoType< css::beans::XPropertySetInfo >::get());
173 types.push_back(cppu::UnoType< css::beans::XPropertySet >::get());
174 types.push_back(cppu::UnoType< css::beans::XMultiPropertySet >::get());
175 types.push_back(
176 cppu::UnoType< css::beans::XHierarchicalPropertySet >::get());
177 types.push_back(
178 cppu::UnoType< css::beans::XMultiHierarchicalPropertySet >::get());
179 types.push_back(
180 cppu::UnoType< css::beans::XHierarchicalPropertySetInfo >::get());
182 if (getRootAccess()->isUpdate()) {
183 types.push_back(cppu::UnoType< css::container::XNameReplace >::get());
184 types.push_back(
185 cppu::UnoType< css::container::XHierarchicalNameReplace >::get());
186 if (getNode()->kind() != Node::KIND_GROUP ||
187 dynamic_cast< GroupNode * >(getNode().get())->isExtensible())
189 types.push_back(
190 cppu::UnoType< css::container::XNameContainer >::get());
192 if (getNode()->kind() == Node::KIND_SET) {
193 types.push_back(
194 cppu::UnoType< css::lang::XSingleServiceFactory >::get());
196 } else {
197 types.push_back(
198 cppu::UnoType< css::container::XHierarchicalNameAccess >::get());
200 addTypes(&types);
201 return types.getAsConstList();
204 css::uno::Sequence< sal_Int8 > Access::getImplementationId()
205 throw (css::uno::RuntimeException)
207 assert(thisIs(IS_ANY));
208 osl::MutexGuard g(*lock_);
209 checkLocalizedPropertyAccess();
210 return css::uno::Sequence< sal_Int8 >();
213 rtl::OUString Access::getImplementationName() throw (css::uno::RuntimeException)
215 assert(thisIs(IS_ANY));
216 osl::MutexGuard g(*lock_);
217 checkLocalizedPropertyAccess();
218 return rtl::OUString(
219 RTL_CONSTASCII_USTRINGPARAM("org.openoffice-configmgr::Access"));
222 sal_Bool Access::supportsService(rtl::OUString const & ServiceName)
223 throw (css::uno::RuntimeException)
225 assert(thisIs(IS_ANY));
226 osl::MutexGuard g(*lock_);
227 checkLocalizedPropertyAccess();
228 css::uno::Sequence< rtl::OUString > names(getSupportedServiceNames());
229 for (sal_Int32 i = 0; i < names.getLength(); ++i) {
230 if (names[i] == ServiceName) {
231 return true;
234 return false;
237 css::uno::Sequence< rtl::OUString > Access::getSupportedServiceNames()
238 throw (css::uno::RuntimeException)
240 assert(thisIs(IS_ANY));
241 osl::MutexGuard g(*lock_);
242 checkLocalizedPropertyAccess();
243 comphelper::SequenceAsVector< rtl::OUString > services;
244 services.push_back(
245 rtl::OUString(
246 RTL_CONSTASCII_USTRINGPARAM(
247 "com.sun.star.configuration.ConfigurationAccess")));
248 if (getRootAccess()->isUpdate()) {
249 services.push_back(
250 rtl::OUString(
251 RTL_CONSTASCII_USTRINGPARAM(
252 "com.sun.star.configuration.ConfigurationUpdateAccess")));
254 services.push_back(
255 rtl::OUString(
256 RTL_CONSTASCII_USTRINGPARAM(
257 "com.sun.star.configuration.HierarchyAccess")));
258 services.push_back(
259 rtl::OUString(
260 RTL_CONSTASCII_USTRINGPARAM(
261 "com.sun.star.configuration.HierarchyElement")));
262 if (getNode()->kind() == Node::KIND_GROUP) {
263 services.push_back(
264 rtl::OUString(
265 RTL_CONSTASCII_USTRINGPARAM(
266 "com.sun.star.configuration.GroupAccess")));
267 services.push_back(
268 rtl::OUString(
269 RTL_CONSTASCII_USTRINGPARAM(
270 "com.sun.star.configuration.PropertyHierarchy")));
271 if (getRootAccess()->isUpdate()) {
272 services.push_back(
273 rtl::OUString(
274 RTL_CONSTASCII_USTRINGPARAM(
275 "com.sun.star.configuration.GroupUpdate")));
277 } else {
278 services.push_back(
279 rtl::OUString(
280 RTL_CONSTASCII_USTRINGPARAM(
281 "com.sun.star.configuration.SetAccess")));
282 services.push_back(
283 rtl::OUString(
284 RTL_CONSTASCII_USTRINGPARAM(
285 "com.sun.star.configuration.SimpleSetAccess")));
286 if (getRootAccess()->isUpdate()) {
287 services.push_back(
288 rtl::OUString(
289 RTL_CONSTASCII_USTRINGPARAM(
290 "com.sun.star.configuration.SetUpdate")));
291 services.push_back(
292 rtl::OUString(
293 RTL_CONSTASCII_USTRINGPARAM(
294 "com.sun.star.configuration.SimpleSetUpdate")));
297 addSupportedServiceNames(&services);
298 return services.getAsConstList();
301 void Access::dispose() throw (css::uno::RuntimeException) {
302 assert(thisIs(IS_ANY));
303 Broadcaster bc;
305 osl::MutexGuard g(*lock_);
306 checkLocalizedPropertyAccess();
307 if (getParentAccess().is()) {
308 throw css::uno::RuntimeException(
309 rtl::OUString(
310 RTL_CONSTASCII_USTRINGPARAM(
311 "configmgr dispose inappropriate Access")),
312 static_cast< cppu::OWeakObject * >(this));
314 if (disposed_) {
315 return;
317 initDisposeBroadcaster(&bc);
318 clearListeners();
319 disposed_ = true;
321 bc.send();
324 void Access::addEventListener(
325 css::uno::Reference< css::lang::XEventListener > const & xListener)
326 throw (css::uno::RuntimeException)
328 assert(thisIs(IS_ANY));
330 osl::MutexGuard g(*lock_);
331 checkLocalizedPropertyAccess();
332 if (!xListener.is()) {
333 throw css::uno::RuntimeException(
334 rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("null listener")),
335 static_cast< cppu::OWeakObject * >(this));
337 if (!disposed_) {
338 disposeListeners_.insert(xListener);
339 return;
342 try {
343 xListener->disposing(
344 css::lang::EventObject(static_cast< cppu::OWeakObject * >(this)));
345 } catch (css::lang::DisposedException &) {}
348 void Access::removeEventListener(
349 css::uno::Reference< css::lang::XEventListener > const & aListener)
350 throw (css::uno::RuntimeException)
352 assert(thisIs(IS_ANY));
353 osl::MutexGuard g(*lock_);
354 checkLocalizedPropertyAccess();
355 DisposeListeners::iterator i(disposeListeners_.find(aListener));
356 if (i != disposeListeners_.end()) {
357 disposeListeners_.erase(i);
361 css::uno::Type Access::getElementType() throw (css::uno::RuntimeException) {
362 assert(thisIs(IS_ANY));
363 osl::MutexGuard g(*lock_);
364 checkLocalizedPropertyAccess();
365 rtl::Reference< Node > p(getNode());
366 switch (p->kind()) {
367 case Node::KIND_LOCALIZED_PROPERTY:
368 return mapType(
369 dynamic_cast< LocalizedPropertyNode * >(p.get())->getStaticType());
370 case Node::KIND_GROUP:
371 //TODO: Should a specific type be returned for a non-extensible group
372 // with homogeneous members or for an extensible group that currently
373 // has only homegeneous members?
374 return cppu::UnoType< cppu::UnoVoidType >::get();
375 case Node::KIND_SET:
376 return cppu::UnoType< cppu::UnoVoidType >::get(); //TODO: correct?
377 default:
378 assert(false);
379 throw css::uno::RuntimeException(
380 rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("this cannot happen")),
381 static_cast< cppu::OWeakObject * >(this));
385 sal_Bool Access::hasElements() throw (css::uno::RuntimeException) {
386 assert(thisIs(IS_ANY));
387 osl::MutexGuard g(*lock_);
388 checkLocalizedPropertyAccess();
389 return !getAllChildren().empty(); //TODO: optimize
392 css::uno::Any Access::getByName(rtl::OUString const & aName)
393 throw (
394 css::container::NoSuchElementException,
395 css::lang::WrappedTargetException, css::uno::RuntimeException)
397 assert(thisIs(IS_ANY));
398 osl::MutexGuard g(*lock_);
399 checkLocalizedPropertyAccess();
400 rtl::Reference< ChildAccess > child(getChild(aName));
401 if (!child.is()) {
402 throw css::container::NoSuchElementException(
403 aName, static_cast< cppu::OWeakObject * >(this));
405 return child->asValue();
408 css::uno::Sequence< rtl::OUString > Access::getElementNames()
409 throw (css::uno::RuntimeException)
411 assert(thisIs(IS_ANY));
412 osl::MutexGuard g(*lock_);
413 checkLocalizedPropertyAccess();
414 std::vector< rtl::Reference< ChildAccess > > children(getAllChildren());
415 comphelper::SequenceAsVector< rtl::OUString > names;
416 for (std::vector< rtl::Reference< ChildAccess > >::iterator i(
417 children.begin());
418 i != children.end(); ++i)
420 names.push_back((*i)->getNameInternal());
422 return names.getAsConstList();
425 sal_Bool Access::hasByName(rtl::OUString const & aName)
426 throw (css::uno::RuntimeException)
428 assert(thisIs(IS_ANY));
429 osl::MutexGuard g(*lock_);
430 checkLocalizedPropertyAccess();
431 return getChild(aName).is();
434 css::uno::Any Access::getByHierarchicalName(rtl::OUString const & aName)
435 throw (css::container::NoSuchElementException, css::uno::RuntimeException)
437 assert(thisIs(IS_ANY));
438 osl::MutexGuard g(*lock_);
439 checkLocalizedPropertyAccess();
440 rtl::Reference< ChildAccess > child(getSubChild(aName));
441 if (!child.is()) {
442 throw css::container::NoSuchElementException(
443 aName, static_cast< cppu::OWeakObject * >(this));
445 return child->asValue();
448 sal_Bool Access::hasByHierarchicalName(rtl::OUString const & aName)
449 throw (css::uno::RuntimeException)
451 assert(thisIs(IS_ANY));
452 osl::MutexGuard g(*lock_);
453 checkLocalizedPropertyAccess();
454 return getSubChild(aName).is();
457 void Access::replaceByHierarchicalName(
458 rtl::OUString const & aName, css::uno::Any const & aElement)
459 throw (
460 css::lang::IllegalArgumentException,
461 css::container::NoSuchElementException,
462 css::lang::WrappedTargetException, css::uno::RuntimeException)
464 //TODO: Actually support sets and combine with replaceByName:
465 assert(thisIs(IS_UPDATE));
466 Broadcaster bc;
468 osl::MutexGuard g(*lock_);
469 checkLocalizedPropertyAccess();
470 rtl::Reference< ChildAccess > child(getSubChild(aName));
471 if (!child.is()) {
472 throw css::container::NoSuchElementException(
473 aName, static_cast< cppu::OWeakObject * >(this));
475 child->checkFinalized();
476 rtl::Reference< Node > parent(child->getParentNode());
477 assert(parent.is());
478 Modifications localMods;
479 switch (parent->kind()) {
480 case Node::KIND_LOCALIZED_PROPERTY:
481 case Node::KIND_GROUP:
482 child->setProperty(aElement, &localMods);
483 break;
484 case Node::KIND_SET:
485 throw css::lang::IllegalArgumentException(
486 rtl::OUString(
487 RTL_CONSTASCII_USTRINGPARAM(
488 "configmgr::Access::replaceByHierarchicalName does not"
489 " currently support set members")),
490 static_cast< cppu::OWeakObject * >(this), 0);
491 case Node::KIND_ROOT:
492 throw css::lang::IllegalArgumentException(
493 (rtl::OUString(
494 RTL_CONSTASCII_USTRINGPARAM(
495 "configmgr::Access::replaceByHierarchicalName does not"
496 " allow changing component "))
497 + aName),
498 static_cast< cppu::OWeakObject * >(this), 0);
499 default:
500 assert(false); // this cannot happen
501 break;
503 getNotificationRoot()->initBroadcaster(localMods.getRoot(), &bc);
505 bc.send();
508 void Access::addContainerListener(
509 css::uno::Reference< css::container::XContainerListener > const & xListener)
510 throw (css::uno::RuntimeException)
512 assert(thisIs(IS_ANY));
514 osl::MutexGuard g(*lock_);
515 checkLocalizedPropertyAccess();
516 if (!xListener.is()) {
517 throw css::uno::RuntimeException(
518 rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("null listener")),
519 static_cast< cppu::OWeakObject * >(this));
521 if (!disposed_) {
522 containerListeners_.insert(xListener);
523 return;
526 try {
527 xListener->disposing(
528 css::lang::EventObject(static_cast< cppu::OWeakObject * >(this)));
529 } catch (css::lang::DisposedException &) {}
532 void Access::removeContainerListener(
533 css::uno::Reference< css::container::XContainerListener > const & xListener)
534 throw (css::uno::RuntimeException)
536 assert(thisIs(IS_ANY));
537 osl::MutexGuard g(*lock_);
538 checkLocalizedPropertyAccess();
539 ContainerListeners::iterator i(containerListeners_.find(xListener));
540 if (i != containerListeners_.end()) {
541 containerListeners_.erase(i);
545 rtl::OUString Access::getExactName(rtl::OUString const & aApproximateName)
546 throw (css::uno::RuntimeException)
548 assert(thisIs(IS_ANY));
549 osl::MutexGuard g(*lock_);
550 checkLocalizedPropertyAccess();
551 return aApproximateName;
554 css::uno::Sequence< css::beans::Property > Access::getProperties()
555 throw (css::uno::RuntimeException)
557 assert(thisIs(IS_GROUP));
558 osl::MutexGuard g(*lock_);
559 std::vector< rtl::Reference< ChildAccess > > children(getAllChildren());
560 comphelper::SequenceAsVector< css::beans::Property > properties;
561 for (std::vector< rtl::Reference< ChildAccess > >::iterator i(
562 children.begin());
563 i != children.end(); ++i)
565 properties.push_back((*i)->asProperty());
567 return properties.getAsConstList();
570 css::beans::Property Access::getPropertyByName(rtl::OUString const & aName)
571 throw (css::beans::UnknownPropertyException, css::uno::RuntimeException)
573 assert(thisIs(IS_GROUP));
574 osl::MutexGuard g(*lock_);
575 rtl::Reference< ChildAccess > child(getChild(aName));
576 if (!child.is()) {
577 throw css::beans::UnknownPropertyException(
578 aName, static_cast< cppu::OWeakObject * >(this));
580 return child->asProperty();
583 sal_Bool Access::hasPropertyByName(rtl::OUString const & Name)
584 throw (css::uno::RuntimeException)
586 assert(thisIs(IS_GROUP));
587 osl::MutexGuard g(*lock_);
588 return getChild(Name).is();
591 rtl::OUString Access::getHierarchicalName() throw (css::uno::RuntimeException) {
592 assert(thisIs(IS_ANY));
593 osl::MutexGuard g(*lock_);
594 checkLocalizedPropertyAccess();
595 // For backwards compatibility, return an absolute path representation where
596 // available:
597 rtl::OUStringBuffer path;
598 rtl::Reference< RootAccess > root(getRootAccess());
599 if (root.is()) {
600 path.append(root->getAbsolutePathRepresentation());
602 rtl::OUString rel(getRelativePathRepresentation());
603 if (path.getLength() != 0 && !rel.isEmpty()) {
604 path.append(sal_Unicode('/'));
606 path.append(rel);
607 return path.makeStringAndClear();
610 rtl::OUString Access::composeHierarchicalName(
611 rtl::OUString const & aRelativeName)
612 throw (
613 css::lang::IllegalArgumentException, css::lang::NoSupportException,
614 css::uno::RuntimeException)
616 assert(thisIs(IS_ANY));
617 osl::MutexGuard g(*lock_);
618 checkLocalizedPropertyAccess();
619 if (aRelativeName.isEmpty() || aRelativeName[0] == '/') {
620 throw css::lang::IllegalArgumentException(
621 rtl::OUString(
622 RTL_CONSTASCII_USTRINGPARAM(
623 "configmgr composeHierarchicalName inappropriate relative"
624 " name")),
625 static_cast< cppu::OWeakObject * >(this), -1);
627 rtl::OUStringBuffer path(getRelativePathRepresentation());
628 if (path.getLength() != 0) {
629 path.append(sal_Unicode('/'));
631 path.append(aRelativeName);
632 return path.makeStringAndClear();
635 rtl::OUString Access::getName() throw (css::uno::RuntimeException) {
636 assert(thisIs(IS_ANY));
637 osl::MutexGuard g(*lock_);
638 checkLocalizedPropertyAccess();
639 return getNameInternal();
642 void Access::setName(rtl::OUString const & aName)
643 throw (css::uno::RuntimeException)
645 assert(thisIs(IS_ANY));
646 Broadcaster bc;
648 osl::MutexGuard g(*lock_);
649 checkLocalizedPropertyAccess();
650 checkFinalized();
651 Modifications localMods;
652 switch (getNode()->kind()) {
653 case Node::KIND_GROUP:
654 case Node::KIND_SET:
656 rtl::Reference< Access > parent(getParentAccess());
657 if (parent.is()) {
658 rtl::Reference< Node > node(getNode());
659 if (! node->getTemplateName().isEmpty()) {
660 rtl::Reference< ChildAccess > other(
661 parent->getChild(aName));
662 if (other.get() == this) {
663 break;
665 if (node->getMandatory() == Data::NO_LAYER &&
666 !(other.is() && other->isFinalized()))
668 rtl::Reference< RootAccess > root(getRootAccess());
669 rtl::Reference< ChildAccess > childAccess(
670 dynamic_cast< ChildAccess * >(this));
671 localMods.add(getRelativePath());
672 // unbind() modifies the parent chain that
673 // markChildAsModified() walks, so order is
674 // important:
675 parent->markChildAsModified(childAccess);
676 //TODO: must not throw
677 childAccess->unbind(); // must not throw
678 if (other.is()) {
679 other->unbind(); // must not throw
681 childAccess->bind(root, parent, aName);
682 // must not throw
683 parent->markChildAsModified(childAccess);
684 //TODO: must not throw
685 localMods.add(getRelativePath());
686 break;
691 // fall through
692 case Node::KIND_LOCALIZED_PROPERTY:
693 // renaming a property could only work for an extension property,
694 // but a localized property is never an extension property
695 throw css::uno::RuntimeException(
696 rtl::OUString(
697 RTL_CONSTASCII_USTRINGPARAM(
698 "configmgr setName inappropriate node")),
699 static_cast< cppu::OWeakObject * >(this));
700 default:
701 assert(false); // this cannot happen
702 break;
704 getNotificationRoot()->initBroadcaster(localMods.getRoot(), &bc);
706 bc.send();
709 css::beans::Property Access::getAsProperty() throw (css::uno::RuntimeException)
711 assert(thisIs(IS_ANY));
712 osl::MutexGuard g(*lock_);
713 checkLocalizedPropertyAccess();
714 return asProperty();
717 css::uno::Reference< css::beans::XPropertySetInfo > Access::getPropertySetInfo()
718 throw (css::uno::RuntimeException)
720 assert(thisIs(IS_GROUP));
721 return this;
724 void Access::setPropertyValue(
725 rtl::OUString const & aPropertyName, css::uno::Any const & aValue)
726 throw (
727 css::beans::UnknownPropertyException, css::beans::PropertyVetoException,
728 css::lang::IllegalArgumentException, css::lang::WrappedTargetException,
729 css::uno::RuntimeException)
731 assert(thisIs(IS_GROUP));
732 Broadcaster bc;
734 osl::MutexGuard g(*lock_);
735 if (!getRootAccess()->isUpdate()) {
736 throw css::uno::RuntimeException(
737 rtl::OUString(
738 RTL_CONSTASCII_USTRINGPARAM(
739 "configmgr setPropertyValue on non-update access")),
740 static_cast< cppu::OWeakObject * >(this));
742 Modifications localMods;
743 if (!setChildProperty(aPropertyName, aValue, &localMods)) {
744 throw css::beans::UnknownPropertyException(
745 aPropertyName, static_cast< cppu::OWeakObject * >(this));
747 getNotificationRoot()->initBroadcaster(localMods.getRoot(), &bc);
749 bc.send();
752 css::uno::Any Access::getPropertyValue(rtl::OUString const & PropertyName)
753 throw (
754 css::beans::UnknownPropertyException, css::lang::WrappedTargetException,
755 css::uno::RuntimeException)
757 assert(thisIs(IS_GROUP));
758 osl::MutexGuard g(*lock_);
759 rtl::Reference< ChildAccess > child(getChild(PropertyName));
760 if (!child.is()) {
761 throw css::beans::UnknownPropertyException(
762 PropertyName, static_cast< cppu::OWeakObject * >(this));
764 return child->asValue();
767 void Access::addPropertyChangeListener(
768 rtl::OUString const & aPropertyName,
769 css::uno::Reference< css::beans::XPropertyChangeListener > const &
770 xListener)
771 throw (
772 css::beans::UnknownPropertyException, css::lang::WrappedTargetException,
773 css::uno::RuntimeException)
775 assert(thisIs(IS_GROUP));
777 osl::MutexGuard g(*lock_);
778 if (!xListener.is()) {
779 throw css::uno::RuntimeException(
780 rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("null listener")),
781 static_cast< cppu::OWeakObject * >(this));
783 checkKnownProperty(aPropertyName);
784 if (!disposed_) {
785 propertyChangeListeners_[aPropertyName].insert(xListener);
786 return;
789 try {
790 xListener->disposing(
791 css::lang::EventObject(static_cast< cppu::OWeakObject * >(this)));
792 } catch (css::lang::DisposedException &) {}
795 void Access::removePropertyChangeListener(
796 rtl::OUString const & aPropertyName,
797 css::uno::Reference< css::beans::XPropertyChangeListener > const &
798 aListener)
799 throw (
800 css::beans::UnknownPropertyException, css::lang::WrappedTargetException,
801 css::uno::RuntimeException)
803 assert(thisIs(IS_GROUP));
804 osl::MutexGuard g(*lock_);
805 checkKnownProperty(aPropertyName);
806 PropertyChangeListeners::iterator i(
807 propertyChangeListeners_.find(aPropertyName));
808 if (i != propertyChangeListeners_.end()) {
809 PropertyChangeListenersElement::iterator j(i->second.find(aListener));
810 if (j != i->second.end()) {
811 i->second.erase(j);
812 if (i->second.empty()) {
813 propertyChangeListeners_.erase(i);
819 void Access::addVetoableChangeListener(
820 rtl::OUString const & PropertyName,
821 css::uno::Reference< css::beans::XVetoableChangeListener > const &
822 aListener)
823 throw (
824 css::beans::UnknownPropertyException, css::lang::WrappedTargetException,
825 css::uno::RuntimeException)
827 assert(thisIs(IS_GROUP));
829 osl::MutexGuard g(*lock_);
830 if (!aListener.is()) {
831 throw css::uno::RuntimeException(
832 rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("null listener")),
833 static_cast< cppu::OWeakObject * >(this));
835 checkKnownProperty(PropertyName);
836 if (!disposed_) {
837 vetoableChangeListeners_[PropertyName].insert(aListener);
838 //TODO: actually call vetoableChangeListeners_
839 return;
842 try {
843 aListener->disposing(
844 css::lang::EventObject(static_cast< cppu::OWeakObject * >(this)));
845 } catch (css::lang::DisposedException &) {}
848 void Access::removeVetoableChangeListener(
849 rtl::OUString const & PropertyName,
850 css::uno::Reference< css::beans::XVetoableChangeListener > const &
851 aListener)
852 throw (
853 css::beans::UnknownPropertyException, css::lang::WrappedTargetException,
854 css::uno::RuntimeException)
856 assert(thisIs(IS_GROUP));
857 osl::MutexGuard g(*lock_);
858 checkKnownProperty(PropertyName);
859 VetoableChangeListeners::iterator i(
860 vetoableChangeListeners_.find(PropertyName));
861 if (i != vetoableChangeListeners_.end()) {
862 VetoableChangeListenersElement::iterator j(i->second.find(aListener));
863 if (j != i->second.end()) {
864 i->second.erase(j);
865 if (i->second.empty()) {
866 vetoableChangeListeners_.erase(i);
872 void Access::setPropertyValues(
873 css::uno::Sequence< rtl::OUString > const & aPropertyNames,
874 css::uno::Sequence< css::uno::Any > const & aValues)
875 throw (
876 css::beans::PropertyVetoException, css::lang::IllegalArgumentException,
877 css::lang::WrappedTargetException, css::uno::RuntimeException)
879 assert(thisIs(IS_GROUP));
880 Broadcaster bc;
882 osl::MutexGuard g(*lock_);
883 if (!getRootAccess()->isUpdate()) {
884 throw css::uno::RuntimeException(
885 rtl::OUString(
886 RTL_CONSTASCII_USTRINGPARAM(
887 "configmgr setPropertyValues on non-update access")),
888 static_cast< cppu::OWeakObject * >(this));
890 if (aPropertyNames.getLength() != aValues.getLength()) {
891 throw css::lang::IllegalArgumentException(
892 rtl::OUString(
893 RTL_CONSTASCII_USTRINGPARAM(
894 "configmgr setPropertyValues: aPropertyNames/aValues of"
895 " different length")),
896 static_cast< cppu::OWeakObject * >(this), -1);
898 Modifications localMods;
899 for (sal_Int32 i = 0; i < aPropertyNames.getLength(); ++i) {
900 if (!setChildProperty(aPropertyNames[i], aValues[i], &localMods)) {
901 throw css::lang::IllegalArgumentException(
902 rtl::OUString(
903 RTL_CONSTASCII_USTRINGPARAM(
904 "configmgr setPropertyValues inappropriate property"
905 " name")),
906 static_cast< cppu::OWeakObject * >(this), -1);
909 getNotificationRoot()->initBroadcaster(localMods.getRoot(), &bc);
911 bc.send();
914 css::uno::Sequence< css::uno::Any > Access::getPropertyValues(
915 css::uno::Sequence< rtl::OUString > const & aPropertyNames)
916 throw (css::uno::RuntimeException)
918 assert(thisIs(IS_GROUP));
919 osl::MutexGuard g(*lock_);
920 css::uno::Sequence< css::uno::Any > vals(aPropertyNames.getLength());
921 for (sal_Int32 i = 0; i < aPropertyNames.getLength(); ++i) {
922 rtl::Reference< ChildAccess > child(getChild(aPropertyNames[i]));
923 if (!child.is()) {
924 throw css::uno::RuntimeException(
925 rtl::OUString(
926 RTL_CONSTASCII_USTRINGPARAM(
927 "configmgr getPropertyValues inappropriate property"
928 " name")),
929 static_cast< cppu::OWeakObject * >(this));
931 vals[i] = child->asValue();
933 return vals;
936 void Access::addPropertiesChangeListener(
937 css::uno::Sequence< rtl::OUString > const &,
938 css::uno::Reference< css::beans::XPropertiesChangeListener > const &
939 xListener)
940 throw (css::uno::RuntimeException)
942 assert(thisIs(IS_GROUP));
944 osl::MutexGuard g(*lock_);
945 if (!xListener.is()) {
946 throw css::uno::RuntimeException(
947 rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("null listener")),
948 static_cast< cppu::OWeakObject * >(this));
950 if (!disposed_) {
951 propertiesChangeListeners_.insert(xListener);
952 return;
955 try {
956 xListener->disposing(
957 css::lang::EventObject(static_cast< cppu::OWeakObject * >(this)));
958 } catch (css::lang::DisposedException &) {}
961 void Access::removePropertiesChangeListener(
962 css::uno::Reference< css::beans::XPropertiesChangeListener > const &
963 xListener)
964 throw (css::uno::RuntimeException)
966 assert(thisIs(IS_GROUP));
967 osl::MutexGuard g(*lock_);
968 PropertiesChangeListeners::iterator i(
969 propertiesChangeListeners_.find(xListener));
970 if (i != propertiesChangeListeners_.end()) {
971 propertiesChangeListeners_.erase(i);
975 void Access::firePropertiesChangeEvent(
976 css::uno::Sequence< rtl::OUString > const & aPropertyNames,
977 css::uno::Reference< css::beans::XPropertiesChangeListener > const &
978 xListener)
979 throw (css::uno::RuntimeException)
981 assert(thisIs(IS_GROUP));
982 css::uno::Sequence< css::beans::PropertyChangeEvent > events(
983 aPropertyNames.getLength());
984 for (sal_Int32 i = 0; i < events.getLength(); ++i) {
985 events[i].Source = static_cast< cppu::OWeakObject * >(this);
986 events[i].PropertyName = aPropertyNames[i];
987 events[i].Further = false;
988 events[i].PropertyHandle = -1;
990 xListener->propertiesChange(events);
993 css::uno::Reference< css::beans::XHierarchicalPropertySetInfo >
994 Access::getHierarchicalPropertySetInfo() throw (css::uno::RuntimeException) {
995 assert(thisIs(IS_GROUP));
996 return this;
999 void Access::setHierarchicalPropertyValue(
1000 rtl::OUString const & aHierarchicalPropertyName,
1001 css::uno::Any const & aValue)
1002 throw (
1003 css::beans::UnknownPropertyException, css::beans::PropertyVetoException,
1004 css::lang::IllegalArgumentException, css::lang::WrappedTargetException,
1005 css::uno::RuntimeException)
1007 assert(thisIs(IS_GROUP));
1008 Broadcaster bc;
1010 osl::MutexGuard g(*lock_);
1011 if (!getRootAccess()->isUpdate()) {
1012 throw css::uno::RuntimeException(
1013 rtl::OUString(
1014 RTL_CONSTASCII_USTRINGPARAM(
1015 "configmgr setHierarchicalPropertyName on non-update"
1016 " access")),
1017 static_cast< cppu::OWeakObject * >(this));
1019 rtl::Reference< ChildAccess > child(
1020 getSubChild(aHierarchicalPropertyName));
1021 if (!child.is()) {
1022 throw css::beans::UnknownPropertyException(
1023 aHierarchicalPropertyName,
1024 static_cast< cppu::OWeakObject * >(this));
1026 child->checkFinalized();
1027 Modifications localMods;
1028 child->setProperty(aValue, &localMods);
1029 getNotificationRoot()->initBroadcaster(localMods.getRoot(), &bc);
1031 bc.send();
1034 css::uno::Any Access::getHierarchicalPropertyValue(
1035 rtl::OUString const & aHierarchicalPropertyName)
1036 throw (
1037 css::beans::UnknownPropertyException,
1038 css::lang::IllegalArgumentException, css::lang::WrappedTargetException,
1039 css::uno::RuntimeException)
1041 assert(thisIs(IS_GROUP));
1042 osl::MutexGuard g(*lock_);
1043 rtl::Reference< ChildAccess > child(getSubChild(aHierarchicalPropertyName));
1044 if (!child.is()) {
1045 throw css::beans::UnknownPropertyException(
1046 aHierarchicalPropertyName,
1047 static_cast< cppu::OWeakObject * >(this));
1049 return child->asValue();
1052 void Access::setHierarchicalPropertyValues(
1053 css::uno::Sequence< rtl::OUString > const & aHierarchicalPropertyNames,
1054 css::uno::Sequence< css::uno::Any > const & Values)
1055 throw (
1056 css::beans::PropertyVetoException, css::lang::IllegalArgumentException,
1057 css::lang::WrappedTargetException, css::uno::RuntimeException)
1059 assert(thisIs(IS_GROUP));
1060 Broadcaster bc;
1062 osl::MutexGuard g(*lock_);
1063 if (!getRootAccess()->isUpdate()) {
1064 throw css::uno::RuntimeException(
1065 rtl::OUString(
1066 RTL_CONSTASCII_USTRINGPARAM(
1067 "configmgr setPropertyValues on non-update access")),
1068 static_cast< cppu::OWeakObject * >(this));
1070 if (aHierarchicalPropertyNames.getLength() != Values.getLength()) {
1071 throw css::lang::IllegalArgumentException(
1072 rtl::OUString(
1073 RTL_CONSTASCII_USTRINGPARAM(
1074 "configmgr setHierarchicalPropertyValues:"
1075 " aHierarchicalPropertyNames/Values of different"
1076 " length")),
1077 static_cast< cppu::OWeakObject * >(this), -1);
1079 Modifications localMods;
1080 for (sal_Int32 i = 0; i < aHierarchicalPropertyNames.getLength(); ++i) {
1081 rtl::Reference< ChildAccess > child(
1082 getSubChild(aHierarchicalPropertyNames[i]));
1083 if (!child.is()) {
1084 throw css::lang::IllegalArgumentException(
1085 rtl::OUString(
1086 RTL_CONSTASCII_USTRINGPARAM(
1087 "configmgr setHierarchicalPropertyValues"
1088 " inappropriate property name")),
1089 static_cast< cppu::OWeakObject * >(this), -1);
1091 child->checkFinalized();
1092 child->setProperty(Values[i], &localMods);
1094 getNotificationRoot()->initBroadcaster(localMods.getRoot(), &bc);
1096 bc.send();
1099 css::uno::Sequence< css::uno::Any > Access::getHierarchicalPropertyValues(
1100 css::uno::Sequence< rtl::OUString > const & aHierarchicalPropertyNames)
1101 throw (
1102 css::lang::IllegalArgumentException, css::lang::WrappedTargetException,
1103 css::uno::RuntimeException)
1105 assert(thisIs(IS_GROUP));
1106 osl::MutexGuard g(*lock_);
1107 css::uno::Sequence< css::uno::Any > vals(
1108 aHierarchicalPropertyNames.getLength());
1109 for (sal_Int32 i = 0; i < aHierarchicalPropertyNames.getLength(); ++i) {
1110 rtl::Reference< ChildAccess > child(
1111 getSubChild(aHierarchicalPropertyNames[i]));
1112 if (!child.is()) {
1113 throw css::lang::IllegalArgumentException(
1114 rtl::OUString(
1115 RTL_CONSTASCII_USTRINGPARAM(
1116 "configmgr getHierarchicalPropertyValues inappropriate"
1117 " hierarchical property name")),
1118 static_cast< cppu::OWeakObject * >(this), -1);
1120 vals[i] = child->asValue();
1122 return vals;
1125 css::beans::Property Access::getPropertyByHierarchicalName(
1126 rtl::OUString const & aHierarchicalName)
1127 throw (css::beans::UnknownPropertyException, css::uno::RuntimeException)
1129 assert(thisIs(IS_GROUP));
1130 osl::MutexGuard g(*lock_);
1131 rtl::Reference< ChildAccess > child(getSubChild(aHierarchicalName));
1132 if (!child.is()) {
1133 throw css::beans::UnknownPropertyException(
1134 aHierarchicalName, static_cast< cppu::OWeakObject * >(this));
1136 return child->asProperty();
1139 sal_Bool Access::hasPropertyByHierarchicalName(
1140 rtl::OUString const & aHierarchicalName)
1141 throw (css::uno::RuntimeException)
1143 assert(thisIs(IS_GROUP));
1144 osl::MutexGuard g(*lock_);
1145 return getSubChild(aHierarchicalName).is();
1148 void Access::replaceByName(
1149 rtl::OUString const & aName, css::uno::Any const & aElement)
1150 throw (
1151 css::lang::IllegalArgumentException,
1152 css::container::NoSuchElementException,
1153 css::lang::WrappedTargetException, css::uno::RuntimeException)
1155 assert(thisIs(IS_UPDATE));
1156 Broadcaster bc;
1158 osl::MutexGuard g(*lock_);
1159 checkLocalizedPropertyAccess();
1160 rtl::Reference< ChildAccess > child(getChild(aName));
1161 if (!child.is()) {
1162 throw css::container::NoSuchElementException(
1163 aName, static_cast< cppu::OWeakObject * >(this));
1165 child->checkFinalized();
1166 Modifications localMods;
1167 switch (getNode()->kind()) {
1168 case Node::KIND_LOCALIZED_PROPERTY:
1169 case Node::KIND_GROUP:
1170 child->setProperty(aElement, &localMods);
1171 break;
1172 case Node::KIND_SET:
1174 rtl::Reference< ChildAccess > freeAcc(
1175 getFreeSetMember(aElement));
1176 rtl::Reference< RootAccess > root(getRootAccess());
1177 localMods.add(child->getRelativePath());
1178 child->unbind(); // must not throw
1179 freeAcc->bind(root, this, aName); // must not throw
1180 markChildAsModified(freeAcc); //TODO: must not throw
1182 break;
1183 default:
1184 assert(false); // this cannot happen
1185 break;
1187 getNotificationRoot()->initBroadcaster(localMods.getRoot(), &bc);
1189 bc.send();
1192 void Access::insertByName(
1193 rtl::OUString const & aName, css::uno::Any const & aElement)
1194 throw (
1195 css::lang::IllegalArgumentException,
1196 css::container::ElementExistException,
1197 css::lang::WrappedTargetException, css::uno::RuntimeException)
1199 assert(thisIs(IS_EXTENSIBLE|IS_UPDATE));
1200 Broadcaster bc;
1202 osl::MutexGuard g(*lock_);
1203 checkLocalizedPropertyAccess();
1204 checkFinalized();
1205 if (getChild(aName).is()) {
1206 throw css::container::ElementExistException(
1207 aName, static_cast< cppu::OWeakObject * >(this));
1209 Modifications localMods;
1210 switch (getNode()->kind()) {
1211 case Node::KIND_LOCALIZED_PROPERTY:
1212 insertLocalizedValueChild(aName, aElement, &localMods);
1213 break;
1214 case Node::KIND_GROUP:
1216 checkValue(aElement, TYPE_ANY, true);
1217 rtl::Reference< ChildAccess > child(
1218 new ChildAccess(
1219 components_, getRootAccess(), this, aName,
1220 new PropertyNode(
1221 Data::NO_LAYER, TYPE_ANY, true, aElement, true)));
1222 markChildAsModified(child);
1223 localMods.add(child->getRelativePath());
1225 break;
1226 case Node::KIND_SET:
1228 rtl::Reference< ChildAccess > freeAcc(
1229 getFreeSetMember(aElement));
1230 freeAcc->bind(getRootAccess(), this, aName); // must not throw
1231 markChildAsModified(freeAcc); //TODO: must not throw
1232 localMods.add(freeAcc->getRelativePath());
1234 break;
1235 default:
1236 assert(false); // this cannot happen
1237 break;
1239 getNotificationRoot()->initBroadcaster(localMods.getRoot(), &bc);
1241 bc.send();
1244 void Access::removeByName(rtl::OUString const & aName)
1245 throw (
1246 css::container::NoSuchElementException,
1247 css::lang::WrappedTargetException, css::uno::RuntimeException)
1249 assert(thisIs(IS_EXTENSIBLE|IS_UPDATE));
1250 Broadcaster bc;
1252 osl::MutexGuard g(*lock_);
1253 checkLocalizedPropertyAccess();
1254 rtl::Reference< ChildAccess > child(getChild(aName));
1255 if (!child.is() || child->isFinalized() ||
1256 child->getNode()->getMandatory() != Data::NO_LAYER)
1258 throw css::container::NoSuchElementException(
1259 aName, static_cast< cppu::OWeakObject * >(this));
1261 if (getNode()->kind() == Node::KIND_GROUP) {
1262 rtl::Reference< Node > p(child->getNode());
1263 if (p->kind() != Node::KIND_PROPERTY ||
1264 !dynamic_cast< PropertyNode * >(p.get())->isExtension())
1266 throw css::container::NoSuchElementException(
1267 aName, static_cast< cppu::OWeakObject * >(this));
1270 Modifications localMods;
1271 localMods.add(child->getRelativePath());
1272 // unbind() modifies the parent chain that markChildAsModified() walks,
1273 // so order is important:
1274 markChildAsModified(child); //TODO: must not throw
1275 child->unbind();
1276 getNotificationRoot()->initBroadcaster(localMods.getRoot(), &bc);
1278 bc.send();
1281 css::uno::Reference< css::uno::XInterface > Access::createInstance()
1282 throw (css::uno::Exception, css::uno::RuntimeException)
1284 assert(thisIs(IS_SET|IS_UPDATE));
1285 rtl::OUString tmplName(
1286 dynamic_cast< SetNode * >(getNode().get())->getDefaultTemplateName());
1287 rtl::Reference< Node > tmpl(
1288 components_.getTemplate(Data::NO_LAYER, tmplName));
1289 if (!tmpl.is()) {
1290 throw css::uno::Exception(
1291 (rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("unknown template ")) +
1292 tmplName),
1293 static_cast< cppu::OWeakObject * >(this));
1295 rtl::Reference< Node > node(tmpl->clone(true));
1296 node->setLayer(Data::NO_LAYER);
1297 return static_cast< cppu::OWeakObject * >(
1298 new ChildAccess(components_, getRootAccess(), node));
1301 css::uno::Reference< css::uno::XInterface > Access::createInstanceWithArguments(
1302 css::uno::Sequence< css::uno::Any > const & aArguments)
1303 throw (css::uno::Exception, css::uno::RuntimeException)
1305 assert(thisIs(IS_SET|IS_UPDATE));
1306 if (aArguments.getLength() != 0) {
1307 throw css::uno::Exception(
1308 rtl::OUString(
1309 RTL_CONSTASCII_USTRINGPARAM(
1310 "configuration SimpleSetUpdate createInstanceWithArguments"
1311 " must not specify any arguments")),
1312 static_cast< cppu::OWeakObject * >(this));
1314 return createInstance();
1317 Access::Access(Components & components):
1318 components_(components), disposed_(false)
1320 lock_ = lock();
1323 Access::~Access() {}
1325 void Access::initDisposeBroadcaster(Broadcaster * broadcaster) {
1326 assert(broadcaster != 0);
1327 for (DisposeListeners::iterator i(disposeListeners_.begin());
1328 i != disposeListeners_.end(); ++i)
1330 broadcaster->addDisposeNotification(
1332 css::lang::EventObject(static_cast< cppu::OWeakObject * >(this)));
1334 for (ContainerListeners::iterator i(containerListeners_.begin());
1335 i != containerListeners_.end(); ++i)
1337 broadcaster->addDisposeNotification(
1338 i->get(),
1339 css::lang::EventObject(static_cast< cppu::OWeakObject * >(this)));
1341 for (PropertyChangeListeners::iterator i(propertyChangeListeners_.begin());
1342 i != propertyChangeListeners_.end(); ++i)
1344 for (PropertyChangeListenersElement::iterator j(i->second.begin());
1345 j != i->second.end(); ++j)
1347 broadcaster->addDisposeNotification(
1348 j->get(),
1349 css::lang::EventObject(
1350 static_cast< cppu::OWeakObject * >(this)));
1353 for (VetoableChangeListeners::iterator i(vetoableChangeListeners_.begin());
1354 i != vetoableChangeListeners_.end(); ++i)
1356 for (VetoableChangeListenersElement::iterator j(i->second.begin());
1357 j != i->second.end(); ++j)
1359 broadcaster->addDisposeNotification(
1360 j->get(),
1361 css::lang::EventObject(
1362 static_cast< cppu::OWeakObject * >(this)));
1365 for (PropertiesChangeListeners::iterator i(
1366 propertiesChangeListeners_.begin());
1367 i != propertiesChangeListeners_.end(); ++i)
1369 broadcaster->addDisposeNotification(
1370 i->get(),
1371 css::lang::EventObject(static_cast< cppu::OWeakObject * >(this)));
1373 //TODO: iterate over children w/ listeners (incl. unmodified ones):
1374 for (ModifiedChildren::iterator i(modifiedChildren_.begin());
1375 i != modifiedChildren_.end(); ++i)
1377 rtl::Reference< ChildAccess > child(getModifiedChild(i));
1378 if (child.is()) {
1379 child->initDisposeBroadcaster(broadcaster);
1384 void Access::clearListeners() throw() {
1385 disposeListeners_.clear();
1386 containerListeners_.clear();
1387 propertyChangeListeners_.clear();
1388 vetoableChangeListeners_.clear();
1389 propertiesChangeListeners_.clear();
1390 //TODO: iterate over children w/ listeners (incl. unmodified ones):
1391 for (ModifiedChildren::iterator i(modifiedChildren_.begin());
1392 i != modifiedChildren_.end(); ++i)
1394 rtl::Reference< ChildAccess > child(getModifiedChild(i));
1395 if (child.is()) {
1396 child->clearListeners();
1401 css::uno::Any Access::queryInterface(css::uno::Type const & aType)
1402 throw (css::uno::RuntimeException)
1404 css::uno::Any res(OWeakObject::queryInterface(aType));
1405 if (res.hasValue()) {
1406 return res;
1408 res = cppu::queryInterface(
1409 aType, static_cast< css::lang::XTypeProvider * >(this),
1410 static_cast< css::lang::XServiceInfo * >(this),
1411 static_cast< css::lang::XComponent * >(this),
1412 static_cast< css::container::XHierarchicalNameAccess * >(this),
1413 static_cast< css::container::XContainer * >(this),
1414 static_cast< css::beans::XExactName * >(this),
1415 static_cast< css::container::XHierarchicalName * >(this),
1416 static_cast< css::container::XNamed * >(this),
1417 static_cast< css::beans::XProperty * >(this),
1418 static_cast< css::container::XElementAccess * >(this),
1419 static_cast< css::container::XNameAccess * >(this));
1420 if (res.hasValue()) {
1421 return res;
1423 if (getNode()->kind() == Node::KIND_GROUP) {
1424 res = cppu::queryInterface(
1425 aType, static_cast< css::beans::XPropertySetInfo * >(this),
1426 static_cast< css::beans::XPropertySet * >(this),
1427 static_cast< css::beans::XMultiPropertySet * >(this),
1428 static_cast< css::beans::XHierarchicalPropertySet * >(this),
1429 static_cast< css::beans::XMultiHierarchicalPropertySet * >(this),
1430 static_cast< css::beans::XHierarchicalPropertySetInfo * >(this));
1431 if (res.hasValue()) {
1432 return res;
1435 if (getRootAccess()->isUpdate()) {
1436 res = cppu::queryInterface(
1437 aType, static_cast< css::container::XNameReplace * >(this),
1438 static_cast< css::container::XHierarchicalNameReplace * >(this));
1439 if (res.hasValue()) {
1440 return res;
1442 if (getNode()->kind() != Node::KIND_GROUP ||
1443 dynamic_cast< GroupNode * >(getNode().get())->isExtensible())
1445 res = cppu::queryInterface(
1446 aType, static_cast< css::container::XNameContainer * >(this));
1447 if (res.hasValue()) {
1448 return res;
1451 if (getNode()->kind() == Node::KIND_SET) {
1452 res = cppu::queryInterface(
1453 aType, static_cast< css::lang::XSingleServiceFactory * >(this));
1456 return res;
1459 Components & Access::getComponents() const {
1460 return components_;
1463 void Access::checkLocalizedPropertyAccess() {
1464 if (getNode()->kind() == Node::KIND_LOCALIZED_PROPERTY &&
1465 !Components::allLocales(getRootAccess()->getLocale()))
1467 throw css::uno::RuntimeException(
1468 rtl::OUString(
1469 RTL_CONSTASCII_USTRINGPARAM(
1470 "configmgr Access to specialized LocalizedPropertyNode")),
1471 static_cast< cppu::OWeakObject * >(this));
1475 rtl::Reference< Node > Access::getParentNode() {
1476 rtl::Reference< Access > parent(getParentAccess());
1477 return parent.is() ? parent->getNode() : rtl::Reference< Node >();
1480 rtl::Reference< ChildAccess > Access::getChild(rtl::OUString const & name) {
1481 if (getNode()->kind() == Node::KIND_LOCALIZED_PROPERTY && name.match("*")) {
1482 OUString locale(name.copy(1));
1483 if (locale.match("*")) {
1484 SAL_WARN(
1485 "configmgr",
1486 ("access best-matching localized property value via"
1487 " \"*<locale>\" with <locale> \"")
1488 << locale << "\" recursively starting with \"*\"");
1489 return getChild(locale);
1491 SAL_WARN_IF(
1492 locale.isEmpty(), "configmgr",
1493 ("access best-matching localized property value via \"*<locale>\""
1494 " with empty <locale>; falling back to defaults"));
1495 if (!locale.isEmpty()) {
1496 // Find best match using an adaption of RFC 4647 lookup matching
1497 // rules, removing "-" or "_" delimited segments from the end:
1498 for (;;) {
1499 rtl::Reference< ChildAccess > child(getChild(locale));
1500 if (child.is()) {
1501 return child;
1503 sal_Int32 i = locale.getLength() - 1;
1504 while (i > 0 && locale[i] != '-' && locale[i] != '_') {
1505 --i;
1507 if (i <= 0) {
1508 break;
1510 locale = locale.copy(0, i);
1512 // As a workaround for broken xcu data that does not use shortest
1513 // xml:lang attributes, look for the first entry with the same first
1514 // segment as the requested language tag before falling back to
1515 // defaults (see fdo#33638):
1516 assert(
1517 !locale.isEmpty() && locale.indexOf('-') == -1 &&
1518 locale.indexOf('_') == -1);
1519 std::vector< rtl::Reference< ChildAccess > > children(
1520 getAllChildren());
1521 for (std::vector< rtl::Reference< ChildAccess > >::iterator i(
1522 children.begin());
1523 i != children.end(); ++i)
1525 OUString name2((*i)->getNameInternal());
1526 if (name2.match(locale) &&
1527 (name2.getLength() == locale.getLength() ||
1528 name2[locale.getLength()] == '-' ||
1529 name2[locale.getLength()] == '_'))
1531 return *i;
1535 // Defaults are the "en-US" locale, the "en" locale, the empty string
1536 // locale, the first child (if any), or a null ChildAccess, in that
1537 // order:
1538 rtl::Reference< ChildAccess > child(getChild("en-US"));
1539 if (child.is()) {
1540 return child;
1542 child = getChild("en");
1543 if (child.is()) {
1544 return child;
1546 child = getChild(OUString());
1547 if (child.is()) {
1548 return child;
1550 std::vector< rtl::Reference< ChildAccess > > children(getAllChildren());
1551 if (!children.empty()) {
1552 return children.front();
1554 return rtl::Reference< ChildAccess >();
1556 ModifiedChildren::iterator i(modifiedChildren_.find(name));
1557 return i == modifiedChildren_.end()
1558 ? getUnmodifiedChild(name) : getModifiedChild(i);
1561 std::vector< rtl::Reference< ChildAccess > > Access::getAllChildren() {
1562 std::vector< rtl::Reference< ChildAccess > > vec;
1563 NodeMap const & members = getNode()->getMembers();
1564 for (NodeMap::const_iterator i(members.begin()); i != members.end(); ++i) {
1565 if (modifiedChildren_.find(i->first) == modifiedChildren_.end()) {
1566 vec.push_back(getUnmodifiedChild(i->first));
1567 assert(vec.back().is());
1570 for (ModifiedChildren::iterator i(modifiedChildren_.begin());
1571 i != modifiedChildren_.end(); ++i)
1573 rtl::Reference< ChildAccess > child(getModifiedChild(i));
1574 if (child.is()) {
1575 vec.push_back(child);
1578 return vec;
1581 void Access::checkValue(css::uno::Any const & value, Type type, bool nillable) {
1582 bool ok;
1583 switch (type) {
1584 case TYPE_NIL:
1585 assert(false);
1586 // fall through (cannot happen)
1587 case TYPE_ERROR:
1588 ok = false;
1589 break;
1590 case TYPE_ANY:
1591 switch (getDynamicType(value)) {
1592 case TYPE_ANY:
1593 assert(false);
1594 // fall through (cannot happen)
1595 case TYPE_ERROR:
1596 ok = false;
1597 break;
1598 case TYPE_NIL:
1599 ok = nillable;
1600 break;
1601 default:
1602 ok = true;
1603 break;
1605 break;
1606 default:
1607 ok = value.hasValue() ? value.isExtractableTo(mapType(type)) : nillable;
1608 break;
1610 if (!ok) {
1611 throw css::lang::IllegalArgumentException(
1612 rtl::OUString(
1613 RTL_CONSTASCII_USTRINGPARAM(
1614 "configmgr inappropriate property value")),
1615 static_cast< cppu::OWeakObject * >(this), -1);
1619 void Access::insertLocalizedValueChild(
1620 rtl::OUString const & name, css::uno::Any const & value,
1621 Modifications * localModifications)
1623 assert(localModifications != 0);
1624 LocalizedPropertyNode * locprop = dynamic_cast< LocalizedPropertyNode * >(
1625 getNode().get());
1626 checkValue(value, locprop->getStaticType(), locprop->isNillable());
1627 rtl::Reference< ChildAccess > child(
1628 new ChildAccess(
1629 components_, getRootAccess(), this, name,
1630 new LocalizedValueNode(Data::NO_LAYER, value)));
1631 markChildAsModified(child);
1632 localModifications->add(child->getRelativePath());
1635 void Access::reportChildChanges(
1636 std::vector< css::util::ElementChange > * changes)
1638 assert(changes != 0);
1639 for (ModifiedChildren::iterator i(modifiedChildren_.begin());
1640 i != modifiedChildren_.end(); ++i)
1642 rtl::Reference< ChildAccess > child(getModifiedChild(i));
1643 if (child.is()) {
1644 child->reportChildChanges(changes);
1645 changes->push_back(css::util::ElementChange());
1646 //TODO: changed value and/or inserted node
1647 } else {
1648 changes->push_back(css::util::ElementChange()); //TODO: removed node
1653 void Access::commitChildChanges(
1654 bool valid, Modifications * globalModifications)
1656 assert(globalModifications != 0);
1657 while (!modifiedChildren_.empty()) {
1658 bool childValid = valid;
1659 ModifiedChildren::iterator i(modifiedChildren_.begin());
1660 rtl::Reference< ChildAccess > child(getModifiedChild(i));
1661 if (child.is()) {
1662 childValid = childValid && !child->isFinalized();
1663 child->commitChanges(childValid, globalModifications);
1664 //TODO: currently, this is called here for directly inserted
1665 // children as well as for children whose sub-children were
1666 // modified (and should never be called for directly removed
1667 // children); clarify what exactly should happen here for
1668 // directly inserted children
1670 NodeMap & members = getNode()->getMembers();
1671 NodeMap::iterator j(members.find(i->first));
1672 if (child.is()) {
1673 // Inserted:
1674 if (j != members.end()) {
1675 childValid = childValid &&
1676 j->second->getFinalized() == Data::NO_LAYER;
1677 if (childValid) {
1678 child->getNode()->setMandatory(j->second->getMandatory());
1681 if (childValid) {
1682 members[i->first] = child->getNode();
1684 } else {
1685 // Removed:
1686 childValid = childValid && j != members.end() &&
1687 j->second->getFinalized() == Data::NO_LAYER &&
1688 j->second->getMandatory() == Data::NO_LAYER;
1689 if (childValid) {
1690 members.erase(j);
1693 if (childValid && i->second.directlyModified) {
1694 Path path(getAbsolutePath());
1695 path.push_back(i->first);
1696 components_.addModification(path);
1697 globalModifications->add(path);
1699 i->second.child->committed();
1700 modifiedChildren_.erase(i);
1704 void Access::initBroadcasterAndChanges(
1705 Modifications::Node const & modifications, Broadcaster * broadcaster,
1706 std::vector< css::util::ElementChange > * allChanges)
1708 assert(broadcaster != 0);
1709 comphelper::SequenceAsVector< css::beans::PropertyChangeEvent > propChanges;
1710 bool collectPropChanges = !propertiesChangeListeners_.empty();
1711 for (Modifications::Node::Children::const_iterator i(
1712 modifications.children.begin());
1713 i != modifications.children.end(); ++i)
1715 rtl::Reference< ChildAccess > child(getChild(i->first));
1716 if (child.is()) {
1717 switch (child->getNode()->kind()) {
1718 case Node::KIND_LOCALIZED_PROPERTY:
1719 if (!i->second.children.empty()) {
1720 if (Components::allLocales(getRootAccess()->getLocale())) {
1721 child->initBroadcasterAndChanges(
1722 i->second, broadcaster, allChanges);
1723 //TODO: if allChanges==0, recurse only into children
1724 // w/ listeners
1725 } else {
1726 //TODO: filter child mods that are irrelevant for
1727 // locale:
1728 for (ContainerListeners::iterator j(
1729 containerListeners_.begin());
1730 j != containerListeners_.end(); ++j)
1732 broadcaster->
1733 addContainerElementReplacedNotification(
1735 css::container::ContainerEvent(
1736 static_cast< cppu::OWeakObject * >(
1737 this),
1738 css::uno::makeAny(i->first),
1739 css::uno::Any(), css::uno::Any()));
1740 //TODO: non-void Element, ReplacedElement
1742 PropertyChangeListeners::iterator j(
1743 propertyChangeListeners_.find(i->first));
1744 if (j != propertyChangeListeners_.end()) {
1745 for (PropertyChangeListenersElement::iterator k(
1746 j->second.begin());
1747 k != j->second.end(); ++k)
1749 broadcaster->addPropertyChangeNotification(
1751 css::beans::PropertyChangeEvent(
1752 static_cast< cppu::OWeakObject * >(
1753 this),
1754 i->first, false, -1, css::uno::Any(),
1755 css::uno::Any()));
1758 j = propertyChangeListeners_.find(rtl::OUString());
1759 if (j != propertyChangeListeners_.end()) {
1760 for (PropertyChangeListenersElement::iterator k(
1761 j->second.begin());
1762 k != j->second.end(); ++k)
1764 broadcaster->addPropertyChangeNotification(
1766 css::beans::PropertyChangeEvent(
1767 static_cast< cppu::OWeakObject * >(
1768 this),
1769 i->first, false, -1, css::uno::Any(),
1770 css::uno::Any()));
1773 if (allChanges != 0) {
1774 allChanges->push_back(
1775 css::util::ElementChange(
1776 css::uno::makeAny(
1777 child->getRelativePathRepresentation()),
1778 css::uno::Any(), css::uno::Any()));
1779 //TODO: non-void Element, ReplacedElement
1781 if (collectPropChanges) {
1782 propChanges.push_back(
1783 css::beans::PropertyChangeEvent(
1784 static_cast< cppu::OWeakObject * >(this),
1785 i->first, false, -1, css::uno::Any(),
1786 css::uno::Any()));
1790 // else: spurious Modifications::Node not representing a change
1791 break;
1792 case Node::KIND_LOCALIZED_VALUE:
1793 assert(Components::allLocales(getRootAccess()->getLocale()));
1794 for (ContainerListeners::iterator j(
1795 containerListeners_.begin());
1796 j != containerListeners_.end(); ++j)
1798 broadcaster->addContainerElementReplacedNotification(
1800 css::container::ContainerEvent(
1801 static_cast< cppu::OWeakObject * >(this),
1802 css::uno::makeAny(i->first), child->asValue(),
1803 css::uno::Any()));
1804 //TODO: distinguish add/modify; non-void ReplacedElement
1806 if (allChanges != 0) {
1807 allChanges->push_back(
1808 css::util::ElementChange(
1809 css::uno::makeAny(
1810 child->getRelativePathRepresentation()),
1811 child->asValue(), css::uno::Any()));
1812 //TODO: non-void ReplacedElement
1814 assert(!collectPropChanges);
1815 break;
1816 case Node::KIND_PROPERTY:
1818 for (ContainerListeners::iterator j(
1819 containerListeners_.begin());
1820 j != containerListeners_.end(); ++j)
1822 broadcaster->addContainerElementReplacedNotification(
1824 css::container::ContainerEvent(
1825 static_cast< cppu::OWeakObject * >(this),
1826 css::uno::makeAny(i->first), child->asValue(),
1827 css::uno::Any()));
1828 //TODO: distinguish add/remove/modify; non-void
1829 // ReplacedElement
1831 PropertyChangeListeners::iterator j(
1832 propertyChangeListeners_.find(i->first));
1833 if (j != propertyChangeListeners_.end()) {
1834 for (PropertyChangeListenersElement::iterator k(
1835 j->second.begin());
1836 k != j->second.end(); ++k)
1838 broadcaster->addPropertyChangeNotification(
1840 css::beans::PropertyChangeEvent(
1841 static_cast< cppu::OWeakObject * >(this),
1842 i->first, false, -1, css::uno::Any(),
1843 css::uno::Any()));
1846 j = propertyChangeListeners_.find(rtl::OUString());
1847 if (j != propertyChangeListeners_.end()) {
1848 for (PropertyChangeListenersElement::iterator k(
1849 j->second.begin());
1850 k != j->second.end(); ++k)
1852 broadcaster->addPropertyChangeNotification(
1854 css::beans::PropertyChangeEvent(
1855 static_cast< cppu::OWeakObject * >(this),
1856 i->first, false, -1, css::uno::Any(),
1857 css::uno::Any()));
1860 if (allChanges != 0) {
1861 allChanges->push_back(
1862 css::util::ElementChange(
1863 css::uno::makeAny(
1864 child->getRelativePathRepresentation()),
1865 child->asValue(), css::uno::Any()));
1866 //TODO: non-void ReplacedElement
1868 if (collectPropChanges) {
1869 propChanges.push_back(
1870 css::beans::PropertyChangeEvent(
1871 static_cast< cppu::OWeakObject * >(this),
1872 i->first, false, -1, css::uno::Any(),
1873 css::uno::Any()));
1876 break;
1877 case Node::KIND_GROUP:
1878 case Node::KIND_SET:
1879 if (i->second.children.empty()) {
1880 if (!child->getNode()->getTemplateName().isEmpty()) {
1881 for (ContainerListeners::iterator j(
1882 containerListeners_.begin());
1883 j != containerListeners_.end(); ++j)
1885 broadcaster->
1886 addContainerElementInsertedNotification(
1888 css::container::ContainerEvent(
1889 static_cast< cppu::OWeakObject * >(
1890 this),
1891 css::uno::makeAny(i->first),
1892 child->asValue(), css::uno::Any()));
1894 if (allChanges != 0) {
1895 allChanges->push_back(
1896 css::util::ElementChange(
1897 css::uno::makeAny(
1898 child->getRelativePathRepresentation()),
1899 css::uno::Any(), css::uno::Any()));
1900 //TODO: non-void Element, ReplacedElement
1903 // else: spurious Modifications::Node not representing a
1904 // change
1905 } else {
1906 child->initBroadcasterAndChanges(
1907 i->second, broadcaster, allChanges);
1908 //TODO: if allChanges==0, recurse only into children w/
1909 // listeners
1911 break;
1912 case Node::KIND_ROOT:
1913 assert(false); // this cannot happen
1914 break;
1916 } else {
1917 switch (getNode()->kind()) {
1918 case Node::KIND_LOCALIZED_PROPERTY:
1919 // Removed localized property value:
1920 assert(Components::allLocales(getRootAccess()->getLocale()));
1921 for (ContainerListeners::iterator j(
1922 containerListeners_.begin());
1923 j != containerListeners_.end(); ++j)
1925 broadcaster->addContainerElementRemovedNotification(
1927 css::container::ContainerEvent(
1928 static_cast< cppu::OWeakObject * >(this),
1929 css::uno::makeAny(i->first), css::uno::Any(),
1930 css::uno::Any()));
1931 //TODO: non-void ReplacedElement
1933 if (allChanges != 0) {
1934 rtl::OUStringBuffer path(getRelativePathRepresentation());
1935 if (path.getLength() != 0) {
1936 path.append(sal_Unicode('/'));
1938 path.append(
1939 Data::createSegment(
1940 rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("*")),
1941 i->first));
1942 allChanges->push_back(
1943 css::util::ElementChange(
1944 css::uno::makeAny(path.makeStringAndClear()),
1945 css::uno::Any(), css::uno::Any()));
1946 //TODO: non-void ReplacedElement
1948 assert(!collectPropChanges);
1949 break;
1950 case Node::KIND_GROUP:
1952 // Removed (non-localized) extension property:
1953 for (ContainerListeners::iterator j(
1954 containerListeners_.begin());
1955 j != containerListeners_.end(); ++j)
1957 broadcaster->addContainerElementRemovedNotification(
1959 css::container::ContainerEvent(
1960 static_cast< cppu::OWeakObject * >(this),
1961 css::uno::makeAny(i->first), css::uno::Any(),
1962 css::uno::Any()));
1963 //TODO: non-void ReplacedElement
1965 PropertyChangeListeners::iterator j(
1966 propertyChangeListeners_.find(i->first));
1967 if (j != propertyChangeListeners_.end()) {
1968 for (PropertyChangeListenersElement::iterator k(
1969 j->second.begin());
1970 k != j->second.end(); ++k)
1972 broadcaster->addPropertyChangeNotification(
1974 css::beans::PropertyChangeEvent(
1975 static_cast< cppu::OWeakObject * >(this),
1976 i->first, false, -1, css::uno::Any(),
1977 css::uno::Any()));
1980 j = propertyChangeListeners_.find(rtl::OUString());
1981 if (j != propertyChangeListeners_.end()) {
1982 for (PropertyChangeListenersElement::iterator k(
1983 j->second.begin());
1984 k != j->second.end(); ++k)
1986 broadcaster->addPropertyChangeNotification(
1988 css::beans::PropertyChangeEvent(
1989 static_cast< cppu::OWeakObject * >(this),
1990 i->first, false, -1, css::uno::Any(),
1991 css::uno::Any()));
1994 if (allChanges != 0) {
1995 rtl::OUStringBuffer path(
1996 getRelativePathRepresentation());
1997 if (path.getLength() != 0) {
1998 path.append(sal_Unicode('/'));
2000 path.append(i->first);
2001 allChanges->push_back(
2002 css::util::ElementChange(
2003 css::uno::makeAny(path.makeStringAndClear()),
2004 css::uno::Any(), css::uno::Any()));
2005 //TODO: non-void ReplacedElement
2007 if (collectPropChanges) {
2008 propChanges.push_back(
2009 css::beans::PropertyChangeEvent(
2010 static_cast< cppu::OWeakObject * >(this),
2011 i->first, false, -1, css::uno::Any(),
2012 css::uno::Any()));
2015 break;
2016 case Node::KIND_SET:
2017 // Removed set member:
2018 if (i->second.children.empty()) {
2019 for (ContainerListeners::iterator j(
2020 containerListeners_.begin());
2021 j != containerListeners_.end(); ++j)
2023 broadcaster->addContainerElementRemovedNotification(
2025 css::container::ContainerEvent(
2026 static_cast< cppu::OWeakObject * >(this),
2027 css::uno::makeAny(i->first),
2028 css::uno::Any(), css::uno::Any()));
2029 //TODO: non-void ReplacedElement
2031 if (allChanges != 0) {
2032 rtl::OUStringBuffer path(
2033 getRelativePathRepresentation());
2034 if (path.getLength() != 0) {
2035 path.append(sal_Unicode('/'));
2037 path.append(
2038 Data::createSegment(
2039 rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("*")),
2040 i->first));
2041 allChanges->push_back(
2042 css::util::ElementChange(
2043 css::uno::makeAny(path.makeStringAndClear()),
2044 css::uno::Any(), css::uno::Any()));
2045 //TODO: non-void ReplacedElement
2048 // else: spurious Modifications::Node not representing a change
2049 break;
2050 default:
2051 assert(false); // this cannot happen
2052 break;
2056 if (!propChanges.empty()) {
2057 css::uno::Sequence< css::beans::PropertyChangeEvent > seq(
2058 propChanges.getAsConstList());
2059 for (PropertiesChangeListeners::iterator i(
2060 propertiesChangeListeners_.begin());
2061 i != propertiesChangeListeners_.end(); ++i)
2063 broadcaster->addPropertiesChangeNotification(*i, seq);
2068 bool Access::isDisposed() const {
2069 return disposed_;
2072 Access::ModifiedChild::ModifiedChild() {}
2074 Access::ModifiedChild::ModifiedChild(
2075 rtl::Reference< ChildAccess > const & theChild, bool theDirectlyModified):
2076 child(theChild), directlyModified(theDirectlyModified)
2079 rtl::Reference< ChildAccess > Access::getModifiedChild(
2080 ModifiedChildren::iterator const & childIterator)
2082 return (childIterator->second.child->getParentAccess() == this &&
2083 (childIterator->second.child->getNameInternal() ==
2084 childIterator->first))
2085 ? childIterator->second.child : rtl::Reference< ChildAccess >();
2088 rtl::Reference< ChildAccess > Access::getUnmodifiedChild(
2089 rtl::OUString const & name)
2091 assert(modifiedChildren_.find(name) == modifiedChildren_.end());
2092 rtl::Reference< Node > node(getNode()->getMember(name));
2093 if (!node.is()) {
2094 return rtl::Reference< ChildAccess >();
2096 WeakChildMap::iterator i(cachedChildren_.find(name));
2097 if (i != cachedChildren_.end()) {
2098 rtl::Reference< ChildAccess > child;
2099 if (i->second->acquireCounting() > 1) {
2100 child.set(i->second); // must not throw
2102 i->second->releaseNondeleting();
2103 if (child.is()) {
2104 child->setNode(node);
2105 return child;
2108 rtl::Reference< ChildAccess > child(
2109 new ChildAccess(components_, getRootAccess(), this, name, node));
2110 cachedChildren_[name] = child.get();
2111 return child;
2114 rtl::Reference< ChildAccess > Access::getSubChild(rtl::OUString const & path) {
2115 sal_Int32 i = 0;
2116 // For backwards compatibility, allow absolute paths where meaningful:
2117 if (!path.isEmpty() && path[0] == '/') {
2118 ++i;
2119 if (!getRootAccess().is()) {
2120 return rtl::Reference< ChildAccess >();
2122 Path abs(getAbsolutePath());
2123 for (Path::iterator j(abs.begin()); j != abs.end(); ++j) {
2124 rtl::OUString name1;
2125 bool setElement1;
2126 rtl::OUString templateName1;
2127 i = Data::parseSegment(
2128 path, i, &name1, &setElement1, &templateName1);
2129 if (i == -1 || (i != path.getLength() && path[i] != '/')) {
2130 return rtl::Reference< ChildAccess >();
2132 rtl::OUString name2;
2133 bool setElement2;
2134 rtl::OUString templateName2;
2135 Data::parseSegment(*j, 0, &name2, &setElement2, &templateName2);
2136 if (name1 != name2 || setElement1 != setElement2 ||
2137 (setElement1 &&
2138 !Data::equalTemplateNames(templateName1, templateName2)))
2140 return rtl::Reference< ChildAccess >();
2142 if (i != path.getLength()) {
2143 ++i;
2147 for (rtl::Reference< Access > parent(this);;) {
2148 rtl::OUString name;
2149 bool setElement;
2150 rtl::OUString templateName;
2151 i = Data::parseSegment(path, i, &name, &setElement, &templateName);
2152 if (i == -1 || (i != path.getLength() && path[i] != '/')) {
2153 return rtl::Reference< ChildAccess >();
2155 rtl::Reference< ChildAccess > child(parent->getChild(name));
2156 if (!child.is()) {
2157 return rtl::Reference< ChildAccess >();
2159 if (setElement) {
2160 rtl::Reference< Node > p(parent->getNode());
2161 switch (p->kind()) {
2162 case Node::KIND_LOCALIZED_PROPERTY:
2163 if (!Components::allLocales(getRootAccess()->getLocale()) ||
2164 !templateName.isEmpty())
2166 return rtl::Reference< ChildAccess >();
2168 break;
2169 case Node::KIND_SET:
2170 if (!templateName.isEmpty() &&
2171 !dynamic_cast< SetNode * >(p.get())->isValidTemplate(
2172 templateName))
2174 return rtl::Reference< ChildAccess >();
2176 break;
2177 default:
2178 return rtl::Reference< ChildAccess >();
2181 // For backwards compatibility, ignore a final slash after non-value
2182 // nodes:
2183 if (child->isValue()) {
2184 return i == path.getLength()
2185 ? child : rtl::Reference< ChildAccess >();
2186 } else if (i >= path.getLength() - 1) {
2187 return child;
2189 ++i;
2190 parent = child.get();
2194 bool Access::setChildProperty(
2195 rtl::OUString const & name, css::uno::Any const & value,
2196 Modifications * localModifications)
2198 assert(localModifications != 0);
2199 rtl::Reference< ChildAccess > child(getChild(name));
2200 if (!child.is()) {
2201 return false;
2203 child->checkFinalized();
2204 child->setProperty(value, localModifications);
2205 return true;
2208 css::beans::Property Access::asProperty() {
2209 css::uno::Type type;
2210 bool nillable;
2211 bool removable;
2212 rtl::Reference< Node > p(getNode());
2213 switch (p->kind()) {
2214 case Node::KIND_PROPERTY:
2216 PropertyNode * prop = dynamic_cast< PropertyNode * >(p.get());
2217 type = mapType(prop->getStaticType());
2218 nillable = prop->isNillable();
2219 removable = prop->isExtension();
2221 break;
2222 case Node::KIND_LOCALIZED_PROPERTY:
2224 LocalizedPropertyNode * locprop =
2225 dynamic_cast< LocalizedPropertyNode *>(p.get());
2226 if (Components::allLocales(getRootAccess()->getLocale())) {
2227 type = cppu::UnoType< css::uno::XInterface >::get();
2228 //TODO: correct?
2229 removable = false;
2230 } else {
2231 type = mapType(locprop->getStaticType());
2232 removable = false; //TODO ???
2234 nillable = locprop->isNillable();
2236 break;
2237 case Node::KIND_LOCALIZED_VALUE:
2239 LocalizedPropertyNode * locprop =
2240 dynamic_cast< LocalizedPropertyNode * >(getParentNode().get());
2241 type = mapType(locprop->getStaticType());
2242 nillable = locprop->isNillable();
2243 removable = false; //TODO ???
2245 break;
2246 default:
2247 type = cppu::UnoType< css::uno::XInterface >::get(); //TODO: correct?
2248 nillable = false;
2249 rtl::Reference< Node > parent(getParentNode());
2250 removable = parent.is() && parent->kind() == Node::KIND_SET;
2251 break;
2253 return css::beans::Property(
2254 getNameInternal(), -1, type,
2255 (css::beans::PropertyAttribute::BOUND | //TODO: correct for group/set?
2256 css::beans::PropertyAttribute::CONSTRAINED |
2257 (nillable ? css::beans::PropertyAttribute::MAYBEVOID : 0) |
2258 (getRootAccess()->isUpdate()
2259 ? (removable ? css::beans::PropertyAttribute::REMOVEABLE : 0)
2260 : css::beans::PropertyAttribute::READONLY))); //TODO: MAYBEDEFAULT
2263 void Access::checkFinalized() {
2264 if (isFinalized()) {
2265 throw css::lang::IllegalArgumentException(
2266 rtl::OUString(
2267 RTL_CONSTASCII_USTRINGPARAM(
2268 "configmgr modification of finalized item")),
2269 static_cast< cppu::OWeakObject * >(this), -1);
2273 void Access::checkKnownProperty(rtl::OUString const & descriptor) {
2274 if (descriptor.isEmpty()) {
2275 return;
2277 rtl::Reference< ChildAccess > child(getChild(descriptor));
2278 if (child.is()) {
2279 switch (child->getNode()->kind()) {
2280 case Node::KIND_PROPERTY:
2281 return;
2282 case Node::KIND_LOCALIZED_PROPERTY:
2283 if (!Components::allLocales(getRootAccess()->getLocale())) {
2284 return;
2286 break;
2287 case Node::KIND_LOCALIZED_VALUE:
2288 if (Components::allLocales(getRootAccess()->getLocale())) {
2289 return;
2291 break;
2292 default:
2293 break;
2296 throw css::beans::UnknownPropertyException(
2297 descriptor, static_cast< cppu::OWeakObject * >(this));
2300 rtl::Reference< ChildAccess > Access::getFreeSetMember(
2301 css::uno::Any const & value)
2303 rtl::Reference< ChildAccess > freeAcc;
2304 css::uno::Reference< css::lang::XUnoTunnel > tunnel;
2305 value >>= tunnel;
2306 if (tunnel.is()) {
2307 freeAcc.set(
2308 reinterpret_cast< ChildAccess * >(
2309 tunnel->getSomething(ChildAccess::getTunnelId())));
2311 if (!freeAcc.is() || freeAcc->getParentAccess().is() ||
2312 (freeAcc->isInTransaction() &&
2313 freeAcc->getRootAccess() != getRootAccess()))
2315 throw css::lang::IllegalArgumentException(
2316 rtl::OUString(
2317 RTL_CONSTASCII_USTRINGPARAM(
2318 "configmgr inappropriate set element")),
2319 static_cast< cppu::OWeakObject * >(this), 1);
2321 assert(dynamic_cast< SetNode * >(getNode().get()) != 0);
2322 if (!dynamic_cast< SetNode * >(getNode().get())->isValidTemplate(
2323 freeAcc->getNode()->getTemplateName()))
2325 throw css::lang::IllegalArgumentException(
2326 rtl::OUString(
2327 RTL_CONSTASCII_USTRINGPARAM(
2328 "configmgr inappropriate set element")),
2329 static_cast< cppu::OWeakObject * >(this), 1);
2331 return freeAcc;
2334 rtl::Reference< Access > Access::getNotificationRoot() {
2335 for (rtl::Reference< Access > p(this);;) {
2336 rtl::Reference< Access > parent(p->getParentAccess());
2337 if (!parent.is()) {
2338 return p;
2340 p = parent;
2344 #if !defined NDEBUG
2345 bool Access::thisIs(int what) {
2346 osl::MutexGuard g(*lock_);
2347 rtl::Reference< Node > p(getNode());
2348 Node::Kind k(p->kind());
2349 return (k != Node::KIND_PROPERTY && k != Node::KIND_LOCALIZED_VALUE &&
2350 ((what & IS_GROUP) == 0 || k == Node::KIND_GROUP) &&
2351 ((what & IS_SET) == 0 || k == Node::KIND_SET) &&
2352 ((what & IS_EXTENSIBLE) == 0 || k != Node::KIND_GROUP ||
2353 dynamic_cast< GroupNode * >(p.get())->isExtensible()) &&
2354 ((what & IS_GROUP_MEMBER) == 0 ||
2355 getParentNode()->kind() == Node::KIND_GROUP)) ||
2356 ((what & IS_SET_MEMBER) == 0 ||
2357 getParentNode()->kind() == Node::KIND_SET) ||
2358 ((what & IS_UPDATE) == 0 || getRootAccess()->isUpdate());
2360 #endif
2364 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */