summaryrefslogtreecommitdiffstats
path: root/unotools/source/config
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--unotools/source/config/bootstrap.cxx742
-rw-r--r--unotools/source/config/cmdoptions.cxx356
-rw-r--r--unotools/source/config/compatibility.cxx378
-rw-r--r--unotools/source/config/compatibilityviewoptions.cxx170
-rw-r--r--unotools/source/config/configitem.cxx1066
-rw-r--r--unotools/source/config/configmgr.cxx186
-rw-r--r--unotools/source/config/confignode.cxx578
-rw-r--r--unotools/source/config/configpaths.cxx284
-rw-r--r--unotools/source/config/configvaluecontainer.cxx303
-rw-r--r--unotools/source/config/defaultoptions.cxx357
-rw-r--r--unotools/source/config/docinfohelper.cxx101
-rw-r--r--unotools/source/config/dynamicmenuoptions.cxx558
-rw-r--r--unotools/source/config/eventcfg.cxx378
-rw-r--r--unotools/source/config/extendedsecurityoptions.cxx226
-rw-r--r--unotools/source/config/fltrcfg.cxx690
-rw-r--r--unotools/source/config/fontcfg.cxx1089
-rw-r--r--unotools/source/config/fontoptions.cxx302
-rw-r--r--unotools/source/config/historyoptions.cxx568
-rw-r--r--unotools/source/config/itemholder1.cxx219
-rw-r--r--unotools/source/config/itemholder1.hxx62
-rw-r--r--unotools/source/config/lingucfg.cxx1182
-rw-r--r--unotools/source/config/misccfg.cxx249
-rw-r--r--unotools/source/config/moduleoptions.cxx1118
-rw-r--r--unotools/source/config/options.cxx114
-rw-r--r--unotools/source/config/optionsdlg.cxx236
-rw-r--r--unotools/source/config/pathoptions.cxx850
-rw-r--r--unotools/source/config/printwarningoptions.cxx319
-rw-r--r--unotools/source/config/saveopt.cxx971
-rw-r--r--unotools/source/config/searchopt.cxx614
-rw-r--r--unotools/source/config/securityoptions.cxx1167
-rw-r--r--unotools/source/config/syslocaleoptions.cxx710
-rw-r--r--unotools/source/config/useroptions.cxx348
-rw-r--r--unotools/source/config/viewoptions.cxx1036
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("&amp;",nEscapePos))
+ ch = '&';
+
+ else if (aLocalString.match("&apos;",nEscapePos))
+ ch = '\'';
+
+ else if (aLocalString.match("&quot;",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( "&amp;" ); break;
+ case u'\'': aNormalized.append( "&apos;" ); break;
+ case u'\"': aNormalized.append( "&quot;" ); 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: */