diff options
Diffstat (limited to 'unotools/source/config')
33 files changed, 17527 insertions, 0 deletions
diff --git a/unotools/source/config/bootstrap.cxx b/unotools/source/config/bootstrap.cxx new file mode 100644 index 000000000..a6c8eb228 --- /dev/null +++ b/unotools/source/config/bootstrap.cxx @@ -0,0 +1,742 @@ +/* -*- 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 . + */ + +#include <config_folders.h> + +#include <unotools/bootstrap.hxx> + +#include <rtl/ustring.hxx> +#include <rtl/ustrbuf.hxx> +#include <sal/log.hxx> +#include <osl/file.hxx> +#include <osl/diagnose.h> + +#include <rtl/bootstrap.hxx> +#include <rtl/instance.hxx> +#include <osl/process.h> + +// #define this to true, if remembering defaults is not supported properly +#define RTL_BOOTSTRAP_DEFAULTS_BROKEN true + +#define BOOTSTRAP_ITEM_PRODUCT_KEY "ProductKey" +#define BOOTSTRAP_ITEM_VERSIONFILE "Location" +#define BOOTSTRAP_ITEM_BUILDID "buildid" + +#define BOOTSTRAP_ITEM_BASEINSTALLATION "BRAND_BASE_DIR" +#define BOOTSTRAP_ITEM_USERINSTALLATION "UserInstallation" + +#define BOOTSTRAP_ITEM_USERDIR "UserDataDir" + +#define BOOTSTRAP_DEFAULT_BASEINSTALL "$SYSBINDIR/.." + +#define BOOTSTRAP_DIRNAME_USERDIR "user" + +typedef char const * AsciiString; + +namespace utl +{ + +// Implementation class: Bootstrap::Impl + +static OUString makeImplName() +{ + OUString uri; + rtl::Bootstrap::get( "BRAND_BASE_DIR", uri); + return uri + "/" LIBO_ETC_FOLDER "/" SAL_CONFIGFILE("bootstrap"); +} + +class Bootstrap::Impl +{ + const OUString m_aImplName; +public: // struct to cache the result of a path lookup + struct PathData + { + OUString path; + PathStatus status; + + PathData() + : path() + , status(DATA_UNKNOWN) + {} + }; +public: // data members + // base install data + PathData aBaseInstall_; + + // user install data + PathData aUserInstall_; + + // INI files + PathData aBootstrapINI_; + PathData aVersionINI_; + + // overall status + Status status_; + +public: // construction and initialization + Impl() : m_aImplName(makeImplName()) + { + initialize(); + } + + void initialize(); + + // access helper + OUString getBootstrapValue(OUString const& _sName, OUString const& _sDefault) const; + static bool getVersionValue(OUString const& _sName, OUString& _rValue, OUString const& _sDefault); + + const OUString& getImplName() const { return m_aImplName; } + +private: // implementation + bool initBaseInstallationData(rtl::Bootstrap const & _rData); + bool initUserInstallationData(rtl::Bootstrap const & _rData); +}; + +namespace +{ + class theImpl : public rtl::Static<Bootstrap::Impl, theImpl> {}; +} + +const Bootstrap::Impl& Bootstrap::data() +{ + return theImpl::get(); +} + +bool Bootstrap::getProcessWorkingDir(OUString &rUrl) +{ + rUrl.clear(); + OUString s("$OOO_CWD"); + rtl::Bootstrap::expandMacros(s); + if (s.isEmpty()) + { + if (osl_getProcessWorkingDir(&rUrl.pData) == osl_Process_E_None) + return true; + } + else if (s[0] == '1') + { + rUrl = s.copy(1); + return true; + } + else if (s[0] == '2' && + (osl::FileBase::getFileURLFromSystemPath(s.copy(1), rUrl) == + osl::FileBase::E_None)) + { + return true; + } + return false; +} + +void Bootstrap::reloadData() +{ + theImpl::get().initialize(); +} + +// helper + +typedef Bootstrap::PathStatus PathStatus; + +sal_Unicode const cURLSeparator = '/'; + +// path status utility function +static PathStatus implCheckStatusOfURL(OUString const& _sURL, osl::DirectoryItem& aDirItem) +{ + using namespace osl; + + PathStatus eStatus = Bootstrap::DATA_UNKNOWN; + + if (!_sURL.isEmpty()) + { + switch( DirectoryItem::get(_sURL, aDirItem) ) + { + case DirectoryItem::E_None: // Success + eStatus = Bootstrap::PATH_EXISTS; + break; + + case DirectoryItem::E_NOENT: // No such file or directory + eStatus = Bootstrap::PATH_VALID; + break; + + case DirectoryItem::E_INVAL: // the format of the parameters was not valid + case DirectoryItem::E_NAMETOOLONG: // File name too long + case DirectoryItem::E_NOTDIR: // A component of the path prefix of path is not a directory + eStatus = Bootstrap::DATA_INVALID; + break; + + // how to handle these ? + case DirectoryItem::E_LOOP: // Too many symbolic links encountered + case DirectoryItem::E_ACCES: // permission denied + // any other error - what to do ? + default: + eStatus = Bootstrap::DATA_UNKNOWN; + break; + } + } + else + { + eStatus = Bootstrap::DATA_MISSING; + } + + return eStatus; +} + +static bool implNormalizeURL(OUString & _sURL, osl::DirectoryItem& aDirItem) +{ + using namespace osl; + + OSL_PRECOND(aDirItem.is(), "Opened DirItem required"); + + static const sal_uInt32 cosl_FileStatus_Mask = osl_FileStatus_Mask_FileURL; + + FileStatus aFileStatus(cosl_FileStatus_Mask); + + if (aDirItem.getFileStatus(aFileStatus) != DirectoryItem::E_None) + return false; + + OUString aNormalizedURL = aFileStatus.getFileURL(); + + if (aNormalizedURL.isEmpty()) + return false; + + // #109863# sal/osl returns final slash for file URLs contradicting + // the URL/URI RFCs. + if ( !aNormalizedURL.endsWith(OUStringChar(cURLSeparator)) ) + _sURL = aNormalizedURL; + else + _sURL = aNormalizedURL.copy( 0, aNormalizedURL.getLength()-1 ); + + return true; +} + +static bool implEnsureAbsolute(OUString & _rsURL) // also strips embedded dots !! +{ + using osl::File; + + OUString sBasePath; + OSL_VERIFY(Bootstrap::getProcessWorkingDir(sBasePath)); + + OUString sAbsolute; + if ( File::E_None == File::getAbsoluteFileURL(sBasePath, _rsURL, sAbsolute)) + { + _rsURL = sAbsolute; + return true; + } + else + { + OSL_FAIL("Could not get absolute file URL for URL"); + return false; + } +} + +static bool implMakeAbsoluteURL(OUString & _rsPathOrURL) +{ + using namespace osl; + + bool bURL; + + OUString sOther; + // check if it already was normalized + if ( File::E_None == File::getSystemPathFromFileURL(_rsPathOrURL, sOther) ) + { + bURL = true; + } + + else if ( File::E_None == File::getFileURLFromSystemPath(_rsPathOrURL, sOther) ) + { + _rsPathOrURL = sOther; + bURL = true; + } + else + bURL = false; + + return bURL && implEnsureAbsolute(_rsPathOrURL); +} + +static PathStatus dbgCheckStatusOfURL(OUString const& _sURL) +{ + using namespace osl; + + DirectoryItem aDirItem; + + return implCheckStatusOfURL(_sURL,aDirItem); +} + +static PathStatus checkStatusAndNormalizeURL(OUString & _sURL) +{ + using namespace osl; + + PathStatus eStatus = Bootstrap::DATA_UNKNOWN; + + if (_sURL.isEmpty()) + eStatus = Bootstrap::DATA_MISSING; + + else if ( !implMakeAbsoluteURL(_sURL) ) + eStatus = Bootstrap::DATA_INVALID; + + else + { + DirectoryItem aDirItem; + + eStatus = implCheckStatusOfURL(_sURL,aDirItem); + + if (eStatus == Bootstrap::PATH_EXISTS && !implNormalizeURL(_sURL,aDirItem)) + OSL_FAIL("Unexpected failure getting actual URL for existing object"); + } + return eStatus; +} + +// helpers to build and check a nested URL +static PathStatus getDerivedPath( + OUString& _rURL, + OUString const& _aBaseURL, PathStatus _aBaseStatus, + OUString const& _sRelativeURL, + rtl::Bootstrap const & _rData, OUString const& _sBootstrapParameter + ) +{ + OUString sDerivedURL; + OSL_PRECOND(!_rData.getFrom(_sBootstrapParameter,sDerivedURL),"Setting for derived path is already defined"); + OSL_PRECOND(!_sRelativeURL.isEmpty() && _sRelativeURL[0] != cURLSeparator,"Invalid Relative URL"); + + PathStatus aStatus = _aBaseStatus; + + // do we have a base path ? + if (!_aBaseURL.isEmpty()) + { + OSL_PRECOND(!_aBaseURL.endsWith(OUStringChar(cURLSeparator)), "Unexpected: base URL ends in slash"); + + sDerivedURL = _aBaseURL + OUStringChar(cURLSeparator) + _sRelativeURL; + + // a derived (nested) URL can only exist or have a lesser status, if the parent exists + if (aStatus == Bootstrap::PATH_EXISTS) + aStatus = checkStatusAndNormalizeURL(sDerivedURL); + + else // the relative appendix must be valid + OSL_ASSERT(aStatus != Bootstrap::PATH_VALID || dbgCheckStatusOfURL(sDerivedURL) == Bootstrap::PATH_VALID); + + _rData.getFrom(_sBootstrapParameter, _rURL, sDerivedURL); + + OSL_ENSURE(sDerivedURL == _rURL,"Could not set derived URL via Bootstrap default parameter"); + SAL_WARN_IF( !(RTL_BOOTSTRAP_DEFAULTS_BROKEN || (_rData.getFrom(_sBootstrapParameter,sDerivedURL) && sDerivedURL==_rURL)), + "unotools.config", + "Use of default did not affect bootstrap value"); + } + else + { + // clear the result + _rURL = _aBaseURL; + + // if we have no data it can't be a valid path + OSL_ASSERT( aStatus > Bootstrap::PATH_VALID ); + } + + return aStatus; +} + +static PathStatus getDerivedPath( + OUString& _rURL, + Bootstrap::Impl::PathData const& _aBaseData, + OUString const& _sRelativeURL, + rtl::Bootstrap const & _rData, OUString const& _sBootstrapParameter + ) +{ + return getDerivedPath(_rURL,_aBaseData.path,_aBaseData.status,_sRelativeURL,_rData,_sBootstrapParameter); +} + +static OUString getExecutableBaseName() +{ + OUString sExecutable; + + if (osl_Process_E_None == osl_getExecutableFile(&sExecutable.pData)) + { + // split the executable name + sal_Int32 nSepIndex = sExecutable.lastIndexOf(cURLSeparator); + + sExecutable = sExecutable.copy(nSepIndex + 1); + + // ... and get the basename (strip the extension) + sal_Unicode const cExtensionSep = '.'; + + sal_Int32 const nExtIndex = sExecutable.lastIndexOf(cExtensionSep); + sal_Int32 const nExtLength = sExecutable.getLength() - nExtIndex - 1; + if (0 < nExtIndex && nExtLength < 4) + sExecutable = sExecutable.copy(0,nExtIndex); + } + else + SAL_WARN("unotools.config", "Cannot get executable name: osl_getExecutableFile failed"); + + return sExecutable; +} + +static Bootstrap::PathStatus updateStatus(Bootstrap::Impl::PathData & _rResult) +{ + _rResult.status = checkStatusAndNormalizeURL(_rResult.path); + return _rResult.status; +} + +static Bootstrap::PathStatus implGetBootstrapFile(rtl::Bootstrap const & _rData, Bootstrap::Impl::PathData & _rBootstrapFile) +{ + _rData.getIniName(_rBootstrapFile.path); + + return updateStatus(_rBootstrapFile); +} + +static Bootstrap::PathStatus implGetVersionFile(rtl::Bootstrap const & _rData, Bootstrap::Impl::PathData & _rVersionFile) +{ + _rData.getFrom(BOOTSTRAP_ITEM_VERSIONFILE, _rVersionFile.path); + + return updateStatus(_rVersionFile); +} + +// Error reporting + +static char const IS_MISSING[] = "is missing"; +static char const IS_INVALID[] = "is corrupt"; +static char const PERIOD[] = ". "; + +static void addFileError(OUStringBuffer& _rBuf, OUString const& _aPath, AsciiString _sWhat) +{ + OUString sSimpleFileName = _aPath.copy(1 +_aPath.lastIndexOf(cURLSeparator)); + + _rBuf.append("The configuration file"); + _rBuf.append(" '").append(sSimpleFileName).append("' "); + _rBuf.appendAscii(_sWhat).append(PERIOD); +} + +static void addMissingDirectoryError(OUStringBuffer& _rBuf, OUString const& _aPath) +{ + _rBuf.append("The configuration directory"); + _rBuf.append(" '").append(_aPath).append("' "); + _rBuf.append(IS_MISSING).append(PERIOD); +} + +static void addUnexpectedError(OUStringBuffer& _rBuf, AsciiString _sExtraInfo = nullptr) +{ + if (nullptr == _sExtraInfo) + _sExtraInfo = "An internal failure occurred"; + + _rBuf.appendAscii(_sExtraInfo).append(PERIOD); +} + +static Bootstrap::FailureCode describeError(OUStringBuffer& _rBuf, Bootstrap::Impl const& _rData) +{ + Bootstrap::FailureCode eErrCode = Bootstrap::INVALID_BOOTSTRAP_DATA; + + _rBuf.append("The program cannot be started. "); + + switch (_rData.aUserInstall_.status) + { + case Bootstrap::PATH_EXISTS: + switch (_rData.aBaseInstall_.status) + { + case Bootstrap::PATH_VALID: + addMissingDirectoryError(_rBuf, _rData.aBaseInstall_.path); + eErrCode = Bootstrap::MISSING_INSTALL_DIRECTORY; + break; + + case Bootstrap::DATA_INVALID: + addUnexpectedError(_rBuf,"The installation path is invalid"); + break; + + case Bootstrap::DATA_MISSING: + addUnexpectedError(_rBuf,"The installation path is not available"); + break; + + case Bootstrap::PATH_EXISTS: // seems to be all fine (?) + addUnexpectedError(_rBuf,""); + break; + + default: OSL_ASSERT(false); + addUnexpectedError(_rBuf); + break; + } + break; + + case Bootstrap::PATH_VALID: + addMissingDirectoryError(_rBuf, _rData.aUserInstall_.path); + eErrCode = Bootstrap::MISSING_USER_DIRECTORY; + break; + + // else fall through + case Bootstrap::DATA_INVALID: + if (_rData.aVersionINI_.status == Bootstrap::PATH_EXISTS) + { + addFileError(_rBuf, _rData.aVersionINI_.path, IS_INVALID); + eErrCode = Bootstrap::INVALID_VERSION_FILE_ENTRY; + break; + } + [[fallthrough]]; + + case Bootstrap::DATA_MISSING: + switch (_rData.aVersionINI_.status) + { + case Bootstrap::PATH_EXISTS: + addFileError(_rBuf, _rData.aVersionINI_.path, "does not support the current version"); + eErrCode = Bootstrap::MISSING_VERSION_FILE_ENTRY; + break; + + case Bootstrap::PATH_VALID: + addFileError(_rBuf, _rData.aVersionINI_.path, IS_MISSING); + eErrCode = Bootstrap::MISSING_VERSION_FILE; + break; + + default: + switch (_rData.aBootstrapINI_.status) + { + case Bootstrap::PATH_EXISTS: + addFileError(_rBuf, _rData.aBootstrapINI_.path, IS_INVALID); + + if (_rData.aVersionINI_.status == Bootstrap::DATA_MISSING) + eErrCode = Bootstrap::MISSING_BOOTSTRAP_FILE_ENTRY; + else + eErrCode = Bootstrap::INVALID_BOOTSTRAP_FILE_ENTRY; + break; + + case Bootstrap::DATA_INVALID: OSL_ASSERT(false); [[fallthrough]]; + case Bootstrap::PATH_VALID: + addFileError(_rBuf, _rData.aBootstrapINI_.path, IS_MISSING); + eErrCode = Bootstrap::MISSING_BOOTSTRAP_FILE; + break; + + default: + addUnexpectedError(_rBuf); + break; + } + break; + } + break; + + default: OSL_ASSERT(false); + addUnexpectedError(_rBuf); + break; + } + + return eErrCode; +} + + +OUString Bootstrap::getProductKey() +{ + OUString const csProductKeyItem(BOOTSTRAP_ITEM_PRODUCT_KEY); + + OUString const sDefaultProductKey = getExecutableBaseName(); + + return data().getBootstrapValue( csProductKeyItem, sDefaultProductKey ); +} + +OUString Bootstrap::getProductKey(OUString const& _sDefault) +{ + OUString const csProductKeyItem(BOOTSTRAP_ITEM_PRODUCT_KEY); + + return data().getBootstrapValue( csProductKeyItem, _sDefault ); +} + +OUString Bootstrap::getBuildIdData(OUString const& _sDefault) +{ + OUString const csBuildIdItem(BOOTSTRAP_ITEM_BUILDID); + + OUString sBuildId; + // read buildid from version.ini (versionrc), if it doesn't exist or buildid is empty + if ( !utl::Bootstrap::Impl::getVersionValue( csBuildIdItem, sBuildId, _sDefault ) + || sBuildId.isEmpty() ) + { + // read buildid from bootstrap.ini (bootstraprc) + sBuildId = data().getBootstrapValue( csBuildIdItem, _sDefault ); + } + return sBuildId; +} + +Bootstrap::PathStatus Bootstrap::locateBaseInstallation(OUString& _rURL) +{ + Impl::PathData const& aPathData = data().aBaseInstall_; + + _rURL = aPathData.path; + return aPathData.status; +} + +Bootstrap::PathStatus Bootstrap::locateUserInstallation(OUString& _rURL) +{ + Impl::PathData const& aPathData = data().aUserInstall_; + + _rURL = aPathData.path; + return aPathData.status; +} + +Bootstrap::PathStatus Bootstrap::locateUserData(OUString& _rURL) +{ + OUString const csUserDirItem(BOOTSTRAP_ITEM_USERDIR); + + rtl::Bootstrap aData( data().getImplName() ); + + if ( aData.getFrom(csUserDirItem, _rURL) ) + { + return checkStatusAndNormalizeURL(_rURL); + } + else + { + OUString const csUserDir(BOOTSTRAP_DIRNAME_USERDIR); + return getDerivedPath(_rURL, data().aUserInstall_ ,csUserDir, aData, csUserDirItem); + } +} + +Bootstrap::PathStatus Bootstrap::locateBootstrapFile(OUString& _rURL) +{ + Impl::PathData const& aPathData = data().aBootstrapINI_; + + _rURL = aPathData.path; + return aPathData.status; +} + +Bootstrap::PathStatus Bootstrap::locateVersionFile(OUString& _rURL) +{ + Impl::PathData const& aPathData = data().aVersionINI_; + + _rURL = aPathData.path; + return aPathData.status; +} + +Bootstrap::Status Bootstrap::checkBootstrapStatus(OUString& _rDiagnosticMessage, FailureCode& _rErrCode) +{ + Impl const& aData = data(); + + Status result = aData.status_; + + // maybe do further checks here + + OUStringBuffer sErrorBuffer; + if (result != DATA_OK) + _rErrCode = describeError(sErrorBuffer,aData); + + else + _rErrCode = NO_FAILURE; + + _rDiagnosticMessage = sErrorBuffer.makeStringAndClear(); + + return result; +} + + +bool Bootstrap::Impl::initBaseInstallationData(rtl::Bootstrap const & _rData) +{ + OUString const csBaseInstallItem( BOOTSTRAP_ITEM_BASEINSTALLATION ); + OUString const csBaseInstallDefault( BOOTSTRAP_DEFAULT_BASEINSTALL ); + + _rData.getFrom(csBaseInstallItem, aBaseInstall_.path, csBaseInstallDefault); + + bool bResult = (PATH_EXISTS == updateStatus(aBaseInstall_)); + + implGetBootstrapFile(_rData, aBootstrapINI_); + + return bResult; +} + +bool Bootstrap::Impl::initUserInstallationData(rtl::Bootstrap const & _rData) +{ + OUString const csUserInstallItem( BOOTSTRAP_ITEM_USERINSTALLATION ); + + if (_rData.getFrom(csUserInstallItem, aUserInstall_.path)) + { + updateStatus(aUserInstall_); + } + else + { + // should we do just this + aUserInstall_.status = DATA_MISSING; + + // ... or this - look for a single-user user directory ? + OUString const csUserDirItem(BOOTSTRAP_ITEM_USERDIR); + OUString sDummy; + // look for $BASEINSTALLATION/user only if default UserDir setting is used + if (! _rData.getFrom(csUserDirItem, sDummy)) + { + OUString const csUserDir(BOOTSTRAP_DIRNAME_USERDIR); + + if ( PATH_EXISTS == getDerivedPath(sDummy, aBaseInstall_, csUserDir, _rData, csUserDirItem) ) + aUserInstall_ = aBaseInstall_; + } + } + + bool bResult = (PATH_EXISTS == aUserInstall_.status); + + implGetVersionFile(_rData, aVersionINI_); + + return bResult; +} + +void Bootstrap::Impl::initialize() +{ + rtl::Bootstrap aData( m_aImplName ); + + if (!initBaseInstallationData(aData)) + { + status_ = INVALID_BASE_INSTALL; + } + else if (!initUserInstallationData(aData)) + { + status_ = INVALID_USER_INSTALL; + + if (aUserInstall_.status >= DATA_MISSING) + { + switch (aVersionINI_.status) + { + case PATH_EXISTS: + case PATH_VALID: + status_ = MISSING_USER_INSTALL; + break; + + case DATA_INVALID: + case DATA_MISSING: + status_ = INVALID_BASE_INSTALL; + break; + default: + break; + } + } + } + else + { + status_ = DATA_OK; + } +} + +OUString Bootstrap::Impl::getBootstrapValue(OUString const& _sName, OUString const& _sDefault) const +{ + rtl::Bootstrap aData( m_aImplName ); + + OUString sResult; + aData.getFrom(_sName,sResult,_sDefault); + return sResult; +} + +bool Bootstrap::Impl::getVersionValue(OUString const& _sName, OUString& _rValue, OUString const& _sDefault) +{ + // try to open version.ini (versionrc) + OUString uri; + rtl::Bootstrap::get( "BRAND_BASE_DIR", uri); + rtl::Bootstrap aData( uri + "/" LIBO_ETC_FOLDER "/" SAL_CONFIGFILE("version") ); + if ( aData.getHandle() == nullptr ) + // version.ini (versionrc) doesn't exist + return false; + + // read value + aData.getFrom(_sName,_rValue,_sDefault); + return true; +} + +} // namespace utl + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/unotools/source/config/cmdoptions.cxx b/unotools/source/config/cmdoptions.cxx new file mode 100644 index 000000000..5826eb0ac --- /dev/null +++ b/unotools/source/config/cmdoptions.cxx @@ -0,0 +1,356 @@ +/* -*- 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 . + */ + +#include <sal/config.h> + +#include <sal/log.hxx> +#include <unotools/cmdoptions.hxx> +#include <unotools/configitem.hxx> +#include <tools/debug.hxx> +#include <com/sun/star/uno/Any.hxx> +#include <com/sun/star/uno/Sequence.hxx> +#include <com/sun/star/frame/XFrame.hpp> +#include <cppuhelper/weakref.hxx> +#include <rtl/instance.hxx> + +#include "itemholder1.hxx" + +#include <algorithm> +#include <unordered_map> + +using namespace ::std; +using namespace ::utl; +using namespace ::osl; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; + +#define ROOTNODE_CMDOPTIONS "Office.Commands/Execute" +#define PATHDELIMITER "/" + +#define SETNODE_DISABLED "Disabled" + +#define PROPERTYNAME_CMD "Command" + +namespace { + +/*-**************************************************************************************************************** + @descr support simple command option structures and operations on it +****************************************************************************************************************-*/ +class SvtCmdOptions +{ + public: + + // the only way to free memory! + void Clear() + { + m_aCommandHashMap.clear(); + } + + bool HasEntries() const + { + return ( !m_aCommandHashMap.empty() ); + } + + bool Lookup( const OUString& aCmd ) const + { + CommandHashMap::const_iterator pEntry = m_aCommandHashMap.find( aCmd ); + return ( pEntry != m_aCommandHashMap.end() ); + } + + void AddCommand( const OUString& aCmd ) + { + m_aCommandHashMap.emplace( aCmd, 0 ); + } + + private: + typedef std::unordered_map<OUString, sal_Int32> + CommandHashMap; + + CommandHashMap m_aCommandHashMap; +}; + +} + +typedef ::std::vector< css::uno::WeakReference< css::frame::XFrame > > SvtFrameVector; + +class SvtCommandOptions_Impl : public ConfigItem +{ + public: + + SvtCommandOptions_Impl(); + virtual ~SvtCommandOptions_Impl() override; + + /*-**************************************************************************************************** + @short called for notify of configmanager + @descr This method is called from the ConfigManager before the application ends or from the + PropertyChangeListener if the sub tree broadcasts changes. You must update your + internal values. + + @seealso baseclass ConfigItem + + @param "lPropertyNames" is the list of properties which should be updated. + *//*-*****************************************************************************************************/ + + virtual void Notify( const Sequence< OUString >& lPropertyNames ) override; + + /*-**************************************************************************************************** + @short base implementation of public interface for "SvtDynamicMenuOptions"! + @descr These class is used as static member of "SvtDynamicMenuOptions" ... + => The code exist only for one time and isn't duplicated for every instance! + *//*-*****************************************************************************************************/ + + bool HasEntries ( SvtCommandOptions::CmdOption eOption ) const; + bool Lookup ( SvtCommandOptions::CmdOption eCmdOption, const OUString& ) const; + void EstablishFrameCallback(const css::uno::Reference< css::frame::XFrame >& xFrame); + + private: + + virtual void ImplCommit() override; + + /*-**************************************************************************************************** + @short return list of key names of our configuration management which represent our module tree + @descr This method returns the current list of key names! We need it to get needed values from our + configuration management and support dynamical menu item lists! + @param "nDisabledCount", returns count of menu entries for "new" + @return A list of configuration key names is returned. + *//*-*****************************************************************************************************/ + + Sequence< OUString > impl_GetPropertyNames(); + + private: + SvtCmdOptions m_aDisabledCommands; + SvtFrameVector m_lFrames; +}; + +// constructor + +SvtCommandOptions_Impl::SvtCommandOptions_Impl() + // Init baseclasses first + : ConfigItem( ROOTNODE_CMDOPTIONS ) + // Init member then... +{ + // Get names and values of all accessible menu entries and fill internal structures. + // See impl_GetPropertyNames() for further information. + Sequence< OUString > lNames = impl_GetPropertyNames (); + Sequence< Any > lValues = GetProperties ( lNames ); + + // Safe impossible cases. + // We need values from ALL configuration keys. + // Follow assignment use order of values in relation to our list of key names! + DBG_ASSERT( !(lNames.getLength()!=lValues.getLength()), "SvtCommandOptions_Impl::SvtCommandOptions_Impl()\nI miss some values of configuration keys!\n" ); + + // Copy values from list in right order to our internal member. + // Attention: List for names and values have an internal construction pattern! + sal_Int32 nItem = 0; + OUString sCmd; + + // Get names/values for disabled commands. + for( nItem=0; nItem < lNames.getLength(); ++nItem ) + { + // Currently only one value + lValues[nItem] >>= sCmd; + m_aDisabledCommands.AddCommand( sCmd ); + } + +/*TODO: Not used in the moment! see Notify() ... + // Enable notification mechanism of our baseclass. + // We need it to get information about changes outside these class on our used configuration keys! */ + Sequence<OUString> aNotifySeq { "Disabled" }; + EnableNotification( aNotifySeq, true ); +} + +// destructor + +SvtCommandOptions_Impl::~SvtCommandOptions_Impl() +{ + assert(!IsModified()); // should have been committed +} + +// public method + +void SvtCommandOptions_Impl::Notify( const Sequence< OUString >& ) +{ + MutexGuard aGuard( SvtCommandOptions::GetOwnStaticMutex() ); + + Sequence< OUString > lNames = impl_GetPropertyNames (); + Sequence< Any > lValues = GetProperties ( lNames ); + + // Safe impossible cases. + // We need values from ALL configuration keys. + // Follow assignment use order of values in relation to our list of key names! + DBG_ASSERT( !(lNames.getLength()!=lValues.getLength()), "SvtCommandOptions_Impl::Notify()\nI miss some values of configuration keys!\n" ); + + // Copy values from list in right order to our internal member. + // Attention: List for names and values have an internal construction pattern! + sal_Int32 nItem = 0; + OUString sCmd; + + m_aDisabledCommands.Clear(); + + // Get names/values for disabled commands. + for( nItem=0; nItem < lNames.getLength(); ++nItem ) + { + // Currently only one value + lValues[nItem] >>= sCmd; + m_aDisabledCommands.AddCommand( sCmd ); + } + + // don't forget to update all existing frames and her might cached dispatch objects! + // But look for already killed frames. We hold weak references instead of hard ones ... + for (SvtFrameVector::iterator pIt = m_lFrames.begin(); pIt != m_lFrames.end(); ) + { + css::uno::Reference< css::frame::XFrame > xFrame(pIt->get(), css::uno::UNO_QUERY); + if (xFrame.is()) + { + xFrame->contextChanged(); + ++pIt; + } + else + pIt = m_lFrames.erase(pIt); + } +} + +// public method + +void SvtCommandOptions_Impl::ImplCommit() +{ + SAL_WARN("unotools.config","SvtCommandOptions_Impl::ImplCommit(): Not implemented yet!"); +} + +// public method + +bool SvtCommandOptions_Impl::HasEntries( SvtCommandOptions::CmdOption eOption ) const +{ + if ( eOption == SvtCommandOptions::CMDOPTION_DISABLED ) + return m_aDisabledCommands.HasEntries(); + else + return false; +} + +// public method + +bool SvtCommandOptions_Impl::Lookup( SvtCommandOptions::CmdOption eCmdOption, const OUString& aCommand ) const +{ + switch( eCmdOption ) + { + case SvtCommandOptions::CMDOPTION_DISABLED: + { + return m_aDisabledCommands.Lookup( aCommand ); + } + default: + SAL_WARN( "unotools.config", "SvtCommandOptions_Impl::Lookup() Unknown option type given!" ); + } + + return false; +} + +// public method + +void SvtCommandOptions_Impl::EstablishFrameCallback(const css::uno::Reference< css::frame::XFrame >& xFrame) +{ + // check if frame already exists inside list + // ignore double registrations + // every frame must be notified one times only! + css::uno::WeakReference< css::frame::XFrame > xWeak(xFrame); + SvtFrameVector::const_iterator pIt = ::std::find(m_lFrames.begin(), m_lFrames.end(), xWeak); + if (pIt == m_lFrames.end()) + m_lFrames.push_back(xWeak); +} + +// private method + +Sequence< OUString > SvtCommandOptions_Impl::impl_GetPropertyNames() +{ + // First get ALL names of current existing list items in configuration! + Sequence< OUString > lDisabledItems = GetNodeNames( SETNODE_DISABLED, utl::ConfigNameFormat::LocalPath ); + + // Expand all keys + std::transform(lDisabledItems.begin(), lDisabledItems.end(), lDisabledItems.begin(), + [](const OUString& rItem) -> OUString { + return SETNODE_DISABLED PATHDELIMITER + rItem + PATHDELIMITER PROPERTYNAME_CMD; }); + + // Return result. + return lDisabledItems; +} + +namespace { + +std::weak_ptr<SvtCommandOptions_Impl> g_pCommandOptions; + +} + +SvtCommandOptions::SvtCommandOptions() +{ + // Global access, must be guarded (multithreading!). + MutexGuard aGuard( GetOwnStaticMutex() ); + + m_pImpl = g_pCommandOptions.lock(); + if( !m_pImpl ) + { + m_pImpl = std::make_shared<SvtCommandOptions_Impl>(); + g_pCommandOptions = m_pImpl; + ItemHolder1::holdConfigItem(EItem::CmdOptions); + } +} + +SvtCommandOptions::~SvtCommandOptions() +{ + // Global access, must be guarded (multithreading!) + MutexGuard aGuard( GetOwnStaticMutex() ); + + m_pImpl.reset(); +} + +// public method + +bool SvtCommandOptions::HasEntries( CmdOption eOption ) const +{ + MutexGuard aGuard( GetOwnStaticMutex() ); + return m_pImpl->HasEntries( eOption ); +} + +// public method + +bool SvtCommandOptions::Lookup( CmdOption eCmdOption, const OUString& aCommandURL ) const +{ + MutexGuard aGuard( GetOwnStaticMutex() ); + return m_pImpl->Lookup( eCmdOption, aCommandURL ); +} + +// public method + +void SvtCommandOptions::EstablishFrameCallback(const css::uno::Reference< css::frame::XFrame >& xFrame) +{ + MutexGuard aGuard( GetOwnStaticMutex() ); + m_pImpl->EstablishFrameCallback(xFrame); +} + +namespace +{ + class theCommandOptionsMutex : public rtl::Static<osl::Mutex, theCommandOptionsMutex>{}; +} + +// private method + +Mutex& SvtCommandOptions::GetOwnStaticMutex() +{ + return theCommandOptionsMutex::get(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/unotools/source/config/compatibility.cxx b/unotools/source/config/compatibility.cxx new file mode 100644 index 000000000..5556a0a23 --- /dev/null +++ b/unotools/source/config/compatibility.cxx @@ -0,0 +1,378 @@ +/* -*- 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 . + */ + +#include <unotools/compatibility.hxx> +#include <unotools/configitem.hxx> +#include <unotools/syslocale.hxx> +#include <tools/debug.hxx> +#include <sal/log.hxx> +#include <com/sun/star/uno/Any.hxx> +#include <com/sun/star/uno/Sequence.hxx> +#include <com/sun/star/beans/PropertyValue.hpp> +#include <com/sun/star/lang/Locale.hpp> +#include <i18nlangtag/languagetag.hxx> + +#include "itemholder1.hxx" + +#include <algorithm> +#include <vector> + +using namespace ::std; +using namespace ::utl; +using namespace ::osl; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; + +#define ROOTNODE_OPTIONS "Office.Compatibility" +#define PATHDELIMITER "/" +#define SETNODE_ALLFILEFORMATS "AllFileFormats" + +SvtCompatibilityEntry::SvtCompatibilityEntry() + : m_aPropertyValue( SvtCompatibilityEntry::getElementCount() ) +{ + /* Should be in the start. Do not remove it. */ + setValue<OUString>( Index::Name, OUString() ); + setValue<OUString>( Index::Module, OUString() ); + + /* Editable list of default values. Sync it with the SvtCompatibilityEntry::Index enum class. */ + setValue<bool>( Index::UsePrtMetrics, false ); + setValue<bool>( Index::AddSpacing, false ); + setValue<bool>( Index::AddSpacingAtPages, false ); + setValue<bool>( Index::UseOurTabStops, false ); + setValue<bool>( Index::NoExtLeading, false ); + setValue<bool>( Index::UseLineSpacing, false ); + setValue<bool>( Index::AddTableSpacing, false ); + setValue<bool>( Index::UseObjectPositioning, false ); + setValue<bool>( Index::UseOurTextWrapping, false ); + setValue<bool>( Index::ConsiderWrappingStyle, false ); + setValue<bool>( Index::ExpandWordSpace, true ); + setValue<bool>( Index::ProtectForm, false ); + setValue<bool>( Index::MsWordTrailingBlanks, false ); + setValue<bool>( Index::SubtractFlysAnchoredAtFlys, false ); + setValue<bool>( Index::EmptyDbFieldHidesPara, true ); + setValue<bool>( Index::AddTableLineSpacing, false ); + + setDefaultEntry( false ); +} + +OUString SvtCompatibilityEntry::getName( const Index rIdx ) +{ + static const char* sPropertyName[] = + { + /* Should be in the start. Do not remove it. */ + "Name", + "Module", + + /* Editable list of compatibility option names. Sync it with the SvtCompatibilityEntry::Index enum class. */ + "UsePrinterMetrics", + "AddSpacing", + "AddSpacingAtPages", + "UseOurTabStopFormat", + "NoExternalLeading", + "UseLineSpacing", + "AddTableSpacing", + "UseObjectPositioning", + "UseOurTextWrapping", + "ConsiderWrappingStyle", + "ExpandWordSpace", + "ProtectForm", + "MsWordCompTrailingBlanks", + "SubtractFlysAnchoredAtFlys", + "EmptyDbFieldHidesPara", + "AddTableLineSpacing", + }; + + /* Size of sPropertyName array not equal size of the SvtCompatibilityEntry::Index enum class */ + assert( SAL_N_ELEMENTS(sPropertyName) == static_cast<int>( SvtCompatibilityEntry::getElementCount() ) ); + + return OUString::createFromAscii( sPropertyName[ static_cast<int>(rIdx) ] ); +} + +/*-**************************************************************************************************************** + @descr support simple menu structures and operations on it +****************************************************************************************************************-*/ + +/*-**************************************************************************************************** + @short base implementation of public interface for "SvtCompatibilityOptions"! + @descr These class is used as static member of "SvtCompatibilityOptions" ... + => The code exist only for one time and isn't duplicated for every instance! +*//*-*****************************************************************************************************/ +class SvtCompatibilityOptions_Impl : public ConfigItem +{ + public: + SvtCompatibilityOptions_Impl(); + virtual ~SvtCompatibilityOptions_Impl() override; + + void AppendItem( const SvtCompatibilityEntry& aItem ); + void Clear(); + + void SetDefault( SvtCompatibilityEntry::Index rIdx, bool rValue ); + bool GetDefault( SvtCompatibilityEntry::Index rIdx ) const; + + Sequence< Sequence< PropertyValue > > GetList() const; + + /*-**************************************************************************************************** + @short called for notify of configmanager + @descr This method is called from the ConfigManager before the application ends or from the + PropertyChangeListener if the sub tree broadcasts changes. You must update your + internal values. + + @seealso baseclass ConfigItem + + @param "lPropertyNames" is the list of properties which should be updated. + *//*-*****************************************************************************************************/ + virtual void Notify( const Sequence< OUString >& lPropertyNames ) override; + + private: + virtual void ImplCommit() override; + + /*-**************************************************************************************************** + @short return list of key names of our configuration management which represent one module tree + @descr These methods return the current list of key names! We need it to get needed values from our + configuration management and support dynamical menu item lists! + @return A list of configuration key names is returned. + *//*-*****************************************************************************************************/ + Sequence< OUString > impl_GetPropertyNames( Sequence< OUString >& rItems ); + + private: + std::vector< SvtCompatibilityEntry > m_aOptions; + SvtCompatibilityEntry m_aDefOptions; +}; + +SvtCompatibilityOptions_Impl::SvtCompatibilityOptions_Impl() : ConfigItem( ROOTNODE_OPTIONS ) +{ + // Get names and values of all accessible menu entries and fill internal structures. + // See impl_GetPropertyNames() for further information. + Sequence< OUString > lNodes; + Sequence< OUString > lNames = impl_GetPropertyNames( lNodes ); + Sequence< Any > lValues = GetProperties( lNames ); + + // Safe impossible cases. + // We need values from ALL configuration keys. + // Follow assignment use order of values in relation to our list of key names! + DBG_ASSERT( !( lNames.getLength()!=lValues.getLength() ), "SvtCompatibilityOptions_Impl::SvtCompatibilityOptions_Impl()\nI miss some values of configuration keys!\n" ); + + // Get names/values for new menu. + // 4 subkeys for every item! + bool bDefaultFound = false; + sal_Int32 nDestStep = 0; + for ( const auto& rNode : std::as_const(lNodes) ) + { + SvtCompatibilityEntry aItem; + + aItem.setValue<OUString>( SvtCompatibilityEntry::Index::Name, rNode ); + + for ( int i = static_cast<int>(SvtCompatibilityEntry::Index::Module); i < static_cast<int>(SvtCompatibilityEntry::Index::INVALID); ++i ) + { + aItem.setValue( SvtCompatibilityEntry::Index(i), lValues[ nDestStep ] ); + nDestStep++; + } + + m_aOptions.push_back( aItem ); + + if ( !bDefaultFound && aItem.getValue<OUString>( SvtCompatibilityEntry::Index::Name ) == SvtCompatibilityEntry::getDefaultEntryName() ) + { + SvtSysLocale aSysLocale; + css::lang::Locale aLocale = aSysLocale.GetLanguageTag().getLocale(); + if ( aLocale.Language == "zh" || aLocale.Language == "ja" || aLocale.Language == "ko" ) + aItem.setValue<bool>( SvtCompatibilityEntry::Index::ExpandWordSpace, false ); + + m_aDefOptions = aItem; + bDefaultFound = true; + } + } +} + +SvtCompatibilityOptions_Impl::~SvtCompatibilityOptions_Impl() +{ + assert( !IsModified() ); // should have been committed +} + +void SvtCompatibilityOptions_Impl::AppendItem( const SvtCompatibilityEntry& aItem ) +{ + m_aOptions.push_back( aItem ); + + // default item reset? + if ( aItem.getValue<OUString>( SvtCompatibilityEntry::Index::Name ) == SvtCompatibilityEntry::getDefaultEntryName() ) + m_aDefOptions = aItem; + + SetModified(); +} + +void SvtCompatibilityOptions_Impl::Clear() +{ + m_aOptions.clear(); + + SetModified(); +} + +void SvtCompatibilityOptions_Impl::SetDefault( SvtCompatibilityEntry::Index rIdx, bool rValue ) +{ + /* Are not set Name and Module */ + assert( rIdx != SvtCompatibilityEntry::Index::Name && rIdx != SvtCompatibilityEntry::Index::Module ); + + m_aDefOptions.setValue<bool>( rIdx, rValue ); +} + +bool SvtCompatibilityOptions_Impl::GetDefault( SvtCompatibilityEntry::Index rIdx ) const +{ + /* Are not set Name and Module */ + assert( rIdx != SvtCompatibilityEntry::Index::Name && rIdx != SvtCompatibilityEntry::Index::Module ); + + return m_aDefOptions.getValue<bool>( rIdx ); +} + +Sequence< Sequence< PropertyValue > > SvtCompatibilityOptions_Impl::GetList() const +{ + Sequence< PropertyValue > lProperties( SvtCompatibilityEntry::getElementCount() ); + Sequence< Sequence< PropertyValue > > lResult( m_aOptions.size() ); + + for ( int i = static_cast<int>(SvtCompatibilityEntry::Index::Name); i < static_cast<int>(SvtCompatibilityEntry::Index::INVALID); ++i ) + lProperties[i].Name = SvtCompatibilityEntry::getName( SvtCompatibilityEntry::Index(i) ); + + sal_Int32 j = 0; + for ( const auto& rItem : m_aOptions ) + { + for ( int i = static_cast<int>(SvtCompatibilityEntry::Index::Name); i < static_cast<int>(SvtCompatibilityEntry::Index::INVALID); ++i ) + lProperties[i].Value = rItem.getValue( SvtCompatibilityEntry::Index(i) ); + lResult[ j++ ] = lProperties; + } + + return lResult; +} + +void SvtCompatibilityOptions_Impl::Notify( const Sequence< OUString >& ) +{ + SAL_WARN( "unotools.config", "SvtCompatibilityOptions_Impl::Notify() Not implemented yet! I don't know how I can handle a dynamical list of unknown properties ..." ); +} + +void SvtCompatibilityOptions_Impl::ImplCommit() +{ + // Write all properties! + // Delete complete set first. + ClearNodeSet( SETNODE_ALLFILEFORMATS ); + + Sequence< PropertyValue > lPropertyValues( SvtCompatibilityEntry::getElementCount() - 1 ); + sal_uInt32 nNewCount = m_aOptions.size(); + for ( sal_uInt32 nItem = 0; nItem < nNewCount; ++nItem ) + { + SvtCompatibilityEntry aItem = m_aOptions[ nItem ]; + OUString sNode = SETNODE_ALLFILEFORMATS PATHDELIMITER + aItem.getValue<OUString>( SvtCompatibilityEntry::Index::Name ) + PATHDELIMITER; + + for ( int i = static_cast<int>(SvtCompatibilityEntry::Index::Module); i < static_cast<int>(SvtCompatibilityEntry::Index::INVALID); ++i ) + { + lPropertyValues[ i - 1 ].Name = sNode + SvtCompatibilityEntry::getName( SvtCompatibilityEntry::Index(i) ); + lPropertyValues[ i - 1 ].Value = aItem.getValue( SvtCompatibilityEntry::Index(i) ); + } + + SetSetProperties( SETNODE_ALLFILEFORMATS, lPropertyValues ); + } +} + +Sequence< OUString > SvtCompatibilityOptions_Impl::impl_GetPropertyNames( Sequence< OUString >& rItems ) +{ + // First get ALL names of current existing list items in configuration! + rItems = GetNodeNames( SETNODE_ALLFILEFORMATS ); + + // expand list to result list ... + Sequence< OUString > lProperties( rItems.getLength() * ( SvtCompatibilityEntry::getElementCount() - 1 ) ); + + sal_Int32 nDestStep = 0; + // Copy entries to destination and expand every item with 2 supported sub properties. + for ( const auto& rItem : std::as_const(rItems) ) + { + OUString sFixPath = SETNODE_ALLFILEFORMATS PATHDELIMITER + rItem + PATHDELIMITER; + for ( int i = static_cast<int>(SvtCompatibilityEntry::Index::Module); i < static_cast<int>(SvtCompatibilityEntry::Index::INVALID); ++i ) + { + lProperties[ nDestStep ] = sFixPath + SvtCompatibilityEntry::getName( SvtCompatibilityEntry::Index(i) ); + nDestStep++; + } + } + + // Return result. + return lProperties; +} + +namespace +{ + std::weak_ptr<SvtCompatibilityOptions_Impl> theOptions; +} + +SvtCompatibilityOptions::SvtCompatibilityOptions() +{ + // Global access, must be guarded (multithreading!). + MutexGuard aGuard( GetOwnStaticMutex() ); + + m_pImpl = theOptions.lock(); + if ( !m_pImpl ) + { + m_pImpl = std::make_shared<SvtCompatibilityOptions_Impl>(); + theOptions = m_pImpl; + ItemHolder1::holdConfigItem( EItem::Compatibility ); + } +} + +SvtCompatibilityOptions::~SvtCompatibilityOptions() +{ + // Global access, must be guarded (multithreading!) + MutexGuard aGuard( GetOwnStaticMutex() ); + m_pImpl.reset(); +} + +void SvtCompatibilityOptions::AppendItem( const SvtCompatibilityEntry& aItem ) +{ + MutexGuard aGuard( GetOwnStaticMutex() ); + m_pImpl->AppendItem( aItem ); +} + +void SvtCompatibilityOptions::Clear() +{ + MutexGuard aGuard( GetOwnStaticMutex() ); + m_pImpl->Clear(); +} + +void SvtCompatibilityOptions::SetDefault( SvtCompatibilityEntry::Index rIdx, bool rValue ) +{ + MutexGuard aGuard( GetOwnStaticMutex() ); + m_pImpl->SetDefault( rIdx, rValue ); +} + +bool SvtCompatibilityOptions::GetDefault( SvtCompatibilityEntry::Index rIdx ) const +{ + MutexGuard aGuard( GetOwnStaticMutex() ); + return m_pImpl->GetDefault( rIdx ); +} + +Sequence< Sequence< PropertyValue > > SvtCompatibilityOptions::GetList() const +{ + MutexGuard aGuard( GetOwnStaticMutex() ); + return m_pImpl->GetList(); +} + +namespace +{ + class theCompatibilityOptionsMutex : public rtl::Static<osl::Mutex, theCompatibilityOptionsMutex>{}; +} + +Mutex& SvtCompatibilityOptions::GetOwnStaticMutex() +{ + return theCompatibilityOptionsMutex::get(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/unotools/source/config/compatibilityviewoptions.cxx b/unotools/source/config/compatibilityviewoptions.cxx new file mode 100644 index 000000000..b7a64f43f --- /dev/null +++ b/unotools/source/config/compatibilityviewoptions.cxx @@ -0,0 +1,170 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ +/* + * 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/. + */ + +#include <unotools/compatibilityviewoptions.hxx> +#include <unotools/configitem.hxx> +#include "itemholder1.hxx" + +#define ROOTNODE_COMPATIBILITY_VIEW "Office.Compatibility/View" + +#define PROPERTYNAME_MSCOMPATIBLEFORMSMENU "MSCompatibleFormsMenu" + +#define PROPERTYHANDLE_MSCOMPATIBLEFORMSMENU 0 + +class SvtCompatibilityViewOptions_Impl : public utl::ConfigItem +{ +private: + bool m_bShowMSCompatibleFormsMenu; + +public: + SvtCompatibilityViewOptions_Impl(); + virtual ~SvtCompatibilityViewOptions_Impl() override; + + /** + @short Called for notify of configmanager. + + This method is called from the ConfigManager before application ends or from the + PropertyChangeListener if the sub tree broadcasts changes. You must update your + internal values. + + @see baseclass ConfigItem + + @param "seqPropertyNames" is the list of properties which should be updated. + */ + virtual void Notify(const css::uno::Sequence<OUString>& seqPropertyNames) override; + + bool HasMSOCompatibleFormsMenu() const { return m_bShowMSCompatibleFormsMenu; } + void SetMSOCompatibleFormsMenu(bool bSet) + { + bool bModified = (m_bShowMSCompatibleFormsMenu != bSet); + if (bModified) + { + m_bShowMSCompatibleFormsMenu = bSet; + SetModified(); + Commit(); + } + } + +private: + virtual void ImplCommit() override; + + /** + @short Return list of fix key names of our configuration management which represent our module tree. + + This method returns a static const list of key names. We need it to get needed values from our + configuration management. + + @return A list of needed configuration keys is returned. + */ + static css::uno::Sequence<OUString> const& impl_GetPropertyNames(); +}; + +SvtCompatibilityViewOptions_Impl::SvtCompatibilityViewOptions_Impl() + : ConfigItem(ROOTNODE_COMPATIBILITY_VIEW) + , m_bShowMSCompatibleFormsMenu(false) +{ + // Use our static list of configuration keys to get his values. + css::uno::Sequence<OUString> seqNames = impl_GetPropertyNames(); + css::uno::Sequence<css::uno::Any> seqValues = GetProperties(seqNames); + assert(seqNames.getLength() == seqValues.getLength()); + + if (seqValues[PROPERTYHANDLE_MSCOMPATIBLEFORMSMENU].hasValue()) + { + assert(seqValues[PROPERTYHANDLE_MSCOMPATIBLEFORMSMENU].getValueTypeClass() + == css::uno::TypeClass_BOOLEAN); + seqValues[PROPERTYHANDLE_MSCOMPATIBLEFORMSMENU] >>= m_bShowMSCompatibleFormsMenu; + } + + EnableNotification(seqNames); +} + +SvtCompatibilityViewOptions_Impl::~SvtCompatibilityViewOptions_Impl() +{ + assert(!IsModified()); // should have been committed +} + +void SvtCompatibilityViewOptions_Impl::Notify(const css::uno::Sequence<OUString>& seqPropertyNames) +{ + // Use given list of updated properties to get his values from configuration directly! + css::uno::Sequence<css::uno::Any> seqValues = GetProperties(seqPropertyNames); + assert(seqPropertyNames.getLength() == seqValues.getLength()); + + for (sal_Int32 nProperty = 0; nProperty < seqPropertyNames.getLength(); ++nProperty) + { + if (seqPropertyNames[nProperty] == PROPERTYNAME_MSCOMPATIBLEFORMSMENU) + { + assert(seqValues[nProperty].getValueTypeClass() == css::uno::TypeClass_BOOLEAN); + seqValues[nProperty] >>= m_bShowMSCompatibleFormsMenu; + } + } +} + +void SvtCompatibilityViewOptions_Impl::ImplCommit() +{ + // Get names of supported properties, create a list for values and copy current values to it. + css::uno::Sequence<OUString> seqNames = impl_GetPropertyNames(); + css::uno::Sequence<css::uno::Any> seqValues(seqNames.getLength()); + + seqValues[PROPERTYHANDLE_MSCOMPATIBLEFORMSMENU] <<= m_bShowMSCompatibleFormsMenu; + + // Set properties in configuration. + PutProperties(seqNames, seqValues); +} + +css::uno::Sequence<OUString> const& SvtCompatibilityViewOptions_Impl::impl_GetPropertyNames() +{ + static const css::uno::Sequence<OUString> seqPropertyNames{ OUString( + PROPERTYNAME_MSCOMPATIBLEFORMSMENU) }; + return seqPropertyNames; +} + +namespace +{ +std::weak_ptr<SvtCompatibilityViewOptions_Impl> theOptions; +} + +SvtCompatibilityViewOptions::SvtCompatibilityViewOptions() +{ + // Global access, must be guarded (multithreading!). + osl::MutexGuard aGuard(GetOwnStaticMutex()); + + m_pImpl = theOptions.lock(); + if (!m_pImpl) + { + m_pImpl = std::make_shared<SvtCompatibilityViewOptions_Impl>(); + theOptions = m_pImpl; + ItemHolder1::holdConfigItem(EItem::CompatibilityView); + } +} + +SvtCompatibilityViewOptions::~SvtCompatibilityViewOptions() +{ + // Global access, must be guarded (multithreading!) + osl::MutexGuard aGuard(GetOwnStaticMutex()); + m_pImpl.reset(); +} + +bool SvtCompatibilityViewOptions::HasMSOCompatibleFormsMenu() const +{ + return m_pImpl->HasMSOCompatibleFormsMenu(); +} + +void SvtCompatibilityViewOptions::SetMSOCompatibleFormsMenu(bool bSet) +{ + m_pImpl->SetMSOCompatibleFormsMenu(bSet); +} + +osl::Mutex& SvtCompatibilityViewOptions::GetOwnStaticMutex() +{ + static osl::Mutex ourMutex; + + return ourMutex; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/unotools/source/config/configitem.cxx b/unotools/source/config/configitem.cxx new file mode 100644 index 000000000..a67850797 --- /dev/null +++ b/unotools/source/config/configitem.cxx @@ -0,0 +1,1066 @@ +/* -*- 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 . + */ + +#include <sal/config.h> + +#include <sal/log.hxx> +#include <unotools/configitem.hxx> +#include <unotools/configmgr.hxx> +#include <unotools/configpaths.hxx> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/util/XChangesListener.hpp> +#include <com/sun/star/util/XChangesNotifier.hpp> +#include <com/sun/star/container/XHierarchicalNameAccess.hpp> +#include <com/sun/star/configuration/XTemplateContainer.hpp> +#include <com/sun/star/container/XNameContainer.hpp> +#include <com/sun/star/lang/XSingleServiceFactory.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/beans/PropertyValue.hpp> +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <com/sun/star/util/XChangesBatch.hpp> +#include <osl/diagnose.h> +#include <comphelper/sequence.hxx> +#include <comphelper/solarmutex.hxx> +#include <rtl/ref.hxx> +#include <tools/diagnose_ex.h> + +using namespace utl; +using namespace com::sun::star::uno; +using namespace com::sun::star::util; +using namespace com::sun::star::lang; +using namespace com::sun::star::beans; +using namespace com::sun::star::container; +using namespace com::sun::star::configuration; + +#include <cppuhelper/implbase.hxx> + +/* + The ConfigChangeListener_Impl receives notifications from the configuration about changes that + have happened. It forwards this notification to the ConfigItem it knows a pParent by calling its + "CallNotify" method. As ConfigItems are most probably not thread safe, the SolarMutex is acquired + before doing so. +*/ + +namespace utl{ + class ConfigChangeListener_Impl : public cppu::WeakImplHelper + < + css::util::XChangesListener + > + { + public: + ConfigItem* pParent; + const Sequence< OUString > aPropertyNames; + ConfigChangeListener_Impl(ConfigItem& rItem, const Sequence< OUString >& rNames); + + //XChangesListener + virtual void SAL_CALL changesOccurred( const ChangesEvent& Event ) override; + + //XEventListener + virtual void SAL_CALL disposing( const EventObject& Source ) override; + }; +} + +namespace { + +class ValueCounter_Impl +{ + sal_Int16& rCnt; +public: + explicit ValueCounter_Impl(sal_Int16& rCounter) + : rCnt(rCounter) + { + rCnt++; + } + ~ValueCounter_Impl() + { + OSL_ENSURE(rCnt>0, "RefCount < 0 ??"); + rCnt--; + } +}; + +} + +ConfigChangeListener_Impl::ConfigChangeListener_Impl( + ConfigItem& rItem, const Sequence< OUString >& rNames) : + pParent(&rItem), + aPropertyNames(rNames) +{ +} + +void ConfigChangeListener_Impl::changesOccurred( const ChangesEvent& rEvent ) +{ + Sequence<OUString> aChangedNames(rEvent.Changes.getLength()); + OUString* pNames = aChangedNames.getArray(); + + sal_Int32 nNotify = 0; + for(const auto& rElementChange : rEvent.Changes) + { + OUString sTemp; + rElementChange.Accessor >>= sTemp; + //true if the path is completely correct or if it is longer + //i.e ...Print/Content/Graphic and .../Print + bool bFound = std::any_of(aPropertyNames.begin(), aPropertyNames.end(), + [&sTemp](const OUString& rCheckPropertyName) { return isPrefixOfConfigurationPath(sTemp, rCheckPropertyName); }); + if(bFound) + pNames[nNotify++] = sTemp; + } + if( nNotify ) + { + ::comphelper::SolarMutex *pMutex = ::comphelper::SolarMutex::get(); + if ( pMutex ) + { + osl::Guard<comphelper::SolarMutex> aMutexGuard( pMutex ); + aChangedNames.realloc(nNotify); + pParent->CallNotify(aChangedNames); + } + } +} + +void ConfigChangeListener_Impl::disposing( const EventObject& /*rSource*/ ) +{ + pParent->RemoveChangesListener(); +} + +ConfigItem::ConfigItem(const OUString &rSubTree, ConfigItemMode nSetMode ) : + sSubTree(rSubTree), + m_nMode(nSetMode), + m_bIsModified(false), + m_bEnableInternalNotification(false), + m_nInValueChange(0) +{ + if (utl::ConfigManager::IsFuzzing()) + return; + + if (nSetMode & ConfigItemMode::ReleaseTree) + ConfigManager::getConfigManager().addConfigItem(*this); + else + m_xHierarchyAccess = ConfigManager::getConfigManager().addConfigItem(*this); +} + +ConfigItem::~ConfigItem() +{ + RemoveChangesListener(); + ConfigManager::getConfigManager().removeConfigItem(*this); +} + +void ConfigItem::CallNotify( const css::uno::Sequence<OUString>& rPropertyNames ) +{ + // the call is forwarded to the virtual Notify() method + // it is pure virtual, so all classes deriving from ConfigItem have to decide how they + // want to notify listeners + if(m_nInValueChange <= 0 || m_bEnableInternalNotification) + Notify(rPropertyNames); +} + +void ConfigItem::impl_packLocalizedProperties( const Sequence< OUString >& lInNames , + const Sequence< Any >& lInValues , + Sequence< Any >& lOutValues ) +{ + // Safe impossible cases. + // This method should be called for special ConfigItem-mode only! + OSL_ENSURE( ((m_nMode & ConfigItemMode::AllLocales ) == ConfigItemMode::AllLocales), "ConfigItem::impl_packLocalizedProperties() Wrong call of this method detected!" ); + + sal_Int32 nSourceCounter; // used to step during input lists + sal_Int32 nSourceSize; // marks end of loop over input lists + sal_Int32 nDestinationCounter; // actual position in output lists + sal_Int32 nPropertyCounter; // counter of inner loop for Sequence< PropertyValue > + sal_Int32 nPropertiesSize; // marks end of inner loop + Sequence< OUString > lPropertyNames; // list of all locales for localized entry + Sequence< PropertyValue > lProperties; // localized values of a configuration entry packed for return + Reference< XInterface > xLocalizedNode; // if cfg entry is localized ... lInValues contains an XInterface! + + // Optimise follow algorithm ... A LITTLE BIT :-) + // There exist two different possibilities: + // i ) There exist no localized entries ... => size of lOutValues will be the same like lInNames/lInValues! + // ii) There exist some (mostly one or two) localized entries ... => size of lOutValues will be the same like lInNames/lInValues! + // ... Why? If a localized value exist - the any is filled with an XInterface object (is a SetNode-service). + // We read all his child nodes and pack it into Sequence< PropertyValue >. + // The result list we pack into the return any. We never change size of lists! + nSourceSize = lInNames.getLength(); + lOutValues.realloc( nSourceSize ); + + // Algorithm: + // Copy all names and values from in to out lists. + // Look for special localized entries ... You can detect it as "XInterface" packed into an Any. + // Use this XInterface-object to read all localized values and pack it into Sequence< PropertValue >. + // Add this list to out lists then. + + nDestinationCounter = 0; + for( nSourceCounter=0; nSourceCounter<nSourceSize; ++nSourceCounter ) + { + // If item a special localized one ... convert and pack it ... + if( lInValues[nSourceCounter].getValueTypeName() == "com.sun.star.uno.XInterface" ) + { + lInValues[nSourceCounter] >>= xLocalizedNode; + Reference< XNameContainer > xSetAccess( xLocalizedNode, UNO_QUERY ); + if( xSetAccess.is() ) + { + lPropertyNames = xSetAccess->getElementNames(); + nPropertiesSize = lPropertyNames.getLength(); + lProperties.realloc( nPropertiesSize ); + + for( nPropertyCounter=0; nPropertyCounter<nPropertiesSize; ++nPropertyCounter ) + { + lProperties[nPropertyCounter].Name = lPropertyNames[nPropertyCounter]; + OUString sLocaleValue; + xSetAccess->getByName( lPropertyNames[nPropertyCounter] ) >>= sLocaleValue; + lProperties[nPropertyCounter].Value <<= sLocaleValue; + } + + lOutValues[nDestinationCounter] <<= lProperties; + } + } + // ... or copy normal items to return lists directly. + else + { + lOutValues[nDestinationCounter] = lInValues[nSourceCounter]; + } + ++nDestinationCounter; + } +} + +void ConfigItem::impl_unpackLocalizedProperties( const Sequence< OUString >& lInNames , + const Sequence< Any >& lInValues , + Sequence< OUString >& lOutNames , + Sequence< Any >& lOutValues ) +{ + // Safe impossible cases. + // This method should be called for special ConfigItem-mode only! + OSL_ENSURE( ((m_nMode & ConfigItemMode::AllLocales ) == ConfigItemMode::AllLocales), "ConfigItem::impl_unpackLocalizedProperties() Wrong call of this method detected!" ); + + sal_Int32 nSourceSize; // marks end of loop over input lists + sal_Int32 nDestinationCounter; // actual position in output lists + sal_Int32 nPropertiesSize; // marks end of inner loop + OUString sNodeName; // base name of node ( e.g. "UIName/" ) ... expand to locale ( e.g. "UIName/de" ) + Sequence< PropertyValue > lProperties; // localized values of a configuration entry gotten from lInValues-Any + + // Optimise follow algorithm ... A LITTLE BIT :-) + // There exist two different possibilities: + // i ) There exist no localized entries ... => size of lOutNames/lOutValues will be the same like lInNames/lInValues! + // ii) There exist some (mostly one or two) localized entries ... => size of lOutNames/lOutValues will be some bytes greater then lInNames/lInValues. + // => I think we should make it fast for i). ii) is a special case and mustn't be SOOOO... fast. + // We should reserve same space for output list like input ones first. + // Follow algorithm looks for these borders and change it for ii) only! + // It will be faster then a "realloc()" call in every loop ... + nSourceSize = lInNames.getLength(); + + lOutNames.realloc ( nSourceSize ); + lOutValues.realloc ( nSourceSize ); + + // Algorithm: + // Copy all names and values from const to return lists. + // Look for special localized entries ... You can detect it as Sequence< PropertyValue > packed into an Any. + // Split it ... insert PropertyValue.Name to lOutNames and PropertyValue.Value to lOutValues. + + nDestinationCounter = 0; + for( sal_Int32 nSourceCounter=0; nSourceCounter<nSourceSize; ++nSourceCounter ) + { + // If item a special localized one ... split it and insert his parts to output lists ... + if( lInValues[nSourceCounter].getValueType() == cppu::UnoType<Sequence<PropertyValue>>::get() ) + { + lInValues[nSourceCounter] >>= lProperties; + nPropertiesSize = lProperties.getLength(); + + sNodeName = lInNames[nSourceCounter] + "/"; + + if( (nDestinationCounter+nPropertiesSize) > lOutNames.getLength() ) + { + lOutNames.realloc ( nDestinationCounter+nPropertiesSize ); + lOutValues.realloc ( nDestinationCounter+nPropertiesSize ); + } + + for( const auto& rProperty : std::as_const(lProperties) ) + { + lOutNames [nDestinationCounter] = sNodeName + rProperty.Name; + lOutValues[nDestinationCounter] = rProperty.Value; + ++nDestinationCounter; + } + } + // ... or copy normal items to return lists directly. + else + { + if( (nDestinationCounter+1) > lOutNames.getLength() ) + { + lOutNames.realloc ( nDestinationCounter+1 ); + lOutValues.realloc ( nDestinationCounter+1 ); + } + + lOutNames [nDestinationCounter] = lInNames [nSourceCounter]; + lOutValues[nDestinationCounter] = lInValues[nSourceCounter]; + ++nDestinationCounter; + } + } +} + +Sequence< sal_Bool > ConfigItem::GetReadOnlyStates(const css::uno::Sequence< OUString >& rNames) +{ + sal_Int32 i; + + // size of return list is fix! + // Every item must match to length of incoming name list. + sal_Int32 nCount = rNames.getLength(); + Sequence< sal_Bool > lStates(nCount); + + // We must be sure to return a valid information every time! + // Set default to non readonly... similar to the configuration handling of this property. + std::fill(lStates.begin(), lStates.end(), false); + + // no access - no information... + Reference< XHierarchicalNameAccess > xHierarchyAccess = GetTree(); + if (!xHierarchyAccess.is()) + return lStates; + + for (i=0; i<nCount; ++i) + { + try + { + OUString sName = rNames[i]; + OUString sPath; + OUString sProperty; + + (void)::utl::splitLastFromConfigurationPath(sName,sPath,sProperty); + if (sPath.isEmpty() && sProperty.isEmpty()) + { + OSL_FAIL("ConfigItem::IsReadonly() split failed"); + continue; + } + + Reference< XInterface > xNode; + Reference< XPropertySet > xSet; + Reference< XPropertySetInfo > xInfo; + if (!sPath.isEmpty()) + { + Any aNode = xHierarchyAccess->getByHierarchicalName(sPath); + if (!(aNode >>= xNode) || !xNode.is()) + { + OSL_FAIL("ConfigItem::IsReadonly() no set available"); + continue; + } + } + else + { + xNode = xHierarchyAccess; + } + + xSet.set(xNode, UNO_QUERY); + if (xSet.is()) + { + xInfo = xSet->getPropertySetInfo(); + OSL_ENSURE(xInfo.is(), "ConfigItem::IsReadonly() getPropertySetInfo failed ..."); + } + else + { + xInfo.set(xNode, UNO_QUERY); + OSL_ENSURE(xInfo.is(), "ConfigItem::IsReadonly() UNO_QUERY failed ..."); + } + + if (!xInfo.is()) + { + OSL_FAIL("ConfigItem::IsReadonly() no prop info available"); + continue; + } + + Property aProp = xInfo->getPropertyByName(sProperty); + lStates[i] = ((aProp.Attributes & PropertyAttribute::READONLY) == PropertyAttribute::READONLY); + } + catch (const Exception&) + { + } + } + + return lStates; +} + +Sequence< Any > ConfigItem::GetProperties(const Sequence< OUString >& rNames) +{ + Sequence< Any > aRet(rNames.getLength()); + const OUString* pNames = rNames.getConstArray(); + Any* pRet = aRet.getArray(); + Reference<XHierarchicalNameAccess> xHierarchyAccess = GetTree(); + if(xHierarchyAccess.is()) + { + for(int i = 0; i < rNames.getLength(); i++) + { + try + { + pRet[i] = xHierarchyAccess->getByHierarchicalName(pNames[i]); + } + catch (const Exception&) + { + TOOLS_WARN_EXCEPTION( + "unotools.config", + "ignoring XHierarchicalNameAccess to /org.openoffice." + << sSubTree << "/" << pNames[i]); + } + } + + // In special mode "ALL_LOCALES" we must convert localized values to Sequence< PropertyValue >. + if((m_nMode & ConfigItemMode::AllLocales ) == ConfigItemMode::AllLocales) + { + Sequence< Any > lValues; + impl_packLocalizedProperties( rNames, aRet, lValues ); + aRet = lValues; + } + } + return aRet; +} + +bool ConfigItem::PutProperties( const Sequence< OUString >& rNames, + const Sequence< Any>& rValues) +{ + ValueCounter_Impl aCounter(m_nInValueChange); + Reference<XHierarchicalNameAccess> xHierarchyAccess = GetTree(); + Reference<XNameReplace> xTopNodeReplace(xHierarchyAccess, UNO_QUERY); + bool bRet = xHierarchyAccess.is() && xTopNodeReplace.is(); + if(bRet) + { + Sequence< OUString > lNames; + Sequence< Any > lValues; + const OUString* pNames = nullptr; + const Any* pValues = nullptr; + sal_Int32 nNameCount; + if(( m_nMode & ConfigItemMode::AllLocales ) == ConfigItemMode::AllLocales ) + { + // If ConfigItem works in "ALL_LOCALES"-mode ... we must support a Sequence< PropertyValue > + // as value of a localized configuration entry! + // How we can do that? + // We must split all PropertyValues to "Sequence< OUString >" AND "Sequence< Any >"! + impl_unpackLocalizedProperties( rNames, rValues, lNames, lValues ); + pNames = lNames.getConstArray (); + pValues = lValues.getConstArray (); + nNameCount = lNames.getLength (); + } + else + { + // This is the normal mode ... + // Use given input lists directly. + pNames = rNames.getConstArray (); + pValues = rValues.getConstArray (); + nNameCount = rNames.getLength (); + } + for(int i = 0; i < nNameCount; i++) + { + try + { + OUString sNode, sProperty; + if (splitLastFromConfigurationPath(pNames[i],sNode, sProperty)) + { + Any aNode = xHierarchyAccess->getByHierarchicalName(sNode); + + Reference<XNameAccess> xNodeAcc; + aNode >>= xNodeAcc; + Reference<XNameReplace> xNodeReplace(xNodeAcc, UNO_QUERY); + Reference<XNameContainer> xNodeCont (xNodeAcc, UNO_QUERY); + + bool bExist = (xNodeAcc.is() && xNodeAcc->hasByName(sProperty)); + if (bExist && xNodeReplace.is()) + xNodeReplace->replaceByName(sProperty, pValues[i]); + else + if (!bExist && xNodeCont.is()) + xNodeCont->insertByName(sProperty, pValues[i]); + else + bRet = false; + } + else //direct value + { + xTopNodeReplace->replaceByName(sProperty, pValues[i]); + } + } + catch (css::uno::Exception &) + { + TOOLS_WARN_EXCEPTION("unotools.config", "Exception from PutProperties"); + } + } + try + { + Reference<XChangesBatch> xBatch(xHierarchyAccess, UNO_QUERY); + xBatch->commitChanges(); + } + catch (css::uno::Exception &) + { + TOOLS_WARN_EXCEPTION("unotools.config", "Exception from commitChanges"); + } + } + + return bRet; +} + +void ConfigItem::DisableNotification() +{ + OSL_ENSURE( xChangeLstnr.is(), "ConfigItem::DisableNotification: notifications not enabled currently!" ); + RemoveChangesListener(); +} + +bool ConfigItem::EnableNotification(const Sequence< OUString >& rNames, + bool bEnableInternalNotification ) +{ + OSL_ENSURE(!(m_nMode & ConfigItemMode::ReleaseTree), "notification in ConfigItemMode::ReleaseTree mode not possible"); + m_bEnableInternalNotification = bEnableInternalNotification; + Reference<XHierarchicalNameAccess> xHierarchyAccess = GetTree(); + Reference<XChangesNotifier> xChgNot(xHierarchyAccess, UNO_QUERY); + if(!xChgNot.is()) + return false; + + OSL_ENSURE(!xChangeLstnr.is(), "EnableNotification already called"); + if(xChangeLstnr.is()) + xChgNot->removeChangesListener( xChangeLstnr ); + bool bRet = true; + + try + { + xChangeLstnr = new ConfigChangeListener_Impl(*this, rNames); + xChgNot->addChangesListener( xChangeLstnr ); + } + catch (const RuntimeException&) + { + bRet = false; + } + return bRet; +} + +void ConfigItem::RemoveChangesListener() +{ + Reference<XHierarchicalNameAccess> xHierarchyAccess = GetTree(); + if(xHierarchyAccess.is()) + { + Reference<XChangesNotifier> xChgNot(xHierarchyAccess, UNO_QUERY); + if(xChgNot.is() && xChangeLstnr.is()) + { + try + { + xChgNot->removeChangesListener( xChangeLstnr ); + xChangeLstnr = nullptr; + } + catch (const Exception&) + { + } + } + } +} + +static void lcl_normalizeLocalNames(Sequence< OUString >& _rNames, ConfigNameFormat _eFormat, Reference<XInterface> const& _xParentNode) +{ + switch (_eFormat) + { + case ConfigNameFormat::LocalNode: + // unaltered - this is our input format + break; + + case ConfigNameFormat::LocalPath: + { + Reference<XTemplateContainer> xTypeContainer(_xParentNode, UNO_QUERY); + if (xTypeContainer.is()) + { + OUString sTypeName = xTypeContainer->getElementTemplateName(); + sTypeName = sTypeName.copy(sTypeName.lastIndexOf('/')+1); + + std::transform(_rNames.begin(), _rNames.end(), _rNames.begin(), + [&sTypeName](const OUString& rName) -> OUString { return wrapConfigurationElementName(rName,sTypeName); }); + } + else + { + Reference<XServiceInfo> xSVI(_xParentNode, UNO_QUERY); + if (xSVI.is() && xSVI->supportsService("com.sun.star.configuration.SetAccess")) + { + std::transform(_rNames.begin(), _rNames.end(), _rNames.begin(), + [](const OUString& rName) -> OUString { return wrapConfigurationElementName(rName); }); + } + } + } + break; + + } +} + +Sequence< OUString > ConfigItem::GetNodeNames(const OUString& rNode) +{ + ConfigNameFormat const eDefaultFormat = ConfigNameFormat::LocalNode; // CONFIG_NAME_DEFAULT; + + return GetNodeNames(rNode, eDefaultFormat); +} + +Sequence< OUString > ConfigItem::GetNodeNames(const OUString& rNode, ConfigNameFormat eFormat) +{ + Sequence< OUString > aRet; + Reference<XHierarchicalNameAccess> xHierarchyAccess = GetTree(); + if(xHierarchyAccess.is()) + { + try + { + Reference<XNameAccess> xCont; + if(!rNode.isEmpty()) + { + Any aNode = xHierarchyAccess->getByHierarchicalName(rNode); + aNode >>= xCont; + } + else + xCont.set(xHierarchyAccess, UNO_QUERY); + if(xCont.is()) + { + aRet = xCont->getElementNames(); + lcl_normalizeLocalNames(aRet,eFormat,xCont); + } + + } + catch (css::uno::Exception &) + { + TOOLS_WARN_EXCEPTION("unotools.config", "Exception from GetNodeNames"); + } + } + return aRet; +} + +bool ConfigItem::ClearNodeSet(const OUString& rNode) +{ + ValueCounter_Impl aCounter(m_nInValueChange); + bool bRet = false; + Reference<XHierarchicalNameAccess> xHierarchyAccess = GetTree(); + if(xHierarchyAccess.is()) + { + try + { + Reference<XNameContainer> xCont; + if(!rNode.isEmpty()) + { + Any aNode = xHierarchyAccess->getByHierarchicalName(rNode); + aNode >>= xCont; + } + else + xCont.set(xHierarchyAccess, UNO_QUERY); + if(!xCont.is()) + return false; + const Sequence< OUString > aNames = xCont->getElementNames(); + Reference<XChangesBatch> xBatch(xHierarchyAccess, UNO_QUERY); + for(const OUString& rName : aNames) + { + try + { + xCont->removeByName(rName); + } + catch (css::uno::Exception &) + { + TOOLS_WARN_EXCEPTION("unotools.config", "Exception from removeByName"); + } + } + xBatch->commitChanges(); + bRet = true; + } + catch (css::uno::Exception &) + { + TOOLS_WARN_EXCEPTION("unotools.config", "Exception from ClearNodeSet"); + } + } + return bRet; +} + +bool ConfigItem::ClearNodeElements(const OUString& rNode, Sequence< OUString > const & rElements) +{ + ValueCounter_Impl aCounter(m_nInValueChange); + bool bRet = false; + Reference<XHierarchicalNameAccess> xHierarchyAccess = GetTree(); + if(xHierarchyAccess.is()) + { + try + { + Reference<XNameContainer> xCont; + if(!rNode.isEmpty()) + { + Any aNode = xHierarchyAccess->getByHierarchicalName(rNode); + aNode >>= xCont; + } + else + xCont.set(xHierarchyAccess, UNO_QUERY); + if(!xCont.is()) + return false; + try + { + for(const OUString& rElement : rElements) + { + xCont->removeByName(rElement); + } + Reference<XChangesBatch> xBatch(xHierarchyAccess, UNO_QUERY); + xBatch->commitChanges(); + } + catch (css::uno::Exception &) + { + TOOLS_WARN_EXCEPTION("unotools.config", "Exception from commitChanges()"); + } + bRet = true; + } + catch (css::uno::Exception &) + { + TOOLS_WARN_EXCEPTION("unotools.config", "Exception from GetNodeNames()"); + } + } + return bRet; +} + +static OUString lcl_extractSetPropertyName( const OUString& rInPath, const OUString& rPrefix ) +{ + OUString const sSubPath = dropPrefixFromConfigurationPath( rInPath, rPrefix); + return extractFirstFromConfigurationPath( sSubPath ); +} + +static +Sequence< OUString > lcl_extractSetPropertyNames( const Sequence< PropertyValue >& rValues, const OUString& rPrefix ) +{ + Sequence< OUString > aSubNodeNames(rValues.getLength()); + OUString* pSubNodeNames = aSubNodeNames.getArray(); + + OUString sLastSubNode; + sal_Int32 nSubIndex = 0; + + for(const PropertyValue& rProperty : rValues) + { + OUString const sSubPath = dropPrefixFromConfigurationPath( rProperty.Name, rPrefix); + OUString const sSubNode = extractFirstFromConfigurationPath( sSubPath ); + + if(sLastSubNode != sSubNode) + { + pSubNodeNames[nSubIndex++] = sSubNode; + } + + sLastSubNode = sSubNode; + } + aSubNodeNames.realloc(nSubIndex); + + return aSubNodeNames; +} + +// Add or change properties +bool ConfigItem::SetSetProperties( + const OUString& rNode, const Sequence< PropertyValue >& rValues) +{ + ValueCounter_Impl aCounter(m_nInValueChange); + bool bRet = true; + Reference<XHierarchicalNameAccess> xHierarchyAccess = GetTree(); + if(xHierarchyAccess.is()) + { + Reference<XChangesBatch> xBatch(xHierarchyAccess, UNO_QUERY); + try + { + Reference<XNameContainer> xCont; + if(!rNode.isEmpty()) + { + Any aNode = xHierarchyAccess->getByHierarchicalName(rNode); + aNode >>= xCont; + } + else + xCont.set(xHierarchyAccess, UNO_QUERY); + if(!xCont.is()) + return false; + + Reference<XSingleServiceFactory> xFac(xCont, UNO_QUERY); + + if(xFac.is()) + { + const Sequence< OUString > aSubNodeNames = lcl_extractSetPropertyNames(rValues, rNode); + + for(const auto& rSubNodeName : aSubNodeNames) + { + if(!xCont->hasByName(rSubNodeName)) + { + Reference<XInterface> xInst = xFac->createInstance(); + Any aVal; aVal <<= xInst; + xCont->insertByName(rSubNodeName, aVal); + } + //set values + } + try + { + xBatch->commitChanges(); + } + catch (css::uno::Exception &) + { + TOOLS_WARN_EXCEPTION("unotools.config", "Exception from commitChanges()"); + } + + const PropertyValue* pProperties = rValues.getConstArray(); + + Sequence< OUString > aSetNames(rValues.getLength()); + OUString* pSetNames = aSetNames.getArray(); + + Sequence< Any> aSetValues(rValues.getLength()); + Any* pSetValues = aSetValues.getArray(); + + bool bEmptyNode = rNode.isEmpty(); + for(sal_Int32 k = 0; k < rValues.getLength(); k++) + { + pSetNames[k] = pProperties[k].Name.copy( bEmptyNode ? 1 : 0); + pSetValues[k] = pProperties[k].Value; + } + bRet = PutProperties(aSetNames, aSetValues); + } + else + { + //if no factory is available then the node contains basic data elements + for(const PropertyValue& rValue : rValues) + { + try + { + OUString sSubNode = lcl_extractSetPropertyName( rValue.Name, rNode ); + + if(xCont->hasByName(sSubNode)) + xCont->replaceByName(sSubNode, rValue.Value); + else + xCont->insertByName(sSubNode, rValue.Value); + + OSL_ENSURE( xHierarchyAccess->hasByHierarchicalName(rValue.Name), + "Invalid config path" ); + } + catch (css::uno::Exception &) + { + TOOLS_WARN_EXCEPTION("unotools.config", "Exception from insert/replaceByName()"); + } + } + xBatch->commitChanges(); + } + } + catch (const Exception&) + { + TOOLS_WARN_EXCEPTION("unotools.config", "Exception from SetSetProperties"); + bRet = false; + } + } + return bRet; +} + +bool ConfigItem::ReplaceSetProperties( + const OUString& rNode, const Sequence< PropertyValue >& rValues) +{ + ValueCounter_Impl aCounter(m_nInValueChange); + bool bRet = true; + Reference<XHierarchicalNameAccess> xHierarchyAccess = GetTree(); + if(xHierarchyAccess.is()) + { + Reference<XChangesBatch> xBatch(xHierarchyAccess, UNO_QUERY); + try + { + Reference<XNameContainer> xCont; + if(!rNode.isEmpty()) + { + Any aNode = xHierarchyAccess->getByHierarchicalName(rNode); + aNode >>= xCont; + } + else + xCont.set(xHierarchyAccess, UNO_QUERY); + if(!xCont.is()) + return false; + + // JB: Change: now the same name handling for sets of simple values + const Sequence< OUString > aSubNodeNames = lcl_extractSetPropertyNames(rValues, rNode); + + Reference<XSingleServiceFactory> xFac(xCont, UNO_QUERY); + const bool isSimpleValueSet = !xFac.is(); + + //remove unknown members first + { + const Sequence<OUString> aContainerSubNodes = xCont->getElementNames(); + + for(const OUString& rContainerSubNode : aContainerSubNodes) + { + bool bFound = comphelper::findValue(aSubNodeNames, rContainerSubNode) != -1; + if(!bFound) + try + { + xCont->removeByName(rContainerSubNode); + } + catch (const Exception&) + { + if (isSimpleValueSet) + { + try + { + // #i37322#: fallback action: replace with <void/> + xCont->replaceByName(rContainerSubNode, Any()); + // fallback successful: continue looping + continue; + } + catch (Exception &) + {} // propagate original exception, if fallback fails + } + throw; + } + } + try { xBatch->commitChanges(); } + catch (css::uno::Exception &) + { + TOOLS_WARN_EXCEPTION("unotools.config", "Exception from commitChanges"); + } + } + + if(xFac.is()) // !isSimpleValueSet + { + for(const OUString& rSubNodeName : aSubNodeNames) + { + if(!xCont->hasByName(rSubNodeName)) + { + //create if not available + Reference<XInterface> xInst = xFac->createInstance(); + Any aVal; aVal <<= xInst; + xCont->insertByName(rSubNodeName, aVal); + } + } + try { xBatch->commitChanges(); } + catch (css::uno::Exception &) + { + TOOLS_WARN_EXCEPTION("unotools.config", "Exception from commitChanges"); + } + + const PropertyValue* pProperties = rValues.getConstArray(); + + Sequence< OUString > aSetNames(rValues.getLength()); + OUString* pSetNames = aSetNames.getArray(); + + Sequence< Any> aSetValues(rValues.getLength()); + Any* pSetValues = aSetValues.getArray(); + + bool bEmptyNode = rNode.isEmpty(); + for(sal_Int32 k = 0; k < rValues.getLength(); k++) + { + pSetNames[k] = pProperties[k].Name.copy( bEmptyNode ? 1 : 0); + pSetValues[k] = pProperties[k].Value; + } + bRet = PutProperties(aSetNames, aSetValues); + } + else + { + //if no factory is available then the node contains basic data elements + for(const PropertyValue& rValue : rValues) + { + try + { + OUString sSubNode = lcl_extractSetPropertyName( rValue.Name, rNode ); + + if(xCont->hasByName(sSubNode)) + xCont->replaceByName(sSubNode, rValue.Value); + else + xCont->insertByName(sSubNode, rValue.Value); + } + catch (css::uno::Exception &) + { + TOOLS_WARN_EXCEPTION("unotools.config", "Exception from insert/replaceByName"); + } + } + xBatch->commitChanges(); + } + } + catch (const Exception& ) + { + TOOLS_WARN_EXCEPTION("unotools.config", "Exception from ReplaceSetProperties"); + bRet = false; + } + } + return bRet; +} + +bool ConfigItem::AddNode(const OUString& rNode, const OUString& rNewNode) +{ + ValueCounter_Impl aCounter(m_nInValueChange); + bool bRet = true; + Reference<XHierarchicalNameAccess> xHierarchyAccess = GetTree(); + if(xHierarchyAccess.is()) + { + Reference<XChangesBatch> xBatch(xHierarchyAccess, UNO_QUERY); + try + { + Reference<XNameContainer> xCont; + if(!rNode.isEmpty()) + { + Any aNode = xHierarchyAccess->getByHierarchicalName(rNode); + aNode >>= xCont; + } + else + xCont.set(xHierarchyAccess, UNO_QUERY); + if(!xCont.is()) + return false; + + Reference<XSingleServiceFactory> xFac(xCont, UNO_QUERY); + + if(xFac.is()) + { + if(!xCont->hasByName(rNewNode)) + { + Reference<XInterface> xInst = xFac->createInstance(); + Any aVal; aVal <<= xInst; + xCont->insertByName(rNewNode, aVal); + } + try + { + xBatch->commitChanges(); + } + catch (css::uno::Exception &) + { + TOOLS_WARN_EXCEPTION("unotools.config", "Exception from commitChanges"); + } + } + else + { + //if no factory is available then the node contains basic data elements + try + { + if(!xCont->hasByName(rNewNode)) + xCont->insertByName(rNewNode, Any()); + } + catch (css::uno::Exception &) + { + TOOLS_WARN_EXCEPTION("unotools.config", "Exception from AddNode"); + } + } + xBatch->commitChanges(); + } + catch (const Exception&) + { + DBG_UNHANDLED_EXCEPTION("unotools.config"); + bRet = false; + } + } + return bRet; +} + + +void ConfigItem::SetModified() +{ + m_bIsModified = true; +} + +void ConfigItem::ClearModified() +{ + m_bIsModified = false; +} + +Reference< XHierarchicalNameAccess> ConfigItem::GetTree() +{ + Reference< XHierarchicalNameAccess> xRet; + if (utl::ConfigManager::IsFuzzing()) + return xRet; + if(!m_xHierarchyAccess.is()) + xRet = ConfigManager::acquireTree(*this); + else + xRet = m_xHierarchyAccess; + return xRet; +} + +void ConfigItem::Commit() +{ + ImplCommit(); + ClearModified(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/unotools/source/config/configmgr.cxx b/unotools/source/config/configmgr.cxx new file mode 100644 index 000000000..610246295 --- /dev/null +++ b/unotools/source/config/configmgr.cxx @@ -0,0 +1,186 @@ +/* -*- 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 . + */ + +#include <sal/config.h> + +#include <com/sun/star/beans/NamedValue.hpp> +#include <com/sun/star/container/XHierarchicalNameAccess.hpp> +#include <com/sun/star/configuration/theDefaultProvider.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/uno/Any.hxx> +#include <com/sun/star/uno/Reference.hxx> +#include <com/sun/star/uno/Sequence.hxx> +#include <i18nlangtag/languagetag.hxx> +#include <officecfg/Setup.hxx> +#include <rtl/instance.hxx> +#include <rtl/ustring.hxx> +#include <sal/log.hxx> +#include <unotools/configitem.hxx> +#include <unotools/configmgr.hxx> +#include <comphelper/processfactory.hxx> + +namespace { + +class RegisterConfigItemHelper { +public: + RegisterConfigItemHelper( + utl::ConfigManager & manager, utl::ConfigItem & item): + manager_(manager), item_(&item) + { + manager.registerConfigItem(item_); + } + + ~RegisterConfigItemHelper() { + if (item_ != nullptr) { + manager_.removeConfigItem(*item_); + } + } + + void keep() { item_ = nullptr; } + +private: + utl::ConfigManager & manager_; + utl::ConfigItem * item_; + + RegisterConfigItemHelper(const RegisterConfigItemHelper&) = delete; + RegisterConfigItemHelper& operator=(const RegisterConfigItemHelper&) = delete; +}; + +css::uno::Reference< css::lang::XMultiServiceFactory > +getConfigurationProvider() { + return css::configuration::theDefaultProvider::get( comphelper::getProcessComponentContext() ); +} + +struct theConfigManager: + public rtl::Static< utl::ConfigManager, theConfigManager > +{}; + +} + +OUString utl::ConfigManager::getAboutBoxProductVersion() { + return officecfg::Setup::Product::ooSetupVersionAboutBox::get(); +} + +OUString utl::ConfigManager::getAboutBoxProductVersionSuffix() { + return officecfg::Setup::Product::ooSetupVersionAboutBoxSuffix::get(); +} + +OUString utl::ConfigManager::getDefaultCurrency() { + return officecfg::Setup::L10N::ooSetupCurrency::get(); +} + +OUString utl::ConfigManager::getUILocale() { + return officecfg::Setup::L10N::ooLocale::get(); +} + +OUString utl::ConfigManager::getWorkLocale() { + return officecfg::Setup::L10N::ooSetupSystemLocale::get(); +} + +OUString utl::ConfigManager::getProductExtension() { + return officecfg::Setup::Product::ooSetupExtension::get(); +} + +OUString utl::ConfigManager::getProductName() { + return officecfg::Setup::Product::ooName::get(); +} + +OUString utl::ConfigManager::getProductVersion() { + return officecfg::Setup::Product::ooSetupVersion::get(); +} + +OUString utl::ConfigManager::getVendor() { + return officecfg::Setup::Product::ooVendor::get(); +} + +void utl::ConfigManager::storeConfigItems() { + getConfigManager().doStoreConfigItems(); +} + +utl::ConfigManager & utl::ConfigManager::getConfigManager() { + return theConfigManager::get(); +} + +css::uno::Reference< css::container::XHierarchicalNameAccess > +utl::ConfigManager::acquireTree(utl::ConfigItem const & item) { + css::uno::Sequence< css::uno::Any > args(1); + args[0] <<= css::beans::NamedValue( + "nodepath", + css::uno::makeAny("/org.openoffice." + item.GetSubTreeName())); + if (item.GetMode() & ConfigItemMode::AllLocales) { + args.realloc(2); + args[1] <<= css::beans::NamedValue("locale", css::uno::makeAny(OUString("*"))); + } + return css::uno::Reference< css::container::XHierarchicalNameAccess >( + getConfigurationProvider()->createInstanceWithArguments( + "com.sun.star.configuration.ConfigurationUpdateAccess", + args), + css::uno::UNO_QUERY_THROW); +} + +utl::ConfigManager::ConfigManager() {} + +utl::ConfigManager::~ConfigManager() { + SAL_WARN_IF(!items_.empty(), "unotools.config", "ConfigManager not empty"); +} + +css::uno::Reference< css::container::XHierarchicalNameAccess > +utl::ConfigManager::addConfigItem(utl::ConfigItem & item) { + RegisterConfigItemHelper reg(*this, item); + css::uno::Reference< css::container::XHierarchicalNameAccess > tree( + acquireTree(item)); + reg.keep(); + return tree; +} + +void utl::ConfigManager::removeConfigItem(utl::ConfigItem & item) { + items_.erase(std::remove(items_.begin(), items_.end(), &item), items_.end()); +} + +void utl::ConfigManager::registerConfigItem(utl::ConfigItem * item) { + assert(item != nullptr); + items_.push_back(item); +} + +void utl::ConfigManager::doStoreConfigItems() { + for (auto const& item : items_) + { + if (item->IsModified()) { + item->Commit(); + item->ClearModified(); + } + } +} + +static bool bIsFuzzing = false; + +#if !defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) +bool utl::ConfigManager::IsFuzzing() +{ + return bIsFuzzing; +} +#endif + +void utl::ConfigManager::EnableFuzzing() +{ + bIsFuzzing = true; + LanguageTag::disable_lt_tag_parse(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/unotools/source/config/confignode.cxx b/unotools/source/config/confignode.cxx new file mode 100644 index 000000000..59c5fbba8 --- /dev/null +++ b/unotools/source/config/confignode.cxx @@ -0,0 +1,578 @@ +/* -*- 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 . + */ + +#include <unotools/confignode.hxx> +#include <unotools/configpaths.hxx> +#include <tools/diagnose_ex.h> +#include <osl/diagnose.h> +#include <sal/log.hxx> +#include <com/sun/star/configuration/theDefaultProvider.hpp> +#include <com/sun/star/lang/XSingleServiceFactory.hpp> +#include <com/sun/star/lang/XComponent.hpp> +#include <com/sun/star/util/XChangesBatch.hpp> +#include <com/sun/star/util/XStringEscape.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/container/XNamed.hpp> +#include <com/sun/star/container/XNameContainer.hpp> +#include <com/sun/star/container/XHierarchicalNameAccess.hpp> +#include <comphelper/namedvaluecollection.hxx> + +namespace utl +{ + + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::lang; + using namespace ::com::sun::star::util; + using namespace ::com::sun::star::beans; + using namespace ::com::sun::star::container; + using namespace ::com::sun::star::configuration; + + //= OConfigurationNode + + OConfigurationNode::OConfigurationNode(const Reference< XInterface >& _rxNode ) + :m_bEscapeNames(false) + { + OSL_ENSURE(_rxNode.is(), "OConfigurationNode::OConfigurationNode: invalid node interface!"); + if (_rxNode.is()) + { + // collect all interfaces necessary + m_xHierarchyAccess.set(_rxNode, UNO_QUERY); + m_xDirectAccess.set(_rxNode, UNO_QUERY); + + // reset _all_ interfaces if _one_ of them is not supported + if (!m_xHierarchyAccess.is() || !m_xDirectAccess.is()) + { + m_xHierarchyAccess = nullptr; + m_xDirectAccess = nullptr; + } + + // now for the non-critical interfaces + m_xReplaceAccess.set(_rxNode, UNO_QUERY); + m_xContainerAccess.set(_rxNode, UNO_QUERY); + } + + Reference< XComponent > xConfigNodeComp(m_xDirectAccess, UNO_QUERY); + if (xConfigNodeComp.is()) + startComponentListening(xConfigNodeComp); + + if (isValid()) + m_bEscapeNames = isSetNode() && Reference< XStringEscape >::query(m_xDirectAccess).is(); + } + + OConfigurationNode::OConfigurationNode(const OConfigurationNode& _rSource) + : OEventListenerAdapter() + , m_xHierarchyAccess(_rSource.m_xHierarchyAccess) + , m_xDirectAccess(_rSource.m_xDirectAccess) + , m_xReplaceAccess(_rSource.m_xReplaceAccess) + , m_xContainerAccess(_rSource.m_xContainerAccess) + , m_bEscapeNames(_rSource.m_bEscapeNames) + { + Reference< XComponent > xConfigNodeComp(m_xDirectAccess, UNO_QUERY); + if (xConfigNodeComp.is()) + startComponentListening(xConfigNodeComp); + } + + OConfigurationNode::OConfigurationNode(OConfigurationNode&& _rSource) + : OEventListenerAdapter() + , m_xHierarchyAccess(std::move(_rSource.m_xHierarchyAccess)) + , m_xDirectAccess(std::move(_rSource.m_xDirectAccess)) + , m_xReplaceAccess(std::move(_rSource.m_xReplaceAccess)) + , m_xContainerAccess(std::move(_rSource.m_xContainerAccess)) + , m_bEscapeNames(std::move(_rSource.m_bEscapeNames)) + { + Reference< XComponent > xConfigNodeComp(m_xDirectAccess, UNO_QUERY); + if (xConfigNodeComp.is()) + startComponentListening(xConfigNodeComp); + } + + OConfigurationNode& OConfigurationNode::operator=(const OConfigurationNode& _rSource) + { + stopAllComponentListening(); + + m_xHierarchyAccess = _rSource.m_xHierarchyAccess; + m_xDirectAccess = _rSource.m_xDirectAccess; + m_xContainerAccess = _rSource.m_xContainerAccess; + m_xReplaceAccess = _rSource.m_xReplaceAccess; + m_bEscapeNames = _rSource.m_bEscapeNames; + + Reference< XComponent > xConfigNodeComp(m_xDirectAccess, UNO_QUERY); + if (xConfigNodeComp.is()) + startComponentListening(xConfigNodeComp); + + return *this; + } + + OConfigurationNode& OConfigurationNode::operator=(OConfigurationNode&& _rSource) + { + stopAllComponentListening(); + + m_xHierarchyAccess = std::move(_rSource.m_xHierarchyAccess); + m_xDirectAccess = std::move(_rSource.m_xDirectAccess); + m_xContainerAccess = std::move(_rSource.m_xContainerAccess); + m_xReplaceAccess = std::move(_rSource.m_xReplaceAccess); + m_bEscapeNames = std::move(_rSource.m_bEscapeNames); + + Reference< XComponent > xConfigNodeComp(m_xDirectAccess, UNO_QUERY); + if (xConfigNodeComp.is()) + startComponentListening(xConfigNodeComp); + + return *this; + } + + void OConfigurationNode::_disposing( const EventObject& _rSource ) + { + Reference< XComponent > xDisposingSource(_rSource.Source, UNO_QUERY); + Reference< XComponent > xConfigNodeComp(m_xDirectAccess, UNO_QUERY); + if (xDisposingSource.get() == xConfigNodeComp.get()) + clear(); + } + + OUString OConfigurationNode::getLocalName() const + { + OUString sLocalName; + try + { + Reference< XNamed > xNamed( m_xDirectAccess, UNO_QUERY_THROW ); + sLocalName = xNamed->getName(); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("unotools"); + } + return sLocalName; + } + + OUString OConfigurationNode::normalizeName(const OUString& _rName, NAMEORIGIN _eOrigin) const + { + OUString sName(_rName); + if (m_bEscapeNames) + { + Reference< XStringEscape > xEscaper(m_xDirectAccess, UNO_QUERY); + if (xEscaper.is() && !sName.isEmpty()) + { + try + { + if (NO_CALLER == _eOrigin) + sName = xEscaper->escapeString(sName); + else + sName = xEscaper->unescapeString(sName); + } + catch(Exception&) + { + DBG_UNHANDLED_EXCEPTION("unotools"); + } + } + } + return sName; + } + + Sequence< OUString > OConfigurationNode::getNodeNames() const throw() + { + OSL_ENSURE(m_xDirectAccess.is(), "OConfigurationNode::getNodeNames: object is invalid!"); + Sequence< OUString > aReturn; + if (m_xDirectAccess.is()) + { + try + { + aReturn = m_xDirectAccess->getElementNames(); + // normalize the names + std::transform(aReturn.begin(), aReturn.end(), aReturn.begin(), + [this](const OUString& rName) -> OUString { return normalizeName(rName, NO_CONFIGURATION); }); + } + catch(Exception&) + { + OSL_FAIL("OConfigurationNode::getNodeNames: caught a generic exception!"); + } + } + + return aReturn; + } + + bool OConfigurationNode::removeNode(const OUString& _rName) const throw() + { + OSL_ENSURE(m_xContainerAccess.is(), "OConfigurationNode::removeNode: object is invalid!"); + if (m_xContainerAccess.is()) + { + try + { + OUString sName = normalizeName(_rName, NO_CALLER); + m_xContainerAccess->removeByName(sName); + return true; + } + catch (NoSuchElementException&) + { + SAL_WARN( "unotools", "OConfigurationNode::removeNode: there is no element named: " << _rName ); + } + catch (WrappedTargetException&) + { + OSL_FAIL("OConfigurationNode::removeNode: caught a WrappedTargetException!"); + } + catch(Exception&) + { + OSL_FAIL("OConfigurationNode::removeNode: caught a generic exception!"); + } + } + return false; + } + + OConfigurationNode OConfigurationNode::insertNode(const OUString& _rName,const Reference< XInterface >& _xNode) const throw() + { + if(_xNode.is()) + { + try + { + OUString sName = normalizeName(_rName, NO_CALLER); + m_xContainerAccess->insertByName(sName, makeAny(_xNode)); + // if we're here, all was ok ... + return OConfigurationNode( _xNode ); + } + catch(const Exception&) + { + DBG_UNHANDLED_EXCEPTION("unotools"); + } + + // dispose the child if it has already been created, but could not be inserted + Reference< XComponent > xChildComp(_xNode, UNO_QUERY); + if (xChildComp.is()) + try { xChildComp->dispose(); } catch(Exception&) { } + } + + return OConfigurationNode(); + } + + OConfigurationNode OConfigurationNode::createNode(const OUString& _rName) const throw() + { + Reference< XSingleServiceFactory > xChildFactory(m_xContainerAccess, UNO_QUERY); + OSL_ENSURE(xChildFactory.is(), "OConfigurationNode::createNode: object is invalid or read-only!"); + + if (xChildFactory.is()) // implies m_xContainerAccess.is() + { + Reference< XInterface > xNewChild; + try + { + xNewChild = xChildFactory->createInstance(); + } + catch(const Exception&) + { + DBG_UNHANDLED_EXCEPTION("unotools"); + } + return insertNode(_rName,xNewChild); + } + + return OConfigurationNode(); + } + + OConfigurationNode OConfigurationNode::openNode(const OUString& _rPath) const throw() + { + OSL_ENSURE(m_xDirectAccess.is(), "OConfigurationNode::openNode: object is invalid!"); + OSL_ENSURE(m_xHierarchyAccess.is(), "OConfigurationNode::openNode: object is invalid!"); + try + { + OUString sNormalized = normalizeName(_rPath, NO_CALLER); + + Reference< XInterface > xNode; + if (m_xDirectAccess.is() && m_xDirectAccess->hasByName(sNormalized)) + { + xNode.set( + m_xDirectAccess->getByName(sNormalized), css::uno::UNO_QUERY); + if (!xNode.is()) + OSL_FAIL("OConfigurationNode::openNode: could not open the node!"); + } + else if (m_xHierarchyAccess.is()) + { + xNode.set( + m_xHierarchyAccess->getByHierarchicalName(_rPath), + css::uno::UNO_QUERY); + if (!xNode.is()) + OSL_FAIL("OConfigurationNode::openNode: could not open the node!"); + } + if (xNode.is()) + return OConfigurationNode( xNode ); + } + catch(const NoSuchElementException&) + { + SAL_WARN( "unotools", "OConfigurationNode::openNode: there is no element named " << _rPath ); + } + catch(Exception&) + { + OSL_FAIL("OConfigurationNode::openNode: caught an exception while retrieving the node!"); + } + return OConfigurationNode(); + } + + bool OConfigurationNode::isSetNode() const + { + bool bIsSet = false; + Reference< XServiceInfo > xSI(m_xHierarchyAccess, UNO_QUERY); + if (xSI.is()) + { + try { bIsSet = xSI->supportsService("com.sun.star.configuration.SetAccess"); } + catch(Exception&) { } + } + return bIsSet; + } + + bool OConfigurationNode::hasByHierarchicalName( const OUString& _rName ) const throw() + { + OSL_ENSURE( m_xHierarchyAccess.is(), "OConfigurationNode::hasByHierarchicalName: no hierarchy access!" ); + try + { + if ( m_xHierarchyAccess.is() ) + { + OUString sName = normalizeName( _rName, NO_CALLER ); + return m_xHierarchyAccess->hasByHierarchicalName( sName ); + } + } + catch(Exception&) + { + } + return false; + } + + bool OConfigurationNode::hasByName(const OUString& _rName) const throw() + { + OSL_ENSURE(m_xDirectAccess.is(), "OConfigurationNode::hasByName: object is invalid!"); + try + { + OUString sName = normalizeName(_rName, NO_CALLER); + if (m_xDirectAccess.is()) + return m_xDirectAccess->hasByName(sName); + } + catch(Exception&) + { + } + return false; + } + + bool OConfigurationNode::setNodeValue(const OUString& _rPath, const Any& _rValue) const throw() + { + bool bResult = false; + + OSL_ENSURE(m_xReplaceAccess.is(), "OConfigurationNode::setNodeValue: object is invalid!"); + if (m_xReplaceAccess.is()) + { + try + { + // check if _rPath is a level-1 path + OUString sNormalizedName = normalizeName(_rPath, NO_CALLER); + if (m_xReplaceAccess->hasByName(sNormalizedName)) + { + m_xReplaceAccess->replaceByName(sNormalizedName, _rValue); + bResult = true; + } + + // check if the name refers to an indirect descendant + else if (m_xHierarchyAccess.is() && m_xHierarchyAccess->hasByHierarchicalName(_rPath)) + { + OSL_ASSERT(!_rPath.isEmpty()); + + OUString sParentPath, sLocalName; + + if ( splitLastFromConfigurationPath(_rPath, sParentPath, sLocalName) ) + { + OConfigurationNode aParentAccess = openNode(sParentPath); + if (aParentAccess.isValid()) + bResult = aParentAccess.setNodeValue(sLocalName, _rValue); + } + else + { + m_xReplaceAccess->replaceByName(sLocalName, _rValue); + bResult = true; + } + } + + } + catch(IllegalArgumentException&) + { + OSL_FAIL("OConfigurationNode::setNodeValue: could not replace the value: caught an IllegalArgumentException!"); + } + catch(NoSuchElementException&) + { + OSL_FAIL("OConfigurationNode::setNodeValue: could not replace the value: caught a NoSuchElementException!"); + } + catch(WrappedTargetException&) + { + OSL_FAIL("OConfigurationNode::setNodeValue: could not replace the value: caught a WrappedTargetException!"); + } + catch(Exception&) + { + OSL_FAIL("OConfigurationNode::setNodeValue: could not replace the value: caught a generic Exception!"); + } + + } + return bResult; + } + + Any OConfigurationNode::getNodeValue(const OUString& _rPath) const throw() + { + OSL_ENSURE(m_xDirectAccess.is(), "OConfigurationNode::hasByName: object is invalid!"); + OSL_ENSURE(m_xHierarchyAccess.is(), "OConfigurationNode::hasByName: object is invalid!"); + Any aReturn; + try + { + OUString sNormalizedPath = normalizeName(_rPath, NO_CALLER); + if (m_xDirectAccess.is() && m_xDirectAccess->hasByName(sNormalizedPath) ) + { + aReturn = m_xDirectAccess->getByName(sNormalizedPath); + } + else if (m_xHierarchyAccess.is()) + { + aReturn = m_xHierarchyAccess->getByHierarchicalName(_rPath); + } + } + catch(const NoSuchElementException&) + { + DBG_UNHANDLED_EXCEPTION("unotools"); + } + return aReturn; + } + + void OConfigurationNode::clear() throw() + { + m_xHierarchyAccess.clear(); + m_xDirectAccess.clear(); + m_xReplaceAccess.clear(); + m_xContainerAccess.clear(); + } + + //= helper + + namespace + { + + Reference< XMultiServiceFactory > lcl_getConfigProvider( const Reference<XComponentContext> & i_rContext ) + { + try + { + Reference< XMultiServiceFactory > xProvider = theDefaultProvider::get( i_rContext ); + return xProvider; + } + catch ( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("unotools"); + } + return nullptr; + } + + Reference< XInterface > lcl_createConfigurationRoot( const Reference< XMultiServiceFactory >& i_rxConfigProvider, + const OUString& i_rNodePath, const bool i_bUpdatable, const sal_Int32 i_nDepth ) + { + ENSURE_OR_RETURN( i_rxConfigProvider.is(), "invalid provider", nullptr ); + try + { + ::comphelper::NamedValueCollection aArgs; + aArgs.put( "nodepath", i_rNodePath ); + aArgs.put( "depth", i_nDepth ); + + OUString sAccessService( i_bUpdatable ? + OUString( "com.sun.star.configuration.ConfigurationUpdateAccess" ) : + OUString( "com.sun.star.configuration.ConfigurationAccess" )); + + Reference< XInterface > xRoot( + i_rxConfigProvider->createInstanceWithArguments( sAccessService, aArgs.getWrappedPropertyValues() ), + UNO_SET_THROW + ); + return xRoot; + } + catch ( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("unotools"); + } + return nullptr; + } + } + + OConfigurationTreeRoot::OConfigurationTreeRoot( const Reference< XInterface >& _rxRootNode ) + :OConfigurationNode( _rxRootNode ) + ,m_xCommitter( _rxRootNode, UNO_QUERY ) + { + } + + OConfigurationTreeRoot::OConfigurationTreeRoot( const Reference<XComponentContext> & i_rContext, const OUString& i_rNodePath, const bool i_bUpdatable ) + :OConfigurationNode( lcl_createConfigurationRoot( lcl_getConfigProvider( i_rContext ), + i_rNodePath, i_bUpdatable, -1 ).get() ) + ,m_xCommitter() + { + if ( i_bUpdatable ) + { + m_xCommitter.set( getUNONode(), UNO_QUERY ); + OSL_ENSURE( m_xCommitter.is(), "OConfigurationTreeRoot::OConfigurationTreeRoot: could not create an updatable node!" ); + } + } + + void OConfigurationTreeRoot::clear() throw() + { + OConfigurationNode::clear(); + m_xCommitter.clear(); + } + + bool OConfigurationTreeRoot::commit() const throw() + { + OSL_ENSURE(isValid(), "OConfigurationTreeRoot::commit: object is invalid!"); + if (!isValid()) + return false; + OSL_ENSURE(m_xCommitter.is(), "OConfigurationTreeRoot::commit: I'm a readonly node!"); + if (!m_xCommitter.is()) + return false; + + try + { + m_xCommitter->commitChanges(); + return true; + } + catch(const Exception&) + { + DBG_UNHANDLED_EXCEPTION("unotools"); + } + return false; + } + + OConfigurationTreeRoot OConfigurationTreeRoot::createWithProvider(const Reference< XMultiServiceFactory >& _rxConfProvider, const OUString& _rPath, sal_Int32 _nDepth, CREATION_MODE _eMode) + { + Reference< XInterface > xRoot( lcl_createConfigurationRoot( + _rxConfProvider, _rPath, _eMode != CM_READONLY, _nDepth ) ); + if ( xRoot.is() ) + return OConfigurationTreeRoot( xRoot ); + return OConfigurationTreeRoot(); + } + + OConfigurationTreeRoot OConfigurationTreeRoot::createWithComponentContext( const Reference< XComponentContext >& _rxContext, const OUString& _rPath, sal_Int32 _nDepth, CREATION_MODE _eMode ) + { + return createWithProvider( lcl_getConfigProvider( _rxContext ), _rPath, _nDepth, _eMode ); + } + + OConfigurationTreeRoot OConfigurationTreeRoot::tryCreateWithComponentContext( const Reference< XComponentContext >& rxContext, + const OUString& _rPath, sal_Int32 _nDepth , CREATION_MODE _eMode ) + { + OSL_ENSURE( rxContext.is(), "OConfigurationTreeRoot::tryCreateWithComponentContext: invalid XComponentContext!" ); + try + { + Reference< XMultiServiceFactory > xConfigFactory = theDefaultProvider::get( rxContext ); + return createWithProvider( xConfigFactory, _rPath, _nDepth, _eMode ); + } + catch(const Exception&) + { + // silence this, 'cause the contract of this method states "no assertions" + } + return OConfigurationTreeRoot(); + } + +} // namespace utl + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/unotools/source/config/configpaths.cxx b/unotools/source/config/configpaths.cxx new file mode 100644 index 000000000..81d8cb828 --- /dev/null +++ b/unotools/source/config/configpaths.cxx @@ -0,0 +1,284 @@ +/* -*- 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 . + */ + +#include <sal/config.h> + +#include <string_view> + +#include <unotools/configpaths.hxx> +#include <rtl/ustring.hxx> +#include <rtl/ustrbuf.hxx> +#include <osl/diagnose.h> + +namespace utl +{ + +static +void lcl_resolveCharEntities(OUString & aLocalString) +{ + sal_Int32 nEscapePos=aLocalString.indexOf('&'); + if (nEscapePos < 0) return; + + OUStringBuffer aResult; + sal_Int32 nStart = 0; + + do + { + sal_Unicode ch = 0; + if (aLocalString.match("&",nEscapePos)) + ch = '&'; + + else if (aLocalString.match("'",nEscapePos)) + ch = '\''; + + else if (aLocalString.match(""",nEscapePos)) + ch = '"'; + + OSL_ENSURE(ch,"Configuration path contains '&' that is not part of a valid character escape"); + if (ch) + { + aResult.append(std::u16string_view(aLocalString).substr(nStart,nEscapePos-nStart)).append(ch); + + sal_Int32 nEscapeEnd=aLocalString.indexOf(';',nEscapePos); + nStart = nEscapeEnd+1; + nEscapePos=aLocalString.indexOf('&',nStart); + } + else + { + nEscapePos=aLocalString.indexOf('&',nEscapePos+1); + } + } + while ( nEscapePos > 0); + + aResult.append(std::u16string_view(aLocalString).substr(nStart)); + + aLocalString = aResult.makeStringAndClear(); +} + +bool splitLastFromConfigurationPath(OUString const& _sInPath, + OUString& _rsOutPath, + OUString& _rsLocalName) +{ + sal_Int32 nStart,nEnd; + + sal_Int32 nPos = _sInPath.getLength()-1; + + // strip trailing slash + if (nPos > 0 && _sInPath[ nPos ] == '/') + { + OSL_FAIL("Invalid config path: trailing '/' is not allowed"); + --nPos; + } + + // check for predicate ['xxx'] or ["yyy"] + if (nPos > 0 && _sInPath[ nPos ] == ']') + { + sal_Unicode chQuote = _sInPath[--nPos]; + + if (chQuote == '\'' || chQuote == '\"') + { + nEnd = nPos; + nPos = _sInPath.lastIndexOf(chQuote,nEnd); + nStart = nPos + 1; + --nPos; // nPos = rInPath.lastIndexOf('[',nPos); + } + else // allow [xxx] + { + nEnd = nPos + 1; + nPos = _sInPath.lastIndexOf('[',nEnd); + nStart = nPos + 1; + } + + OSL_ENSURE(nPos >= 0 && _sInPath[nPos] == '[', "Invalid config path: unmatched quotes or brackets"); + if (nPos >= 0 && _sInPath[nPos] == '[') + { + nPos = _sInPath.lastIndexOf('/',nPos); + } + else // defined behavior for invalid paths + { + nStart = 0; + nEnd = _sInPath.getLength(); + nPos = -1; + } + + } + else + { + nEnd = nPos+1; + nPos = _sInPath.lastIndexOf('/',nEnd); + nStart = nPos + 1; + } + OSL_ASSERT( -1 <= nPos && + nPos < nStart && + nStart < nEnd && + nEnd <= _sInPath.getLength() ); + + OSL_ASSERT(nPos == -1 || _sInPath[nPos] == '/'); + OSL_ENSURE(nPos != 0 , "Invalid config child path: immediate child of root"); + + _rsLocalName = _sInPath.copy(nStart, nEnd-nStart); + _rsOutPath = (nPos > 0) ? _sInPath.copy(0,nPos) : OUString(); + lcl_resolveCharEntities(_rsLocalName); + + return nPos >= 0; +} + +OUString extractFirstFromConfigurationPath(OUString const& _sInPath, OUString* _sOutPath) +{ + sal_Int32 nSep = _sInPath.indexOf('/'); + sal_Int32 nBracket = _sInPath.indexOf('['); + + sal_Int32 nStart = nBracket + 1; + sal_Int32 nEnd = nSep; + + if (0 <= nBracket) // found a bracket-quoted relative path + { + if (nSep < 0 || nBracket < nSep) // and the separator comes after it + { + sal_Unicode chQuote = _sInPath[nStart]; + if (chQuote == '\'' || chQuote == '\"') + { + ++nStart; + nEnd = _sInPath.indexOf(chQuote, nStart+1); + nBracket = nEnd+1; + } + else + { + nEnd = _sInPath.indexOf(']',nStart); + nBracket = nEnd; + } + OSL_ENSURE(nEnd > nStart && _sInPath[nBracket] == ']', "Invalid config path: improper mismatch of quote or bracket"); + OSL_ENSURE((nBracket+1 == _sInPath.getLength() && nSep == -1) || (_sInPath[nBracket+1] == '/' && nSep == nBracket+1), "Invalid config path: brackets not followed by slash"); + } + else // ... but our initial element name is in simple form + nStart = 0; + } + + OUString sResult = (nEnd >= 0) ? _sInPath.copy(nStart, nEnd-nStart) : _sInPath; + lcl_resolveCharEntities(sResult); + + if (_sOutPath != nullptr) + { + *_sOutPath = (nSep >= 0) ? _sInPath.copy(nSep + 1) : OUString(); + } + + return sResult; +} + +// find the position after the prefix in the nested path +static sal_Int32 lcl_findPrefixEnd(OUString const& _sNestedPath, OUString const& _sPrefixPath) +{ + // TODO: currently handles only exact prefix matches + sal_Int32 nPrefixLength = _sPrefixPath.getLength(); + + OSL_ENSURE(nPrefixLength == 0 || _sPrefixPath[nPrefixLength-1] != '/', + "Cannot handle slash-terminated prefix paths"); + + bool bIsPrefix; + if (_sNestedPath.getLength() > nPrefixLength) + { + bIsPrefix = _sNestedPath[nPrefixLength] == '/' && + _sNestedPath.startsWith(_sPrefixPath); + ++nPrefixLength; + } + else if (_sNestedPath.getLength() == nPrefixLength) + { + bIsPrefix = _sNestedPath == _sPrefixPath; + } + else + { + bIsPrefix = false; + } + + return bIsPrefix ? nPrefixLength : 0; +} + +bool isPrefixOfConfigurationPath(OUString const& _sNestedPath, + OUString const& _sPrefixPath) +{ + return _sPrefixPath.isEmpty() || lcl_findPrefixEnd(_sNestedPath,_sPrefixPath) != 0; +} + +OUString dropPrefixFromConfigurationPath(OUString const& _sNestedPath, + OUString const& _sPrefixPath) +{ + if ( sal_Int32 nPrefixEnd = lcl_findPrefixEnd(_sNestedPath,_sPrefixPath) ) + { + return _sNestedPath.copy(nPrefixEnd); + } + else + { + OSL_ENSURE(_sPrefixPath.isEmpty(), "Path does not start with expected prefix"); + + return _sNestedPath; + } +} + +static +OUString lcl_wrapName(const OUString& _sContent, const OUString& _sType) +{ + const sal_Unicode * const pBeginContent = _sContent.getStr(); + const sal_Unicode * const pEndContent = pBeginContent + _sContent.getLength(); + + OSL_PRECOND(!_sType.isEmpty(), "Unexpected config type name: empty"); + OSL_PRECOND(pBeginContent <= pEndContent, "Invalid config name: empty"); + + if (pBeginContent == pEndContent) + return _sType; + + OUStringBuffer aNormalized(_sType.getLength() + _sContent.getLength() + 4); // reserve approximate size initially + + // prefix: type, opening bracket and quote + aNormalized.append( _sType ).append( "['" ); + + // content: copy over each char and handle escaping + for(const sal_Unicode* pCur = pBeginContent; pCur != pEndContent; ++pCur) + { + // append (escape if needed) + switch(*pCur) + { + case u'&' : aNormalized.append( "&" ); break; + case u'\'': aNormalized.append( "'" ); break; + case u'\"': aNormalized.append( """ ); break; + + default: aNormalized.append( *pCur ); + } + } + + // suffix: closing quote and bracket + aNormalized.append( "']" ); + + return aNormalized.makeStringAndClear(); +} + +OUString wrapConfigurationElementName(OUString const& _sElementName) +{ + return lcl_wrapName(_sElementName, "*" ); +} + +OUString wrapConfigurationElementName(OUString const& _sElementName, + OUString const& _sTypeName) +{ + // todo: check that _sTypeName is valid + return lcl_wrapName(_sElementName, _sTypeName); +} + +} // namespace utl + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/unotools/source/config/configvaluecontainer.cxx b/unotools/source/config/configvaluecontainer.cxx new file mode 100644 index 000000000..6fc60d753 --- /dev/null +++ b/unotools/source/config/configvaluecontainer.cxx @@ -0,0 +1,303 @@ +/* -*- 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 . + */ + +#include <sal/config.h> + +#include <sal/log.hxx> +#include <unotools/configvaluecontainer.hxx> +#include <unotools/confignode.hxx> +#include <uno/data.h> +#include <algorithm> +#include <vector> + +namespace utl +{ + + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::lang; + + //= NodeValueAccessor + + namespace { + + enum class LocationType + { + SimplyObjectInstance, + Unbound + }; + + } + + struct NodeValueAccessor + { + private: + OUString sRelativePath; // the relative path of the node + LocationType eLocationType; // the type of location where the value is stored + void* pLocation; // the pointer to the location + Type aDataType; // the type object pointed to by pLocation + + public: + explicit NodeValueAccessor( const OUString& _rNodePath ); + + void bind( void* _pLocation, const Type& _rType ); + + bool isBound( ) const { return ( LocationType::Unbound != eLocationType ) && ( nullptr != pLocation ); } + const OUString& getPath( ) const { return sRelativePath; } + LocationType getLocType( ) const { return eLocationType; } + void* getLocation( ) const { return pLocation; } + const Type& getDataType( ) const { return aDataType; } + + bool operator == ( const NodeValueAccessor& rhs ) const; + }; + + NodeValueAccessor::NodeValueAccessor( const OUString& _rNodePath ) + :sRelativePath( _rNodePath ) + ,eLocationType( LocationType::Unbound ) + ,pLocation( nullptr ) + { + } + + bool NodeValueAccessor::operator == ( const NodeValueAccessor& rhs ) const + { + return ( sRelativePath == rhs.sRelativePath ) + && ( eLocationType == rhs.eLocationType ) + && ( pLocation == rhs.pLocation ); + } + + void NodeValueAccessor::bind( void* _pLocation, const Type& _rType ) + { + SAL_WARN_IF(isBound(), "unotools.config", "NodeValueAccessor::bind: already bound!"); + + eLocationType = LocationType::SimplyObjectInstance; + pLocation = _pLocation; + aDataType = _rType; + } + + static + void lcl_copyData( const NodeValueAccessor& _rAccessor, const Any& _rData, ::osl::Mutex& _rMutex ) + { + ::osl::MutexGuard aGuard( _rMutex ); + + SAL_WARN_IF(!_rAccessor.isBound(), "unotools.config", "::utl::lcl_copyData: invalid accessor!"); + switch ( _rAccessor.getLocType() ) + { + case LocationType::SimplyObjectInstance: + { + if ( _rData.hasValue() ) + { + // assign the value + bool bSuccess = uno_type_assignData( + _rAccessor.getLocation(), _rAccessor.getDataType().getTypeLibType(), + const_cast< void* >( _rData.getValue() ), _rData.getValueType().getTypeLibType(), + cpp_queryInterface, cpp_acquire, cpp_release + ); + SAL_WARN_IF(!bSuccess, "unotools.config", + "::utl::lcl_copyData( Accessor, Any ): could not assign the data (node path: \"" << _rAccessor.getPath() << "\""); + } + else { + SAL_INFO("unotools.config", "::utl::lcl_copyData: NULL value lost!"); + } + } + break; + default: + break; + } + } + + static + void lcl_copyData( Any& _rData, const NodeValueAccessor& _rAccessor, ::osl::Mutex& _rMutex ) + { + ::osl::MutexGuard aGuard( _rMutex ); + + SAL_WARN_IF(!_rAccessor.isBound(), "unotools.config", "::utl::lcl_copyData: invalid accessor!" ); + switch ( _rAccessor.getLocType() ) + { + case LocationType::SimplyObjectInstance: + // a simple setValue... + _rData.setValue( _rAccessor.getLocation(), _rAccessor.getDataType() ); + break; + + default: + break; + } + } + + //= functors on NodeValueAccessor instances + + namespace { + + /// base class for functors synchronizing between exchange locations and config sub nodes + struct SubNodeAccess + { + protected: + const OConfigurationNode& m_rRootNode; + ::osl::Mutex& m_rMutex; + + public: + SubNodeAccess( const OConfigurationNode& _rRootNode, ::osl::Mutex& _rMutex ) + :m_rRootNode( _rRootNode ) + ,m_rMutex( _rMutex ) + { + } + }; + + struct UpdateFromConfig : public SubNodeAccess + { + public: + UpdateFromConfig( const OConfigurationNode& _rRootNode, ::osl::Mutex& _rMutex ) : SubNodeAccess( _rRootNode, _rMutex ) { } + + void operator() ( NodeValueAccessor const & _rAccessor ) + { + ::utl::lcl_copyData( _rAccessor, m_rRootNode.getNodeValue( _rAccessor.getPath( ) ), m_rMutex ); + } + }; + + struct UpdateToConfig : public SubNodeAccess + { + public: + UpdateToConfig( const OConfigurationNode& _rRootNode, ::osl::Mutex& _rMutex ) : SubNodeAccess( _rRootNode, _rMutex ) { } + + void operator() ( NodeValueAccessor const & _rAccessor ) + { + Any aNewValue; + lcl_copyData( aNewValue, _rAccessor, m_rMutex ); + m_rRootNode.setNodeValue( _rAccessor.getPath( ), aNewValue ); + } + }; + + } + + //= OConfigurationValueContainerImpl + + struct OConfigurationValueContainerImpl + { + Reference< XComponentContext > xORB; // the service factory + ::osl::Mutex& rMutex; // the mutex for accessing the data containers + OConfigurationTreeRoot aConfigRoot; // the configuration node we're accessing + + std::vector<NodeValueAccessor> aAccessors; // the accessors to the node values + + OConfigurationValueContainerImpl( const Reference< XComponentContext >& _rxORB, ::osl::Mutex& _rMutex ) + :xORB( _rxORB ) + ,rMutex( _rMutex ) + { + } + }; + + //= OConfigurationValueContainer + + OConfigurationValueContainer::OConfigurationValueContainer( + const Reference< XComponentContext >& _rxORB, ::osl::Mutex& _rAccessSafety, + const char* _pConfigLocation, const sal_Int32 _nLevels ) + :m_pImpl( new OConfigurationValueContainerImpl( _rxORB, _rAccessSafety ) ) + { + implConstruct( OUString::createFromAscii( _pConfigLocation ), _nLevels ); + } + + OConfigurationValueContainer::~OConfigurationValueContainer() + { + } + + void OConfigurationValueContainer::implConstruct( const OUString& _rConfigLocation, + const sal_Int32 _nLevels ) + { + SAL_WARN_IF(m_pImpl->aConfigRoot.isValid(), "unotools.config", "OConfigurationValueContainer::implConstruct: already initialized!"); + + // create the configuration node we're about to work with + m_pImpl->aConfigRoot = OConfigurationTreeRoot::createWithComponentContext( + m_pImpl->xORB, + _rConfigLocation, + _nLevels + ); + SAL_WARN_IF(!m_pImpl->aConfigRoot.isValid(), "unotools.config", + "Could not access the configuration node located at " << _rConfigLocation); + } + + void OConfigurationValueContainer::registerExchangeLocation( const char* _pRelativePath, + void* _pContainer, const Type& _rValueType ) + { + // checks... + SAL_WARN_IF(!_pContainer, "unotools.config", + "OConfigurationValueContainer::registerExchangeLocation: invalid container location!"); + SAL_WARN_IF(!( (TypeClass_CHAR == _rValueType.getTypeClass( ) ) + || ( TypeClass_BOOLEAN == _rValueType.getTypeClass( ) ) + || ( TypeClass_BYTE == _rValueType.getTypeClass( ) ) + || ( TypeClass_SHORT == _rValueType.getTypeClass( ) ) + || ( TypeClass_LONG == _rValueType.getTypeClass( ) ) + || ( TypeClass_DOUBLE == _rValueType.getTypeClass( ) ) + || ( TypeClass_STRING == _rValueType.getTypeClass( ) ) + || ( TypeClass_SEQUENCE == _rValueType.getTypeClass( ) )), + "unotools.config", + "OConfigurationValueContainer::registerExchangeLocation: invalid type!" ); + + // build an accessor for this container + NodeValueAccessor aNewAccessor( OUString::createFromAscii( _pRelativePath ) ); + aNewAccessor.bind( _pContainer, _rValueType ); + + // insert it into our structure + implRegisterExchangeLocation( aNewAccessor ); + } + + void OConfigurationValueContainer::read( ) + { + std::for_each( + m_pImpl->aAccessors.begin(), + m_pImpl->aAccessors.end(), + UpdateFromConfig( m_pImpl->aConfigRoot, m_pImpl->rMutex ) + ); + } + + void OConfigurationValueContainer::commit() + { + // write the current values in the exchange locations + std::for_each( + m_pImpl->aAccessors.begin(), + m_pImpl->aAccessors.end(), + UpdateToConfig( m_pImpl->aConfigRoot, m_pImpl->rMutex ) + ); + + // commit the changes done + m_pImpl->aConfigRoot.commit( ); + } + + void OConfigurationValueContainer::implRegisterExchangeLocation( const NodeValueAccessor& _rAccessor ) + { + // some checks + SAL_WARN_IF(m_pImpl->aConfigRoot.isValid() && !m_pImpl->aConfigRoot.hasByHierarchicalName(_rAccessor.getPath()), + "unotools.config", + "OConfigurationValueContainer::implRegisterExchangeLocation: invalid relative path!" ); + + // another check (should be the first container for this node) + SAL_WARN_IF(!(m_pImpl->aAccessors.end() == ::std::find( + m_pImpl->aAccessors.begin(), + m_pImpl->aAccessors.end(), + _rAccessor)), + "unotools.config", + "OConfigurationValueContainer::implRegisterExchangeLocation: already registered a container for this subnode!" ); + + // remember the accessor + m_pImpl->aAccessors.push_back( _rAccessor ); + + // and initially fill the value + lcl_copyData( _rAccessor, m_pImpl->aConfigRoot.getNodeValue( _rAccessor.getPath() ), m_pImpl->rMutex ); + } + +} // namespace utl + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/unotools/source/config/defaultoptions.cxx b/unotools/source/config/defaultoptions.cxx new file mode 100644 index 000000000..80a597abc --- /dev/null +++ b/unotools/source/config/defaultoptions.cxx @@ -0,0 +1,357 @@ +/* -*- 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 . + */ + +#include <sal/config.h> + +#include <osl/file.hxx> +#include <sal/log.hxx> +#include <unotools/defaultoptions.hxx> +#include <unotools/pathoptions.hxx> +#include <unotools/configitem.hxx> +#include <tools/debug.hxx> +#include <com/sun/star/uno/Any.hxx> +#include <com/sun/star/uno/Sequence.hxx> +#include <osl/mutex.hxx> + +#include <rtl/instance.hxx> +#include <rtl/ustrbuf.hxx> + +#include "itemholder1.hxx" + +using namespace osl; +using namespace utl; +using namespace com::sun::star::uno; + +#define DEFAULTPATH_ADDIN 0 +#define DEFAULTPATH_AUTOCORRECT 1 +#define DEFAULTPATH_AUTOTEXT 2 +#define DEFAULTPATH_BACKUP 3 +#define DEFAULTPATH_BASIC 4 +#define DEFAULTPATH_BITMAP 5 +#define DEFAULTPATH_CONFIG 6 +#define DEFAULTPATH_DICTIONARY 7 +#define DEFAULTPATH_FAVORITES 8 +#define DEFAULTPATH_FILTER 9 +#define DEFAULTPATH_GALLERY 10 +#define DEFAULTPATH_GRAPHIC 11 +#define DEFAULTPATH_HELP 12 +#define DEFAULTPATH_LINGUISTIC 13 +#define DEFAULTPATH_MODULE 14 +#define DEFAULTPATH_PALETTE 15 +#define DEFAULTPATH_PLUGIN 16 +#define DEFAULTPATH_TEMP 17 +#define DEFAULTPATH_TEMPLATE 18 +#define DEFAULTPATH_USERCONFIG 19 +#define DEFAULTPATH_WORK 20 +#define DEFAULTPATH_CLASSIFICATION 21 +#define DEFAULTPATH_USERDICTIONARY 22 + +// class SvtDefaultOptions_Impl ------------------------------------------ + +class SvtDefaultOptions_Impl : public utl::ConfigItem +{ +public: + OUString m_aAddinPath; + OUString m_aAutoCorrectPath; + OUString m_aAutoTextPath; + OUString m_aBackupPath; + OUString m_aBasicPath; + OUString m_aBitmapPath; + OUString m_aConfigPath; + OUString m_aDictionaryPath; + OUString m_aFavoritesPath; + OUString m_aFilterPath; + OUString m_aGalleryPath; + OUString m_aGraphicPath; + OUString m_aHelpPath; + OUString m_aLinguisticPath; + OUString m_aModulePath; + OUString m_aPalettePath; + OUString m_aPluginPath; + OUString m_aTempPath; + OUString m_aTemplatePath; + OUString m_aUserConfigPath; + OUString m_aWorkPath; + OUString m_aClassificationPath; + + SvtDefaultOptions_Impl(); + virtual ~SvtDefaultOptions_Impl() override; + + OUString GetDefaultPath( sal_uInt16 nId ) const; + virtual void Notify( const css::uno::Sequence<OUString>& aPropertyNames) override; + +private: + virtual void ImplCommit() final override; +}; + +// global ---------------------------------------------------------------- + +namespace { + +std::weak_ptr<SvtDefaultOptions_Impl> g_pOptions; + +} + +typedef OUString SvtDefaultOptions_Impl:: *PathStrPtr; + +namespace { + +struct PathToDefaultMapping_Impl +{ + SvtPathOptions::Paths _ePath; + PathStrPtr _pDefaultPath; +}; + +} + +static PathToDefaultMapping_Impl const PathMap_Impl[] = +{ + { SvtPathOptions::PATH_ADDIN, &SvtDefaultOptions_Impl::m_aAddinPath }, + { SvtPathOptions::PATH_AUTOCORRECT, &SvtDefaultOptions_Impl::m_aAutoCorrectPath }, + { SvtPathOptions::PATH_AUTOTEXT, &SvtDefaultOptions_Impl::m_aAutoTextPath }, + { SvtPathOptions::PATH_BACKUP, &SvtDefaultOptions_Impl::m_aBackupPath }, + { SvtPathOptions::PATH_BASIC, &SvtDefaultOptions_Impl::m_aBasicPath }, + { SvtPathOptions::PATH_BITMAP, &SvtDefaultOptions_Impl::m_aBitmapPath }, + { SvtPathOptions::PATH_CONFIG, &SvtDefaultOptions_Impl::m_aConfigPath }, + { SvtPathOptions::PATH_DICTIONARY, &SvtDefaultOptions_Impl::m_aDictionaryPath }, + { SvtPathOptions::PATH_FAVORITES, &SvtDefaultOptions_Impl::m_aFavoritesPath }, + { SvtPathOptions::PATH_FILTER, &SvtDefaultOptions_Impl::m_aFilterPath }, + { SvtPathOptions::PATH_GALLERY, &SvtDefaultOptions_Impl::m_aGalleryPath }, + { SvtPathOptions::PATH_GRAPHIC, &SvtDefaultOptions_Impl::m_aGraphicPath }, + { SvtPathOptions::PATH_HELP, &SvtDefaultOptions_Impl::m_aHelpPath }, + { SvtPathOptions::PATH_LINGUISTIC, &SvtDefaultOptions_Impl::m_aLinguisticPath }, + { SvtPathOptions::PATH_MODULE, &SvtDefaultOptions_Impl::m_aModulePath }, + { SvtPathOptions::PATH_PALETTE, &SvtDefaultOptions_Impl::m_aPalettePath }, + { SvtPathOptions::PATH_PLUGIN, &SvtDefaultOptions_Impl::m_aPluginPath }, + { SvtPathOptions::PATH_TEMP, &SvtDefaultOptions_Impl::m_aTempPath }, + { SvtPathOptions::PATH_TEMPLATE, &SvtDefaultOptions_Impl::m_aTemplatePath }, + { SvtPathOptions::PATH_USERCONFIG, &SvtDefaultOptions_Impl::m_aUserConfigPath }, + { SvtPathOptions::PATH_WORK, &SvtDefaultOptions_Impl::m_aWorkPath }, + { SvtPathOptions::PATH_CLASSIFICATION, &SvtDefaultOptions_Impl::m_aClassificationPath } +}; + +// functions ------------------------------------------------------------- + +static Sequence< OUString > GetDefaultPropertyNames() +{ + static const char* aPropNames[] = + { + "Addin", // PATH_ADDIN + "AutoCorrect", // PATH_AUTOCORRECT + "AutoText", // PATH_AUTOTEXT + "Backup", // PATH_BACKUP + "Basic", // PATH_BASIC + "Bitmap", // PATH_BITMAP + "Config", // PATH_CONFIG + "Dictionary", // PATH_DICTIONARY + "Favorite", // PATH_FAVORITES + "Filter", // PATH_FILTER + "Gallery", // PATH_GALLERY + "Graphic", // PATH_GRAPHIC + "Help", // PATH_HELP + "Linguistic", // PATH_LINGUISTIC + "Module", // PATH_MODULE + "Palette", // PATH_PALETTE + "Plugin", // PATH_PLUGIN + "Temp", // PATH_TEMP + "Template", // PATH_TEMPLATE + "UserConfig", // PATH_USERCONFIG + "Work", // PATH_WORK + "Classification" // PATH_CLASSIFICATION + }; + + const int nCount = SAL_N_ELEMENTS( aPropNames ); + Sequence< OUString > aNames( nCount ); + OUString* pNames = aNames.getArray(); + for ( int i = 0; i < nCount; i++ ) + pNames[i] = OUString::createFromAscii( aPropNames[i] ); + + return aNames; +} + +void SvtDefaultOptions_Impl::Notify( const Sequence< OUString >& ) +{ + // no notification, will never be changed +} + +void SvtDefaultOptions_Impl::ImplCommit() +{ + // will never be changed +} + +// class SvtDefaultOptions_Impl ------------------------------------------ + +OUString SvtDefaultOptions_Impl::GetDefaultPath( sal_uInt16 nId ) const +{ + OUString aRet; + sal_uInt16 nIdx = 0; + + while ( PathMap_Impl[nIdx]._ePath <= SvtPathOptions::PATH_CLASSIFICATION ) + { + if ( nId == PathMap_Impl[nIdx]._ePath && PathMap_Impl[nIdx]._pDefaultPath ) + { + aRet = this->*(PathMap_Impl[nIdx]._pDefaultPath); + if ( nId == SvtPathOptions::PATH_ADDIN || + nId == SvtPathOptions::PATH_FILTER || + nId == SvtPathOptions::PATH_HELP || + nId == SvtPathOptions::PATH_MODULE || + nId == SvtPathOptions::PATH_PLUGIN ) + { + OUString aTmp; + osl::FileBase::getFileURLFromSystemPath( aRet, aTmp ); + aRet = aTmp; + } + + break; + } + ++nIdx; + } + + return aRet; +} + +SvtDefaultOptions_Impl::SvtDefaultOptions_Impl() : ConfigItem( "Office.Common/Path/Default" ) +{ + Sequence< OUString > aNames = GetDefaultPropertyNames(); + Sequence< Any > aValues = GetProperties( aNames ); + EnableNotification( aNames ); + const Any* pValues = aValues.getConstArray(); + DBG_ASSERT( aValues.getLength() == aNames.getLength(), "GetProperties failed" ); + if ( aValues.getLength() == aNames.getLength() ) + { + SvtPathOptions aPathOpt; + OUString aTempStr; + OUStringBuffer aFullPathBuf; + + for ( int nProp = 0; nProp < aNames.getLength(); nProp++ ) + { + if ( pValues[nProp].hasValue() ) + { + switch ( pValues[nProp].getValueTypeClass() ) + { + case css::uno::TypeClass_STRING : + { + // multi paths + if ( pValues[nProp] >>= aTempStr ) + aFullPathBuf = aPathOpt.SubstituteVariable( aTempStr ); + else + { + SAL_WARN( "unotools.config", "any operator >>= failed" ); + } + break; + } + + case css::uno::TypeClass_SEQUENCE : + { + // single paths + aFullPathBuf.setLength(0); + Sequence < OUString > aList; + if ( pValues[nProp] >>= aList ) + { + sal_Int32 nCount = aList.getLength(); + for ( sal_Int32 nPosition = 0; nPosition < nCount; ++nPosition ) + { + aFullPathBuf.append(aPathOpt.SubstituteVariable( aList[ nPosition ] )); + if ( nPosition < nCount-1 ) + aFullPathBuf.append(";"); + } + } + else + { + SAL_WARN( "unotools.config", "any operator >>= failed" ); + } + break; + } + + default: + { + SAL_WARN( "unotools.config", "Wrong any type" ); + } + } + + auto aFullPath = aFullPathBuf.makeStringAndClear(); + switch ( nProp ) + { + case DEFAULTPATH_ADDIN: m_aAddinPath = aFullPath; break; + case DEFAULTPATH_AUTOCORRECT: m_aAutoCorrectPath = aFullPath; break; + case DEFAULTPATH_AUTOTEXT: m_aAutoTextPath = aFullPath; break; + case DEFAULTPATH_BACKUP: m_aBackupPath = aFullPath; break; + case DEFAULTPATH_BASIC: m_aBasicPath = aFullPath; break; + case DEFAULTPATH_BITMAP: m_aBitmapPath = aFullPath; break; + case DEFAULTPATH_CONFIG: m_aConfigPath = aFullPath; break; + case DEFAULTPATH_DICTIONARY: m_aDictionaryPath = aFullPath; break; + case DEFAULTPATH_FAVORITES: m_aFavoritesPath = aFullPath; break; + case DEFAULTPATH_FILTER: m_aFilterPath = aFullPath; break; + case DEFAULTPATH_GALLERY: m_aGalleryPath = aFullPath; break; + case DEFAULTPATH_GRAPHIC: m_aGraphicPath = aFullPath; break; + case DEFAULTPATH_HELP: m_aHelpPath = aFullPath; break; + case DEFAULTPATH_LINGUISTIC: m_aLinguisticPath = aFullPath; break; + case DEFAULTPATH_MODULE: m_aModulePath = aFullPath; break; + case DEFAULTPATH_PALETTE: m_aPalettePath = aFullPath; break; + case DEFAULTPATH_PLUGIN: m_aPluginPath = aFullPath; break; + case DEFAULTPATH_TEMP: m_aTempPath = aFullPath; break; + case DEFAULTPATH_TEMPLATE: m_aTemplatePath = aFullPath; break; + case DEFAULTPATH_USERCONFIG: m_aUserConfigPath = aFullPath; break; + case DEFAULTPATH_WORK: m_aWorkPath = aFullPath; break; + case DEFAULTPATH_CLASSIFICATION: m_aClassificationPath = aFullPath;break; + case DEFAULTPATH_USERDICTIONARY: break; + + default: + SAL_WARN( "unotools.config", "invalid index to load a default path" ); + } + } + } + } +} + +SvtDefaultOptions_Impl::~SvtDefaultOptions_Impl() +{ + if ( IsModified() ) + Commit(); +} + +// class SvtDefaultOptions ----------------------------------------------- +namespace { struct lclMutex : public rtl::Static< ::osl::Mutex, lclMutex > {}; } + +SvtDefaultOptions::SvtDefaultOptions() +{ + // Global access, must be guarded (multithreading) + ::osl::MutexGuard aGuard( lclMutex::get() ); + pImpl = g_pOptions.lock(); + if ( !pImpl ) + { + pImpl = std::make_shared<SvtDefaultOptions_Impl>(); + g_pOptions = pImpl; + ItemHolder1::holdConfigItem(EItem::DefaultOptions); + } +} + +SvtDefaultOptions::~SvtDefaultOptions() +{ + // Global access, must be guarded (multithreading) + ::osl::MutexGuard aGuard( lclMutex::get() ); + pImpl.reset(); +} + +OUString SvtDefaultOptions::GetDefaultPath( sal_uInt16 nId ) const +{ + return pImpl->GetDefaultPath( nId ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/unotools/source/config/docinfohelper.cxx b/unotools/source/config/docinfohelper.cxx new file mode 100644 index 000000000..7e605d187 --- /dev/null +++ b/unotools/source/config/docinfohelper.cxx @@ -0,0 +1,101 @@ +/* -*- 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 . + */ + +#include <rtl/ustrbuf.hxx> +#include <unotools/configmgr.hxx> +#include <unotools/bootstrap.hxx> +#include <unotools/docinfohelper.hxx> +#include <rtl/bootstrap.hxx> + +using namespace ::com::sun::star; + +namespace utl +{ + +OUString DocInfoHelper::GetGeneratorString() +{ + OUStringBuffer aResult(128); + + // First product: branded name + version + // version is <product_versions>_<product_extension>$<platform> + + // plain product name + OUString aValue( utl::ConfigManager::getProductName() ); + if ( !aValue.isEmpty() ) + { + aResult.append( aValue.replace( ' ', '_' ) ); + aResult.append( '/' ); + + aValue = utl::ConfigManager::getProductVersion(); + if ( !aValue.isEmpty() ) + { + aResult.append( aValue.replace( ' ', '_' ) ); + + aValue = utl::ConfigManager::getProductExtension(); + if ( !aValue.isEmpty() ) + { + aResult.append( aValue.replace( ' ', '_' ) ); + } + } + + OUString os( "$_OS" ); + OUString arch( "$_ARCH" ); + ::rtl::Bootstrap::expandMacros(os); + ::rtl::Bootstrap::expandMacros(arch); + aResult.append( '$' ); + aResult.append( os ); + aResult.append( '_' ); + aResult.append( arch ); + aResult.append( ' ' ); + } + + // second product: LibreOffice_project/<build_information> + // build_information has '(' and '[' encoded as '$', ')' and ']' ignored + // and ':' replaced by '-' + { + aResult.append( "LibreOffice_project/" ); + OUString aBuildId( Bootstrap::getBuildIdData( OUString() ) ); + for( sal_Int32 i=0; i < aBuildId.getLength(); i++ ) + { + sal_Unicode c = aBuildId[i]; + switch( c ) + { + case '(': + case '[': + aResult.append( '$' ); + break; + case ')': + case ']': + break; + case ':': + aResult.append( '-' ); + break; + default: + aResult.append( c ); + break; + } + } + } + + return aResult.makeStringAndClear(); +} + +} // end of namespace utl + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/unotools/source/config/dynamicmenuoptions.cxx b/unotools/source/config/dynamicmenuoptions.cxx new file mode 100644 index 000000000..019ca1b86 --- /dev/null +++ b/unotools/source/config/dynamicmenuoptions.cxx @@ -0,0 +1,558 @@ +/* -*- 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 . + */ + +#include <sal/config.h> + +#include <sal/log.hxx> +#include <unotools/dynamicmenuoptions.hxx> +#include <unotools/configitem.hxx> +#include <tools/debug.hxx> +#include <com/sun/star/uno/Any.hxx> +#include <com/sun/star/uno/Sequence.hxx> +#include <com/sun/star/beans/PropertyValue.hpp> + +#include <vector> + +#include "itemholder1.hxx" + +#include <algorithm> + +using namespace ::std; +using namespace ::utl; +using namespace ::osl; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; + +#define ROOTNODE_MENUS "Office.Common/Menus/" +#define PATHDELIMITER "/" + +#define SETNODE_NEWMENU "New" +#define SETNODE_WIZARDMENU "Wizard" + +#define PROPERTYNAME_URL DYNAMICMENU_PROPERTYNAME_URL +#define PROPERTYNAME_TITLE DYNAMICMENU_PROPERTYNAME_TITLE +#define PROPERTYNAME_IMAGEIDENTIFIER DYNAMICMENU_PROPERTYNAME_IMAGEIDENTIFIER +#define PROPERTYNAME_TARGETNAME DYNAMICMENU_PROPERTYNAME_TARGETNAME + +#define PROPERTYCOUNT 4 + +#define OFFSET_URL 0 +#define OFFSET_TITLE 1 +#define OFFSET_IMAGEIDENTIFIER 2 +#define OFFSET_TARGETNAME 3 + +#define PATHPREFIX_SETUP "m" + +namespace { + +/*-**************************************************************************************************************** + @descr struct to hold information about one menu entry. +****************************************************************************************************************-*/ +struct SvtDynMenuEntry +{ + OUString sURL; + OUString sTitle; + OUString sImageIdentifier; + OUString sTargetName; +}; + +/*-**************************************************************************************************************** + @descr support simple menu structures and operations on it +****************************************************************************************************************-*/ +class SvtDynMenu +{ + public: + // append setup written menu entry + // Don't touch name of entry. It was defined by setup and must be the same every time! + // Look for double menu entries here too... may be some separator items are superfluous... + void AppendSetupEntry( const SvtDynMenuEntry& rEntry ) + { + if( + ( lSetupEntries.empty() ) || + ( lSetupEntries.rbegin()->sURL != rEntry.sURL ) + ) + { + lSetupEntries.push_back( rEntry ); + } + } + + // convert internal list to external format + // for using it on right menus really + // Notice: We build a property list with 4 entries and set it on result list then. + // Separator entries will be packed in another way then normal entries! We define + // special string "sSeparator" to perform too ... + Sequence< Sequence< PropertyValue > > GetList() const + { + sal_Int32 nSetupCount = static_cast<sal_Int32>(lSetupEntries.size()); + sal_Int32 nUserCount = static_cast<sal_Int32>(lUserEntries.size()); + sal_Int32 nStep = 0; + Sequence< PropertyValue > lProperties ( PROPERTYCOUNT ); + Sequence< Sequence< PropertyValue > > lResult ( nSetupCount+nUserCount ); + OUString sSeparator ( "private:separator" ); + + lProperties[OFFSET_URL ].Name = PROPERTYNAME_URL; + lProperties[OFFSET_TITLE ].Name = PROPERTYNAME_TITLE; + lProperties[OFFSET_IMAGEIDENTIFIER].Name = PROPERTYNAME_IMAGEIDENTIFIER; + lProperties[OFFSET_TARGETNAME ].Name = PROPERTYNAME_TARGETNAME; + + for( const auto& pList : {&lSetupEntries, &lUserEntries} ) + { + for( const auto& rItem : *pList ) + { + if( rItem.sURL == sSeparator ) + { + lProperties[OFFSET_URL ].Value <<= sSeparator; + lProperties[OFFSET_TITLE ].Value <<= OUString(); + lProperties[OFFSET_IMAGEIDENTIFIER ].Value <<= OUString(); + lProperties[OFFSET_TARGETNAME ].Value <<= OUString(); + } + else + { + lProperties[OFFSET_URL ].Value <<= rItem.sURL; + lProperties[OFFSET_TITLE ].Value <<= rItem.sTitle; + lProperties[OFFSET_IMAGEIDENTIFIER ].Value <<= rItem.sImageIdentifier; + lProperties[OFFSET_TARGETNAME ].Value <<= rItem.sTargetName; + } + lResult[nStep] = lProperties; + ++nStep; + } + } + return lResult; + } + + private: + vector< SvtDynMenuEntry > lSetupEntries; + vector< SvtDynMenuEntry > lUserEntries; +}; + +} + +class SvtDynamicMenuOptions_Impl : public ConfigItem +{ + public: + + SvtDynamicMenuOptions_Impl(); + virtual ~SvtDynamicMenuOptions_Impl() override; + + /*-**************************************************************************************************** + @short called for notify of configmanager + @descr This method is called from the ConfigManager before the application ends or from the + PropertyChangeListener if the sub tree broadcasts changes. You must update your + internal values. + + @seealso baseclass ConfigItem + + @param "lPropertyNames" is the list of properties which should be updated. + *//*-*****************************************************************************************************/ + + virtual void Notify( const Sequence< OUString >& lPropertyNames ) override; + + /*-**************************************************************************************************** + @short base implementation of public interface for "SvtDynamicMenuOptions"! + @descr These class is used as static member of "SvtDynamicMenuOptions" ... + => The code exist only for one time and isn't duplicated for every instance! + *//*-*****************************************************************************************************/ + + Sequence< Sequence< PropertyValue > > GetMenu ( EDynamicMenuType eMenu ) const; + + private: + + virtual void ImplCommit() override; + + /*-**************************************************************************************************** + @short return list of key names of our configuration management which represent our module tree + @descr This method returns the current list of key names! We need it to get needed values from our + configuration management and support dynamical menu item lists! + @param "nNewCount" , returns count of menu entries for "new" + @param "nWizardCount" , returns count of menu entries for "wizard" + @return A list of configuration key names is returned. + *//*-*****************************************************************************************************/ + + Sequence< OUString > impl_GetPropertyNames( sal_uInt32& nNewCount, sal_uInt32& nWizardCount ); + + /*-**************************************************************************************************** + @short sort given source list and expand it for all well known properties to destination + @descr We must support sets of entries with count inside the name .. but some of them could be missing! + e.g. s1-s2-s3-s0-u1-s6-u5-u7 + Then we must sort it by name and expand it to the follow one: + sSetNode/s0/URL + sSetNode/s0/Title + sSetNode/s0/... + sSetNode/s1/URL + sSetNode/s1/Title + sSetNode/s1/... + ... + sSetNode/s6/URL + sSetNode/s6/Title + sSetNode/s6/... + sSetNode/u1/URL + sSetNode/u1/Title + sSetNode/u1/... + ... + sSetNode/u7/URL + sSetNode/u7/Title + sSetNode/u7/... + Rules: We start with all setup written entries names "sx" and x=[0..n]. + Then we handle all "ux" items. Inside these blocks we sort it ascending by number. + + @attention We add these expanded list to the end of given "lDestination" list! + So we must start on "lDestination.getLength()". + Reallocation of memory of destination list is done by us! + + @seealso method impl_GetPropertyNames() + + @param "lSource" , original list (e.g. [m1-m2-m3-m6-m0] ) + @param "lDestination" , destination of operation + @param "sSetNode" , name of configuration set to build complete path + @return A list of configuration key names is returned. + *//*-*****************************************************************************************************/ + + static void impl_SortAndExpandPropertyNames( const Sequence< OUString >& lSource , + Sequence< OUString >& lDestination , + const OUString& sSetNode ); + + // private member + + private: + + SvtDynMenu m_aNewMenu; + SvtDynMenu m_aWizardMenu; +}; + +// constructor + +SvtDynamicMenuOptions_Impl::SvtDynamicMenuOptions_Impl() + // Init baseclasses first + : ConfigItem( ROOTNODE_MENUS ) + // Init member then... +{ + // Get names and values of all accessible menu entries and fill internal structures. + // See impl_GetPropertyNames() for further information. + sal_uInt32 nNewCount = 0; + sal_uInt32 nWizardCount = 0; + Sequence< OUString > lNames = impl_GetPropertyNames ( nNewCount , + nWizardCount ); + Sequence< Any > lValues = GetProperties ( lNames ); + + // Safe impossible cases. + // We need values from ALL configuration keys. + // Follow assignment use order of values in relation to our list of key names! + DBG_ASSERT( !(lNames.getLength()!=lValues.getLength()), "SvtDynamicMenuOptions_Impl::SvtDynamicMenuOptions_Impl()\nI miss some values of configuration keys!\n" ); + + // Copy values from list in right order to our internal member. + // Attention: List for names and values have an internal construction pattern! + + // first "New" menu ... + // Name Value + // /New/1/URL "private:factory/swriter" + // /New/1/Title "New Writer Document" + // /New/1/ImageIdentifier "icon_writer" + // /New/1/TargetName "_blank" + + // /New/2/URL "private:factory/scalc" + // /New/2/Title "New Calc Document" + // /New/2/ImageIdentifier "icon_calc" + // /New/2/TargetName "_blank" + + // second "Wizard" menu ... + // /Wizard/1/URL "file://b" + // /Wizard/1/Title "PaintSomething" + // /Wizard/1/ImageIdentifier "icon_?" + // /Wizard/1/TargetName "_self" + + // ... and so on ... + + sal_uInt32 nItem = 0; + sal_uInt32 nPosition = 0; + + // Get names/values for new menu. + // 4 subkeys for every item! + for( nItem=0; nItem<nNewCount; ++nItem ) + { + SvtDynMenuEntry aItem; + lValues[nPosition] >>= aItem.sURL; + ++nPosition; + lValues[nPosition] >>= aItem.sTitle; + ++nPosition; + lValues[nPosition] >>= aItem.sImageIdentifier; + ++nPosition; + lValues[nPosition] >>= aItem.sTargetName; + ++nPosition; + m_aNewMenu.AppendSetupEntry( aItem ); + } + + // Attention: Don't reset nPosition here! + + // Get names/values for wizard menu. + // 4 subkeys for every item! + for( nItem=0; nItem<nWizardCount; ++nItem ) + { + SvtDynMenuEntry aItem; + lValues[nPosition] >>= aItem.sURL; + ++nPosition; + lValues[nPosition] >>= aItem.sTitle; + ++nPosition; + lValues[nPosition] >>= aItem.sImageIdentifier; + ++nPosition; + lValues[nPosition] >>= aItem.sTargetName; + ++nPosition; + m_aWizardMenu.AppendSetupEntry( aItem ); + } + + // Attention: Don't reset nPosition here! + +/*TODO: Not used in the moment! see Notify() ... + // Enable notification mechanism of our baseclass. + // We need it to get information about changes outside these class on our used configuration keys! + EnableNotification( lNames ); +*/ +} + +// destructor + +SvtDynamicMenuOptions_Impl::~SvtDynamicMenuOptions_Impl() +{ + assert(!IsModified()); // should have been committed +} + +// public method + +void SvtDynamicMenuOptions_Impl::Notify( const Sequence< OUString >& ) +{ + SAL_WARN( "unotools.config", "SvtDynamicMenuOptions_Impl::Notify() Not implemented yet! I don't know how I can handle a dynamical list of unknown properties ..." ); +} + +// public method + +void SvtDynamicMenuOptions_Impl::ImplCommit() +{ + SAL_WARN("unotools.config", "SvtDynamicMenuOptions_Impl::ImplCommit(): Not implemented yet!"); + /* + // Write all properties! + // Delete complete sets first. + ClearNodeSet( SETNODE_NEWMENU ); + ClearNodeSet( SETNODE_WIZARDMENU ); + + MenuEntry aItem; + OUString sNode; + Sequence< PropertyValue > lPropertyValues( PROPERTYCOUNT ); + sal_uInt32 nItem = 0; + + // Copy "new" menu entries to save-list! + sal_uInt32 nNewCount = m_aNewMenu.size(); + for( nItem=0; nItem<nNewCount; ++nItem ) + { + aItem = m_aNewMenu[nItem]; + // Format: "New/1/URL" + // "New/1/Title" + // ... + sNode = SETNODE_NEWMENU + PATHDELIMITER + PATHPREFIX + OUString::valueOf( (sal_Int32)nItem ) + PATHDELIMITER; + + lPropertyValues[OFFSET_URL ].Name = sNode + PROPERTYNAME_URL; + lPropertyValues[OFFSET_TITLE ].Name = sNode + PROPERTYNAME_TITLE; + lPropertyValues[OFFSET_IMAGEIDENTIFIER ].Name = sNode + PROPERTYNAME_IMAGEIDENTIFIER; + lPropertyValues[OFFSET_TARGETNAME ].Name = sNode + PROPERTYNAME_TARGETNAME; + + lPropertyValues[OFFSET_URL ].Value <<= aItem.sURL; + lPropertyValues[OFFSET_TITLE ].Value <<= aItem.sTitle; + lPropertyValues[OFFSET_IMAGEIDENTIFIER ].Value <<= aItem.sImageIdentifier; + lPropertyValues[OFFSET_TARGETNAME ].Value <<= aItem.sTargetName; + + SetSetProperties( SETNODE_NEWMENU, lPropertyValues ); + } + + // Copy "wizard" menu entries to save-list! + sal_uInt32 nWizardCount = m_aWizardMenu.size(); + for( nItem=0; nItem<nWizardCount; ++nItem ) + { + aItem = m_aWizardMenu[nItem]; + // Format: "Wizard/1/URL" + // "Wizard/1/Title" + // ... + sNode = SETNODE_WIZARDMENU + PATHDELIMITER + PATHPREFIX + OUString::valueOf( (sal_Int32)nItem ) + PATHDELIMITER; + + lPropertyValues[OFFSET_URL ].Name = sNode + PROPERTYNAME_URL; + lPropertyValues[OFFSET_TITLE ].Name = sNode + PROPERTYNAME_TITLE; + lPropertyValues[OFFSET_IMAGEIDENTIFIER ].Name = sNode + PROPERTYNAME_IMAGEIDENTIFIER; + lPropertyValues[OFFSET_TARGETNAME ].Name = sNode + PROPERTYNAME_TARGETNAME; + + lPropertyValues[OFFSET_URL ].Value <<= aItem.sURL; + lPropertyValues[OFFSET_TITLE ].Value <<= aItem.sTitle; + lPropertyValues[OFFSET_IMAGEIDENTIFIER ].Value <<= aItem.sImageIdentifier; + lPropertyValues[OFFSET_TARGETNAME ].Value <<= aItem.sTargetName; + + SetSetProperties( SETNODE_WIZARDMENU, lPropertyValues ); + } + + */ +} + +// public method + +Sequence< Sequence< PropertyValue > > SvtDynamicMenuOptions_Impl::GetMenu( EDynamicMenuType eMenu ) const +{ + Sequence< Sequence< PropertyValue > > lReturn; + switch( eMenu ) + { + case EDynamicMenuType::NewMenu : + lReturn = m_aNewMenu.GetList(); + break; + + case EDynamicMenuType::WizardMenu : + lReturn = m_aWizardMenu.GetList(); + break; + } + return lReturn; +} + +// private method + +Sequence< OUString > SvtDynamicMenuOptions_Impl::impl_GetPropertyNames( sal_uInt32& nNewCount, sal_uInt32& nWizardCount ) +{ + // First get ALL names of current existing list items in configuration! + Sequence< OUString > lNewItems = GetNodeNames( SETNODE_NEWMENU ); + Sequence< OUString > lWizardItems = GetNodeNames( SETNODE_WIZARDMENU ); + + // Get information about list counts ... + nNewCount = lNewItems.getLength (); + nWizardCount = lWizardItems.getLength (); + + // Sort and expand all three list to result list ... + Sequence< OUString > lProperties; + impl_SortAndExpandPropertyNames( lNewItems , lProperties, SETNODE_NEWMENU ); + impl_SortAndExpandPropertyNames( lWizardItems , lProperties, SETNODE_WIZARDMENU ); + + // Return result. + return lProperties; +} + +// private helper + +namespace { + +class CountWithPrefixSort +{ + public: + bool operator() ( const OUString& s1 , + const OUString& s2 ) const + { + // Get order numbers from entry name without prefix. + // e.g. "m10" => 10 + // "m5" => 5 + sal_Int32 n1 = s1.copy( 1 ).toInt32(); + sal_Int32 n2 = s2.copy( 1 ).toInt32(); + // MUST be in [0,1] ... because it's a difference between + // insert-positions of given entries in sorted list! + return( n1<n2 ); + } +}; + +class SelectByPrefix +{ + public: + bool operator() ( const OUString& s ) const + { + // Prefer setup written entries by check first letter of given string. It must be a "s". + return s.startsWith( PATHPREFIX_SETUP ); + } +}; + +} + +// private method + +void SvtDynamicMenuOptions_Impl::impl_SortAndExpandPropertyNames( const Sequence< OUString >& lSource , + Sequence< OUString >& lDestination , + const OUString& sSetNode ) +{ + vector< OUString > lTemp; + sal_Int32 nSourceCount = lSource.getLength(); + sal_Int32 nDestinationStep = lDestination.getLength(); // start on end of current list ...! + + lDestination.realloc( (nSourceCount*PROPERTYCOUNT)+nDestinationStep ); // get enough memory for copy operations after nDestination ... + + // Copy all items to temp. vector to use fast sort operations :-) + lTemp.reserve(nSourceCount); + std::copy(lSource.begin(), lSource.end(), std::back_inserter(lTemp)); + + // Sort all entries by number ... + stable_sort( lTemp.begin(), lTemp.end(), CountWithPrefixSort() ); + // and split into setup & user written entries! + stable_partition( lTemp.begin(), lTemp.end(), SelectByPrefix() ); + + // Copy sorted entries to destination and expand every item with + // 4 supported sub properties. + for( const auto& rItem : lTemp ) + { + OUString sFixPath(sSetNode + PATHDELIMITER + rItem + PATHDELIMITER); + lDestination[nDestinationStep++] = sFixPath + PROPERTYNAME_URL; + lDestination[nDestinationStep++] = sFixPath + PROPERTYNAME_TITLE; + lDestination[nDestinationStep++] = sFixPath + PROPERTYNAME_IMAGEIDENTIFIER; + lDestination[nDestinationStep++] = sFixPath + PROPERTYNAME_TARGETNAME; + } +} + +namespace { + // global + std::weak_ptr<SvtDynamicMenuOptions_Impl> g_pDynamicMenuOptions; +} + +SvtDynamicMenuOptions::SvtDynamicMenuOptions() +{ + // Global access, must be guarded (multithreading!). + MutexGuard aGuard( GetOwnStaticMutex() ); + + m_pImpl = g_pDynamicMenuOptions.lock(); + if( !m_pImpl ) + { + m_pImpl = std::make_shared<SvtDynamicMenuOptions_Impl>(); + g_pDynamicMenuOptions = m_pImpl; + ItemHolder1::holdConfigItem(EItem::DynamicMenuOptions); + } +} + +SvtDynamicMenuOptions::~SvtDynamicMenuOptions() +{ + // Global access, must be guarded (multithreading!) + MutexGuard aGuard( GetOwnStaticMutex() ); + + m_pImpl.reset(); +} + +// public method + +Sequence< Sequence< PropertyValue > > SvtDynamicMenuOptions::GetMenu( EDynamicMenuType eMenu ) const +{ + MutexGuard aGuard( GetOwnStaticMutex() ); + return m_pImpl->GetMenu( eMenu ); +} + +namespace +{ + class theDynamicMenuOptionsMutex : public rtl::Static<osl::Mutex, theDynamicMenuOptionsMutex>{}; +} + +// private method + +Mutex& SvtDynamicMenuOptions::GetOwnStaticMutex() +{ + return theDynamicMenuOptionsMutex::get(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/unotools/source/config/eventcfg.cxx b/unotools/source/config/eventcfg.cxx new file mode 100644 index 000000000..b0e36fc62 --- /dev/null +++ b/unotools/source/config/eventcfg.cxx @@ -0,0 +1,378 @@ +/* -*- 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 . + */ + +#include <unotools/eventcfg.hxx> +#include <unotools/configmgr.hxx> +#include <unotools/configitem.hxx> +#include <com/sun/star/uno/Any.hxx> +#include <com/sun/star/uno/Sequence.hxx> +#include <com/sun/star/beans/PropertyValue.hpp> +#include <o3tl/enumarray.hxx> +#include <o3tl/enumrange.hxx> +#include <rtl/ref.hxx> +#include <sal/log.hxx> + +#include "itemholder1.hxx" + +#include <algorithm> +#include <unordered_map> + +using namespace ::std; +using namespace ::utl; +using namespace ::osl; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star; + +#define PATHDELIMITER "/" +#define SETNODE_BINDINGS "Bindings" +#define PROPERTYNAME_BINDINGURL "BindingURL" + +static o3tl::enumarray<GlobalEventId, const char*> pEventAsciiNames = +{ +"OnStartApp", +"OnCloseApp", +"OnCreate", +"OnNew", +"OnLoadFinished", +"OnLoad", +"OnPrepareUnload", +"OnUnload", +"OnSave", +"OnSaveDone", +"OnSaveFailed", +"OnSaveAs", +"OnSaveAsDone", +"OnSaveAsFailed", +"OnCopyTo", +"OnCopyToDone", +"OnCopyToFailed", +"OnFocus", +"OnUnfocus", +"OnPrint", +"OnViewCreated", +"OnPrepareViewClosing", +"OnViewClosed", +"OnModifyChanged", +"OnTitleChanged", +"OnVisAreaChanged", +"OnModeChanged", +"OnStorageChanged" +}; + +typedef std::unordered_map< OUString, OUString > EventBindingHash; +typedef o3tl::enumarray< GlobalEventId, OUString > SupportedEventsVector; + +class GlobalEventConfig_Impl : public utl::ConfigItem +{ +private: + EventBindingHash m_eventBindingHash; + SupportedEventsVector m_supportedEvents; + + void initBindingInfo(); + + virtual void ImplCommit() override; + +public: + GlobalEventConfig_Impl( ); + virtual ~GlobalEventConfig_Impl( ) override; + + void Notify( const css::uno::Sequence<OUString>& aPropertyNames) override; + + /// @throws css::lang::IllegalArgumentException + /// @throws css::container::NoSuchElementException + /// @throws css::lang::WrappedTargetException + /// @throws css::uno::RuntimeException + void replaceByName( const OUString& aName, const css::uno::Any& aElement ); + /// @throws css::container::NoSuchElementException + /// @throws css::lang::WrappedTargetException + /// @throws css::uno::RuntimeException + css::uno::Any getByName( const OUString& aName ); + /// @throws css::uno::RuntimeException + css::uno::Sequence< OUString > getElementNames( ); + /// @throws css::uno::RuntimeException + bool hasByName( const OUString& aName ); + /// @throws css::uno::RuntimeException + static css::uno::Type const & getElementType( ); + /// @throws css::uno::RuntimeException + bool hasElements() const; + OUString const & GetEventName( GlobalEventId nID ) const; +}; + + +GlobalEventConfig_Impl::GlobalEventConfig_Impl() + : ConfigItem( "Office.Events/ApplicationEvents", ConfigItemMode::NONE ) +{ + // the supported event names + for (const GlobalEventId id : o3tl::enumrange<GlobalEventId>()) + m_supportedEvents[id] = OUString::createFromAscii( pEventAsciiNames[id] ); + + initBindingInfo(); + +/*TODO: Not used in the moment! see Notify() ... + // Enable notification mechanism of our baseclass. + // We need it to get information about changes outside these class on our used configuration keys! */ + Sequence<OUString> aNotifySeq { "Events" }; + EnableNotification( aNotifySeq, true ); +} + +// destructor + +GlobalEventConfig_Impl::~GlobalEventConfig_Impl() +{ + assert(!IsModified()); // should have been committed +} + +OUString const & GlobalEventConfig_Impl::GetEventName( GlobalEventId nIndex ) const +{ + return m_supportedEvents[nIndex]; +} + +// public method + +void GlobalEventConfig_Impl::Notify( const Sequence< OUString >& ) +{ + MutexGuard aGuard( GlobalEventConfig::GetOwnStaticMutex() ); + + initBindingInfo(); +} + +// public method + +void GlobalEventConfig_Impl::ImplCommit() +{ + //DF need to check it this is correct?? + SAL_INFO("unotools", "In GlobalEventConfig_Impl::ImplCommit"); + // clear the existing nodes + ClearNodeSet( SETNODE_BINDINGS ); + Sequence< beans::PropertyValue > seqValues( 1 ); + OUString sNode; + //step through the list of events + for(const auto& rEntry : m_eventBindingHash) + { + //no point in writing out empty bindings! + if(rEntry.second.isEmpty() ) + continue; + sNode = SETNODE_BINDINGS PATHDELIMITER "BindingType['" + + rEntry.first + + "']" PATHDELIMITER PROPERTYNAME_BINDINGURL; + SAL_INFO("unotools", "writing binding for: " << sNode); + seqValues[ 0 ].Name = sNode; + seqValues[ 0 ].Value <<= rEntry.second; + //write the data to the registry + SetSetProperties(SETNODE_BINDINGS,seqValues); + } +} + +// private method + +void GlobalEventConfig_Impl::initBindingInfo() +{ + // Get ALL names of current existing list items in configuration! + const Sequence< OUString > lEventNames = GetNodeNames( SETNODE_BINDINGS, utl::ConfigNameFormat::LocalPath ); + + OUString aSetNode = SETNODE_BINDINGS PATHDELIMITER; + OUString aCommandKey = PATHDELIMITER PROPERTYNAME_BINDINGURL; + + // Expand all keys + Sequence< OUString > lMacros(1); + for (const auto& rEventName : lEventNames ) + { + lMacros[0] = aSetNode + rEventName + aCommandKey; + SAL_INFO("unotools", "reading binding for: " << lMacros[0]); + Sequence< Any > lValues = GetProperties( lMacros ); + OUString sMacroURL; + if( lValues.hasElements() ) + { + lValues[0] >>= sMacroURL; + sal_Int32 startIndex = rEventName.indexOf('\''); + sal_Int32 endIndex = rEventName.lastIndexOf('\''); + if( startIndex >=0 && endIndex > 0 ) + { + startIndex++; + OUString eventName = rEventName.copy(startIndex,endIndex-startIndex); + m_eventBindingHash[ eventName ] = sMacroURL; + } + } + } +} + +void GlobalEventConfig_Impl::replaceByName( const OUString& aName, const Any& aElement ) +{ + Sequence< beans::PropertyValue > props; + //DF should we prepopulate the hash with a list of valid event Names? + if( !( aElement >>= props ) ) + { + throw lang::IllegalArgumentException( OUString(), + Reference< XInterface > (), 2); + } + OUString macroURL; + for( const auto& rProp : std::as_const(props) ) + { + if ( rProp.Name == "Script" ) + rProp.Value >>= macroURL; + } + m_eventBindingHash[ aName ] = macroURL; + SetModified(); +} + +Any GlobalEventConfig_Impl::getByName( const OUString& aName ) +{ + Any aRet; + Sequence< beans::PropertyValue > props(2); + props[0].Name = "EventType"; + props[0].Value <<= OUString("Script"); + props[1].Name = "Script"; + EventBindingHash::const_iterator it = m_eventBindingHash.find( aName ); + if( it != m_eventBindingHash.end() ) + { + props[1].Value <<= it->second; + } + else + { + // not yet accessed - is it a supported name? + SupportedEventsVector::iterator pos = ::std::find( + m_supportedEvents.begin(), m_supportedEvents.end(), aName ); + if ( pos == m_supportedEvents.end() ) + throw container::NoSuchElementException( aName ); + + props[1].Value <<= OUString(); + } + aRet <<= props; + return aRet; +} + +Sequence< OUString > GlobalEventConfig_Impl::getElementNames( ) +{ + return uno::Sequence< OUString >(m_supportedEvents.data(), SupportedEventsVector::size()); +} + +bool GlobalEventConfig_Impl::hasByName( const OUString& aName ) +{ + if ( m_eventBindingHash.find( aName ) != m_eventBindingHash.end() ) + return true; + + // never accessed before - is it supported in general? + SupportedEventsVector::iterator pos = ::std::find( + m_supportedEvents.begin(), m_supportedEvents.end(), aName ); + return pos != m_supportedEvents.end(); +} + +Type const & GlobalEventConfig_Impl::getElementType( ) +{ + //DF definitely not sure about this?? + return cppu::UnoType<Sequence<beans::PropertyValue>>::get(); +} + +bool GlobalEventConfig_Impl::hasElements() const +{ + return !m_eventBindingHash.empty(); +} + +// and now the wrapper + +//initialize static member +GlobalEventConfig_Impl* GlobalEventConfig::m_pImpl = nullptr; +sal_Int32 GlobalEventConfig::m_nRefCount = 0; + +GlobalEventConfig::GlobalEventConfig() +{ + // Global access, must be guarded (multithreading!). + MutexGuard aGuard( GetOwnStaticMutex() ); + // Increase our refcount ... + ++m_nRefCount; + // ... and initialize our data container only if it not already exist! + if( m_pImpl == nullptr ) + { + m_pImpl = new GlobalEventConfig_Impl; + ItemHolder1::holdConfigItem(EItem::EventConfig); + } +} + +GlobalEventConfig::~GlobalEventConfig() +{ + // Global access, must be guarded (multithreading!) + MutexGuard aGuard( GetOwnStaticMutex() ); + // Decrease our refcount. + --m_nRefCount; + // If last instance was deleted ... + // we must destroy our static data container! + if( m_nRefCount <= 0 ) + { + delete m_pImpl; + m_pImpl = nullptr; + } +} + +Reference< container::XNameReplace > SAL_CALL GlobalEventConfig::getEvents() +{ + MutexGuard aGuard( GetOwnStaticMutex() ); + Reference< container::XNameReplace > ret(this); + return ret; +} + +void SAL_CALL GlobalEventConfig::replaceByName( const OUString& aName, const Any& aElement ) +{ + MutexGuard aGuard( GetOwnStaticMutex() ); + m_pImpl->replaceByName( aName, aElement ); +} +Any SAL_CALL GlobalEventConfig::getByName( const OUString& aName ) +{ + MutexGuard aGuard( GetOwnStaticMutex() ); + return m_pImpl->getByName( aName ); +} +Sequence< OUString > SAL_CALL GlobalEventConfig::getElementNames( ) +{ + MutexGuard aGuard( GetOwnStaticMutex() ); + return m_pImpl->getElementNames( ); +} +sal_Bool SAL_CALL GlobalEventConfig::hasByName( const OUString& aName ) +{ + MutexGuard aGuard( GetOwnStaticMutex() ); + return m_pImpl->hasByName( aName ); +} +Type SAL_CALL GlobalEventConfig::getElementType( ) +{ + MutexGuard aGuard( GetOwnStaticMutex() ); + return GlobalEventConfig_Impl::getElementType( ); +} +sal_Bool SAL_CALL GlobalEventConfig::hasElements( ) +{ + MutexGuard aGuard( GetOwnStaticMutex() ); + return m_pImpl->hasElements( ); +} + +namespace +{ + class theGlobalEventConfigMutex : public rtl::Static<osl::Mutex, theGlobalEventConfigMutex>{}; +} + +Mutex& GlobalEventConfig::GetOwnStaticMutex() +{ + return theGlobalEventConfigMutex::get(); +} + +OUString GlobalEventConfig::GetEventName( GlobalEventId nIndex ) +{ + if (utl::ConfigManager::IsFuzzing()) + return OUString(); + rtl::Reference<GlobalEventConfig> createImpl(new GlobalEventConfig); + return GlobalEventConfig::m_pImpl->GetEventName( nIndex ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/unotools/source/config/extendedsecurityoptions.cxx b/unotools/source/config/extendedsecurityoptions.cxx new file mode 100644 index 000000000..2d57ab423 --- /dev/null +++ b/unotools/source/config/extendedsecurityoptions.cxx @@ -0,0 +1,226 @@ +/* -*- 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 . + */ + +#include <sal/config.h> + +#include <unotools/extendedsecurityoptions.hxx> +#include <unotools/configitem.hxx> +#include <tools/debug.hxx> +#include <com/sun/star/uno/Any.hxx> +#include <com/sun/star/uno/Sequence.hxx> +#include <osl/diagnose.h> + +#include "itemholder1.hxx" + +#include <unordered_map> + +using namespace ::utl; +using namespace ::osl; +using namespace ::com::sun::star::uno; + +#define ROOTNODE_SECURITY "Office.Security" + +#define SECURE_EXTENSIONS_SET OUString("SecureExtensions") + +#define PROPERTYNAME_HYPERLINKS_OPEN OUString("Hyperlinks/Open") + +#define PROPERTYHANDLE_HYPERLINKS_OPEN 0 + +#define PROPERTYCOUNT 1 + +typedef std::unordered_map<OUString, sal_Int32> + ExtensionHashMap; + +class SvtExtendedSecurityOptions_Impl : public ConfigItem +{ + public: + SvtExtendedSecurityOptions_Impl(); + virtual ~SvtExtendedSecurityOptions_Impl() override; + + /*-**************************************************************************************************** + @short called for notify of configmanager + @descr This method is called from the ConfigManager before the application ends or from the + PropertyChangeListener if the sub tree broadcasts changes. You must update your + internal values. + + @seealso baseclass ConfigItem + + @param "seqPropertyNames" is the list of properties which should be updated. + *//*-*****************************************************************************************************/ + + virtual void Notify( const Sequence< OUString >& seqPropertyNames ) override; + + SvtExtendedSecurityOptions::OpenHyperlinkMode GetOpenHyperlinkMode() const { return m_eOpenHyperlinkMode;} + + private: + virtual void ImplCommit() override; + + /*-**************************************************************************************************** + @short return list of key names of our configuration management which represent our module tree + @descr This method returns a static const list of key names. We need it to get needed values from our + configuration management. + @return A list of needed configuration keys is returned. + *//*-*****************************************************************************************************/ + + static Sequence< OUString > GetPropertyNames(); + + SvtExtendedSecurityOptions::OpenHyperlinkMode m_eOpenHyperlinkMode; +}; + +// constructor + +SvtExtendedSecurityOptions_Impl::SvtExtendedSecurityOptions_Impl() + // Init baseclasses first + : ConfigItem ( ROOTNODE_SECURITY ) + , m_eOpenHyperlinkMode(SvtExtendedSecurityOptions::OPEN_NEVER) + // Init member then. +{ + Sequence< OUString > seqNames = GetPropertyNames(); + Sequence< Any > seqValues = GetProperties( seqNames ); + + sal_Int32 nPropertyCount = seqValues.getLength(); + for( sal_Int32 nProperty=0; nProperty<nPropertyCount; ++nProperty ) + { + // Safe impossible cases. + // Check any for valid value. + DBG_ASSERT( seqValues[nProperty].hasValue(), "SvtExtendedSecurityOptions_Impl::SvtExtendedSecurityOptions_Impl()\nInvalid property value detected!\n" ); + switch( nProperty ) + { + case PROPERTYHANDLE_HYPERLINKS_OPEN: + { + DBG_ASSERT( ( seqValues[nProperty].getValueTypeClass() == TypeClass_LONG ), "SvtExtendedSecurityOptions_Impl::SvtExtendedSecurityOptions_Impl()\nWho has changed the value type of 'Hyperlink/Open'?" ); + + sal_Int32 nMode = SvtExtendedSecurityOptions::OPEN_WITHSECURITYCHECK; + if ( seqValues[nProperty] >>= nMode ) + m_eOpenHyperlinkMode = static_cast<SvtExtendedSecurityOptions::OpenHyperlinkMode>(nMode); + else { + OSL_FAIL("Wrong type for Open mode!"); + } + } + break; + } + } + + // Enable notification mechanism of our baseclass. + // We need it to get information about changes outside these class on our used configuration keys! + Sequence<OUString> seqNotifyNames { SECURE_EXTENSIONS_SET }; + EnableNotification( seqNotifyNames ); +} + +// destructor + +SvtExtendedSecurityOptions_Impl::~SvtExtendedSecurityOptions_Impl() +{ + assert(!IsModified()); // should have been committed +} + +// public method + +void SvtExtendedSecurityOptions_Impl::Notify( const Sequence< OUString >& ) +{ + // Not implemented +} + +// public method + +void SvtExtendedSecurityOptions_Impl::ImplCommit() +{ + // Get names of supported properties, create a list for values and copy current values to it. + Sequence< OUString > seqNames = GetPropertyNames (); + sal_Int32 nCount = seqNames.getLength(); + Sequence< Any > seqValues ( nCount ); + for( sal_Int32 nProperty=0; nProperty<nCount; ++nProperty ) + { + switch( nProperty ) + { + case PROPERTYHANDLE_HYPERLINKS_OPEN: { + seqValues[nProperty] <<= static_cast<sal_Int32>(m_eOpenHyperlinkMode); + } + break; + } + } + + // Set properties in configuration. + PutProperties( seqNames, seqValues ); +} + +// private method (currently not used) + +Sequence< OUString > SvtExtendedSecurityOptions_Impl::GetPropertyNames() +{ + // Build list of configuration key names. + const OUString pProperties[] = + { + PROPERTYNAME_HYPERLINKS_OPEN + }; + // Initialize return sequence with these list ... + const Sequence< OUString > seqPropertyNames( pProperties, PROPERTYCOUNT ); + // ... and return it. + return seqPropertyNames; +} + +namespace { + +std::weak_ptr<SvtExtendedSecurityOptions_Impl> g_pExtendedSecurityOptions; + +} + +SvtExtendedSecurityOptions::SvtExtendedSecurityOptions() +{ + // Global access, must be guarded (multithreading!). + MutexGuard aGuard( GetInitMutex() ); + + m_pImpl = g_pExtendedSecurityOptions.lock(); + if( !m_pImpl ) + { + m_pImpl = std::make_shared<SvtExtendedSecurityOptions_Impl>(); + g_pExtendedSecurityOptions = m_pImpl; + ItemHolder1::holdConfigItem(EItem::ExtendedSecurityOptions); + } +} + +SvtExtendedSecurityOptions::~SvtExtendedSecurityOptions() +{ + // Global access, must be guarded (multithreading!) + MutexGuard aGuard( GetInitMutex() ); + + m_pImpl.reset(); +} + +// public method + +SvtExtendedSecurityOptions::OpenHyperlinkMode SvtExtendedSecurityOptions::GetOpenHyperlinkMode() const +{ + MutexGuard aGuard( GetInitMutex() ); + return m_pImpl->GetOpenHyperlinkMode(); +} + +namespace +{ + class theExtendedSecurityOptionsMutex : public rtl::Static<osl::Mutex, theExtendedSecurityOptionsMutex>{}; +} + +// private method + +Mutex& SvtExtendedSecurityOptions::GetInitMutex() +{ + return theExtendedSecurityOptionsMutex::get(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/unotools/source/config/fltrcfg.cxx b/unotools/source/config/fltrcfg.cxx new file mode 100644 index 000000000..c68ac827e --- /dev/null +++ b/unotools/source/config/fltrcfg.cxx @@ -0,0 +1,690 @@ +/* -*- 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 . + */ + +#include <o3tl/any.hxx> +#include <o3tl/typed_flags_set.hxx> +#include <unotools/fltrcfg.hxx> +#include <tools/debug.hxx> +#include <osl/diagnose.h> + +#include <com/sun/star/uno/Sequence.hxx> + +using namespace utl; +using namespace com::sun::star::uno; + +namespace { + +enum class ConfigFlags { + NONE = 0x0000000, + WordCode = 0x0000001, + WordStorage = 0x0000002, + ExcelCode = 0x0000004, + ExcelStorage = 0x0000008, + PowerPointCode = 0x0000010, + PowerPointStorage = 0x0000020, + MathLoad = 0x0000100, + MathSave = 0x0000200, + WriterLoad = 0x0000400, + WriterSave = 0x0000800, + CalcLoad = 0x0001000, + CalcSave = 0x0002000, + ImpressLoad = 0x0004000, + ImpressSave = 0x0008000, + ExcelExecTbl = 0x0010000, + EnablePowerPointPreview = 0x0020000, + EnableExcelPreview = 0x0040000, + EnableWordPreview = 0x0080000, + UseEnhancedFields = 0x0100000, + WordWbctbl = 0x0200000, + SmartArtShapeLoad = 0x0400000, + CharBackgroundToHighlighting = 0x8000000, + CreateMSOLockFiles = 0x2000000, + VisioLoad = 0x4000000, +}; + +} + +namespace o3tl { + template<> struct typed_flags<ConfigFlags> : is_typed_flags<ConfigFlags, 0xe7fff3f> {}; +} + +namespace { + +class SvtAppFilterOptions_Impl : public utl::ConfigItem +{ +private: + bool bLoadVBA; + bool bSaveVBA; + +protected: + virtual void ImplCommit() override; + +public: + explicit SvtAppFilterOptions_Impl(const OUString& rRoot) : + utl::ConfigItem(rRoot), + bLoadVBA(false), + bSaveVBA(false) {} + virtual ~SvtAppFilterOptions_Impl() override; + virtual void Notify( const css::uno::Sequence<OUString>& aPropertyNames) override; + void Load(); + + bool IsLoad() const {return bLoadVBA;} + void SetLoad(bool bSet) + { + if(bSet != bLoadVBA) + SetModified(); + bLoadVBA = bSet; + } + bool IsSave() const {return bSaveVBA;} + void SetSave(bool bSet) + { + if(bSet != bSaveVBA) + SetModified(); + bSaveVBA = bSet; + } +}; + +} + +SvtAppFilterOptions_Impl::~SvtAppFilterOptions_Impl() +{ + assert(!IsModified()); // should have been committed +} + +void SvtAppFilterOptions_Impl::ImplCommit() +{ + PutProperties( + {"Load", "Save"}, {css::uno::Any(bLoadVBA), css::uno::Any(bSaveVBA)}); +} + +void SvtAppFilterOptions_Impl::Notify( const Sequence< OUString >& ) +{ + // no listeners supported yet +} + +void SvtAppFilterOptions_Impl::Load() +{ + Sequence<OUString> aNames(2); + OUString* pNames = aNames.getArray(); + pNames[0] = "Load"; + pNames[1] = "Save"; + + Sequence<Any> aValues = GetProperties(aNames); + const Any* pValues = aValues.getConstArray(); + + if(pValues[0].hasValue()) + bLoadVBA = *o3tl::doAccess<bool>(pValues[0]); + if(pValues[1].hasValue()) + bSaveVBA = *o3tl::doAccess<bool>(pValues[1]); +} + +namespace { + +class SvtWriterFilterOptions_Impl : public SvtAppFilterOptions_Impl +{ +private: + bool bLoadExecutable; + + virtual void ImplCommit() override; + +public: + explicit SvtWriterFilterOptions_Impl(const OUString& rRoot) : + SvtAppFilterOptions_Impl(rRoot), + bLoadExecutable(false) + {} + void Load(); + + bool IsLoadExecutable() const {return bLoadExecutable;} + void SetLoadExecutable(bool bSet) + { + if(bSet != bLoadExecutable) + SetModified(); + bLoadExecutable = bSet; + } +}; + +} + +void SvtWriterFilterOptions_Impl::ImplCommit() +{ + SvtAppFilterOptions_Impl::ImplCommit(); + + Sequence<OUString> aNames { "Executable" }; + Sequence<Any> aValues(1); + aValues[0] <<= bLoadExecutable; + + PutProperties(aNames, aValues); +} + +void SvtWriterFilterOptions_Impl::Load() +{ + SvtAppFilterOptions_Impl::Load(); + + Sequence<OUString> aNames { "Executable" }; + + Sequence<Any> aValues = GetProperties(aNames); + const Any* pValues = aValues.getConstArray(); + if(pValues[0].hasValue()) + bLoadExecutable = *o3tl::doAccess<bool>(pValues[0]); +} + +namespace { + +class SvtCalcFilterOptions_Impl : public SvtAppFilterOptions_Impl +{ +private: + bool bLoadExecutable; + + virtual void ImplCommit() override; + +public: + explicit SvtCalcFilterOptions_Impl(const OUString& rRoot) : + SvtAppFilterOptions_Impl(rRoot), + bLoadExecutable(false) + {} + void Load(); + + bool IsLoadExecutable() const {return bLoadExecutable;} + void SetLoadExecutable(bool bSet) + { + if(bSet != bLoadExecutable) + SetModified(); + bLoadExecutable = bSet; + } +}; + +} + +void SvtCalcFilterOptions_Impl::ImplCommit() +{ + SvtAppFilterOptions_Impl::ImplCommit(); + + Sequence<OUString> aNames { "Executable" }; + Sequence<Any> aValues(1); + aValues[0] <<= bLoadExecutable; + + PutProperties(aNames, aValues); +} + +void SvtCalcFilterOptions_Impl::Load() +{ + SvtAppFilterOptions_Impl::Load(); + + Sequence<OUString> aNames { "Executable" }; + + Sequence<Any> aValues = GetProperties(aNames); + const Any* pValues = aValues.getConstArray(); + if(pValues[0].hasValue()) + bLoadExecutable = *o3tl::doAccess<bool>(pValues[0]); +} + +struct SvtFilterOptions_Impl +{ + ConfigFlags nFlags; + SvtWriterFilterOptions_Impl aWriterCfg; + SvtCalcFilterOptions_Impl aCalcCfg; + SvtAppFilterOptions_Impl aImpressCfg; + + SvtFilterOptions_Impl() : + aWriterCfg("Office.Writer/Filter/Import/VBA"), + aCalcCfg("Office.Calc/Filter/Import/VBA"), + aImpressCfg("Office.Impress/Filter/Import/VBA") + { + nFlags = ConfigFlags::WordCode | + ConfigFlags::WordStorage | + ConfigFlags::ExcelCode | + ConfigFlags::ExcelStorage | + ConfigFlags::PowerPointCode | + ConfigFlags::PowerPointStorage | + ConfigFlags::MathLoad | + ConfigFlags::MathSave | + ConfigFlags::WriterLoad | + ConfigFlags::WriterSave | + ConfigFlags::CalcLoad | + ConfigFlags::CalcSave | + ConfigFlags::ImpressLoad | + ConfigFlags::ImpressSave | + ConfigFlags::UseEnhancedFields | + ConfigFlags::SmartArtShapeLoad | + ConfigFlags::CharBackgroundToHighlighting| + ConfigFlags::CreateMSOLockFiles; + Load(); + } + + void SetFlag( ConfigFlags nFlag, bool bSet ); + bool IsFlag( ConfigFlags nFlag ) const; + void Load() + { + aWriterCfg.Load(); + aCalcCfg.Load(); + aImpressCfg.Load(); + } +}; + +void SvtFilterOptions_Impl::SetFlag( ConfigFlags nFlag, bool bSet ) +{ + switch(nFlag) + { + case ConfigFlags::WordCode: aWriterCfg.SetLoad(bSet);break; + case ConfigFlags::WordStorage: aWriterCfg.SetSave(bSet);break; + case ConfigFlags::WordWbctbl: aWriterCfg.SetLoadExecutable(bSet);break; + case ConfigFlags::ExcelCode: aCalcCfg.SetLoad(bSet);break; + case ConfigFlags::ExcelStorage: aCalcCfg.SetSave(bSet);break; + case ConfigFlags::ExcelExecTbl: aCalcCfg.SetLoadExecutable(bSet);break; + case ConfigFlags::PowerPointCode: aImpressCfg.SetLoad(bSet);break; + case ConfigFlags::PowerPointStorage: aImpressCfg.SetSave(bSet);break; + default: + if( bSet ) + nFlags |= nFlag; + else + nFlags &= ~nFlag; + } +} + +bool SvtFilterOptions_Impl::IsFlag( ConfigFlags nFlag ) const +{ + bool bRet; + switch(nFlag) + { + case ConfigFlags::WordCode : bRet = aWriterCfg.IsLoad();break; + case ConfigFlags::WordStorage : bRet = aWriterCfg.IsSave();break; + case ConfigFlags::WordWbctbl : bRet = aWriterCfg.IsLoadExecutable();break; + case ConfigFlags::ExcelCode : bRet = aCalcCfg.IsLoad();break; + case ConfigFlags::ExcelStorage : bRet = aCalcCfg.IsSave();break; + case ConfigFlags::ExcelExecTbl : bRet = aCalcCfg.IsLoadExecutable();break; + case ConfigFlags::PowerPointCode : bRet = aImpressCfg.IsLoad();break; + case ConfigFlags::PowerPointStorage : bRet = aImpressCfg.IsSave();break; + default: + bRet = bool(nFlags & nFlag ); + } + return bRet; +} + +namespace { + +const Sequence<OUString>& GetPropertyNames() +{ + static Sequence<OUString> const aNames + { + "Import/MathTypeToMath", // 0 + "Import/WinWordToWriter", // 1 + "Import/PowerPointToImpress", // 2 + "Import/ExcelToCalc", // 3 + "Export/MathToMathType", // 4 + "Export/WriterToWinWord", // 5 + "Export/ImpressToPowerPoint", // 6 + "Export/CalcToExcel", // 7 + "Export/EnablePowerPointPreview", // 8 + "Export/EnableExcelPreview", // 9 + "Export/EnableWordPreview", // 10 + "Import/ImportWWFieldsAsEnhancedFields", // 11 + "Import/SmartArtToShapes", // 12 + "Export/CharBackgroundToHighlighting", // 13 + "Import/CreateMSOLockFiles", // 14 + "Import/VisioToDraw" // 15 + }; + return aNames; +} + +} + +SvtFilterOptions::SvtFilterOptions() : + ConfigItem( "Office.Common/Filter/Microsoft" ), + pImpl(new SvtFilterOptions_Impl) +{ + EnableNotification(GetPropertyNames()); + Load(); +} + +SvtFilterOptions::~SvtFilterOptions() +{ +} + +static ConfigFlags lcl_GetFlag(sal_Int32 nProp) +{ + ConfigFlags nFlag = ConfigFlags::NONE; + switch(nProp) + { + case 0: nFlag = ConfigFlags::MathLoad; break; + case 1: nFlag = ConfigFlags::WriterLoad; break; + case 2: nFlag = ConfigFlags::ImpressLoad; break; + case 3: nFlag = ConfigFlags::CalcLoad; break; + case 4: nFlag = ConfigFlags::MathSave; break; + case 5: nFlag = ConfigFlags::WriterSave; break; + case 6: nFlag = ConfigFlags::ImpressSave; break; + case 7: nFlag = ConfigFlags::CalcSave; break; + case 8: nFlag = ConfigFlags::EnablePowerPointPreview; break; + case 9: nFlag = ConfigFlags::EnableExcelPreview; break; + case 10: nFlag = ConfigFlags::EnableWordPreview; break; + case 11: nFlag = ConfigFlags::UseEnhancedFields; break; + case 12: nFlag = ConfigFlags::SmartArtShapeLoad; break; + case 13: nFlag = ConfigFlags::CharBackgroundToHighlighting; break; + case 14: nFlag = ConfigFlags::CreateMSOLockFiles; break; + case 15: + nFlag = ConfigFlags::VisioLoad; + break; + + default: OSL_FAIL("illegal value"); + } + return nFlag; +} + +void SvtFilterOptions::Notify( const Sequence<OUString>& ) +{ + Load(); +} + +void SvtFilterOptions::ImplCommit() +{ + const Sequence<OUString>& aNames = GetPropertyNames(); + Sequence<Any> aValues(aNames.getLength()); + Any* pValues = aValues.getArray(); + + for(int nProp = 0; nProp < aNames.getLength(); nProp++) + { + ConfigFlags nFlag = lcl_GetFlag(nProp); + pValues[nProp] <<= pImpl->IsFlag(nFlag); + + } + PutProperties(aNames, aValues); +} + +void SvtFilterOptions::Load() +{ + pImpl->Load(); + const Sequence<OUString>& rNames = GetPropertyNames(); + Sequence<Any> aValues = GetProperties(rNames); + const Any* pValues = aValues.getConstArray(); + DBG_ASSERT(aValues.getLength() == rNames.getLength(), "GetProperties failed"); + if(aValues.getLength() == rNames.getLength()) + { + for(int nProp = 0; nProp < rNames.getLength(); nProp++) + { + if(pValues[nProp].hasValue()) + { + bool bVal = *o3tl::doAccess<bool>(pValues[nProp]); + ConfigFlags nFlag = lcl_GetFlag(nProp); + pImpl->SetFlag( nFlag, bVal); + } + } + } +} + +void SvtFilterOptions::SetLoadWordBasicCode( bool bFlag ) +{ + pImpl->SetFlag( ConfigFlags::WordCode, bFlag ); + SetModified(); +} + +bool SvtFilterOptions::IsLoadWordBasicCode() const +{ + return pImpl->IsFlag( ConfigFlags::WordCode ); +} + +void SvtFilterOptions::SetLoadWordBasicExecutable( bool bFlag ) +{ + pImpl->SetFlag( ConfigFlags::WordWbctbl, bFlag ); + SetModified(); +} + +bool SvtFilterOptions::IsLoadWordBasicExecutable() const +{ + return pImpl->IsFlag( ConfigFlags::WordWbctbl ); +} + +void SvtFilterOptions::SetLoadWordBasicStorage( bool bFlag ) +{ + pImpl->SetFlag( ConfigFlags::WordStorage, bFlag ); + SetModified(); +} + +bool SvtFilterOptions::IsLoadWordBasicStorage() const +{ + return pImpl->IsFlag( ConfigFlags::WordStorage ); +} + +void SvtFilterOptions::SetLoadExcelBasicCode( bool bFlag ) +{ + pImpl->SetFlag( ConfigFlags::ExcelCode, bFlag ); + SetModified(); +} + +bool SvtFilterOptions::IsLoadExcelBasicCode() const +{ + return pImpl->IsFlag( ConfigFlags::ExcelCode ); +} + +void SvtFilterOptions::SetLoadExcelBasicExecutable( bool bFlag ) +{ + pImpl->SetFlag( ConfigFlags::ExcelExecTbl, bFlag ); + SetModified(); +} + +bool SvtFilterOptions::IsLoadExcelBasicExecutable() const +{ + return pImpl->IsFlag( ConfigFlags::ExcelExecTbl ); +} + +void SvtFilterOptions::SetLoadExcelBasicStorage( bool bFlag ) +{ + pImpl->SetFlag( ConfigFlags::ExcelStorage, bFlag ); + SetModified(); +} + +bool SvtFilterOptions::IsLoadExcelBasicStorage() const +{ + return pImpl->IsFlag( ConfigFlags::ExcelStorage ); +} + +void SvtFilterOptions::SetLoadPPointBasicCode( bool bFlag ) +{ + pImpl->SetFlag( ConfigFlags::PowerPointCode, bFlag ); + SetModified(); +} + +bool SvtFilterOptions::IsLoadPPointBasicCode() const +{ + return pImpl->IsFlag( ConfigFlags::PowerPointCode ); +} + +void SvtFilterOptions::SetLoadPPointBasicStorage( bool bFlag ) +{ + pImpl->SetFlag( ConfigFlags::PowerPointStorage, bFlag ); + SetModified(); +} + +bool SvtFilterOptions::IsLoadPPointBasicStorage() const +{ + return pImpl->IsFlag( ConfigFlags::PowerPointStorage ); +} + +bool SvtFilterOptions::IsMathType2Math() const +{ + return pImpl->IsFlag( ConfigFlags::MathLoad ); +} + +void SvtFilterOptions::SetMathType2Math( bool bFlag ) +{ + pImpl->SetFlag( ConfigFlags::MathLoad, bFlag ); + SetModified(); +} + +bool SvtFilterOptions::IsMath2MathType() const +{ + return pImpl->IsFlag( ConfigFlags::MathSave ); +} + +void SvtFilterOptions::SetMath2MathType( bool bFlag ) +{ + pImpl->SetFlag( ConfigFlags::MathSave, bFlag ); + SetModified(); +} + +bool SvtFilterOptions::IsWinWord2Writer() const +{ + return pImpl->IsFlag( ConfigFlags::WriterLoad ); +} + +void SvtFilterOptions::SetWinWord2Writer( bool bFlag ) +{ + pImpl->SetFlag( ConfigFlags::WriterLoad, bFlag ); + SetModified(); +} + +bool SvtFilterOptions::IsWriter2WinWord() const +{ + return pImpl->IsFlag( ConfigFlags::WriterSave ); +} + +void SvtFilterOptions::SetWriter2WinWord( bool bFlag ) +{ + pImpl->SetFlag( ConfigFlags::WriterSave, bFlag ); + SetModified(); +} + +bool SvtFilterOptions::IsUseEnhancedFields() const +{ + return pImpl->IsFlag( ConfigFlags::UseEnhancedFields ); +} + +bool SvtFilterOptions::IsExcel2Calc() const +{ + return pImpl->IsFlag( ConfigFlags::CalcLoad ); +} + +void SvtFilterOptions::SetExcel2Calc( bool bFlag ) +{ + pImpl->SetFlag( ConfigFlags::CalcLoad, bFlag ); + SetModified(); +} + +bool SvtFilterOptions::IsCalc2Excel() const +{ + return pImpl->IsFlag( ConfigFlags::CalcSave ); +} + +void SvtFilterOptions::SetCalc2Excel( bool bFlag ) +{ + pImpl->SetFlag( ConfigFlags::CalcSave, bFlag ); + SetModified(); +} + +bool SvtFilterOptions::IsPowerPoint2Impress() const +{ + return pImpl->IsFlag( ConfigFlags::ImpressLoad ); +} + +void SvtFilterOptions::SetPowerPoint2Impress( bool bFlag ) +{ + pImpl->SetFlag( ConfigFlags::ImpressLoad, bFlag ); + SetModified(); +} + +bool SvtFilterOptions::IsImpress2PowerPoint() const +{ + return pImpl->IsFlag( ConfigFlags::ImpressSave ); +} + +void SvtFilterOptions::SetImpress2PowerPoint( bool bFlag ) +{ + pImpl->SetFlag( ConfigFlags::ImpressSave, bFlag ); + SetModified(); +} + +bool SvtFilterOptions::IsSmartArt2Shape() const +{ + return pImpl->IsFlag( ConfigFlags::SmartArtShapeLoad ); +} + +void SvtFilterOptions::SetSmartArt2Shape( bool bFlag ) +{ + pImpl->SetFlag( ConfigFlags::SmartArtShapeLoad, bFlag ); + SetModified(); +} + +bool SvtFilterOptions::IsVisio2Draw() const { return pImpl->IsFlag(ConfigFlags::VisioLoad); } + +void SvtFilterOptions::SetVisio2Draw(bool bFlag) +{ + pImpl->SetFlag(ConfigFlags::VisioLoad, bFlag); + SetModified(); +} + +namespace +{ + class theFilterOptions + : public rtl::Static<SvtFilterOptions, theFilterOptions> + { + }; +} + +SvtFilterOptions& SvtFilterOptions::Get() +{ + return theFilterOptions::get(); +} + +bool SvtFilterOptions::IsEnablePPTPreview() const +{ + return pImpl->IsFlag( ConfigFlags::EnablePowerPointPreview ); +} + +bool SvtFilterOptions::IsEnableCalcPreview() const +{ + return pImpl->IsFlag( ConfigFlags::EnableExcelPreview ); +} + +bool SvtFilterOptions::IsEnableWordPreview() const +{ + return pImpl->IsFlag( ConfigFlags::EnableWordPreview ); +} + +bool SvtFilterOptions::IsCharBackground2Highlighting() const +{ + return pImpl->IsFlag( ConfigFlags::CharBackgroundToHighlighting ); +} + +bool SvtFilterOptions::IsCharBackground2Shading() const +{ + return !pImpl->IsFlag( ConfigFlags::CharBackgroundToHighlighting ); +} + +void SvtFilterOptions::SetCharBackground2Highlighting() +{ + pImpl->SetFlag( ConfigFlags::CharBackgroundToHighlighting, true ); + SetModified(); +} + +void SvtFilterOptions::SetCharBackground2Shading() +{ + pImpl->SetFlag( ConfigFlags::CharBackgroundToHighlighting, false ); + SetModified(); +} + +bool SvtFilterOptions::IsMSOLockFileCreationIsEnabled() const +{ + return pImpl->IsFlag( ConfigFlags::CreateMSOLockFiles ); +} + +void SvtFilterOptions::EnableMSOLockFileCreation(bool bEnable) +{ + pImpl->SetFlag( ConfigFlags::CreateMSOLockFiles, bEnable ); + SetModified(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/unotools/source/config/fontcfg.cxx b/unotools/source/config/fontcfg.cxx new file mode 100644 index 000000000..8cc694bbb --- /dev/null +++ b/unotools/source/config/fontcfg.cxx @@ -0,0 +1,1089 @@ +/* -*- 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 . + */ + +#include <i18nlangtag/mslangid.hxx> +#include <i18nlangtag/languagetag.hxx> +#include <o3tl/any.hxx> +#include <unotools/configmgr.hxx> +#include <unotools/fontcfg.hxx> +#include <unotools/fontdefs.hxx> +#include <comphelper/processfactory.hxx> +#include <com/sun/star/uno/Any.hxx> +#include <com/sun/star/uno/Sequence.hxx> +#include <com/sun/star/configuration/theDefaultProvider.hpp> +#include <com/sun/star/container/XNameAccess.hpp> +#include <comphelper/propertysequence.hxx> +#include <unotools/syslocale.hxx> +#include <rtl/ustrbuf.hxx> +#include <rtl/instance.hxx> +#include <osl/diagnose.h> +#include <sal/macros.h> +#include <sal/log.hxx> + +#include <string.h> +#include <algorithm> + +using namespace utl; +using namespace com::sun::star::uno; +using namespace com::sun::star::lang; +using namespace com::sun::star::beans; +using namespace com::sun::star::container; +using namespace com::sun::star::configuration; + +/* + * DefaultFontConfiguration + */ + +static const char* getKeyType( DefaultFontType nKeyType ) +{ + switch( nKeyType ) + { + case DefaultFontType::CJK_DISPLAY: return "CJK_DISPLAY"; + case DefaultFontType::CJK_HEADING: return "CJK_HEADING"; + case DefaultFontType::CJK_PRESENTATION: return "CJK_PRESENTATION"; + case DefaultFontType::CJK_SPREADSHEET: return "CJK_SPREADSHEET"; + case DefaultFontType::CJK_TEXT: return "CJK_TEXT"; + case DefaultFontType::CTL_DISPLAY: return "CTL_DISPLAY"; + case DefaultFontType::CTL_HEADING: return "CTL_HEADING"; + case DefaultFontType::CTL_PRESENTATION: return "CTL_PRESENTATION"; + case DefaultFontType::CTL_SPREADSHEET: return "CTL_SPREADSHEET"; + case DefaultFontType::CTL_TEXT: return "CTL_TEXT"; + case DefaultFontType::FIXED: return "FIXED"; + case DefaultFontType::LATIN_DISPLAY: return "LATIN_DISPLAY"; + case DefaultFontType::LATIN_FIXED: return "LATIN_FIXED"; + case DefaultFontType::LATIN_HEADING: return "LATIN_HEADING"; + case DefaultFontType::LATIN_PRESENTATION: return "LATIN_PRESENTATION"; + case DefaultFontType::LATIN_SPREADSHEET: return "LATIN_SPREADSHEET"; + case DefaultFontType::LATIN_TEXT: return "LATIN_TEXT"; + case DefaultFontType::SANS: return "SANS"; + case DefaultFontType::SANS_UNICODE: return "SANS_UNICODE"; + case DefaultFontType::SERIF: return "SERIF"; + case DefaultFontType::SYMBOL: return "SYMBOL"; + case DefaultFontType::UI_FIXED: return "UI_FIXED"; + case DefaultFontType::UI_SANS: return "UI_SANS"; + default: + OSL_FAIL( "unmatched type" ); + return ""; + } +} + +namespace +{ + class theDefaultFontConfiguration + : public rtl::Static<DefaultFontConfiguration, + theDefaultFontConfiguration> + { + }; +} + +DefaultFontConfiguration& DefaultFontConfiguration::get() +{ + return theDefaultFontConfiguration::get(); +} + +DefaultFontConfiguration::DefaultFontConfiguration() +{ + if (utl::ConfigManager::IsFuzzing()) + return; + // create configuration hierarchical access name + try + { + // get service provider + m_xConfigProvider = theDefaultProvider::get(comphelper::getProcessComponentContext()); + Sequence<Any> aArgs(comphelper::InitAnyPropertySequence( + { + {"nodepath", Any(OUString( "/org.openoffice.VCL/DefaultFonts" ))} + })); + m_xConfigAccess = + Reference< XNameAccess >( + m_xConfigProvider->createInstanceWithArguments( "com.sun.star.configuration.ConfigurationAccess", + aArgs ), + UNO_QUERY ); + if( m_xConfigAccess.is() ) + { + const Sequence< OUString > aLocales = m_xConfigAccess->getElementNames(); + // fill config hash with empty interfaces + for( const OUString& rLocaleString : aLocales ) + { + // Feed through LanguageTag for casing. + OUString aLoc( LanguageTag( rLocaleString, true).getBcp47( false)); + m_aConfig[ aLoc ] = LocaleAccess(); + m_aConfig[ aLoc ].aConfigLocaleString = rLocaleString; + } + } + } + catch (const Exception&) + { + // configuration is awry + m_xConfigProvider.clear(); + m_xConfigAccess.clear(); + } + SAL_INFO("unotools.config", "config provider: " << m_xConfigProvider.is() + << ", config access: " << m_xConfigAccess.is()); +} + +DefaultFontConfiguration::~DefaultFontConfiguration() +{ + // release all nodes + m_aConfig.clear(); + // release top node + m_xConfigAccess.clear(); + // release config provider + m_xConfigProvider.clear(); +} + +OUString DefaultFontConfiguration::tryLocale( const OUString& rBcp47, const OUString& rType ) const +{ + OUString aRet; + + std::unordered_map< OUString, LocaleAccess >::const_iterator it = m_aConfig.find( rBcp47 ); + if( it != m_aConfig.end() ) + { + if( !it->second.xAccess.is() ) + { + try + { + Reference< XNameAccess > xNode; + if ( m_xConfigAccess->hasByName( it->second.aConfigLocaleString ) ) + { + Any aAny = m_xConfigAccess->getByName( it->second.aConfigLocaleString ); + if( aAny >>= xNode ) + it->second.xAccess = xNode; + } + } + catch (const NoSuchElementException&) + { + } + catch (const WrappedTargetException&) + { + } + } + if( it->second.xAccess.is() ) + { + try + { + if ( it->second.xAccess->hasByName( rType ) ) + { + Any aAny = it->second.xAccess->getByName( rType ); + aAny >>= aRet; + } + } + catch (const NoSuchElementException&) + { + } + catch (const WrappedTargetException&) + { + } + } + } + + return aRet; +} + +OUString DefaultFontConfiguration::getDefaultFont( const LanguageTag& rLanguageTag, DefaultFontType nType ) const +{ + OUString aType = OUString::createFromAscii( getKeyType( nType ) ); + // Try the simple cases first without constructing fallbacks. + OUString aRet = tryLocale( rLanguageTag.getBcp47(), aType ); + if (aRet.isEmpty()) + { + if (rLanguageTag.isIsoLocale()) + { + if (!rLanguageTag.getCountry().isEmpty()) + { + aRet = tryLocale( rLanguageTag.getLanguage(), aType ); + } + } + else + { + ::std::vector< OUString > aFallbacks( rLanguageTag.getFallbackStrings( false)); + for (const auto& rFallback : aFallbacks) + { + aRet = tryLocale( rFallback, aType ); + if (!aRet.isEmpty()) + break; + } + } + } + if( aRet.isEmpty() ) + { + aRet = tryLocale( "en", aType ); + } + return aRet; +} + +OUString DefaultFontConfiguration::getUserInterfaceFont( const LanguageTag& rLanguageTag ) const +{ + LanguageTag aLanguageTag( rLanguageTag); + if( aLanguageTag.isSystemLocale() ) + aLanguageTag = SvtSysLocale().GetUILanguageTag(); + + OUString aUIFont = getDefaultFont( aLanguageTag, DefaultFontType::UI_SANS ); + + if( !aUIFont.isEmpty() ) + return aUIFont; + + // fallback mechanism (either no configuration or no entry in configuration + + #define FALLBACKFONT_UI_SANS "Andale Sans UI;Albany;Albany AMT;Tahoma;Arial Unicode MS;Arial;Nimbus Sans L;Bitstream Vera Sans;gnu-unifont;Interface User;Geneva;WarpSans;Dialog;Swiss;Lucida;Helvetica;Charcoal;Chicago;MS Sans Serif;Helv;Times;Times New Roman;Interface System" + #define FALLBACKFONT_UI_SANS_LATIN2 "Andale Sans UI;Albany;Albany AMT;Tahoma;Arial Unicode MS;Arial;Nimbus Sans L;Luxi Sans;Bitstream Vera Sans;Interface User;Geneva;WarpSans;Dialog;Swiss;Lucida;Helvetica;Charcoal;Chicago;MS Sans Serif;Helv;Times;Times New Roman;Interface System" + #define FALLBACKFONT_UI_SANS_ARABIC "Tahoma;Traditional Arabic;Simplified Arabic;Lucidasans;Lucida Sans;Supplement;Andale Sans UI;clearlyU;Interface User;Arial Unicode MS;Lucida Sans Unicode;WarpSans;Geneva;MS Sans Serif;Helv;Dialog;Albany;Lucida;Helvetica;Charcoal;Chicago;Arial;Helmet;Interface System;Sans Serif" + #define FALLBACKFONT_UI_SANS_THAI "OONaksit;Tahoma;Lucidasans;Arial Unicode MS" + #define FALLBACKFONT_UI_SANS_KOREAN "Noto Sans CJK KR;Noto Sans KR;Source Han Sans KR;NanumGothic;NanumBarunGothic;NanumBarunGothic YetHangul;KoPubWorld Dotum;Malgun Gothic;Apple SD Gothic Neo;Dotum;Gulim;Apple Gothic;UnDotum;Baekmuk Gulim;Arial Unicode MS;Lucida Sans Unicode;gnu-unifont;Andale Sans UI" + #define FALLBACKFONT_UI_SANS_CHINSIM "Andale Sans UI;Arial Unicode MS;ZYSong18030;AR PL SungtiL GB;AR PL KaitiM GB;SimSun;Lucida Sans Unicode;Fangsong;Hei;Song;Kai;Ming;gnu-unifont;Interface User;" + #define FALLBACKFONT_UI_SANS_CHINTRD "Andale Sans UI;Arial Unicode MS;AR PL Mingti2L Big5;AR PL KaitiM Big5;Kai;PMingLiU;MingLiU;Ming;Lucida Sans Unicode;gnu-unifont;Interface User;" + + const OUString aLanguage( aLanguageTag.getLanguage()); + + // optimize font list for some locales, as long as Andale Sans UI does not support them + if( aLanguage == "ar" || aLanguage == "he" || aLanguage == "iw" ) + { + return FALLBACKFONT_UI_SANS_ARABIC; + } + else if ( aLanguage == "th" ) + { + return FALLBACKFONT_UI_SANS_THAI; + } + else if ( aLanguage == "ko" ) + { + return FALLBACKFONT_UI_SANS_KOREAN; + } + else if( aLanguage == "cs" || + aLanguage == "hu" || + aLanguage == "pl" || + aLanguage == "ro" || + aLanguage == "rm" || + aLanguage == "hr" || + aLanguage == "sk" || + aLanguage == "sl" || + aLanguage == "sb") + { + return FALLBACKFONT_UI_SANS_LATIN2; + } + else + { + const Locale& aLocale( aLanguageTag.getLocale()); + if (MsLangId::isTraditionalChinese(aLocale)) + return FALLBACKFONT_UI_SANS_CHINTRD; + else if (MsLangId::isSimplifiedChinese(aLocale)) + return FALLBACKFONT_UI_SANS_CHINSIM; + } + + return FALLBACKFONT_UI_SANS; +} + +/* + * FontSubstConfigItem::get + */ + +namespace +{ + class theFontSubstConfiguration + : public rtl::Static<FontSubstConfiguration, theFontSubstConfiguration> + { + }; +} + +FontSubstConfiguration& FontSubstConfiguration::get() +{ + return theFontSubstConfiguration::get(); +} + +/* + * FontSubstConfigItem::FontSubstConfigItem + */ + +FontSubstConfiguration::FontSubstConfiguration() : + maSubstHash( 300 ) +{ + if (utl::ConfigManager::IsFuzzing()) + return; + try + { + // get service provider + Reference< XComponentContext > xContext( comphelper::getProcessComponentContext() ); + // create configuration hierarchical access name + m_xConfigProvider = theDefaultProvider::get( xContext ); + Sequence<Any> aArgs(comphelper::InitAnyPropertySequence( + { + {"nodepath", Any(OUString( "/org.openoffice.VCL/FontSubstitutions" ))} + })); + m_xConfigAccess = + Reference< XNameAccess >( + m_xConfigProvider->createInstanceWithArguments( "com.sun.star.configuration.ConfigurationAccess", + aArgs ), + UNO_QUERY ); + if( m_xConfigAccess.is() ) + { + const Sequence< OUString > aLocales = m_xConfigAccess->getElementNames(); + // fill config hash with empty interfaces + for( const OUString& rLocaleString : aLocales ) + { + // Feed through LanguageTag for casing. + OUString aLoc( LanguageTag( rLocaleString, true).getBcp47( false)); + m_aSubst[ aLoc ] = LocaleSubst(); + m_aSubst[ aLoc ].aConfigLocaleString = rLocaleString; + } + } + } + catch (const Exception&) + { + // configuration is awry + m_xConfigProvider.clear(); + m_xConfigAccess.clear(); + } + SAL_INFO("unotools.config", "config provider: " << m_xConfigProvider.is() + << ", config access: " << m_xConfigAccess.is()); +} + +/* + * FontSubstConfigItem::~FontSubstConfigItem + */ + +FontSubstConfiguration::~FontSubstConfiguration() +{ + // release config access + m_xConfigAccess.clear(); + // release config provider + m_xConfigProvider.clear(); +} + +/* + * FontSubstConfigItem::getMapName + */ + +static const char* const aImplKillLeadingList[] = +{ + "microsoft", + "monotype", + "linotype", + "baekmuk", + "adobe", + "nimbus", + "zycjk", + "itc", + "sun", + "amt", + "ms", + "mt", + "cg", + "hg", + "fz", + "ipa", + "sazanami", + "kochi", + nullptr +}; + +static const char* const aImplKillTrailingList[] = +{ + "microsoft", + "monotype", + "linotype", + "adobe", + "nimbus", + "itc", + "sun", + "amt", + "ms", + "mt", + "clm", + // Scripts, for compatibility with older versions + "we", + "cyr", + "tur", + "wt", + "greek", + "wl", + // CJK extensions + "gb", + "big5", + "pro", + "z01", + "z02", + "z03", + "z13", + "b01", + "w3x12", + // Old Printer Fontnames + "5cpi", + "6cpi", + "7cpi", + "8cpi", + "9cpi", + "10cpi", + "11cpi", + "12cpi", + "13cpi", + "14cpi", + "15cpi", + "16cpi", + "18cpi", + "24cpi", + "scale", + "pc", + nullptr +}; + +static const char* const aImplKillTrailingWithExceptionsList[] = +{ + "ce", "monospace", "oldface", nullptr, + "ps", "caps", nullptr, + nullptr +}; + +namespace { + +struct ImplFontAttrWeightSearchData +{ + const char* mpStr; + FontWeight meWeight; +}; + +} + +static ImplFontAttrWeightSearchData const aImplWeightAttrSearchList[] = +{ +// the attribute names are ordered by "first match wins" +// e.g. "semilight" should wins over "semi" +{ "extrablack", WEIGHT_BLACK }, +{ "ultrablack", WEIGHT_BLACK }, +{ "ultrabold", WEIGHT_ULTRABOLD }, +{ "semibold", WEIGHT_SEMIBOLD }, +{ "semilight", WEIGHT_SEMILIGHT }, +{ "semi", WEIGHT_SEMIBOLD }, +{ "demi", WEIGHT_SEMIBOLD }, +{ "black", WEIGHT_BLACK }, +{ "bold", WEIGHT_BOLD }, +{ "heavy", WEIGHT_BLACK }, +{ "ultralight", WEIGHT_ULTRALIGHT }, +{ "light", WEIGHT_LIGHT }, +{ "medium", WEIGHT_MEDIUM }, +{ nullptr, WEIGHT_DONTKNOW }, +}; + +namespace { + +struct ImplFontAttrWidthSearchData +{ + const char* mpStr; + FontWidth meWidth; +}; + +} + +static ImplFontAttrWidthSearchData const aImplWidthAttrSearchList[] = +{ +{ "narrow", WIDTH_CONDENSED }, +{ "semicondensed", WIDTH_SEMI_CONDENSED }, +{ "ultracondensed", WIDTH_ULTRA_CONDENSED }, +{ "semiexpanded", WIDTH_SEMI_EXPANDED }, +{ "ultraexpanded", WIDTH_ULTRA_EXPANDED }, +{ "expanded", WIDTH_EXPANDED }, +{ "wide", WIDTH_ULTRA_EXPANDED }, +{ "condensed", WIDTH_CONDENSED }, +{ "cond", WIDTH_CONDENSED }, +{ "cn", WIDTH_CONDENSED }, +{ nullptr, WIDTH_DONTKNOW }, +}; + +namespace { + +struct ImplFontAttrTypeSearchData +{ + const char* mpStr; + ImplFontAttrs mnType; +}; + +} + +static ImplFontAttrTypeSearchData const aImplTypeAttrSearchList[] = +{ +{ "monotype", ImplFontAttrs::None }, +{ "linotype", ImplFontAttrs::None }, +{ "titling", ImplFontAttrs::Titling }, +{ "captitals", ImplFontAttrs::Capitals }, +{ "captital", ImplFontAttrs::Capitals }, +{ "caps", ImplFontAttrs::Capitals }, +{ "italic", ImplFontAttrs::Italic }, +{ "oblique", ImplFontAttrs::Italic }, +{ "rounded", ImplFontAttrs::Rounded }, +{ "outline", ImplFontAttrs::Outline }, +{ "shadow", ImplFontAttrs::Shadow }, +{ "handwriting", ImplFontAttrs::Handwriting | ImplFontAttrs::Script }, +{ "hand", ImplFontAttrs::Handwriting | ImplFontAttrs::Script }, +{ "signet", ImplFontAttrs::Handwriting | ImplFontAttrs::Script }, +{ "script", ImplFontAttrs::BrushScript | ImplFontAttrs::Script }, +{ "calligraphy", ImplFontAttrs::Chancery | ImplFontAttrs::Script }, +{ "chancery", ImplFontAttrs::Chancery | ImplFontAttrs::Script }, +{ "corsiva", ImplFontAttrs::Chancery | ImplFontAttrs::Script }, +{ "gothic", ImplFontAttrs::SansSerif | ImplFontAttrs::Gothic }, +{ "schoolbook", ImplFontAttrs::Serif | ImplFontAttrs::Schoolbook }, +{ "schlbk", ImplFontAttrs::Serif | ImplFontAttrs::Schoolbook }, +{ "typewriter", ImplFontAttrs::Typewriter | ImplFontAttrs::Fixed }, +{ "lineprinter", ImplFontAttrs::Typewriter | ImplFontAttrs::Fixed }, +{ "monospaced", ImplFontAttrs::Fixed }, +{ "monospace", ImplFontAttrs::Fixed }, +{ "mono", ImplFontAttrs::Fixed }, +{ "fixed", ImplFontAttrs::Fixed }, +{ "sansserif", ImplFontAttrs::SansSerif }, +{ "sans", ImplFontAttrs::SansSerif }, +{ "swiss", ImplFontAttrs::SansSerif }, +{ "serif", ImplFontAttrs::Serif }, +{ "bright", ImplFontAttrs::Serif }, +{ "symbols", ImplFontAttrs::Symbol }, +{ "symbol", ImplFontAttrs::Symbol }, +{ "dingbats", ImplFontAttrs::Symbol }, +{ "dings", ImplFontAttrs::Symbol }, +{ "ding", ImplFontAttrs::Symbol }, +{ "bats", ImplFontAttrs::Symbol }, +{ "math", ImplFontAttrs::Symbol }, +{ "oldstyle", ImplFontAttrs::OtherStyle }, +{ "oldface", ImplFontAttrs::OtherStyle }, +{ "old", ImplFontAttrs::OtherStyle }, +{ "new", ImplFontAttrs::None }, +{ "modern", ImplFontAttrs::None }, +{ "lucida", ImplFontAttrs::None }, +{ "regular", ImplFontAttrs::None }, +{ "extended", ImplFontAttrs::None }, +{ "extra", ImplFontAttrs::OtherStyle }, +{ "ext", ImplFontAttrs::None }, +{ "scalable", ImplFontAttrs::None }, +{ "scale", ImplFontAttrs::None }, +{ "nimbus", ImplFontAttrs::None }, +{ "adobe", ImplFontAttrs::None }, +{ "itc", ImplFontAttrs::None }, +{ "amt", ImplFontAttrs::None }, +{ "mt", ImplFontAttrs::None }, +{ "ms", ImplFontAttrs::None }, +{ "cpi", ImplFontAttrs::None }, +{ "no", ImplFontAttrs::None }, +{ nullptr, ImplFontAttrs::None }, +}; + +static bool ImplKillLeading( OUString& rName, const char* const* ppStr ) +{ + for(; *ppStr; ++ppStr ) + { + const char* pStr = *ppStr; + const sal_Unicode* pNameStr = rName.getStr(); + while ( (*pNameStr == static_cast<sal_Unicode>(static_cast<unsigned char>(*pStr))) && *pStr ) + { + pNameStr++; + pStr++; + } + if ( !*pStr ) + { + sal_Int32 nLen = static_cast<sal_Int32>(pNameStr - rName.getStr()); + rName = rName.copy(nLen); + return true; + } + } + + // special case for Baekmuk + // TODO: allow non-ASCII KillLeading list + const sal_Unicode* pNameStr = rName.getStr(); + if( (pNameStr[0]==0xBC31) && (pNameStr[1]==0xBC35) ) + { + sal_Int32 nLen = (pNameStr[2]==0x0020) ? 3 : 2; + rName = rName.copy(nLen); + return true; + } + + return false; +} + +static sal_Int32 ImplIsTrailing( const OUString& rName, const char* pStr ) +{ + sal_Int32 nStrLen = static_cast<sal_Int32>(strlen( pStr )); + if( nStrLen >= rName.getLength() ) + return 0; + + const sal_Unicode* pEndName = rName.getStr() + rName.getLength(); + const sal_Unicode* pNameStr = pEndName - nStrLen; + do if( *(pNameStr++) != *(pStr++) ) + return 0; + while( *pStr ); + + return nStrLen; +} + +static bool ImplKillTrailing( OUString& rName, const char* const* ppStr ) +{ + for(; *ppStr; ++ppStr ) + { + sal_Int32 nTrailLen = ImplIsTrailing( rName, *ppStr ); + if( nTrailLen ) + { + rName = rName.copy(0, rName.getLength() - nTrailLen ); + return true; + } + } + + return false; +} + +static bool ImplKillTrailingWithExceptions( OUString& rName, const char* const* ppStr ) +{ + for(; *ppStr; ++ppStr ) + { + sal_Int32 nTrailLen = ImplIsTrailing( rName, *ppStr ); + if( nTrailLen ) + { + // check string match against string exceptions + while( *++ppStr ) + if( ImplIsTrailing( rName, *ppStr ) ) + return false; + + rName = rName.copy(0, rName.getLength() - nTrailLen ); + return true; + } + else + { + // skip exception strings + while( *++ppStr ) {} + } + } + + return false; +} + +static bool ImplFindAndErase( OUString& rName, const char* pStr ) +{ + sal_Int32 nLen = static_cast<sal_Int32>(strlen(pStr)); + sal_Int32 nPos = rName.indexOfAsciiL(pStr, nLen ); + if ( nPos < 0 ) + return false; + + OUStringBuffer sBuff(rName); + sBuff.remove(nPos, nLen); + rName = sBuff.makeStringAndClear(); + return true; +} + +void FontSubstConfiguration::getMapName( const OUString& rOrgName, OUString& rShortName, + OUString& rFamilyName, FontWeight& rWeight, + FontWidth& rWidth, ImplFontAttrs& rType ) +{ + rShortName = rOrgName; + + // TODO: get rid of the crazy O(N*strlen) searches below + // they should be possible in O(strlen) + + // Kill leading vendor names and other unimportant data + ImplKillLeading( rShortName, aImplKillLeadingList ); + + // Kill trailing vendor names and other unimportant data + ImplKillTrailing( rShortName, aImplKillTrailingList ); + ImplKillTrailingWithExceptions( rShortName, aImplKillTrailingWithExceptionsList ); + + rFamilyName = rShortName; + + // Kill attributes from the name and update the data + // Weight + const ImplFontAttrWeightSearchData* pWeightList = aImplWeightAttrSearchList; + while ( pWeightList->mpStr ) + { + if ( ImplFindAndErase( rFamilyName, pWeightList->mpStr ) ) + { + if ( (rWeight == WEIGHT_DONTKNOW) || (rWeight == WEIGHT_NORMAL) ) + rWeight = pWeightList->meWeight; + break; + } + pWeightList++; + } + + // Width + const ImplFontAttrWidthSearchData* pWidthList = aImplWidthAttrSearchList; + while ( pWidthList->mpStr ) + { + if ( ImplFindAndErase( rFamilyName, pWidthList->mpStr ) ) + { + if ( (rWidth == WIDTH_DONTKNOW) || (rWidth == WIDTH_NORMAL) ) + rWidth = pWidthList->meWidth; + break; + } + pWidthList++; + } + + // Type + rType = ImplFontAttrs::None; + const ImplFontAttrTypeSearchData* pTypeList = aImplTypeAttrSearchList; + while ( pTypeList->mpStr ) + { + if ( ImplFindAndErase( rFamilyName, pTypeList->mpStr ) ) + rType |= pTypeList->mnType; + pTypeList++; + } + + // Remove numbers + // TODO: also remove localized and fullwidth digits + sal_Int32 i = 0; + OUStringBuffer sBuff(rFamilyName); + while ( i < sBuff.getLength() ) + { + sal_Unicode c = sBuff[ i ]; + if ( (c >= 0x0030) && (c <= 0x0039) ) + sBuff.remove(i, 1); + else + i++; + } +} + +namespace { + +struct StrictStringSort +{ + bool operator()( const FontNameAttr& rLeft, const FontNameAttr& rRight ) + { return rLeft.Name.compareTo( rRight.Name ) < 0; } +}; + +} + +// The entries in this table must match the bits in the ImplFontAttrs enum. + +static const char* const pAttribNames[] = +{ + "default", + "standard", + "normal", + "symbol", + "fixed", + "sansserif", + "serif", + "decorative", + "special", + "italic", + "title", + "capitals", + "cjk", + "cjk_jp", + "cjk_sc", + "cjk_tc", + "cjk_kr", + "ctl", + "nonelatin", + "full", + "outline", + "shadow", + "rounded", + "typewriter", + "script", + "handwriting", + "chancery", + "comic", + "brushscript", + "gothic", + "schoolbook", + "other" +}; + +namespace { + +struct enum_convert +{ + const char* pName; + int nEnum; +}; + +} + +static const enum_convert pWeightNames[] = +{ + { "normal", WEIGHT_NORMAL }, + { "medium", WEIGHT_MEDIUM }, + { "bold", WEIGHT_BOLD }, + { "black", WEIGHT_BLACK }, + { "semibold", WEIGHT_SEMIBOLD }, + { "light", WEIGHT_LIGHT }, + { "semilight", WEIGHT_SEMILIGHT }, + { "ultrabold", WEIGHT_ULTRABOLD }, + { "semi", WEIGHT_SEMIBOLD }, + { "demi", WEIGHT_SEMIBOLD }, + { "heavy", WEIGHT_BLACK }, + { "unknown", WEIGHT_DONTKNOW }, + { "thin", WEIGHT_THIN }, + { "ultralight", WEIGHT_ULTRALIGHT } +}; + +static const enum_convert pWidthNames[] = +{ + { "normal", WIDTH_NORMAL }, + { "condensed", WIDTH_CONDENSED }, + { "expanded", WIDTH_EXPANDED }, + { "unknown", WIDTH_DONTKNOW }, + { "ultracondensed", WIDTH_ULTRA_CONDENSED }, + { "extracondensed", WIDTH_EXTRA_CONDENSED }, + { "semicondensed", WIDTH_SEMI_CONDENSED }, + { "semiexpanded", WIDTH_SEMI_EXPANDED }, + { "extraexpanded", WIDTH_EXTRA_EXPANDED }, + { "ultraexpanded", WIDTH_ULTRA_EXPANDED } +}; + +void FontSubstConfiguration::fillSubstVector( const css::uno::Reference< XNameAccess >& rFont, + const OUString& rType, + std::vector< OUString >& rSubstVector ) const +{ + try + { + Any aAny = rFont->getByName( rType ); + if( auto pLine = o3tl::tryAccess<OUString>(aAny) ) + { + sal_Int32 nLength = pLine->getLength(); + if( nLength ) + { + const sal_Unicode* pStr = pLine->getStr(); + sal_Int32 nTokens = 0; + // count tokens + while( nLength-- ) + { + if( *pStr++ == ';' ) + nTokens++; + } + rSubstVector.clear(); + // optimize performance, heap fragmentation + rSubstVector.reserve( nTokens ); + sal_Int32 nIndex = 0; + while( nIndex != -1 ) + { + OUString aSubst( pLine->getToken( 0, ';', nIndex ) ); + if( !aSubst.isEmpty() ) + { + auto itPair = maSubstHash.insert( aSubst ); + if (!itPair.second) + aSubst = *itPair.first; + rSubstVector.push_back( aSubst ); + } + } + } + } + } + catch (const NoSuchElementException&) + { + } + catch (const WrappedTargetException&) + { + } +} + +FontWeight FontSubstConfiguration::getSubstWeight( const css::uno::Reference< XNameAccess >& rFont, + const OUString& rType ) const +{ + int weight = -1; + try + { + Any aAny = rFont->getByName( rType ); + if( auto pLine = o3tl::tryAccess<OUString>(aAny) ) + { + if( !pLine->isEmpty() ) + { + for( weight=SAL_N_ELEMENTS(pWeightNames)-1; weight >= 0; weight-- ) + if( pLine->equalsIgnoreAsciiCaseAscii( pWeightNames[weight].pName ) ) + break; + } + SAL_WARN_IF(weight < 0, "unotools.config", "Error: invalid weight " << *pLine); + } + } + catch (const NoSuchElementException&) + { + } + catch (const WrappedTargetException&) + { + } + return static_cast<FontWeight>( weight >= 0 ? pWeightNames[weight].nEnum : WEIGHT_DONTKNOW ); +} + +FontWidth FontSubstConfiguration::getSubstWidth( const css::uno::Reference< XNameAccess >& rFont, + const OUString& rType ) const +{ + int width = -1; + try + { + Any aAny = rFont->getByName( rType ); + if( auto pLine = o3tl::tryAccess<OUString>(aAny) ) + { + if( !pLine->isEmpty() ) + { + for( width=SAL_N_ELEMENTS(pWidthNames)-1; width >= 0; width-- ) + if( pLine->equalsIgnoreAsciiCaseAscii( pWidthNames[width].pName ) ) + break; + } + SAL_WARN_IF( width < 0, "unotools.config", "Error: invalid width " << *pLine); + } + } + catch (const NoSuchElementException&) + { + } + catch (const WrappedTargetException&) + { + } + return static_cast<FontWidth>( width >= 0 ? pWidthNames[width].nEnum : WIDTH_DONTKNOW ); +} + +ImplFontAttrs FontSubstConfiguration::getSubstType( const css::uno::Reference< XNameAccess >& rFont, + const OUString& rType ) const +{ + sal_uLong type = 0; + try + { + Any aAny = rFont->getByName( rType ); + auto pLine = o3tl::tryAccess<OUString>(aAny); + if( !pLine ) + return ImplFontAttrs::None; + if( pLine->isEmpty() ) + return ImplFontAttrs::None; + sal_Int32 nIndex = 0; + while( nIndex != -1 ) + { + OUString aToken( pLine->getToken( 0, ',', nIndex ) ); + for( int k = 0; k < 32; k++ ) + if( aToken.equalsIgnoreAsciiCaseAscii( pAttribNames[k] ) ) + { + type |= sal_uLong(1) << k; + break; + } + } + assert(((type & ~o3tl::typed_flags<ImplFontAttrs>::mask) == 0) && "invalid font attributes"); + } + catch (const NoSuchElementException&) + { + } + catch (const WrappedTargetException&) + { + } + + return static_cast<ImplFontAttrs>(type); +} + +void FontSubstConfiguration::readLocaleSubst( const OUString& rBcp47 ) const +{ + std::unordered_map< OUString, LocaleSubst >::const_iterator it = m_aSubst.find( rBcp47 ); + if( it != m_aSubst.end() ) + { + if( ! it->second.bConfigRead ) + { + it->second.bConfigRead = true; + Reference< XNameAccess > xNode; + try + { + Any aAny = m_xConfigAccess->getByName( it->second.aConfigLocaleString ); + aAny >>= xNode; + } + catch (const NoSuchElementException&) + { + } + catch (const WrappedTargetException&) + { + } + if( xNode.is() ) + { + const Sequence< OUString > aFonts = xNode->getElementNames(); + int nFonts = aFonts.getLength(); + // improve performance, heap fragmentation + it->second.aSubstAttributes.reserve( nFonts ); + + // strings for subst retrieval, construct only once + OUString const aSubstFontsStr ( "SubstFonts" ); + OUString const aSubstFontsMSStr ( "SubstFontsMS" ); + OUString const aSubstWeightStr ( "FontWeight" ); + OUString const aSubstWidthStr ( "FontWidth" ); + OUString const aSubstTypeStr ( "FontType" ); + for( const OUString& rFontName : aFonts ) + { + Reference< XNameAccess > xFont; + try + { + Any aAny = xNode->getByName( rFontName ); + aAny >>= xFont; + } + catch (const NoSuchElementException&) + { + } + catch (const WrappedTargetException&) + { + } + if( ! xFont.is() ) + { + SAL_WARN("unotools.config", "did not get font attributes for " << rFontName); + continue; + } + + FontNameAttr aAttr; + // read subst attributes from config + aAttr.Name = rFontName; + fillSubstVector( xFont, aSubstFontsStr, aAttr.Substitutions ); + fillSubstVector( xFont, aSubstFontsMSStr, aAttr.MSSubstitutions ); + aAttr.Weight = getSubstWeight( xFont, aSubstWeightStr ); + aAttr.Width = getSubstWidth( xFont, aSubstWidthStr ); + aAttr.Type = getSubstType( xFont, aSubstTypeStr ); + + // finally insert this entry + it->second.aSubstAttributes.push_back( aAttr ); + } + std::sort( it->second.aSubstAttributes.begin(), it->second.aSubstAttributes.end(), StrictStringSort() ); + } + } + } +} + +const FontNameAttr* FontSubstConfiguration::getSubstInfo( const OUString& rFontName ) const +{ + if( rFontName.isEmpty() ) + return nullptr; + + // search if a (language dep.) replacement table for the given font exists + // fallback is english + OUString aSearchFont( rFontName.toAsciiLowerCase() ); + FontNameAttr aSearchAttr; + aSearchAttr.Name = aSearchFont; + + LanguageTag aLanguageTag("en"); + + if( aLanguageTag.isSystemLocale() ) + aLanguageTag = SvtSysLocale().GetUILanguageTag(); + + ::std::vector< OUString > aFallbacks( aLanguageTag.getFallbackStrings( true)); + if (aLanguageTag.getLanguage() != "en") + aFallbacks.emplace_back("en"); + + for (const auto& rFallback : aFallbacks) + { + std::unordered_map< OUString, LocaleSubst >::const_iterator lang = m_aSubst.find( rFallback ); + if( lang != m_aSubst.end() ) + { + if( ! lang->second.bConfigRead ) + readLocaleSubst( rFallback ); + // try to find an exact match + // because the list is sorted this will also find fontnames of the form searchfontname* + std::vector< FontNameAttr >::const_iterator it = ::std::lower_bound( lang->second.aSubstAttributes.begin(), lang->second.aSubstAttributes.end(), aSearchAttr, StrictStringSort() ); + if( it != lang->second.aSubstAttributes.end()) + { + const FontNameAttr& rFoundAttr = *it; + // a search for "abcblack" may match with an entry for "abc" + // the reverse is not a good idea (e.g. #i112731# alba->albani) + if( rFoundAttr.Name.getLength() <= aSearchFont.getLength() ) + if( aSearchFont.startsWith( rFoundAttr.Name)) + return &rFoundAttr; + } + } + } + return nullptr; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/unotools/source/config/fontoptions.cxx b/unotools/source/config/fontoptions.cxx new file mode 100644 index 000000000..c9fa6ec48 --- /dev/null +++ b/unotools/source/config/fontoptions.cxx @@ -0,0 +1,302 @@ +/* -*- 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 . + */ + +#include <unotools/fontoptions.hxx> +#include <unotools/configitem.hxx> +#include <tools/debug.hxx> +#include <com/sun/star/uno/Any.hxx> +#include <com/sun/star/uno/Sequence.hxx> + +#include <rtl/instance.hxx> +#include "itemholder1.hxx" + +using namespace ::utl; +using namespace ::osl; +using namespace ::com::sun::star::uno; + +#define ROOTNODE_FONT "Office.Common/Font" + +#define PROPERTYNAME_REPLACEMENTTABLE "Substitution/Replacement" +#define PROPERTYNAME_FONTHISTORY "View/History" +#define PROPERTYNAME_FONTWYSIWYG "View/ShowFontBoxWYSIWYG" + +#define PROPERTYHANDLE_REPLACEMENTTABLE 0 +#define PROPERTYHANDLE_FONTHISTORY 1 +#define PROPERTYHANDLE_FONTWYSIWYG 2 + +class SvtFontOptions_Impl : public ConfigItem +{ + public: + + SvtFontOptions_Impl(); + virtual ~SvtFontOptions_Impl() override; + + /*-**************************************************************************************************** + @short called for notify of configmanager + @descr This method is called from the ConfigManager before the application ends or from the + PropertyChangeListener if the sub tree broadcasts changes. You must update your + internal values. + + @seealso baseclass ConfigItem + + @param "seqPropertyNames" is the list of properties which should be updated. + *//*-*****************************************************************************************************/ + + virtual void Notify( const Sequence< OUString >& seqPropertyNames ) override; + + /*-**************************************************************************************************** + @short access method to get internal values + @descr These method give us a chance to regulate access to our internal values. + It's not used in the moment - but it's possible for the feature! + *//*-*****************************************************************************************************/ + + bool IsFontHistoryEnabled ( ) const { return m_bFontHistory;} + + bool IsFontWYSIWYGEnabled ( ) const { return m_bFontWYSIWYG;} + void EnableFontWYSIWYG ( bool bState ); + + private: + + virtual void ImplCommit() override; + + /*-**************************************************************************************************** + @short return list of key names of our configuration management which represent our module tree + @descr This method returns a static const list of key names. We need it to get needed values from our + configuration management. + @return A list of needed configuration keys is returned. + *//*-*****************************************************************************************************/ + + static Sequence< OUString > impl_GetPropertyNames(); + + private: + + bool m_bReplacementTable; + bool m_bFontHistory; + bool m_bFontWYSIWYG; +}; + +// constructor + +SvtFontOptions_Impl::SvtFontOptions_Impl() + // Init baseclasses first + : ConfigItem ( ROOTNODE_FONT ) + // Init member then. + , m_bReplacementTable ( false ) + , m_bFontHistory ( false ) + , m_bFontWYSIWYG ( false ) +{ + // Use our static list of configuration keys to get his values. + Sequence< OUString > seqNames = impl_GetPropertyNames ( ); + Sequence< Any > seqValues = GetProperties ( seqNames ); + + // Safe impossible cases. + // We need values from ALL configuration keys. + // Follow assignment use order of values in relation to our list of key names! + DBG_ASSERT( !(seqNames.getLength()!=seqValues.getLength()), "SvtFontOptions_Impl::SvtFontOptions_Impl()\nI miss some values of configuration keys!\n" ); + + // Copy values from list in right order to our internal member. + sal_Int32 nPropertyCount = seqValues.getLength(); + for( sal_Int32 nProperty=0; nProperty<nPropertyCount; ++nProperty ) + { + // Safe impossible cases. + // Check any for valid value. + DBG_ASSERT( seqValues[nProperty].hasValue(), "SvtFontOptions_Impl::SvtFontOptions_Impl()\nInvalid property value detected!\n" ); + switch( nProperty ) + { + case PROPERTYHANDLE_REPLACEMENTTABLE : { + DBG_ASSERT(!(seqValues[nProperty].getValueTypeClass()!=TypeClass_BOOLEAN), "SvtFontOptions_Impl::SvtFontOptions_Impl()\nWho has changed the value type of \"Office.Common\\Font\\Substitution\\Replacement\"?" ); + seqValues[nProperty] >>= m_bReplacementTable; + } + break; + case PROPERTYHANDLE_FONTHISTORY : { + DBG_ASSERT(!(seqValues[nProperty].getValueTypeClass()!=TypeClass_BOOLEAN), "SvtFontOptions_Impl::SvtFontOptions_Impl()\nWho has changed the value type of \"Office.Common\\Font\\View\\History\"?" ); + seqValues[nProperty] >>= m_bFontHistory; + } + break; + case PROPERTYHANDLE_FONTWYSIWYG : { + DBG_ASSERT(!(seqValues[nProperty].getValueTypeClass()!=TypeClass_BOOLEAN), "SvtFontOptions_Impl::SvtFontOptions_Impl()\nWho has changed the value type of \"Office.Common\\Font\\View\\ShowFontBoxWYSIWYG\"?" ); + seqValues[nProperty] >>= m_bFontWYSIWYG; + } + break; + } + } + + // Enable notification mechanism of our baseclass. + // We need it to get information about changes outside these class on our used configuration keys! + EnableNotification( seqNames ); +} + +// destructor + +SvtFontOptions_Impl::~SvtFontOptions_Impl() +{ + assert(!IsModified()); // should have been committed +} + +// public method + +void SvtFontOptions_Impl::Notify( const Sequence< OUString >& seqPropertyNames ) +{ + // Use given list of updated properties to get his values from configuration directly! + Sequence< Any > seqValues = GetProperties( seqPropertyNames ); + // Safe impossible cases. + // We need values from ALL notified configuration keys. + DBG_ASSERT( !(seqPropertyNames.getLength()!=seqValues.getLength()), "SvtFontOptions_Impl::Notify()\nI miss some values of configuration keys!\n" ); + // Step over list of property names and get right value from coreesponding value list to set it on internal members! + sal_Int32 nCount = seqPropertyNames.getLength(); + for( sal_Int32 nProperty=0; nProperty<nCount; ++nProperty ) + { + if( seqPropertyNames[nProperty] == PROPERTYNAME_REPLACEMENTTABLE ) + { + DBG_ASSERT(!(seqValues[nProperty].getValueTypeClass()!=TypeClass_BOOLEAN), "SvtFontOptions_Impl::Notify()\nWho has changed the value type of \"Office.Common\\Font\\Substitution\\Replacement\"?" ); + seqValues[nProperty] >>= m_bReplacementTable; + } + else + if( seqPropertyNames[nProperty] == PROPERTYNAME_FONTHISTORY ) + { + DBG_ASSERT(!(seqValues[nProperty].getValueTypeClass()!=TypeClass_BOOLEAN), "SvtFontOptions_Impl::Notify()\nWho has changed the value type of \"Office.Common\\Font\\View\\History\"?" ); + seqValues[nProperty] >>= m_bFontHistory; + } + else + if( seqPropertyNames[nProperty] == PROPERTYNAME_FONTWYSIWYG ) + { + DBG_ASSERT(!(seqValues[nProperty].getValueTypeClass()!=TypeClass_BOOLEAN), "SvtFontOptions_Impl::Notify()\nWho has changed the value type of \"Office.Common\\Font\\View\\ShowFontBoxWYSIWYG\"?" ); + seqValues[nProperty] >>= m_bFontWYSIWYG; + } +#if OSL_DEBUG_LEVEL > 0 + else assert(false && "Unknown property detected ... I can't handle these!"); +#endif + } +} + +// public method + +void SvtFontOptions_Impl::ImplCommit() +{ + // Get names of supported properties, create a list for values and copy current values to it. + Sequence< OUString > seqNames = impl_GetPropertyNames(); + sal_Int32 nCount = seqNames.getLength(); + Sequence< Any > seqValues ( nCount ); + for( sal_Int32 nProperty=0; nProperty<nCount; ++nProperty ) + { + switch( nProperty ) + { + case PROPERTYHANDLE_REPLACEMENTTABLE : { + seqValues[nProperty] <<= m_bReplacementTable; + } + break; + case PROPERTYHANDLE_FONTHISTORY : { + seqValues[nProperty] <<= m_bFontHistory; + } + break; + case PROPERTYHANDLE_FONTWYSIWYG : { + seqValues[nProperty] <<= m_bFontWYSIWYG; + } + break; + } + } + // Set properties in configuration. + PutProperties( seqNames, seqValues ); +} + +// public method + +void SvtFontOptions_Impl::EnableFontWYSIWYG( bool bState ) +{ + m_bFontWYSIWYG = bState; + SetModified(); +} + +// private method + +Sequence< OUString > SvtFontOptions_Impl::impl_GetPropertyNames() +{ + return Sequence< OUString > + { + PROPERTYNAME_REPLACEMENTTABLE , + PROPERTYNAME_FONTHISTORY , + PROPERTYNAME_FONTWYSIWYG , + }; +} + +namespace { + +std::weak_ptr<SvtFontOptions_Impl> g_pFontOptions; + +} + +SvtFontOptions::SvtFontOptions() +{ + // Global access, must be guarded (multithreading!). + MutexGuard aGuard( impl_GetOwnStaticMutex() ); + + m_pImpl = g_pFontOptions.lock(); + if( !m_pImpl ) + { + m_pImpl = std::make_shared<SvtFontOptions_Impl>(); + g_pFontOptions = m_pImpl; + ItemHolder1::holdConfigItem(EItem::FontOptions); + } +} + +SvtFontOptions::~SvtFontOptions() +{ + // Global access, must be guarded (multithreading!) + MutexGuard aGuard( impl_GetOwnStaticMutex() ); + + m_pImpl.reset(); +} + +// public method + +bool SvtFontOptions::IsFontHistoryEnabled() const +{ + MutexGuard aGuard( impl_GetOwnStaticMutex() ); + return m_pImpl->IsFontHistoryEnabled(); +} + +// public method + +bool SvtFontOptions::IsFontWYSIWYGEnabled() const +{ + MutexGuard aGuard( impl_GetOwnStaticMutex() ); + return m_pImpl->IsFontWYSIWYGEnabled(); +} + +// public method + +void SvtFontOptions::EnableFontWYSIWYG( bool bState ) +{ + MutexGuard aGuard( impl_GetOwnStaticMutex() ); + m_pImpl->EnableFontWYSIWYG( bState ); +} + +namespace +{ + class theFontOptionsMutex : public rtl::Static<osl::Mutex, theFontOptionsMutex> {}; +} + +// private method + +Mutex& SvtFontOptions::impl_GetOwnStaticMutex() +{ + return theFontOptionsMutex::get(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/unotools/source/config/historyoptions.cxx b/unotools/source/config/historyoptions.cxx new file mode 100644 index 000000000..986e39898 --- /dev/null +++ b/unotools/source/config/historyoptions.cxx @@ -0,0 +1,568 @@ +/* -*- 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 . + */ + +#include <unotools/historyoptions.hxx> +#include <com/sun/star/uno/Any.hxx> +#include <com/sun/star/uno/Sequence.hxx> + +#include <cassert> +#include <algorithm> + +#include "itemholder1.hxx" + +#include <com/sun/star/beans/PropertyValue.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/container/XNameAccess.hpp> +#include <com/sun/star/container/XNameContainer.hpp> +#include <com/sun/star/lang/XSingleServiceFactory.hpp> +#include <comphelper/configurationhelper.hxx> +#include <comphelper/processfactory.hxx> +#include <tools/diagnose_ex.h> +#include <optional> + +using namespace ::std; +using namespace ::utl; +using namespace ::osl; +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; + +namespace { + static const ::sal_Int32 s_nOffsetURL = 0; + static const ::sal_Int32 s_nOffsetFilter = 1; + static const ::sal_Int32 s_nOffsetTitle = 2; + static const ::sal_Int32 s_nOffsetPassword = 3; + static const ::sal_Int32 s_nOffsetThumbnail = 4; + + const char s_sItemList[] = "ItemList"; + const char s_sOrderList[] = "OrderList"; + const char s_sHistoryItemRef[] = "HistoryItemRef"; + const char s_sFilter[] = "Filter"; + const char s_sTitle[] = "Title"; + const char s_sPassword[] = "Password"; + const char s_sThumbnail[] = "Thumbnail"; + + class theHistoryOptionsMutex : public rtl::Static<osl::Mutex, theHistoryOptionsMutex>{}; +} + +/// Internal implementation of the SvtHistoryOptions. +class SvtHistoryOptions_Impl +{ +public: + SvtHistoryOptions_Impl(); + + /// Returns the maximum size of the internal lists, ie. the capacity not the size. + sal_uInt32 GetCapacity(EHistoryType eHistory) const; + + /// Clear the specified history list. + void Clear(EHistoryType eHistory); + + /// Get a sequence list from the items. + Sequence< Sequence<PropertyValue> > GetList(EHistoryType eHistory); + + void AppendItem(EHistoryType eHistory, + const OUString& sURL, const OUString& sFilter, const OUString& sTitle, + const std::optional<OUString>& sThumbnail); + + void DeleteItem(EHistoryType eHistory, const OUString& sURL); + +private: + /// Return the appropriate list of recent documents (based on eHistory). + uno::Reference<container::XNameAccess> GetListAccess(EHistoryType eHistory) const; + + void impl_truncateList(EHistoryType eHistory, sal_uInt32 nSize); + +private: + uno::Reference<container::XNameAccess> m_xCfg; + uno::Reference<container::XNameAccess> m_xCommonXCU; +}; + +SvtHistoryOptions_Impl::SvtHistoryOptions_Impl() +{ + try + { + m_xCfg.set( + ::comphelper::ConfigurationHelper::openConfig( + ::comphelper::getProcessComponentContext(), + "org.openoffice.Office.Histories/Histories", + ::comphelper::EConfigurationModes::Standard), + uno::UNO_QUERY); + + m_xCommonXCU.set( + ::comphelper::ConfigurationHelper::openConfig( + ::comphelper::getProcessComponentContext(), + "org.openoffice.Office.Common/History", + ::comphelper::EConfigurationModes::Standard), + uno::UNO_QUERY); + } + catch(const uno::Exception&) + { + DBG_UNHANDLED_EXCEPTION("unotools.config"); + m_xCfg.clear(); + m_xCommonXCU.clear(); + } +} + +sal_uInt32 SvtHistoryOptions_Impl::GetCapacity(EHistoryType eHistory) const +{ + uno::Reference<beans::XPropertySet> xListAccess(m_xCommonXCU, uno::UNO_QUERY); + + if (!xListAccess.is()) + return 0; + + sal_uInt32 nSize = 0; + + try + { + switch (eHistory) + { + case ePICKLIST: + xListAccess->getPropertyValue("PickListSize") >>= nSize; + break; + + case eHELPBOOKMARKS: + xListAccess->getPropertyValue("HelpBookmarkSize") >>= nSize; + break; + + default: + break; + } + } + catch (const uno::Exception&) + { + DBG_UNHANDLED_EXCEPTION("unotools.config"); + } + + return nSize; +} + +uno::Reference<container::XNameAccess> SvtHistoryOptions_Impl::GetListAccess(EHistoryType eHistory) const +{ + uno::Reference<container::XNameAccess> xListAccess; + + try + { + switch (eHistory) + { + case ePICKLIST: + m_xCfg->getByName("PickList") >>= xListAccess; + break; + + case eHELPBOOKMARKS: + m_xCfg->getByName("HelpBookmarks") >>= xListAccess; + break; + + default: + break; + } + } + catch (const uno::Exception&) + { + DBG_UNHANDLED_EXCEPTION("unotools.config"); + } + + return xListAccess; +} + +void SvtHistoryOptions_Impl::impl_truncateList(EHistoryType eHistory, sal_uInt32 nSize) +{ + uno::Reference<container::XNameAccess> xList(GetListAccess(eHistory)); + if (!xList.is()) + return; + + uno::Reference<container::XNameContainer> xItemList; + uno::Reference<container::XNameContainer> xOrderList; + uno::Reference<beans::XPropertySet> xSet; + + try + { + xList->getByName(s_sOrderList) >>= xOrderList; + xList->getByName(s_sItemList) >>= xItemList; + + const sal_uInt32 nLength = xOrderList->getElementNames().getLength(); + if (nSize < nLength) + { + for (sal_uInt32 i=nLength-1; i>=nSize; --i) + { + OUString sTmp; + const OUString sRemove = OUString::number(i); + xOrderList->getByName(sRemove) >>= xSet; + xSet->getPropertyValue(s_sHistoryItemRef) >>= sTmp; + xItemList->removeByName(sTmp); + xOrderList->removeByName(sRemove); + } + + ::comphelper::ConfigurationHelper::flush(m_xCfg); + } + } + catch(const uno::Exception&) + { + DBG_UNHANDLED_EXCEPTION("unotools.config"); + } +} + +void SvtHistoryOptions_Impl::Clear( EHistoryType eHistory ) +{ + uno::Reference<container::XNameAccess> xListAccess(GetListAccess(eHistory)); + if (!xListAccess.is()) + return; + + uno::Reference<container::XNameContainer> xNode; + + try + { + // clear ItemList + xListAccess->getByName(s_sItemList) >>= xNode; + Sequence<OUString> aStrings(xNode->getElementNames()); + + for (const auto& rString : std::as_const(aStrings)) + xNode->removeByName(rString); + + // clear OrderList + xListAccess->getByName(s_sOrderList) >>= xNode; + aStrings = xNode->getElementNames(); + + for (const auto& rString : std::as_const(aStrings)) + xNode->removeByName(rString); + + ::comphelper::ConfigurationHelper::flush(m_xCfg); + } + catch(const uno::Exception&) + { + DBG_UNHANDLED_EXCEPTION("unotools.config"); + } +} + +Sequence< Sequence<PropertyValue> > SvtHistoryOptions_Impl::GetList(EHistoryType eHistory) +{ + uno::Reference<container::XNameAccess> xListAccess(GetListAccess(eHistory)); + if (!xListAccess.is()) + return Sequence< Sequence<PropertyValue> >(); + + impl_truncateList(eHistory, GetCapacity(eHistory)); + + Sequence<PropertyValue> seqProperties(5); + seqProperties[s_nOffsetURL ].Name = HISTORY_PROPERTYNAME_URL; + seqProperties[s_nOffsetFilter ].Name = HISTORY_PROPERTYNAME_FILTER; + seqProperties[s_nOffsetTitle ].Name = HISTORY_PROPERTYNAME_TITLE; + seqProperties[s_nOffsetPassword ].Name = HISTORY_PROPERTYNAME_PASSWORD; + seqProperties[s_nOffsetThumbnail ].Name = HISTORY_PROPERTYNAME_THUMBNAIL; + + uno::Reference<container::XNameAccess> xItemList; + uno::Reference<container::XNameAccess> xOrderList; + try + { + xListAccess->getByName(s_sItemList) >>= xItemList; + xListAccess->getByName(s_sOrderList) >>= xOrderList; + } + catch(const uno::Exception&) + { + DBG_UNHANDLED_EXCEPTION("unotools.config"); + } + + const sal_Int32 nLength = xOrderList->getElementNames().getLength(); + Sequence< Sequence<PropertyValue> > aRet(nLength); + sal_Int32 nCount = 0; + + for (sal_Int32 nItem = 0; nItem < nLength; ++nItem) + { + try + { + OUString sUrl; + uno::Reference<beans::XPropertySet> xSet; + xOrderList->getByName(OUString::number(nItem)) >>= xSet; + xSet->getPropertyValue(s_sHistoryItemRef) >>= sUrl; + + xItemList->getByName(sUrl) >>= xSet; + seqProperties[s_nOffsetURL ].Value <<= sUrl; + + seqProperties[s_nOffsetFilter ].Value = xSet->getPropertyValue(s_sFilter); + seqProperties[s_nOffsetTitle ].Value = xSet->getPropertyValue(s_sTitle); + seqProperties[s_nOffsetPassword ].Value = xSet->getPropertyValue(s_sPassword); + seqProperties[s_nOffsetThumbnail].Value = xSet->getPropertyValue(s_sThumbnail); + aRet[nCount++] = seqProperties; + } + catch(const uno::Exception&) + { + // <https://bugs.libreoffice.org/show_bug.cgi?id=46074> + // "FILEOPEN: No Recent Documents..." discusses a problem + // with corrupted /org.openoffice.Office/Histories/Histories + // configuration items; to work around that problem, simply + // ignore such corrupted individual items here, so that at + // least newly added items are successfully reported back + // from this function: + DBG_UNHANDLED_EXCEPTION("unotools.config"); + } + } + assert(nCount <= nLength); + aRet.realloc(nCount); + return aRet; +} + +void SvtHistoryOptions_Impl::AppendItem(EHistoryType eHistory, + const OUString& sURL, const OUString& sFilter, const OUString& sTitle, + const std::optional<OUString>& sThumbnail) +{ + uno::Reference<container::XNameAccess> xListAccess(GetListAccess(eHistory)); + if (!xListAccess.is()) + return; + + impl_truncateList(eHistory, GetCapacity(eHistory)); + + sal_Int32 nMaxSize = GetCapacity(eHistory); + if (nMaxSize == 0) + return; + + uno::Reference<container::XNameContainer> xItemList; + uno::Reference<container::XNameContainer> xOrderList; + uno::Reference<beans::XPropertySet> xSet; + + try + { + xListAccess->getByName(s_sItemList) >>= xItemList; + xListAccess->getByName(s_sOrderList) >>= xOrderList; + sal_Int32 nLength = xOrderList->getElementNames().getLength(); + + // The item to be appended already exists + if (xItemList->hasByName(sURL)) + { + if (sThumbnail) + { + // update the thumbnail + xItemList->getByName(sURL) >>= xSet; + xSet->setPropertyValue(s_sThumbnail, uno::makeAny(*sThumbnail)); + } + + for (sal_Int32 i=0; i<nLength; ++i) + { + OUString aItem; + xOrderList->getByName(OUString::number(i)) >>= xSet; + xSet->getPropertyValue(s_sHistoryItemRef) >>= aItem; + + if (aItem == sURL) + { + for (sal_Int32 j = i - 1; j >= 0; --j) + { + uno::Reference<beans::XPropertySet> xPrevSet; + uno::Reference<beans::XPropertySet> xNextSet; + xOrderList->getByName(OUString::number(j+1)) >>= xPrevSet; + xOrderList->getByName(OUString::number(j)) >>= xNextSet; + + OUString sTemp; + xNextSet->getPropertyValue(s_sHistoryItemRef) >>= sTemp; + xPrevSet->setPropertyValue(s_sHistoryItemRef, uno::makeAny(sTemp)); + } + xOrderList->getByName(OUString::number(0)) >>= xSet; + xSet->setPropertyValue(s_sHistoryItemRef, uno::makeAny(aItem)); + break; + } + } + + ::comphelper::ConfigurationHelper::flush(m_xCfg); + } + else // The item to be appended does not exist yet + { + uno::Reference<lang::XSingleServiceFactory> xFac; + uno::Reference<uno::XInterface> xInst; + uno::Reference<beans::XPropertySet> xPrevSet; + uno::Reference<beans::XPropertySet> xNextSet; + + // Append new item to OrderList. + if ( nLength == nMaxSize ) + { + OUString sRemove; + xOrderList->getByName(OUString::number(nLength-1)) >>= xSet; + xSet->getPropertyValue(s_sHistoryItemRef) >>= sRemove; + try + { + xItemList->removeByName(sRemove); + } + catch (container::NoSuchElementException &) + { + // <https://bugs.libreoffice.org/show_bug.cgi?id=46074> + // "FILEOPEN: No Recent Documents..." discusses a problem + // with corrupted /org.openoffice.Office/Histories/Histories + // configuration items; to work around that problem, simply + // ignore such corrupted individual items here, so that at + // least newly added items are successfully added: + if (!sRemove.isEmpty()) + { + throw; + } + } + } + if (nLength != nMaxSize) + { + xFac.set(xOrderList, uno::UNO_QUERY); + xInst = xFac->createInstance(); + OUString sPush = OUString::number(nLength++); + xOrderList->insertByName(sPush, uno::makeAny(xInst)); + } + for (sal_Int32 j=nLength-1; j>0; --j) + { + xOrderList->getByName( OUString::number(j) ) >>= xPrevSet; + xOrderList->getByName( OUString::number(j-1) ) >>= xNextSet; + OUString sTemp; + xNextSet->getPropertyValue(s_sHistoryItemRef) >>= sTemp; + xPrevSet->setPropertyValue(s_sHistoryItemRef, uno::makeAny(sTemp)); + } + xOrderList->getByName( OUString::number(0) ) >>= xSet; + xSet->setPropertyValue(s_sHistoryItemRef, uno::makeAny(sURL)); + + // Append the item to ItemList. + xFac.set(xItemList, uno::UNO_QUERY); + xInst = xFac->createInstance(); + xItemList->insertByName(sURL, uno::makeAny(xInst)); + + xSet.set(xInst, uno::UNO_QUERY); + xSet->setPropertyValue(s_sFilter, uno::makeAny(sFilter)); + xSet->setPropertyValue(s_sTitle, uno::makeAny(sTitle)); + xSet->setPropertyValue(s_sPassword, uno::makeAny(OUString())); + xSet->setPropertyValue(s_sThumbnail, uno::makeAny(sThumbnail.value_or(OUString()))); + + ::comphelper::ConfigurationHelper::flush(m_xCfg); + } + } + catch(const uno::Exception&) + { + DBG_UNHANDLED_EXCEPTION("unotools.config"); + } +} + +void SvtHistoryOptions_Impl::DeleteItem(EHistoryType eHistory, const OUString& sURL) +{ + uno::Reference<container::XNameAccess> xListAccess(GetListAccess(eHistory)); + if (!xListAccess.is()) + return; + + uno::Reference<container::XNameContainer> xItemList; + uno::Reference<container::XNameContainer> xOrderList; + uno::Reference<beans::XPropertySet> xSet; + + try + { + xListAccess->getByName(s_sItemList) >>= xItemList; + xListAccess->getByName(s_sOrderList) >>= xOrderList; + sal_Int32 nLength = xOrderList->getElementNames().getLength(); + + // if it does not exist, nothing to do + if (!xItemList->hasByName(sURL)) + return; + + // it's the last one, just clear the lists + if (nLength == 1) + { + Clear(eHistory); + return; + } + + // find it in the OrderList + sal_Int32 nFromWhere = 0; + for (; nFromWhere < nLength - 1; ++nFromWhere) + { + OUString aItem; + xOrderList->getByName(OUString::number(nFromWhere)) >>= xSet; + xSet->getPropertyValue(s_sHistoryItemRef) >>= aItem; + + if (aItem == sURL) + break; + } + + // and shift the rest of the items in OrderList accordingly + for (sal_Int32 i = nFromWhere; i < nLength - 1; ++i) + { + uno::Reference<beans::XPropertySet> xPrevSet; + uno::Reference<beans::XPropertySet> xNextSet; + xOrderList->getByName(OUString::number(i)) >>= xPrevSet; + xOrderList->getByName(OUString::number(i + 1)) >>= xNextSet; + + OUString sTemp; + xNextSet->getPropertyValue(s_sHistoryItemRef) >>= sTemp; + xPrevSet->setPropertyValue(s_sHistoryItemRef, uno::makeAny(sTemp)); + } + xOrderList->removeByName(OUString::number(nLength - 1)); + + // and finally remove it from the ItemList + xItemList->removeByName(sURL); + + ::comphelper::ConfigurationHelper::flush(m_xCfg); + } + catch (const uno::Exception&) + { + DBG_UNHANDLED_EXCEPTION("unotools.config"); + } +} + +namespace { + +std::weak_ptr<SvtHistoryOptions_Impl> g_pHistoryOptions; + +} + +SvtHistoryOptions::SvtHistoryOptions() +{ + MutexGuard aGuard(theHistoryOptionsMutex::get()); + + m_pImpl = g_pHistoryOptions.lock(); + if( !m_pImpl ) + { + m_pImpl = std::make_shared<SvtHistoryOptions_Impl>(); + g_pHistoryOptions = m_pImpl; + ItemHolder1::holdConfigItem(EItem::HistoryOptions); + } +} + +SvtHistoryOptions::~SvtHistoryOptions() +{ + MutexGuard aGuard(theHistoryOptionsMutex::get()); + + m_pImpl.reset(); +} + +void SvtHistoryOptions::Clear( EHistoryType eHistory ) +{ + MutexGuard aGuard(theHistoryOptionsMutex::get()); + + m_pImpl->Clear( eHistory ); +} + +Sequence< Sequence< PropertyValue > > SvtHistoryOptions::GetList( EHistoryType eHistory ) const +{ + MutexGuard aGuard(theHistoryOptionsMutex::get()); + + return m_pImpl->GetList( eHistory ); +} + +void SvtHistoryOptions::AppendItem(EHistoryType eHistory, + const OUString& sURL, const OUString& sFilter, const OUString& sTitle, + const std::optional<OUString>& sThumbnail) +{ + MutexGuard aGuard(theHistoryOptionsMutex::get()); + + m_pImpl->AppendItem(eHistory, sURL, sFilter, sTitle, sThumbnail); +} + +void SvtHistoryOptions::DeleteItem(EHistoryType eHistory, const OUString& sURL) +{ + MutexGuard aGuard(theHistoryOptionsMutex::get()); + + m_pImpl->DeleteItem(eHistory, sURL); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/unotools/source/config/itemholder1.cxx b/unotools/source/config/itemholder1.cxx new file mode 100644 index 000000000..81c0137cd --- /dev/null +++ b/unotools/source/config/itemholder1.cxx @@ -0,0 +1,219 @@ +/* -*- 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 . + */ + +#include "itemholder1.hxx" + +#include <comphelper/processfactory.hxx> +#include <com/sun/star/lang/XComponent.hpp> +#include <com/sun/star/configuration/theDefaultProvider.hpp> + +#include <unotools/misccfg.hxx> +#include <unotools/useroptions.hxx> +#include <unotools/cmdoptions.hxx> +#include <unotools/compatibility.hxx> +#include <unotools/compatibilityviewoptions.hxx> +#include <unotools/defaultoptions.hxx> +#include <unotools/dynamicmenuoptions.hxx> +#include <unotools/extendedsecurityoptions.hxx> +#include <unotools/fontoptions.hxx> +#include <unotools/historyoptions.hxx> +#include <unotools/lingucfg.hxx> +#include <unotools/moduleoptions.hxx> +#include <unotools/pathoptions.hxx> +#include <unotools/printwarningoptions.hxx> +#include <unotools/optionsdlg.hxx> +#include <unotools/securityoptions.hxx> +#include <unotools/viewoptions.hxx> +#include <unotools/options.hxx> +#include <unotools/syslocaleoptions.hxx> +#include <sal/log.hxx> +#include <osl/diagnose.h> +#include <tools/diagnose_ex.h> + +ItemHolder1::ItemHolder1() + : ItemHolderMutexBase() +{ + try + { + css::uno::Reference< css::uno::XComponentContext > xContext = ::comphelper::getProcessComponentContext(); + css::uno::Reference< css::lang::XComponent > xCfg( + css::configuration::theDefaultProvider::get( xContext ), + css::uno::UNO_QUERY_THROW ); + xCfg->addEventListener(static_cast< css::lang::XEventListener* >(this)); + } +#ifdef DBG_UTIL + catch(const css::uno::Exception&) + { + static bool bMessage = true; + if(bMessage) + { + bMessage = false; + css::uno::Any ex( cppu::getCaughtException() ); + SAL_WARN( "unotools", "CreateInstance with arguments exception: " << exceptionToString(ex)); + } + } +#else + catch(css::uno::Exception&){} +#endif +} + +ItemHolder1::~ItemHolder1() +{ + impl_releaseAllItems(); +} + +void ItemHolder1::holdConfigItem(EItem eItem) +{ + static ItemHolder1* pHolder = new ItemHolder1(); + pHolder->impl_addItem(eItem); +} + +void SAL_CALL ItemHolder1::disposing(const css::lang::EventObject&) +{ + css::uno::Reference< css::uno::XInterface > xSelfHold(static_cast< css::lang::XEventListener* >(this), css::uno::UNO_QUERY); + impl_releaseAllItems(); +} + +void ItemHolder1::impl_addItem(EItem eItem) +{ + osl::MutexGuard aLock(m_aLock); + + for ( auto const & rInfo : m_lItems ) + { + if (rInfo.eItem == eItem) + return; + } + + TItemInfo aNewItem; + aNewItem.eItem = eItem; + impl_newItem(aNewItem); + if (aNewItem.pItem) + m_lItems.emplace_back(std::move(aNewItem)); +} + +void ItemHolder1::impl_releaseAllItems() +{ + std::vector< TItemInfo > items; + { + ::osl::MutexGuard aLock(m_aLock); + items.swap(m_lItems); + } + + // items will be freed when the block exits +} + +void ItemHolder1::impl_newItem(TItemInfo& rItem) +{ + switch(rItem.eItem) + { + case EItem::CmdOptions : + rItem.pItem.reset( new SvtCommandOptions() ); + break; + + case EItem::Compatibility : + rItem.pItem.reset( new SvtCompatibilityOptions() ); + break; + + case EItem::CompatibilityView : + rItem.pItem.reset( new SvtCompatibilityViewOptions() ); + break; + + case EItem::DefaultOptions : + rItem.pItem.reset( new SvtDefaultOptions() ); + break; + + case EItem::DynamicMenuOptions : + rItem.pItem.reset( new SvtDynamicMenuOptions() ); + break; + + case EItem::EventConfig : + //rItem.pItem.reset( new GlobalEventConfig() ); + break; + + case EItem::ExtendedSecurityOptions : + rItem.pItem.reset( new SvtExtendedSecurityOptions() ); + break; + + case EItem::FontOptions : + rItem.pItem.reset( new SvtFontOptions() ); + break; + + case EItem::HistoryOptions : + rItem.pItem.reset( new SvtHistoryOptions() ); + break; + + case EItem::LinguConfig : + rItem.pItem.reset( new SvtLinguConfig() ); + break; + + case EItem::ModuleOptions : + rItem.pItem.reset( new SvtModuleOptions() ); + break; + + case EItem::OptionsDialogOptions : + rItem.pItem.reset( new SvtOptionsDialogOptions() ); + break; + + case EItem::PathOptions : + rItem.pItem.reset( new SvtPathOptions() ); + break; + + case EItem::PrintWarningOptions : + rItem.pItem.reset( new SvtPrintWarningOptions() ); + break; + + case EItem::MiscConfig : + rItem.pItem.reset( new ::utl::MiscCfg() ); + break; + + case EItem::SecurityOptions : + rItem.pItem.reset( new SvtSecurityOptions() ); + break; + + case EItem::ViewOptionsDialog : + rItem.pItem.reset( new SvtViewOptions(EViewType::Dialog, OUString()) ); + break; + + case EItem::ViewOptionsTabDialog : + rItem.pItem.reset( new SvtViewOptions(EViewType::TabDialog, OUString()) ); + break; + + case EItem::ViewOptionsTabPage : + rItem.pItem.reset( new SvtViewOptions(EViewType::TabPage, OUString()) ); + break; + + case EItem::ViewOptionsWindow : + rItem.pItem.reset( new SvtViewOptions(EViewType::Window, OUString()) ); + break; + + case EItem::UserOptions : + rItem.pItem.reset( new SvtUserOptions() ); + break; + + case EItem::SysLocaleOptions : + rItem.pItem.reset( new SvtSysLocaleOptions() ); + break; + + default: + OSL_FAIL( "unknown item type" ); + break; + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/unotools/source/config/itemholder1.hxx b/unotools/source/config/itemholder1.hxx new file mode 100644 index 000000000..c632eedc7 --- /dev/null +++ b/unotools/source/config/itemholder1.hxx @@ -0,0 +1,62 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_UNOTOOLS_SOURCE_CONFIG_ITEMHOLDER1_HXX +#define INCLUDED_UNOTOOLS_SOURCE_CONFIG_ITEMHOLDER1_HXX + +#include <unotools/itemholderbase.hxx> +#include <cppuhelper/implbase.hxx> +#include <com/sun/star/lang/XEventListener.hpp> + +class ItemHolder1 : private ItemHolderMutexBase + , public ::cppu::WeakImplHelper< css::lang::XEventListener > +{ + + // member + private: + + std::vector<TItemInfo> m_lItems; + + // c++ interface + public: + + ItemHolder1(); + virtual ~ItemHolder1() override; + static void holdConfigItem(EItem eItem); + + // uno interface + public: + + virtual void SAL_CALL disposing(const css::lang::EventObject& aEvent) override; + + // helper + private: + + void impl_addItem(EItem eItem); + void impl_releaseAllItems(); + static void impl_newItem(TItemInfo& rItem); +}; + +// namespaces + +#undef css + +#endif // INCLUDED_UNOTOOLS_SOURCE_CONFIG_ITEMHOLDER1_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/unotools/source/config/lingucfg.cxx b/unotools/source/config/lingucfg.cxx new file mode 100644 index 000000000..3bd595388 --- /dev/null +++ b/unotools/source/config/lingucfg.cxx @@ -0,0 +1,1182 @@ +/* -*- 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 . + */ + +#include <sal/config.h> + +#include <com/sun/star/lang/Locale.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/beans/PropertyValue.hpp> +#include <com/sun/star/configuration/theDefaultProvider.hpp> +#include <com/sun/star/container/XNameAccess.hpp> +#include <com/sun/star/util/XChangesBatch.hpp> +#include <rtl/instance.hxx> +#include <sal/log.hxx> +#include <osl/mutex.hxx> +#include <tools/diagnose_ex.h> +#include <i18nlangtag/mslangid.hxx> +#include <i18nlangtag/languagetag.hxx> +#include <tools/debug.hxx> +#include <unotools/configitem.hxx> +#include <unotools/lingucfg.hxx> +#include <unotools/linguprops.hxx> +#include <sal/macros.h> +#include <comphelper/getexpandeduri.hxx> +#include <comphelper/processfactory.hxx> + +#include "itemholder1.hxx" + +using namespace com::sun::star; + +#define FILE_PROTOCOL "file:///" + +namespace +{ + class theSvtLinguConfigItemMutex : + public rtl::Static< osl::Mutex, theSvtLinguConfigItemMutex > {}; +} + +static bool lcl_SetLocale( LanguageType &rLanguage, const uno::Any &rVal ) +{ + bool bSucc = false; + + lang::Locale aNew; + if (rVal >>= aNew) // conversion successful? + { + LanguageType nNew = LanguageTag::convertToLanguageType( aNew, false); + if (nNew != rLanguage) + { + rLanguage = nNew; + bSucc = true; + } + } + return bSucc; +} + +static OUString lcl_LanguageToCfgLocaleStr( LanguageType nLanguage ) +{ + OUString aRes; + if (LANGUAGE_SYSTEM != nLanguage) + aRes = LanguageTag::convertToBcp47( nLanguage ); + return aRes; +} + +static LanguageType lcl_CfgAnyToLanguage( const uno::Any &rVal ) +{ + OUString aTmp; + rVal >>= aTmp; + return (aTmp.isEmpty()) ? LANGUAGE_SYSTEM : LanguageTag::convertToLanguageTypeWithFallback( aTmp ); +} + +SvtLinguOptions::SvtLinguOptions() + : bROActiveDics(false) + , bROActiveConvDics(false) + , nHyphMinLeading(2) + , nHyphMinTrailing(2) + , nHyphMinWordLength(0) + , bROHyphMinLeading(false) + , bROHyphMinTrailing(false) + , bROHyphMinWordLength(false) + , nDefaultLanguage(LANGUAGE_NONE) + , nDefaultLanguage_CJK(LANGUAGE_NONE) + , nDefaultLanguage_CTL(LANGUAGE_NONE) + , bRODefaultLanguage(false) + , bRODefaultLanguage_CJK(false) + , bRODefaultLanguage_CTL(false) + , bIsSpellSpecial(true) + , bIsSpellAuto(false) + , bIsSpellReverse(false) + , bROIsSpellSpecial(false) + , bROIsSpellAuto(false) + , bROIsSpellReverse(false) + , bIsHyphSpecial(true) + , bIsHyphAuto(false) + , bROIsHyphSpecial(false) + , bROIsHyphAuto(false) + , bIsUseDictionaryList(true) + , bIsIgnoreControlCharacters(true) + , bROIsUseDictionaryList(false) + , bROIsIgnoreControlCharacters(false) + , bIsSpellWithDigits(false) + , bIsSpellUpperCase(false) + , bIsSpellCapitalization(true) + , bROIsSpellWithDigits(false) + , bROIsSpellUpperCase(false) + , bROIsSpellCapitalization(false) + , bIsIgnorePostPositionalWord(true) + , bIsAutoCloseDialog(false) + , bIsShowEntriesRecentlyUsedFirst(false) + , bIsAutoReplaceUniqueEntries(false) + , bIsDirectionToSimplified(true) + , bIsUseCharacterVariants(false) + , bIsTranslateCommonTerms(false) + , bIsReverseMapping(false) + , bROIsIgnorePostPositionalWord(false) + , bROIsAutoCloseDialog(false) + , bROIsShowEntriesRecentlyUsedFirst(false) + , bROIsAutoReplaceUniqueEntries(false) + , bROIsDirectionToSimplified(false) + , bROIsUseCharacterVariants(false) + , bROIsTranslateCommonTerms(false) + , bROIsReverseMapping(false) + , nDataFilesChangedCheckValue(0) + , bRODataFilesChangedCheckValue(false) + , bIsGrammarAuto(false) + , bIsGrammarInteractive(false) + , bROIsGrammarAuto(false) + , bROIsGrammarInteractive(false) +{ +} + +class SvtLinguConfigItem : public utl::ConfigItem +{ + SvtLinguOptions aOpt; + + static bool GetHdlByName( sal_Int32 &rnHdl, const OUString &rPropertyName, bool bFullPropName = false ); + static uno::Sequence< OUString > GetPropertyNames(); + void LoadOptions( const uno::Sequence< OUString > &rProperyNames ); + bool SaveOptions( const uno::Sequence< OUString > &rProperyNames ); + + SvtLinguConfigItem(const SvtLinguConfigItem&) = delete; + SvtLinguConfigItem& operator=(const SvtLinguConfigItem&) = delete; + virtual void ImplCommit() override; + +public: + SvtLinguConfigItem(); + + // utl::ConfigItem + virtual void Notify( const css::uno::Sequence< OUString > &rPropertyNames ) override; + + // make some protected functions of utl::ConfigItem public + using utl::ConfigItem::GetNodeNames; + using utl::ConfigItem::GetProperties; + //using utl::ConfigItem::PutProperties; + //using utl::ConfigItem::SetSetProperties; + using utl::ConfigItem::ReplaceSetProperties; + //using utl::ConfigItem::GetReadOnlyStates; + + css::uno::Any + GetProperty( const OUString &rPropertyName ) const; + css::uno::Any + GetProperty( sal_Int32 nPropertyHandle ) const; + + bool SetProperty( const OUString &rPropertyName, + const css::uno::Any &rValue ); + bool SetProperty( sal_Int32 nPropertyHandle, + const css::uno::Any &rValue ); + + const SvtLinguOptions& GetOptions() const; + + bool IsReadOnly( const OUString &rPropertyName ) const; + bool IsReadOnly( sal_Int32 nPropertyHandle ) const; +}; + +SvtLinguConfigItem::SvtLinguConfigItem() : + utl::ConfigItem( "Office.Linguistic" ) +{ + const uno::Sequence< OUString > &rPropertyNames = GetPropertyNames(); + LoadOptions( rPropertyNames ); + ClearModified(); + + // request notify events when properties change + EnableNotification( rPropertyNames ); +} + +void SvtLinguConfigItem::Notify( const uno::Sequence< OUString > &rPropertyNames ) +{ + LoadOptions( rPropertyNames ); + NotifyListeners(ConfigurationHints::NONE); +} + +void SvtLinguConfigItem::ImplCommit() +{ + SaveOptions( GetPropertyNames() ); +} + +namespace { + +struct NamesToHdl +{ + const char *pFullPropName; // full qualified name as used in configuration + const char *pPropName; // property name only (atom) of above + sal_Int32 nHdl; // numeric handle representing the property +}; + +} + +static NamesToHdl const aNamesToHdl[] = +{ +{/* 0 */ "General/DefaultLocale", UPN_DEFAULT_LOCALE, UPH_DEFAULT_LOCALE}, +{/* 1 */ "General/DictionaryList/ActiveDictionaries", UPN_ACTIVE_DICTIONARIES, UPH_ACTIVE_DICTIONARIES}, +{/* 2 */ "General/DictionaryList/IsUseDictionaryList", UPN_IS_USE_DICTIONARY_LIST, UPH_IS_USE_DICTIONARY_LIST}, +{/* 3 */ "General/IsIgnoreControlCharacters", UPN_IS_IGNORE_CONTROL_CHARACTERS, UPH_IS_IGNORE_CONTROL_CHARACTERS}, +{/* 5 */ "General/DefaultLocale_CJK", UPN_DEFAULT_LOCALE_CJK, UPH_DEFAULT_LOCALE_CJK}, +{/* 6 */ "General/DefaultLocale_CTL", UPN_DEFAULT_LOCALE_CTL, UPH_DEFAULT_LOCALE_CTL}, + +{/* 7 */ "SpellChecking/IsSpellUpperCase", UPN_IS_SPELL_UPPER_CASE, UPH_IS_SPELL_UPPER_CASE}, +{/* 8 */ "SpellChecking/IsSpellWithDigits", UPN_IS_SPELL_WITH_DIGITS, UPH_IS_SPELL_WITH_DIGITS}, +{/* 9 */ "SpellChecking/IsSpellCapitalization", UPN_IS_SPELL_CAPITALIZATION, UPH_IS_SPELL_CAPITALIZATION}, +{/* 10 */ "SpellChecking/IsSpellAuto", UPN_IS_SPELL_AUTO, UPH_IS_SPELL_AUTO}, +{/* 11 */ "SpellChecking/IsSpellSpecial", UPN_IS_SPELL_SPECIAL, UPH_IS_SPELL_SPECIAL}, +{/* 14 */ "SpellChecking/IsReverseDirection", UPN_IS_WRAP_REVERSE, UPH_IS_WRAP_REVERSE}, + +{/* 15 */ "Hyphenation/MinLeading", UPN_HYPH_MIN_LEADING, UPH_HYPH_MIN_LEADING}, +{/* 16 */ "Hyphenation/MinTrailing", UPN_HYPH_MIN_TRAILING, UPH_HYPH_MIN_TRAILING}, +{/* 17 */ "Hyphenation/MinWordLength", UPN_HYPH_MIN_WORD_LENGTH, UPH_HYPH_MIN_WORD_LENGTH}, +{/* 18 */ "Hyphenation/IsHyphSpecial", UPN_IS_HYPH_SPECIAL, UPH_IS_HYPH_SPECIAL}, +{/* 19 */ "Hyphenation/IsHyphAuto", UPN_IS_HYPH_AUTO, UPH_IS_HYPH_AUTO}, + +{/* 20 */ "TextConversion/ActiveConversionDictionaries", UPN_ACTIVE_CONVERSION_DICTIONARIES, UPH_ACTIVE_CONVERSION_DICTIONARIES}, +{/* 21 */ "TextConversion/IsIgnorePostPositionalWord", UPN_IS_IGNORE_POST_POSITIONAL_WORD, UPH_IS_IGNORE_POST_POSITIONAL_WORD}, +{/* 22 */ "TextConversion/IsAutoCloseDialog", UPN_IS_AUTO_CLOSE_DIALOG, UPH_IS_AUTO_CLOSE_DIALOG}, +{/* 23 */ "TextConversion/IsShowEntriesRecentlyUsedFirst", UPN_IS_SHOW_ENTRIES_RECENTLY_USED_FIRST, UPH_IS_SHOW_ENTRIES_RECENTLY_USED_FIRST}, +{/* 24 */ "TextConversion/IsAutoReplaceUniqueEntries", UPN_IS_AUTO_REPLACE_UNIQUE_ENTRIES, UPH_IS_AUTO_REPLACE_UNIQUE_ENTRIES}, +{/* 25 */ "TextConversion/IsDirectionToSimplified", UPN_IS_DIRECTION_TO_SIMPLIFIED, UPH_IS_DIRECTION_TO_SIMPLIFIED}, +{/* 26 */ "TextConversion/IsUseCharacterVariants", UPN_IS_USE_CHARACTER_VARIANTS, UPH_IS_USE_CHARACTER_VARIANTS}, +{/* 27 */ "TextConversion/IsTranslateCommonTerms", UPN_IS_TRANSLATE_COMMON_TERMS, UPH_IS_TRANSLATE_COMMON_TERMS}, +{/* 28 */ "TextConversion/IsReverseMapping", UPN_IS_REVERSE_MAPPING, UPH_IS_REVERSE_MAPPING}, + +{/* 29 */ "ServiceManager/DataFilesChangedCheckValue", UPN_DATA_FILES_CHANGED_CHECK_VALUE, UPH_DATA_FILES_CHANGED_CHECK_VALUE}, + +{/* 30 */ "GrammarChecking/IsAutoCheck", UPN_IS_GRAMMAR_AUTO, UPH_IS_GRAMMAR_AUTO}, +{/* 31 */ "GrammarChecking/IsInteractiveCheck", UPN_IS_GRAMMAR_INTERACTIVE, UPH_IS_GRAMMAR_INTERACTIVE}, + + /* similar to entry 0 (thus no own configuration entry) but with different property name and type */ +{ nullptr, UPN_DEFAULT_LANGUAGE, UPH_DEFAULT_LANGUAGE}, + +{ nullptr, nullptr, -1} +}; + +uno::Sequence< OUString > SvtLinguConfigItem::GetPropertyNames() +{ + uno::Sequence< OUString > aNames; + + sal_Int32 nMax = SAL_N_ELEMENTS(aNamesToHdl); + + aNames.realloc( nMax ); + OUString *pNames = aNames.getArray(); + sal_Int32 nIdx = 0; + for (sal_Int32 i = 0; i < nMax; ++i) + { + const char *pFullPropName = aNamesToHdl[i].pFullPropName; + if (pFullPropName) + pNames[ nIdx++ ] = OUString::createFromAscii( pFullPropName ); + } + aNames.realloc( nIdx ); + + return aNames; +} + +bool SvtLinguConfigItem::GetHdlByName( + sal_Int32 &rnHdl, + const OUString &rPropertyName, + bool bFullPropName ) +{ + NamesToHdl const *pEntry = &aNamesToHdl[0]; + + if (bFullPropName) + { + while (pEntry && pEntry->pFullPropName != nullptr) + { + if (rPropertyName.equalsAscii( pEntry->pFullPropName )) + { + rnHdl = pEntry->nHdl; + break; + } + ++pEntry; + } + return pEntry && pEntry->pFullPropName != nullptr; + } + else + { + while (pEntry && pEntry->pPropName != nullptr) + { + if (rPropertyName.equalsAscii( pEntry->pPropName )) + { + rnHdl = pEntry->nHdl; + break; + } + ++pEntry; + } + return pEntry && pEntry->pPropName != nullptr; + } +} + +uno::Any SvtLinguConfigItem::GetProperty( const OUString &rPropertyName ) const +{ + osl::MutexGuard aGuard(theSvtLinguConfigItemMutex::get()); + + sal_Int32 nHdl; + return GetHdlByName( nHdl, rPropertyName ) ? GetProperty( nHdl ) : uno::Any(); +} + +uno::Any SvtLinguConfigItem::GetProperty( sal_Int32 nPropertyHandle ) const +{ + osl::MutexGuard aGuard(theSvtLinguConfigItemMutex::get()); + + uno::Any aRes; + + const sal_Int16 *pnVal = nullptr; + const LanguageType *plVal = nullptr; + const bool *pbVal = nullptr; + const sal_Int32 *pnInt32Val = nullptr; + + const SvtLinguOptions &rOpt = const_cast< SvtLinguConfigItem * >(this)->aOpt; + switch (nPropertyHandle) + { + case UPH_IS_USE_DICTIONARY_LIST : pbVal = &rOpt.bIsUseDictionaryList; break; + case UPH_IS_IGNORE_CONTROL_CHARACTERS : pbVal = &rOpt.bIsIgnoreControlCharacters; break; + case UPH_IS_HYPH_AUTO : pbVal = &rOpt.bIsHyphAuto; break; + case UPH_IS_HYPH_SPECIAL : pbVal = &rOpt.bIsHyphSpecial; break; + case UPH_IS_SPELL_AUTO : pbVal = &rOpt.bIsSpellAuto; break; + case UPH_IS_SPELL_SPECIAL : pbVal = &rOpt.bIsSpellSpecial; break; + case UPH_IS_WRAP_REVERSE : pbVal = &rOpt.bIsSpellReverse; break; + case UPH_DEFAULT_LANGUAGE : plVal = &rOpt.nDefaultLanguage; break; + case UPH_IS_SPELL_CAPITALIZATION : pbVal = &rOpt.bIsSpellCapitalization; break; + case UPH_IS_SPELL_WITH_DIGITS : pbVal = &rOpt.bIsSpellWithDigits; break; + case UPH_IS_SPELL_UPPER_CASE : pbVal = &rOpt.bIsSpellUpperCase; break; + case UPH_HYPH_MIN_LEADING : pnVal = &rOpt.nHyphMinLeading; break; + case UPH_HYPH_MIN_TRAILING : pnVal = &rOpt.nHyphMinTrailing; break; + case UPH_HYPH_MIN_WORD_LENGTH : pnVal = &rOpt.nHyphMinWordLength; break; + case UPH_ACTIVE_DICTIONARIES : + { + aRes <<= rOpt.aActiveDics; + break; + } + case UPH_ACTIVE_CONVERSION_DICTIONARIES : + { + aRes <<= rOpt.aActiveConvDics; + break; + } + case UPH_DEFAULT_LOCALE : + { + aRes <<= LanguageTag::convertToLocale( rOpt.nDefaultLanguage, false); + break; + } + case UPH_DEFAULT_LOCALE_CJK : + { + aRes <<= LanguageTag::convertToLocale( rOpt.nDefaultLanguage_CJK, false); + break; + } + case UPH_DEFAULT_LOCALE_CTL : + { + aRes <<= LanguageTag::convertToLocale( rOpt.nDefaultLanguage_CTL, false); + break; + } + case UPH_IS_IGNORE_POST_POSITIONAL_WORD : pbVal = &rOpt.bIsIgnorePostPositionalWord; break; + case UPH_IS_AUTO_CLOSE_DIALOG : pbVal = &rOpt.bIsAutoCloseDialog; break; + case UPH_IS_SHOW_ENTRIES_RECENTLY_USED_FIRST : pbVal = &rOpt.bIsShowEntriesRecentlyUsedFirst; break; + case UPH_IS_AUTO_REPLACE_UNIQUE_ENTRIES : pbVal = &rOpt.bIsAutoReplaceUniqueEntries; break; + + case UPH_IS_DIRECTION_TO_SIMPLIFIED: pbVal = &rOpt.bIsDirectionToSimplified; break; + case UPH_IS_USE_CHARACTER_VARIANTS : pbVal = &rOpt.bIsUseCharacterVariants; break; + case UPH_IS_TRANSLATE_COMMON_TERMS : pbVal = &rOpt.bIsTranslateCommonTerms; break; + case UPH_IS_REVERSE_MAPPING : pbVal = &rOpt.bIsReverseMapping; break; + + case UPH_DATA_FILES_CHANGED_CHECK_VALUE : pnInt32Val = &rOpt.nDataFilesChangedCheckValue; break; + case UPH_IS_GRAMMAR_AUTO: pbVal = &rOpt.bIsGrammarAuto; break; + case UPH_IS_GRAMMAR_INTERACTIVE: pbVal = &rOpt.bIsGrammarInteractive; break; + default : + SAL_WARN( "unotools.config", "unexpected property handle" ); + } + + if (pbVal) + aRes <<= *pbVal; + else if (pnVal) + aRes <<= *pnVal; + else if (plVal) + aRes <<= static_cast<sal_Int16>(static_cast<sal_uInt16>(*plVal)); + else if (pnInt32Val) + aRes <<= *pnInt32Val; + + return aRes; +} + +bool SvtLinguConfigItem::SetProperty( const OUString &rPropertyName, const uno::Any &rValue ) +{ + osl::MutexGuard aGuard(theSvtLinguConfigItemMutex::get()); + + bool bSucc = false; + sal_Int32 nHdl; + if (GetHdlByName( nHdl, rPropertyName )) + bSucc = SetProperty( nHdl, rValue ); + return bSucc; +} + +bool SvtLinguConfigItem::SetProperty( sal_Int32 nPropertyHandle, const uno::Any &rValue ) +{ + osl::MutexGuard aGuard(theSvtLinguConfigItemMutex::get()); + + bool bSucc = false; + if (!rValue.hasValue()) + return bSucc; + + bool bMod = false; + + sal_Int16 *pnVal = nullptr; + LanguageType *plVal = nullptr; + bool *pbVal = nullptr; + sal_Int32 *pnInt32Val = nullptr; + + SvtLinguOptions &rOpt = aOpt; + switch (nPropertyHandle) + { + case UPH_IS_USE_DICTIONARY_LIST : pbVal = &rOpt.bIsUseDictionaryList; break; + case UPH_IS_IGNORE_CONTROL_CHARACTERS : pbVal = &rOpt.bIsIgnoreControlCharacters; break; + case UPH_IS_HYPH_AUTO : pbVal = &rOpt.bIsHyphAuto; break; + case UPH_IS_HYPH_SPECIAL : pbVal = &rOpt.bIsHyphSpecial; break; + case UPH_IS_SPELL_AUTO : pbVal = &rOpt.bIsSpellAuto; break; + case UPH_IS_SPELL_SPECIAL : pbVal = &rOpt.bIsSpellSpecial; break; + case UPH_IS_WRAP_REVERSE : pbVal = &rOpt.bIsSpellReverse; break; + case UPH_DEFAULT_LANGUAGE : plVal = &rOpt.nDefaultLanguage; break; + case UPH_IS_SPELL_CAPITALIZATION : pbVal = &rOpt.bIsSpellCapitalization; break; + case UPH_IS_SPELL_WITH_DIGITS : pbVal = &rOpt.bIsSpellWithDigits; break; + case UPH_IS_SPELL_UPPER_CASE : pbVal = &rOpt.bIsSpellUpperCase; break; + case UPH_HYPH_MIN_LEADING : pnVal = &rOpt.nHyphMinLeading; break; + case UPH_HYPH_MIN_TRAILING : pnVal = &rOpt.nHyphMinTrailing; break; + case UPH_HYPH_MIN_WORD_LENGTH : pnVal = &rOpt.nHyphMinWordLength; break; + case UPH_ACTIVE_DICTIONARIES : + { + rValue >>= rOpt.aActiveDics; + bMod = true; + break; + } + case UPH_ACTIVE_CONVERSION_DICTIONARIES : + { + rValue >>= rOpt.aActiveConvDics; + bMod = true; + break; + } + case UPH_DEFAULT_LOCALE : + { + bSucc = lcl_SetLocale( rOpt.nDefaultLanguage, rValue ); + bMod = bSucc; + break; + } + case UPH_DEFAULT_LOCALE_CJK : + { + bSucc = lcl_SetLocale( rOpt.nDefaultLanguage_CJK, rValue ); + bMod = bSucc; + break; + } + case UPH_DEFAULT_LOCALE_CTL : + { + bSucc = lcl_SetLocale( rOpt.nDefaultLanguage_CTL, rValue ); + bMod = bSucc; + break; + } + case UPH_IS_IGNORE_POST_POSITIONAL_WORD : pbVal = &rOpt.bIsIgnorePostPositionalWord; break; + case UPH_IS_AUTO_CLOSE_DIALOG : pbVal = &rOpt.bIsAutoCloseDialog; break; + case UPH_IS_SHOW_ENTRIES_RECENTLY_USED_FIRST : pbVal = &rOpt.bIsShowEntriesRecentlyUsedFirst; break; + case UPH_IS_AUTO_REPLACE_UNIQUE_ENTRIES : pbVal = &rOpt.bIsAutoReplaceUniqueEntries; break; + + case UPH_IS_DIRECTION_TO_SIMPLIFIED : pbVal = &rOpt.bIsDirectionToSimplified; break; + case UPH_IS_USE_CHARACTER_VARIANTS : pbVal = &rOpt.bIsUseCharacterVariants; break; + case UPH_IS_TRANSLATE_COMMON_TERMS : pbVal = &rOpt.bIsTranslateCommonTerms; break; + case UPH_IS_REVERSE_MAPPING : pbVal = &rOpt.bIsReverseMapping; break; + + case UPH_DATA_FILES_CHANGED_CHECK_VALUE : pnInt32Val = &rOpt.nDataFilesChangedCheckValue; break; + case UPH_IS_GRAMMAR_AUTO: pbVal = &rOpt.bIsGrammarAuto; break; + case UPH_IS_GRAMMAR_INTERACTIVE: pbVal = &rOpt.bIsGrammarInteractive; break; + default : + SAL_WARN( "unotools.config", "unexpected property handle" ); + } + + if (pbVal) + { + bool bNew = bool(); + if (rValue >>= bNew) + { + if (bNew != *pbVal) + { + *pbVal = bNew; + bMod = true; + } + bSucc = true; + } + } + else if (pnVal) + { + sal_Int16 nNew = sal_Int16(); + if (rValue >>= nNew) + { + if (nNew != *pnVal) + { + *pnVal = nNew; + bMod = true; + } + bSucc = true; + } + } + else if (plVal) + { + sal_Int16 nNew = sal_Int16(); + if (rValue >>= nNew) + { + if (nNew != static_cast<sal_uInt16>(*plVal)) + { + *plVal = LanguageType(static_cast<sal_uInt16>(nNew)); + bMod = true; + } + bSucc = true; + } + } + else if (pnInt32Val) + { + sal_Int32 nNew = sal_Int32(); + if (rValue >>= nNew) + { + if (nNew != *pnInt32Val) + { + *pnInt32Val = nNew; + bMod = true; + } + bSucc = true; + } + } + + if (bMod) + SetModified(); + + NotifyListeners(ConfigurationHints::NONE); + return bSucc; +} + +const SvtLinguOptions& SvtLinguConfigItem::GetOptions() const +{ + osl::MutexGuard aGuard(theSvtLinguConfigItemMutex::get()); + return aOpt; +} + +void SvtLinguConfigItem::LoadOptions( const uno::Sequence< OUString > &rProperyNames ) +{ + osl::MutexGuard aGuard(theSvtLinguConfigItemMutex::get()); + + bool bRes = false; + + const OUString *pProperyNames = rProperyNames.getConstArray(); + sal_Int32 nProps = rProperyNames.getLength(); + + const uno::Sequence< uno::Any > aValues = GetProperties( rProperyNames ); + const uno::Sequence< sal_Bool > aROStates = GetReadOnlyStates( rProperyNames ); + + if (nProps && aValues.getLength() == nProps && aROStates.getLength() == nProps) + { + SvtLinguOptions &rOpt = aOpt; + + const uno::Any *pValue = aValues.getConstArray(); + const sal_Bool *pROStates = aROStates.getConstArray(); + for (sal_Int32 i = 0; i < nProps; ++i) + { + const uno::Any &rVal = pValue[i]; + sal_Int32 nPropertyHandle(0); + GetHdlByName( nPropertyHandle, pProperyNames[i], true ); + switch ( nPropertyHandle ) + { + case UPH_DEFAULT_LOCALE : + { rOpt.bRODefaultLanguage = pROStates[i]; rOpt.nDefaultLanguage = lcl_CfgAnyToLanguage( rVal ); } break; + case UPH_ACTIVE_DICTIONARIES : + { rOpt.bROActiveDics = pROStates[i]; rVal >>= rOpt.aActiveDics; } break; + case UPH_IS_USE_DICTIONARY_LIST : + { rOpt.bROIsUseDictionaryList = pROStates[i]; rVal >>= rOpt.bIsUseDictionaryList; } break; + case UPH_IS_IGNORE_CONTROL_CHARACTERS : + { rOpt.bROIsIgnoreControlCharacters = pROStates[i]; rVal >>= rOpt.bIsIgnoreControlCharacters; } break; + case UPH_DEFAULT_LOCALE_CJK : + { rOpt.bRODefaultLanguage_CJK = pROStates[i]; rOpt.nDefaultLanguage_CJK = lcl_CfgAnyToLanguage( rVal ); } break; + case UPH_DEFAULT_LOCALE_CTL : + { rOpt.bRODefaultLanguage_CTL = pROStates[i]; rOpt.nDefaultLanguage_CTL = lcl_CfgAnyToLanguage( rVal ); } break; + + case UPH_IS_SPELL_UPPER_CASE : + { rOpt.bROIsSpellUpperCase = pROStates[i]; rVal >>= rOpt.bIsSpellUpperCase; } break; + case UPH_IS_SPELL_WITH_DIGITS : + { rOpt.bROIsSpellWithDigits = pROStates[i]; rVal >>= rOpt.bIsSpellWithDigits; } break; + case UPH_IS_SPELL_CAPITALIZATION : + { rOpt.bROIsSpellCapitalization = pROStates[i]; rVal >>= rOpt.bIsSpellCapitalization; } break; + case UPH_IS_SPELL_AUTO : + { rOpt.bROIsSpellAuto = pROStates[i]; rVal >>= rOpt.bIsSpellAuto; } break; + case UPH_IS_SPELL_SPECIAL : + { rOpt.bROIsSpellSpecial = pROStates[i]; rVal >>= rOpt.bIsSpellSpecial; } break; + case UPH_IS_WRAP_REVERSE : + { rOpt.bROIsSpellReverse = pROStates[i]; rVal >>= rOpt.bIsSpellReverse; } break; + + case UPH_HYPH_MIN_LEADING : + { rOpt.bROHyphMinLeading = pROStates[i]; rVal >>= rOpt.nHyphMinLeading; } break; + case UPH_HYPH_MIN_TRAILING : + { rOpt.bROHyphMinTrailing = pROStates[i]; rVal >>= rOpt.nHyphMinTrailing; } break; + case UPH_HYPH_MIN_WORD_LENGTH : + { rOpt.bROHyphMinWordLength = pROStates[i]; rVal >>= rOpt.nHyphMinWordLength; } break; + case UPH_IS_HYPH_SPECIAL : + { rOpt.bROIsHyphSpecial = pROStates[i]; rVal >>= rOpt.bIsHyphSpecial; } break; + case UPH_IS_HYPH_AUTO : + { rOpt.bROIsHyphAuto = pROStates[i]; rVal >>= rOpt.bIsHyphAuto; } break; + + case UPH_ACTIVE_CONVERSION_DICTIONARIES : { rOpt.bROActiveConvDics = pROStates[i]; rVal >>= rOpt.aActiveConvDics; } break; + + case UPH_IS_IGNORE_POST_POSITIONAL_WORD : + { rOpt.bROIsIgnorePostPositionalWord = pROStates[i]; rVal >>= rOpt.bIsIgnorePostPositionalWord; } break; + case UPH_IS_AUTO_CLOSE_DIALOG : + { rOpt.bROIsAutoCloseDialog = pROStates[i]; rVal >>= rOpt.bIsAutoCloseDialog; } break; + case UPH_IS_SHOW_ENTRIES_RECENTLY_USED_FIRST : + { rOpt.bROIsShowEntriesRecentlyUsedFirst = pROStates[i]; rVal >>= rOpt.bIsShowEntriesRecentlyUsedFirst; } break; + case UPH_IS_AUTO_REPLACE_UNIQUE_ENTRIES : + { rOpt.bROIsAutoReplaceUniqueEntries = pROStates[i]; rVal >>= rOpt.bIsAutoReplaceUniqueEntries; } break; + + case UPH_IS_DIRECTION_TO_SIMPLIFIED : + { + rOpt.bROIsDirectionToSimplified = pROStates[i]; + if( ! (rVal >>= rOpt.bIsDirectionToSimplified) ) + { + //default is locale dependent: + if (MsLangId::isTraditionalChinese(rOpt.nDefaultLanguage_CJK)) + { + rOpt.bIsDirectionToSimplified = false; + } + else + { + rOpt.bIsDirectionToSimplified = true; + } + } + } break; + case UPH_IS_USE_CHARACTER_VARIANTS : + { rOpt.bROIsUseCharacterVariants = pROStates[i]; rVal >>= rOpt.bIsUseCharacterVariants; } break; + case UPH_IS_TRANSLATE_COMMON_TERMS : + { rOpt.bROIsTranslateCommonTerms = pROStates[i]; rVal >>= rOpt.bIsTranslateCommonTerms; } break; + case UPH_IS_REVERSE_MAPPING : + { rOpt.bROIsReverseMapping = pROStates[i]; rVal >>= rOpt.bIsReverseMapping; } break; + + case UPH_DATA_FILES_CHANGED_CHECK_VALUE : + { rOpt.bRODataFilesChangedCheckValue = pROStates[i]; rVal >>= rOpt.nDataFilesChangedCheckValue; } break; + + case UPH_IS_GRAMMAR_AUTO: + { rOpt.bROIsGrammarAuto = pROStates[i]; rVal >>= rOpt.bIsGrammarAuto; } + break; + case UPH_IS_GRAMMAR_INTERACTIVE: + { rOpt.bROIsGrammarInteractive = pROStates[i]; rVal >>= rOpt.bIsGrammarInteractive; } + break; + + default: + SAL_WARN( "unotools.config", "unexpected case" ); + } + } + + bRes = true; + } + DBG_ASSERT( bRes, "LoadOptions failed" ); +} + +bool SvtLinguConfigItem::SaveOptions( const uno::Sequence< OUString > &rProperyNames ) +{ + if (!IsModified()) + return true; + + osl::MutexGuard aGuard(theSvtLinguConfigItemMutex::get()); + + bool bRet = false; + + sal_Int32 nProps = rProperyNames.getLength(); + uno::Sequence< uno::Any > aValues( nProps ); + uno::Any *pValue = aValues.getArray(); + + if (nProps && aValues.getLength() == nProps) + { + const SvtLinguOptions &rOpt = aOpt; + + OUString aTmp( lcl_LanguageToCfgLocaleStr( rOpt.nDefaultLanguage ) ); + *pValue++ <<= aTmp; // 0 + *pValue++ <<= rOpt.aActiveDics; // 1 + *pValue++ <<= rOpt.bIsUseDictionaryList; // 2 + *pValue++ <<= rOpt.bIsIgnoreControlCharacters; // 3 + aTmp = lcl_LanguageToCfgLocaleStr( rOpt.nDefaultLanguage_CJK ); + *pValue++ <<= aTmp; // 5 + aTmp = lcl_LanguageToCfgLocaleStr( rOpt.nDefaultLanguage_CTL ); + *pValue++ <<= aTmp; // 6 + + *pValue++ <<= rOpt.bIsSpellUpperCase; // 7 + *pValue++ <<= rOpt.bIsSpellWithDigits; // 8 + *pValue++ <<= rOpt.bIsSpellCapitalization; // 9 + *pValue++ <<= rOpt.bIsSpellAuto; // 10 + *pValue++ <<= rOpt.bIsSpellSpecial; // 11 + *pValue++ <<= rOpt.bIsSpellReverse; // 14 + + *pValue++ <<= rOpt.nHyphMinLeading; // 15 + *pValue++ <<= rOpt.nHyphMinTrailing; // 16 + *pValue++ <<= rOpt.nHyphMinWordLength; // 17 + *pValue++ <<= rOpt.bIsHyphSpecial; // 18 + *pValue++ <<= rOpt.bIsHyphAuto; // 19 + + *pValue++ <<= rOpt.aActiveConvDics; // 20 + + *pValue++ <<= rOpt.bIsIgnorePostPositionalWord; // 21 + *pValue++ <<= rOpt.bIsAutoCloseDialog; // 22 + *pValue++ <<= rOpt.bIsShowEntriesRecentlyUsedFirst; // 23 + *pValue++ <<= rOpt.bIsAutoReplaceUniqueEntries; // 24 + + *pValue++ <<= rOpt.bIsDirectionToSimplified; // 25 + *pValue++ <<= rOpt.bIsUseCharacterVariants; // 26 + *pValue++ <<= rOpt.bIsTranslateCommonTerms; // 27 + *pValue++ <<= rOpt.bIsReverseMapping; // 28 + + *pValue++ <<= rOpt.nDataFilesChangedCheckValue; // 29 + *pValue++ <<= rOpt.bIsGrammarAuto; // 30 + *pValue++ <<= rOpt.bIsGrammarInteractive; // 31 + + bRet |= PutProperties( rProperyNames, aValues ); + } + + if (bRet) + ClearModified(); + + return bRet; +} + +bool SvtLinguConfigItem::IsReadOnly( const OUString &rPropertyName ) const +{ + osl::MutexGuard aGuard(theSvtLinguConfigItemMutex::get()); + + bool bReadOnly = false; + sal_Int32 nHdl; + if (GetHdlByName( nHdl, rPropertyName )) + bReadOnly = IsReadOnly( nHdl ); + return bReadOnly; +} + +bool SvtLinguConfigItem::IsReadOnly( sal_Int32 nPropertyHandle ) const +{ + osl::MutexGuard aGuard(theSvtLinguConfigItemMutex::get()); + + bool bReadOnly = false; + + const SvtLinguOptions &rOpt = const_cast< SvtLinguConfigItem * >(this)->aOpt; + switch(nPropertyHandle) + { + case UPH_IS_USE_DICTIONARY_LIST : bReadOnly = rOpt.bROIsUseDictionaryList; break; + case UPH_IS_IGNORE_CONTROL_CHARACTERS : bReadOnly = rOpt.bROIsIgnoreControlCharacters; break; + case UPH_IS_HYPH_AUTO : bReadOnly = rOpt.bROIsHyphAuto; break; + case UPH_IS_HYPH_SPECIAL : bReadOnly = rOpt.bROIsHyphSpecial; break; + case UPH_IS_SPELL_AUTO : bReadOnly = rOpt.bROIsSpellAuto; break; + case UPH_IS_SPELL_SPECIAL : bReadOnly = rOpt.bROIsSpellSpecial; break; + case UPH_IS_WRAP_REVERSE : bReadOnly = rOpt.bROIsSpellReverse; break; + case UPH_DEFAULT_LANGUAGE : bReadOnly = rOpt.bRODefaultLanguage; break; + case UPH_IS_SPELL_CAPITALIZATION : bReadOnly = rOpt.bROIsSpellCapitalization; break; + case UPH_IS_SPELL_WITH_DIGITS : bReadOnly = rOpt.bROIsSpellWithDigits; break; + case UPH_IS_SPELL_UPPER_CASE : bReadOnly = rOpt.bROIsSpellUpperCase; break; + case UPH_HYPH_MIN_LEADING : bReadOnly = rOpt.bROHyphMinLeading; break; + case UPH_HYPH_MIN_TRAILING : bReadOnly = rOpt.bROHyphMinTrailing; break; + case UPH_HYPH_MIN_WORD_LENGTH : bReadOnly = rOpt.bROHyphMinWordLength; break; + case UPH_ACTIVE_DICTIONARIES : bReadOnly = rOpt.bROActiveDics; break; + case UPH_ACTIVE_CONVERSION_DICTIONARIES : bReadOnly = rOpt.bROActiveConvDics; break; + case UPH_DEFAULT_LOCALE : bReadOnly = rOpt.bRODefaultLanguage; break; + case UPH_DEFAULT_LOCALE_CJK : bReadOnly = rOpt.bRODefaultLanguage_CJK; break; + case UPH_DEFAULT_LOCALE_CTL : bReadOnly = rOpt.bRODefaultLanguage_CTL; break; + case UPH_IS_IGNORE_POST_POSITIONAL_WORD : bReadOnly = rOpt.bROIsIgnorePostPositionalWord; break; + case UPH_IS_AUTO_CLOSE_DIALOG : bReadOnly = rOpt.bROIsAutoCloseDialog; break; + case UPH_IS_SHOW_ENTRIES_RECENTLY_USED_FIRST : bReadOnly = rOpt.bROIsShowEntriesRecentlyUsedFirst; break; + case UPH_IS_AUTO_REPLACE_UNIQUE_ENTRIES : bReadOnly = rOpt.bROIsAutoReplaceUniqueEntries; break; + case UPH_IS_DIRECTION_TO_SIMPLIFIED : bReadOnly = rOpt.bROIsDirectionToSimplified; break; + case UPH_IS_USE_CHARACTER_VARIANTS : bReadOnly = rOpt.bROIsUseCharacterVariants; break; + case UPH_IS_TRANSLATE_COMMON_TERMS : bReadOnly = rOpt.bROIsTranslateCommonTerms; break; + case UPH_IS_REVERSE_MAPPING : bReadOnly = rOpt.bROIsReverseMapping; break; + case UPH_DATA_FILES_CHANGED_CHECK_VALUE : bReadOnly = rOpt.bRODataFilesChangedCheckValue; break; + case UPH_IS_GRAMMAR_AUTO: bReadOnly = rOpt.bROIsGrammarAuto; break; + case UPH_IS_GRAMMAR_INTERACTIVE: bReadOnly = rOpt.bROIsGrammarInteractive; break; + default : + SAL_WARN( "unotools.config", "unexpected property handle" ); + } + return bReadOnly; +} + +static SvtLinguConfigItem *pCfgItem = nullptr; +static sal_Int32 nCfgItemRefCount = 0; + +static const char aG_Dictionaries[] = "Dictionaries"; + +SvtLinguConfig::SvtLinguConfig() +{ + // Global access, must be guarded (multithreading) + osl::MutexGuard aGuard(theSvtLinguConfigItemMutex::get()); + ++nCfgItemRefCount; +} + +SvtLinguConfig::~SvtLinguConfig() +{ + osl::MutexGuard aGuard(theSvtLinguConfigItemMutex::get()); + + if (pCfgItem && pCfgItem->IsModified()) + pCfgItem->Commit(); + + if (--nCfgItemRefCount <= 0) + { + delete pCfgItem; + pCfgItem = nullptr; + } +} + +SvtLinguConfigItem & SvtLinguConfig::GetConfigItem() +{ + // Global access, must be guarded (multithreading) + osl::MutexGuard aGuard(theSvtLinguConfigItemMutex::get()); + if (!pCfgItem) + { + pCfgItem = new SvtLinguConfigItem; + ItemHolder1::holdConfigItem(EItem::LinguConfig); + } + return *pCfgItem; +} + +uno::Sequence< OUString > SvtLinguConfig::GetNodeNames( const OUString &rNode ) const +{ + return GetConfigItem().GetNodeNames( rNode ); +} + +uno::Sequence< uno::Any > SvtLinguConfig::GetProperties( const uno::Sequence< OUString > &rNames ) const +{ + return GetConfigItem().GetProperties(rNames); +} + +bool SvtLinguConfig::ReplaceSetProperties( + const OUString &rNode, const uno::Sequence< beans::PropertyValue >& rValues ) +{ + return GetConfigItem().ReplaceSetProperties( rNode, rValues ); +} + +uno::Any SvtLinguConfig::GetProperty( const OUString &rPropertyName ) const +{ + return GetConfigItem().GetProperty( rPropertyName ); +} + +uno::Any SvtLinguConfig::GetProperty( sal_Int32 nPropertyHandle ) const +{ + return GetConfigItem().GetProperty( nPropertyHandle ); +} + +bool SvtLinguConfig::SetProperty( const OUString &rPropertyName, const uno::Any &rValue ) +{ + return GetConfigItem().SetProperty( rPropertyName, rValue ); +} + +bool SvtLinguConfig::SetProperty( sal_Int32 nPropertyHandle, const uno::Any &rValue ) +{ + return GetConfigItem().SetProperty( nPropertyHandle, rValue ); +} + +void SvtLinguConfig::GetOptions( SvtLinguOptions &rOptions ) const +{ + rOptions = GetConfigItem().GetOptions(); +} + +bool SvtLinguConfig::IsReadOnly( const OUString &rPropertyName ) const +{ + return GetConfigItem().IsReadOnly( rPropertyName ); +} + +bool SvtLinguConfig::GetElementNamesFor( + const OUString &rNodeName, + uno::Sequence< OUString > &rElementNames ) const +{ + bool bSuccess = false; + try + { + uno::Reference< container::XNameAccess > xNA( GetMainUpdateAccess(), uno::UNO_QUERY_THROW ); + xNA.set( xNA->getByName("ServiceManager"), uno::UNO_QUERY_THROW ); + xNA.set( xNA->getByName( rNodeName ), uno::UNO_QUERY_THROW ); + rElementNames = xNA->getElementNames(); + bSuccess = true; + } + catch (uno::Exception &) + { + } + return bSuccess; +} + +bool SvtLinguConfig::GetSupportedDictionaryFormatsFor( + const OUString &rSetName, + const OUString &rSetEntry, + uno::Sequence< OUString > &rFormatList ) const +{ + if (rSetName.isEmpty() || rSetEntry.isEmpty()) + return false; + bool bSuccess = false; + try + { + uno::Reference< container::XNameAccess > xNA( GetMainUpdateAccess(), uno::UNO_QUERY_THROW ); + xNA.set( xNA->getByName("ServiceManager"), uno::UNO_QUERY_THROW ); + xNA.set( xNA->getByName( rSetName ), uno::UNO_QUERY_THROW ); + xNA.set( xNA->getByName( rSetEntry ), uno::UNO_QUERY_THROW ); + if (xNA->getByName( "SupportedDictionaryFormats" ) >>= rFormatList) + bSuccess = true; + DBG_ASSERT( rFormatList.hasElements(), "supported dictionary format list is empty" ); + } + catch (uno::Exception &) + { + } + return bSuccess; +} + +static bool lcl_GetFileUrlFromOrigin( + OUString /*out*/ &rFileUrl, + const OUString &rOrigin ) +{ + OUString aURL( + comphelper::getExpandedUri( + comphelper::getProcessComponentContext(), rOrigin)); + if (aURL.startsWith( FILE_PROTOCOL )) + { + rFileUrl = aURL; + return true; + } + else + { + SAL_WARN( + "unotools.config", "not a file URL, <" << aURL << ">" ); + return false; + } +} + +bool SvtLinguConfig::GetDictionaryEntry( + const OUString &rNodeName, + SvtLinguConfigDictionaryEntry &rDicEntry ) const +{ + if (rNodeName.isEmpty()) + return false; + bool bSuccess = false; + try + { + uno::Reference< container::XNameAccess > xNA( GetMainUpdateAccess(), uno::UNO_QUERY_THROW ); + xNA.set( xNA->getByName("ServiceManager"), uno::UNO_QUERY_THROW ); + xNA.set( xNA->getByName( aG_Dictionaries ), uno::UNO_QUERY_THROW ); + xNA.set( xNA->getByName( rNodeName ), uno::UNO_QUERY_THROW ); + + // read group data... + uno::Sequence< OUString > aLocations; + OUString aFormatName; + uno::Sequence< OUString > aLocaleNames; + bSuccess = (xNA->getByName( "Locations" ) >>= aLocations) && + (xNA->getByName( "Format" ) >>= aFormatName) && + (xNA->getByName( "Locales" ) >>= aLocaleNames); + DBG_ASSERT( aLocations.hasElements(), "Dictionary locations not set" ); + DBG_ASSERT( !aFormatName.isEmpty(), "Dictionary format name not set" ); + DBG_ASSERT( aLocaleNames.hasElements(), "No locales set for the dictionary" ); + + // if successful continue + if (bSuccess) + { + // get file URL's for the locations + for (OUString& rLocation : aLocations) + { + if (!lcl_GetFileUrlFromOrigin( rLocation, rLocation )) + bSuccess = false; + } + + // if everything was fine return the result + if (bSuccess) + { + rDicEntry.aLocations = aLocations; + rDicEntry.aFormatName = aFormatName; + rDicEntry.aLocaleNames = aLocaleNames; + } + } + } + catch (uno::Exception &) + { + } + return bSuccess; +} + +uno::Sequence< OUString > SvtLinguConfig::GetDisabledDictionaries() const +{ + uno::Sequence< OUString > aResult; + try + { + uno::Reference< container::XNameAccess > xNA( GetMainUpdateAccess(), uno::UNO_QUERY_THROW ); + xNA.set( xNA->getByName("ServiceManager"), uno::UNO_QUERY_THROW ); + xNA->getByName( "DisabledDictionaries" ) >>= aResult; + } + catch (uno::Exception &) + { + } + return aResult; +} + +std::vector< SvtLinguConfigDictionaryEntry > SvtLinguConfig::GetActiveDictionariesByFormat( + const OUString &rFormatName ) const +{ + std::vector< SvtLinguConfigDictionaryEntry > aRes; + if (rFormatName.isEmpty()) + return aRes; + + try + { + uno::Sequence< OUString > aElementNames; + GetElementNamesFor( aG_Dictionaries, aElementNames ); + + const uno::Sequence< OUString > aDisabledDics( GetDisabledDictionaries() ); + + SvtLinguConfigDictionaryEntry aDicEntry; + for (const OUString& rElementName : std::as_const(aElementNames)) + { + // does dictionary match the format we are looking for? + if (GetDictionaryEntry( rElementName, aDicEntry ) && + aDicEntry.aFormatName == rFormatName) + { + // check if it is active or not + bool bDicIsActive = std::none_of(aDisabledDics.begin(), aDisabledDics.end(), + [&rElementName](const OUString& rDic) { return rDic == rElementName; }); + + if (bDicIsActive) + { + DBG_ASSERT( !aDicEntry.aFormatName.isEmpty(), + "FormatName not set" ); + DBG_ASSERT( aDicEntry.aLocations.hasElements(), + "Locations not set" ); + DBG_ASSERT( aDicEntry.aLocaleNames.hasElements(), + "Locales not set" ); + aRes.push_back( aDicEntry ); + } + } + } + } + catch (uno::Exception &) + { + } + + return aRes; +} + +uno::Reference< util::XChangesBatch > const & SvtLinguConfig::GetMainUpdateAccess() const +{ + if (!m_xMainUpdateAccess.is()) + { + try + { + // get configuration provider + uno::Reference< uno::XComponentContext > xContext = comphelper::getProcessComponentContext(); + uno::Reference< lang::XMultiServiceFactory > xConfigurationProvider = + configuration::theDefaultProvider::get( xContext ); + + // get configuration update access + beans::PropertyValue aValue; + aValue.Name = "nodepath"; + aValue.Value <<= OUString("org.openoffice.Office.Linguistic"); + uno::Sequence< uno::Any > aProps(1); + aProps[0] <<= aValue; + m_xMainUpdateAccess.set( + xConfigurationProvider->createInstanceWithArguments( + "com.sun.star.configuration.ConfigurationUpdateAccess", aProps), + uno::UNO_QUERY_THROW ); + } + catch (uno::Exception &) + { + } + } + + return m_xMainUpdateAccess; +} + +OUString SvtLinguConfig::GetVendorImageUrl_Impl( + const OUString &rServiceImplName, + const OUString &rImageName ) const +{ + OUString aRes; + try + { + uno::Reference< container::XNameAccess > xImagesNA( GetMainUpdateAccess(), uno::UNO_QUERY_THROW ); + xImagesNA.set( xImagesNA->getByName("Images"), uno::UNO_QUERY_THROW ); + + uno::Reference< container::XNameAccess > xNA( xImagesNA->getByName("ServiceNameEntries"), uno::UNO_QUERY_THROW ); + xNA.set( xNA->getByName( rServiceImplName ), uno::UNO_QUERY_THROW ); + uno::Any aAny(xNA->getByName("VendorImagesNode")); + OUString aVendorImagesNode; + if (aAny >>= aVendorImagesNode) + { + xNA = xImagesNA; + xNA.set( xNA->getByName("VendorImages"), uno::UNO_QUERY_THROW ); + xNA.set( xNA->getByName( aVendorImagesNode ), uno::UNO_QUERY_THROW ); + aAny = xNA->getByName( rImageName ); + OUString aTmp; + if (aAny >>= aTmp) + { + if (lcl_GetFileUrlFromOrigin( aTmp, aTmp )) + aRes = aTmp; + } + } + } + catch (uno::Exception &) + { + DBG_UNHANDLED_EXCEPTION("unotools"); + } + return aRes; +} + +OUString SvtLinguConfig::GetSpellAndGrammarContextSuggestionImage( + const OUString &rServiceImplName +) const +{ + OUString aRes; + if (!rServiceImplName.isEmpty()) + { + aRes = GetVendorImageUrl_Impl( rServiceImplName, "SpellAndGrammarContextMenuSuggestionImage" ); + } + return aRes; +} + +OUString SvtLinguConfig::GetSpellAndGrammarContextDictionaryImage( + const OUString &rServiceImplName +) const +{ + OUString aRes; + if (!rServiceImplName.isEmpty()) + { + aRes = GetVendorImageUrl_Impl( rServiceImplName, "SpellAndGrammarContextMenuDictionaryImage" ); + } + return aRes; +} + +OUString SvtLinguConfig::GetSynonymsContextImage( + const OUString &rServiceImplName +) const +{ + OUString aRes; + if (!rServiceImplName.isEmpty()) + { + OUString aPath( GetVendorImageUrl_Impl( rServiceImplName, "SynonymsContextMenuImage" ) ); + aRes = aPath; + } + return aRes; +} + +bool SvtLinguConfig::HasGrammarChecker() const +{ + bool bRes = false; + + try + { + uno::Reference< container::XNameAccess > xNA( GetMainUpdateAccess(), uno::UNO_QUERY_THROW ); + xNA.set( xNA->getByName("ServiceManager"), uno::UNO_QUERY_THROW ); + xNA.set( xNA->getByName("GrammarCheckerList"), uno::UNO_QUERY_THROW ); + + uno::Sequence< OUString > aElementNames( xNA->getElementNames() ); + bRes = aElementNames.hasElements(); + } + catch (const uno::Exception&) + { + } + + return bRes; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/unotools/source/config/misccfg.cxx b/unotools/source/config/misccfg.cxx new file mode 100644 index 000000000..4941773af --- /dev/null +++ b/unotools/source/config/misccfg.cxx @@ -0,0 +1,249 @@ +/* -*- 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 . + */ + +#include <sal/config.h> + +#include <o3tl/any.hxx> +#include <unotools/misccfg.hxx> +#include <rtl/instance.hxx> +#include <unotools/configitem.hxx> +#include <tools/debug.hxx> +#include <com/sun/star/uno/Sequence.hxx> +#include <osl/mutex.hxx> +#include "itemholder1.hxx" + +using namespace com::sun::star::uno; + +namespace utl +{ +class SfxMiscCfg; + +static std::weak_ptr<SfxMiscCfg> g_pOptions; + +class SfxMiscCfg : public utl::ConfigItem +{ +private: + bool bPaperSize; // printer warnings + bool bPaperOrientation; + bool bNotFound; + sal_Int32 nYear2000; // two digit year representation + + static css::uno::Sequence<OUString> GetPropertyNames(); + void Load(); + + virtual void ImplCommit() final override; + +public: + SfxMiscCfg( ); + virtual ~SfxMiscCfg( ) override; + + virtual void Notify( const css::uno::Sequence<OUString>& aPropertyNames) override; + + bool IsNotFoundWarning() const {return bNotFound;} + void SetNotFoundWarning( bool bSet); + + bool IsPaperSizeWarning() const {return bPaperSize;} + void SetPaperSizeWarning(bool bSet); + + bool IsPaperOrientationWarning() const {return bPaperOrientation;} + void SetPaperOrientationWarning( bool bSet); + + // 0 ... 99 + sal_Int32 GetYear2000() const { return nYear2000; } + void SetYear2000( sal_Int32 nSet ); + +}; + +SfxMiscCfg::SfxMiscCfg() : + ConfigItem( "Office.Common" ), + bPaperSize(false), + bPaperOrientation (false), + bNotFound (false), + nYear2000( 1930 ) +{ + Load(); +} + +SfxMiscCfg::~SfxMiscCfg() +{ + if ( IsModified() ) + Commit(); +} + +void SfxMiscCfg::SetNotFoundWarning( bool bSet) +{ + if(bNotFound != bSet) + SetModified(); + bNotFound = bSet; +} + +void SfxMiscCfg::SetPaperSizeWarning( bool bSet) +{ + if(bPaperSize != bSet) + SetModified(); + bPaperSize = bSet; +} + +void SfxMiscCfg::SetPaperOrientationWarning( bool bSet) +{ + if(bPaperOrientation != bSet) + SetModified(); + bPaperOrientation = bSet; +} + +void SfxMiscCfg::SetYear2000( sal_Int32 nSet ) +{ + if(nYear2000 != nSet) + SetModified(); + nYear2000 = nSet; +} + +Sequence<OUString> SfxMiscCfg::GetPropertyNames() +{ + return + { + OUString("Print/Warning/PaperSize"), + OUString("Print/Warning/PaperOrientation"), + OUString("Print/Warning/NotFound"), + OUString("DateFormat/TwoDigitYear") + }; +} + +void SfxMiscCfg::Load() +{ + const Sequence<OUString>& rNames = GetPropertyNames(); + Sequence<Any> aValues = GetProperties(rNames); + EnableNotification(rNames); + const Any* pValues = aValues.getConstArray(); + DBG_ASSERT(aValues.getLength() == rNames.getLength(), "GetProperties failed"); + if(aValues.getLength() == rNames.getLength()) + { + for(int nProp = 0; nProp < rNames.getLength(); nProp++) + { + if(pValues[nProp].hasValue()) + { + switch(nProp) + { + case 0: bPaperSize = *o3tl::doAccess<bool>(pValues[nProp]); break; //"Print/Warning/PaperSize", + case 1: bPaperOrientation = *o3tl::doAccess<bool>(pValues[nProp]); break; //"Print/Warning/PaperOrientation", + case 2: bNotFound = *o3tl::doAccess<bool>(pValues[nProp]); break; //"Print/Warning/NotFound", + case 3: pValues[nProp] >>= nYear2000;break; //"DateFormat/TwoDigitYear", + } + } + } + } +} + +void SfxMiscCfg::Notify( const css::uno::Sequence<OUString>& ) +{ + Load(); +} + +void SfxMiscCfg::ImplCommit() +{ + const Sequence<OUString>& rNames = GetPropertyNames(); + Sequence<Any> aValues(rNames.getLength()); + Any* pValues = aValues.getArray(); + + for(int nProp = 0; nProp < rNames.getLength(); nProp++) + { + switch(nProp) + { + case 0: pValues[nProp] <<= bPaperSize;break; //"Print/Warning/PaperSize", + case 1: pValues[nProp] <<= bPaperOrientation;break; //"Print/Warning/PaperOrientation", + case 2: pValues[nProp] <<= bNotFound;break; //"Print/Warning/NotFound", + case 3: pValues[nProp] <<= nYear2000;break; //"DateFormat/TwoDigitYear", + } + } + PutProperties(rNames, aValues); +} + +namespace +{ + class LocalSingleton : public rtl::Static< osl::Mutex, LocalSingleton > + { + }; +} + +MiscCfg::MiscCfg( ) +{ + // Global access, must be guarded (multithreading) + ::osl::MutexGuard aGuard( LocalSingleton::get() ); + m_pImpl = g_pOptions.lock(); + if ( !m_pImpl ) + { + m_pImpl = std::make_shared<SfxMiscCfg>(); + g_pOptions = m_pImpl; + ItemHolder1::holdConfigItem(EItem::MiscConfig); + } + + m_pImpl->AddListener(this); +} + +MiscCfg::~MiscCfg( ) +{ + // Global access, must be guarded (multithreading) + ::osl::MutexGuard aGuard( LocalSingleton::get() ); + m_pImpl->RemoveListener(this); + m_pImpl.reset(); +} + +bool MiscCfg::IsNotFoundWarning() const +{ + return m_pImpl->IsNotFoundWarning(); +} + +void MiscCfg::SetNotFoundWarning( bool bSet) +{ + m_pImpl->SetNotFoundWarning( bSet ); +} + +bool MiscCfg::IsPaperSizeWarning() const +{ + return m_pImpl->IsPaperSizeWarning(); +} + +void MiscCfg::SetPaperSizeWarning(bool bSet) +{ + m_pImpl->SetPaperSizeWarning( bSet ); +} + +bool MiscCfg::IsPaperOrientationWarning() const +{ + return m_pImpl->IsPaperOrientationWarning(); +} + +void MiscCfg::SetPaperOrientationWarning( bool bSet) +{ + m_pImpl->SetPaperOrientationWarning( bSet ); +} + +sal_Int32 MiscCfg::GetYear2000() const +{ + return m_pImpl->GetYear2000(); +} + +void MiscCfg::SetYear2000( sal_Int32 nSet ) +{ + m_pImpl->SetYear2000( nSet ); +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/unotools/source/config/moduleoptions.cxx b/unotools/source/config/moduleoptions.cxx new file mode 100644 index 000000000..8082749e9 --- /dev/null +++ b/unotools/source/config/moduleoptions.cxx @@ -0,0 +1,1118 @@ +/* -*- 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 . + */ + +#include <unotools/moduleoptions.hxx> +#include <comphelper/sequenceashashmap.hxx> +#include <unotools/configitem.hxx> +#include <comphelper/processfactory.hxx> +#include <comphelper/sequence.hxx> +#include <osl/diagnose.h> +#include <o3tl/enumarray.hxx> +#include <rtl/instance.hxx> +#include <com/sun/star/uno/Any.hxx> +#include <com/sun/star/uno/Sequence.hxx> +#include <com/sun/star/beans/PropertyValue.hpp> +#include <com/sun/star/container/XNameAccess.hpp> +#include <com/sun/star/frame/XModel.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/document/XTypeDetection.hpp> +#include <com/sun/star/util/PathSubstitution.hpp> +#include <com/sun/star/util/XStringSubstitution.hpp> + +#include "itemholder1.hxx" + +/*-************************************************************************************************************ + @descr These values are used to define necessary keys from our configuration management to support + all functionality of these implementation. + It's a fast way to make changes if some keys change its name or location! + + Property handle are necessary to specify right position in return list of configuration + for asked values. We ask it with a list of properties to get its values. The returned list + has the same order like our given name list! + e.g.: + NAMELIST[ PROPERTYHANDLE_xxx ] => VALUELIST[ PROPERTYHANDLE_xxx ] +*//*-*************************************************************************************************************/ +#define ROOTNODE_FACTORIES "Setup/Office/Factories" +#define PATHSEPARATOR "/" + +// Attention: The property "ooSetupFactoryEmptyDocumentURL" is read from configuration but not used! There is +// special code that uses hard coded strings to return them. +#define PROPERTYNAME_SHORTNAME "ooSetupFactoryShortName" +#define PROPERTYNAME_TEMPLATEFILE "ooSetupFactoryTemplateFile" +#define PROPERTYNAME_WINDOWATTRIBUTES "ooSetupFactoryWindowAttributes" +#define PROPERTYNAME_EMPTYDOCUMENTURL "ooSetupFactoryEmptyDocumentURL" +#define PROPERTYNAME_DEFAULTFILTER "ooSetupFactoryDefaultFilter" +#define PROPERTYNAME_ICON "ooSetupFactoryIcon" + +#define PROPERTYHANDLE_SHORTNAME 0 +#define PROPERTYHANDLE_TEMPLATEFILE 1 +#define PROPERTYHANDLE_WINDOWATTRIBUTES 2 +#define PROPERTYHANDLE_EMPTYDOCUMENTURL 3 +#define PROPERTYHANDLE_DEFAULTFILTER 4 +#define PROPERTYHANDLE_ICON 5 + +#define PROPERTYCOUNT 6 + +#define FACTORYNAME_WRITER "com.sun.star.text.TextDocument" +#define FACTORYNAME_WRITERWEB "com.sun.star.text.WebDocument" +#define FACTORYNAME_WRITERGLOBAL "com.sun.star.text.GlobalDocument" +#define FACTORYNAME_CALC "com.sun.star.sheet.SpreadsheetDocument" +#define FACTORYNAME_DRAW "com.sun.star.drawing.DrawingDocument" +#define FACTORYNAME_IMPRESS "com.sun.star.presentation.PresentationDocument" +#define FACTORYNAME_MATH "com.sun.star.formula.FormulaProperties" +#define FACTORYNAME_CHART "com.sun.star.chart2.ChartDocument" +#define FACTORYNAME_DATABASE "com.sun.star.sdb.OfficeDatabaseDocument" +#define FACTORYNAME_STARTMODULE "com.sun.star.frame.StartModule" +#define FACTORYNAME_BASIC "com.sun.star.script.BasicIDE" + +#define FACTORYCOUNT 11 + +namespace { + +/*-************************************************************************************************************ + @descr This struct hold information about one factory. We declare a complete array which can hold infos + for all well known factories. Values of enum "EFactory" (see header!) are directly used as index! + So we can support a fast access on this information. +*//*-*************************************************************************************************************/ +struct FactoryInfo +{ + public: + + // initialize empty struct + FactoryInfo() + { + free(); + } + + // easy way to reset struct member! + void free() + { + bInstalled = false; + sFactory.clear(); + sTemplateFile.clear(); + sDefaultFilter.clear(); + nIcon = 0; + bChangedTemplateFile = false; + bChangedDefaultFilter = false; + bDefaultFilterReadonly = false; + } + + // returns list of properties, which has changed only! + // We use given value of sNodeBase to build full qualified paths ... + // Last sign of it must be "/". because we use it directly, without any additional things! + css::uno::Sequence< css::beans::PropertyValue > getChangedProperties( const OUString& sNodeBase ) + { + // a) reserve memory for max. count of changed properties + // b) add names and values of changed ones only and count it + // c) resize return list by using count + css::uno::Sequence< css::beans::PropertyValue > lProperties ( 4 ); + sal_Int8 nRealyChanged = 0; + + if( bChangedTemplateFile ) + { + lProperties[nRealyChanged].Name = sNodeBase + PROPERTYNAME_TEMPLATEFILE; + + if ( !sTemplateFile.isEmpty() ) + { + lProperties[nRealyChanged].Value + <<= getStringSubstitution() + ->reSubstituteVariables( sTemplateFile ); + } + else + { + lProperties[nRealyChanged].Value <<= sTemplateFile; + } + + ++nRealyChanged; + } + if( bChangedDefaultFilter ) + { + lProperties[nRealyChanged].Name = sNodeBase + PROPERTYNAME_DEFAULTFILTER; + lProperties[nRealyChanged].Value <<= sDefaultFilter; + ++nRealyChanged; + } + + // Don't forget to reset changed flags! Otherwise we save it again and again and ... + bChangedTemplateFile = false; + bChangedDefaultFilter = false; + + lProperties.realloc( nRealyChanged ); + return lProperties; + } + + // We must support setting AND marking of changed values. + // That's why we can't make our member public. We must use get/set/init methods + // to control access on it! + bool getInstalled () const { return bInstalled; }; + const OUString& getFactory () const { return sFactory; }; + const OUString& getTemplateFile () const { return sTemplateFile; }; + const OUString& getDefaultFilter () const { return sDefaultFilter; }; + bool isDefaultFilterReadonly() const { return bDefaultFilterReadonly; } + sal_Int32 getIcon () const { return nIcon; }; + + // If you call set-methods - we check for changes of values and mark it. + // But if you wish to set it without that... you must initialize it! + void initInstalled () { bInstalled = true; } + void initFactory ( const OUString& sNewFactory ) { sFactory = sNewFactory; } + void initDefaultFilter ( const OUString& sNewDefaultFilter ) { sDefaultFilter = sNewDefaultFilter; } + void setDefaultFilterReadonly( const bool bVal){bDefaultFilterReadonly = bVal;} + void initIcon ( sal_Int32 nNewIcon ) { nIcon = nNewIcon; } + + void initTemplateFile( const OUString& sNewTemplateFile ) + { + if ( !sNewTemplateFile.isEmpty() ) + { + sTemplateFile= getStringSubstitution()->substituteVariables( sNewTemplateFile, false ); + } + else + { + sTemplateFile = sNewTemplateFile; + } + } + + void setTemplateFile( const OUString& sNewTemplateFile ) + { + if( sTemplateFile != sNewTemplateFile ) + { + sTemplateFile = sNewTemplateFile; + bChangedTemplateFile = true; + } + }; + + void setDefaultFilter( const OUString& sNewDefaultFilter ) + { + if( sDefaultFilter != sNewDefaultFilter ) + { + sDefaultFilter = sNewDefaultFilter; + bChangedDefaultFilter = true; + } + }; + + private: + css::uno::Reference< css::util::XStringSubstitution > const & getStringSubstitution() + { + if ( !xSubstVars.is() ) + { + xSubstVars.set( css::util::PathSubstitution::create(::comphelper::getProcessComponentContext()) ); + } + return xSubstVars; + } + + bool bInstalled; + OUString sFactory; + OUString sTemplateFile; + OUString sDefaultFilter; + sal_Int32 nIcon; + + bool bChangedTemplateFile :1; + bool bChangedDefaultFilter :1; + bool bDefaultFilterReadonly :1; + + css::uno::Reference< css::util::XStringSubstitution > xSubstVars; +}; + +} + +class SvtModuleOptions_Impl : public ::utl::ConfigItem +{ + + // public methods + + public: + + // constructor / destructor + + SvtModuleOptions_Impl(); + virtual ~SvtModuleOptions_Impl() override; + + // override methods of baseclass + + virtual void Notify( const css::uno::Sequence< OUString >& lPropertyNames ) override; + + // public interface + + bool IsModuleInstalled ( SvtModuleOptions::EModule eModule ) const; + css::uno::Sequence < OUString > GetAllServiceNames(); + OUString const & GetFactoryName ( SvtModuleOptions::EFactory eFactory ) const; + OUString const & GetFactoryStandardTemplate( SvtModuleOptions::EFactory eFactory ) const; + static OUString GetFactoryEmptyDocumentURL( SvtModuleOptions::EFactory eFactory ); + OUString const & GetFactoryDefaultFilter ( SvtModuleOptions::EFactory eFactory ) const; + bool IsDefaultFilterReadonly( SvtModuleOptions::EFactory eFactory ) const; + sal_Int32 GetFactoryIcon ( SvtModuleOptions::EFactory eFactory ) const; + static bool ClassifyFactoryByName ( const OUString& sName , + SvtModuleOptions::EFactory& eFactory ); + void SetFactoryStandardTemplate( SvtModuleOptions::EFactory eFactory , + const OUString& sTemplate ); + void SetFactoryDefaultFilter ( SvtModuleOptions::EFactory eFactory , + const OUString& sFilter ); + void MakeReadonlyStatesAvailable(); + + // private methods + + private: + static css::uno::Sequence< OUString > impl_ExpandSetNames ( const css::uno::Sequence< OUString >& lSetNames ); + void impl_Read ( const css::uno::Sequence< OUString >& lSetNames ); + + virtual void ImplCommit() override; + + // private member + + private: + o3tl::enumarray<SvtModuleOptions::EFactory, FactoryInfo> m_lFactories; + bool m_bReadOnlyStatesWellKnown; +}; + +/*-************************************************************************************************************ + @short default ctor + @descr We open our configuration here and read all necessary values from it. + These values are cached till everyone call Commit(). Then we write changed ones back to cfg. + + @seealso baseclass ConfigItem + @seealso method impl_Read() + @threadsafe no +*//*-*************************************************************************************************************/ +SvtModuleOptions_Impl::SvtModuleOptions_Impl() + : ::utl::ConfigItem( ROOTNODE_FACTORIES ) + , m_bReadOnlyStatesWellKnown( false ) +{ + // First initialize list of factory infos! Otherwise we couldn't guarantee right working of these class. + for( auto & rFactory : m_lFactories ) + rFactory.free(); + + // Get name list of all existing set node names in configuration to read her properties in impl_Read(). + // These list is a list of long names of our factories. + const css::uno::Sequence< OUString > lFactories = GetNodeNames( OUString() ); + impl_Read( lFactories ); + + // Enable notification for changes by using configuration directly. + // So we can update our internal values immediately. + EnableNotification( lFactories ); +} + +SvtModuleOptions_Impl::~SvtModuleOptions_Impl() +{ + assert(!IsModified()); // should have been committed +} + +/*-************************************************************************************************************ + @short called for notify of configmanager + @descr This method is called from the ConfigManager before application ends or from the + PropertyChangeListener if the sub tree broadcasts changes. You must update our + internal values. + + @attention We are registered for pure set node names only. So we can use our internal method "impl_Read()" to + update our info list. Because - this method expand given name list to full qualified property list + and use it to read the values. These values are filled into our internal member list m_lFactories + at right position. + + @seealso method impl_Read() + + @param "lNames" is the list of set node entries which should be updated. + @threadsafe no +*//*-*************************************************************************************************************/ +void SvtModuleOptions_Impl::Notify( const css::uno::Sequence< OUString >& ) +{ + OSL_FAIL( "SvtModuleOptions_Impl::Notify() Not implemented yet!" ); +} + +/*-**************************************************************************************************** + @short write changes to configuration + @descr This method writes the changed values into the sub tree + and should always called in our destructor to guarantee consistency of config data. + + @attention We clear complete set in configuration first and write it completely new! So we don't must + distinguish between existing, added or removed elements. Our internal cached values + are the only and right ones. + + @seealso baseclass ConfigItem + @threadsafe no +*//*-*****************************************************************************************************/ +void SvtModuleOptions_Impl::ImplCommit() +{ + // Reserve memory for ALL possible factory properties! + // Step over all factories and get her really changed values only. + // Build list of these ones and use it for commit. + css::uno::Sequence< css::beans::PropertyValue > lCommitProperties( FACTORYCOUNT*PROPERTYCOUNT ); + sal_Int32 nRealCount = 0; + OUString sBasePath; + for( FactoryInfo & rInfo : m_lFactories ) + { + // These path is used to build full qualified property names... + // See pInfo->getChangedProperties() for further information + sBasePath = PATHSEPARATOR + rInfo.getFactory() + PATHSEPARATOR; + + const css::uno::Sequence< css::beans::PropertyValue > lChangedProperties = rInfo.getChangedProperties ( sBasePath ); + std::copy(lChangedProperties.begin(), lChangedProperties.end(), std::next(lCommitProperties.begin(), nRealCount)); + nRealCount += lChangedProperties.getLength(); + } + // Resize commit list to real size. + // If nothing to do - suppress calling of configuration... + // It could be too expensive :-) + if( nRealCount > 0 ) + { + lCommitProperties.realloc( nRealCount ); + SetSetProperties( OUString(), lCommitProperties ); + } +} + +/*-**************************************************************************************************** + @short access method to get internal values + @descr These methods implement easy access to our internal values. + You give us right enum value to specify which module interest you ... we return right information. + + @attention Some people use any value as enum ... but we support in header specified values only! + We use it directly as index in our internal list. If enum value isn't right - we crash with an + "index out of range"!!! Please use me right - otherwise there is no guarantee. + @param "eModule" , index in list - specify module + @return Queried information. + + @onerror We return default values. (mostly "not installed"!) + @threadsafe no +*//*-*****************************************************************************************************/ +bool SvtModuleOptions_Impl::IsModuleInstalled( SvtModuleOptions::EModule eModule ) const +{ + switch( eModule ) + { + case SvtModuleOptions::EModule::WRITER: + return m_lFactories[SvtModuleOptions::EFactory::WRITER].getInstalled(); + case SvtModuleOptions::EModule::WEB: + return m_lFactories[SvtModuleOptions::EFactory::WRITERWEB].getInstalled(); + case SvtModuleOptions::EModule::GLOBAL: + return m_lFactories[SvtModuleOptions::EFactory::WRITERGLOBAL].getInstalled(); + case SvtModuleOptions::EModule::CALC: + return m_lFactories[SvtModuleOptions::EFactory::CALC].getInstalled(); + case SvtModuleOptions::EModule::DRAW: + return m_lFactories[SvtModuleOptions::EFactory::DRAW].getInstalled(); + case SvtModuleOptions::EModule::IMPRESS: + return m_lFactories[SvtModuleOptions::EFactory::IMPRESS].getInstalled(); + case SvtModuleOptions::EModule::MATH: + return m_lFactories[SvtModuleOptions::EFactory::MATH].getInstalled(); + case SvtModuleOptions::EModule::CHART: + return m_lFactories[SvtModuleOptions::EFactory::CHART].getInstalled(); + case SvtModuleOptions::EModule::STARTMODULE: + return m_lFactories[SvtModuleOptions::EFactory::STARTMODULE].getInstalled(); + case SvtModuleOptions::EModule::BASIC: + return true; // Couldn't be deselected by setup yet! + case SvtModuleOptions::EModule::DATABASE: + return m_lFactories[SvtModuleOptions::EFactory::DATABASE].getInstalled(); + } + + return false; +} + +css::uno::Sequence < OUString > SvtModuleOptions_Impl::GetAllServiceNames() +{ + std::vector<OUString> aVec; + + for( const auto & rFactory : m_lFactories ) + if( rFactory.getInstalled() ) + aVec.push_back( rFactory.getFactory() ); + + return comphelper::containerToSequence(aVec); +} + +OUString const & SvtModuleOptions_Impl::GetFactoryName( SvtModuleOptions::EFactory eFactory ) const +{ + return m_lFactories[eFactory].getFactory(); +} + +OUString SvtModuleOptions::GetFactoryShortName(SvtModuleOptions::EFactory eFactory) +{ + // Attention: Hard configured yet ... because it's not fine to make changes possible by xml file yet. + // But it's good to plan further possibilities! + + //return m_lFactories[eFactory].sShortName; + + OUString sShortName; + switch( eFactory ) + { + case SvtModuleOptions::EFactory::WRITER : sShortName = "swriter"; + break; + case SvtModuleOptions::EFactory::WRITERWEB: sShortName = "swriter/web"; + break; + case SvtModuleOptions::EFactory::WRITERGLOBAL: sShortName = "swriter/GlobalDocument"; + break; + case SvtModuleOptions::EFactory::CALC : sShortName = "scalc"; + break; + case SvtModuleOptions::EFactory::DRAW : sShortName = "sdraw"; + break; + case SvtModuleOptions::EFactory::IMPRESS : sShortName = "simpress"; + break; + case SvtModuleOptions::EFactory::MATH : sShortName = "smath"; + break; + case SvtModuleOptions::EFactory::CHART : sShortName = "schart"; + break; + case SvtModuleOptions::EFactory::BASIC : sShortName = "sbasic"; + break; + case SvtModuleOptions::EFactory::DATABASE : sShortName = "sdatabase"; + break; + default: + OSL_FAIL( "unknown factory" ); + break; + } + + return sShortName; +} + +OUString const & SvtModuleOptions_Impl::GetFactoryStandardTemplate( SvtModuleOptions::EFactory eFactory ) const +{ + return m_lFactories[eFactory].getTemplateFile(); +} + +OUString SvtModuleOptions_Impl::GetFactoryEmptyDocumentURL( SvtModuleOptions::EFactory eFactory ) +{ + // Attention: Hard configured yet ... because it's not fine to make changes possible by xml file yet. + // But it's good to plan further possibilities! + + //return m_lFactories[eFactory].getEmptyDocumentURL(); + + OUString sURL; + switch( eFactory ) + { + case SvtModuleOptions::EFactory::WRITER : sURL = "private:factory/swriter"; + break; + case SvtModuleOptions::EFactory::WRITERWEB : sURL = "private:factory/swriter/web"; + break; + case SvtModuleOptions::EFactory::WRITERGLOBAL : sURL = "private:factory/swriter/GlobalDocument"; + break; + case SvtModuleOptions::EFactory::CALC : sURL = "private:factory/scalc"; + break; + case SvtModuleOptions::EFactory::DRAW : sURL = "private:factory/sdraw"; + break; + case SvtModuleOptions::EFactory::IMPRESS : sURL = "private:factory/simpress?slot=6686"; + break; + case SvtModuleOptions::EFactory::MATH : sURL = "private:factory/smath"; + break; + case SvtModuleOptions::EFactory::CHART : sURL = "private:factory/schart"; + break; + case SvtModuleOptions::EFactory::BASIC : sURL = "private:factory/sbasic"; + break; + case SvtModuleOptions::EFactory::DATABASE : sURL = "private:factory/sdatabase?Interactive"; + break; + default: + OSL_FAIL( "unknown factory" ); + break; + } + return sURL; +} + +OUString const & SvtModuleOptions_Impl::GetFactoryDefaultFilter( SvtModuleOptions::EFactory eFactory ) const +{ + return m_lFactories[eFactory].getDefaultFilter(); +} + +bool SvtModuleOptions_Impl::IsDefaultFilterReadonly( SvtModuleOptions::EFactory eFactory ) const +{ + return m_lFactories[eFactory].isDefaultFilterReadonly(); +} + +sal_Int32 SvtModuleOptions_Impl::GetFactoryIcon( SvtModuleOptions::EFactory eFactory ) const +{ + return m_lFactories[eFactory].getIcon(); +} + +void SvtModuleOptions_Impl::SetFactoryStandardTemplate( SvtModuleOptions::EFactory eFactory , + const OUString& sTemplate ) +{ + m_lFactories[eFactory].setTemplateFile( sTemplate ); + SetModified(); +} + +void SvtModuleOptions_Impl::SetFactoryDefaultFilter( SvtModuleOptions::EFactory eFactory, + const OUString& sFilter ) +{ + m_lFactories[eFactory].setDefaultFilter( sFilter ); + SetModified(); +} + +/*-************************************************************************************************************ + @short return list of key names of our configuration management which represent our module tree + @descr You give use a list of current existing set node names .. and we expand it for all + well known properties which are necessary for this implementation. + These full expanded list should be used to get values of this properties. + + @seealso ctor + @return List of all relative addressed properties of given set entry names. + + @onerror List will be empty. + @threadsafe no +*//*-*************************************************************************************************************/ +css::uno::Sequence< OUString > SvtModuleOptions_Impl::impl_ExpandSetNames( const css::uno::Sequence< OUString >& lSetNames ) +{ + sal_Int32 nCount = lSetNames.getLength(); + css::uno::Sequence< OUString > lPropNames ( nCount*PROPERTYCOUNT ); + OUString* pPropNames = lPropNames.getArray(); + sal_Int32 nPropStart = 0; + + for( const auto& rSetName : lSetNames ) + { + pPropNames[nPropStart+PROPERTYHANDLE_SHORTNAME ] = rSetName + PATHSEPARATOR PROPERTYNAME_SHORTNAME; + pPropNames[nPropStart+PROPERTYHANDLE_TEMPLATEFILE ] = rSetName + PATHSEPARATOR PROPERTYNAME_TEMPLATEFILE; + pPropNames[nPropStart+PROPERTYHANDLE_WINDOWATTRIBUTES] = rSetName + PATHSEPARATOR PROPERTYNAME_WINDOWATTRIBUTES; + pPropNames[nPropStart+PROPERTYHANDLE_EMPTYDOCUMENTURL] = rSetName + PATHSEPARATOR PROPERTYNAME_EMPTYDOCUMENTURL; + pPropNames[nPropStart+PROPERTYHANDLE_DEFAULTFILTER ] = rSetName + PATHSEPARATOR PROPERTYNAME_DEFAULTFILTER; + pPropNames[nPropStart+PROPERTYHANDLE_ICON ] = rSetName + PATHSEPARATOR PROPERTYNAME_ICON; + nPropStart += PROPERTYCOUNT; + } + + return lPropNames; +} + +/*-************************************************************************************************************ + @short helper to classify given factory by name + @descr Every factory has its own long and short name. So we can match right enum value for internal using. + + @attention We change in/out parameter "eFactory" in every case! But you should use it only, if return value is sal_True! + Algorithm: Set out-parameter to probably value ... and check the longname. + If it matches with these factory - break operation and return true AND right set parameter. + Otherwise try next one and so on. If no factory was found return false. Out parameter eFactory + is set to last tried value but shouldn't be used! Because our return value is false! + @param "sLongName" , long name of factory, which should be classified + @return "eFactory" , right enum value, which match given long name + and true for successfully classification, false otherwise + + @onerror We return false. + @threadsafe no +*//*-*************************************************************************************************************/ +bool SvtModuleOptions_Impl::ClassifyFactoryByName( const OUString& sName, SvtModuleOptions::EFactory& eFactory ) +{ + bool bState; + + eFactory = SvtModuleOptions::EFactory::WRITER; + bState = ( sName == FACTORYNAME_WRITER ); + + if( !bState ) + { + eFactory = SvtModuleOptions::EFactory::WRITERWEB; + bState = ( sName == FACTORYNAME_WRITERWEB ); + } + // no else! + if( !bState ) + { + eFactory = SvtModuleOptions::EFactory::WRITERGLOBAL; + bState = ( sName == FACTORYNAME_WRITERGLOBAL ); + } + // no else! + if( !bState ) + { + eFactory = SvtModuleOptions::EFactory::CALC; + bState = ( sName == FACTORYNAME_CALC ); + } + // no else! + if( !bState ) + { + eFactory = SvtModuleOptions::EFactory::DRAW; + bState = ( sName == FACTORYNAME_DRAW ); + } + // no else! + if( !bState ) + { + eFactory = SvtModuleOptions::EFactory::IMPRESS; + bState = ( sName == FACTORYNAME_IMPRESS ); + } + // no else! + if( !bState ) + { + eFactory = SvtModuleOptions::EFactory::MATH; + bState = ( sName == FACTORYNAME_MATH ); + } + // no else! + if( !bState ) + { + eFactory = SvtModuleOptions::EFactory::CHART; + bState = ( sName == FACTORYNAME_CHART ); + } + // no else! + if( !bState ) + { + eFactory = SvtModuleOptions::EFactory::DATABASE; + bState = ( sName == FACTORYNAME_DATABASE ); + } + // no else! + if( !bState ) + { + eFactory = SvtModuleOptions::EFactory::STARTMODULE; + bState = ( sName == FACTORYNAME_STARTMODULE); + } + // no else! + if( !bState ) + { + eFactory = SvtModuleOptions::EFactory::BASIC; + bState = ( sName == FACTORYNAME_BASIC); + } + + return bState; +} + +/*-************************************************************************************************************ + @short read factory configuration + @descr Give us a list of pure factory names (long names!) which can be used as + direct set node names... and we read her property values and fill internal list. + These method can be used by initial reading at ctor and later updating by "Notify()". + + @seealso ctor + @seealso method Notify() + + @param "lFactories" is the list of set node entries which should be read. + @onerror We do nothing. + @threadsafe no +*//*-*************************************************************************************************************/ +void SvtModuleOptions_Impl::impl_Read( const css::uno::Sequence< OUString >& lFactories ) +{ + // Expand every set node name in lFactories to full qualified paths to its properties + // and get right values from configuration. + const css::uno::Sequence< OUString > lProperties = impl_ExpandSetNames( lFactories ); + const css::uno::Sequence< css::uno::Any > lValues = GetProperties( lProperties ); + + // Safe impossible cases. + // We need values from ALL configuration keys. + // Follow assignment use order of values in relation to our list of key names! + OSL_ENSURE( !(lProperties.getLength()!=lValues.getLength()), "SvtModuleOptions_Impl::impl_Read()\nI miss some values of configuration keys!" ); + + // Algorithm: We step over all given factory names and classify it. These enum value can be used as direct index + // in our member list m_lFactories! VAriable nPropertyStart marks start position of every factory + // and her properties in expanded property/value list. The defines PROPERTHANDLE_xxx are used as offset values + // added to nPropertyStart. So we can address every property relative in these lists. + // If we found any valid values ... we reset all existing information for corresponding m_lFactories-entry and + // use a pointer to these struct in memory directly to set new values. + // But we set it only, if bInstalled is true. Otherwise all other values of a factory can be undeclared .. They + // shouldn't be used then. + // Attention: If a propertyset of a factory will be ignored we must step to next start position of next factory infos! + // see "nPropertyStart += PROPERTYCOUNT" ... + + sal_Int32 nPropertyStart = 0; + FactoryInfo* pInfo = nullptr; + SvtModuleOptions::EFactory eFactory; + + for( const OUString& sFactoryName : lFactories ) + { + if( ClassifyFactoryByName( sFactoryName, eFactory ) ) + { + OUString sTemp; + sal_Int32 nTemp = 0; + + pInfo = &(m_lFactories[eFactory]); + pInfo->free(); + + pInfo->initInstalled(); + pInfo->initFactory ( sFactoryName ); + + if (lValues[nPropertyStart+PROPERTYHANDLE_TEMPLATEFILE] >>= sTemp) + pInfo->initTemplateFile( sTemp ); + if (lValues[nPropertyStart+PROPERTYHANDLE_DEFAULTFILTER ] >>= sTemp) + pInfo->initDefaultFilter( sTemp ); + if (lValues[nPropertyStart+PROPERTYHANDLE_ICON] >>= nTemp) + pInfo->initIcon( nTemp ); + } + nPropertyStart += PROPERTYCOUNT; + } +} + +void SvtModuleOptions_Impl::MakeReadonlyStatesAvailable() +{ + if (m_bReadOnlyStatesWellKnown) + return; + + css::uno::Sequence< OUString > lFactories = GetNodeNames(OUString()); + std::transform(lFactories.begin(), lFactories.end(), lFactories.begin(), + [](const OUString& rFactory) -> OUString { + return rFactory + PATHSEPARATOR PROPERTYNAME_DEFAULTFILTER; + }); + + css::uno::Sequence< sal_Bool > lReadonlyStates = GetReadOnlyStates(lFactories); + sal_Int32 c = lFactories.getLength(); + for (sal_Int32 i=0; i<c; ++i) + { + OUString& rFactoryName = lFactories[i]; + SvtModuleOptions::EFactory eFactory; + + if (!ClassifyFactoryByName(rFactoryName, eFactory)) + continue; + + FactoryInfo& rInfo = m_lFactories[eFactory]; + rInfo.setDefaultFilterReadonly(lReadonlyStates[i]); + } + + m_bReadOnlyStatesWellKnown = true; +} + +namespace { + //global + std::weak_ptr<SvtModuleOptions_Impl> g_pModuleOptions; +} + +/*-************************************************************************************************************ + @short standard constructor and destructor + @descr This will initialize an instance with default values. We initialize/deinitialize our static data + container and create a static mutex, which is used for threadsafe code in further time of this object. + + @seealso method impl_GetOwnStaticMutex() + @threadsafe yes +*//*-*************************************************************************************************************/ +SvtModuleOptions::SvtModuleOptions() +{ + // Global access, must be guarded (multithreading!) + ::osl::MutexGuard aGuard( impl_GetOwnStaticMutex() ); + + m_pImpl = g_pModuleOptions.lock(); + if( !m_pImpl ) + { + m_pImpl = std::make_shared<SvtModuleOptions_Impl>(); + g_pModuleOptions = m_pImpl; + ItemHolder1::holdConfigItem(EItem::ModuleOptions); + } +} + +SvtModuleOptions::~SvtModuleOptions() +{ + // Global access, must be guarded (multithreading!) + ::osl::MutexGuard aGuard( impl_GetOwnStaticMutex() ); + + m_pImpl.reset(); +} + +/*-************************************************************************************************************ + @short access to configuration data + @descr This methods allow read/write access to configuration values. + They are threadsafe. All calls are forwarded to impl-data-container. See there for further information! + + @seealso method impl_GetOwnStaticMutex() + @threadsafe yes +*//*-*************************************************************************************************************/ +bool SvtModuleOptions::IsModuleInstalled( EModule eModule ) const +{ + ::osl::MutexGuard aGuard( impl_GetOwnStaticMutex() ); + return m_pImpl->IsModuleInstalled( eModule ); +} + +OUString SvtModuleOptions::GetFactoryName( EFactory eFactory ) const +{ + ::osl::MutexGuard aGuard( impl_GetOwnStaticMutex() ); + return m_pImpl->GetFactoryName( eFactory ); +} + +OUString SvtModuleOptions::GetFactoryStandardTemplate( EFactory eFactory ) const +{ + ::osl::MutexGuard aGuard( impl_GetOwnStaticMutex() ); + return m_pImpl->GetFactoryStandardTemplate( eFactory ); +} + +OUString SvtModuleOptions::GetFactoryEmptyDocumentURL( EFactory eFactory ) const +{ + ::osl::MutexGuard aGuard( impl_GetOwnStaticMutex() ); + return SvtModuleOptions_Impl::GetFactoryEmptyDocumentURL( eFactory ); +} + +OUString SvtModuleOptions::GetFactoryDefaultFilter( EFactory eFactory ) const +{ + ::osl::MutexGuard aGuard( impl_GetOwnStaticMutex() ); + return m_pImpl->GetFactoryDefaultFilter( eFactory ); +} + +bool SvtModuleOptions::IsDefaultFilterReadonly( EFactory eFactory ) const +{ + ::osl::MutexGuard aGuard( impl_GetOwnStaticMutex() ); + m_pImpl->MakeReadonlyStatesAvailable(); + return m_pImpl->IsDefaultFilterReadonly( eFactory ); +} + +sal_Int32 SvtModuleOptions::GetFactoryIcon( EFactory eFactory ) const +{ + ::osl::MutexGuard aGuard( impl_GetOwnStaticMutex() ); + return m_pImpl->GetFactoryIcon( eFactory ); +} + +bool SvtModuleOptions::ClassifyFactoryByName( const OUString& sName , + EFactory& eFactory ) +{ + // We don't need any mutex here ... because we don't use any member here! + return SvtModuleOptions_Impl::ClassifyFactoryByName( sName, eFactory ); +} + +void SvtModuleOptions::SetFactoryStandardTemplate( EFactory eFactory , + const OUString& sTemplate ) +{ + ::osl::MutexGuard aGuard( impl_GetOwnStaticMutex() ); + m_pImpl->SetFactoryStandardTemplate( eFactory, sTemplate ); +} + +void SvtModuleOptions::SetFactoryDefaultFilter( EFactory eFactory, + const OUString& sFilter ) +{ + ::osl::MutexGuard aGuard( impl_GetOwnStaticMutex() ); + m_pImpl->SetFactoryDefaultFilter( eFactory, sFilter ); +} + +bool SvtModuleOptions::IsMath() const +{ + ::osl::MutexGuard aGuard( impl_GetOwnStaticMutex() ); + return m_pImpl->IsModuleInstalled( EModule::MATH ); +} + +bool SvtModuleOptions::IsChart() const +{ + ::osl::MutexGuard aGuard( impl_GetOwnStaticMutex() ); + return m_pImpl->IsModuleInstalled( EModule::CHART ); +} + +bool SvtModuleOptions::IsCalc() const +{ + ::osl::MutexGuard aGuard( impl_GetOwnStaticMutex() ); + return m_pImpl->IsModuleInstalled( EModule::CALC ); +} + +bool SvtModuleOptions::IsDraw() const +{ + ::osl::MutexGuard aGuard( impl_GetOwnStaticMutex() ); + return m_pImpl->IsModuleInstalled( EModule::DRAW ); +} + +bool SvtModuleOptions::IsWriter() const +{ + ::osl::MutexGuard aGuard( impl_GetOwnStaticMutex() ); + return m_pImpl->IsModuleInstalled( EModule::WRITER ); +} + +bool SvtModuleOptions::IsImpress() const +{ + ::osl::MutexGuard aGuard( impl_GetOwnStaticMutex() ); + return m_pImpl->IsModuleInstalled( EModule::IMPRESS ); +} + +bool SvtModuleOptions::IsDataBase() const +{ + ::osl::MutexGuard aGuard( impl_GetOwnStaticMutex() ); + return m_pImpl->IsModuleInstalled( EModule::DATABASE ); +} + +namespace +{ + class theModuleOptionsMutex : public rtl::Static<osl::Mutex, theModuleOptionsMutex> {}; +} +/*-**************************************************************************************************** + @short return a reference to a static mutex + @descr These class is threadsafe. + We create a static mutex only for one time and use it to protect our refcount and container + member! + @return A reference to a static mutex member. + @threadsafe yes +*//*-*****************************************************************************************************/ +::osl::Mutex& SvtModuleOptions::impl_GetOwnStaticMutex() +{ + return theModuleOptionsMutex::get(); +} + +OUString SvtModuleOptions::GetModuleName( EModule eModule ) const +{ + switch( eModule ) + { + case SvtModuleOptions::EModule::WRITER : { return "Writer"; } + case SvtModuleOptions::EModule::WEB : { return "Web"; } + case SvtModuleOptions::EModule::GLOBAL : { return "Global"; } + case SvtModuleOptions::EModule::CALC : { return "Calc"; } + case SvtModuleOptions::EModule::DRAW : { return "Draw"; } + case SvtModuleOptions::EModule::IMPRESS : { return "Impress"; } + case SvtModuleOptions::EModule::MATH : { return "Math"; } + case SvtModuleOptions::EModule::CHART : { return "Chart"; } + case SvtModuleOptions::EModule::BASIC : { return "Basic"; } + case SvtModuleOptions::EModule::DATABASE : { return "Database"; } + default: + OSL_FAIL( "unknown module" ); + break; + } + + return OUString(); +} + +SvtModuleOptions::EFactory SvtModuleOptions::ClassifyFactoryByShortName(const OUString& sName) +{ + if ( sName == "swriter" ) + return EFactory::WRITER; + if (sName.equalsIgnoreAsciiCase("swriter/Web")) // sometimes they are registered for swriter/web :-( + return EFactory::WRITERWEB; + if (sName.equalsIgnoreAsciiCase("swriter/GlobalDocument")) // sometimes they are registered for swriter/globaldocument :-( + return EFactory::WRITERGLOBAL; + if ( sName == "scalc" ) + return EFactory::CALC; + if ( sName == "sdraw" ) + return EFactory::DRAW; + if ( sName == "simpress" ) + return EFactory::IMPRESS; + if ( sName == "schart" ) + return EFactory::CHART; + if ( sName == "smath" ) + return EFactory::MATH; + if ( sName == "sbasic" ) + return EFactory::BASIC; + if ( sName == "sdatabase" ) + return EFactory::DATABASE; + + return EFactory::UNKNOWN_FACTORY; +} + +SvtModuleOptions::EFactory SvtModuleOptions::ClassifyFactoryByServiceName(const OUString& sName) +{ + if (sName == FACTORYNAME_WRITERGLOBAL) + return EFactory::WRITERGLOBAL; + if (sName == FACTORYNAME_WRITERWEB) + return EFactory::WRITERWEB; + if (sName == FACTORYNAME_WRITER) + return EFactory::WRITER; + if (sName == FACTORYNAME_CALC) + return EFactory::CALC; + if (sName == FACTORYNAME_DRAW) + return EFactory::DRAW; + if (sName == FACTORYNAME_IMPRESS) + return EFactory::IMPRESS; + if (sName == FACTORYNAME_MATH) + return EFactory::MATH; + if (sName == FACTORYNAME_CHART) + return EFactory::CHART; + if (sName == FACTORYNAME_DATABASE) + return EFactory::DATABASE; + if (sName == FACTORYNAME_STARTMODULE) + return EFactory::STARTMODULE; + if (sName == FACTORYNAME_BASIC) + return EFactory::BASIC; + + return EFactory::UNKNOWN_FACTORY; +} + +SvtModuleOptions::EFactory SvtModuleOptions::ClassifyFactoryByURL(const OUString& sURL , + const css::uno::Sequence< css::beans::PropertyValue >& lMediaDescriptor) +{ + css::uno::Reference< css::uno::XComponentContext > xContext = ::comphelper::getProcessComponentContext(); + + css::uno::Reference< css::container::XNameAccess > xFilterCfg; + css::uno::Reference< css::container::XNameAccess > xTypeCfg; + try + { + xFilterCfg.set( + xContext->getServiceManager()->createInstanceWithContext("com.sun.star.document.FilterFactory", xContext), css::uno::UNO_QUERY); + xTypeCfg.set( + xContext->getServiceManager()->createInstanceWithContext("com.sun.star.document.TypeDetection", xContext), css::uno::UNO_QUERY); + } + catch(const css::uno::RuntimeException&) + { throw; } + catch(const css::uno::Exception&) + { return EFactory::UNKNOWN_FACTORY; } + + ::comphelper::SequenceAsHashMap stlDesc(lMediaDescriptor); + + // is there already a filter inside the descriptor? + OUString sFilterName = stlDesc.getUnpackedValueOrDefault("FilterName", OUString()); + if (!sFilterName.isEmpty()) + { + try + { + ::comphelper::SequenceAsHashMap stlFilterProps (xFilterCfg->getByName(sFilterName)); + OUString sDocumentService = stlFilterProps.getUnpackedValueOrDefault("DocumentService", OUString()); + SvtModuleOptions::EFactory eApp = SvtModuleOptions::ClassifyFactoryByServiceName(sDocumentService); + + if (eApp != EFactory::UNKNOWN_FACTORY) + return eApp; + } + catch(const css::uno::RuntimeException&) + { throw; } + catch(const css::uno::Exception&) + { /* do nothing here ... may the following code can help!*/ } + } + + // is there already a type inside the descriptor? + OUString sTypeName = stlDesc.getUnpackedValueOrDefault("TypeName", OUString()); + if (sTypeName.isEmpty()) + { + // no :-( + // start flat detection of URL + css::uno::Reference< css::document::XTypeDetection > xDetect(xTypeCfg, css::uno::UNO_QUERY); + sTypeName = xDetect->queryTypeByURL(sURL); + } + + if (sTypeName.isEmpty()) + return EFactory::UNKNOWN_FACTORY; + + // yes - there is a type info + // Try to find the preferred filter. + try + { + ::comphelper::SequenceAsHashMap stlTypeProps (xTypeCfg->getByName(sTypeName)); + OUString sPreferredFilter = stlTypeProps.getUnpackedValueOrDefault("PreferredFilter", OUString()); + ::comphelper::SequenceAsHashMap stlFilterProps (xFilterCfg->getByName(sPreferredFilter)); + OUString sDocumentService = stlFilterProps.getUnpackedValueOrDefault("DocumentService", OUString()); + SvtModuleOptions::EFactory eApp = SvtModuleOptions::ClassifyFactoryByServiceName(sDocumentService); + + if (eApp != EFactory::UNKNOWN_FACTORY) + return eApp; + } + catch(const css::uno::RuntimeException&) + { throw; } + catch(const css::uno::Exception&) + { /* do nothing here ... may the following code can help!*/ } + + // no filter/no type/no detection result => no fun :-) + return EFactory::UNKNOWN_FACTORY; +} + +SvtModuleOptions::EFactory SvtModuleOptions::ClassifyFactoryByModel(const css::uno::Reference< css::frame::XModel >& xModel) +{ + css::uno::Reference< css::lang::XServiceInfo > xInfo(xModel, css::uno::UNO_QUERY); + if (!xInfo.is()) + return EFactory::UNKNOWN_FACTORY; + + const css::uno::Sequence< OUString > lServices = xInfo->getSupportedServiceNames(); + + for (const OUString& rService : lServices) + { + SvtModuleOptions::EFactory eApp = SvtModuleOptions::ClassifyFactoryByServiceName(rService); + if (eApp != EFactory::UNKNOWN_FACTORY) + return eApp; + } + + return EFactory::UNKNOWN_FACTORY; +} + +css::uno::Sequence < OUString > SvtModuleOptions::GetAllServiceNames() +{ + ::osl::MutexGuard aGuard( impl_GetOwnStaticMutex() ); + return m_pImpl->GetAllServiceNames(); +} + +OUString SvtModuleOptions::GetDefaultModuleName() const +{ + OUString aModule; + if (m_pImpl->IsModuleInstalled(SvtModuleOptions::EModule::WRITER)) + aModule = GetFactoryShortName(SvtModuleOptions::EFactory::WRITER); + else if (m_pImpl->IsModuleInstalled(SvtModuleOptions::EModule::CALC)) + aModule = GetFactoryShortName(SvtModuleOptions::EFactory::CALC); + else if (m_pImpl->IsModuleInstalled(SvtModuleOptions::EModule::IMPRESS)) + aModule = GetFactoryShortName(SvtModuleOptions::EFactory::IMPRESS); + else if (m_pImpl->IsModuleInstalled(SvtModuleOptions::EModule::DATABASE)) + aModule = GetFactoryShortName(SvtModuleOptions::EFactory::DATABASE); + else if (m_pImpl->IsModuleInstalled(SvtModuleOptions::EModule::DRAW)) + aModule = GetFactoryShortName(SvtModuleOptions::EFactory::DRAW); + else if (m_pImpl->IsModuleInstalled(SvtModuleOptions::EModule::WEB)) + aModule = GetFactoryShortName(SvtModuleOptions::EFactory::WRITERWEB); + else if (m_pImpl->IsModuleInstalled(SvtModuleOptions::EModule::GLOBAL)) + aModule = GetFactoryShortName(SvtModuleOptions::EFactory::WRITERGLOBAL); + else if (m_pImpl->IsModuleInstalled(SvtModuleOptions::EModule::MATH)) + aModule = GetFactoryShortName(SvtModuleOptions::EFactory::MATH); + return aModule; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/unotools/source/config/options.cxx b/unotools/source/config/options.cxx new file mode 100644 index 000000000..4da44fa27 --- /dev/null +++ b/unotools/source/config/options.cxx @@ -0,0 +1,114 @@ +/* -*- 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 . + */ + +#include <sal/config.h> +#include <unotools/options.hxx> + +#include <algorithm> + +using utl::detail::Options; +using utl::ConfigurationBroadcaster; + +utl::ConfigurationListener::~ConfigurationListener() {} + +ConfigurationBroadcaster::ConfigurationBroadcaster() +: m_nBroadcastBlocked( 0 ) +, m_nBlockedHint( ConfigurationHints::NONE ) +{ +} + +ConfigurationBroadcaster::ConfigurationBroadcaster(ConfigurationBroadcaster const & rSource) +: mpList( rSource.mpList ? new IMPL_ConfigurationListenerList(*rSource.mpList) : nullptr ) +, m_nBroadcastBlocked( rSource.m_nBroadcastBlocked ) +, m_nBlockedHint( rSource.m_nBlockedHint ) +{ +} + +ConfigurationBroadcaster::~ConfigurationBroadcaster() +{ +} + +ConfigurationBroadcaster & ConfigurationBroadcaster::operator =( + ConfigurationBroadcaster const & other) +{ + if (&other != this) { + mpList.reset( + other.mpList == nullptr ? nullptr : new IMPL_ConfigurationListenerList(*other.mpList)); + m_nBroadcastBlocked = other.m_nBroadcastBlocked; + m_nBlockedHint = other.m_nBlockedHint; + } + return *this; +} + +void ConfigurationBroadcaster::AddListener( utl::ConfigurationListener* pListener ) +{ + if ( !mpList ) + mpList.reset(new IMPL_ConfigurationListenerList); + mpList->push_back( pListener ); +} + +void ConfigurationBroadcaster::RemoveListener( utl::ConfigurationListener const * pListener ) +{ + if ( mpList ) { + auto it = std::find(mpList->begin(), mpList->end(), pListener); + if ( it != mpList->end() ) + mpList->erase( it ); + } +} + +void ConfigurationBroadcaster::NotifyListeners( ConfigurationHints nHint ) +{ + if ( m_nBroadcastBlocked ) + m_nBlockedHint |= nHint; + else + { + nHint |= m_nBlockedHint; + m_nBlockedHint = ConfigurationHints::NONE; + if ( mpList ) { + for ( size_t n = 0; n < mpList->size(); n++ ) + (*mpList)[ n ]->ConfigurationChanged( this, nHint ); + } + } +} + +void ConfigurationBroadcaster::BlockBroadcasts( bool bBlock ) +{ + if ( bBlock ) + ++m_nBroadcastBlocked; + else if ( m_nBroadcastBlocked ) + { + if ( --m_nBroadcastBlocked == 0 ) + NotifyListeners( ConfigurationHints::NONE ); + } +} + +Options::Options() +{ +} + +Options::~Options() +{ +} + +void Options::ConfigurationChanged( ConfigurationBroadcaster*, ConfigurationHints nHint ) +{ + NotifyListeners( nHint ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/unotools/source/config/optionsdlg.cxx b/unotools/source/config/optionsdlg.cxx new file mode 100644 index 000000000..18cd92386 --- /dev/null +++ b/unotools/source/config/optionsdlg.cxx @@ -0,0 +1,236 @@ +/* -*- 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 . + */ + +#include <unotools/optionsdlg.hxx> +#include <unotools/configitem.hxx> +#include <com/sun/star/uno/Any.hxx> +#include <com/sun/star/uno/Sequence.hxx> +#include <osl/mutex.hxx> + +#include "itemholder1.hxx" + +#include <unordered_map> + +using namespace utl; +using namespace com::sun::star::beans; +using namespace com::sun::star::uno; + +#define CFG_FILENAME "Office.OptionsDialog" +#define ROOT_NODE "OptionsDialogGroups" +#define PAGES_NODE "Pages" +#define OPTIONS_NODE "Options" + +static SvtOptionsDlgOptions_Impl* pOptions = nullptr; +static sal_Int32 nRefCount = 0; + +class SvtOptionsDlgOptions_Impl : public utl::ConfigItem +{ +private: + typedef std::unordered_map< OUString, bool > OptionNodeList; + + static constexpr OUStringLiteral g_sPathDelimiter = "/"; + OptionNodeList m_aOptionNodeList; + + enum NodeType{ NT_Group, NT_Page, NT_Option }; + void ReadNode( const OUString& _rNode, NodeType _eType ); + bool IsHidden( const OUString& _rPath ) const; + + virtual void ImplCommit() override; + +public: + SvtOptionsDlgOptions_Impl(); + + virtual void Notify( const css::uno::Sequence< OUString >& aPropertyNames ) override; + + static ::osl::Mutex & getInitMutex(); + + bool IsGroupHidden ( const OUString& _rGroup ) const; + bool IsPageHidden ( const OUString& _rPage, + const OUString& _rGroup ) const; + bool IsOptionHidden ( const OUString& _rOption, + const OUString& _rPage, + const OUString& _rGroup ) const; +}; + +namespace +{ + class theOptionsDlgOptions_ImplMutex : public rtl::Static<osl::Mutex, theOptionsDlgOptions_ImplMutex>{}; +} + +::osl::Mutex & SvtOptionsDlgOptions_Impl::getInitMutex() +{ + return theOptionsDlgOptions_ImplMutex::get(); +} + +SvtOptionsDlgOptions_Impl::SvtOptionsDlgOptions_Impl() + : ConfigItem( CFG_FILENAME ), + m_aOptionNodeList( OptionNodeList() ) +{ + OUString sRootNode( ROOT_NODE ); + const Sequence< OUString > aNodeSeq = GetNodeNames( sRootNode ); + OUString sNode( sRootNode + g_sPathDelimiter ); + for ( const auto& rNode : aNodeSeq ) + { + OUString sSubNode( sNode + rNode ); + ReadNode( sSubNode, NT_Group ); + } +} + +void SvtOptionsDlgOptions_Impl::ImplCommit() +{ + // nothing to commit +} + +void SvtOptionsDlgOptions_Impl::Notify( const Sequence< OUString >& ) +{ + // nothing to notify +} + +void SvtOptionsDlgOptions_Impl::ReadNode( const OUString& _rNode, NodeType _eType ) +{ + OUString sNode( _rNode + g_sPathDelimiter ); + OUString sSet; + sal_Int32 nLen = 0; + switch ( _eType ) + { + case NT_Group : + { + sSet = PAGES_NODE; + nLen = 2; + break; + } + + case NT_Page : + { + sSet = OPTIONS_NODE; + nLen = 2; + break; + } + + case NT_Option : + { + nLen = 1; + break; + } + } + + Sequence< OUString > lResult( nLen ); + lResult[0] = sNode + "Hide"; + if ( _eType != NT_Option ) + lResult[1] = sNode + sSet; + + Sequence< Any > aValues = GetProperties( lResult ); + bool bHide = false; + if ( aValues[0] >>= bHide ) + m_aOptionNodeList.emplace( sNode, bHide ); + + if ( _eType != NT_Option ) + { + OUString sNodes( sNode + sSet ); + const Sequence< OUString > aNodes = GetNodeNames( sNodes ); + for ( const auto& rNode : aNodes ) + { + OUString sSubNodeName( sNodes + g_sPathDelimiter + rNode ); + ReadNode( sSubNodeName, _eType == NT_Group ? NT_Page : NT_Option ); + } + } +} + +static OUString getGroupPath( const OUString& _rGroup ) +{ + return OUString( ROOT_NODE "/" + _rGroup + "/" ); +} +static OUString getPagePath( const OUString& _rPage ) +{ + return OUString( PAGES_NODE "/" + _rPage + "/" ); +} +static OUString getOptionPath( const OUString& _rOption ) +{ + return OUString( OPTIONS_NODE "/" + _rOption + "/" ); +} + +bool SvtOptionsDlgOptions_Impl::IsHidden( const OUString& _rPath ) const +{ + bool bRet = false; + OptionNodeList::const_iterator pIter = m_aOptionNodeList.find( _rPath ); + if ( pIter != m_aOptionNodeList.end() ) + bRet = pIter->second; + return bRet; +} + +bool SvtOptionsDlgOptions_Impl::IsGroupHidden( const OUString& _rGroup ) const +{ + return IsHidden( getGroupPath( _rGroup ) ); +} + +bool SvtOptionsDlgOptions_Impl::IsPageHidden( const OUString& _rPage, const OUString& _rGroup ) const +{ + return IsHidden( getGroupPath( _rGroup ) + getPagePath( _rPage ) ); +} + +bool SvtOptionsDlgOptions_Impl::IsOptionHidden( + const OUString& _rOption, const OUString& _rPage, const OUString& _rGroup ) const +{ + return IsHidden( getGroupPath( _rGroup ) + getPagePath( _rPage ) + getOptionPath( _rOption ) ); +} + +SvtOptionsDialogOptions::SvtOptionsDialogOptions() +{ + // Global access, must be guarded (multithreading) + ::osl::MutexGuard aGuard( SvtOptionsDlgOptions_Impl::getInitMutex() ); + ++nRefCount; + if ( !pOptions ) + { + pOptions = new SvtOptionsDlgOptions_Impl; + + ItemHolder1::holdConfigItem( EItem::OptionsDialogOptions ); + } + m_pImp = pOptions; +} + +SvtOptionsDialogOptions::~SvtOptionsDialogOptions() +{ + // Global access, must be guarded (multithreading) + ::osl::MutexGuard aGuard( SvtOptionsDlgOptions_Impl::getInitMutex() ); + if ( !--nRefCount ) + { + if ( pOptions->IsModified() ) + pOptions->Commit(); + delete pOptions; + pOptions = nullptr; + } +} + +bool SvtOptionsDialogOptions::IsGroupHidden( const OUString& _rGroup ) const +{ + return m_pImp->IsGroupHidden( _rGroup ); +} + +bool SvtOptionsDialogOptions::IsPageHidden( const OUString& _rPage, const OUString& _rGroup ) const +{ + return m_pImp->IsPageHidden( _rPage, _rGroup ); +} + +bool SvtOptionsDialogOptions::IsOptionHidden( + const OUString& _rOption, const OUString& _rPage, const OUString& _rGroup ) const +{ + return m_pImp->IsOptionHidden( _rOption, _rPage, _rGroup ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/unotools/source/config/pathoptions.cxx b/unotools/source/config/pathoptions.cxx new file mode 100644 index 000000000..9d1927042 --- /dev/null +++ b/unotools/source/config/pathoptions.cxx @@ -0,0 +1,850 @@ +/* -*- 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 . + */ + +#include <sal/config.h> + +#include <sal/log.hxx> +#include <unotools/pathoptions.hxx> +#include <tools/diagnose_ex.h> +#include <tools/urlobj.hxx> +#include <com/sun/star/uno/Any.hxx> +#include <com/sun/star/uno/Sequence.hxx> +#include <osl/mutex.hxx> +#include <osl/file.hxx> + +#include <unotools/ucbhelper.hxx> +#include <comphelper/getexpandeduri.hxx> +#include <comphelper/processfactory.hxx> +#include <com/sun/star/beans/XFastPropertySet.hpp> +#include <com/sun/star/beans/XPropertySetInfo.hpp> +#include <com/sun/star/util/thePathSettings.hpp> +#include <com/sun/star/util/PathSubstitution.hpp> +#include <com/sun/star/util/XStringSubstitution.hpp> +#include <com/sun/star/util/theMacroExpander.hpp> +#include <rtl/instance.hxx> + +#include "itemholder1.hxx" + +#include <set> +#include <unordered_map> +#include <vector> + +using namespace osl; +using namespace utl; +using namespace com::sun::star::uno; +using namespace com::sun::star::beans; +using namespace com::sun::star::util; +using namespace com::sun::star::lang; + +#define SEARCHPATH_DELIMITER ';' +#define SIGN_STARTVARIABLE "$(" +#define SIGN_ENDVARIABLE ")" + +// Supported variables by the old SvtPathOptions implementation +#define SUBSTITUTE_INSTPATH "$(instpath)" +#define SUBSTITUTE_PROGPATH "$(progpath)" +#define SUBSTITUTE_USERPATH "$(userpath)" +#define SUBSTITUTE_PATH "$(path)" + +#define STRPOS_NOTFOUND -1 + +typedef std::unordered_map<OUString, sal_Int32> NameToHandleMap; + +typedef std::set<OUString> VarNameSet; + +// class SvtPathOptions_Impl --------------------------------------------- +class SvtPathOptions_Impl +{ + private: + // Local variables to return const references + std::vector< OUString > m_aPathArray; + Reference< XFastPropertySet > m_xPathSettings; + Reference< XStringSubstitution > m_xSubstVariables; + Reference< XMacroExpander > m_xMacroExpander; + mutable std::unordered_map<sal_Int32, sal_Int32> + m_aMapEnumToPropHandle; + VarNameSet m_aSystemPathVarNames; + + OUString m_aEmptyString; + mutable ::osl::Mutex m_aMutex; + + public: + SvtPathOptions_Impl(); + + // get the paths, not const because of using a mutex + const OUString& GetPath( SvtPathOptions::Paths ); + const OUString& GetAddinPath() { return GetPath( SvtPathOptions::PATH_ADDIN ); } + const OUString& GetAutoCorrectPath() { return GetPath( SvtPathOptions::PATH_AUTOCORRECT ); } + const OUString& GetAutoTextPath() { return GetPath( SvtPathOptions::PATH_AUTOTEXT ); } + const OUString& GetBackupPath() { return GetPath( SvtPathOptions::PATH_BACKUP ); } + const OUString& GetBasicPath() { return GetPath( SvtPathOptions::PATH_BASIC ); } + const OUString& GetBitmapPath() { return GetPath( SvtPathOptions::PATH_BITMAP ); } + const OUString& GetConfigPath() { return GetPath( SvtPathOptions::PATH_CONFIG ); } + const OUString& GetDictionaryPath() { return GetPath( SvtPathOptions::PATH_DICTIONARY ); } + const OUString& GetFavoritesPath() { return GetPath( SvtPathOptions::PATH_FAVORITES ); } + const OUString& GetFilterPath() { return GetPath( SvtPathOptions::PATH_FILTER ); } + const OUString& GetGalleryPath() { return GetPath( SvtPathOptions::PATH_GALLERY ); } + const OUString& GetGraphicPath() { return GetPath( SvtPathOptions::PATH_GRAPHIC ); } + const OUString& GetHelpPath() { return GetPath( SvtPathOptions::PATH_HELP ); } + const OUString& GetLinguisticPath() { return GetPath( SvtPathOptions::PATH_LINGUISTIC ); } + const OUString& GetModulePath() { return GetPath( SvtPathOptions::PATH_MODULE ); } + const OUString& GetPalettePath() { return GetPath( SvtPathOptions::PATH_PALETTE ); } + const OUString& GetIconsetPath() { return GetPath( SvtPathOptions::PATH_ICONSET); } + const OUString& GetPluginPath() { return GetPath( SvtPathOptions::PATH_PLUGIN ); } + const OUString& GetStoragePath() { return GetPath( SvtPathOptions::PATH_STORAGE ); } + const OUString& GetTempPath() { return GetPath( SvtPathOptions::PATH_TEMP ); } + const OUString& GetTemplatePath() { return GetPath( SvtPathOptions::PATH_TEMPLATE ); } + const OUString& GetUserConfigPath() { return GetPath( SvtPathOptions::PATH_USERCONFIG ); } + const OUString& GetWorkPath() { return GetPath( SvtPathOptions::PATH_WORK ); } + const OUString& GetUIConfigPath() { return GetPath( SvtPathOptions::PATH_UICONFIG ); } + const OUString& GetFingerprintPath() { return GetPath( SvtPathOptions::PATH_FINGERPRINT ); } + const OUString& GetNumbertextPath() { return GetPath( SvtPathOptions::PATH_NUMBERTEXT ); } + const OUString& GetClassificationPath() { return GetPath( SvtPathOptions::PATH_CLASSIFICATION ); } + + // set the paths + void SetPath( SvtPathOptions::Paths, const OUString& rNewPath ); + void SetAddinPath( const OUString& rPath ) { SetPath( SvtPathOptions::PATH_ADDIN, rPath ); } + void SetAutoCorrectPath( const OUString& rPath ) { SetPath( SvtPathOptions::PATH_AUTOCORRECT, rPath ); } + void SetAutoTextPath( const OUString& rPath ) { SetPath( SvtPathOptions::PATH_AUTOTEXT, rPath ); } + void SetBackupPath( const OUString& rPath ) { SetPath( SvtPathOptions::PATH_BACKUP, rPath ); } + void SetBasicPath( const OUString& rPath ) { SetPath( SvtPathOptions::PATH_BASIC, rPath ); } + void SetBitmapPath( const OUString& rPath ) { SetPath( SvtPathOptions::PATH_BITMAP, rPath ); } + void SetConfigPath( const OUString& rPath ) { SetPath( SvtPathOptions::PATH_CONFIG, rPath ); } + void SetDictionaryPath( const OUString& rPath ) { SetPath( SvtPathOptions::PATH_DICTIONARY, rPath ); } + void SetFavoritesPath( const OUString& rPath ) { SetPath( SvtPathOptions::PATH_FAVORITES, rPath ); } + void SetFilterPath( const OUString& rPath ) { SetPath( SvtPathOptions::PATH_FILTER, rPath ); } + void SetGalleryPath( const OUString& rPath ) { SetPath( SvtPathOptions::PATH_GALLERY, rPath ); } + void SetGraphicPath( const OUString& rPath ) { SetPath( SvtPathOptions::PATH_GRAPHIC, rPath ); } + void SetHelpPath( const OUString& rPath ) { SetPath( SvtPathOptions::PATH_HELP, rPath ); } + void SetLinguisticPath( const OUString& rPath ) { SetPath( SvtPathOptions::PATH_LINGUISTIC, rPath ); } + void SetModulePath( const OUString& rPath ) { SetPath( SvtPathOptions::PATH_MODULE, rPath ); } + void SetPalettePath( const OUString& rPath ) { SetPath( SvtPathOptions::PATH_PALETTE, rPath ); } + void SetPluginPath( const OUString& rPath ) { SetPath( SvtPathOptions::PATH_PLUGIN, rPath ); } + void SetStoragePath( const OUString& rPath ) { SetPath( SvtPathOptions::PATH_STORAGE, rPath ); } + void SetTempPath( const OUString& rPath ) { SetPath( SvtPathOptions::PATH_TEMP, rPath ); } + void SetTemplatePath( const OUString& rPath ) { SetPath( SvtPathOptions::PATH_TEMPLATE, rPath ); } + void SetUserConfigPath( const OUString& rPath ) { SetPath( SvtPathOptions::PATH_USERCONFIG, rPath ); } + void SetWorkPath( const OUString& rPath ) { SetPath( SvtPathOptions::PATH_WORK, rPath ); } + + OUString SubstVar( const OUString& rVar ) const; + OUString ExpandMacros( const OUString& rPath ) const; + OUString UsePathVariables( const OUString& rPath ) const; +}; + +// global ---------------------------------------------------------------- + +static std::weak_ptr<SvtPathOptions_Impl> g_pOptions; + +namespace { + +// functions ------------------------------------------------------------- +struct PropertyStruct +{ + const char* pPropName; // The ascii name of the Office path + SvtPathOptions::Paths ePath; // The enum value used by SvtPathOptions +}; + +struct VarNameAttribute +{ + const char* pVarName; // The name of the path variable +}; + +} + +static const PropertyStruct aPropNames[] = +{ + { "Addin", SvtPathOptions::PATH_ADDIN }, + { "AutoCorrect", SvtPathOptions::PATH_AUTOCORRECT }, + { "AutoText", SvtPathOptions::PATH_AUTOTEXT }, + { "Backup", SvtPathOptions::PATH_BACKUP }, + { "Basic", SvtPathOptions::PATH_BASIC }, + { "Bitmap", SvtPathOptions::PATH_BITMAP }, + { "Config", SvtPathOptions::PATH_CONFIG }, + { "Dictionary", SvtPathOptions::PATH_DICTIONARY }, + { "Favorite", SvtPathOptions::PATH_FAVORITES }, + { "Filter", SvtPathOptions::PATH_FILTER }, + { "Gallery", SvtPathOptions::PATH_GALLERY }, + { "Graphic", SvtPathOptions::PATH_GRAPHIC }, + { "Help", SvtPathOptions::PATH_HELP }, + { "Iconset", SvtPathOptions::PATH_ICONSET }, + { "Linguistic", SvtPathOptions::PATH_LINGUISTIC }, + { "Module", SvtPathOptions::PATH_MODULE }, + { "Palette", SvtPathOptions::PATH_PALETTE }, + { "Plugin", SvtPathOptions::PATH_PLUGIN }, + { "Storage", SvtPathOptions::PATH_STORAGE }, + { "Temp", SvtPathOptions::PATH_TEMP }, + { "Template", SvtPathOptions::PATH_TEMPLATE }, + { "UserConfig", SvtPathOptions::PATH_USERCONFIG }, + { "Work", SvtPathOptions::PATH_WORK }, + { "UIConfig", SvtPathOptions::PATH_UICONFIG }, + { "Fingerprint", SvtPathOptions::PATH_FINGERPRINT }, + { "Numbertext", SvtPathOptions::PATH_NUMBERTEXT }, + { "Classification", SvtPathOptions::PATH_CLASSIFICATION } +}; + +static const VarNameAttribute aVarNameAttribute[] = +{ + { SUBSTITUTE_INSTPATH }, // $(instpath) + { SUBSTITUTE_PROGPATH }, // $(progpath) + { SUBSTITUTE_USERPATH }, // $(userpath) + { SUBSTITUTE_PATH }, // $(path) +}; + +// class SvtPathOptions_Impl --------------------------------------------- + +const OUString& SvtPathOptions_Impl::GetPath( SvtPathOptions::Paths ePath ) +{ + if ( ePath >= SvtPathOptions::PATH_COUNT ) + return m_aEmptyString; + + ::osl::MutexGuard aGuard( m_aMutex ); + + try + { + OUString aPathValue; + OUString aResult; + sal_Int32 nHandle = m_aMapEnumToPropHandle[ static_cast<sal_Int32>(ePath) ]; + + // Substitution is done by the service itself using the substitution service + Any a = m_xPathSettings->getFastPropertyValue( nHandle ); + a >>= aPathValue; + if( ePath == SvtPathOptions::PATH_ADDIN || + ePath == SvtPathOptions::PATH_FILTER || + ePath == SvtPathOptions::PATH_HELP || + ePath == SvtPathOptions::PATH_MODULE || + ePath == SvtPathOptions::PATH_PLUGIN || + ePath == SvtPathOptions::PATH_STORAGE + ) + { + // These office paths have to be converted to system pates + osl::FileBase::getSystemPathFromFileURL( aPathValue, aResult ); + aPathValue = aResult; + } + else if (ePath == SvtPathOptions::PATH_PALETTE || + ePath == SvtPathOptions::PATH_ICONSET) + { + auto ctx = comphelper::getProcessComponentContext(); + OUStringBuffer buf(aPathValue.getLength()*2); + for (sal_Int32 i = 0;;) + { + buf.append( + comphelper::getExpandedUri( + ctx, aPathValue.getToken(0, ';', i))); + if (i == -1) { + break; + } + buf.append(';'); + } + aPathValue = buf.makeStringAndClear(); + } + + m_aPathArray[ ePath ] = aPathValue; + return m_aPathArray[ ePath ]; + } + catch (UnknownPropertyException &) + { + } + + return m_aEmptyString; +} + +void SvtPathOptions_Impl::SetPath( SvtPathOptions::Paths ePath, const OUString& rNewPath ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + + if ( ePath < SvtPathOptions::PATH_COUNT ) + { + OUString aResult; + OUString aNewValue; + Any a; + + switch ( ePath ) + { + case SvtPathOptions::PATH_ADDIN: + case SvtPathOptions::PATH_FILTER: + case SvtPathOptions::PATH_HELP: + case SvtPathOptions::PATH_MODULE: + case SvtPathOptions::PATH_PLUGIN: + case SvtPathOptions::PATH_STORAGE: + { + // These office paths have to be convert back to UCB-URL's + osl::FileBase::getFileURLFromSystemPath( rNewPath, aResult ); + aNewValue = aResult; + } + break; + + default: + aNewValue = rNewPath; + } + + // Resubstitution is done by the service itself using the substitution service + a <<= aNewValue; + try + { + m_xPathSettings->setFastPropertyValue( m_aMapEnumToPropHandle[ static_cast<sal_Int32>(ePath)], a ); + } + catch (const Exception&) + { + TOOLS_WARN_EXCEPTION("unotools.config", "SetPath"); + } + } +} + +OUString SvtPathOptions_Impl::ExpandMacros( const OUString& rPath ) const +{ + OUString sExpanded( rPath ); + + const INetURLObject aParser( rPath ); + if ( aParser.GetProtocol() == INetProtocol::VndSunStarExpand ) + sExpanded = m_xMacroExpander->expandMacros( aParser.GetURLPath( INetURLObject::DecodeMechanism::WithCharset ) ); + + return sExpanded; +} + +OUString SvtPathOptions_Impl::UsePathVariables( const OUString& rPath ) const +{ + return m_xSubstVariables->reSubstituteVariables( rPath ); +} + +OUString SvtPathOptions_Impl::SubstVar( const OUString& rVar ) const +{ + // Don't work at parameter-string directly. Copy it. + OUString aWorkText = rVar; + + // Convert the returned path to system path! + bool bConvertLocal = false; + + // Search for first occurrence of "$(...". + sal_Int32 nPosition = aWorkText.indexOf( SIGN_STARTVARIABLE ); // = first position of "$(" in string + sal_Int32 nLength = 0; // = count of letters from "$(" to ")" in string + + // Have we found any variable like "$(...)"? + if ( nPosition != STRPOS_NOTFOUND ) + { + // Yes; Get length of found variable. + // If no ")" was found - nLength is set to 0 by default! see before. + sal_Int32 nEndPosition = aWorkText.indexOf( SIGN_ENDVARIABLE, nPosition ); + if ( nEndPosition != STRPOS_NOTFOUND ) + nLength = nEndPosition - nPosition + 1; + } + + // Is there another path variable? + while ( ( nPosition != STRPOS_NOTFOUND ) && ( nLength > 0 ) ) + { + // YES; Get the next variable for replace. + OUString aSubString = aWorkText.copy( nPosition, nLength ); + aSubString = aSubString.toAsciiLowerCase(); + + // Look for special variable that needs a system path. + VarNameSet::const_iterator pIter = m_aSystemPathVarNames.find( aSubString ); + if ( pIter != m_aSystemPathVarNames.end() ) + bConvertLocal = true; + + nPosition += nLength; + + // We must control index in string before call something at OUString! + // The OUString-implementation don't do it for us :-( but the result is not defined otherwise. + if ( nPosition + 1 > aWorkText.getLength() ) + { + // Position is out of range. Break loop! + nPosition = STRPOS_NOTFOUND; + nLength = 0; + } + else + { + // Else; Position is valid. Search for next variable. + nPosition = aWorkText.indexOf( SIGN_STARTVARIABLE, nPosition ); + // Have we found any variable like "$(...)"? + if ( nPosition != STRPOS_NOTFOUND ) + { + // Yes; Get length of found variable. If no ")" was found - nLength must set to 0! + nLength = 0; + sal_Int32 nEndPosition = aWorkText.indexOf( SIGN_ENDVARIABLE, nPosition ); + if ( nEndPosition != STRPOS_NOTFOUND ) + nLength = nEndPosition - nPosition + 1; + } + } + } + + aWorkText = m_xSubstVariables->substituteVariables( rVar, false ); + + if ( bConvertLocal ) + { + // Convert the URL to a system path for special path variables + OUString aReturn; + osl::FileBase::getSystemPathFromFileURL( aWorkText, aReturn ); + return aReturn; + } + + return aWorkText; +} + +SvtPathOptions_Impl::SvtPathOptions_Impl() : + m_aPathArray( sal_Int32(SvtPathOptions::PATH_COUNT) ) +{ + Reference< XComponentContext > xContext = comphelper::getProcessComponentContext(); + + // Create necessary services + Reference< XPathSettings > xPathSettings = thePathSettings::get(xContext); + m_xPathSettings.set( xPathSettings, UNO_QUERY_THROW ); + m_xSubstVariables.set( PathSubstitution::create(xContext) ); + m_xMacroExpander = theMacroExpander::get(xContext); + + // Create temporary hash map to have a mapping between property names and property handles + Reference< XPropertySetInfo > xPropSetInfo = xPathSettings->getPropertySetInfo(); + const Sequence< Property > aPathPropSeq = xPropSetInfo->getProperties(); + + NameToHandleMap aTempHashMap; + for ( const css::beans::Property& aProperty : aPathPropSeq ) + { + aTempHashMap.emplace(aProperty.Name, aProperty.Handle); + } + + // Create mapping between internal enum (SvtPathOptions::Paths) and property handle + for ( auto const & p : aPropNames ) + { + NameToHandleMap::const_iterator pIter = + aTempHashMap.find( OUString::createFromAscii( p.pPropName )); + + if ( pIter != aTempHashMap.end() ) + { + sal_Int32 nHandle = pIter->second; + sal_Int32 nEnum = p.ePath; + m_aMapEnumToPropHandle.emplace( nEnum, nHandle ); + } + } + + // Create hash map for path variables that need a system path as a return value! + for ( auto const & i : aVarNameAttribute ) + { + m_aSystemPathVarNames.insert( OUString::createFromAscii( i.pVarName ) ); + } +} + +// class SvtPathOptions -------------------------------------------------- + +namespace { struct lclMutex : public rtl::Static< ::osl::Mutex, lclMutex > {}; } + +SvtPathOptions::SvtPathOptions() +{ + // Global access, must be guarded (multithreading) + ::osl::MutexGuard aGuard( lclMutex::get() ); + pImpl = g_pOptions.lock(); + if ( !pImpl ) + { + pImpl = std::make_shared<SvtPathOptions_Impl>(); + g_pOptions = pImpl; + ItemHolder1::holdConfigItem(EItem::PathOptions); + } +} + +SvtPathOptions::~SvtPathOptions() +{ + // Global access, must be guarded (multithreading) + ::osl::MutexGuard aGuard( lclMutex::get() ); + + pImpl.reset(); +} + +const OUString& SvtPathOptions::GetAddinPath() const +{ + return pImpl->GetAddinPath(); +} + +const OUString& SvtPathOptions::GetAutoCorrectPath() const +{ + return pImpl->GetAutoCorrectPath(); +} + +const OUString& SvtPathOptions::GetAutoTextPath() const +{ + return pImpl->GetAutoTextPath(); +} + +const OUString& SvtPathOptions::GetBackupPath() const +{ + return pImpl->GetBackupPath(); +} + +const OUString& SvtPathOptions::GetBasicPath() const +{ + return pImpl->GetBasicPath(); +} + +const OUString& SvtPathOptions::GetBitmapPath() const +{ + return pImpl->GetBitmapPath(); +} + +const OUString& SvtPathOptions::GetConfigPath() const +{ + return pImpl->GetConfigPath(); +} + +const OUString& SvtPathOptions::GetDictionaryPath() const +{ + return pImpl->GetDictionaryPath(); +} + +const OUString& SvtPathOptions::GetFavoritesPath() const +{ + return pImpl->GetFavoritesPath(); +} + +const OUString& SvtPathOptions::GetFilterPath() const +{ + return pImpl->GetFilterPath(); +} + +const OUString& SvtPathOptions::GetGalleryPath() const +{ + return pImpl->GetGalleryPath(); +} + +const OUString& SvtPathOptions::GetGraphicPath() const +{ + return pImpl->GetGraphicPath(); +} + +const OUString& SvtPathOptions::GetHelpPath() const +{ + return pImpl->GetHelpPath(); +} + +const OUString& SvtPathOptions::GetLinguisticPath() const +{ + return pImpl->GetLinguisticPath(); +} + +const OUString& SvtPathOptions::GetFingerprintPath() const +{ + return pImpl->GetFingerprintPath(); +} + +const OUString& SvtPathOptions::GetNumbertextPath() const +{ + return pImpl->GetNumbertextPath(); +} + +const OUString& SvtPathOptions::GetModulePath() const +{ + return pImpl->GetModulePath(); +} + +const OUString& SvtPathOptions::GetPalettePath() const +{ + return pImpl->GetPalettePath(); +} + +const OUString& SvtPathOptions::GetIconsetPath() const +{ + return pImpl->GetIconsetPath(); +} + +const OUString& SvtPathOptions::GetPluginPath() const +{ + return pImpl->GetPluginPath(); +} + +const OUString& SvtPathOptions::GetStoragePath() const +{ + return pImpl->GetStoragePath(); +} + +const OUString& SvtPathOptions::GetTempPath() const +{ + return pImpl->GetTempPath(); +} + +const OUString& SvtPathOptions::GetTemplatePath() const +{ + return pImpl->GetTemplatePath(); +} + +const OUString& SvtPathOptions::GetUserConfigPath() const +{ + return pImpl->GetUserConfigPath(); +} + +const OUString& SvtPathOptions::GetWorkPath() const +{ + return pImpl->GetWorkPath(); +} + +const OUString& SvtPathOptions::GetClassificationPath() const +{ + return pImpl->GetClassificationPath(); +} + +void SvtPathOptions::SetAddinPath( const OUString& rPath ) +{ + pImpl->SetAddinPath( rPath ); +} + +void SvtPathOptions::SetAutoCorrectPath( const OUString& rPath ) +{ + pImpl->SetAutoCorrectPath( rPath ); +} + +void SvtPathOptions::SetAutoTextPath( const OUString& rPath ) +{ + pImpl->SetAutoTextPath( rPath ); +} + +void SvtPathOptions::SetBackupPath( const OUString& rPath ) +{ + pImpl->SetBackupPath( rPath ); +} + +void SvtPathOptions::SetBasicPath( const OUString& rPath ) +{ + pImpl->SetBasicPath( rPath ); +} + +void SvtPathOptions::SetBitmapPath( const OUString& rPath ) +{ + pImpl->SetBitmapPath( rPath ); +} + +void SvtPathOptions::SetConfigPath( const OUString& rPath ) +{ + pImpl->SetConfigPath( rPath ); +} + +void SvtPathOptions::SetDictionaryPath( const OUString& rPath ) +{ + pImpl->SetDictionaryPath( rPath ); +} + +void SvtPathOptions::SetFavoritesPath( const OUString& rPath ) +{ + pImpl->SetFavoritesPath( rPath ); +} + +void SvtPathOptions::SetFilterPath( const OUString& rPath ) +{ + pImpl->SetFilterPath( rPath ); +} + +void SvtPathOptions::SetGalleryPath( const OUString& rPath ) +{ + pImpl->SetGalleryPath( rPath ); +} + +void SvtPathOptions::SetGraphicPath( const OUString& rPath ) +{ + pImpl->SetGraphicPath( rPath ); +} + +void SvtPathOptions::SetHelpPath( const OUString& rPath ) +{ + pImpl->SetHelpPath( rPath ); +} + +void SvtPathOptions::SetLinguisticPath( const OUString& rPath ) +{ + pImpl->SetLinguisticPath( rPath ); +} + +void SvtPathOptions::SetModulePath( const OUString& rPath ) +{ + pImpl->SetModulePath( rPath ); +} + +void SvtPathOptions::SetPalettePath( const OUString& rPath ) +{ + pImpl->SetPalettePath( rPath ); +} + +void SvtPathOptions::SetPluginPath( const OUString& rPath ) +{ + pImpl->SetPluginPath( rPath ); +} + +void SvtPathOptions::SetStoragePath( const OUString& rPath ) +{ + pImpl->SetStoragePath( rPath ); +} + +void SvtPathOptions::SetTempPath( const OUString& rPath ) +{ + pImpl->SetTempPath( rPath ); +} + +void SvtPathOptions::SetTemplatePath( const OUString& rPath ) +{ + pImpl->SetTemplatePath( rPath ); +} + +void SvtPathOptions::SetUserConfigPath( const OUString& rPath ) +{ + pImpl->SetUserConfigPath( rPath ); +} + +void SvtPathOptions::SetWorkPath( const OUString& rPath ) +{ + pImpl->SetWorkPath( rPath ); +} + +OUString SvtPathOptions::SubstituteVariable( const OUString& rVar ) const +{ + return pImpl->SubstVar( rVar ); +} + +OUString SvtPathOptions::ExpandMacros( const OUString& rPath ) const +{ + return pImpl->ExpandMacros( rPath ); +} + +OUString SvtPathOptions::UseVariable( const OUString& rPath ) const +{ + return pImpl->UsePathVariables( rPath ); +} + +bool SvtPathOptions::SearchFile( OUString& rIniFile, Paths ePath ) +{ + // check parameter: empty inifile name? + if ( rIniFile.isEmpty() ) + { + SAL_WARN( "unotools.config", "SvtPathOptions::SearchFile(): invalid parameter" ); + return false; + } + + OUString aIniFile = pImpl->SubstVar( rIniFile ); + bool bRet = false; + + switch ( ePath ) + { + case PATH_USERCONFIG: + { + // path is a URL + bRet = true; + INetURLObject aObj( GetUserConfigPath() ); + + sal_Int32 nIniIndex = 0; + do + { + OUString aToken = aIniFile.getToken( 0, '/', nIniIndex ); + aObj.insertName(aToken); + } + while ( nIniIndex >= 0 ); + + if ( !::utl::UCBContentHelper::Exists( aObj.GetMainURL( INetURLObject::DecodeMechanism::NONE ) ) ) + { + aObj.SetSmartURL( GetConfigPath() ); + aObj.insertName( aIniFile ); + bRet = ::utl::UCBContentHelper::Exists( aObj.GetMainURL( INetURLObject::DecodeMechanism::NONE ) ); + } + + if ( bRet ) + rIniFile = aObj.GetMainURL( INetURLObject::DecodeMechanism::NONE ); + + break; + } + + default: + { + OUString aPath; + switch ( ePath ) + { + case PATH_ADDIN: aPath = GetAddinPath(); break; + case PATH_AUTOCORRECT: aPath = GetAutoCorrectPath(); break; + case PATH_AUTOTEXT: aPath = GetAutoTextPath(); break; + case PATH_BACKUP: aPath = GetBackupPath(); break; + case PATH_BASIC: aPath = GetBasicPath(); break; + case PATH_BITMAP: aPath = GetBitmapPath(); break; + case PATH_CONFIG: aPath = GetConfigPath(); break; + case PATH_DICTIONARY: aPath = GetDictionaryPath(); break; + case PATH_FAVORITES: aPath = GetFavoritesPath(); break; + case PATH_FILTER: aPath = GetFilterPath(); break; + case PATH_GALLERY: aPath = GetGalleryPath(); break; + case PATH_GRAPHIC: aPath = GetGraphicPath(); break; + case PATH_HELP: aPath = GetHelpPath(); break; + case PATH_LINGUISTIC: aPath = GetLinguisticPath(); break; + case PATH_MODULE: aPath = GetModulePath(); break; + case PATH_PALETTE: aPath = GetPalettePath(); break; + case PATH_ICONSET: aPath = GetIconsetPath(); break; + case PATH_PLUGIN: aPath = GetPluginPath(); break; + case PATH_STORAGE: aPath = GetStoragePath(); break; + case PATH_TEMP: aPath = GetTempPath(); break; + case PATH_TEMPLATE: aPath = GetTemplatePath(); break; + case PATH_WORK: aPath = GetWorkPath(); break; + case PATH_UICONFIG: aPath = pImpl->GetUIConfigPath(); break; + case PATH_FINGERPRINT: aPath = GetFingerprintPath(); break; + case PATH_NUMBERTEXT: aPath = GetNumbertextPath(); break; + case PATH_CLASSIFICATION: aPath = GetClassificationPath(); break; + // coverity[dead_error_begin] - following conditions exist to avoid compiler warning + case PATH_USERCONFIG: + case PATH_COUNT: + break; + } + + sal_Int32 nPathIndex = 0; + do + { + bool bIsURL = true; + OUString aPathToken = aPath.getToken( 0, SEARCHPATH_DELIMITER, nPathIndex ); + INetURLObject aObj( aPathToken ); + if ( aObj.HasError() ) + { + bIsURL = false; + OUString aURL; + if ( osl::FileBase::getFileURLFromSystemPath( aPathToken, aURL ) + == osl::FileBase::E_None ) + aObj.SetURL( aURL ); + } + if ( aObj.GetProtocol() == INetProtocol::VndSunStarExpand ) + { + Reference< XMacroExpander > xMacroExpander = theMacroExpander::get( ::comphelper::getProcessComponentContext() ); + const OUString sExpandedPath = xMacroExpander->expandMacros( aObj.GetURLPath( INetURLObject::DecodeMechanism::WithCharset ) ); + aObj.SetURL( sExpandedPath ); + } + + sal_Int32 nIniIndex = 0; + do + { + OUString aToken = aIniFile.getToken( 0, '/', nIniIndex ); + aObj.insertName(aToken); + } + while ( nIniIndex >= 0 ); + + bRet = ::utl::UCBContentHelper::Exists( aObj.GetMainURL( INetURLObject::DecodeMechanism::NONE ) ); + + if ( bRet ) + { + if ( !bIsURL ) + { + OUString sTmp; + osl::FileBase::getSystemPathFromFileURL( + aObj.GetMainURL( INetURLObject::DecodeMechanism::NONE ), sTmp ); + rIniFile = sTmp; + } + else + rIniFile = aObj.GetMainURL( INetURLObject::DecodeMechanism::NONE ); + break; + } + } + while ( nPathIndex >= 0 ); + } + } + + return bRet; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/unotools/source/config/printwarningoptions.cxx b/unotools/source/config/printwarningoptions.cxx new file mode 100644 index 000000000..c2409dab3 --- /dev/null +++ b/unotools/source/config/printwarningoptions.cxx @@ -0,0 +1,319 @@ +/* -*- 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 . + */ + +#include <unotools/printwarningoptions.hxx> +#include <unotools/configitem.hxx> +#include <tools/debug.hxx> +#include <com/sun/star/uno/Any.hxx> +#include <com/sun/star/uno/Sequence.hxx> + +#include "itemholder1.hxx" + +// namespaces + +using namespace ::utl; +using namespace ::osl; +using namespace ::com::sun::star::uno; + +#define ROOTNODE_START "Office.Common/Print" + +#define PROPERTYNAME_PAPERSIZE OUString("Warning/PaperSize") +#define PROPERTYNAME_PAPERORIENTATION OUString("Warning/PaperOrientation") +#define PROPERTYNAME_NOTFOUND OUString("Warning/NotFound") +#define PROPERTYNAME_TRANSPARENCY OUString("Warning/Transparency") +#define PROPERTYNAME_PRINTINGMODIFIESDOCUMENT OUString("PrintingModifiesDocument") + +#define PROPERTYHANDLE_PAPERSIZE 0 +#define PROPERTYHANDLE_PAPERORIENTATION 1 +#define PROPERTYHANDLE_NOTFOUND 2 +#define PROPERTYHANDLE_TRANSPARENCY 3 +#define PROPERTYHDL_PRINTINGMODIFIESDOCUMENT 4 + +#define PROPERTYCOUNT 5 + +class SvtPrintWarningOptions_Impl : public ConfigItem +{ +public: + +// constructor / destructor + + SvtPrintWarningOptions_Impl(); + virtual ~SvtPrintWarningOptions_Impl() override; + +// override methods of baseclass + + virtual void Notify( const css::uno::Sequence< OUString >& aPropertyNames ) override; + +// public interface + + bool IsPaperSize() const { return m_bPaperSize; } + bool IsPaperOrientation() const { return m_bPaperOrientation; } + bool IsTransparency() const { return m_bTransparency; } + bool IsModifyDocumentOnPrintingAllowed() const { return m_bModifyDocumentOnPrintingAllowed; } + + void SetPaperSize( bool bState ) { m_bPaperSize = bState; SetModified(); } + void SetPaperOrientation( bool bState ) { m_bPaperOrientation = bState; SetModified(); } + void SetTransparency( bool bState ) { m_bTransparency = bState; SetModified(); } + void SetModifyDocumentOnPrintingAllowed( bool bState ) { m_bModifyDocumentOnPrintingAllowed = bState; SetModified(); } + +// private methods + +private: + + virtual void ImplCommit() override; + + static Sequence< OUString > impl_GetPropertyNames(); + +// private member + +private: + + bool m_bPaperSize; + bool m_bPaperOrientation; + bool m_bNotFound; + bool m_bTransparency; + bool m_bModifyDocumentOnPrintingAllowed; +}; + +// constructor + +SvtPrintWarningOptions_Impl::SvtPrintWarningOptions_Impl() : + ConfigItem( ROOTNODE_START ), + m_bPaperSize( false ), + m_bPaperOrientation( false ), + m_bNotFound( false ), + m_bTransparency( true ), + m_bModifyDocumentOnPrintingAllowed( true ) +{ + Sequence< OUString > seqNames( impl_GetPropertyNames() ); + Sequence< Any > seqValues( GetProperties( seqNames ) ); + + DBG_ASSERT( !(seqNames.getLength()!=seqValues.getLength()), "SvtPrintWarningOptions_Impl::SvtPrintWarningOptions_Impl()\nI miss some values of configuration keys!\n" ); + + // Copy values from list in right order to our internal member. + sal_Int32 nPropertyCount = seqValues.getLength(); + sal_Int32 nProperty = 0; + + for( nProperty=0; nProperty<nPropertyCount; ++nProperty ) + { + DBG_ASSERT( seqValues[nProperty].hasValue(), "SvtPrintWarningOptions_Impl::SvtPrintWarningOptions_Impl()\nInvalid property value for property detected!\n" ); + + switch( nProperty ) + { + case PROPERTYHANDLE_PAPERSIZE: + { + DBG_ASSERT(!(seqValues[nProperty].getValueTypeClass()!=TypeClass_BOOLEAN), "Invalid type" ); + seqValues[nProperty] >>= m_bPaperSize; + } + break; + + case PROPERTYHANDLE_PAPERORIENTATION: + { + DBG_ASSERT(!(seqValues[nProperty].getValueTypeClass()!=TypeClass_BOOLEAN), "Invalid type" ); + seqValues[nProperty] >>= m_bPaperOrientation; + } + break; + + case PROPERTYHANDLE_NOTFOUND: + { + DBG_ASSERT(!(seqValues[nProperty].getValueTypeClass()!=TypeClass_BOOLEAN), "Invalid type" ); + seqValues[nProperty] >>= m_bNotFound; + } + break; + + case PROPERTYHANDLE_TRANSPARENCY: + { + DBG_ASSERT(!(seqValues[nProperty].getValueTypeClass()!=TypeClass_BOOLEAN), "Invalid type" ); + seqValues[nProperty] >>= m_bTransparency; + } + break; + case PROPERTYHDL_PRINTINGMODIFIESDOCUMENT: + { + DBG_ASSERT(!(seqValues[nProperty].getValueTypeClass()!=TypeClass_BOOLEAN), "Invalid type" ); + seqValues[nProperty] >>= m_bModifyDocumentOnPrintingAllowed; + } + break; + + } + } +} + +// destructor + +SvtPrintWarningOptions_Impl::~SvtPrintWarningOptions_Impl() +{ + assert(!IsModified()); // should have been committed +} + +// Commit + +void SvtPrintWarningOptions_Impl::ImplCommit() +{ + Sequence< OUString > aSeqNames( impl_GetPropertyNames() ); + Sequence< Any > aSeqValues( aSeqNames.getLength() ); + + for( sal_Int32 nProperty = 0, nCount = aSeqNames.getLength(); nProperty < nCount; ++nProperty ) + { + switch( nProperty ) + { + case PROPERTYHANDLE_PAPERSIZE: + aSeqValues[nProperty] <<= m_bPaperSize; + break; + + case PROPERTYHANDLE_PAPERORIENTATION: + aSeqValues[nProperty] <<= m_bPaperOrientation; + break; + + case PROPERTYHANDLE_NOTFOUND: + aSeqValues[nProperty] <<= m_bNotFound; + break; + + case PROPERTYHANDLE_TRANSPARENCY: + aSeqValues[nProperty] <<= m_bTransparency; + break; + case PROPERTYHDL_PRINTINGMODIFIESDOCUMENT: + aSeqValues[nProperty] <<= m_bModifyDocumentOnPrintingAllowed; + break; + } + } + + PutProperties( aSeqNames, aSeqValues ); +} + +void SvtPrintWarningOptions_Impl::Notify( const Sequence< OUString >& ) +{ +} + +// private method + +Sequence< OUString > SvtPrintWarningOptions_Impl::impl_GetPropertyNames() +{ + // Build list of configuration key names. + const OUString pProperties[] = + { + PROPERTYNAME_PAPERSIZE, + PROPERTYNAME_PAPERORIENTATION, + PROPERTYNAME_NOTFOUND, + PROPERTYNAME_TRANSPARENCY, + PROPERTYNAME_PRINTINGMODIFIESDOCUMENT + }; + + // Initialize return sequence with these list ... + const Sequence< OUString > seqPropertyNames( pProperties, PROPERTYCOUNT ); + + return seqPropertyNames; +} + +static std::weak_ptr<SvtPrintWarningOptions_Impl> g_pPrintWarningOptions; + +SvtPrintWarningOptions::SvtPrintWarningOptions() +{ + // Global access, must be guarded (multithreading!). + MutexGuard aGuard( GetOwnStaticMutex() ); + + m_pImpl = g_pPrintWarningOptions.lock(); + if( !m_pImpl ) + { + m_pImpl = std::make_shared<SvtPrintWarningOptions_Impl>(); + g_pPrintWarningOptions = m_pImpl; + ItemHolder1::holdConfigItem(EItem::PrintWarningOptions); + } +} + +SvtPrintWarningOptions::~SvtPrintWarningOptions() +{ + // Global access, must be guarded (multithreading!) + MutexGuard aGuard( GetOwnStaticMutex() ); + + m_pImpl.reset(); +} + +// public method + +bool SvtPrintWarningOptions::IsPaperSize() const +{ + MutexGuard aGuard( GetOwnStaticMutex() ); + return m_pImpl->IsPaperSize(); +} + +// public method + +bool SvtPrintWarningOptions::IsPaperOrientation() const +{ + MutexGuard aGuard( GetOwnStaticMutex() ); + return m_pImpl->IsPaperOrientation(); +} + +// public method + +bool SvtPrintWarningOptions::IsTransparency() const +{ + MutexGuard aGuard( GetOwnStaticMutex() ); + return m_pImpl->IsTransparency(); +} + +// public method + +void SvtPrintWarningOptions::SetPaperSize( bool bState ) +{ + MutexGuard aGuard( GetOwnStaticMutex() ); + m_pImpl->SetPaperSize( bState ); +} + +// public method + +void SvtPrintWarningOptions::SetPaperOrientation( bool bState ) +{ + MutexGuard aGuard( GetOwnStaticMutex() ); + m_pImpl->SetPaperOrientation( bState ); +} + +// public method + +void SvtPrintWarningOptions::SetTransparency( bool bState ) +{ + MutexGuard aGuard( GetOwnStaticMutex() ); + m_pImpl->SetTransparency( bState ); +} + +bool SvtPrintWarningOptions::IsModifyDocumentOnPrintingAllowed() const +{ + MutexGuard aGuard( GetOwnStaticMutex() ); + return m_pImpl->IsModifyDocumentOnPrintingAllowed(); +} + +void SvtPrintWarningOptions::SetModifyDocumentOnPrintingAllowed( bool bState ) +{ + MutexGuard aGuard( GetOwnStaticMutex() ); + m_pImpl->SetModifyDocumentOnPrintingAllowed( bState ); +} + +namespace +{ + class thePrintWarningOptionsMutex : public rtl::Static<osl::Mutex, thePrintWarningOptionsMutex>{}; +} + +// private method + +Mutex& SvtPrintWarningOptions::GetOwnStaticMutex() +{ + return thePrintWarningOptionsMutex::get(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/unotools/source/config/saveopt.cxx b/unotools/source/config/saveopt.cxx new file mode 100644 index 000000000..d8f4d37dd --- /dev/null +++ b/unotools/source/config/saveopt.cxx @@ -0,0 +1,971 @@ +/* -*- 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 . + */ + +#include <sal/config.h> + +#include <sal/log.hxx> +#include <unotools/saveopt.hxx> +#include <rtl/instance.hxx> +#include <unotools/configmgr.hxx> +#include <unotools/configitem.hxx> +#include <tools/debug.hxx> +#include <com/sun/star/uno/Any.hxx> +#include <com/sun/star/uno/Sequence.hxx> + +#include <osl/diagnose.h> +#include <osl/mutex.hxx> +#include <officecfg/Office/Recovery.hxx> + +using namespace utl; +using namespace com::sun::star::uno; + +namespace { + +class SvtSaveOptions_Impl; +class SvtLoadOptions_Impl; + +} + +#define CFG_READONLY_DEFAULT false + +struct SvtLoadSaveOptions_Impl +{ + std::unique_ptr<SvtSaveOptions_Impl> pSaveOpt; + std::unique_ptr<SvtLoadOptions_Impl> pLoadOpt; +}; + +static std::unique_ptr<SvtLoadSaveOptions_Impl> pOptions; +static sal_Int32 nRefCount = 0; + +namespace { + +class SvtSaveOptions_Impl : public utl::ConfigItem +{ + sal_Int32 nAutoSaveTime; + bool bUseUserData, + bBackup, + bAutoSave, + bAutoSavePrompt, + bUserAutoSave, + bDocInfSave, + bSaveWorkingSet, + bSaveDocView, + bSaveRelINet, + bSaveRelFSys, + bDoPrettyPrinting, + bWarnAlienFormat, + bLoadDocPrinter; + + SvtSaveOptions::ODFDefaultVersion eODFDefaultVersion; + + bool bROAutoSaveTime, + bROUseUserData, + bROBackup, + bROAutoSave, + bROAutoSavePrompt, + bROUserAutoSave, + bRODocInfSave, + bROSaveWorkingSet, + bROSaveDocView, + bROSaveRelINet, + bROSaveRelFSys, + bROWarnAlienFormat, + bRODoPrettyPrinting, + bROLoadDocPrinter, + bROODFDefaultVersion; + + virtual void ImplCommit() override; + +public: + SvtSaveOptions_Impl(); + + virtual void Notify( const css::uno::Sequence< OUString >& aPropertyNames ) override; + + sal_Int32 GetAutoSaveTime() const { return nAutoSaveTime; } + bool IsUseUserData() const { return bUseUserData; } + bool IsBackup() const { return bBackup; } + bool IsAutoSave() const { return bAutoSave; } + bool IsAutoSavePrompt() const { return bAutoSavePrompt; } + bool IsUserAutoSave() const { return bUserAutoSave; } + bool IsDocInfoSave() const { return bDocInfSave; } + bool IsSaveWorkingSet() const { return bSaveWorkingSet; } + bool IsSaveDocView() const { return bSaveDocView; } + bool IsSaveRelINet() const { return bSaveRelINet; } + bool IsSaveRelFSys() const { return bSaveRelFSys; } + bool IsPrettyPrintingEnabled( ) const { return bDoPrettyPrinting; } + bool IsWarnAlienFormat() const { return bWarnAlienFormat; } + bool IsLoadDocPrinter() const { return bLoadDocPrinter; } + + SvtSaveOptions::ODFDefaultVersion + GetODFDefaultVersion() const { return eODFDefaultVersion; } + + void SetAutoSaveTime( sal_Int32 n ); + void SetUseUserData( bool b ); + void SetBackup( bool b ); + void SetAutoSave( bool b ); + void SetAutoSavePrompt( bool b ); + void SetUserAutoSave( bool b ); + void SetDocInfoSave( bool b ); + void SetSaveWorkingSet( bool b ); + void SetSaveDocView( bool b ); + void SetSaveRelINet( bool b ); + void SetSaveRelFSys( bool b ); + void EnablePrettyPrinting( bool _bDoPP ); + void SetWarnAlienFormat( bool _bDoPP ); + void SetLoadDocPrinter( bool bNew ); + void SetODFDefaultVersion( SvtSaveOptions::ODFDefaultVersion eNew ); + + bool IsReadOnly( SvtSaveOptions::EOption eOption ) const; +}; + +} + +void SvtSaveOptions_Impl::SetAutoSaveTime( sal_Int32 n ) +{ + if (!bROAutoSaveTime && nAutoSaveTime!=n) + { + nAutoSaveTime = n; + SetModified(); + Commit(); + } +} + +void SvtSaveOptions_Impl::SetUseUserData( bool b ) +{ + if (!bROUseUserData && bUseUserData!=b) + { + bUseUserData = b; + SetModified(); + } +} + +void SvtSaveOptions_Impl::SetBackup( bool b ) +{ + if (!bROBackup && bBackup!=b) + { + bBackup = b; + SetModified(); + } +} + +void SvtSaveOptions_Impl::SetAutoSave( bool b ) +{ + if (!bROAutoSave && bAutoSave!=b) + { + bAutoSave = b; + SetModified(); + Commit(); + } +} + +void SvtSaveOptions_Impl::SetAutoSavePrompt( bool b ) +{ + if (!bROAutoSavePrompt && bAutoSavePrompt!=b) + { + bAutoSavePrompt = b; + SetModified(); + } +} + +void SvtSaveOptions_Impl::SetUserAutoSave( bool b ) +{ + if (!bROUserAutoSave && bUserAutoSave!=b) + { + bUserAutoSave = b; + SetModified(); + Commit(); + } +} + +void SvtSaveOptions_Impl::SetDocInfoSave(bool b) +{ + if (!bRODocInfSave && bDocInfSave!=b) + { + bDocInfSave = b; + SetModified(); + } +} + +void SvtSaveOptions_Impl::SetSaveWorkingSet( bool b ) +{ + if (!bROSaveWorkingSet && bSaveWorkingSet!=b) + { + bSaveWorkingSet = b; + SetModified(); + } +} + +void SvtSaveOptions_Impl::SetSaveDocView( bool b ) +{ + if (!bROSaveDocView && bSaveDocView!=b) + { + bSaveDocView = b; + SetModified(); + } +} + +void SvtSaveOptions_Impl::SetSaveRelINet( bool b ) +{ + if (!bROSaveRelINet && bSaveRelINet!=b) + { + bSaveRelINet = b; + SetModified(); + } +} + +void SvtSaveOptions_Impl::SetSaveRelFSys( bool b ) +{ + if (!bROSaveRelFSys && bSaveRelFSys!=b) + { + bSaveRelFSys = b; + SetModified(); + } +} + +void SvtSaveOptions_Impl::EnablePrettyPrinting( bool _bDoPP ) +{ + if (!bRODoPrettyPrinting && bDoPrettyPrinting!=_bDoPP) + { + bDoPrettyPrinting = _bDoPP; + SetModified(); + } +} + +void SvtSaveOptions_Impl::SetWarnAlienFormat( bool _bDoPP ) +{ + if (!bROWarnAlienFormat && bWarnAlienFormat!=_bDoPP) + { + bWarnAlienFormat = _bDoPP; + SetModified(); + } +} + +void SvtSaveOptions_Impl::SetLoadDocPrinter( bool bNew ) +{ + if ( !bROLoadDocPrinter && bLoadDocPrinter != bNew ) + { + bLoadDocPrinter = bNew; + SetModified(); + } +} + +void SvtSaveOptions_Impl::SetODFDefaultVersion( SvtSaveOptions::ODFDefaultVersion eNew ) +{ + if ( !bROODFDefaultVersion && eODFDefaultVersion != eNew ) + { + eODFDefaultVersion = eNew; + SetModified(); + } +} + +bool SvtSaveOptions_Impl::IsReadOnly( SvtSaveOptions::EOption eOption ) const +{ + bool bReadOnly = CFG_READONLY_DEFAULT; + switch(eOption) + { + case SvtSaveOptions::EOption::AutoSaveTime : + bReadOnly = bROAutoSaveTime; + break; + case SvtSaveOptions::EOption::UseUserData : + bReadOnly = bROUseUserData; + break; + case SvtSaveOptions::EOption::Backup : + bReadOnly = bROBackup; + break; + case SvtSaveOptions::EOption::AutoSave : + bReadOnly = bROAutoSave; + break; + case SvtSaveOptions::EOption::AutoSavePrompt : + bReadOnly = bROAutoSavePrompt; + break; + case SvtSaveOptions::EOption::UserAutoSave : + bReadOnly = bROUserAutoSave; + break; + case SvtSaveOptions::EOption::DocInfSave : + bReadOnly = bRODocInfSave; + break; + case SvtSaveOptions::EOption::SaveWorkingSet : + bReadOnly = bROSaveWorkingSet; + break; + case SvtSaveOptions::EOption::SaveDocView : + bReadOnly = bROSaveDocView; + break; + case SvtSaveOptions::EOption::SaveRelInet : + bReadOnly = bROSaveRelINet; + break; + case SvtSaveOptions::EOption::SaveRelFsys : + bReadOnly = bROSaveRelFSys; + break; + case SvtSaveOptions::EOption::DoPrettyPrinting : + bReadOnly = bRODoPrettyPrinting; + break; + case SvtSaveOptions::EOption::WarnAlienFormat : + bReadOnly = bROWarnAlienFormat; + break; + case SvtSaveOptions::EOption::LoadDocPrinter : + bReadOnly = bROLoadDocPrinter; + break; + case SvtSaveOptions::EOption::OdfDefaultVersion : + bReadOnly = bROODFDefaultVersion; + break; + } + return bReadOnly; +} + +#define FORMAT 0 +#define TIMEINTERVALL 1 +#define USEUSERDATA 2 +#define CREATEBACKUP 3 +#define AUTOSAVE 4 +#define PROMPT 5 +#define EDITPROPERTY 6 +#define SAVEVIEWINFO 7 +#define PRETTYPRINTING 8 +#define WARNALIENFORMAT 9 +#define LOADDOCPRINTER 10 +#define FILESYSTEM 11 +#define INTERNET 12 +#define SAVEWORKINGSET 13 +#define ODFDEFAULTVERSION 14 + +static Sequence< OUString > GetPropertyNames() +{ + static const char* aPropNames[] = + { + "Graphic/Format", + "Document/AutoSaveTimeIntervall", + "Document/UseUserData", + "Document/CreateBackup", + "Document/AutoSave", + "Document/AutoSavePrompt", + "Document/EditProperty", + "Document/ViewInfo", + "Document/PrettyPrinting", + "Document/WarnAlienFormat", + "Document/LoadPrinter", + "URL/FileSystem", + "URL/Internet", + "WorkingSet", + "ODF/DefaultVersion" + }; + + const int nCount = SAL_N_ELEMENTS( aPropNames ); + Sequence< OUString > aNames( nCount ); + OUString* pNames = aNames.getArray(); + for ( int i = 0; i < nCount; i++ ) + pNames[i] = OUString::createFromAscii( aPropNames[i] ); + + return aNames; +} + +SvtSaveOptions_Impl::SvtSaveOptions_Impl() + : ConfigItem( "Office.Common/Save" ) + , nAutoSaveTime( 0 ) + , bUseUserData( false ) + , bBackup( false ) + , bAutoSave( false ) + , bAutoSavePrompt( false ) + , bUserAutoSave( false ) + , bDocInfSave( false ) + , bSaveWorkingSet( false ) + , bSaveDocView( false ) + , bSaveRelINet( false ) + , bSaveRelFSys( false ) + , bDoPrettyPrinting( false ) + , bWarnAlienFormat( true ) + , bLoadDocPrinter( true ) + , eODFDefaultVersion( SvtSaveOptions::ODFVER_LATEST ) + , bROAutoSaveTime( CFG_READONLY_DEFAULT ) + , bROUseUserData( CFG_READONLY_DEFAULT ) + , bROBackup( CFG_READONLY_DEFAULT ) + , bROAutoSave( CFG_READONLY_DEFAULT ) + , bROAutoSavePrompt( CFG_READONLY_DEFAULT ) + , bROUserAutoSave( CFG_READONLY_DEFAULT ) + , bRODocInfSave( CFG_READONLY_DEFAULT ) + , bROSaveWorkingSet( CFG_READONLY_DEFAULT ) + , bROSaveDocView( CFG_READONLY_DEFAULT ) + , bROSaveRelINet( CFG_READONLY_DEFAULT ) + , bROSaveRelFSys( CFG_READONLY_DEFAULT ) + , bROWarnAlienFormat( CFG_READONLY_DEFAULT ) + , bRODoPrettyPrinting( CFG_READONLY_DEFAULT ) + , bROLoadDocPrinter( CFG_READONLY_DEFAULT ) + , bROODFDefaultVersion( CFG_READONLY_DEFAULT ) +{ + Sequence< OUString > aNames = GetPropertyNames(); + Sequence< Any > aValues = GetProperties( aNames ); + Sequence< sal_Bool > aROStates = GetReadOnlyStates( aNames ); + EnableNotification( aNames ); + const Any* pValues = aValues.getConstArray(); + const sal_Bool* pROStates = aROStates.getConstArray(); + DBG_ASSERT( aValues.getLength() == aNames.getLength(), "GetProperties failed" ); + DBG_ASSERT( aROStates.getLength() == aNames.getLength(), "GetReadOnlyStates failed" ); + if ( aValues.getLength() == aNames.getLength() && aROStates.getLength() == aNames.getLength() ) + { + for ( int nProp = 0; nProp < aNames.getLength(); nProp++ ) + { + if ( pValues[nProp].hasValue() ) + { + sal_Int32 nTemp = 0; + switch ( nProp ) + { + case FORMAT: + // not supported anymore + break; + + case TIMEINTERVALL : + if ( pValues[nProp] >>= nTemp ) + nAutoSaveTime = nTemp; + else { + OSL_FAIL( "Wrong Type!" ); + }; + bROAutoSaveTime = pROStates[nProp]; + break; + + case ODFDEFAULTVERSION : + { + sal_Int16 nTmp = 0; + if ( pValues[nProp] >>= nTmp ) + { + if( nTmp == 3 ) + eODFDefaultVersion = SvtSaveOptions::ODFVER_LATEST; + else + eODFDefaultVersion = SvtSaveOptions::ODFDefaultVersion( nTmp ); + } + else { + SAL_WARN( "unotools.config", "SvtSaveOptions_Impl::SvtSaveOptions_Impl(): Wrong Type!" ); + }; + bROODFDefaultVersion = pROStates[nProp]; + break; + } + + default: + { + bool bTemp = bool(); + if ( pValues[nProp] >>= bTemp ) + { + switch ( nProp ) + { + case USEUSERDATA : + bUseUserData = bTemp; + bROUseUserData = pROStates[nProp]; + break; + case CREATEBACKUP : + bBackup = bTemp; + bROBackup = pROStates[nProp]; + break; + case AUTOSAVE : + bAutoSave = bTemp; + bROAutoSave = pROStates[nProp]; + break; + case PROMPT : + bAutoSavePrompt = bTemp; + bROAutoSavePrompt = pROStates[nProp]; + break; + case EDITPROPERTY : + bDocInfSave = bTemp; + bRODocInfSave = pROStates[nProp]; + break; + case SAVEWORKINGSET : + bSaveWorkingSet = bTemp; + bROSaveWorkingSet = pROStates[nProp]; + break; + case SAVEVIEWINFO : + bSaveDocView = bTemp; + bROSaveDocView = pROStates[nProp]; + break; + case FILESYSTEM : + bSaveRelFSys = bTemp; + bROSaveRelFSys = pROStates[nProp]; + break; + case INTERNET : + bSaveRelINet = bTemp; + bROSaveRelINet = pROStates[nProp]; + break; + + case PRETTYPRINTING: + bDoPrettyPrinting = bTemp; + bRODoPrettyPrinting = pROStates[nProp]; + break; + + case WARNALIENFORMAT: + bWarnAlienFormat = bTemp; + bROWarnAlienFormat = pROStates[nProp]; + break; + + case LOADDOCPRINTER: + bLoadDocPrinter = bTemp; + bROLoadDocPrinter = pROStates[nProp]; + break; + + default : + SAL_WARN( "unotools.config", "invalid index to load a path" ); + } + } + else + { + OSL_FAIL( "Wrong Type!" ); + } + } + } + } + } + } + + if (!utl::ConfigManager::IsFuzzing()) + { + bAutoSave = officecfg::Office::Recovery::AutoSave::Enabled::get(); + nAutoSaveTime = officecfg::Office::Recovery::AutoSave::TimeIntervall::get(); + bUserAutoSave = officecfg::Office::Recovery::AutoSave::UserAutoSaveEnabled::get(); + } + else + { + bAutoSave = false; + nAutoSaveTime = 0; + bUserAutoSave = false; + } +} + +void SvtSaveOptions_Impl::ImplCommit() +{ + Sequence< OUString > aOrgNames = GetPropertyNames(); + OUString* pOrgNames = aOrgNames.getArray(); + sal_Int32 nOrgCount = aOrgNames.getLength(); + + Sequence< OUString > aNames( nOrgCount ); + Sequence< Any > aValues( nOrgCount ); + OUString* pNames = aNames.getArray(); + Any* pValues = aValues.getArray(); + sal_Int32 nRealCount = 0; + + for (sal_Int32 i=0; i<nOrgCount; ++i) + { + switch (i) + { + case FORMAT: + // not supported anymore + break; + case TIMEINTERVALL : + if (!bROAutoSaveTime) + { + pValues[nRealCount] <<= nAutoSaveTime; + pNames[nRealCount] = pOrgNames[i]; + ++nRealCount; + } + break; + case USEUSERDATA : + if (!bROUseUserData) + { + pValues[nRealCount] <<= bUseUserData; + pNames[nRealCount] = pOrgNames[i]; + ++nRealCount; + } + break; + case CREATEBACKUP : + if (!bROBackup) + { + pValues[nRealCount] <<= bBackup; + pNames[nRealCount] = pOrgNames[i]; + ++nRealCount; + } + break; + case AUTOSAVE : + if (!bROAutoSave) + { + pValues[nRealCount] <<= bAutoSave; + pNames[nRealCount] = pOrgNames[i]; + ++nRealCount; + } + break; + case PROMPT : + if (!bROAutoSavePrompt) + { + pValues[nRealCount] <<= bAutoSavePrompt; + pNames[nRealCount] = pOrgNames[i]; + ++nRealCount; + } + break; + case EDITPROPERTY : + if (!bRODocInfSave) + { + pValues[nRealCount] <<= bDocInfSave; + pNames[nRealCount] = pOrgNames[i]; + ++nRealCount; + } + break; + case SAVEWORKINGSET : + if (!bROSaveWorkingSet) + { + pValues[nRealCount] <<= bSaveWorkingSet; + pNames[nRealCount] = pOrgNames[i]; + ++nRealCount; + } + break; + case SAVEVIEWINFO : + if (!bROSaveDocView) + { + pValues[nRealCount] <<= bSaveDocView; + pNames[nRealCount] = pOrgNames[i]; + ++nRealCount; + } + break; + case FILESYSTEM : + if (!bROSaveRelFSys) + { + pValues[nRealCount] <<= bSaveRelFSys; + pNames[nRealCount] = pOrgNames[i]; + ++nRealCount; + } + break; + case INTERNET : + if (!bROSaveRelINet) + { + pValues[nRealCount] <<= bSaveRelINet; + pNames[nRealCount] = pOrgNames[i]; + ++nRealCount; + } + break; + case PRETTYPRINTING: + if (!bRODoPrettyPrinting) + { + pValues[nRealCount] <<= bDoPrettyPrinting; + pNames[nRealCount] = pOrgNames[i]; + ++nRealCount; + } + break; + case WARNALIENFORMAT: + if (!bROWarnAlienFormat) + { + pValues[nRealCount] <<= bWarnAlienFormat; + pNames[nRealCount] = pOrgNames[i]; + ++nRealCount; + } + break; + case LOADDOCPRINTER: + if (!bROLoadDocPrinter) + { + pValues[nRealCount] <<= bLoadDocPrinter; + pNames[nRealCount] = pOrgNames[i]; + ++nRealCount; + } + break; + case ODFDEFAULTVERSION: + if (!bROODFDefaultVersion) + { + pValues[nRealCount] <<= (eODFDefaultVersion == SvtSaveOptions::ODFVER_LATEST) ? sal_Int16( 3 ) : sal_Int16( eODFDefaultVersion ); + pNames[nRealCount] = pOrgNames[i]; + ++nRealCount; + } + break; + + default: + SAL_WARN( "unotools.config", "invalid index to save a path" ); + } + } + + aNames.realloc(nRealCount); + aValues.realloc(nRealCount); + PutProperties( aNames, aValues ); + + std::shared_ptr< comphelper::ConfigurationChanges > batch( + comphelper::ConfigurationChanges::create()); + officecfg::Office::Recovery::AutoSave::TimeIntervall::set(nAutoSaveTime, batch); + officecfg::Office::Recovery::AutoSave::Enabled::set(bAutoSave, batch); + officecfg::Office::Recovery::AutoSave::UserAutoSaveEnabled::set(bUserAutoSave, batch); + batch->commit(); +} + +void SvtSaveOptions_Impl::Notify( const Sequence<OUString>& ) +{ +} + +namespace { + +class SvtLoadOptions_Impl : public utl::ConfigItem +{ +private: + bool bLoadUserDefinedSettings; + + virtual void ImplCommit() override; + +public: + SvtLoadOptions_Impl(); + + virtual void Notify( const css::uno::Sequence< OUString >& aPropertyNames ) override; + + void SetLoadUserSettings(bool b){bLoadUserDefinedSettings = b; SetModified();} + bool IsLoadUserSettings() const {return bLoadUserDefinedSettings;} +}; + +} + +const char cUserDefinedSettings[] = "UserDefinedSettings"; + +SvtLoadOptions_Impl::SvtLoadOptions_Impl() + : ConfigItem( "Office.Common/Load" ) + , bLoadUserDefinedSettings( false ) +{ + Sequence< OUString > aNames { cUserDefinedSettings }; + Sequence< Any > aValues = GetProperties( aNames ); + EnableNotification( aNames ); + const Any* pValues = aValues.getConstArray(); + DBG_ASSERT( aValues.getLength() == aNames.getLength(), "GetProperties failed" ); + pValues[0] >>= bLoadUserDefinedSettings; +} + +void SvtLoadOptions_Impl::ImplCommit() +{ + PutProperties( + {cUserDefinedSettings}, {css::uno::Any(bLoadUserDefinedSettings)}); +} + +void SvtLoadOptions_Impl::Notify( const Sequence<OUString>& ) +{ + SAL_WARN( "unotools.config", "properties have been changed" ); +} + +namespace +{ + class LocalSingleton : public rtl::Static< osl::Mutex, LocalSingleton > + { + }; +} + +SvtSaveOptions::SvtSaveOptions() +{ + // Global access, must be guarded (multithreading) + ::osl::MutexGuard aGuard( LocalSingleton::get() ); + if ( !pOptions ) + { + pOptions.reset(new SvtLoadSaveOptions_Impl); + pOptions->pSaveOpt.reset(new SvtSaveOptions_Impl); + pOptions->pLoadOpt.reset( new SvtLoadOptions_Impl); + } + ++nRefCount; + pImp = pOptions.get(); +} + +SvtSaveOptions::~SvtSaveOptions() +{ + // Global access, must be guarded (multithreading) + ::osl::MutexGuard aGuard( LocalSingleton::get() ); + if ( !--nRefCount ) + { + if ( pOptions->pSaveOpt->IsModified() ) + pOptions->pSaveOpt->Commit(); + if ( pOptions->pLoadOpt->IsModified() ) + pOptions->pLoadOpt->Commit(); + + pOptions.reset(); + } +} + +void SvtSaveOptions::SetAutoSaveTime( sal_Int32 n ) +{ + pImp->pSaveOpt->SetAutoSaveTime( n ); +} + +sal_Int32 SvtSaveOptions::GetAutoSaveTime() const +{ + return pImp->pSaveOpt->GetAutoSaveTime(); +} + +void SvtSaveOptions::SetUseUserData( bool b ) +{ + pImp->pSaveOpt->SetUseUserData( b ); +} + +bool SvtSaveOptions::IsUseUserData() const +{ + return pImp->pSaveOpt->IsUseUserData(); +} + +void SvtSaveOptions::SetBackup( bool b ) +{ + pImp->pSaveOpt->SetBackup( b ); +} + +bool SvtSaveOptions::IsBackup() const +{ + return pImp->pSaveOpt->IsBackup(); +} + +void SvtSaveOptions::SetAutoSave( bool b ) +{ + pImp->pSaveOpt->SetAutoSave( b ); +} + +bool SvtSaveOptions::IsAutoSave() const +{ + return pImp->pSaveOpt->IsAutoSave(); +} + +void SvtSaveOptions::SetAutoSavePrompt( bool b ) +{ + pImp->pSaveOpt->SetAutoSavePrompt( b ); +} + +bool SvtSaveOptions::IsAutoSavePrompt() const +{ + return pImp->pSaveOpt->IsAutoSavePrompt(); +} + +void SvtSaveOptions::SetUserAutoSave( bool b ) +{ + pImp->pSaveOpt->SetUserAutoSave( b ); +} + +bool SvtSaveOptions::IsUserAutoSave() const +{ + return pImp->pSaveOpt->IsUserAutoSave(); +} + +void SvtSaveOptions::SetDocInfoSave(bool b) +{ + pImp->pSaveOpt->SetDocInfoSave( b ); +} + +bool SvtSaveOptions::IsDocInfoSave() const +{ + return pImp->pSaveOpt->IsDocInfoSave(); +} + +void SvtSaveOptions::SetSaveWorkingSet( bool b ) +{ + pImp->pSaveOpt->SetSaveWorkingSet( b ); +} + +bool SvtSaveOptions::IsSaveWorkingSet() const +{ + return pImp->pSaveOpt->IsSaveWorkingSet(); +} + +void SvtSaveOptions::SetSaveDocView( bool b ) +{ + pImp->pSaveOpt->SetSaveDocView( b ); +} + +bool SvtSaveOptions::IsSaveDocView() const +{ + return pImp->pSaveOpt->IsSaveDocView(); +} + +void SvtSaveOptions::SetSaveRelINet( bool b ) +{ + pImp->pSaveOpt->SetSaveRelINet( b ); +} + +bool SvtSaveOptions::IsSaveRelINet() const +{ + return pImp->pSaveOpt->IsSaveRelINet(); +} + +void SvtSaveOptions::SetSaveRelFSys( bool b ) +{ + pImp->pSaveOpt->SetSaveRelFSys( b ); +} + +bool SvtSaveOptions::IsSaveRelFSys() const +{ + return pImp->pSaveOpt->IsSaveRelFSys(); +} + +void SvtSaveOptions::SetLoadUserSettings(bool b) +{ + pImp->pLoadOpt->SetLoadUserSettings(b); +} + +bool SvtSaveOptions::IsLoadUserSettings() const +{ + return pImp->pLoadOpt->IsLoadUserSettings(); +} + +void SvtSaveOptions::SetPrettyPrinting( bool _bEnable ) +{ + pImp->pSaveOpt->EnablePrettyPrinting( _bEnable ); +} + +bool SvtSaveOptions::IsPrettyPrinting() const +{ + return pImp->pSaveOpt->IsPrettyPrintingEnabled(); +} + +void SvtSaveOptions::SetWarnAlienFormat( bool _bEnable ) +{ + pImp->pSaveOpt->SetWarnAlienFormat( _bEnable ); +} + +bool SvtSaveOptions::IsWarnAlienFormat() const +{ + return pImp->pSaveOpt->IsWarnAlienFormat(); +} + +void SvtSaveOptions::SetLoadDocumentPrinter( bool _bEnable ) +{ + pImp->pSaveOpt->SetLoadDocPrinter( _bEnable ); +} + +bool SvtSaveOptions::IsLoadDocumentPrinter() const +{ + return pImp->pSaveOpt->IsLoadDocPrinter(); +} + +void SvtSaveOptions::SetODFDefaultVersion( SvtSaveOptions::ODFDefaultVersion eVersion ) +{ + pImp->pSaveOpt->SetODFDefaultVersion( eVersion ); +} + +SvtSaveOptions::ODFDefaultVersion SvtSaveOptions::GetODFDefaultVersion() const +{ + auto const nRet = pImp->pSaveOpt->GetODFDefaultVersion(); + SAL_WARN_IF(nRet == ODFVER_UNKNOWN, "unotools.config", "DefaultVersion is ODFVER_UNKNOWN?"); + return (nRet == ODFVER_UNKNOWN) ? ODFVER_LATEST : nRet; +} + +SvtSaveOptions::ODFSaneDefaultVersion SvtSaveOptions::GetODFSaneDefaultVersion() const +{ + switch (pImp->pSaveOpt->GetODFDefaultVersion()) + { + default: + assert(!"map new ODFDefaultVersion to ODFSaneDefaultVersion"); + break; + case ODFVER_UNKNOWN: + case ODFVER_LATEST: + return ODFSVER_LATEST_EXTENDED; + case ODFVER_010: + return ODFSVER_010; + case ODFVER_011: + return ODFSVER_011; + case ODFVER_012: + return ODFSVER_012; + case ODFVER_012_EXT_COMPAT: + return ODFSVER_012_EXT_COMPAT; + case ODFVER_012_EXTENDED: + return ODFSVER_012_EXTENDED; + case ODFVER_013: + return ODFSVER_013; + } + return ODFSVER_LATEST_EXTENDED; +} + +bool SvtSaveOptions::IsReadOnly( SvtSaveOptions::EOption eOption ) const +{ + return pImp->pSaveOpt->IsReadOnly(eOption); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/unotools/source/config/searchopt.cxx b/unotools/source/config/searchopt.cxx new file mode 100644 index 000000000..23a2ae933 --- /dev/null +++ b/unotools/source/config/searchopt.cxx @@ -0,0 +1,614 @@ +/* -*- 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 . + */ + +#include <sal/config.h> + +#include <unotools/searchopt.hxx> +#include <tools/debug.hxx> +#include <unotools/configitem.hxx> +#include <com/sun/star/uno/Sequence.hxx> +#include <com/sun/star/uno/Any.h> +#include <sal/macros.h> +#include <osl/diagnose.h> +#include <i18nutil/transliteration.hxx> + +using namespace utl; +using namespace com::sun::star::uno; + +#define MAX_FLAGS_OFFSET 29 + +class SvtSearchOptions_Impl : public ConfigItem +{ + sal_Int32 nFlags; + bool bModified; + + SvtSearchOptions_Impl(const SvtSearchOptions_Impl&) = delete; + SvtSearchOptions_Impl& operator=(const SvtSearchOptions_Impl&) = delete; + + // ConfigItem + virtual void ImplCommit() override; + +protected: + bool IsModified() const { return bModified; } + using ConfigItem::SetModified; + void SetModified( bool bVal ); + void Load(); + bool Save(); + + static Sequence< OUString > GetPropertyNames(); + +public: + SvtSearchOptions_Impl(); + virtual ~SvtSearchOptions_Impl() override; + + virtual void Notify( const css::uno::Sequence< OUString >& aPropertyNames ) override; + + bool GetFlag( sal_uInt16 nOffset ) const; + void SetFlag( sal_uInt16 nOffset, bool bVal ); + void SetSearchAlgorithm( sal_uInt16 nOffset, bool bVal ); +}; + +SvtSearchOptions_Impl::SvtSearchOptions_Impl() : + ConfigItem( "Office.Common/SearchOptions" ), + nFlags(0x0003FFFF) // set all options values to 'true' + +{ + Load(); + SetModified( false ); +} + +SvtSearchOptions_Impl::~SvtSearchOptions_Impl() +{ + assert(!IsModified()); // should have been committed +} + +void SvtSearchOptions_Impl::ImplCommit() +{ + if (IsModified()) + Save(); +} + +void SvtSearchOptions_Impl::Notify( const Sequence< OUString >& ) +{ +} + +bool SvtSearchOptions_Impl::GetFlag( sal_uInt16 nOffset ) const +{ + DBG_ASSERT( nOffset <= MAX_FLAGS_OFFSET, "offset out of range"); + return ((nFlags >> nOffset) & 0x01) != 0; +} + +void SvtSearchOptions_Impl::SetFlag( sal_uInt16 nOffset, bool bVal ) +{ + DBG_ASSERT( nOffset <= MAX_FLAGS_OFFSET, "offset out of range"); + sal_Int32 nOldFlags = nFlags; + sal_Int32 nMask = (sal_Int32(1)) << nOffset; + if (bVal) + nFlags |= nMask; + else + nFlags &= ~nMask; + if (nFlags != nOldFlags) + SetModified( true ); +} + +void SvtSearchOptions_Impl::SetModified( bool bVal ) +{ + bModified = bVal; + if (bModified) + { + ConfigItem::SetModified(); + } +} + +Sequence< OUString > SvtSearchOptions_Impl::GetPropertyNames() +{ + static const char* aPropNames[ MAX_FLAGS_OFFSET + 1 ] = + { + "IsWholeWordsOnly", // 0 + "IsBackwards", // 1 + "IsUseRegularExpression", // 2 + //"IsCurrentSelectionOnly", // interactively set or not... + "IsSearchForStyles", // 3 + "IsSimilaritySearch", // 4 + "IsUseAsianOptions", // 5 + "IsMatchCase", // 6 + "Japanese/IsMatchFullHalfWidthForms", // 7 + "Japanese/IsMatchHiraganaKatakana", // 8 + "Japanese/IsMatchContractions", // 9 + "Japanese/IsMatchMinusDashCho-on", // 10 + "Japanese/IsMatchRepeatCharMarks", // 11 + "Japanese/IsMatchVariantFormKanji", // 12 + "Japanese/IsMatchOldKanaForms", // 13 + "Japanese/IsMatch_DiZi_DuZu", // 14 + "Japanese/IsMatch_BaVa_HaFa", // 15 + "Japanese/IsMatch_TsiThiChi_DhiZi", // 16 + "Japanese/IsMatch_HyuIyu_ByuVyu", // 17 + "Japanese/IsMatch_SeShe_ZeJe", // 18 + "Japanese/IsMatch_IaIya", // 19 + "Japanese/IsMatch_KiKu", // 20 + "Japanese/IsIgnorePunctuation", // 21 + "Japanese/IsIgnoreWhitespace", // 22 + "Japanese/IsIgnoreProlongedSoundMark", // 23 + "Japanese/IsIgnoreMiddleDot", // 24 + "IsNotes", // 25 + "IsIgnoreDiacritics_CTL", // 26 + "IsIgnoreKashida_CTL", // 27 + "IsSearchFormatted", // 28 + "IsUseWildcard" // 29 + }; + + const int nCount = SAL_N_ELEMENTS( aPropNames ); + Sequence< OUString > aNames( nCount ); + OUString* pNames = aNames.getArray(); + for (sal_Int32 i = 0; i < nCount; ++i) + pNames[i] = OUString::createFromAscii( aPropNames[i] ); + + return aNames; +} + +void SvtSearchOptions_Impl::SetSearchAlgorithm( sal_uInt16 nOffset, bool bVal ) +{ + if (bVal) + { + // Search algorithms are mutually exclusive. + if (nOffset != 2 && GetFlag(2)) + SetFlag( 2, false ); + if (nOffset != 4 && GetFlag(4)) + SetFlag( 4, false ); + if (nOffset != 29 && GetFlag(29)) + SetFlag( 29, false ); + } + SetFlag( nOffset, bVal ); +} + +void SvtSearchOptions_Impl::Load() +{ + bool bSucc = false; + + Sequence< OUString > aNames = GetPropertyNames(); + sal_Int32 nProps = aNames.getLength(); + + const Sequence< Any > aValues = GetProperties( aNames ); + DBG_ASSERT( aValues.getLength() == aNames.getLength(), + "GetProperties failed" ); + //EnableNotification( aNames ); + + if (nProps && aValues.getLength() == nProps) + { + bSucc = true; + + const Any* pValues = aValues.getConstArray(); + for (sal_Int32 i = 0; i < nProps; ++i) + { + const Any &rVal = pValues[i]; + DBG_ASSERT( rVal.hasValue(), "property value missing" ); + if (rVal.hasValue()) + { + bool bVal = bool(); + if (rVal >>= bVal) + { + if (i <= MAX_FLAGS_OFFSET) + { + // use index in sequence as flag index + SetFlag( i, bVal ); + } + else { + OSL_FAIL( "unexpected index" ); + } + } + else + { + OSL_FAIL( "unexpected type" ); + bSucc = false; + } + } + else + { + OSL_FAIL( "value missing" ); + bSucc = false; + } + } + } + DBG_ASSERT( bSucc, "LoadConfig failed" ); +} + +bool SvtSearchOptions_Impl::Save() +{ + bool bSucc = false; + + const Sequence< OUString > aNames = GetPropertyNames(); + sal_Int32 nProps = aNames.getLength(); + + Sequence< Any > aValues( nProps ); + Any *pValue = aValues.getArray(); + + DBG_ASSERT( nProps == MAX_FLAGS_OFFSET + 1, + "unexpected size of index" ); + if (nProps == MAX_FLAGS_OFFSET + 1) + { + for (sal_Int32 i = 0; i < nProps; ++i) + pValue[i] <<= GetFlag(i); + bSucc |= PutProperties( aNames, aValues ); + } + + if (bSucc) + SetModified( false ); + + return bSucc; +} + +SvtSearchOptions::SvtSearchOptions() + : pImpl( new SvtSearchOptions_Impl ) +{ +} + +SvtSearchOptions::~SvtSearchOptions() +{ +} + +void SvtSearchOptions::Commit() +{ + pImpl->Commit(); +} + +TransliterationFlags SvtSearchOptions::GetTransliterationFlags() const +{ + TransliterationFlags nRes = TransliterationFlags::NONE; + + if (!IsMatchCase()) // 'IsMatchCase' means act case sensitive + nRes |= TransliterationFlags::IGNORE_CASE; + if ( IsMatchFullHalfWidthForms()) + nRes |= TransliterationFlags::IGNORE_WIDTH; + if ( IsMatchHiraganaKatakana()) + nRes |= TransliterationFlags::IGNORE_KANA; + if ( IsMatchContractions()) + nRes |= TransliterationFlags::ignoreSize_ja_JP; + if ( IsMatchMinusDashChoon()) + nRes |= TransliterationFlags::ignoreMinusSign_ja_JP; + if ( IsMatchRepeatCharMarks()) + nRes |= TransliterationFlags::ignoreIterationMark_ja_JP; + if ( IsMatchVariantFormKanji()) + nRes |= TransliterationFlags::ignoreTraditionalKanji_ja_JP; + if ( IsMatchOldKanaForms()) + nRes |= TransliterationFlags::ignoreTraditionalKana_ja_JP; + if ( IsMatchDiziDuzu()) + nRes |= TransliterationFlags::ignoreZiZu_ja_JP; + if ( IsMatchBavaHafa()) + nRes |= TransliterationFlags::ignoreBaFa_ja_JP; + if ( IsMatchTsithichiDhizi()) + nRes |= TransliterationFlags::ignoreTiJi_ja_JP; + if ( IsMatchHyuiyuByuvyu()) + nRes |= TransliterationFlags::ignoreHyuByu_ja_JP; + if ( IsMatchSesheZeje()) + nRes |= TransliterationFlags::ignoreSeZe_ja_JP; + if ( IsMatchIaiya()) + nRes |= TransliterationFlags::ignoreIandEfollowedByYa_ja_JP; + if ( IsMatchKiku()) + nRes |= TransliterationFlags::ignoreKiKuFollowedBySa_ja_JP; + if ( IsIgnorePunctuation()) + nRes |= TransliterationFlags::ignoreSeparator_ja_JP; + if ( IsIgnoreWhitespace()) + nRes |= TransliterationFlags::ignoreSpace_ja_JP; + if ( IsIgnoreProlongedSoundMark()) + nRes |= TransliterationFlags::ignoreProlongedSoundMark_ja_JP; + if ( IsIgnoreMiddleDot()) + nRes |= TransliterationFlags::ignoreMiddleDot_ja_JP; + if ( IsIgnoreDiacritics_CTL()) + nRes |= TransliterationFlags::IGNORE_DIACRITICS_CTL; + if ( IsIgnoreKashida_CTL()) + nRes |= TransliterationFlags::IGNORE_KASHIDA_CTL; + return nRes; +} + +bool SvtSearchOptions::IsWholeWordsOnly() const +{ + return pImpl->GetFlag( 0 ); +} + +void SvtSearchOptions::SetWholeWordsOnly( bool bVal ) +{ + pImpl->SetFlag( 0, bVal ); +} + +bool SvtSearchOptions::IsBackwards() const +{ + return pImpl->GetFlag( 1 ); +} + +void SvtSearchOptions::SetBackwards( bool bVal ) +{ + pImpl->SetFlag( 1, bVal ); +} + +bool SvtSearchOptions::IsUseRegularExpression() const +{ + return pImpl->GetFlag( 2 ); +} + +void SvtSearchOptions::SetUseRegularExpression( bool bVal ) +{ + pImpl->SetSearchAlgorithm( 2, bVal ); +} + +void SvtSearchOptions::SetSearchForStyles( bool bVal ) +{ + pImpl->SetFlag( 3, bVal ); +} + +bool SvtSearchOptions::IsSimilaritySearch() const +{ + return pImpl->GetFlag( 4 ); +} + +void SvtSearchOptions::SetSimilaritySearch( bool bVal ) +{ + pImpl->SetSearchAlgorithm( 4, bVal ); +} + +bool SvtSearchOptions::IsUseAsianOptions() const +{ + return pImpl->GetFlag( 5 ); +} + +void SvtSearchOptions::SetUseAsianOptions( bool bVal ) +{ + pImpl->SetFlag( 5, bVal ); +} + +bool SvtSearchOptions::IsMatchCase() const +{ + return pImpl->GetFlag( 6 ); +} + +void SvtSearchOptions::SetMatchCase( bool bVal ) +{ + pImpl->SetFlag( 6, bVal ); +} + +bool SvtSearchOptions::IsMatchFullHalfWidthForms() const +{ + return pImpl->GetFlag( 7 ); +} + +void SvtSearchOptions::SetMatchFullHalfWidthForms( bool bVal ) +{ + pImpl->SetFlag( 7, bVal ); +} + +bool SvtSearchOptions::IsMatchHiraganaKatakana() const +{ + return pImpl->GetFlag( 8 ); +} + +void SvtSearchOptions::SetMatchHiraganaKatakana( bool bVal ) +{ + pImpl->SetFlag( 8, bVal ); +} + +bool SvtSearchOptions::IsMatchContractions() const +{ + return pImpl->GetFlag( 9 ); +} + +void SvtSearchOptions::SetMatchContractions( bool bVal ) +{ + pImpl->SetFlag( 9, bVal ); +} + +bool SvtSearchOptions::IsMatchMinusDashChoon() const +{ + return pImpl->GetFlag( 10 ); +} + +void SvtSearchOptions::SetMatchMinusDashChoon( bool bVal ) +{ + pImpl->SetFlag( 10, bVal ); +} + +bool SvtSearchOptions::IsMatchRepeatCharMarks() const +{ + return pImpl->GetFlag( 11 ); +} + +void SvtSearchOptions::SetMatchRepeatCharMarks( bool bVal ) +{ + pImpl->SetFlag( 11, bVal ); +} + +bool SvtSearchOptions::IsMatchVariantFormKanji() const +{ + return pImpl->GetFlag( 12 ); +} + +void SvtSearchOptions::SetMatchVariantFormKanji( bool bVal ) +{ + pImpl->SetFlag( 12, bVal ); +} + +bool SvtSearchOptions::IsMatchOldKanaForms() const +{ + return pImpl->GetFlag( 13 ); +} + +void SvtSearchOptions::SetMatchOldKanaForms( bool bVal ) +{ + pImpl->SetFlag( 13, bVal ); +} + +bool SvtSearchOptions::IsMatchDiziDuzu() const +{ + return pImpl->GetFlag( 14 ); +} + +void SvtSearchOptions::SetMatchDiziDuzu( bool bVal ) +{ + pImpl->SetFlag( 14, bVal ); +} + +bool SvtSearchOptions::IsMatchBavaHafa() const +{ + return pImpl->GetFlag( 15 ); +} + +void SvtSearchOptions::SetMatchBavaHafa( bool bVal ) +{ + pImpl->SetFlag( 15, bVal ); +} + +bool SvtSearchOptions::IsMatchTsithichiDhizi() const +{ + return pImpl->GetFlag( 16 ); +} + +void SvtSearchOptions::SetMatchTsithichiDhizi( bool bVal ) +{ + pImpl->SetFlag( 16, bVal ); +} + +bool SvtSearchOptions::IsMatchHyuiyuByuvyu() const +{ + return pImpl->GetFlag( 17 ); +} + +void SvtSearchOptions::SetMatchHyuiyuByuvyu( bool bVal ) +{ + pImpl->SetFlag( 17, bVal ); +} + +bool SvtSearchOptions::IsMatchSesheZeje() const +{ + return pImpl->GetFlag( 18 ); +} + +void SvtSearchOptions::SetMatchSesheZeje( bool bVal ) +{ + pImpl->SetFlag( 18, bVal ); +} + +bool SvtSearchOptions::IsMatchIaiya() const +{ + return pImpl->GetFlag( 19 ); +} + +void SvtSearchOptions::SetMatchIaiya( bool bVal ) +{ + pImpl->SetFlag( 19, bVal ); +} + +bool SvtSearchOptions::IsMatchKiku() const +{ + return pImpl->GetFlag( 20 ); +} + +void SvtSearchOptions::SetMatchKiku( bool bVal ) +{ + pImpl->SetFlag( 20, bVal ); +} + +bool SvtSearchOptions::IsIgnorePunctuation() const +{ + return pImpl->GetFlag( 21 ); +} + +void SvtSearchOptions::SetIgnorePunctuation( bool bVal ) +{ + pImpl->SetFlag( 21, bVal ); +} + +bool SvtSearchOptions::IsIgnoreWhitespace() const +{ + return pImpl->GetFlag( 22 ); +} + +void SvtSearchOptions::SetIgnoreWhitespace( bool bVal ) +{ + pImpl->SetFlag( 22, bVal ); +} + +bool SvtSearchOptions::IsIgnoreProlongedSoundMark() const +{ + return pImpl->GetFlag( 23 ); +} + +void SvtSearchOptions::SetIgnoreProlongedSoundMark( bool bVal ) +{ + pImpl->SetFlag( 23, bVal ); +} + +bool SvtSearchOptions::IsIgnoreMiddleDot() const +{ + return pImpl->GetFlag( 24 ); +} + +void SvtSearchOptions::SetIgnoreMiddleDot( bool bVal ) +{ + pImpl->SetFlag( 24, bVal ); +} + +bool SvtSearchOptions::IsNotes() const +{ + return pImpl->GetFlag( 25 ); +} + +void SvtSearchOptions::SetNotes( bool bVal ) +{ + pImpl->SetFlag( 25, bVal ); +} + +bool SvtSearchOptions::IsIgnoreDiacritics_CTL() const +{ + return pImpl->GetFlag( 26 ); +} + +void SvtSearchOptions::SetIgnoreDiacritics_CTL( bool bVal ) +{ + pImpl->SetFlag( 26, bVal ); +} + +bool SvtSearchOptions::IsIgnoreKashida_CTL() const +{ + return pImpl->GetFlag( 27 ); +} + +void SvtSearchOptions::SetIgnoreKashida_CTL( bool bVal ) +{ + pImpl->SetFlag( 27, bVal ); +} + +bool SvtSearchOptions::IsSearchFormatted() const +{ + return pImpl->GetFlag( 28 ); +} + +void SvtSearchOptions::SetSearchFormatted( bool bVal ) +{ + pImpl->SetFlag( 28, bVal ); +} + +bool SvtSearchOptions::IsUseWildcard() const +{ + return pImpl->GetFlag( 29 ); +} + +void SvtSearchOptions::SetUseWildcard( bool bVal ) +{ + pImpl->SetSearchAlgorithm( 29, bVal ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/unotools/source/config/securityoptions.cxx b/unotools/source/config/securityoptions.cxx new file mode 100644 index 000000000..d81517f25 --- /dev/null +++ b/unotools/source/config/securityoptions.cxx @@ -0,0 +1,1167 @@ +/* -*- 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 . + */ + +#include <unotools/securityoptions.hxx> +#include <unotools/configmgr.hxx> +#include <unotools/configitem.hxx> +#include <unotools/ucbhelper.hxx> +#include <tools/debug.hxx> +#include <com/sun/star/uno/Any.hxx> +#include <com/sun/star/uno/Sequence.hxx> + +#include <com/sun/star/beans/PropertyValue.hpp> +#include <comphelper/sequence.hxx> +#include <tools/urlobj.hxx> + +#include <unotools/pathoptions.hxx> + +#include "itemholder1.hxx" + +// namespaces + +using namespace ::utl; +using namespace ::osl; +using namespace ::com::sun::star::uno; + +#define ROOTNODE_SECURITY "Office.Common/Security/Scripting" +#define DEFAULT_SECUREURL Sequence< OUString >() +#define DEFAULT_TRUSTEDAUTHORS Sequence< SvtSecurityOptions::Certificate >() + +// xmlsec05 deprecated +#define DEFAULT_STAROFFICEBASIC eALWAYS_EXECUTE + +#define PROPERTYNAME_SECUREURL "SecureURL" +#define PROPERTYNAME_DOCWARN_SAVEORSEND "WarnSaveOrSendDoc" +#define PROPERTYNAME_DOCWARN_SIGNING "WarnSignDoc" +#define PROPERTYNAME_DOCWARN_PRINT "WarnPrintDoc" +#define PROPERTYNAME_DOCWARN_CREATEPDF "WarnCreatePDF" +#define PROPERTYNAME_DOCWARN_REMOVEPERSONALINFO "RemovePersonalInfoOnSaving" +#define PROPERTYNAME_DOCWARN_RECOMMENDPASSWORD "RecommendPasswordProtection" +#define PROPERTYNAME_CTRLCLICK_HYPERLINK "HyperlinksWithCtrlClick" +#define PROPERTYNAME_BLOCKUNTRUSTEDREFERERLINKS "BlockUntrustedRefererLinks" +#define PROPERTYNAME_MACRO_SECLEVEL "MacroSecurityLevel" +#define PROPERTYNAME_MACRO_TRUSTEDAUTHORS "TrustedAuthors" +#define PROPERTYNAME_MACRO_DISABLE "DisableMacrosExecution" +#define PROPERTYNAME_TRUSTEDAUTHOR_SUBJECTNAME "SubjectName" +#define PROPERTYNAME_TRUSTEDAUTHOR_SERIALNUMBER "SerialNumber" +#define PROPERTYNAME_TRUSTEDAUTHOR_RAWDATA "RawData" + +// xmlsec05 deprecated +#define PROPERTYNAME_STAROFFICEBASIC "OfficeBasic" +#define PROPERTYNAME_EXECUTEPLUGINS "ExecutePlugins" +#define PROPERTYNAME_WARNINGENABLED "Warning" +#define PROPERTYNAME_CONFIRMATIONENABLED "Confirmation" +// xmlsec05 deprecated + +#define PROPERTYHANDLE_SECUREURL 0 + +// xmlsec05 deprecated +#define PROPERTYHANDLE_STAROFFICEBASIC 1 +#define PROPERTYHANDLE_EXECUTEPLUGINS 2 +#define PROPERTYHANDLE_WARNINGENABLED 3 +#define PROPERTYHANDLE_CONFIRMATIONENABLED 4 +// xmlsec05 deprecated + +#define PROPERTYHANDLE_DOCWARN_SAVEORSEND 5 +#define PROPERTYHANDLE_DOCWARN_SIGNING 6 +#define PROPERTYHANDLE_DOCWARN_PRINT 7 +#define PROPERTYHANDLE_DOCWARN_CREATEPDF 8 +#define PROPERTYHANDLE_DOCWARN_REMOVEPERSONALINFO 9 +#define PROPERTYHANDLE_DOCWARN_RECOMMENDPASSWORD 10 +#define PROPERTYHANDLE_CTRLCLICK_HYPERLINK 11 +#define PROPERTYHANDLE_BLOCKUNTRUSTEDREFERERLINKS 12 +#define PROPERTYHANDLE_MACRO_SECLEVEL 13 +#define PROPERTYHANDLE_MACRO_TRUSTEDAUTHORS 14 +#define PROPERTYHANDLE_MACRO_DISABLE 15 + +#define PROPERTYHANDLE_INVALID -1 + +#define CFG_READONLY_DEFAULT false + +// private declarations! + +class SvtSecurityOptions_Impl : public ConfigItem +{ + + private: + virtual void ImplCommit() override; + + // public methods + + public: + + // constructor / destructor + + SvtSecurityOptions_Impl(); + virtual ~SvtSecurityOptions_Impl() override; + + // override methods of baseclass + + /*-**************************************************************************************************** + @short called for notify of configmanager + @descr This method is called from the ConfigManager before application ends or from the + PropertyChangeListener if the sub tree broadcasts changes. You must update your + internal values. + + @seealso baseclass ConfigItem + + @param "seqPropertyNames" is the list of properties which should be updated. + *//*-*****************************************************************************************************/ + + virtual void Notify( const Sequence< OUString >& seqPropertyNames ) override; + + // public interface + + bool IsReadOnly ( SvtSecurityOptions::EOption eOption ) const; + + const Sequence< OUString >& GetSecureURLs( ) const { return m_seqSecureURLs;} + void SetSecureURLs ( const Sequence< OUString >& seqURLList ); + inline sal_Int32 GetMacroSecurityLevel ( ) const; + void SetMacroSecurityLevel ( sal_Int32 _nLevel ); + + inline bool IsMacroDisabled ( ) const; + + const Sequence< SvtSecurityOptions::Certificate >& GetTrustedAuthors( ) const { return m_seqTrustedAuthors;} + void SetTrustedAuthors ( const Sequence< SvtSecurityOptions::Certificate >& rAuthors ); + + bool IsOptionSet ( SvtSecurityOptions::EOption eOption ) const; + void SetOption ( SvtSecurityOptions::EOption eOption, bool bValue ); + bool IsOptionEnabled ( SvtSecurityOptions::EOption eOption ) const; + + + void SetProperty( sal_Int32 nHandle, const Any& rValue, bool bReadOnly ); + void LoadAuthors(); + static sal_Int32 GetHandle( const OUString& rPropertyName ); + bool GetOption( SvtSecurityOptions::EOption eOption, bool*& rpValue, bool*& rpRO ); + + /*-**************************************************************************************************** + @short return list of key names of our configuration management which represent our module tree + @descr This method returns a static const list of key names. We need it to get needed values from our + configuration management. + @return A list of needed configuration keys is returned. + *//*-*****************************************************************************************************/ + static Sequence< OUString > GetPropertyNames(); + + Sequence< OUString > m_seqSecureURLs; + bool m_bSaveOrSend; + bool m_bSigning; + bool m_bPrint; + bool m_bCreatePDF; + bool m_bRemoveInfo; + bool m_bRecommendPwd; + bool m_bCtrlClickHyperlink; + bool m_bBlockUntrustedRefererLinks; + sal_Int32 m_nSecLevel; + Sequence< SvtSecurityOptions::Certificate > m_seqTrustedAuthors; + bool m_bDisableMacros; + + bool m_bROSecureURLs; + bool m_bROSaveOrSend; + bool m_bROSigning; + bool m_bROPrint; + bool m_bROCreatePDF; + bool m_bRORemoveInfo; + bool m_bRORecommendPwd; + bool m_bROCtrlClickHyperlink; + bool m_bROBlockUntrustedRefererLinks; + bool m_bROSecLevel; + bool m_bROTrustedAuthors; + bool m_bRODisableMacros; + + // xmlsec05 deprecated + EBasicSecurityMode m_eBasicMode; + bool m_bExecutePlugins; + bool m_bWarning; + bool m_bConfirmation; + + bool m_bROConfirmation; + bool m_bROWarning; + bool m_bROExecutePlugins; + bool m_bROBasicMode; + public: + bool IsWarningEnabled() const { return m_bWarning;} + void SetWarningEnabled( bool bSet ); + bool IsConfirmationEnabled() const { return m_bConfirmation;} + void SetConfirmationEnabled( bool bSet ); + bool IsExecutePlugins() const { return m_bExecutePlugins;} + void SetExecutePlugins( bool bSet ); + // xmlsec05 deprecated + EBasicSecurityMode GetBasicMode ( ) const { return m_eBasicMode;} + void SetBasicMode ( EBasicSecurityMode eMode ); +}; + +// constructor + +SvtSecurityOptions_Impl::SvtSecurityOptions_Impl() + :ConfigItem ( ROOTNODE_SECURITY ) + ,m_seqSecureURLs ( DEFAULT_SECUREURL ) + ,m_bSaveOrSend ( true ) + ,m_bSigning ( true ) + ,m_bPrint ( true ) + ,m_bCreatePDF ( true ) + ,m_bRemoveInfo ( true ) + ,m_bRecommendPwd(false) + ,m_bCtrlClickHyperlink(false) + ,m_bBlockUntrustedRefererLinks(false) + ,m_nSecLevel ( 1 ) + ,m_seqTrustedAuthors ( DEFAULT_TRUSTEDAUTHORS ) + ,m_bDisableMacros ( false ) + ,m_bROSecureURLs ( CFG_READONLY_DEFAULT ) + ,m_bROSaveOrSend ( CFG_READONLY_DEFAULT ) + ,m_bROSigning ( CFG_READONLY_DEFAULT ) + ,m_bROPrint ( CFG_READONLY_DEFAULT ) + ,m_bROCreatePDF ( CFG_READONLY_DEFAULT ) + ,m_bRORemoveInfo ( CFG_READONLY_DEFAULT ) + ,m_bRORecommendPwd(CFG_READONLY_DEFAULT) + ,m_bROCtrlClickHyperlink(CFG_READONLY_DEFAULT) + ,m_bROBlockUntrustedRefererLinks(CFG_READONLY_DEFAULT) + ,m_bROSecLevel ( CFG_READONLY_DEFAULT ) + ,m_bROTrustedAuthors ( CFG_READONLY_DEFAULT ) + ,m_bRODisableMacros ( true ) // currently is not intended to be changed + + // xmlsec05 deprecated + , m_eBasicMode ( DEFAULT_STAROFFICEBASIC ) + , m_bExecutePlugins ( true ) + , m_bWarning ( true ) + , m_bConfirmation ( true ) + , m_bROConfirmation ( CFG_READONLY_DEFAULT ) + , m_bROWarning ( CFG_READONLY_DEFAULT ) + , m_bROExecutePlugins ( CFG_READONLY_DEFAULT ) + , m_bROBasicMode ( CFG_READONLY_DEFAULT ) + // xmlsec05 deprecated + +{ + Sequence< OUString > seqNames = GetPropertyNames ( ); + Sequence< Any > seqValues = GetProperties ( seqNames ); + Sequence< sal_Bool > seqRO = GetReadOnlyStates ( seqNames ); + + // Safe impossible cases. + // We need values from ALL configuration keys. + // Follow assignment use order of values in relation to our list of key names! + DBG_ASSERT( !(seqNames.getLength()!=seqValues.getLength()), "SvtSecurityOptions_Impl::SvtSecurityOptions_Impl()\nI miss some values of configuration keys!\n" ); + + // Copy values from list in right order to our internal member. + sal_Int32 nPropertyCount = seqValues.getLength(); + for( sal_Int32 nProperty = 0; nProperty < nPropertyCount; ++nProperty ) + SetProperty( nProperty, seqValues[ nProperty ], seqRO[ nProperty ] ); + + LoadAuthors(); + + // Enable notification mechanism of our baseclass. + // We need it to get information about changes outside these class on our used configuration keys!*/ + + EnableNotification( seqNames ); +} + +// destructor + +SvtSecurityOptions_Impl::~SvtSecurityOptions_Impl() +{ + assert(!IsModified()); // should have been committed +} + +void SvtSecurityOptions_Impl::SetProperty( sal_Int32 nProperty, const Any& rValue, bool bRO ) +{ + switch( nProperty ) + { + case PROPERTYHANDLE_SECUREURL: + { + m_seqSecureURLs.realloc( 0 ); + rValue >>= m_seqSecureURLs; + if (!utl::ConfigManager::IsFuzzing()) + { + SvtPathOptions aOpt; + std::transform(m_seqSecureURLs.begin(), m_seqSecureURLs.end(), m_seqSecureURLs.begin(), + [&aOpt](const OUString& rUrl) -> OUString { return aOpt.SubstituteVariable( rUrl ); }); + } + m_bROSecureURLs = bRO; + } + break; + + case PROPERTYHANDLE_DOCWARN_SAVEORSEND: + { + rValue >>= m_bSaveOrSend; + m_bROSaveOrSend = bRO; + } + break; + + case PROPERTYHANDLE_DOCWARN_SIGNING: + { + rValue >>= m_bSigning; + m_bROSigning = bRO; + } + break; + + case PROPERTYHANDLE_DOCWARN_PRINT: + { + rValue >>= m_bPrint; + m_bROPrint = bRO; + } + break; + + case PROPERTYHANDLE_DOCWARN_CREATEPDF: + { + rValue >>= m_bCreatePDF; + m_bROCreatePDF = bRO; + } + break; + + case PROPERTYHANDLE_DOCWARN_REMOVEPERSONALINFO: + { + rValue >>= m_bRemoveInfo; + m_bRORemoveInfo = bRO; + } + break; + + case PROPERTYHANDLE_DOCWARN_RECOMMENDPASSWORD: + { + rValue >>= m_bRecommendPwd; + m_bRORecommendPwd = bRO; + } + break; + + case PROPERTYHANDLE_CTRLCLICK_HYPERLINK: + { + rValue >>= m_bCtrlClickHyperlink; + m_bROCtrlClickHyperlink = bRO; + } + break; + + case PROPERTYHANDLE_BLOCKUNTRUSTEDREFERERLINKS: + { + rValue >>= m_bBlockUntrustedRefererLinks; + m_bROBlockUntrustedRefererLinks = bRO; + } + break; + + case PROPERTYHANDLE_MACRO_SECLEVEL: + { + rValue >>= m_nSecLevel; + m_bROSecLevel = bRO; + } + break; + + case PROPERTYHANDLE_MACRO_TRUSTEDAUTHORS: + { + // don't care about value here... + m_bROTrustedAuthors = bRO; + } + break; + + case PROPERTYHANDLE_MACRO_DISABLE: + { + rValue >>= m_bDisableMacros; + m_bRODisableMacros = bRO; + } + break; + + // xmlsec05 deprecated + case PROPERTYHANDLE_STAROFFICEBASIC: + { + sal_Int32 nMode = 0; + rValue >>= nMode; + m_eBasicMode = static_cast<EBasicSecurityMode>(nMode); + m_bROBasicMode = bRO; + } + break; + case PROPERTYHANDLE_EXECUTEPLUGINS: + { + rValue >>= m_bExecutePlugins; + m_bROExecutePlugins = bRO; + } + break; + case PROPERTYHANDLE_WARNINGENABLED: + { + rValue >>= m_bWarning; + m_bROWarning = bRO; + } + break; + case PROPERTYHANDLE_CONFIRMATIONENABLED: + { + rValue >>= m_bConfirmation; + m_bROConfirmation = bRO; + } + break; + // xmlsec05 deprecated + +#if OSL_DEBUG_LEVEL > 0 + default: + assert(false && "Unknown property!"); +#endif + } +} + +void SvtSecurityOptions_Impl::LoadAuthors() +{ + m_seqTrustedAuthors.realloc( 0 ); // first clear + const Sequence< OUString > lAuthors = GetNodeNames( PROPERTYNAME_MACRO_TRUSTEDAUTHORS ); + sal_Int32 c1 = lAuthors.getLength(); + if( c1 ) + { + sal_Int32 c2 = c1 * 3; // 3 Properties inside Struct TrustedAuthor + Sequence< OUString > lAllAuthors( c2 ); + + sal_Int32 i2 = 0; + OUString aSep( "/" ); + for( const auto& rAuthor : lAuthors ) + { + lAllAuthors[ i2 ] = PROPERTYNAME_MACRO_TRUSTEDAUTHORS + aSep + rAuthor + aSep + PROPERTYNAME_TRUSTEDAUTHOR_SUBJECTNAME; + ++i2; + lAllAuthors[ i2 ] = PROPERTYNAME_MACRO_TRUSTEDAUTHORS + aSep + rAuthor + aSep + PROPERTYNAME_TRUSTEDAUTHOR_SERIALNUMBER; + ++i2; + lAllAuthors[ i2 ] = PROPERTYNAME_MACRO_TRUSTEDAUTHORS + aSep + rAuthor + aSep + PROPERTYNAME_TRUSTEDAUTHOR_RAWDATA; + ++i2; + } + + Sequence< Any > lValues = GetProperties( lAllAuthors ); + if( lValues.getLength() == c2 ) + { + std::vector< SvtSecurityOptions::Certificate > v; + SvtSecurityOptions::Certificate aCert( 3 ); + i2 = 0; + for( sal_Int32 i1 = 0; i1 < c1; ++i1 ) + { + lValues[ i2 ] >>= aCert[ 0 ]; + ++i2; + lValues[ i2 ] >>= aCert[ 1 ]; + ++i2; + lValues[ i2 ] >>= aCert[ 2 ]; + ++i2; + // Filter out TrustedAuthor entries with empty RawData, which + // would cause an unexpected std::bad_alloc in + // SecurityEnvironment_NssImpl::createCertificateFromAscii and + // have been observed in the wild (fdo#55019): + if( !aCert[ 2 ].isEmpty() ) + { + v.push_back( aCert ); + } + } + m_seqTrustedAuthors = comphelper::containerToSequence(v); + } + } +} + +sal_Int32 SvtSecurityOptions_Impl::GetHandle( const OUString& rName ) +{ + sal_Int32 nHandle; + + if( rName == PROPERTYNAME_SECUREURL ) + nHandle = PROPERTYHANDLE_SECUREURL; + else if( rName == PROPERTYNAME_DOCWARN_SAVEORSEND ) + nHandle = PROPERTYHANDLE_DOCWARN_SAVEORSEND; + else if( rName == PROPERTYNAME_DOCWARN_SIGNING ) + nHandle = PROPERTYHANDLE_DOCWARN_SIGNING; + else if( rName == PROPERTYNAME_DOCWARN_PRINT ) + nHandle = PROPERTYHANDLE_DOCWARN_PRINT; + else if( rName == PROPERTYNAME_DOCWARN_CREATEPDF ) + nHandle = PROPERTYHANDLE_DOCWARN_CREATEPDF; + else if( rName == PROPERTYNAME_DOCWARN_REMOVEPERSONALINFO ) + nHandle = PROPERTYHANDLE_DOCWARN_REMOVEPERSONALINFO; + else if( rName == PROPERTYNAME_DOCWARN_RECOMMENDPASSWORD ) + nHandle = PROPERTYHANDLE_DOCWARN_RECOMMENDPASSWORD; + else if( rName == PROPERTYNAME_CTRLCLICK_HYPERLINK ) + nHandle = PROPERTYHANDLE_CTRLCLICK_HYPERLINK; + else if( rName == PROPERTYNAME_BLOCKUNTRUSTEDREFERERLINKS ) + nHandle = PROPERTYHANDLE_BLOCKUNTRUSTEDREFERERLINKS; + else if( rName == PROPERTYNAME_MACRO_SECLEVEL ) + nHandle = PROPERTYHANDLE_MACRO_SECLEVEL; + else if( rName == PROPERTYNAME_MACRO_TRUSTEDAUTHORS ) + nHandle = PROPERTYHANDLE_MACRO_TRUSTEDAUTHORS; + else if( rName == PROPERTYNAME_MACRO_DISABLE ) + nHandle = PROPERTYHANDLE_MACRO_DISABLE; + + // xmlsec05 deprecated + else if( rName == PROPERTYNAME_STAROFFICEBASIC ) + nHandle = PROPERTYHANDLE_STAROFFICEBASIC; + else if( rName == PROPERTYNAME_EXECUTEPLUGINS ) + nHandle = PROPERTYHANDLE_EXECUTEPLUGINS; + else if( rName == PROPERTYNAME_WARNINGENABLED ) + nHandle = PROPERTYHANDLE_WARNINGENABLED; + else if( rName == PROPERTYNAME_CONFIRMATIONENABLED ) + nHandle = PROPERTYHANDLE_CONFIRMATIONENABLED; + // xmlsec05 deprecated + + else + nHandle = PROPERTYHANDLE_INVALID; + + return nHandle; +} + +bool SvtSecurityOptions_Impl::GetOption( SvtSecurityOptions::EOption eOption, bool*& rpValue, bool*& rpRO ) +{ + switch( eOption ) + { + case SvtSecurityOptions::EOption::DocWarnSaveOrSend: + rpValue = &m_bSaveOrSend; + rpRO = &m_bROSaveOrSend; + break; + case SvtSecurityOptions::EOption::DocWarnSigning: + rpValue = &m_bSigning; + rpRO = &m_bROSigning; + break; + case SvtSecurityOptions::EOption::DocWarnPrint: + rpValue = &m_bPrint; + rpRO = &m_bROPrint; + break; + case SvtSecurityOptions::EOption::DocWarnCreatePdf: + rpValue = &m_bCreatePDF; + rpRO = &m_bROCreatePDF; + break; + case SvtSecurityOptions::EOption::DocWarnRemovePersonalInfo: + rpValue = &m_bRemoveInfo; + rpRO = &m_bRORemoveInfo; + break; + case SvtSecurityOptions::EOption::DocWarnRecommendPassword: + rpValue = &m_bRecommendPwd; + rpRO = &m_bRORecommendPwd; + break; + case SvtSecurityOptions::EOption::CtrlClickHyperlink: + rpValue = &m_bCtrlClickHyperlink; + rpRO = &m_bROCtrlClickHyperlink; + break; + case SvtSecurityOptions::EOption::BlockUntrustedRefererLinks: + rpValue = &m_bBlockUntrustedRefererLinks; + rpRO = &m_bROBlockUntrustedRefererLinks; + break; + default: + rpValue = nullptr; + rpRO = nullptr; + break; + } + + return rpValue != nullptr; +} + +void SvtSecurityOptions_Impl::Notify( const Sequence< OUString >& seqPropertyNames ) +{ + // Use given list of updated properties to get his values from configuration directly! + Sequence< Any > seqValues = GetProperties( seqPropertyNames ); + Sequence< sal_Bool > seqRO = GetReadOnlyStates( seqPropertyNames ); + // Safe impossible cases. + // We need values from ALL notified configuration keys. + DBG_ASSERT( !(seqPropertyNames.getLength()!=seqValues.getLength()), "SvtSecurityOptions_Impl::Notify()\nI miss some values of configuration keys!\n" ); + // Step over list of property names and get right value from coreesponding value list to set it on internal members! + sal_Int32 nCount = seqPropertyNames.getLength(); + for( sal_Int32 nProperty = 0; nProperty < nCount; ++nProperty ) + SetProperty( GetHandle( seqPropertyNames[ nProperty ] ), seqValues[ nProperty ], seqRO[ nProperty ] ); + + // read set of trusted authors separately + LoadAuthors(); +} + +void SvtSecurityOptions_Impl::ImplCommit() +{ + // Get names of supported properties, create a list for values and copy current values to it. + Sequence< OUString > lOrgNames = GetPropertyNames(); + sal_Int32 nOrgCount = lOrgNames.getLength(); + + Sequence< OUString > lNames(nOrgCount); + Sequence< Any > lValues(nOrgCount); + sal_Int32 nRealCount = 0; + bool bDone; + + ClearNodeSet( PROPERTYNAME_MACRO_TRUSTEDAUTHORS ); + + for( sal_Int32 nProperty = 0; nProperty < nOrgCount; ++nProperty ) + { + switch( nProperty ) + { + case PROPERTYHANDLE_SECUREURL: + { + bDone = !m_bROSecureURLs; + if( bDone ) + { + Sequence< OUString > lURLs( m_seqSecureURLs ); + SvtPathOptions aOpt; + std::transform(lURLs.begin(), lURLs.end(), lURLs.begin(), + [&aOpt](const OUString& rUrl) -> OUString { return aOpt.UseVariable( rUrl ); }); + lValues[ nRealCount ] <<= lURLs; + } + } + break; + + case PROPERTYHANDLE_DOCWARN_SAVEORSEND: + { + bDone = !m_bROSaveOrSend; + if( bDone ) + lValues[ nRealCount ] <<= m_bSaveOrSend; + } + break; + + case PROPERTYHANDLE_DOCWARN_SIGNING: + { + bDone = !m_bROSigning; + if( bDone ) + lValues[ nRealCount ] <<= m_bSigning; + } + break; + + case PROPERTYHANDLE_DOCWARN_PRINT: + { + bDone = !m_bROPrint; + if( bDone ) + lValues[ nRealCount ] <<= m_bPrint; + } + break; + + case PROPERTYHANDLE_DOCWARN_CREATEPDF: + { + bDone = !m_bROCreatePDF; + if( bDone ) + lValues[ nRealCount ] <<= m_bCreatePDF; + } + break; + + case PROPERTYHANDLE_DOCWARN_REMOVEPERSONALINFO: + { + bDone = !m_bRORemoveInfo; + if( bDone ) + lValues[ nRealCount ] <<= m_bRemoveInfo; + } + break; + + case PROPERTYHANDLE_DOCWARN_RECOMMENDPASSWORD: + { + bDone = !m_bRORecommendPwd; + if( bDone ) + lValues[ nRealCount ] <<= m_bRecommendPwd; + } + break; + + case PROPERTYHANDLE_CTRLCLICK_HYPERLINK: + { + bDone = !m_bROCtrlClickHyperlink; + if( bDone ) + lValues[ nRealCount ] <<= m_bCtrlClickHyperlink; + } + break; + + case PROPERTYHANDLE_BLOCKUNTRUSTEDREFERERLINKS: + { + bDone = !m_bROBlockUntrustedRefererLinks; + if( bDone ) + lValues[ nRealCount ] <<= m_bBlockUntrustedRefererLinks; + } + break; + + case PROPERTYHANDLE_MACRO_SECLEVEL: + { + bDone = !m_bROSecLevel; + if( bDone ) + lValues[ nRealCount ] <<= m_nSecLevel; + } + break; + + case PROPERTYHANDLE_MACRO_TRUSTEDAUTHORS: + { + bDone = !m_bROTrustedAuthors; + if( bDone ) + { + sal_Int32 nCnt = m_seqTrustedAuthors.getLength(); + if( nCnt ) + { + for( sal_Int32 i = 0; i < nCnt; ++i ) + { + OUString aPrefix( + PROPERTYNAME_MACRO_TRUSTEDAUTHORS "/a" + + OUString::number(i) + "/"); + Sequence< css::beans::PropertyValue > lPropertyValues( 3 ); + lPropertyValues[ 0 ].Name = aPrefix + PROPERTYNAME_TRUSTEDAUTHOR_SUBJECTNAME; + lPropertyValues[ 0 ].Value <<= m_seqTrustedAuthors[ i ][0]; + lPropertyValues[ 1 ].Name = aPrefix + PROPERTYNAME_TRUSTEDAUTHOR_SERIALNUMBER; + lPropertyValues[ 1 ].Value <<= m_seqTrustedAuthors[ i ][1]; + lPropertyValues[ 2 ].Name = aPrefix + PROPERTYNAME_TRUSTEDAUTHOR_RAWDATA; + lPropertyValues[ 2 ].Value <<= m_seqTrustedAuthors[ i ][2]; + + SetSetProperties( PROPERTYNAME_MACRO_TRUSTEDAUTHORS, lPropertyValues ); + } + + bDone = false; // because we save in loop above! + } + else + bDone = false; + } + } + break; + + case PROPERTYHANDLE_MACRO_DISABLE: + { + bDone = !m_bRODisableMacros; + if( bDone ) + lValues[ nRealCount ] <<= m_bDisableMacros; + } + break; + + // xmlsec05 deprecated + case PROPERTYHANDLE_STAROFFICEBASIC: + { + bDone = !m_bROBasicMode; + if( bDone ) + lValues[ nRealCount ] <<= static_cast<sal_Int32>(m_eBasicMode); + } + break; + case PROPERTYHANDLE_EXECUTEPLUGINS: + { + bDone = !m_bROExecutePlugins; + if( bDone ) + lValues[ nRealCount ] <<= m_bExecutePlugins; + } + break; + case PROPERTYHANDLE_WARNINGENABLED: + { + bDone = !m_bROWarning; + if( bDone ) + lValues[ nRealCount ] <<= m_bWarning; + } + break; + case PROPERTYHANDLE_CONFIRMATIONENABLED: + { + bDone = !m_bROConfirmation; + if( bDone ) + lValues[ nRealCount ] <<= m_bConfirmation; + } + break; + // xmlsec05 deprecated + + default: + bDone = false; + } + + if( bDone ) + { + lNames[ nRealCount ] = lOrgNames[ nProperty ]; + ++nRealCount; + } + } + // Set properties in configuration. + lNames.realloc(nRealCount); + lValues.realloc(nRealCount); + PutProperties( lNames, lValues ); +} + +bool SvtSecurityOptions_Impl::IsReadOnly( SvtSecurityOptions::EOption eOption ) const +{ + bool bReadonly; + switch(eOption) + { + case SvtSecurityOptions::EOption::SecureUrls : + bReadonly = m_bROSecureURLs; + break; + case SvtSecurityOptions::EOption::DocWarnSaveOrSend: + bReadonly = m_bROSaveOrSend; + break; + case SvtSecurityOptions::EOption::DocWarnSigning: + bReadonly = m_bROSigning; + break; + case SvtSecurityOptions::EOption::DocWarnPrint: + bReadonly = m_bROPrint; + break; + case SvtSecurityOptions::EOption::DocWarnCreatePdf: + bReadonly = m_bROCreatePDF; + break; + case SvtSecurityOptions::EOption::DocWarnRemovePersonalInfo: + bReadonly = m_bRORemoveInfo; + break; + case SvtSecurityOptions::EOption::DocWarnRecommendPassword: + bReadonly = m_bRORecommendPwd; + break; + case SvtSecurityOptions::EOption::MacroSecLevel: + bReadonly = m_bROSecLevel; + break; + case SvtSecurityOptions::EOption::MacroTrustedAuthors: + bReadonly = m_bROTrustedAuthors; + break; + case SvtSecurityOptions::EOption::CtrlClickHyperlink: + bReadonly = m_bROCtrlClickHyperlink; + break; + case SvtSecurityOptions::EOption::BlockUntrustedRefererLinks: + bReadonly = m_bROBlockUntrustedRefererLinks; + break; + + // xmlsec05 deprecated + case SvtSecurityOptions::EOption::BasicMode: + bReadonly = m_bROBasicMode; + break; + case SvtSecurityOptions::EOption::ExecutePlugins: + bReadonly = m_bROExecutePlugins; + break; + case SvtSecurityOptions::EOption::Warning: + bReadonly = m_bROWarning; + break; + case SvtSecurityOptions::EOption::Confirmation: + bReadonly = m_bROConfirmation; + break; + // xmlsec05 deprecated + + default: + bReadonly = true; + } + + return bReadonly; +} + + +void SvtSecurityOptions_Impl::SetSecureURLs( const Sequence< OUString >& seqURLList ) +{ + DBG_ASSERT(!m_bROSecureURLs, "SvtSecurityOptions_Impl::SetSecureURLs()\nYou tried to write on a readonly value!\n"); + if (!m_bROSecureURLs && m_seqSecureURLs!=seqURLList) + { + m_seqSecureURLs = seqURLList; + SetModified(); + } +} + +inline sal_Int32 SvtSecurityOptions_Impl::GetMacroSecurityLevel() const +{ + return m_nSecLevel; +} + +inline bool SvtSecurityOptions_Impl::IsMacroDisabled() const +{ + return m_bDisableMacros; +} + +void SvtSecurityOptions_Impl::SetMacroSecurityLevel( sal_Int32 _nLevel ) +{ + if( !m_bROSecLevel ) + { + if( _nLevel > 3 || _nLevel < 0 ) + _nLevel = 3; + + if( m_nSecLevel != _nLevel ) + { + m_nSecLevel = _nLevel; + SetModified(); + } + } +} + + +void SvtSecurityOptions_Impl::SetTrustedAuthors( const Sequence< SvtSecurityOptions::Certificate >& rAuthors ) +{ + DBG_ASSERT(!m_bROTrustedAuthors, "SvtSecurityOptions_Impl::SetTrustedAuthors()\nYou tried to write on a readonly value!\n"); + if( !m_bROTrustedAuthors && rAuthors != m_seqTrustedAuthors ) + { + m_seqTrustedAuthors = rAuthors; + SetModified(); + } +} + +bool SvtSecurityOptions_Impl::IsOptionSet( SvtSecurityOptions::EOption eOption ) const +{ + bool* pValue; + bool* pRO; + bool bRet = false; + + if( const_cast< SvtSecurityOptions_Impl* >( this )->GetOption( eOption, pValue, pRO ) ) + bRet = *pValue; + + return bRet; +} + +void SvtSecurityOptions_Impl::SetOption( SvtSecurityOptions::EOption eOption, bool bValue ) +{ + bool* pValue; + bool* pRO; + + if( GetOption( eOption, pValue, pRO ) && !*pRO && *pValue != bValue) + { + *pValue = bValue; + SetModified(); + } +} + +bool SvtSecurityOptions_Impl::IsOptionEnabled( SvtSecurityOptions::EOption eOption ) const +{ + bool* pValue; + bool* pRO; + bool bRet = false; + + if( const_cast< SvtSecurityOptions_Impl* >( this )->GetOption( eOption, pValue, pRO ) ) + bRet = !*pRO; + + return bRet; +} + +Sequence< OUString > SvtSecurityOptions_Impl::GetPropertyNames() +{ + return Sequence< OUString > + { + PROPERTYNAME_SECUREURL, + PROPERTYNAME_STAROFFICEBASIC, + PROPERTYNAME_EXECUTEPLUGINS, + PROPERTYNAME_WARNINGENABLED, + PROPERTYNAME_CONFIRMATIONENABLED, + PROPERTYNAME_DOCWARN_SAVEORSEND, + PROPERTYNAME_DOCWARN_SIGNING, + PROPERTYNAME_DOCWARN_PRINT, + PROPERTYNAME_DOCWARN_CREATEPDF, + PROPERTYNAME_DOCWARN_REMOVEPERSONALINFO, + PROPERTYNAME_DOCWARN_RECOMMENDPASSWORD, + PROPERTYNAME_CTRLCLICK_HYPERLINK, + PROPERTYNAME_BLOCKUNTRUSTEDREFERERLINKS, + PROPERTYNAME_MACRO_SECLEVEL, + PROPERTYNAME_MACRO_TRUSTEDAUTHORS, + PROPERTYNAME_MACRO_DISABLE + }; +} + +namespace { + +std::weak_ptr<SvtSecurityOptions_Impl> g_pSecurityOptions; + +} + +SvtSecurityOptions::SvtSecurityOptions() +{ + // Global access, must be guarded (multithreading!). + MutexGuard aGuard( GetInitMutex() ); + + m_pImpl = g_pSecurityOptions.lock(); + if( !m_pImpl ) + { + m_pImpl = std::make_shared<SvtSecurityOptions_Impl>(); + g_pSecurityOptions = m_pImpl; + + ItemHolder1::holdConfigItem(EItem::SecurityOptions); + } +} + +SvtSecurityOptions::~SvtSecurityOptions() +{ + // Global access, must be guarded (multithreading!) + MutexGuard aGuard( GetInitMutex() ); + + m_pImpl.reset(); +} + +bool SvtSecurityOptions::IsReadOnly( EOption eOption ) const +{ + MutexGuard aGuard( GetInitMutex() ); + return m_pImpl->IsReadOnly(eOption); +} + +Sequence< OUString > SvtSecurityOptions::GetSecureURLs() const +{ + MutexGuard aGuard( GetInitMutex() ); + return m_pImpl->GetSecureURLs(); +} + +void SvtSecurityOptions::SetSecureURLs( const Sequence< OUString >& seqURLList ) +{ + MutexGuard aGuard( GetInitMutex() ); + m_pImpl->SetSecureURLs( seqURLList ); +} + +bool SvtSecurityOptions::isSecureMacroUri( + OUString const & uri, OUString const & referer) const +{ + switch (INetURLObject(uri).GetProtocol()) { + case INetProtocol::Macro: + if (uri.startsWithIgnoreAsciiCase("macro:///")) { + // Denotes an App-BASIC macro (see SfxMacroLoader::loadMacro), which + // is considered safe: + return true; + } + [[fallthrough]]; + case INetProtocol::Slot: + return referer.equalsIgnoreAsciiCase("private:user") + || isTrustedLocationUri(referer); + default: + return true; + } +} + +bool SvtSecurityOptions::isUntrustedReferer(OUString const & referer) const { + MutexGuard g(GetInitMutex()); + return m_pImpl->IsOptionSet(EOption::BlockUntrustedRefererLinks) + && !(referer.isEmpty() || referer.startsWithIgnoreAsciiCase("private:") + || isTrustedLocationUri(referer)); +} + +bool SvtSecurityOptions::isTrustedLocationUri(OUString const & uri) const { + MutexGuard g(GetInitMutex()); + for (const auto & url : std::as_const(m_pImpl->m_seqSecureURLs)) + { + if (UCBContentHelper::IsSubPath(url, uri)) + { + return true; + } + } + return false; +} + +bool SvtSecurityOptions::isTrustedLocationUriForUpdatingLinks( + OUString const & uri) const +{ + return GetMacroSecurityLevel() == 0 || uri.isEmpty() + || uri.startsWithIgnoreAsciiCase("private:") + || isTrustedLocationUri(uri); +} + +sal_Int32 SvtSecurityOptions::GetMacroSecurityLevel() const +{ + MutexGuard aGuard( GetInitMutex() ); + return m_pImpl->GetMacroSecurityLevel(); +} + +void SvtSecurityOptions::SetMacroSecurityLevel( sal_Int32 _nLevel ) +{ + MutexGuard aGuard( GetInitMutex() ); + m_pImpl->SetMacroSecurityLevel( _nLevel ); +} + +bool SvtSecurityOptions::IsMacroDisabled() const +{ + MutexGuard aGuard( GetInitMutex() ); + return m_pImpl->IsMacroDisabled(); +} + +Sequence< SvtSecurityOptions::Certificate > SvtSecurityOptions::GetTrustedAuthors() const +{ + MutexGuard aGuard( GetInitMutex() ); + return m_pImpl->GetTrustedAuthors(); +} + +void SvtSecurityOptions::SetTrustedAuthors( const Sequence< Certificate >& rAuthors ) +{ + MutexGuard aGuard( GetInitMutex() ); + m_pImpl->SetTrustedAuthors( rAuthors ); +} + +bool SvtSecurityOptions::IsOptionSet( EOption eOption ) const +{ + MutexGuard aGuard( GetInitMutex() ); + return m_pImpl->IsOptionSet( eOption ); +} + +void SvtSecurityOptions::SetOption( EOption eOption, bool bValue ) +{ + MutexGuard aGuard( GetInitMutex() ); + m_pImpl->SetOption( eOption, bValue ); +} + +bool SvtSecurityOptions::IsOptionEnabled( EOption eOption ) const +{ + MutexGuard aGuard( GetInitMutex() ); + return m_pImpl->IsOptionEnabled( eOption ); +} + +namespace +{ + class theSecurityOptionsMutex : public rtl::Static<osl::Mutex, theSecurityOptionsMutex>{}; +} + +Mutex& SvtSecurityOptions::GetInitMutex() +{ + return theSecurityOptionsMutex::get(); +} + +void SvtSecurityOptions_Impl::SetBasicMode( EBasicSecurityMode eMode ) +{ + DBG_ASSERT(!m_bROBasicMode, "SvtSecurityOptions_Impl::SetBasicMode()\nYou tried to write on a readonly value!\n"); + if (!m_bROBasicMode && m_eBasicMode!=eMode) + { + m_eBasicMode = eMode; + SetModified(); + } +} + + +void SvtSecurityOptions_Impl::SetExecutePlugins( bool bSet ) +{ + DBG_ASSERT(!m_bROExecutePlugins, "SvtSecurityOptions_Impl::SetExecutePlugins()\nYou tried to write on a readonly value!\n"); + if (!m_bROExecutePlugins && m_bExecutePlugins!=bSet) + { + m_bExecutePlugins = bSet; + SetModified(); + } +} + + +void SvtSecurityOptions_Impl::SetWarningEnabled( bool bSet ) +{ + DBG_ASSERT(!m_bROWarning, "SvtSecurityOptions_Impl::SetWarningEnabled()\nYou tried to write on a readonly value!\n"); + if (!m_bROWarning && m_bWarning!=bSet) + { + m_bWarning = bSet; + SetModified(); + } +} + + +void SvtSecurityOptions_Impl::SetConfirmationEnabled( bool bSet ) +{ + DBG_ASSERT(!m_bROConfirmation, "SvtSecurityOptions_Impl::SetConfirmationEnabled()\nYou tried to write on a readonly value!\n"); + if (!m_bROConfirmation && m_bConfirmation!=bSet) + { + m_bConfirmation = bSet; + SetModified(); + } +} + +bool SvtSecurityOptions::IsExecutePlugins() const +{ + MutexGuard aGuard( GetInitMutex() ); + return m_pImpl->IsExecutePlugins(); +} + +void SvtSecurityOptions::SetExecutePlugins( bool bSet ) +{ + MutexGuard aGuard( GetInitMutex() ); + m_pImpl->SetExecutePlugins( bSet ); +} + +bool SvtSecurityOptions::IsWarningEnabled() const +{ + MutexGuard aGuard( GetInitMutex() ); + return m_pImpl->IsWarningEnabled(); +} + +void SvtSecurityOptions::SetWarningEnabled( bool bSet ) +{ + MutexGuard aGuard( GetInitMutex() ); + m_pImpl->SetWarningEnabled( bSet ); +} + +bool SvtSecurityOptions::IsConfirmationEnabled() const +{ + MutexGuard aGuard( GetInitMutex() ); + return m_pImpl->IsConfirmationEnabled(); +} + +void SvtSecurityOptions::SetConfirmationEnabled( bool bSet ) +{ + MutexGuard aGuard( GetInitMutex() ); + m_pImpl->SetConfirmationEnabled( bSet ); +} + +void SvtSecurityOptions::SetBasicMode( EBasicSecurityMode eMode ) +{ + MutexGuard aGuard( GetInitMutex() ); + m_pImpl->SetBasicMode( eMode ); +} + +EBasicSecurityMode SvtSecurityOptions::GetBasicMode() const +{ + MutexGuard aGuard( GetInitMutex() ); + return m_pImpl->GetBasicMode(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/unotools/source/config/syslocaleoptions.cxx b/unotools/source/config/syslocaleoptions.cxx new file mode 100644 index 000000000..7cbb817ee --- /dev/null +++ b/unotools/source/config/syslocaleoptions.cxx @@ -0,0 +1,710 @@ +/* -*- 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 . + */ + +#include <com/sun/star/uno/Sequence.hxx> +#include <rtl/instance.hxx> +#include <sal/log.hxx> +#include <i18nlangtag/mslangid.hxx> +#include <i18nlangtag/languagetag.hxx> +#include <tools/debug.hxx> +#include <tools/link.hxx> +#include <unotools/syslocaleoptions.hxx> +#include <unotools/configmgr.hxx> +#include <unotools/configitem.hxx> +#include <com/sun/star/uno/Any.hxx> + +#include "itemholder1.hxx" + +#define CFG_READONLY_DEFAULT false + +using namespace osl; +using namespace utl; +using namespace com::sun::star::uno; +using namespace com::sun::star::lang; + +namespace +{ + std::weak_ptr<SvtSysLocaleOptions_Impl> g_pSysLocaleOptions; + struct CurrencyChangeLink + : public rtl::Static<Link<LinkParamNone*,void>, CurrencyChangeLink> {}; + +Mutex& GetMutex() +{ + // #i77768# Due to a static reference in the toolkit lib + // we need a mutex that lives longer than the svl library. + // Otherwise the dtor would use a destructed mutex!! + static Mutex* persistentMutex(new Mutex); + + return *persistentMutex; +} + +} + +class SvtSysLocaleOptions_Impl : public utl::ConfigItem +{ + LanguageTag m_aRealLocale; + LanguageTag m_aRealUILocale; + OUString m_aLocaleString; // en-US or de-DE or empty for SYSTEM + OUString m_aUILocaleString; // en-US or de-DE or empty for SYSTEM + OUString m_aCurrencyString; // USD-en-US or EUR-de-DE + OUString m_aDatePatternsString; // "Y-M-D;M-D" + bool m_bDecimalSeparator; //use decimal separator same as locale + bool m_bIgnoreLanguageChange; //OS language change doesn't affect LO document language + + bool m_bROLocale; + bool m_bROUILocale; + bool m_bROCurrency; + bool m_bRODatePatterns; + bool m_bRODecimalSeparator; + bool m_bROIgnoreLanguageChange; + + static Sequence<OUString> GetPropertyNames(); + void MakeRealLocale(); + void MakeRealUILocale(); + + virtual void ImplCommit() override; + +public: + SvtSysLocaleOptions_Impl(); + virtual ~SvtSysLocaleOptions_Impl() override; + + virtual void Notify( const css::uno::Sequence< OUString >& aPropertyNames ) override; + + const OUString& GetLocaleString() const + { return m_aLocaleString; } + void SetLocaleString( const OUString& rStr ); + + void SetUILocaleString( const OUString& rStr ); + + const OUString& GetCurrencyString() const + { return m_aCurrencyString; } + void SetCurrencyString( const OUString& rStr ); + + const OUString& GetDatePatternsString() const + { return m_aDatePatternsString; } + void SetDatePatternsString( const OUString& rStr ); + + bool IsDecimalSeparatorAsLocale() const { return m_bDecimalSeparator;} + void SetDecimalSeparatorAsLocale( bool bSet); + + bool IsIgnoreLanguageChange() const { return m_bIgnoreLanguageChange;} + void SetIgnoreLanguageChange( bool bSet); + + bool IsReadOnly( SvtSysLocaleOptions::EOption eOption ) const; + const LanguageTag& GetRealLocale() const { return m_aRealLocale; } + const LanguageTag& GetRealUILocale() const { return m_aRealUILocale; } +}; + +#define ROOTNODE_SYSLOCALE "Setup/L10N" + +#define PROPERTYNAME_LOCALE "ooSetupSystemLocale" +#define PROPERTYNAME_UILOCALE "ooLocale" +#define PROPERTYNAME_CURRENCY "ooSetupCurrency" +#define PROPERTYNAME_DECIMALSEPARATOR "DecimalSeparatorAsLocale" +#define PROPERTYNAME_DATEPATTERNS "DateAcceptancePatterns" +#define PROPERTYNAME_IGNORELANGCHANGE "IgnoreLanguageChange" + +#define PROPERTYHANDLE_LOCALE 0 +#define PROPERTYHANDLE_UILOCALE 1 +#define PROPERTYHANDLE_CURRENCY 2 +#define PROPERTYHANDLE_DECIMALSEPARATOR 3 +#define PROPERTYHANDLE_DATEPATTERNS 4 +#define PROPERTYHANDLE_IGNORELANGCHANGE 5 + +Sequence< OUString > SvtSysLocaleOptions_Impl::GetPropertyNames() +{ + return Sequence< OUString > + { + PROPERTYNAME_LOCALE, + PROPERTYNAME_UILOCALE, + PROPERTYNAME_CURRENCY, + PROPERTYNAME_DECIMALSEPARATOR, + PROPERTYNAME_DATEPATTERNS, + PROPERTYNAME_IGNORELANGCHANGE + }; +} + +SvtSysLocaleOptions_Impl::SvtSysLocaleOptions_Impl() + : ConfigItem( ROOTNODE_SYSLOCALE ) + , m_aRealLocale( LANGUAGE_SYSTEM) + , m_aRealUILocale( LANGUAGE_SYSTEM) + , m_bDecimalSeparator( true ) + , m_bIgnoreLanguageChange( false) + , m_bROLocale(CFG_READONLY_DEFAULT) + , m_bROUILocale(CFG_READONLY_DEFAULT) + , m_bROCurrency(CFG_READONLY_DEFAULT) + , m_bRODatePatterns(CFG_READONLY_DEFAULT) + , m_bRODecimalSeparator(false) + , m_bROIgnoreLanguageChange(false) + +{ + const Sequence< OUString > aNames = GetPropertyNames(); + Sequence< Any > aValues = GetProperties( aNames ); + Sequence< sal_Bool > aROStates = GetReadOnlyStates( aNames ); + const Any* pValues = aValues.getConstArray(); + const sal_Bool* pROStates = aROStates.getConstArray(); + DBG_ASSERT( aValues.getLength() == aNames.getLength(), "GetProperties failed" ); + DBG_ASSERT( aROStates.getLength() == aNames.getLength(), "GetReadOnlyStates failed" ); + if ( aValues.getLength() == aNames.getLength() && aROStates.getLength() == aNames.getLength() ) + { + for ( sal_Int32 nProp = 0; nProp < aNames.getLength(); nProp++ ) + { + if ( pValues[nProp].hasValue() ) + { + switch ( nProp ) + { + case PROPERTYHANDLE_LOCALE : + { + OUString aStr; + if ( pValues[nProp] >>= aStr ) + m_aLocaleString = aStr; + else + { + SAL_WARN( "unotools.config", "Wrong property type!" ); + } + m_bROLocale = pROStates[nProp]; + } + break; + case PROPERTYHANDLE_UILOCALE : + { + OUString aStr; + if ( pValues[nProp] >>= aStr ) + m_aUILocaleString = aStr; + else + { + SAL_WARN( "unotools.config", "Wrong property type!" ); + } + m_bROUILocale = pROStates[nProp]; + } + break; + case PROPERTYHANDLE_CURRENCY : + { + OUString aStr; + if ( pValues[nProp] >>= aStr ) + m_aCurrencyString = aStr; + else + { + SAL_WARN( "unotools.config", "Wrong property type!" ); + } + m_bROCurrency = pROStates[nProp]; + } + break; + case PROPERTYHANDLE_DECIMALSEPARATOR: + { + bool bValue = false; + if ( pValues[nProp] >>= bValue ) + m_bDecimalSeparator = bValue; + else + { + SAL_WARN( "unotools.config", "Wrong property type!" ); + } + m_bRODecimalSeparator = pROStates[nProp]; + } + break; + case PROPERTYHANDLE_DATEPATTERNS : + { + OUString aStr; + if ( pValues[nProp] >>= aStr ) + m_aDatePatternsString = aStr; + else + { + SAL_WARN( "unotools.config", "Wrong property type!" ); + } + m_bRODatePatterns = pROStates[nProp]; + } + break; + case PROPERTYHANDLE_IGNORELANGCHANGE : + { + bool bValue = false; + if ( pValues[nProp] >>= bValue ) + m_bIgnoreLanguageChange = bValue; + else + { + SAL_WARN( "unotools.config", "Wrong property type!" ); + } + m_bROIgnoreLanguageChange = pROStates[nProp]; + } + break; + default: + SAL_WARN( "unotools.config", "Wrong property type!" ); + } + } + } + } + EnableNotification( aNames ); + + MakeRealLocale(); + MakeRealUILocale(); +} + +SvtSysLocaleOptions_Impl::~SvtSysLocaleOptions_Impl() +{ + assert(!IsModified()); // should have been committed +} + +void SvtSysLocaleOptions_Impl::MakeRealLocale() +{ + if (m_aLocaleString.isEmpty()) + { + LanguageType nLang = MsLangId::getSystemLanguage(); + m_aRealLocale.reset( nLang).makeFallback(); + } + else + { + m_aRealLocale.reset( m_aLocaleString).makeFallback(); + } +} + +void SvtSysLocaleOptions_Impl::MakeRealUILocale() +{ + if (m_aUILocaleString.isEmpty()) + { + LanguageType nLang = MsLangId::getSystemUILanguage(); + m_aRealUILocale.reset( nLang).makeFallback(); + } + else + { + m_aRealUILocale.reset( m_aUILocaleString).makeFallback(); + } +} + +bool SvtSysLocaleOptions_Impl::IsReadOnly( SvtSysLocaleOptions::EOption eOption ) const +{ + bool bReadOnly = CFG_READONLY_DEFAULT; + switch(eOption) + { + case SvtSysLocaleOptions::EOption::Locale : + { + bReadOnly = m_bROLocale; + break; + } + case SvtSysLocaleOptions::EOption::Currency : + { + bReadOnly = m_bROCurrency; + break; + } + case SvtSysLocaleOptions::EOption::DatePatterns : + { + bReadOnly = m_bRODatePatterns; + break; + } + } + return bReadOnly; +} + +void SvtSysLocaleOptions_Impl::ImplCommit() +{ + const Sequence< OUString > aOrgNames = GetPropertyNames(); + sal_Int32 nOrgCount = aOrgNames.getLength(); + + Sequence< OUString > aNames( nOrgCount ); + Sequence< Any > aValues( nOrgCount ); + + OUString* pNames = aNames.getArray(); + Any* pValues = aValues.getArray(); + sal_Int32 nRealCount = 0; + + for ( sal_Int32 nProp = 0; nProp < nOrgCount; nProp++ ) + { + switch ( nProp ) + { + case PROPERTYHANDLE_LOCALE : + { + if (!m_bROLocale) + { + pNames[nRealCount] = aOrgNames[nProp]; + pValues[nRealCount] <<= m_aLocaleString; + ++nRealCount; + } + } + break; + case PROPERTYHANDLE_UILOCALE : + { + if (!m_bROUILocale) + { + pNames[nRealCount] = aOrgNames[nProp]; + pValues[nRealCount] <<= m_aUILocaleString; + ++nRealCount; + } + } + break; + case PROPERTYHANDLE_CURRENCY : + { + if (!m_bROCurrency) + { + pNames[nRealCount] = aOrgNames[nProp]; + pValues[nRealCount] <<= m_aCurrencyString; + ++nRealCount; + } + } + break; + case PROPERTYHANDLE_DECIMALSEPARATOR: + if( !m_bRODecimalSeparator ) + { + pNames[nRealCount] = aOrgNames[nProp]; + pValues[nRealCount] <<= m_bDecimalSeparator; + ++nRealCount; + } + break; + case PROPERTYHANDLE_DATEPATTERNS : + if (!m_bRODatePatterns) + { + pNames[nRealCount] = aOrgNames[nProp]; + pValues[nRealCount] <<= m_aDatePatternsString; + ++nRealCount; + } + break; + case PROPERTYHANDLE_IGNORELANGCHANGE : + if (!m_bROIgnoreLanguageChange) + { + pNames[nRealCount] = aOrgNames[nProp]; + pValues[nRealCount] <<= m_bIgnoreLanguageChange; + ++nRealCount; + } + break; + default: + SAL_WARN( "unotools.config", "invalid index to save a path" ); + } + } + aNames.realloc(nRealCount); + aValues.realloc(nRealCount); + PutProperties( aNames, aValues ); +} + +void SvtSysLocaleOptions_Impl::SetLocaleString( const OUString& rStr ) +{ + ConfigurationHints nHint = ConfigurationHints::Locale; + { + MutexGuard aGuard( GetMutex() ); + if (m_bROLocale || rStr == m_aLocaleString ) + { + return; + } + m_aLocaleString = rStr; + MakeRealLocale(); + LanguageTag::setConfiguredSystemLanguage( m_aRealLocale.getLanguageType() ); + SetModified(); + if ( m_aCurrencyString.isEmpty() ) + nHint |= ConfigurationHints::Currency; + } + NotifyListeners( nHint ); +} + +void SvtSysLocaleOptions_Impl::SetUILocaleString( const OUString& rStr ) +{ + { + MutexGuard aGuard( GetMutex() ); + if (m_bROUILocale || rStr == m_aUILocaleString ) + { + return; + } + m_aUILocaleString = rStr; + + // as we can't switch UILocale at runtime, we only store changes in the configuration + MakeRealUILocale(); + SetModified(); + } + NotifyListeners( ConfigurationHints::UiLocale ); +} + +void SvtSysLocaleOptions_Impl::SetCurrencyString( const OUString& rStr ) +{ + { + MutexGuard aGuard( GetMutex() ); + if (m_bROCurrency || rStr == m_aCurrencyString ) + { + return; + } + m_aCurrencyString = rStr; + SetModified(); + } + NotifyListeners( ConfigurationHints::Currency ); +} + +void SvtSysLocaleOptions_Impl::SetDatePatternsString( const OUString& rStr ) +{ + { + MutexGuard aGuard( GetMutex() ); + if (m_bRODatePatterns || rStr == m_aDatePatternsString ) + { + return; + } + m_aDatePatternsString = rStr; + SetModified(); + } + NotifyListeners( ConfigurationHints::DatePatterns ); +} + +void SvtSysLocaleOptions_Impl::SetDecimalSeparatorAsLocale( bool bSet) +{ + { + MutexGuard aGuard( GetMutex() ); + if(bSet == m_bDecimalSeparator) + { + return; + } + m_bDecimalSeparator = bSet; + SetModified(); + } + NotifyListeners( ConfigurationHints::DecSep ); +} + +void SvtSysLocaleOptions_Impl::SetIgnoreLanguageChange( bool bSet) +{ + { + MutexGuard aGuard( GetMutex() ); + if(bSet == m_bIgnoreLanguageChange) + { + return; + } + m_bIgnoreLanguageChange = bSet; + SetModified(); + } + NotifyListeners( ConfigurationHints::IgnoreLang ); +} + +void SvtSysLocaleOptions_Impl::Notify( const Sequence< OUString >& seqPropertyNames ) +{ + ConfigurationHints nHint = ConfigurationHints::NONE; + Sequence< Any > seqValues = GetProperties( seqPropertyNames ); + Sequence< sal_Bool > seqROStates = GetReadOnlyStates( seqPropertyNames ); + sal_Int32 nCount = seqPropertyNames.getLength(); + for( sal_Int32 nProp = 0; nProp < nCount; ++nProp ) + { + if( seqPropertyNames[nProp] == PROPERTYNAME_LOCALE ) + { + DBG_ASSERT( seqValues[nProp].getValueTypeClass() == TypeClass_STRING, "Locale property type" ); + seqValues[nProp] >>= m_aLocaleString; + m_bROLocale = seqROStates[nProp]; + nHint |= ConfigurationHints::Locale; + if ( m_aCurrencyString.isEmpty() ) + nHint |= ConfigurationHints::Currency; + MakeRealLocale(); + } + if( seqPropertyNames[nProp] == PROPERTYNAME_UILOCALE ) + { + DBG_ASSERT( seqValues[nProp].getValueTypeClass() == TypeClass_STRING, "Locale property type" ); + seqValues[nProp] >>= m_aUILocaleString; + m_bROUILocale = seqROStates[nProp]; + nHint |= ConfigurationHints::UiLocale; + MakeRealUILocale(); + } + else if( seqPropertyNames[nProp] == PROPERTYNAME_CURRENCY ) + { + DBG_ASSERT( seqValues[nProp].getValueTypeClass() == TypeClass_STRING, "Currency property type" ); + seqValues[nProp] >>= m_aCurrencyString; + m_bROCurrency = seqROStates[nProp]; + nHint |= ConfigurationHints::Currency; + } + else if( seqPropertyNames[nProp] == PROPERTYNAME_DECIMALSEPARATOR ) + { + seqValues[nProp] >>= m_bDecimalSeparator; + m_bRODecimalSeparator = seqROStates[nProp]; + } + else if( seqPropertyNames[nProp] == PROPERTYNAME_IGNORELANGCHANGE ) + { + seqValues[nProp] >>= m_bIgnoreLanguageChange; + m_bROIgnoreLanguageChange = seqROStates[nProp]; + } + else if( seqPropertyNames[nProp] == PROPERTYNAME_DATEPATTERNS ) + { + DBG_ASSERT( seqValues[nProp].getValueTypeClass() == TypeClass_STRING, "DatePatterns property type" ); + seqValues[nProp] >>= m_aDatePatternsString; + m_bRODatePatterns = seqROStates[nProp]; + nHint |= ConfigurationHints::DatePatterns; + } + } + if ( nHint != ConfigurationHints::NONE ) + NotifyListeners( nHint ); +} + +SvtSysLocaleOptions::SvtSysLocaleOptions() +{ + MutexGuard aGuard( GetMutex() ); + pImpl = g_pSysLocaleOptions.lock(); + if ( !pImpl ) + { + pImpl = std::make_shared<SvtSysLocaleOptions_Impl>(); + g_pSysLocaleOptions = pImpl; + if (!utl::ConfigManager::IsFuzzing()) + ItemHolder1::holdConfigItem(EItem::SysLocaleOptions); + } + pImpl->AddListener(this); +} + +SvtSysLocaleOptions::~SvtSysLocaleOptions() +{ + MutexGuard aGuard( GetMutex() ); + pImpl->RemoveListener(this); + pImpl.reset(); +} + +bool SvtSysLocaleOptions::IsModified() const +{ + MutexGuard aGuard( GetMutex() ); + return pImpl->IsModified(); +} + +void SvtSysLocaleOptions::Commit() +{ + MutexGuard aGuard( GetMutex() ); + pImpl->Commit(); +} + +void SvtSysLocaleOptions::BlockBroadcasts( bool bBlock ) +{ + MutexGuard aGuard( GetMutex() ); + pImpl->BlockBroadcasts( bBlock ); +} + +void SvtSysLocaleOptions::SetLocaleConfigString( const OUString& rStr ) +{ + pImpl->SetLocaleString( rStr ); +} + +void SvtSysLocaleOptions::SetUILocaleConfigString( const OUString& rStr ) +{ + pImpl->SetUILocaleString( rStr ); +} + +const OUString& SvtSysLocaleOptions::GetCurrencyConfigString() const +{ + MutexGuard aGuard( GetMutex() ); + return pImpl->GetCurrencyString(); +} + +void SvtSysLocaleOptions::SetCurrencyConfigString( const OUString& rStr ) +{ + pImpl->SetCurrencyString( rStr ); +} + +const OUString& SvtSysLocaleOptions::GetDatePatternsConfigString() const +{ + MutexGuard aGuard( GetMutex() ); + return pImpl->GetDatePatternsString(); +} + +void SvtSysLocaleOptions::SetDatePatternsConfigString( const OUString& rStr ) +{ + pImpl->SetDatePatternsString( rStr ); +} + +bool SvtSysLocaleOptions::IsDecimalSeparatorAsLocale() const +{ + MutexGuard aGuard( GetMutex() ); + return pImpl->IsDecimalSeparatorAsLocale(); +} + +void SvtSysLocaleOptions::SetDecimalSeparatorAsLocale( bool bSet) +{ + pImpl->SetDecimalSeparatorAsLocale(bSet); +} + +bool SvtSysLocaleOptions::IsIgnoreLanguageChange() const +{ + MutexGuard aGuard( GetMutex() ); + return pImpl->IsIgnoreLanguageChange(); +} + +void SvtSysLocaleOptions::SetIgnoreLanguageChange( bool bSet) +{ + pImpl->SetIgnoreLanguageChange(bSet); +} + +bool SvtSysLocaleOptions::IsReadOnly( EOption eOption ) const +{ + MutexGuard aGuard( GetMutex() ); + return pImpl->IsReadOnly( eOption ); +} + +// static +void SvtSysLocaleOptions::GetCurrencyAbbrevAndLanguage( OUString& rAbbrev, + LanguageType& eLang, + const OUString& rConfigString ) +{ + sal_Int32 nDelim = rConfigString.indexOf( '-' ); + if ( nDelim >= 0 ) + { + rAbbrev = rConfigString.copy( 0, nDelim ); + OUString aIsoStr( rConfigString.copy( nDelim+1 ) ); + eLang = LanguageTag::convertToLanguageTypeWithFallback( aIsoStr ); + } + else + { + rAbbrev = rConfigString; + eLang = (rAbbrev.isEmpty() ? LANGUAGE_SYSTEM : LANGUAGE_NONE); + } +} + +// static +OUString SvtSysLocaleOptions::CreateCurrencyConfigString( + const OUString& rAbbrev, LanguageType eLang ) +{ + OUString aIsoStr( LanguageTag::convertToBcp47( eLang ) ); + if ( !aIsoStr.isEmpty() ) + { + return rAbbrev + "-" + aIsoStr; + } + else + return rAbbrev; +} + +// static +void SvtSysLocaleOptions::SetCurrencyChangeLink( const Link<LinkParamNone*,void>& rLink ) +{ + MutexGuard aGuard( GetMutex() ); + DBG_ASSERT( !CurrencyChangeLink::get().IsSet(), "SvtSysLocaleOptions::SetCurrencyChangeLink: already set" ); + CurrencyChangeLink::get() = rLink; +} + +// static +const Link<LinkParamNone*,void>& SvtSysLocaleOptions::GetCurrencyChangeLink() +{ + MutexGuard aGuard( GetMutex() ); + return CurrencyChangeLink::get(); +} + +void SvtSysLocaleOptions::ConfigurationChanged( utl::ConfigurationBroadcaster* p, ConfigurationHints nHint ) +{ + if ( nHint & ConfigurationHints::Currency ) + { + const Link<LinkParamNone*,void>& rLink = GetCurrencyChangeLink(); + rLink.Call( nullptr ); + } + + ::utl::detail::Options::ConfigurationChanged( p, nHint ); +} + +LanguageTag SvtSysLocaleOptions::GetLanguageTag() const +{ + MutexGuard aGuard( GetMutex() ); + return LanguageTag( pImpl->GetLocaleString() ); +} + +const LanguageTag & SvtSysLocaleOptions::GetRealLanguageTag() const +{ + return pImpl->GetRealLocale(); +} + +const LanguageTag & SvtSysLocaleOptions::GetRealUILanguageTag() const +{ + return pImpl->GetRealUILocale(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/unotools/source/config/useroptions.cxx b/unotools/source/config/useroptions.cxx new file mode 100644 index 000000000..66f354ef5 --- /dev/null +++ b/unotools/source/config/useroptions.cxx @@ -0,0 +1,348 @@ +/* -*- 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 . + */ + +#include <sal/config.h> + +#include <unotools/useroptions.hxx> +#include <unotools/syslocale.hxx> +#include <com/sun/star/uno/Any.hxx> +#include <osl/mutex.hxx> +#include <rtl/instance.hxx> +#include "itemholder1.hxx" + +#include <cppuhelper/implbase.hxx> +#include <com/sun/star/beans/Property.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <com/sun/star/container/XNameAccess.hpp> +#include <com/sun/star/util/XChangesListener.hpp> +#include <com/sun/star/util/XChangesNotifier.hpp> +#include <com/sun/star/util/ChangesEvent.hpp> +#include <comphelper/configurationhelper.hxx> +#include <comphelper/processfactory.hxx> +#include <i18nlangtag/mslangid.hxx> +#include <i18nlangtag/languagetag.hxx> +#include <o3tl/enumarray.hxx> +#include <tools/diagnose_ex.h> + +using namespace utl; +using namespace com::sun::star; + +// vOptionNames[] -- names of the user option entries +// The order must correspond to the enum class UserOptToken in useroptions.hxx. +static o3tl::enumarray<UserOptToken, char const *> vOptionNames = { + "l", // UserOptToken::City + "o", // UserOptToken::Company + "c", // UserOptToken::Country + "mail", // UserOptToken::Email + "facsimiletelephonenumber", // UserOptToken::Fax + "givenname", // UserOptToken::FirstName + "sn", // UserOptToken::LastName + "position", // UserOptToken::Position + "st", // UserOptToken::State + "street", // UserOptToken::Street + "homephone", // UserOptToken::TelephoneHome + "telephonenumber", // UserOptToken::TelephoneWork + "title", // UserOptToken::Title + "initials", // UserOptToken::ID + "postalcode", // UserOptToken::Zip + "fathersname", // UserOptToken::FathersName + "apartment", // UserOptToken::Apartment + "signingkey", // UserOptToken::SigningKey + "encryptionkey", // UserOptToken::EncryptionKey + "encrypttoself" // UserOptToken::EncryptToSelf +}; + +std::weak_ptr<SvtUserOptions::Impl> SvtUserOptions::xSharedImpl; + +class SvtUserOptions::ChangeListener : public cppu::WeakImplHelper<util::XChangesListener> +{ +public: + explicit ChangeListener (Impl& rParent): m_rParent(rParent) { } + + // XChangesListener + virtual void SAL_CALL changesOccurred (util::ChangesEvent const& Event) override; + // XEventListener + virtual void SAL_CALL disposing (lang::EventObject const& Source) override; + +private: + Impl& m_rParent; +}; + +class SvtUserOptions::Impl : public utl::ConfigurationBroadcaster +{ +public: + Impl (); + + OUString GetFullName () const; + + bool IsTokenReadonly (UserOptToken nToken) const; + OUString GetToken (UserOptToken nToken) const; + void SetToken (UserOptToken nToken, OUString const& rNewToken); + bool GetBoolValue (UserOptToken nToken) const; + void SetBoolValue (UserOptToken nToken, bool bNewValue); + void Notify (); + +private: + uno::Reference<util::XChangesListener> m_xChangeListener; + uno::Reference<container::XNameAccess> m_xCfg; + uno::Reference<beans::XPropertySet> m_xData; + + template < typename ValueType > + ValueType GetValue_Impl( UserOptToken nToken ) const; + template < typename ValueType > + void SetValue_Impl( UserOptToken nToken, ValueType const& rNewValue ); +}; + +void SvtUserOptions::ChangeListener::changesOccurred (util::ChangesEvent const& rEvent) +{ + if (rEvent.Changes.hasElements()) + m_rParent.Notify(); +} + +void SvtUserOptions::ChangeListener::disposing (lang::EventObject const& rSource) +{ + try + { + uno::Reference<util::XChangesNotifier> xChgNot(rSource.Source, uno::UNO_QUERY_THROW); + xChgNot->removeChangesListener(this); + } + catch (uno::Exception&) + { + } +} + +SvtUserOptions::Impl::Impl() : + m_xChangeListener( new ChangeListener(*this) ) +{ + try + { + m_xCfg.set( + comphelper::ConfigurationHelper::openConfig( + comphelper::getProcessComponentContext(), + "org.openoffice.UserProfile/Data", + comphelper::EConfigurationModes::Standard + ), + uno::UNO_QUERY + ); + + m_xData.set(m_xCfg, uno::UNO_QUERY); + uno::Reference<util::XChangesNotifier> xChgNot(m_xCfg, uno::UNO_QUERY); + try + { + xChgNot->addChangesListener(m_xChangeListener); + } + catch (uno::RuntimeException&) + { + } + } + catch (uno::Exception const&) + { + DBG_UNHANDLED_EXCEPTION("unotools.config"); + m_xCfg.clear(); + } +} + +template < typename ValueType > +ValueType SvtUserOptions::Impl::GetValue_Impl (UserOptToken nToken) const +{ + ValueType sToken = ValueType(); + try + { + if (m_xData.is()) + m_xData->getPropertyValue(OUString::createFromAscii(vOptionNames[nToken])) >>= sToken; + } + catch (uno::Exception const&) + { + DBG_UNHANDLED_EXCEPTION("unotools.config"); + } + return sToken; +} + +template < typename ValueType > +void SvtUserOptions::Impl::SetValue_Impl (UserOptToken nToken, ValueType const& sToken) +{ + try + { + if (m_xData.is()) + m_xData->setPropertyValue(OUString::createFromAscii(vOptionNames[nToken]), uno::makeAny(sToken)); + comphelper::ConfigurationHelper::flush(m_xCfg); + } + catch (uno::Exception const&) + { + DBG_UNHANDLED_EXCEPTION("unotools.config"); + } +} + +OUString SvtUserOptions::Impl::GetToken (UserOptToken nToken) const +{ + return GetValue_Impl<OUString>( nToken ); +} + +void SvtUserOptions::Impl::SetToken (UserOptToken nToken, OUString const& sToken) +{ + SetValue_Impl<OUString>( nToken, sToken ); +} + +bool SvtUserOptions::Impl::GetBoolValue (UserOptToken nToken) const +{ + return GetValue_Impl<bool>( nToken ); +} + +void SvtUserOptions::Impl::SetBoolValue (UserOptToken nToken, bool bNewValue) +{ + SetValue_Impl<bool>( nToken, bNewValue ); +} + +OUString SvtUserOptions::Impl::GetFullName () const +{ + OUString sFullName; + LanguageType const eLang = SvtSysLocale().GetUILanguageTag().getLanguageType(); + if (eLang == LANGUAGE_RUSSIAN) + { + sFullName = GetToken(UserOptToken::FirstName).trim(); + if (!sFullName.isEmpty()) + sFullName += " "; + sFullName += GetToken(UserOptToken::FathersName).trim(); + if (!sFullName.isEmpty()) + sFullName += " "; + sFullName += GetToken(UserOptToken::LastName).trim(); + } + else + { + if (MsLangId::isFamilyNameFirst(eLang)) + { + sFullName = GetToken(UserOptToken::LastName).trim(); + if (!sFullName.isEmpty()) + sFullName += " "; + sFullName += GetToken(UserOptToken::FirstName).trim(); + } + else + { + sFullName = GetToken(UserOptToken::FirstName).trim(); + if (!sFullName.isEmpty()) + sFullName += " "; + sFullName += GetToken(UserOptToken::LastName).trim(); + } + } + + return sFullName; +} + +void SvtUserOptions::Impl::Notify () +{ + NotifyListeners(ConfigurationHints::NONE); +} + +bool SvtUserOptions::Impl::IsTokenReadonly (UserOptToken nToken) const +{ + uno::Reference<beans::XPropertySet> xData(m_xCfg, uno::UNO_QUERY); + uno::Reference<beans::XPropertySetInfo> xInfo = xData->getPropertySetInfo(); + beans::Property aProp = xInfo->getPropertyByName(OUString::createFromAscii(vOptionNames[nToken])); + return ((aProp.Attributes & beans::PropertyAttribute::READONLY) == + beans::PropertyAttribute::READONLY); +} + +SvtUserOptions::SvtUserOptions () +{ + // Global access, must be guarded (multithreading) + osl::MutexGuard aGuard(GetInitMutex()); + + if (xSharedImpl.expired()) + { + xImpl = std::make_shared<Impl>(); + xSharedImpl = xImpl; + ItemHolder1::holdConfigItem(EItem::UserOptions); + } + xImpl = xSharedImpl.lock(); + xImpl->AddListener(this); +} + +SvtUserOptions::~SvtUserOptions() +{ + // Global access, must be guarded (multithreading) + osl::MutexGuard aGuard( GetInitMutex() ); + xImpl->RemoveListener(this); +} + +namespace +{ + class theUserOptionsMutex : public rtl::Static<osl::Mutex, theUserOptionsMutex>{}; +} + +osl::Mutex& SvtUserOptions::GetInitMutex() +{ + return theUserOptionsMutex::get(); +} + +OUString SvtUserOptions::GetCompany () const { return GetToken(UserOptToken::Company); } +OUString SvtUserOptions::GetFirstName () const { return GetToken(UserOptToken::FirstName); } +OUString SvtUserOptions::GetLastName () const { return GetToken(UserOptToken::LastName); } +OUString SvtUserOptions::GetID () const { return GetToken(UserOptToken::ID); } +OUString SvtUserOptions::GetStreet () const { return GetToken(UserOptToken::Street); } +OUString SvtUserOptions::GetCity () const { return GetToken(UserOptToken::City); } +OUString SvtUserOptions::GetState () const { return GetToken(UserOptToken::State); } +OUString SvtUserOptions::GetZip () const { return GetToken(UserOptToken::Zip); } +OUString SvtUserOptions::GetCountry () const { return GetToken(UserOptToken::Country); } +OUString SvtUserOptions::GetPosition () const { return GetToken(UserOptToken::Position); } +OUString SvtUserOptions::GetTitle () const { return GetToken(UserOptToken::Title); } +OUString SvtUserOptions::GetTelephoneHome () const { return GetToken(UserOptToken::TelephoneHome); } +OUString SvtUserOptions::GetTelephoneWork () const { return GetToken(UserOptToken::TelephoneWork); } +OUString SvtUserOptions::GetFax () const { return GetToken(UserOptToken::Fax); } +OUString SvtUserOptions::GetEmail () const { return GetToken(UserOptToken::Email); } +OUString SvtUserOptions::GetSigningKey () const { return GetToken(UserOptToken::SigningKey); } +OUString SvtUserOptions::GetEncryptionKey () const { return GetToken(UserOptToken::EncryptionKey); } + +bool SvtUserOptions::IsTokenReadonly (UserOptToken nToken) const +{ + osl::MutexGuard aGuard(GetInitMutex()); + return xImpl->IsTokenReadonly(nToken); +} + +OUString SvtUserOptions::GetToken (UserOptToken nToken) const +{ + osl::MutexGuard aGuard(GetInitMutex()); + return xImpl->GetToken(nToken); +} + +void SvtUserOptions::SetToken (UserOptToken nToken, OUString const& rNewToken) +{ + osl::MutexGuard aGuard(GetInitMutex()); + xImpl->SetToken(nToken, rNewToken); +} + +void SvtUserOptions::SetBoolValue (UserOptToken nToken, bool bNewValue) +{ + osl::MutexGuard aGuard(GetInitMutex()); + xImpl->SetBoolValue(nToken, bNewValue); +} + +bool SvtUserOptions::GetEncryptToSelf() const +{ + osl::MutexGuard aGuard(GetInitMutex()); + return xImpl->GetBoolValue(UserOptToken::EncryptToSelf); +} + +OUString SvtUserOptions::GetFullName () const +{ + osl::MutexGuard aGuard(GetInitMutex()); + return xImpl->GetFullName(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/unotools/source/config/viewoptions.cxx b/unotools/source/config/viewoptions.cxx new file mode 100644 index 000000000..4a36ad2c2 --- /dev/null +++ b/unotools/source/config/viewoptions.cxx @@ -0,0 +1,1036 @@ +/* -*- 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 . + */ + +#include <unotools/viewoptions.hxx> +#include <com/sun/star/uno/Any.hxx> + +#include <com/sun/star/beans/NamedValue.hpp> +#include <com/sun/star/container/XNameContainer.hpp> +#include <com/sun/star/container/XNameAccess.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <osl/diagnose.h> +#include <sal/log.hxx> +#include <unotools/configmgr.hxx> +#include <comphelper/configurationhelper.hxx> +#include <comphelper/processfactory.hxx> +#include <tools/diagnose_ex.h> + +#include "itemholder1.hxx" + +#define PACKAGE_VIEWS "org.openoffice.Office.Views" + +#define LIST_DIALOGS "Dialogs" +#define LIST_TABDIALOGS "TabDialogs" +#define LIST_TABPAGES "TabPages" +#define LIST_WINDOWS "Windows" + +#define PROPERTY_WINDOWSTATE "WindowState" +#define PROPERTY_PAGEID "PageID" +#define PROPERTY_VISIBLE "Visible" +#define PROPERTY_USERDATA "UserData" + +//#define DEBUG_VIEWOPTIONS + +#ifdef DEBUG_VIEWOPTIONS + #define _LOG_COUNTER_( _SVIEW_, _NREAD_, _NWRITE_ ) \ + { \ + FILE* pFile = fopen( "viewdbg.txt", "a" ); \ + fprintf( pFile, "%s[%d, %d]\n", OUStringToOString(_SVIEW_, RTL_TEXTENCODING_UTF8).getStr(), _NREAD_, _NWRITE_ ); \ + fclose( pFile ); \ + } +#endif // DEBUG_VIEWOPTIONS + +// initialization! + +SvtViewOptionsBase_Impl* SvtViewOptions::m_pDataContainer_Dialogs = nullptr ; +sal_Int32 SvtViewOptions::m_nRefCount_Dialogs = 0 ; +SvtViewOptionsBase_Impl* SvtViewOptions::m_pDataContainer_TabDialogs = nullptr ; +sal_Int32 SvtViewOptions::m_nRefCount_TabDialogs = 0 ; +SvtViewOptionsBase_Impl* SvtViewOptions::m_pDataContainer_TabPages = nullptr ; +sal_Int32 SvtViewOptions::m_nRefCount_TabPages = 0 ; +SvtViewOptionsBase_Impl* SvtViewOptions::m_pDataContainer_Windows = nullptr ; +sal_Int32 SvtViewOptions::m_nRefCount_Windows = 0 ; + +/*-************************************************************************************************************ + @descr Implement base data container for view options elements. + Every item support ALL possible configuration information. + But not every superclass should use them! Because some view types don't + have it really. + + @attention We implement a write-through cache! We use it for reading - but write all changes directly to + configuration. (changes are made on internal cache too!). So it's easier to distinguish + between added/changed/removed elements without any complex mask or bool flag information. + Caches from configuration and our own one are synchronized every time - if we do so. +*//*-*************************************************************************************************************/ +class SvtViewOptionsBase_Impl final +{ + + public: + enum State { STATE_NONE, STATE_FALSE, STATE_TRUE }; + + explicit SvtViewOptionsBase_Impl(const OUString& rList); + ~SvtViewOptionsBase_Impl ( ); + bool Exists ( const OUString& sName ); + void Delete ( const OUString& sName ); + OUString GetWindowState ( const OUString& sName ); + void SetWindowState ( const OUString& sName , + const OUString& sState ); + css::uno::Sequence< css::beans::NamedValue > GetUserData ( const OUString& sName ); + void SetUserData ( const OUString& sName , + const css::uno::Sequence< css::beans::NamedValue >& lData ); + OString GetPageID ( const OUString& sName ); + void SetPageID ( const OUString& sName , + const OString& sID ); + State GetVisible ( const OUString& sName ); + void SetVisible ( const OUString& sName , + bool bVisible ); + css::uno::Any GetUserItem ( const OUString& sName , + const OUString& sItem ); + void SetUserItem ( const OUString& sName , + const OUString& sItem , + const css::uno::Any& aValue ); + + private: + css::uno::Reference< css::uno::XInterface > impl_getSetNode( const OUString& sNode , + bool bCreateIfMissing); + + private: + OUString m_sListName; + css::uno::Reference< css::container::XNameAccess > m_xRoot; + css::uno::Reference< css::container::XNameAccess > m_xSet; + + #ifdef DEBUG_VIEWOPTIONS + sal_Int32 m_nReadCount; + sal_Int32 m_nWriteCount; + #endif +}; + +/*-************************************************************************************************************ + @descr Implement the base data container. +*//*-*************************************************************************************************************/ + +/*-************************************************************************************************************ + @short ctor + @descr We use it to open right configuration file and let configuration objects fill her caches. + Then we read all existing entries from right list and cached it inside our object too. + Normally we should enable notifications for changes on these values too ... but these feature + isn't full implemented in the moment. + + @seealso baseclass ::utl::ConfigItem + @seealso method Notify() +*//*-*************************************************************************************************************/ +SvtViewOptionsBase_Impl::SvtViewOptionsBase_Impl( const OUString& sList ) + : m_sListName ( sList ) // we must know, which view type we must support + #ifdef DEBUG_VIEWOPTIONS + , m_nReadCount ( 0 ) + , m_nWriteCount( 0 ) + #endif +{ + if (utl::ConfigManager::IsFuzzing()) + return; + + try + { + m_xRoot.set( ::comphelper::ConfigurationHelper::openConfig( + ::comphelper::getProcessComponentContext(), + PACKAGE_VIEWS, + ::comphelper::EConfigurationModes::Standard), + css::uno::UNO_QUERY); + if (m_xRoot.is()) + m_xRoot->getByName(sList) >>= m_xSet; + } + catch(const css::uno::Exception&) + { + TOOLS_WARN_EXCEPTION("unotools", "Unexpected exception"); + m_xRoot.clear(); + m_xSet.clear(); + } +} + +/*-************************************************************************************************************ + @short dtor + @descr clean up something + + @attention We implement a write through cache! So we mustn't do it really. All changes was written to cfg directly. + Commit isn't necessary then. + + @seealso baseclass ::utl::ConfigItem + @seealso method IsModified() + @seealso method SetModified() + @seealso method Commit() +*//*-*************************************************************************************************************/ +SvtViewOptionsBase_Impl::~SvtViewOptionsBase_Impl() +{ + // don't flush configuration changes here to m_xRoot. + // That must be done inside every SetXXX() method already ! + // Here it's too late - DisposedExceptions from used configuration access can occur otherwise. + + m_xRoot.clear(); + m_xSet.clear(); + + #ifdef DEBUG_VIEWOPTIONS + _LOG_COUNTER_( m_sListName, m_nReadCount, m_nWriteCount ) + #endif // DEBUG_VIEWOPTIONS +} + +/*-************************************************************************************************************ + @short checks for already existing entries + @descr If user don't know, if an entry already exist - he can get this information by calling this method. + + @seealso member m_aList + + @param "sName", name of entry to check exist state + @return true , if item exist + false, otherwise +*//*-*************************************************************************************************************/ +bool SvtViewOptionsBase_Impl::Exists( const OUString& sName ) +{ + bool bExists = false; + + try + { + if (m_xSet.is()) + bExists = m_xSet->hasByName(sName); + } + catch(const css::uno::Exception&) + { + TOOLS_WARN_EXCEPTION("unotools", "Unexpected exception"); + bExists = false; + } + + return bExists; +} + +/*-************************************************************************************************************ + @short delete entry + @descr Use it to delete set entry by given name. + + @seealso member m_aList + + @param "sName", name of entry to delete it +*//*-*************************************************************************************************************/ +void SvtViewOptionsBase_Impl::Delete( const OUString& sName ) +{ + #ifdef DEBUG_VIEWOPTIONS + ++m_nWriteCount; + #endif + + try + { + css::uno::Reference< css::container::XNameContainer > xSet(m_xSet, css::uno::UNO_QUERY_THROW); + xSet->removeByName(sName); + ::comphelper::ConfigurationHelper::flush(m_xRoot); + } + catch(const css::container::NoSuchElementException&) + { } + catch(const css::uno::Exception&) + { + TOOLS_WARN_EXCEPTION("unotools", "Unexpected exception"); + } +} + +/*-************************************************************************************************************ + @short read/write access to cache view items and her properties + @descr Follow methods support read/write access to all cache view items. + + @seealso member m_sList +*//*-*************************************************************************************************************/ +OUString SvtViewOptionsBase_Impl::GetWindowState( const OUString& sName ) +{ + #ifdef DEBUG_VIEWOPTIONS + ++m_nReadCount; + #endif + + OUString sWindowState; + try + { + css::uno::Reference< css::beans::XPropertySet > xNode( + impl_getSetNode(sName, false), + css::uno::UNO_QUERY); + if (xNode.is()) + xNode->getPropertyValue(PROPERTY_WINDOWSTATE) >>= sWindowState; + } + catch(const css::uno::Exception&) + { + TOOLS_WARN_EXCEPTION("unotools", "Unexpected exception"); + sWindowState.clear(); + } + + return sWindowState; +} + +void SvtViewOptionsBase_Impl::SetWindowState( const OUString& sName , + const OUString& sState ) +{ + #ifdef DEBUG_VIEWOPTIONS + ++m_nWriteCount; + #endif + + try + { + css::uno::Reference< css::beans::XPropertySet > xNode( + impl_getSetNode(sName, true), + css::uno::UNO_QUERY_THROW); + xNode->setPropertyValue(PROPERTY_WINDOWSTATE, css::uno::makeAny(sState)); + ::comphelper::ConfigurationHelper::flush(m_xRoot); + } + catch(const css::uno::Exception&) + { + TOOLS_WARN_EXCEPTION("unotools", "Unexpected exception"); + } +} + +css::uno::Sequence< css::beans::NamedValue > SvtViewOptionsBase_Impl::GetUserData( const OUString& sName ) +{ + #ifdef DEBUG_VIEWOPTIONS + ++m_nReadCount; + #endif + + try + { + css::uno::Reference< css::container::XNameAccess > xNode( + impl_getSetNode(sName, false), + css::uno::UNO_QUERY); // no _THROW ! because we don't create missing items here. So we have to live with zero references .-) + css::uno::Reference< css::container::XNameAccess > xUserData; + if (xNode.is()) + xNode->getByName(PROPERTY_USERDATA) >>= xUserData; + if (xUserData.is()) + { + const css::uno::Sequence<OUString> lNames = xUserData->getElementNames(); + sal_Int32 c = lNames.getLength(); + css::uno::Sequence< css::beans::NamedValue > lUserData(c); + + std::transform(lNames.begin(), lNames.end(), lUserData.begin(), + [&xUserData](const OUString& rName) -> css::beans::NamedValue { + return { rName, xUserData->getByName(rName) }; }); + + return lUserData; + } + } + catch(const css::uno::Exception&) + { + TOOLS_WARN_EXCEPTION("unotools", "Unexpected exception"); + } + + return css::uno::Sequence< css::beans::NamedValue >(); +} + +void SvtViewOptionsBase_Impl::SetUserData( const OUString& sName , + const css::uno::Sequence< css::beans::NamedValue >& lData ) +{ + #ifdef DEBUG_VIEWOPTIONS + ++m_nWriteCount; + #endif + + try + { + css::uno::Reference< css::container::XNameAccess > xNode( + impl_getSetNode(sName, true), + css::uno::UNO_QUERY_THROW); + css::uno::Reference< css::container::XNameContainer > xUserData; + xNode->getByName(PROPERTY_USERDATA) >>= xUserData; + if (xUserData.is()) + { + for (const css::beans::NamedValue& rData : lData) + { + if (xUserData->hasByName(rData.Name)) + xUserData->replaceByName(rData.Name, rData.Value); + else + xUserData->insertByName(rData.Name, rData.Value); + } + } + ::comphelper::ConfigurationHelper::flush(m_xRoot); + } + catch(const css::uno::Exception&) + { + TOOLS_WARN_EXCEPTION("unotools", "Unexpected exception"); + } +} + +css::uno::Any SvtViewOptionsBase_Impl::GetUserItem( const OUString& sName , + const OUString& sItem ) +{ + #ifdef DEBUG_VIEWOPTIONS + ++m_nReadCount; + #endif + + css::uno::Any aItem; + try + { + css::uno::Reference< css::container::XNameAccess > xNode( + impl_getSetNode(sName, false), + css::uno::UNO_QUERY); + css::uno::Reference< css::container::XNameAccess > xUserData; + if (xNode.is()) + xNode->getByName(PROPERTY_USERDATA) >>= xUserData; + if (xUserData.is()) + aItem = xUserData->getByName(sItem); + } + catch(const css::container::NoSuchElementException&) + { aItem.clear(); } + catch(const css::uno::Exception&) + { + TOOLS_WARN_EXCEPTION("unotools", "Unexpected exception"); + aItem.clear(); + } + + return aItem; +} + +void SvtViewOptionsBase_Impl::SetUserItem( const OUString& sName , + const OUString& sItem , + const css::uno::Any& aValue ) +{ + #ifdef DEBUG_VIEWOPTIONS + ++m_nWriteCount; + #endif + + try + { + css::uno::Reference< css::container::XNameAccess > xNode( + impl_getSetNode(sName, true), + css::uno::UNO_QUERY_THROW); + css::uno::Reference< css::container::XNameContainer > xUserData; + xNode->getByName(PROPERTY_USERDATA) >>= xUserData; + if (xUserData.is()) + { + if (xUserData->hasByName(sItem)) + xUserData->replaceByName(sItem, aValue); + else + xUserData->insertByName(sItem, aValue); + } + ::comphelper::ConfigurationHelper::flush(m_xRoot); + } + catch(const css::uno::Exception&) + { + TOOLS_WARN_EXCEPTION("unotools", "Unexpected exception"); + } +} + +OString SvtViewOptionsBase_Impl::GetPageID( const OUString& sName ) +{ + #ifdef DEBUG_VIEWOPTIONS + ++m_nReadCount; + #endif + + OUString sID; + try + { + css::uno::Reference< css::beans::XPropertySet > xNode( + impl_getSetNode(sName, false), + css::uno::UNO_QUERY); + if (xNode.is()) + xNode->getPropertyValue(PROPERTY_PAGEID) >>= sID; + } + catch(const css::uno::Exception&) + { + TOOLS_WARN_EXCEPTION("unotools", "Unexpected exception"); + } + + return sID.toUtf8(); +} + +void SvtViewOptionsBase_Impl::SetPageID( const OUString& sName , + const OString& sID ) +{ + #ifdef DEBUG_VIEWOPTIONS + ++m_nWriteCount; + #endif + + try + { + css::uno::Reference< css::beans::XPropertySet > xNode( + impl_getSetNode(sName, true), + css::uno::UNO_QUERY_THROW); + xNode->setPropertyValue(PROPERTY_PAGEID, css::uno::makeAny(OUString::fromUtf8(sID))); + ::comphelper::ConfigurationHelper::flush(m_xRoot); + } + catch(const css::uno::Exception&) + { + TOOLS_WARN_EXCEPTION("unotools", "Unexpected exception"); + } +} + +SvtViewOptionsBase_Impl::State SvtViewOptionsBase_Impl::GetVisible( const OUString& sName ) +{ + #ifdef DEBUG_VIEWOPTIONS + ++m_nReadCount; + #endif + + State eState = STATE_NONE; + try + { + css::uno::Reference< css::beans::XPropertySet > xNode( + impl_getSetNode(sName, false), + css::uno::UNO_QUERY); + if (xNode.is()) + { + bool bVisible = false; + if (xNode->getPropertyValue(PROPERTY_VISIBLE) >>= bVisible) + { + eState = bVisible ? STATE_TRUE : STATE_FALSE; + } + } + } + catch(const css::uno::Exception&) + { + TOOLS_WARN_EXCEPTION("unotools", "Unexpected exception"); + } + + return eState; +} + +void SvtViewOptionsBase_Impl::SetVisible( const OUString& sName , + bool bVisible ) +{ + #ifdef DEBUG_VIEWOPTIONS + ++m_nWriteCount; + #endif + + try + { + css::uno::Reference< css::beans::XPropertySet > xNode( + impl_getSetNode(sName, true), + css::uno::UNO_QUERY_THROW); + xNode->setPropertyValue(PROPERTY_VISIBLE, css::uno::makeAny(bVisible)); + ::comphelper::ConfigurationHelper::flush(m_xRoot); + } + catch(const css::uno::Exception&) + { + TOOLS_WARN_EXCEPTION("unotools", "Unexpected exception"); + } +} + +/*-************************************************************************************************************ + @short create new set node with default values on disk + @descr To create a new UserData item - the super node of these property must already exist! + You can call this method to create these new entry with default values and change UserData then. + + @seealso method impl_writeDirectProp() + + @param "sNode", name of new entry +*//*-*************************************************************************************************************/ +css::uno::Reference< css::uno::XInterface > SvtViewOptionsBase_Impl::impl_getSetNode( const OUString& sNode , + bool bCreateIfMissing) +{ + css::uno::Reference< css::uno::XInterface > xNode; + + try + { + if (bCreateIfMissing) + xNode = ::comphelper::ConfigurationHelper::makeSureSetNodeExists(m_xRoot, m_sListName, sNode); + else + { + if (m_xSet.is() && m_xSet->hasByName(sNode) ) + m_xSet->getByName(sNode) >>= xNode; + } + } + catch(const css::container::NoSuchElementException&) + { xNode.clear(); } + catch(const css::uno::Exception&) + { + TOOLS_WARN_EXCEPTION("unotools", "Unexpected exception"); + xNode.clear(); + } + + return xNode; +} + +// constructor + +SvtViewOptions::SvtViewOptions( EViewType eType , + const OUString& sViewName ) + : m_eViewType ( eType ) + , m_sViewName ( sViewName ) +{ + // Global access, must be guarded (multithreading!) + ::osl::MutexGuard aGuard( GetOwnStaticMutex() ); + + // Search for right dat container for this view type and initialize right data container or set right ref count! + switch( eType ) + { + case EViewType::Dialog: { + // Increase ref count for dialog data container first. + ++m_nRefCount_Dialogs; + // If these instance the first user of the dialog data container - create these impl static container! + if( m_nRefCount_Dialogs == 1 ) + { + //m_pDataContainer_Dialogs = new SvtViewDialogOptions_Impl( LIST_DIALOGS ); + m_pDataContainer_Dialogs = new SvtViewOptionsBase_Impl( LIST_DIALOGS ); + ItemHolder1::holdConfigItem(EItem::ViewOptionsDialog); + } + } + break; + case EViewType::TabDialog: { + // Increase ref count for tab-dialog data container first. + ++m_nRefCount_TabDialogs; + // If these instance the first user of the tab-dialog data container - create these impl static container! + if( m_nRefCount_TabDialogs == 1 ) + { + m_pDataContainer_TabDialogs = new SvtViewOptionsBase_Impl( LIST_TABDIALOGS ); + ItemHolder1::holdConfigItem(EItem::ViewOptionsTabDialog); + } + } + break; + case EViewType::TabPage:{ + // Increase ref count for tab-page data container first. + ++m_nRefCount_TabPages; + // If these instance the first user of the tab-page data container - create these impl static container! + if( m_nRefCount_TabPages == 1 ) + { + m_pDataContainer_TabPages = new SvtViewOptionsBase_Impl( LIST_TABPAGES ); + ItemHolder1::holdConfigItem(EItem::ViewOptionsTabPage); + } + } + break; + case EViewType::Window: { + // Increase ref count for window data container first. + ++m_nRefCount_Windows; + // If these instance the first user of the window data container - create these impl static container! + if( m_nRefCount_Windows == 1 ) + { + m_pDataContainer_Windows = new SvtViewOptionsBase_Impl( LIST_WINDOWS ); + ItemHolder1::holdConfigItem(EItem::ViewOptionsWindow); + } + } + break; + default : OSL_FAIL( "SvtViewOptions::SvtViewOptions()\nThese view type is unknown! All following calls at these instance will do nothing!" ); + } +} + +// destructor + +SvtViewOptions::~SvtViewOptions() +{ + // Global access, must be guarded (multithreading!) + ::osl::MutexGuard aGuard( GetOwnStaticMutex() ); + + // Search for right dat container for this view type and deinitialize right data container or set right ref count! + switch( m_eViewType ) + { + case EViewType::Dialog: { + // Decrease ref count for dialog data container first. + --m_nRefCount_Dialogs; + // If these instance the last user of the dialog data container - delete these impl static container! + if( m_nRefCount_Dialogs == 0 ) + { + delete m_pDataContainer_Dialogs; + m_pDataContainer_Dialogs = nullptr; + } + } + break; + case EViewType::TabDialog: { + // Decrease ref count for tab-dialog data container first. + --m_nRefCount_TabDialogs; + // If these instance the last user of the tab-dialog data container - delete these impl static container! + if( m_nRefCount_TabDialogs == 0 ) + { + delete m_pDataContainer_TabDialogs; + m_pDataContainer_TabDialogs = nullptr; + } + } + break; + case EViewType::TabPage:{ + // Decrease ref count for tab-page data container first. + --m_nRefCount_TabPages; + // If these instance the last user of the tab-page data container - delete these impl static container! + if( m_nRefCount_TabPages == 0 ) + { + delete m_pDataContainer_TabPages; + m_pDataContainer_TabPages = nullptr; + } + } + break; + case EViewType::Window: { + // Decrease ref count for window data container first. + --m_nRefCount_Windows; + // If these instance the last user of the window data container - delete these impl static container! + if( m_nRefCount_Windows == 0 ) + { + delete m_pDataContainer_Windows; + m_pDataContainer_Windows = nullptr; + } + } + break; + } +} + +// public method + +bool SvtViewOptions::Exists() const +{ + // Ready for multithreading + ::osl::MutexGuard aGuard( GetOwnStaticMutex() ); + + bool bExists = false; + switch( m_eViewType ) + { + case EViewType::Dialog: { + bExists = m_pDataContainer_Dialogs->Exists( m_sViewName ); + } + break; + case EViewType::TabDialog: { + bExists = m_pDataContainer_TabDialogs->Exists( m_sViewName ); + } + break; + case EViewType::TabPage:{ + bExists = m_pDataContainer_TabPages->Exists( m_sViewName ); + } + break; + case EViewType::Window: { + bExists = m_pDataContainer_Windows->Exists( m_sViewName ); + } + break; + } + return bExists; +} + +// public method + +void SvtViewOptions::Delete() +{ + // Ready for multithreading + ::osl::MutexGuard aGuard( GetOwnStaticMutex() ); + + switch( m_eViewType ) + { + case EViewType::Dialog : m_pDataContainer_Dialogs->Delete( m_sViewName ); + break; + case EViewType::TabDialog : m_pDataContainer_TabDialogs->Delete( m_sViewName ); + break; + case EViewType::TabPage : m_pDataContainer_TabPages->Delete( m_sViewName ); + break; + case EViewType::Window : m_pDataContainer_Windows->Delete( m_sViewName ); + break; + } +} + +// public method + +OUString SvtViewOptions::GetWindowState() const +{ + // Ready for multithreading + ::osl::MutexGuard aGuard( GetOwnStaticMutex() ); + + OUString sState; + switch( m_eViewType ) + { + case EViewType::Dialog: { + sState = m_pDataContainer_Dialogs->GetWindowState( m_sViewName ); + } + break; + case EViewType::TabDialog:{ + sState = m_pDataContainer_TabDialogs->GetWindowState( m_sViewName ); + } + break; + case EViewType::TabPage:{ + sState = m_pDataContainer_TabPages->GetWindowState( m_sViewName ); + } + break; + case EViewType::Window: { + sState = m_pDataContainer_Windows->GetWindowState( m_sViewName ); + } + break; + } + return sState; +} + +// public method + +void SvtViewOptions::SetWindowState( const OUString& sState ) +{ + // Ready for multithreading + ::osl::MutexGuard aGuard( GetOwnStaticMutex() ); + + switch( m_eViewType ) + { + case EViewType::Dialog: { + m_pDataContainer_Dialogs->SetWindowState( m_sViewName, sState ); + } + break; + case EViewType::TabDialog: { + m_pDataContainer_TabDialogs->SetWindowState( m_sViewName, sState ); + } + break; + case EViewType::TabPage:{ + m_pDataContainer_TabPages->SetWindowState( m_sViewName, sState ); + } + break; + case EViewType::Window: { + m_pDataContainer_Windows->SetWindowState( m_sViewName, sState ); + } + break; + } +} + +// public method + +OString SvtViewOptions::GetPageID() const +{ + // Ready for multithreading + ::osl::MutexGuard aGuard( GetOwnStaticMutex() ); + + // Safe impossible cases. + // These call isn't allowed for dialogs, tab-pages or windows! + OSL_ENSURE( !(m_eViewType==EViewType::Dialog||m_eViewType==EViewType::TabPage||m_eViewType==EViewType::Window), "SvtViewOptions::GetPageID()\nCall not allowed for Dialogs, TabPages or Windows! I do nothing!" ); + + OString sID; + if( m_eViewType == EViewType::TabDialog ) + sID = m_pDataContainer_TabDialogs->GetPageID( m_sViewName ); + return sID; +} + +// public method + +void SvtViewOptions::SetPageID(const OString& rID) +{ + // Ready for multithreading + ::osl::MutexGuard aGuard( GetOwnStaticMutex() ); + + // Safe impossible cases. + // These call isn't allowed for dialogs, tab-pages or windows! + OSL_ENSURE( !(m_eViewType==EViewType::Dialog||m_eViewType==EViewType::TabPage||m_eViewType==EViewType::Window), "SvtViewOptions::SetPageID()\nCall not allowed for Dialogs, TabPages or Windows! I do nothing!" ); + + if( m_eViewType == EViewType::TabDialog ) + m_pDataContainer_TabDialogs->SetPageID(m_sViewName, rID); +} + +// public method + +bool SvtViewOptions::IsVisible() const +{ + // Ready for multithreading + ::osl::MutexGuard aGuard( GetOwnStaticMutex() ); + + // Safe impossible cases. + // These call isn't allowed for dialogs, tab-dialogs or tab-pages! + OSL_ENSURE( !(m_eViewType==EViewType::Dialog||m_eViewType==EViewType::TabDialog||m_eViewType==EViewType::TabPage), "SvtViewOptions::IsVisible()\nCall not allowed for Dialogs, TabDialogs or TabPages! I do nothing!" ); + + bool bState = false; + if( m_eViewType == EViewType::Window ) + bState = m_pDataContainer_Windows->GetVisible( m_sViewName ) == SvtViewOptionsBase_Impl::STATE_TRUE; + + return bState; +} + +// public method + +void SvtViewOptions::SetVisible( bool bState ) +{ + // Ready for multithreading + ::osl::MutexGuard aGuard( GetOwnStaticMutex() ); + + // Safe impossible cases. + // These call isn't allowed for dialogs, tab-dialogs or tab-pages! + OSL_ENSURE( !(m_eViewType==EViewType::Dialog||m_eViewType==EViewType::TabDialog||m_eViewType==EViewType::TabPage), "SvtViewOptions::SetVisible()\nCall not allowed for Dialogs, TabDialogs or TabPages! I do nothing!" ); + + if( m_eViewType == EViewType::Window ) + m_pDataContainer_Windows->SetVisible( m_sViewName, bState ); +} + +// public method + +bool SvtViewOptions::HasVisible() const +{ + // Ready for multithreading + ::osl::MutexGuard aGuard( GetOwnStaticMutex() ); + + // Safe impossible cases. + // These call isn't allowed for dialogs, tab-dialogs or tab-pages! + OSL_ENSURE( !(m_eViewType==EViewType::Dialog||m_eViewType==EViewType::TabDialog||m_eViewType==EViewType::TabPage), "SvtViewOptions::IsVisible()\nCall not allowed for Dialogs, TabDialogs or TabPages! I do nothing!" ); + + bool bState = false; + if( m_eViewType == EViewType::Window ) + bState = m_pDataContainer_Windows->GetVisible( m_sViewName ) != SvtViewOptionsBase_Impl::STATE_NONE; + + return bState; +} + +css::uno::Sequence< css::beans::NamedValue > SvtViewOptions::GetUserData() const +{ + // Ready for multithreading + ::osl::MutexGuard aGuard( GetOwnStaticMutex() ); + + css::uno::Sequence< css::beans::NamedValue > lData; + switch( m_eViewType ) + { + case EViewType::Dialog: { + lData = m_pDataContainer_Dialogs->GetUserData( m_sViewName ); + } + break; + case EViewType::TabDialog: { + lData = m_pDataContainer_TabDialogs->GetUserData( m_sViewName ); + } + break; + case EViewType::TabPage:{ + lData = m_pDataContainer_TabPages->GetUserData( m_sViewName ); + } + break; + case EViewType::Window: { + lData = m_pDataContainer_Windows->GetUserData( m_sViewName ); + } + break; + } + return lData; +} + +void SvtViewOptions::SetUserData( const css::uno::Sequence< css::beans::NamedValue >& lData ) +{ + // Ready for multithreading + ::osl::MutexGuard aGuard( GetOwnStaticMutex() ); + + switch( m_eViewType ) + { + case EViewType::Dialog: { + m_pDataContainer_Dialogs->SetUserData( m_sViewName, lData ); + } + break; + case EViewType::TabDialog: { + m_pDataContainer_TabDialogs->SetUserData( m_sViewName, lData ); + } + break; + case EViewType::TabPage:{ + m_pDataContainer_TabPages->SetUserData( m_sViewName, lData ); + } + break; + case EViewType::Window: { + m_pDataContainer_Windows->SetUserData( m_sViewName, lData ); + } + break; + } +} + +css::uno::Any SvtViewOptions::GetUserItem( const OUString& sName ) const +{ + // Ready for multithreading + ::osl::MutexGuard aGuard( GetOwnStaticMutex() ); + + css::uno::Any aItem; + switch( m_eViewType ) + { + case EViewType::Dialog: { + aItem = m_pDataContainer_Dialogs->GetUserItem( m_sViewName, sName ); + } + break; + case EViewType::TabDialog: { + aItem = m_pDataContainer_TabDialogs->GetUserItem( m_sViewName, sName ); + } + break; + case EViewType::TabPage:{ + aItem = m_pDataContainer_TabPages->GetUserItem( m_sViewName, sName ); + } + break; + case EViewType::Window: { + aItem = m_pDataContainer_Windows->GetUserItem( m_sViewName, sName ); + } + break; + } + return aItem; +} + +void SvtViewOptions::SetUserItem( const OUString& sName , + const css::uno::Any& aValue ) +{ + // Ready for multithreading + ::osl::MutexGuard aGuard( GetOwnStaticMutex() ); + + switch( m_eViewType ) + { + case EViewType::Dialog: { + m_pDataContainer_Dialogs->SetUserItem( m_sViewName, sName, aValue ); + } + break; + case EViewType::TabDialog: { + m_pDataContainer_TabDialogs->SetUserItem( m_sViewName, sName, aValue ); + } + break; + case EViewType::TabPage:{ + m_pDataContainer_TabPages->SetUserItem( m_sViewName, sName, aValue ); + } + break; + case EViewType::Window: { + m_pDataContainer_Windows->SetUserItem( m_sViewName, sName, aValue ); + } + break; + } +} + +namespace +{ + class theViewOptionsMutex : public rtl::Static<osl::Mutex, theViewOptionsMutex>{}; +} + +// private method + +::osl::Mutex& SvtViewOptions::GetOwnStaticMutex() +{ + return theViewOptionsMutex::get(); +} + +void SvtViewOptions::AcquireOptions() +{ + ::osl::MutexGuard aGuard( GetOwnStaticMutex() ); + if( ++m_nRefCount_Dialogs == 1 ) + { + m_pDataContainer_Dialogs = new SvtViewOptionsBase_Impl( LIST_DIALOGS ); + ItemHolder1::holdConfigItem(EItem::ViewOptionsDialog); + } + if( ++m_nRefCount_TabDialogs == 1 ) + { + m_pDataContainer_TabDialogs = new SvtViewOptionsBase_Impl( LIST_TABDIALOGS ); + ItemHolder1::holdConfigItem(EItem::ViewOptionsTabDialog); + } + if( ++m_nRefCount_TabPages == 1 ) + { + m_pDataContainer_TabPages = new SvtViewOptionsBase_Impl( LIST_TABPAGES ); + ItemHolder1::holdConfigItem(EItem::ViewOptionsTabPage); + } + if( ++m_nRefCount_Windows == 1 ) + { + m_pDataContainer_Windows = new SvtViewOptionsBase_Impl( LIST_WINDOWS ); + ItemHolder1::holdConfigItem(EItem::ViewOptionsWindow); + } +} + +void SvtViewOptions::ReleaseOptions() +{ + ::osl::MutexGuard aGuard( GetOwnStaticMutex() ); + if( --m_nRefCount_Dialogs == 0 ) + { + delete m_pDataContainer_Dialogs; + m_pDataContainer_Dialogs = nullptr; + } + if( --m_nRefCount_TabDialogs == 0 ) + { + delete m_pDataContainer_TabDialogs; + m_pDataContainer_TabDialogs = nullptr; + } + if( --m_nRefCount_TabPages == 0 ) + { + delete m_pDataContainer_TabPages; + m_pDataContainer_TabPages = nullptr; + } + if( --m_nRefCount_Windows == 0 ) + { + delete m_pDataContainer_Windows; + m_pDataContainer_Windows = nullptr; + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |