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 // MARKER(update_precomp.py): autogen include statement, do not remove 23 #include "precompiled_framework.hxx" 24 // ______________________________________________ 25 // my own includes 26 27 /** Attention: stl headers must(!) be included at first. Otherwise it can make trouble 28 with solaris headers ... 29 */ 30 #include <vector> 31 #include <services/pathsettings.hxx> 32 #include <threadhelp/readguard.hxx> 33 #include <threadhelp/writeguard.hxx> 34 #include <services.h> 35 36 // ______________________________________________ 37 // interface includes 38 #include <com/sun/star/beans/Property.hpp> 39 #include <com/sun/star/beans/XProperty.hpp> 40 #include <com/sun/star/beans/PropertyAttribute.hpp> 41 #include <com/sun/star/container/XContainer.hpp> 42 #include <com/sun/star/beans/XPropertySet.hpp> 43 #include <com/sun/star/util/XChangesNotifier.hpp> 44 45 // ______________________________________________ 46 // includes of other projects 47 #include <tools/urlobj.hxx> 48 #include <rtl/ustrbuf.hxx> 49 #include <rtl/logfile.hxx> 50 51 #include <comphelper/configurationhelper.hxx> 52 #include <unotools/configpathes.hxx> 53 54 #include <fwkdllapi.h> 55 56 // ______________________________________________ 57 // non exported const 58 59 #define CFG_READONLY_DEFAULT sal_False 60 61 const ::rtl::OUString CFGPROP_INTERNALPATHES = ::rtl::OUString::createFromAscii("InternalPaths"); 62 const ::rtl::OUString CFGPROP_USERPATHES = ::rtl::OUString::createFromAscii("UserPaths" ); 63 const ::rtl::OUString CFGPROP_WRITEPATH = ::rtl::OUString::createFromAscii("WritePath" ); 64 const ::rtl::OUString CFGPROP_ISSINGLEPATH = ::rtl::OUString::createFromAscii("IsSinglePath" ); 65 66 /* 67 0 : old style "Template" string using ";" as seperator 68 1 : internal paths "Template_internal" string list 69 2 : user paths "Template_user" string list 70 3 : write path "Template_write" string 71 */ 72 73 const ::rtl::OUString POSTFIX_INTERNAL_PATHES = ::rtl::OUString::createFromAscii("_internal"); 74 const ::rtl::OUString POSTFIX_USER_PATHES = ::rtl::OUString::createFromAscii("_user" ); 75 const ::rtl::OUString POSTFIX_WRITE_PATH = ::rtl::OUString::createFromAscii("_writable"); 76 77 const sal_Int32 IDGROUP_OLDSTYLE = 0; 78 const sal_Int32 IDGROUP_INTERNAL_PATHES = 1; 79 const sal_Int32 IDGROUP_USER_PATHES = 2; 80 const sal_Int32 IDGROUP_WRITE_PATH = 3; 81 82 const sal_Int32 IDGROUP_COUNT = 4; 83 84 sal_Int32 impl_getPropGroup(sal_Int32 nID) 85 { 86 return (nID % IDGROUP_COUNT); 87 } 88 89 // ______________________________________________ 90 // namespace 91 92 namespace framework 93 { 94 95 //----------------------------------------------------------------------------- 96 // XInterface, XTypeProvider, XServiceInfo 97 98 DEFINE_XINTERFACE_7 ( PathSettings , 99 OWeakObject , 100 DIRECT_INTERFACE ( css::lang::XTypeProvider ), 101 DIRECT_INTERFACE ( css::lang::XServiceInfo ), 102 DERIVED_INTERFACE( css::lang::XEventListener, css::util::XChangesListener), 103 DIRECT_INTERFACE ( css::util::XChangesListener ), 104 DIRECT_INTERFACE ( css::beans::XPropertySet ), 105 DIRECT_INTERFACE ( css::beans::XFastPropertySet ), 106 DIRECT_INTERFACE ( css::beans::XMultiPropertySet ) 107 ) 108 109 DEFINE_XTYPEPROVIDER_7 ( PathSettings , 110 css::lang::XTypeProvider , 111 css::lang::XServiceInfo , 112 css::lang::XEventListener , 113 css::util::XChangesListener , 114 css::beans::XPropertySet , 115 css::beans::XFastPropertySet , 116 css::beans::XMultiPropertySet 117 ) 118 119 DEFINE_XSERVICEINFO_ONEINSTANCESERVICE ( PathSettings , 120 ::cppu::OWeakObject , 121 SERVICENAME_PATHSETTINGS , 122 IMPLEMENTATIONNAME_PATHSETTINGS 123 ) 124 125 DEFINE_INIT_SERVICE ( PathSettings, 126 { 127 /*Attention 128 I think we don't need any mutex or lock here ... because we are called by our own static method impl_createInstance() 129 to create a new instance of this class by our own supported service factory. 130 see macro DEFINE_XSERVICEINFO_MULTISERVICE and "impl_initService()" for further information! 131 */ 132 133 // fill cache 134 impl_readAll(); 135 } 136 ) 137 138 //----------------------------------------------------------------------------- 139 PathSettings::PathSettings( const css::uno::Reference< css::lang::XMultiServiceFactory >& xSMGR ) 140 // Init baseclasses first 141 // Attention: Don't change order of initialization! 142 // ThreadHelpBase is a struct with a lock as member. We can't use a lock as direct member! 143 // We must garant right initialization and a valid value of this to initialize other baseclasses! 144 : ThreadHelpBase() 145 , ::cppu::OBroadcastHelperVar< ::cppu::OMultiTypeInterfaceContainerHelper, ::cppu::OMultiTypeInterfaceContainerHelper::keyType >(m_aLock.getShareableOslMutex()) 146 , ::cppu::OPropertySetHelper(*(static_cast< ::cppu::OBroadcastHelper* >(this))) 147 , ::cppu::OWeakObject() 148 // Init member 149 , m_xSMGR (xSMGR) 150 , m_pPropHelp(0 ) 151 , m_bIgnoreEvents(sal_False) 152 { 153 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "framework", "Ocke.Janssen@sun.com", "PathSettings::PathSettings" ); 154 } 155 156 //----------------------------------------------------------------------------- 157 PathSettings::~PathSettings() 158 { 159 if (m_pPropHelp) 160 delete m_pPropHelp; 161 } 162 163 //----------------------------------------------------------------------------- 164 void SAL_CALL PathSettings::changesOccurred(const css::util::ChangesEvent& aEvent) 165 { 166 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "framework", "Ocke.Janssen@sun.com", "PathSettings::changesOccurred" ); 167 /* 168 if (m_bIgnoreEvents) 169 return; 170 */ 171 172 sal_Int32 c = aEvent.Changes.getLength(); 173 sal_Int32 i = 0; 174 sal_Bool bUpdateDescriptor = sal_False; 175 176 for (i=0; i<c; ++i) 177 { 178 const css::util::ElementChange& aChange = aEvent.Changes[i]; 179 180 ::rtl::OUString sChanged; 181 aChange.Accessor >>= sChanged; 182 183 ::rtl::OUString sPath = ::utl::extractFirstFromConfigurationPath(sChanged); 184 if (sPath.getLength()) 185 { 186 PathSettings::EChangeOp eOp = impl_updatePath(sPath, sal_True); 187 if ( 188 (eOp == PathSettings::E_ADDED ) || 189 (eOp == PathSettings::E_REMOVED) 190 ) 191 bUpdateDescriptor = sal_True; 192 } 193 } 194 195 if (bUpdateDescriptor) 196 impl_rebuildPropertyDescriptor(); 197 } 198 199 //----------------------------------------------------------------------------- 200 void SAL_CALL PathSettings::disposing(const css::lang::EventObject& aSource) 201 { 202 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "framework", "Ocke.Janssen@sun.com", "PathSettings::disposing" ); 203 // SAFE -> 204 WriteGuard aWriteLock(m_aLock); 205 206 if (aSource.Source == m_xCfgNew) 207 m_xCfgNew.clear(); 208 209 aWriteLock.unlock(); 210 // <- SAFE 211 } 212 213 //----------------------------------------------------------------------------- 214 void PathSettings::impl_readAll() 215 { 216 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "framework", "Ocke.Janssen@sun.com", "PathSettings::impl_readAll" ); 217 RTL_LOGFILE_CONTEXT(aLog, "framework (as96863) ::PathSettings::load config (all)"); 218 219 // TODO think about me 220 css::uno::Reference< css::container::XNameAccess > xCfg = fa_getCfgNew(); 221 css::uno::Sequence< ::rtl::OUString > lPaths = xCfg->getElementNames(); 222 223 sal_Int32 c = lPaths.getLength(); 224 sal_Int32 i = 0; 225 226 for (i=0; i<c; ++i) 227 { 228 const ::rtl::OUString& sPath = lPaths[i]; 229 impl_updatePath(sPath, sal_False); 230 } 231 232 impl_rebuildPropertyDescriptor(); 233 } 234 235 //----------------------------------------------------------------------------- 236 // NO substitution here ! It's done outside ... 237 OUStringList PathSettings::impl_readOldFormat(const ::rtl::OUString& sPath) 238 { 239 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "framework", "Ocke.Janssen@sun.com", "PathSettings::impl_readOldFormat" ); 240 css::uno::Reference< css::container::XNameAccess > xCfg( fa_getCfgOld() ); 241 OUStringList aPathVal; 242 243 if( xCfg->hasByName(sPath) ) 244 { 245 css::uno::Any aVal( xCfg->getByName(sPath) ); 246 247 ::rtl::OUString sStringVal; 248 css::uno::Sequence< ::rtl::OUString > lStringListVal; 249 250 if (aVal >>= sStringVal) 251 { 252 aPathVal.push_back(sStringVal); 253 } 254 else if (aVal >>= lStringListVal) 255 { 256 aPathVal << lStringListVal; 257 } 258 } 259 260 return aPathVal; 261 } 262 263 //----------------------------------------------------------------------------- 264 // NO substitution here ! It's done outside ... 265 PathSettings::PathInfo PathSettings::impl_readNewFormat(const ::rtl::OUString& sPath) 266 { 267 css::uno::Reference< css::container::XNameAccess > xCfg = fa_getCfgNew(); 268 269 // get access to the "queried" path 270 css::uno::Reference< css::container::XNameAccess > xPath; 271 xCfg->getByName(sPath) >>= xPath; 272 273 PathSettings::PathInfo aPathVal; 274 275 // read internal path list 276 css::uno::Reference< css::container::XNameAccess > xIPath; 277 xPath->getByName(CFGPROP_INTERNALPATHES) >>= xIPath; 278 aPathVal.lInternalPaths << xIPath->getElementNames(); 279 280 // read user defined path list 281 aPathVal.lUserPaths << xPath->getByName(CFGPROP_USERPATHES); 282 283 // read the writeable path 284 xPath->getByName(CFGPROP_WRITEPATH) >>= aPathVal.sWritePath; 285 286 // read state props 287 xPath->getByName(CFGPROP_ISSINGLEPATH) >>= aPathVal.bIsSinglePath; 288 289 // analyze finalized/mandatory states 290 aPathVal.bIsReadonly = sal_False; 291 css::uno::Reference< css::beans::XProperty > xInfo(xPath, css::uno::UNO_QUERY); 292 if (xInfo.is()) 293 { 294 css::beans::Property aInfo = xInfo->getAsProperty(); 295 sal_Bool bFinalized = ((aInfo.Attributes & css::beans::PropertyAttribute::READONLY ) == css::beans::PropertyAttribute::READONLY ); 296 //sal_Bool bMandatory = ((aInfo.Attributes & css::beans::PropertyAttribute::REMOVEABLE) != css::beans::PropertyAttribute::REMOVEABLE); 297 298 // Note: Till we support finalized / mandatory on our API more in detail we handle 299 // all states simple as READONLY ! But because all really needed paths are "mandatory" by default 300 // we have to handle "finalized" as the real "readonly" indicator . 301 aPathVal.bIsReadonly = bFinalized; 302 } 303 304 return aPathVal; 305 } 306 307 //----------------------------------------------------------------------------- 308 void PathSettings::impl_storePath(const PathSettings::PathInfo& aPath) 309 { 310 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "framework", "Ocke.Janssen@sun.com", "PathSettings::impl_storePath" ); 311 m_bIgnoreEvents = sal_True; 312 313 css::uno::Reference< css::container::XNameAccess > xCfgNew = fa_getCfgNew(); 314 css::uno::Reference< css::container::XNameAccess > xCfgOld = fa_getCfgOld(); 315 316 // try to replace path-parts with well known and supported variables. 317 // So an office can be moved easily to another location without losing 318 // its related paths. 319 PathInfo aResubstPath(aPath); 320 impl_subst(aResubstPath, sal_True); 321 322 // update new configuration 323 if (! aResubstPath.bIsSinglePath) 324 { 325 ::comphelper::ConfigurationHelper::writeRelativeKey(xCfgNew, 326 aResubstPath.sPathName, 327 CFGPROP_USERPATHES, 328 css::uno::makeAny(aResubstPath.lUserPaths.getAsConstList())); 329 } 330 331 ::comphelper::ConfigurationHelper::writeRelativeKey(xCfgNew, 332 aResubstPath.sPathName, 333 CFGPROP_WRITEPATH, 334 css::uno::makeAny(aResubstPath.sWritePath)); 335 336 ::comphelper::ConfigurationHelper::flush(xCfgNew); 337 338 // remove the whole path from the old configuration ! 339 // Otherwise we can't make sure that the diff between new and old configuration 340 // on loading time really represent an user setting !!! 341 342 // Check if the given path exists inside the old configuration. 343 // Because our new configuration knows more then the list of old paths ... ! 344 if (xCfgOld->hasByName(aResubstPath.sPathName)) 345 { 346 css::uno::Reference< css::beans::XPropertySet > xProps(xCfgOld, css::uno::UNO_QUERY_THROW); 347 xProps->setPropertyValue(aResubstPath.sPathName, css::uno::Any()); 348 ::comphelper::ConfigurationHelper::flush(xCfgOld); 349 } 350 351 m_bIgnoreEvents = sal_False; 352 } 353 354 //----------------------------------------------------------------------------- 355 #ifdef MIGRATE_OLD_USER_PATHES 356 void PathSettings::impl_mergeOldUserPaths( PathSettings::PathInfo& rPath, 357 const OUStringList& lOld ) 358 { 359 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "framework", "Ocke.Janssen@sun.com", "PathSettings::impl_mergeOldUserPaths" ); 360 OUStringList::const_iterator pIt; 361 for ( pIt = lOld.begin(); 362 pIt != lOld.end() ; 363 ++pIt ) 364 { 365 const ::rtl::OUString& sOld = *pIt; 366 367 if (rPath.bIsSinglePath) 368 { 369 LOG_ASSERT2(lOld.size()>1, "PathSettings::impl_mergeOldUserPaths()", "Single path has more then one path value inside old configuration (Common.xcu)!") 370 if (! rPath.sWritePath.equals(sOld)) 371 rPath.sWritePath = sOld; 372 } 373 else 374 { 375 if ( 376 ( rPath.lInternalPaths.findConst(sOld) == rPath.lInternalPaths.end()) && 377 ( rPath.lUserPaths.findConst(sOld) == rPath.lUserPaths.end() ) && 378 (! rPath.sWritePath.equals(sOld) ) 379 ) 380 rPath.lUserPaths.push_back(sOld); 381 } 382 } 383 } 384 #endif // MIGRATE_OLD_USER_PATHES 385 386 //----------------------------------------------------------------------------- 387 PathSettings::EChangeOp PathSettings::impl_updatePath(const ::rtl::OUString& sPath , 388 sal_Bool bNotifyListener) 389 { 390 // SAFE -> 391 WriteGuard aWriteLock(m_aLock); 392 393 PathSettings::PathInfo* pPathOld = 0; 394 PathSettings::PathInfo* pPathNew = 0; 395 PathSettings::EChangeOp eOp = PathSettings::E_UNDEFINED; 396 PathSettings::PathInfo aPath; 397 398 try 399 { 400 aPath = impl_readNewFormat(sPath); 401 aPath.sPathName = sPath; 402 // replace all might existing variables with real values 403 // Do it before these old paths will be compared against the 404 // new path configuration. Otherwise some strings uses different variables ... but substitution 405 // will produce strings with same content (because some variables are redundant!) 406 impl_subst(aPath, sal_False); 407 } 408 catch(const css::uno::RuntimeException& exRun) 409 { throw exRun; } 410 catch(const css::container::NoSuchElementException&) 411 { eOp = PathSettings::E_REMOVED; } 412 catch(const css::uno::Exception& exAny) 413 { throw exAny; } 414 415 #ifdef MIGRATE_OLD_USER_PATHES 416 try 417 { 418 // migration of old user defined values on demand 419 // can be disabled for a new major 420 OUStringList lOldVals = impl_readOldFormat(sPath); 421 // replace all might existing variables with real values 422 // Do it before these old paths will be compared against the 423 // new path configuration. Otherwise some strings uses different variables ... but substitution 424 // will produce strings with same content (because some variables are redundant!) 425 impl_subst(lOldVals, fa_getSubstitution(), sal_False); 426 impl_mergeOldUserPaths(aPath, lOldVals); 427 } 428 catch(const css::uno::RuntimeException& exRun) 429 { throw exRun; } 430 // Normal(!) exceptions can be ignored! 431 // E.g. in case an addon installs a new path, which was not well known for an OOo 1.x installation 432 // we can't find a value for it inside the "old" configuration. So a NoSuchElementException 433 // will be normal .-) 434 catch(const css::uno::Exception&) 435 {} 436 #endif // MIGRATE_OLD_USER_PATHES 437 438 PathSettings::PathHash::iterator pPath = m_lPaths.find(sPath); 439 if (eOp == PathSettings::E_UNDEFINED) 440 { 441 if (pPath != m_lPaths.end()) 442 eOp = PathSettings::E_CHANGED; 443 else 444 eOp = PathSettings::E_ADDED; 445 } 446 447 switch(eOp) 448 { 449 case PathSettings::E_ADDED : 450 { 451 if (bNotifyListener) 452 { 453 pPathOld = 0; 454 pPathNew = &aPath; 455 impl_notifyPropListener(eOp, sPath, pPathOld, pPathNew); 456 } 457 m_lPaths[sPath] = aPath; 458 } 459 break; 460 461 case PathSettings::E_CHANGED : 462 { 463 if (bNotifyListener) 464 { 465 pPathOld = &(pPath->second); 466 pPathNew = &aPath; 467 impl_notifyPropListener(eOp, sPath, pPathOld, pPathNew); 468 } 469 m_lPaths[sPath] = aPath; 470 } 471 break; 472 473 case PathSettings::E_REMOVED : 474 { 475 if (pPath != m_lPaths.end()) 476 { 477 if (bNotifyListener) 478 { 479 pPathOld = &(pPath->second); 480 pPathNew = 0; 481 impl_notifyPropListener(eOp, sPath, pPathOld, pPathNew); 482 } 483 m_lPaths.erase(pPath); 484 } 485 } 486 break; 487 488 default: // to let compiler be happy 489 break; 490 } 491 492 return eOp; 493 } 494 495 //----------------------------------------------------------------------------- 496 css::uno::Sequence< sal_Int32 > PathSettings::impl_mapPathName2IDList(const ::rtl::OUString& sPath) 497 { 498 ::rtl::OUString sOldStyleProp = sPath; 499 ::rtl::OUString sInternalProp = sPath+POSTFIX_INTERNAL_PATHES; 500 ::rtl::OUString sUserProp = sPath+POSTFIX_USER_PATHES; 501 ::rtl::OUString sWriteProp = sPath+POSTFIX_WRITE_PATH; 502 503 // Attention: The default set of IDs is fix and must follow these schema. 504 // Otherwise the outside code ant work for new added properties. 505 // Why ? 506 // The outside code must fire N events for every changed property. 507 // And the knowing about packaging of variables of the structure PathInfo 508 // follow these group IDs ! But if such ID isn't in the range of [0..IDGROUP_COUNT] 509 // the outside can't determine the right group ... and can't fire the right events .-) 510 511 css::uno::Sequence< sal_Int32 > lIDs(IDGROUP_COUNT); 512 lIDs[0] = IDGROUP_OLDSTYLE ; 513 lIDs[1] = IDGROUP_INTERNAL_PATHES; 514 lIDs[2] = IDGROUP_USER_PATHES ; 515 lIDs[3] = IDGROUP_WRITE_PATH ; 516 517 sal_Int32 c = m_lPropDesc.getLength(); 518 sal_Int32 i = 0; 519 for (i=0; i<c; ++i) 520 { 521 const css::beans::Property& rProp = m_lPropDesc[i]; 522 523 if (rProp.Name.equals(sOldStyleProp)) 524 lIDs[IDGROUP_OLDSTYLE] = rProp.Handle; 525 else 526 if (rProp.Name.equals(sInternalProp)) 527 lIDs[IDGROUP_INTERNAL_PATHES] = rProp.Handle; 528 else 529 if (rProp.Name.equals(sUserProp)) 530 lIDs[IDGROUP_USER_PATHES] = rProp.Handle; 531 else 532 if (rProp.Name.equals(sWriteProp)) 533 lIDs[IDGROUP_WRITE_PATH] = rProp.Handle; 534 } 535 536 return lIDs; 537 } 538 539 //----------------------------------------------------------------------------- 540 void PathSettings::impl_notifyPropListener( PathSettings::EChangeOp /*eOp*/ , 541 const ::rtl::OUString& sPath , 542 const PathSettings::PathInfo* pPathOld, 543 const PathSettings::PathInfo* pPathNew) 544 { 545 css::uno::Sequence< sal_Int32 > lHandles(1); 546 css::uno::Sequence< css::uno::Any > lOldVals(1); 547 css::uno::Sequence< css::uno::Any > lNewVals(1); 548 549 css::uno::Sequence< sal_Int32 > lIDs = impl_mapPathName2IDList(sPath); 550 sal_Int32 c = lIDs.getLength(); 551 sal_Int32 i = 0; 552 sal_Int32 nMaxID = m_lPropDesc.getLength()-1; 553 for (i=0; i<c; ++i) 554 { 555 sal_Int32 nID = lIDs[i]; 556 557 if ( 558 (nID < 0 ) || 559 (nID > nMaxID) 560 ) 561 continue; 562 563 lHandles[0] = nID; 564 switch(impl_getPropGroup(nID)) 565 { 566 case IDGROUP_OLDSTYLE : 567 { 568 if (pPathOld) 569 { 570 ::rtl::OUString sVal = impl_convertPath2OldStyle(*pPathOld); 571 lOldVals[0] <<= sVal; 572 } 573 if (pPathNew) 574 { 575 ::rtl::OUString sVal = impl_convertPath2OldStyle(*pPathNew); 576 lNewVals[0] <<= sVal; 577 } 578 } 579 break; 580 581 case IDGROUP_INTERNAL_PATHES : 582 { 583 if (pPathOld) 584 lOldVals[0] <<= pPathOld->lInternalPaths.getAsConstList(); 585 if (pPathNew) 586 lNewVals[0] <<= pPathNew->lInternalPaths.getAsConstList(); 587 } 588 break; 589 590 case IDGROUP_USER_PATHES : 591 { 592 if (pPathOld) 593 lOldVals[0] <<= pPathOld->lUserPaths.getAsConstList(); 594 if (pPathNew) 595 lNewVals[0] <<= pPathNew->lUserPaths.getAsConstList(); 596 } 597 break; 598 599 case IDGROUP_WRITE_PATH : 600 { 601 if (pPathOld) 602 lOldVals[0] <<= pPathOld->sWritePath; 603 if (pPathNew) 604 lNewVals[0] <<= pPathNew->sWritePath; 605 } 606 break; 607 } 608 609 fire(lHandles.getArray(), 610 lNewVals.getArray(), 611 lOldVals.getArray(), 612 1, 613 sal_False); 614 } 615 } 616 617 //----------------------------------------------------------------------------- 618 void PathSettings::impl_subst( OUStringList& lVals , 619 const css::uno::Reference< css::util::XStringSubstitution >& xSubst , 620 sal_Bool bReSubst) 621 { 622 OUStringList::iterator pIt; 623 624 for ( pIt = lVals.begin(); 625 pIt != lVals.end() ; 626 ++pIt ) 627 { 628 const ::rtl::OUString& sOld = *pIt; 629 ::rtl::OUString sNew ; 630 if (bReSubst) 631 sNew = xSubst->reSubstituteVariables(sOld); 632 else 633 sNew = xSubst->substituteVariables(sOld, sal_False); 634 635 *pIt = sNew; 636 } 637 } 638 639 //----------------------------------------------------------------------------- 640 void PathSettings::impl_subst(PathSettings::PathInfo& aPath , 641 sal_Bool bReSubst) 642 { 643 css::uno::Reference< css::util::XStringSubstitution > xSubst = fa_getSubstitution(); 644 645 impl_subst(aPath.lInternalPaths, xSubst, bReSubst); 646 impl_subst(aPath.lUserPaths , xSubst, bReSubst); 647 if (bReSubst) 648 aPath.sWritePath = xSubst->reSubstituteVariables(aPath.sWritePath); 649 else 650 aPath.sWritePath = xSubst->substituteVariables(aPath.sWritePath, sal_False); 651 } 652 653 //----------------------------------------------------------------------------- 654 ::rtl::OUString PathSettings::impl_convertPath2OldStyle(const PathSettings::PathInfo& rPath) const 655 { 656 OUStringList::const_iterator pIt; 657 OUStringList lTemp; 658 lTemp.reserve(rPath.lInternalPaths.size() + rPath.lUserPaths.size() + 1); 659 660 for ( pIt = rPath.lInternalPaths.begin(); 661 pIt != rPath.lInternalPaths.end() ; 662 ++pIt ) 663 { 664 lTemp.push_back(*pIt); 665 } 666 for ( pIt = rPath.lUserPaths.begin(); 667 pIt != rPath.lUserPaths.end() ; 668 ++pIt ) 669 { 670 lTemp.push_back(*pIt); 671 } 672 673 if (rPath.sWritePath.getLength() > 0) 674 lTemp.push_back(rPath.sWritePath); 675 676 ::rtl::OUStringBuffer sPathVal(256); 677 for ( pIt = lTemp.begin(); 678 pIt != lTemp.end() ; 679 ) 680 { 681 sPathVal.append(*pIt); 682 ++pIt; 683 if (pIt != lTemp.end()) 684 sPathVal.appendAscii(";"); 685 } 686 687 return sPathVal.makeStringAndClear(); 688 } 689 690 //----------------------------------------------------------------------------- 691 OUStringList PathSettings::impl_convertOldStyle2Path(const ::rtl::OUString& sOldStylePath) const 692 { 693 OUStringList lList; 694 sal_Int32 nToken = 0; 695 do 696 { 697 ::rtl::OUString sToken = sOldStylePath.getToken(0, ';', nToken); 698 if (sToken.getLength()) 699 lList.push_back(sToken); 700 } 701 while(nToken >= 0); 702 703 return lList; 704 } 705 706 //----------------------------------------------------------------------------- 707 void PathSettings::impl_purgeKnownPaths(const PathSettings::PathInfo& rPath, 708 OUStringList& lList) 709 { 710 OUStringList::const_iterator pIt; 711 for ( pIt = rPath.lInternalPaths.begin(); 712 pIt != rPath.lInternalPaths.end() ; 713 ++pIt ) 714 { 715 const ::rtl::OUString& rItem = *pIt; 716 OUStringList::iterator pItem = lList.find(rItem); 717 if (pItem != lList.end()) 718 lList.erase(pItem); 719 } 720 for ( pIt = rPath.lUserPaths.begin(); 721 pIt != rPath.lUserPaths.end() ; 722 ++pIt ) 723 { 724 const ::rtl::OUString& rItem = *pIt; 725 OUStringList::iterator pItem = lList.find(rItem); 726 if (pItem != lList.end()) 727 lList.erase(pItem); 728 } 729 730 OUStringList::iterator pItem = lList.find(rPath.sWritePath); 731 if (pItem != lList.end()) 732 lList.erase(pItem); 733 } 734 735 //----------------------------------------------------------------------------- 736 void PathSettings::impl_rebuildPropertyDescriptor() 737 { 738 // SAFE -> 739 WriteGuard aWriteLock(m_aLock); 740 741 sal_Int32 c = (sal_Int32)m_lPaths.size(); 742 sal_Int32 i = 0; 743 m_lPropDesc.realloc(c*IDGROUP_COUNT); 744 745 PathHash::const_iterator pIt; 746 for ( pIt = m_lPaths.begin(); 747 pIt != m_lPaths.end() ; 748 ++pIt ) 749 { 750 const PathSettings::PathInfo& rPath = pIt->second; 751 css::beans::Property* pProp = 0; 752 753 pProp = &(m_lPropDesc[i]); 754 pProp->Name = rPath.sPathName; 755 pProp->Handle = i; 756 pProp->Type = ::getCppuType((::rtl::OUString*)0); 757 pProp->Attributes = css::beans::PropertyAttribute::BOUND; 758 if (rPath.bIsReadonly) 759 pProp->Attributes |= css::beans::PropertyAttribute::READONLY; 760 ++i; 761 762 pProp = &(m_lPropDesc[i]); 763 pProp->Name = rPath.sPathName+POSTFIX_INTERNAL_PATHES; 764 pProp->Handle = i; 765 pProp->Type = ::getCppuType((css::uno::Sequence< ::rtl::OUString >*)0); 766 pProp->Attributes = css::beans::PropertyAttribute::BOUND | 767 css::beans::PropertyAttribute::READONLY; 768 ++i; 769 770 pProp = &(m_lPropDesc[i]); 771 pProp->Name = rPath.sPathName+POSTFIX_USER_PATHES; 772 pProp->Handle = i; 773 pProp->Type = ::getCppuType((css::uno::Sequence< ::rtl::OUString >*)0); 774 pProp->Attributes = css::beans::PropertyAttribute::BOUND; 775 if (rPath.bIsReadonly) 776 pProp->Attributes |= css::beans::PropertyAttribute::READONLY; 777 ++i; 778 779 pProp = &(m_lPropDesc[i]); 780 pProp->Name = rPath.sPathName+POSTFIX_WRITE_PATH; 781 pProp->Handle = i; 782 pProp->Type = ::getCppuType((::rtl::OUString*)0); 783 pProp->Attributes = css::beans::PropertyAttribute::BOUND; 784 if (rPath.bIsReadonly) 785 pProp->Attributes |= css::beans::PropertyAttribute::READONLY; 786 ++i; 787 } 788 789 if (m_pPropHelp) 790 delete m_pPropHelp; 791 m_pPropHelp = new ::cppu::OPropertyArrayHelper(m_lPropDesc, sal_False); // false => not sorted ... must be done inside helper 792 793 aWriteLock.unlock(); 794 // <- SAFE 795 } 796 797 //----------------------------------------------------------------------------- 798 css::uno::Any PathSettings::impl_getPathValue(sal_Int32 nID) const 799 { 800 const PathSettings::PathInfo* pPath = impl_getPathAccessConst(nID); 801 if (! pPath) 802 throw css::container::NoSuchElementException(); 803 804 css::uno::Any aVal; 805 switch(impl_getPropGroup(nID)) 806 { 807 case IDGROUP_OLDSTYLE : 808 { 809 ::rtl::OUString sVal = impl_convertPath2OldStyle(*pPath); 810 aVal <<= sVal; 811 } 812 break; 813 814 case IDGROUP_INTERNAL_PATHES : 815 { 816 aVal <<= pPath->lInternalPaths.getAsConstList(); 817 } 818 break; 819 820 case IDGROUP_USER_PATHES : 821 { 822 aVal <<= pPath->lUserPaths.getAsConstList(); 823 } 824 break; 825 826 case IDGROUP_WRITE_PATH : 827 { 828 aVal <<= pPath->sWritePath; 829 } 830 break; 831 } 832 833 return aVal; 834 } 835 836 //----------------------------------------------------------------------------- 837 void PathSettings::impl_setPathValue( sal_Int32 nID , 838 const css::uno::Any& aVal) 839 { 840 PathSettings::PathInfo* pOrgPath = impl_getPathAccess(nID); 841 if (! pOrgPath) 842 throw css::container::NoSuchElementException(); 843 844 // We work on a copied path ... so we can be sure that errors during this operation 845 // does not make our internal cache invalid .-) 846 PathSettings::PathInfo aChangePath(*pOrgPath); 847 848 switch(impl_getPropGroup(nID)) 849 { 850 case IDGROUP_OLDSTYLE : 851 { 852 ::rtl::OUString sVal; 853 aVal >>= sVal; 854 OUStringList lList = impl_convertOldStyle2Path(sVal); 855 impl_subst(lList, fa_getSubstitution(), sal_False); 856 impl_purgeKnownPaths(aChangePath, lList); 857 if (! impl_isValidPath(lList)) 858 throw css::lang::IllegalArgumentException(); 859 860 if (aChangePath.bIsSinglePath) 861 { 862 LOG_ASSERT2(lList.size()>1, "PathSettings::impl_setPathValue()", "You try to set more then path value for a defined SINGLE_PATH!") 863 if ( !lList.empty() ) 864 aChangePath.sWritePath = *(lList.begin()); 865 else 866 aChangePath.sWritePath = ::rtl::OUString(); 867 } 868 else 869 { 870 OUStringList::const_iterator pIt; 871 for ( pIt = lList.begin(); 872 pIt != lList.end() ; 873 ++pIt ) 874 { 875 aChangePath.lUserPaths.push_back(*pIt); 876 } 877 } 878 } 879 break; 880 881 case IDGROUP_INTERNAL_PATHES : 882 { 883 if (aChangePath.bIsSinglePath) 884 { 885 ::rtl::OUStringBuffer sMsg(256); 886 sMsg.appendAscii("The path '" ); 887 sMsg.append (aChangePath.sPathName); 888 sMsg.appendAscii("' is defined as SINGLE_PATH. It's sub set of internal paths can't be set."); 889 throw css::uno::Exception(sMsg.makeStringAndClear(), 890 static_cast< ::cppu::OWeakObject* >(this)); 891 } 892 893 OUStringList lList; 894 lList << aVal; 895 if (! impl_isValidPath(lList)) 896 throw css::lang::IllegalArgumentException(); 897 aChangePath.lInternalPaths = lList; 898 } 899 break; 900 901 case IDGROUP_USER_PATHES : 902 { 903 if (aChangePath.bIsSinglePath) 904 { 905 ::rtl::OUStringBuffer sMsg(256); 906 sMsg.appendAscii("The path '" ); 907 sMsg.append (aChangePath.sPathName); 908 sMsg.appendAscii("' is defined as SINGLE_PATH. It's sub set of internal paths can't be set."); 909 throw css::uno::Exception(sMsg.makeStringAndClear(), 910 static_cast< ::cppu::OWeakObject* >(this)); 911 } 912 913 OUStringList lList; 914 lList << aVal; 915 if (! impl_isValidPath(lList)) 916 throw css::lang::IllegalArgumentException(); 917 aChangePath.lUserPaths = lList; 918 } 919 break; 920 921 case IDGROUP_WRITE_PATH : 922 { 923 ::rtl::OUString sVal; 924 aVal >>= sVal; 925 if (! impl_isValidPath(sVal)) 926 throw css::lang::IllegalArgumentException(); 927 aChangePath.sWritePath = sVal; 928 } 929 break; 930 } 931 932 // TODO check if path has at least one path value set 933 // At least it depends from the feature using this path, if an empty path list is allowed. 934 /* 935 if (impl_isPathEmpty(aChangePath)) 936 { 937 ::rtl::OUStringBuffer sMsg(256); 938 sMsg.appendAscii("The path '" ); 939 sMsg.append (aChangePath.sPathName); 940 sMsg.appendAscii("' is empty now ... Not a real good idea."); 941 throw css::uno::Exception(sMsg.makeStringAndClear(), 942 static_cast< ::cppu::OWeakObject* >(this)); 943 } 944 */ 945 946 // first we should try to store the changed (copied!) path ... 947 // In case an error occurs on saving time an exception is thrown ... 948 // If no exception occurs we can update our internal cache (means 949 // we can overwrite pOrgPath ! 950 impl_storePath(aChangePath); 951 pOrgPath->takeOver(aChangePath); 952 } 953 954 //----------------------------------------------------------------------------- 955 sal_Bool PathSettings::impl_isValidPath(const OUStringList& lPath) const 956 { 957 OUStringList::const_iterator pIt; 958 for ( pIt = lPath.begin(); 959 pIt != lPath.end() ; 960 ++pIt ) 961 { 962 const ::rtl::OUString& rVal = *pIt; 963 if (! impl_isValidPath(rVal)) 964 return sal_False; 965 } 966 967 return sal_True; 968 } 969 970 //----------------------------------------------------------------------------- 971 sal_Bool PathSettings::impl_isValidPath(const ::rtl::OUString& sPath) const 972 { 973 // allow empty path to reset a path. 974 // idea by LLA to support empty paths 975 // if (sPath.getLength() == 0) 976 // { 977 // return sal_True; 978 // } 979 980 return (! INetURLObject(sPath).HasError()); 981 } 982 983 //----------------------------------------------------------------------------- 984 ::rtl::OUString impl_extractBaseFromPropName(const ::rtl::OUString& sPropName) 985 { 986 sal_Int32 i = -1; 987 988 i = sPropName.indexOf(POSTFIX_INTERNAL_PATHES); 989 if (i > -1) 990 return sPropName.copy(0, i); 991 i = sPropName.indexOf(POSTFIX_USER_PATHES); 992 if (i > -1) 993 return sPropName.copy(0, i); 994 i = sPropName.indexOf(POSTFIX_WRITE_PATH); 995 if (i > -1) 996 return sPropName.copy(0, i); 997 998 return sPropName; 999 } 1000 1001 //----------------------------------------------------------------------------- 1002 PathSettings::PathInfo* PathSettings::impl_getPathAccess(sal_Int32 nHandle) 1003 { 1004 // SAFE -> 1005 ReadGuard aReadLock(m_aLock); 1006 1007 if (nHandle > (m_lPropDesc.getLength()-1)) 1008 return 0; 1009 1010 const css::beans::Property& rProp = m_lPropDesc[nHandle]; 1011 ::rtl::OUString sProp = impl_extractBaseFromPropName(rProp.Name); 1012 PathSettings::PathHash::iterator rPath = m_lPaths.find(sProp); 1013 1014 if (rPath != m_lPaths.end()) 1015 return &(rPath->second); 1016 1017 return 0; 1018 // <- SAFE 1019 } 1020 1021 //----------------------------------------------------------------------------- 1022 const PathSettings::PathInfo* PathSettings::impl_getPathAccessConst(sal_Int32 nHandle) const 1023 { 1024 // SAFE -> 1025 ReadGuard aReadLock(m_aLock); 1026 1027 if (nHandle > (m_lPropDesc.getLength()-1)) 1028 return 0; 1029 1030 const css::beans::Property& rProp = m_lPropDesc[nHandle]; 1031 ::rtl::OUString sProp = impl_extractBaseFromPropName(rProp.Name); 1032 PathSettings::PathHash::const_iterator rPath = m_lPaths.find(sProp); 1033 1034 if (rPath != m_lPaths.end()) 1035 return &(rPath->second); 1036 1037 return 0; 1038 // <- SAFE 1039 } 1040 1041 //----------------------------------------------------------------------------- 1042 sal_Bool SAL_CALL PathSettings::convertFastPropertyValue( css::uno::Any& aConvertedValue, 1043 css::uno::Any& aOldValue , 1044 sal_Int32 nHandle , 1045 const css::uno::Any& aValue ) 1046 { 1047 // throws NoSuchElementException ! 1048 css::uno::Any aCurrentVal = impl_getPathValue(nHandle); 1049 1050 return PropHelper::willPropertyBeChanged( 1051 aCurrentVal, 1052 aValue, 1053 aOldValue, 1054 aConvertedValue); 1055 } 1056 1057 //----------------------------------------------------------------------------- 1058 void SAL_CALL PathSettings::setFastPropertyValue_NoBroadcast( sal_Int32 nHandle, 1059 const css::uno::Any& aValue ) 1060 { 1061 // throws NoSuchElement- and IllegalArgumentException ! 1062 impl_setPathValue(nHandle, aValue); 1063 } 1064 1065 //----------------------------------------------------------------------------- 1066 void SAL_CALL PathSettings::getFastPropertyValue(css::uno::Any& aValue , 1067 sal_Int32 nHandle) const 1068 { 1069 aValue = impl_getPathValue(nHandle); 1070 } 1071 1072 //----------------------------------------------------------------------------- 1073 ::cppu::IPropertyArrayHelper& SAL_CALL PathSettings::getInfoHelper() 1074 { 1075 return *m_pPropHelp; 1076 } 1077 1078 //----------------------------------------------------------------------------- 1079 css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL PathSettings::getPropertySetInfo() 1080 { 1081 return css::uno::Reference< css::beans::XPropertySetInfo >(createPropertySetInfo(getInfoHelper())); 1082 } 1083 1084 //----------------------------------------------------------------------------- 1085 css::uno::Reference< css::util::XStringSubstitution > PathSettings::fa_getSubstitution() 1086 { 1087 // SAFE -> 1088 ReadGuard aReadLock(m_aLock); 1089 css::uno::Reference< css::lang::XMultiServiceFactory > xSMGR = m_xSMGR; 1090 css::uno::Reference< css::util::XStringSubstitution > xSubst = m_xSubstitution; 1091 aReadLock.unlock(); 1092 // <- SAFE 1093 1094 if (! xSubst.is()) 1095 { 1096 // create the needed substitution service. 1097 // We must replace all used variables inside read path values. 1098 // In case we can't do so ... the whole office can't work really. 1099 // That's why it seems to be OK to throw a RuntimeException then. 1100 xSubst = css::uno::Reference< css::util::XStringSubstitution >( 1101 xSMGR->createInstance(SERVICENAME_SUBSTITUTEPATHVARIABLES), 1102 css::uno::UNO_QUERY_THROW); 1103 1104 // SAFE -> 1105 WriteGuard aWriteLock(m_aLock); 1106 m_xSubstitution = xSubst; 1107 aWriteLock.unlock(); 1108 } 1109 1110 return xSubst; 1111 } 1112 1113 //----------------------------------------------------------------------------- 1114 css::uno::Reference< css::container::XNameAccess > PathSettings::fa_getCfgOld() 1115 { 1116 const static ::rtl::OUString CFG_NODE_OLD = ::rtl::OUString::createFromAscii("org.openoffice.Office.Common/Path/Current"); 1117 1118 // SAFE -> 1119 ReadGuard aReadLock(m_aLock); 1120 css::uno::Reference< css::lang::XMultiServiceFactory > xSMGR = m_xSMGR; 1121 css::uno::Reference< css::container::XNameAccess > xCfg = m_xCfgOld; 1122 aReadLock.unlock(); 1123 // <- SAFE 1124 1125 if (! xCfg.is()) 1126 { 1127 xCfg = css::uno::Reference< css::container::XNameAccess >( 1128 ::comphelper::ConfigurationHelper::openConfig( 1129 xSMGR, 1130 CFG_NODE_OLD, 1131 ::comphelper::ConfigurationHelper::E_STANDARD), // not readonly! Sometimes we need write access there !!! 1132 css::uno::UNO_QUERY_THROW); 1133 1134 // SAFE -> 1135 WriteGuard aWriteLock(m_aLock); 1136 m_xCfgOld = xCfg; 1137 aWriteLock.unlock(); 1138 } 1139 1140 return xCfg; 1141 } 1142 1143 //----------------------------------------------------------------------------- 1144 css::uno::Reference< css::container::XNameAccess > PathSettings::fa_getCfgNew() 1145 { 1146 const static ::rtl::OUString CFG_NODE_NEW = ::rtl::OUString::createFromAscii("org.openoffice.Office.Paths/Paths"); 1147 1148 // SAFE -> 1149 ReadGuard aReadLock(m_aLock); 1150 css::uno::Reference< css::lang::XMultiServiceFactory > xSMGR = m_xSMGR; 1151 css::uno::Reference< css::container::XNameAccess > xCfg = m_xCfgNew; 1152 aReadLock.unlock(); 1153 // <- SAFE 1154 1155 if (! xCfg.is()) 1156 { 1157 xCfg = css::uno::Reference< css::container::XNameAccess >( 1158 ::comphelper::ConfigurationHelper::openConfig( 1159 xSMGR, 1160 CFG_NODE_NEW, 1161 ::comphelper::ConfigurationHelper::E_STANDARD), 1162 css::uno::UNO_QUERY_THROW); 1163 1164 // SAFE -> 1165 WriteGuard aWriteLock(m_aLock); 1166 m_xCfgNew = xCfg; 1167 aWriteLock.unlock(); 1168 1169 css::uno::Reference< css::util::XChangesNotifier > xBroadcaster(xCfg, css::uno::UNO_QUERY_THROW); 1170 xBroadcaster->addChangesListener(static_cast< css::util::XChangesListener* >(this)); 1171 } 1172 1173 return xCfg; 1174 } 1175 1176 } // namespace framework 1177 1178 /* vim: set noet sw=4 ts=4: */ 1179