office-gobmx/framework/source/accelerators/acceleratorconfiguration.cxx
Noel Grandin 4f5f24a4a3 loplugin:ostr in framework
Change-Id: I2fdc32aa5de6a1315fe69997f9b531259aa78605
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/167339
Tested-by: Jenkins
Reviewed-by: Noel Grandin <noel.grandin@collabora.co.uk>
2024-05-08 17:18:51 +02:00

1327 lines
48 KiB
C++

/* -*- 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 <utility>
#include <accelerators/acceleratorconfiguration.hxx>
#include <accelerators/keymapping.hxx>
#include <accelerators/presethandler.hxx>
#include <xml/saxnamespacefilter.hxx>
#include <xml/acceleratorconfigurationreader.hxx>
#include <xml/acceleratorconfigurationwriter.hxx>
#include <com/sun/star/xml/sax/Parser.hpp>
#include <com/sun/star/xml/sax/InputSource.hpp>
#include <com/sun/star/xml/sax/Writer.hpp>
#include <com/sun/star/io/IOException.hpp>
#include <com/sun/star/embed/ElementModes.hpp>
#include <com/sun/star/io/XSeekable.hpp>
#include <com/sun/star/io/XTruncate.hpp>
#include <vcl/svapp.hxx>
#include <com/sun/star/container/XNamed.hpp>
#include <com/sun/star/container/XNameContainer.hpp>
#include <com/sun/star/container/XHierarchicalNameAccess.hpp>
#include <com/sun/star/awt/KeyEvent.hpp>
#include <com/sun/star/awt/KeyModifier.hpp>
#include <com/sun/star/lang/XSingleServiceFactory.hpp>
#include <comphelper/configurationhelper.hxx>
#include <comphelper/sequence.hxx>
#include <officecfg/Setup.hxx>
#include <unotools/configpaths.hxx>
#include <svtools/acceleratorexecute.hxx>
#include <sal/log.hxx>
#include <rtl/ustrbuf.hxx>
#include <o3tl/string_view.hxx>
constexpr OUString PRESET_DEFAULT = u"default"_ustr;
constexpr OUString TARGET_CURRENT = u"current"_ustr;
namespace framework
{
constexpr OUString CFG_ENTRY_SECONDARY = u"SecondaryKeys"_ustr;
constexpr OUString CFG_PROP_COMMAND = u"Command"_ustr;
static OUString lcl_getKeyString(const css::awt::KeyEvent& aKeyEvent)
{
const sal_Int32 nBeginIndex = 4; // "KEY_" is the prefix of an identifier...
OUString sKey(KeyMapping::get().mapCodeToIdentifier(aKeyEvent.KeyCode));
if (sKey.getLength() < nBeginIndex) // dead key
return OUString();
OUStringBuffer sKeyBuffer(sKey.subView(nBeginIndex));
if ( (aKeyEvent.Modifiers & css::awt::KeyModifier::SHIFT) == css::awt::KeyModifier::SHIFT )
sKeyBuffer.append("_SHIFT");
if ( (aKeyEvent.Modifiers & css::awt::KeyModifier::MOD1 ) == css::awt::KeyModifier::MOD1 )
sKeyBuffer.append("_MOD1");
if ( (aKeyEvent.Modifiers & css::awt::KeyModifier::MOD2 ) == css::awt::KeyModifier::MOD2 )
sKeyBuffer.append("_MOD2");
if ( (aKeyEvent.Modifiers & css::awt::KeyModifier::MOD3 ) == css::awt::KeyModifier::MOD3 )
sKeyBuffer.append("_MOD3");
return sKeyBuffer.makeStringAndClear();
}
XMLBasedAcceleratorConfiguration::XMLBasedAcceleratorConfiguration(const css::uno::Reference< css::uno::XComponentContext >& xContext)
: m_xContext (xContext )
, m_aPresetHandler(xContext )
{
}
XMLBasedAcceleratorConfiguration::~XMLBasedAcceleratorConfiguration()
{
SAL_WARN_IF(m_pWriteCache, "fwk.accelerators", "XMLBasedAcceleratorConfiguration::~XMLBasedAcceleratorConfiguration(): Changes not flushed. Ignore it ...");
}
css::uno::Sequence< css::awt::KeyEvent > SAL_CALL XMLBasedAcceleratorConfiguration::getAllKeyEvents()
{
SolarMutexGuard g;
AcceleratorCache& rCache = impl_getCFG();
AcceleratorCache::TKeyList lKeys = rCache.getAllKeys();
return comphelper::containerToSequence(lKeys);
}
OUString SAL_CALL XMLBasedAcceleratorConfiguration::getCommandByKeyEvent(const css::awt::KeyEvent& aKeyEvent)
{
SolarMutexGuard g;
AcceleratorCache& rCache = impl_getCFG();
if (!rCache.hasKey(aKeyEvent))
throw css::container::NoSuchElementException(
OUString(),
static_cast< ::cppu::OWeakObject* >(this));
return rCache.getCommandByKey(aKeyEvent);
}
void SAL_CALL XMLBasedAcceleratorConfiguration::setKeyEvent(const css::awt::KeyEvent& aKeyEvent,
const OUString& sCommand )
{
if (
(aKeyEvent.KeyCode == 0) &&
(aKeyEvent.KeyChar == 0) &&
(aKeyEvent.KeyFunc == 0) &&
(aKeyEvent.Modifiers == 0)
)
throw css::lang::IllegalArgumentException(
u"Such key event seems not to be supported by any operating system."_ustr,
static_cast< ::cppu::OWeakObject* >(this),
0);
if (sCommand.isEmpty())
throw css::lang::IllegalArgumentException(
u"Empty command strings are not allowed here."_ustr,
static_cast< ::cppu::OWeakObject* >(this),
1);
SolarMutexGuard g;
AcceleratorCache& rCache = impl_getCFG(true); // sal_True => force getting of a writeable cache!
rCache.setKeyCommandPair(aKeyEvent, sCommand);
}
void SAL_CALL XMLBasedAcceleratorConfiguration::removeKeyEvent(const css::awt::KeyEvent& aKeyEvent)
{
SolarMutexGuard g;
AcceleratorCache& rCache = impl_getCFG(true); // true => force using of a writeable cache
if (!rCache.hasKey(aKeyEvent))
throw css::container::NoSuchElementException(
OUString(),
static_cast< ::cppu::OWeakObject* >(this));
rCache.removeKey(aKeyEvent);
}
css::uno::Sequence< css::awt::KeyEvent > SAL_CALL XMLBasedAcceleratorConfiguration::getKeyEventsByCommand(const OUString& sCommand)
{
if (sCommand.isEmpty())
throw css::lang::IllegalArgumentException(
u"Empty command strings are not allowed here."_ustr,
static_cast< ::cppu::OWeakObject* >(this),
1);
SolarMutexGuard g;
AcceleratorCache& rCache = impl_getCFG();
if (!rCache.hasCommand(sCommand))
throw css::container::NoSuchElementException(
OUString(),
static_cast< ::cppu::OWeakObject* >(this));
AcceleratorCache::TKeyList lKeys = rCache.getKeysByCommand(sCommand);
return comphelper::containerToSequence(lKeys);
}
css::uno::Sequence< css::uno::Any > SAL_CALL XMLBasedAcceleratorConfiguration::getPreferredKeyEventsForCommandList(const css::uno::Sequence< OUString >& lCommandList)
{
SolarMutexGuard g;
sal_Int32 i = 0;
sal_Int32 c = lCommandList.getLength();
css::uno::Sequence< css::uno::Any > lPreferredOnes (c); // don't pack list!
AcceleratorCache& rCache = impl_getCFG();
auto lPreferredOnesRange = asNonConstRange(lPreferredOnes);
for (i=0; i<c; ++i)
{
const OUString& rCommand = lCommandList[i];
if (rCommand.isEmpty())
throw css::lang::IllegalArgumentException(
u"Empty command strings are not allowed here."_ustr,
static_cast< ::cppu::OWeakObject* >(this),
static_cast<sal_Int16>(i));
if (!rCache.hasCommand(rCommand))
continue;
AcceleratorCache::TKeyList lKeys = rCache.getKeysByCommand(rCommand);
if ( lKeys.empty() )
continue;
css::uno::Any& rAny = lPreferredOnesRange[i];
rAny <<= *(lKeys.begin());
}
return lPreferredOnes;
}
void SAL_CALL XMLBasedAcceleratorConfiguration::removeCommandFromAllKeyEvents(const OUString& sCommand)
{
if (sCommand.isEmpty())
throw css::lang::IllegalArgumentException(
u"Empty command strings are not allowed here."_ustr,
static_cast< ::cppu::OWeakObject* >(this),
0);
SolarMutexGuard g;
AcceleratorCache& rCache = impl_getCFG(true); // sal_True => force getting of a writeable cache!
if (!rCache.hasCommand(sCommand))
throw css::container::NoSuchElementException(
u"Command does not exists inside this container."_ustr,
static_cast< ::cppu::OWeakObject* >(this));
rCache.removeCommand(sCommand);
}
void SAL_CALL XMLBasedAcceleratorConfiguration::reload()
{
css::uno::Reference< css::io::XStream > xStream;
css::uno::Reference< css::io::XStream > xStreamNoLang;
{
SolarMutexGuard g;
xStream = m_aPresetHandler.openTarget(TARGET_CURRENT,
css::embed::ElementModes::READ);
try
{
xStreamNoLang = m_aPresetHandler.openPreset(PRESET_DEFAULT);
}
catch(const css::io::IOException&) {} // does not have to exist
}
css::uno::Reference< css::io::XInputStream > xIn;
if (xStream.is())
xIn = xStream->getInputStream();
if (!xIn.is())
throw css::io::IOException(
u"Could not open accelerator configuration for reading."_ustr,
static_cast< ::cppu::OWeakObject* >(this));
// impl_ts_load() does not clear the cache
{
SolarMutexGuard g;
m_aReadCache = AcceleratorCache();
}
impl_ts_load(xIn);
// Load also the general language independent default accelerators
// (ignoring the already defined accelerators)
if (xStreamNoLang.is())
{
xIn = xStreamNoLang->getInputStream();
if (xIn.is())
impl_ts_load(xIn);
}
}
void SAL_CALL XMLBasedAcceleratorConfiguration::store()
{
css::uno::Reference< css::io::XStream > xStream;
{
SolarMutexGuard g;
xStream = m_aPresetHandler.openTarget(TARGET_CURRENT,
css::embed::ElementModes::READWRITE); // open or create!
}
css::uno::Reference< css::io::XOutputStream > xOut;
if (xStream.is())
xOut = xStream->getOutputStream();
if (!xOut.is())
throw css::io::IOException(
u"Could not open accelerator configuration for saving."_ustr,
static_cast< ::cppu::OWeakObject* >(this));
impl_ts_save(xOut);
xOut.clear();
xStream.clear();
m_aPresetHandler.commitUserChanges();
}
void SAL_CALL XMLBasedAcceleratorConfiguration::storeToStorage(const css::uno::Reference< css::embed::XStorage >& xStorage)
{
// no fallback from read/write to readonly!
css::uno::Reference< css::io::XStream > xStream = xStorage->openStreamElement(TARGET_CURRENT, css::embed::ElementModes::READWRITE);
css::uno::Reference< css::io::XOutputStream > xOut;
if (xStream.is())
xOut = xStream->getOutputStream();
if (!xOut.is())
throw css::io::IOException(
u"Could not open accelerator configuration for saving."_ustr,
static_cast< ::cppu::OWeakObject* >(this));
impl_ts_save(xOut);
// TODO inform listener about success, so it can flush the root and sub storage of this stream!
}
sal_Bool SAL_CALL XMLBasedAcceleratorConfiguration::isModified()
{
SolarMutexGuard g;
return (m_pWriteCache != nullptr);
}
sal_Bool SAL_CALL XMLBasedAcceleratorConfiguration::isReadOnly()
{
css::uno::Reference< css::io::XStream > xStream;
{
SolarMutexGuard g;
xStream = m_aPresetHandler.openTarget(TARGET_CURRENT,
css::embed::ElementModes::READWRITE); // open or create!
}
css::uno::Reference< css::io::XOutputStream > xOut;
if (xStream.is())
xOut = xStream->getOutputStream();
return !(xOut.is());
}
void SAL_CALL XMLBasedAcceleratorConfiguration::setStorage(const css::uno::Reference< css::embed::XStorage >& /*xStorage*/)
{
SAL_INFO("fwk.accelerators", "XMLBasedAcceleratorConfiguration::setStorage(): implement this HACK .-)");
}
sal_Bool SAL_CALL XMLBasedAcceleratorConfiguration::hasStorage()
{
SAL_INFO("fwk.accelerators", "XMLBasedAcceleratorConfiguration::hasStorage(): implement this HACK .-)");
return false;
}
void SAL_CALL XMLBasedAcceleratorConfiguration::addConfigurationListener(const css::uno::Reference< css::ui::XUIConfigurationListener >& /*xListener*/)
{
SAL_INFO("fwk.accelerators", "XMLBasedAcceleratorConfiguration::addConfigurationListener(): implement me");
}
void SAL_CALL XMLBasedAcceleratorConfiguration::removeConfigurationListener(const css::uno::Reference< css::ui::XUIConfigurationListener >& /*xListener*/)
{
SAL_INFO("fwk.accelerators", "XMLBasedAcceleratorConfiguration::removeConfigurationListener(): implement me");
}
void SAL_CALL XMLBasedAcceleratorConfiguration::reset()
{
{
SolarMutexGuard g;
m_aPresetHandler.copyPresetToTarget(PRESET_DEFAULT, TARGET_CURRENT);
}
reload();
}
void SAL_CALL XMLBasedAcceleratorConfiguration::addResetListener(const css::uno::Reference< css::form::XResetListener >& /*xListener*/)
{
SAL_INFO("fwk.accelerators", "XMLBasedAcceleratorConfiguration::addResetListener(): implement me");
}
void SAL_CALL XMLBasedAcceleratorConfiguration::removeResetListener(const css::uno::Reference< css::form::XResetListener >& /*xListener*/)
{
SAL_INFO("fwk.accelerators", "XMLBasedAcceleratorConfiguration::removeResetListener(): implement me");
}
// IStorageListener
void XMLBasedAcceleratorConfiguration::changesOccurred()
{
reload();
}
void XMLBasedAcceleratorConfiguration::impl_ts_load(const css::uno::Reference< css::io::XInputStream >& xStream)
{
css::uno::Reference< css::uno::XComponentContext > xContext;
{
SolarMutexGuard g;
xContext = m_xContext;
m_pWriteCache.reset();
}
css::uno::Reference< css::io::XSeekable > xSeek(xStream, css::uno::UNO_QUERY);
if (xSeek.is())
xSeek->seek(0);
SolarMutexGuard g;
// create the parser queue
// Note: Use special filter object between parser and reader
// to get filtered xml with right namespaces ...
// Use further a temp cache for reading!
rtl::Reference<AcceleratorConfigurationReader> pReader = new AcceleratorConfigurationReader(m_aReadCache);
rtl::Reference<SaxNamespaceFilter> pFilter = new SaxNamespaceFilter(pReader);
// connect parser, filter and stream
css::uno::Reference< css::xml::sax::XParser > xParser = css::xml::sax::Parser::create(xContext);
xParser->setDocumentHandler(pFilter);
css::xml::sax::InputSource aSource;
aSource.aInputStream = xStream;
// TODO think about error handling
xParser->parseStream(aSource);
}
void XMLBasedAcceleratorConfiguration::impl_ts_save(const css::uno::Reference< css::io::XOutputStream >& xStream)
{
bool bChanged;
AcceleratorCache aCache;
css::uno::Reference< css::uno::XComponentContext > xContext;
{
SolarMutexGuard g;
bChanged = (m_pWriteCache != nullptr);
if (bChanged)
aCache = *m_pWriteCache;
else
aCache = m_aReadCache;
xContext = m_xContext;
}
css::uno::Reference< css::io::XTruncate > xClearable(xStream, css::uno::UNO_QUERY_THROW);
xClearable->truncate();
// TODO can be removed if seek(0) is done by truncate() automatically!
css::uno::Reference< css::io::XSeekable > xSeek(xStream, css::uno::UNO_QUERY);
if (xSeek.is())
xSeek->seek(0);
// combine writer/cache/stream etcpp.
css::uno::Reference< css::xml::sax::XWriter > xWriter = css::xml::sax::Writer::create(xContext);
xWriter->setOutputStream(xStream);
// write into the stream
css::uno::Reference< css::xml::sax::XDocumentHandler > xHandler(xWriter, css::uno::UNO_QUERY_THROW);
AcceleratorConfigurationWriter aWriter(aCache, xHandler);
aWriter.flush();
SolarMutexGuard g;
// take over all changes into the readonly cache ...
// and forget the copy-on-write copied cache
if (bChanged)
{
m_aReadCache = *m_pWriteCache;
m_pWriteCache.reset();
}
}
AcceleratorCache& XMLBasedAcceleratorConfiguration::impl_getCFG(bool bWriteAccessRequested)
{
SolarMutexGuard g;
//create copy of our readonly-cache, if write access is forced ... but
//not still possible!
if ( bWriteAccessRequested && !m_pWriteCache )
{
m_pWriteCache.reset(new AcceleratorCache(m_aReadCache));
}
// in case, we have a writeable cache, we use it for reading too!
// Otherwise the API user can't find its own changes...
if (m_pWriteCache)
return *m_pWriteCache;
else
return m_aReadCache;
}
// static
OUString XMLBasedAcceleratorConfiguration::impl_ts_getLocale()
{
OUString sISOLocale = officecfg::Setup::L10N::ooLocale::get();
if (sISOLocale.isEmpty())
return u"en-US"_ustr;
return sISOLocale;
}
/*******************************************************************************
*
* XCU based accelerator configuration
*
*******************************************************************************/
XCUBasedAcceleratorConfiguration::XCUBasedAcceleratorConfiguration(css::uno::Reference< css::uno::XComponentContext > xContext)
: m_xContext (std::move(xContext ))
{
m_xCfg.set(
::comphelper::ConfigurationHelper::openConfig( m_xContext, u"org.openoffice.Office.Accelerators"_ustr, ::comphelper::EConfigurationModes::AllLocales ),
css::uno::UNO_QUERY );
}
XCUBasedAcceleratorConfiguration::~XCUBasedAcceleratorConfiguration()
{
}
css::uno::Sequence< css::awt::KeyEvent > SAL_CALL XCUBasedAcceleratorConfiguration::getAllKeyEvents()
{
SolarMutexGuard g;
AcceleratorCache::TKeyList lKeys = impl_getCFG(true).getAllKeys(); //get keys from PrimaryKeys set
AcceleratorCache::TKeyList lSecondaryKeys = impl_getCFG(false).getAllKeys(); //get keys from SecondaryKeys set
lKeys.reserve(lKeys.size()+lSecondaryKeys.size());
for (auto const& secondaryKey : lSecondaryKeys)
lKeys.push_back(secondaryKey);
return comphelper::containerToSequence(lKeys);
}
OUString SAL_CALL XCUBasedAcceleratorConfiguration::getCommandByKeyEvent(const css::awt::KeyEvent& aKeyEvent)
{
SolarMutexGuard g;
AcceleratorCache& rPrimaryCache = impl_getCFG(true );
AcceleratorCache& rSecondaryCache = impl_getCFG(false);
if (!rPrimaryCache.hasKey(aKeyEvent) && !rSecondaryCache.hasKey(aKeyEvent))
throw css::container::NoSuchElementException(
OUString(),
static_cast< ::cppu::OWeakObject* >(this));
if (rPrimaryCache.hasKey(aKeyEvent))
return rPrimaryCache.getCommandByKey(aKeyEvent);
else
return rSecondaryCache.getCommandByKey(aKeyEvent);
}
void SAL_CALL XCUBasedAcceleratorConfiguration::setKeyEvent(const css::awt::KeyEvent& aKeyEvent,
const OUString& sCommand )
{
SAL_INFO( "fwk.accelerators", "XCUBasedAcceleratorConfiguration::setKeyEvent" );
if (
(aKeyEvent.KeyCode == 0) &&
(aKeyEvent.KeyChar == 0) &&
(aKeyEvent.KeyFunc == 0) &&
(aKeyEvent.Modifiers == 0)
)
throw css::lang::IllegalArgumentException(
u"Such key event seems not to be supported by any operating system."_ustr,
static_cast< ::cppu::OWeakObject* >(this),
0);
if (sCommand.isEmpty())
throw css::lang::IllegalArgumentException(
u"Empty command strings are not allowed here."_ustr,
static_cast< ::cppu::OWeakObject* >(this),
1);
SolarMutexGuard g;
AcceleratorCache& rPrimaryCache = impl_getCFG(true, true ); // sal_True => force getting of a writeable cache!
AcceleratorCache& rSecondaryCache = impl_getCFG(false, true); // sal_True => force getting of a writeable cache!
if ( rPrimaryCache.hasKey(aKeyEvent) )
{
OUString sOriginalCommand = rPrimaryCache.getCommandByKey(aKeyEvent);
if ( sCommand != sOriginalCommand )
{
if (rSecondaryCache.hasCommand(sOriginalCommand))
{
AcceleratorCache::TKeyList lSecondaryKeys = rSecondaryCache.getKeysByCommand(sOriginalCommand);
rSecondaryCache.removeKey(lSecondaryKeys[0]);
rPrimaryCache.setKeyCommandPair(lSecondaryKeys[0], sOriginalCommand);
}
if (rPrimaryCache.hasCommand(sCommand))
{
AcceleratorCache::TKeyList lPrimaryKeys = rPrimaryCache.getKeysByCommand(sCommand);
rPrimaryCache.removeKey(lPrimaryKeys[0]);
rSecondaryCache.setKeyCommandPair(lPrimaryKeys[0], sCommand);
}
rPrimaryCache.setKeyCommandPair(aKeyEvent, sCommand);
}
}
else if ( rSecondaryCache.hasKey(aKeyEvent) )
{
OUString sOriginalCommand = rSecondaryCache.getCommandByKey(aKeyEvent);
if (sCommand != sOriginalCommand)
{
if (rPrimaryCache.hasCommand(sCommand))
{
AcceleratorCache::TKeyList lPrimaryKeys = rPrimaryCache.getKeysByCommand(sCommand);
rPrimaryCache.removeKey(lPrimaryKeys[0]);
rSecondaryCache.setKeyCommandPair(lPrimaryKeys[0], sCommand);
}
rSecondaryCache.removeKey(aKeyEvent);
rPrimaryCache.setKeyCommandPair(aKeyEvent, sCommand);
}
}
else
{
if (rPrimaryCache.hasCommand(sCommand))
{
AcceleratorCache::TKeyList lPrimaryKeys = rPrimaryCache.getKeysByCommand(sCommand);
rPrimaryCache.removeKey(lPrimaryKeys[0]);
rSecondaryCache.setKeyCommandPair(lPrimaryKeys[0], sCommand);
}
rPrimaryCache.setKeyCommandPair(aKeyEvent, sCommand);
}
}
void SAL_CALL XCUBasedAcceleratorConfiguration::removeKeyEvent(const css::awt::KeyEvent& aKeyEvent)
{
SolarMutexGuard g;
AcceleratorCache& rPrimaryCache = impl_getCFG(true, true );
AcceleratorCache& rSecondaryCache = impl_getCFG(false, true);
if (!rPrimaryCache.hasKey(aKeyEvent) && !rSecondaryCache.hasKey(aKeyEvent))
throw css::container::NoSuchElementException(
OUString(),
static_cast< ::cppu::OWeakObject* >(this));
if (rPrimaryCache.hasKey(aKeyEvent))
{
OUString sOriginalCommand = rPrimaryCache.getCommandByKey(aKeyEvent);
if (!sOriginalCommand.isEmpty())
{
if (rSecondaryCache.hasCommand(sOriginalCommand))
{
AcceleratorCache::TKeyList lSecondaryKeys = rSecondaryCache.getKeysByCommand(sOriginalCommand);
rSecondaryCache.removeKey(lSecondaryKeys[0]);
rPrimaryCache.setKeyCommandPair(lSecondaryKeys[0], sOriginalCommand);
}
rPrimaryCache.removeKey(aKeyEvent);
}
}
else
{
OUString sDelCommand = rSecondaryCache.getCommandByKey(aKeyEvent);
if (!sDelCommand.isEmpty())
rSecondaryCache.removeKey(aKeyEvent);
}
}
css::uno::Sequence< css::awt::KeyEvent > SAL_CALL XCUBasedAcceleratorConfiguration::getKeyEventsByCommand(const OUString& sCommand)
{
if (sCommand.isEmpty())
throw css::lang::IllegalArgumentException(
u"Empty command strings are not allowed here."_ustr,
static_cast< ::cppu::OWeakObject* >(this),
1);
SolarMutexGuard g;
AcceleratorCache& rPrimaryCache = impl_getCFG(true );
AcceleratorCache& rSecondaryCache = impl_getCFG(false);
if (!rPrimaryCache.hasCommand(sCommand) && !rSecondaryCache.hasCommand(sCommand))
throw css::container::NoSuchElementException(
OUString(),
static_cast< ::cppu::OWeakObject* >(this));
AcceleratorCache::TKeyList lKeys = rPrimaryCache.getKeysByCommand(sCommand);
AcceleratorCache::TKeyList lSecondaryKeys = rSecondaryCache.getKeysByCommand(sCommand);
for (auto const& secondaryKey : lSecondaryKeys)
lKeys.push_back(secondaryKey);
return comphelper::containerToSequence(lKeys);
}
static AcceleratorCache::TKeyList::const_iterator lcl_getPreferredKey(const AcceleratorCache::TKeyList& lKeys)
{
return std::find_if(lKeys.begin(), lKeys.end(), [](const css::awt::KeyEvent& rAWTKey) {
return !::svt::AcceleratorExecute::st_AWTKey2VCLKey(rAWTKey).GetName().isEmpty(); });
}
css::uno::Sequence< css::uno::Any > SAL_CALL XCUBasedAcceleratorConfiguration::getPreferredKeyEventsForCommandList(const css::uno::Sequence< OUString >& lCommandList)
{
SolarMutexGuard g;
sal_Int32 i = 0;
sal_Int32 c = lCommandList.getLength();
css::uno::Sequence< css::uno::Any > lPreferredOnes (c); // don't pack list!
AcceleratorCache& rCache = impl_getCFG(true);
auto lPreferredOnesRange = asNonConstRange(lPreferredOnes);
for (i=0; i<c; ++i)
{
const OUString& rCommand = lCommandList[i];
if (rCommand.isEmpty())
throw css::lang::IllegalArgumentException(
u"Empty command strings are not allowed here."_ustr,
static_cast< ::cppu::OWeakObject* >(this),
static_cast<sal_Int16>(i));
if (!rCache.hasCommand(rCommand))
continue;
AcceleratorCache::TKeyList lKeys = rCache.getKeysByCommand(rCommand);
if ( lKeys.empty() )
continue;
AcceleratorCache::TKeyList::const_iterator pPreferredKey = lcl_getPreferredKey(lKeys);
if (pPreferredKey != lKeys.end ())
{
css::uno::Any& rAny = lPreferredOnesRange[i];
rAny <<= *pPreferredKey;
}
}
return lPreferredOnes;
}
void SAL_CALL XCUBasedAcceleratorConfiguration::removeCommandFromAllKeyEvents(const OUString& sCommand)
{
if (sCommand.isEmpty())
throw css::lang::IllegalArgumentException(
u"Empty command strings are not allowed here."_ustr,
static_cast< ::cppu::OWeakObject* >(this),
0);
SolarMutexGuard g;
AcceleratorCache& rPrimaryCache = impl_getCFG(true, true );
AcceleratorCache& rSecondaryCache = impl_getCFG(false, true);
if (!rPrimaryCache.hasCommand(sCommand) && !rSecondaryCache.hasCommand(sCommand))
throw css::container::NoSuchElementException(
u"Command does not exists inside this container."_ustr,
static_cast< ::cppu::OWeakObject* >(this));
if (rPrimaryCache.hasCommand(sCommand))
rPrimaryCache.removeCommand(sCommand);
if (rSecondaryCache.hasCommand(sCommand))
rSecondaryCache.removeCommand(sCommand);
}
void SAL_CALL XCUBasedAcceleratorConfiguration::reload()
{
SAL_INFO( "fwk.accelerators", "XCUBasedAcceleratorConfiguration::reload()" );
SolarMutexGuard g;
bool bPreferred;
css::uno::Reference< css::container::XNameAccess > xAccess;
bPreferred = true;
m_aPrimaryReadCache = AcceleratorCache();
m_pPrimaryWriteCache.reset();
m_xCfg->getByName(CFG_ENTRY_PRIMARY) >>= xAccess;
impl_ts_load(bPreferred, xAccess); // load the preferred keys
bPreferred = false;
m_aSecondaryReadCache = AcceleratorCache();
m_pSecondaryWriteCache.reset();
m_xCfg->getByName(CFG_ENTRY_SECONDARY) >>= xAccess;
impl_ts_load(bPreferred, xAccess); // load the secondary keys
}
void SAL_CALL XCUBasedAcceleratorConfiguration::store()
{
SAL_INFO( "fwk.accelerators", "XCUBasedAcceleratorConfiguration::store()" );
SolarMutexGuard g;
bool bPreferred;
bPreferred = true;
// on-demand creation of the primary write cache
impl_getCFG(bPreferred, true);
impl_ts_save(bPreferred);
bPreferred = false;
// on-demand creation of the secondary write cache
impl_getCFG(bPreferred, true);
impl_ts_save(bPreferred);
}
void SAL_CALL XCUBasedAcceleratorConfiguration::storeToStorage(const css::uno::Reference< css::embed::XStorage >& xStorage)
{
// use m_aCache + old AcceleratorXMLWriter to store data directly on storage given as parameter ...
if (!xStorage.is())
return;
tools::Long nOpenModes = css::embed::ElementModes::READWRITE;
css::uno::Reference< css::embed::XStorage > xAcceleratorTypeStorage = xStorage->openStorageElement(u"accelerator"_ustr, nOpenModes);
if (!xAcceleratorTypeStorage.is())
return;
css::uno::Reference< css::io::XStream > xStream = xAcceleratorTypeStorage->openStreamElement(u"current"_ustr, nOpenModes);
css::uno::Reference< css::io::XOutputStream > xOut;
if (xStream.is())
xOut = xStream->getOutputStream();
if (!xOut.is())
throw css::io::IOException(
u"Could not open accelerator configuration for saving."_ustr,
static_cast< ::cppu::OWeakObject* >(this));
// the original m_aCache has been split into primary cache and secondary cache...
// we should merge them before storing to storage
AcceleratorCache aCache;
{
SolarMutexGuard g;
if (m_pPrimaryWriteCache != nullptr)
aCache = *m_pPrimaryWriteCache;
else
aCache = m_aPrimaryReadCache;
AcceleratorCache::TKeyList lKeys;
if (m_pSecondaryWriteCache!=nullptr)
{
lKeys = m_pSecondaryWriteCache->getAllKeys();
for (auto const& lKey : lKeys)
aCache.setKeyCommandPair(lKey, m_pSecondaryWriteCache->getCommandByKey(lKey));
}
else
{
lKeys = m_aSecondaryReadCache.getAllKeys();
for (auto const& lKey : lKeys)
aCache.setKeyCommandPair(lKey, m_aSecondaryReadCache.getCommandByKey(lKey));
}
}
css::uno::Reference< css::io::XTruncate > xClearable(xOut, css::uno::UNO_QUERY_THROW);
xClearable->truncate();
css::uno::Reference< css::io::XSeekable > xSeek(xOut, css::uno::UNO_QUERY);
if (xSeek.is())
xSeek->seek(0);
css::uno::Reference< css::xml::sax::XWriter > xWriter = css::xml::sax::Writer::create(m_xContext);
xWriter->setOutputStream(xOut);
// write into the stream
css::uno::Reference< css::xml::sax::XDocumentHandler > xHandler(xWriter, css::uno::UNO_QUERY_THROW);
AcceleratorConfigurationWriter aWriter(aCache, xHandler);
aWriter.flush();
}
sal_Bool SAL_CALL XCUBasedAcceleratorConfiguration::isModified()
{
return false;
}
sal_Bool SAL_CALL XCUBasedAcceleratorConfiguration::isReadOnly()
{
return false;
}
void SAL_CALL XCUBasedAcceleratorConfiguration::setStorage(const css::uno::Reference< css::embed::XStorage >& /*xStorage*/)
{
SAL_INFO("fwk.accelerators", "XCUBasedAcceleratorConfiguration::setStorage(): implement this HACK .-)");
}
sal_Bool SAL_CALL XCUBasedAcceleratorConfiguration::hasStorage()
{
SAL_INFO("fwk.accelerators", "XCUBasedAcceleratorConfiguration::hasStorage(): implement this HACK .-)");
return false;
}
void SAL_CALL XCUBasedAcceleratorConfiguration::addConfigurationListener(const css::uno::Reference< css::ui::XUIConfigurationListener >& /*xListener*/)
{
SAL_INFO("fwk.accelerators", "XCUBasedAcceleratorConfiguration::addConfigurationListener(): implement me");
}
void SAL_CALL XCUBasedAcceleratorConfiguration::removeConfigurationListener(const css::uno::Reference< css::ui::XUIConfigurationListener >& /*xListener*/)
{
SAL_INFO("fwk.accelerators", "XCUBasedAcceleratorConfiguration::removeConfigurationListener(): implement me");
}
void SAL_CALL XCUBasedAcceleratorConfiguration::reset()
{
css::uno::Reference< css::container::XNamed > xNamed(m_xCfg, css::uno::UNO_QUERY);
OUString sConfig = xNamed->getName();
if ( sConfig == "Global" )
{
m_xCfg.set(
::comphelper::ConfigurationHelper::openConfig( m_xContext, CFG_ENTRY_GLOBAL, ::comphelper::EConfigurationModes::AllLocales ),
css::uno::UNO_QUERY );
XCUBasedAcceleratorConfiguration::reload();
}
else if ( sConfig == "Modules" )
{
m_xCfg.set(
::comphelper::ConfigurationHelper::openConfig( m_xContext, CFG_ENTRY_MODULES, ::comphelper::EConfigurationModes::AllLocales ),
css::uno::UNO_QUERY );
XCUBasedAcceleratorConfiguration::reload();
}
}
void SAL_CALL XCUBasedAcceleratorConfiguration::addResetListener(const css::uno::Reference< css::form::XResetListener >& /*xListener*/)
{
SAL_INFO("fwk.accelerators", "XCUBasedAcceleratorConfiguration::addResetListener(): implement me");
}
void SAL_CALL XCUBasedAcceleratorConfiguration::removeResetListener(const css::uno::Reference< css::form::XResetListener >& /*xListener*/)
{
SAL_INFO("fwk.accelerators", "XCUBasedAcceleratorConfiguration::removeResetListener(): implement me");
}
void SAL_CALL XCUBasedAcceleratorConfiguration::changesOccurred(const css::util::ChangesEvent& aEvent)
{
SAL_INFO( "fwk.accelerators", "XCUBasedAcceleratorConfiguration::changesOccurred()" );
css::uno::Reference< css::container::XHierarchicalNameAccess > xHAccess;
aEvent.Base >>= xHAccess;
if (! xHAccess.is ())
return;
css::util::ChangesEvent aReceivedEvents( aEvent );
const sal_Int32 c = aReceivedEvents.Changes.getLength();
for (sal_Int32 i=0; i<c; ++i)
{
const css::util::ElementChange& aChange = aReceivedEvents.Changes[i];
// Only path of form "PrimaryKeys/Modules/Module['<module_name>']/Key['<command_url>']/Command[<locale>]" will
// be interesting for use. Sometimes short path values are given also by the broadcaster ... but they must be ignored :-)
// So we try to split the path into 3 parts (module isn't important here, because we already know it ... because
// these instance is bound to a specific module configuration ... or it''s the global configuration where no module is given at all.
OUString sOrgPath;
OUString sPath;
OUString sKey;
aChange.Accessor >>= sOrgPath;
sPath = sOrgPath;
OUString sPrimarySecondary = ::utl::extractFirstFromConfigurationPath(sPath, &sPath);
OUString sGlobalModules = ::utl::extractFirstFromConfigurationPath(sPath, &sPath);
if ( sGlobalModules == CFG_ENTRY_GLOBAL )
{
sKey = ::utl::extractFirstFromConfigurationPath(sPath, &sPath);
if ( !sKey.isEmpty() && !sPath.isEmpty() )
reloadChanged(sPrimarySecondary, sGlobalModules, OUString(), sKey);
}
else if ( sGlobalModules == CFG_ENTRY_MODULES )
{
OUString sModule = ::utl::extractFirstFromConfigurationPath(sPath, &sPath);
sKey = ::utl::extractFirstFromConfigurationPath(sPath, &sPath);
if ( !sKey.isEmpty() && !sPath.isEmpty() )
{
reloadChanged(sPrimarySecondary, sGlobalModules, sModule, sKey);
}
}
}
}
void SAL_CALL XCUBasedAcceleratorConfiguration::disposing(const css::lang::EventObject& /*aSource*/)
{
}
void XCUBasedAcceleratorConfiguration::impl_ts_load( bool bPreferred, const css::uno::Reference< css::container::XNameAccess >& xCfg )
{
AcceleratorCache aReadCache;
css::uno::Reference< css::container::XNameAccess > xAccess;
if ( m_sGlobalOrModules == "Global" )
xCfg->getByName(CFG_ENTRY_GLOBAL) >>= xAccess;
else if ( m_sGlobalOrModules == "Modules" )
{
css::uno::Reference< css::container::XNameAccess > xModules;
xCfg->getByName(CFG_ENTRY_MODULES) >>= xModules;
xModules->getByName(m_sModuleCFG) >>= xAccess;
}
const OUString sIsoLang = impl_ts_getLocale();
static constexpr OUStringLiteral sDefaultLocale(u"en-US");
css::uno::Reference< css::container::XNameAccess > xKey;
css::uno::Reference< css::container::XNameAccess > xCommand;
if (xAccess.is())
{
css::uno::Sequence< OUString > lKeys = xAccess->getElementNames();
sal_Int32 nKeys = lKeys.getLength();
for ( sal_Int32 i=0; i<nKeys; ++i )
{
OUString sKey = lKeys[i];
xAccess->getByName(sKey) >>= xKey;
xKey->getByName(CFG_PROP_COMMAND) >>= xCommand;
const css::uno::Sequence< OUString > lLocales = xCommand->getElementNames();
::std::vector< OUString > aLocales { lLocales.begin(), lLocales.end() };
OUString sLocale;
for (auto const& locale : aLocales)
{
if ( locale == sIsoLang )
{
sLocale = locale;
break;
}
}
if (sLocale.isEmpty())
{
for (auto const& locale : aLocales)
{
if ( locale == sDefaultLocale )
{
sLocale = locale;
break;
}
}
if (sLocale.isEmpty())
continue;
}
OUString sCommand;
xCommand->getByName(sLocale) >>= sCommand;
if (sCommand.isEmpty())
continue;
css::awt::KeyEvent aKeyEvent;
sal_Int32 nIndex = 0;
std::u16string_view sKeyCommand = o3tl::getToken(sKey, 0, '_', nIndex);
aKeyEvent.KeyCode = KeyMapping::get().mapIdentifierToCode(OUString::Concat("KEY_") + sKeyCommand);
const sal_Int32 nToken = 4;
bool bValid = true;
sal_Int32 k;
for (k = 0; k < nToken; ++k)
{
if (nIndex < 0)
break;
std::u16string_view sToken = o3tl::getToken(sKey, 0, '_', nIndex);
if (sToken.empty())
{
bValid = false;
break;
}
if ( sToken == u"SHIFT" )
aKeyEvent.Modifiers |= css::awt::KeyModifier::SHIFT;
else if ( sToken == u"MOD1" )
aKeyEvent.Modifiers |= css::awt::KeyModifier::MOD1;
else if ( sToken == u"MOD2" )
aKeyEvent.Modifiers |= css::awt::KeyModifier::MOD2;
else if ( sToken == u"MOD3" )
aKeyEvent.Modifiers |= css::awt::KeyModifier::MOD3;
else
{
bValid = false;
break;
}
}
if ( !aReadCache.hasKey(aKeyEvent) && bValid && k<nToken)
aReadCache.setKeyCommandPair(aKeyEvent, sCommand);
}
}
if (bPreferred)
m_aPrimaryReadCache = std::move(aReadCache);
else
m_aSecondaryReadCache = std::move(aReadCache);
}
void XCUBasedAcceleratorConfiguration::impl_ts_save(bool bPreferred)
{
if (bPreferred)
{
AcceleratorCache::TKeyList lPrimaryReadKeys = m_aPrimaryReadCache.getAllKeys();
AcceleratorCache::TKeyList lPrimaryWriteKeys = m_pPrimaryWriteCache->getAllKeys();
for (auto const& primaryReadKey : lPrimaryReadKeys)
{
if (!m_pPrimaryWriteCache->hasKey(primaryReadKey))
removeKeyFromConfiguration(primaryReadKey, true);
}
for (auto const& primaryWriteKey : lPrimaryWriteKeys)
{
OUString sCommand = m_pPrimaryWriteCache->getCommandByKey(primaryWriteKey);
if (!m_aPrimaryReadCache.hasKey(primaryWriteKey))
{
insertKeyToConfiguration(primaryWriteKey, sCommand, true);
}
else
{
OUString sReadCommand = m_aPrimaryReadCache.getCommandByKey(primaryWriteKey);
if (sReadCommand != sCommand)
insertKeyToConfiguration(primaryWriteKey, sCommand, true);
}
}
// take over all changes into the original container
SolarMutexGuard g;
// coverity[check_after_deref] - confusing but correct
if (m_pPrimaryWriteCache)
{
m_aPrimaryReadCache = *m_pPrimaryWriteCache;
m_pPrimaryWriteCache.reset();
}
}
else
{
AcceleratorCache::TKeyList lSecondaryReadKeys = m_aSecondaryReadCache.getAllKeys();
AcceleratorCache::TKeyList lSecondaryWriteKeys = m_pSecondaryWriteCache->getAllKeys();
for (auto const& secondaryReadKey : lSecondaryReadKeys)
{
if (!m_pSecondaryWriteCache->hasKey(secondaryReadKey))
removeKeyFromConfiguration(secondaryReadKey, false);
}
for (auto const& secondaryWriteKey : lSecondaryWriteKeys)
{
OUString sCommand = m_pSecondaryWriteCache->getCommandByKey(secondaryWriteKey);
if (!m_aSecondaryReadCache.hasKey(secondaryWriteKey))
{
insertKeyToConfiguration(secondaryWriteKey, sCommand, false);
}
else
{
OUString sReadCommand = m_aSecondaryReadCache.getCommandByKey(secondaryWriteKey);
if (sReadCommand != sCommand)
insertKeyToConfiguration(secondaryWriteKey, sCommand, false);
}
}
// take over all changes into the original container
SolarMutexGuard g;
// coverity[check_after_deref] - confusing but correct
if (m_pSecondaryWriteCache)
{
m_aSecondaryReadCache = *m_pSecondaryWriteCache;
m_pSecondaryWriteCache.reset();
}
}
::comphelper::ConfigurationHelper::flush(m_xCfg);
}
void XCUBasedAcceleratorConfiguration::insertKeyToConfiguration( const css::awt::KeyEvent& aKeyEvent, const OUString& sCommand, const bool bPreferred )
{
css::uno::Reference< css::container::XNameAccess > xAccess;
css::uno::Reference< css::container::XNameContainer > xContainer;
css::uno::Reference< css::lang::XSingleServiceFactory > xFac;
css::uno::Reference< css::uno::XInterface > xInst;
if ( bPreferred )
m_xCfg->getByName(CFG_ENTRY_PRIMARY) >>= xAccess;
else
m_xCfg->getByName(CFG_ENTRY_SECONDARY) >>= xAccess;
if ( m_sGlobalOrModules == CFG_ENTRY_GLOBAL )
xAccess->getByName(CFG_ENTRY_GLOBAL) >>= xContainer;
else if ( m_sGlobalOrModules == CFG_ENTRY_MODULES )
{
css::uno::Reference< css::container::XNameContainer > xModules;
xAccess->getByName(CFG_ENTRY_MODULES) >>= xModules;
if ( !xModules->hasByName(m_sModuleCFG) )
{
xFac.set(xModules, css::uno::UNO_QUERY);
xInst = xFac->createInstance();
xModules->insertByName(m_sModuleCFG, css::uno::Any(xInst));
}
xModules->getByName(m_sModuleCFG) >>= xContainer;
}
const OUString sKey = lcl_getKeyString(aKeyEvent);
css::uno::Reference< css::container::XNameAccess > xKey;
css::uno::Reference< css::container::XNameContainer > xCommand;
if ( !xContainer->hasByName(sKey) )
{
xFac.set(xContainer, css::uno::UNO_QUERY);
xInst = xFac->createInstance();
xContainer->insertByName(sKey, css::uno::Any(xInst));
}
xContainer->getByName(sKey) >>= xKey;
xKey->getByName(CFG_PROP_COMMAND) >>= xCommand;
OUString sLocale = impl_ts_getLocale();
if ( !xCommand->hasByName(sLocale) )
xCommand->insertByName(sLocale, css::uno::Any(sCommand));
else
xCommand->replaceByName(sLocale, css::uno::Any(sCommand));
}
void XCUBasedAcceleratorConfiguration::removeKeyFromConfiguration( const css::awt::KeyEvent& aKeyEvent, const bool bPreferred )
{
css::uno::Reference< css::container::XNameAccess > xAccess;
css::uno::Reference< css::container::XNameContainer > xContainer;
if ( bPreferred )
m_xCfg->getByName(CFG_ENTRY_PRIMARY) >>= xAccess;
else
m_xCfg->getByName(CFG_ENTRY_SECONDARY) >>= xAccess;
if ( m_sGlobalOrModules == CFG_ENTRY_GLOBAL )
xAccess->getByName(CFG_ENTRY_GLOBAL) >>= xContainer;
else if ( m_sGlobalOrModules == CFG_ENTRY_MODULES )
{
css::uno::Reference< css::container::XNameAccess > xModules;
xAccess->getByName(CFG_ENTRY_MODULES) >>= xModules;
if ( !xModules->hasByName(m_sModuleCFG) )
return;
xModules->getByName(m_sModuleCFG) >>= xContainer;
}
const OUString sKey = lcl_getKeyString(aKeyEvent);
xContainer->removeByName(sKey);
}
void XCUBasedAcceleratorConfiguration::reloadChanged( const OUString& sPrimarySecondary, std::u16string_view sGlobalModules, const OUString& sModule, const OUString& sKey )
{
css::uno::Reference< css::container::XNameAccess > xAccess;
css::uno::Reference< css::container::XNameContainer > xContainer;
m_xCfg->getByName(sPrimarySecondary) >>= xAccess;
if ( sGlobalModules == CFG_ENTRY_GLOBAL )
xAccess->getByName(CFG_ENTRY_GLOBAL) >>= xContainer;
else
{
css::uno::Reference< css::container::XNameAccess > xModules;
xAccess->getByName(CFG_ENTRY_MODULES) >>= xModules;
if ( !xModules->hasByName(sModule) )
return;
xModules->getByName(sModule) >>= xContainer;
}
css::awt::KeyEvent aKeyEvent;
sal_Int32 nIndex = 0;
std::u16string_view sKeyIdentifier = o3tl::getToken(sKey, 0, '_', nIndex);
aKeyEvent.KeyCode = KeyMapping::get().mapIdentifierToCode(OUString::Concat("KEY_") + sKeyIdentifier);
const int nToken = 4;
for (sal_Int32 i = 0; i < nToken; ++i)
{
if ( nIndex < 0 )
break;
std::u16string_view sToken = o3tl::getToken(sKey, 0, '_', nIndex);
if ( sToken == u"SHIFT" )
aKeyEvent.Modifiers |= css::awt::KeyModifier::SHIFT;
else if ( sToken == u"MOD1" )
aKeyEvent.Modifiers |= css::awt::KeyModifier::MOD1;
else if ( sToken == u"MOD2" )
aKeyEvent.Modifiers |= css::awt::KeyModifier::MOD2;
else if ( sToken == u"MOD3" )
aKeyEvent.Modifiers |= css::awt::KeyModifier::MOD3;
}
css::uno::Reference< css::container::XNameAccess > xKey;
css::uno::Reference< css::container::XNameAccess > xCommand;
OUString sCommand;
if (xContainer->hasByName(sKey))
{
OUString sLocale = impl_ts_getLocale();
xContainer->getByName(sKey) >>= xKey;
xKey->getByName(CFG_PROP_COMMAND) >>= xCommand;
xCommand->getByName(sLocale) >>= sCommand;
}
if ( sPrimarySecondary == CFG_ENTRY_PRIMARY )
{
if (sCommand.isEmpty())
m_aPrimaryReadCache.removeKey(aKeyEvent);
else
m_aPrimaryReadCache.setKeyCommandPair(aKeyEvent, sCommand);
}
else if ( sPrimarySecondary == CFG_ENTRY_SECONDARY )
{
if (sCommand.isEmpty())
m_aSecondaryReadCache.removeKey(aKeyEvent);
else
m_aSecondaryReadCache.setKeyCommandPair(aKeyEvent, sCommand);
}
}
AcceleratorCache& XCUBasedAcceleratorConfiguration::impl_getCFG(bool bPreferred, bool bWriteAccessRequested)
{
SolarMutexGuard g;
if (bPreferred)
{
//create copy of our readonly-cache, if write access is forced ... but
//not still possible!
if ( bWriteAccessRequested && !m_pPrimaryWriteCache )
{
m_pPrimaryWriteCache.reset(new AcceleratorCache(m_aPrimaryReadCache));
}
// in case, we have a writeable cache, we use it for reading too!
// Otherwise the API user can't find its own changes...
if (m_pPrimaryWriteCache)
return *m_pPrimaryWriteCache;
else
return m_aPrimaryReadCache;
}
else
{
//create copy of our readonly-cache, if write access is forced ... but
//not still possible!
if ( bWriteAccessRequested && !m_pSecondaryWriteCache )
{
m_pSecondaryWriteCache.reset(new AcceleratorCache(m_aSecondaryReadCache));
}
// in case, we have a writeable cache, we use it for reading too!
// Otherwise the API user can't find its own changes...
if (m_pSecondaryWriteCache)
return *m_pSecondaryWriteCache;
else
return m_aSecondaryReadCache;
}
}
// static
OUString XCUBasedAcceleratorConfiguration::impl_ts_getLocale()
{
OUString sISOLocale = officecfg::Setup::L10N::ooLocale::get();
if (sISOLocale.isEmpty())
return u"en-US"_ustr;
return sISOLocale;
}
} // namespace framework
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */