/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed * with this work for additional information regarding copyright * ownership. The ASF licenses this file to you under the Apache * License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
/** reference to factory, which has create this instance. */
css::uno::Reference< css::uno::XComponentContext > m_xContext;
/** list of all path variables and her corresponding values. */
PathSettings::PathHash m_lPaths;
/** describes all properties available on our interface.
Will be generated on demand based on our path list m_lPaths. */
css::uno::Sequence< css::beans::Property > m_lPropDesc;
/** helper needed to (re-)substitute all internal save path values. */
css::uno::Reference< css::util::XStringSubstitution > m_xSubstitution;
/** provides access to the old configuration schema (which will be migrated on demand). */
css::uno::Reference< css::container::XNameAccess > m_xCfgOld;
/** provides access to the new configuration schema. */
css::uno::Reference< css::container::XNameAccess > m_xCfgNew;
/** helper to listen for configuration changes without ownership cycle problems */
rtl::Reference< WeakChangesListener > m_xCfgNewListener;
/** initialize a new instance of this class. Attention: It's necessary for right function of this class, that the order of base classes is the right one. Because we transfer information from one base to another
during this ctor runs! */ explicit PathSettings(css::uno::Reference< css::uno::XComponentContext > xContext);
/** free all used resources ... if it was not already done. */ virtual ~PathSettings() override;
/** read a path info using the old cfg schema. This is needed for "migration on demand" reasons only.
Can be removed for next major release .-) */
std::vector<OUString> impl_readOldFormat(const OUString& sPath);
/** read a path info using the new cfg schema. */
PathSettings::PathInfo impl_readNewFormat(const OUString& sPath);
/** filter "real user defined paths" from the old configuration schema and set it as UserPaths on the new schema.
Can be removed with new major release ... */ staticvoid impl_mergeOldUserPaths( PathSettings::PathInfo& rPath, const std::vector<OUString>& lOld );
/** reload one path directly from the new configuration schema (because
it was updated by any external code) */
PathSettings::EChangeOp impl_updatePath(const OUString& sPath , bool bNotifyListener);
/** replace all might existing placeholder variables inside the given path ... or check if the given path value uses paths, which can be replaced with predefined placeholder variables ...
*/ staticvoid impl_subst(std::vector<OUString>& lVals , const css::uno::Reference< css::util::XStringSubstitution >& xSubst , bool bReSubst);
/** converts our new string list schema to the old ";" separated schema ... */ static OUString impl_convertPath2OldStyle(const PathSettings::PathInfo& rPath ); static std::vector<OUString> impl_convertOldStyle2Path(std::u16string_view sOldStylePath);
/** remove still known paths from the given lList argument. So real user defined paths can be extracted from the list of fix internal paths !
*/ staticvoid impl_purgeKnownPaths(PathSettings::PathInfo& rPath,
std::vector<OUString>& lList);
/** rebuild the member m_lPropDesc using the path list m_lPaths. */ void impl_rebuildPropertyDescriptor();
/** provides direct access to the list of path values using its internal property id.
*/
css::uno::Any impl_getPathValue( sal_Int32 nID ) const; void impl_setPathValue( sal_Int32 nID , const css::uno::Any& aVal);
/** check the given handle and return the corresponding PathInfo reference.
These reference can be used then directly to manipulate these path. */
PathSettings::PathInfo* impl_getPathAccess (sal_Int32 nHandle); const PathSettings::PathInfo* impl_getPathAccessConst(sal_Int32 nHandle) const;
/** it checks, if the given path value seems to be a valid URL or system path. */ staticbool impl_isValidPath(std::u16string_view sPath); staticbool impl_isValidPath(const std::vector<OUString>& lPath);
// read user defined path list
css::uno::Sequence<OUString> vTmpUserPathsSeq;
xPath->getByName(CFGPROP_USERPATHS) >>= vTmpUserPathsSeq;
aPathVal.lUserPaths = comphelper::sequenceToContainer<std::vector<OUString>>(vTmpUserPathsSeq);
// read the writeable path
xPath->getByName(CFGPROP_WRITEPATH) >>= aPathVal.sWritePath;
// avoid duplicates, by removing the writeable path from // the user defined path list if it happens to be there too
std::vector<OUString>::iterator aI = std::find(aPathVal.lUserPaths.begin(), aPathVal.lUserPaths.end(), aPathVal.sWritePath); if (aI != aPathVal.lUserPaths.end())
aPathVal.lUserPaths.erase(aI);
// read state props
xPath->getByName(u"IsSinglePath"_ustr) >>= aPathVal.bIsSinglePath;
// Note: 'till we support finalized/mandatory on our API more in detail we handle // all states simple as READONLY! But because all really needed paths are "mandatory" by default // we have to handle "finalized" as the real "readonly" indicator.
aPathVal.bIsReadonly = bFinalized;
}
// try to replace path-parts with well known and supported variables. // So an office can be moved easily to another location without losing // its related paths.
PathInfo aResubstPath(aPath);
impl_subst(aResubstPath, true);
// update new configuration if (! aResubstPath.bIsSinglePath)
{
::comphelper::ConfigurationHelper::writeRelativeKey(xCfgNew,
aResubstPath.sPathName,
CFGPROP_USERPATHS,
css::uno::Any(comphelper::containerToSequence(aResubstPath.lUserPaths)));
}
// remove the whole path from the old configuration! // Otherwise we can't make sure that the diff between new and old configuration // on loading time really represents a user setting!!!
// Check if the given path exists inside the old configuration. // Because our new configuration knows more than the list of old paths ... ! 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);
}
}
// static void PathSettings::impl_mergeOldUserPaths( PathSettings::PathInfo& rPath, const std::vector<OUString>& lOld )
{ for (autoconst& old : lOld)
{ if (rPath.bIsSinglePath)
{
SAL_WARN_IF(lOld.size()>1, "fwk", "PathSettings::impl_mergeOldUserPaths(): Single path has more than one path value inside old configuration (Common.xcu)!"); if ( rPath.sWritePath != old )
rPath.sWritePath = old;
} else
{ if (
( std::find(rPath.lInternalPaths.begin(), rPath.lInternalPaths.end(), old) == rPath.lInternalPaths.end()) &&
( std::find(rPath.lUserPaths.begin(), rPath.lUserPaths.end(), old) == rPath.lUserPaths.end() ) &&
( rPath.sWritePath != old )
)
rPath.lUserPaths.push_back(old);
}
}
}
try
{
aPath = impl_readNewFormat(sPath);
aPath.sPathName = sPath; // replace all might existing variables with real values // Do it before these old paths will be compared against the // new path configuration. Otherwise some strings uses different variables ... but substitution // will produce strings with same content (because some variables are redundant!)
impl_subst(aPath, false);
} catch(const css::uno::RuntimeException&)
{ throw; } catch(const css::container::NoSuchElementException&)
{ eOp = PathSettings::E_REMOVED; } catch(const css::uno::Exception&)
{ throw; }
try
{ // migration of old user defined values on demand // can be disabled for a new major
std::vector<OUString> lOldVals = impl_readOldFormat(sPath); // replace all might existing variables with real values // Do it before these old paths will be compared against the // new path configuration. Otherwise some strings uses different variables ... but substitution // will produce strings with same content (because some variables are redundant!)
impl_subst(lOldVals, fa_getSubstitution(), false);
impl_mergeOldUserPaths(aPath, lOldVals);
} catch(const css::uno::RuntimeException&)
{ throw; } // 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 can't find a value for it inside the "old" configuration. So a NoSuchElementException // will be normal .-) catch(const css::uno::Exception&)
{}
// Attention: The default set of IDs is fix and must follow these schema. // Otherwise 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 is not in the range of [0..IDGROUP_COUNT] // the outside can't determine the right group ... and can not fire the right events .-)
for (autoconst& internalPath : rPath.lInternalPaths)
{ if (sPathVal.getLength())
sPathVal.append(";");
sPathVal.append(internalPath);
} for (autoconst& userPath : rPath.lUserPaths)
{ if (sPathVal.getLength())
sPathVal.append(";");
sPathVal.append(userPath);
} if (!rPath.sWritePath.isEmpty())
{ if (sPathVal.getLength())
sPathVal.append(";");
sPathVal.append(rPath.sWritePath);
}
// static void PathSettings::impl_purgeKnownPaths(PathSettings::PathInfo& rPath,
std::vector<OUString>& lList)
{ // Erase items in the internal path list from lList. // Also erase items in the internal path list from the user path list. for (autoconst& internalPath : rPath.lInternalPaths)
{
std::vector<OUString>::iterator pItem = std::find(lList.begin(), lList.end(), internalPath); if (pItem != lList.end())
lList.erase(pItem);
pItem = std::find(rPath.lUserPaths.begin(), rPath.lUserPaths.end(), internalPath); if (pItem != rPath.lUserPaths.end())
rPath.lUserPaths.erase(pItem);
}
// Erase items not in lList from the user path list.
std::erase_if(rPath.lUserPaths,
[&lList](const OUString& rItem) { return std::find(lList.begin(), lList.end(), rItem) == lList.end();
});
// Erase items in the user path list from lList. for (autoconst& userPath : rPath.lUserPaths)
{
std::vector<OUString>::iterator pItem = std::find(lList.begin(), lList.end(), userPath); if (pItem != lList.end())
lList.erase(pItem);
}
// Erase the write path from lList
std::vector<OUString>::iterator pItem = std::find(lList.begin(), lList.end(), rPath.sWritePath); if (pItem != lList.end())
lList.erase(pItem);
}
sal_Int32 c = static_cast<sal_Int32>(m_lPaths.size());
sal_Int32 i = 0;
m_lPropDesc.realloc(c*IDGROUP_COUNT); auto plPropDesc = m_lPropDesc.getArray();
case IDGROUP_INTERNAL_PATHS :
{
aVal <<= comphelper::containerToSequence(pPath->lInternalPaths);
} break;
case IDGROUP_USER_PATHS :
{
aVal <<= comphelper::containerToSequence(pPath->lUserPaths);
} 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);
if (aChangePath.bIsSinglePath)
{
SAL_WARN_IF(lList.size()>1, "fwk", "PathSettings::impl_setPathValue(): You try to set more than path value for a defined SINGLE_PATH!"); if ( !lList.empty() )
aChangePath.sWritePath = *(lList.begin()); else
aChangePath.sWritePath.clear();
} else
{ for (autoconst& elem : lList)
{
aChangePath.lUserPaths.push_back(elem);
}
}
} break;
case IDGROUP_INTERNAL_PATHS :
{ if (aChangePath.bIsSinglePath)
{ throw css::uno::Exception( "The path '" + aChangePath.sPathName
+ "' is defined as SINGLE_PATH. It's sub set of internal paths can't be set.", static_cast< ::cppu::OWeakObject* >(this));
}
case IDGROUP_USER_PATHS :
{ if (aChangePath.bIsSinglePath)
{ throw css::uno::Exception( "The path '" + aChangePath.sPathName
+ "' is defined as SINGLE_PATH. It's sub set of internal paths can't be set.", static_cast< ::cppu::OWeakObject* >(this));
}
case IDGROUP_WRITE_PATH :
{
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.
// first we should try to store the changed (copied!) path ... // In case an error occurs on saving time an exception is thrown ... // If no exception occurs we can update our internal cache (means // we can overwrite pOrgPath !
impl_storePath(aChangePath);
*pOrgPath = std::move(aChangePath);
}
// static bool PathSettings::impl_isValidPath(const std::vector<OUString>& lPath)
{ for (autoconst& path : lPath)
{ if (! impl_isValidPath(path)) returnfalse;
}
returntrue;
}
// static bool PathSettings::impl_isValidPath(std::u16string_view sPath)
{ // allow empty path to reset a path. // idea by LLA to support empty paths // if (sPath.getLength() == 0) // { // return sal_True; // }
return (! INetURLObject(sPath).HasError());
}
OUString impl_extractBaseFromPropName(const OUString& sPropName)
{
sal_Int32 i = sPropName.indexOf(POSTFIX_INTERNAL_PATHS); if (i > -1) return sPropName.copy(0, i);
i = sPropName.indexOf(POSTFIX_USER_PATHS); if (i > -1) return sPropName.copy(0, i);
i = sPropName.indexOf(POSTFIX_WRITE_PATH); if (i > -1) return sPropName.copy(0, i);
if (! xSubst.is())
{ // create the needed substitution service. // We must replace all used variables inside read path values. // In case we can't do so... the whole office can't work really. // That's why it seems to be OK to throw a RuntimeException then.
xSubst = css::util::PathSubstitution::create(m_xContext);
if (! xCfg.is())
{
xCfg.set( ::comphelper::ConfigurationHelper::openConfig(
m_xContext,
u"org.openoffice.Office.Common/Path/Current"_ustr,
::comphelper::EConfigurationModes::Standard), // not readonly! Sometimes we need write access there !!!
css::uno::UNO_QUERY_THROW);
// XInitialization void SAL_CALL PathSettings::initialize(const css::uno::Sequence<css::uno::Any>& /*rArguments*/)
{ // so we can reinitialize/reset all path variables to default
osl::MutexGuard g(cppu::WeakComponentImplHelperBase::rBHelper.rMutex);
impl_readAll();
}
}
extern"C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
com_sun_star_comp_framework_PathSettings_get_implementation(
css::uno::XComponentContext *context,
css::uno::Sequence<css::uno::Any> const &)
{
rtl::Reference<PathSettings> xPathSettings = new PathSettings(context); // fill cache
xPathSettings->impl_readAll();
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.