xref: /trunk/main/linguistic/source/lngsvcmgr.cxx (revision 91144cd0085a7583d2099b982122deb2184ab956)
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