merge the formfield patch from ooo-build
[ooovba.git] / framework / source / services / pathsettings.cxx
blob8871fea73456488b77a69a45dfb524d0231de6ad
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: pathsettings.cxx,v $
10 * $Revision: 1.12 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_framework.hxx"
33 // ______________________________________________
34 // my own includes
36 /** Attention: stl headers must(!) be included at first. Otherwhise it can make trouble
37 with solaris headers ...
39 #include <vector>
40 #include <services/pathsettings.hxx>
41 #include <threadhelp/readguard.hxx>
42 #include <threadhelp/writeguard.hxx>
43 #include <services.h>
45 // ______________________________________________
46 // interface includes
47 #include <com/sun/star/beans/Property.hpp>
48 #include <com/sun/star/beans/XProperty.hpp>
49 #include <com/sun/star/beans/PropertyAttribute.hpp>
50 #include <com/sun/star/container/XContainer.hpp>
51 #include <com/sun/star/beans/XPropertySet.hpp>
52 #include <com/sun/star/util/XChangesNotifier.hpp>
54 // ______________________________________________
55 // includes of other projects
56 #include <tools/urlobj.hxx>
57 #include <rtl/ustrbuf.hxx>
58 #include <rtl/logfile.hxx>
60 #include <comphelper/configurationhelper.hxx>
61 #include <unotools/configpathes.hxx>
63 // ______________________________________________
64 // non exported const
66 #define CFG_READONLY_DEFAULT sal_False
68 const ::rtl::OUString CFGPROP_INTERNALPATHES = ::rtl::OUString::createFromAscii("InternalPaths");
69 const ::rtl::OUString CFGPROP_USERPATHES = ::rtl::OUString::createFromAscii("UserPaths" );
70 const ::rtl::OUString CFGPROP_WRITEPATH = ::rtl::OUString::createFromAscii("WritePath" );
71 const ::rtl::OUString CFGPROP_ISSINGLEPATH = ::rtl::OUString::createFromAscii("IsSinglePath" );
74 0 : old style "Template" string using ";" as seperator
75 1 : internal paths "Template_internal" string list
76 2 : user paths "Template_user" string list
77 3 : write path "Template_write" string
80 const ::rtl::OUString POSTFIX_INTERNAL_PATHES = ::rtl::OUString::createFromAscii("_internal");
81 const ::rtl::OUString POSTFIX_USER_PATHES = ::rtl::OUString::createFromAscii("_user" );
82 const ::rtl::OUString POSTFIX_WRITE_PATH = ::rtl::OUString::createFromAscii("_writable");
84 const sal_Int32 IDGROUP_OLDSTYLE = 0;
85 const sal_Int32 IDGROUP_INTERNAL_PATHES = 1;
86 const sal_Int32 IDGROUP_USER_PATHES = 2;
87 const sal_Int32 IDGROUP_WRITE_PATH = 3;
89 const sal_Int32 IDGROUP_COUNT = 4;
91 sal_Int32 impl_getPropGroup(sal_Int32 nID)
93 return (nID % IDGROUP_COUNT);
96 // ______________________________________________
97 // namespace
99 namespace framework
102 //-----------------------------------------------------------------------------
103 // XInterface, XTypeProvider, XServiceInfo
105 DEFINE_XINTERFACE_7 ( PathSettings ,
106 OWeakObject ,
107 DIRECT_INTERFACE ( css::lang::XTypeProvider ),
108 DIRECT_INTERFACE ( css::lang::XServiceInfo ),
109 DERIVED_INTERFACE( css::lang::XEventListener, css::util::XChangesListener),
110 DIRECT_INTERFACE ( css::util::XChangesListener ),
111 DIRECT_INTERFACE ( css::beans::XPropertySet ),
112 DIRECT_INTERFACE ( css::beans::XFastPropertySet ),
113 DIRECT_INTERFACE ( css::beans::XMultiPropertySet )
116 DEFINE_XTYPEPROVIDER_7 ( PathSettings ,
117 css::lang::XTypeProvider ,
118 css::lang::XServiceInfo ,
119 css::lang::XEventListener ,
120 css::util::XChangesListener ,
121 css::beans::XPropertySet ,
122 css::beans::XFastPropertySet ,
123 css::beans::XMultiPropertySet
126 DEFINE_XSERVICEINFO_ONEINSTANCESERVICE ( PathSettings ,
127 ::cppu::OWeakObject ,
128 SERVICENAME_PATHSETTINGS ,
129 IMPLEMENTATIONNAME_PATHSETTINGS
132 DEFINE_INIT_SERVICE ( PathSettings,
134 /*Attention
135 I think we don't need any mutex or lock here ... because we are called by our own static method impl_createInstance()
136 to create a new instance of this class by our own supported service factory.
137 see macro DEFINE_XSERVICEINFO_MULTISERVICE and "impl_initService()" for further informations!
140 // fill cache
141 impl_readAll();
145 //-----------------------------------------------------------------------------
146 PathSettings::PathSettings( const css::uno::Reference< css::lang::XMultiServiceFactory >& xSMGR )
147 // Init baseclasses first
148 // Attention: Don't change order of initialization!
149 // ThreadHelpBase is a struct with a lock as member. We can't use a lock as direct member!
150 // We must garant right initialization and a valid value of this to initialize other baseclasses!
151 : ThreadHelpBase()
152 , ::cppu::OBroadcastHelperVar< ::cppu::OMultiTypeInterfaceContainerHelper, ::cppu::OMultiTypeInterfaceContainerHelper::keyType >(m_aLock.getShareableOslMutex())
153 , ::cppu::OPropertySetHelper(*(static_cast< ::cppu::OBroadcastHelper* >(this)))
154 , ::cppu::OWeakObject()
155 // Init member
156 , m_xSMGR (xSMGR)
157 , m_pPropHelp(0 )
158 , m_bIgnoreEvents(sal_False)
160 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "framework", "Ocke.Janssen@sun.com", "PathSettings::PathSettings" );
163 //-----------------------------------------------------------------------------
164 PathSettings::~PathSettings()
166 if (m_pPropHelp)
167 delete m_pPropHelp;
170 //-----------------------------------------------------------------------------
171 void SAL_CALL PathSettings::changesOccurred(const css::util::ChangesEvent& aEvent)
172 throw (css::uno::RuntimeException)
174 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "framework", "Ocke.Janssen@sun.com", "PathSettings::changesOccurred" );
176 if (m_bIgnoreEvents)
177 return;
180 sal_Int32 c = aEvent.Changes.getLength();
181 sal_Int32 i = 0;
182 sal_Bool bUpdateDescriptor = sal_False;
184 for (i=0; i<c; ++i)
186 const css::util::ElementChange& aChange = aEvent.Changes[i];
188 ::rtl::OUString sChanged;
189 aChange.Accessor >>= sChanged;
191 ::rtl::OUString sPath = ::utl::extractFirstFromConfigurationPath(sChanged);
192 if (sPath.getLength())
194 PathSettings::EChangeOp eOp = impl_updatePath(sPath, sal_True);
195 if (
196 (eOp == PathSettings::E_ADDED ) ||
197 (eOp == PathSettings::E_REMOVED)
199 bUpdateDescriptor = sal_True;
203 if (bUpdateDescriptor)
204 impl_rebuildPropertyDescriptor();
207 //-----------------------------------------------------------------------------
208 void SAL_CALL PathSettings::disposing(const css::lang::EventObject& aSource)
209 throw(css::uno::RuntimeException)
211 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "framework", "Ocke.Janssen@sun.com", "PathSettings::disposing" );
212 // SAFE ->
213 WriteGuard aWriteLock(m_aLock);
215 if (aSource.Source == m_xCfgNew)
216 m_xCfgNew.clear();
218 aWriteLock.unlock();
219 // <- SAFE
222 //-----------------------------------------------------------------------------
223 void PathSettings::impl_readAll()
225 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "framework", "Ocke.Janssen@sun.com", "PathSettings::impl_readAll" );
226 RTL_LOGFILE_CONTEXT(aLog, "framework (as96863) ::PathSettings::load config (all)");
228 // TODO think about me
229 css::uno::Reference< css::container::XNameAccess > xCfg = fa_getCfgNew();
230 css::uno::Sequence< ::rtl::OUString > lPaths = xCfg->getElementNames();
232 sal_Int32 c = lPaths.getLength();
233 sal_Int32 i = 0;
235 for (i=0; i<c; ++i)
237 const ::rtl::OUString& sPath = lPaths[i];
238 impl_updatePath(sPath, sal_False);
241 impl_rebuildPropertyDescriptor();
244 //-----------------------------------------------------------------------------
245 // NO substitution here ! It's done outside ...
246 OUStringList PathSettings::impl_readOldFormat(const ::rtl::OUString& sPath)
248 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "framework", "Ocke.Janssen@sun.com", "PathSettings::impl_readOldFormat" );
249 css::uno::Reference< css::container::XNameAccess > xCfg = fa_getCfgOld();
250 css::uno::Any aVal = xCfg->getByName(sPath);
252 ::rtl::OUString sStringVal;
253 css::uno::Sequence< ::rtl::OUString > lStringListVal;
254 OUStringList aPathVal;
256 if (aVal >>= sStringVal)
258 aPathVal.push_back(sStringVal);
260 else
261 if (aVal >>= lStringListVal)
263 aPathVal << lStringListVal;
266 return aPathVal;
269 //-----------------------------------------------------------------------------
270 // NO substitution here ! It's done outside ...
271 PathSettings::PathInfo PathSettings::impl_readNewFormat(const ::rtl::OUString& sPath)
273 css::uno::Reference< css::container::XNameAccess > xCfg = fa_getCfgNew();
275 // get access to the "queried" path
276 css::uno::Reference< css::container::XNameAccess > xPath;
277 xCfg->getByName(sPath) >>= xPath;
279 PathSettings::PathInfo aPathVal;
281 // read internal path list
282 css::uno::Reference< css::container::XNameAccess > xIPath;
283 xPath->getByName(CFGPROP_INTERNALPATHES) >>= xIPath;
284 aPathVal.lInternalPaths << xIPath->getElementNames();
286 // read user defined path list
287 aPathVal.lUserPaths << xPath->getByName(CFGPROP_USERPATHES);
289 // read the writeable path
290 xPath->getByName(CFGPROP_WRITEPATH) >>= aPathVal.sWritePath;
292 // read state props
293 xPath->getByName(CFGPROP_ISSINGLEPATH) >>= aPathVal.bIsSinglePath;
295 // analyze finalized/mandatory states
296 aPathVal.bIsReadonly = sal_False;
297 css::uno::Reference< css::beans::XProperty > xInfo(xPath, css::uno::UNO_QUERY);
298 if (xInfo.is())
300 css::beans::Property aInfo = xInfo->getAsProperty();
301 sal_Bool bFinalized = ((aInfo.Attributes & css::beans::PropertyAttribute::READONLY ) == css::beans::PropertyAttribute::READONLY );
302 //sal_Bool bMandatory = ((aInfo.Attributes & css::beans::PropertyAttribute::REMOVEABLE) != css::beans::PropertyAttribute::REMOVEABLE);
304 // Note: Till we support finalized / mandatory on our API more in detail we handle
305 // all states simple as READONLY ! But because all realy needed pathes are "mandatory" by default
306 // we have to handle "finalized" as the real "readonly" indicator .
307 aPathVal.bIsReadonly = bFinalized;
310 return aPathVal;
313 //-----------------------------------------------------------------------------
314 void PathSettings::impl_storePath(const PathSettings::PathInfo& aPath)
316 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "framework", "Ocke.Janssen@sun.com", "PathSettings::impl_storePath" );
317 m_bIgnoreEvents = sal_True;
319 css::uno::Reference< css::container::XNameAccess > xCfgNew = fa_getCfgNew();
320 css::uno::Reference< css::container::XNameAccess > xCfgOld = fa_getCfgOld();
322 // try to replace path-parts with well known and uspported variables.
323 // So an office can be moved easialy to another location without loosing
324 // it's related pathes.
325 PathInfo aResubstPath(aPath);
326 impl_subst(aResubstPath, sal_True);
328 // update new configuration
329 if (! aResubstPath.bIsSinglePath)
331 ::comphelper::ConfigurationHelper::writeRelativeKey(xCfgNew,
332 aResubstPath.sPathName,
333 CFGPROP_USERPATHES,
334 css::uno::makeAny(aResubstPath.lUserPaths.getAsConstList()));
337 ::comphelper::ConfigurationHelper::writeRelativeKey(xCfgNew,
338 aResubstPath.sPathName,
339 CFGPROP_WRITEPATH,
340 css::uno::makeAny(aResubstPath.sWritePath));
342 ::comphelper::ConfigurationHelper::flush(xCfgNew);
344 // remove the whole path from the old configuration !
345 // Otherwise we cant make sure that the diff between new and old configuration
346 // on loading time realy represent an user setting !!!
348 // Check if the given path exists inside the old configuration.
349 // Because our new configuration knows more then the list of old pathes ... !
350 if (xCfgOld->hasByName(aResubstPath.sPathName))
352 css::uno::Reference< css::beans::XPropertySet > xProps(xCfgOld, css::uno::UNO_QUERY_THROW);
353 xProps->setPropertyValue(aResubstPath.sPathName, css::uno::Any());
354 ::comphelper::ConfigurationHelper::flush(xCfgOld);
357 m_bIgnoreEvents = sal_False;
360 //-----------------------------------------------------------------------------
361 #ifdef MIGRATE_OLD_USER_PATHES
362 void PathSettings::impl_mergeOldUserPaths( PathSettings::PathInfo& rPath,
363 const OUStringList& lOld )
365 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "framework", "Ocke.Janssen@sun.com", "PathSettings::impl_mergeOldUserPaths" );
366 OUStringList::const_iterator pIt;
367 for ( pIt = lOld.begin();
368 pIt != lOld.end() ;
369 ++pIt )
371 const ::rtl::OUString& sOld = *pIt;
373 if (rPath.bIsSinglePath)
375 LOG_ASSERT2(lOld.size()>1, "PathSettings::impl_mergeOldUserPaths()", "Single path has more then one path value inside old configuration (Common.xcu)!")
376 if (! rPath.sWritePath.equals(sOld))
377 rPath.sWritePath = sOld;
379 else
381 if (
382 ( rPath.lInternalPaths.findConst(sOld) == rPath.lInternalPaths.end()) &&
383 ( rPath.lUserPaths.findConst(sOld) == rPath.lUserPaths.end() ) &&
384 (! rPath.sWritePath.equals(sOld) )
386 rPath.lUserPaths.push_back(sOld);
390 #endif // MIGRATE_OLD_USER_PATHES
392 //-----------------------------------------------------------------------------
393 PathSettings::EChangeOp PathSettings::impl_updatePath(const ::rtl::OUString& sPath ,
394 sal_Bool bNotifyListener)
396 // SAFE ->
397 WriteGuard aWriteLock(m_aLock);
399 PathSettings::PathInfo* pPathOld = 0;
400 PathSettings::PathInfo* pPathNew = 0;
401 PathSettings::EChangeOp eOp = PathSettings::E_UNDEFINED;
402 PathSettings::PathInfo aPath;
406 aPath = impl_readNewFormat(sPath);
407 aPath.sPathName = sPath;
408 // replace all might existing variables with real values
409 // Do it before these old pathes will be compared against the
410 // new path configuration. Otherwise some striungs uses different variables ... but substitution
411 // will produce strings with same content (because some variables are redundant!)
412 impl_subst(aPath, sal_False);
414 catch(const css::uno::RuntimeException& exRun)
415 { throw exRun; }
416 catch(const css::container::NoSuchElementException&)
417 { eOp = PathSettings::E_REMOVED; }
418 catch(const css::uno::Exception& exAny)
419 { throw exAny; }
421 #ifdef MIGRATE_OLD_USER_PATHES
424 // migration of old user defined values on demand
425 // can be disabled for a new major
426 OUStringList lOldVals = impl_readOldFormat(sPath);
427 // replace all might existing variables with real values
428 // Do it before these old pathes will be compared against the
429 // new path configuration. Otherwise some striungs uses different variables ... but substitution
430 // will produce strings with same content (because some variables are redundant!)
431 impl_subst(lOldVals, fa_getSubstitution(), sal_False);
432 impl_mergeOldUserPaths(aPath, lOldVals);
434 catch(const css::uno::RuntimeException& exRun)
435 { throw exRun; }
436 // Normal(!) exceptions can be ignored!
437 // E.g. in case an addon installs a new path, which was not well known for an OOo 1.x installation
438 // we cant find a value for it inside the "old" configuration. So a NoSuchElementException
439 // will be normal .-)
440 catch(const css::uno::Exception&)
442 #endif // MIGRATE_OLD_USER_PATHES
444 PathSettings::PathHash::iterator pPath = m_lPaths.find(sPath);
445 if (eOp == PathSettings::E_UNDEFINED)
447 if (pPath != m_lPaths.end())
448 eOp = PathSettings::E_CHANGED;
449 else
450 eOp = PathSettings::E_ADDED;
453 switch(eOp)
455 case PathSettings::E_ADDED :
457 if (bNotifyListener)
459 pPathOld = 0;
460 pPathNew = &aPath;
461 impl_notifyPropListener(eOp, sPath, pPathOld, pPathNew);
463 m_lPaths[sPath] = aPath;
465 break;
467 case PathSettings::E_CHANGED :
469 if (bNotifyListener)
471 pPathOld = &(pPath->second);
472 pPathNew = &aPath;
473 impl_notifyPropListener(eOp, sPath, pPathOld, pPathNew);
475 m_lPaths[sPath] = aPath;
477 break;
479 case PathSettings::E_REMOVED :
481 if (pPath != m_lPaths.end())
483 if (bNotifyListener)
485 pPathOld = &(pPath->second);
486 pPathNew = 0;
487 impl_notifyPropListener(eOp, sPath, pPathOld, pPathNew);
489 m_lPaths.erase(pPath);
492 break;
494 default: // to let compiler be happy
495 break;
498 return eOp;
501 //-----------------------------------------------------------------------------
502 css::uno::Sequence< sal_Int32 > PathSettings::impl_mapPathName2IDList(const ::rtl::OUString& sPath)
504 ::rtl::OUString sOldStyleProp = sPath;
505 ::rtl::OUString sInternalProp = sPath+POSTFIX_INTERNAL_PATHES;
506 ::rtl::OUString sUserProp = sPath+POSTFIX_USER_PATHES;
507 ::rtl::OUString sWriteProp = sPath+POSTFIX_WRITE_PATH;
509 // Attention: The default set of IDs is fix and must follow these schema.
510 // Otherwhise the outside code ant work for new added properties.
511 // Why ?
512 // The outside code must fire N events for every changed property.
513 // And the knowing about packaging of variables of the structure PathInfo
514 // follow these group IDs ! But if such ID isnt in the range of [0..IDGROUP_COUNT]
515 // the outside cant determine the right group ... and cant fire the right events .-)
517 css::uno::Sequence< sal_Int32 > lIDs(IDGROUP_COUNT);
518 lIDs[0] = IDGROUP_OLDSTYLE ;
519 lIDs[1] = IDGROUP_INTERNAL_PATHES;
520 lIDs[2] = IDGROUP_USER_PATHES ;
521 lIDs[3] = IDGROUP_WRITE_PATH ;
523 sal_Int32 c = m_lPropDesc.getLength();
524 sal_Int32 i = 0;
525 for (i=0; i<c; ++i)
527 const css::beans::Property& rProp = m_lPropDesc[i];
529 if (rProp.Name.equals(sOldStyleProp))
530 lIDs[IDGROUP_OLDSTYLE] = rProp.Handle;
531 else
532 if (rProp.Name.equals(sInternalProp))
533 lIDs[IDGROUP_INTERNAL_PATHES] = rProp.Handle;
534 else
535 if (rProp.Name.equals(sUserProp))
536 lIDs[IDGROUP_USER_PATHES] = rProp.Handle;
537 else
538 if (rProp.Name.equals(sWriteProp))
539 lIDs[IDGROUP_WRITE_PATH] = rProp.Handle;
542 return lIDs;
545 //-----------------------------------------------------------------------------
546 void PathSettings::impl_notifyPropListener( PathSettings::EChangeOp /*eOp*/ ,
547 const ::rtl::OUString& sPath ,
548 const PathSettings::PathInfo* pPathOld,
549 const PathSettings::PathInfo* pPathNew)
551 css::uno::Sequence< sal_Int32 > lHandles(1);
552 css::uno::Sequence< css::uno::Any > lOldVals(1);
553 css::uno::Sequence< css::uno::Any > lNewVals(1);
555 css::uno::Sequence< sal_Int32 > lIDs = impl_mapPathName2IDList(sPath);
556 sal_Int32 c = lIDs.getLength();
557 sal_Int32 i = 0;
558 sal_Int32 nMaxID = m_lPropDesc.getLength()-1;
559 for (i=0; i<c; ++i)
561 sal_Int32 nID = lIDs[i];
563 if (
564 (nID < 0 ) ||
565 (nID > nMaxID)
567 continue;
569 lHandles[0] = nID;
570 switch(impl_getPropGroup(nID))
572 case IDGROUP_OLDSTYLE :
574 if (pPathOld)
576 ::rtl::OUString sVal = impl_convertPath2OldStyle(*pPathOld);
577 lOldVals[0] <<= sVal;
579 if (pPathNew)
581 ::rtl::OUString sVal = impl_convertPath2OldStyle(*pPathNew);
582 lNewVals[0] <<= sVal;
585 break;
587 case IDGROUP_INTERNAL_PATHES :
589 if (pPathOld)
590 lOldVals[0] <<= pPathOld->lInternalPaths.getAsConstList();
591 if (pPathNew)
592 lNewVals[0] <<= pPathNew->lInternalPaths.getAsConstList();
594 break;
596 case IDGROUP_USER_PATHES :
598 if (pPathOld)
599 lOldVals[0] <<= pPathOld->lUserPaths.getAsConstList();
600 if (pPathNew)
601 lNewVals[0] <<= pPathNew->lUserPaths.getAsConstList();
603 break;
605 case IDGROUP_WRITE_PATH :
607 if (pPathOld)
608 lOldVals[0] <<= pPathOld->sWritePath;
609 if (pPathNew)
610 lNewVals[0] <<= pPathNew->sWritePath;
612 break;
615 fire(lHandles.getArray(),
616 lNewVals.getArray(),
617 lOldVals.getArray(),
619 sal_False);
623 //-----------------------------------------------------------------------------
624 void PathSettings::impl_subst( OUStringList& lVals ,
625 const css::uno::Reference< css::util::XStringSubstitution >& xSubst ,
626 sal_Bool bReSubst)
628 OUStringList::iterator pIt;
630 for ( pIt = lVals.begin();
631 pIt != lVals.end() ;
632 ++pIt )
634 const ::rtl::OUString& sOld = *pIt;
635 ::rtl::OUString sNew ;
636 if (bReSubst)
637 sNew = xSubst->reSubstituteVariables(sOld);
638 else
639 sNew = xSubst->substituteVariables(sOld, sal_False);
641 *pIt = sNew;
645 //-----------------------------------------------------------------------------
646 void PathSettings::impl_subst(PathSettings::PathInfo& aPath ,
647 sal_Bool bReSubst)
649 css::uno::Reference< css::util::XStringSubstitution > xSubst = fa_getSubstitution();
651 impl_subst(aPath.lInternalPaths, xSubst, bReSubst);
652 impl_subst(aPath.lUserPaths , xSubst, bReSubst);
653 if (bReSubst)
654 aPath.sWritePath = xSubst->reSubstituteVariables(aPath.sWritePath);
655 else
656 aPath.sWritePath = xSubst->substituteVariables(aPath.sWritePath, sal_False);
659 //-----------------------------------------------------------------------------
660 ::rtl::OUString PathSettings::impl_convertPath2OldStyle(const PathSettings::PathInfo& rPath) const
662 OUStringList::const_iterator pIt;
663 OUStringList lTemp;
664 lTemp.reserve(rPath.lInternalPaths.size() + rPath.lUserPaths.size() + 1);
666 for ( pIt = rPath.lInternalPaths.begin();
667 pIt != rPath.lInternalPaths.end() ;
668 ++pIt )
670 lTemp.push_back(*pIt);
672 for ( pIt = rPath.lUserPaths.begin();
673 pIt != rPath.lUserPaths.end() ;
674 ++pIt )
676 lTemp.push_back(*pIt);
679 if (rPath.sWritePath.getLength() > 0)
680 lTemp.push_back(rPath.sWritePath);
682 ::rtl::OUStringBuffer sPathVal(256);
683 for ( pIt = lTemp.begin();
684 pIt != lTemp.end() ;
687 sPathVal.append(*pIt);
688 ++pIt;
689 if (pIt != lTemp.end())
690 sPathVal.appendAscii(";");
693 return sPathVal.makeStringAndClear();
696 //-----------------------------------------------------------------------------
697 OUStringList PathSettings::impl_convertOldStyle2Path(const ::rtl::OUString& sOldStylePath) const
699 OUStringList lList;
700 sal_Int32 nToken = 0;
703 ::rtl::OUString sToken = sOldStylePath.getToken(0, ';', nToken);
704 if (sToken.getLength())
705 lList.push_back(sToken);
707 while(nToken >= 0);
709 return lList;
712 //-----------------------------------------------------------------------------
713 void PathSettings::impl_purgeKnownPaths(const PathSettings::PathInfo& rPath,
714 OUStringList& lList)
716 OUStringList::const_iterator pIt;
717 for ( pIt = rPath.lInternalPaths.begin();
718 pIt != rPath.lInternalPaths.end() ;
719 ++pIt )
721 const ::rtl::OUString& rItem = *pIt;
722 OUStringList::iterator pItem = lList.find(rItem);
723 if (pItem != lList.end())
724 lList.erase(pItem);
726 for ( pIt = rPath.lUserPaths.begin();
727 pIt != rPath.lUserPaths.end() ;
728 ++pIt )
730 const ::rtl::OUString& rItem = *pIt;
731 OUStringList::iterator pItem = lList.find(rItem);
732 if (pItem != lList.end())
733 lList.erase(pItem);
736 OUStringList::iterator pItem = lList.find(rPath.sWritePath);
737 if (pItem != lList.end())
738 lList.erase(pItem);
741 //-----------------------------------------------------------------------------
742 void PathSettings::impl_rebuildPropertyDescriptor()
744 // SAFE ->
745 WriteGuard aWriteLock(m_aLock);
747 sal_Int32 c = (sal_Int32)m_lPaths.size();
748 sal_Int32 i = 0;
749 m_lPropDesc.realloc(c*IDGROUP_COUNT);
751 PathHash::const_iterator pIt;
752 for ( pIt = m_lPaths.begin();
753 pIt != m_lPaths.end() ;
754 ++pIt )
756 const PathSettings::PathInfo& rPath = pIt->second;
757 css::beans::Property* pProp = 0;
759 pProp = &(m_lPropDesc[i]);
760 pProp->Name = rPath.sPathName;
761 pProp->Handle = i;
762 pProp->Type = ::getCppuType((::rtl::OUString*)0);
763 pProp->Attributes = css::beans::PropertyAttribute::BOUND;
764 if (rPath.bIsReadonly)
765 pProp->Attributes |= css::beans::PropertyAttribute::READONLY;
766 ++i;
768 pProp = &(m_lPropDesc[i]);
769 pProp->Name = rPath.sPathName+POSTFIX_INTERNAL_PATHES;
770 pProp->Handle = i;
771 pProp->Type = ::getCppuType((css::uno::Sequence< ::rtl::OUString >*)0);
772 pProp->Attributes = css::beans::PropertyAttribute::BOUND |
773 css::beans::PropertyAttribute::READONLY;
774 ++i;
776 pProp = &(m_lPropDesc[i]);
777 pProp->Name = rPath.sPathName+POSTFIX_USER_PATHES;
778 pProp->Handle = i;
779 pProp->Type = ::getCppuType((css::uno::Sequence< ::rtl::OUString >*)0);
780 pProp->Attributes = css::beans::PropertyAttribute::BOUND;
781 if (rPath.bIsReadonly)
782 pProp->Attributes |= css::beans::PropertyAttribute::READONLY;
783 ++i;
785 pProp = &(m_lPropDesc[i]);
786 pProp->Name = rPath.sPathName+POSTFIX_WRITE_PATH;
787 pProp->Handle = i;
788 pProp->Type = ::getCppuType((::rtl::OUString*)0);
789 pProp->Attributes = css::beans::PropertyAttribute::BOUND;
790 if (rPath.bIsReadonly)
791 pProp->Attributes |= css::beans::PropertyAttribute::READONLY;
792 ++i;
795 if (m_pPropHelp)
796 delete m_pPropHelp;
797 m_pPropHelp = new ::cppu::OPropertyArrayHelper(m_lPropDesc, sal_False); // false => not sorted ... must be done inside helper
799 aWriteLock.unlock();
800 // <- SAFE
803 //-----------------------------------------------------------------------------
804 css::uno::Any PathSettings::impl_getPathValue(sal_Int32 nID) const
806 const PathSettings::PathInfo* pPath = impl_getPathAccessConst(nID);
807 if (! pPath)
808 throw css::container::NoSuchElementException();
810 css::uno::Any aVal;
811 switch(impl_getPropGroup(nID))
813 case IDGROUP_OLDSTYLE :
815 ::rtl::OUString sVal = impl_convertPath2OldStyle(*pPath);
816 aVal <<= sVal;
818 break;
820 case IDGROUP_INTERNAL_PATHES :
822 aVal <<= pPath->lInternalPaths.getAsConstList();
824 break;
826 case IDGROUP_USER_PATHES :
828 aVal <<= pPath->lUserPaths.getAsConstList();
830 break;
832 case IDGROUP_WRITE_PATH :
834 aVal <<= pPath->sWritePath;
836 break;
839 return aVal;
842 //-----------------------------------------------------------------------------
843 void PathSettings::impl_setPathValue( sal_Int32 nID ,
844 const css::uno::Any& aVal)
846 PathSettings::PathInfo* pOrgPath = impl_getPathAccess(nID);
847 if (! pOrgPath)
848 throw css::container::NoSuchElementException();
850 // We work on a copied path ... so we can be sure that errors during this operation
851 // does not make our internal cache invalid .-)
852 PathSettings::PathInfo aChangePath(*pOrgPath);
854 switch(impl_getPropGroup(nID))
856 case IDGROUP_OLDSTYLE :
858 ::rtl::OUString sVal;
859 aVal >>= sVal;
860 OUStringList lList = impl_convertOldStyle2Path(sVal);
861 impl_purgeKnownPaths(aChangePath, lList);
862 if (! impl_isValidPath(lList))
863 throw css::lang::IllegalArgumentException();
865 if (aChangePath.bIsSinglePath)
867 LOG_ASSERT2(lList.size()>1, "PathSettings::impl_setPathValue()", "You try to set more then path value for a defined SINGLE_PATH!")
868 if ( !lList.empty() )
869 aChangePath.sWritePath = *(lList.begin());
870 else
871 aChangePath.sWritePath = ::rtl::OUString();
873 else
875 OUStringList::const_iterator pIt;
876 for ( pIt = lList.begin();
877 pIt != lList.end() ;
878 ++pIt )
880 aChangePath.lUserPaths.push_back(*pIt);
884 break;
886 case IDGROUP_INTERNAL_PATHES :
888 if (aChangePath.bIsSinglePath)
890 ::rtl::OUStringBuffer sMsg(256);
891 sMsg.appendAscii("The path '" );
892 sMsg.append (aChangePath.sPathName);
893 sMsg.appendAscii("' is defined as SINGLE_PATH. It's sub set of internal pathes cant be set.");
894 throw css::uno::Exception(sMsg.makeStringAndClear(),
895 static_cast< ::cppu::OWeakObject* >(this));
898 OUStringList lList;
899 lList << aVal;
900 if (! impl_isValidPath(lList))
901 throw css::lang::IllegalArgumentException();
902 aChangePath.lInternalPaths = lList;
904 break;
906 case IDGROUP_USER_PATHES :
908 if (aChangePath.bIsSinglePath)
910 ::rtl::OUStringBuffer sMsg(256);
911 sMsg.appendAscii("The path '" );
912 sMsg.append (aChangePath.sPathName);
913 sMsg.appendAscii("' is defined as SINGLE_PATH. It's sub set of internal pathes cant be set.");
914 throw css::uno::Exception(sMsg.makeStringAndClear(),
915 static_cast< ::cppu::OWeakObject* >(this));
918 OUStringList lList;
919 lList << aVal;
920 if (! impl_isValidPath(lList))
921 throw css::lang::IllegalArgumentException();
922 aChangePath.lUserPaths = lList;
924 break;
926 case IDGROUP_WRITE_PATH :
928 ::rtl::OUString sVal;
929 aVal >>= sVal;
930 if (! impl_isValidPath(sVal))
931 throw css::lang::IllegalArgumentException();
932 aChangePath.sWritePath = sVal;
934 break;
937 // TODO check if path has at least one path value set
938 // At least it depends from the feature using this path, if an empty path list is allowed.
940 if (impl_isPathEmpty(aChangePath))
942 ::rtl::OUStringBuffer sMsg(256);
943 sMsg.appendAscii("The path '" );
944 sMsg.append (aChangePath.sPathName);
945 sMsg.appendAscii("' is empty now ... Not a real good idea.");
946 throw css::uno::Exception(sMsg.makeStringAndClear(),
947 static_cast< ::cppu::OWeakObject* >(this));
951 // first we should try to store the changed (copied!) path ...
952 // In case an error occure on saving time an exception is thrown ...
953 // If no exception occures we can update our internal cache (means
954 // we can overwrite pOrgPath !
955 impl_storePath(aChangePath);
956 pOrgPath->takeOver(aChangePath);
959 //-----------------------------------------------------------------------------
960 sal_Bool PathSettings::impl_isValidPath(const OUStringList& lPath) const
962 OUStringList::const_iterator pIt;
963 for ( pIt = lPath.begin();
964 pIt != lPath.end() ;
965 ++pIt )
967 const ::rtl::OUString& rVal = *pIt;
968 if (! impl_isValidPath(rVal))
969 return sal_False;
972 return sal_True;
975 //-----------------------------------------------------------------------------
976 sal_Bool PathSettings::impl_isValidPath(const ::rtl::OUString& sPath) const
978 return (! INetURLObject(sPath).HasError());
981 //-----------------------------------------------------------------------------
982 ::rtl::OUString impl_extractBaseFromPropName(const ::rtl::OUString& sPropName)
984 sal_Int32 i = -1;
986 i = sPropName.indexOf(POSTFIX_INTERNAL_PATHES);
987 if (i > -1)
988 return sPropName.copy(0, i);
989 i = sPropName.indexOf(POSTFIX_USER_PATHES);
990 if (i > -1)
991 return sPropName.copy(0, i);
992 i = sPropName.indexOf(POSTFIX_WRITE_PATH);
993 if (i > -1)
994 return sPropName.copy(0, i);
996 return sPropName;
999 //-----------------------------------------------------------------------------
1000 PathSettings::PathInfo* PathSettings::impl_getPathAccess(sal_Int32 nHandle)
1002 // SAFE ->
1003 ReadGuard aReadLock(m_aLock);
1005 if (nHandle > (m_lPropDesc.getLength()-1))
1006 return 0;
1008 const css::beans::Property& rProp = m_lPropDesc[nHandle];
1009 ::rtl::OUString sProp = impl_extractBaseFromPropName(rProp.Name);
1010 PathSettings::PathHash::iterator rPath = m_lPaths.find(sProp);
1012 if (rPath != m_lPaths.end())
1013 return &(rPath->second);
1015 return 0;
1016 // <- SAFE
1019 //-----------------------------------------------------------------------------
1020 const PathSettings::PathInfo* PathSettings::impl_getPathAccessConst(sal_Int32 nHandle) const
1022 // SAFE ->
1023 ReadGuard aReadLock(m_aLock);
1025 if (nHandle > (m_lPropDesc.getLength()-1))
1026 return 0;
1028 const css::beans::Property& rProp = m_lPropDesc[nHandle];
1029 ::rtl::OUString sProp = impl_extractBaseFromPropName(rProp.Name);
1030 PathSettings::PathHash::const_iterator rPath = m_lPaths.find(sProp);
1032 if (rPath != m_lPaths.end())
1033 return &(rPath->second);
1035 return 0;
1036 // <- SAFE
1039 //-----------------------------------------------------------------------------
1040 sal_Bool SAL_CALL PathSettings::convertFastPropertyValue( css::uno::Any& aConvertedValue,
1041 css::uno::Any& aOldValue ,
1042 sal_Int32 nHandle ,
1043 const css::uno::Any& aValue )
1044 throw(css::lang::IllegalArgumentException)
1046 // throws NoSuchElementException !
1047 css::uno::Any aCurrentVal = impl_getPathValue(nHandle);
1049 return PropHelper::willPropertyBeChanged(
1050 aCurrentVal,
1051 aValue,
1052 aOldValue,
1053 aConvertedValue);
1056 //-----------------------------------------------------------------------------
1057 void SAL_CALL PathSettings::setFastPropertyValue_NoBroadcast( sal_Int32 nHandle,
1058 const css::uno::Any& aValue )
1059 throw(css::uno::Exception)
1061 // throws NoSuchElement- and IllegalArgumentException !
1062 impl_setPathValue(nHandle, aValue);
1065 //-----------------------------------------------------------------------------
1066 void SAL_CALL PathSettings::getFastPropertyValue(css::uno::Any& aValue ,
1067 sal_Int32 nHandle) const
1069 aValue = impl_getPathValue(nHandle);
1072 //-----------------------------------------------------------------------------
1073 ::cppu::IPropertyArrayHelper& SAL_CALL PathSettings::getInfoHelper()
1075 return *m_pPropHelp;
1078 //-----------------------------------------------------------------------------
1079 css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL PathSettings::getPropertySetInfo()
1080 throw(css::uno::RuntimeException)
1082 return css::uno::Reference< css::beans::XPropertySetInfo >(createPropertySetInfo(getInfoHelper()));
1085 //-----------------------------------------------------------------------------
1086 css::uno::Reference< css::util::XStringSubstitution > PathSettings::fa_getSubstitution()
1088 // SAFE ->
1089 ReadGuard aReadLock(m_aLock);
1090 css::uno::Reference< css::lang::XMultiServiceFactory > xSMGR = m_xSMGR;
1091 css::uno::Reference< css::util::XStringSubstitution > xSubst = m_xSubstitution;
1092 aReadLock.unlock();
1093 // <- SAFE
1095 if (! xSubst.is())
1097 // create the needed substitution service.
1098 // We must replace all used variables inside readed path values.
1099 // In case we can't do so ... the whole office can't work realy.
1100 // That's why it seams to be OK to throw a RuntimeException then.
1101 xSubst = css::uno::Reference< css::util::XStringSubstitution >(
1102 xSMGR->createInstance(SERVICENAME_SUBSTITUTEPATHVARIABLES),
1103 css::uno::UNO_QUERY_THROW);
1105 // SAFE ->
1106 WriteGuard aWriteLock(m_aLock);
1107 m_xSubstitution = xSubst;
1108 aWriteLock.unlock();
1111 return xSubst;
1114 //-----------------------------------------------------------------------------
1115 css::uno::Reference< css::container::XNameAccess > PathSettings::fa_getCfgOld()
1117 const static ::rtl::OUString CFG_NODE_OLD = ::rtl::OUString::createFromAscii("org.openoffice.Office.Common/Path/Current");
1119 // SAFE ->
1120 ReadGuard aReadLock(m_aLock);
1121 css::uno::Reference< css::lang::XMultiServiceFactory > xSMGR = m_xSMGR;
1122 css::uno::Reference< css::container::XNameAccess > xCfg = m_xCfgOld;
1123 aReadLock.unlock();
1124 // <- SAFE
1126 if (! xCfg.is())
1128 xCfg = css::uno::Reference< css::container::XNameAccess >(
1129 ::comphelper::ConfigurationHelper::openConfig(
1130 xSMGR,
1131 CFG_NODE_OLD,
1132 ::comphelper::ConfigurationHelper::E_STANDARD), // not readonly! Somtimes we need write access there !!!
1133 css::uno::UNO_QUERY_THROW);
1135 // SAFE ->
1136 WriteGuard aWriteLock(m_aLock);
1137 m_xCfgOld = xCfg;
1138 aWriteLock.unlock();
1141 return xCfg;
1144 //-----------------------------------------------------------------------------
1145 css::uno::Reference< css::container::XNameAccess > PathSettings::fa_getCfgNew()
1147 const static ::rtl::OUString CFG_NODE_NEW = ::rtl::OUString::createFromAscii("org.openoffice.Office.Paths/Paths");
1149 // SAFE ->
1150 ReadGuard aReadLock(m_aLock);
1151 css::uno::Reference< css::lang::XMultiServiceFactory > xSMGR = m_xSMGR;
1152 css::uno::Reference< css::container::XNameAccess > xCfg = m_xCfgNew;
1153 aReadLock.unlock();
1154 // <- SAFE
1156 if (! xCfg.is())
1158 xCfg = css::uno::Reference< css::container::XNameAccess >(
1159 ::comphelper::ConfigurationHelper::openConfig(
1160 xSMGR,
1161 CFG_NODE_NEW,
1162 ::comphelper::ConfigurationHelper::E_STANDARD),
1163 css::uno::UNO_QUERY_THROW);
1165 // SAFE ->
1166 WriteGuard aWriteLock(m_aLock);
1167 m_xCfgNew = xCfg;
1168 aWriteLock.unlock();
1170 css::uno::Reference< css::util::XChangesNotifier > xBroadcaster(xCfg, css::uno::UNO_QUERY_THROW);
1171 xBroadcaster->addChangesListener(static_cast< css::util::XChangesListener* >(this));
1174 return xCfg;
1177 } // namespace framework