Avoid potential negative array index access to cached text.
[LibreOffice.git] / framework / source / accelerators / acceleratorconfiguration.cxx
blob0dff986fa91e55657263b2b81526238c630b9a97
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <sal/config.h>
22 #include <utility>
24 #include <accelerators/acceleratorconfiguration.hxx>
25 #include <accelerators/keymapping.hxx>
26 #include <accelerators/presethandler.hxx>
28 #include <xml/saxnamespacefilter.hxx>
29 #include <xml/acceleratorconfigurationreader.hxx>
30 #include <xml/acceleratorconfigurationwriter.hxx>
32 #include <com/sun/star/xml/sax/Parser.hpp>
33 #include <com/sun/star/xml/sax/InputSource.hpp>
34 #include <com/sun/star/xml/sax/Writer.hpp>
35 #include <com/sun/star/io/IOException.hpp>
36 #include <com/sun/star/embed/ElementModes.hpp>
37 #include <com/sun/star/io/XSeekable.hpp>
38 #include <com/sun/star/io/XTruncate.hpp>
40 #include <vcl/svapp.hxx>
41 #include <com/sun/star/container/XNamed.hpp>
42 #include <com/sun/star/container/XNameContainer.hpp>
43 #include <com/sun/star/container/XHierarchicalNameAccess.hpp>
44 #include <com/sun/star/awt/KeyEvent.hpp>
45 #include <com/sun/star/awt/KeyModifier.hpp>
46 #include <com/sun/star/lang/XSingleServiceFactory.hpp>
47 #include <comphelper/configurationhelper.hxx>
48 #include <comphelper/sequence.hxx>
49 #include <officecfg/Setup.hxx>
50 #include <unotools/configpaths.hxx>
51 #include <svtools/acceleratorexecute.hxx>
52 #include <sal/log.hxx>
53 #include <rtl/ustrbuf.hxx>
54 #include <o3tl/string_view.hxx>
56 constexpr OUString PRESET_DEFAULT = u"default"_ustr;
57 constexpr OUString TARGET_CURRENT = u"current"_ustr;
59 namespace framework
61 constexpr OUString CFG_ENTRY_SECONDARY = u"SecondaryKeys"_ustr;
62 constexpr OUString CFG_PROP_COMMAND = u"Command"_ustr;
64 static OUString lcl_getKeyString(const css::awt::KeyEvent& aKeyEvent)
66 const sal_Int32 nBeginIndex = 4; // "KEY_" is the prefix of an identifier...
67 OUString sKey(KeyMapping::get().mapCodeToIdentifier(aKeyEvent.KeyCode));
68 if (sKey.getLength() < nBeginIndex) // dead key
69 return OUString();
70 OUStringBuffer sKeyBuffer(sKey.subView(nBeginIndex));
72 if ( (aKeyEvent.Modifiers & css::awt::KeyModifier::SHIFT) == css::awt::KeyModifier::SHIFT )
73 sKeyBuffer.append("_SHIFT");
74 if ( (aKeyEvent.Modifiers & css::awt::KeyModifier::MOD1 ) == css::awt::KeyModifier::MOD1 )
75 sKeyBuffer.append("_MOD1");
76 if ( (aKeyEvent.Modifiers & css::awt::KeyModifier::MOD2 ) == css::awt::KeyModifier::MOD2 )
77 sKeyBuffer.append("_MOD2");
78 if ( (aKeyEvent.Modifiers & css::awt::KeyModifier::MOD3 ) == css::awt::KeyModifier::MOD3 )
79 sKeyBuffer.append("_MOD3");
81 return sKeyBuffer.makeStringAndClear();
84 XMLBasedAcceleratorConfiguration::XMLBasedAcceleratorConfiguration(const css::uno::Reference< css::uno::XComponentContext >& xContext)
85 : m_xContext (xContext )
86 , m_aPresetHandler(xContext )
90 XMLBasedAcceleratorConfiguration::~XMLBasedAcceleratorConfiguration()
92 SAL_WARN_IF(m_pWriteCache, "fwk.accelerators", "XMLBasedAcceleratorConfiguration::~XMLBasedAcceleratorConfiguration(): Changes not flushed. Ignore it ...");
95 css::uno::Sequence< css::awt::KeyEvent > SAL_CALL XMLBasedAcceleratorConfiguration::getAllKeyEvents()
97 SolarMutexGuard g;
98 AcceleratorCache& rCache = impl_getCFG();
99 AcceleratorCache::TKeyList lKeys = rCache.getAllKeys();
100 return comphelper::containerToSequence(lKeys);
103 OUString SAL_CALL XMLBasedAcceleratorConfiguration::getCommandByKeyEvent(const css::awt::KeyEvent& aKeyEvent)
105 SolarMutexGuard g;
106 AcceleratorCache& rCache = impl_getCFG();
107 if (!rCache.hasKey(aKeyEvent))
108 throw css::container::NoSuchElementException(
109 OUString(),
110 static_cast< ::cppu::OWeakObject* >(this));
111 return rCache.getCommandByKey(aKeyEvent);
114 void SAL_CALL XMLBasedAcceleratorConfiguration::setKeyEvent(const css::awt::KeyEvent& aKeyEvent,
115 const OUString& sCommand )
117 if (
118 (aKeyEvent.KeyCode == 0) &&
119 (aKeyEvent.KeyChar == 0) &&
120 (aKeyEvent.KeyFunc == 0) &&
121 (aKeyEvent.Modifiers == 0)
123 throw css::lang::IllegalArgumentException(
124 "Such key event seems not to be supported by any operating system.",
125 static_cast< ::cppu::OWeakObject* >(this),
128 if (sCommand.isEmpty())
129 throw css::lang::IllegalArgumentException(
130 "Empty command strings are not allowed here.",
131 static_cast< ::cppu::OWeakObject* >(this),
134 SolarMutexGuard g;
135 AcceleratorCache& rCache = impl_getCFG(true); // sal_True => force getting of a writeable cache!
136 rCache.setKeyCommandPair(aKeyEvent, sCommand);
139 void SAL_CALL XMLBasedAcceleratorConfiguration::removeKeyEvent(const css::awt::KeyEvent& aKeyEvent)
141 SolarMutexGuard g;
142 AcceleratorCache& rCache = impl_getCFG(true); // true => force using of a writeable cache
143 if (!rCache.hasKey(aKeyEvent))
144 throw css::container::NoSuchElementException(
145 OUString(),
146 static_cast< ::cppu::OWeakObject* >(this));
147 rCache.removeKey(aKeyEvent);
150 css::uno::Sequence< css::awt::KeyEvent > SAL_CALL XMLBasedAcceleratorConfiguration::getKeyEventsByCommand(const OUString& sCommand)
152 if (sCommand.isEmpty())
153 throw css::lang::IllegalArgumentException(
154 "Empty command strings are not allowed here.",
155 static_cast< ::cppu::OWeakObject* >(this),
158 SolarMutexGuard g;
159 AcceleratorCache& rCache = impl_getCFG();
160 if (!rCache.hasCommand(sCommand))
161 throw css::container::NoSuchElementException(
162 OUString(),
163 static_cast< ::cppu::OWeakObject* >(this));
165 AcceleratorCache::TKeyList lKeys = rCache.getKeysByCommand(sCommand);
166 return comphelper::containerToSequence(lKeys);
169 css::uno::Sequence< css::uno::Any > SAL_CALL XMLBasedAcceleratorConfiguration::getPreferredKeyEventsForCommandList(const css::uno::Sequence< OUString >& lCommandList)
171 SolarMutexGuard g;
173 sal_Int32 i = 0;
174 sal_Int32 c = lCommandList.getLength();
175 css::uno::Sequence< css::uno::Any > lPreferredOnes (c); // don't pack list!
176 AcceleratorCache& rCache = impl_getCFG();
178 auto lPreferredOnesRange = asNonConstRange(lPreferredOnes);
179 for (i=0; i<c; ++i)
181 const OUString& rCommand = lCommandList[i];
182 if (rCommand.isEmpty())
183 throw css::lang::IllegalArgumentException(
184 "Empty command strings are not allowed here.",
185 static_cast< ::cppu::OWeakObject* >(this),
186 static_cast<sal_Int16>(i));
188 if (!rCache.hasCommand(rCommand))
189 continue;
191 AcceleratorCache::TKeyList lKeys = rCache.getKeysByCommand(rCommand);
192 if ( lKeys.empty() )
193 continue;
195 css::uno::Any& rAny = lPreferredOnesRange[i];
196 rAny <<= *(lKeys.begin());
199 return lPreferredOnes;
202 void SAL_CALL XMLBasedAcceleratorConfiguration::removeCommandFromAllKeyEvents(const OUString& sCommand)
204 if (sCommand.isEmpty())
205 throw css::lang::IllegalArgumentException(
206 "Empty command strings are not allowed here.",
207 static_cast< ::cppu::OWeakObject* >(this),
210 SolarMutexGuard g;
211 AcceleratorCache& rCache = impl_getCFG(true); // sal_True => force getting of a writeable cache!
212 if (!rCache.hasCommand(sCommand))
213 throw css::container::NoSuchElementException(
214 "Command does not exists inside this container.",
215 static_cast< ::cppu::OWeakObject* >(this));
216 rCache.removeCommand(sCommand);
219 void SAL_CALL XMLBasedAcceleratorConfiguration::reload()
221 css::uno::Reference< css::io::XStream > xStream;
222 css::uno::Reference< css::io::XStream > xStreamNoLang;
224 SolarMutexGuard g;
225 xStream = m_aPresetHandler.openTarget(TARGET_CURRENT,
226 css::embed::ElementModes::READ);
229 xStreamNoLang = m_aPresetHandler.openPreset(PRESET_DEFAULT);
231 catch(const css::io::IOException&) {} // does not have to exist
234 css::uno::Reference< css::io::XInputStream > xIn;
235 if (xStream.is())
236 xIn = xStream->getInputStream();
237 if (!xIn.is())
238 throw css::io::IOException(
239 "Could not open accelerator configuration for reading.",
240 static_cast< ::cppu::OWeakObject* >(this));
242 // impl_ts_load() does not clear the cache
244 SolarMutexGuard g;
245 m_aReadCache = AcceleratorCache();
248 impl_ts_load(xIn);
250 // Load also the general language independent default accelerators
251 // (ignoring the already defined accelerators)
252 if (xStreamNoLang.is())
254 xIn = xStreamNoLang->getInputStream();
255 if (xIn.is())
256 impl_ts_load(xIn);
260 void SAL_CALL XMLBasedAcceleratorConfiguration::store()
262 css::uno::Reference< css::io::XStream > xStream;
264 SolarMutexGuard g;
265 xStream = m_aPresetHandler.openTarget(TARGET_CURRENT,
266 css::embed::ElementModes::READWRITE); // open or create!
269 css::uno::Reference< css::io::XOutputStream > xOut;
270 if (xStream.is())
271 xOut = xStream->getOutputStream();
273 if (!xOut.is())
274 throw css::io::IOException(
275 "Could not open accelerator configuration for saving.",
276 static_cast< ::cppu::OWeakObject* >(this));
278 impl_ts_save(xOut);
280 xOut.clear();
281 xStream.clear();
283 m_aPresetHandler.commitUserChanges();
286 void SAL_CALL XMLBasedAcceleratorConfiguration::storeToStorage(const css::uno::Reference< css::embed::XStorage >& xStorage)
288 // no fallback from read/write to readonly!
289 css::uno::Reference< css::io::XStream > xStream = xStorage->openStreamElement(TARGET_CURRENT, css::embed::ElementModes::READWRITE);
291 css::uno::Reference< css::io::XOutputStream > xOut;
292 if (xStream.is())
293 xOut = xStream->getOutputStream();
295 if (!xOut.is())
296 throw css::io::IOException(
297 "Could not open accelerator configuration for saving.",
298 static_cast< ::cppu::OWeakObject* >(this));
300 impl_ts_save(xOut);
302 // TODO inform listener about success, so it can flush the root and sub storage of this stream!
305 sal_Bool SAL_CALL XMLBasedAcceleratorConfiguration::isModified()
307 SolarMutexGuard g;
308 return (m_pWriteCache != nullptr);
311 sal_Bool SAL_CALL XMLBasedAcceleratorConfiguration::isReadOnly()
313 css::uno::Reference< css::io::XStream > xStream;
315 SolarMutexGuard g;
316 xStream = m_aPresetHandler.openTarget(TARGET_CURRENT,
317 css::embed::ElementModes::READWRITE); // open or create!
320 css::uno::Reference< css::io::XOutputStream > xOut;
321 if (xStream.is())
322 xOut = xStream->getOutputStream();
323 return !(xOut.is());
326 void SAL_CALL XMLBasedAcceleratorConfiguration::setStorage(const css::uno::Reference< css::embed::XStorage >& /*xStorage*/)
328 SAL_INFO("fwk.accelerators", "XMLBasedAcceleratorConfiguration::setStorage(): implement this HACK .-)");
331 sal_Bool SAL_CALL XMLBasedAcceleratorConfiguration::hasStorage()
333 SAL_INFO("fwk.accelerators", "XMLBasedAcceleratorConfiguration::hasStorage(): implement this HACK .-)");
334 return false;
337 void SAL_CALL XMLBasedAcceleratorConfiguration::addConfigurationListener(const css::uno::Reference< css::ui::XUIConfigurationListener >& /*xListener*/)
339 SAL_INFO("fwk.accelerators", "XMLBasedAcceleratorConfiguration::addConfigurationListener(): implement me");
342 void SAL_CALL XMLBasedAcceleratorConfiguration::removeConfigurationListener(const css::uno::Reference< css::ui::XUIConfigurationListener >& /*xListener*/)
344 SAL_INFO("fwk.accelerators", "XMLBasedAcceleratorConfiguration::removeConfigurationListener(): implement me");
347 void SAL_CALL XMLBasedAcceleratorConfiguration::reset()
350 SolarMutexGuard g;
351 m_aPresetHandler.copyPresetToTarget(PRESET_DEFAULT, TARGET_CURRENT);
354 reload();
357 void SAL_CALL XMLBasedAcceleratorConfiguration::addResetListener(const css::uno::Reference< css::form::XResetListener >& /*xListener*/)
359 SAL_INFO("fwk.accelerators", "XMLBasedAcceleratorConfiguration::addResetListener(): implement me");
362 void SAL_CALL XMLBasedAcceleratorConfiguration::removeResetListener(const css::uno::Reference< css::form::XResetListener >& /*xListener*/)
364 SAL_INFO("fwk.accelerators", "XMLBasedAcceleratorConfiguration::removeResetListener(): implement me");
367 // IStorageListener
368 void XMLBasedAcceleratorConfiguration::changesOccurred()
370 reload();
373 void XMLBasedAcceleratorConfiguration::impl_ts_load(const css::uno::Reference< css::io::XInputStream >& xStream)
375 css::uno::Reference< css::uno::XComponentContext > xContext;
377 SolarMutexGuard g;
378 xContext = m_xContext;
379 m_pWriteCache.reset();
382 css::uno::Reference< css::io::XSeekable > xSeek(xStream, css::uno::UNO_QUERY);
383 if (xSeek.is())
384 xSeek->seek(0);
386 SolarMutexGuard g;
388 // create the parser queue
389 // Note: Use special filter object between parser and reader
390 // to get filtered xml with right namespaces ...
391 // Use further a temp cache for reading!
392 rtl::Reference<AcceleratorConfigurationReader> pReader = new AcceleratorConfigurationReader(m_aReadCache);
393 rtl::Reference<SaxNamespaceFilter> pFilter = new SaxNamespaceFilter(pReader);
395 // connect parser, filter and stream
396 css::uno::Reference< css::xml::sax::XParser > xParser = css::xml::sax::Parser::create(xContext);
397 xParser->setDocumentHandler(pFilter);
399 css::xml::sax::InputSource aSource;
400 aSource.aInputStream = xStream;
402 // TODO think about error handling
403 xParser->parseStream(aSource);
406 void XMLBasedAcceleratorConfiguration::impl_ts_save(const css::uno::Reference< css::io::XOutputStream >& xStream)
408 bool bChanged;
409 AcceleratorCache aCache;
410 css::uno::Reference< css::uno::XComponentContext > xContext;
412 SolarMutexGuard g;
413 bChanged = (m_pWriteCache != nullptr);
414 if (bChanged)
415 aCache = *m_pWriteCache;
416 else
417 aCache = m_aReadCache;
418 xContext = m_xContext;
421 css::uno::Reference< css::io::XTruncate > xClearable(xStream, css::uno::UNO_QUERY_THROW);
422 xClearable->truncate();
424 // TODO can be removed if seek(0) is done by truncate() automatically!
425 css::uno::Reference< css::io::XSeekable > xSeek(xStream, css::uno::UNO_QUERY);
426 if (xSeek.is())
427 xSeek->seek(0);
429 // combine writer/cache/stream etcpp.
430 css::uno::Reference< css::xml::sax::XWriter > xWriter = css::xml::sax::Writer::create(xContext);
431 xWriter->setOutputStream(xStream);
433 // write into the stream
434 css::uno::Reference< css::xml::sax::XDocumentHandler > xHandler(xWriter, css::uno::UNO_QUERY_THROW);
435 AcceleratorConfigurationWriter aWriter(aCache, xHandler);
436 aWriter.flush();
438 SolarMutexGuard g;
439 // take over all changes into the readonly cache ...
440 // and forget the copy-on-write copied cache
441 if (bChanged)
443 m_aReadCache = *m_pWriteCache;
444 m_pWriteCache.reset();
448 AcceleratorCache& XMLBasedAcceleratorConfiguration::impl_getCFG(bool bWriteAccessRequested)
450 SolarMutexGuard g;
452 //create copy of our readonly-cache, if write access is forced ... but
453 //not still possible!
454 if ( bWriteAccessRequested && !m_pWriteCache )
456 m_pWriteCache.reset(new AcceleratorCache(m_aReadCache));
459 // in case, we have a writeable cache, we use it for reading too!
460 // Otherwise the API user can't find its own changes...
461 if (m_pWriteCache)
462 return *m_pWriteCache;
463 else
464 return m_aReadCache;
467 OUString XMLBasedAcceleratorConfiguration::impl_ts_getLocale() const
469 OUString sISOLocale = officecfg::Setup::L10N::ooLocale::get();
471 if (sISOLocale.isEmpty())
472 return "en-US";
473 return sISOLocale;
476 /*******************************************************************************
478 * XCU based accelerator configuration
480 *******************************************************************************/
482 XCUBasedAcceleratorConfiguration::XCUBasedAcceleratorConfiguration(css::uno::Reference< css::uno::XComponentContext > xContext)
483 : m_xContext (std::move(xContext ))
485 m_xCfg.set(
486 ::comphelper::ConfigurationHelper::openConfig( m_xContext, "org.openoffice.Office.Accelerators", ::comphelper::EConfigurationModes::AllLocales ),
487 css::uno::UNO_QUERY );
490 XCUBasedAcceleratorConfiguration::~XCUBasedAcceleratorConfiguration()
494 css::uno::Sequence< css::awt::KeyEvent > SAL_CALL XCUBasedAcceleratorConfiguration::getAllKeyEvents()
496 SolarMutexGuard g;
498 AcceleratorCache::TKeyList lKeys = impl_getCFG(true).getAllKeys(); //get keys from PrimaryKeys set
500 AcceleratorCache::TKeyList lSecondaryKeys = impl_getCFG(false).getAllKeys(); //get keys from SecondaryKeys set
501 lKeys.reserve(lKeys.size()+lSecondaryKeys.size());
502 for (auto const& secondaryKey : lSecondaryKeys)
503 lKeys.push_back(secondaryKey);
505 return comphelper::containerToSequence(lKeys);
508 OUString SAL_CALL XCUBasedAcceleratorConfiguration::getCommandByKeyEvent(const css::awt::KeyEvent& aKeyEvent)
510 SolarMutexGuard g;
512 AcceleratorCache& rPrimaryCache = impl_getCFG(true );
513 AcceleratorCache& rSecondaryCache = impl_getCFG(false);
515 if (!rPrimaryCache.hasKey(aKeyEvent) && !rSecondaryCache.hasKey(aKeyEvent))
516 throw css::container::NoSuchElementException(
517 OUString(),
518 static_cast< ::cppu::OWeakObject* >(this));
520 if (rPrimaryCache.hasKey(aKeyEvent))
521 return rPrimaryCache.getCommandByKey(aKeyEvent);
522 else
523 return rSecondaryCache.getCommandByKey(aKeyEvent);
526 void SAL_CALL XCUBasedAcceleratorConfiguration::setKeyEvent(const css::awt::KeyEvent& aKeyEvent,
527 const OUString& sCommand )
529 SAL_INFO( "fwk.accelerators", "XCUBasedAcceleratorConfiguration::setKeyEvent" );
531 if (
532 (aKeyEvent.KeyCode == 0) &&
533 (aKeyEvent.KeyChar == 0) &&
534 (aKeyEvent.KeyFunc == 0) &&
535 (aKeyEvent.Modifiers == 0)
537 throw css::lang::IllegalArgumentException(
538 "Such key event seems not to be supported by any operating system.",
539 static_cast< ::cppu::OWeakObject* >(this),
542 if (sCommand.isEmpty())
543 throw css::lang::IllegalArgumentException(
544 "Empty command strings are not allowed here.",
545 static_cast< ::cppu::OWeakObject* >(this),
548 SolarMutexGuard g;
550 AcceleratorCache& rPrimaryCache = impl_getCFG(true, true ); // sal_True => force getting of a writeable cache!
551 AcceleratorCache& rSecondaryCache = impl_getCFG(false, true); // sal_True => force getting of a writeable cache!
553 if ( rPrimaryCache.hasKey(aKeyEvent) )
555 OUString sOriginalCommand = rPrimaryCache.getCommandByKey(aKeyEvent);
556 if ( sCommand != sOriginalCommand )
558 if (rSecondaryCache.hasCommand(sOriginalCommand))
560 AcceleratorCache::TKeyList lSecondaryKeys = rSecondaryCache.getKeysByCommand(sOriginalCommand);
561 rSecondaryCache.removeKey(lSecondaryKeys[0]);
562 rPrimaryCache.setKeyCommandPair(lSecondaryKeys[0], sOriginalCommand);
565 if (rPrimaryCache.hasCommand(sCommand))
567 AcceleratorCache::TKeyList lPrimaryKeys = rPrimaryCache.getKeysByCommand(sCommand);
568 rPrimaryCache.removeKey(lPrimaryKeys[0]);
569 rSecondaryCache.setKeyCommandPair(lPrimaryKeys[0], sCommand);
572 rPrimaryCache.setKeyCommandPair(aKeyEvent, sCommand);
576 else if ( rSecondaryCache.hasKey(aKeyEvent) )
578 OUString sOriginalCommand = rSecondaryCache.getCommandByKey(aKeyEvent);
579 if (sCommand != sOriginalCommand)
581 if (rPrimaryCache.hasCommand(sCommand))
583 AcceleratorCache::TKeyList lPrimaryKeys = rPrimaryCache.getKeysByCommand(sCommand);
584 rPrimaryCache.removeKey(lPrimaryKeys[0]);
585 rSecondaryCache.setKeyCommandPair(lPrimaryKeys[0], sCommand);
588 rSecondaryCache.removeKey(aKeyEvent);
589 rPrimaryCache.setKeyCommandPair(aKeyEvent, sCommand);
593 else
595 if (rPrimaryCache.hasCommand(sCommand))
597 AcceleratorCache::TKeyList lPrimaryKeys = rPrimaryCache.getKeysByCommand(sCommand);
598 rPrimaryCache.removeKey(lPrimaryKeys[0]);
599 rSecondaryCache.setKeyCommandPair(lPrimaryKeys[0], sCommand);
602 rPrimaryCache.setKeyCommandPair(aKeyEvent, sCommand);
606 void SAL_CALL XCUBasedAcceleratorConfiguration::removeKeyEvent(const css::awt::KeyEvent& aKeyEvent)
608 SolarMutexGuard g;
610 AcceleratorCache& rPrimaryCache = impl_getCFG(true, true );
611 AcceleratorCache& rSecondaryCache = impl_getCFG(false, true);
613 if (!rPrimaryCache.hasKey(aKeyEvent) && !rSecondaryCache.hasKey(aKeyEvent))
614 throw css::container::NoSuchElementException(
615 OUString(),
616 static_cast< ::cppu::OWeakObject* >(this));
618 if (rPrimaryCache.hasKey(aKeyEvent))
620 OUString sOriginalCommand = rPrimaryCache.getCommandByKey(aKeyEvent);
621 if (!sOriginalCommand.isEmpty())
623 if (rSecondaryCache.hasCommand(sOriginalCommand))
625 AcceleratorCache::TKeyList lSecondaryKeys = rSecondaryCache.getKeysByCommand(sOriginalCommand);
626 rSecondaryCache.removeKey(lSecondaryKeys[0]);
627 rPrimaryCache.setKeyCommandPair(lSecondaryKeys[0], sOriginalCommand);
630 rPrimaryCache.removeKey(aKeyEvent);
634 else
636 OUString sDelCommand = rSecondaryCache.getCommandByKey(aKeyEvent);
637 if (!sDelCommand.isEmpty())
638 rSecondaryCache.removeKey(aKeyEvent);
642 css::uno::Sequence< css::awt::KeyEvent > SAL_CALL XCUBasedAcceleratorConfiguration::getKeyEventsByCommand(const OUString& sCommand)
644 if (sCommand.isEmpty())
645 throw css::lang::IllegalArgumentException(
646 "Empty command strings are not allowed here.",
647 static_cast< ::cppu::OWeakObject* >(this),
650 SolarMutexGuard g;
652 AcceleratorCache& rPrimaryCache = impl_getCFG(true );
653 AcceleratorCache& rSecondaryCache = impl_getCFG(false);
655 if (!rPrimaryCache.hasCommand(sCommand) && !rSecondaryCache.hasCommand(sCommand))
656 throw css::container::NoSuchElementException(
657 OUString(),
658 static_cast< ::cppu::OWeakObject* >(this));
660 AcceleratorCache::TKeyList lKeys = rPrimaryCache.getKeysByCommand(sCommand);
662 AcceleratorCache::TKeyList lSecondaryKeys = rSecondaryCache.getKeysByCommand(sCommand);
663 for (auto const& secondaryKey : lSecondaryKeys)
664 lKeys.push_back(secondaryKey);
666 return comphelper::containerToSequence(lKeys);
669 static AcceleratorCache::TKeyList::const_iterator lcl_getPreferredKey(const AcceleratorCache::TKeyList& lKeys)
671 return std::find_if(lKeys.begin(), lKeys.end(), [](const css::awt::KeyEvent& rAWTKey) {
672 return !::svt::AcceleratorExecute::st_AWTKey2VCLKey(rAWTKey).GetName().isEmpty(); });
675 css::uno::Sequence< css::uno::Any > SAL_CALL XCUBasedAcceleratorConfiguration::getPreferredKeyEventsForCommandList(const css::uno::Sequence< OUString >& lCommandList)
677 SolarMutexGuard g;
679 sal_Int32 i = 0;
680 sal_Int32 c = lCommandList.getLength();
681 css::uno::Sequence< css::uno::Any > lPreferredOnes (c); // don't pack list!
682 AcceleratorCache& rCache = impl_getCFG(true);
684 auto lPreferredOnesRange = asNonConstRange(lPreferredOnes);
685 for (i=0; i<c; ++i)
687 const OUString& rCommand = lCommandList[i];
688 if (rCommand.isEmpty())
689 throw css::lang::IllegalArgumentException(
690 "Empty command strings are not allowed here.",
691 static_cast< ::cppu::OWeakObject* >(this),
692 static_cast<sal_Int16>(i));
694 if (!rCache.hasCommand(rCommand))
695 continue;
697 AcceleratorCache::TKeyList lKeys = rCache.getKeysByCommand(rCommand);
698 if ( lKeys.empty() )
699 continue;
701 AcceleratorCache::TKeyList::const_iterator pPreferredKey = lcl_getPreferredKey(lKeys);
702 if (pPreferredKey != lKeys.end ())
704 css::uno::Any& rAny = lPreferredOnesRange[i];
705 rAny <<= *pPreferredKey;
709 return lPreferredOnes;
712 void SAL_CALL XCUBasedAcceleratorConfiguration::removeCommandFromAllKeyEvents(const OUString& sCommand)
714 if (sCommand.isEmpty())
715 throw css::lang::IllegalArgumentException(
716 "Empty command strings are not allowed here.",
717 static_cast< ::cppu::OWeakObject* >(this),
720 SolarMutexGuard g;
722 AcceleratorCache& rPrimaryCache = impl_getCFG(true, true );
723 AcceleratorCache& rSecondaryCache = impl_getCFG(false, true);
725 if (!rPrimaryCache.hasCommand(sCommand) && !rSecondaryCache.hasCommand(sCommand))
726 throw css::container::NoSuchElementException(
727 "Command does not exists inside this container.",
728 static_cast< ::cppu::OWeakObject* >(this));
730 if (rPrimaryCache.hasCommand(sCommand))
731 rPrimaryCache.removeCommand(sCommand);
732 if (rSecondaryCache.hasCommand(sCommand))
733 rSecondaryCache.removeCommand(sCommand);
736 void SAL_CALL XCUBasedAcceleratorConfiguration::reload()
738 SAL_INFO( "fwk.accelerators", "XCUBasedAcceleratorConfiguration::reload()" );
740 SolarMutexGuard g;
742 bool bPreferred;
743 css::uno::Reference< css::container::XNameAccess > xAccess;
745 bPreferred = true;
746 m_aPrimaryReadCache = AcceleratorCache();
747 m_pPrimaryWriteCache.reset();
748 m_xCfg->getByName(CFG_ENTRY_PRIMARY) >>= xAccess;
749 impl_ts_load(bPreferred, xAccess); // load the preferred keys
751 bPreferred = false;
752 m_aSecondaryReadCache = AcceleratorCache();
753 m_pSecondaryWriteCache.reset();
754 m_xCfg->getByName(CFG_ENTRY_SECONDARY) >>= xAccess;
755 impl_ts_load(bPreferred, xAccess); // load the secondary keys
758 void SAL_CALL XCUBasedAcceleratorConfiguration::store()
760 SAL_INFO( "fwk.accelerators", "XCUBasedAcceleratorConfiguration::store()" );
762 SolarMutexGuard g;
764 bool bPreferred;
766 bPreferred = true;
767 // on-demand creation of the primary write cache
768 impl_getCFG(bPreferred, true);
769 impl_ts_save(bPreferred);
771 bPreferred = false;
772 // on-demand creation of the secondary write cache
773 impl_getCFG(bPreferred, true);
774 impl_ts_save(bPreferred);
777 void SAL_CALL XCUBasedAcceleratorConfiguration::storeToStorage(const css::uno::Reference< css::embed::XStorage >& xStorage)
779 // use m_aCache + old AcceleratorXMLWriter to store data directly on storage given as parameter ...
780 if (!xStorage.is())
781 return;
783 tools::Long nOpenModes = css::embed::ElementModes::READWRITE;
784 css::uno::Reference< css::embed::XStorage > xAcceleratorTypeStorage = xStorage->openStorageElement("accelerator", nOpenModes);
785 if (!xAcceleratorTypeStorage.is())
786 return;
788 css::uno::Reference< css::io::XStream > xStream = xAcceleratorTypeStorage->openStreamElement("current", nOpenModes);
789 css::uno::Reference< css::io::XOutputStream > xOut;
790 if (xStream.is())
791 xOut = xStream->getOutputStream();
792 if (!xOut.is())
793 throw css::io::IOException(
794 "Could not open accelerator configuration for saving.",
795 static_cast< ::cppu::OWeakObject* >(this));
797 // the original m_aCache has been split into primary cache and secondary cache...
798 // we should merge them before storing to storage
799 AcceleratorCache aCache;
801 SolarMutexGuard g;
803 if (m_pPrimaryWriteCache != nullptr)
804 aCache = *m_pPrimaryWriteCache;
805 else
806 aCache = m_aPrimaryReadCache;
808 AcceleratorCache::TKeyList lKeys;
809 if (m_pSecondaryWriteCache!=nullptr)
811 lKeys = m_pSecondaryWriteCache->getAllKeys();
812 for (auto const& lKey : lKeys)
813 aCache.setKeyCommandPair(lKey, m_pSecondaryWriteCache->getCommandByKey(lKey));
815 else
817 lKeys = m_aSecondaryReadCache.getAllKeys();
818 for (auto const& lKey : lKeys)
819 aCache.setKeyCommandPair(lKey, m_aSecondaryReadCache.getCommandByKey(lKey));
823 css::uno::Reference< css::io::XTruncate > xClearable(xOut, css::uno::UNO_QUERY_THROW);
824 xClearable->truncate();
825 css::uno::Reference< css::io::XSeekable > xSeek(xOut, css::uno::UNO_QUERY);
826 if (xSeek.is())
827 xSeek->seek(0);
829 css::uno::Reference< css::xml::sax::XWriter > xWriter = css::xml::sax::Writer::create(m_xContext);
830 xWriter->setOutputStream(xOut);
832 // write into the stream
833 css::uno::Reference< css::xml::sax::XDocumentHandler > xHandler(xWriter, css::uno::UNO_QUERY_THROW);
834 AcceleratorConfigurationWriter aWriter(aCache, xHandler);
835 aWriter.flush();
838 sal_Bool SAL_CALL XCUBasedAcceleratorConfiguration::isModified()
840 return false;
843 sal_Bool SAL_CALL XCUBasedAcceleratorConfiguration::isReadOnly()
845 return false;
848 void SAL_CALL XCUBasedAcceleratorConfiguration::setStorage(const css::uno::Reference< css::embed::XStorage >& /*xStorage*/)
850 SAL_INFO("fwk.accelerators", "XCUBasedAcceleratorConfiguration::setStorage(): implement this HACK .-)");
853 sal_Bool SAL_CALL XCUBasedAcceleratorConfiguration::hasStorage()
855 SAL_INFO("fwk.accelerators", "XCUBasedAcceleratorConfiguration::hasStorage(): implement this HACK .-)");
856 return false;
859 void SAL_CALL XCUBasedAcceleratorConfiguration::addConfigurationListener(const css::uno::Reference< css::ui::XUIConfigurationListener >& /*xListener*/)
861 SAL_INFO("fwk.accelerators", "XCUBasedAcceleratorConfiguration::addConfigurationListener(): implement me");
864 void SAL_CALL XCUBasedAcceleratorConfiguration::removeConfigurationListener(const css::uno::Reference< css::ui::XUIConfigurationListener >& /*xListener*/)
866 SAL_INFO("fwk.accelerators", "XCUBasedAcceleratorConfiguration::removeConfigurationListener(): implement me");
869 void SAL_CALL XCUBasedAcceleratorConfiguration::reset()
871 css::uno::Reference< css::container::XNamed > xNamed(m_xCfg, css::uno::UNO_QUERY);
872 OUString sConfig = xNamed->getName();
873 if ( sConfig == "Global" )
875 m_xCfg.set(
876 ::comphelper::ConfigurationHelper::openConfig( m_xContext, CFG_ENTRY_GLOBAL, ::comphelper::EConfigurationModes::AllLocales ),
877 css::uno::UNO_QUERY );
878 XCUBasedAcceleratorConfiguration::reload();
880 else if ( sConfig == "Modules" )
882 m_xCfg.set(
883 ::comphelper::ConfigurationHelper::openConfig( m_xContext, CFG_ENTRY_MODULES, ::comphelper::EConfigurationModes::AllLocales ),
884 css::uno::UNO_QUERY );
885 XCUBasedAcceleratorConfiguration::reload();
889 void SAL_CALL XCUBasedAcceleratorConfiguration::addResetListener(const css::uno::Reference< css::form::XResetListener >& /*xListener*/)
891 SAL_INFO("fwk.accelerators", "XCUBasedAcceleratorConfiguration::addResetListener(): implement me");
894 void SAL_CALL XCUBasedAcceleratorConfiguration::removeResetListener(const css::uno::Reference< css::form::XResetListener >& /*xListener*/)
896 SAL_INFO("fwk.accelerators", "XCUBasedAcceleratorConfiguration::removeResetListener(): implement me");
899 void SAL_CALL XCUBasedAcceleratorConfiguration::changesOccurred(const css::util::ChangesEvent& aEvent)
901 SAL_INFO( "fwk.accelerators", "XCUBasedAcceleratorConfiguration::changesOccurred()" );
903 css::uno::Reference< css::container::XHierarchicalNameAccess > xHAccess;
904 aEvent.Base >>= xHAccess;
905 if (! xHAccess.is ())
906 return;
908 css::util::ChangesEvent aReceivedEvents( aEvent );
909 const sal_Int32 c = aReceivedEvents.Changes.getLength();
910 for (sal_Int32 i=0; i<c; ++i)
912 const css::util::ElementChange& aChange = aReceivedEvents.Changes[i];
914 // Only path of form "PrimaryKeys/Modules/Module['<module_name>']/Key['<command_url>']/Command[<locale>]" will
915 // be interesting for use. Sometimes short path values are given also by the broadcaster ... but they must be ignored :-)
916 // So we try to split the path into 3 parts (module isn't important here, because we already know it ... because
917 // these instance is bound to a specific module configuration ... or it''s the global configuration where no module is given at all.
919 OUString sOrgPath;
920 OUString sPath;
921 OUString sKey;
923 aChange.Accessor >>= sOrgPath;
924 sPath = sOrgPath;
925 OUString sPrimarySecondary = ::utl::extractFirstFromConfigurationPath(sPath, &sPath);
926 OUString sGlobalModules = ::utl::extractFirstFromConfigurationPath(sPath, &sPath);
928 if ( sGlobalModules == CFG_ENTRY_GLOBAL )
930 sKey = ::utl::extractFirstFromConfigurationPath(sPath, &sPath);
931 if ( !sKey.isEmpty() && !sPath.isEmpty() )
932 reloadChanged(sPrimarySecondary, sGlobalModules, OUString(), sKey);
934 else if ( sGlobalModules == CFG_ENTRY_MODULES )
936 OUString sModule = ::utl::extractFirstFromConfigurationPath(sPath, &sPath);
937 sKey = ::utl::extractFirstFromConfigurationPath(sPath, &sPath);
939 if ( !sKey.isEmpty() && !sPath.isEmpty() )
941 reloadChanged(sPrimarySecondary, sGlobalModules, sModule, sKey);
947 void SAL_CALL XCUBasedAcceleratorConfiguration::disposing(const css::lang::EventObject& /*aSource*/)
951 void XCUBasedAcceleratorConfiguration::impl_ts_load( bool bPreferred, const css::uno::Reference< css::container::XNameAccess >& xCfg )
953 AcceleratorCache aReadCache;
954 css::uno::Reference< css::container::XNameAccess > xAccess;
955 if ( m_sGlobalOrModules == "Global" )
956 xCfg->getByName(CFG_ENTRY_GLOBAL) >>= xAccess;
957 else if ( m_sGlobalOrModules == "Modules" )
959 css::uno::Reference< css::container::XNameAccess > xModules;
960 xCfg->getByName(CFG_ENTRY_MODULES) >>= xModules;
961 xModules->getByName(m_sModuleCFG) >>= xAccess;
964 const OUString sIsoLang = impl_ts_getLocale();
965 static constexpr OUStringLiteral sDefaultLocale(u"en-US");
967 css::uno::Reference< css::container::XNameAccess > xKey;
968 css::uno::Reference< css::container::XNameAccess > xCommand;
969 if (xAccess.is())
971 css::uno::Sequence< OUString > lKeys = xAccess->getElementNames();
972 sal_Int32 nKeys = lKeys.getLength();
973 for ( sal_Int32 i=0; i<nKeys; ++i )
975 OUString sKey = lKeys[i];
976 xAccess->getByName(sKey) >>= xKey;
977 xKey->getByName(CFG_PROP_COMMAND) >>= xCommand;
979 const css::uno::Sequence< OUString > lLocales = xCommand->getElementNames();
980 ::std::vector< OUString > aLocales { lLocales.begin(), lLocales.end() };
982 OUString sLocale;
983 for (auto const& locale : aLocales)
985 if ( locale == sIsoLang )
987 sLocale = locale;
988 break;
992 if (sLocale.isEmpty())
994 for (auto const& locale : aLocales)
996 if ( locale == sDefaultLocale )
998 sLocale = locale;
999 break;
1003 if (sLocale.isEmpty())
1004 continue;
1007 OUString sCommand;
1008 xCommand->getByName(sLocale) >>= sCommand;
1009 if (sCommand.isEmpty())
1010 continue;
1012 css::awt::KeyEvent aKeyEvent;
1014 sal_Int32 nIndex = 0;
1015 std::u16string_view sKeyCommand = o3tl::getToken(sKey, 0, '_', nIndex);
1016 aKeyEvent.KeyCode = KeyMapping::get().mapIdentifierToCode(OUString::Concat("KEY_") + sKeyCommand);
1018 const sal_Int32 nToken = 4;
1019 bool bValid = true;
1020 sal_Int32 k;
1021 for (k = 0; k < nToken; ++k)
1023 if (nIndex < 0)
1024 break;
1026 std::u16string_view sToken = o3tl::getToken(sKey, 0, '_', nIndex);
1027 if (sToken.empty())
1029 bValid = false;
1030 break;
1033 if ( sToken == u"SHIFT" )
1034 aKeyEvent.Modifiers |= css::awt::KeyModifier::SHIFT;
1035 else if ( sToken == u"MOD1" )
1036 aKeyEvent.Modifiers |= css::awt::KeyModifier::MOD1;
1037 else if ( sToken == u"MOD2" )
1038 aKeyEvent.Modifiers |= css::awt::KeyModifier::MOD2;
1039 else if ( sToken == u"MOD3" )
1040 aKeyEvent.Modifiers |= css::awt::KeyModifier::MOD3;
1041 else
1043 bValid = false;
1044 break;
1048 if ( !aReadCache.hasKey(aKeyEvent) && bValid && k<nToken)
1049 aReadCache.setKeyCommandPair(aKeyEvent, sCommand);
1053 if (bPreferred)
1054 m_aPrimaryReadCache = std::move(aReadCache);
1055 else
1056 m_aSecondaryReadCache = std::move(aReadCache);
1059 void XCUBasedAcceleratorConfiguration::impl_ts_save(bool bPreferred)
1061 if (bPreferred)
1063 AcceleratorCache::TKeyList lPrimaryReadKeys = m_aPrimaryReadCache.getAllKeys();
1064 AcceleratorCache::TKeyList lPrimaryWriteKeys = m_pPrimaryWriteCache->getAllKeys();
1066 for (auto const& primaryReadKey : lPrimaryReadKeys)
1068 if (!m_pPrimaryWriteCache->hasKey(primaryReadKey))
1069 removeKeyFromConfiguration(primaryReadKey, true);
1072 for (auto const& primaryWriteKey : lPrimaryWriteKeys)
1074 OUString sCommand = m_pPrimaryWriteCache->getCommandByKey(primaryWriteKey);
1075 if (!m_aPrimaryReadCache.hasKey(primaryWriteKey))
1077 insertKeyToConfiguration(primaryWriteKey, sCommand, true);
1079 else
1081 OUString sReadCommand = m_aPrimaryReadCache.getCommandByKey(primaryWriteKey);
1082 if (sReadCommand != sCommand)
1083 insertKeyToConfiguration(primaryWriteKey, sCommand, true);
1087 // take over all changes into the original container
1088 SolarMutexGuard g;
1089 // coverity[check_after_deref] - confusing but correct
1090 if (m_pPrimaryWriteCache)
1092 m_aPrimaryReadCache = *m_pPrimaryWriteCache;
1093 m_pPrimaryWriteCache.reset();
1097 else
1099 AcceleratorCache::TKeyList lSecondaryReadKeys = m_aSecondaryReadCache.getAllKeys();
1100 AcceleratorCache::TKeyList lSecondaryWriteKeys = m_pSecondaryWriteCache->getAllKeys();
1102 for (auto const& secondaryReadKey : lSecondaryReadKeys)
1104 if (!m_pSecondaryWriteCache->hasKey(secondaryReadKey))
1105 removeKeyFromConfiguration(secondaryReadKey, false);
1108 for (auto const& secondaryWriteKey : lSecondaryWriteKeys)
1110 OUString sCommand = m_pSecondaryWriteCache->getCommandByKey(secondaryWriteKey);
1111 if (!m_aSecondaryReadCache.hasKey(secondaryWriteKey))
1113 insertKeyToConfiguration(secondaryWriteKey, sCommand, false);
1115 else
1117 OUString sReadCommand = m_aSecondaryReadCache.getCommandByKey(secondaryWriteKey);
1118 if (sReadCommand != sCommand)
1119 insertKeyToConfiguration(secondaryWriteKey, sCommand, false);
1123 // take over all changes into the original container
1124 SolarMutexGuard g;
1125 // coverity[check_after_deref] - confusing but correct
1126 if (m_pSecondaryWriteCache)
1128 m_aSecondaryReadCache = *m_pSecondaryWriteCache;
1129 m_pSecondaryWriteCache.reset();
1133 ::comphelper::ConfigurationHelper::flush(m_xCfg);
1136 void XCUBasedAcceleratorConfiguration::insertKeyToConfiguration( const css::awt::KeyEvent& aKeyEvent, const OUString& sCommand, const bool bPreferred )
1138 css::uno::Reference< css::container::XNameAccess > xAccess;
1139 css::uno::Reference< css::container::XNameContainer > xContainer;
1140 css::uno::Reference< css::lang::XSingleServiceFactory > xFac;
1141 css::uno::Reference< css::uno::XInterface > xInst;
1143 if ( bPreferred )
1144 m_xCfg->getByName(CFG_ENTRY_PRIMARY) >>= xAccess;
1145 else
1146 m_xCfg->getByName(CFG_ENTRY_SECONDARY) >>= xAccess;
1148 if ( m_sGlobalOrModules == CFG_ENTRY_GLOBAL )
1149 xAccess->getByName(CFG_ENTRY_GLOBAL) >>= xContainer;
1150 else if ( m_sGlobalOrModules == CFG_ENTRY_MODULES )
1152 css::uno::Reference< css::container::XNameContainer > xModules;
1153 xAccess->getByName(CFG_ENTRY_MODULES) >>= xModules;
1154 if ( !xModules->hasByName(m_sModuleCFG) )
1156 xFac.set(xModules, css::uno::UNO_QUERY);
1157 xInst = xFac->createInstance();
1158 xModules->insertByName(m_sModuleCFG, css::uno::Any(xInst));
1160 xModules->getByName(m_sModuleCFG) >>= xContainer;
1163 const OUString sKey = lcl_getKeyString(aKeyEvent);
1164 css::uno::Reference< css::container::XNameAccess > xKey;
1165 css::uno::Reference< css::container::XNameContainer > xCommand;
1166 if ( !xContainer->hasByName(sKey) )
1168 xFac.set(xContainer, css::uno::UNO_QUERY);
1169 xInst = xFac->createInstance();
1170 xContainer->insertByName(sKey, css::uno::Any(xInst));
1172 xContainer->getByName(sKey) >>= xKey;
1174 xKey->getByName(CFG_PROP_COMMAND) >>= xCommand;
1175 OUString sLocale = impl_ts_getLocale();
1176 if ( !xCommand->hasByName(sLocale) )
1177 xCommand->insertByName(sLocale, css::uno::Any(sCommand));
1178 else
1179 xCommand->replaceByName(sLocale, css::uno::Any(sCommand));
1182 void XCUBasedAcceleratorConfiguration::removeKeyFromConfiguration( const css::awt::KeyEvent& aKeyEvent, const bool bPreferred )
1184 css::uno::Reference< css::container::XNameAccess > xAccess;
1185 css::uno::Reference< css::container::XNameContainer > xContainer;
1187 if ( bPreferred )
1188 m_xCfg->getByName(CFG_ENTRY_PRIMARY) >>= xAccess;
1189 else
1190 m_xCfg->getByName(CFG_ENTRY_SECONDARY) >>= xAccess;
1192 if ( m_sGlobalOrModules == CFG_ENTRY_GLOBAL )
1193 xAccess->getByName(CFG_ENTRY_GLOBAL) >>= xContainer;
1194 else if ( m_sGlobalOrModules == CFG_ENTRY_MODULES )
1196 css::uno::Reference< css::container::XNameAccess > xModules;
1197 xAccess->getByName(CFG_ENTRY_MODULES) >>= xModules;
1198 if ( !xModules->hasByName(m_sModuleCFG) )
1199 return;
1200 xModules->getByName(m_sModuleCFG) >>= xContainer;
1203 const OUString sKey = lcl_getKeyString(aKeyEvent);
1204 xContainer->removeByName(sKey);
1207 void XCUBasedAcceleratorConfiguration::reloadChanged( const OUString& sPrimarySecondary, std::u16string_view sGlobalModules, const OUString& sModule, const OUString& sKey )
1209 css::uno::Reference< css::container::XNameAccess > xAccess;
1210 css::uno::Reference< css::container::XNameContainer > xContainer;
1212 m_xCfg->getByName(sPrimarySecondary) >>= xAccess;
1213 if ( sGlobalModules == CFG_ENTRY_GLOBAL )
1214 xAccess->getByName(CFG_ENTRY_GLOBAL) >>= xContainer;
1215 else
1217 css::uno::Reference< css::container::XNameAccess > xModules;
1218 xAccess->getByName(CFG_ENTRY_MODULES) >>= xModules;
1219 if ( !xModules->hasByName(sModule) )
1220 return;
1221 xModules->getByName(sModule) >>= xContainer;
1224 css::awt::KeyEvent aKeyEvent;
1226 sal_Int32 nIndex = 0;
1227 std::u16string_view sKeyIdentifier = o3tl::getToken(sKey, 0, '_', nIndex);
1228 aKeyEvent.KeyCode = KeyMapping::get().mapIdentifierToCode(OUString::Concat("KEY_") + sKeyIdentifier);
1230 const int nToken = 4;
1231 for (sal_Int32 i = 0; i < nToken; ++i)
1233 if ( nIndex < 0 )
1234 break;
1236 std::u16string_view sToken = o3tl::getToken(sKey, 0, '_', nIndex);
1237 if ( sToken == u"SHIFT" )
1238 aKeyEvent.Modifiers |= css::awt::KeyModifier::SHIFT;
1239 else if ( sToken == u"MOD1" )
1240 aKeyEvent.Modifiers |= css::awt::KeyModifier::MOD1;
1241 else if ( sToken == u"MOD2" )
1242 aKeyEvent.Modifiers |= css::awt::KeyModifier::MOD2;
1243 else if ( sToken == u"MOD3" )
1244 aKeyEvent.Modifiers |= css::awt::KeyModifier::MOD3;
1247 css::uno::Reference< css::container::XNameAccess > xKey;
1248 css::uno::Reference< css::container::XNameAccess > xCommand;
1249 OUString sCommand;
1251 if (xContainer->hasByName(sKey))
1253 OUString sLocale = impl_ts_getLocale();
1254 xContainer->getByName(sKey) >>= xKey;
1255 xKey->getByName(CFG_PROP_COMMAND) >>= xCommand;
1256 xCommand->getByName(sLocale) >>= sCommand;
1259 if ( sPrimarySecondary == CFG_ENTRY_PRIMARY )
1261 if (sCommand.isEmpty())
1262 m_aPrimaryReadCache.removeKey(aKeyEvent);
1263 else
1264 m_aPrimaryReadCache.setKeyCommandPair(aKeyEvent, sCommand);
1266 else if ( sPrimarySecondary == CFG_ENTRY_SECONDARY )
1268 if (sCommand.isEmpty())
1269 m_aSecondaryReadCache.removeKey(aKeyEvent);
1270 else
1271 m_aSecondaryReadCache.setKeyCommandPair(aKeyEvent, sCommand);
1275 AcceleratorCache& XCUBasedAcceleratorConfiguration::impl_getCFG(bool bPreferred, bool bWriteAccessRequested)
1277 SolarMutexGuard g;
1279 if (bPreferred)
1281 //create copy of our readonly-cache, if write access is forced ... but
1282 //not still possible!
1283 if ( bWriteAccessRequested && !m_pPrimaryWriteCache )
1285 m_pPrimaryWriteCache.reset(new AcceleratorCache(m_aPrimaryReadCache));
1288 // in case, we have a writeable cache, we use it for reading too!
1289 // Otherwise the API user can't find its own changes...
1290 if (m_pPrimaryWriteCache)
1291 return *m_pPrimaryWriteCache;
1292 else
1293 return m_aPrimaryReadCache;
1296 else
1298 //create copy of our readonly-cache, if write access is forced ... but
1299 //not still possible!
1300 if ( bWriteAccessRequested && !m_pSecondaryWriteCache )
1302 m_pSecondaryWriteCache.reset(new AcceleratorCache(m_aSecondaryReadCache));
1305 // in case, we have a writeable cache, we use it for reading too!
1306 // Otherwise the API user can't find its own changes...
1307 if (m_pSecondaryWriteCache)
1308 return *m_pSecondaryWriteCache;
1309 else
1310 return m_aSecondaryReadCache;
1314 OUString XCUBasedAcceleratorConfiguration::impl_ts_getLocale() const
1316 OUString sISOLocale = officecfg::Setup::L10N::ooLocale::get();
1318 if (sISOLocale.isEmpty())
1319 return "en-US";
1320 return sISOLocale;
1323 } // namespace framework
1325 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */