tdf#130857 qt weld: Implement QtInstanceWidget::get_text_height
[LibreOffice.git] / framework / source / accelerators / acceleratorconfiguration.cxx
blob8876093fc4f6d349956c37b15be94757e775fa9a
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 u"Such key event seems not to be supported by any operating system."_ustr,
125 static_cast< ::cppu::OWeakObject* >(this),
128 if (sCommand.isEmpty())
129 throw css::lang::IllegalArgumentException(
130 u"Empty command strings are not allowed here."_ustr,
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 u"Empty command strings are not allowed here."_ustr,
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 u"Empty command strings are not allowed here."_ustr,
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 u"Empty command strings are not allowed here."_ustr,
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 u"Command does not exists inside this container."_ustr,
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 u"Could not open accelerator configuration for reading."_ustr,
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 u"Could not open accelerator configuration for saving."_ustr,
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 u"Could not open accelerator configuration for saving."_ustr,
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 // static
468 OUString XMLBasedAcceleratorConfiguration::impl_ts_getLocale()
470 OUString sISOLocale = officecfg::Setup::L10N::ooLocale::get();
472 if (sISOLocale.isEmpty())
473 return u"en-US"_ustr;
474 return sISOLocale;
477 /*******************************************************************************
479 * XCU based accelerator configuration
481 *******************************************************************************/
483 XCUBasedAcceleratorConfiguration::XCUBasedAcceleratorConfiguration(css::uno::Reference< css::uno::XComponentContext > xContext)
484 : m_xContext (std::move(xContext ))
486 m_xCfg.set(
487 ::comphelper::ConfigurationHelper::openConfig( m_xContext, u"org.openoffice.Office.Accelerators"_ustr, ::comphelper::EConfigurationModes::AllLocales ),
488 css::uno::UNO_QUERY );
491 XCUBasedAcceleratorConfiguration::~XCUBasedAcceleratorConfiguration()
495 css::uno::Sequence< css::awt::KeyEvent > SAL_CALL XCUBasedAcceleratorConfiguration::getAllKeyEvents()
497 SolarMutexGuard g;
499 AcceleratorCache::TKeyList lKeys = impl_getCFG(true).getAllKeys(); //get keys from PrimaryKeys set
501 AcceleratorCache::TKeyList lSecondaryKeys = impl_getCFG(false).getAllKeys(); //get keys from SecondaryKeys set
502 lKeys.reserve(lKeys.size()+lSecondaryKeys.size());
503 for (auto const& secondaryKey : lSecondaryKeys)
504 lKeys.push_back(secondaryKey);
506 return comphelper::containerToSequence(lKeys);
509 OUString SAL_CALL XCUBasedAcceleratorConfiguration::getCommandByKeyEvent(const css::awt::KeyEvent& aKeyEvent)
511 SolarMutexGuard g;
513 AcceleratorCache& rPrimaryCache = impl_getCFG(true );
514 AcceleratorCache& rSecondaryCache = impl_getCFG(false);
516 if (!rPrimaryCache.hasKey(aKeyEvent) && !rSecondaryCache.hasKey(aKeyEvent))
517 throw css::container::NoSuchElementException(
518 OUString(),
519 static_cast< ::cppu::OWeakObject* >(this));
521 if (rPrimaryCache.hasKey(aKeyEvent))
522 return rPrimaryCache.getCommandByKey(aKeyEvent);
523 else
524 return rSecondaryCache.getCommandByKey(aKeyEvent);
527 void SAL_CALL XCUBasedAcceleratorConfiguration::setKeyEvent(const css::awt::KeyEvent& aKeyEvent,
528 const OUString& sCommand )
530 SAL_INFO( "fwk.accelerators", "XCUBasedAcceleratorConfiguration::setKeyEvent" );
532 if (
533 (aKeyEvent.KeyCode == 0) &&
534 (aKeyEvent.KeyChar == 0) &&
535 (aKeyEvent.KeyFunc == 0) &&
536 (aKeyEvent.Modifiers == 0)
538 throw css::lang::IllegalArgumentException(
539 u"Such key event seems not to be supported by any operating system."_ustr,
540 static_cast< ::cppu::OWeakObject* >(this),
543 if (sCommand.isEmpty())
544 throw css::lang::IllegalArgumentException(
545 u"Empty command strings are not allowed here."_ustr,
546 static_cast< ::cppu::OWeakObject* >(this),
549 SolarMutexGuard g;
551 AcceleratorCache& rPrimaryCache = impl_getCFG(true, true ); // sal_True => force getting of a writeable cache!
552 AcceleratorCache& rSecondaryCache = impl_getCFG(false, true); // sal_True => force getting of a writeable cache!
554 if ( rPrimaryCache.hasKey(aKeyEvent) )
556 OUString sOriginalCommand = rPrimaryCache.getCommandByKey(aKeyEvent);
557 if ( sCommand != sOriginalCommand )
559 if (rSecondaryCache.hasCommand(sOriginalCommand))
561 AcceleratorCache::TKeyList lSecondaryKeys = rSecondaryCache.getKeysByCommand(sOriginalCommand);
562 rSecondaryCache.removeKey(lSecondaryKeys[0]);
563 rPrimaryCache.setKeyCommandPair(lSecondaryKeys[0], sOriginalCommand);
566 if (rPrimaryCache.hasCommand(sCommand))
568 AcceleratorCache::TKeyList lPrimaryKeys = rPrimaryCache.getKeysByCommand(sCommand);
569 rPrimaryCache.removeKey(lPrimaryKeys[0]);
570 rSecondaryCache.setKeyCommandPair(lPrimaryKeys[0], sCommand);
573 rPrimaryCache.setKeyCommandPair(aKeyEvent, sCommand);
577 else if ( rSecondaryCache.hasKey(aKeyEvent) )
579 OUString sOriginalCommand = rSecondaryCache.getCommandByKey(aKeyEvent);
580 if (sCommand != sOriginalCommand)
582 if (rPrimaryCache.hasCommand(sCommand))
584 AcceleratorCache::TKeyList lPrimaryKeys = rPrimaryCache.getKeysByCommand(sCommand);
585 rPrimaryCache.removeKey(lPrimaryKeys[0]);
586 rSecondaryCache.setKeyCommandPair(lPrimaryKeys[0], sCommand);
589 rSecondaryCache.removeKey(aKeyEvent);
590 rPrimaryCache.setKeyCommandPair(aKeyEvent, sCommand);
594 else
596 if (rPrimaryCache.hasCommand(sCommand))
598 AcceleratorCache::TKeyList lPrimaryKeys = rPrimaryCache.getKeysByCommand(sCommand);
599 rPrimaryCache.removeKey(lPrimaryKeys[0]);
600 rSecondaryCache.setKeyCommandPair(lPrimaryKeys[0], sCommand);
603 rPrimaryCache.setKeyCommandPair(aKeyEvent, sCommand);
607 void SAL_CALL XCUBasedAcceleratorConfiguration::removeKeyEvent(const css::awt::KeyEvent& aKeyEvent)
609 SolarMutexGuard g;
611 AcceleratorCache& rPrimaryCache = impl_getCFG(true, true );
612 AcceleratorCache& rSecondaryCache = impl_getCFG(false, true);
614 if (!rPrimaryCache.hasKey(aKeyEvent) && !rSecondaryCache.hasKey(aKeyEvent))
615 throw css::container::NoSuchElementException(
616 OUString(),
617 static_cast< ::cppu::OWeakObject* >(this));
619 if (rPrimaryCache.hasKey(aKeyEvent))
621 OUString sOriginalCommand = rPrimaryCache.getCommandByKey(aKeyEvent);
622 if (!sOriginalCommand.isEmpty())
624 if (rSecondaryCache.hasCommand(sOriginalCommand))
626 AcceleratorCache::TKeyList lSecondaryKeys = rSecondaryCache.getKeysByCommand(sOriginalCommand);
627 rSecondaryCache.removeKey(lSecondaryKeys[0]);
628 rPrimaryCache.setKeyCommandPair(lSecondaryKeys[0], sOriginalCommand);
631 rPrimaryCache.removeKey(aKeyEvent);
635 else
637 OUString sDelCommand = rSecondaryCache.getCommandByKey(aKeyEvent);
638 if (!sDelCommand.isEmpty())
639 rSecondaryCache.removeKey(aKeyEvent);
643 css::uno::Sequence< css::awt::KeyEvent > SAL_CALL XCUBasedAcceleratorConfiguration::getKeyEventsByCommand(const OUString& sCommand)
645 if (sCommand.isEmpty())
646 throw css::lang::IllegalArgumentException(
647 u"Empty command strings are not allowed here."_ustr,
648 static_cast< ::cppu::OWeakObject* >(this),
651 SolarMutexGuard g;
653 AcceleratorCache& rPrimaryCache = impl_getCFG(true );
654 AcceleratorCache& rSecondaryCache = impl_getCFG(false);
656 if (!rPrimaryCache.hasCommand(sCommand) && !rSecondaryCache.hasCommand(sCommand))
657 throw css::container::NoSuchElementException(
658 OUString(),
659 static_cast< ::cppu::OWeakObject* >(this));
661 AcceleratorCache::TKeyList lKeys = rPrimaryCache.getKeysByCommand(sCommand);
663 AcceleratorCache::TKeyList lSecondaryKeys = rSecondaryCache.getKeysByCommand(sCommand);
664 for (auto const& secondaryKey : lSecondaryKeys)
665 lKeys.push_back(secondaryKey);
667 return comphelper::containerToSequence(lKeys);
670 static AcceleratorCache::TKeyList::const_iterator lcl_getPreferredKey(const AcceleratorCache::TKeyList& lKeys)
672 return std::find_if(lKeys.begin(), lKeys.end(), [](const css::awt::KeyEvent& rAWTKey) {
673 return !::svt::AcceleratorExecute::st_AWTKey2VCLKey(rAWTKey).GetName().isEmpty(); });
676 css::uno::Sequence< css::uno::Any > SAL_CALL XCUBasedAcceleratorConfiguration::getPreferredKeyEventsForCommandList(const css::uno::Sequence< OUString >& lCommandList)
678 SolarMutexGuard g;
680 sal_Int32 i = 0;
681 sal_Int32 c = lCommandList.getLength();
682 css::uno::Sequence< css::uno::Any > lPreferredOnes (c); // don't pack list!
683 AcceleratorCache& rCache = impl_getCFG(true);
685 auto lPreferredOnesRange = asNonConstRange(lPreferredOnes);
686 for (i=0; i<c; ++i)
688 const OUString& rCommand = lCommandList[i];
689 if (rCommand.isEmpty())
690 throw css::lang::IllegalArgumentException(
691 u"Empty command strings are not allowed here."_ustr,
692 static_cast< ::cppu::OWeakObject* >(this),
693 static_cast<sal_Int16>(i));
695 if (!rCache.hasCommand(rCommand))
696 continue;
698 AcceleratorCache::TKeyList lKeys = rCache.getKeysByCommand(rCommand);
699 if ( lKeys.empty() )
700 continue;
702 AcceleratorCache::TKeyList::const_iterator pPreferredKey = lcl_getPreferredKey(lKeys);
703 if (pPreferredKey != lKeys.end ())
705 css::uno::Any& rAny = lPreferredOnesRange[i];
706 rAny <<= *pPreferredKey;
710 return lPreferredOnes;
713 void SAL_CALL XCUBasedAcceleratorConfiguration::removeCommandFromAllKeyEvents(const OUString& sCommand)
715 if (sCommand.isEmpty())
716 throw css::lang::IllegalArgumentException(
717 u"Empty command strings are not allowed here."_ustr,
718 static_cast< ::cppu::OWeakObject* >(this),
721 SolarMutexGuard g;
723 AcceleratorCache& rPrimaryCache = impl_getCFG(true, true );
724 AcceleratorCache& rSecondaryCache = impl_getCFG(false, true);
726 if (!rPrimaryCache.hasCommand(sCommand) && !rSecondaryCache.hasCommand(sCommand))
727 throw css::container::NoSuchElementException(
728 u"Command does not exists inside this container."_ustr,
729 static_cast< ::cppu::OWeakObject* >(this));
731 if (rPrimaryCache.hasCommand(sCommand))
732 rPrimaryCache.removeCommand(sCommand);
733 if (rSecondaryCache.hasCommand(sCommand))
734 rSecondaryCache.removeCommand(sCommand);
737 void SAL_CALL XCUBasedAcceleratorConfiguration::reload()
739 SAL_INFO( "fwk.accelerators", "XCUBasedAcceleratorConfiguration::reload()" );
741 SolarMutexGuard g;
743 bool bPreferred;
744 css::uno::Reference< css::container::XNameAccess > xAccess;
746 bPreferred = true;
747 m_aPrimaryReadCache = AcceleratorCache();
748 m_pPrimaryWriteCache.reset();
749 m_xCfg->getByName(CFG_ENTRY_PRIMARY) >>= xAccess;
750 impl_ts_load(bPreferred, xAccess); // load the preferred keys
752 bPreferred = false;
753 m_aSecondaryReadCache = AcceleratorCache();
754 m_pSecondaryWriteCache.reset();
755 m_xCfg->getByName(CFG_ENTRY_SECONDARY) >>= xAccess;
756 impl_ts_load(bPreferred, xAccess); // load the secondary keys
759 void SAL_CALL XCUBasedAcceleratorConfiguration::store()
761 SAL_INFO( "fwk.accelerators", "XCUBasedAcceleratorConfiguration::store()" );
763 SolarMutexGuard g;
765 bool bPreferred;
767 bPreferred = true;
768 // on-demand creation of the primary write cache
769 impl_getCFG(bPreferred, true);
770 impl_ts_save(bPreferred);
772 bPreferred = false;
773 // on-demand creation of the secondary write cache
774 impl_getCFG(bPreferred, true);
775 impl_ts_save(bPreferred);
778 void SAL_CALL XCUBasedAcceleratorConfiguration::storeToStorage(const css::uno::Reference< css::embed::XStorage >& xStorage)
780 // use m_aCache + old AcceleratorXMLWriter to store data directly on storage given as parameter ...
781 if (!xStorage.is())
782 return;
784 tools::Long nOpenModes = css::embed::ElementModes::READWRITE;
785 css::uno::Reference< css::embed::XStorage > xAcceleratorTypeStorage = xStorage->openStorageElement(u"accelerator"_ustr, nOpenModes);
786 if (!xAcceleratorTypeStorage.is())
787 return;
789 css::uno::Reference< css::io::XStream > xStream = xAcceleratorTypeStorage->openStreamElement(u"current"_ustr, nOpenModes);
790 css::uno::Reference< css::io::XOutputStream > xOut;
791 if (xStream.is())
792 xOut = xStream->getOutputStream();
793 if (!xOut.is())
794 throw css::io::IOException(
795 u"Could not open accelerator configuration for saving."_ustr,
796 static_cast< ::cppu::OWeakObject* >(this));
798 // the original m_aCache has been split into primary cache and secondary cache...
799 // we should merge them before storing to storage
800 AcceleratorCache aCache;
802 SolarMutexGuard g;
804 if (m_pPrimaryWriteCache != nullptr)
805 aCache = *m_pPrimaryWriteCache;
806 else
807 aCache = m_aPrimaryReadCache;
809 AcceleratorCache::TKeyList lKeys;
810 if (m_pSecondaryWriteCache!=nullptr)
812 lKeys = m_pSecondaryWriteCache->getAllKeys();
813 for (auto const& lKey : lKeys)
814 aCache.setKeyCommandPair(lKey, m_pSecondaryWriteCache->getCommandByKey(lKey));
816 else
818 lKeys = m_aSecondaryReadCache.getAllKeys();
819 for (auto const& lKey : lKeys)
820 aCache.setKeyCommandPair(lKey, m_aSecondaryReadCache.getCommandByKey(lKey));
824 css::uno::Reference< css::io::XTruncate > xClearable(xOut, css::uno::UNO_QUERY_THROW);
825 xClearable->truncate();
826 css::uno::Reference< css::io::XSeekable > xSeek(xOut, css::uno::UNO_QUERY);
827 if (xSeek.is())
828 xSeek->seek(0);
830 css::uno::Reference< css::xml::sax::XWriter > xWriter = css::xml::sax::Writer::create(m_xContext);
831 xWriter->setOutputStream(xOut);
833 // write into the stream
834 css::uno::Reference< css::xml::sax::XDocumentHandler > xHandler(xWriter, css::uno::UNO_QUERY_THROW);
835 AcceleratorConfigurationWriter aWriter(aCache, xHandler);
836 aWriter.flush();
839 sal_Bool SAL_CALL XCUBasedAcceleratorConfiguration::isModified()
841 return false;
844 sal_Bool SAL_CALL XCUBasedAcceleratorConfiguration::isReadOnly()
846 return false;
849 void SAL_CALL XCUBasedAcceleratorConfiguration::setStorage(const css::uno::Reference< css::embed::XStorage >& /*xStorage*/)
851 SAL_INFO("fwk.accelerators", "XCUBasedAcceleratorConfiguration::setStorage(): implement this HACK .-)");
854 sal_Bool SAL_CALL XCUBasedAcceleratorConfiguration::hasStorage()
856 SAL_INFO("fwk.accelerators", "XCUBasedAcceleratorConfiguration::hasStorage(): implement this HACK .-)");
857 return false;
860 void SAL_CALL XCUBasedAcceleratorConfiguration::addConfigurationListener(const css::uno::Reference< css::ui::XUIConfigurationListener >& /*xListener*/)
862 SAL_INFO("fwk.accelerators", "XCUBasedAcceleratorConfiguration::addConfigurationListener(): implement me");
865 void SAL_CALL XCUBasedAcceleratorConfiguration::removeConfigurationListener(const css::uno::Reference< css::ui::XUIConfigurationListener >& /*xListener*/)
867 SAL_INFO("fwk.accelerators", "XCUBasedAcceleratorConfiguration::removeConfigurationListener(): implement me");
870 void SAL_CALL XCUBasedAcceleratorConfiguration::reset()
872 css::uno::Reference< css::container::XNamed > xNamed(m_xCfg, css::uno::UNO_QUERY);
873 OUString sConfig = xNamed->getName();
874 if ( sConfig == "Global" )
876 m_xCfg.set(
877 ::comphelper::ConfigurationHelper::openConfig( m_xContext, CFG_ENTRY_GLOBAL, ::comphelper::EConfigurationModes::AllLocales ),
878 css::uno::UNO_QUERY );
879 XCUBasedAcceleratorConfiguration::reload();
881 else if ( sConfig == "Modules" )
883 m_xCfg.set(
884 ::comphelper::ConfigurationHelper::openConfig( m_xContext, CFG_ENTRY_MODULES, ::comphelper::EConfigurationModes::AllLocales ),
885 css::uno::UNO_QUERY );
886 XCUBasedAcceleratorConfiguration::reload();
890 void SAL_CALL XCUBasedAcceleratorConfiguration::addResetListener(const css::uno::Reference< css::form::XResetListener >& /*xListener*/)
892 SAL_INFO("fwk.accelerators", "XCUBasedAcceleratorConfiguration::addResetListener(): implement me");
895 void SAL_CALL XCUBasedAcceleratorConfiguration::removeResetListener(const css::uno::Reference< css::form::XResetListener >& /*xListener*/)
897 SAL_INFO("fwk.accelerators", "XCUBasedAcceleratorConfiguration::removeResetListener(): implement me");
900 void SAL_CALL XCUBasedAcceleratorConfiguration::changesOccurred(const css::util::ChangesEvent& aReceivedEvents)
902 SAL_INFO( "fwk.accelerators", "XCUBasedAcceleratorConfiguration::changesOccurred()" );
904 css::uno::Reference< css::container::XHierarchicalNameAccess > xHAccess;
905 aReceivedEvents.Base >>= xHAccess;
906 if (! xHAccess.is ())
907 return;
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 const 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 // static
1315 OUString XCUBasedAcceleratorConfiguration::impl_ts_getLocale()
1317 OUString sISOLocale = officecfg::Setup::L10N::ooLocale::get();
1319 if (sISOLocale.isEmpty())
1320 return u"en-US"_ustr;
1321 return sISOLocale;
1324 } // namespace framework
1326 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */