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