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