xref: /trunk/main/linguistic/source/lngsvcmgr.cxx (revision a893be29)
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 
lcl_SeqHasString(const uno::Sequence<OUString> & rSeq,const OUString & rText)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 
GetAvailLocales(const uno::Sequence<OUString> & rSvcImplNames)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 
SvcInfoSvcInfo160     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 
HasLanguage(sal_Int16 nLanguage) const171 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 
SetAvailableCfgServiceLists(LinguDispatcher & rDispatcher,const SvcInfoArray & rAvailSvcs)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 
LngSvcMgrListenerHelper(LngSvcMgr & rLngSvcMgr,const uno::Reference<uno::XInterface> & rxSource,const uno::Reference<linguistic2::XDictionaryList> & rxDicList)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 unnecessary actions of
361 	//! this objects listeners!
362 //	aLaunchTimer.SetTimeout( 2000 );
363 //	aLaunchTimer.SetTimeoutHdl( LINK( this, LngSvcMgrListenerHelper, TimeOut ) );
364 	nCombinedLngSvcEvt = 0;
365 }
366 
367 
disposing(const lang::EventObject & rSource)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 )
Timeout()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 
AddLngSvcEvt(sal_Int16 nLngSvcEvt)413 void LngSvcMgrListenerHelper::AddLngSvcEvt( sal_Int16 nLngSvcEvt )
414 {
415     nCombinedLngSvcEvt |= nLngSvcEvt;
416 //	aLaunchTimer.Start();
417 	Timeout();
418 }
419 
420 
421 void SAL_CALL
processLinguServiceEvent(const linguistic2::LinguServiceEvent & rLngSvcEvent)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
processDictionaryListEvent(const linguistic2::DictionaryListEvent & rDicListEvent)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 
LaunchEvent(sal_Int16 nLngSvcEvtFlags)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 
AddLngSvcMgrListener(const uno::Reference<lang::XEventListener> & rxListener)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 
RemoveLngSvcMgrListener(const uno::Reference<lang::XEventListener> & rxListener)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 
DisposeAndClear(const lang::EventObject & rEvtObj)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 
AddLngSvcEvtBroadcaster(const uno::Reference<linguistic2::XLinguServiceEventBroadcaster> & rxBroadcaster)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 
RemoveLngSvcEvtBroadcaster(const uno::Reference<linguistic2::XLinguServiceEventBroadcaster> & rxBroadcaster)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 
LngSvcMgr()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 
clearSvcInfoArray(SvcInfoArray * pInfo)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 
~LngSvcMgr()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 
Notify(const uno::Sequence<OUString> & rPropertyNames)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 
Commit()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 
GetListenerHelper_Impl()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 
GetSpellCheckerDsp_Impl(sal_Bool bSetSvcList)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 
GetGrammarCheckerDsp_Impl(sal_Bool bSetSvcList)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 
GetHyphenatorDsp_Impl(sal_Bool bSetSvcList)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 
GetThesaurusDsp_Impl(sal_Bool bSetSvcList)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 
GetAvailableSpellSvcs_Impl()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 
GetAvailableGrammarSvcs_Impl()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 
GetAvailableHyphSvcs_Impl()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 
GetAvailableThesSvcs_Impl()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 
SetCfgServiceLists(SpellCheckerDispatcher & rSpellDsp)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 
SetCfgServiceLists(GrammarCheckingIterator & rGrammarDsp)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 
SetCfgServiceLists(HyphenatorDispatcher & rHyphDsp)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 
SetCfgServiceLists(ThesaurusDispatcher & rThesDsp)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
getSpellChecker()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
getHyphenator()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
getThesaurus()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
addLinguServiceManagerListener(const uno::Reference<lang::XEventListener> & xListener)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
removeLinguServiceManagerListener(const uno::Reference<lang::XEventListener> & xListener)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
getAvailableServices(const OUString & rServiceName,const lang::Locale & rLocale)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 clear cache as it makes start with some extensions so slow it looks
1418         // like a freeze (a restart is needed anyway after grammar checker installation),
1419         // see https://issues.apache.org/ooo/show_bug.cgi?id=116409
1420         //clearSvcInfoArray(pAvailGrammarSvcs);  pAvailGrammarSvcs = 0;
1421         GetAvailableGrammarSvcs_Impl();
1422         pInfoArray = pAvailGrammarSvcs;
1423     }
1424 	else if (0 == rServiceName.compareToAscii( SN_HYPHENATOR ))
1425 	{
1426         // don't used cached data here (force re-evaluation in order to have downloaded dictionaries
1427         // already found without the need to restart the office
1428 		clearSvcInfoArray(pAvailHyphSvcs);  pAvailHyphSvcs = 0;
1429 		GetAvailableHyphSvcs_Impl();
1430 		pInfoArray = pAvailHyphSvcs;
1431 	}
1432 	else if (0 == rServiceName.compareToAscii( SN_THESAURUS ))
1433 	{
1434         // don't used cached data here (force re-evaluation in order to have downloaded dictionaries
1435         // already found without the need to restart the office
1436 		clearSvcInfoArray(pAvailThesSvcs);  pAvailThesSvcs = 0;
1437 		GetAvailableThesSvcs_Impl();
1438 		pInfoArray = pAvailThesSvcs;
1439 	}
1440 
1441 	if (pInfoArray)
1442 	{
1443 		// resize to max number of entries
1444         size_t nMaxCnt = pInfoArray->size();
1445 		aRes.realloc( nMaxCnt );
1446 		OUString *pImplName = aRes.getArray();
1447 
1448 		sal_uInt16 nCnt = 0;
1449         LanguageType nLanguage = LocaleToLanguage( rLocale );
1450         for (size_t i = 0;  i < nMaxCnt;  ++i)
1451 		{
1452             const SvcInfo *pInfo = (*pInfoArray)[i];
1453 			if (LANGUAGE_NONE == nLanguage
1454 				|| (pInfo && pInfo->HasLanguage( nLanguage )))
1455 			{
1456 				pImplName[ nCnt++ ] = pInfo->aSvcImplName;
1457 			}
1458 		}
1459 
1460 		// resize to actual number of entries
1461 		if (nCnt != nMaxCnt)
1462 			aRes.realloc( nCnt );
1463 	}
1464 
1465 	return aRes;
1466 }
1467 
1468 
1469 uno::Sequence< lang::Locale > SAL_CALL
getAvailableLocales(const OUString & rServiceName)1470 	LngSvcMgr::getAvailableLocales(
1471 			const OUString& rServiceName )
1472         throw(uno::RuntimeException)
1473 {
1474     osl::MutexGuard aGuard( GetLinguMutex() );
1475 
1476     uno::Sequence< lang::Locale > aRes;
1477 
1478     uno::Sequence< lang::Locale >  *pAvailLocales     = NULL;
1479 	sal_Bool				*pHasAvailLocales	= NULL;
1480 	if (0 == rServiceName.compareToAscii( SN_SPELLCHECKER ))
1481 	{
1482 		pAvailLocales		= &aAvailSpellLocales;
1483 		pHasAvailLocales	= &bHasAvailSpellLocales;
1484 	}
1485     else if (0 == rServiceName.compareToAscii( SN_GRAMMARCHECKER ))
1486     {
1487         pAvailLocales       = &aAvailGrammarLocales;
1488         pHasAvailLocales    = &bHasAvailGrammarLocales;
1489     }
1490 	else if (0 == rServiceName.compareToAscii( SN_HYPHENATOR ))
1491 	{
1492 		pAvailLocales		= &aAvailHyphLocales;
1493 		pHasAvailLocales	= &bHasAvailHyphLocales;
1494 	}
1495 	else if (0 == rServiceName.compareToAscii( SN_THESAURUS ))
1496 	{
1497 		pAvailLocales		= &aAvailThesLocales;
1498 		pHasAvailLocales	= &bHasAvailThesLocales;
1499 	}
1500 
1501 	// about pHasAvailLocales: nowadays (with OOo lingu in SO) we want to know immediately about
1502 	// new downloaded dictionaries and have them ready right away if the Tools/Options...
1503 	// is used to activate them. Thus we can not rely anymore on buffered data.
1504 	if (pAvailLocales  /*&&  pHasAvailLocales */)
1505 	{
1506 //		if (!*pHasAvailLocales)
1507 //		{
1508 			*pAvailLocales = GetAvailLocales(
1509                     getAvailableServices( rServiceName, lang::Locale() ) );
1510 //			*pHasAvailLocales = sal_True;
1511 //		}
1512 		aRes = *pAvailLocales;
1513 	}
1514 
1515 	return aRes;
1516 }
1517 
IsEqSvcList(const uno::Sequence<OUString> & rList1,const uno::Sequence<OUString> & rList2)1518 static sal_Bool IsEqSvcList( const uno::Sequence< OUString > &rList1,
1519                         const uno::Sequence< OUString > &rList2 )
1520 {
1521     // returns sal_True iff both sequences are equal
1522 
1523     sal_Bool bRes = sal_False;
1524     sal_Int32 nLen = rList1.getLength();
1525     if (rList2.getLength() == nLen)
1526     {
1527         const OUString *pStr1 = rList1.getConstArray();
1528         const OUString *pStr2 = rList2.getConstArray();
1529         bRes = sal_True;
1530         for (sal_Int32 i = 0;  i < nLen  &&  bRes;  ++i)
1531         {
1532             if (*pStr1++ != *pStr2++)
1533                 bRes = sal_False;
1534         }
1535     }
1536     return bRes;
1537 }
1538 
1539 
1540 void SAL_CALL
setConfiguredServices(const OUString & rServiceName,const lang::Locale & rLocale,const uno::Sequence<OUString> & rServiceImplNames)1541 	LngSvcMgr::setConfiguredServices(
1542 			const OUString& rServiceName,
1543             const lang::Locale& rLocale,
1544             const uno::Sequence< OUString >& rServiceImplNames )
1545         throw(uno::RuntimeException)
1546 {
1547     RTL_LOGFILE_CONTEXT( aLog, "linguistic: LngSvcMgr::setConfiguredServices" );
1548 
1549     osl::MutexGuard aGuard( GetLinguMutex() );
1550 
1551 #if OSL_DEBUG_LEVEL > 1
1552 //    const OUString *pImplNames = rServiceImplNames.getConstArray();
1553 #endif
1554 
1555     LanguageType nLanguage = LocaleToLanguage( rLocale );
1556     if (LANGUAGE_NONE != nLanguage)
1557 	{
1558 		if (0 == rServiceName.compareToAscii( SN_SPELLCHECKER ))
1559 		{
1560 			if (!xSpellDsp.is())
1561 				GetSpellCheckerDsp_Impl();
1562             sal_Bool bChanged = !IsEqSvcList( rServiceImplNames,
1563                                           pSpellDsp->GetServiceList( rLocale ) );
1564             if (bChanged)
1565             {
1566                 pSpellDsp->SetServiceList( rLocale, rServiceImplNames );
1567                 SaveCfgSvcs( A2OU( SN_SPELLCHECKER ) );
1568 
1569                 if (pListenerHelper  &&  bChanged)
1570                     pListenerHelper->AddLngSvcEvt(
1571                             linguistic2::LinguServiceEventFlags::SPELL_CORRECT_WORDS_AGAIN |
1572                             linguistic2::LinguServiceEventFlags::SPELL_WRONG_WORDS_AGAIN );
1573             }
1574 		}
1575         else if (0 == rServiceName.compareToAscii( SN_GRAMMARCHECKER ))
1576         {
1577             if (!xGrammarDsp.is())
1578                 GetGrammarCheckerDsp_Impl();
1579             sal_Bool bChanged = !IsEqSvcList( rServiceImplNames,
1580                                           pGrammarDsp->GetServiceList( rLocale ) );
1581             if (bChanged)
1582             {
1583                 pGrammarDsp->SetServiceList( rLocale, rServiceImplNames );
1584                 SaveCfgSvcs( A2OU( SN_GRAMMARCHECKER ) );
1585 
1586                 if (pListenerHelper  &&  bChanged)
1587                     pListenerHelper->AddLngSvcEvt(
1588                             linguistic2::LinguServiceEventFlags::PROOFREAD_AGAIN );
1589             }
1590         }
1591 		else if (0 == rServiceName.compareToAscii( SN_HYPHENATOR ))
1592 		{
1593 			if (!xHyphDsp.is())
1594 				GetHyphenatorDsp_Impl();
1595             sal_Bool bChanged = !IsEqSvcList( rServiceImplNames,
1596                                           pHyphDsp->GetServiceList( rLocale ) );
1597             if (bChanged)
1598             {
1599                 pHyphDsp->SetServiceList( rLocale, rServiceImplNames );
1600                 SaveCfgSvcs( A2OU( SN_HYPHENATOR ) );
1601 
1602                 if (pListenerHelper  &&  bChanged)
1603                     pListenerHelper->AddLngSvcEvt(
1604                             linguistic2::LinguServiceEventFlags::HYPHENATE_AGAIN );
1605             }
1606 		}
1607 		else if (0 == rServiceName.compareToAscii( SN_THESAURUS ))
1608 		{
1609 			if (!xThesDsp.is())
1610 				GetThesaurusDsp_Impl();
1611             sal_Bool bChanged = !IsEqSvcList( rServiceImplNames,
1612                                           pThesDsp->GetServiceList( rLocale ) );
1613             if (bChanged)
1614             {
1615                 pThesDsp->SetServiceList( rLocale, rServiceImplNames );
1616                 SaveCfgSvcs( A2OU( SN_THESAURUS ) );
1617             }
1618 		}
1619 	}
1620 }
1621 
1622 
SaveCfgSvcs(const String & rServiceName)1623 sal_Bool LngSvcMgr::SaveCfgSvcs( const String &rServiceName )
1624 {
1625     RTL_LOGFILE_CONTEXT( aLog, "linguistic: LngSvcMgr::SaveCfgSvcs" );
1626 
1627     sal_Bool bRes = sal_False;
1628 
1629 	LinguDispatcher *pDsp = 0;
1630     uno::Sequence< lang::Locale > aLocales;
1631 
1632 	if (0 == rServiceName.CompareToAscii( SN_SPELLCHECKER ))
1633 	{
1634 		if (!pSpellDsp)
1635 			GetSpellCheckerDsp_Impl();
1636 		pDsp = pSpellDsp;
1637         aLocales = getAvailableLocales( A2OU( SN_SPELLCHECKER ) );
1638 	}
1639     else if (0 == rServiceName.CompareToAscii( SN_GRAMMARCHECKER ))
1640     {
1641         if (!pGrammarDsp)
1642             GetGrammarCheckerDsp_Impl();
1643         pDsp = pGrammarDsp;
1644         aLocales = getAvailableLocales( A2OU( SN_GRAMMARCHECKER ) );
1645     }
1646 	else if (0 == rServiceName.CompareToAscii( SN_HYPHENATOR ))
1647 	{
1648 		if (!pHyphDsp)
1649 			GetHyphenatorDsp_Impl();
1650 		pDsp = pHyphDsp;
1651         aLocales = getAvailableLocales( A2OU( SN_HYPHENATOR ) );
1652 	}
1653 	else if (0 == rServiceName.CompareToAscii( SN_THESAURUS ))
1654 	{
1655 		if (!pThesDsp)
1656 			GetThesaurusDsp_Impl();
1657 		pDsp = pThesDsp;
1658         aLocales = getAvailableLocales( A2OU( SN_THESAURUS ) );
1659 	}
1660 
1661 	if (pDsp  &&  aLocales.getLength())
1662 	{
1663         sal_Int32 nLen = aLocales.getLength();
1664         const lang::Locale *pLocale = aLocales.getConstArray();
1665 
1666         uno::Sequence< beans::PropertyValue > aValues( nLen );
1667         beans::PropertyValue *pValues = aValues.getArray();
1668         beans::PropertyValue *pValue  = pValues;
1669 
1670         // get node name to be used
1671         const char *pNodeName = NULL;
1672         if (pDsp == pSpellDsp)
1673             pNodeName = "ServiceManager/SpellCheckerList";
1674         else if (pDsp == pGrammarDsp)
1675             pNodeName = "ServiceManager/GrammarCheckerList";
1676         else if (pDsp == pHyphDsp)
1677             pNodeName = "ServiceManager/HyphenatorList";
1678         else if (pDsp == pThesDsp)
1679             pNodeName = "ServiceManager/ThesaurusList";
1680         else
1681         {
1682             DBG_ASSERT( 0, "node name missing" );
1683         }
1684         OUString aNodeName( A2OU(pNodeName) );
1685 
1686 		for (sal_Int32 i = 0;  i < nLen;  ++i)
1687 		{
1688             uno::Sequence< OUString > aSvcImplNames;
1689 			aSvcImplNames = pDsp->GetServiceList( pLocale[i] );
1690 
1691 #if OSL_DEBUG_LEVEL > 1
1692 			sal_Int32 nSvcs = aSvcImplNames.getLength();
1693 			const OUString *pSvcImplName = aSvcImplNames.getConstArray();
1694 			for (sal_Int32 j = 0;  j < nSvcs;  ++j)
1695 			{
1696 				OUString aImplName( pSvcImplName[j] );
1697 			}
1698 #endif
1699 			// build value to be written back to configuration
1700             uno::Any aCfgAny;
1701             if ((pDsp == pHyphDsp || pDsp == pGrammarDsp) && aSvcImplNames.getLength() > 1)
1702                 aSvcImplNames.realloc(1);   // there should be only one entry for hyphenators or grammar checkers (because they are not chained)
1703             aCfgAny <<= aSvcImplNames;
1704 			DBG_ASSERT( aCfgAny.hasValue(), "missing value for 'Any' type" );
1705 
1706 			OUString aCfgLocaleStr( MsLangId::convertLanguageToIsoString(
1707 										LocaleToLanguage( pLocale[i] ) ) );
1708             pValue->Value = aCfgAny;
1709             pValue->Name  = aNodeName;
1710             pValue->Name += OUString::valueOf( (sal_Unicode) '/' );
1711             pValue->Name += aCfgLocaleStr;
1712             pValue++;
1713 		}
1714         {
1715         RTL_LOGFILE_CONTEXT( aLog, "linguistic: LngSvcMgr::SaveCfgSvcs - ReplaceSetProperties" );
1716         // change, add new or replace existing entries.
1717         bRes |= /*aCfg.*/ReplaceSetProperties( aNodeName, aValues );
1718         }
1719 	}
1720 
1721 	return bRes;
1722 }
1723 
1724 
GetLangSvcList(const uno::Any & rVal)1725 static uno::Sequence< OUString > GetLangSvcList( const uno::Any &rVal )
1726 {
1727     uno::Sequence< OUString > aRes;
1728 
1729 	if (rVal.hasValue())
1730 	{
1731 		rVal >>= aRes;
1732 #if OSL_DEBUG_LEVEL > 1
1733 		sal_Int32 nSvcs = aRes.getLength();
1734 		if (nSvcs)
1735 		{
1736 			const OUString *pSvcName = aRes.getConstArray();
1737 			for (sal_Int32 j = 0;  j < nSvcs;  ++j)
1738 			{
1739 				OUString aImplName( pSvcName[j] );
1740                 DBG_ASSERT( aImplName.getLength(), "service impl-name missing" );
1741 			}
1742 		}
1743 #endif
1744 	}
1745 
1746 	return aRes;
1747 }
1748 
1749 
GetLangSvc(const uno::Any & rVal)1750 static uno::Sequence< OUString > GetLangSvc( const uno::Any &rVal )
1751 {
1752     uno::Sequence< OUString > aRes;
1753 	if (!rVal.hasValue())
1754 		return aRes;
1755 
1756 	// allowing for a sequence here as well (even though it should only
1757 	// be a string) makes coding easier in other places since one needs
1758 	// not make a special case for writing a string only and not a
1759 	// sequence of strings.
1760 	if (rVal >>= aRes)
1761 	{
1762 		// but only the first string should be used.
1763 		if (aRes.getLength() > 1)
1764 			aRes.realloc(1);
1765 	}
1766 	else
1767 	{
1768 		OUString aImplName;
1769 		if ((rVal >>= aImplName) && aImplName.getLength() != 0)
1770 		{
1771 			aRes.realloc(1);
1772 			aRes.getArray()[0] = aImplName;
1773 		}
1774         else
1775         {
1776             DBG_ASSERT( 0, "GetLangSvc: unexpected type encountered" );
1777         }
1778 	}
1779 
1780 	return aRes;
1781 }
1782 
1783 
1784 ///////////////////////////////////////////////////////////////////////////
1785 
1786 uno::Sequence< OUString > SAL_CALL
getConfiguredServices(const OUString & rServiceName,const lang::Locale & rLocale)1787 	LngSvcMgr::getConfiguredServices(
1788 			const OUString& rServiceName,
1789             const lang::Locale& rLocale )
1790         throw(uno::RuntimeException)
1791 {
1792     osl::MutexGuard aGuard( GetLinguMutex() );
1793 
1794     uno::Sequence< OUString > aSvcImplNames;
1795 
1796     LanguageType nLanguage = LocaleToLanguage( rLocale );
1797     OUString aCfgLocale( MsLangId::convertLanguageToIsoString( nLanguage ) );
1798 
1799     uno::Sequence< uno::Any > aValues;
1800     uno::Sequence< OUString > aNames( 1 );
1801     OUString *pNames = aNames.getArray();
1802 	if ( 0 == rServiceName.compareToAscii( SN_SPELLCHECKER ) )
1803 	{
1804         OUString aNode( OUString::createFromAscii( "ServiceManager/SpellCheckerList" ));
1805         const uno::Sequence< OUString > aNodeEntries( GetNodeNames( aNode ) );
1806         if (lcl_SeqHasString( aNodeEntries, aCfgLocale ))
1807         {
1808             OUString aPropName( aNode );
1809             aPropName += OUString::valueOf( (sal_Unicode) '/' );
1810             aPropName += aCfgLocale;
1811             pNames[0] = aPropName;
1812             aValues = /*aCfg.*/GetProperties( aNames );
1813             if (aValues.getLength())
1814                 aSvcImplNames = GetLangSvcList( aValues.getConstArray()[0] );
1815         }
1816 	}
1817     else if ( 0 == rServiceName.compareToAscii( SN_GRAMMARCHECKER ) )
1818     {
1819         OUString aNode( OUString::createFromAscii( "ServiceManager/GrammarCheckerList" ));
1820         const uno::Sequence< OUString > aNodeEntries( GetNodeNames( aNode ) );
1821         if (lcl_SeqHasString( aNodeEntries, aCfgLocale ))
1822         {
1823             OUString aPropName( aNode );
1824             aPropName += OUString::valueOf( (sal_Unicode) '/' );
1825             aPropName += aCfgLocale;
1826             pNames[0] = aPropName;
1827             aValues = /*aCfg.*/GetProperties( aNames );
1828             if (aValues.getLength())
1829                 aSvcImplNames = GetLangSvc( aValues.getConstArray()[0] );
1830         }
1831     }
1832 	else if ( 0 == rServiceName.compareToAscii( SN_HYPHENATOR ) )
1833 	{
1834         OUString aNode( OUString::createFromAscii( "ServiceManager/HyphenatorList" ));
1835         const uno::Sequence< OUString > aNodeEntries( GetNodeNames( aNode ) );
1836         if (lcl_SeqHasString( aNodeEntries, aCfgLocale ))
1837         {
1838             OUString aPropName( aNode );
1839             aPropName += OUString::valueOf( (sal_Unicode) '/' );
1840             aPropName += aCfgLocale;
1841             pNames[0] = aPropName;
1842             aValues = /*aCfg.*/GetProperties( aNames );
1843             if (aValues.getLength())
1844                 aSvcImplNames = GetLangSvc( aValues.getConstArray()[0] );
1845         }
1846     }
1847 	else if ( 0 == rServiceName.compareToAscii( SN_THESAURUS ) )
1848 	{
1849         OUString aNode( OUString::createFromAscii( "ServiceManager/ThesaurusList" ));
1850         const uno::Sequence< OUString > aNodeEntries( GetNodeNames( aNode ) );
1851         if (lcl_SeqHasString( aNodeEntries, aCfgLocale ))
1852         {
1853             OUString aPropName( aNode );
1854             aPropName += OUString::valueOf( (sal_Unicode) '/' );
1855             aPropName += aCfgLocale;
1856             pNames[0] = aPropName;
1857             aValues = /*aCfg.*/GetProperties( aNames );
1858             if (aValues.getLength())
1859                 aSvcImplNames = GetLangSvcList( aValues.getConstArray()[0] );
1860         }
1861     }
1862 
1863 #if OSL_DEBUG_LEVEL > 1
1864     const OUString *pImplNames = aSvcImplNames.getConstArray();
1865     (void) pImplNames;
1866 #endif
1867 	return aSvcImplNames;
1868 }
1869 
1870 
1871 void SAL_CALL
dispose()1872 	LngSvcMgr::dispose()
1873         throw(uno::RuntimeException)
1874 {
1875     osl::MutexGuard aGuard( GetLinguMutex() );
1876 
1877 	if (!bDisposing)
1878 	{
1879 		bDisposing = sal_True;
1880 
1881 		// require listeners to release this object
1882         lang::EventObject aEvtObj( (XLinguServiceManager *) this );
1883 		aEvtListeners.disposeAndClear( aEvtObj );
1884 
1885 		if (pListenerHelper)
1886 			pListenerHelper->DisposeAndClear( aEvtObj );
1887 	}
1888 }
1889 
1890 
1891 void SAL_CALL
addEventListener(const uno::Reference<lang::XEventListener> & xListener)1892 	LngSvcMgr::addEventListener(
1893             const uno::Reference< lang::XEventListener >& xListener )
1894         throw(uno::RuntimeException)
1895 {
1896     osl::MutexGuard aGuard( GetLinguMutex() );
1897 
1898 	if (!bDisposing  &&  xListener.is())
1899 	{
1900         aEvtListeners.addInterface( xListener );
1901 	}
1902 }
1903 
1904 
1905 void SAL_CALL
removeEventListener(const uno::Reference<lang::XEventListener> & xListener)1906 	LngSvcMgr::removeEventListener(
1907             const uno::Reference< lang::XEventListener >& xListener )
1908         throw(uno::RuntimeException)
1909 {
1910     osl::MutexGuard aGuard( GetLinguMutex() );
1911 
1912 	if (xListener.is())
1913 	{
1914         aEvtListeners.removeInterface( xListener );
1915 	}
1916 }
1917 
1918 
AddLngSvcEvtBroadcaster(const uno::Reference<linguistic2::XLinguServiceEventBroadcaster> & rxBroadcaster)1919 sal_Bool LngSvcMgr::AddLngSvcEvtBroadcaster(
1920             const uno::Reference< linguistic2::XLinguServiceEventBroadcaster > &rxBroadcaster )
1921 {
1922 	sal_Bool bRes = sal_False;
1923 	if (rxBroadcaster.is())
1924 	{
1925 		if (!pListenerHelper)
1926 			GetListenerHelper_Impl();
1927 		bRes = pListenerHelper->AddLngSvcEvtBroadcaster( rxBroadcaster );
1928 	}
1929 	return bRes;
1930 }
1931 
1932 
RemoveLngSvcEvtBroadcaster(const uno::Reference<linguistic2::XLinguServiceEventBroadcaster> & rxBroadcaster)1933 sal_Bool LngSvcMgr::RemoveLngSvcEvtBroadcaster(
1934             const uno::Reference< linguistic2::XLinguServiceEventBroadcaster > &rxBroadcaster )
1935 {
1936 	sal_Bool bRes = sal_False;
1937 	if (rxBroadcaster.is())
1938 	{
1939 		DBG_ASSERT( pListenerHelper, "pListenerHelper non existent" );
1940 		if (!pListenerHelper)
1941 			GetListenerHelper_Impl();
1942 		bRes = pListenerHelper->RemoveLngSvcEvtBroadcaster( rxBroadcaster );
1943 	}
1944 	return bRes;
1945 }
1946 
1947 
1948 OUString SAL_CALL
getImplementationName()1949 	LngSvcMgr::getImplementationName()
1950         throw(uno::RuntimeException)
1951 {
1952     osl::MutexGuard aGuard( GetLinguMutex() );
1953 	return getImplementationName_Static();
1954 }
1955 
1956 
1957 sal_Bool SAL_CALL
supportsService(const OUString & ServiceName)1958 	LngSvcMgr::supportsService( const OUString& ServiceName )
1959         throw(uno::RuntimeException)
1960 {
1961     osl::MutexGuard aGuard( GetLinguMutex() );
1962 
1963 	uno::Sequence< OUString > aSNL = getSupportedServiceNames();
1964 	const OUString * pArray = aSNL.getConstArray();
1965 	for( sal_Int32 i = 0; i < aSNL.getLength(); i++ )
1966 		if( pArray[i] == ServiceName )
1967 			return sal_True;
1968 	return sal_False;
1969 }
1970 
1971 
1972 uno::Sequence< OUString > SAL_CALL
getSupportedServiceNames()1973 	LngSvcMgr::getSupportedServiceNames()
1974         throw(uno::RuntimeException)
1975 {
1976     osl::MutexGuard aGuard( GetLinguMutex() );
1977 	return getSupportedServiceNames_Static();
1978 }
1979 
1980 
getSupportedServiceNames_Static()1981 uno::Sequence< OUString > LngSvcMgr::getSupportedServiceNames_Static()
1982 		throw()
1983 {
1984     osl::MutexGuard aGuard( GetLinguMutex() );
1985 
1986 	uno::Sequence< OUString > aSNS( 1 );	// auch mehr als 1 Service moeglich
1987 	aSNS.getArray()[0] = A2OU( SN_LINGU_SERVCICE_MANAGER );
1988 	return aSNS;
1989 }
1990 
1991 
LngSvcMgr_CreateInstance(const uno::Reference<lang::XMultiServiceFactory> &)1992 uno::Reference< uno::XInterface > SAL_CALL LngSvcMgr_CreateInstance(
1993             const uno::Reference< lang::XMultiServiceFactory > & /*rSMgr*/ )
1994         throw(uno::Exception)
1995 {
1996     uno::Reference< uno::XInterface > xService = (cppu::OWeakObject*) new LngSvcMgr;
1997 	return xService;
1998 }
1999 
LngSvcMgr_getFactory(const sal_Char * pImplName,lang::XMultiServiceFactory * pServiceManager,void *)2000 void * SAL_CALL LngSvcMgr_getFactory(
2001 			const sal_Char * pImplName,
2002             lang::XMultiServiceFactory * pServiceManager,
2003 			void * /*pRegistryKey*/ )
2004 {
2005 
2006 	void * pRet = 0;
2007 	if ( !LngSvcMgr::getImplementationName_Static().compareToAscii( pImplName ) )
2008 	{
2009         uno::Reference< lang::XSingleServiceFactory > xFactory =
2010 			cppu::createOneInstanceFactory(
2011 				pServiceManager,
2012 				LngSvcMgr::getImplementationName_Static(),
2013 				LngSvcMgr_CreateInstance,
2014 				LngSvcMgr::getSupportedServiceNames_Static());
2015 		// acquire, because we return an interface pointer instead of a reference
2016 		xFactory->acquire();
2017 		pRet = xFactory.get();
2018 	}
2019 	return pRet;
2020 }
2021 
2022 
2023 ///////////////////////////////////////////////////////////////////////////
2024 
2025