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