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