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