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

Generated by: LCOV version 1.10