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 <properties.h> 21 #include <stdtypes.h> 22 #include <helper/mischelper.hxx> 23 24 #include <com/sun/star/beans/Property.hpp> 25 #include <com/sun/star/beans/XProperty.hpp> 26 #include <com/sun/star/beans/PropertyAttribute.hpp> 27 #include <com/sun/star/beans/XPropertySet.hpp> 28 #include <com/sun/star/util/XChangesNotifier.hpp> 29 #include <com/sun/star/util/PathSubstitution.hpp> 30 #include <com/sun/star/container/XNameAccess.hpp> 31 #include <com/sun/star/lang/XServiceInfo.hpp> 32 #include <com/sun/star/util/XStringSubstitution.hpp> 33 #include <com/sun/star/util/XChangesListener.hpp> 34 #include <com/sun/star/util/XPathSettings.hpp> 35 36 #include <tools/urlobj.hxx> 37 #include <rtl/ustrbuf.hxx> 38 #include <sal/log.hxx> 39 40 #include <cppuhelper/basemutex.hxx> 41 #include <cppuhelper/propshlp.hxx> 42 #include <cppuhelper/compbase.hxx> 43 #include <cppuhelper/supportsservice.hxx> 44 #include <comphelper/sequence.hxx> 45 #include <comphelper/configurationhelper.hxx> 46 #include <unotools/configitem.hxx> 47 #include <unotools/configpaths.hxx> 48 49 using namespace framework; 50 51 #define CFGPROP_USERPATHS "UserPaths" 52 #define CFGPROP_WRITEPATH "WritePath" 53 54 /* 55 0 : old style "Template" string using ";" as separator 56 1 : internal paths "Template_internal" string list 57 2 : user paths "Template_user" string list 58 3 : write path "Template_write" string 59 */ 60 61 #define POSTFIX_INTERNAL_PATHS "_internal" 62 #define POSTFIX_USER_PATHS "_user" 63 #define POSTFIX_WRITE_PATH "_writable" 64 65 namespace { 66 67 const sal_Int32 IDGROUP_OLDSTYLE = 0; 68 const sal_Int32 IDGROUP_INTERNAL_PATHS = 1; 69 const sal_Int32 IDGROUP_USER_PATHS = 2; 70 const sal_Int32 IDGROUP_WRITE_PATH = 3; 71 72 const sal_Int32 IDGROUP_COUNT = 4; 73 74 sal_Int32 impl_getPropGroup(sal_Int32 nID) 75 { 76 return (nID % IDGROUP_COUNT); 77 } 78 79 /* enable it if you wish to migrate old user settings (using the old cfg schema) on demand .... 80 disable it in case only the new schema must be used. 81 */ 82 83 typedef ::cppu::WeakComponentImplHelper< 84 css::lang::XServiceInfo, 85 css::util::XChangesListener, // => XEventListener 86 css::util::XPathSettings> // => XPropertySet 87 PathSettings_BASE; 88 89 class PathSettings : private cppu::BaseMutex 90 , public PathSettings_BASE 91 , public ::cppu::OPropertySetHelper 92 { 93 struct PathInfo 94 { 95 public: 96 97 PathInfo() 98 : sPathName () 99 , lInternalPaths() 100 , lUserPaths () 101 , sWritePath () 102 , bIsSinglePath (false) 103 , bIsReadonly (false) 104 {} 105 106 void takeOver(const PathInfo& rCopy) 107 { 108 sPathName = rCopy.sPathName; 109 lInternalPaths = rCopy.lInternalPaths; 110 lUserPaths = rCopy.lUserPaths; 111 sWritePath = rCopy.sWritePath; 112 bIsSinglePath = rCopy.bIsSinglePath; 113 bIsReadonly = rCopy.bIsReadonly; 114 } 115 116 /// an internal name describing this path 117 OUString sPathName; 118 119 /// contains all paths, which are used internally - but are not visible for the user. 120 std::vector<OUString> lInternalPaths; 121 122 /// contains all paths configured by the user 123 std::vector<OUString> lUserPaths; 124 125 /// this special path is used to generate feature depending content there 126 OUString sWritePath; 127 128 /// indicates real single paths, which uses WritePath property only 129 bool bIsSinglePath; 130 131 /// simple handling of finalized/mandatory states ... => we know one state READONLY only .-) 132 bool bIsReadonly; 133 }; 134 135 typedef std::unordered_map<OUString, PathSettings::PathInfo> PathHash; 136 137 enum EChangeOp 138 { 139 E_UNDEFINED, 140 E_ADDED, 141 E_CHANGED, 142 E_REMOVED 143 }; 144 145 private: 146 147 /** reference to factory, which has create this instance. */ 148 css::uno::Reference< css::uno::XComponentContext > m_xContext; 149 150 /** list of all path variables and her corresponding values. */ 151 PathSettings::PathHash m_lPaths; 152 153 /** describes all properties available on our interface. 154 Will be generated on demand based on our path list m_lPaths. */ 155 css::uno::Sequence< css::beans::Property > m_lPropDesc; 156 157 /** helper needed to (re-)substitute all internal save path values. */ 158 css::uno::Reference< css::util::XStringSubstitution > m_xSubstitution; 159 160 /** provides access to the old configuration schema (which will be migrated on demand). */ 161 css::uno::Reference< css::container::XNameAccess > m_xCfgOld; 162 163 /** provides access to the new configuration schema. */ 164 css::uno::Reference< css::container::XNameAccess > m_xCfgNew; 165 166 /** helper to listen for configuration changes without ownership cycle problems */ 167 css::uno::Reference< css::util::XChangesListener > m_xCfgNewListener; 168 169 std::unique_ptr<::cppu::OPropertyArrayHelper> m_pPropHelp; 170 171 public: 172 173 /** initialize a new instance of this class. 174 Attention: It's necessary for right function of this class, that the order of base 175 classes is the right one. Because we transfer information from one base to another 176 during this ctor runs! */ 177 explicit PathSettings(const css::uno::Reference< css::uno::XComponentContext >& xContext); 178 179 /** free all used resources ... if it was not already done. */ 180 virtual ~PathSettings() override; 181 182 virtual OUString SAL_CALL getImplementationName() override 183 { 184 return OUString("com.sun.star.comp.framework.PathSettings"); 185 } 186 187 virtual sal_Bool SAL_CALL supportsService(OUString const & ServiceName) override 188 { 189 return cppu::supportsService(this, ServiceName); 190 } 191 192 virtual css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override 193 { 194 css::uno::Sequence< OUString > aSeq { "com.sun.star.util.PathSettings" }; 195 return aSeq; 196 } 197 198 // XInterface 199 virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type& type) override; 200 virtual void SAL_CALL acquire() throw () override 201 { OWeakObject::acquire(); } 202 virtual void SAL_CALL release() throw () override 203 { OWeakObject::release(); } 204 205 // XTypeProvider 206 virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override; 207 208 // css::util::XChangesListener 209 virtual void SAL_CALL changesOccurred(const css::util::ChangesEvent& aEvent) override; 210 211 // css::lang::XEventListener 212 virtual void SAL_CALL disposing(const css::lang::EventObject& aSource) override; 213 214 /** 215 * XPathSettings attribute methods 216 */ 217 virtual OUString SAL_CALL getAddin() override 218 { return getStringProperty("Addin"); } 219 virtual void SAL_CALL setAddin(const OUString& p1) override 220 { setStringProperty("Addin", p1); } 221 virtual OUString SAL_CALL getAutoCorrect() override 222 { return getStringProperty("AutoCorrect"); } 223 virtual void SAL_CALL setAutoCorrect(const OUString& p1) override 224 { setStringProperty("AutoCorrect", p1); } 225 virtual OUString SAL_CALL getAutoText() override 226 { return getStringProperty("AutoText"); } 227 virtual void SAL_CALL setAutoText(const OUString& p1) override 228 { setStringProperty("AutoText", p1); } 229 virtual OUString SAL_CALL getBackup() override 230 { return getStringProperty("Backup"); } 231 virtual void SAL_CALL setBackup(const OUString& p1) override 232 { setStringProperty("Backup", p1); } 233 virtual OUString SAL_CALL getBasic() override 234 { return getStringProperty("Basic"); } 235 virtual void SAL_CALL setBasic(const OUString& p1) override 236 { setStringProperty("Basic", p1); } 237 virtual OUString SAL_CALL getBitmap() override 238 { return getStringProperty("Bitmap"); } 239 virtual void SAL_CALL setBitmap(const OUString& p1) override 240 { setStringProperty("Bitmap", p1); } 241 virtual OUString SAL_CALL getConfig() override 242 { return getStringProperty("Config"); } 243 virtual void SAL_CALL setConfig(const OUString& p1) override 244 { setStringProperty("Config", p1); } 245 virtual OUString SAL_CALL getDictionary() override 246 { return getStringProperty("Dictionary"); } 247 virtual void SAL_CALL setDictionary(const OUString& p1) override 248 { setStringProperty("Dictionary", p1); } 249 virtual OUString SAL_CALL getFavorite() override 250 { return getStringProperty("Favorite"); } 251 virtual void SAL_CALL setFavorite(const OUString& p1) override 252 { setStringProperty("Favorite", p1); } 253 virtual OUString SAL_CALL getFilter() override 254 { return getStringProperty("Filter"); } 255 virtual void SAL_CALL setFilter(const OUString& p1) override 256 { setStringProperty("Filter", p1); } 257 virtual OUString SAL_CALL getGallery() override 258 { return getStringProperty("Gallery"); } 259 virtual void SAL_CALL setGallery(const OUString& p1) override 260 { setStringProperty("Gallery", p1); } 261 virtual OUString SAL_CALL getGraphic() override 262 { return getStringProperty("Graphic"); } 263 virtual void SAL_CALL setGraphic(const OUString& p1) override 264 { setStringProperty("Graphic", p1); } 265 virtual OUString SAL_CALL getHelp() override 266 { return getStringProperty("Help"); } 267 virtual void SAL_CALL setHelp(const OUString& p1) override 268 { setStringProperty("Help", p1); } 269 virtual OUString SAL_CALL getLinguistic() override 270 { return getStringProperty("Linguistic"); } 271 virtual void SAL_CALL setLinguistic(const OUString& p1) override 272 { setStringProperty("Linguistic", p1); } 273 virtual OUString SAL_CALL getModule() override 274 { return getStringProperty("Module"); } 275 virtual void SAL_CALL setModule(const OUString& p1) override 276 { setStringProperty("Module", p1); } 277 virtual OUString SAL_CALL getPalette() override 278 { return getStringProperty("Palette"); } 279 virtual void SAL_CALL setPalette(const OUString& p1) override 280 { setStringProperty("Palette", p1); } 281 virtual OUString SAL_CALL getPlugin() override 282 { return getStringProperty("Plugin"); } 283 virtual void SAL_CALL setPlugin(const OUString& p1) override 284 { setStringProperty("Plugin", p1); } 285 virtual OUString SAL_CALL getStorage() override 286 { return getStringProperty("Storage"); } 287 virtual void SAL_CALL setStorage(const OUString& p1) override 288 { setStringProperty("Storage", p1); } 289 virtual OUString SAL_CALL getTemp() override 290 { return getStringProperty("Temp"); } 291 virtual void SAL_CALL setTemp(const OUString& p1) override 292 { setStringProperty("Temp", p1); } 293 virtual OUString SAL_CALL getTemplate() override 294 { return getStringProperty("Template"); } 295 virtual void SAL_CALL setTemplate(const OUString& p1) override 296 { setStringProperty("Template", p1); } 297 virtual OUString SAL_CALL getUIConfig() override 298 { return getStringProperty("UIConfig"); } 299 virtual void SAL_CALL setUIConfig(const OUString& p1) override 300 { setStringProperty("UIConfig", p1); } 301 virtual OUString SAL_CALL getUserConfig() override 302 { return getStringProperty("UserConfig"); } 303 virtual void SAL_CALL setUserConfig(const OUString& p1) override 304 { setStringProperty("UserConfig", p1); } 305 virtual OUString SAL_CALL getUserDictionary() override 306 { return getStringProperty("UserDictionary"); } 307 virtual void SAL_CALL setUserDictionary(const OUString& p1) override 308 { setStringProperty("UserDictionary", p1); } 309 virtual OUString SAL_CALL getWork() override 310 { return getStringProperty("Work"); } 311 virtual void SAL_CALL setWork(const OUString& p1) override 312 { setStringProperty("Work", p1); } 313 virtual OUString SAL_CALL getBasePathShareLayer() override 314 { return getStringProperty("UIConfig"); } 315 virtual void SAL_CALL setBasePathShareLayer(const OUString& p1) override 316 { setStringProperty("UIConfig", p1); } 317 virtual OUString SAL_CALL getBasePathUserLayer() override 318 { return getStringProperty("UserConfig"); } 319 virtual void SAL_CALL setBasePathUserLayer(const OUString& p1) override 320 { setStringProperty("UserConfig", p1); } 321 322 /** 323 * overrides to resolve inheritance ambiguity 324 */ 325 virtual void SAL_CALL setPropertyValue(const OUString& p1, const css::uno::Any& p2) override 326 { ::cppu::OPropertySetHelper::setPropertyValue(p1, p2); } 327 virtual css::uno::Any SAL_CALL getPropertyValue(const OUString& p1) override 328 { return ::cppu::OPropertySetHelper::getPropertyValue(p1); } 329 virtual void SAL_CALL addPropertyChangeListener(const OUString& p1, const css::uno::Reference<css::beans::XPropertyChangeListener>& p2) override 330 { ::cppu::OPropertySetHelper::addPropertyChangeListener(p1, p2); } 331 virtual void SAL_CALL removePropertyChangeListener(const OUString& p1, const css::uno::Reference<css::beans::XPropertyChangeListener>& p2) override 332 { ::cppu::OPropertySetHelper::removePropertyChangeListener(p1, p2); } 333 virtual void SAL_CALL addVetoableChangeListener(const OUString& p1, const css::uno::Reference<css::beans::XVetoableChangeListener>& p2) override 334 { ::cppu::OPropertySetHelper::addVetoableChangeListener(p1, p2); } 335 virtual void SAL_CALL removeVetoableChangeListener(const OUString& p1, const css::uno::Reference<css::beans::XVetoableChangeListener>& p2) override 336 { ::cppu::OPropertySetHelper::removeVetoableChangeListener(p1, p2); } 337 /** read all configured paths and create all needed internal structures. */ 338 void impl_readAll(); 339 340 private: 341 virtual void SAL_CALL disposing() final override; 342 343 /// @throws css::uno::RuntimeException 344 OUString getStringProperty(const OUString& p1); 345 346 /// @throws css::uno::RuntimeException 347 void setStringProperty(const OUString& p1, const OUString& p2); 348 349 /** read a path info using the old cfg schema. 350 This is needed for "migration on demand" reasons only. 351 Can be removed for next major release .-) */ 352 std::vector<OUString> impl_readOldFormat(const OUString& sPath); 353 354 /** read a path info using the new cfg schema. */ 355 PathSettings::PathInfo impl_readNewFormat(const OUString& sPath); 356 357 /** filter "real user defined paths" from the old configuration schema 358 and set it as UserPaths on the new schema. 359 Can be removed with new major release ... */ 360 361 void impl_mergeOldUserPaths( PathSettings::PathInfo& rPath, 362 const std::vector<OUString>& lOld ); 363 364 /** reload one path directly from the new configuration schema (because 365 it was updated by any external code) */ 366 PathSettings::EChangeOp impl_updatePath(const OUString& sPath , 367 bool bNotifyListener); 368 369 /** replace all might existing placeholder variables inside the given path ... 370 or check if the given path value uses paths, which can be replaced with predefined 371 placeholder variables ... 372 */ 373 void impl_subst(std::vector<OUString>& lVals , 374 const css::uno::Reference< css::util::XStringSubstitution >& xSubst , 375 bool bReSubst); 376 377 void impl_subst(PathSettings::PathInfo& aPath , 378 bool bReSubst); 379 380 /** converts our new string list schema to the old ";" separated schema ... */ 381 OUString impl_convertPath2OldStyle(const PathSettings::PathInfo& rPath ) const; 382 std::vector<OUString> impl_convertOldStyle2Path(const OUString& sOldStylePath) const; 383 384 /** remove still known paths from the given lList argument. 385 So real user defined paths can be extracted from the list of 386 fix internal paths ! 387 */ 388 void impl_purgeKnownPaths(PathSettings::PathInfo& rPath, 389 std::vector<OUString>& lList); 390 391 /** rebuild the member m_lPropDesc using the path list m_lPaths. */ 392 void impl_rebuildPropertyDescriptor(); 393 394 /** provides direct access to the list of path values 395 using its internal property id. 396 */ 397 css::uno::Any impl_getPathValue( sal_Int32 nID ) const; 398 void impl_setPathValue( sal_Int32 nID , 399 const css::uno::Any& aVal); 400 401 /** check the given handle and return the corresponding PathInfo reference. 402 These reference can be used then directly to manipulate these path. */ 403 PathSettings::PathInfo* impl_getPathAccess (sal_Int32 nHandle); 404 const PathSettings::PathInfo* impl_getPathAccessConst(sal_Int32 nHandle) const; 405 406 /** it checks, if the given path value seems to be a valid URL or system path. */ 407 bool impl_isValidPath(const OUString& sPath) const; 408 bool impl_isValidPath(const std::vector<OUString>& lPath) const; 409 410 void impl_storePath(const PathSettings::PathInfo& aPath); 411 412 css::uno::Sequence< sal_Int32 > impl_mapPathName2IDList(const OUString& sPath); 413 414 void impl_notifyPropListener( const OUString& sPath , 415 const PathSettings::PathInfo* pPathOld, 416 const PathSettings::PathInfo* pPathNew); 417 418 // OPropertySetHelper 419 virtual sal_Bool SAL_CALL convertFastPropertyValue( css::uno::Any& aConvertedValue, 420 css::uno::Any& aOldValue, 421 sal_Int32 nHandle, 422 const css::uno::Any& aValue ) override; 423 virtual void SAL_CALL setFastPropertyValue_NoBroadcast( sal_Int32 nHandle, 424 const css::uno::Any& aValue ) override; 425 virtual void SAL_CALL getFastPropertyValue( css::uno::Any& aValue, 426 sal_Int32 nHandle ) const override; 427 // Avoid: 428 // warning: ‘virtual css::uno::Any cppu::OPropertySetHelper::getFastPropertyValue(sal_Int32)’ was hidden [-Woverloaded-virtual] 429 // warning: by ‘virtual void {anonymous}::PathSettings::getFastPropertyValue(css::uno::Any&, sal_Int32) const’ [-Woverloaded-virtual] 430 using cppu::OPropertySetHelper::getFastPropertyValue; 431 virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() override; 432 virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo() override; 433 434 /** factory methods to guarantee right (but on demand) initialized members ... */ 435 css::uno::Reference< css::util::XStringSubstitution > fa_getSubstitution(); 436 css::uno::Reference< css::container::XNameAccess > fa_getCfgOld(); 437 css::uno::Reference< css::container::XNameAccess > fa_getCfgNew(); 438 }; 439 440 PathSettings::PathSettings( const css::uno::Reference< css::uno::XComponentContext >& xContext ) 441 : PathSettings_BASE(m_aMutex) 442 , ::cppu::OPropertySetHelper(cppu::WeakComponentImplHelperBase::rBHelper) 443 , m_xContext (xContext) 444 { 445 } 446 447 PathSettings::~PathSettings() 448 { 449 disposing(); 450 } 451 452 void SAL_CALL PathSettings::disposing() 453 { 454 osl::MutexGuard g(cppu::WeakComponentImplHelperBase::rBHelper.rMutex); 455 456 css::uno::Reference< css::util::XChangesNotifier > 457 xBroadcaster(m_xCfgNew, css::uno::UNO_QUERY); 458 if (xBroadcaster.is()) 459 xBroadcaster->removeChangesListener(m_xCfgNewListener); 460 461 m_xSubstitution.clear(); 462 m_xCfgOld.clear(); 463 m_xCfgNew.clear(); 464 m_xCfgNewListener.clear(); 465 466 m_pPropHelp.reset(); 467 } 468 469 css::uno::Any SAL_CALL PathSettings::queryInterface( const css::uno::Type& _rType ) 470 { 471 css::uno::Any aRet = PathSettings_BASE::queryInterface( _rType ); 472 if ( !aRet.hasValue() ) 473 aRet = ::cppu::OPropertySetHelper::queryInterface( _rType ); 474 return aRet; 475 } 476 477 css::uno::Sequence< css::uno::Type > SAL_CALL PathSettings::getTypes( ) 478 { 479 return comphelper::concatSequences( 480 PathSettings_BASE::getTypes(), 481 ::cppu::OPropertySetHelper::getTypes() 482 ); 483 } 484 485 void SAL_CALL PathSettings::changesOccurred(const css::util::ChangesEvent& aEvent) 486 { 487 sal_Int32 c = aEvent.Changes.getLength(); 488 sal_Int32 i = 0; 489 bool bUpdateDescriptor = false; 490 491 for (i=0; i<c; ++i) 492 { 493 const css::util::ElementChange& aChange = aEvent.Changes[i]; 494 495 OUString sChanged; 496 aChange.Accessor >>= sChanged; 497 498 OUString sPath = ::utl::extractFirstFromConfigurationPath(sChanged); 499 if (!sPath.isEmpty()) 500 { 501 PathSettings::EChangeOp eOp = impl_updatePath(sPath, true); 502 if ( 503 (eOp == PathSettings::E_ADDED ) || 504 (eOp == PathSettings::E_REMOVED) 505 ) 506 bUpdateDescriptor = true; 507 } 508 } 509 510 if (bUpdateDescriptor) 511 impl_rebuildPropertyDescriptor(); 512 } 513 514 void SAL_CALL PathSettings::disposing(const css::lang::EventObject& aSource) 515 { 516 osl::MutexGuard g(cppu::WeakComponentImplHelperBase::rBHelper.rMutex); 517 518 if (aSource.Source == m_xCfgNew) 519 m_xCfgNew.clear(); 520 } 521 522 OUString PathSettings::getStringProperty(const OUString& p1) 523 { 524 css::uno::Any a = ::cppu::OPropertySetHelper::getPropertyValue(p1); 525 OUString s; 526 a >>= s; 527 return s; 528 } 529 530 void PathSettings::setStringProperty(const OUString& p1, const OUString& p2) 531 { 532 ::cppu::OPropertySetHelper::setPropertyValue(p1, css::uno::Any(p2)); 533 } 534 535 void PathSettings::impl_readAll() 536 { 537 try 538 { 539 // TODO think about me 540 css::uno::Reference< css::container::XNameAccess > xCfg = fa_getCfgNew(); 541 css::uno::Sequence< OUString > lPaths = xCfg->getElementNames(); 542 543 sal_Int32 c = lPaths.getLength(); 544 for (sal_Int32 i = 0; i < c; ++i) 545 { 546 const OUString& sPath = lPaths[i]; 547 impl_updatePath(sPath, false); 548 } 549 } 550 catch(const css::uno::RuntimeException& ) 551 { 552 } 553 554 impl_rebuildPropertyDescriptor(); 555 } 556 557 // NO substitution here ! It's done outside ... 558 std::vector<OUString> PathSettings::impl_readOldFormat(const OUString& sPath) 559 { 560 css::uno::Reference< css::container::XNameAccess > xCfg( fa_getCfgOld() ); 561 std::vector<OUString> aPathVal; 562 563 if( xCfg->hasByName(sPath) ) 564 { 565 css::uno::Any aVal( xCfg->getByName(sPath) ); 566 567 OUString sStringVal; 568 css::uno::Sequence< OUString > lStringListVal; 569 570 if (aVal >>= sStringVal) 571 { 572 aPathVal.push_back(sStringVal); 573 } 574 else if (aVal >>= lStringListVal) 575 { 576 aPathVal = comphelper::sequenceToContainer<std::vector<OUString>>(lStringListVal); 577 } 578 } 579 580 return aPathVal; 581 } 582 583 // NO substitution here ! It's done outside ... 584 PathSettings::PathInfo PathSettings::impl_readNewFormat(const OUString& sPath) 585 { 586 const OUString CFGPROP_INTERNALPATHS("InternalPaths"); 587 const OUString CFGPROP_ISSINGLEPATH("IsSinglePath"); 588 589 css::uno::Reference< css::container::XNameAccess > xCfg = fa_getCfgNew(); 590 591 // get access to the "queried" path 592 css::uno::Reference< css::container::XNameAccess > xPath; 593 xCfg->getByName(sPath) >>= xPath; 594 595 PathSettings::PathInfo aPathVal; 596 597 // read internal path list 598 css::uno::Reference< css::container::XNameAccess > xIPath; 599 xPath->getByName(CFGPROP_INTERNALPATHS) >>= xIPath; 600 aPathVal.lInternalPaths = comphelper::sequenceToContainer<std::vector<OUString>>(xIPath->getElementNames()); 601 602 // read user defined path list 603 css::uno::Sequence<OUString> vTmpUserPathsSeq; 604 xPath->getByName(CFGPROP_USERPATHS) >>= vTmpUserPathsSeq; 605 aPathVal.lUserPaths = comphelper::sequenceToContainer<std::vector<OUString>>(vTmpUserPathsSeq); 606 607 // read the writeable path 608 xPath->getByName(CFGPROP_WRITEPATH) >>= aPathVal.sWritePath; 609 610 // avoid duplicates, by removing the writeable path from 611 // the user defined path list if it happens to be there too 612 std::vector<OUString>::iterator aI = std::find(aPathVal.lUserPaths.begin(), aPathVal.lUserPaths.end(), aPathVal.sWritePath); 613 if (aI != aPathVal.lUserPaths.end()) 614 aPathVal.lUserPaths.erase(aI); 615 616 // read state props 617 xPath->getByName(CFGPROP_ISSINGLEPATH) >>= aPathVal.bIsSinglePath; 618 619 // analyze finalized/mandatory states 620 aPathVal.bIsReadonly = false; 621 css::uno::Reference< css::beans::XProperty > xInfo(xPath, css::uno::UNO_QUERY); 622 if (xInfo.is()) 623 { 624 css::beans::Property aInfo = xInfo->getAsProperty(); 625 bool bFinalized = ((aInfo.Attributes & css::beans::PropertyAttribute::READONLY ) == css::beans::PropertyAttribute::READONLY ); 626 627 // Note: 'till we support finalized/mandatory on our API more in detail we handle 628 // all states simple as READONLY! But because all really needed paths are "mandatory" by default 629 // we have to handle "finalized" as the real "readonly" indicator. 630 aPathVal.bIsReadonly = bFinalized; 631 } 632 633 return aPathVal; 634 } 635 636 void PathSettings::impl_storePath(const PathSettings::PathInfo& aPath) 637 { 638 css::uno::Reference< css::container::XNameAccess > xCfgNew = fa_getCfgNew(); 639 css::uno::Reference< css::container::XNameAccess > xCfgOld = fa_getCfgOld(); 640 641 // try to replace path-parts with well known and supported variables. 642 // So an office can be moved easily to another location without losing 643 // its related paths. 644 PathInfo aResubstPath(aPath); 645 impl_subst(aResubstPath, true); 646 647 // update new configuration 648 if (! aResubstPath.bIsSinglePath) 649 { 650 ::comphelper::ConfigurationHelper::writeRelativeKey(xCfgNew, 651 aResubstPath.sPathName, 652 CFGPROP_USERPATHS, 653 css::uno::makeAny(comphelper::containerToSequence(aResubstPath.lUserPaths))); 654 } 655 656 ::comphelper::ConfigurationHelper::writeRelativeKey(xCfgNew, 657 aResubstPath.sPathName, 658 CFGPROP_WRITEPATH, 659 css::uno::makeAny(aResubstPath.sWritePath)); 660 661 ::comphelper::ConfigurationHelper::flush(xCfgNew); 662 663 // remove the whole path from the old configuration! 664 // Otherwise we can't make sure that the diff between new and old configuration 665 // on loading time really represents a user setting!!! 666 667 // Check if the given path exists inside the old configuration. 668 // Because our new configuration knows more than the list of old paths ... ! 669 if (xCfgOld->hasByName(aResubstPath.sPathName)) 670 { 671 css::uno::Reference< css::beans::XPropertySet > xProps(xCfgOld, css::uno::UNO_QUERY_THROW); 672 xProps->setPropertyValue(aResubstPath.sPathName, css::uno::Any()); 673 ::comphelper::ConfigurationHelper::flush(xCfgOld); 674 } 675 } 676 677 void PathSettings::impl_mergeOldUserPaths( PathSettings::PathInfo& rPath, 678 const std::vector<OUString>& lOld ) 679 { 680 for (auto const& old : lOld) 681 { 682 if (rPath.bIsSinglePath) 683 { 684 SAL_WARN_IF(lOld.size()>1, "fwk", "PathSettings::impl_mergeOldUserPaths(): Single path has more than one path value inside old configuration (Common.xcu)!"); 685 if ( rPath.sWritePath != old ) 686 rPath.sWritePath = old; 687 } 688 else 689 { 690 if ( 691 ( std::find(rPath.lInternalPaths.begin(), rPath.lInternalPaths.end(), old) == rPath.lInternalPaths.end()) && 692 ( std::find(rPath.lUserPaths.begin(), rPath.lUserPaths.end(), old) == rPath.lUserPaths.end() ) && 693 ( rPath.sWritePath != old ) 694 ) 695 rPath.lUserPaths.push_back(old); 696 } 697 } 698 } 699 700 PathSettings::EChangeOp PathSettings::impl_updatePath(const OUString& sPath , 701 bool bNotifyListener) 702 { 703 // SAFE -> 704 osl::MutexGuard g(cppu::WeakComponentImplHelperBase::rBHelper.rMutex); 705 706 PathSettings::PathInfo* pPathOld = nullptr; 707 PathSettings::PathInfo* pPathNew = nullptr; 708 PathSettings::EChangeOp eOp = PathSettings::E_UNDEFINED; 709 PathSettings::PathInfo aPath; 710 711 try 712 { 713 aPath = impl_readNewFormat(sPath); 714 aPath.sPathName = sPath; 715 // replace all might existing variables with real values 716 // Do it before these old paths will be compared against the 717 // new path configuration. Otherwise some strings uses different variables ... but substitution 718 // will produce strings with same content (because some variables are redundant!) 719 impl_subst(aPath, false); 720 } 721 catch(const css::uno::RuntimeException&) 722 { throw; } 723 catch(const css::container::NoSuchElementException&) 724 { eOp = PathSettings::E_REMOVED; } 725 catch(const css::uno::Exception&) 726 { throw; } 727 728 try 729 { 730 // migration of old user defined values on demand 731 // can be disabled for a new major 732 std::vector<OUString> lOldVals = impl_readOldFormat(sPath); 733 // replace all might existing variables with real values 734 // Do it before these old paths will be compared against the 735 // new path configuration. Otherwise some strings uses different variables ... but substitution 736 // will produce strings with same content (because some variables are redundant!) 737 impl_subst(lOldVals, fa_getSubstitution(), false); 738 impl_mergeOldUserPaths(aPath, lOldVals); 739 } 740 catch(const css::uno::RuntimeException&) 741 { throw; } 742 // Normal(!) exceptions can be ignored! 743 // E.g. in case an addon installs a new path, which was not well known for an OOo 1.x installation 744 // we can't find a value for it inside the "old" configuration. So a NoSuchElementException 745 // will be normal .-) 746 catch(const css::uno::Exception&) 747 {} 748 749 PathSettings::PathHash::iterator pPath = m_lPaths.find(sPath); 750 if (eOp == PathSettings::E_UNDEFINED) 751 { 752 if (pPath != m_lPaths.end()) 753 eOp = PathSettings::E_CHANGED; 754 else 755 eOp = PathSettings::E_ADDED; 756 } 757 758 switch(eOp) 759 { 760 case PathSettings::E_ADDED : 761 { 762 if (bNotifyListener) 763 { 764 pPathOld = nullptr; 765 pPathNew = &aPath; 766 impl_notifyPropListener(sPath, pPathOld, pPathNew); 767 } 768 m_lPaths[sPath] = aPath; 769 } 770 break; 771 772 case PathSettings::E_CHANGED : 773 { 774 if (bNotifyListener) 775 { 776 pPathOld = &(pPath->second); 777 pPathNew = &aPath; 778 impl_notifyPropListener(sPath, pPathOld, pPathNew); 779 } 780 m_lPaths[sPath] = aPath; 781 } 782 break; 783 784 case PathSettings::E_REMOVED : 785 { 786 if (pPath != m_lPaths.end()) 787 { 788 if (bNotifyListener) 789 { 790 pPathOld = &(pPath->second); 791 pPathNew = nullptr; 792 impl_notifyPropListener(sPath, pPathOld, pPathNew); 793 } 794 m_lPaths.erase(pPath); 795 } 796 } 797 break; 798 799 default: // to let compiler be happy 800 break; 801 } 802 803 return eOp; 804 } 805 806 css::uno::Sequence< sal_Int32 > PathSettings::impl_mapPathName2IDList(const OUString& sPath) 807 { 808 OUString sInternalProp = sPath+POSTFIX_INTERNAL_PATHS; 809 OUString sUserProp = sPath+POSTFIX_USER_PATHS; 810 OUString sWriteProp = sPath+POSTFIX_WRITE_PATH; 811 812 // Attention: The default set of IDs is fix and must follow these schema. 813 // Otherwise the outside code ant work for new added properties. 814 // Why? 815 // The outside code must fire N events for every changed property. 816 // And the knowing about packaging of variables of the structure PathInfo 817 // follow these group IDs! But if such ID is not in the range of [0..IDGROUP_COUNT] 818 // the outside can't determine the right group ... and can not fire the right events .-) 819 820 css::uno::Sequence< sal_Int32 > lIDs(IDGROUP_COUNT); 821 lIDs[0] = IDGROUP_OLDSTYLE; 822 lIDs[1] = IDGROUP_INTERNAL_PATHS; 823 lIDs[2] = IDGROUP_USER_PATHS; 824 lIDs[3] = IDGROUP_WRITE_PATH; 825 826 sal_Int32 c = m_lPropDesc.getLength(); 827 sal_Int32 i = 0; 828 for (i=0; i<c; ++i) 829 { 830 const css::beans::Property& rProp = m_lPropDesc[i]; 831 832 if (rProp.Name == sPath) 833 lIDs[IDGROUP_OLDSTYLE] = rProp.Handle; 834 else 835 if (rProp.Name == sInternalProp) 836 lIDs[IDGROUP_INTERNAL_PATHS] = rProp.Handle; 837 else 838 if (rProp.Name == sUserProp) 839 lIDs[IDGROUP_USER_PATHS] = rProp.Handle; 840 else 841 if (rProp.Name == sWriteProp) 842 lIDs[IDGROUP_WRITE_PATH] = rProp.Handle; 843 } 844 845 return lIDs; 846 } 847 848 void PathSettings::impl_notifyPropListener( const OUString& sPath, 849 const PathSettings::PathInfo* pPathOld, 850 const PathSettings::PathInfo* pPathNew) 851 { 852 css::uno::Sequence< sal_Int32 > lHandles(1); 853 css::uno::Sequence< css::uno::Any > lOldVals(1); 854 css::uno::Sequence< css::uno::Any > lNewVals(1); 855 856 css::uno::Sequence< sal_Int32 > lIDs = impl_mapPathName2IDList(sPath); 857 sal_Int32 c = lIDs.getLength(); 858 sal_Int32 i = 0; 859 sal_Int32 nMaxID = m_lPropDesc.getLength()-1; 860 for (i=0; i<c; ++i) 861 { 862 sal_Int32 nID = lIDs[i]; 863 864 if ( 865 (nID < 0 ) || 866 (nID > nMaxID) 867 ) 868 continue; 869 870 lHandles[0] = nID; 871 switch(impl_getPropGroup(nID)) 872 { 873 case IDGROUP_OLDSTYLE : 874 { 875 if (pPathOld) 876 { 877 OUString sVal = impl_convertPath2OldStyle(*pPathOld); 878 lOldVals[0] <<= sVal; 879 } 880 if (pPathNew) 881 { 882 OUString sVal = impl_convertPath2OldStyle(*pPathNew); 883 lNewVals[0] <<= sVal; 884 } 885 } 886 break; 887 888 case IDGROUP_INTERNAL_PATHS : 889 { 890 if (pPathOld) 891 lOldVals[0] <<= comphelper::containerToSequence(pPathOld->lInternalPaths); 892 if (pPathNew) 893 lNewVals[0] <<= comphelper::containerToSequence(pPathNew->lInternalPaths); 894 } 895 break; 896 897 case IDGROUP_USER_PATHS : 898 { 899 if (pPathOld) 900 lOldVals[0] <<= comphelper::containerToSequence(pPathOld->lUserPaths); 901 if (pPathNew) 902 lNewVals[0] <<= comphelper::containerToSequence(pPathNew->lUserPaths); 903 } 904 break; 905 906 case IDGROUP_WRITE_PATH : 907 { 908 if (pPathOld) 909 lOldVals[0] <<= pPathOld->sWritePath; 910 if (pPathNew) 911 lNewVals[0] <<= pPathNew->sWritePath; 912 } 913 break; 914 } 915 916 fire(lHandles.getArray(), 917 lNewVals.getArray(), 918 lOldVals.getArray(), 919 1, 920 false); 921 } 922 } 923 924 void PathSettings::impl_subst(std::vector<OUString>& lVals , 925 const css::uno::Reference< css::util::XStringSubstitution >& xSubst , 926 bool bReSubst) 927 { 928 for (auto & old : lVals) 929 { 930 OUString sNew; 931 if (bReSubst) 932 sNew = xSubst->reSubstituteVariables(old); 933 else 934 sNew = xSubst->substituteVariables(old, false); 935 936 old = sNew; 937 } 938 } 939 940 void PathSettings::impl_subst(PathSettings::PathInfo& aPath , 941 bool bReSubst) 942 { 943 css::uno::Reference< css::util::XStringSubstitution > xSubst = fa_getSubstitution(); 944 945 impl_subst(aPath.lInternalPaths, xSubst, bReSubst); 946 impl_subst(aPath.lUserPaths , xSubst, bReSubst); 947 if (bReSubst) 948 aPath.sWritePath = xSubst->reSubstituteVariables(aPath.sWritePath); 949 else 950 aPath.sWritePath = xSubst->substituteVariables(aPath.sWritePath, false); 951 } 952 953 OUString PathSettings::impl_convertPath2OldStyle(const PathSettings::PathInfo& rPath) const 954 { 955 std::vector<OUString> lTemp; 956 lTemp.reserve(rPath.lInternalPaths.size() + rPath.lUserPaths.size() + 1); 957 958 for (auto const& internalPath : rPath.lInternalPaths) 959 { 960 lTemp.push_back(internalPath); 961 } 962 for (auto const& userPath : rPath.lUserPaths) 963 { 964 lTemp.push_back(userPath); 965 } 966 967 if (!rPath.sWritePath.isEmpty()) 968 lTemp.push_back(rPath.sWritePath); 969 970 OUStringBuffer sPathVal(256); 971 for ( auto pIt = lTemp.begin(); 972 pIt != lTemp.end(); 973 ) 974 { 975 sPathVal.append(*pIt); 976 ++pIt; 977 if (pIt != lTemp.end()) 978 sPathVal.append(";"); 979 } 980 981 return sPathVal.makeStringAndClear(); 982 } 983 984 std::vector<OUString> PathSettings::impl_convertOldStyle2Path(const OUString& sOldStylePath) const 985 { 986 std::vector<OUString> lList; 987 sal_Int32 nToken = 0; 988 do 989 { 990 OUString sToken = sOldStylePath.getToken(0, ';', nToken); 991 if (!sToken.isEmpty()) 992 lList.push_back(sToken); 993 } 994 while(nToken >= 0); 995 996 return lList; 997 } 998 999 void PathSettings::impl_purgeKnownPaths(PathSettings::PathInfo& rPath, 1000 std::vector<OUString>& lList) 1001 { 1002 std::vector<OUString>::iterator pIt; 1003 1004 // Erase items in the internal path list from lList. 1005 // Also erase items in the internal path list from the user path list. 1006 for (auto const& internalPath : rPath.lInternalPaths) 1007 { 1008 std::vector<OUString>::iterator pItem = std::find(lList.begin(), lList.end(), internalPath); 1009 if (pItem != lList.end()) 1010 lList.erase(pItem); 1011 pItem = std::find(rPath.lUserPaths.begin(), rPath.lUserPaths.end(), internalPath); 1012 if (pItem != rPath.lUserPaths.end()) 1013 rPath.lUserPaths.erase(pItem); 1014 } 1015 1016 // Erase items not in lList from the user path list. 1017 pIt = rPath.lUserPaths.begin(); 1018 while ( pIt != rPath.lUserPaths.end() ) 1019 { 1020 const OUString& rItem = *pIt; 1021 std::vector<OUString>::iterator pItem = std::find(lList.begin(), lList.end(), rItem); 1022 if ( pItem == lList.end() ) 1023 { 1024 pIt = rPath.lUserPaths.erase(pIt); 1025 } 1026 else 1027 { 1028 ++pIt; 1029 } 1030 } 1031 1032 // Erase items in the user path list from lList. 1033 for (auto const& userPath : rPath.lUserPaths) 1034 { 1035 std::vector<OUString>::iterator pItem = std::find(lList.begin(), lList.end(), userPath); 1036 if (pItem != lList.end()) 1037 lList.erase(pItem); 1038 } 1039 1040 // Erase the write path from lList 1041 std::vector<OUString>::iterator pItem = std::find(lList.begin(), lList.end(), rPath.sWritePath); 1042 if (pItem != lList.end()) 1043 lList.erase(pItem); 1044 } 1045 1046 void PathSettings::impl_rebuildPropertyDescriptor() 1047 { 1048 // SAFE -> 1049 osl::MutexGuard g(cppu::WeakComponentImplHelperBase::rBHelper.rMutex); 1050 1051 sal_Int32 c = static_cast<sal_Int32>(m_lPaths.size()); 1052 sal_Int32 i = 0; 1053 m_lPropDesc.realloc(c*IDGROUP_COUNT); 1054 1055 for (auto const& path : m_lPaths) 1056 { 1057 const PathSettings::PathInfo& rPath = path.second; 1058 css::beans::Property* pProp = nullptr; 1059 1060 pProp = &(m_lPropDesc[i]); 1061 pProp->Name = rPath.sPathName; 1062 pProp->Handle = i; 1063 pProp->Type = cppu::UnoType<OUString>::get(); 1064 pProp->Attributes = css::beans::PropertyAttribute::BOUND; 1065 if (rPath.bIsReadonly) 1066 pProp->Attributes |= css::beans::PropertyAttribute::READONLY; 1067 ++i; 1068 1069 pProp = &(m_lPropDesc[i]); 1070 pProp->Name = rPath.sPathName+POSTFIX_INTERNAL_PATHS; 1071 pProp->Handle = i; 1072 pProp->Type = cppu::UnoType<css::uno::Sequence< OUString >>::get(); 1073 pProp->Attributes = css::beans::PropertyAttribute::BOUND | 1074 css::beans::PropertyAttribute::READONLY; 1075 ++i; 1076 1077 pProp = &(m_lPropDesc[i]); 1078 pProp->Name = rPath.sPathName+POSTFIX_USER_PATHS; 1079 pProp->Handle = i; 1080 pProp->Type = cppu::UnoType<css::uno::Sequence< OUString >>::get(); 1081 pProp->Attributes = css::beans::PropertyAttribute::BOUND; 1082 if (rPath.bIsReadonly) 1083 pProp->Attributes |= css::beans::PropertyAttribute::READONLY; 1084 ++i; 1085 1086 pProp = &(m_lPropDesc[i]); 1087 pProp->Name = rPath.sPathName+POSTFIX_WRITE_PATH; 1088 pProp->Handle = i; 1089 pProp->Type = cppu::UnoType<OUString>::get(); 1090 pProp->Attributes = css::beans::PropertyAttribute::BOUND; 1091 if (rPath.bIsReadonly) 1092 pProp->Attributes |= css::beans::PropertyAttribute::READONLY; 1093 ++i; 1094 } 1095 1096 m_pPropHelp.reset(new ::cppu::OPropertyArrayHelper(m_lPropDesc, false)); // false => not sorted ... must be done inside helper 1097 1098 // <- SAFE 1099 } 1100 1101 css::uno::Any PathSettings::impl_getPathValue(sal_Int32 nID) const 1102 { 1103 const PathSettings::PathInfo* pPath = impl_getPathAccessConst(nID); 1104 if (! pPath) 1105 throw css::lang::IllegalArgumentException(); 1106 1107 css::uno::Any aVal; 1108 switch(impl_getPropGroup(nID)) 1109 { 1110 case IDGROUP_OLDSTYLE : 1111 { 1112 OUString sVal = impl_convertPath2OldStyle(*pPath); 1113 aVal <<= sVal; 1114 } 1115 break; 1116 1117 case IDGROUP_INTERNAL_PATHS : 1118 { 1119 aVal <<= comphelper::containerToSequence(pPath->lInternalPaths); 1120 } 1121 break; 1122 1123 case IDGROUP_USER_PATHS : 1124 { 1125 aVal <<= comphelper::containerToSequence(pPath->lUserPaths); 1126 } 1127 break; 1128 1129 case IDGROUP_WRITE_PATH : 1130 { 1131 aVal <<= pPath->sWritePath; 1132 } 1133 break; 1134 } 1135 1136 return aVal; 1137 } 1138 1139 void PathSettings::impl_setPathValue( sal_Int32 nID , 1140 const css::uno::Any& aVal) 1141 { 1142 PathSettings::PathInfo* pOrgPath = impl_getPathAccess(nID); 1143 if (! pOrgPath) 1144 throw css::container::NoSuchElementException(); 1145 1146 // We work on a copied path ... so we can be sure that errors during this operation 1147 // does not make our internal cache invalid .-) 1148 PathSettings::PathInfo aChangePath(*pOrgPath); 1149 1150 switch(impl_getPropGroup(nID)) 1151 { 1152 case IDGROUP_OLDSTYLE : 1153 { 1154 OUString sVal; 1155 aVal >>= sVal; 1156 std::vector<OUString> lList = impl_convertOldStyle2Path(sVal); 1157 impl_subst(lList, fa_getSubstitution(), false); 1158 impl_purgeKnownPaths(aChangePath, lList); 1159 if (! impl_isValidPath(lList)) 1160 throw css::lang::IllegalArgumentException(); 1161 1162 if (aChangePath.bIsSinglePath) 1163 { 1164 SAL_WARN_IF(lList.size()>1, "fwk", "PathSettings::impl_setPathValue(): You try to set more than path value for a defined SINGLE_PATH!"); 1165 if ( !lList.empty() ) 1166 aChangePath.sWritePath = *(lList.begin()); 1167 else 1168 aChangePath.sWritePath.clear(); 1169 } 1170 else 1171 { 1172 for (auto const& elem : lList) 1173 { 1174 aChangePath.lUserPaths.push_back(elem); 1175 } 1176 } 1177 } 1178 break; 1179 1180 case IDGROUP_INTERNAL_PATHS : 1181 { 1182 if (aChangePath.bIsSinglePath) 1183 { 1184 throw css::uno::Exception( 1185 "The path '" + aChangePath.sPathName 1186 + "' is defined as SINGLE_PATH. It's sub set of internal paths can't be set.", 1187 static_cast< ::cppu::OWeakObject* >(this)); 1188 } 1189 1190 css::uno::Sequence<OUString> lTmpList; 1191 aVal >>= lTmpList; 1192 std::vector<OUString> lList = comphelper::sequenceToContainer<std::vector<OUString>>(lTmpList); 1193 if (! impl_isValidPath(lList)) 1194 throw css::lang::IllegalArgumentException(); 1195 aChangePath.lInternalPaths = lList; 1196 } 1197 break; 1198 1199 case IDGROUP_USER_PATHS : 1200 { 1201 if (aChangePath.bIsSinglePath) 1202 { 1203 throw css::uno::Exception( 1204 "The path '" + aChangePath.sPathName 1205 + "' is defined as SINGLE_PATH. It's sub set of internal paths can't be set.", 1206 static_cast< ::cppu::OWeakObject* >(this)); 1207 } 1208 1209 css::uno::Sequence<OUString> lTmpList; 1210 aVal >>= lTmpList; 1211 std::vector<OUString> lList = comphelper::sequenceToContainer<std::vector<OUString>>(lTmpList); 1212 if (! impl_isValidPath(lList)) 1213 throw css::lang::IllegalArgumentException(); 1214 aChangePath.lUserPaths = lList; 1215 } 1216 break; 1217 1218 case IDGROUP_WRITE_PATH : 1219 { 1220 OUString sVal; 1221 aVal >>= sVal; 1222 if (! impl_isValidPath(sVal)) 1223 throw css::lang::IllegalArgumentException(); 1224 aChangePath.sWritePath = sVal; 1225 } 1226 break; 1227 } 1228 1229 // TODO check if path has at least one path value set 1230 // At least it depends from the feature using this path, if an empty path list is allowed. 1231 1232 // first we should try to store the changed (copied!) path ... 1233 // In case an error occurs on saving time an exception is thrown ... 1234 // If no exception occurs we can update our internal cache (means 1235 // we can overwrite pOrgPath ! 1236 impl_storePath(aChangePath); 1237 pOrgPath->takeOver(aChangePath); 1238 } 1239 1240 bool PathSettings::impl_isValidPath(const std::vector<OUString>& lPath) const 1241 { 1242 for (auto const& path : lPath) 1243 { 1244 if (! impl_isValidPath(path)) 1245 return false; 1246 } 1247 1248 return true; 1249 } 1250 1251 bool PathSettings::impl_isValidPath(const OUString& sPath) const 1252 { 1253 // allow empty path to reset a path. 1254 // idea by LLA to support empty paths 1255 // if (sPath.getLength() == 0) 1256 // { 1257 // return sal_True; 1258 // } 1259 1260 return (! INetURLObject(sPath).HasError()); 1261 } 1262 1263 OUString impl_extractBaseFromPropName(const OUString& sPropName) 1264 { 1265 sal_Int32 i = sPropName.indexOf(POSTFIX_INTERNAL_PATHS); 1266 if (i > -1) 1267 return sPropName.copy(0, i); 1268 i = sPropName.indexOf(POSTFIX_USER_PATHS); 1269 if (i > -1) 1270 return sPropName.copy(0, i); 1271 i = sPropName.indexOf(POSTFIX_WRITE_PATH); 1272 if (i > -1) 1273 return sPropName.copy(0, i); 1274 1275 return sPropName; 1276 } 1277 1278 PathSettings::PathInfo* PathSettings::impl_getPathAccess(sal_Int32 nHandle) 1279 { 1280 // SAFE -> 1281 osl::MutexGuard g(cppu::WeakComponentImplHelperBase::rBHelper.rMutex); 1282 1283 if (nHandle > (m_lPropDesc.getLength()-1)) 1284 return nullptr; 1285 1286 const css::beans::Property& rProp = m_lPropDesc[nHandle]; 1287 OUString sProp = impl_extractBaseFromPropName(rProp.Name); 1288 PathSettings::PathHash::iterator rPath = m_lPaths.find(sProp); 1289 1290 if (rPath != m_lPaths.end()) 1291 return &(rPath->second); 1292 1293 return nullptr; 1294 // <- SAFE 1295 } 1296 1297 const PathSettings::PathInfo* PathSettings::impl_getPathAccessConst(sal_Int32 nHandle) const 1298 { 1299 // SAFE -> 1300 osl::MutexGuard g(cppu::WeakComponentImplHelperBase::rBHelper.rMutex); 1301 1302 if (nHandle > (m_lPropDesc.getLength()-1)) 1303 return nullptr; 1304 1305 const css::beans::Property& rProp = m_lPropDesc[nHandle]; 1306 OUString sProp = impl_extractBaseFromPropName(rProp.Name); 1307 PathSettings::PathHash::const_iterator rPath = m_lPaths.find(sProp); 1308 1309 if (rPath != m_lPaths.end()) 1310 return &(rPath->second); 1311 1312 return nullptr; 1313 // <- SAFE 1314 } 1315 1316 sal_Bool SAL_CALL PathSettings::convertFastPropertyValue( css::uno::Any& aConvertedValue, 1317 css::uno::Any& aOldValue , 1318 sal_Int32 nHandle , 1319 const css::uno::Any& aValue ) 1320 { 1321 // throws NoSuchElementException ! 1322 css::uno::Any aCurrentVal = impl_getPathValue(nHandle); 1323 1324 return PropHelper::willPropertyBeChanged( 1325 aCurrentVal, 1326 aValue, 1327 aOldValue, 1328 aConvertedValue); 1329 } 1330 1331 void SAL_CALL PathSettings::setFastPropertyValue_NoBroadcast( sal_Int32 nHandle, 1332 const css::uno::Any& aValue ) 1333 { 1334 // throws NoSuchElement- and IllegalArgumentException ! 1335 impl_setPathValue(nHandle, aValue); 1336 } 1337 1338 void SAL_CALL PathSettings::getFastPropertyValue(css::uno::Any& aValue , 1339 sal_Int32 nHandle) const 1340 { 1341 aValue = impl_getPathValue(nHandle); 1342 } 1343 1344 ::cppu::IPropertyArrayHelper& SAL_CALL PathSettings::getInfoHelper() 1345 { 1346 return *m_pPropHelp; 1347 } 1348 1349 css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL PathSettings::getPropertySetInfo() 1350 { 1351 return ::cppu::OPropertySetHelper::createPropertySetInfo(getInfoHelper()); 1352 } 1353 1354 css::uno::Reference< css::util::XStringSubstitution > PathSettings::fa_getSubstitution() 1355 { 1356 css::uno::Reference< css::util::XStringSubstitution > xSubst; 1357 { // SAFE -> 1358 osl::MutexGuard g(cppu::WeakComponentImplHelperBase::rBHelper.rMutex); 1359 xSubst = m_xSubstitution; 1360 } 1361 1362 if (! xSubst.is()) 1363 { 1364 // create the needed substitution service. 1365 // We must replace all used variables inside read path values. 1366 // In case we can't do so... the whole office can't work really. 1367 // That's why it seems to be OK to throw a RuntimeException then. 1368 xSubst = css::util::PathSubstitution::create(m_xContext); 1369 1370 { // SAFE -> 1371 osl::MutexGuard g(cppu::WeakComponentImplHelperBase::rBHelper.rMutex); 1372 m_xSubstitution = xSubst; 1373 } 1374 } 1375 1376 return xSubst; 1377 } 1378 1379 css::uno::Reference< css::container::XNameAccess > PathSettings::fa_getCfgOld() 1380 { 1381 const OUString CFG_NODE_OLD("org.openoffice.Office.Common/Path/Current"); 1382 1383 css::uno::Reference< css::container::XNameAccess > xCfg; 1384 { // SAFE -> 1385 osl::MutexGuard g(cppu::WeakComponentImplHelperBase::rBHelper.rMutex); 1386 xCfg = m_xCfgOld; 1387 } // <- SAFE 1388 1389 if (! xCfg.is()) 1390 { 1391 xCfg.set( ::comphelper::ConfigurationHelper::openConfig( 1392 m_xContext, 1393 CFG_NODE_OLD, 1394 ::comphelper::EConfigurationModes::Standard), // not readonly! Sometimes we need write access there !!! 1395 css::uno::UNO_QUERY_THROW); 1396 1397 { // SAFE -> 1398 osl::MutexGuard g(cppu::WeakComponentImplHelperBase::rBHelper.rMutex); 1399 m_xCfgOld = xCfg; 1400 } 1401 } 1402 1403 return xCfg; 1404 } 1405 1406 css::uno::Reference< css::container::XNameAccess > PathSettings::fa_getCfgNew() 1407 { 1408 const OUString CFG_NODE_NEW("org.openoffice.Office.Paths/Paths"); 1409 1410 css::uno::Reference< css::container::XNameAccess > xCfg; 1411 { // SAFE -> 1412 osl::MutexGuard g(cppu::WeakComponentImplHelperBase::rBHelper.rMutex); 1413 xCfg = m_xCfgNew; 1414 } // <- SAFE 1415 1416 if (! xCfg.is()) 1417 { 1418 xCfg.set( ::comphelper::ConfigurationHelper::openConfig( 1419 m_xContext, 1420 CFG_NODE_NEW, 1421 ::comphelper::EConfigurationModes::Standard), 1422 css::uno::UNO_QUERY_THROW); 1423 1424 { // SAFE -> 1425 osl::MutexGuard g(cppu::WeakComponentImplHelperBase::rBHelper.rMutex); 1426 m_xCfgNew = xCfg; 1427 m_xCfgNewListener = new WeakChangesListener(this); 1428 } 1429 1430 css::uno::Reference< css::util::XChangesNotifier > xBroadcaster(xCfg, css::uno::UNO_QUERY_THROW); 1431 xBroadcaster->addChangesListener(m_xCfgNewListener); 1432 } 1433 1434 return xCfg; 1435 } 1436 1437 struct Instance { 1438 explicit Instance( 1439 css::uno::Reference<css::uno::XComponentContext> const & context): 1440 instance( 1441 static_cast<cppu::OWeakObject *>(new PathSettings(context))) 1442 { 1443 // fill cache 1444 static_cast<PathSettings *>(static_cast<cppu::OWeakObject *> 1445 (instance.get()))->impl_readAll(); 1446 } 1447 1448 css::uno::Reference<css::uno::XInterface> instance; 1449 }; 1450 1451 struct Singleton: 1452 public rtl::StaticWithArg< 1453 Instance, css::uno::Reference<css::uno::XComponentContext>, Singleton> 1454 {}; 1455 1456 } 1457 1458 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * 1459 com_sun_star_comp_framework_PathSettings_get_implementation( 1460 css::uno::XComponentContext *context, 1461 css::uno::Sequence<css::uno::Any> const &) 1462 { 1463 return cppu::acquire(static_cast<cppu::OWeakObject *>( 1464 Singleton::get(context).instance.get())); 1465 } 1466 1467 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ 1468
