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