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