1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_framework.hxx"
26 #include <accelerators/acceleratorconfiguration.hxx>
27 
28 //_______________________________________________
29 // own includes
30 #include <pattern/configuration.hxx>
31 #include <accelerators/presethandler.hxx>
32 
33 #include <xml/saxnamespacefilter.hxx>
34 #include <xml/acceleratorconfigurationreader.hxx>
35 #include <xml/acceleratorconfigurationwriter.hxx>
36 
37 #include <threadhelp/readguard.hxx>
38 #include <threadhelp/writeguard.hxx>
39 
40 #include <acceleratorconst.h>
41 #include <services.h>
42 
43 //_______________________________________________
44 // interface includes
45 #include <com/sun/star/xml/sax/XParser.hpp>
46 #include <com/sun/star/xml/sax/InputSource.hpp>
47 #include <com/sun/star/io/XActiveDataSource.hpp>
48 #include <com/sun/star/embed/ElementModes.hpp>
49 #include <com/sun/star/io/XSeekable.hpp>
50 #include <com/sun/star/io/XTruncate.hpp>
51 #include <com/sun/star/beans/XPropertySet.hpp>
52 
53 //_______________________________________________
54 // other includes
55 #include <vcl/svapp.hxx>
56 
57 #ifndef _COM_SUN_STAR_CONTAINER_XNAMED_HPP_
58 #include <com/sun/star/container/XNamed.hpp>
59 #endif
60 
61 #ifndef _COM_SUN_STAR_CONTAINER_XNAMECONTAINER_HPP_
62 #include <com/sun/star/container/XNameContainer.hpp>
63 #endif
64 
65 #ifndef __COM_SUN_STAR_AWT_KEYEVENT_HPP_
66 #include <com/sun/star/awt/KeyEvent.hpp>
67 #endif
68 
69 #ifndef __COM_SUN_STAR_AWT_KEYMODIFIER_HPP_
70 #include <com/sun/star/awt/KeyModifier.hpp>
71 #endif
72 
73 #ifndef _COM_SUN_STAR_LANG_XSINGLESERVICEFACTORY_HPP_
74 #include <com/sun/star/lang/XSingleServiceFactory.hpp>
75 #endif
76 
77 #ifndef _COM_SUN_STAR_UTIL_XCHANGESNOTIFIER_HPP_
78 #include <com/sun/star/util/XChangesNotifier.hpp>
79 #endif
80 
81 #ifndef _COMPHELPER_CONFIGURATIONHELPER_HXX_
82 #include <comphelper/configurationhelper.hxx>
83 #endif
84 
85 #ifndef UNOTOOLS_CONFIGPATHES_HXX_INCLUDED
86 #include <unotools/configpathes.hxx>
87 #endif
88 
89 #ifndef _RTL_LOGFILE_HXX_
90 #include <rtl/logfile.hxx>
91 #endif
92 
93 #include <svtools/acceleratorexecute.hxx>
94 
95 #include <stdio.h>
96 
97 //_______________________________________________
98 // const
99 
100 namespace framework
101 {
102 
103 #ifdef fpc
104     #error "Who exports this define? I use it as namespace alias ..."
105 #else
106     namespace fpc = ::framework::pattern::configuration;
107 #endif
108 
109     ::rtl::OUString lcl_getKeyString(salhelper::SingletonRef<framework::KeyMapping>& _rKeyMapping, const css::awt::KeyEvent& aKeyEvent)
110     {
111 	    const sal_Int32 nBeginIndex = 4; // "KEY_" is the prefix of a identifier...
112 	    ::rtl::OUStringBuffer sKeyBuffer((_rKeyMapping->mapCodeToIdentifier(aKeyEvent.KeyCode)).copy(nBeginIndex));
113 
114 	    if ( (aKeyEvent.Modifiers & css::awt::KeyModifier::SHIFT) == css::awt::KeyModifier::SHIFT )
115 		    sKeyBuffer.appendAscii("_SHIFT");
116 	    if ( (aKeyEvent.Modifiers & css::awt::KeyModifier::MOD1 ) == css::awt::KeyModifier::MOD1  )
117 		    sKeyBuffer.appendAscii("_MOD1");
118 	    if ( (aKeyEvent.Modifiers & css::awt::KeyModifier::MOD2 ) == css::awt::KeyModifier::MOD2  )
119 		    sKeyBuffer.appendAscii("_MOD2");
120         if ( (aKeyEvent.Modifiers & css::awt::KeyModifier::MOD3 ) == css::awt::KeyModifier::MOD3  )
121             sKeyBuffer.appendAscii("_MOD3");
122 
123         return sKeyBuffer.makeStringAndClear();
124     }
125 
126 //-----------------------------------------------
127 //	XInterface, XTypeProvider
128 DEFINE_XINTERFACE_6(XMLBasedAcceleratorConfiguration                       ,
129                     OWeakObject                                            ,
130                     DIRECT_INTERFACE(css::lang::XTypeProvider             ),
131                     DIRECT_INTERFACE(css::ui::XAcceleratorConfiguration  ),
132                     DIRECT_INTERFACE(css::form::XReset                    ),
133                     DIRECT_INTERFACE(css::ui::XUIConfigurationPersistence),
134                     DIRECT_INTERFACE(css::ui::XUIConfigurationStorage    ),
135                     DIRECT_INTERFACE(css::ui::XUIConfiguration           ))
136 
137 DEFINE_XTYPEPROVIDER_6(XMLBasedAcceleratorConfiguration     ,
138                        css::lang::XTypeProvider             ,
139                        css::ui::XAcceleratorConfiguration  ,
140                        css::form::XReset                    ,
141                        css::ui::XUIConfigurationPersistence,
142                        css::ui::XUIConfigurationStorage    ,
143                        css::ui::XUIConfiguration           )
144 
145 //-----------------------------------------------
146 XMLBasedAcceleratorConfiguration::XMLBasedAcceleratorConfiguration(const css::uno::Reference< css::lang::XMultiServiceFactory > xSMGR)
147     : ThreadHelpBase  (&Application::GetSolarMutex())
148     , m_xSMGR         (xSMGR                        )
149     , m_aPresetHandler(xSMGR                        )
150     , m_pWriteCache   (0                            )
151 {
152 }
153 
154 //-----------------------------------------------
155 XMLBasedAcceleratorConfiguration::~XMLBasedAcceleratorConfiguration()
156 {
157     LOG_ASSERT(!m_pWriteCache, "XMLBasedAcceleratorConfiguration::~XMLBasedAcceleratorConfiguration()\nChanges not flushed. Ignore it ...")
158 }
159 
160 //-----------------------------------------------
161 css::uno::Sequence< css::awt::KeyEvent > SAL_CALL XMLBasedAcceleratorConfiguration::getAllKeyEvents()
162     throw(css::uno::RuntimeException)
163 {
164     // SAFE -> ----------------------------------
165     ReadGuard aReadLock(m_aLock);
166 
167     AcceleratorCache&          rCache = impl_getCFG();
168     AcceleratorCache::TKeyList lKeys  = rCache.getAllKeys();
169     return lKeys.getAsConstList();
170 
171     // <- SAFE ----------------------------------
172 }
173 
174 //-----------------------------------------------
175 ::rtl::OUString SAL_CALL XMLBasedAcceleratorConfiguration::getCommandByKeyEvent(const css::awt::KeyEvent& aKeyEvent)
176     throw(css::container::NoSuchElementException,
177           css::uno::RuntimeException            )
178 {
179     // SAFE -> ----------------------------------
180     ReadGuard aReadLock(m_aLock);
181 
182     AcceleratorCache& rCache = impl_getCFG();
183     if (!rCache.hasKey(aKeyEvent))
184         throw css::container::NoSuchElementException(
185                 ::rtl::OUString(),
186                 static_cast< ::cppu::OWeakObject* >(this));
187     return rCache.getCommandByKey(aKeyEvent);
188 
189     // <- SAFE ----------------------------------
190 }
191 
192 //-----------------------------------------------
193 void SAL_CALL XMLBasedAcceleratorConfiguration::setKeyEvent(const css::awt::KeyEvent& aKeyEvent,
194 													const ::rtl::OUString&    sCommand )
195 													throw(css::lang::IllegalArgumentException,
196 													css::uno::RuntimeException         )
197 {
198 	if (
199 		(aKeyEvent.KeyCode   == 0) &&
200 		(aKeyEvent.KeyChar   == 0) &&
201 		(aKeyEvent.KeyFunc   == 0) &&
202 		(aKeyEvent.Modifiers == 0)
203 		)
204 		throw css::lang::IllegalArgumentException(
205 		::rtl::OUString::createFromAscii("Such key event seams not to be supported by any operating system."),
206 		static_cast< ::cppu::OWeakObject* >(this),
207 		0);
208 
209 	if (!sCommand.getLength())
210 		throw css::lang::IllegalArgumentException(
211 		::rtl::OUString::createFromAscii("Empty command strings are not allowed here."),
212 		static_cast< ::cppu::OWeakObject* >(this),
213 		1);
214 
215 	// SAFE -> ----------------------------------
216 	WriteGuard aWriteLock(m_aLock);
217 
218 	AcceleratorCache& rCache = impl_getCFG(sal_True); // sal_True => force getting of a writeable cache!
219 	rCache.setKeyCommandPair(aKeyEvent, sCommand);
220 
221 	aWriteLock.unlock();
222 	// <- SAFE ----------------------------------
223 }
224 
225 //-----------------------------------------------
226 void SAL_CALL XMLBasedAcceleratorConfiguration::removeKeyEvent(const css::awt::KeyEvent& aKeyEvent)
227 throw(css::container::NoSuchElementException,
228 	  css::uno::RuntimeException            )
229 {
230 	// SAFE -> ----------------------------------
231 	WriteGuard aWriteLock(m_aLock);
232 
233 	AcceleratorCache& rCache = impl_getCFG(sal_True); // true => force using of a writeable cache
234 	if (!rCache.hasKey(aKeyEvent))
235 		throw css::container::NoSuchElementException(
236 		::rtl::OUString(),
237 		static_cast< ::cppu::OWeakObject* >(this));
238 	rCache.removeKey(aKeyEvent);
239 
240 	// <- SAFE ----------------------------------
241 }
242 
243 //-----------------------------------------------
244 css::uno::Sequence< css::awt::KeyEvent > SAL_CALL XMLBasedAcceleratorConfiguration::getKeyEventsByCommand(const ::rtl::OUString& sCommand)
245     throw(css::lang::IllegalArgumentException   ,
246           css::container::NoSuchElementException,
247           css::uno::RuntimeException            )
248 {
249     if (!sCommand.getLength())
250         throw css::lang::IllegalArgumentException(
251                 ::rtl::OUString::createFromAscii("Empty command strings are not allowed here."),
252                 static_cast< ::cppu::OWeakObject* >(this),
253                 1);
254 
255     // SAFE -> ----------------------------------
256     ReadGuard aReadLock(m_aLock);
257 
258     AcceleratorCache& rCache = impl_getCFG();
259     if (!rCache.hasCommand(sCommand))
260         throw css::container::NoSuchElementException(
261                 ::rtl::OUString(),
262                 static_cast< ::cppu::OWeakObject* >(this));
263 
264     AcceleratorCache::TKeyList lKeys  = rCache.getKeysByCommand(sCommand);
265     return lKeys.getAsConstList();
266 
267     // <- SAFE ----------------------------------
268 }
269 
270 //-----------------------------------------------
271 css::uno::Sequence< css::uno::Any > SAL_CALL XMLBasedAcceleratorConfiguration::getPreferredKeyEventsForCommandList(const css::uno::Sequence< ::rtl::OUString >& lCommandList)
272     throw(css::lang::IllegalArgumentException   ,
273           css::uno::RuntimeException            )
274 {
275     // SAFE -> ----------------------------------
276     ReadGuard aReadLock(m_aLock);
277 
278     sal_Int32                           i              = 0;
279     sal_Int32                           c              = lCommandList.getLength();
280     css::uno::Sequence< css::uno::Any > lPreferredOnes (c); // dont pack list!
281     AcceleratorCache&                   rCache         = impl_getCFG();
282 
283     for (i=0; i<c; ++i)
284     {
285         const ::rtl::OUString& rCommand = lCommandList[i];
286         if (!rCommand.getLength())
287             throw css::lang::IllegalArgumentException(
288                     ::rtl::OUString::createFromAscii("Empty command strings are not allowed here."),
289                     static_cast< ::cppu::OWeakObject* >(this),
290                     (sal_Int16)i);
291 
292         if (!rCache.hasCommand(rCommand))
293             continue;
294 
295         AcceleratorCache::TKeyList lKeys = rCache.getKeysByCommand(rCommand);
296         if ( lKeys.empty() )
297             continue;
298 
299         css::uno::Any& rAny = lPreferredOnes[i];
300         rAny <<= *(lKeys.begin());
301     }
302 
303     aReadLock.unlock();
304     // <- SAFE ----------------------------------
305 
306     return lPreferredOnes;
307 }
308 
309 //-----------------------------------------------
310 void SAL_CALL XMLBasedAcceleratorConfiguration::removeCommandFromAllKeyEvents(const ::rtl::OUString& sCommand)
311     throw(css::lang::IllegalArgumentException   ,
312           css::container::NoSuchElementException,
313           css::uno::RuntimeException            )
314 {
315     if (!sCommand.getLength())
316         throw css::lang::IllegalArgumentException(
317                 ::rtl::OUString::createFromAscii("Empty command strings are not allowed here."),
318                 static_cast< ::cppu::OWeakObject* >(this),
319                 0);
320 
321     // SAFE -> ----------------------------------
322     WriteGuard aWriteLock(m_aLock);
323 
324     AcceleratorCache& rCache = impl_getCFG(sal_True); // sal_True => force getting of a writeable cache!
325     if (!rCache.hasCommand(sCommand))
326         throw css::container::NoSuchElementException(
327                 ::rtl::OUString::createFromAscii("Command does not exists inside this container."),
328                 static_cast< ::cppu::OWeakObject* >(this));
329     rCache.removeCommand(sCommand);
330 
331     aWriteLock.unlock();
332     // <- SAFE ----------------------------------
333 }
334 
335 //-----------------------------------------------
336 void SAL_CALL XMLBasedAcceleratorConfiguration::reload()
337 	throw(css::uno::Exception       ,
338 		css::uno::RuntimeException)
339 {
340 	css::uno::Reference< css::io::XStream > xStreamNoLang;
341 
342 	// SAFE -> ----------------------------------
343 	ReadGuard aReadLock(m_aLock);
344 	css::uno::Reference< css::io::XStream > xStream = m_aPresetHandler.openTarget(PresetHandler::TARGET_CURRENT(), sal_True); // sal_True => open or create!
345 	try
346 	{
347 		xStreamNoLang = m_aPresetHandler.openPreset(PresetHandler::PRESET_DEFAULT(), sal_True);
348 	}
349 	catch(const css::io::IOException&) {} // does not have to exist
350 	aReadLock.unlock();
351 	// <- SAFE ----------------------------------
352 
353 	css::uno::Reference< css::io::XInputStream > xIn;
354 	if (xStream.is())
355 		xIn = xStream->getInputStream();
356 	if (!xIn.is())
357 		throw css::io::IOException(
358 		::rtl::OUString::createFromAscii("Could not open accelerator configuration for reading."),
359 		static_cast< ::cppu::OWeakObject* >(this));
360 
361 	// impl_ts_load() does not clear the cache
362 	// SAFE -> ----------------------------------
363 	WriteGuard aWriteLock(m_aLock);
364 	m_aReadCache = AcceleratorCache();
365 	aWriteLock.unlock();
366 	// <- SAFE ----------------------------------
367 
368 	impl_ts_load(xIn);
369 
370 	// Load also the general language independent default accelerators
371 	// (ignoring the already defined accelerators)
372 	if (xStreamNoLang.is())
373 	{
374 		xIn = xStreamNoLang->getInputStream();
375 		if (xIn.is())
376 			impl_ts_load(xIn);
377 	}
378 }
379 
380 //-----------------------------------------------
381 void SAL_CALL XMLBasedAcceleratorConfiguration::store()
382 	throw(css::uno::Exception       ,
383 		css::uno::RuntimeException)
384 {
385 	// SAFE -> ----------------------------------
386 	ReadGuard aReadLock(m_aLock);
387 	css::uno::Reference< css::io::XStream > xStream = m_aPresetHandler.openTarget(PresetHandler::TARGET_CURRENT(), sal_True); // sal_True => open or create!
388 	aReadLock.unlock();
389 	// <- SAFE ----------------------------------
390 
391 	css::uno::Reference< css::io::XOutputStream > xOut;
392 	if (xStream.is())
393 		xOut = xStream->getOutputStream();
394 
395 	if (!xOut.is())
396 		throw css::io::IOException(
397 		::rtl::OUString::createFromAscii("Could not open accelerator configuration for saving."),
398 		static_cast< ::cppu::OWeakObject* >(this));
399 
400 	impl_ts_save(xOut);
401 
402 	xOut.clear();
403 	xStream.clear();
404 
405 	m_aPresetHandler.commitUserChanges();
406 }
407 
408 //-----------------------------------------------
409 void SAL_CALL XMLBasedAcceleratorConfiguration::storeToStorage(const css::uno::Reference< css::embed::XStorage >& xStorage)
410     throw(css::uno::Exception       ,
411           css::uno::RuntimeException)
412 {
413     css::uno::Reference< css::io::XStream > xStream = StorageHolder::openSubStreamWithFallback(
414                                                             xStorage,
415                                                             PresetHandler::TARGET_CURRENT(),
416                                                             css::embed::ElementModes::READWRITE,
417                                                             sal_False); // False => no fallback from read/write to readonly!
418     css::uno::Reference< css::io::XOutputStream > xOut;
419     if (xStream.is())
420         xOut = xStream->getOutputStream();
421 
422     if (!xOut.is())
423         throw css::io::IOException(
424                 ::rtl::OUString::createFromAscii("Could not open accelerator configuration for saving."),
425                 static_cast< ::cppu::OWeakObject* >(this));
426 
427     impl_ts_save(xOut);
428 
429     // TODO inform listener about success, so it can flush the root and sub storage of this stream!
430 }
431 
432 //-----------------------------------------------
433 ::sal_Bool SAL_CALL XMLBasedAcceleratorConfiguration::isModified()
434     throw(css::uno::RuntimeException)
435 {
436     // SAFE -> ----------------------------------
437     ReadGuard aReadLock(m_aLock);
438     return (m_pWriteCache != 0);
439     // <- SAFE ----------------------------------
440 }
441 
442 //-----------------------------------------------
443 ::sal_Bool SAL_CALL XMLBasedAcceleratorConfiguration::isReadOnly()
444     throw(css::uno::RuntimeException)
445 {
446 	// SAFE -> ----------------------------------
447 	ReadGuard aReadLock(m_aLock);
448 	css::uno::Reference< css::io::XStream > xStream = m_aPresetHandler.openTarget(PresetHandler::TARGET_CURRENT(), sal_True); // sal_True => open or create!
449 	aReadLock.unlock();
450 	// <- SAFE ----------------------------------
451 
452 	css::uno::Reference< css::io::XOutputStream > xOut;
453 	if (xStream.is())
454 		xOut = xStream->getOutputStream();
455 	return !(xOut.is());
456 }
457 
458 //-----------------------------------------------
459 void SAL_CALL XMLBasedAcceleratorConfiguration::setStorage(const css::uno::Reference< css::embed::XStorage >& /*xStorage*/)
460     throw(css::uno::RuntimeException)
461 {
462     LOG_WARNING("XMLBasedAcceleratorConfiguration::setStorage()", "TODO implement this HACK .-)")
463 }
464 
465 //-----------------------------------------------
466 ::sal_Bool SAL_CALL XMLBasedAcceleratorConfiguration::hasStorage()
467     throw(css::uno::RuntimeException)
468 {
469     LOG_WARNING("XMLBasedAcceleratorConfiguration::hasStorage()", "TODO implement this HACK .-)")
470     return sal_False;
471 }
472 
473 //-----------------------------------------------
474 void SAL_CALL XMLBasedAcceleratorConfiguration::addConfigurationListener(const css::uno::Reference< css::ui::XUIConfigurationListener >& /*xListener*/)
475     throw(css::uno::RuntimeException)
476 {
477     LOG_WARNING("XMLBasedAcceleratorConfiguration::addConfigurationListener()", "TODO implement me")
478 }
479 
480 //-----------------------------------------------
481 void SAL_CALL XMLBasedAcceleratorConfiguration::removeConfigurationListener(const css::uno::Reference< css::ui::XUIConfigurationListener >& /*xListener*/)
482     throw(css::uno::RuntimeException)
483 {
484     LOG_WARNING("XMLBasedAcceleratorConfiguration::removeConfigurationListener()", "TODO implement me")
485 }
486 
487 //-----------------------------------------------
488 void SAL_CALL XMLBasedAcceleratorConfiguration::reset()
489 throw(css::uno::RuntimeException)
490 {
491 	// SAFE -> ----------------------------------
492 	WriteGuard aWriteLock(m_aLock);
493 	m_aPresetHandler.copyPresetToTarget(PresetHandler::PRESET_DEFAULT(), PresetHandler::TARGET_CURRENT());
494 	aWriteLock.unlock();
495 	// <- SAFE ----------------------------------
496 
497 	reload();
498 }
499 
500 //-----------------------------------------------
501 void SAL_CALL XMLBasedAcceleratorConfiguration::addResetListener(const css::uno::Reference< css::form::XResetListener >& /*xListener*/)
502     throw(css::uno::RuntimeException)
503 {
504     LOG_WARNING("XMLBasedAcceleratorConfiguration::addResetListener()", "TODO implement me")
505 }
506 
507 //-----------------------------------------------
508 void SAL_CALL XMLBasedAcceleratorConfiguration::removeResetListener(const css::uno::Reference< css::form::XResetListener >& /*xListener*/)
509     throw(css::uno::RuntimeException)
510 {
511     LOG_WARNING("XMLBasedAcceleratorConfiguration::removeResetListener()", "TODO implement me")
512 }
513 
514 //-----------------------------------------------
515 // IStorageListener
516 void XMLBasedAcceleratorConfiguration::changesOccured(const ::rtl::OUString& /*sPath*/)
517 {
518     reload();
519 }
520 
521 //-----------------------------------------------
522 void XMLBasedAcceleratorConfiguration::impl_ts_load(const css::uno::Reference< css::io::XInputStream >& xStream)
523 {
524     // SAFE -> ----------------------------------
525     WriteGuard aWriteLock(m_aLock);
526 
527     css::uno::Reference< css::lang::XMultiServiceFactory > xSMGR = m_xSMGR;
528     if (m_pWriteCache)
529     {
530         // be aware of reentrance problems - use temp variable for calling delete ... :-)
531         AcceleratorCache* pTemp = m_pWriteCache;
532         m_pWriteCache = 0;
533         delete pTemp;
534     }
535 
536     aWriteLock.unlock();
537     // <- SAFE ----------------------------------
538 
539     css::uno::Reference< css::io::XSeekable > xSeek(xStream, css::uno::UNO_QUERY);
540     if (xSeek.is())
541         xSeek->seek(0);
542 
543     // add accelerators to the cache (the cache is not cleared)
544     // SAFE -> ----------------------------------
545     aWriteLock.lock();
546 
547     // create the parser queue
548     // Note: Use special filter object between parser and reader
549     // to get filtered xml with right namespaces ...
550     // Use further a temp cache for reading!
551     AcceleratorConfigurationReader*                        pReader = new AcceleratorConfigurationReader(m_aReadCache);
552     css::uno::Reference< css::xml::sax::XDocumentHandler > xReader (static_cast< ::cppu::OWeakObject* >(pReader), css::uno::UNO_QUERY_THROW);
553     SaxNamespaceFilter*                                    pFilter = new SaxNamespaceFilter(xReader);
554     css::uno::Reference< css::xml::sax::XDocumentHandler > xFilter (static_cast< ::cppu::OWeakObject* >(pFilter), css::uno::UNO_QUERY_THROW);
555 
556 	// connect parser, filter and stream
557 	css::uno::Reference< css::xml::sax::XParser > xParser(xSMGR->createInstance(SERVICENAME_SAXPARSER), css::uno::UNO_QUERY_THROW);
558 	xParser->setDocumentHandler(xFilter);
559 
560     css::xml::sax::InputSource aSource;
561     aSource.aInputStream = xStream;
562 
563     // TODO think about error handling
564     xParser->parseStream(aSource);
565 
566     aWriteLock.unlock();
567     // <- SAFE ----------------------------------
568 }
569 
570 //-----------------------------------------------
571 void XMLBasedAcceleratorConfiguration::impl_ts_save(const css::uno::Reference< css::io::XOutputStream >& xStream)
572 {
573     // SAFE -> ----------------------------------
574     ReadGuard aReadLock(m_aLock);
575 
576     AcceleratorCache aCache;
577     sal_Bool bChanged = (m_pWriteCache != 0);
578     if (bChanged)
579         aCache.takeOver(*m_pWriteCache);
580     else
581         aCache.takeOver(m_aReadCache);
582     css::uno::Reference< css::lang::XMultiServiceFactory > xSMGR = m_xSMGR;
583 
584     aReadLock.unlock();
585     // <- SAFE ----------------------------------
586 
587     css::uno::Reference< css::io::XTruncate > xClearable(xStream, css::uno::UNO_QUERY_THROW);
588     xClearable->truncate();
589 
590     // TODO can be removed if seek(0) is done by truncate() automaticly!
591     css::uno::Reference< css::io::XSeekable > xSeek(xStream, css::uno::UNO_QUERY);
592     if (xSeek.is())
593         xSeek->seek(0);
594 
595     // combine writer/cache/stream etcpp.
596     css::uno::Reference< css::xml::sax::XDocumentHandler > xWriter    (xSMGR->createInstance(SERVICENAME_SAXWRITER), css::uno::UNO_QUERY_THROW);
597 	css::uno::Reference< css::io::XActiveDataSource>       xDataSource(xWriter                                     , css::uno::UNO_QUERY_THROW);
598     xDataSource->setOutputStream(xStream);
599 
600     // write into the stream
601     AcceleratorConfigurationWriter aWriter(aCache, xWriter);
602     aWriter.flush();
603 
604     // take over all changes into the original container
605     // SAFE -> ----------------------------------
606     WriteGuard aWriteLock(m_aLock);
607 
608     // take over all changes into the readonly cache ...
609     // and forget the copy-on-write copied cache
610     if (bChanged)
611     {
612         m_aReadCache.takeOver(*m_pWriteCache);
613         // live with reentrance .-)
614         AcceleratorCache* pTemp = m_pWriteCache;
615         m_pWriteCache = 0;
616         delete pTemp;
617     }
618 
619     aWriteLock.unlock();
620     // <- SAFE ----------------------------------
621 }
622 
623 //-----------------------------------------------
624 AcceleratorCache& XMLBasedAcceleratorConfiguration::impl_getCFG(sal_Bool bWriteAccessRequested)
625 {
626     // SAFE -> ----------------------------------
627     WriteGuard aWriteLock(m_aLock);
628 
629     //create copy of our readonly-cache, if write access is forced ... but
630     //not still possible!
631     if (
632         (bWriteAccessRequested) &&
633         (!m_pWriteCache       )
634        )
635     {
636         m_pWriteCache = new AcceleratorCache(m_aReadCache);
637     }
638 
639     // in case, we have a writeable cache, we use it for reading too!
640     // Otherwhise the API user cant find its own changes ...
641     if (m_pWriteCache)
642         return *m_pWriteCache;
643     else
644         return m_aReadCache;
645     // <- SAFE ----------------------------------
646 }
647 
648 //-----------------------------------------------
649 ::comphelper::Locale XMLBasedAcceleratorConfiguration::impl_ts_getLocale() const
650 {
651     static ::rtl::OUString LOCALE_PACKAGE = ::rtl::OUString::createFromAscii("/org.openoffice.Setup");
652     static ::rtl::OUString LOCALE_PATH    = ::rtl::OUString::createFromAscii("L10N"                 );
653     static ::rtl::OUString LOCALE_KEY     = ::rtl::OUString::createFromAscii("ooLocale"             );
654 
655     // SAFE -> ----------------------------------
656     ReadGuard aReadLock(m_aLock);
657     css::uno::Reference< css::lang::XMultiServiceFactory > xSMGR = m_xSMGR;
658     aReadLock.unlock();
659     // <- SAFE ----------------------------------
660 
661     css::uno::Reference< css::uno::XInterface >     xCFG      = fpc::ConfigurationHelper::openConfig(xSMGR, LOCALE_PACKAGE, LOCALE_PATH, fpc::ConfigurationHelper::E_READONLY);
662     css::uno::Reference< css::beans::XPropertySet > xProp     (xCFG, css::uno::UNO_QUERY_THROW);
663     ::rtl::OUString                                 sISOLocale;
664     xProp->getPropertyValue(LOCALE_KEY) >>= sISOLocale;
665 
666     if (!sISOLocale.getLength())
667         return ::comphelper::Locale::EN_US();
668     return ::comphelper::Locale(sISOLocale);
669 }
670 
671 /*******************************************************************************
672 *
673 * XCU based accelerator configuration
674 *
675 *******************************************************************************/
676 
677 //-----------------------------------------------
678 //	XInterface, XTypeProvider
679 DEFINE_XINTERFACE_7(XCUBasedAcceleratorConfiguration                       ,
680 					OWeakObject                                            ,
681 					DIRECT_INTERFACE(css::lang::XTypeProvider             ),
682 					DIRECT_INTERFACE(css::ui::XAcceleratorConfiguration  ),
683 					DIRECT_INTERFACE(css::util::XChangesListener          ),
684 					DIRECT_INTERFACE(css::form::XReset                    ),
685 					DIRECT_INTERFACE(css::ui::XUIConfigurationPersistence),
686 					DIRECT_INTERFACE(css::ui::XUIConfigurationStorage    ),
687 					DIRECT_INTERFACE(css::ui::XUIConfiguration           ))
688 
689 					DEFINE_XTYPEPROVIDER_7(XCUBasedAcceleratorConfiguration ,
690 					css::lang::XTypeProvider             ,
691 					css::ui::XAcceleratorConfiguration  ,
692 					css::util::XChangesListener          ,
693 					css::form::XReset                    ,
694 					css::ui::XUIConfigurationPersistence,
695 					css::ui::XUIConfigurationStorage    ,
696 					css::ui::XUIConfiguration           )
697 
698 //-----------------------------------------------
699 XCUBasedAcceleratorConfiguration::XCUBasedAcceleratorConfiguration(const css::uno::Reference< css::lang::XMultiServiceFactory > xSMGR)
700 								: ThreadHelpBase  (&Application::GetSolarMutex())
701 								, m_xSMGR         (xSMGR                        )
702                                 , m_pPrimaryWriteCache(0                        )
703                                 , m_pSecondaryWriteCache(0                      )
704 {
705     static const ::rtl::OUString CFG_ENTRY_ACCELERATORS(RTL_CONSTASCII_USTRINGPARAM("org.openoffice.Office.Accelerators"));
706     m_xCfg = css::uno::Reference< css::container::XNameAccess > (
707 			 ::comphelper::ConfigurationHelper::openConfig( m_xSMGR, CFG_ENTRY_ACCELERATORS, ::comphelper::ConfigurationHelper::E_ALL_LOCALES ),
708 			 css::uno::UNO_QUERY );
709 }
710 
711 //-----------------------------------------------
712 XCUBasedAcceleratorConfiguration::~XCUBasedAcceleratorConfiguration()
713 {
714 }
715 
716 //-----------------------------------------------
717 css::uno::Sequence< css::awt::KeyEvent > SAL_CALL XCUBasedAcceleratorConfiguration::getAllKeyEvents()
718 	throw(css::uno::RuntimeException)
719 {
720 	// SAFE -> ----------------------------------
721 	ReadGuard aReadLock(m_aLock);
722 
723 	AcceleratorCache::TKeyList lKeys  = impl_getCFG(sal_True).getAllKeys(); //get keys from PrimaryKeys set
724 
725     AcceleratorCache::TKeyList lSecondaryKeys = impl_getCFG(sal_False).getAllKeys(); //get keys from SecondaryKeys set
726     lKeys.reserve(lKeys.size()+lSecondaryKeys.size());
727     AcceleratorCache::TKeyList::const_iterator pIt;
728     AcceleratorCache::TKeyList::const_iterator pEnd = lSecondaryKeys.end();
729     for ( pIt  = lSecondaryKeys.begin(); pIt != pEnd; ++pIt )
730         lKeys.push_back(*pIt);
731 
732     return lKeys.getAsConstList();
733 
734 	// <- SAFE ----------------------------------
735 }
736 
737 //-----------------------------------------------
738 ::rtl::OUString SAL_CALL XCUBasedAcceleratorConfiguration::getCommandByKeyEvent(const css::awt::KeyEvent& aKeyEvent)
739 	throw(css::container::NoSuchElementException,
740 		  css::uno::RuntimeException            )
741 {
742 	// SAFE -> ----------------------------------
743 	ReadGuard aReadLock(m_aLock);
744 
745     AcceleratorCache& rPrimaryCache   = impl_getCFG(sal_True );
746     AcceleratorCache& rSecondaryCache = impl_getCFG(sal_False);
747 
748 	if (!rPrimaryCache.hasKey(aKeyEvent) && !rSecondaryCache.hasKey(aKeyEvent))
749 		throw css::container::NoSuchElementException(
750 		::rtl::OUString(),
751 		static_cast< ::cppu::OWeakObject* >(this));
752 
753     if (rPrimaryCache.hasKey(aKeyEvent))
754 	    return rPrimaryCache.getCommandByKey(aKeyEvent);
755     else
756         return rSecondaryCache.getCommandByKey(aKeyEvent);
757 
758 	// <- SAFE ----------------------------------
759 }
760 
761 //-----------------------------------------------
762 void SAL_CALL XCUBasedAcceleratorConfiguration::setKeyEvent(const css::awt::KeyEvent& aKeyEvent,
763 													const ::rtl::OUString&    sCommand )
764 													throw(css::lang::IllegalArgumentException,
765 													css::uno::RuntimeException         )
766 {
767 	RTL_LOGFILE_PRODUCT_CONTEXT( aLog, "XCUBasedAcceleratorConfiguration::setKeyEvent" );
768 
769 	if (
770 		(aKeyEvent.KeyCode   == 0) &&
771 		(aKeyEvent.KeyChar   == 0) &&
772 		(aKeyEvent.KeyFunc   == 0) &&
773 		(aKeyEvent.Modifiers == 0)
774 		)
775 		throw css::lang::IllegalArgumentException(
776 				::rtl::OUString::createFromAscii("Such key event seams not to be supported by any operating system."),
777 				static_cast< ::cppu::OWeakObject* >(this),
778 				0);
779 
780 	if (!sCommand.getLength())
781 				throw css::lang::IllegalArgumentException(
782 				::rtl::OUString::createFromAscii("Empty command strings are not allowed here."),
783 				static_cast< ::cppu::OWeakObject* >(this),
784 				1);
785 
786 	// SAFE -> ----------------------------------
787 	WriteGuard aWriteLock(m_aLock);
788 
789     AcceleratorCache& rPrimaryCache   = impl_getCFG(sal_True, sal_True ); // sal_True => force getting of a writeable cache!
790     AcceleratorCache& rSecondaryCache = impl_getCFG(sal_False, sal_True); // sal_True => force getting of a writeable cache!
791 
792     if ( rPrimaryCache.hasKey(aKeyEvent) )
793     {
794         ::rtl::OUString sOriginalCommand = rPrimaryCache.getCommandByKey(aKeyEvent);
795         if ( sCommand != sOriginalCommand )
796         {
797             if (rSecondaryCache.hasCommand(sOriginalCommand))
798             {
799                 AcceleratorCache::TKeyList lSecondaryKeys = rSecondaryCache.getKeysByCommand(sOriginalCommand);
800                 rSecondaryCache.removeKey(lSecondaryKeys[0]);
801                 rPrimaryCache.setKeyCommandPair(lSecondaryKeys[0], sOriginalCommand);
802             }
803 
804             if (rPrimaryCache.hasCommand(sCommand))
805             {
806                 AcceleratorCache::TKeyList lPrimaryKeys = rPrimaryCache.getKeysByCommand(sCommand);
807                 rPrimaryCache.removeKey(lPrimaryKeys[0]);
808                 rSecondaryCache.setKeyCommandPair(lPrimaryKeys[0], sCommand);
809             }
810 
811             rPrimaryCache.setKeyCommandPair(aKeyEvent, sCommand);
812         }
813     }
814 
815     else if ( rSecondaryCache.hasKey(aKeyEvent) )
816     {
817         ::rtl::OUString sOriginalCommand = rSecondaryCache.getCommandByKey(aKeyEvent);
818         if (sCommand != sOriginalCommand)
819         {
820             if (rPrimaryCache.hasCommand(sCommand))
821             {
822                 AcceleratorCache::TKeyList lPrimaryKeys = rPrimaryCache.getKeysByCommand(sCommand);
823                 rPrimaryCache.removeKey(lPrimaryKeys[0]);
824                 rSecondaryCache.setKeyCommandPair(lPrimaryKeys[0], sCommand);
825             }
826 
827             rSecondaryCache.removeKey(aKeyEvent);
828             rPrimaryCache.setKeyCommandPair(aKeyEvent, sCommand);
829         }
830     }
831 
832     else
833     {
834         if (rPrimaryCache.hasCommand(sCommand))
835         {
836             AcceleratorCache::TKeyList lPrimaryKeys = rPrimaryCache.getKeysByCommand(sCommand);
837             rPrimaryCache.removeKey(lPrimaryKeys[0]);
838             rSecondaryCache.setKeyCommandPair(lPrimaryKeys[0], sCommand);
839         }
840 
841         rPrimaryCache.setKeyCommandPair(aKeyEvent, sCommand);
842     }
843 
844 	aWriteLock.unlock();
845 	// <- SAFE ----------------------------------
846 }
847 
848 //-----------------------------------------------
849 void SAL_CALL XCUBasedAcceleratorConfiguration::removeKeyEvent(const css::awt::KeyEvent& aKeyEvent)
850 	throw(css::container::NoSuchElementException,
851 		  css::uno::RuntimeException            )
852 {
853 	// SAFE -> ----------------------------------
854 	WriteGuard aWriteLock(m_aLock);
855 
856     AcceleratorCache& rPrimaryCache   = impl_getCFG(sal_True, sal_True );
857     AcceleratorCache& rSecondaryCache = impl_getCFG(sal_False, sal_True);
858 
859 	if (!rPrimaryCache.hasKey(aKeyEvent) && !rSecondaryCache.hasKey(aKeyEvent))
860 		throw css::container::NoSuchElementException(
861 		::rtl::OUString(),
862 		static_cast< ::cppu::OWeakObject* >(this));
863 
864     if (rPrimaryCache.hasKey(aKeyEvent))
865     {
866         ::rtl::OUString sDelCommand = rPrimaryCache.getCommandByKey(aKeyEvent);
867         if (sDelCommand.getLength() > 0)
868         {
869             ::rtl::OUString sOriginalCommand = rPrimaryCache.getCommandByKey(aKeyEvent);
870             if (rSecondaryCache.hasCommand(sOriginalCommand))
871             {
872                 AcceleratorCache::TKeyList lSecondaryKeys = rSecondaryCache.getKeysByCommand(sOriginalCommand);
873                 rSecondaryCache.removeKey(lSecondaryKeys[0]);
874                 rPrimaryCache.setKeyCommandPair(lSecondaryKeys[0], sOriginalCommand);
875             }
876 
877             rPrimaryCache.removeKey(aKeyEvent);
878         }
879 
880     }
881     else
882     {
883         ::rtl::OUString sDelCommand = rSecondaryCache.getCommandByKey(aKeyEvent);
884         if (sDelCommand.getLength() > 0)
885             rSecondaryCache.removeKey(aKeyEvent);
886     }
887 
888 	// <- SAFE ----------------------------------
889 }
890 
891 //-----------------------------------------------
892 css::uno::Sequence< css::awt::KeyEvent > SAL_CALL XCUBasedAcceleratorConfiguration::getKeyEventsByCommand(const ::rtl::OUString& sCommand)
893 	throw(css::lang::IllegalArgumentException   ,
894 		css::container::NoSuchElementException,
895 		css::uno::RuntimeException            )
896 {
897 	if (!sCommand.getLength())
898 		throw css::lang::IllegalArgumentException(
899 				::rtl::OUString::createFromAscii("Empty command strings are not allowed here."),
900 				static_cast< ::cppu::OWeakObject* >(this),
901 				1);
902 
903 	// SAFE -> ----------------------------------
904 	ReadGuard aReadLock(m_aLock);
905 
906     AcceleratorCache& rPrimaryCache   = impl_getCFG(sal_True );
907     AcceleratorCache& rSecondaryCache = impl_getCFG(sal_False);
908 
909 	if (!rPrimaryCache.hasCommand(sCommand) && !rSecondaryCache.hasCommand(sCommand))
910 		throw css::container::NoSuchElementException(
911 				::rtl::OUString(),
912 				static_cast< ::cppu::OWeakObject* >(this));
913 
914 	AcceleratorCache::TKeyList lKeys  = rPrimaryCache.getKeysByCommand(sCommand);
915 
916     AcceleratorCache::TKeyList lSecondaryKeys = rSecondaryCache.getKeysByCommand(sCommand);
917     AcceleratorCache::TKeyList::const_iterator pIt;
918     for (pIt = lSecondaryKeys.begin(); pIt != lSecondaryKeys.end(); ++pIt)
919         lKeys.push_back(*pIt);
920 
921 	return lKeys.getAsConstList();
922 
923 	// <- SAFE ----------------------------------
924 }
925 
926 //-----------------------------------------------
927 AcceleratorCache::TKeyList::const_iterator lcl_getPreferredKey(const AcceleratorCache::TKeyList& lKeys)
928 {
929     AcceleratorCache::TKeyList::const_iterator pIt;
930     for (  pIt  = lKeys.begin ();
931            pIt != lKeys.end   ();
932          ++pIt                  )
933     {
934         const css::awt::KeyEvent& rAWTKey = *pIt;
935         const KeyCode             aVCLKey = ::svt::AcceleratorExecute::st_AWTKey2VCLKey(rAWTKey);
936         const String              sName   = aVCLKey.GetName();
937 
938         if (sName.Len () > 0)
939             return pIt;
940     }
941 
942     return lKeys.end ();
943 }
944 
945 //-----------------------------------------------
946 css::uno::Sequence< css::uno::Any > SAL_CALL XCUBasedAcceleratorConfiguration::getPreferredKeyEventsForCommandList(const css::uno::Sequence< ::rtl::OUString >& lCommandList)
947 	throw(css::lang::IllegalArgumentException   ,
948 		css::uno::RuntimeException            )
949 {
950     // SAFE -> ----------------------------------
951 	ReadGuard aReadLock(m_aLock);
952 
953 	sal_Int32                           i              = 0;
954 	sal_Int32                           c              = lCommandList.getLength();
955 	css::uno::Sequence< css::uno::Any > lPreferredOnes (c); // dont pack list!
956     AcceleratorCache&                   rCache         = impl_getCFG(sal_True);
957 
958 	for (i=0; i<c; ++i)
959 	{
960 		const ::rtl::OUString& rCommand = lCommandList[i];
961 		if (!rCommand.getLength())
962 			throw css::lang::IllegalArgumentException(
963 					::rtl::OUString::createFromAscii("Empty command strings are not allowed here."),
964 					static_cast< ::cppu::OWeakObject* >(this),
965 					(sal_Int16)i);
966 
967 		if (!rCache.hasCommand(rCommand))
968 			continue;
969 
970 		AcceleratorCache::TKeyList lKeys = rCache.getKeysByCommand(rCommand);
971 		if ( lKeys.empty() )
972 			continue;
973 
974 		AcceleratorCache::TKeyList::const_iterator pPreferredKey = lcl_getPreferredKey(lKeys);
975 		if (pPreferredKey != lKeys.end ())
976 		{
977 			css::uno::Any& rAny = lPreferredOnes[i];
978 			rAny <<= *(pPreferredKey);
979 		}
980 	}
981 
982 	aReadLock.unlock();
983 	// <- SAFE ----------------------------------
984 
985 	return lPreferredOnes;
986 }
987 
988 //-----------------------------------------------
989 void SAL_CALL XCUBasedAcceleratorConfiguration::removeCommandFromAllKeyEvents(const ::rtl::OUString& sCommand)
990 	throw(css::lang::IllegalArgumentException   ,
991 		css::container::NoSuchElementException,
992 		css::uno::RuntimeException            )
993 {
994 	if (!sCommand.getLength())
995 		throw css::lang::IllegalArgumentException(
996 				::rtl::OUString::createFromAscii("Empty command strings are not allowed here."),
997 				static_cast< ::cppu::OWeakObject* >(this),
998 				0);
999 
1000 	// SAFE -> ----------------------------------
1001 	WriteGuard aWriteLock(m_aLock);
1002 
1003     AcceleratorCache& rPrimaryCache   = impl_getCFG(sal_True, sal_True );
1004     AcceleratorCache& rSecondaryCache = impl_getCFG(sal_False, sal_True);
1005 
1006 	if (!rPrimaryCache.hasCommand(sCommand) && !rSecondaryCache.hasCommand(sCommand))
1007 		throw css::container::NoSuchElementException(
1008 				::rtl::OUString::createFromAscii("Command does not exists inside this container."),
1009 				static_cast< ::cppu::OWeakObject* >(this));
1010 
1011     if (rPrimaryCache.hasCommand(sCommand))
1012 	    rPrimaryCache.removeCommand(sCommand);
1013     if (rSecondaryCache.hasCommand(sCommand))
1014         rSecondaryCache.removeCommand(sCommand);
1015 
1016 	aWriteLock.unlock();
1017 	// <- SAFE ----------------------------------
1018 }
1019 
1020 //-----------------------------------------------
1021 void SAL_CALL XCUBasedAcceleratorConfiguration::reload()
1022 	throw(css::uno::Exception       ,
1023 		css::uno::RuntimeException)
1024 {
1025     RTL_LOGFILE_PRODUCT_CONTEXT( aLog, "XCUBasedAcceleratorConfiguration::reload()" );
1026 
1027 	// SAFE -> ----------------------------------
1028 	WriteGuard aWriteLock(m_aLock);
1029 
1030     sal_Bool bPreferred;
1031     css::uno::Reference< css::container::XNameAccess > xAccess;
1032 
1033     bPreferred = sal_True;
1034 	m_aPrimaryReadCache = AcceleratorCache();
1035     if (m_pPrimaryWriteCache)
1036     {
1037         // be aware of reentrance problems - use temp variable for calling delete ... :-)
1038         AcceleratorCache* pTemp = m_pPrimaryWriteCache;
1039         m_pPrimaryWriteCache = 0;
1040         delete pTemp;
1041     }
1042     m_xCfg->getByName(CFG_ENTRY_PRIMARY) >>= xAccess;
1043     impl_ts_load(bPreferred, xAccess); // load the preferred keys
1044 
1045     bPreferred = sal_False;
1046 	m_aSecondaryReadCache = AcceleratorCache();
1047     if (m_pSecondaryWriteCache)
1048     {
1049         // be aware of reentrance problems - use temp variable for calling delete ... :-)
1050         AcceleratorCache* pTemp = m_pSecondaryWriteCache;
1051         m_pSecondaryWriteCache = 0;
1052         delete pTemp;
1053     }
1054     m_xCfg->getByName(CFG_ENTRY_SECONDARY) >>= xAccess;
1055     impl_ts_load(bPreferred, xAccess); // load the secondary keys
1056 
1057 	aWriteLock.unlock();
1058 	// <- SAFE ----------------------------------
1059 }
1060 
1061 //-----------------------------------------------
1062 void SAL_CALL XCUBasedAcceleratorConfiguration::store()
1063 	throw(css::uno::Exception       ,
1064 		  css::uno::RuntimeException)
1065 {
1066     RTL_LOGFILE_PRODUCT_CONTEXT( aLog, "XCUBasedAcceleratorConfiguration::store()" );
1067 
1068     // SAFE -> ----------------------------------
1069     ReadGuard aReadLock(m_aLock);
1070 
1071     sal_Bool bPreferred;
1072     css::uno::Reference< css::container::XNameAccess > xAccess;
1073 
1074     bPreferred = sal_True;
1075     // on-demand creation of the primary write cache
1076     impl_getCFG(bPreferred, sal_True);
1077     m_xCfg->getByName(CFG_ENTRY_PRIMARY) >>= xAccess;
1078     impl_ts_save(bPreferred, xAccess);
1079 
1080     bPreferred = sal_False;
1081     // on-demand creation of the secondary write cache
1082     impl_getCFG(bPreferred, sal_True);
1083     m_xCfg->getByName(CFG_ENTRY_SECONDARY) >>= xAccess;
1084     impl_ts_save(bPreferred, xAccess);
1085 
1086     aReadLock.unlock();
1087     // <- SAFE ----------------------------------
1088 }
1089 
1090 //-----------------------------------------------
1091 void SAL_CALL XCUBasedAcceleratorConfiguration::storeToStorage(const css::uno::Reference< css::embed::XStorage >& xStorage)
1092 	throw(css::uno::Exception       ,
1093 	  css::uno::RuntimeException)
1094 {
1095     // use m_aCache + old AcceleratorXMLWriter to store data directly on storage given as parameter ...
1096     if (!xStorage.is())
1097         return;
1098 
1099     long nOpenModes = css::embed::ElementModes::READWRITE;
1100     css::uno::Reference< css::embed::XStorage > xAcceleratorTypeStorage = xStorage->openStorageElement(::rtl::OUString::createFromAscii("accelerator"), nOpenModes);
1101     if (!xAcceleratorTypeStorage.is())
1102         return;
1103 
1104     css::uno::Reference< css::io::XStream > xStream = xAcceleratorTypeStorage->openStreamElement(::rtl::OUString::createFromAscii("current"), nOpenModes);
1105     css::uno::Reference< css::io::XOutputStream > xOut;
1106     if (xStream.is())
1107         xOut = xStream->getOutputStream();
1108     if (!xOut.is())
1109         throw css::io::IOException(
1110         ::rtl::OUString::createFromAscii("Could not open accelerator configuration for saving."),
1111         static_cast< ::cppu::OWeakObject* >(this));
1112 
1113     // the original m_aCache has been split into primay cache and secondary cache...
1114     // we should merge them before storing to storage
1115     // SAFE -> ----------------------------------
1116     WriteGuard aWriteLock(m_aLock);
1117 
1118     AcceleratorCache aCache;
1119     if (m_pPrimaryWriteCache != 0)
1120         aCache.takeOver(*m_pPrimaryWriteCache);
1121     else
1122         aCache.takeOver(m_aPrimaryReadCache);
1123 
1124     AcceleratorCache::TKeyList lKeys;
1125     AcceleratorCache::TKeyList::const_iterator pIt;
1126     if (m_pSecondaryWriteCache!=0)
1127     {
1128         lKeys = m_pSecondaryWriteCache->getAllKeys();
1129         for ( pIt=lKeys.begin(); pIt!=lKeys.end(); ++pIt )
1130             aCache.setKeyCommandPair(*pIt, m_pSecondaryWriteCache->getCommandByKey(*pIt));
1131     }
1132     else
1133     {
1134         lKeys = m_aSecondaryReadCache.getAllKeys();
1135         for ( pIt=lKeys.begin(); pIt!=lKeys.end(); ++pIt )
1136             aCache.setKeyCommandPair(*pIt, m_aSecondaryReadCache.getCommandByKey(*pIt));
1137     }
1138 
1139     aWriteLock.unlock();
1140     // <- SAFE ----------------------------------
1141 
1142     css::uno::Reference< css::io::XTruncate > xClearable(xOut, css::uno::UNO_QUERY_THROW);
1143     xClearable->truncate();
1144     css::uno::Reference< css::io::XSeekable > xSeek(xOut, css::uno::UNO_QUERY);
1145     if (xSeek.is())
1146         xSeek->seek(0);
1147 
1148     css::uno::Reference< css::xml::sax::XDocumentHandler > xWriter    (m_xSMGR->createInstance(SERVICENAME_SAXWRITER), css::uno::UNO_QUERY_THROW);
1149     css::uno::Reference< css::io::XActiveDataSource>       xDataSource(xWriter                                     , css::uno::UNO_QUERY_THROW);
1150     xDataSource->setOutputStream(xOut);
1151 
1152     // write into the stream
1153     AcceleratorConfigurationWriter aWriter(aCache, xWriter);
1154     aWriter.flush();
1155 }
1156 
1157 //-----------------------------------------------
1158 ::sal_Bool SAL_CALL XCUBasedAcceleratorConfiguration::isModified()
1159 	throw(css::uno::RuntimeException)
1160 {
1161 	return sal_False;
1162 }
1163 
1164 //-----------------------------------------------
1165 ::sal_Bool SAL_CALL XCUBasedAcceleratorConfiguration::isReadOnly()
1166 	throw(css::uno::RuntimeException)
1167 {
1168 	return sal_False;
1169 }
1170 
1171 //-----------------------------------------------
1172 void SAL_CALL XCUBasedAcceleratorConfiguration::setStorage(const css::uno::Reference< css::embed::XStorage >& /*xStorage*/)
1173 	throw(css::uno::RuntimeException)
1174 {
1175 	LOG_WARNING("XCUBasedAcceleratorConfiguration::setStorage()", "TODO implement this HACK .-)")
1176 }
1177 
1178 //-----------------------------------------------
1179 ::sal_Bool SAL_CALL XCUBasedAcceleratorConfiguration::hasStorage()
1180 	throw(css::uno::RuntimeException)
1181 {
1182 	LOG_WARNING("XCUBasedAcceleratorConfiguration::hasStorage()", "TODO implement this HACK .-)")
1183 		return sal_False;
1184 }
1185 
1186 //-----------------------------------------------
1187 void SAL_CALL XCUBasedAcceleratorConfiguration::addConfigurationListener(const css::uno::Reference< css::ui::XUIConfigurationListener >& /*xListener*/)
1188 	throw(css::uno::RuntimeException)
1189 {
1190 	LOG_WARNING("XCUBasedAcceleratorConfiguration::addConfigurationListener()", "TODO implement me")
1191 }
1192 
1193 //-----------------------------------------------
1194 void SAL_CALL XCUBasedAcceleratorConfiguration::removeConfigurationListener(const css::uno::Reference< css::ui::XUIConfigurationListener >& /*xListener*/)
1195 	throw(css::uno::RuntimeException)
1196 {
1197 	LOG_WARNING("XCUBasedAcceleratorConfiguration::removeConfigurationListener()", "TODO implement me")
1198 }
1199 
1200 //-----------------------------------------------
1201 void SAL_CALL XCUBasedAcceleratorConfiguration::reset()
1202 	throw(css::uno::RuntimeException)
1203 {
1204 	css::uno::Reference< css::container::XNamed > xNamed(m_xCfg, css::uno::UNO_QUERY);
1205 	::rtl::OUString sConfig = xNamed->getName();
1206 	if ( sConfig.equalsAscii("Global") )
1207 	{
1208 		m_xCfg = css::uno::Reference< css::container::XNameAccess > (
1209 			::comphelper::ConfigurationHelper::openConfig( m_xSMGR, CFG_ENTRY_GLOBAL, ::comphelper::ConfigurationHelper::E_ALL_LOCALES ),
1210 			css::uno::UNO_QUERY );
1211 		XCUBasedAcceleratorConfiguration::reload();
1212 	}
1213 	else if ( sConfig.equalsAscii("Modules") )
1214 	{
1215 		m_xCfg = css::uno::Reference< css::container::XNameAccess > (
1216 			::comphelper::ConfigurationHelper::openConfig( m_xSMGR, CFG_ENTRY_MODULES, ::comphelper::ConfigurationHelper::E_ALL_LOCALES ),
1217 			css::uno::UNO_QUERY );
1218 		XCUBasedAcceleratorConfiguration::reload();
1219 	}
1220 }
1221 
1222 //-----------------------------------------------
1223 void SAL_CALL XCUBasedAcceleratorConfiguration::addResetListener(const css::uno::Reference< css::form::XResetListener >& /*xListener*/)
1224 	throw(css::uno::RuntimeException)
1225 {
1226 	LOG_WARNING("XCUBasedAcceleratorConfiguration::addResetListener()", "TODO implement me")
1227 }
1228 
1229 //-----------------------------------------------
1230 void SAL_CALL XCUBasedAcceleratorConfiguration::removeResetListener(const css::uno::Reference< css::form::XResetListener >& /*xListener*/)
1231 	throw(css::uno::RuntimeException)
1232 {
1233 	LOG_WARNING("XCUBasedAcceleratorConfiguration::removeResetListener()", "TODO implement me")
1234 }
1235 
1236 //-----------------------------------------------
1237 void SAL_CALL XCUBasedAcceleratorConfiguration::changesOccurred(const css::util::ChangesEvent& aEvent)
1238 	throw(css::uno::RuntimeException)
1239 {
1240 	RTL_LOGFILE_PRODUCT_CONTEXT( aLog, "XCUBasedAcceleratorConfiguration::changesOccurred()" );
1241 
1242 	css::uno::Reference< css::container::XHierarchicalNameAccess > xHAccess;
1243 	aEvent.Base >>= xHAccess;
1244 	if (! xHAccess.is ())
1245 		return;
1246 
1247     css::util::ChangesEvent aReceivedEvents( aEvent );
1248     const sal_Int32 c = aReceivedEvents.Changes.getLength();
1249 	      sal_Int32 i = 0;
1250     for (i=0; i<c; ++i)
1251 	{
1252 		const css::util::ElementChange& aChange  =   aReceivedEvents.Changes[i];
1253 
1254         // Only path of form "PrimaryKeys/Modules/Module['<module_name>']/Key['<command_url>']/Command[<locale>]" will
1255         // be interesting for use. Sometimes short path values are given also by the broadcaster ... but they must be ignored :-)
1256         // So we try to split the path into 3 parts (module isnt important here, because we already know it ... because
1257         // these instance is bound to a specific module configuration ... or it''s the global configuration where no module is given at all.
1258 
1259         ::rtl::OUString sOrgPath ;
1260         ::rtl::OUString sPath    ;
1261         ::rtl::OUString sKey;
1262 
1263         aChange.Accessor >>= sOrgPath;
1264         sPath              = sOrgPath;
1265         ::rtl::OUString sPrimarySecondary = ::utl::extractFirstFromConfigurationPath(sPath, &sPath);
1266         ::rtl::OUString sGlobalModules = ::utl::extractFirstFromConfigurationPath(sPath, &sPath);
1267 
1268         if ( sGlobalModules.equals(CFG_ENTRY_GLOBAL) )
1269         {
1270             ::rtl::OUString sModule;
1271             sKey = ::utl::extractFirstFromConfigurationPath(sPath, &sPath);
1272             if (( sKey.getLength() > 0 ) && ( sPath.getLength() > 0 ))
1273                 reloadChanged(sPrimarySecondary, sGlobalModules, sModule, sKey);
1274         }
1275         else if ( sGlobalModules.equals(CFG_ENTRY_MODULES) )
1276         {
1277             ::rtl::OUString sModule = ::utl::extractFirstFromConfigurationPath(sPath, &sPath);
1278             sKey = ::utl::extractFirstFromConfigurationPath(sPath, &sPath);
1279 
1280             if (( sKey.getLength() > 0 ) && ( sPath.getLength() > 0 ))
1281             {
1282                 reloadChanged(sPrimarySecondary, sGlobalModules, sModule, sKey);
1283             }
1284         }
1285 	}
1286 }
1287 
1288 //-----------------------------------------------
1289 void SAL_CALL XCUBasedAcceleratorConfiguration::disposing(const css::lang::EventObject& /*aSource*/)
1290 	throw(css::uno::RuntimeException)
1291 {
1292 }
1293 
1294 //-----------------------------------------------
1295 void XCUBasedAcceleratorConfiguration::impl_ts_load( sal_Bool bPreferred, const css::uno::Reference< css::container::XNameAccess >& xCfg )
1296 {
1297     AcceleratorCache aReadCache = AcceleratorCache();
1298     css::uno::Reference< css::container::XNameAccess > xAccess;
1299     if (m_sGlobalOrModules.equalsAscii("Global"))
1300         xCfg->getByName(CFG_ENTRY_GLOBAL) >>= xAccess;
1301     else if (m_sGlobalOrModules.equalsAscii("Modules"))
1302     {
1303         css::uno::Reference< css::container::XNameAccess > xModules;
1304         xCfg->getByName(CFG_ENTRY_MODULES) >>= xModules;
1305         xModules->getByName(m_sModuleCFG) >>= xAccess;
1306     }
1307 
1308     const ::rtl::OUString sIsoLang       = impl_ts_getLocale().toISO();
1309 	const ::rtl::OUString sDefaultLocale = ::rtl::OUString::createFromAscii("en-US");
1310 
1311     css::uno::Reference< css::container::XNameAccess > xKey;
1312     css::uno::Reference< css::container::XNameAccess > xCommand;
1313     if (xAccess.is())
1314     {
1315         css::uno::Sequence< ::rtl::OUString > lKeys = xAccess->getElementNames();
1316         sal_Int32 nKeys = lKeys.getLength();
1317         for ( sal_Int32 i=0; i<nKeys; ++i )
1318         {
1319             ::rtl::OUString sKey = lKeys[i];
1320             xAccess->getByName(sKey) >>= xKey;
1321             xKey->getByName(CFG_PROP_COMMAND) >>= xCommand;
1322 
1323             css::uno::Sequence< ::rtl::OUString > lLocales = xCommand->getElementNames();
1324             sal_Int32 nLocales = lLocales.getLength();
1325             ::std::vector< ::rtl::OUString > aLocales;
1326             for ( sal_Int32 j=0; j<nLocales; ++j )
1327                 aLocales.push_back(lLocales[j]);
1328 
1329             ::std::vector< ::rtl::OUString >::const_iterator pFound;
1330             for ( pFound = aLocales.begin(); pFound != aLocales.end(); ++pFound )
1331             {
1332                 if ( *pFound == sIsoLang )
1333                     break;
1334             }
1335 
1336             if ( pFound == aLocales.end() )
1337             {
1338                 for ( pFound = aLocales.begin(); pFound != aLocales.end(); ++pFound )
1339                 {
1340                     if ( *pFound == sDefaultLocale )
1341                         break;
1342                 }
1343 
1344                 if ( pFound == aLocales.end() )
1345                     continue;
1346             }
1347 
1348             ::rtl::OUString sLocale = *pFound;
1349             ::rtl::OUString sCommand;
1350             xCommand->getByName(sLocale) >>= sCommand;
1351             if (sCommand.getLength()<1)
1352                 continue;
1353 
1354             css::awt::KeyEvent aKeyEvent;
1355 
1356             sal_Int32 nIndex = 0;
1357             ::rtl::OUString sKeyCommand = sKey.getToken(0, '_', nIndex);
1358             ::rtl::OUString sPrefix = ::rtl::OUString::createFromAscii("KEY_");
1359             aKeyEvent.KeyCode = m_rKeyMapping->mapIdentifierToCode(sPrefix + sKeyCommand);
1360 
1361             css::uno::Sequence< ::rtl::OUString > sToken(4);
1362             const sal_Int32 nToken = 4;
1363             sal_Bool bValid = sal_True;
1364             sal_Int32 k;
1365             for (k=0; k<nToken; ++k)
1366             {
1367                 if (nIndex < 0)
1368                     break;
1369 
1370                 sToken[k] = sKey.getToken(0, '_', nIndex);
1371                 ::rtl::OUString sTest = sToken[k];
1372                 if (sToken[k].getLength() < 1)
1373                 {
1374                     bValid = sal_False;
1375                     break;
1376                 }
1377 
1378                 if (sToken[k].equalsAscii("SHIFT"))
1379                     aKeyEvent.Modifiers |= css::awt::KeyModifier::SHIFT;
1380                 else if (sToken[k].equalsAscii("MOD1"))
1381                     aKeyEvent.Modifiers |= css::awt::KeyModifier::MOD1;
1382                 else if (sToken[k].equalsAscii("MOD2"))
1383                     aKeyEvent.Modifiers |= css::awt::KeyModifier::MOD2;
1384                 else if (sToken[k].equalsAscii("MOD3"))
1385 		            aKeyEvent.Modifiers |= css::awt::KeyModifier::MOD3;
1386                 else
1387                 {
1388                     bValid = sal_False;
1389                     break;
1390                 }
1391             }
1392 
1393             if ( !aReadCache.hasKey(aKeyEvent) && bValid && k<nToken)
1394                 aReadCache.setKeyCommandPair(aKeyEvent, sCommand);
1395         }
1396     }
1397 
1398     if (bPreferred)
1399         m_aPrimaryReadCache.takeOver(aReadCache);
1400     else
1401         m_aSecondaryReadCache.takeOver(aReadCache);
1402 }
1403 
1404 //-----------------------------------------------
1405 void XCUBasedAcceleratorConfiguration::impl_ts_save(sal_Bool bPreferred, const css::uno::Reference< css::container::XNameAccess >& /*xCfg*/)
1406 {
1407     if (bPreferred)
1408     {
1409         AcceleratorCache::TKeyList::const_iterator pIt;
1410         AcceleratorCache::TKeyList lPrimaryReadKeys  = m_aPrimaryReadCache.getAllKeys();
1411         AcceleratorCache::TKeyList lPrimaryWriteKeys = m_pPrimaryWriteCache->getAllKeys();
1412 
1413         for ( pIt  = lPrimaryReadKeys.begin(); pIt != lPrimaryReadKeys.end(); ++pIt )
1414         {
1415             if (!m_pPrimaryWriteCache->hasKey(*pIt))
1416                 removeKeyFromConfiguration(*pIt, sal_True);
1417         }
1418 
1419         for ( pIt  = lPrimaryWriteKeys.begin(); pIt != lPrimaryWriteKeys.end(); ++pIt )
1420         {
1421             ::rtl::OUString sCommand = m_pPrimaryWriteCache->getCommandByKey(*pIt);
1422             if (!m_aPrimaryReadCache.hasKey(*pIt))
1423             {
1424                 insertKeyToConfiguration(*pIt, sCommand, sal_True);
1425             }
1426             else
1427             {
1428                 ::rtl::OUString sReadCommand = m_aPrimaryReadCache.getCommandByKey(*pIt);
1429                 if (sReadCommand != sCommand)
1430                     insertKeyToConfiguration(*pIt, sCommand, sal_True);
1431             }
1432         }
1433 
1434         // take over all changes into the original container
1435         // SAFE -> ----------------------------------
1436         WriteGuard aWriteLock(m_aLock);
1437 
1438         if (m_pPrimaryWriteCache)
1439         {
1440             m_aPrimaryReadCache.takeOver(*m_pPrimaryWriteCache);
1441             AcceleratorCache* pTemp = m_pPrimaryWriteCache;
1442             m_pPrimaryWriteCache = 0;
1443             delete pTemp;
1444         }
1445 
1446         aWriteLock.unlock();
1447         // <- SAFE ----------------------------------
1448     }
1449 
1450     else
1451     {
1452         AcceleratorCache::TKeyList::const_iterator pIt;
1453         AcceleratorCache::TKeyList lSecondaryReadKeys  = m_aSecondaryReadCache.getAllKeys();
1454         AcceleratorCache::TKeyList lSecondaryWriteKeys = m_pSecondaryWriteCache->getAllKeys();
1455 
1456         for ( pIt  = lSecondaryReadKeys.begin(); pIt != lSecondaryReadKeys.end(); ++pIt)
1457         {
1458             if (!m_pSecondaryWriteCache->hasKey(*pIt))
1459                 removeKeyFromConfiguration(*pIt, sal_False);
1460         }
1461 
1462 
1463         for ( pIt  = lSecondaryWriteKeys.begin(); pIt != lSecondaryWriteKeys.end(); ++pIt )
1464         {
1465             ::rtl::OUString sCommand = m_pSecondaryWriteCache->getCommandByKey(*pIt);
1466             if (!m_aSecondaryReadCache.hasKey(*pIt))
1467             {
1468                 insertKeyToConfiguration(*pIt, sCommand, sal_False);
1469             }
1470             else
1471             {
1472                 ::rtl::OUString sReadCommand = m_aSecondaryReadCache.getCommandByKey(*pIt);
1473                 if (sReadCommand != sCommand)
1474                     insertKeyToConfiguration(*pIt, sCommand, sal_False);
1475             }
1476         }
1477 
1478         // take over all changes into the original container
1479         // SAFE -> ----------------------------------
1480         WriteGuard aWriteLock(m_aLock);
1481 
1482         if (m_pSecondaryWriteCache)
1483         {
1484             m_aSecondaryReadCache.takeOver(*m_pSecondaryWriteCache);
1485             AcceleratorCache* pTemp = m_pSecondaryWriteCache;
1486             m_pSecondaryWriteCache = 0;
1487             delete pTemp;
1488         }
1489 
1490         aWriteLock.unlock();
1491         // <- SAFE ----------------------------------
1492     }
1493 
1494     ::comphelper::ConfigurationHelper::flush(m_xCfg);
1495 }
1496 
1497 //-----------------------------------------------
1498 void XCUBasedAcceleratorConfiguration::insertKeyToConfiguration( const css::awt::KeyEvent& aKeyEvent, const ::rtl::OUString& sCommand, const sal_Bool bPreferred )
1499 {
1500     css::uno::Reference< css::container::XNameAccess > xAccess;
1501     css::uno::Reference< css::container::XNameContainer > xContainer;
1502     css::uno::Reference< css::lang::XSingleServiceFactory > xFac;
1503 	css::uno::Reference< css::uno::XInterface > xInst;
1504 
1505     if ( bPreferred )
1506         m_xCfg->getByName(CFG_ENTRY_PRIMARY) >>= xAccess;
1507     else
1508         m_xCfg->getByName(CFG_ENTRY_SECONDARY) >>= xAccess;
1509 
1510 	if ( m_sGlobalOrModules.equals(CFG_ENTRY_GLOBAL) )
1511 		xAccess->getByName(CFG_ENTRY_GLOBAL) >>= xContainer;
1512 	else if ( m_sGlobalOrModules.equals(CFG_ENTRY_MODULES) )
1513     {
1514         css::uno::Reference< css::container::XNameContainer > xModules;
1515 		xAccess->getByName(CFG_ENTRY_MODULES) >>= xModules;
1516         if ( !xModules->hasByName(m_sModuleCFG) )
1517         {
1518             xFac = css::uno::Reference< css::lang::XSingleServiceFactory >(xModules, css::uno::UNO_QUERY);
1519             xInst = xFac->createInstance();
1520             xModules->insertByName(m_sModuleCFG, css::uno::makeAny(xInst));
1521         }
1522         xModules->getByName(m_sModuleCFG) >>= xContainer;
1523     }
1524 
1525     const ::rtl::OUString sKey = lcl_getKeyString(m_rKeyMapping,aKeyEvent);
1526 	css::uno::Reference< css::container::XNameAccess > xKey;
1527 	css::uno::Reference< css::container::XNameContainer > xCommand;
1528 	if ( !xContainer->hasByName(sKey) )
1529 	{
1530 		xFac = css::uno::Reference< css::lang::XSingleServiceFactory >(xContainer, css::uno::UNO_QUERY);
1531 		xInst = xFac->createInstance();
1532 		xContainer->insertByName(sKey, css::uno::makeAny(xInst));
1533 	}
1534 	xContainer->getByName(sKey) >>= xKey;
1535 
1536     xKey->getByName(CFG_PROP_COMMAND) >>= xCommand;
1537 	::rtl::OUString sLocale = impl_ts_getLocale().toISO();
1538 	if ( !xCommand->hasByName(sLocale) )
1539 		xCommand->insertByName(sLocale, css::uno::makeAny(sCommand));
1540 	else
1541 		xCommand->replaceByName(sLocale, css::uno::makeAny(sCommand));
1542 }
1543 
1544 //-----------------------------------------------
1545 void XCUBasedAcceleratorConfiguration::removeKeyFromConfiguration( const css::awt::KeyEvent& aKeyEvent, const sal_Bool bPreferred )
1546 {
1547     css::uno::Reference< css::container::XNameAccess > xAccess;
1548     css::uno::Reference< css::container::XNameContainer > xContainer;
1549 
1550     if ( bPreferred )
1551         m_xCfg->getByName(CFG_ENTRY_PRIMARY) >>= xAccess;
1552     else
1553         m_xCfg->getByName(CFG_ENTRY_SECONDARY) >>= xAccess;
1554 
1555 	if ( m_sGlobalOrModules.equals(CFG_ENTRY_GLOBAL) )
1556 		xAccess->getByName(CFG_ENTRY_GLOBAL) >>= xContainer;
1557 	else if ( m_sGlobalOrModules.equals(CFG_ENTRY_MODULES) )
1558     {
1559         css::uno::Reference< css::container::XNameAccess > xModules;
1560 		xAccess->getByName(CFG_ENTRY_MODULES) >>= xModules;
1561         if ( !xModules->hasByName(m_sModuleCFG) )
1562             return;
1563         xModules->getByName(m_sModuleCFG) >>= xContainer;
1564     }
1565 
1566     const ::rtl::OUString sKey = lcl_getKeyString(m_rKeyMapping,aKeyEvent);
1567 	xContainer->removeByName(sKey);
1568 }
1569 
1570 //-----------------------------------------------
1571 void XCUBasedAcceleratorConfiguration::reloadChanged( const ::rtl::OUString& sPrimarySecondary, const ::rtl::OUString& sGlobalModules, const ::rtl::OUString& sModule, const ::rtl::OUString& sKey )
1572 {
1573     css::uno::Reference< css::container::XNameAccess > xAccess;
1574     css::uno::Reference< css::container::XNameContainer > xContainer;
1575 
1576     m_xCfg->getByName(sPrimarySecondary) >>= xAccess;
1577 	if ( sGlobalModules.equals(CFG_ENTRY_GLOBAL) )
1578 		xAccess->getByName(CFG_ENTRY_GLOBAL) >>= xContainer;
1579 	else
1580     {
1581         css::uno::Reference< css::container::XNameAccess > xModules;
1582 		xAccess->getByName(CFG_ENTRY_MODULES) >>= xModules;
1583         if ( !xModules->hasByName(sModule) )
1584             return;
1585         xModules->getByName(sModule) >>= xContainer;
1586     }
1587 
1588 	css::awt::KeyEvent aKeyEvent;
1589 	::rtl::OUString sKeyIdentifier;
1590 
1591 	sal_Int32 nIndex = 0;
1592 	sKeyIdentifier = sKey.getToken(0, '_', nIndex);
1593 	aKeyEvent.KeyCode = m_rKeyMapping->mapIdentifierToCode(::rtl::OUString::createFromAscii("KEY_")+sKeyIdentifier);
1594 
1595 	css::uno::Sequence< ::rtl::OUString > sToken(3);
1596 	const sal_Int32 nToken = 3;
1597 	for (sal_Int32 i=0; i<nToken; ++i)
1598 	{
1599 		if ( nIndex < 0 )
1600 			break;
1601 
1602 		sToken[i] = sKey.getToken(0, '_', nIndex);
1603 		if (sToken[i].equalsAscii("SHIFT"))
1604 			aKeyEvent.Modifiers |= css::awt::KeyModifier::SHIFT;
1605 		else if (sToken[i].equalsAscii("MOD1"))
1606 			aKeyEvent.Modifiers |= css::awt::KeyModifier::MOD1;
1607 		else if (sToken[i].equalsAscii("MOD2"))
1608 			aKeyEvent.Modifiers |= css::awt::KeyModifier::MOD2;
1609                 else if (sToken[i].equalsAscii("MOD3"))
1610                         aKeyEvent.Modifiers |= css::awt::KeyModifier::MOD3;
1611 	}
1612 
1613 	css::uno::Reference< css::container::XNameAccess > xKey;
1614 	css::uno::Reference< css::container::XNameAccess > xCommand;
1615 	::rtl::OUString sCommand;
1616 
1617 	if (xContainer->hasByName(sKey))
1618 	{
1619 		::rtl::OUString sLocale = impl_ts_getLocale().toISO();
1620 		xContainer->getByName(sKey)    >>= xKey;
1621 		xKey->getByName(CFG_PROP_COMMAND)  >>= xCommand;
1622 		xCommand->getByName(sLocale)       >>= sCommand;
1623 	}
1624 
1625     if (sPrimarySecondary.equals(CFG_ENTRY_PRIMARY))
1626     {
1627         if (sCommand.getLength() ==0)
1628             m_aPrimaryReadCache.removeKey(aKeyEvent);
1629         else
1630 	        m_aPrimaryReadCache.setKeyCommandPair(aKeyEvent, sCommand);
1631     }
1632     else if (sPrimarySecondary.equals(CFG_ENTRY_SECONDARY))
1633     {
1634         if (sCommand.getLength() ==0)
1635             m_aSecondaryReadCache.removeKey(aKeyEvent);
1636         else
1637             m_aSecondaryReadCache.setKeyCommandPair(aKeyEvent, sCommand);
1638     }
1639 }
1640 
1641 //-----------------------------------------------
1642 AcceleratorCache& XCUBasedAcceleratorConfiguration::impl_getCFG(sal_Bool bPreferred, sal_Bool bWriteAccessRequested)
1643 {
1644     // SAFE -> ----------------------------------
1645     WriteGuard aWriteLock(m_aLock);
1646 
1647     if (bPreferred)
1648     {
1649         //create copy of our readonly-cache, if write access is forced ... but
1650         //not still possible!
1651         if (
1652             (bWriteAccessRequested) &&
1653             (!m_pPrimaryWriteCache       )
1654             )
1655         {
1656             m_pPrimaryWriteCache = new AcceleratorCache(m_aPrimaryReadCache);
1657         }
1658 
1659         // in case, we have a writeable cache, we use it for reading too!
1660         // Otherwhise the API user cant find its own changes ...
1661         if (m_pPrimaryWriteCache)
1662             return *m_pPrimaryWriteCache;
1663         else
1664             return m_aPrimaryReadCache;
1665     }
1666 
1667     else
1668     {
1669         //create copy of our readonly-cache, if write access is forced ... but
1670         //not still possible!
1671         if (
1672             (bWriteAccessRequested) &&
1673             (!m_pSecondaryWriteCache       )
1674             )
1675         {
1676             m_pSecondaryWriteCache = new AcceleratorCache(m_aSecondaryReadCache);
1677         }
1678 
1679         // in case, we have a writeable cache, we use it for reading too!
1680         // Otherwhise the API user cant find its own changes ...
1681         if (m_pSecondaryWriteCache)
1682             return *m_pSecondaryWriteCache;
1683         else
1684             return m_aSecondaryReadCache;
1685     }
1686 
1687 	// <- SAFE ----------------------------------
1688 }
1689 
1690 //-----------------------------------------------
1691 ::comphelper::Locale XCUBasedAcceleratorConfiguration::impl_ts_getLocale() const
1692 {
1693 	static ::rtl::OUString LOCALE_PACKAGE = ::rtl::OUString::createFromAscii("/org.openoffice.Setup");
1694 	static ::rtl::OUString LOCALE_PATH    = ::rtl::OUString::createFromAscii("L10N"                 );
1695 	static ::rtl::OUString LOCALE_KEY     = ::rtl::OUString::createFromAscii("ooLocale"             );
1696 
1697 	// SAFE -> ----------------------------------
1698 	ReadGuard aReadLock(m_aLock);
1699 	css::uno::Reference< css::lang::XMultiServiceFactory > xSMGR = m_xSMGR;
1700 	aReadLock.unlock();
1701 	// <- SAFE ----------------------------------
1702 
1703 	css::uno::Reference< css::uno::XInterface >     xCFG      = fpc::ConfigurationHelper::openConfig(xSMGR, LOCALE_PACKAGE, LOCALE_PATH, fpc::ConfigurationHelper::E_READONLY);
1704 	css::uno::Reference< css::beans::XPropertySet > xProp     (xCFG, css::uno::UNO_QUERY_THROW);
1705 	::rtl::OUString                                 sISOLocale;
1706 	xProp->getPropertyValue(LOCALE_KEY) >>= sISOLocale;
1707 
1708 	if (!sISOLocale.getLength())
1709 		return ::comphelper::Locale::EN_US();
1710 	return ::comphelper::Locale(sISOLocale);
1711 }
1712 
1713 } // namespace framework
1714