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