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