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