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
MergeProposals(Reference<XSpellAlternatives> & rxAlt1,Reference<XSpellAlternatives> & rxAlt2)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
SeqHasEntry(const Sequence<OUString> & rSeq,const OUString & rTxt)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
SearchSimilarText(const OUString & rText,sal_Int16 nLanguage,Reference<XDictionaryList> & xDicList,std::vector<OUString> & rDicListProps)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
SeqRemoveNegEntries(Sequence<OUString> & rSeq,Reference<XDictionaryList> & rxDicList,sal_Int16 nLanguage)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
MergeProposalSeqs(Sequence<OUString> & rAlt1,Sequence<OUString> & rAlt2,sal_Bool bAllowDuplicates)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
SpellAlternatives()243 SpellAlternatives::SpellAlternatives()
244 {
245 nLanguage = LANGUAGE_NONE;
246 nType = SpellFailure::IS_NEGATIVE_WORD;
247 }
248
249
SpellAlternatives(const OUString & rWord,sal_Int16 nLang,sal_Int16 nFailureType,const OUString & rRplcWord)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
SpellAlternatives(const OUString & rWord,sal_Int16 nLang,sal_Int16 nFailureType,const Sequence<OUString> & rAlternatives)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
~SpellAlternatives()276 SpellAlternatives::~SpellAlternatives()
277 {
278 }
279
280
getWord()281 OUString SAL_CALL SpellAlternatives::getWord()
282 throw(RuntimeException)
283 {
284 MutexGuard aGuard( GetLinguMutex() );
285 return aWord;
286 }
287
288
getLocale()289 Locale SAL_CALL SpellAlternatives::getLocale()
290 throw(RuntimeException)
291 {
292 MutexGuard aGuard( GetLinguMutex() );
293 return CreateLocale( nLanguage );
294 }
295
296
getFailureType()297 sal_Int16 SAL_CALL SpellAlternatives::getFailureType()
298 throw(RuntimeException)
299 {
300 MutexGuard aGuard( GetLinguMutex() );
301 return nType;
302 }
303
304
getAlternativesCount()305 sal_Int16 SAL_CALL SpellAlternatives::getAlternativesCount()
306 throw(RuntimeException)
307 {
308 MutexGuard aGuard( GetLinguMutex() );
309 return (sal_Int16) aAlt.getLength();
310 }
311
312
getAlternatives()313 Sequence< OUString > SAL_CALL SpellAlternatives::getAlternatives()
314 throw(RuntimeException)
315 {
316 MutexGuard aGuard( GetLinguMutex() );
317 return aAlt;
318 }
319
320
setAlternatives(const uno::Sequence<OUString> & rAlternatives)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
setFailureType(sal_Int16 nFailureType)329 void SAL_CALL SpellAlternatives::setFailureType( sal_Int16 nFailureType )
330 throw (uno::RuntimeException)
331 {
332 MutexGuard aGuard( GetLinguMutex() );
333 nType = nFailureType;
334 }
335
336
SetWordLanguage(const OUString & rWord,sal_Int16 nLang)337 void SpellAlternatives::SetWordLanguage(const OUString &rWord, sal_Int16 nLang)
338 {
339 MutexGuard aGuard( GetLinguMutex() );
340 aWord = rWord;
341 nLanguage = nLang;
342 }
343
344
SetFailureType(sal_Int16 nTypeP)345 void SpellAlternatives::SetFailureType(sal_Int16 nTypeP)
346 {
347 MutexGuard aGuard( GetLinguMutex() );
348 nType = nTypeP;
349 }
350
351
SetAlternatives(const Sequence<OUString> & rAlt)352 void SpellAlternatives::SetAlternatives( const Sequence< OUString > &rAlt )
353 {
354 MutexGuard aGuard( GetLinguMutex() );
355 aAlt = rAlt;
356 }
357
358
CreateSpellAlternatives(const::rtl::OUString & rWord,sal_Int16 nLang,sal_Int16 nTypeP,const::com::sun::star::uno::Sequence<::rtl::OUString> & rAlt)359 com::sun::star::uno::Reference < com::sun::star::linguistic2::XSpellAlternatives > SpellAlternatives::CreateSpellAlternatives(
360 const ::rtl::OUString &rWord, sal_Int16 nLang, sal_Int16 nTypeP, const ::com::sun::star::uno::Sequence< ::rtl::OUString > &rAlt )
361 {
362 SpellAlternatives* pAlt = new SpellAlternatives;
363 pAlt->SetWordLanguage( rWord, nLang );
364 pAlt->SetFailureType( nTypeP );
365 pAlt->SetAlternatives( rAlt );
366 return Reference < XSpellAlternatives >(pAlt);
367 }
368
369 ///////////////////////////////////////////////////////////////////////////
370
371 } // namespace linguistic
372
373