1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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>
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
;
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
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()
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
)
106 AcceleratorCache
& rCache
= impl_getCFG();
107 if (!rCache
.hasKey(aKeyEvent
))
108 throw css::container::NoSuchElementException(
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
)
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),
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
)
142 AcceleratorCache
& rCache
= impl_getCFG(true); // true => force using of a writeable cache
143 if (!rCache
.hasKey(aKeyEvent
))
144 throw css::container::NoSuchElementException(
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),
159 AcceleratorCache
& rCache
= impl_getCFG();
160 if (!rCache
.hasCommand(sCommand
))
161 throw css::container::NoSuchElementException(
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
)
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
);
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
))
191 AcceleratorCache::TKeyList lKeys
= rCache
.getKeysByCommand(rCommand
);
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),
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
;
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
;
236 xIn
= xStream
->getInputStream();
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
245 m_aReadCache
= AcceleratorCache();
250 // Load also the general language independent default accelerators
251 // (ignoring the already defined accelerators)
252 if (xStreamNoLang
.is())
254 xIn
= xStreamNoLang
->getInputStream();
260 void SAL_CALL
XMLBasedAcceleratorConfiguration::store()
262 css::uno::Reference
< css::io::XStream
> xStream
;
265 xStream
= m_aPresetHandler
.openTarget(TARGET_CURRENT
,
266 css::embed::ElementModes::READWRITE
); // open or create!
269 css::uno::Reference
< css::io::XOutputStream
> xOut
;
271 xOut
= xStream
->getOutputStream();
274 throw css::io::IOException(
275 u
"Could not open accelerator configuration for saving."_ustr
,
276 static_cast< ::cppu::OWeakObject
* >(this));
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
;
293 xOut
= xStream
->getOutputStream();
296 throw css::io::IOException(
297 u
"Could not open accelerator configuration for saving."_ustr
,
298 static_cast< ::cppu::OWeakObject
* >(this));
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()
308 return (m_pWriteCache
!= nullptr);
311 sal_Bool SAL_CALL
XMLBasedAcceleratorConfiguration::isReadOnly()
313 css::uno::Reference
< css::io::XStream
> xStream
;
316 xStream
= m_aPresetHandler
.openTarget(TARGET_CURRENT
,
317 css::embed::ElementModes::READWRITE
); // open or create!
320 css::uno::Reference
< css::io::XOutputStream
> xOut
;
322 xOut
= xStream
->getOutputStream();
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 .-)");
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()
351 m_aPresetHandler
.copyPresetToTarget(PRESET_DEFAULT
, TARGET_CURRENT
);
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");
368 void XMLBasedAcceleratorConfiguration::changesOccurred()
373 void XMLBasedAcceleratorConfiguration::impl_ts_load(const css::uno::Reference
< css::io::XInputStream
>& xStream
)
375 css::uno::Reference
< css::uno::XComponentContext
> xContext
;
378 xContext
= m_xContext
;
379 m_pWriteCache
.reset();
382 css::uno::Reference
< css::io::XSeekable
> xSeek(xStream
, css::uno::UNO_QUERY
);
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
)
409 AcceleratorCache aCache
;
410 css::uno::Reference
< css::uno::XComponentContext
> xContext
;
413 bChanged
= (m_pWriteCache
!= nullptr);
415 aCache
= *m_pWriteCache
;
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
);
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
);
439 // take over all changes into the readonly cache ...
440 // and forget the copy-on-write copied cache
443 m_aReadCache
= *m_pWriteCache
;
444 m_pWriteCache
.reset();
448 AcceleratorCache
& XMLBasedAcceleratorConfiguration::impl_getCFG(bool bWriteAccessRequested
)
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...
462 return *m_pWriteCache
;
468 OUString
XMLBasedAcceleratorConfiguration::impl_ts_getLocale()
470 OUString sISOLocale
= officecfg::Setup::L10N::ooLocale::get();
472 if (sISOLocale
.isEmpty())
473 return u
"en-US"_ustr
;
477 /*******************************************************************************
479 * XCU based accelerator configuration
481 *******************************************************************************/
483 XCUBasedAcceleratorConfiguration::XCUBasedAcceleratorConfiguration(css::uno::Reference
< css::uno::XComponentContext
> xContext
)
484 : m_xContext (std::move(xContext
))
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()
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
)
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(
519 static_cast< ::cppu::OWeakObject
* >(this));
521 if (rPrimaryCache
.hasKey(aKeyEvent
))
522 return rPrimaryCache
.getCommandByKey(aKeyEvent
);
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" );
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),
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
);
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
)
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(
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
);
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),
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(
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
)
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
);
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
))
698 AcceleratorCache::TKeyList lKeys
= rCache
.getKeysByCommand(rCommand
);
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),
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()" );
744 css::uno::Reference
< css::container::XNameAccess
> xAccess
;
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
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()" );
768 // on-demand creation of the primary write cache
769 impl_getCFG(bPreferred
, true);
770 impl_ts_save(bPreferred
);
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 ...
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())
789 css::uno::Reference
< css::io::XStream
> xStream
= xAcceleratorTypeStorage
->openStreamElement(u
"current"_ustr
, nOpenModes
);
790 css::uno::Reference
< css::io::XOutputStream
> xOut
;
792 xOut
= xStream
->getOutputStream();
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
;
804 if (m_pPrimaryWriteCache
!= nullptr)
805 aCache
= *m_pPrimaryWriteCache
;
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
));
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
);
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
);
839 sal_Bool SAL_CALL
XCUBasedAcceleratorConfiguration::isModified()
844 sal_Bool SAL_CALL
XCUBasedAcceleratorConfiguration::isReadOnly()
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 .-)");
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" )
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" )
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 ())
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.
923 aChange
.Accessor
>>= 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
;
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() };
983 for (auto const& locale
: aLocales
)
985 if ( locale
== sIsoLang
)
992 if (sLocale
.isEmpty())
994 for (auto const& locale
: aLocales
)
996 if ( locale
== sDefaultLocale
)
1003 if (sLocale
.isEmpty())
1008 xCommand
->getByName(sLocale
) >>= sCommand
;
1009 if (sCommand
.isEmpty())
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;
1021 for (k
= 0; k
< nToken
; ++k
)
1026 std::u16string_view sToken
= o3tl::getToken(sKey
, 0, '_', nIndex
);
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
;
1048 if ( !aReadCache
.hasKey(aKeyEvent
) && bValid
&& k
<nToken
)
1049 aReadCache
.setKeyCommandPair(aKeyEvent
, sCommand
);
1054 m_aPrimaryReadCache
= std::move(aReadCache
);
1056 m_aSecondaryReadCache
= std::move(aReadCache
);
1059 void XCUBasedAcceleratorConfiguration::impl_ts_save(bool 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);
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
1089 // coverity[check_after_deref] - confusing but correct
1090 if (m_pPrimaryWriteCache
)
1092 m_aPrimaryReadCache
= *m_pPrimaryWriteCache
;
1093 m_pPrimaryWriteCache
.reset();
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);
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
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
;
1144 m_xCfg
->getByName(CFG_ENTRY_PRIMARY
) >>= xAccess
;
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
));
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
;
1188 m_xCfg
->getByName(CFG_ENTRY_PRIMARY
) >>= xAccess
;
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
) )
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
;
1217 css::uno::Reference
< css::container::XNameAccess
> xModules
;
1218 xAccess
->getByName(CFG_ENTRY_MODULES
) >>= xModules
;
1219 if ( !xModules
->hasByName(sModule
) )
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
)
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
;
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
);
1264 m_aPrimaryReadCache
.setKeyCommandPair(aKeyEvent
, sCommand
);
1266 else if ( sPrimarySecondary
== CFG_ENTRY_SECONDARY
)
1268 if (sCommand
.isEmpty())
1269 m_aSecondaryReadCache
.removeKey(aKeyEvent
);
1271 m_aSecondaryReadCache
.setKeyCommandPair(aKeyEvent
, sCommand
);
1275 AcceleratorCache
& XCUBasedAcceleratorConfiguration::impl_getCFG(bool bPreferred
, bool bWriteAccessRequested
)
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
;
1293 return m_aPrimaryReadCache
;
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
;
1310 return m_aSecondaryReadCache
;
1315 OUString
XCUBasedAcceleratorConfiguration::impl_ts_getLocale()
1317 OUString sISOLocale
= officecfg::Setup::L10N::ooLocale::get();
1319 if (sISOLocale
.isEmpty())
1320 return u
"en-US"_ustr
;
1324 } // namespace framework
1326 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */