xref: /aoo41x/main/linguistic/source/spelldsp.cxx (revision 3b8558fd)
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