LCOV - code coverage report
Current view: top level - usr/local/src/libreoffice/linguistic/source - spelldsp.cxx (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 159 381 41.7 %
Date: 2013-07-09 Functions: 15 31 48.4 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /*
       3             :  * This file is part of the LibreOffice project.
       4             :  *
       5             :  * This Source Code Form is subject to the terms of the Mozilla Public
       6             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       7             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       8             :  *
       9             :  * This file incorporates work covered by the following license notice:
      10             :  *
      11             :  *   Licensed to the Apache Software Foundation (ASF) under one or more
      12             :  *   contributor license agreements. See the NOTICE file distributed
      13             :  *   with this work for additional information regarding copyright
      14             :  *   ownership. The ASF licenses this file to you under the Apache
      15             :  *   License, Version 2.0 (the "License"); you may not use this file
      16             :  *   except in compliance with the License. You may obtain a copy of
      17             :  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
      18             :  */
      19             : 
      20             : 
      21             : #include <com/sun/star/uno/Reference.h>
      22             : #include <com/sun/star/linguistic2/XSearchableDictionaryList.hpp>
      23             : #include <com/sun/star/linguistic2/SpellFailure.hpp>
      24             : #include <com/sun/star/registry/XRegistryKey.hpp>
      25             : 
      26             : #include <cppuhelper/factory.hxx>   // helper for factories
      27             : #include <unotools/localedatawrapper.hxx>
      28             : #include <comphelper/processfactory.hxx>
      29             : #include <tools/debug.hxx>
      30             : #include <svl/lngmisc.hxx>
      31             : #include <osl/mutex.hxx>
      32             : 
      33             : #include <vector>
      34             : 
      35             : #include "spelldsp.hxx"
      36             : #include "linguistic/spelldta.hxx"
      37             : #include "lngsvcmgr.hxx"
      38             : #include "linguistic/lngprops.hxx"
      39             : 
      40             : using namespace osl;
      41             : using namespace com::sun::star;
      42             : using namespace com::sun::star::beans;
      43             : using namespace com::sun::star::lang;
      44             : using namespace com::sun::star::uno;
      45             : using namespace com::sun::star::linguistic2;
      46             : using namespace linguistic;
      47             : 
      48             : 
      49             : // ProposalList: list of proposals for misspelled words
      50             : //   The order of strings in the array should be left unchanged because the
      51             : // spellchecker should have put the more likely suggestions at the top.
      52             : // New entries will be added to the end but duplicates are to be avoided.
      53             : // Removing entries is done by assigning the empty string.
      54             : // The sequence is constructed from all non empty strings in the original
      55             : // while maintaining the order.
      56           0 : class ProposalList
      57             : {
      58             :     std::vector< OUString > aVec;
      59             : 
      60             :     sal_Bool    HasEntry( const OUString &rText ) const;
      61             : 
      62             :     // make copy c-tor and assignment operator private
      63             :     ProposalList( const ProposalList & );
      64             :     ProposalList & operator = ( const ProposalList & );
      65             : 
      66             : public:
      67           0 :     ProposalList()  {}
      68             : 
      69             :     size_t  Count() const;
      70             :     void    Prepend( const OUString &rText );
      71             :     void    Append( const OUString &rNew );
      72             :     void    Append( const std::vector< OUString > &rNew );
      73             :     void    Append( const Sequence< OUString > &rNew );
      74             :     Sequence< OUString >    GetSequence() const;
      75             : };
      76             : 
      77             : 
      78           0 : sal_Bool ProposalList::HasEntry( const OUString &rText ) const
      79             : {
      80           0 :     sal_Bool bFound = sal_False;
      81           0 :     size_t nCnt = aVec.size();
      82           0 :     for (size_t i = 0;  !bFound && i < nCnt;  ++i)
      83             :     {
      84           0 :         if (aVec[i] == rText)
      85           0 :             bFound = sal_True;
      86             :     }
      87           0 :     return bFound;
      88             : }
      89             : 
      90           0 : void ProposalList::Prepend( const OUString &rText )
      91             : {
      92           0 :     if (!HasEntry( rText ))
      93           0 :         aVec.insert( aVec.begin(), rText );
      94           0 : }
      95             : 
      96           0 : void ProposalList::Append( const OUString &rText )
      97             : {
      98           0 :     if (!HasEntry( rText ))
      99           0 :         aVec.push_back( rText );
     100           0 : }
     101             : 
     102           0 : void ProposalList::Append( const std::vector< OUString > &rNew )
     103             : {
     104           0 :     size_t nLen = rNew.size();
     105           0 :     for ( size_t i = 0;  i < nLen;  ++i)
     106             :     {
     107           0 :         const OUString &rText = rNew[i];
     108           0 :         if (!HasEntry( rText ))
     109           0 :             Append( rText );
     110             :     }
     111           0 : }
     112             : 
     113           0 : void ProposalList::Append( const Sequence< OUString > &rNew )
     114             : {
     115           0 :     sal_Int32 nLen = rNew.getLength();
     116           0 :     const OUString *pNew = rNew.getConstArray();
     117           0 :     for (sal_Int32 i = 0;  i < nLen;  ++i)
     118             :     {
     119           0 :         const OUString &rText = pNew[i];
     120           0 :         if (!HasEntry( rText ))
     121           0 :             Append( rText );
     122             :     }
     123           0 : }
     124             : 
     125           0 : size_t ProposalList::Count() const
     126             : {
     127             :     // returns the number of non-empty strings in the vector
     128             : 
     129           0 :     size_t nRes = 0;
     130           0 :     size_t nLen = aVec.size();
     131           0 :     for (size_t i = 0;  i < nLen;  ++i)
     132             :     {
     133           0 :         if (!aVec[i].isEmpty())
     134           0 :             ++nRes;
     135             :     }
     136           0 :     return nRes;
     137             : }
     138             : 
     139           0 : Sequence< OUString > ProposalList::GetSequence() const
     140             : {
     141           0 :     sal_Int32 nCount = Count();
     142           0 :     sal_Int32 nIdx = 0;
     143           0 :     Sequence< OUString > aRes( nCount );
     144           0 :     OUString *pRes = aRes.getArray();
     145           0 :     sal_Int32 nLen = aVec.size();
     146           0 :     for (sal_Int32 i = 0;  i < nLen;  ++i)
     147             :     {
     148           0 :         const OUString &rText = aVec[i];
     149             :         DBG_ASSERT( nIdx < nCount, "index our of range" );
     150           0 :         if (nIdx < nCount && !rText.isEmpty())
     151           0 :             pRes[ nIdx++ ] = rText;
     152             :     }
     153           0 :     return aRes;
     154             : }
     155             : 
     156          19 : sal_Bool SvcListHasLanguage(
     157             :         const LangSvcEntries_Spell &rEntry,
     158             :         LanguageType nLanguage )
     159             : {
     160          19 :     sal_Bool bHasLanguage = sal_False;
     161          19 :     Locale aTmpLocale;
     162             : 
     163          19 :     const Reference< XSpellChecker >  *pRef  = rEntry.aSvcRefs .getConstArray();
     164          19 :     sal_Int32 nLen = rEntry.aSvcRefs.getLength();
     165          38 :     for (sal_Int32 k = 0;  k < nLen  &&  !bHasLanguage;  ++k)
     166             :     {
     167          19 :         if (pRef[k].is())
     168             :         {
     169          19 :             if (aTmpLocale.Language.isEmpty())
     170          19 :                 aTmpLocale = LanguageTag( nLanguage ).getLocale();
     171          19 :             bHasLanguage = pRef[k]->hasLocale( aTmpLocale );
     172             :         }
     173             :     }
     174             : 
     175          19 :     return bHasLanguage;
     176             : }
     177             : 
     178          28 : SpellCheckerDispatcher::SpellCheckerDispatcher( LngSvcMgr &rLngSvcMgr ) :
     179          28 :     rMgr    (rLngSvcMgr)
     180             : {
     181          28 :     pCache = NULL;
     182          28 :     pCharClass = NULL;
     183          28 : }
     184             : 
     185             : 
     186          81 : SpellCheckerDispatcher::~SpellCheckerDispatcher()
     187             : {
     188          27 :     ClearSvcList();
     189          27 :     delete pCache;
     190          27 :     delete pCharClass;
     191          54 : }
     192             : 
     193             : 
     194          27 : void SpellCheckerDispatcher::ClearSvcList()
     195             : {
     196             :     // release memory for each table entry
     197          27 :     SpellSvcByLangMap_t aTmp;
     198          27 :     aSvcMap.swap( aTmp );
     199          27 : }
     200             : 
     201             : 
     202           0 : Sequence< Locale > SAL_CALL SpellCheckerDispatcher::getLocales()
     203             :         throw(RuntimeException)
     204             : {
     205           0 :     MutexGuard  aGuard( GetLinguMutex() );
     206             : 
     207           0 :     Sequence< Locale > aLocales( static_cast< sal_Int32 >(aSvcMap.size()) );
     208           0 :     Locale *pLocales = aLocales.getArray();
     209           0 :     SpellSvcByLangMap_t::const_iterator aIt;
     210           0 :     for (aIt = aSvcMap.begin();  aIt != aSvcMap.end();  ++aIt)
     211             :     {
     212           0 :         *pLocales++ = LanguageTag( aIt->first ).getLocale();
     213             :     }
     214           0 :     return aLocales;
     215             : }
     216             : 
     217             : 
     218        9304 : sal_Bool SAL_CALL SpellCheckerDispatcher::hasLocale( const Locale& rLocale )
     219             :         throw(RuntimeException)
     220             : {
     221        9304 :     MutexGuard  aGuard( GetLinguMutex() );
     222        9304 :     SpellSvcByLangMap_t::const_iterator aIt( aSvcMap.find( LinguLocaleToLanguage( rLocale ) ) );
     223        9304 :     return aIt != aSvcMap.end();
     224             : }
     225             : 
     226             : 
     227             : sal_Bool SAL_CALL
     228       12950 :     SpellCheckerDispatcher::isValid( const OUString& rWord, const Locale& rLocale,
     229             :             const PropertyValues& rProperties )
     230             :         throw(IllegalArgumentException, RuntimeException)
     231             : {
     232       12950 :     MutexGuard  aGuard( GetLinguMutex() );
     233       12950 :     return isValid_Impl( rWord, LinguLocaleToLanguage( rLocale ), rProperties, sal_True );
     234             : }
     235             : 
     236             : 
     237             : Reference< XSpellAlternatives > SAL_CALL
     238           0 :     SpellCheckerDispatcher::spell( const OUString& rWord, const Locale& rLocale,
     239             :             const PropertyValues& rProperties )
     240             :         throw(IllegalArgumentException, RuntimeException)
     241             : {
     242           0 :     MutexGuard  aGuard( GetLinguMutex() );
     243           0 :     return spell_Impl( rWord, LinguLocaleToLanguage( rLocale ), rProperties, sal_True );
     244             : }
     245             : 
     246             : 
     247             : // returns the overall result of cross-checking with all user-dictionaries
     248             : // including the IgnoreAll list
     249       17019 : static Reference< XDictionaryEntry > lcl_GetRulingDictionaryEntry(
     250             :     const OUString &rWord,
     251             :     LanguageType nLanguage )
     252             : {
     253       17019 :     Reference< XDictionaryEntry > xRes;
     254             : 
     255             :     // the order of winning from top to bottom is:
     256             :     // 1) IgnoreAll list will always win
     257             :     // 2) Negative dictionaries will win over positive dictionaries
     258       34038 :     Reference< XDictionary > xIgnoreAll( GetIgnoreAllList() );
     259       17019 :     if (xIgnoreAll.is())
     260       17019 :         xRes = xIgnoreAll->getEntry( rWord );
     261       17019 :     if (!xRes.is())
     262             :     {
     263       17019 :         Reference< XSearchableDictionaryList > xDList( GetDictionaryList() );
     264             :         Reference< XDictionaryEntry > xNegEntry( SearchDicList( xDList,
     265       34038 :                 rWord, nLanguage, sal_False, sal_True ) );
     266       17019 :         if (xNegEntry.is())
     267           0 :             xRes = xNegEntry;
     268             :         else
     269             :         {
     270             :             Reference< XDictionaryEntry > xPosEntry( SearchDicList( xDList,
     271       17019 :                     rWord, nLanguage, sal_True, sal_True ) );
     272       17019 :             if (xPosEntry.is())
     273         234 :                 xRes = xPosEntry;
     274       17019 :         }
     275             :     }
     276             : 
     277       34038 :     return xRes;
     278             : }
     279             : 
     280             : 
     281       12950 : sal_Bool SpellCheckerDispatcher::isValid_Impl(
     282             :             const OUString& rWord,
     283             :             LanguageType nLanguage,
     284             :             const PropertyValues& rProperties,
     285             :             sal_Bool bCheckDics)
     286             :         throw( RuntimeException, IllegalArgumentException )
     287             : {
     288       12950 :     MutexGuard  aGuard( GetLinguMutex() );
     289             : 
     290       12950 :     sal_Bool bRes = sal_True;
     291             : 
     292       12950 :     if (LinguIsUnspecified( nLanguage) || rWord.isEmpty())
     293           0 :         return bRes;
     294             : 
     295             :     // search for entry with that language
     296       12950 :     SpellSvcByLangMap_t::iterator    aIt( aSvcMap.find( nLanguage ) );
     297       12950 :     LangSvcEntries_Spell    *pEntry = aIt != aSvcMap.end() ? aIt->second.get() : NULL;
     298             : 
     299       12950 :     if (pEntry)
     300             :     {
     301       11471 :         OUString aChkWord( rWord );
     302       22942 :         Locale aLocale( LanguageTag( nLanguage ).getLocale() );
     303             : 
     304             :         // replace typographical apostroph by ascii apostroph
     305       22942 :         String aSingleQuote( GetLocaleDataWrapper( nLanguage ).getQuotationMarkEnd() );
     306             :         DBG_ASSERT( 1 == aSingleQuote.Len(), "unexpectend length of quotation mark" );
     307       11471 :         if (aSingleQuote.Len())
     308       11471 :             aChkWord = aChkWord.replace( aSingleQuote.GetChar(0), '\'' );
     309             : 
     310       11471 :         RemoveHyphens( aChkWord );
     311       11471 :         if (IsIgnoreControlChars( rProperties, GetPropSet() ))
     312       11471 :             RemoveControlChars( aChkWord );
     313             : 
     314       11471 :         sal_Int32 nLen = pEntry->aSvcRefs.getLength();
     315             :         DBG_ASSERT( nLen == pEntry->aSvcImplNames.getLength(),
     316             :                 "lng : sequence length mismatch");
     317             :         DBG_ASSERT( pEntry->nLastTriedSvcIndex < nLen,
     318             :                 "lng : index out of range");
     319             : 
     320       11471 :         sal_Int32 i = 0;
     321       11471 :         sal_Bool bTmpRes = sal_True;
     322       11471 :         sal_Bool bTmpResValid = sal_False;
     323             : 
     324             :         // try already instantiated services first
     325             :         {
     326             :             const Reference< XSpellChecker >  *pRef  =
     327       11471 :                     pEntry->aSvcRefs.getConstArray();
     328       34394 :             while (i <= pEntry->nLastTriedSvcIndex
     329       11452 :                    &&  (!bTmpResValid  ||  sal_False == bTmpRes))
     330             :             {
     331       11452 :                 bTmpResValid = sal_True;
     332       11452 :                 if (pRef[i].is()  &&  pRef[i]->hasLocale( aLocale ))
     333             :                 {
     334       11452 :                     bTmpRes = GetCache().CheckWord( aChkWord, nLanguage );
     335       11452 :                     if (!bTmpRes)
     336             :                     {
     337        6533 :                         bTmpRes = pRef[i]->isValid( aChkWord, aLocale, rProperties );
     338             : 
     339             :                         // Add correct words to the cache.
     340             :                         // But not those that are correct only because of
     341             :                         // the temporary supplied settings.
     342        6533 :                         if (bTmpRes  &&  0 == rProperties.getLength())
     343        5452 :                             GetCache().AddWord( aChkWord, nLanguage );
     344             :                     }
     345             :                 }
     346             :                 else
     347           0 :                     bTmpResValid = sal_False;
     348             : 
     349       11452 :                 if (bTmpResValid)
     350       11452 :                     bRes = bTmpRes;
     351             : 
     352       11452 :                 ++i;
     353             :             }
     354             :         }
     355             : 
     356             :         // if still no result instantiate new services and try those
     357       11471 :         if ((!bTmpResValid  ||  sal_False == bTmpRes)
     358        1100 :             &&  pEntry->nLastTriedSvcIndex < nLen - 1)
     359             :         {
     360          19 :             const OUString *pImplNames = pEntry->aSvcImplNames.getConstArray();
     361          19 :             Reference< XSpellChecker >  *pRef  = pEntry->aSvcRefs .getArray();
     362             : 
     363             :             Reference< XComponentContext > xContext(
     364          19 :                 comphelper::getProcessComponentContext() );
     365             : 
     366             :             // build service initialization argument
     367          38 :             Sequence< Any > aArgs(2);
     368          19 :             aArgs.getArray()[0] <<= GetPropSet();
     369             : 
     370          57 :             while (i < nLen  &&  (!bTmpResValid  ||  sal_False == bTmpRes))
     371             :             {
     372             :                 // create specific service via it's implementation name
     373          19 :                 Reference< XSpellChecker > xSpell;
     374             :                 try
     375             :                 {
     376          57 :                     xSpell = Reference< XSpellChecker >(
     377          38 :                                 xContext->getServiceManager()->createInstanceWithArgumentsAndContext(
     378          38 :                                     pImplNames[i], aArgs, xContext ),
     379          19 :                                 UNO_QUERY );
     380             :                 }
     381           0 :                 catch (uno::Exception &)
     382             :                 {
     383             :                     DBG_ASSERT( 0, "createInstanceWithArguments failed" );
     384             :                 }
     385          19 :                 pRef [i] = xSpell;
     386             : 
     387             :                 Reference< XLinguServiceEventBroadcaster >
     388          38 :                         xBroadcaster( xSpell, UNO_QUERY );
     389          19 :                 if (xBroadcaster.is())
     390          19 :                     rMgr.AddLngSvcEvtBroadcaster( xBroadcaster );
     391             : 
     392          19 :                 bTmpResValid = sal_True;
     393          19 :                 if (xSpell.is()  &&  xSpell->hasLocale( aLocale ))
     394             :                 {
     395          19 :                     bTmpRes = GetCache().CheckWord( aChkWord, nLanguage );
     396          19 :                     if (!bTmpRes)
     397             :                     {
     398          19 :                         bTmpRes = xSpell->isValid( aChkWord, aLocale, rProperties );
     399             :                          // Add correct words to the cache.
     400             :                         // But not those that are correct only because of
     401             :                         // the temporary supplied settings.
     402          19 :                         if (bTmpRes  &&  0 == rProperties.getLength())
     403          16 :                             GetCache().AddWord( aChkWord, nLanguage );
     404             :                     }
     405             :                 }
     406             :                 else
     407           0 :                     bTmpResValid = sal_False;
     408          19 :                 if (bTmpResValid)
     409          19 :                     bRes = bTmpRes;
     410             : 
     411          19 :                 pEntry->nLastTriedSvcIndex = (sal_Int16) i;
     412          19 :                 ++i;
     413          19 :             }
     414             : 
     415             :             // if language is not supported by any of the services
     416             :             // remove it from the list.
     417          19 :             if (i == nLen)
     418             :             {
     419          19 :                 if (!SvcListHasLanguage( *pEntry, nLanguage ))
     420           0 :                     aSvcMap.erase( nLanguage );
     421          19 :             }
     422             :         }
     423             : 
     424             :         // cross-check against results from dictionaries which have precedence!
     425       45884 :         if (bCheckDics  &&
     426       57355 :             GetDicList().is()  &&  IsUseDicList( rProperties, GetPropSet() ))
     427             :         {
     428       11471 :             Reference< XDictionaryEntry > xTmp( lcl_GetRulingDictionaryEntry( aChkWord, nLanguage ) );
     429       11471 :             if (xTmp.is()) {
     430         234 :                 bRes = !xTmp->isNegative();
     431             :             } else {
     432       11237 :                 setCharClass(LanguageTag(nLanguage));
     433       11237 :                 sal_uInt16 ct = capitalType(aChkWord, pCharClass);
     434       11237 :                 if (ct == CAPTYPE_INITCAP || ct == CAPTYPE_ALLCAP) {
     435        5548 :                     Reference< XDictionaryEntry > xTmp2( lcl_GetRulingDictionaryEntry( makeLowerCase(aChkWord, pCharClass), nLanguage ) );
     436        5548 :                     if (xTmp2.is()) {
     437           0 :                         bRes = !xTmp2->isNegative();
     438        5548 :                     }
     439             :                 }
     440       11471 :             }
     441       11471 :         }
     442             :     }
     443             : 
     444       12950 :     return bRes;
     445             : }
     446             : 
     447             : 
     448           0 : Reference< XSpellAlternatives > SpellCheckerDispatcher::spell_Impl(
     449             :             const OUString& rWord,
     450             :             LanguageType nLanguage,
     451             :             const PropertyValues& rProperties,
     452             :             sal_Bool bCheckDics )
     453             :         throw(IllegalArgumentException, RuntimeException)
     454             : {
     455           0 :     MutexGuard  aGuard( GetLinguMutex() );
     456             : 
     457           0 :     Reference< XSpellAlternatives > xRes;
     458             : 
     459           0 :     if (LinguIsUnspecified( nLanguage) || rWord.isEmpty())
     460           0 :         return xRes;
     461             : 
     462             :     // search for entry with that language
     463           0 :     SpellSvcByLangMap_t::iterator    aIt( aSvcMap.find( nLanguage ) );
     464           0 :     LangSvcEntries_Spell    *pEntry = aIt != aSvcMap.end() ? aIt->second.get() : NULL;
     465             : 
     466           0 :     if (pEntry)
     467             :     {
     468           0 :         OUString aChkWord( rWord );
     469           0 :         Locale aLocale( LanguageTag( nLanguage ).getLocale() );
     470             : 
     471             :         // replace typographical apostroph by ascii apostroph
     472           0 :         String aSingleQuote( GetLocaleDataWrapper( nLanguage ).getQuotationMarkEnd() );
     473             :         DBG_ASSERT( 1 == aSingleQuote.Len(), "unexpectend length of quotation mark" );
     474           0 :         if (aSingleQuote.Len())
     475           0 :             aChkWord = aChkWord.replace( aSingleQuote.GetChar(0), '\'' );
     476             : 
     477           0 :         RemoveHyphens( aChkWord );
     478           0 :         if (IsIgnoreControlChars( rProperties, GetPropSet() ))
     479           0 :             RemoveControlChars( aChkWord );
     480             : 
     481           0 :         sal_Int32 nLen = pEntry->aSvcRefs.getLength();
     482             :         DBG_ASSERT( nLen == pEntry->aSvcImplNames.getLength(),
     483             :                 "lng : sequence length mismatch");
     484             :         DBG_ASSERT( pEntry->nLastTriedSvcIndex < nLen,
     485             :                 "lng : index out of range");
     486             : 
     487           0 :         sal_Int32 i = 0;
     488           0 :         Reference< XSpellAlternatives > xTmpRes;
     489           0 :         sal_Bool bTmpResValid = sal_False;
     490             : 
     491             :         // try already instantiated services first
     492             :         {
     493           0 :             const Reference< XSpellChecker >  *pRef  = pEntry->aSvcRefs.getConstArray();
     494           0 :             sal_Int32 nNumSugestions = -1;
     495           0 :             while (i <= pEntry->nLastTriedSvcIndex
     496           0 :                    &&  (!bTmpResValid || xTmpRes.is()) )
     497             :             {
     498           0 :                 bTmpResValid = sal_True;
     499           0 :                 if (pRef[i].is()  &&  pRef[i]->hasLocale( aLocale ))
     500             :                 {
     501           0 :                     sal_Bool bOK = GetCache().CheckWord( aChkWord, nLanguage );
     502           0 :                     if (bOK)
     503           0 :                         xTmpRes = NULL;
     504             :                     else
     505             :                     {
     506           0 :                         xTmpRes = pRef[i]->spell( aChkWord, aLocale, rProperties );
     507             : 
     508             :                         // Add correct words to the cache.
     509             :                         // But not those that are correct only because of
     510             :                         // the temporary supplied settings.
     511           0 :                         if (!xTmpRes.is()  &&  0 == rProperties.getLength())
     512           0 :                             GetCache().AddWord( aChkWord, nLanguage );
     513             :                     }
     514             :                 }
     515             :                 else
     516           0 :                     bTmpResValid = sal_False;
     517             : 
     518             :                 // return first found result if the word is not known by any checker.
     519             :                 // But if that result has no suggestions use the first one that does
     520             :                 // provide suggestions for the misspelled word.
     521           0 :                 if (!xRes.is() && bTmpResValid)
     522             :                 {
     523           0 :                     xRes = xTmpRes;
     524           0 :                     nNumSugestions = 0;
     525           0 :                     if (xRes.is())
     526           0 :                         nNumSugestions = xRes->getAlternatives().getLength();
     527             :                 }
     528           0 :                 sal_Int32 nTmpNumSugestions = 0;
     529           0 :                 if (xTmpRes.is() && bTmpResValid)
     530           0 :                     nTmpNumSugestions = xTmpRes->getAlternatives().getLength();
     531           0 :                 if (xRes.is() && nNumSugestions == 0 && nTmpNumSugestions > 0)
     532             :                 {
     533           0 :                     xRes = xTmpRes;
     534           0 :                     nNumSugestions = nTmpNumSugestions;
     535             :                 }
     536             : 
     537           0 :                 ++i;
     538             :             }
     539             :         }
     540             : 
     541             :         // if still no result instantiate new services and try those
     542           0 :         if ((!bTmpResValid || xTmpRes.is())
     543           0 :             &&  pEntry->nLastTriedSvcIndex < nLen - 1)
     544             :         {
     545           0 :             const OUString *pImplNames = pEntry->aSvcImplNames.getConstArray();
     546           0 :             Reference< XSpellChecker >  *pRef  = pEntry->aSvcRefs .getArray();
     547             : 
     548             :             Reference< XComponentContext > xContext(
     549           0 :                 comphelper::getProcessComponentContext() );
     550             : 
     551             :             // build service initialization argument
     552           0 :             Sequence< Any > aArgs(2);
     553           0 :             aArgs.getArray()[0] <<= GetPropSet();
     554             : 
     555           0 :             sal_Int32 nNumSugestions = -1;
     556           0 :             while (i < nLen  &&  (!bTmpResValid || xTmpRes.is()))
     557             :             {
     558             :                 // create specific service via it's implementation name
     559           0 :                 Reference< XSpellChecker > xSpell;
     560             :                 try
     561             :                 {
     562           0 :                     xSpell = Reference< XSpellChecker >(
     563           0 :                                 xContext->getServiceManager()->createInstanceWithArgumentsAndContext(
     564           0 :                                     pImplNames[i], aArgs, xContext ),
     565           0 :                                 UNO_QUERY );
     566             :                 }
     567           0 :                 catch (uno::Exception &)
     568             :                 {
     569             :                     DBG_ASSERT( 0, "createInstanceWithArguments failed" );
     570             :                 }
     571           0 :                 pRef [i] = xSpell;
     572             : 
     573             :                 Reference< XLinguServiceEventBroadcaster >
     574           0 :                         xBroadcaster( xSpell, UNO_QUERY );
     575           0 :                 if (xBroadcaster.is())
     576           0 :                     rMgr.AddLngSvcEvtBroadcaster( xBroadcaster );
     577             : 
     578           0 :                 bTmpResValid = sal_True;
     579           0 :                 if (xSpell.is()  &&  xSpell->hasLocale( aLocale ))
     580             :                 {
     581           0 :                     sal_Bool bOK = GetCache().CheckWord( aChkWord, nLanguage );
     582           0 :                     if (bOK)
     583           0 :                         xTmpRes = NULL;
     584             :                     else
     585             :                     {
     586           0 :                         xTmpRes = xSpell->spell( aChkWord, aLocale, rProperties );
     587             : 
     588             :                         // Add correct words to the cache.
     589             :                         // But not those that are correct only because of
     590             :                         // the temporary supplied settings.
     591           0 :                         if (!xTmpRes.is()  &&  0 == rProperties.getLength())
     592           0 :                             GetCache().AddWord( aChkWord, nLanguage );
     593             :                     }
     594             :                 }
     595             :                 else
     596           0 :                     bTmpResValid = sal_False;
     597             : 
     598             :                 // return first found result if the word is not known by any checker.
     599             :                 // But if that result has no suggestions use the first one that does
     600             :                 // provide suggestions for the misspelled word.
     601           0 :                 if (!xRes.is() && bTmpResValid)
     602             :                 {
     603           0 :                     xRes = xTmpRes;
     604           0 :                     nNumSugestions = 0;
     605           0 :                     if (xRes.is())
     606           0 :                         nNumSugestions = xRes->getAlternatives().getLength();
     607             :                 }
     608           0 :                 sal_Int32 nTmpNumSugestions = 0;
     609           0 :                 if (xTmpRes.is() && bTmpResValid)
     610           0 :                     nTmpNumSugestions = xTmpRes->getAlternatives().getLength();
     611           0 :                 if (xRes.is() && nNumSugestions == 0 && nTmpNumSugestions > 0)
     612             :                 {
     613           0 :                     xRes = xTmpRes;
     614           0 :                     nNumSugestions = nTmpNumSugestions;
     615             :                 }
     616             : 
     617           0 :                 pEntry->nLastTriedSvcIndex = (sal_Int16) i;
     618           0 :                 ++i;
     619           0 :             }
     620             : 
     621             :             // if language is not supported by any of the services
     622             :             // remove it from the list.
     623           0 :             if (i == nLen)
     624             :             {
     625           0 :                 if (!SvcListHasLanguage( *pEntry, nLanguage ))
     626           0 :                     aSvcMap.erase( nLanguage );
     627           0 :             }
     628             :         }
     629             : 
     630             :         // if word is finally found to be correct
     631             :         // clear previously remembered alternatives
     632           0 :         if (bTmpResValid  &&  !xTmpRes.is())
     633           0 :             xRes = NULL;
     634             : 
     635             :         // list of proposals found (to be checked against entries of
     636             :         // neagtive dictionaries)
     637           0 :         ProposalList aProposalList;
     638           0 :         sal_Int16 eFailureType = -1;    // no failure
     639           0 :         if (xRes.is())
     640             :         {
     641           0 :             aProposalList.Append( xRes->getAlternatives() );
     642           0 :             eFailureType = xRes->getFailureType();
     643             :         }
     644           0 :         Reference< XSearchableDictionaryList > xDList;
     645           0 :         if (GetDicList().is()  &&  IsUseDicList( rProperties, GetPropSet() ))
     646           0 :             xDList = GetDicList();
     647             : 
     648             :         // cross-check against results from user-dictionaries which have precedence!
     649           0 :         if (bCheckDics  &&  xDList.is())
     650             :         {
     651           0 :             Reference< XDictionaryEntry > xTmp( lcl_GetRulingDictionaryEntry( aChkWord, nLanguage ) );
     652           0 :             if (xTmp.is())
     653             :             {
     654           0 :                 if (xTmp->isNegative())    // positive entry found
     655             :                 {
     656           0 :                     eFailureType = SpellFailure::IS_NEGATIVE_WORD;
     657             : 
     658             :                     // replacement text to be added to suggestions, if not empty
     659           0 :                     OUString aAddRplcTxt( xTmp->getReplacementText() );
     660             : 
     661             :                     // replacement text must not be in negative dictionary itself
     662           0 :                     if (!aAddRplcTxt.isEmpty() &&
     663           0 :                         !SearchDicList( xDList, aAddRplcTxt, nLanguage, sal_False, sal_True ).is())
     664             :                     {
     665           0 :                         aProposalList.Prepend( aAddRplcTxt );
     666           0 :                     }
     667             :                 }
     668             :                 else    // positive entry found
     669             :                 {
     670           0 :                     xRes = NULL;
     671           0 :                     eFailureType = -1;  // no failure
     672             :                 }
     673           0 :             }
     674             :         }
     675             : 
     676           0 :         if (eFailureType != -1)     // word misspelled or found in negative user-dictionary
     677             :         {
     678             :             // search suitable user-dictionaries for suggestions that are
     679             :             // similar to the misspelled word
     680           0 :             std::vector< OUString > aDicListProps;   // list of proposals from user-dictionaries
     681           0 :             SearchSimilarText( aChkWord, nLanguage, xDList, aDicListProps );
     682           0 :             aProposalList.Append( aDicListProps );
     683           0 :             Sequence< OUString > aProposals = aProposalList.GetSequence();
     684             : 
     685             :             // remove entries listed in negative dictionaries
     686             :             // (we don't want to display suggestions that will be regarded as misspelledlater on)
     687           0 :             if (bCheckDics  &&  xDList.is())
     688           0 :                 SeqRemoveNegEntries( aProposals, xDList, nLanguage );
     689             : 
     690           0 :             uno::Reference< linguistic2::XSetSpellAlternatives > xSetAlt( xRes, uno::UNO_QUERY );
     691           0 :             if (xSetAlt.is())
     692             :             {
     693           0 :                 xSetAlt->setAlternatives( aProposals );
     694           0 :                 xSetAlt->setFailureType( eFailureType );
     695             :             }
     696             :             else
     697             :             {
     698           0 :                 if (xRes.is())
     699             :                 {
     700             :                     DBG_ASSERT( 0, "XSetSpellAlternatives not implemented!" );
     701             :                 }
     702           0 :                 else if (aProposals.getLength() > 0)
     703             :                 {
     704             :                     // no xRes but Proposals found from the user-dictionaries.
     705             :                     // Thus we need to create an xRes...
     706           0 :                     xRes = new linguistic::SpellAlternatives( rWord, nLanguage,
     707           0 :                             SpellFailure::IS_NEGATIVE_WORD, aProposals );
     708             :                 }
     709           0 :             }
     710           0 :         }
     711             :     }
     712             : 
     713           0 :     return xRes;
     714             : }
     715             : 
     716           0 : uno::Sequence< sal_Int16 > SAL_CALL SpellCheckerDispatcher::getLanguages(  )
     717             : throw (uno::RuntimeException)
     718             : {
     719           0 :     MutexGuard  aGuard( GetLinguMutex() );
     720           0 :     uno::Sequence< Locale > aTmp( getLocales() );
     721           0 :     uno::Sequence< sal_Int16 > aRes( LocaleSeqToLangSeq( aTmp ) );
     722           0 :     return aRes;
     723             : }
     724             : 
     725             : 
     726        9304 : sal_Bool SAL_CALL SpellCheckerDispatcher::hasLanguage(
     727             :     sal_Int16 nLanguage )
     728             : throw (uno::RuntimeException)
     729             : {
     730        9304 :     MutexGuard  aGuard( GetLinguMutex() );
     731        9304 :     return hasLocale( LanguageTag( nLanguage).getLocale() );
     732             : }
     733             : 
     734             : 
     735       12950 : sal_Bool SAL_CALL SpellCheckerDispatcher::isValid(
     736             :     const OUString& rWord,
     737             :     sal_Int16 nLanguage,
     738             :     const uno::Sequence< beans::PropertyValue >& rProperties )
     739             : throw (lang::IllegalArgumentException, uno::RuntimeException)
     740             : {
     741       12950 :     MutexGuard  aGuard( GetLinguMutex() );
     742       12950 :     return isValid( rWord, LanguageTag( nLanguage ).getLocale(), rProperties);
     743             : }
     744             : 
     745             : 
     746           0 : uno::Reference< linguistic2::XSpellAlternatives > SAL_CALL SpellCheckerDispatcher::spell(
     747             :     const OUString& rWord,
     748             :     sal_Int16 nLanguage,
     749             :     const uno::Sequence< beans::PropertyValue >& rProperties )
     750             : throw (lang::IllegalArgumentException, uno::RuntimeException)
     751             : {
     752           0 :     MutexGuard  aGuard( GetLinguMutex() );
     753           0 :     return spell( rWord, LanguageTag( nLanguage).getLocale(), rProperties);
     754             : }
     755             : 
     756             : 
     757          23 : void SpellCheckerDispatcher::SetServiceList( const Locale &rLocale,
     758             :         const Sequence< OUString > &rSvcImplNames )
     759             : {
     760          23 :     MutexGuard  aGuard( GetLinguMutex() );
     761             : 
     762          23 :     if (pCache)
     763           1 :         pCache->Flush();    // new services may spell differently...
     764             : 
     765          23 :     sal_Int16 nLanguage = LinguLocaleToLanguage( rLocale );
     766             : 
     767          23 :     sal_Int32 nLen = rSvcImplNames.getLength();
     768          23 :     if (0 == nLen)
     769             :         // remove entry
     770           0 :         aSvcMap.erase( nLanguage );
     771             :     else
     772             :     {
     773             :         // modify/add entry
     774          23 :         LangSvcEntries_Spell *pEntry = aSvcMap[ nLanguage ].get();
     775          23 :         if (pEntry)
     776             :         {
     777           1 :             pEntry->Clear();
     778           1 :             pEntry->aSvcImplNames = rSvcImplNames;
     779           1 :             pEntry->aSvcRefs = Sequence< Reference < XSpellChecker > > ( nLen );
     780             :         }
     781             :         else
     782             :         {
     783          22 :             boost::shared_ptr< LangSvcEntries_Spell > pTmpEntry( new LangSvcEntries_Spell( rSvcImplNames ) );
     784          22 :             pTmpEntry->aSvcRefs = Sequence< Reference < XSpellChecker > >( nLen );
     785          22 :             aSvcMap[ nLanguage ] = pTmpEntry;
     786             :         }
     787          23 :     }
     788          23 : }
     789             : 
     790             : 
     791             : Sequence< OUString >
     792           0 :     SpellCheckerDispatcher::GetServiceList( const Locale &rLocale ) const
     793             : {
     794           0 :     MutexGuard  aGuard( GetLinguMutex() );
     795             : 
     796           0 :     Sequence< OUString > aRes;
     797             : 
     798             :     // search for entry with that language and use data from that
     799           0 :     sal_Int16 nLanguage = LinguLocaleToLanguage( rLocale );
     800           0 :     SpellCheckerDispatcher          *pThis = (SpellCheckerDispatcher *) this;
     801           0 :     const SpellSvcByLangMap_t::iterator aIt( pThis->aSvcMap.find( nLanguage ) );
     802           0 :     const LangSvcEntries_Spell      *pEntry = aIt != aSvcMap.end() ? aIt->second.get() : NULL;
     803           0 :     if (pEntry)
     804           0 :         aRes = pEntry->aSvcImplNames;
     805             : 
     806           0 :     return aRes;
     807             : }
     808             : 
     809             : 
     810           0 : LinguDispatcher::DspType SpellCheckerDispatcher::GetDspType() const
     811             : {
     812           0 :     return DSP_SPELL;
     813             : }
     814             : 
     815           1 : void SpellCheckerDispatcher::FlushSpellCache()
     816             : {
     817           1 :     if (pCache)
     818           1 :         pCache->Flush();
     819           1 : }
     820             : 
     821       11237 : void SpellCheckerDispatcher::setCharClass(const LanguageTag& rLanguageTag)
     822             : {
     823       11237 :     if (!pCharClass)
     824          19 :         pCharClass = new CharClass(rLanguageTag);
     825       11237 :     pCharClass->setLanguageTag(rLanguageTag);
     826       11237 : }
     827             : 
     828             : 
     829             : 
     830        5548 : OUString SAL_CALL SpellCheckerDispatcher::makeLowerCase(const OUString& aTerm, CharClass * pCC)
     831             : {
     832        5548 :     if (pCC)
     833        5548 :         return pCC->lowercase(aTerm);
     834           0 :     return aTerm;
     835             : }
     836             : 
     837             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10