xref: /aoo42x/main/linguistic/source/spelldta.cxx (revision cdf0e10c)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_linguistic.hxx"
30 #include <com/sun/star/uno/Reference.h>
31 
32 #include <com/sun/star/linguistic2/SpellFailure.hpp>
33 #include <com/sun/star/linguistic2/XSearchableDictionaryList.hpp>
34 #include <tools/debug.hxx>
35 #include <unotools/processfactory.hxx>
36 #include <osl/mutex.hxx>
37 
38 #include <vector>
39 
40 #include "linguistic/spelldta.hxx"
41 #include "lngsvcmgr.hxx"
42 
43 
44 using namespace utl;
45 using namespace osl;
46 using namespace rtl;
47 using namespace com::sun::star;
48 using namespace com::sun::star::beans;
49 using namespace com::sun::star::lang;
50 using namespace com::sun::star::uno;
51 using namespace com::sun::star::linguistic2;
52 
53 namespace linguistic
54 {
55 
56 ///////////////////////////////////////////////////////////////////////////
57 
58 
59 #define MAX_PROPOSALS	40
60 
61 Reference< XSpellAlternatives > MergeProposals(
62 			Reference< XSpellAlternatives > &rxAlt1,
63 			Reference< XSpellAlternatives > &rxAlt2)
64 {
65 	Reference< XSpellAlternatives > xMerged;
66 
67 	if (!rxAlt1.is())
68 		xMerged = rxAlt2;
69 	else if (!rxAlt2.is())
70 		xMerged = rxAlt1;
71 	else
72 	{
73 		sal_Int32 nAltCount1 = rxAlt1->getAlternativesCount();
74 		Sequence< OUString > aAlt1( rxAlt1->getAlternatives() );
75 		const OUString *pAlt1 = aAlt1.getConstArray();
76 
77 		sal_Int32 nAltCount2 = rxAlt2->getAlternativesCount();
78 		Sequence< OUString > aAlt2( rxAlt2->getAlternatives() );
79 		const OUString *pAlt2 = aAlt2.getConstArray();
80 
81 		sal_Int32 nCountNew = Min( nAltCount1 + nAltCount2, (sal_Int32) MAX_PROPOSALS );
82 		Sequence< OUString > aAltNew( nCountNew );
83 		OUString *pAltNew = aAltNew.getArray();
84 
85 		sal_Int32 nIndex = 0;
86 		sal_Int32 i = 0;
87 		for (int j = 0;  j < 2;  j++)
88 		{
89 			sal_Int32 			nCount 	= j == 0 ? nAltCount1 : nAltCount2;
90 			const OUString  *pAlt 	= j == 0 ? pAlt1 : pAlt2;
91 			for (i = 0;  i < nCount  &&  nIndex < MAX_PROPOSALS;  i++)
92 			{
93 				if (pAlt[i].getLength())
94 					pAltNew[ nIndex++ ] = pAlt[ i ];
95 			}
96 		}
97 		DBG_ASSERT(nIndex == nCountNew, "lng : wrong number of proposals");
98 
99 		SpellAlternatives *pSpellAlt = new SpellAlternatives;
100 		pSpellAlt->SetWordLanguage( rxAlt1->getWord(),
101 							LocaleToLanguage( rxAlt1->getLocale() ) );
102 		pSpellAlt->SetFailureType( rxAlt1->getFailureType() );
103 		pSpellAlt->SetAlternatives( aAltNew );
104 		xMerged = pSpellAlt;
105 	}
106 
107 	return xMerged;
108 }
109 
110 
111 sal_Bool SeqHasEntry(
112         const Sequence< OUString > &rSeq,
113         const OUString &rTxt)
114 {
115     sal_Bool bRes = sal_False;
116     sal_Int32 nLen = rSeq.getLength();
117     const OUString *pEntry = rSeq.getConstArray();
118     for (sal_Int32 i = 0;  i < nLen  &&  !bRes;  ++i)
119     {
120         if (rTxt == pEntry[i])
121             bRes = sal_True;
122     }
123     return bRes;
124 }
125 
126 
127 void SearchSimilarText( const OUString &rText, sal_Int16 nLanguage,
128         Reference< XDictionaryList > &xDicList,
129         std::vector< OUString > & rDicListProps )
130 {
131     if (!xDicList.is())
132         return;
133 
134     const uno::Sequence< Reference< XDictionary > >
135             aDics( xDicList->getDictionaries() );
136     const Reference< XDictionary >
137             *pDic = aDics.getConstArray();
138     sal_Int32 nDics = xDicList->getCount();
139 
140     for (sal_Int32 i = 0;  i < nDics;  i++)
141     {
142         Reference< XDictionary > xDic( pDic[i], UNO_QUERY );
143 
144         sal_Int16           nLang = LocaleToLanguage( xDic->getLocale() );
145 
146         if ( xDic.is() && xDic->isActive()
147             && (nLang == nLanguage  ||  nLang == LANGUAGE_NONE) )
148         {
149 #if OSL_DEBUG_LEVEL > 1
150             DictionaryType  eType = xDic->getDictionaryType();
151 			(void) eType;
152             DBG_ASSERT( eType != DictionaryType_MIXED, "unexpected dictionary type" );
153 #endif
154             const Sequence< Reference< XDictionaryEntry > > aEntries = xDic->getEntries();
155             const Reference< XDictionaryEntry > *pEntries = aEntries.getConstArray();
156             sal_Int32 nLen = aEntries.getLength();
157             for (sal_Int32 k = 0;  k < nLen;  ++k)
158             {
159 				String aEntryTxt;
160 				if (pEntries[k].is())
161 				{
162 					aEntryTxt = pEntries[k]->getDictionaryWord();
163 					// remove characters used to determine hyphenation positions
164 					aEntryTxt.EraseAllChars( '=' );
165 				}
166                 if (aEntryTxt.Len() > 0  &&  LevDistance( rText, aEntryTxt ) <= 2)
167                     rDicListProps.push_back( aEntryTxt );
168             }
169         }
170     }
171 }
172 
173 
174 void SeqRemoveNegEntries( Sequence< OUString > &rSeq,
175         Reference< XDictionaryList > &rxDicList,
176         sal_Int16 nLanguage )
177 {
178     static const OUString aEmpty;
179     sal_Bool bSthRemoved = sal_False;
180     sal_Int32 nLen = rSeq.getLength();
181     OUString *pEntries = rSeq.getArray();
182     for (sal_Int32 i = 0;  i < nLen;  ++i)
183     {
184         Reference< XDictionaryEntry > xNegEntry( SearchDicList( rxDicList,
185                     pEntries[i], nLanguage, sal_False, sal_True ) );
186         if (xNegEntry.is())
187         {
188             pEntries[i] = aEmpty;
189             bSthRemoved = sal_True;
190         }
191     }
192     if (bSthRemoved)
193     {
194         Sequence< OUString > aNew;
195         // merge sequence without duplicates and empty strings in new empty sequence
196         aNew = MergeProposalSeqs( aNew, rSeq, sal_False );
197         rSeq = aNew;
198     }
199 }
200 
201 
202 Sequence< OUString > MergeProposalSeqs(
203             Sequence< OUString > &rAlt1,
204             Sequence< OUString > &rAlt2,
205             sal_Bool bAllowDuplicates )
206 {
207     Sequence< OUString > aMerged;
208 
209     if (0 == rAlt1.getLength() && bAllowDuplicates)
210         aMerged = rAlt2;
211     else if (0 == rAlt2.getLength() && bAllowDuplicates)
212         aMerged = rAlt1;
213     else
214     {
215         sal_Int32 nAltCount1 = rAlt1.getLength();
216         const OUString *pAlt1 = rAlt1.getConstArray();
217         sal_Int32 nAltCount2 = rAlt2.getLength();
218         const OUString *pAlt2 = rAlt2.getConstArray();
219 
220         sal_Int32 nCountNew = Min( nAltCount1 + nAltCount2, (sal_Int32) MAX_PROPOSALS );
221         aMerged.realloc( nCountNew );
222         OUString *pMerged = aMerged.getArray();
223 
224         sal_Int32 nIndex = 0;
225         sal_Int32 i = 0;
226         for (int j = 0;  j < 2;  j++)
227         {
228             sal_Int32           nCount  = j == 0 ? nAltCount1 : nAltCount2;
229             const OUString  *pAlt   = j == 0 ? pAlt1 : pAlt2;
230             for (i = 0;  i < nCount  &&  nIndex < MAX_PROPOSALS;  i++)
231             {
232                 if (pAlt[i].getLength() &&
233                     (bAllowDuplicates || !SeqHasEntry(aMerged, pAlt[i] )))
234                     pMerged[ nIndex++ ] = pAlt[ i ];
235             }
236         }
237         //DBG_ASSERT(nIndex == nCountNew, "wrong number of proposals");
238         aMerged.realloc( nIndex );
239     }
240 
241     return aMerged;
242 }
243 
244 ///////////////////////////////////////////////////////////////////////////
245 
246 
247 SpellAlternatives::SpellAlternatives()
248 {
249 	nLanguage	= LANGUAGE_NONE;
250 	nType 		= SpellFailure::IS_NEGATIVE_WORD;
251 }
252 
253 
254 SpellAlternatives::SpellAlternatives(
255 			const OUString &rWord, sal_Int16 nLang,
256 			sal_Int16 nFailureType, const OUString &rRplcWord ) :
257     aAlt        ( Sequence< OUString >(1) ),
258 	aWord		(rWord),
259     nType       (nFailureType),
260     nLanguage   (nLang)
261 {
262 	if (rRplcWord.getLength())
263 		aAlt.getArray()[ 0 ] = rRplcWord;
264 	else
265 		aAlt.realloc( 0 );
266 }
267 
268 
269 SpellAlternatives::SpellAlternatives(
270         const OUString &rWord, sal_Int16 nLang, sal_Int16 nFailureType,
271         const Sequence< OUString > &rAlternatives ) :
272     aAlt        (rAlternatives),
273     aWord       (rWord),
274     nType       (nFailureType),
275     nLanguage   (nLang)
276 {
277 }
278 
279 
280 SpellAlternatives::~SpellAlternatives()
281 {
282 }
283 
284 
285 OUString SAL_CALL SpellAlternatives::getWord()
286 		throw(RuntimeException)
287 {
288 	MutexGuard	aGuard( GetLinguMutex() );
289 	return aWord;
290 }
291 
292 
293 Locale SAL_CALL SpellAlternatives::getLocale()
294 		throw(RuntimeException)
295 {
296 	MutexGuard	aGuard( GetLinguMutex() );
297 	return CreateLocale( nLanguage );
298 }
299 
300 
301 sal_Int16 SAL_CALL SpellAlternatives::getFailureType()
302 		throw(RuntimeException)
303 {
304 	MutexGuard	aGuard( GetLinguMutex() );
305 	return nType;
306 }
307 
308 
309 sal_Int16 SAL_CALL SpellAlternatives::getAlternativesCount()
310 		throw(RuntimeException)
311 {
312 	MutexGuard	aGuard( GetLinguMutex() );
313 	return (sal_Int16) aAlt.getLength();
314 }
315 
316 
317 Sequence< OUString > SAL_CALL SpellAlternatives::getAlternatives()
318 		throw(RuntimeException)
319 {
320 	MutexGuard	aGuard( GetLinguMutex() );
321 	return aAlt;
322 }
323 
324 
325 void SAL_CALL SpellAlternatives::setAlternatives( const uno::Sequence< OUString >& rAlternatives )
326 throw (uno::RuntimeException)
327 {
328     MutexGuard  aGuard( GetLinguMutex() );
329     aAlt = rAlternatives;
330 }
331 
332 
333 void SAL_CALL SpellAlternatives::setFailureType( sal_Int16 nFailureType )
334 throw (uno::RuntimeException)
335 {
336     MutexGuard  aGuard( GetLinguMutex() );
337     nType = nFailureType;
338 }
339 
340 
341 void SpellAlternatives::SetWordLanguage(const OUString &rWord, sal_Int16 nLang)
342 {
343 	MutexGuard	aGuard( GetLinguMutex() );
344 	aWord = rWord;
345 	nLanguage = nLang;
346 }
347 
348 
349 void SpellAlternatives::SetFailureType(sal_Int16 nTypeP)
350 {
351 	MutexGuard	aGuard( GetLinguMutex() );
352 	nType = nTypeP;
353 }
354 
355 
356 void SpellAlternatives::SetAlternatives( const Sequence< OUString > &rAlt )
357 {
358 	MutexGuard	aGuard( GetLinguMutex() );
359 	aAlt = rAlt;
360 }
361 
362 
363 ///////////////////////////////////////////////////////////////////////////
364 
365 }	// namespace linguistic
366 
367