summaryrefslogtreecommitdiffstats
path: root/framework/source/accelerators/presethandler.cxx
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:06:44 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:06:44 +0000
commited5640d8b587fbcfed7dd7967f3de04b37a76f26 (patch)
tree7a5f7c6c9d02226d7471cb3cc8fbbf631b415303 /framework/source/accelerators/presethandler.cxx
parentInitial commit. (diff)
downloadlibreoffice-upstream.tar.xz
libreoffice-upstream.zip
Adding upstream version 4:7.4.7.upstream/4%7.4.7upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'framework/source/accelerators/presethandler.cxx')
-rw-r--r--framework/source/accelerators/presethandler.cxx727
1 files changed, 727 insertions, 0 deletions
diff --git a/framework/source/accelerators/presethandler.cxx b/framework/source/accelerators/presethandler.cxx
new file mode 100644
index 000000000..7bd487684
--- /dev/null
+++ b/framework/source/accelerators/presethandler.cxx
@@ -0,0 +1,727 @@
+/* -*- 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 <accelerators/presethandler.hxx>
+
+#include <classes/fwkresid.hxx>
+
+#include <strings.hrc>
+
+#include <com/sun/star/configuration/CorruptedUIConfigurationException.hpp>
+#include <com/sun/star/container/XNameAccess.hpp>
+#include <com/sun/star/embed/ElementModes.hpp>
+#include <com/sun/star/embed/FileSystemStorageFactory.hpp>
+#include <com/sun/star/lang/XSingleServiceFactory.hpp>
+#include <com/sun/star/util/thePathSettings.hpp>
+
+#include <utility>
+#include <vcl/svapp.hxx>
+#include <cppuhelper/exc_hlp.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <osl/diagnose.h>
+#include <i18nlangtag/languagetag.hxx>
+
+const ::sal_Int32 ID_CORRUPT_UICONFIG_SHARE = 1;
+const ::sal_Int32 ID_CORRUPT_UICONFIG_USER = 2;
+const ::sal_Int32 ID_CORRUPT_UICONFIG_GENERAL = 3;
+
+namespace framework
+{
+
+namespace {
+
+/** @short because a concurrent access to the same storage from different implementations
+ isn't supported, we have to share it with others.
+
+ @descr This struct is allegedly shared and must be used within a
+ synchronized section. But it isn't.
+ */
+struct TSharedStorages final
+{
+ StorageHolder m_lStoragesShare;
+ StorageHolder m_lStoragesUser;
+
+ TSharedStorages()
+ {};
+};
+
+/** @short provides access to the:
+ a) shared root storages
+ b) shared "inbetween" storages
+ of the share and user layer. */
+struct SharedStorages: public rtl::Static<TSharedStorages, SharedStorages> {};
+
+}
+
+PresetHandler::PresetHandler(css::uno::Reference< css::uno::XComponentContext > xContext)
+ : m_xContext(std::move(xContext))
+ , m_eConfigType(E_GLOBAL)
+{
+}
+
+PresetHandler::PresetHandler(const PresetHandler& rCopy)
+{
+ m_xContext = rCopy.m_xContext;
+ m_eConfigType = rCopy.m_eConfigType;
+ m_xWorkingStorageShare = rCopy.m_xWorkingStorageShare;
+ m_xWorkingStorageNoLang = rCopy.m_xWorkingStorageNoLang;
+ m_xWorkingStorageUser = rCopy.m_xWorkingStorageUser;
+ m_lDocumentStorages = rCopy.m_lDocumentStorages;
+ m_sRelPathShare = rCopy.m_sRelPathShare;
+ m_sRelPathUser = rCopy.m_sRelPathUser;
+}
+
+PresetHandler::~PresetHandler()
+{
+ m_xWorkingStorageShare.clear();
+ m_xWorkingStorageNoLang.clear();
+ m_xWorkingStorageUser.clear();
+
+ /* #i46497#
+ Don't call forgetCachedStorages() here for shared storages.
+ Because we opened different sub storages by using openPath().
+ And every already open path was reused and referenced (means it's
+ ref count was increased!)
+ So now we have to release our ref counts to these shared storages
+ only ... and not to free all used storages.
+ Otherwise we will disconnect all other open configuration access
+ objects which base on these storages.
+ */
+ auto & sharedStorages = SharedStorages::get();
+ sharedStorages.m_lStoragesShare.closePath(m_sRelPathShare);
+ sharedStorages.m_lStoragesUser.closePath (m_sRelPathUser );
+
+ /* On the other side closePath() is not needed for our special handled
+ document storage. Because it's not shared with others ... so we can
+ free it.
+ */
+ m_lDocumentStorages.forgetCachedStorages();
+}
+
+void PresetHandler::forgetCachedStorages()
+{
+ SolarMutexGuard g;
+
+ if (m_eConfigType == E_DOCUMENT)
+ {
+ m_xWorkingStorageShare.clear();
+ m_xWorkingStorageNoLang.clear();
+ m_xWorkingStorageUser.clear();
+ }
+
+ m_lDocumentStorages.forgetCachedStorages();
+}
+
+namespace {
+
+OUString lcl_getLocalizedMessage(::sal_Int32 nID)
+{
+ OUString sMessage("Unknown error.");
+
+ switch(nID)
+ {
+ case ID_CORRUPT_UICONFIG_SHARE :
+ sMessage = FwkResId(STR_CORRUPT_UICFG_SHARE);
+
+ break;
+
+ case ID_CORRUPT_UICONFIG_USER :
+ sMessage = FwkResId(STR_CORRUPT_UICFG_USER);
+ break;
+
+ case ID_CORRUPT_UICONFIG_GENERAL :
+ sMessage = FwkResId(STR_CORRUPT_UICFG_GENERAL);
+ break;
+ }
+
+ return sMessage;
+}
+
+void lcl_throwCorruptedUIConfigurationException(
+ css::uno::Any const & exception, sal_Int32 id)
+{
+ css::uno::Exception e;
+ bool ok = (exception >>= e);
+ OSL_ASSERT(ok);
+ throw css::configuration::CorruptedUIConfigurationException(
+ lcl_getLocalizedMessage(id),
+ css::uno::Reference< css::uno::XInterface >(),
+ exception.getValueTypeName() + ": \"" + e.Message + "\"");
+}
+
+}
+
+css::uno::Reference< css::embed::XStorage > PresetHandler::getOrCreateRootStorageShare()
+{
+ auto & sharedStorages = SharedStorages::get();
+ css::uno::Reference< css::embed::XStorage > xRoot = sharedStorages.m_lStoragesShare.getRootStorage();
+ if (xRoot.is())
+ return xRoot;
+
+ css::uno::Reference< css::uno::XComponentContext > xContext;
+ {
+ SolarMutexGuard g;
+ xContext = m_xContext;
+ }
+
+ css::uno::Reference< css::util::XPathSettings > xPathSettings =
+ css::util::thePathSettings::get( xContext );
+
+ OUString sShareLayer = xPathSettings->getBasePathShareLayer();
+
+ // "UIConfig" is a "multi path" ... use first part only here!
+ sal_Int32 nPos = sShareLayer.indexOf(';');
+ if (nPos > 0)
+ sShareLayer = sShareLayer.copy(0, nPos);
+
+ // Note: May be an user uses URLs without a final slash! Check it ...
+ nPos = sShareLayer.lastIndexOf('/');
+ if (nPos != sShareLayer.getLength()-1)
+ sShareLayer += "/";
+
+ sShareLayer += "soffice.cfg";
+ /*
+ // TODO remove me!
+ // Attention: This is temp. workaround ... We create a temp. storage file
+ // based of a system directory. This must be used so, till the storage implementation
+ // can work on directories too.
+ */
+ css::uno::Sequence< css::uno::Any > lArgs{
+ css::uno::Any(sShareLayer),
+ css::uno::Any(css::embed::ElementModes::READ | css::embed::ElementModes::NOCREATE)
+ };
+
+ css::uno::Reference< css::lang::XSingleServiceFactory > xStorageFactory = css::embed::FileSystemStorageFactory::create( xContext );
+ css::uno::Reference< css::embed::XStorage > xStorage;
+
+ try
+ {
+ xStorage.set(xStorageFactory->createInstanceWithArguments(lArgs), css::uno::UNO_QUERY_THROW);
+ }
+ catch(const css::uno::Exception&)
+ {
+ css::uno::Any ex(cppu::getCaughtException());
+ lcl_throwCorruptedUIConfigurationException(
+ ex, ID_CORRUPT_UICONFIG_SHARE);
+ }
+
+ sharedStorages.m_lStoragesShare.setRootStorage(xStorage);
+
+ return xStorage;
+}
+
+css::uno::Reference< css::embed::XStorage > PresetHandler::getOrCreateRootStorageUser()
+{
+ auto & sharedStorages = SharedStorages::get();
+ css::uno::Reference< css::embed::XStorage > xRoot = sharedStorages.m_lStoragesUser.getRootStorage();
+ if (xRoot.is())
+ return xRoot;
+
+ css::uno::Reference< css::uno::XComponentContext > xContext;
+ {
+ SolarMutexGuard g;
+ xContext = m_xContext;
+ }
+
+ css::uno::Reference< css::util::XPathSettings > xPathSettings =
+ css::util::thePathSettings::get( xContext );
+
+ OUString sUserLayer = xPathSettings->getBasePathUserLayer();
+
+ // Note: May be an user uses URLs without a final slash! Check it ...
+ sal_Int32 nPos = sUserLayer.lastIndexOf('/');
+ if (nPos != sUserLayer.getLength()-1)
+ sUserLayer += "/";
+
+ sUserLayer += "soffice.cfg"; // storage file
+
+ css::uno::Sequence< css::uno::Any > lArgs{ css::uno::Any(sUserLayer),
+ css::uno::Any(css::embed::ElementModes::READWRITE) };
+
+ css::uno::Reference< css::lang::XSingleServiceFactory > xStorageFactory = css::embed::FileSystemStorageFactory::create( xContext );
+ css::uno::Reference< css::embed::XStorage > xStorage;
+
+ try
+ {
+ xStorage.set(xStorageFactory->createInstanceWithArguments(lArgs), css::uno::UNO_QUERY_THROW);
+ }
+ catch(const css::uno::Exception&)
+ {
+ css::uno::Any ex(cppu::getCaughtException());
+ lcl_throwCorruptedUIConfigurationException(
+ ex, ID_CORRUPT_UICONFIG_USER);
+ }
+
+ sharedStorages.m_lStoragesUser.setRootStorage(xStorage);
+
+ return xStorage;
+}
+
+css::uno::Reference< css::embed::XStorage > PresetHandler::getWorkingStorageUser() const
+{
+ SolarMutexGuard g;
+ return m_xWorkingStorageUser;
+}
+
+css::uno::Reference< css::embed::XStorage > PresetHandler::getParentStorageShare()
+{
+ css::uno::Reference< css::embed::XStorage > xWorking;
+ {
+ SolarMutexGuard g;
+ xWorking = m_xWorkingStorageShare;
+ }
+
+ return SharedStorages::get().m_lStoragesShare.getParentStorage(xWorking);
+}
+
+css::uno::Reference< css::embed::XStorage > PresetHandler::getParentStorageUser()
+{
+ css::uno::Reference< css::embed::XStorage > xWorking;
+ {
+ SolarMutexGuard g;
+ xWorking = m_xWorkingStorageUser;
+ }
+
+ return SharedStorages::get().m_lStoragesUser.getParentStorage(xWorking);
+}
+
+void PresetHandler::connectToResource( PresetHandler::EConfigType eConfigType ,
+ std::u16string_view sResource ,
+ std::u16string_view sModule ,
+ const css::uno::Reference< css::embed::XStorage >& xDocumentRoot,
+ const LanguageTag& rLanguageTag )
+{
+ // TODO free all current open storages!
+
+ {
+ SolarMutexGuard g;
+ m_eConfigType = eConfigType;
+ }
+
+ css::uno::Reference< css::embed::XStorage > xShare;
+ css::uno::Reference< css::embed::XStorage > xNoLang;
+ css::uno::Reference< css::embed::XStorage > xUser;
+
+ // special case for documents
+ // use outside root storage, if we run in E_DOCUMENT mode!
+ if (eConfigType == E_DOCUMENT)
+ {
+ if (!xDocumentRoot.is())
+ throw css::uno::RuntimeException(
+ "There is valid root storage, where the UI configuration can work on.");
+ m_lDocumentStorages.setRootStorage(xDocumentRoot);
+ xShare = xDocumentRoot;
+ xUser = xDocumentRoot;
+ }
+ else
+ {
+ xShare = getOrCreateRootStorageShare();
+ xUser = getOrCreateRootStorageUser();
+ }
+
+ // #...#
+ try
+ {
+
+ // a) inside share layer we should not create any new structures... We have to use
+ // existing ones only!
+ // b) inside user layer we can (SOFT mode!) but sometimes we should not (HARD mode!)
+ // create new empty structures. We should prefer using of any existing structure.
+ sal_Int32 eShareMode = (css::embed::ElementModes::READ | css::embed::ElementModes::NOCREATE);
+ sal_Int32 eUserMode = css::embed::ElementModes::READWRITE;
+
+ OUStringBuffer sRelPathBuf(1024);
+ OUString sRelPathShare;
+ OUString sRelPathUser;
+ switch(eConfigType)
+ {
+ case E_GLOBAL :
+ {
+ sRelPathShare = OUString::Concat("global/") + sResource;
+ sRelPathUser = sRelPathShare;
+
+ xShare = impl_openPathIgnoringErrors(sRelPathShare, eShareMode, true );
+ xUser = impl_openPathIgnoringErrors(sRelPathUser , eUserMode , false);
+ }
+ break;
+
+ case E_MODULES :
+ {
+ sRelPathShare = OUString::Concat("modules/") + sModule + "/" + sResource;
+ sRelPathUser = sRelPathShare;
+
+ xShare = impl_openPathIgnoringErrors(sRelPathShare, eShareMode, true );
+ xUser = impl_openPathIgnoringErrors(sRelPathUser , eUserMode , false);
+ }
+ break;
+
+ case E_DOCUMENT :
+ {
+ // A document does not have a share layer in real.
+ // It has one layer only, and this one should be opened READ_WRITE.
+ // So we open the user layer here only and set the share layer equals to it .-)
+
+ sRelPathBuf.append(sResource);
+ sRelPathUser = sRelPathBuf.makeStringAndClear();
+ sRelPathShare = sRelPathUser;
+
+ try
+ {
+ xUser = m_lDocumentStorages.openPath(sRelPathUser , eUserMode );
+ xShare = xUser;
+ }
+ catch(const css::uno::RuntimeException&)
+ { throw; }
+ catch(const css::uno::Exception&)
+ { xShare.clear(); xUser.clear(); }
+ }
+ break;
+ }
+
+ // Non-localized global share
+ xNoLang = xShare;
+
+ if (
+ (rLanguageTag != LanguageTag(LANGUAGE_USER_PRIV_NOTRANSLATE)) && // localized level?
+ (eConfigType != E_DOCUMENT ) // no localization in document mode!
+ )
+ {
+ // First try to find the right localized set inside share layer.
+ // Fallbacks are allowed there.
+ OUString aShareLocale( rLanguageTag.getBcp47());
+ OUString sLocalizedSharePath(sRelPathShare);
+ bool bAllowFallbacks = true;
+ xShare = impl_openLocalizedPathIgnoringErrors(sLocalizedSharePath, eShareMode, true , aShareLocale, bAllowFallbacks);
+
+ // The try to locate the right sub dir inside user layer ... without using fallbacks!
+ // Normally the corresponding sub dir should be created matching the specified locale.
+ // Because we allow creation of storages inside user layer by default.
+ OUString aUserLocale( rLanguageTag.getBcp47());
+ OUString sLocalizedUserPath(sRelPathUser);
+ bAllowFallbacks = false;
+ xUser = impl_openLocalizedPathIgnoringErrors(sLocalizedUserPath, eUserMode, false, aUserLocale, bAllowFallbacks);
+
+ sRelPathShare = sLocalizedSharePath;
+ sRelPathUser = sLocalizedUserPath;
+ }
+
+ {
+ SolarMutexGuard g;
+ m_xWorkingStorageShare = xShare;
+ m_xWorkingStorageNoLang= xNoLang;
+ m_xWorkingStorageUser = xUser;
+ m_sRelPathShare = sRelPathShare;
+ m_sRelPathUser = sRelPathUser;
+ }
+
+ }
+ catch(const css::uno::Exception&)
+ {
+ css::uno::Any ex(cppu::getCaughtException());
+ lcl_throwCorruptedUIConfigurationException(
+ ex, ID_CORRUPT_UICONFIG_GENERAL);
+ }
+}
+
+void PresetHandler::copyPresetToTarget(std::u16string_view sPreset,
+ std::u16string_view sTarget)
+{
+ // don't check our preset list, if element exists
+ // We try to open it and forward all errors to the user!
+
+ css::uno::Reference< css::embed::XStorage > xWorkingShare;
+ css::uno::Reference< css::embed::XStorage > xWorkingNoLang;
+ css::uno::Reference< css::embed::XStorage > xWorkingUser;
+ {
+ SolarMutexGuard g;
+ xWorkingShare = m_xWorkingStorageShare;
+ xWorkingNoLang= m_xWorkingStorageNoLang;
+ xWorkingUser = m_xWorkingStorageUser;
+ }
+
+ // e.g. module without any config data ?!
+ if (
+ (!xWorkingShare.is()) ||
+ (!xWorkingUser.is() )
+ )
+ {
+ return;
+ }
+
+ OUString sPresetFile = OUString::Concat(sPreset) + ".xml";
+ OUString sTargetFile = OUString::Concat(sTarget) + ".xml";
+
+ // remove existing elements before you try to copy the preset to that location ...
+ // Otherwise w will get an ElementExistException inside copyElementTo()!
+ css::uno::Reference< css::container::XNameAccess > xCheckingUser(xWorkingUser, css::uno::UNO_QUERY_THROW);
+ if (xCheckingUser->hasByName(sTargetFile))
+ xWorkingUser->removeElement(sTargetFile);
+
+ xWorkingShare->copyElementTo(sPresetFile, xWorkingUser, sTargetFile);
+
+ // If our storages work in transacted mode, we have
+ // to commit all changes from bottom to top!
+ commitUserChanges();
+}
+
+css::uno::Reference< css::io::XStream > PresetHandler::openPreset(std::u16string_view sPreset)
+{
+ css::uno::Reference< css::embed::XStorage > xFolder;
+ {
+ SolarMutexGuard g;
+ xFolder = m_xWorkingStorageNoLang;
+ }
+
+ // e.g. module without any config data ?!
+ if (!xFolder.is())
+ return css::uno::Reference< css::io::XStream >();
+
+ OUString sFile = OUString::Concat(sPreset) + ".xml";
+
+ // inform user about errors (use original exceptions!)
+ css::uno::Reference< css::io::XStream > xStream = xFolder->openStreamElement(sFile, css::embed::ElementModes::READ);
+ return xStream;
+}
+
+css::uno::Reference< css::io::XStream > PresetHandler::openTarget(
+ std::u16string_view sTarget, sal_Int32 const nMode)
+{
+ css::uno::Reference< css::embed::XStorage > xFolder;
+ {
+ SolarMutexGuard g;
+ xFolder = m_xWorkingStorageUser;
+ }
+
+ // e.g. module without any config data ?!
+ if (!xFolder.is())
+ return css::uno::Reference< css::io::XStream >();
+
+ OUString const sFile(OUString::Concat(sTarget) + ".xml");
+
+ return xFolder->openStreamElement(sFile, nMode);
+}
+
+void PresetHandler::commitUserChanges()
+{
+ css::uno::Reference< css::embed::XStorage > xWorking;
+ EConfigType eCfgType;
+ {
+ SolarMutexGuard g;
+ xWorking = m_xWorkingStorageUser;
+ eCfgType = m_eConfigType;
+ }
+
+ // e.g. module without any config data ?!
+ if (!xWorking.is())
+ return;
+
+ OUString sPath;
+
+ switch(eCfgType)
+ {
+ case E_GLOBAL :
+ case E_MODULES :
+ {
+ auto & sharedStorages = SharedStorages::get();
+ sPath = sharedStorages.m_lStoragesUser.getPathOfStorage(xWorking);
+ sharedStorages.m_lStoragesUser.commitPath(sPath);
+ sharedStorages.m_lStoragesUser.notifyPath(sPath);
+ }
+ break;
+
+ case E_DOCUMENT :
+ {
+ sPath = m_lDocumentStorages.getPathOfStorage(xWorking);
+ m_lDocumentStorages.commitPath(sPath);
+ m_lDocumentStorages.notifyPath(sPath);
+ }
+ break;
+ }
+}
+
+void PresetHandler::addStorageListener(XMLBasedAcceleratorConfiguration* pListener)
+{
+ OUString sRelPath;
+ EConfigType eCfgType;
+ {
+ SolarMutexGuard g;
+ sRelPath = m_sRelPathUser; // use user path ... because we don't work directly on the share layer!
+ eCfgType = m_eConfigType;
+ }
+
+ if (sRelPath.isEmpty())
+ return;
+
+ switch(eCfgType)
+ {
+ case E_GLOBAL :
+ case E_MODULES :
+ {
+ SharedStorages::get().m_lStoragesUser.addStorageListener(pListener, sRelPath);
+ }
+ break;
+
+ case E_DOCUMENT :
+ {
+ m_lDocumentStorages.addStorageListener(pListener, sRelPath);
+ }
+ break;
+ }
+}
+
+void PresetHandler::removeStorageListener(XMLBasedAcceleratorConfiguration* pListener)
+{
+ OUString sRelPath;
+ EConfigType eCfgType;
+ {
+ SolarMutexGuard g;
+ sRelPath = m_sRelPathUser; // use user path ... because we don't work directly on the share layer!
+ eCfgType = m_eConfigType;
+ }
+
+ if (sRelPath.isEmpty())
+ return;
+
+ switch(eCfgType)
+ {
+ case E_GLOBAL :
+ case E_MODULES :
+ {
+ SharedStorages::get().m_lStoragesUser.removeStorageListener(pListener, sRelPath);
+ }
+ break;
+
+ case E_DOCUMENT :
+ {
+ m_lDocumentStorages.removeStorageListener(pListener, sRelPath);
+ }
+ break;
+ }
+}
+
+css::uno::Reference< css::embed::XStorage > PresetHandler::impl_openPathIgnoringErrors(const OUString& sPath ,
+ sal_Int32 eMode ,
+ bool bShare)
+{
+ css::uno::Reference< css::embed::XStorage > xPath;
+ try
+ {
+ if (bShare)
+ xPath = SharedStorages::get().m_lStoragesShare.openPath(sPath, eMode);
+ else
+ xPath = SharedStorages::get().m_lStoragesUser.openPath(sPath, eMode);
+ }
+ catch(const css::uno::RuntimeException&)
+ { throw; }
+ catch(const css::uno::Exception&)
+ { xPath.clear(); }
+ return xPath;
+}
+
+::std::vector< OUString >::const_iterator PresetHandler::impl_findMatchingLocalizedValue(
+ const ::std::vector< OUString >& lLocalizedValues,
+ OUString& rLanguageTag,
+ bool bAllowFallbacks )
+{
+ ::std::vector< OUString >::const_iterator pFound = lLocalizedValues.end();
+ if (bAllowFallbacks)
+ {
+ pFound = LanguageTag::getFallback(lLocalizedValues, rLanguageTag);
+ // if we found a valid locale ... take it over to our in/out parameter
+ // rLanguageTag
+ if (pFound != lLocalizedValues.end())
+ {
+ rLanguageTag = *pFound;
+ }
+ }
+ else
+ {
+ pFound = std::find(lLocalizedValues.begin(), lLocalizedValues.end(), rLanguageTag);
+ }
+
+ return pFound;
+}
+
+css::uno::Reference< css::embed::XStorage > PresetHandler::impl_openLocalizedPathIgnoringErrors(
+ OUString& sPath ,
+ sal_Int32 eMode ,
+ bool bShare ,
+ OUString& rLanguageTag ,
+ bool bAllowFallback)
+{
+ css::uno::Reference< css::embed::XStorage > xPath = impl_openPathIgnoringErrors(sPath, eMode, bShare);
+ ::std::vector< OUString > lSubFolders = impl_getSubFolderNames(xPath);
+ ::std::vector< OUString >::const_iterator pLocaleFolder = impl_findMatchingLocalizedValue(lSubFolders, rLanguageTag, bAllowFallback);
+
+ // no fallback ... creation not allowed => no storage
+ if (
+ (pLocaleFolder == lSubFolders.end() ) &&
+ ((eMode & css::embed::ElementModes::NOCREATE) == css::embed::ElementModes::NOCREATE)
+ )
+ return css::uno::Reference< css::embed::XStorage >();
+
+ // it doesn't matter, if there is a locale fallback or not
+ // If creation of storages is allowed, we do it anyway.
+ // Otherwise we have no acc config at all, which can make other trouble.
+ OUString sLocalizedPath = sPath + "/";
+ if (pLocaleFolder != lSubFolders.end())
+ sLocalizedPath += *pLocaleFolder;
+ else
+ sLocalizedPath += rLanguageTag;
+
+ css::uno::Reference< css::embed::XStorage > xLocalePath = impl_openPathIgnoringErrors(sLocalizedPath, eMode, bShare);
+
+ if (xLocalePath.is())
+ sPath = sLocalizedPath;
+ else
+ sPath.clear();
+
+ return xLocalePath;
+}
+
+::std::vector< OUString > PresetHandler::impl_getSubFolderNames(const css::uno::Reference< css::embed::XStorage >& xFolder)
+{
+ if (!xFolder.is())
+ return ::std::vector< OUString >();
+
+ ::std::vector< OUString > lSubFolders;
+ const css::uno::Sequence< OUString > lNames = xFolder->getElementNames();
+ const OUString* pNames = lNames.getConstArray();
+ sal_Int32 c = lNames.getLength();
+ sal_Int32 i = 0;
+
+ for (i=0; i<c; ++i)
+ {
+ try
+ {
+ if (xFolder->isStorageElement(pNames[i]))
+ lSubFolders.push_back(pNames[i]);
+ }
+ catch(const css::uno::RuntimeException&)
+ { throw; }
+ catch(const css::uno::Exception&)
+ {}
+ }
+
+ return lSubFolders;
+}
+
+} // namespace framework
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */