LCOV - code coverage report
Current view: top level - linguistic/source - lngsvcmgr.cxx (source / functions) Hit Total Coverage
Test: commit 10e77ab3ff6f4314137acd6e2702a6e5c1ce1fae Lines: 693 1052 65.9 %
Date: 2014-11-03 Functions: 50 72 69.4 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.10