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