summaryrefslogtreecommitdiff
path: root/framework/source/services/pathsettings.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'framework/source/services/pathsettings.cxx')
-rw-r--r--framework/source/services/pathsettings.cxx1187
1 files changed, 1187 insertions, 0 deletions
diff --git a/framework/source/services/pathsettings.cxx b/framework/source/services/pathsettings.cxx
new file mode 100644
index 000000000000..baf3a785c5e6
--- /dev/null
+++ b/framework/source/services/pathsettings.cxx
@@ -0,0 +1,1187 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_framework.hxx"
+// ______________________________________________
+// my own includes
+
+/** Attention: stl headers must(!) be included at first. Otherwhise it can make trouble
+ with solaris headers ...
+*/
+#include <vector>
+#include <services/pathsettings.hxx>
+#include <threadhelp/readguard.hxx>
+#include <threadhelp/writeguard.hxx>
+#include <services.h>
+
+// ______________________________________________
+// interface includes
+#include <com/sun/star/beans/Property.hpp>
+#include <com/sun/star/beans/XProperty.hpp>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/container/XContainer.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/util/XChangesNotifier.hpp>
+
+// ______________________________________________
+// includes of other projects
+#include <tools/urlobj.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <rtl/logfile.hxx>
+
+#include <comphelper/configurationhelper.hxx>
+#include <unotools/configpathes.hxx>
+
+#include <fwkdllapi.h>
+
+// ______________________________________________
+// non exported const
+
+#define CFG_READONLY_DEFAULT sal_False
+
+const ::rtl::OUString CFGPROP_INTERNALPATHES = ::rtl::OUString::createFromAscii("InternalPaths");
+const ::rtl::OUString CFGPROP_USERPATHES = ::rtl::OUString::createFromAscii("UserPaths" );
+const ::rtl::OUString CFGPROP_WRITEPATH = ::rtl::OUString::createFromAscii("WritePath" );
+const ::rtl::OUString CFGPROP_ISSINGLEPATH = ::rtl::OUString::createFromAscii("IsSinglePath" );
+
+/*
+ 0 : old style "Template" string using ";" as seperator
+ 1 : internal paths "Template_internal" string list
+ 2 : user paths "Template_user" string list
+ 3 : write path "Template_write" string
+ */
+
+const ::rtl::OUString POSTFIX_INTERNAL_PATHES = ::rtl::OUString::createFromAscii("_internal");
+const ::rtl::OUString POSTFIX_USER_PATHES = ::rtl::OUString::createFromAscii("_user" );
+const ::rtl::OUString POSTFIX_WRITE_PATH = ::rtl::OUString::createFromAscii("_writable");
+
+const sal_Int32 IDGROUP_OLDSTYLE = 0;
+const sal_Int32 IDGROUP_INTERNAL_PATHES = 1;
+const sal_Int32 IDGROUP_USER_PATHES = 2;
+const sal_Int32 IDGROUP_WRITE_PATH = 3;
+
+const sal_Int32 IDGROUP_COUNT = 4;
+
+sal_Int32 impl_getPropGroup(sal_Int32 nID)
+{
+ return (nID % IDGROUP_COUNT);
+}
+
+// ______________________________________________
+// namespace
+
+namespace framework
+{
+
+//-----------------------------------------------------------------------------
+// XInterface, XTypeProvider, XServiceInfo
+
+DEFINE_XINTERFACE_7 ( PathSettings ,
+ OWeakObject ,
+ DIRECT_INTERFACE ( css::lang::XTypeProvider ),
+ DIRECT_INTERFACE ( css::lang::XServiceInfo ),
+ DERIVED_INTERFACE( css::lang::XEventListener, css::util::XChangesListener),
+ DIRECT_INTERFACE ( css::util::XChangesListener ),
+ DIRECT_INTERFACE ( css::beans::XPropertySet ),
+ DIRECT_INTERFACE ( css::beans::XFastPropertySet ),
+ DIRECT_INTERFACE ( css::beans::XMultiPropertySet )
+ )
+
+DEFINE_XTYPEPROVIDER_7 ( PathSettings ,
+ css::lang::XTypeProvider ,
+ css::lang::XServiceInfo ,
+ css::lang::XEventListener ,
+ css::util::XChangesListener ,
+ css::beans::XPropertySet ,
+ css::beans::XFastPropertySet ,
+ css::beans::XMultiPropertySet
+ )
+
+DEFINE_XSERVICEINFO_ONEINSTANCESERVICE ( PathSettings ,
+ ::cppu::OWeakObject ,
+ SERVICENAME_PATHSETTINGS ,
+ IMPLEMENTATIONNAME_PATHSETTINGS
+ )
+
+DEFINE_INIT_SERVICE ( PathSettings,
+ {
+ /*Attention
+ I think we don't need any mutex or lock here ... because we are called by our own static method impl_createInstance()
+ to create a new instance of this class by our own supported service factory.
+ see macro DEFINE_XSERVICEINFO_MULTISERVICE and "impl_initService()" for further informations!
+ */
+
+ // fill cache
+ impl_readAll();
+ }
+ )
+
+//-----------------------------------------------------------------------------
+PathSettings::PathSettings( const css::uno::Reference< css::lang::XMultiServiceFactory >& xSMGR )
+ // Init baseclasses first
+ // Attention: Don't change order of initialization!
+ // ThreadHelpBase is a struct with a lock as member. We can't use a lock as direct member!
+ // We must garant right initialization and a valid value of this to initialize other baseclasses!
+ : ThreadHelpBase()
+ , ::cppu::OBroadcastHelperVar< ::cppu::OMultiTypeInterfaceContainerHelper, ::cppu::OMultiTypeInterfaceContainerHelper::keyType >(m_aLock.getShareableOslMutex())
+ , ::cppu::OPropertySetHelper(*(static_cast< ::cppu::OBroadcastHelper* >(this)))
+ , ::cppu::OWeakObject()
+ // Init member
+ , m_xSMGR (xSMGR)
+ , m_pPropHelp(0 )
+ , m_bIgnoreEvents(sal_False)
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "framework", "Ocke.Janssen@sun.com", "PathSettings::PathSettings" );
+}
+
+//-----------------------------------------------------------------------------
+PathSettings::~PathSettings()
+{
+ if (m_pPropHelp)
+ delete m_pPropHelp;
+}
+
+//-----------------------------------------------------------------------------
+void SAL_CALL PathSettings::changesOccurred(const css::util::ChangesEvent& aEvent)
+ throw (css::uno::RuntimeException)
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "framework", "Ocke.Janssen@sun.com", "PathSettings::changesOccurred" );
+ /*
+ if (m_bIgnoreEvents)
+ return;
+ */
+
+ sal_Int32 c = aEvent.Changes.getLength();
+ sal_Int32 i = 0;
+ sal_Bool bUpdateDescriptor = sal_False;
+
+ for (i=0; i<c; ++i)
+ {
+ const css::util::ElementChange& aChange = aEvent.Changes[i];
+
+ ::rtl::OUString sChanged;
+ aChange.Accessor >>= sChanged;
+
+ ::rtl::OUString sPath = ::utl::extractFirstFromConfigurationPath(sChanged);
+ if (sPath.getLength())
+ {
+ PathSettings::EChangeOp eOp = impl_updatePath(sPath, sal_True);
+ if (
+ (eOp == PathSettings::E_ADDED ) ||
+ (eOp == PathSettings::E_REMOVED)
+ )
+ bUpdateDescriptor = sal_True;
+ }
+ }
+
+ if (bUpdateDescriptor)
+ impl_rebuildPropertyDescriptor();
+}
+
+//-----------------------------------------------------------------------------
+void SAL_CALL PathSettings::disposing(const css::lang::EventObject& aSource)
+ throw(css::uno::RuntimeException)
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "framework", "Ocke.Janssen@sun.com", "PathSettings::disposing" );
+ // SAFE ->
+ WriteGuard aWriteLock(m_aLock);
+
+ if (aSource.Source == m_xCfgNew)
+ m_xCfgNew.clear();
+
+ aWriteLock.unlock();
+ // <- SAFE
+}
+
+//-----------------------------------------------------------------------------
+void PathSettings::impl_readAll()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "framework", "Ocke.Janssen@sun.com", "PathSettings::impl_readAll" );
+ RTL_LOGFILE_CONTEXT(aLog, "framework (as96863) ::PathSettings::load config (all)");
+
+ // TODO think about me
+ css::uno::Reference< css::container::XNameAccess > xCfg = fa_getCfgNew();
+ css::uno::Sequence< ::rtl::OUString > lPaths = xCfg->getElementNames();
+
+ sal_Int32 c = lPaths.getLength();
+ sal_Int32 i = 0;
+
+ for (i=0; i<c; ++i)
+ {
+ const ::rtl::OUString& sPath = lPaths[i];
+ impl_updatePath(sPath, sal_False);
+ }
+
+ impl_rebuildPropertyDescriptor();
+}
+
+//-----------------------------------------------------------------------------
+// NO substitution here ! It's done outside ...
+OUStringList PathSettings::impl_readOldFormat(const ::rtl::OUString& sPath)
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "framework", "Ocke.Janssen@sun.com", "PathSettings::impl_readOldFormat" );
+ css::uno::Reference< css::container::XNameAccess > xCfg( fa_getCfgOld() );
+ OUStringList aPathVal;
+
+ if( xCfg->hasByName(sPath) )
+ {
+ css::uno::Any aVal( xCfg->getByName(sPath) );
+
+ ::rtl::OUString sStringVal;
+ css::uno::Sequence< ::rtl::OUString > lStringListVal;
+
+ if (aVal >>= sStringVal)
+ {
+ aPathVal.push_back(sStringVal);
+ }
+ else if (aVal >>= lStringListVal)
+ {
+ aPathVal << lStringListVal;
+ }
+ }
+
+ return aPathVal;
+}
+
+//-----------------------------------------------------------------------------
+// NO substitution here ! It's done outside ...
+PathSettings::PathInfo PathSettings::impl_readNewFormat(const ::rtl::OUString& sPath)
+{
+ css::uno::Reference< css::container::XNameAccess > xCfg = fa_getCfgNew();
+
+ // get access to the "queried" path
+ css::uno::Reference< css::container::XNameAccess > xPath;
+ xCfg->getByName(sPath) >>= xPath;
+
+ PathSettings::PathInfo aPathVal;
+
+ // read internal path list
+ css::uno::Reference< css::container::XNameAccess > xIPath;
+ xPath->getByName(CFGPROP_INTERNALPATHES) >>= xIPath;
+ aPathVal.lInternalPaths << xIPath->getElementNames();
+
+ // read user defined path list
+ aPathVal.lUserPaths << xPath->getByName(CFGPROP_USERPATHES);
+
+ // read the writeable path
+ xPath->getByName(CFGPROP_WRITEPATH) >>= aPathVal.sWritePath;
+
+ // read state props
+ xPath->getByName(CFGPROP_ISSINGLEPATH) >>= aPathVal.bIsSinglePath;
+
+ // analyze finalized/mandatory states
+ aPathVal.bIsReadonly = sal_False;
+ css::uno::Reference< css::beans::XProperty > xInfo(xPath, css::uno::UNO_QUERY);
+ if (xInfo.is())
+ {
+ css::beans::Property aInfo = xInfo->getAsProperty();
+ sal_Bool bFinalized = ((aInfo.Attributes & css::beans::PropertyAttribute::READONLY ) == css::beans::PropertyAttribute::READONLY );
+ //sal_Bool bMandatory = ((aInfo.Attributes & css::beans::PropertyAttribute::REMOVEABLE) != css::beans::PropertyAttribute::REMOVEABLE);
+
+ // Note: Till we support finalized / mandatory on our API more in detail we handle
+ // all states simple as READONLY ! But because all realy needed pathes are "mandatory" by default
+ // we have to handle "finalized" as the real "readonly" indicator .
+ aPathVal.bIsReadonly = bFinalized;
+ }
+
+ return aPathVal;
+}
+
+//-----------------------------------------------------------------------------
+void PathSettings::impl_storePath(const PathSettings::PathInfo& aPath)
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "framework", "Ocke.Janssen@sun.com", "PathSettings::impl_storePath" );
+ m_bIgnoreEvents = sal_True;
+
+ css::uno::Reference< css::container::XNameAccess > xCfgNew = fa_getCfgNew();
+ css::uno::Reference< css::container::XNameAccess > xCfgOld = fa_getCfgOld();
+
+ // try to replace path-parts with well known and uspported variables.
+ // So an office can be moved easialy to another location without loosing
+ // it's related pathes.
+ PathInfo aResubstPath(aPath);
+ impl_subst(aResubstPath, sal_True);
+
+ // update new configuration
+ if (! aResubstPath.bIsSinglePath)
+ {
+ ::comphelper::ConfigurationHelper::writeRelativeKey(xCfgNew,
+ aResubstPath.sPathName,
+ CFGPROP_USERPATHES,
+ css::uno::makeAny(aResubstPath.lUserPaths.getAsConstList()));
+ }
+
+ ::comphelper::ConfigurationHelper::writeRelativeKey(xCfgNew,
+ aResubstPath.sPathName,
+ CFGPROP_WRITEPATH,
+ css::uno::makeAny(aResubstPath.sWritePath));
+
+ ::comphelper::ConfigurationHelper::flush(xCfgNew);
+
+ // remove the whole path from the old configuration !
+ // Otherwise we cant make sure that the diff between new and old configuration
+ // on loading time realy represent an user setting !!!
+
+ // Check if the given path exists inside the old configuration.
+ // Because our new configuration knows more then the list of old pathes ... !
+ if (xCfgOld->hasByName(aResubstPath.sPathName))
+ {
+ css::uno::Reference< css::beans::XPropertySet > xProps(xCfgOld, css::uno::UNO_QUERY_THROW);
+ xProps->setPropertyValue(aResubstPath.sPathName, css::uno::Any());
+ ::comphelper::ConfigurationHelper::flush(xCfgOld);
+ }
+
+ m_bIgnoreEvents = sal_False;
+}
+
+//-----------------------------------------------------------------------------
+#ifdef MIGRATE_OLD_USER_PATHES
+void PathSettings::impl_mergeOldUserPaths( PathSettings::PathInfo& rPath,
+ const OUStringList& lOld )
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "framework", "Ocke.Janssen@sun.com", "PathSettings::impl_mergeOldUserPaths" );
+ OUStringList::const_iterator pIt;
+ for ( pIt = lOld.begin();
+ pIt != lOld.end() ;
+ ++pIt )
+ {
+ const ::rtl::OUString& sOld = *pIt;
+
+ if (rPath.bIsSinglePath)
+ {
+ LOG_ASSERT2(lOld.size()>1, "PathSettings::impl_mergeOldUserPaths()", "Single path has more then one path value inside old configuration (Common.xcu)!")
+ if (! rPath.sWritePath.equals(sOld))
+ rPath.sWritePath = sOld;
+ }
+ else
+ {
+ if (
+ ( rPath.lInternalPaths.findConst(sOld) == rPath.lInternalPaths.end()) &&
+ ( rPath.lUserPaths.findConst(sOld) == rPath.lUserPaths.end() ) &&
+ (! rPath.sWritePath.equals(sOld) )
+ )
+ rPath.lUserPaths.push_back(sOld);
+ }
+ }
+}
+#endif // MIGRATE_OLD_USER_PATHES
+
+//-----------------------------------------------------------------------------
+PathSettings::EChangeOp PathSettings::impl_updatePath(const ::rtl::OUString& sPath ,
+ sal_Bool bNotifyListener)
+{
+ // SAFE ->
+ WriteGuard aWriteLock(m_aLock);
+
+ PathSettings::PathInfo* pPathOld = 0;
+ PathSettings::PathInfo* pPathNew = 0;
+ PathSettings::EChangeOp eOp = PathSettings::E_UNDEFINED;
+ PathSettings::PathInfo aPath;
+
+ try
+ {
+ aPath = impl_readNewFormat(sPath);
+ aPath.sPathName = sPath;
+ // replace all might existing variables with real values
+ // Do it before these old pathes will be compared against the
+ // new path configuration. Otherwise some striungs uses different variables ... but substitution
+ // will produce strings with same content (because some variables are redundant!)
+ impl_subst(aPath, sal_False);
+ }
+ catch(const css::uno::RuntimeException& exRun)
+ { throw exRun; }
+ catch(const css::container::NoSuchElementException&)
+ { eOp = PathSettings::E_REMOVED; }
+ catch(const css::uno::Exception& exAny)
+ { throw exAny; }
+
+ #ifdef MIGRATE_OLD_USER_PATHES
+ try
+ {
+ // migration of old user defined values on demand
+ // can be disabled for a new major
+ OUStringList lOldVals = impl_readOldFormat(sPath);
+ // replace all might existing variables with real values
+ // Do it before these old pathes will be compared against the
+ // new path configuration. Otherwise some striungs uses different variables ... but substitution
+ // will produce strings with same content (because some variables are redundant!)
+ impl_subst(lOldVals, fa_getSubstitution(), sal_False);
+ impl_mergeOldUserPaths(aPath, lOldVals);
+ }
+ catch(const css::uno::RuntimeException& exRun)
+ { throw exRun; }
+ // Normal(!) exceptions can be ignored!
+ // E.g. in case an addon installs a new path, which was not well known for an OOo 1.x installation
+ // we cant find a value for it inside the "old" configuration. So a NoSuchElementException
+ // will be normal .-)
+ catch(const css::uno::Exception&)
+ {}
+ #endif // MIGRATE_OLD_USER_PATHES
+
+ PathSettings::PathHash::iterator pPath = m_lPaths.find(sPath);
+ if (eOp == PathSettings::E_UNDEFINED)
+ {
+ if (pPath != m_lPaths.end())
+ eOp = PathSettings::E_CHANGED;
+ else
+ eOp = PathSettings::E_ADDED;
+ }
+
+ switch(eOp)
+ {
+ case PathSettings::E_ADDED :
+ {
+ if (bNotifyListener)
+ {
+ pPathOld = 0;
+ pPathNew = &aPath;
+ impl_notifyPropListener(eOp, sPath, pPathOld, pPathNew);
+ }
+ m_lPaths[sPath] = aPath;
+ }
+ break;
+
+ case PathSettings::E_CHANGED :
+ {
+ if (bNotifyListener)
+ {
+ pPathOld = &(pPath->second);
+ pPathNew = &aPath;
+ impl_notifyPropListener(eOp, sPath, pPathOld, pPathNew);
+ }
+ m_lPaths[sPath] = aPath;
+ }
+ break;
+
+ case PathSettings::E_REMOVED :
+ {
+ if (pPath != m_lPaths.end())
+ {
+ if (bNotifyListener)
+ {
+ pPathOld = &(pPath->second);
+ pPathNew = 0;
+ impl_notifyPropListener(eOp, sPath, pPathOld, pPathNew);
+ }
+ m_lPaths.erase(pPath);
+ }
+ }
+ break;
+
+ default: // to let compiler be happy
+ break;
+ }
+
+ return eOp;
+}
+
+//-----------------------------------------------------------------------------
+css::uno::Sequence< sal_Int32 > PathSettings::impl_mapPathName2IDList(const ::rtl::OUString& sPath)
+{
+ ::rtl::OUString sOldStyleProp = sPath;
+ ::rtl::OUString sInternalProp = sPath+POSTFIX_INTERNAL_PATHES;
+ ::rtl::OUString sUserProp = sPath+POSTFIX_USER_PATHES;
+ ::rtl::OUString sWriteProp = sPath+POSTFIX_WRITE_PATH;
+
+ // Attention: The default set of IDs is fix and must follow these schema.
+ // Otherwhise the outside code ant work for new added properties.
+ // Why ?
+ // The outside code must fire N events for every changed property.
+ // And the knowing about packaging of variables of the structure PathInfo
+ // follow these group IDs ! But if such ID isnt in the range of [0..IDGROUP_COUNT]
+ // the outside cant determine the right group ... and cant fire the right events .-)
+
+ css::uno::Sequence< sal_Int32 > lIDs(IDGROUP_COUNT);
+ lIDs[0] = IDGROUP_OLDSTYLE ;
+ lIDs[1] = IDGROUP_INTERNAL_PATHES;
+ lIDs[2] = IDGROUP_USER_PATHES ;
+ lIDs[3] = IDGROUP_WRITE_PATH ;
+
+ sal_Int32 c = m_lPropDesc.getLength();
+ sal_Int32 i = 0;
+ for (i=0; i<c; ++i)
+ {
+ const css::beans::Property& rProp = m_lPropDesc[i];
+
+ if (rProp.Name.equals(sOldStyleProp))
+ lIDs[IDGROUP_OLDSTYLE] = rProp.Handle;
+ else
+ if (rProp.Name.equals(sInternalProp))
+ lIDs[IDGROUP_INTERNAL_PATHES] = rProp.Handle;
+ else
+ if (rProp.Name.equals(sUserProp))
+ lIDs[IDGROUP_USER_PATHES] = rProp.Handle;
+ else
+ if (rProp.Name.equals(sWriteProp))
+ lIDs[IDGROUP_WRITE_PATH] = rProp.Handle;
+ }
+
+ return lIDs;
+}
+
+//-----------------------------------------------------------------------------
+void PathSettings::impl_notifyPropListener( PathSettings::EChangeOp /*eOp*/ ,
+ const ::rtl::OUString& sPath ,
+ const PathSettings::PathInfo* pPathOld,
+ const PathSettings::PathInfo* pPathNew)
+{
+ css::uno::Sequence< sal_Int32 > lHandles(1);
+ css::uno::Sequence< css::uno::Any > lOldVals(1);
+ css::uno::Sequence< css::uno::Any > lNewVals(1);
+
+ css::uno::Sequence< sal_Int32 > lIDs = impl_mapPathName2IDList(sPath);
+ sal_Int32 c = lIDs.getLength();
+ sal_Int32 i = 0;
+ sal_Int32 nMaxID = m_lPropDesc.getLength()-1;
+ for (i=0; i<c; ++i)
+ {
+ sal_Int32 nID = lIDs[i];
+
+ if (
+ (nID < 0 ) ||
+ (nID > nMaxID)
+ )
+ continue;
+
+ lHandles[0] = nID;
+ switch(impl_getPropGroup(nID))
+ {
+ case IDGROUP_OLDSTYLE :
+ {
+ if (pPathOld)
+ {
+ ::rtl::OUString sVal = impl_convertPath2OldStyle(*pPathOld);
+ lOldVals[0] <<= sVal;
+ }
+ if (pPathNew)
+ {
+ ::rtl::OUString sVal = impl_convertPath2OldStyle(*pPathNew);
+ lNewVals[0] <<= sVal;
+ }
+ }
+ break;
+
+ case IDGROUP_INTERNAL_PATHES :
+ {
+ if (pPathOld)
+ lOldVals[0] <<= pPathOld->lInternalPaths.getAsConstList();
+ if (pPathNew)
+ lNewVals[0] <<= pPathNew->lInternalPaths.getAsConstList();
+ }
+ break;
+
+ case IDGROUP_USER_PATHES :
+ {
+ if (pPathOld)
+ lOldVals[0] <<= pPathOld->lUserPaths.getAsConstList();
+ if (pPathNew)
+ lNewVals[0] <<= pPathNew->lUserPaths.getAsConstList();
+ }
+ break;
+
+ case IDGROUP_WRITE_PATH :
+ {
+ if (pPathOld)
+ lOldVals[0] <<= pPathOld->sWritePath;
+ if (pPathNew)
+ lNewVals[0] <<= pPathNew->sWritePath;
+ }
+ break;
+ }
+
+ fire(lHandles.getArray(),
+ lNewVals.getArray(),
+ lOldVals.getArray(),
+ 1,
+ sal_False);
+ }
+}
+
+//-----------------------------------------------------------------------------
+void PathSettings::impl_subst( OUStringList& lVals ,
+ const css::uno::Reference< css::util::XStringSubstitution >& xSubst ,
+ sal_Bool bReSubst)
+{
+ OUStringList::iterator pIt;
+
+ for ( pIt = lVals.begin();
+ pIt != lVals.end() ;
+ ++pIt )
+ {
+ const ::rtl::OUString& sOld = *pIt;
+ ::rtl::OUString sNew ;
+ if (bReSubst)
+ sNew = xSubst->reSubstituteVariables(sOld);
+ else
+ sNew = xSubst->substituteVariables(sOld, sal_False);
+
+ *pIt = sNew;
+ }
+}
+
+//-----------------------------------------------------------------------------
+void PathSettings::impl_subst(PathSettings::PathInfo& aPath ,
+ sal_Bool bReSubst)
+{
+ css::uno::Reference< css::util::XStringSubstitution > xSubst = fa_getSubstitution();
+
+ impl_subst(aPath.lInternalPaths, xSubst, bReSubst);
+ impl_subst(aPath.lUserPaths , xSubst, bReSubst);
+ if (bReSubst)
+ aPath.sWritePath = xSubst->reSubstituteVariables(aPath.sWritePath);
+ else
+ aPath.sWritePath = xSubst->substituteVariables(aPath.sWritePath, sal_False);
+}
+
+//-----------------------------------------------------------------------------
+::rtl::OUString PathSettings::impl_convertPath2OldStyle(const PathSettings::PathInfo& rPath) const
+{
+ OUStringList::const_iterator pIt;
+ OUStringList lTemp;
+ lTemp.reserve(rPath.lInternalPaths.size() + rPath.lUserPaths.size() + 1);
+
+ for ( pIt = rPath.lInternalPaths.begin();
+ pIt != rPath.lInternalPaths.end() ;
+ ++pIt )
+ {
+ lTemp.push_back(*pIt);
+ }
+ for ( pIt = rPath.lUserPaths.begin();
+ pIt != rPath.lUserPaths.end() ;
+ ++pIt )
+ {
+ lTemp.push_back(*pIt);
+ }
+
+ if (rPath.sWritePath.getLength() > 0)
+ lTemp.push_back(rPath.sWritePath);
+
+ ::rtl::OUStringBuffer sPathVal(256);
+ for ( pIt = lTemp.begin();
+ pIt != lTemp.end() ;
+ )
+ {
+ sPathVal.append(*pIt);
+ ++pIt;
+ if (pIt != lTemp.end())
+ sPathVal.appendAscii(";");
+ }
+
+ return sPathVal.makeStringAndClear();
+}
+
+//-----------------------------------------------------------------------------
+OUStringList PathSettings::impl_convertOldStyle2Path(const ::rtl::OUString& sOldStylePath) const
+{
+ OUStringList lList;
+ sal_Int32 nToken = 0;
+ do
+ {
+ ::rtl::OUString sToken = sOldStylePath.getToken(0, ';', nToken);
+ if (sToken.getLength())
+ lList.push_back(sToken);
+ }
+ while(nToken >= 0);
+
+ return lList;
+}
+
+//-----------------------------------------------------------------------------
+void PathSettings::impl_purgeKnownPaths(const PathSettings::PathInfo& rPath,
+ OUStringList& lList)
+{
+ OUStringList::const_iterator pIt;
+ for ( pIt = rPath.lInternalPaths.begin();
+ pIt != rPath.lInternalPaths.end() ;
+ ++pIt )
+ {
+ const ::rtl::OUString& rItem = *pIt;
+ OUStringList::iterator pItem = lList.find(rItem);
+ if (pItem != lList.end())
+ lList.erase(pItem);
+ }
+ for ( pIt = rPath.lUserPaths.begin();
+ pIt != rPath.lUserPaths.end() ;
+ ++pIt )
+ {
+ const ::rtl::OUString& rItem = *pIt;
+ OUStringList::iterator pItem = lList.find(rItem);
+ if (pItem != lList.end())
+ lList.erase(pItem);
+ }
+
+ OUStringList::iterator pItem = lList.find(rPath.sWritePath);
+ if (pItem != lList.end())
+ lList.erase(pItem);
+}
+
+//-----------------------------------------------------------------------------
+void PathSettings::impl_rebuildPropertyDescriptor()
+{
+ // SAFE ->
+ WriteGuard aWriteLock(m_aLock);
+
+ sal_Int32 c = (sal_Int32)m_lPaths.size();
+ sal_Int32 i = 0;
+ m_lPropDesc.realloc(c*IDGROUP_COUNT);
+
+ PathHash::const_iterator pIt;
+ for ( pIt = m_lPaths.begin();
+ pIt != m_lPaths.end() ;
+ ++pIt )
+ {
+ const PathSettings::PathInfo& rPath = pIt->second;
+ css::beans::Property* pProp = 0;
+
+ pProp = &(m_lPropDesc[i]);
+ pProp->Name = rPath.sPathName;
+ pProp->Handle = i;
+ pProp->Type = ::getCppuType((::rtl::OUString*)0);
+ pProp->Attributes = css::beans::PropertyAttribute::BOUND;
+ if (rPath.bIsReadonly)
+ pProp->Attributes |= css::beans::PropertyAttribute::READONLY;
+ ++i;
+
+ pProp = &(m_lPropDesc[i]);
+ pProp->Name = rPath.sPathName+POSTFIX_INTERNAL_PATHES;
+ pProp->Handle = i;
+ pProp->Type = ::getCppuType((css::uno::Sequence< ::rtl::OUString >*)0);
+ pProp->Attributes = css::beans::PropertyAttribute::BOUND |
+ css::beans::PropertyAttribute::READONLY;
+ ++i;
+
+ pProp = &(m_lPropDesc[i]);
+ pProp->Name = rPath.sPathName+POSTFIX_USER_PATHES;
+ pProp->Handle = i;
+ pProp->Type = ::getCppuType((css::uno::Sequence< ::rtl::OUString >*)0);
+ pProp->Attributes = css::beans::PropertyAttribute::BOUND;
+ if (rPath.bIsReadonly)
+ pProp->Attributes |= css::beans::PropertyAttribute::READONLY;
+ ++i;
+
+ pProp = &(m_lPropDesc[i]);
+ pProp->Name = rPath.sPathName+POSTFIX_WRITE_PATH;
+ pProp->Handle = i;
+ pProp->Type = ::getCppuType((::rtl::OUString*)0);
+ pProp->Attributes = css::beans::PropertyAttribute::BOUND;
+ if (rPath.bIsReadonly)
+ pProp->Attributes |= css::beans::PropertyAttribute::READONLY;
+ ++i;
+ }
+
+ if (m_pPropHelp)
+ delete m_pPropHelp;
+ m_pPropHelp = new ::cppu::OPropertyArrayHelper(m_lPropDesc, sal_False); // false => not sorted ... must be done inside helper
+
+ aWriteLock.unlock();
+ // <- SAFE
+}
+
+//-----------------------------------------------------------------------------
+css::uno::Any PathSettings::impl_getPathValue(sal_Int32 nID) const
+{
+ const PathSettings::PathInfo* pPath = impl_getPathAccessConst(nID);
+ if (! pPath)
+ throw css::container::NoSuchElementException();
+
+ css::uno::Any aVal;
+ switch(impl_getPropGroup(nID))
+ {
+ case IDGROUP_OLDSTYLE :
+ {
+ ::rtl::OUString sVal = impl_convertPath2OldStyle(*pPath);
+ aVal <<= sVal;
+ }
+ break;
+
+ case IDGROUP_INTERNAL_PATHES :
+ {
+ aVal <<= pPath->lInternalPaths.getAsConstList();
+ }
+ break;
+
+ case IDGROUP_USER_PATHES :
+ {
+ aVal <<= pPath->lUserPaths.getAsConstList();
+ }
+ break;
+
+ case IDGROUP_WRITE_PATH :
+ {
+ aVal <<= pPath->sWritePath;
+ }
+ break;
+ }
+
+ return aVal;
+}
+
+//-----------------------------------------------------------------------------
+void PathSettings::impl_setPathValue( sal_Int32 nID ,
+ const css::uno::Any& aVal)
+{
+ PathSettings::PathInfo* pOrgPath = impl_getPathAccess(nID);
+ if (! pOrgPath)
+ throw css::container::NoSuchElementException();
+
+ // We work on a copied path ... so we can be sure that errors during this operation
+ // does not make our internal cache invalid .-)
+ PathSettings::PathInfo aChangePath(*pOrgPath);
+
+ switch(impl_getPropGroup(nID))
+ {
+ case IDGROUP_OLDSTYLE :
+ {
+ ::rtl::OUString sVal;
+ aVal >>= sVal;
+ OUStringList lList = impl_convertOldStyle2Path(sVal);
+ impl_subst(lList, fa_getSubstitution(), sal_False);
+ impl_purgeKnownPaths(aChangePath, lList);
+ if (! impl_isValidPath(lList))
+ throw css::lang::IllegalArgumentException();
+
+ if (aChangePath.bIsSinglePath)
+ {
+ LOG_ASSERT2(lList.size()>1, "PathSettings::impl_setPathValue()", "You try to set more then path value for a defined SINGLE_PATH!")
+ if ( !lList.empty() )
+ aChangePath.sWritePath = *(lList.begin());
+ else
+ aChangePath.sWritePath = ::rtl::OUString();
+ }
+ else
+ {
+ OUStringList::const_iterator pIt;
+ for ( pIt = lList.begin();
+ pIt != lList.end() ;
+ ++pIt )
+ {
+ aChangePath.lUserPaths.push_back(*pIt);
+ }
+ }
+ }
+ break;
+
+ case IDGROUP_INTERNAL_PATHES :
+ {
+ if (aChangePath.bIsSinglePath)
+ {
+ ::rtl::OUStringBuffer sMsg(256);
+ sMsg.appendAscii("The path '" );
+ sMsg.append (aChangePath.sPathName);
+ sMsg.appendAscii("' is defined as SINGLE_PATH. It's sub set of internal pathes cant be set.");
+ throw css::uno::Exception(sMsg.makeStringAndClear(),
+ static_cast< ::cppu::OWeakObject* >(this));
+ }
+
+ OUStringList lList;
+ lList << aVal;
+ if (! impl_isValidPath(lList))
+ throw css::lang::IllegalArgumentException();
+ aChangePath.lInternalPaths = lList;
+ }
+ break;
+
+ case IDGROUP_USER_PATHES :
+ {
+ if (aChangePath.bIsSinglePath)
+ {
+ ::rtl::OUStringBuffer sMsg(256);
+ sMsg.appendAscii("The path '" );
+ sMsg.append (aChangePath.sPathName);
+ sMsg.appendAscii("' is defined as SINGLE_PATH. It's sub set of internal pathes cant be set.");
+ throw css::uno::Exception(sMsg.makeStringAndClear(),
+ static_cast< ::cppu::OWeakObject* >(this));
+ }
+
+ OUStringList lList;
+ lList << aVal;
+ if (! impl_isValidPath(lList))
+ throw css::lang::IllegalArgumentException();
+ aChangePath.lUserPaths = lList;
+ }
+ break;
+
+ case IDGROUP_WRITE_PATH :
+ {
+ ::rtl::OUString sVal;
+ aVal >>= sVal;
+ if (! impl_isValidPath(sVal))
+ throw css::lang::IllegalArgumentException();
+ aChangePath.sWritePath = sVal;
+ }
+ break;
+ }
+
+ // TODO check if path has at least one path value set
+ // At least it depends from the feature using this path, if an empty path list is allowed.
+ /*
+ if (impl_isPathEmpty(aChangePath))
+ {
+ ::rtl::OUStringBuffer sMsg(256);
+ sMsg.appendAscii("The path '" );
+ sMsg.append (aChangePath.sPathName);
+ sMsg.appendAscii("' is empty now ... Not a real good idea.");
+ throw css::uno::Exception(sMsg.makeStringAndClear(),
+ static_cast< ::cppu::OWeakObject* >(this));
+ }
+ */
+
+ // first we should try to store the changed (copied!) path ...
+ // In case an error occure on saving time an exception is thrown ...
+ // If no exception occures we can update our internal cache (means
+ // we can overwrite pOrgPath !
+ impl_storePath(aChangePath);
+ pOrgPath->takeOver(aChangePath);
+}
+
+//-----------------------------------------------------------------------------
+sal_Bool PathSettings::impl_isValidPath(const OUStringList& lPath) const
+{
+ OUStringList::const_iterator pIt;
+ for ( pIt = lPath.begin();
+ pIt != lPath.end() ;
+ ++pIt )
+ {
+ const ::rtl::OUString& rVal = *pIt;
+ if (! impl_isValidPath(rVal))
+ return sal_False;
+ }
+
+ return sal_True;
+}
+
+//-----------------------------------------------------------------------------
+sal_Bool PathSettings::impl_isValidPath(const ::rtl::OUString& sPath) const
+{
+ // allow empty path to reset a path.
+// idea by LLA to support empty pathes
+// if (sPath.getLength() == 0)
+// {
+// return sal_True;
+// }
+
+ return (! INetURLObject(sPath).HasError());
+}
+
+//-----------------------------------------------------------------------------
+::rtl::OUString impl_extractBaseFromPropName(const ::rtl::OUString& sPropName)
+{
+ sal_Int32 i = -1;
+
+ i = sPropName.indexOf(POSTFIX_INTERNAL_PATHES);
+ if (i > -1)
+ return sPropName.copy(0, i);
+ i = sPropName.indexOf(POSTFIX_USER_PATHES);
+ if (i > -1)
+ return sPropName.copy(0, i);
+ i = sPropName.indexOf(POSTFIX_WRITE_PATH);
+ if (i > -1)
+ return sPropName.copy(0, i);
+
+ return sPropName;
+}
+
+//-----------------------------------------------------------------------------
+PathSettings::PathInfo* PathSettings::impl_getPathAccess(sal_Int32 nHandle)
+{
+ // SAFE ->
+ ReadGuard aReadLock(m_aLock);
+
+ if (nHandle > (m_lPropDesc.getLength()-1))
+ return 0;
+
+ const css::beans::Property& rProp = m_lPropDesc[nHandle];
+ ::rtl::OUString sProp = impl_extractBaseFromPropName(rProp.Name);
+ PathSettings::PathHash::iterator rPath = m_lPaths.find(sProp);
+
+ if (rPath != m_lPaths.end())
+ return &(rPath->second);
+
+ return 0;
+ // <- SAFE
+}
+
+//-----------------------------------------------------------------------------
+const PathSettings::PathInfo* PathSettings::impl_getPathAccessConst(sal_Int32 nHandle) const
+{
+ // SAFE ->
+ ReadGuard aReadLock(m_aLock);
+
+ if (nHandle > (m_lPropDesc.getLength()-1))
+ return 0;
+
+ const css::beans::Property& rProp = m_lPropDesc[nHandle];
+ ::rtl::OUString sProp = impl_extractBaseFromPropName(rProp.Name);
+ PathSettings::PathHash::const_iterator rPath = m_lPaths.find(sProp);
+
+ if (rPath != m_lPaths.end())
+ return &(rPath->second);
+
+ return 0;
+ // <- SAFE
+}
+
+//-----------------------------------------------------------------------------
+sal_Bool SAL_CALL PathSettings::convertFastPropertyValue( css::uno::Any& aConvertedValue,
+ css::uno::Any& aOldValue ,
+ sal_Int32 nHandle ,
+ const css::uno::Any& aValue )
+ throw(css::lang::IllegalArgumentException)
+{
+ // throws NoSuchElementException !
+ css::uno::Any aCurrentVal = impl_getPathValue(nHandle);
+
+ return PropHelper::willPropertyBeChanged(
+ aCurrentVal,
+ aValue,
+ aOldValue,
+ aConvertedValue);
+}
+
+//-----------------------------------------------------------------------------
+void SAL_CALL PathSettings::setFastPropertyValue_NoBroadcast( sal_Int32 nHandle,
+ const css::uno::Any& aValue )
+ throw(css::uno::Exception)
+{
+ // throws NoSuchElement- and IllegalArgumentException !
+ impl_setPathValue(nHandle, aValue);
+}
+
+//-----------------------------------------------------------------------------
+void SAL_CALL PathSettings::getFastPropertyValue(css::uno::Any& aValue ,
+ sal_Int32 nHandle) const
+{
+ aValue = impl_getPathValue(nHandle);
+}
+
+//-----------------------------------------------------------------------------
+::cppu::IPropertyArrayHelper& SAL_CALL PathSettings::getInfoHelper()
+{
+ return *m_pPropHelp;
+}
+
+//-----------------------------------------------------------------------------
+css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL PathSettings::getPropertySetInfo()
+ throw(css::uno::RuntimeException)
+{
+ return css::uno::Reference< css::beans::XPropertySetInfo >(createPropertySetInfo(getInfoHelper()));
+}
+
+//-----------------------------------------------------------------------------
+css::uno::Reference< css::util::XStringSubstitution > PathSettings::fa_getSubstitution()
+{
+ // SAFE ->
+ ReadGuard aReadLock(m_aLock);
+ css::uno::Reference< css::lang::XMultiServiceFactory > xSMGR = m_xSMGR;
+ css::uno::Reference< css::util::XStringSubstitution > xSubst = m_xSubstitution;
+ aReadLock.unlock();
+ // <- SAFE
+
+ if (! xSubst.is())
+ {
+ // create the needed substitution service.
+ // We must replace all used variables inside readed path values.
+ // In case we can't do so ... the whole office can't work realy.
+ // That's why it seams to be OK to throw a RuntimeException then.
+ xSubst = css::uno::Reference< css::util::XStringSubstitution >(
+ xSMGR->createInstance(SERVICENAME_SUBSTITUTEPATHVARIABLES),
+ css::uno::UNO_QUERY_THROW);
+
+ // SAFE ->
+ WriteGuard aWriteLock(m_aLock);
+ m_xSubstitution = xSubst;
+ aWriteLock.unlock();
+ }
+
+ return xSubst;
+}
+
+//-----------------------------------------------------------------------------
+css::uno::Reference< css::container::XNameAccess > PathSettings::fa_getCfgOld()
+{
+ const static ::rtl::OUString CFG_NODE_OLD = ::rtl::OUString::createFromAscii("org.openoffice.Office.Common/Path/Current");
+
+ // SAFE ->
+ ReadGuard aReadLock(m_aLock);
+ css::uno::Reference< css::lang::XMultiServiceFactory > xSMGR = m_xSMGR;
+ css::uno::Reference< css::container::XNameAccess > xCfg = m_xCfgOld;
+ aReadLock.unlock();
+ // <- SAFE
+
+ if (! xCfg.is())
+ {
+ xCfg = css::uno::Reference< css::container::XNameAccess >(
+ ::comphelper::ConfigurationHelper::openConfig(
+ xSMGR,
+ CFG_NODE_OLD,
+ ::comphelper::ConfigurationHelper::E_STANDARD), // not readonly! Somtimes we need write access there !!!
+ css::uno::UNO_QUERY_THROW);
+
+ // SAFE ->
+ WriteGuard aWriteLock(m_aLock);
+ m_xCfgOld = xCfg;
+ aWriteLock.unlock();
+ }
+
+ return xCfg;
+}
+
+//-----------------------------------------------------------------------------
+css::uno::Reference< css::container::XNameAccess > PathSettings::fa_getCfgNew()
+{
+ const static ::rtl::OUString CFG_NODE_NEW = ::rtl::OUString::createFromAscii("org.openoffice.Office.Paths/Paths");
+
+ // SAFE ->
+ ReadGuard aReadLock(m_aLock);
+ css::uno::Reference< css::lang::XMultiServiceFactory > xSMGR = m_xSMGR;
+ css::uno::Reference< css::container::XNameAccess > xCfg = m_xCfgNew;
+ aReadLock.unlock();
+ // <- SAFE
+
+ if (! xCfg.is())
+ {
+ xCfg = css::uno::Reference< css::container::XNameAccess >(
+ ::comphelper::ConfigurationHelper::openConfig(
+ xSMGR,
+ CFG_NODE_NEW,
+ ::comphelper::ConfigurationHelper::E_STANDARD),
+ css::uno::UNO_QUERY_THROW);
+
+ // SAFE ->
+ WriteGuard aWriteLock(m_aLock);
+ m_xCfgNew = xCfg;
+ aWriteLock.unlock();
+
+ css::uno::Reference< css::util::XChangesNotifier > xBroadcaster(xCfg, css::uno::UNO_QUERY_THROW);
+ xBroadcaster->addChangesListener(static_cast< css::util::XChangesListener* >(this));
+ }
+
+ return xCfg;
+}
+
+} // namespace framework