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