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