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