1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28 #include "precompiled_configmgr.hxx" 29 #include "sal/config.h" 30 31 #include <vector> 32 33 #include "com/sun/star/lang/DisposedException.hpp" 34 #include "com/sun/star/lang/EventObject.hpp" 35 #include "com/sun/star/lang/WrappedTargetException.hpp" 36 #include "com/sun/star/uno/Any.hxx" 37 #include "com/sun/star/uno/Reference.hxx" 38 #include "com/sun/star/uno/RuntimeException.hpp" 39 #include "com/sun/star/uno/Type.hxx" 40 #include "com/sun/star/uno/XInterface.hpp" 41 #include "com/sun/star/util/ChangesEvent.hpp" 42 #include "com/sun/star/util/ChangesSet.hpp" 43 #include "com/sun/star/util/ElementChange.hpp" 44 #include "com/sun/star/util/XChangesBatch.hpp" 45 #include "com/sun/star/util/XChangesListener.hpp" 46 #include "com/sun/star/util/XChangesNotifier.hpp" 47 #include "comphelper/sequenceasvector.hxx" 48 #include "cppu/unotype.hxx" 49 #include "cppuhelper/queryinterface.hxx" 50 #include "cppuhelper/weak.hxx" 51 #include "osl/diagnose.h" 52 #include "osl/mutex.hxx" 53 #include "rtl/ref.hxx" 54 #include "rtl/ustring.h" 55 #include "rtl/ustring.hxx" 56 57 #include "broadcaster.hxx" 58 #include "childaccess.hxx" 59 #include "components.hxx" 60 #include "data.hxx" 61 #include "lock.hxx" 62 #include "modifications.hxx" 63 #include "node.hxx" 64 #include "path.hxx" 65 #include "rootaccess.hxx" 66 67 namespace configmgr { 68 69 namespace { 70 71 namespace css = com::sun::star; 72 73 } 74 75 RootAccess::RootAccess( 76 Components & components, rtl::OUString const & pathRepresentation, 77 rtl::OUString const & locale, bool update): 78 Access(components), pathRepresentation_(pathRepresentation), 79 locale_(locale), update_(update) 80 {} 81 82 Path RootAccess::getAbsolutePath() { 83 getNode(); 84 return path_; 85 } 86 87 void RootAccess::initBroadcaster( 88 Modifications::Node const & modifications, Broadcaster * broadcaster) 89 { 90 OSL_ASSERT(broadcaster != 0); 91 comphelper::SequenceAsVector< css::util::ElementChange > changes; 92 initBroadcasterAndChanges( 93 modifications, broadcaster, changesListeners_.empty() ? 0 : &changes); 94 if (!changes.empty()) { 95 css::util::ChangesSet set(changes.getAsConstList()); 96 for (ChangesListeners::iterator i(changesListeners_.begin()); 97 i != changesListeners_.end(); ++i) 98 { 99 cppu::OWeakObject* pSource = static_cast< cppu::OWeakObject * >(this); 100 css::uno::Reference< css::uno::XInterface > xBase( pSource, css::uno::UNO_QUERY ); 101 broadcaster->addChangesNotification( 102 *i, 103 css::util::ChangesEvent( 104 pSource, makeAny( xBase ), set)); 105 } 106 } 107 } 108 109 void RootAccess::acquire() throw () { 110 Access::acquire(); 111 } 112 113 void RootAccess::release() throw () { 114 Access::release(); 115 } 116 117 rtl::OUString RootAccess::getAbsolutePathRepresentation() { 118 getNode(); // turn pathRepresentation_ into canonic form 119 return pathRepresentation_; 120 } 121 122 rtl::OUString RootAccess::getLocale() const { 123 return locale_; 124 } 125 126 bool RootAccess::isUpdate() const { 127 return update_; 128 } 129 130 RootAccess::~RootAccess() { 131 osl::MutexGuard g(lock); 132 getComponents().removeRootAccess(this); 133 } 134 135 Path RootAccess::getRelativePath() { 136 return Path(); 137 } 138 139 rtl::OUString RootAccess::getRelativePathRepresentation() { 140 return rtl::OUString(); 141 } 142 143 rtl::Reference< Node > RootAccess::getNode() { 144 if (!node_.is()) { 145 rtl::OUString canonic; 146 int finalizedLayer; 147 node_ = getComponents().resolvePathRepresentation( 148 pathRepresentation_, &canonic, &path_, &finalizedLayer); 149 if (!node_.is()) { 150 throw css::uno::RuntimeException( 151 (rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("cannot find ")) + 152 pathRepresentation_), 153 0); 154 // RootAccess::queryInterface indirectly calls 155 // RootAccess::getNode, so if this RootAccess were passed out in 156 // RuntimeException.Context, client code that called 157 // queryInterface on it would cause trouble; therefore, 158 // RuntimeException.Context is left null here 159 } 160 pathRepresentation_ = canonic; 161 OSL_ASSERT(!path_.empty()); 162 name_ = path_.back(); 163 finalized_ = finalizedLayer != Data::NO_LAYER; 164 } 165 return node_; 166 } 167 168 bool RootAccess::isFinalized() { 169 getNode(); 170 return finalized_; 171 } 172 173 rtl::OUString RootAccess::getNameInternal() { 174 getNode(); 175 return name_; 176 } 177 178 rtl::Reference< RootAccess > RootAccess::getRootAccess() { 179 return this; 180 } 181 182 rtl::Reference< Access > RootAccess::getParentAccess() { 183 return rtl::Reference< Access >(); 184 } 185 186 void RootAccess::addTypes(std::vector< css::uno::Type > * types) const { 187 OSL_ASSERT(types != 0); 188 types->push_back(cppu::UnoType< css::util::XChangesNotifier >::get()); 189 types->push_back(cppu::UnoType< css::util::XChangesBatch >::get()); 190 } 191 192 void RootAccess::addSupportedServiceNames( 193 std::vector< rtl::OUString > * services) 194 { 195 OSL_ASSERT(services != 0); 196 services->push_back( 197 rtl::OUString( 198 RTL_CONSTASCII_USTRINGPARAM( 199 "com.sun.star.configuration.AccessRootElement"))); 200 if (update_) { 201 services->push_back( 202 rtl::OUString( 203 RTL_CONSTASCII_USTRINGPARAM( 204 "com.sun.star.configuration.UpdateRootElement"))); 205 } 206 } 207 208 void RootAccess::initDisposeBroadcaster(Broadcaster * broadcaster) { 209 OSL_ASSERT(broadcaster != 0); 210 for (ChangesListeners::iterator i(changesListeners_.begin()); 211 i != changesListeners_.end(); ++i) 212 { 213 broadcaster->addDisposeNotification( 214 i->get(), 215 css::lang::EventObject(static_cast< cppu::OWeakObject * >(this))); 216 } 217 Access::initDisposeBroadcaster(broadcaster); 218 } 219 220 void RootAccess::clearListeners() throw() { 221 changesListeners_.clear(); 222 Access::clearListeners(); 223 } 224 225 css::uno::Any RootAccess::queryInterface(css::uno::Type const & aType) 226 throw (css::uno::RuntimeException) 227 { 228 OSL_ASSERT(thisIs(IS_ANY)); 229 osl::MutexGuard g(lock); 230 checkLocalizedPropertyAccess(); 231 css::uno::Any res(Access::queryInterface(aType)); 232 if (res.hasValue()) { 233 return res; 234 } 235 res = cppu::queryInterface( 236 aType, static_cast< css::util::XChangesNotifier * >(this)); 237 if (res.hasValue()) { 238 return res; 239 } 240 if (!res.hasValue() && update_) { 241 res = cppu::queryInterface( 242 aType, static_cast< css::util::XChangesBatch * >(this)); 243 } 244 return res; 245 } 246 247 void RootAccess::addChangesListener( 248 css::uno::Reference< css::util::XChangesListener > const & aListener) 249 throw (css::uno::RuntimeException) 250 { 251 OSL_ASSERT(thisIs(IS_ANY)); 252 { 253 osl::MutexGuard g(lock); 254 checkLocalizedPropertyAccess(); 255 if (!aListener.is()) { 256 throw css::uno::RuntimeException( 257 rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("null listener")), 258 static_cast< cppu::OWeakObject * >(this)); 259 } 260 if (!isDisposed()) { 261 changesListeners_.insert(aListener); 262 return; 263 } 264 } 265 try { 266 aListener->disposing( 267 css::lang::EventObject(static_cast< cppu::OWeakObject * >(this))); 268 } catch (css::lang::DisposedException &) {} 269 } 270 271 void RootAccess::removeChangesListener( 272 css::uno::Reference< css::util::XChangesListener > const & aListener) 273 throw (css::uno::RuntimeException) 274 { 275 OSL_ASSERT(thisIs(IS_ANY)); 276 osl::MutexGuard g(lock); 277 checkLocalizedPropertyAccess(); 278 ChangesListeners::iterator i(changesListeners_.find(aListener)); 279 if (i != changesListeners_.end()) { 280 changesListeners_.erase(i); 281 } 282 } 283 284 void RootAccess::commitChanges() 285 throw (css::lang::WrappedTargetException, css::uno::RuntimeException) 286 { 287 OSL_ASSERT(thisIs(IS_UPDATE)); 288 Broadcaster bc; 289 { 290 osl::MutexGuard g(lock); 291 checkLocalizedPropertyAccess(); 292 int finalizedLayer; 293 Modifications globalMods; 294 commitChildChanges( 295 ((getComponents().resolvePathRepresentation( 296 pathRepresentation_, 0, 0, &finalizedLayer) 297 == node_) && 298 finalizedLayer == Data::NO_LAYER), 299 &globalMods); 300 getComponents().writeModifications(); 301 getComponents().initGlobalBroadcaster(globalMods, this, &bc); 302 } 303 bc.send(); 304 } 305 306 sal_Bool RootAccess::hasPendingChanges() throw (css::uno::RuntimeException) { 307 OSL_ASSERT(thisIs(IS_UPDATE)); 308 osl::MutexGuard g(lock); 309 checkLocalizedPropertyAccess(); 310 //TODO: Optimize: 311 std::vector< css::util::ElementChange > changes; 312 reportChildChanges(&changes); 313 return !changes.empty(); 314 } 315 316 css::util::ChangesSet RootAccess::getPendingChanges() 317 throw (css::uno::RuntimeException) 318 { 319 OSL_ASSERT(thisIs(IS_UPDATE)); 320 osl::MutexGuard g(lock); 321 checkLocalizedPropertyAccess(); 322 comphelper::SequenceAsVector< css::util::ElementChange > changes; 323 reportChildChanges(&changes); 324 return changes.getAsConstList(); 325 } 326 327 } 328