xref: /aoo42x/main/linguistic/source/lngsvcmgr.cxx (revision cdf0e10c)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_linguistic.hxx"
30 
31 #include <com/sun/star/registry/XRegistryKey.hpp>
32 #include <com/sun/star/container/XContentEnumerationAccess.hpp>
33 #include <com/sun/star/container/XEnumeration.hpp>
34 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
35 #include <com/sun/star/linguistic2/XSupportedLocales.hpp>
36 #include <com/sun/star/linguistic2/DictionaryListEventFlags.hpp>
37 #include <com/sun/star/linguistic2/LinguServiceEventFlags.hpp>
38 
39 #include <tools/solar.h>
40 #include <unotools/lingucfg.hxx>
41 #include <unotools/processfactory.hxx>
42 #include <i18npool/lang.h>
43 #include <i18npool/mslangid.hxx>
44 #include <cppuhelper/factory.hxx>
45 #include <comphelper/extract.hxx>
46 #include <rtl/logfile.hxx>
47 
48 #include <boost/checked_delete.hpp>
49 
50 #include "lngsvcmgr.hxx"
51 #include "lngopt.hxx"
52 #include "linguistic/misc.hxx"
53 #include "spelldsp.hxx"
54 #include "hyphdsp.hxx"
55 #include "thesdsp.hxx"
56 #include "gciterator.hxx"
57 
58 
59 using namespace com::sun::star;
60 using namespace linguistic;
61 using ::rtl::OUString;
62 
63 // forward declarations
64 uno::Sequence< OUString > static GetLangSvcList( const uno::Any &rVal );
65 uno::Sequence< OUString > static GetLangSvc( const uno::Any &rVal );
66 
67 ///////////////////////////////////////////////////////////////////////////
68 
69 static sal_Bool lcl_SeqHasString( const uno::Sequence< OUString > &rSeq, const OUString &rText )
70 {
71     sal_Bool bRes = sal_False;
72 
73     sal_Int32 nLen = rSeq.getLength();
74     if (nLen == 0 || rText.getLength() == 0)
75         return bRes;
76 
77     const OUString *pSeq = rSeq.getConstArray();
78     for (sal_Int32 i = 0;  i < nLen  &&  !bRes;  ++i)
79     {
80         if (rText == pSeq[i])
81             bRes = sal_True;
82     }
83     return bRes;
84 }
85 
86 ///////////////////////////////////////////////////////////////////////////
87 
88 static uno::Sequence< lang::Locale > GetAvailLocales(
89         const uno::Sequence< OUString > &rSvcImplNames )
90 {
91     uno::Sequence< lang::Locale > aRes;
92 
93     uno::Reference< lang::XMultiServiceFactory >  xFac( utl::getProcessServiceFactory() );
94 	sal_Int32 nNames = rSvcImplNames.getLength();
95 	if (nNames  &&  xFac.is())
96 	{
97         std::set< LanguageType > aLanguages;
98 
99 		//! since we're going to create one-instance services we have to
100 		//! supply their arguments even if we would not need them here...
101         uno::Sequence< uno::Any > aArgs(2);
102 		aArgs.getArray()[0] <<= GetLinguProperties();
103 
104 		// check all services for the supported languages and new
105 		// languages to the result
106 		const OUString *pImplNames = rSvcImplNames.getConstArray();
107 		sal_Int32 i;
108 
109 		for (i = 0;  i < nNames;  ++i)
110 		{
111             uno::Reference< linguistic2::XSupportedLocales > xSuppLoc;
112 			try
113 			{
114                 xSuppLoc = uno::Reference< linguistic2::XSupportedLocales >(
115                         xFac->createInstanceWithArguments( pImplNames[i], aArgs ), uno::UNO_QUERY );
116 			}
117             catch (uno::Exception &)
118 			{
119                 DBG_ASSERT( 0, "createInstanceWithArguments failed" );
120 			}
121 
122 			if (xSuppLoc.is())
123 			{
124                 uno::Sequence< lang::Locale > aLoc( xSuppLoc->getLocales() );
125 				sal_Int32 nLoc = aLoc.getLength();
126 				for (sal_Int32 k = 0;  k < nLoc;  ++k)
127 				{
128                     const lang::Locale *pLoc = aLoc.getConstArray();
129                     LanguageType nLang = LocaleToLanguage( pLoc[k] );
130 
131 					// language not already added?
132                     if (aLanguages.find( nLang ) == aLanguages.end())
133                         aLanguages.insert( nLang );
134 				}
135 			}
136             else
137             {
138                 DBG_ASSERT( 0, "interface not supported by service" );
139             }
140 		}
141 
142         // build return sequence
143         sal_Int32 nLanguages = static_cast< sal_Int32 >(aLanguages.size());
144 		aRes.realloc( nLanguages );
145         lang::Locale *pRes = aRes.getArray();
146         std::set< LanguageType >::const_iterator aIt( aLanguages.begin() );
147         for (i = 0;  aIt != aLanguages.end();  ++aIt, ++i)
148 		{
149             LanguageType nLang = *aIt;
150 			pRes[i] = CreateLocale( nLang );
151 		}
152 	}
153 
154 	return aRes;
155 }
156 
157 ///////////////////////////////////////////////////////////////////////////
158 
159 struct SvcInfo
160 {
161     const OUString                  aSvcImplName;
162     const uno::Sequence< sal_Int16 >    aSuppLanguages;
163 
164     SvcInfo( const OUString &rSvcImplName,
165              const uno::Sequence< sal_Int16 >  &rSuppLanguages ) :
166 		aSvcImplName	(rSvcImplName),
167 		aSuppLanguages	(rSuppLanguages)
168 	{
169 	}
170 
171     sal_Bool    HasLanguage( sal_Int16 nLanguage ) const;
172 };
173 
174 
175 sal_Bool SvcInfo::HasLanguage( sal_Int16 nLanguage ) const
176 {
177 	sal_Int32 nCnt = aSuppLanguages.getLength();
178     const sal_Int16 *pLang = aSuppLanguages.getConstArray();
179 	sal_Int32 i;
180 
181 	for ( i = 0;  i < nCnt;  ++i)
182 	{
183 		if (nLanguage == pLang[i])
184 			break;
185 	}
186 	return i < nCnt;
187 }
188 
189 
190 ///////////////////////////////////////////////////////////////////////////
191 
192 
193 void LngSvcMgr::SetAvailableCfgServiceLists( LinguDispatcher &rDispatcher,
194 		const SvcInfoArray &rAvailSvcs )
195 {
196 	// get list of nodenames to look at for their service list
197 	const char *pEntryName = 0;
198 	sal_Bool bHasLangSvcList = sal_True;
199 	switch (rDispatcher.GetDspType())
200 	{
201         case LinguDispatcher::DSP_SPELL     : pEntryName = "ServiceManager/SpellCheckerList";    break;
202         case LinguDispatcher::DSP_GRAMMAR   : pEntryName = "ServiceManager/GrammarCheckerList";
203                                               bHasLangSvcList = sal_False;
204                                               break;
205         case LinguDispatcher::DSP_HYPH      : pEntryName = "ServiceManager/HyphenatorList";
206                                               bHasLangSvcList = sal_False;
207                                               break;
208         case LinguDispatcher::DSP_THES      : pEntryName = "ServiceManager/ThesaurusList";  break;
209 		default :
210             DBG_ASSERT( 0, "unexpected case" );
211 	}
212 	String	aNode( String::CreateFromAscii( pEntryName ) );
213     uno::Sequence < OUString > aNodeNames( /*aCfg.*/GetNodeNames( aNode ) );
214 
215 
216 	sal_Int32 nLen = aNodeNames.getLength();
217 	const OUString *pNodeNames = aNodeNames.getConstArray();
218 	for (sal_Int32 i = 0;  i < nLen;  ++i)
219 	{
220         uno::Sequence< OUString >   aSvcImplNames;
221 
222         uno::Sequence< OUString >    aNames( 1 );
223         OUString *pNames = aNames.getArray();
224 
225 		OUString aPropName( aNode );
226 		aPropName += OUString::valueOf( (sal_Unicode) '/' );
227 		aPropName += pNodeNames[i];
228 		pNames[0] = aPropName;
229 
230         uno::Sequence< uno::Any > aValues = /*aCfg.*/GetProperties( aNames );
231 		if (aValues.getLength())
232 		{
233 			// get list of configured service names for the
234 			// current node (language)
235             const uno::Any &rValue = aValues.getConstArray()[0];
236 			if (bHasLangSvcList)
237 				aSvcImplNames = GetLangSvcList( rValue );
238 			else
239 				aSvcImplNames = GetLangSvc( rValue );
240 
241 			sal_Int32 nSvcs = aSvcImplNames.getLength();
242 			if (nSvcs)
243 			{
244 				const OUString *pImplNames = aSvcImplNames.getConstArray();
245 
246                 LanguageType nLang = MsLangId::convertIsoStringToLanguage( pNodeNames[i] );
247 
248 				// build list of available services from those
249 				sal_Int32 nCnt = 0;
250                 uno::Sequence< OUString > aAvailSvcs( nSvcs );
251 				OUString *pAvailSvcs = aAvailSvcs.getArray();
252 				for (sal_Int32 k = 0;  k < nSvcs;  ++k)
253 				{
254 					// check for availability of the service
255                     size_t nAvailSvcs = rAvailSvcs.size();
256                     for (size_t m = 0;  m < nAvailSvcs;  ++m)
257 					{
258 						const SvcInfo &rSvcInfo = *rAvailSvcs[m];
259 						if (rSvcInfo.aSvcImplName == pImplNames[k]  &&
260 							rSvcInfo.HasLanguage( nLang ))
261 						{
262 							pAvailSvcs[ nCnt++ ] = rSvcInfo.aSvcImplName;
263 							break;
264 						}
265 					}
266 				}
267 
268 				if (nCnt)
269 				{
270 					aAvailSvcs.realloc( nCnt );
271 					rDispatcher.SetServiceList( CreateLocale( nLang ), aAvailSvcs );
272 				}
273 			}
274 		}
275 	}
276 }
277 
278 
279 ///////////////////////////////////////////////////////////////////////////
280 
281 
282 class LngSvcMgrListenerHelper :
283 	public cppu::WeakImplHelper2
284 	<
285         linguistic2::XLinguServiceEventListener,
286         linguistic2::XDictionaryListEventListener
287 	>
288 {
289     LngSvcMgr  &rMyManager;
290 //    Timer       aLaunchTimer;
291 
292 	//cppu::OMultiTypeInterfaceContainerHelper	aListeners;
293 	::cppu::OInterfaceContainerHelper			aLngSvcMgrListeners;
294 	::cppu::OInterfaceContainerHelper			aLngSvcEvtBroadcasters;
295     uno::Reference< linguistic2::XDictionaryList >               xDicList;
296     uno::Reference< uno::XInterface >                        xMyEvtObj;
297 
298 	sal_Int16	nCombinedLngSvcEvt;
299 
300 	// disallow copy-constructor and assignment-operator for now
301 	LngSvcMgrListenerHelper(const LngSvcMgrListenerHelper &);
302 	LngSvcMgrListenerHelper & operator = (const LngSvcMgrListenerHelper &);
303 
304 	void	LaunchEvent( sal_Int16 nLngSvcEvtFlags );
305 
306 //	DECL_LINK( TimeOut, Timer* );
307 	long Timeout();
308 
309 public:
310     LngSvcMgrListenerHelper( LngSvcMgr &rLngSvcMgr,
311             const uno::Reference< uno::XInterface > &rxSource,
312             const uno::Reference< linguistic2::XDictionaryList > &rxDicList );
313 
314     // lang::XEventListener
315 	virtual void SAL_CALL
316         disposing( const lang::EventObject& rSource )
317             throw(uno::RuntimeException);
318 
319     // linguistic2::XLinguServiceEventListener
320     virtual void SAL_CALL
321         processLinguServiceEvent( const linguistic2::LinguServiceEvent& aLngSvcEvent )
322             throw(uno::RuntimeException);
323 
324     // linguistic2::XDictionaryListEventListener
325     virtual void SAL_CALL
326 		processDictionaryListEvent(
327                 const linguistic2::DictionaryListEvent& rDicListEvent )
328             throw(uno::RuntimeException);
329 
330 	inline	sal_Bool	AddLngSvcMgrListener(
331                         const uno::Reference< lang::XEventListener >& rxListener );
332 	inline	sal_Bool    RemoveLngSvcMgrListener(
333                         const uno::Reference< lang::XEventListener >& rxListener );
334     void    DisposeAndClear( const lang::EventObject &rEvtObj );
335 	sal_Bool	AddLngSvcEvtBroadcaster(
336                         const uno::Reference< linguistic2::XLinguServiceEventBroadcaster > &rxBroadcaster );
337 	sal_Bool	RemoveLngSvcEvtBroadcaster(
338                         const uno::Reference< linguistic2::XLinguServiceEventBroadcaster > &rxBroadcaster );
339 
340     void    AddLngSvcEvt( sal_Int16 nLngSvcEvt );
341 };
342 
343 
344 LngSvcMgrListenerHelper::LngSvcMgrListenerHelper(
345         LngSvcMgr &rLngSvcMgr,
346         const uno::Reference< uno::XInterface > &rxSource,
347         const uno::Reference< linguistic2::XDictionaryList > &rxDicList  ) :
348     rMyManager              ( rLngSvcMgr ),
349 	aLngSvcMgrListeners		( GetLinguMutex() ),
350 	aLngSvcEvtBroadcasters	( GetLinguMutex() ),
351 	xDicList				( rxDicList ),
352 	xMyEvtObj				( rxSource )
353 {
354 	if (xDicList.is())
355 	{
356 		xDicList->addDictionaryListEventListener(
357             (linguistic2::XDictionaryListEventListener *) this, sal_False );
358 	}
359 
360 	//! The timer is used to 'sum up' different events in order to reduce the
361 	//! number of events forwarded.
362 	//! (This may happen already if a property was changed that has several
363 	//! listeners, and each of them is launching an event of it's own!)
364 	//! Thus this behaviour is necessary to avoid unecessary actions of
365 	//! this objects listeners!
366 //	aLaunchTimer.SetTimeout( 2000 );
367 //	aLaunchTimer.SetTimeoutHdl( LINK( this, LngSvcMgrListenerHelper, TimeOut ) );
368 	nCombinedLngSvcEvt = 0;
369 }
370 
371 
372 void SAL_CALL LngSvcMgrListenerHelper::disposing( const lang::EventObject& rSource )
373         throw(uno::RuntimeException)
374 {
375     osl::MutexGuard aGuard( GetLinguMutex() );
376 
377     uno::Reference< uno::XInterface > xRef( rSource.Source );
378 	if ( xRef.is() )
379 	{
380 		aLngSvcMgrListeners   .removeInterface( xRef );
381 		aLngSvcEvtBroadcasters.removeInterface( xRef );
382 		if (xDicList == xRef)
383 			xDicList = 0;
384 	}
385 }
386 
387 
388 //IMPL_LINK( LngSvcMgrListenerHelper, TimeOut, Timer*, pTimer )
389 long LngSvcMgrListenerHelper::Timeout()
390 {
391     osl::MutexGuard aGuard( GetLinguMutex() );
392 
393 //	if (&aLaunchTimer == pTimer)
394 	{
395 		// change event source to LinguServiceManager since the listeners
396 		// probably do not know (and need not to know) about the specific
397 		// SpellChecker's or Hyphenator's.
398         linguistic2::LinguServiceEvent aEvtObj( xMyEvtObj, nCombinedLngSvcEvt );
399 		nCombinedLngSvcEvt = 0;
400 
401         if (rMyManager.pSpellDsp)
402             rMyManager.pSpellDsp->FlushSpellCache();
403 
404         // pass event on to linguistic2::XLinguServiceEventListener's
405 		cppu::OInterfaceIteratorHelper aIt( aLngSvcMgrListeners );
406 		while (aIt.hasMoreElements())
407 		{
408             uno::Reference< linguistic2::XLinguServiceEventListener > xRef( aIt.next(), uno::UNO_QUERY );
409 			if (xRef.is())
410 				xRef->processLinguServiceEvent( aEvtObj );
411 		}
412 	}
413 	return 0;
414 }
415 
416 
417 void LngSvcMgrListenerHelper::AddLngSvcEvt( sal_Int16 nLngSvcEvt )
418 {
419     nCombinedLngSvcEvt |= nLngSvcEvt;
420 //	aLaunchTimer.Start();
421 	Timeout();
422 }
423 
424 
425 void SAL_CALL
426 	LngSvcMgrListenerHelper::processLinguServiceEvent(
427             const linguistic2::LinguServiceEvent& rLngSvcEvent )
428         throw(uno::RuntimeException)
429 {
430     osl::MutexGuard aGuard( GetLinguMutex() );
431     AddLngSvcEvt( rLngSvcEvent.nEvent );
432 }
433 
434 
435 void SAL_CALL
436 	LngSvcMgrListenerHelper::processDictionaryListEvent(
437             const linguistic2::DictionaryListEvent& rDicListEvent )
438         throw(uno::RuntimeException)
439 {
440     osl::MutexGuard aGuard( GetLinguMutex() );
441 
442 	sal_Int16 nDlEvt = rDicListEvent.nCondensedEvent;
443 	if (0 == nDlEvt)
444 		return;
445 
446 	// we do keep the original event source here though...
447 
448     // pass event on to linguistic2::XDictionaryListEventListener's
449 	cppu::OInterfaceIteratorHelper aIt( aLngSvcMgrListeners );
450 	while (aIt.hasMoreElements())
451 	{
452         uno::Reference< linguistic2::XDictionaryListEventListener > xRef( aIt.next(), uno::UNO_QUERY );
453 		if (xRef.is())
454 			xRef->processDictionaryListEvent( rDicListEvent );
455 	}
456 
457 	//
458     // "translate" DictionaryList event into linguistic2::LinguServiceEvent
459 	//
460 	sal_Int16 nLngSvcEvt = 0;
461 	//
462 	sal_Int16 nSpellCorrectFlags =
463             linguistic2::DictionaryListEventFlags::ADD_NEG_ENTRY        |
464             linguistic2::DictionaryListEventFlags::DEL_POS_ENTRY        |
465             linguistic2::DictionaryListEventFlags::ACTIVATE_NEG_DIC |
466             linguistic2::DictionaryListEventFlags::DEACTIVATE_POS_DIC;
467 	if (0 != (nDlEvt & nSpellCorrectFlags))
468         nLngSvcEvt |= linguistic2::LinguServiceEventFlags::SPELL_CORRECT_WORDS_AGAIN;
469 	//
470 	sal_Int16 nSpellWrongFlags =
471             linguistic2::DictionaryListEventFlags::ADD_POS_ENTRY        |
472             linguistic2::DictionaryListEventFlags::DEL_NEG_ENTRY        |
473             linguistic2::DictionaryListEventFlags::ACTIVATE_POS_DIC |
474             linguistic2::DictionaryListEventFlags::DEACTIVATE_NEG_DIC;
475 	if (0 != (nDlEvt & nSpellWrongFlags))
476         nLngSvcEvt |= linguistic2::LinguServiceEventFlags::SPELL_WRONG_WORDS_AGAIN;
477 	//
478 	sal_Int16 nHyphenateFlags =
479             linguistic2::DictionaryListEventFlags::ADD_POS_ENTRY        |
480             linguistic2::DictionaryListEventFlags::DEL_POS_ENTRY        |
481             linguistic2::DictionaryListEventFlags::ACTIVATE_POS_DIC |
482             linguistic2::DictionaryListEventFlags::ACTIVATE_NEG_DIC;
483 	if (0 != (nDlEvt & nHyphenateFlags))
484         nLngSvcEvt |= linguistic2::LinguServiceEventFlags::HYPHENATE_AGAIN;
485 
486     if (rMyManager.pSpellDsp)
487         rMyManager.pSpellDsp->FlushSpellCache();
488 	if (nLngSvcEvt)
489 		LaunchEvent( nLngSvcEvt );
490 }
491 
492 
493 void LngSvcMgrListenerHelper::LaunchEvent( sal_Int16 nLngSvcEvtFlags )
494 {
495     linguistic2::LinguServiceEvent aEvt( xMyEvtObj, nLngSvcEvtFlags );
496 
497     // pass event on to linguistic2::XLinguServiceEventListener's
498 	cppu::OInterfaceIteratorHelper aIt( aLngSvcMgrListeners );
499 	while (aIt.hasMoreElements())
500 	{
501         uno::Reference< linguistic2::XLinguServiceEventListener > xRef( aIt.next(), uno::UNO_QUERY );
502 		if (xRef.is())
503 			xRef->processLinguServiceEvent( aEvt );
504 	}
505 }
506 
507 
508 inline sal_Bool LngSvcMgrListenerHelper::AddLngSvcMgrListener(
509         const uno::Reference< lang::XEventListener >& rxListener )
510 {
511     aLngSvcMgrListeners.addInterface( rxListener );
512 	return sal_True;
513 }
514 
515 
516 inline sal_Bool LngSvcMgrListenerHelper::RemoveLngSvcMgrListener(
517         const uno::Reference< lang::XEventListener >& rxListener )
518 {
519     aLngSvcMgrListeners.removeInterface( rxListener );
520 	return sal_True;
521 }
522 
523 
524 void LngSvcMgrListenerHelper::DisposeAndClear( const lang::EventObject &rEvtObj )
525 {
526 	// call "disposing" for all listeners and clear list
527 	aLngSvcMgrListeners   .disposeAndClear( rEvtObj );
528 
529 	// remove references to this object hold by the broadcasters
530 	cppu::OInterfaceIteratorHelper aIt( aLngSvcEvtBroadcasters );
531 	while (aIt.hasMoreElements())
532 	{
533         uno::Reference< linguistic2::XLinguServiceEventBroadcaster > xRef( aIt.next(), uno::UNO_QUERY );
534 		if (xRef.is())
535 			RemoveLngSvcEvtBroadcaster( xRef );
536 	}
537 
538 	// remove refernce to this object hold by the dictionary-list
539 	if (xDicList.is())
540 	{
541 		xDicList->removeDictionaryListEventListener(
542             (linguistic2::XDictionaryListEventListener *) this );
543 		xDicList = 0;
544 	}
545 }
546 
547 
548 sal_Bool LngSvcMgrListenerHelper::AddLngSvcEvtBroadcaster(
549         const uno::Reference< linguistic2::XLinguServiceEventBroadcaster > &rxBroadcaster )
550 {
551 	sal_Bool bRes = sal_False;
552 	if (rxBroadcaster.is())
553 	{
554 		aLngSvcEvtBroadcasters.addInterface( rxBroadcaster );
555 		rxBroadcaster->addLinguServiceEventListener(
556                 (linguistic2::XLinguServiceEventListener *) this );
557 	}
558 	return bRes;
559 }
560 
561 
562 sal_Bool LngSvcMgrListenerHelper::RemoveLngSvcEvtBroadcaster(
563         const uno::Reference< linguistic2::XLinguServiceEventBroadcaster > &rxBroadcaster )
564 {
565 	sal_Bool bRes = sal_False;
566 	if (rxBroadcaster.is())
567 	{
568 		aLngSvcEvtBroadcasters.removeInterface( rxBroadcaster );
569 		rxBroadcaster->removeLinguServiceEventListener(
570                 (linguistic2::XLinguServiceEventListener *) this );
571 	}
572 	return bRes;
573 }
574 
575 
576 ///////////////////////////////////////////////////////////////////////////
577 
578 
579 LngSvcMgr::LngSvcMgr() :
580     utl::ConfigItem( String::CreateFromAscii( "Office.Linguistic" ) ),
581 	aEvtListeners	( GetLinguMutex() )
582 {
583 	bHasAvailSpellLocales	=
584     bHasAvailGrammarLocales =
585 	bHasAvailHyphLocales	=
586 	bHasAvailThesLocales	=
587     bDisposing = sal_False;
588 
589 	pSpellDsp	= 0;
590     pGrammarDsp = 0;
591 	pHyphDsp	= 0;
592 	pThesDsp	= 0;
593 
594     pAvailSpellSvcs     = 0;
595     pAvailGrammarSvcs   = 0;
596     pAvailHyphSvcs      = 0;
597     pAvailThesSvcs      = 0;
598     pListenerHelper     = 0;
599 
600     // request notify events when properties (i.e. something in the subtree) changes
601     uno::Sequence< OUString > aNames(4);
602     OUString *pNames = aNames.getArray();
603     pNames[0] = A2OU( "ServiceManager/SpellCheckerList" );
604     pNames[1] = A2OU( "ServiceManager/GrammarCheckerList" );
605     pNames[2] = A2OU( "ServiceManager/HyphenatorList" );
606     pNames[3] = A2OU( "ServiceManager/ThesaurusList" );
607     EnableNotification( aNames );
608 }
609 
610 void LngSvcMgr::clearSvcInfoArray(SvcInfoArray* pInfo)
611 {
612     if (pInfo)
613     {
614         std::for_each(pInfo->begin(), pInfo->end(), boost::checked_deleter<SvcInfo>());
615         delete pInfo;
616     }
617 }
618 
619 LngSvcMgr::~LngSvcMgr()
620 {
621 	// memory for pSpellDsp, pHyphDsp, pThesDsp, pListenerHelper
622 	// will be freed in the destructor of the respective Reference's
623     // xSpellDsp, xGrammarDsp, xHyphDsp, xThesDsp
624 
625     clearSvcInfoArray(pAvailSpellSvcs);
626     clearSvcInfoArray(pAvailGrammarSvcs);
627     clearSvcInfoArray(pAvailHyphSvcs);
628     clearSvcInfoArray(pAvailThesSvcs);
629 }
630 
631 
632 void LngSvcMgr::Notify( const uno::Sequence< OUString > &rPropertyNames )
633 {
634 	const OUString aSpellCheckerList( A2OU("ServiceManager/SpellCheckerList") );
635     const OUString aGrammarCheckerList( A2OU("ServiceManager/GrammarCheckerList") );
636 	const OUString aHyphenatorList( A2OU("ServiceManager/HyphenatorList") );
637 	const OUString aThesaurusList( A2OU("ServiceManager/ThesaurusList") );
638 
639     const uno::Sequence< OUString > aSpellCheckerListEntries( GetNodeNames( aSpellCheckerList ) );
640     const uno::Sequence< OUString > aGrammarCheckerListEntries( GetNodeNames( aGrammarCheckerList ) );
641     const uno::Sequence< OUString > aHyphenatorListEntries( GetNodeNames( aHyphenatorList ) );
642     const uno::Sequence< OUString > aThesaurusListEntries( GetNodeNames( aThesaurusList ) );
643 
644     uno::Sequence< uno::Any > aValues;
645     uno::Sequence< OUString > aNames( 1 );
646 	OUString *pNames = aNames.getArray();
647 
648     sal_Int32 nLen = rPropertyNames.getLength();
649     const OUString *pPropertyNames = rPropertyNames.getConstArray();
650     for (sal_Int32 i = 0;  i < nLen;  ++i)
651     {
652 		// property names look like
653 		// "ServiceManager/ThesaurusList/de-CH"
654 
655 		const OUString &rName = pPropertyNames[i];
656 		sal_Int32 nKeyStart;
657 		nKeyStart = rName.lastIndexOf( '/' );
658 		OUString aKeyText;
659 		if (nKeyStart != -1)
660 			aKeyText = rName.copy( nKeyStart + 1 );
661         DBG_ASSERT( aKeyText.getLength() != 0, "unexpected key (lang::Locale) string" );
662         if (0 == rName.compareTo( aSpellCheckerList, aSpellCheckerList.getLength() ))
663         {
664 			// delete old cached data, needs to be acquired new on demand
665 			clearSvcInfoArray(pAvailSpellSvcs);		pAvailSpellSvcs = 0;
666 
667 			OUString aNode( aSpellCheckerList );
668             if (lcl_SeqHasString( aSpellCheckerListEntries, aKeyText ))
669 			{
670 				OUString aPropName( aNode );
671 				aPropName += OUString::valueOf( (sal_Unicode) '/' );
672 				aPropName += aKeyText;
673 				pNames[0] = aPropName;
674 				aValues = /*aCfg.*/GetProperties( aNames );
675                 uno::Sequence< OUString > aSvcImplNames;
676 				if (aValues.getLength())
677 					aSvcImplNames = GetLangSvcList( aValues.getConstArray()[0] );
678 
679 				LanguageType nLang = LANGUAGE_NONE;
680 			    if (0 != aKeyText.getLength())
681 					nLang = MsLangId::convertIsoStringToLanguage( aKeyText );
682 
683                 GetSpellCheckerDsp_Impl( sal_False );     // don't set service list, it will be done below
684 				pSpellDsp->SetServiceList( CreateLocale(nLang), aSvcImplNames );
685 			}
686         }
687         else if (0 == rName.compareTo( aGrammarCheckerList, aGrammarCheckerList.getLength() ))
688         {
689             // delete old cached data, needs to be acquired new on demand
690             clearSvcInfoArray(pAvailGrammarSvcs);      pAvailGrammarSvcs = 0;
691 
692             OUString aNode( aGrammarCheckerList );
693             if (lcl_SeqHasString( aGrammarCheckerListEntries, aKeyText ))
694             {
695                 OUString aPropName( aNode );
696                 aPropName += OUString::valueOf( (sal_Unicode) '/' );
697                 aPropName += aKeyText;
698                 pNames[0] = aPropName;
699                 aValues = /*aCfg.*/GetProperties( aNames );
700                 uno::Sequence< OUString > aSvcImplNames;
701                 if (aValues.getLength())
702                     aSvcImplNames = GetLangSvc( aValues.getConstArray()[0] );
703 
704                 LanguageType nLang = LANGUAGE_NONE;
705                 if (0 != aKeyText.getLength())
706                     nLang = MsLangId::convertIsoStringToLanguage( aKeyText );
707 
708 				if (SvtLinguConfig().HasGrammarChecker())
709 				{
710 					GetGrammarCheckerDsp_Impl( sal_False );   // don't set service list, it will be done below
711 					pGrammarDsp->SetServiceList( CreateLocale(nLang), aSvcImplNames );
712 				}
713             }
714         }
715 		else if (0 == rName.compareTo( aHyphenatorList, aHyphenatorList.getLength() ))
716 		{
717 			// delete old cached data, needs to be acquired new on demand
718 			clearSvcInfoArray(pAvailHyphSvcs);		pAvailHyphSvcs = 0;
719 
720 			OUString aNode( aHyphenatorList );
721             if (lcl_SeqHasString( aHyphenatorListEntries, aKeyText ))
722 			{
723 				OUString aPropName( aNode );
724 				aPropName += OUString::valueOf( (sal_Unicode) '/' );
725 				aPropName += aKeyText;
726 				pNames[0] = aPropName;
727 				aValues = /*aCfg.*/GetProperties( aNames );
728                 uno::Sequence< OUString > aSvcImplNames;
729 				if (aValues.getLength())
730 					aSvcImplNames = GetLangSvc( aValues.getConstArray()[0] );
731 
732 				LanguageType nLang = LANGUAGE_NONE;
733 				if (0 != aKeyText.getLength())
734 					nLang = MsLangId::convertIsoStringToLanguage( aKeyText );
735 
736                 GetHyphenatorDsp_Impl( sal_False );   // don't set service list, it will be done below
737 				pHyphDsp->SetServiceList( CreateLocale(nLang), aSvcImplNames );
738 			}
739 		}
740 		else if (0 == rName.compareTo( aThesaurusList, aThesaurusList.getLength() ))
741 		{
742 			// delete old cached data, needs to be acquired new on demand
743 			clearSvcInfoArray(pAvailThesSvcs);		pAvailThesSvcs = 0;
744 
745 			OUString aNode( aThesaurusList );
746             if (lcl_SeqHasString( aThesaurusListEntries, aKeyText ))
747 			{
748 				OUString aPropName( aNode );
749 				aPropName += OUString::valueOf( (sal_Unicode) '/' );
750 				aPropName += aKeyText;
751 				pNames[0] = aPropName;
752 				aValues = /*aCfg.*/GetProperties( aNames );
753                 uno::Sequence< OUString > aSvcImplNames;
754 				if (aValues.getLength())
755 					aSvcImplNames = GetLangSvcList( aValues.getConstArray()[0] );
756 
757 				LanguageType nLang = LANGUAGE_NONE;
758 				if (0 != aKeyText.getLength())
759 					nLang = MsLangId::convertIsoStringToLanguage( aKeyText );
760 
761                 GetThesaurusDsp_Impl( sal_False );  // don't set service list, it will be done below
762 				pThesDsp->SetServiceList( CreateLocale(nLang), aSvcImplNames );
763 			}
764 		}
765         else
766         {
767             DBG_ASSERT( 0, "nofified for unexpected property" );
768         }
769     }
770 }
771 
772 
773 void LngSvcMgr::Commit()
774 {
775     // everything necessary should have already been done by 'SaveCfgSvcs'
776     // called from within 'setConfiguredServices'.
777     // Also this class usually exits only when the Office i sbeing shutdown.
778 }
779 
780 
781 void LngSvcMgr::GetListenerHelper_Impl()
782 {
783 	if (!pListenerHelper)
784 	{
785         pListenerHelper = new LngSvcMgrListenerHelper( *this,
786 				(XLinguServiceManager *) this, linguistic::GetDictionaryList() );
787         xListenerHelper = (linguistic2::XLinguServiceEventListener *) pListenerHelper;
788 	}
789 }
790 
791 
792 void LngSvcMgr::GetSpellCheckerDsp_Impl( sal_Bool bSetSvcList )
793 {
794 	if (!pSpellDsp)
795 	{
796 		pSpellDsp	= new SpellCheckerDispatcher( *this );
797 		xSpellDsp	= pSpellDsp;
798         if (bSetSvcList)
799             SetCfgServiceLists( *pSpellDsp );
800 	}
801 }
802 
803 
804 void LngSvcMgr::GetGrammarCheckerDsp_Impl( sal_Bool bSetSvcList  )
805 {
806     if (!pGrammarDsp && SvtLinguConfig().HasGrammarChecker())
807     {
808         //! since the grammar checking iterator needs to be a one instance service
809         //! we need to create it the correct way!
810         uno::Reference< linguistic2::XProofreadingIterator > xGCI;
811         try
812         {
813             uno::Reference< lang::XMultiServiceFactory > xMgr(
814                     utl::getProcessServiceFactory(), uno::UNO_QUERY_THROW );
815             xGCI = uno::Reference< linguistic2::XProofreadingIterator >(
816                     xMgr->createInstance( A2OU( SN_GRAMMARCHECKINGITERATOR ) ), uno::UNO_QUERY_THROW );
817         }
818         catch (uno::Exception &)
819         {
820         }
821         DBG_ASSERT( xGCI.is(), "instantiating grammar checking iterator failed" );
822 
823         if (xGCI.is())
824         {
825             pGrammarDsp    = dynamic_cast< GrammarCheckingIterator * >(xGCI.get());
826             xGrammarDsp    = xGCI;
827             DBG_ASSERT( pGrammarDsp, "failed to get implementation" );
828             if (bSetSvcList)
829                 SetCfgServiceLists( *pGrammarDsp );
830         }
831     }
832 }
833 
834 
835 void LngSvcMgr::GetHyphenatorDsp_Impl( sal_Bool bSetSvcList  )
836 {
837 	if (!pHyphDsp)
838 	{
839 		pHyphDsp	= new HyphenatorDispatcher( *this );
840 		xHyphDsp	= pHyphDsp;
841         if (bSetSvcList)
842             SetCfgServiceLists( *pHyphDsp );
843 	}
844 }
845 
846 
847 void LngSvcMgr::GetThesaurusDsp_Impl( sal_Bool bSetSvcList  )
848 {
849 	if (!pThesDsp)
850 	{
851 		pThesDsp	= new ThesaurusDispatcher;
852 		xThesDsp	= pThesDsp;
853         if (bSetSvcList)
854             SetCfgServiceLists( *pThesDsp );
855 	}
856 }
857 
858 
859 void LngSvcMgr::GetAvailableSpellSvcs_Impl()
860 {
861 	if (!pAvailSpellSvcs)
862 	{
863 		pAvailSpellSvcs = new SvcInfoArray;
864 
865         uno::Reference< lang::XMultiServiceFactory >  xFac( utl::getProcessServiceFactory() );
866 		if (xFac.is())
867 		{
868             uno::Reference< container::XContentEnumerationAccess > xEnumAccess( xFac, uno::UNO_QUERY );
869             uno::Reference< container::XEnumeration > xEnum;
870 			if (xEnumAccess.is())
871 				xEnum = xEnumAccess->createContentEnumeration(
872 						A2OU( SN_SPELLCHECKER ) );
873 
874 			if (xEnum.is())
875 			{
876 				while (xEnum->hasMoreElements())
877 				{
878                     uno::Any aCurrent = xEnum->nextElement();
879                     uno::Reference< lang::XSingleComponentFactory > xCompFactory;
880                     uno::Reference< lang::XSingleServiceFactory > xFactory;
881 
882                     uno::Reference< linguistic2::XSpellChecker > xSvc;
883 					if ( cppu::extractInterface( xCompFactory, aCurrent ) || ::cppu::extractInterface( xFactory, aCurrent ) )
884 					{
885 						try
886 						{
887                             uno::Reference < uno::XComponentContext > xContext;
888                             uno::Reference< beans::XPropertySet > xProps( xFac, uno::UNO_QUERY );
889 
890                             xProps->getPropertyValue( OUString( RTL_CONSTASCII_USTRINGPARAM( "DefaultContext" ))) >>= xContext;
891                             xSvc = uno::Reference< linguistic2::XSpellChecker >( ( xCompFactory.is() ? xCompFactory->createInstanceWithContext( xContext ) : xFactory->createInstance() ), uno::UNO_QUERY );
892 						}
893                         catch (uno::Exception &rEx)
894 						{
895                             (void) rEx;
896                             DBG_ASSERT( 0, "createInstance failed" );
897 						}
898 					}
899 
900 					if (xSvc.is())
901 					{
902 						OUString 			aImplName;
903                         uno::Sequence< sal_Int16 >    aLanguages;
904                         uno::Reference< XServiceInfo > xInfo( xSvc, uno::UNO_QUERY );
905 						if (xInfo.is())
906 							aImplName = xInfo->getImplementationName();
907 						DBG_ASSERT( aImplName.getLength(),
908 								"empty implementation name" );
909                         uno::Reference< linguistic2::XSupportedLocales > xSuppLoc( xSvc, uno::UNO_QUERY );
910 						DBG_ASSERT( xSuppLoc.is(), "interfaces not supported" );
911 						if (xSuppLoc.is()) {
912                             uno::Sequence<lang::Locale> aLocaleSequence(xSuppLoc->getLocales());
913 							aLanguages = LocaleSeqToLangSeq( aLocaleSequence );
914                         }
915 
916                         pAvailSpellSvcs->push_back( new SvcInfo( aImplName, aLanguages ) );
917 					}
918 				}
919 			}
920 		}
921 	}
922 }
923 
924 
925 void LngSvcMgr::GetAvailableGrammarSvcs_Impl()
926 {
927     if (!pAvailGrammarSvcs)
928     {
929         pAvailGrammarSvcs = new SvcInfoArray;
930 
931         uno::Reference< lang::XMultiServiceFactory >  xFac( utl::getProcessServiceFactory() );
932         if (xFac.is())
933         {
934             uno::Reference< container::XContentEnumerationAccess > xEnumAccess( xFac, uno::UNO_QUERY );
935             uno::Reference< container::XEnumeration > xEnum;
936             if (xEnumAccess.is())
937                 xEnum = xEnumAccess->createContentEnumeration(
938                         A2OU( SN_GRAMMARCHECKER ) );
939 
940             if (xEnum.is())
941             {
942                 while (xEnum->hasMoreElements())
943                 {
944                     uno::Any aCurrent = xEnum->nextElement();
945                     uno::Reference< lang::XSingleComponentFactory > xCompFactory;
946                     uno::Reference< lang::XSingleServiceFactory > xFactory;
947 
948                     uno::Reference< linguistic2::XProofreader > xSvc;
949                     if ( cppu::extractInterface( xCompFactory, aCurrent ) || ::cppu::extractInterface( xFactory, aCurrent ) )
950                     {
951                         try
952                         {
953                             uno::Reference < uno::XComponentContext > xContext;
954                             uno::Reference< beans::XPropertySet > xProps( xFac, uno::UNO_QUERY );
955 
956                             xProps->getPropertyValue( OUString( RTL_CONSTASCII_USTRINGPARAM( "DefaultContext" ))) >>= xContext;
957                             xSvc = uno::Reference< linguistic2::XProofreader >( ( xCompFactory.is() ? xCompFactory->createInstanceWithContext( xContext ) : xFactory->createInstance() ), uno::UNO_QUERY );
958                         }
959                         catch (uno::Exception &rEx)
960                         {
961                             (void) rEx;
962                             DBG_ASSERT( 0, "createInstance failed" );
963                         }
964                     }
965 
966                     if (xSvc.is())
967                     {
968                         OUString            aImplName;
969                         uno::Sequence< sal_Int16 >   aLanguages;
970                         uno::Reference< XServiceInfo > xInfo( xSvc, uno::UNO_QUERY );
971                         if (xInfo.is())
972                             aImplName = xInfo->getImplementationName();
973                         DBG_ASSERT( aImplName.getLength(),
974                                 "empty implementation name" );
975                         uno::Reference< linguistic2::XSupportedLocales > xSuppLoc( xSvc, uno::UNO_QUERY );
976                         DBG_ASSERT( xSuppLoc.is(), "interfaces not supported" );
977                         if (xSuppLoc.is()) {
978                             uno::Sequence<lang::Locale> aLocaleSequence(xSuppLoc->getLocales());
979                             aLanguages = LocaleSeqToLangSeq( aLocaleSequence );
980                         }
981 
982                         pAvailGrammarSvcs->push_back( new SvcInfo( aImplName, aLanguages ) );
983                     }
984                 }
985             }
986         }
987     }
988 }
989 
990 
991 void LngSvcMgr::GetAvailableHyphSvcs_Impl()
992 {
993 	if (!pAvailHyphSvcs)
994 	{
995 		pAvailHyphSvcs = new SvcInfoArray;
996         uno::Reference< lang::XMultiServiceFactory >  xFac( utl::getProcessServiceFactory() );
997 		if (xFac.is())
998 		{
999             uno::Reference< container::XContentEnumerationAccess > xEnumAccess( xFac, uno::UNO_QUERY );
1000             uno::Reference< container::XEnumeration > xEnum;
1001 			if (xEnumAccess.is())
1002 				xEnum = xEnumAccess->createContentEnumeration( A2OU( SN_HYPHENATOR ) );
1003 
1004 			if (xEnum.is())
1005 			{
1006 				while (xEnum->hasMoreElements())
1007 				{
1008                     uno::Any aCurrent = xEnum->nextElement();
1009                     uno::Reference< lang::XSingleComponentFactory > xCompFactory;
1010                     uno::Reference< lang::XSingleServiceFactory > xFactory;
1011 
1012                     uno::Reference< linguistic2::XHyphenator > xSvc;
1013 					if ( cppu::extractInterface( xCompFactory, aCurrent ) || ::cppu::extractInterface( xFactory, aCurrent ) )
1014 					{
1015 						try
1016 						{
1017                             uno::Reference < uno::XComponentContext > xContext;
1018                             uno::Reference< beans::XPropertySet > xProps( xFac, uno::UNO_QUERY );
1019 
1020                             xProps->getPropertyValue( OUString( RTL_CONSTASCII_USTRINGPARAM( "DefaultContext" ))) >>= xContext;
1021                             xSvc = uno::Reference< linguistic2::XHyphenator >( ( xCompFactory.is() ? xCompFactory->createInstanceWithContext( xContext ) : xFactory->createInstance() ), uno::UNO_QUERY );
1022 
1023 						}
1024                         catch (uno::Exception &rEx)
1025 						{
1026                             (void) rEx;
1027                             DBG_ASSERT( 0, "createInstance failed" );
1028 						}
1029 					}
1030 
1031 					if (xSvc.is())
1032 					{
1033 						OUString 			aImplName;
1034                         uno::Sequence< sal_Int16 >    aLanguages;
1035                         uno::Reference< XServiceInfo > xInfo( xSvc, uno::UNO_QUERY );
1036 						if (xInfo.is())
1037 							aImplName = xInfo->getImplementationName();
1038 						DBG_ASSERT( aImplName.getLength(),
1039 								"empty implementation name" );
1040                         uno::Reference< linguistic2::XSupportedLocales > xSuppLoc( xSvc, uno::UNO_QUERY );
1041 						DBG_ASSERT( xSuppLoc.is(), "interfaces not supported" );
1042 						if (xSuppLoc.is()) {
1043                             uno::Sequence<lang::Locale> aLocaleSequence(xSuppLoc->getLocales());
1044 							aLanguages = LocaleSeqToLangSeq( aLocaleSequence );
1045                         }
1046 
1047                         pAvailHyphSvcs->push_back( new SvcInfo( aImplName, aLanguages ) );
1048 					}
1049 				}
1050 			}
1051 		}
1052 	}
1053 }
1054 
1055 
1056 void LngSvcMgr::GetAvailableThesSvcs_Impl()
1057 {
1058 	if (!pAvailThesSvcs)
1059 	{
1060 		pAvailThesSvcs = new SvcInfoArray;
1061 
1062         uno::Reference< lang::XMultiServiceFactory >  xFac( utl::getProcessServiceFactory() );
1063 		if (xFac.is())
1064 		{
1065             uno::Reference< container::XContentEnumerationAccess > xEnumAccess( xFac, uno::UNO_QUERY );
1066             uno::Reference< container::XEnumeration > xEnum;
1067 			if (xEnumAccess.is())
1068 				xEnum = xEnumAccess->createContentEnumeration(
1069 						A2OU( SN_THESAURUS ) );
1070 
1071 			if (xEnum.is())
1072 			{
1073 				while (xEnum->hasMoreElements())
1074 				{
1075                     uno::Any aCurrent = xEnum->nextElement();
1076 
1077                     uno::Reference< lang::XSingleComponentFactory > xCompFactory;
1078                     uno::Reference< lang::XSingleServiceFactory > xFactory;
1079 
1080                     uno::Reference< linguistic2::XThesaurus > xSvc;
1081 					if ( cppu::extractInterface( xCompFactory, aCurrent ) || ::cppu::extractInterface( xFactory, aCurrent ) )
1082 					{
1083 						try
1084 						{
1085                             uno::Reference < uno::XComponentContext > xContext;
1086                             uno::Reference< beans::XPropertySet > xProps( xFac, uno::UNO_QUERY );
1087 
1088                             xProps->getPropertyValue( OUString( RTL_CONSTASCII_USTRINGPARAM( "DefaultContext" ))) >>= xContext;
1089                             xSvc = uno::Reference< linguistic2::XThesaurus >( ( xCompFactory.is() ? xCompFactory->createInstanceWithContext( xContext ) : xFactory->createInstance() ), uno::UNO_QUERY );
1090 						}
1091                         catch (uno::Exception &rEx)
1092 						{
1093                             (void) rEx;
1094                             DBG_ASSERT( 0, "createInstance failed" );
1095 						}
1096 					}
1097 
1098 					if (xSvc.is())
1099 					{
1100 						OUString 			aImplName;
1101                         uno::Sequence< sal_Int16 >    aLanguages;
1102                         uno::Reference< XServiceInfo > xInfo( xSvc, uno::UNO_QUERY );
1103 						if (xInfo.is())
1104 							aImplName = xInfo->getImplementationName();
1105 						DBG_ASSERT( aImplName.getLength(),
1106 								"empty implementation name" );
1107                         uno::Reference< linguistic2::XSupportedLocales > xSuppLoc( xSvc, uno::UNO_QUERY );
1108 						DBG_ASSERT( xSuppLoc.is(), "interfaces not supported" );
1109 						if (xSuppLoc.is()) {
1110                             uno::Sequence<lang::Locale> aLocaleSequence(xSuppLoc->getLocales());
1111 							aLanguages = LocaleSeqToLangSeq( aLocaleSequence );
1112                         }
1113 
1114                         pAvailThesSvcs->push_back( new SvcInfo( aImplName, aLanguages ) );
1115 					}
1116 				}
1117 			}
1118 		}
1119 	}
1120 }
1121 
1122 
1123 void LngSvcMgr::SetCfgServiceLists( SpellCheckerDispatcher &rSpellDsp )
1124 {
1125     RTL_LOGFILE_CONTEXT( aLog, "linguistic: LngSvcMgr::SetCfgServiceLists - Spell" );
1126 
1127     String  aNode( String::CreateFromAscii( "ServiceManager/SpellCheckerList" ) );
1128     uno::Sequence< OUString > aNames( /*aCfg.*/GetNodeNames( aNode ) );
1129     OUString *pNames = aNames.getArray();
1130     sal_Int32 nLen = aNames.getLength();
1131 
1132 	// append path prefix need for 'GetProperties' call below
1133 	String aPrefix( aNode );
1134 	aPrefix.Append( (sal_Unicode) '/' );
1135 	for (int i = 0;  i < nLen;  ++i)
1136 	{
1137 		OUString aTmp( aPrefix );
1138 		aTmp += pNames[i];
1139 		pNames[i] = aTmp;
1140 	}
1141 
1142     uno::Sequence< uno::Any > aValues( /*aCfg.*/GetProperties( aNames ) );
1143     if (nLen  &&  nLen == aValues.getLength())
1144     {
1145         const uno::Any *pValues = aValues.getConstArray();
1146         for (sal_Int32 i = 0;  i < nLen;  ++i)
1147         {
1148             uno::Sequence< OUString > aSvcImplNames;
1149             if (pValues[i] >>= aSvcImplNames)
1150             {
1151 #if OSL_DEBUG_LEVEL > 1
1152 //                sal_Int32 nSvcs = aSvcImplNames.getLength();
1153 //                const OUString *pSvcImplNames = aSvcImplNames.getConstArray();
1154 #endif
1155 				String aLocaleStr( pNames[i] );
1156 				xub_StrLen nSeperatorPos = aLocaleStr.SearchBackward( sal_Unicode( '/' ) );
1157 				aLocaleStr = aLocaleStr.Copy( nSeperatorPos + 1 );
1158                 lang::Locale aLocale( CreateLocale( MsLangId::convertIsoStringToLanguage(aLocaleStr) ) );
1159                 rSpellDsp.SetServiceList( aLocale, aSvcImplNames );
1160             }
1161         }
1162     }
1163 }
1164 
1165 
1166 void LngSvcMgr::SetCfgServiceLists( GrammarCheckingIterator &rGrammarDsp )
1167 {
1168     RTL_LOGFILE_CONTEXT( aLog, "linguistic: LngSvcMgr::SetCfgServiceLists - Grammar" );
1169 
1170     String  aNode( String::CreateFromAscii( "ServiceManager/GrammarCheckerList" ) );
1171     uno::Sequence< OUString > aNames( /*aCfg.*/GetNodeNames( aNode ) );
1172     OUString *pNames = aNames.getArray();
1173     sal_Int32 nLen = aNames.getLength();
1174 
1175     // append path prefix need for 'GetProperties' call below
1176     String aPrefix( aNode );
1177     aPrefix.Append( (sal_Unicode) '/' );
1178     for (int i = 0;  i < nLen;  ++i)
1179     {
1180         OUString aTmp( aPrefix );
1181         aTmp += pNames[i];
1182         pNames[i] = aTmp;
1183     }
1184 
1185     uno::Sequence< uno::Any > aValues( /*aCfg.*/GetProperties( aNames ) );
1186     if (nLen  &&  nLen == aValues.getLength())
1187     {
1188         const uno::Any *pValues = aValues.getConstArray();
1189         for (sal_Int32 i = 0;  i < nLen;  ++i)
1190         {
1191             uno::Sequence< OUString > aSvcImplNames;
1192             if (pValues[i] >>= aSvcImplNames)
1193             {
1194                 // there should only be one grammar checker in use per language...
1195                 if (aSvcImplNames.getLength() > 1)
1196                     aSvcImplNames.realloc(1);
1197 
1198 #if OSL_DEBUG_LEVEL > 1
1199 //                sal_Int32 nSvcs = aSvcImplNames.getLength();
1200 //                const OUString *pSvcImplNames = aSvcImplNames.getConstArray();
1201 #endif
1202                 String aLocaleStr( pNames[i] );
1203                 xub_StrLen nSeperatorPos = aLocaleStr.SearchBackward( sal_Unicode( '/' ) );
1204                 aLocaleStr = aLocaleStr.Copy( nSeperatorPos + 1 );
1205                 lang::Locale aLocale( CreateLocale( MsLangId::convertIsoStringToLanguage(aLocaleStr) ) );
1206                 rGrammarDsp.SetServiceList( aLocale, aSvcImplNames );
1207             }
1208         }
1209     }
1210 }
1211 
1212 
1213 void LngSvcMgr::SetCfgServiceLists( HyphenatorDispatcher &rHyphDsp )
1214 {
1215     RTL_LOGFILE_CONTEXT( aLog, "linguistic: LngSvcMgr::SetCfgServiceLists - Hyph" );
1216 
1217     String  aNode( String::CreateFromAscii( "ServiceManager/HyphenatorList" ) );
1218     uno::Sequence< OUString > aNames( /*aCfg.*/GetNodeNames( aNode ) );
1219     OUString *pNames = aNames.getArray();
1220     sal_Int32 nLen = aNames.getLength();
1221 
1222 	// append path prefix need for 'GetProperties' call below
1223 	String aPrefix( aNode );
1224 	aPrefix.Append( (sal_Unicode) '/' );
1225 	for (int i = 0;  i < nLen;  ++i)
1226 	{
1227 		OUString aTmp( aPrefix );
1228 		aTmp += pNames[i];
1229 		pNames[i] = aTmp;
1230 	}
1231 
1232     uno::Sequence< uno::Any > aValues( /*aCfg.*/GetProperties( aNames ) );
1233     if (nLen  &&  nLen == aValues.getLength())
1234     {
1235         const uno::Any *pValues = aValues.getConstArray();
1236         for (sal_Int32 i = 0;  i < nLen;  ++i)
1237         {
1238             uno::Sequence< OUString > aSvcImplNames;
1239             if (pValues[i] >>= aSvcImplNames)
1240             {
1241                 // there should only be one hyphenator in use per language...
1242                 if (aSvcImplNames.getLength() > 1)
1243                     aSvcImplNames.realloc(1);
1244 
1245 #if OSL_DEBUG_LEVEL > 1
1246 //                sal_Int32 nSvcs = aSvcImplNames.getLength();
1247 //                const OUString *pSvcImplNames = aSvcImplNames.getConstArray();
1248 #endif
1249                 String aLocaleStr( pNames[i] );
1250                 xub_StrLen nSeperatorPos = aLocaleStr.SearchBackward( sal_Unicode( '/' ) );
1251                 aLocaleStr = aLocaleStr.Copy( nSeperatorPos + 1 );
1252                 lang::Locale aLocale( CreateLocale( MsLangId::convertIsoStringToLanguage(aLocaleStr) ) );
1253                 rHyphDsp.SetServiceList( aLocale, aSvcImplNames );
1254             }
1255         }
1256     }
1257 }
1258 
1259 
1260 void LngSvcMgr::SetCfgServiceLists( ThesaurusDispatcher &rThesDsp )
1261 {
1262     RTL_LOGFILE_CONTEXT( aLog, "linguistic: LngSvcMgr::SetCfgServiceLists - Thes" );
1263 
1264     String  aNode( String::CreateFromAscii( "ServiceManager/ThesaurusList" ) );
1265     uno::Sequence< OUString > aNames( /*aCfg.*/GetNodeNames( aNode ) );
1266     OUString *pNames = aNames.getArray();
1267     sal_Int32 nLen = aNames.getLength();
1268 
1269 	// append path prefix need for 'GetProperties' call below
1270 	String aPrefix( aNode );
1271 	aPrefix.Append( (sal_Unicode) '/' );
1272 	for (int i = 0;  i < nLen;  ++i)
1273 	{
1274 		OUString aTmp( aPrefix );
1275 		aTmp += pNames[i];
1276 		pNames[i] = aTmp;
1277 	}
1278 
1279     uno::Sequence< uno::Any > aValues( /*aCfg.*/GetProperties( aNames ) );
1280     if (nLen  &&  nLen == aValues.getLength())
1281     {
1282         const uno::Any *pValues = aValues.getConstArray();
1283         for (sal_Int32 i = 0;  i < nLen;  ++i)
1284         {
1285             uno::Sequence< OUString > aSvcImplNames;
1286             if (pValues[i] >>= aSvcImplNames)
1287             {
1288 #if OSL_DEBUG_LEVEL > 1
1289 //                sal_Int32 nSvcs = aSvcImplNames.getLength();
1290 //                const OUString *pSvcImplNames = aSvcImplNames.getConstArray();
1291 #endif
1292 				String aLocaleStr( pNames[i] );
1293 				xub_StrLen nSeperatorPos = aLocaleStr.SearchBackward( sal_Unicode( '/' ) );
1294 				aLocaleStr = aLocaleStr.Copy( nSeperatorPos + 1 );
1295                 lang::Locale aLocale( CreateLocale( MsLangId::convertIsoStringToLanguage(aLocaleStr) ) );
1296                 rThesDsp.SetServiceList( aLocale, aSvcImplNames );
1297             }
1298         }
1299     }
1300 }
1301 
1302 
1303 uno::Reference< linguistic2::XSpellChecker > SAL_CALL
1304 	LngSvcMgr::getSpellChecker()
1305         throw(uno::RuntimeException)
1306 {
1307     osl::MutexGuard aGuard( GetLinguMutex() );
1308 #if OSL_DEBUG_LEVEL > 1
1309 	getAvailableLocales( A2OU( SN_SPELLCHECKER ));
1310 #endif
1311 
1312     uno::Reference< linguistic2::XSpellChecker > xRes;
1313 	if (!bDisposing)
1314 	{
1315 		if (!xSpellDsp.is())
1316 			GetSpellCheckerDsp_Impl();
1317 		xRes = xSpellDsp;
1318 	}
1319 	return xRes;
1320 }
1321 
1322 
1323 uno::Reference< linguistic2::XHyphenator > SAL_CALL
1324 	LngSvcMgr::getHyphenator()
1325         throw(uno::RuntimeException)
1326 {
1327     osl::MutexGuard aGuard( GetLinguMutex() );
1328 #if OSL_DEBUG_LEVEL > 1
1329 	getAvailableLocales( A2OU( SN_HYPHENATOR ));
1330 #endif
1331 
1332     uno::Reference< linguistic2::XHyphenator >   xRes;
1333 	if (!bDisposing)
1334 	{
1335 		if (!xHyphDsp.is())
1336 			GetHyphenatorDsp_Impl();
1337 		xRes = xHyphDsp;
1338 	}
1339 	return xRes;
1340 }
1341 
1342 
1343 uno::Reference< linguistic2::XThesaurus > SAL_CALL
1344 	LngSvcMgr::getThesaurus()
1345         throw(uno::RuntimeException)
1346 {
1347     osl::MutexGuard aGuard( GetLinguMutex() );
1348 #if OSL_DEBUG_LEVEL > 1
1349 	getAvailableLocales( A2OU( SN_THESAURUS ));
1350 #endif
1351 
1352     uno::Reference< linguistic2::XThesaurus >    xRes;
1353 	if (!bDisposing)
1354 	{
1355 		if (!xThesDsp.is())
1356 			GetThesaurusDsp_Impl();
1357 		xRes = xThesDsp;
1358 	}
1359 	return xRes;
1360 }
1361 
1362 
1363 sal_Bool SAL_CALL
1364 	LngSvcMgr::addLinguServiceManagerListener(
1365             const uno::Reference< lang::XEventListener >& xListener )
1366         throw(uno::RuntimeException)
1367 {
1368     osl::MutexGuard aGuard( GetLinguMutex() );
1369 
1370 	sal_Bool bRes = sal_False;
1371 	if (!bDisposing  &&  xListener.is())
1372 	{
1373 		if (!pListenerHelper)
1374 			GetListenerHelper_Impl();
1375 		bRes = pListenerHelper->AddLngSvcMgrListener( xListener );
1376 	}
1377 	return bRes;
1378 }
1379 
1380 
1381 sal_Bool SAL_CALL
1382 	LngSvcMgr::removeLinguServiceManagerListener(
1383             const uno::Reference< lang::XEventListener >& xListener )
1384         throw(uno::RuntimeException)
1385 {
1386     osl::MutexGuard aGuard( GetLinguMutex() );
1387 
1388 	sal_Bool bRes = sal_False;
1389 	if (!bDisposing  &&  xListener.is())
1390 	{
1391 		DBG_ASSERT( pListenerHelper, "listener removed without being added" );
1392 		if (!pListenerHelper)
1393 			GetListenerHelper_Impl();
1394 		bRes = pListenerHelper->RemoveLngSvcMgrListener( xListener );
1395 	}
1396 	return bRes;
1397 }
1398 
1399 
1400 uno::Sequence< OUString > SAL_CALL
1401 	LngSvcMgr::getAvailableServices(
1402 			const OUString& rServiceName,
1403             const lang::Locale& rLocale )
1404         throw(uno::RuntimeException)
1405 {
1406     osl::MutexGuard aGuard( GetLinguMutex() );
1407 
1408     uno::Sequence< OUString > aRes;
1409 	const SvcInfoArray *pInfoArray = 0;
1410 
1411 	if (0 == rServiceName.compareToAscii( SN_SPELLCHECKER ))
1412 	{
1413         // don't used cached data here (force re-evaluation in order to have downloaded dictionaries
1414         // already found without the need to restart the office
1415 		clearSvcInfoArray(pAvailSpellSvcs);  pAvailSpellSvcs = 0;
1416 		GetAvailableSpellSvcs_Impl();
1417 		pInfoArray = pAvailSpellSvcs;
1418 	}
1419     else if (0 == rServiceName.compareToAscii( SN_GRAMMARCHECKER ))
1420     {
1421         // don't used cached data here (force re-evaluation in order to have downloaded dictionaries
1422         // already found without the need to restart the office
1423         clearSvcInfoArray(pAvailGrammarSvcs);  pAvailGrammarSvcs = 0;
1424         GetAvailableGrammarSvcs_Impl();
1425         pInfoArray = pAvailGrammarSvcs;
1426     }
1427 	else if (0 == rServiceName.compareToAscii( SN_HYPHENATOR ))
1428 	{
1429         // don't used cached data here (force re-evaluation in order to have downloaded dictionaries
1430         // already found without the need to restart the office
1431 		clearSvcInfoArray(pAvailHyphSvcs);  pAvailHyphSvcs = 0;
1432 		GetAvailableHyphSvcs_Impl();
1433 		pInfoArray = pAvailHyphSvcs;
1434 	}
1435 	else if (0 == rServiceName.compareToAscii( SN_THESAURUS ))
1436 	{
1437         // don't used cached data here (force re-evaluation in order to have downloaded dictionaries
1438         // already found without the need to restart the office
1439 		clearSvcInfoArray(pAvailThesSvcs);  pAvailThesSvcs = 0;
1440 		GetAvailableThesSvcs_Impl();
1441 		pInfoArray = pAvailThesSvcs;
1442 	}
1443 
1444 	if (pInfoArray)
1445 	{
1446 		// resize to max number of entries
1447         size_t nMaxCnt = pInfoArray->size();
1448 		aRes.realloc( nMaxCnt );
1449 		OUString *pImplName = aRes.getArray();
1450 
1451 		sal_uInt16 nCnt = 0;
1452         LanguageType nLanguage = LocaleToLanguage( rLocale );
1453         for (size_t i = 0;  i < nMaxCnt;  ++i)
1454 		{
1455             const SvcInfo *pInfo = (*pInfoArray)[i];
1456 			if (LANGUAGE_NONE == nLanguage
1457 				|| (pInfo && pInfo->HasLanguage( nLanguage )))
1458 			{
1459 				pImplName[ nCnt++ ] = pInfo->aSvcImplName;
1460 			}
1461 		}
1462 
1463 		// resize to actual number of entries
1464 		if (nCnt != nMaxCnt)
1465 			aRes.realloc( nCnt );
1466 	}
1467 
1468 	return aRes;
1469 }
1470 
1471 
1472 uno::Sequence< lang::Locale > SAL_CALL
1473 	LngSvcMgr::getAvailableLocales(
1474 			const OUString& rServiceName )
1475         throw(uno::RuntimeException)
1476 {
1477     osl::MutexGuard aGuard( GetLinguMutex() );
1478 
1479     uno::Sequence< lang::Locale > aRes;
1480 
1481     uno::Sequence< lang::Locale >  *pAvailLocales     = NULL;
1482 	sal_Bool				*pHasAvailLocales	= NULL;
1483 	if (0 == rServiceName.compareToAscii( SN_SPELLCHECKER ))
1484 	{
1485 		pAvailLocales		= &aAvailSpellLocales;
1486 		pHasAvailLocales	= &bHasAvailSpellLocales;
1487 	}
1488     else if (0 == rServiceName.compareToAscii( SN_GRAMMARCHECKER ))
1489     {
1490         pAvailLocales       = &aAvailGrammarLocales;
1491         pHasAvailLocales    = &bHasAvailGrammarLocales;
1492     }
1493 	else if (0 == rServiceName.compareToAscii( SN_HYPHENATOR ))
1494 	{
1495 		pAvailLocales		= &aAvailHyphLocales;
1496 		pHasAvailLocales	= &bHasAvailHyphLocales;
1497 	}
1498 	else if (0 == rServiceName.compareToAscii( SN_THESAURUS ))
1499 	{
1500 		pAvailLocales		= &aAvailThesLocales;
1501 		pHasAvailLocales	= &bHasAvailThesLocales;
1502 	}
1503 
1504 	// about pHasAvailLocales: nowadays (with OOo lingu in SO) we want to know immediately about
1505 	// new downloaded dictionaries and have them ready right away if the Tools/Options...
1506 	// is used to activate them. Thus we can not rely anymore on buffered data.
1507 	if (pAvailLocales  /*&&  pHasAvailLocales */)
1508 	{
1509 //		if (!*pHasAvailLocales)
1510 //		{
1511 			*pAvailLocales = GetAvailLocales(
1512                     getAvailableServices( rServiceName, lang::Locale() ) );
1513 //			*pHasAvailLocales = sal_True;
1514 //		}
1515 		aRes = *pAvailLocales;
1516 	}
1517 
1518 	return aRes;
1519 }
1520 
1521 static sal_Bool IsEqSvcList( const uno::Sequence< OUString > &rList1,
1522                         const uno::Sequence< OUString > &rList2 )
1523 {
1524     // returns sal_True iff both sequences are equal
1525 
1526     sal_Bool bRes = sal_False;
1527     sal_Int32 nLen = rList1.getLength();
1528     if (rList2.getLength() == nLen)
1529     {
1530         const OUString *pStr1 = rList1.getConstArray();
1531         const OUString *pStr2 = rList2.getConstArray();
1532         bRes = sal_True;
1533         for (sal_Int32 i = 0;  i < nLen  &&  bRes;  ++i)
1534         {
1535             if (*pStr1++ != *pStr2++)
1536                 bRes = sal_False;
1537         }
1538     }
1539     return bRes;
1540 }
1541 
1542 
1543 void SAL_CALL
1544 	LngSvcMgr::setConfiguredServices(
1545 			const OUString& rServiceName,
1546             const lang::Locale& rLocale,
1547             const uno::Sequence< OUString >& rServiceImplNames )
1548         throw(uno::RuntimeException)
1549 {
1550     RTL_LOGFILE_CONTEXT( aLog, "linguistic: LngSvcMgr::setConfiguredServices" );
1551 
1552     osl::MutexGuard aGuard( GetLinguMutex() );
1553 
1554 #if OSL_DEBUG_LEVEL > 1
1555 //    const OUString *pImplNames = rServiceImplNames.getConstArray();
1556 #endif
1557 
1558     LanguageType nLanguage = LocaleToLanguage( rLocale );
1559     if (LANGUAGE_NONE != nLanguage)
1560 	{
1561 		if (0 == rServiceName.compareToAscii( SN_SPELLCHECKER ))
1562 		{
1563 			if (!xSpellDsp.is())
1564 				GetSpellCheckerDsp_Impl();
1565             sal_Bool bChanged = !IsEqSvcList( rServiceImplNames,
1566                                           pSpellDsp->GetServiceList( rLocale ) );
1567             if (bChanged)
1568             {
1569                 pSpellDsp->SetServiceList( rLocale, rServiceImplNames );
1570                 SaveCfgSvcs( A2OU( SN_SPELLCHECKER ) );
1571 
1572                 if (pListenerHelper  &&  bChanged)
1573                     pListenerHelper->AddLngSvcEvt(
1574                             linguistic2::LinguServiceEventFlags::SPELL_CORRECT_WORDS_AGAIN |
1575                             linguistic2::LinguServiceEventFlags::SPELL_WRONG_WORDS_AGAIN );
1576             }
1577 		}
1578         else if (0 == rServiceName.compareToAscii( SN_GRAMMARCHECKER ))
1579         {
1580             if (!xGrammarDsp.is())
1581                 GetGrammarCheckerDsp_Impl();
1582             sal_Bool bChanged = !IsEqSvcList( rServiceImplNames,
1583                                           pGrammarDsp->GetServiceList( rLocale ) );
1584             if (bChanged)
1585             {
1586                 pGrammarDsp->SetServiceList( rLocale, rServiceImplNames );
1587                 SaveCfgSvcs( A2OU( SN_GRAMMARCHECKER ) );
1588 
1589                 if (pListenerHelper  &&  bChanged)
1590                     pListenerHelper->AddLngSvcEvt(
1591                             linguistic2::LinguServiceEventFlags::PROOFREAD_AGAIN );
1592             }
1593         }
1594 		else if (0 == rServiceName.compareToAscii( SN_HYPHENATOR ))
1595 		{
1596 			if (!xHyphDsp.is())
1597 				GetHyphenatorDsp_Impl();
1598             sal_Bool bChanged = !IsEqSvcList( rServiceImplNames,
1599                                           pHyphDsp->GetServiceList( rLocale ) );
1600             if (bChanged)
1601             {
1602                 pHyphDsp->SetServiceList( rLocale, rServiceImplNames );
1603                 SaveCfgSvcs( A2OU( SN_HYPHENATOR ) );
1604 
1605                 if (pListenerHelper  &&  bChanged)
1606                     pListenerHelper->AddLngSvcEvt(
1607                             linguistic2::LinguServiceEventFlags::HYPHENATE_AGAIN );
1608             }
1609 		}
1610 		else if (0 == rServiceName.compareToAscii( SN_THESAURUS ))
1611 		{
1612 			if (!xThesDsp.is())
1613 				GetThesaurusDsp_Impl();
1614             sal_Bool bChanged = !IsEqSvcList( rServiceImplNames,
1615                                           pThesDsp->GetServiceList( rLocale ) );
1616             if (bChanged)
1617             {
1618                 pThesDsp->SetServiceList( rLocale, rServiceImplNames );
1619                 SaveCfgSvcs( A2OU( SN_THESAURUS ) );
1620             }
1621 		}
1622 	}
1623 }
1624 
1625 
1626 sal_Bool LngSvcMgr::SaveCfgSvcs( const String &rServiceName )
1627 {
1628     RTL_LOGFILE_CONTEXT( aLog, "linguistic: LngSvcMgr::SaveCfgSvcs" );
1629 
1630     sal_Bool bRes = sal_False;
1631 
1632 	LinguDispatcher *pDsp = 0;
1633     uno::Sequence< lang::Locale > aLocales;
1634 
1635 	if (0 == rServiceName.CompareToAscii( SN_SPELLCHECKER ))
1636 	{
1637 		if (!pSpellDsp)
1638 			GetSpellCheckerDsp_Impl();
1639 		pDsp = pSpellDsp;
1640         aLocales = getAvailableLocales( A2OU( SN_SPELLCHECKER ) );
1641 	}
1642     else if (0 == rServiceName.CompareToAscii( SN_GRAMMARCHECKER ))
1643     {
1644         if (!pGrammarDsp)
1645             GetGrammarCheckerDsp_Impl();
1646         pDsp = pGrammarDsp;
1647         aLocales = getAvailableLocales( A2OU( SN_GRAMMARCHECKER ) );
1648     }
1649 	else if (0 == rServiceName.CompareToAscii( SN_HYPHENATOR ))
1650 	{
1651 		if (!pHyphDsp)
1652 			GetHyphenatorDsp_Impl();
1653 		pDsp = pHyphDsp;
1654         aLocales = getAvailableLocales( A2OU( SN_HYPHENATOR ) );
1655 	}
1656 	else if (0 == rServiceName.CompareToAscii( SN_THESAURUS ))
1657 	{
1658 		if (!pThesDsp)
1659 			GetThesaurusDsp_Impl();
1660 		pDsp = pThesDsp;
1661         aLocales = getAvailableLocales( A2OU( SN_THESAURUS ) );
1662 	}
1663 
1664 	if (pDsp  &&  aLocales.getLength())
1665 	{
1666         sal_Int32 nLen = aLocales.getLength();
1667         const lang::Locale *pLocale = aLocales.getConstArray();
1668 
1669         uno::Sequence< beans::PropertyValue > aValues( nLen );
1670         beans::PropertyValue *pValues = aValues.getArray();
1671         beans::PropertyValue *pValue  = pValues;
1672 
1673         // get node name to be used
1674         const char *pNodeName = NULL;
1675         if (pDsp == pSpellDsp)
1676             pNodeName = "ServiceManager/SpellCheckerList";
1677         else if (pDsp == pGrammarDsp)
1678             pNodeName = "ServiceManager/GrammarCheckerList";
1679         else if (pDsp == pHyphDsp)
1680             pNodeName = "ServiceManager/HyphenatorList";
1681         else if (pDsp == pThesDsp)
1682             pNodeName = "ServiceManager/ThesaurusList";
1683         else
1684         {
1685             DBG_ASSERT( 0, "node name missing" );
1686         }
1687         OUString aNodeName( A2OU(pNodeName) );
1688 
1689 		for (sal_Int32 i = 0;  i < nLen;  ++i)
1690 		{
1691             uno::Sequence< OUString > aSvcImplNames;
1692 			aSvcImplNames = pDsp->GetServiceList( pLocale[i] );
1693 
1694 #if OSL_DEBUG_LEVEL > 1
1695 			sal_Int32 nSvcs = aSvcImplNames.getLength();
1696 			const OUString *pSvcImplName = aSvcImplNames.getConstArray();
1697 			for (sal_Int32 j = 0;  j < nSvcs;  ++j)
1698 			{
1699 				OUString aImplName( pSvcImplName[j] );
1700 			}
1701 #endif
1702 			// build value to be written back to configuration
1703             uno::Any aCfgAny;
1704             if ((pDsp == pHyphDsp || pDsp == pGrammarDsp) && aSvcImplNames.getLength() > 1)
1705                 aSvcImplNames.realloc(1);   // there should be only one entry for hyphenators or grammar checkers (because they are not chained)
1706             aCfgAny <<= aSvcImplNames;
1707 			DBG_ASSERT( aCfgAny.hasValue(), "missing value for 'Any' type" );
1708 
1709 			OUString aCfgLocaleStr( MsLangId::convertLanguageToIsoString(
1710 										LocaleToLanguage( pLocale[i] ) ) );
1711             pValue->Value = aCfgAny;
1712             pValue->Name  = aNodeName;
1713             pValue->Name += OUString::valueOf( (sal_Unicode) '/' );
1714             pValue->Name += aCfgLocaleStr;
1715             pValue++;
1716 		}
1717         {
1718         RTL_LOGFILE_CONTEXT( aLog, "linguistic: LngSvcMgr::SaveCfgSvcs - ReplaceSetProperties" );
1719         // change, add new or replace existing entries.
1720         bRes |= /*aCfg.*/ReplaceSetProperties( aNodeName, aValues );
1721         }
1722 	}
1723 
1724 	return bRes;
1725 }
1726 
1727 
1728 static uno::Sequence< OUString > GetLangSvcList( const uno::Any &rVal )
1729 {
1730     uno::Sequence< OUString > aRes;
1731 
1732 	if (rVal.hasValue())
1733 	{
1734 		rVal >>= aRes;
1735 #if OSL_DEBUG_LEVEL > 1
1736 		sal_Int32 nSvcs = aRes.getLength();
1737 		if (nSvcs)
1738 		{
1739 			const OUString *pSvcName = aRes.getConstArray();
1740 			for (sal_Int32 j = 0;  j < nSvcs;  ++j)
1741 			{
1742 				OUString aImplName( pSvcName[j] );
1743                 DBG_ASSERT( aImplName.getLength(), "service impl-name missing" );
1744 			}
1745 		}
1746 #endif
1747 	}
1748 
1749 	return aRes;
1750 }
1751 
1752 
1753 static uno::Sequence< OUString > GetLangSvc( const uno::Any &rVal )
1754 {
1755     uno::Sequence< OUString > aRes;
1756 	if (!rVal.hasValue())
1757 		return aRes;
1758 
1759 	// allowing for a sequence here as well (even though it should only
1760 	// be a string) makes coding easier in other places since one needs
1761 	// not make a special case for writing a string only and not a
1762 	// sequence of strings.
1763 	if (rVal >>= aRes)
1764 	{
1765 		// but only the first string should be used.
1766 		if (aRes.getLength() > 1)
1767 			aRes.realloc(1);
1768 	}
1769 	else
1770 	{
1771 		OUString aImplName;
1772 		if ((rVal >>= aImplName) && aImplName.getLength() != 0)
1773 		{
1774 			aRes.realloc(1);
1775 			aRes.getArray()[0] = aImplName;
1776 		}
1777         else
1778         {
1779             DBG_ASSERT( 0, "GetLangSvc: unexpected type encountered" );
1780         }
1781 	}
1782 
1783 	return aRes;
1784 }
1785 
1786 
1787 ///////////////////////////////////////////////////////////////////////////
1788 
1789 uno::Sequence< OUString > SAL_CALL
1790 	LngSvcMgr::getConfiguredServices(
1791 			const OUString& rServiceName,
1792             const lang::Locale& rLocale )
1793         throw(uno::RuntimeException)
1794 {
1795     osl::MutexGuard aGuard( GetLinguMutex() );
1796 
1797     uno::Sequence< OUString > aSvcImplNames;
1798 
1799     LanguageType nLanguage = LocaleToLanguage( rLocale );
1800     OUString aCfgLocale( MsLangId::convertLanguageToIsoString( nLanguage ) );
1801 
1802     uno::Sequence< uno::Any > aValues;
1803     uno::Sequence< OUString > aNames( 1 );
1804     OUString *pNames = aNames.getArray();
1805 	if ( 0 == rServiceName.compareToAscii( SN_SPELLCHECKER ) )
1806 	{
1807         OUString aNode( OUString::createFromAscii( "ServiceManager/SpellCheckerList" ));
1808         const uno::Sequence< OUString > aNodeEntries( GetNodeNames( aNode ) );
1809         if (lcl_SeqHasString( aNodeEntries, aCfgLocale ))
1810         {
1811             OUString aPropName( aNode );
1812             aPropName += OUString::valueOf( (sal_Unicode) '/' );
1813             aPropName += aCfgLocale;
1814             pNames[0] = aPropName;
1815             aValues = /*aCfg.*/GetProperties( aNames );
1816             if (aValues.getLength())
1817                 aSvcImplNames = GetLangSvcList( aValues.getConstArray()[0] );
1818         }
1819 	}
1820     else if ( 0 == rServiceName.compareToAscii( SN_GRAMMARCHECKER ) )
1821     {
1822         OUString aNode( OUString::createFromAscii( "ServiceManager/GrammarCheckerList" ));
1823         const uno::Sequence< OUString > aNodeEntries( GetNodeNames( aNode ) );
1824         if (lcl_SeqHasString( aNodeEntries, aCfgLocale ))
1825         {
1826             OUString aPropName( aNode );
1827             aPropName += OUString::valueOf( (sal_Unicode) '/' );
1828             aPropName += aCfgLocale;
1829             pNames[0] = aPropName;
1830             aValues = /*aCfg.*/GetProperties( aNames );
1831             if (aValues.getLength())
1832                 aSvcImplNames = GetLangSvc( aValues.getConstArray()[0] );
1833         }
1834     }
1835 	else if ( 0 == rServiceName.compareToAscii( SN_HYPHENATOR ) )
1836 	{
1837         OUString aNode( OUString::createFromAscii( "ServiceManager/HyphenatorList" ));
1838         const uno::Sequence< OUString > aNodeEntries( GetNodeNames( aNode ) );
1839         if (lcl_SeqHasString( aNodeEntries, aCfgLocale ))
1840         {
1841             OUString aPropName( aNode );
1842             aPropName += OUString::valueOf( (sal_Unicode) '/' );
1843             aPropName += aCfgLocale;
1844             pNames[0] = aPropName;
1845             aValues = /*aCfg.*/GetProperties( aNames );
1846             if (aValues.getLength())
1847                 aSvcImplNames = GetLangSvc( aValues.getConstArray()[0] );
1848         }
1849     }
1850 	else if ( 0 == rServiceName.compareToAscii( SN_THESAURUS ) )
1851 	{
1852         OUString aNode( OUString::createFromAscii( "ServiceManager/ThesaurusList" ));
1853         const uno::Sequence< OUString > aNodeEntries( GetNodeNames( aNode ) );
1854         if (lcl_SeqHasString( aNodeEntries, aCfgLocale ))
1855         {
1856             OUString aPropName( aNode );
1857             aPropName += OUString::valueOf( (sal_Unicode) '/' );
1858             aPropName += aCfgLocale;
1859             pNames[0] = aPropName;
1860             aValues = /*aCfg.*/GetProperties( aNames );
1861             if (aValues.getLength())
1862                 aSvcImplNames = GetLangSvcList( aValues.getConstArray()[0] );
1863         }
1864     }
1865 
1866 #if OSL_DEBUG_LEVEL > 1
1867     const OUString *pImplNames = aSvcImplNames.getConstArray();
1868     (void) pImplNames;
1869 #endif
1870 	return aSvcImplNames;
1871 }
1872 
1873 
1874 void SAL_CALL
1875 	LngSvcMgr::dispose()
1876         throw(uno::RuntimeException)
1877 {
1878     osl::MutexGuard aGuard( GetLinguMutex() );
1879 
1880 	if (!bDisposing)
1881 	{
1882 		bDisposing = sal_True;
1883 
1884 		// require listeners to release this object
1885         lang::EventObject aEvtObj( (XLinguServiceManager *) this );
1886 		aEvtListeners.disposeAndClear( aEvtObj );
1887 
1888 		if (pListenerHelper)
1889 			pListenerHelper->DisposeAndClear( aEvtObj );
1890 	}
1891 }
1892 
1893 
1894 void SAL_CALL
1895 	LngSvcMgr::addEventListener(
1896             const uno::Reference< lang::XEventListener >& xListener )
1897         throw(uno::RuntimeException)
1898 {
1899     osl::MutexGuard aGuard( GetLinguMutex() );
1900 
1901 	if (!bDisposing  &&  xListener.is())
1902 	{
1903         aEvtListeners.addInterface( xListener );
1904 	}
1905 }
1906 
1907 
1908 void SAL_CALL
1909 	LngSvcMgr::removeEventListener(
1910             const uno::Reference< lang::XEventListener >& xListener )
1911         throw(uno::RuntimeException)
1912 {
1913     osl::MutexGuard aGuard( GetLinguMutex() );
1914 
1915 	if (xListener.is())
1916 	{
1917         aEvtListeners.removeInterface( xListener );
1918 	}
1919 }
1920 
1921 
1922 sal_Bool LngSvcMgr::AddLngSvcEvtBroadcaster(
1923             const uno::Reference< linguistic2::XLinguServiceEventBroadcaster > &rxBroadcaster )
1924 {
1925 	sal_Bool bRes = sal_False;
1926 	if (rxBroadcaster.is())
1927 	{
1928 		if (!pListenerHelper)
1929 			GetListenerHelper_Impl();
1930 		bRes = pListenerHelper->AddLngSvcEvtBroadcaster( rxBroadcaster );
1931 	}
1932 	return bRes;
1933 }
1934 
1935 
1936 sal_Bool LngSvcMgr::RemoveLngSvcEvtBroadcaster(
1937             const uno::Reference< linguistic2::XLinguServiceEventBroadcaster > &rxBroadcaster )
1938 {
1939 	sal_Bool bRes = sal_False;
1940 	if (rxBroadcaster.is())
1941 	{
1942 		DBG_ASSERT( pListenerHelper, "pListenerHelper non existent" );
1943 		if (!pListenerHelper)
1944 			GetListenerHelper_Impl();
1945 		bRes = pListenerHelper->RemoveLngSvcEvtBroadcaster( rxBroadcaster );
1946 	}
1947 	return bRes;
1948 }
1949 
1950 
1951 OUString SAL_CALL
1952 	LngSvcMgr::getImplementationName()
1953         throw(uno::RuntimeException)
1954 {
1955     osl::MutexGuard aGuard( GetLinguMutex() );
1956 	return getImplementationName_Static();
1957 }
1958 
1959 
1960 sal_Bool SAL_CALL
1961 	LngSvcMgr::supportsService( const OUString& ServiceName )
1962         throw(uno::RuntimeException)
1963 {
1964     osl::MutexGuard aGuard( GetLinguMutex() );
1965 
1966 	uno::Sequence< OUString > aSNL = getSupportedServiceNames();
1967 	const OUString * pArray = aSNL.getConstArray();
1968 	for( sal_Int32 i = 0; i < aSNL.getLength(); i++ )
1969 		if( pArray[i] == ServiceName )
1970 			return sal_True;
1971 	return sal_False;
1972 }
1973 
1974 
1975 uno::Sequence< OUString > SAL_CALL
1976 	LngSvcMgr::getSupportedServiceNames()
1977         throw(uno::RuntimeException)
1978 {
1979     osl::MutexGuard aGuard( GetLinguMutex() );
1980 	return getSupportedServiceNames_Static();
1981 }
1982 
1983 
1984 uno::Sequence< OUString > LngSvcMgr::getSupportedServiceNames_Static()
1985 		throw()
1986 {
1987     osl::MutexGuard aGuard( GetLinguMutex() );
1988 
1989 	uno::Sequence< OUString > aSNS( 1 );	// auch mehr als 1 Service moeglich
1990 	aSNS.getArray()[0] = A2OU( SN_LINGU_SERVCICE_MANAGER );
1991 	return aSNS;
1992 }
1993 
1994 
1995 uno::Reference< uno::XInterface > SAL_CALL LngSvcMgr_CreateInstance(
1996             const uno::Reference< lang::XMultiServiceFactory > & /*rSMgr*/ )
1997         throw(uno::Exception)
1998 {
1999     uno::Reference< uno::XInterface > xService = (cppu::OWeakObject*) new LngSvcMgr;
2000 	return xService;
2001 }
2002 
2003 void * SAL_CALL LngSvcMgr_getFactory(
2004 			const sal_Char * pImplName,
2005             lang::XMultiServiceFactory * pServiceManager,
2006 			void * /*pRegistryKey*/ )
2007 {
2008 
2009 	void * pRet = 0;
2010 	if ( !LngSvcMgr::getImplementationName_Static().compareToAscii( pImplName ) )
2011 	{
2012         uno::Reference< lang::XSingleServiceFactory > xFactory =
2013 			cppu::createOneInstanceFactory(
2014 				pServiceManager,
2015 				LngSvcMgr::getImplementationName_Static(),
2016 				LngSvcMgr_CreateInstance,
2017 				LngSvcMgr::getSupportedServiceNames_Static());
2018 		// acquire, because we return an interface pointer instead of a reference
2019 		xFactory->acquire();
2020 		pRet = xFactory.get();
2021 	}
2022 	return pRet;
2023 }
2024 
2025 
2026 ///////////////////////////////////////////////////////////////////////////
2027 
2028