1 /************************************************************** 2 * 3 * Licensed to the Apache Software Foundation (ASF) under one 4 * or more contributor license agreements. See the NOTICE file 5 * distributed with this work for additional information 6 * regarding copyright ownership. The ASF licenses this file 7 * to you under the Apache License, Version 2.0 (the 8 * "License"); you may not use this file except in compliance 9 * with the License. You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, 14 * software distributed under the License is distributed on an 15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 * KIND, either express or implied. See the License for the 17 * specific language governing permissions and limitations 18 * under the License. 19 * 20 *************************************************************/ 21 22 23 24 #include "precompiled_configmgr.hxx" 25 #include "sal/config.h" 26 27 #include <vector> 28 29 #include "com/sun/star/container/XChild.hpp" 30 #include "com/sun/star/lang/NoSupportException.hpp" 31 #include "com/sun/star/lang/XUnoTunnel.hpp" 32 #include "com/sun/star/uno/Any.hxx" 33 #include "com/sun/star/uno/Reference.hxx" 34 #include "com/sun/star/uno/RuntimeException.hpp" 35 #include "com/sun/star/uno/Sequence.hxx" 36 #include "com/sun/star/uno/Type.hxx" 37 #include "com/sun/star/uno/XInterface.hpp" 38 #include "cppu/unotype.hxx" 39 #include "cppuhelper/queryinterface.hxx" 40 #include "cppuhelper/weak.hxx" 41 #include "osl/diagnose.h" 42 #include "osl/mutex.hxx" 43 #include "rtl/ref.hxx" 44 #include "rtl/string.h" 45 #include "rtl/ustrbuf.hxx" 46 #include "rtl/ustring.h" 47 #include "rtl/ustring.hxx" 48 #include "rtl/uuid.h" 49 #include "sal/types.h" 50 51 #include "access.hxx" 52 #include "childaccess.hxx" 53 #include "components.hxx" 54 #include "data.hxx" 55 #include "groupnode.hxx" 56 #include "localizedpropertynode.hxx" 57 #include "localizedvaluenode.hxx" 58 #include "lock.hxx" 59 #include "modifications.hxx" 60 #include "node.hxx" 61 #include "path.hxx" 62 #include "propertynode.hxx" 63 #include "rootaccess.hxx" 64 #include "setnode.hxx" 65 #include "type.hxx" 66 67 namespace configmgr { 68 69 namespace { 70 71 namespace css = com::sun::star; 72 73 } 74 75 css::uno::Sequence< sal_Int8 > ChildAccess::getTunnelId() { 76 static css::uno::Sequence< sal_Int8 > id; 77 if (id.getLength() == 0) { 78 css::uno::Sequence< sal_Int8 > uuid(16); 79 rtl_createUuid( 80 reinterpret_cast< sal_uInt8 * >(uuid.getArray()), 0, false); 81 id = uuid; 82 } 83 return id; 84 } 85 86 ChildAccess::ChildAccess( 87 Components & components, rtl::Reference< RootAccess > const & root, 88 rtl::Reference< Access > const & parent, rtl::OUString const & name, 89 rtl::Reference< Node > const & node): 90 Access(components), root_(root), parent_(parent), name_(name), node_(node), 91 inTransaction_(false) 92 { 93 OSL_ASSERT(root.is() && parent.is() && node.is()); 94 } 95 96 ChildAccess::ChildAccess( 97 Components & components, rtl::Reference< RootAccess > const & root, 98 rtl::Reference< Node > const & node): 99 Access(components), root_(root), node_(node), inTransaction_(false) 100 { 101 OSL_ASSERT(root.is() && node.is()); 102 } 103 104 Path ChildAccess::getAbsolutePath() { 105 OSL_ASSERT(getParentAccess().is()); 106 Path path(getParentAccess()->getAbsolutePath()); 107 path.push_back(name_); 108 return path; 109 } 110 111 Path ChildAccess::getRelativePath() { 112 Path path; 113 rtl::Reference< Access > parent(getParentAccess()); 114 if (parent.is()) { 115 path = parent->getRelativePath(); 116 } 117 path.push_back(name_); 118 return path; 119 } 120 121 rtl::OUString ChildAccess::getRelativePathRepresentation() { 122 rtl::OUStringBuffer path; 123 rtl::Reference< Access > parent(getParentAccess()); 124 if (parent.is()) { 125 path.append(parent->getRelativePathRepresentation()); 126 if (path.getLength() != 0) { 127 path.append(sal_Unicode('/')); 128 } 129 } 130 path.append(Data::createSegment(node_->getTemplateName(), name_)); 131 return path.makeStringAndClear(); 132 } 133 134 rtl::Reference< Node > ChildAccess::getNode() { 135 return node_; 136 } 137 138 bool ChildAccess::isFinalized() { 139 return node_->getFinalized() != Data::NO_LAYER || 140 (parent_.is() && parent_->isFinalized()); 141 } 142 143 rtl::OUString ChildAccess::getNameInternal() { 144 return name_; 145 } 146 147 rtl::Reference< RootAccess > ChildAccess::getRootAccess() { 148 return root_; 149 } 150 151 rtl::Reference< Access > ChildAccess::getParentAccess() { 152 return parent_; 153 } 154 155 void ChildAccess::acquire() throw () { 156 Access::acquire(); 157 } 158 159 void ChildAccess::release() throw () { 160 Access::release(); 161 } 162 163 css::uno::Reference< css::uno::XInterface > ChildAccess::getParent() 164 throw (css::uno::RuntimeException) 165 { 166 OSL_ASSERT(thisIs(IS_ANY)); 167 osl::MutexGuard g(lock); 168 checkLocalizedPropertyAccess(); 169 return static_cast< cppu::OWeakObject * >(parent_.get()); 170 } 171 172 void ChildAccess::setParent(css::uno::Reference< css::uno::XInterface > const &) 173 throw (css::lang::NoSupportException, css::uno::RuntimeException) 174 { 175 OSL_ASSERT(thisIs(IS_ANY)); 176 osl::MutexGuard g(lock); 177 checkLocalizedPropertyAccess(); 178 throw css::lang::NoSupportException( 179 rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("setParent")), 180 static_cast< cppu::OWeakObject * >(this)); 181 } 182 183 sal_Int64 ChildAccess::getSomething( 184 css::uno::Sequence< sal_Int8 > const & aIdentifier) 185 throw (css::uno::RuntimeException) 186 { 187 OSL_ASSERT(thisIs(IS_ANY)); 188 osl::MutexGuard g(lock); 189 checkLocalizedPropertyAccess(); 190 return aIdentifier == getTunnelId() 191 ? reinterpret_cast< sal_Int64 >(this) : 0; 192 } 193 194 void ChildAccess::bind( 195 rtl::Reference< RootAccess > const & root, 196 rtl::Reference< Access > const & parent, rtl::OUString const & name) 197 throw () 198 { 199 OSL_ASSERT( 200 !parent_.is() && root.is() && parent.is() && name.getLength() != 0); 201 root_ = root; 202 parent_ = parent; 203 name_ = name; 204 } 205 206 void ChildAccess::unbind() throw () { 207 OSL_ASSERT(parent_.is()); 208 parent_->releaseChild(name_); 209 parent_.clear(); 210 inTransaction_ = true; 211 } 212 213 void ChildAccess::committed() { 214 inTransaction_ = false; 215 } 216 217 void ChildAccess::setNode(rtl::Reference< Node > const & node) { 218 node_ = node; 219 } 220 221 void ChildAccess::setProperty( 222 css::uno::Any const & value, Modifications * localModifications) 223 { 224 OSL_ASSERT(localModifications != 0); 225 Type type = TYPE_ERROR; 226 bool nillable = false; 227 switch (node_->kind()) { 228 case Node::KIND_PROPERTY: 229 { 230 PropertyNode * prop = dynamic_cast< PropertyNode * >(node_.get()); 231 type = prop->getStaticType(); 232 nillable = prop->isNillable(); 233 } 234 break; 235 case Node::KIND_LOCALIZED_PROPERTY: 236 { 237 rtl::OUString locale(getRootAccess()->getLocale()); 238 if (!Components::allLocales(locale)) { 239 rtl::Reference< ChildAccess > child(getChild(locale)); 240 if (child.is()) { 241 child->setProperty(value, localModifications); 242 } else { 243 insertLocalizedValueChild( 244 locale, value, localModifications); 245 } 246 return; 247 } 248 } 249 break; 250 case Node::KIND_LOCALIZED_VALUE: 251 { 252 LocalizedPropertyNode * locprop = 253 dynamic_cast< LocalizedPropertyNode * >(getParentNode().get()); 254 type = locprop->getStaticType(); 255 nillable = locprop->isNillable(); 256 } 257 break; 258 default: 259 break; 260 } 261 checkValue(value, type, nillable); 262 getParentAccess()->markChildAsModified(this); 263 changedValue_.reset(new css::uno::Any(value)); 264 localModifications->add(getRelativePath()); 265 } 266 267 css::uno::Any ChildAccess::asValue() { 268 if (changedValue_.get() != 0) { 269 return *changedValue_; 270 } 271 switch (node_->kind()) { 272 case Node::KIND_PROPERTY: 273 return dynamic_cast< PropertyNode * >(node_.get())->getValue( 274 getComponents()); 275 case Node::KIND_LOCALIZED_PROPERTY: 276 { 277 rtl::OUString locale(getRootAccess()->getLocale()); 278 if (!Components::allLocales(locale)) { 279 // Find best match using an adaption of RFC 4647 lookup matching 280 // rules, removing "-" or "_" delimited segments from the end; 281 // defaults are the "en-US" locale, the "en" locale, the empty 282 // string locale, the first child (if any), or a nil value (even 283 // though it may be illegal for the given property), in that 284 // order: 285 rtl::Reference< ChildAccess > child; 286 for (;;) { 287 child = getChild(locale); 288 if (child.is() || locale.getLength() == 0) { 289 break; 290 } 291 sal_Int32 i = locale.getLength() - 1; 292 while (i > 0 && locale[i] != '-' && locale[i] != '_') { 293 --i; 294 } 295 if (i == 0) { 296 break; 297 } 298 locale = locale.copy(0, i); 299 } 300 if (!child.is()) { 301 child = getChild( 302 rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("en-US"))); 303 if (!child.is()) { 304 child = getChild( 305 rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("en"))); 306 if (!child.is()) { 307 child = getChild(rtl::OUString()); 308 if (!child.is()) { 309 std::vector< rtl::Reference< ChildAccess > > 310 all(getAllChildren()); 311 if (!all.empty()) { 312 child = all.front(); 313 } 314 } 315 } 316 } 317 } 318 return child.is() ? child->asValue() : css::uno::Any(); 319 } 320 } 321 break; 322 case Node::KIND_LOCALIZED_VALUE: 323 return dynamic_cast< LocalizedValueNode * >(node_.get())->getValue(); 324 default: 325 break; 326 } 327 return css::uno::makeAny( 328 css::uno::Reference< css::uno::XInterface >( 329 static_cast< cppu::OWeakObject * >(this))); 330 } 331 332 void ChildAccess::commitChanges(bool valid, Modifications * globalModifications) 333 { 334 OSL_ASSERT(globalModifications != 0); 335 commitChildChanges(valid, globalModifications); 336 if (valid && changedValue_.get() != 0) { 337 Path path(getAbsolutePath()); 338 getComponents().addModification(path); 339 globalModifications->add(path); 340 switch (node_->kind()) { 341 case Node::KIND_PROPERTY: 342 dynamic_cast< PropertyNode * >(node_.get())->setValue( 343 Data::NO_LAYER, *changedValue_); 344 break; 345 case Node::KIND_LOCALIZED_VALUE: 346 dynamic_cast< LocalizedValueNode * >(node_.get())->setValue( 347 Data::NO_LAYER, *changedValue_); 348 break; 349 default: 350 OSL_ASSERT(false); // this cannot happen 351 break; 352 } 353 } 354 changedValue_.reset(); 355 } 356 357 ChildAccess::~ChildAccess() { 358 osl::MutexGuard g(lock); 359 if (parent_.is()) { 360 parent_->releaseChild(name_); 361 } 362 } 363 364 void ChildAccess::addTypes(std::vector< css::uno::Type > * types) const { 365 OSL_ASSERT(types != 0); 366 types->push_back(cppu::UnoType< css::container::XChild >::get()); 367 types->push_back(cppu::UnoType< css::lang::XUnoTunnel >::get()); 368 } 369 370 void ChildAccess::addSupportedServiceNames( 371 std::vector< rtl::OUString > * services) 372 { 373 OSL_ASSERT(services != 0); 374 services->push_back( 375 getParentNode()->kind() == Node::KIND_GROUP 376 ? rtl::OUString( 377 RTL_CONSTASCII_USTRINGPARAM( 378 "com.sun.star.configuration.GroupElement")) 379 : rtl::OUString( 380 RTL_CONSTASCII_USTRINGPARAM( 381 "com.sun.star.configuration.SetElement"))); 382 } 383 384 css::uno::Any ChildAccess::queryInterface(css::uno::Type const & aType) 385 throw (css::uno::RuntimeException) 386 { 387 OSL_ASSERT(thisIs(IS_ANY)); 388 osl::MutexGuard g(lock); 389 checkLocalizedPropertyAccess(); 390 css::uno::Any res(Access::queryInterface(aType)); 391 return res.hasValue() 392 ? res 393 : cppu::queryInterface( 394 aType, static_cast< css::container::XChild * >(this), 395 static_cast< css::lang::XUnoTunnel * >(this)); 396 } 397 398 } 399