Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
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/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
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 .
18 : */
19 :
20 : #include <accelerators/acceleratorconfiguration.hxx>
21 :
22 : #include <accelerators/presethandler.hxx>
23 :
24 : #include <xml/saxnamespacefilter.hxx>
25 : #include <xml/acceleratorconfigurationreader.hxx>
26 : #include <xml/acceleratorconfigurationwriter.hxx>
27 :
28 : #include <acceleratorconst.h>
29 : #include <services.h>
30 :
31 : #include <com/sun/star/xml/sax/Parser.hpp>
32 : #include <com/sun/star/xml/sax/InputSource.hpp>
33 : #include <com/sun/star/xml/sax/Writer.hpp>
34 : #include <com/sun/star/io/XActiveDataSource.hpp>
35 : #include <com/sun/star/embed/ElementModes.hpp>
36 : #include <com/sun/star/io/XSeekable.hpp>
37 : #include <com/sun/star/io/XTruncate.hpp>
38 : #include <com/sun/star/beans/XPropertySet.hpp>
39 :
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/awt/KeyEvent.hpp>
44 : #include <com/sun/star/awt/KeyModifier.hpp>
45 : #include <com/sun/star/lang/XSingleServiceFactory.hpp>
46 : #include <comphelper/configurationhelper.hxx>
47 : #include <comphelper/sequence.hxx>
48 : #include <officecfg/Setup.hxx>
49 : #include <unotools/configpaths.hxx>
50 : #include <svtools/acceleratorexecute.hxx>
51 :
52 : #define PRESET_DEFAULT "default"
53 : #define TARGET_CURRENT "current"
54 :
55 : namespace framework
56 : {
57 : const char CFG_ENTRY_SECONDARY[] = "SecondaryKeys";
58 : const char CFG_PROP_COMMAND[] = "Command";
59 :
60 0 : OUString lcl_getKeyString(salhelper::SingletonRef<framework::KeyMapping>& _rKeyMapping, const css::awt::KeyEvent& aKeyEvent)
61 : {
62 0 : const sal_Int32 nBeginIndex = 4; // "KEY_" is the prefix of a identifier...
63 0 : OUStringBuffer sKeyBuffer((_rKeyMapping->mapCodeToIdentifier(aKeyEvent.KeyCode)).copy(nBeginIndex));
64 :
65 0 : if ( (aKeyEvent.Modifiers & css::awt::KeyModifier::SHIFT) == css::awt::KeyModifier::SHIFT )
66 0 : sKeyBuffer.appendAscii("_SHIFT");
67 0 : if ( (aKeyEvent.Modifiers & css::awt::KeyModifier::MOD1 ) == css::awt::KeyModifier::MOD1 )
68 0 : sKeyBuffer.appendAscii("_MOD1");
69 0 : if ( (aKeyEvent.Modifiers & css::awt::KeyModifier::MOD2 ) == css::awt::KeyModifier::MOD2 )
70 0 : sKeyBuffer.appendAscii("_MOD2");
71 0 : if ( (aKeyEvent.Modifiers & css::awt::KeyModifier::MOD3 ) == css::awt::KeyModifier::MOD3 )
72 0 : sKeyBuffer.appendAscii("_MOD3");
73 :
74 0 : return sKeyBuffer.makeStringAndClear();
75 : }
76 :
77 588 : XMLBasedAcceleratorConfiguration::XMLBasedAcceleratorConfiguration(const css::uno::Reference< css::uno::XComponentContext >& xContext)
78 : : m_xContext (xContext )
79 : , m_aPresetHandler(xContext )
80 588 : , m_pWriteCache (0 )
81 : {
82 588 : }
83 :
84 585 : XMLBasedAcceleratorConfiguration::~XMLBasedAcceleratorConfiguration()
85 : {
86 : SAL_WARN_IF(m_pWriteCache, "fwk", "XMLBasedAcceleratorConfiguration::~XMLBasedAcceleratorConfiguration(): Changes not flushed. Ignore it ...");
87 585 : }
88 :
89 0 : css::uno::Sequence< css::awt::KeyEvent > SAL_CALL XMLBasedAcceleratorConfiguration::getAllKeyEvents()
90 : throw(css::uno::RuntimeException, std::exception)
91 : {
92 0 : SolarMutexGuard g;
93 0 : AcceleratorCache& rCache = impl_getCFG();
94 0 : AcceleratorCache::TKeyList lKeys = rCache.getAllKeys();
95 0 : return comphelper::containerToSequence(lKeys);
96 : }
97 :
98 2 : OUString SAL_CALL XMLBasedAcceleratorConfiguration::getCommandByKeyEvent(const css::awt::KeyEvent& aKeyEvent)
99 : throw(css::container::NoSuchElementException,
100 : css::uno::RuntimeException, std::exception )
101 : {
102 2 : SolarMutexGuard g;
103 2 : AcceleratorCache& rCache = impl_getCFG();
104 2 : if (!rCache.hasKey(aKeyEvent))
105 : throw css::container::NoSuchElementException(
106 : OUString(),
107 2 : static_cast< ::cppu::OWeakObject* >(this));
108 2 : return rCache.getCommandByKey(aKeyEvent);
109 : }
110 :
111 0 : void SAL_CALL XMLBasedAcceleratorConfiguration::setKeyEvent(const css::awt::KeyEvent& aKeyEvent,
112 : const OUString& sCommand )
113 : throw(css::lang::IllegalArgumentException,
114 : css::uno::RuntimeException, std::exception )
115 : {
116 0 : if (
117 0 : (aKeyEvent.KeyCode == 0) &&
118 0 : (aKeyEvent.KeyChar == 0) &&
119 0 : (aKeyEvent.KeyFunc == 0) &&
120 0 : (aKeyEvent.Modifiers == 0)
121 : )
122 : throw css::lang::IllegalArgumentException(
123 : OUString("Such key event seems not to be supported by any operating system."),
124 : static_cast< ::cppu::OWeakObject* >(this),
125 0 : 0);
126 :
127 0 : if (sCommand.isEmpty())
128 : throw css::lang::IllegalArgumentException(
129 : OUString("Empty command strings are not allowed here."),
130 : static_cast< ::cppu::OWeakObject* >(this),
131 0 : 1);
132 :
133 0 : SolarMutexGuard g;
134 0 : AcceleratorCache& rCache = impl_getCFG(true); // sal_True => force getting of a writeable cache!
135 0 : rCache.setKeyCommandPair(aKeyEvent, sCommand);
136 0 : }
137 :
138 0 : void SAL_CALL XMLBasedAcceleratorConfiguration::removeKeyEvent(const css::awt::KeyEvent& aKeyEvent)
139 : throw(css::container::NoSuchElementException,
140 : css::uno::RuntimeException, std::exception )
141 : {
142 0 : SolarMutexGuard g;
143 0 : AcceleratorCache& rCache = impl_getCFG(true); // true => force using of a writeable cache
144 0 : if (!rCache.hasKey(aKeyEvent))
145 : throw css::container::NoSuchElementException(
146 : OUString(),
147 0 : static_cast< ::cppu::OWeakObject* >(this));
148 0 : rCache.removeKey(aKeyEvent);
149 0 : }
150 :
151 0 : css::uno::Sequence< css::awt::KeyEvent > SAL_CALL XMLBasedAcceleratorConfiguration::getKeyEventsByCommand(const OUString& sCommand)
152 : throw(css::lang::IllegalArgumentException ,
153 : css::container::NoSuchElementException,
154 : css::uno::RuntimeException, std::exception )
155 : {
156 0 : if (sCommand.isEmpty())
157 : throw css::lang::IllegalArgumentException(
158 : OUString("Empty command strings are not allowed here."),
159 : static_cast< ::cppu::OWeakObject* >(this),
160 0 : 1);
161 :
162 0 : SolarMutexGuard g;
163 0 : AcceleratorCache& rCache = impl_getCFG();
164 0 : if (!rCache.hasCommand(sCommand))
165 : throw css::container::NoSuchElementException(
166 : OUString(),
167 0 : static_cast< ::cppu::OWeakObject* >(this));
168 :
169 0 : AcceleratorCache::TKeyList lKeys = rCache.getKeysByCommand(sCommand);
170 0 : return comphelper::containerToSequence(lKeys);
171 : }
172 :
173 18877 : css::uno::Sequence< css::uno::Any > SAL_CALL XMLBasedAcceleratorConfiguration::getPreferredKeyEventsForCommandList(const css::uno::Sequence< OUString >& lCommandList)
174 : throw (css::lang::IllegalArgumentException, css::container::NoSuchElementException,
175 : css::uno::RuntimeException, std::exception)
176 : {
177 18877 : SolarMutexGuard g;
178 :
179 18877 : sal_Int32 i = 0;
180 18877 : sal_Int32 c = lCommandList.getLength();
181 18877 : css::uno::Sequence< css::uno::Any > lPreferredOnes (c); // dont pack list!
182 18877 : AcceleratorCache& rCache = impl_getCFG();
183 :
184 38012 : for (i=0; i<c; ++i)
185 : {
186 19135 : const OUString& rCommand = lCommandList[i];
187 19135 : if (rCommand.isEmpty())
188 : throw css::lang::IllegalArgumentException(
189 : OUString("Empty command strings are not allowed here."),
190 : static_cast< ::cppu::OWeakObject* >(this),
191 0 : (sal_Int16)i);
192 :
193 19135 : if (!rCache.hasCommand(rCommand))
194 38270 : continue;
195 :
196 0 : AcceleratorCache::TKeyList lKeys = rCache.getKeysByCommand(rCommand);
197 0 : if ( lKeys.empty() )
198 0 : continue;
199 :
200 0 : css::uno::Any& rAny = lPreferredOnes[i];
201 0 : rAny <<= *(lKeys.begin());
202 0 : }
203 :
204 18877 : return lPreferredOnes;
205 : }
206 :
207 0 : void SAL_CALL XMLBasedAcceleratorConfiguration::removeCommandFromAllKeyEvents(const OUString& sCommand)
208 : throw(css::lang::IllegalArgumentException ,
209 : css::container::NoSuchElementException,
210 : css::uno::RuntimeException, std::exception )
211 : {
212 0 : if (sCommand.isEmpty())
213 : throw css::lang::IllegalArgumentException(
214 : OUString("Empty command strings are not allowed here."),
215 : static_cast< ::cppu::OWeakObject* >(this),
216 0 : 0);
217 :
218 0 : SolarMutexGuard g;
219 0 : AcceleratorCache& rCache = impl_getCFG(true); // sal_True => force getting of a writeable cache!
220 0 : if (!rCache.hasCommand(sCommand))
221 : throw css::container::NoSuchElementException(
222 : OUString("Command does not exists inside this container."),
223 0 : static_cast< ::cppu::OWeakObject* >(this));
224 0 : rCache.removeCommand(sCommand);
225 0 : }
226 :
227 592 : void SAL_CALL XMLBasedAcceleratorConfiguration::reload()
228 : throw(css::uno::Exception ,
229 : css::uno::RuntimeException, std::exception)
230 : {
231 592 : css::uno::Reference< css::io::XStream > xStream;
232 1184 : css::uno::Reference< css::io::XStream > xStreamNoLang;
233 : {
234 592 : SolarMutexGuard g;
235 592 : xStream = m_aPresetHandler.openTarget(TARGET_CURRENT, true); // sal_True => open or create!
236 : try
237 : {
238 592 : xStreamNoLang = m_aPresetHandler.openPreset(PRESET_DEFAULT, true);
239 : }
240 1184 : catch(const css::io::IOException&) {} // does not have to exist
241 : }
242 :
243 1184 : css::uno::Reference< css::io::XInputStream > xIn;
244 592 : if (xStream.is())
245 592 : xIn = xStream->getInputStream();
246 592 : if (!xIn.is())
247 : throw css::io::IOException(
248 : OUString("Could not open accelerator configuration for reading."),
249 0 : static_cast< ::cppu::OWeakObject* >(this));
250 :
251 : // impl_ts_load() does not clear the cache
252 : {
253 592 : SolarMutexGuard g;
254 592 : m_aReadCache = AcceleratorCache();
255 : }
256 :
257 592 : impl_ts_load(xIn);
258 :
259 : // Load also the general language independent default accelerators
260 : // (ignoring the already defined accelerators)
261 592 : if (xStreamNoLang.is())
262 : {
263 0 : xIn = xStreamNoLang->getInputStream();
264 0 : if (xIn.is())
265 0 : impl_ts_load(xIn);
266 592 : }
267 592 : }
268 :
269 0 : void SAL_CALL XMLBasedAcceleratorConfiguration::store()
270 : throw(css::uno::Exception ,
271 : css::uno::RuntimeException, std::exception)
272 : {
273 0 : css::uno::Reference< css::io::XStream > xStream;
274 : {
275 0 : SolarMutexGuard g;
276 0 : xStream = m_aPresetHandler.openTarget(TARGET_CURRENT, true); // sal_True => open or create!
277 : }
278 :
279 0 : css::uno::Reference< css::io::XOutputStream > xOut;
280 0 : if (xStream.is())
281 0 : xOut = xStream->getOutputStream();
282 :
283 0 : if (!xOut.is())
284 : throw css::io::IOException(
285 : OUString("Could not open accelerator configuration for saving."),
286 0 : static_cast< ::cppu::OWeakObject* >(this));
287 :
288 0 : impl_ts_save(xOut);
289 :
290 0 : xOut.clear();
291 0 : xStream.clear();
292 :
293 0 : m_aPresetHandler.commitUserChanges();
294 0 : }
295 :
296 0 : void SAL_CALL XMLBasedAcceleratorConfiguration::storeToStorage(const css::uno::Reference< css::embed::XStorage >& xStorage)
297 : throw(css::uno::Exception ,
298 : css::uno::RuntimeException, std::exception)
299 : {
300 : css::uno::Reference< css::io::XStream > xStream = StorageHolder::openSubStreamWithFallback(
301 : xStorage,
302 : TARGET_CURRENT,
303 : css::embed::ElementModes::READWRITE,
304 0 : false); // False => no fallback from read/write to readonly!
305 0 : css::uno::Reference< css::io::XOutputStream > xOut;
306 0 : if (xStream.is())
307 0 : xOut = xStream->getOutputStream();
308 :
309 0 : if (!xOut.is())
310 : throw css::io::IOException(
311 : OUString("Could not open accelerator configuration for saving."),
312 0 : static_cast< ::cppu::OWeakObject* >(this));
313 :
314 0 : impl_ts_save(xOut);
315 :
316 : // TODO inform listener about success, so it can flush the root and sub storage of this stream!
317 0 : }
318 :
319 0 : sal_Bool SAL_CALL XMLBasedAcceleratorConfiguration::isModified()
320 : throw(css::uno::RuntimeException, std::exception)
321 : {
322 0 : SolarMutexGuard g;
323 0 : return (m_pWriteCache != 0);
324 : }
325 :
326 0 : sal_Bool SAL_CALL XMLBasedAcceleratorConfiguration::isReadOnly()
327 : throw(css::uno::RuntimeException, std::exception)
328 : {
329 0 : css::uno::Reference< css::io::XStream > xStream;
330 : {
331 0 : SolarMutexGuard g;
332 0 : xStream = m_aPresetHandler.openTarget(TARGET_CURRENT, true); // sal_True => open or create!
333 : }
334 :
335 0 : css::uno::Reference< css::io::XOutputStream > xOut;
336 0 : if (xStream.is())
337 0 : xOut = xStream->getOutputStream();
338 0 : return !(xOut.is());
339 : }
340 :
341 0 : void SAL_CALL XMLBasedAcceleratorConfiguration::setStorage(const css::uno::Reference< css::embed::XStorage >& /*xStorage*/)
342 : throw(css::uno::RuntimeException, std::exception)
343 : {
344 : SAL_INFO("fwk", "XMLBasedAcceleratorConfiguration::setStorage(): implement this HACK .-)");
345 0 : }
346 :
347 0 : sal_Bool SAL_CALL XMLBasedAcceleratorConfiguration::hasStorage()
348 : throw(css::uno::RuntimeException, std::exception)
349 : {
350 : SAL_INFO("fwk", "XMLBasedAcceleratorConfiguration::hasStorage(): implement this HACK .-)");
351 0 : return sal_False;
352 : }
353 :
354 0 : void SAL_CALL XMLBasedAcceleratorConfiguration::addConfigurationListener(const css::uno::Reference< css::ui::XUIConfigurationListener >& /*xListener*/)
355 : throw(css::uno::RuntimeException, std::exception)
356 : {
357 : SAL_INFO("fwk", "XMLBasedAcceleratorConfiguration::addConfigurationListener(): implement me");
358 0 : }
359 :
360 0 : void SAL_CALL XMLBasedAcceleratorConfiguration::removeConfigurationListener(const css::uno::Reference< css::ui::XUIConfigurationListener >& /*xListener*/)
361 : throw(css::uno::RuntimeException, std::exception)
362 : {
363 : SAL_INFO("fwk", "XMLBasedAcceleratorConfiguration::removeConfigurationListener(): implement me");
364 0 : }
365 :
366 0 : void SAL_CALL XMLBasedAcceleratorConfiguration::reset()
367 : throw(css::uno::RuntimeException, std::exception)
368 : {
369 : {
370 0 : SolarMutexGuard g;
371 0 : m_aPresetHandler.copyPresetToTarget(PRESET_DEFAULT, TARGET_CURRENT);
372 : }
373 :
374 0 : reload();
375 0 : }
376 :
377 0 : void SAL_CALL XMLBasedAcceleratorConfiguration::addResetListener(const css::uno::Reference< css::form::XResetListener >& /*xListener*/)
378 : throw(css::uno::RuntimeException, std::exception)
379 : {
380 : SAL_INFO("fwk", "XMLBasedAcceleratorConfiguration::addResetListener(): implement me");
381 0 : }
382 :
383 0 : void SAL_CALL XMLBasedAcceleratorConfiguration::removeResetListener(const css::uno::Reference< css::form::XResetListener >& /*xListener*/)
384 : throw(css::uno::RuntimeException, std::exception)
385 : {
386 : SAL_INFO("fwk", "XMLBasedAcceleratorConfiguration::removeResetListener(): implement me");
387 0 : }
388 :
389 : // IStorageListener
390 0 : void XMLBasedAcceleratorConfiguration::changesOccurred(const OUString& /*sPath*/)
391 : {
392 0 : reload();
393 0 : }
394 :
395 592 : void XMLBasedAcceleratorConfiguration::impl_ts_load(const css::uno::Reference< css::io::XInputStream >& xStream)
396 : {
397 592 : css::uno::Reference< css::uno::XComponentContext > xContext;
398 : {
399 592 : SolarMutexGuard g;
400 592 : xContext = m_xContext;
401 592 : if (m_pWriteCache)
402 : {
403 : // be aware of reentrance problems - use temp variable for calling delete ... :-)
404 0 : AcceleratorCache* pTemp = m_pWriteCache;
405 0 : m_pWriteCache = 0;
406 0 : delete pTemp;
407 592 : }
408 : }
409 :
410 1184 : css::uno::Reference< css::io::XSeekable > xSeek(xStream, css::uno::UNO_QUERY);
411 592 : if (xSeek.is())
412 592 : xSeek->seek(0);
413 :
414 1184 : SolarMutexGuard g;
415 :
416 : // create the parser queue
417 : // Note: Use special filter object between parser and reader
418 : // to get filtered xml with right namespaces ...
419 : // Use further a temp cache for reading!
420 592 : AcceleratorConfigurationReader* pReader = new AcceleratorConfigurationReader(m_aReadCache);
421 1184 : css::uno::Reference< css::xml::sax::XDocumentHandler > xReader (static_cast< ::cppu::OWeakObject* >(pReader), css::uno::UNO_QUERY_THROW);
422 592 : SaxNamespaceFilter* pFilter = new SaxNamespaceFilter(xReader);
423 1184 : css::uno::Reference< css::xml::sax::XDocumentHandler > xFilter (static_cast< ::cppu::OWeakObject* >(pFilter), css::uno::UNO_QUERY_THROW);
424 :
425 : // connect parser, filter and stream
426 1184 : css::uno::Reference< css::xml::sax::XParser > xParser = css::xml::sax::Parser::create(xContext);
427 592 : xParser->setDocumentHandler(xFilter);
428 :
429 1184 : css::xml::sax::InputSource aSource;
430 592 : aSource.aInputStream = xStream;
431 :
432 : // TODO think about error handling
433 1184 : xParser->parseStream(aSource);
434 592 : }
435 :
436 0 : void XMLBasedAcceleratorConfiguration::impl_ts_save(const css::uno::Reference< css::io::XOutputStream >& xStream)
437 : {
438 : bool bChanged;
439 0 : AcceleratorCache aCache;
440 0 : css::uno::Reference< css::uno::XComponentContext > xContext;
441 : {
442 0 : SolarMutexGuard g;
443 0 : bChanged = (m_pWriteCache != 0);
444 0 : if (bChanged)
445 0 : aCache.takeOver(*m_pWriteCache);
446 : else
447 0 : aCache.takeOver(m_aReadCache);
448 0 : xContext = m_xContext;
449 : }
450 :
451 0 : css::uno::Reference< css::io::XTruncate > xClearable(xStream, css::uno::UNO_QUERY_THROW);
452 0 : xClearable->truncate();
453 :
454 : // TODO can be removed if seek(0) is done by truncate() automatically!
455 0 : css::uno::Reference< css::io::XSeekable > xSeek(xStream, css::uno::UNO_QUERY);
456 0 : if (xSeek.is())
457 0 : xSeek->seek(0);
458 :
459 : // combine writer/cache/stream etcpp.
460 0 : css::uno::Reference< css::xml::sax::XWriter > xWriter = css::xml::sax::Writer::create(xContext);
461 0 : xWriter->setOutputStream(xStream);
462 :
463 : // write into the stream
464 0 : css::uno::Reference< css::xml::sax::XDocumentHandler > xHandler(xWriter, css::uno::UNO_QUERY_THROW);
465 0 : AcceleratorConfigurationWriter aWriter(aCache, xHandler);
466 0 : aWriter.flush();
467 :
468 0 : SolarMutexGuard g;
469 : // take over all changes into the readonly cache ...
470 : // and forget the copy-on-write copied cache
471 0 : if (bChanged)
472 : {
473 0 : m_aReadCache.takeOver(*m_pWriteCache);
474 : // live with reentrance .-)
475 0 : AcceleratorCache* pTemp = m_pWriteCache;
476 0 : m_pWriteCache = 0;
477 0 : delete pTemp;
478 0 : }
479 0 : }
480 :
481 18879 : AcceleratorCache& XMLBasedAcceleratorConfiguration::impl_getCFG(bool bWriteAccessRequested)
482 : {
483 18879 : SolarMutexGuard g;
484 :
485 : //create copy of our readonly-cache, if write access is forced ... but
486 : //not still possible!
487 18879 : if (
488 0 : (bWriteAccessRequested) &&
489 0 : (!m_pWriteCache )
490 : )
491 : {
492 0 : m_pWriteCache = new AcceleratorCache(m_aReadCache);
493 : }
494 :
495 : // in case, we have a writeable cache, we use it for reading too!
496 : // Otherwise the API user can't find its own changes ...
497 18879 : if (m_pWriteCache)
498 0 : return *m_pWriteCache;
499 : else
500 18879 : return m_aReadCache;
501 : }
502 :
503 592 : OUString XMLBasedAcceleratorConfiguration::impl_ts_getLocale() const
504 : {
505 592 : OUString sISOLocale = officecfg::Setup::L10N::ooLocale::get();
506 :
507 592 : if (sISOLocale.isEmpty())
508 1 : return OUString("en-US");
509 591 : return sISOLocale;
510 : }
511 :
512 : /*******************************************************************************
513 : *
514 : * XCU based accelerator configuration
515 : *
516 : *******************************************************************************/
517 :
518 1364 : XCUBasedAcceleratorConfiguration::XCUBasedAcceleratorConfiguration(const css::uno::Reference< css::uno::XComponentContext >& xContext)
519 : : m_xContext (xContext )
520 : , m_pPrimaryWriteCache(0 )
521 1364 : , m_pSecondaryWriteCache(0 )
522 : {
523 1364 : const OUString CFG_ENTRY_ACCELERATORS("org.openoffice.Office.Accelerators");
524 2728 : m_xCfg = css::uno::Reference< css::container::XNameAccess > (
525 : ::comphelper::ConfigurationHelper::openConfig( m_xContext, CFG_ENTRY_ACCELERATORS, ::comphelper::ConfigurationHelper::E_ALL_LOCALES ),
526 2728 : css::uno::UNO_QUERY );
527 1364 : }
528 :
529 1359 : XCUBasedAcceleratorConfiguration::~XCUBasedAcceleratorConfiguration()
530 : {
531 1359 : }
532 :
533 0 : css::uno::Sequence< css::awt::KeyEvent > SAL_CALL XCUBasedAcceleratorConfiguration::getAllKeyEvents()
534 : throw(css::uno::RuntimeException, std::exception)
535 : {
536 0 : SolarMutexGuard g;
537 :
538 0 : AcceleratorCache::TKeyList lKeys = impl_getCFG(true).getAllKeys(); //get keys from PrimaryKeys set
539 :
540 0 : AcceleratorCache::TKeyList lSecondaryKeys = impl_getCFG(false).getAllKeys(); //get keys from SecondaryKeys set
541 0 : lKeys.reserve(lKeys.size()+lSecondaryKeys.size());
542 0 : AcceleratorCache::TKeyList::const_iterator pIt;
543 0 : AcceleratorCache::TKeyList::const_iterator pEnd = lSecondaryKeys.end();
544 0 : for ( pIt = lSecondaryKeys.begin(); pIt != pEnd; ++pIt )
545 0 : lKeys.push_back(*pIt);
546 :
547 0 : return comphelper::containerToSequence(lKeys);
548 : }
549 :
550 4 : OUString SAL_CALL XCUBasedAcceleratorConfiguration::getCommandByKeyEvent(const css::awt::KeyEvent& aKeyEvent)
551 : throw(css::container::NoSuchElementException,
552 : css::uno::RuntimeException, std::exception )
553 : {
554 4 : SolarMutexGuard g;
555 :
556 4 : AcceleratorCache& rPrimaryCache = impl_getCFG(true );
557 4 : AcceleratorCache& rSecondaryCache = impl_getCFG(false);
558 :
559 4 : if (!rPrimaryCache.hasKey(aKeyEvent) && !rSecondaryCache.hasKey(aKeyEvent))
560 : throw css::container::NoSuchElementException(
561 : OUString(),
562 4 : static_cast< ::cppu::OWeakObject* >(this));
563 :
564 0 : if (rPrimaryCache.hasKey(aKeyEvent))
565 0 : return rPrimaryCache.getCommandByKey(aKeyEvent);
566 : else
567 4 : return rSecondaryCache.getCommandByKey(aKeyEvent);
568 : }
569 :
570 0 : void SAL_CALL XCUBasedAcceleratorConfiguration::setKeyEvent(const css::awt::KeyEvent& aKeyEvent,
571 : const OUString& sCommand )
572 : throw (css::lang::IllegalArgumentException,
573 : css::container::NoSuchElementException,
574 : css::uno::RuntimeException, std::exception)
575 : {
576 : SAL_INFO( "fwk.accelerators", "XCUBasedAcceleratorConfiguration::setKeyEvent" );
577 :
578 0 : if (
579 0 : (aKeyEvent.KeyCode == 0) &&
580 0 : (aKeyEvent.KeyChar == 0) &&
581 0 : (aKeyEvent.KeyFunc == 0) &&
582 0 : (aKeyEvent.Modifiers == 0)
583 : )
584 : throw css::lang::IllegalArgumentException(
585 : OUString("Such key event seems not to be supported by any operating system."),
586 : static_cast< ::cppu::OWeakObject* >(this),
587 0 : 0);
588 :
589 0 : if (sCommand.isEmpty())
590 : throw css::lang::IllegalArgumentException(
591 : OUString("Empty command strings are not allowed here."),
592 : static_cast< ::cppu::OWeakObject* >(this),
593 0 : 1);
594 :
595 0 : SolarMutexGuard g;
596 :
597 0 : AcceleratorCache& rPrimaryCache = impl_getCFG(true, true ); // sal_True => force getting of a writeable cache!
598 0 : AcceleratorCache& rSecondaryCache = impl_getCFG(false, true); // sal_True => force getting of a writeable cache!
599 :
600 0 : if ( rPrimaryCache.hasKey(aKeyEvent) )
601 : {
602 0 : OUString sOriginalCommand = rPrimaryCache.getCommandByKey(aKeyEvent);
603 0 : if ( sCommand != sOriginalCommand )
604 : {
605 0 : if (rSecondaryCache.hasCommand(sOriginalCommand))
606 : {
607 0 : AcceleratorCache::TKeyList lSecondaryKeys = rSecondaryCache.getKeysByCommand(sOriginalCommand);
608 0 : rSecondaryCache.removeKey(lSecondaryKeys[0]);
609 0 : rPrimaryCache.setKeyCommandPair(lSecondaryKeys[0], sOriginalCommand);
610 : }
611 :
612 0 : if (rPrimaryCache.hasCommand(sCommand))
613 : {
614 0 : AcceleratorCache::TKeyList lPrimaryKeys = rPrimaryCache.getKeysByCommand(sCommand);
615 0 : rPrimaryCache.removeKey(lPrimaryKeys[0]);
616 0 : rSecondaryCache.setKeyCommandPair(lPrimaryKeys[0], sCommand);
617 : }
618 :
619 0 : rPrimaryCache.setKeyCommandPair(aKeyEvent, sCommand);
620 0 : }
621 : }
622 :
623 0 : else if ( rSecondaryCache.hasKey(aKeyEvent) )
624 : {
625 0 : OUString sOriginalCommand = rSecondaryCache.getCommandByKey(aKeyEvent);
626 0 : if (sCommand != sOriginalCommand)
627 : {
628 0 : if (rPrimaryCache.hasCommand(sCommand))
629 : {
630 0 : AcceleratorCache::TKeyList lPrimaryKeys = rPrimaryCache.getKeysByCommand(sCommand);
631 0 : rPrimaryCache.removeKey(lPrimaryKeys[0]);
632 0 : rSecondaryCache.setKeyCommandPair(lPrimaryKeys[0], sCommand);
633 : }
634 :
635 0 : rSecondaryCache.removeKey(aKeyEvent);
636 0 : rPrimaryCache.setKeyCommandPair(aKeyEvent, sCommand);
637 0 : }
638 : }
639 :
640 : else
641 : {
642 0 : if (rPrimaryCache.hasCommand(sCommand))
643 : {
644 0 : AcceleratorCache::TKeyList lPrimaryKeys = rPrimaryCache.getKeysByCommand(sCommand);
645 0 : rPrimaryCache.removeKey(lPrimaryKeys[0]);
646 0 : rSecondaryCache.setKeyCommandPair(lPrimaryKeys[0], sCommand);
647 : }
648 :
649 0 : rPrimaryCache.setKeyCommandPair(aKeyEvent, sCommand);
650 0 : }
651 0 : }
652 :
653 0 : void SAL_CALL XCUBasedAcceleratorConfiguration::removeKeyEvent(const css::awt::KeyEvent& aKeyEvent)
654 : throw(css::container::NoSuchElementException,
655 : css::uno::RuntimeException, std::exception )
656 : {
657 0 : SolarMutexGuard g;
658 :
659 0 : AcceleratorCache& rPrimaryCache = impl_getCFG(true, true );
660 0 : AcceleratorCache& rSecondaryCache = impl_getCFG(false, true);
661 :
662 0 : if (!rPrimaryCache.hasKey(aKeyEvent) && !rSecondaryCache.hasKey(aKeyEvent))
663 : throw css::container::NoSuchElementException(
664 : OUString(),
665 0 : static_cast< ::cppu::OWeakObject* >(this));
666 :
667 0 : if (rPrimaryCache.hasKey(aKeyEvent))
668 : {
669 0 : OUString sDelCommand = rPrimaryCache.getCommandByKey(aKeyEvent);
670 0 : if (!sDelCommand.isEmpty())
671 : {
672 0 : OUString sOriginalCommand = rPrimaryCache.getCommandByKey(aKeyEvent);
673 0 : if (rSecondaryCache.hasCommand(sOriginalCommand))
674 : {
675 0 : AcceleratorCache::TKeyList lSecondaryKeys = rSecondaryCache.getKeysByCommand(sOriginalCommand);
676 0 : rSecondaryCache.removeKey(lSecondaryKeys[0]);
677 0 : rPrimaryCache.setKeyCommandPair(lSecondaryKeys[0], sOriginalCommand);
678 : }
679 :
680 0 : rPrimaryCache.removeKey(aKeyEvent);
681 0 : }
682 :
683 : }
684 : else
685 : {
686 0 : OUString sDelCommand = rSecondaryCache.getCommandByKey(aKeyEvent);
687 0 : if (!sDelCommand.isEmpty())
688 0 : rSecondaryCache.removeKey(aKeyEvent);
689 0 : }
690 0 : }
691 :
692 0 : css::uno::Sequence< css::awt::KeyEvent > SAL_CALL XCUBasedAcceleratorConfiguration::getKeyEventsByCommand(const OUString& sCommand)
693 : throw(css::lang::IllegalArgumentException ,
694 : css::container::NoSuchElementException,
695 : css::uno::RuntimeException, std::exception )
696 : {
697 0 : if (sCommand.isEmpty())
698 : throw css::lang::IllegalArgumentException(
699 : OUString("Empty command strings are not allowed here."),
700 : static_cast< ::cppu::OWeakObject* >(this),
701 0 : 1);
702 :
703 0 : SolarMutexGuard g;
704 :
705 0 : AcceleratorCache& rPrimaryCache = impl_getCFG(true );
706 0 : AcceleratorCache& rSecondaryCache = impl_getCFG(false);
707 :
708 0 : if (!rPrimaryCache.hasCommand(sCommand) && !rSecondaryCache.hasCommand(sCommand))
709 : throw css::container::NoSuchElementException(
710 : OUString(),
711 0 : static_cast< ::cppu::OWeakObject* >(this));
712 :
713 0 : AcceleratorCache::TKeyList lKeys = rPrimaryCache.getKeysByCommand(sCommand);
714 :
715 0 : AcceleratorCache::TKeyList lSecondaryKeys = rSecondaryCache.getKeysByCommand(sCommand);
716 0 : AcceleratorCache::TKeyList::const_iterator pIt;
717 0 : for (pIt = lSecondaryKeys.begin(); pIt != lSecondaryKeys.end(); ++pIt)
718 0 : lKeys.push_back(*pIt);
719 :
720 0 : return comphelper::containerToSequence(lKeys);
721 : }
722 :
723 41259 : AcceleratorCache::TKeyList::const_iterator lcl_getPreferredKey(const AcceleratorCache::TKeyList& lKeys)
724 : {
725 41259 : AcceleratorCache::TKeyList::const_iterator pIt;
726 252963 : for ( pIt = lKeys.begin ();
727 168642 : pIt != lKeys.end ();
728 : ++pIt )
729 : {
730 43067 : const css::awt::KeyEvent& rAWTKey = *pIt;
731 43067 : const vcl::KeyCode aVCLKey = ::svt::AcceleratorExecute::st_AWTKey2VCLKey(rAWTKey);
732 43067 : const OUString sName = aVCLKey.GetName();
733 :
734 43067 : if (!sName.isEmpty())
735 5 : return pIt;
736 43062 : }
737 :
738 41254 : return lKeys.end();
739 : }
740 :
741 196971 : css::uno::Sequence< css::uno::Any > SAL_CALL XCUBasedAcceleratorConfiguration::getPreferredKeyEventsForCommandList(const css::uno::Sequence< OUString >& lCommandList)
742 : throw(css::lang::IllegalArgumentException, css::container::NoSuchElementException,
743 : css::uno::RuntimeException, std::exception)
744 : {
745 196971 : SolarMutexGuard g;
746 :
747 196971 : sal_Int32 i = 0;
748 196971 : sal_Int32 c = lCommandList.getLength();
749 196971 : css::uno::Sequence< css::uno::Any > lPreferredOnes (c); // dont pack list!
750 196971 : AcceleratorCache& rCache = impl_getCFG(true);
751 :
752 394458 : for (i=0; i<c; ++i)
753 : {
754 197487 : const OUString& rCommand = lCommandList[i];
755 197487 : if (rCommand.isEmpty())
756 : throw css::lang::IllegalArgumentException(
757 : OUString("Empty command strings are not allowed here."),
758 : static_cast< ::cppu::OWeakObject* >(this),
759 0 : (sal_Int16)i);
760 :
761 197487 : if (!rCache.hasCommand(rCommand))
762 312456 : continue;
763 :
764 41259 : AcceleratorCache::TKeyList lKeys = rCache.getKeysByCommand(rCommand);
765 41259 : if ( lKeys.empty() )
766 0 : continue;
767 :
768 41259 : AcceleratorCache::TKeyList::const_iterator pPreferredKey = lcl_getPreferredKey(lKeys);
769 41259 : if (pPreferredKey != lKeys.end ())
770 : {
771 5 : css::uno::Any& rAny = lPreferredOnes[i];
772 5 : rAny <<= *(pPreferredKey);
773 : }
774 41259 : }
775 :
776 196971 : return lPreferredOnes;
777 : }
778 :
779 0 : void SAL_CALL XCUBasedAcceleratorConfiguration::removeCommandFromAllKeyEvents(const OUString& sCommand)
780 : throw(css::lang::IllegalArgumentException ,
781 : css::container::NoSuchElementException,
782 : css::uno::RuntimeException, std::exception )
783 : {
784 0 : if (sCommand.isEmpty())
785 : throw css::lang::IllegalArgumentException(
786 : OUString("Empty command strings are not allowed here."),
787 : static_cast< ::cppu::OWeakObject* >(this),
788 0 : 0);
789 :
790 0 : SolarMutexGuard g;
791 :
792 0 : AcceleratorCache& rPrimaryCache = impl_getCFG(true, true );
793 0 : AcceleratorCache& rSecondaryCache = impl_getCFG(false, true);
794 :
795 0 : if (!rPrimaryCache.hasCommand(sCommand) && !rSecondaryCache.hasCommand(sCommand))
796 : throw css::container::NoSuchElementException(
797 : OUString("Command does not exists inside this container."),
798 0 : static_cast< ::cppu::OWeakObject* >(this));
799 :
800 0 : if (rPrimaryCache.hasCommand(sCommand))
801 0 : rPrimaryCache.removeCommand(sCommand);
802 0 : if (rSecondaryCache.hasCommand(sCommand))
803 0 : rSecondaryCache.removeCommand(sCommand);
804 0 : }
805 :
806 1364 : void SAL_CALL XCUBasedAcceleratorConfiguration::reload()
807 : throw(css::uno::Exception ,
808 : css::uno::RuntimeException, std::exception)
809 : {
810 : SAL_INFO( "fwk.accelerators", "XCUBasedAcceleratorConfiguration::reload()" );
811 :
812 1364 : SolarMutexGuard g;
813 :
814 : bool bPreferred;
815 2728 : css::uno::Reference< css::container::XNameAccess > xAccess;
816 :
817 1364 : bPreferred = true;
818 1364 : m_aPrimaryReadCache = AcceleratorCache();
819 1364 : if (m_pPrimaryWriteCache)
820 : {
821 : // be aware of reentrance problems - use temp variable for calling delete ... :-)
822 0 : AcceleratorCache* pTemp = m_pPrimaryWriteCache;
823 0 : m_pPrimaryWriteCache = 0;
824 0 : delete pTemp;
825 : }
826 1364 : m_xCfg->getByName(CFG_ENTRY_PRIMARY) >>= xAccess;
827 1364 : impl_ts_load(bPreferred, xAccess); // load the preferred keys
828 :
829 1364 : bPreferred = false;
830 1364 : m_aSecondaryReadCache = AcceleratorCache();
831 1364 : if (m_pSecondaryWriteCache)
832 : {
833 : // be aware of reentrance problems - use temp variable for calling delete ... :-)
834 0 : AcceleratorCache* pTemp = m_pSecondaryWriteCache;
835 0 : m_pSecondaryWriteCache = 0;
836 0 : delete pTemp;
837 : }
838 1364 : m_xCfg->getByName(CFG_ENTRY_SECONDARY) >>= xAccess;
839 2728 : impl_ts_load(bPreferred, xAccess); // load the secondary keys
840 1356 : }
841 :
842 0 : void SAL_CALL XCUBasedAcceleratorConfiguration::store()
843 : throw(css::uno::Exception ,
844 : css::uno::RuntimeException, std::exception)
845 : {
846 : SAL_INFO( "fwk.accelerators", "XCUBasedAcceleratorConfiguration::store()" );
847 :
848 0 : SolarMutexGuard g;
849 :
850 : bool bPreferred;
851 0 : css::uno::Reference< css::container::XNameAccess > xAccess;
852 :
853 0 : bPreferred = true;
854 : // on-demand creation of the primary write cache
855 0 : impl_getCFG(bPreferred, true);
856 0 : m_xCfg->getByName(CFG_ENTRY_PRIMARY) >>= xAccess;
857 0 : impl_ts_save(bPreferred, xAccess);
858 :
859 0 : bPreferred = false;
860 : // on-demand creation of the secondary write cache
861 0 : impl_getCFG(bPreferred, true);
862 0 : m_xCfg->getByName(CFG_ENTRY_SECONDARY) >>= xAccess;
863 0 : impl_ts_save(bPreferred, xAccess);
864 0 : }
865 :
866 0 : void SAL_CALL XCUBasedAcceleratorConfiguration::storeToStorage(const css::uno::Reference< css::embed::XStorage >& xStorage)
867 : throw(css::uno::Exception ,
868 : css::uno::RuntimeException, std::exception)
869 : {
870 : // use m_aCache + old AcceleratorXMLWriter to store data directly on storage given as parameter ...
871 0 : if (!xStorage.is())
872 0 : return;
873 :
874 0 : long nOpenModes = css::embed::ElementModes::READWRITE;
875 0 : css::uno::Reference< css::embed::XStorage > xAcceleratorTypeStorage = xStorage->openStorageElement(OUString("accelerator"), nOpenModes);
876 0 : if (!xAcceleratorTypeStorage.is())
877 0 : return;
878 :
879 0 : css::uno::Reference< css::io::XStream > xStream = xAcceleratorTypeStorage->openStreamElement(OUString("current"), nOpenModes);
880 0 : css::uno::Reference< css::io::XOutputStream > xOut;
881 0 : if (xStream.is())
882 0 : xOut = xStream->getOutputStream();
883 0 : if (!xOut.is())
884 : throw css::io::IOException(
885 : OUString("Could not open accelerator configuration for saving."),
886 0 : static_cast< ::cppu::OWeakObject* >(this));
887 :
888 : // the original m_aCache has been split into primay cache and secondary cache...
889 : // we should merge them before storing to storage
890 0 : AcceleratorCache aCache;
891 : {
892 0 : SolarMutexGuard g;
893 :
894 0 : if (m_pPrimaryWriteCache != 0)
895 0 : aCache.takeOver(*m_pPrimaryWriteCache);
896 : else
897 0 : aCache.takeOver(m_aPrimaryReadCache);
898 :
899 0 : AcceleratorCache::TKeyList lKeys;
900 0 : AcceleratorCache::TKeyList::const_iterator pIt;
901 0 : if (m_pSecondaryWriteCache!=0)
902 : {
903 0 : lKeys = m_pSecondaryWriteCache->getAllKeys();
904 0 : for ( pIt=lKeys.begin(); pIt!=lKeys.end(); ++pIt )
905 0 : aCache.setKeyCommandPair(*pIt, m_pSecondaryWriteCache->getCommandByKey(*pIt));
906 : }
907 : else
908 : {
909 0 : lKeys = m_aSecondaryReadCache.getAllKeys();
910 0 : for ( pIt=lKeys.begin(); pIt!=lKeys.end(); ++pIt )
911 0 : aCache.setKeyCommandPair(*pIt, m_aSecondaryReadCache.getCommandByKey(*pIt));
912 0 : }
913 : }
914 :
915 0 : css::uno::Reference< css::io::XTruncate > xClearable(xOut, css::uno::UNO_QUERY_THROW);
916 0 : xClearable->truncate();
917 0 : css::uno::Reference< css::io::XSeekable > xSeek(xOut, css::uno::UNO_QUERY);
918 0 : if (xSeek.is())
919 0 : xSeek->seek(0);
920 :
921 0 : css::uno::Reference< css::xml::sax::XWriter > xWriter = css::xml::sax::Writer::create(m_xContext);
922 0 : xWriter->setOutputStream(xOut);
923 :
924 : // write into the stream
925 0 : css::uno::Reference< css::xml::sax::XDocumentHandler > xHandler(xWriter, css::uno::UNO_QUERY_THROW);
926 0 : AcceleratorConfigurationWriter aWriter(aCache, xHandler);
927 0 : aWriter.flush();
928 : }
929 :
930 0 : sal_Bool SAL_CALL XCUBasedAcceleratorConfiguration::isModified()
931 : throw(css::uno::RuntimeException, std::exception)
932 : {
933 0 : return sal_False;
934 : }
935 :
936 0 : sal_Bool SAL_CALL XCUBasedAcceleratorConfiguration::isReadOnly()
937 : throw(css::uno::RuntimeException, std::exception)
938 : {
939 0 : return sal_False;
940 : }
941 :
942 0 : void SAL_CALL XCUBasedAcceleratorConfiguration::setStorage(const css::uno::Reference< css::embed::XStorage >& /*xStorage*/)
943 : throw(css::uno::RuntimeException, std::exception)
944 : {
945 : SAL_INFO("fwk", "XCUBasedAcceleratorConfiguration::setStorage(): implement this HACK .-)");
946 0 : }
947 :
948 0 : sal_Bool SAL_CALL XCUBasedAcceleratorConfiguration::hasStorage()
949 : throw(css::uno::RuntimeException, std::exception)
950 : {
951 : SAL_INFO("fwk", "XCUBasedAcceleratorConfiguration::hasStorage(): implement this HACK .-)");
952 0 : return sal_False;
953 : }
954 :
955 0 : void SAL_CALL XCUBasedAcceleratorConfiguration::addConfigurationListener(const css::uno::Reference< css::ui::XUIConfigurationListener >& /*xListener*/)
956 : throw(css::uno::RuntimeException, std::exception)
957 : {
958 : SAL_INFO("fwk", "XCUBasedAcceleratorConfiguration::addConfigurationListener(): implement me");
959 0 : }
960 :
961 0 : void SAL_CALL XCUBasedAcceleratorConfiguration::removeConfigurationListener(const css::uno::Reference< css::ui::XUIConfigurationListener >& /*xListener*/)
962 : throw(css::uno::RuntimeException, std::exception)
963 : {
964 : SAL_INFO("fwk", "XCUBasedAcceleratorConfiguration::removeConfigurationListener(): implement me");
965 0 : }
966 :
967 0 : void SAL_CALL XCUBasedAcceleratorConfiguration::reset()
968 : throw(css::uno::RuntimeException, std::exception)
969 : {
970 0 : css::uno::Reference< css::container::XNamed > xNamed(m_xCfg, css::uno::UNO_QUERY);
971 0 : OUString sConfig = xNamed->getName();
972 0 : if ( sConfig == "Global" )
973 : {
974 0 : m_xCfg = css::uno::Reference< css::container::XNameAccess > (
975 : ::comphelper::ConfigurationHelper::openConfig( m_xContext, CFG_ENTRY_GLOBAL, ::comphelper::ConfigurationHelper::E_ALL_LOCALES ),
976 0 : css::uno::UNO_QUERY );
977 0 : XCUBasedAcceleratorConfiguration::reload();
978 : }
979 0 : else if ( sConfig == "Modules" )
980 : {
981 0 : m_xCfg = css::uno::Reference< css::container::XNameAccess > (
982 : ::comphelper::ConfigurationHelper::openConfig( m_xContext, CFG_ENTRY_MODULES, ::comphelper::ConfigurationHelper::E_ALL_LOCALES ),
983 0 : css::uno::UNO_QUERY );
984 0 : XCUBasedAcceleratorConfiguration::reload();
985 0 : }
986 0 : }
987 :
988 0 : void SAL_CALL XCUBasedAcceleratorConfiguration::addResetListener(const css::uno::Reference< css::form::XResetListener >& /*xListener*/)
989 : throw(css::uno::RuntimeException, std::exception)
990 : {
991 : SAL_INFO("fwk", "XCUBasedAcceleratorConfiguration::addResetListener(): implement me");
992 0 : }
993 :
994 0 : void SAL_CALL XCUBasedAcceleratorConfiguration::removeResetListener(const css::uno::Reference< css::form::XResetListener >& /*xListener*/)
995 : throw(css::uno::RuntimeException, std::exception)
996 : {
997 : SAL_INFO("fwk", "XCUBasedAcceleratorConfiguration::removeResetListener(): implement me");
998 0 : }
999 :
1000 0 : void SAL_CALL XCUBasedAcceleratorConfiguration::changesOccurred(const css::util::ChangesEvent& aEvent)
1001 : throw(css::uno::RuntimeException, std::exception)
1002 : {
1003 : SAL_INFO( "fwk.accelerators", "XCUBasedAcceleratorConfiguration::changesOccurred()" );
1004 :
1005 0 : css::uno::Reference< css::container::XHierarchicalNameAccess > xHAccess;
1006 0 : aEvent.Base >>= xHAccess;
1007 0 : if (! xHAccess.is ())
1008 0 : return;
1009 :
1010 0 : css::util::ChangesEvent aReceivedEvents( aEvent );
1011 0 : const sal_Int32 c = aReceivedEvents.Changes.getLength();
1012 0 : sal_Int32 i = 0;
1013 0 : for (i=0; i<c; ++i)
1014 : {
1015 0 : const css::util::ElementChange& aChange = aReceivedEvents.Changes[i];
1016 :
1017 : // Only path of form "PrimaryKeys/Modules/Module['<module_name>']/Key['<command_url>']/Command[<locale>]" will
1018 : // be interesting for use. Sometimes short path values are given also by the broadcaster ... but they must be ignored :-)
1019 : // So we try to split the path into 3 parts (module isn't important here, because we already know it ... because
1020 : // these instance is bound to a specific module configuration ... or it''s the global configuration where no module is given at all.
1021 :
1022 0 : OUString sOrgPath;
1023 0 : OUString sPath;
1024 0 : OUString sKey;
1025 :
1026 0 : aChange.Accessor >>= sOrgPath;
1027 0 : sPath = sOrgPath;
1028 0 : OUString sPrimarySecondary = ::utl::extractFirstFromConfigurationPath(sPath, &sPath);
1029 0 : OUString sGlobalModules = ::utl::extractFirstFromConfigurationPath(sPath, &sPath);
1030 :
1031 0 : if ( sGlobalModules == CFG_ENTRY_GLOBAL )
1032 : {
1033 0 : OUString sModule;
1034 0 : sKey = ::utl::extractFirstFromConfigurationPath(sPath, &sPath);
1035 0 : if ( !sKey.isEmpty() && !sPath.isEmpty() )
1036 0 : reloadChanged(sPrimarySecondary, sGlobalModules, sModule, sKey);
1037 : }
1038 0 : else if ( sGlobalModules == CFG_ENTRY_MODULES )
1039 : {
1040 0 : OUString sModule = ::utl::extractFirstFromConfigurationPath(sPath, &sPath);
1041 0 : sKey = ::utl::extractFirstFromConfigurationPath(sPath, &sPath);
1042 :
1043 0 : if ( !sKey.isEmpty() && !sPath.isEmpty() )
1044 : {
1045 0 : reloadChanged(sPrimarySecondary, sGlobalModules, sModule, sKey);
1046 0 : }
1047 : }
1048 0 : }
1049 : }
1050 :
1051 0 : void SAL_CALL XCUBasedAcceleratorConfiguration::disposing(const css::lang::EventObject& /*aSource*/)
1052 : throw(css::uno::RuntimeException, std::exception)
1053 : {
1054 0 : }
1055 :
1056 0 : void SAL_CALL XCUBasedAcceleratorConfiguration::dispose()
1057 : throw(css::uno::RuntimeException, std::exception)
1058 : {
1059 : // nop
1060 0 : }
1061 :
1062 0 : void SAL_CALL XCUBasedAcceleratorConfiguration::addEventListener( const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XEventListener >& /*xListener*/ )
1063 : throw(css::uno::RuntimeException, std::exception)
1064 : {
1065 : // nop
1066 0 : }
1067 :
1068 0 : void SAL_CALL XCUBasedAcceleratorConfiguration::removeEventListener( const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XEventListener >& /*xListener*/ )
1069 : throw(css::uno::RuntimeException, std::exception)
1070 : {
1071 : // nop
1072 0 : }
1073 :
1074 2728 : void XCUBasedAcceleratorConfiguration::impl_ts_load( bool bPreferred, const css::uno::Reference< css::container::XNameAccess >& xCfg )
1075 : {
1076 2728 : AcceleratorCache aReadCache = AcceleratorCache();
1077 5456 : css::uno::Reference< css::container::XNameAccess > xAccess;
1078 2728 : if ( m_sGlobalOrModules == "Global" )
1079 2594 : xCfg->getByName(CFG_ENTRY_GLOBAL) >>= xAccess;
1080 134 : else if ( m_sGlobalOrModules == "Modules" )
1081 : {
1082 134 : css::uno::Reference< css::container::XNameAccess > xModules;
1083 134 : xCfg->getByName(CFG_ENTRY_MODULES) >>= xModules;
1084 134 : xModules->getByName(m_sModuleCFG) >>= xAccess;
1085 : }
1086 :
1087 5440 : const OUString sIsoLang = impl_ts_getLocale();
1088 5440 : const OUString sDefaultLocale("en-US");
1089 :
1090 5440 : css::uno::Reference< css::container::XNameAccess > xKey;
1091 5440 : css::uno::Reference< css::container::XNameAccess > xCommand;
1092 2720 : if (xAccess.is())
1093 : {
1094 2720 : css::uno::Sequence< OUString > lKeys = xAccess->getElementNames();
1095 2720 : sal_Int32 nKeys = lKeys.getLength();
1096 65153 : for ( sal_Int32 i=0; i<nKeys; ++i )
1097 : {
1098 62433 : OUString sKey = lKeys[i];
1099 62433 : xAccess->getByName(sKey) >>= xKey;
1100 62433 : xKey->getByName(CFG_PROP_COMMAND) >>= xCommand;
1101 :
1102 116291 : css::uno::Sequence< OUString > lLocales = xCommand->getElementNames();
1103 62433 : sal_Int32 nLocales = lLocales.getLength();
1104 116291 : ::std::vector< OUString > aLocales;
1105 116451 : for ( sal_Int32 j=0; j<nLocales; ++j )
1106 54018 : aLocales.push_back(lLocales[j]);
1107 :
1108 62433 : ::std::vector< OUString >::const_iterator pFound;
1109 62593 : for ( pFound = aLocales.begin(); pFound != aLocales.end(); ++pFound )
1110 : {
1111 54018 : if ( *pFound == sIsoLang )
1112 53858 : break;
1113 : }
1114 :
1115 62433 : if ( pFound == aLocales.end() )
1116 : {
1117 8735 : for ( pFound = aLocales.begin(); pFound != aLocales.end(); ++pFound )
1118 : {
1119 160 : if ( *pFound == sDefaultLocale )
1120 0 : break;
1121 : }
1122 :
1123 8575 : if ( pFound == aLocales.end() )
1124 8575 : continue;
1125 : }
1126 :
1127 107716 : OUString sLocale = *pFound;
1128 107716 : OUString sCommand;
1129 53858 : xCommand->getByName(sLocale) >>= sCommand;
1130 53858 : if (sCommand.isEmpty())
1131 0 : continue;
1132 :
1133 107716 : css::awt::KeyEvent aKeyEvent;
1134 :
1135 53858 : sal_Int32 nIndex = 0;
1136 107716 : OUString sKeyCommand = sKey.getToken(0, '_', nIndex);
1137 107716 : OUString sPrefix("KEY_");
1138 53858 : aKeyEvent.KeyCode = m_rKeyMapping->mapIdentifierToCode(sPrefix + sKeyCommand);
1139 :
1140 107716 : css::uno::Sequence< OUString > sToken(4);
1141 53858 : const sal_Int32 nToken = 4;
1142 53858 : bool bValid = true;
1143 : sal_Int32 k;
1144 112354 : for (k=0; k<nToken; ++k)
1145 : {
1146 112354 : if (nIndex < 0)
1147 53858 : break;
1148 :
1149 58496 : sToken[k] = sKey.getToken(0, '_', nIndex);
1150 58496 : if (sToken[k].isEmpty())
1151 : {
1152 0 : bValid = false;
1153 0 : break;
1154 : }
1155 :
1156 58496 : if ( sToken[k] == "SHIFT" )
1157 17952 : aKeyEvent.Modifiers |= css::awt::KeyModifier::SHIFT;
1158 40544 : else if ( sToken[k] == "MOD1" )
1159 38901 : aKeyEvent.Modifiers |= css::awt::KeyModifier::MOD1;
1160 1643 : else if ( sToken[k] == "MOD2" )
1161 1643 : aKeyEvent.Modifiers |= css::awt::KeyModifier::MOD2;
1162 0 : else if ( sToken[k] == "MOD3" )
1163 0 : aKeyEvent.Modifiers |= css::awt::KeyModifier::MOD3;
1164 : else
1165 : {
1166 0 : bValid = false;
1167 0 : break;
1168 : }
1169 : }
1170 :
1171 53858 : if ( !aReadCache.hasKey(aKeyEvent) && bValid && k<nToken)
1172 53858 : aReadCache.setKeyCommandPair(aKeyEvent, sCommand);
1173 56578 : }
1174 : }
1175 :
1176 2720 : if (bPreferred)
1177 1364 : m_aPrimaryReadCache.takeOver(aReadCache);
1178 : else
1179 4084 : m_aSecondaryReadCache.takeOver(aReadCache);
1180 2720 : }
1181 :
1182 0 : void XCUBasedAcceleratorConfiguration::impl_ts_save(bool bPreferred, const css::uno::Reference< css::container::XNameAccess >& /*xCfg*/)
1183 : {
1184 0 : if (bPreferred)
1185 : {
1186 0 : AcceleratorCache::TKeyList::const_iterator pIt;
1187 0 : AcceleratorCache::TKeyList lPrimaryReadKeys = m_aPrimaryReadCache.getAllKeys();
1188 0 : AcceleratorCache::TKeyList lPrimaryWriteKeys = m_pPrimaryWriteCache->getAllKeys();
1189 :
1190 0 : for ( pIt = lPrimaryReadKeys.begin(); pIt != lPrimaryReadKeys.end(); ++pIt )
1191 : {
1192 0 : if (!m_pPrimaryWriteCache->hasKey(*pIt))
1193 0 : removeKeyFromConfiguration(*pIt, true);
1194 : }
1195 :
1196 0 : for ( pIt = lPrimaryWriteKeys.begin(); pIt != lPrimaryWriteKeys.end(); ++pIt )
1197 : {
1198 0 : OUString sCommand = m_pPrimaryWriteCache->getCommandByKey(*pIt);
1199 0 : if (!m_aPrimaryReadCache.hasKey(*pIt))
1200 : {
1201 0 : insertKeyToConfiguration(*pIt, sCommand, true);
1202 : }
1203 : else
1204 : {
1205 0 : OUString sReadCommand = m_aPrimaryReadCache.getCommandByKey(*pIt);
1206 0 : if (sReadCommand != sCommand)
1207 0 : insertKeyToConfiguration(*pIt, sCommand, true);
1208 : }
1209 0 : }
1210 :
1211 : // take over all changes into the original container
1212 0 : SolarMutexGuard g;
1213 : // coverity[check_after_deref]
1214 0 : if (m_pPrimaryWriteCache)
1215 : {
1216 0 : m_aPrimaryReadCache.takeOver(*m_pPrimaryWriteCache);
1217 0 : AcceleratorCache* pTemp = m_pPrimaryWriteCache;
1218 0 : m_pPrimaryWriteCache = 0;
1219 0 : delete pTemp;
1220 0 : }
1221 : }
1222 :
1223 : else
1224 : {
1225 0 : AcceleratorCache::TKeyList::const_iterator pIt;
1226 0 : AcceleratorCache::TKeyList lSecondaryReadKeys = m_aSecondaryReadCache.getAllKeys();
1227 0 : AcceleratorCache::TKeyList lSecondaryWriteKeys = m_pSecondaryWriteCache->getAllKeys();
1228 :
1229 0 : for ( pIt = lSecondaryReadKeys.begin(); pIt != lSecondaryReadKeys.end(); ++pIt)
1230 : {
1231 0 : if (!m_pSecondaryWriteCache->hasKey(*pIt))
1232 0 : removeKeyFromConfiguration(*pIt, false);
1233 : }
1234 :
1235 0 : for ( pIt = lSecondaryWriteKeys.begin(); pIt != lSecondaryWriteKeys.end(); ++pIt )
1236 : {
1237 0 : OUString sCommand = m_pSecondaryWriteCache->getCommandByKey(*pIt);
1238 0 : if (!m_aSecondaryReadCache.hasKey(*pIt))
1239 : {
1240 0 : insertKeyToConfiguration(*pIt, sCommand, false);
1241 : }
1242 : else
1243 : {
1244 0 : OUString sReadCommand = m_aSecondaryReadCache.getCommandByKey(*pIt);
1245 0 : if (sReadCommand != sCommand)
1246 0 : insertKeyToConfiguration(*pIt, sCommand, false);
1247 : }
1248 0 : }
1249 :
1250 : // take over all changes into the original container
1251 0 : SolarMutexGuard g;
1252 : // coverity[check_after_deref]
1253 0 : if (m_pSecondaryWriteCache)
1254 : {
1255 0 : m_aSecondaryReadCache.takeOver(*m_pSecondaryWriteCache);
1256 0 : AcceleratorCache* pTemp = m_pSecondaryWriteCache;
1257 0 : m_pSecondaryWriteCache = 0;
1258 0 : delete pTemp;
1259 0 : }
1260 : }
1261 :
1262 0 : ::comphelper::ConfigurationHelper::flush(m_xCfg);
1263 0 : }
1264 :
1265 0 : void XCUBasedAcceleratorConfiguration::insertKeyToConfiguration( const css::awt::KeyEvent& aKeyEvent, const OUString& sCommand, const bool bPreferred )
1266 : {
1267 0 : css::uno::Reference< css::container::XNameAccess > xAccess;
1268 0 : css::uno::Reference< css::container::XNameContainer > xContainer;
1269 0 : css::uno::Reference< css::lang::XSingleServiceFactory > xFac;
1270 0 : css::uno::Reference< css::uno::XInterface > xInst;
1271 :
1272 0 : if ( bPreferred )
1273 0 : m_xCfg->getByName(CFG_ENTRY_PRIMARY) >>= xAccess;
1274 : else
1275 0 : m_xCfg->getByName(CFG_ENTRY_SECONDARY) >>= xAccess;
1276 :
1277 0 : if ( m_sGlobalOrModules == CFG_ENTRY_GLOBAL )
1278 0 : xAccess->getByName(CFG_ENTRY_GLOBAL) >>= xContainer;
1279 0 : else if ( m_sGlobalOrModules == CFG_ENTRY_MODULES )
1280 : {
1281 0 : css::uno::Reference< css::container::XNameContainer > xModules;
1282 0 : xAccess->getByName(CFG_ENTRY_MODULES) >>= xModules;
1283 0 : if ( !xModules->hasByName(m_sModuleCFG) )
1284 : {
1285 0 : xFac = css::uno::Reference< css::lang::XSingleServiceFactory >(xModules, css::uno::UNO_QUERY);
1286 0 : xInst = xFac->createInstance();
1287 0 : xModules->insertByName(m_sModuleCFG, css::uno::makeAny(xInst));
1288 : }
1289 0 : xModules->getByName(m_sModuleCFG) >>= xContainer;
1290 : }
1291 :
1292 0 : const OUString sKey = lcl_getKeyString(m_rKeyMapping,aKeyEvent);
1293 0 : css::uno::Reference< css::container::XNameAccess > xKey;
1294 0 : css::uno::Reference< css::container::XNameContainer > xCommand;
1295 0 : if ( !xContainer->hasByName(sKey) )
1296 : {
1297 0 : xFac = css::uno::Reference< css::lang::XSingleServiceFactory >(xContainer, css::uno::UNO_QUERY);
1298 0 : xInst = xFac->createInstance();
1299 0 : xContainer->insertByName(sKey, css::uno::makeAny(xInst));
1300 : }
1301 0 : xContainer->getByName(sKey) >>= xKey;
1302 :
1303 0 : xKey->getByName(CFG_PROP_COMMAND) >>= xCommand;
1304 0 : OUString sLocale = impl_ts_getLocale();
1305 0 : if ( !xCommand->hasByName(sLocale) )
1306 0 : xCommand->insertByName(sLocale, css::uno::makeAny(sCommand));
1307 : else
1308 0 : xCommand->replaceByName(sLocale, css::uno::makeAny(sCommand));
1309 0 : }
1310 :
1311 0 : void XCUBasedAcceleratorConfiguration::removeKeyFromConfiguration( const css::awt::KeyEvent& aKeyEvent, const bool bPreferred )
1312 : {
1313 0 : css::uno::Reference< css::container::XNameAccess > xAccess;
1314 0 : css::uno::Reference< css::container::XNameContainer > xContainer;
1315 :
1316 0 : if ( bPreferred )
1317 0 : m_xCfg->getByName(CFG_ENTRY_PRIMARY) >>= xAccess;
1318 : else
1319 0 : m_xCfg->getByName(CFG_ENTRY_SECONDARY) >>= xAccess;
1320 :
1321 0 : if ( m_sGlobalOrModules == CFG_ENTRY_GLOBAL )
1322 0 : xAccess->getByName(CFG_ENTRY_GLOBAL) >>= xContainer;
1323 0 : else if ( m_sGlobalOrModules == CFG_ENTRY_MODULES )
1324 : {
1325 0 : css::uno::Reference< css::container::XNameAccess > xModules;
1326 0 : xAccess->getByName(CFG_ENTRY_MODULES) >>= xModules;
1327 0 : if ( !xModules->hasByName(m_sModuleCFG) )
1328 0 : return;
1329 0 : xModules->getByName(m_sModuleCFG) >>= xContainer;
1330 : }
1331 :
1332 0 : const OUString sKey = lcl_getKeyString(m_rKeyMapping,aKeyEvent);
1333 0 : xContainer->removeByName(sKey);
1334 : }
1335 :
1336 0 : void XCUBasedAcceleratorConfiguration::reloadChanged( const OUString& sPrimarySecondary, const OUString& sGlobalModules, const OUString& sModule, const OUString& sKey )
1337 : {
1338 0 : css::uno::Reference< css::container::XNameAccess > xAccess;
1339 0 : css::uno::Reference< css::container::XNameContainer > xContainer;
1340 :
1341 0 : m_xCfg->getByName(sPrimarySecondary) >>= xAccess;
1342 0 : if ( sGlobalModules == CFG_ENTRY_GLOBAL )
1343 0 : xAccess->getByName(CFG_ENTRY_GLOBAL) >>= xContainer;
1344 : else
1345 : {
1346 0 : css::uno::Reference< css::container::XNameAccess > xModules;
1347 0 : xAccess->getByName(CFG_ENTRY_MODULES) >>= xModules;
1348 0 : if ( !xModules->hasByName(sModule) )
1349 0 : return;
1350 0 : xModules->getByName(sModule) >>= xContainer;
1351 : }
1352 :
1353 0 : css::awt::KeyEvent aKeyEvent;
1354 0 : OUString sKeyIdentifier;
1355 :
1356 0 : sal_Int32 nIndex = 0;
1357 0 : sKeyIdentifier = sKey.getToken(0, '_', nIndex);
1358 0 : aKeyEvent.KeyCode = m_rKeyMapping->mapIdentifierToCode("KEY_"+sKeyIdentifier);
1359 :
1360 0 : css::uno::Sequence< OUString > sToken(3);
1361 0 : const sal_Int32 nToken = 3;
1362 0 : for (sal_Int32 i=0; i<nToken; ++i)
1363 : {
1364 0 : if ( nIndex < 0 )
1365 0 : break;
1366 :
1367 0 : sToken[i] = sKey.getToken(0, '_', nIndex);
1368 0 : if ( sToken[i] == "SHIFT" )
1369 0 : aKeyEvent.Modifiers |= css::awt::KeyModifier::SHIFT;
1370 0 : else if ( sToken[i] == "MOD1" )
1371 0 : aKeyEvent.Modifiers |= css::awt::KeyModifier::MOD1;
1372 0 : else if ( sToken[i] == "MOD2" )
1373 0 : aKeyEvent.Modifiers |= css::awt::KeyModifier::MOD2;
1374 0 : else if ( sToken[i] == "MOD3" )
1375 0 : aKeyEvent.Modifiers |= css::awt::KeyModifier::MOD3;
1376 : }
1377 :
1378 0 : css::uno::Reference< css::container::XNameAccess > xKey;
1379 0 : css::uno::Reference< css::container::XNameAccess > xCommand;
1380 0 : OUString sCommand;
1381 :
1382 0 : if (xContainer->hasByName(sKey))
1383 : {
1384 0 : OUString sLocale = impl_ts_getLocale();
1385 0 : xContainer->getByName(sKey) >>= xKey;
1386 0 : xKey->getByName(CFG_PROP_COMMAND) >>= xCommand;
1387 0 : xCommand->getByName(sLocale) >>= sCommand;
1388 : }
1389 :
1390 0 : if ( sPrimarySecondary == CFG_ENTRY_PRIMARY )
1391 : {
1392 0 : if (sCommand.isEmpty())
1393 0 : m_aPrimaryReadCache.removeKey(aKeyEvent);
1394 : else
1395 0 : m_aPrimaryReadCache.setKeyCommandPair(aKeyEvent, sCommand);
1396 : }
1397 0 : else if ( sPrimarySecondary == CFG_ENTRY_SECONDARY )
1398 : {
1399 0 : if (sCommand.isEmpty())
1400 0 : m_aSecondaryReadCache.removeKey(aKeyEvent);
1401 : else
1402 0 : m_aSecondaryReadCache.setKeyCommandPair(aKeyEvent, sCommand);
1403 0 : }
1404 : }
1405 :
1406 196979 : AcceleratorCache& XCUBasedAcceleratorConfiguration::impl_getCFG(bool bPreferred, bool bWriteAccessRequested)
1407 : {
1408 196979 : SolarMutexGuard g;
1409 :
1410 196979 : if (bPreferred)
1411 : {
1412 : //create copy of our readonly-cache, if write access is forced ... but
1413 : //not still possible!
1414 196975 : if (
1415 0 : (bWriteAccessRequested) &&
1416 0 : (!m_pPrimaryWriteCache )
1417 : )
1418 : {
1419 0 : m_pPrimaryWriteCache = new AcceleratorCache(m_aPrimaryReadCache);
1420 : }
1421 :
1422 : // in case, we have a writeable cache, we use it for reading too!
1423 : // Otherwise the API user can't find its own changes ...
1424 196975 : if (m_pPrimaryWriteCache)
1425 0 : return *m_pPrimaryWriteCache;
1426 : else
1427 196975 : return m_aPrimaryReadCache;
1428 : }
1429 :
1430 : else
1431 : {
1432 : //create copy of our readonly-cache, if write access is forced ... but
1433 : //not still possible!
1434 4 : if (
1435 0 : (bWriteAccessRequested) &&
1436 0 : (!m_pSecondaryWriteCache )
1437 : )
1438 : {
1439 0 : m_pSecondaryWriteCache = new AcceleratorCache(m_aSecondaryReadCache);
1440 : }
1441 :
1442 : // in case, we have a writeable cache, we use it for reading too!
1443 : // Otherwise the API user can't find its own changes ...
1444 4 : if (m_pSecondaryWriteCache)
1445 0 : return *m_pSecondaryWriteCache;
1446 : else
1447 4 : return m_aSecondaryReadCache;
1448 196979 : }
1449 : }
1450 :
1451 2720 : OUString XCUBasedAcceleratorConfiguration::impl_ts_getLocale() const
1452 : {
1453 2720 : OUString sISOLocale = officecfg::Setup::L10N::ooLocale::get();
1454 :
1455 2720 : if (sISOLocale.isEmpty())
1456 7 : return OUString("en-US");
1457 2713 : return sISOLocale;
1458 : }
1459 :
1460 : } // namespace framework
1461 :
1462 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|