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