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 <tools/string.hxx> 31 #include <tools/fsys.hxx> 32 #include <tools/debug.hxx> 33 #include <unotools/pathoptions.hxx> 34 #include <svl/lngmisc.hxx> 35 #include <ucbhelper/content.hxx> 36 #include <i18npool/mslangid.hxx> 37 #include <com/sun/star/ucb/XCommandEnvironment.hpp> 38 #include <com/sun/star/beans/XPropertySet.hpp> 39 #include <com/sun/star/beans/XFastPropertySet.hpp> 40 #include <com/sun/star/beans/XPropertyChangeListener.hpp> 41 #include <com/sun/star/frame/XTerminateListener.hpp> 42 #include <com/sun/star/frame/XDesktop.hpp> 43 #include <com/sun/star/frame/XStorable.hpp> 44 45 #include <com/sun/star/beans/PropertyValues.hpp> 46 #include <com/sun/star/uno/Sequence.hxx> 47 #include <com/sun/star/uno/Reference.h> 48 #include <com/sun/star/linguistic2/DictionaryType.hpp> 49 #include <com/sun/star/linguistic2/XSearchableDictionaryList.hpp> 50 #include <unotools/processfactory.hxx> 51 #include <unotools/localedatawrapper.hxx> 52 #include <unotools/syslocale.hxx> 53 54 #include <rtl/instance.hxx> 55 56 #include "linguistic/misc.hxx" 57 #include "defs.hxx" 58 #include "linguistic/lngprops.hxx" 59 #include "linguistic/hyphdta.hxx" 60 #include <i18npool/mslangid.hxx> 61 62 using namespace utl; 63 using namespace osl; 64 using namespace rtl; 65 using namespace com::sun::star; 66 using namespace com::sun::star::beans; 67 using namespace com::sun::star::lang; 68 using namespace com::sun::star::uno; 69 using namespace com::sun::star::i18n; 70 using namespace com::sun::star::linguistic2; 71 72 namespace linguistic 73 { 74 75 /////////////////////////////////////////////////////////////////////////// 76 77 //!! multi-thread safe mutex for all platforms !! 78 struct LinguMutex : public rtl::Static< osl::Mutex, LinguMutex > 79 { 80 }; 81 82 osl::Mutex & GetLinguMutex() 83 { 84 return LinguMutex::get(); 85 } 86 87 /////////////////////////////////////////////////////////////////////////// 88 89 LocaleDataWrapper & GetLocaleDataWrapper( sal_Int16 nLang ) 90 { 91 static LocaleDataWrapper aLclDtaWrp( 92 getProcessServiceFactory(), 93 CreateLocale( SvtSysLocale().GetUILanguage() ) ); 94 95 const Locale &rLcl = aLclDtaWrp.getLoadedLocale(); 96 Locale aLcl( CreateLocale( nLang ) ); 97 if (aLcl.Language != rLcl.Language || 98 aLcl.Country != rLcl.Country || 99 aLcl.Variant != rLcl.Variant) 100 aLclDtaWrp.setLocale( aLcl ); 101 return aLclDtaWrp; 102 } 103 104 /////////////////////////////////////////////////////////////////////////// 105 106 /** 107 returns text-encoding used for ByteString unicode String conversion 108 */ 109 rtl_TextEncoding GetTextEncoding( sal_Int16 nLanguage ) 110 { 111 DBG_ASSERT( nLanguage != LANGUAGE_NONE, "invalid language argument" ); 112 static sal_Int16 nLastLanguage = LANGUAGE_NONE; 113 114 // set default value for unknown languages 115 static rtl_TextEncoding nEncoding = RTL_TEXTENCODING_DONTKNOW; 116 117 if (nLastLanguage != nLanguage) 118 { 119 //!! IPR uses textencodings Latin-1, Latin-2, Latin-5 and Latin-7 !! 120 121 nLastLanguage = nLanguage; 122 switch (nLanguage) 123 { 124 case LANGUAGE_GERMAN : 125 case LANGUAGE_GERMAN_SWISS : 126 case LANGUAGE_ENGLISH_US : 127 case LANGUAGE_ENGLISH_UK : 128 case LANGUAGE_FRENCH : 129 case LANGUAGE_ITALIAN : 130 case LANGUAGE_SPANISH : 131 case LANGUAGE_CATALAN : 132 case LANGUAGE_PORTUGUESE : 133 case LANGUAGE_PORTUGUESE_BRAZILIAN : 134 case LANGUAGE_DANISH : 135 case LANGUAGE_DUTCH : 136 case LANGUAGE_SWEDISH : 137 case LANGUAGE_FINNISH : 138 case LANGUAGE_NORWEGIAN_BOKMAL : 139 case LANGUAGE_NORWEGIAN_NYNORSK : 140 case LANGUAGE_AFRIKAANS : 141 case LANGUAGE_ENGLISH_EIRE : 142 case LANGUAGE_ENGLISH_AUS : 143 #ifdef WNT 144 nEncoding = RTL_TEXTENCODING_MS_1252; break; 145 #else 146 nEncoding = RTL_TEXTENCODING_ISO_8859_1; break; 147 #endif 148 case LANGUAGE_CZECH : 149 case LANGUAGE_HUNGARIAN : 150 case LANGUAGE_POLISH : 151 #ifdef WNT 152 nEncoding = RTL_TEXTENCODING_MS_1250; break; 153 #else 154 nEncoding = RTL_TEXTENCODING_ISO_8859_2; break; 155 #endif 156 case LANGUAGE_RUSSIAN : 157 #ifdef WNT 158 nEncoding = RTL_TEXTENCODING_MS_1251; break; 159 #else 160 nEncoding = RTL_TEXTENCODING_ISO_8859_5; break; 161 #endif 162 case LANGUAGE_GREEK : 163 #ifdef WNT 164 nEncoding = RTL_TEXTENCODING_MS_1253; break; 165 #else 166 nEncoding = RTL_TEXTENCODING_ISO_8859_7; break; 167 #endif 168 default: 169 DBG_ASSERT( 0, "unexpected language" ); 170 } 171 } 172 173 return nEncoding; 174 } 175 176 /////////////////////////////////////////////////////////////////////////// 177 178 static inline sal_Int32 Minimum( sal_Int32 n1, sal_Int32 n2, sal_Int32 n3 ) 179 { 180 sal_Int32 nMin = n1 < n2 ? n1 : n2; 181 return nMin < n3 ? nMin : n3; 182 } 183 184 /////////////////////////////////////////////////////////////////////////// 185 186 class IntArray2D 187 { 188 private: 189 sal_Int32 *pData; 190 int n1, n2; 191 192 public: 193 IntArray2D( int nDim1, int nDim2 ); 194 ~IntArray2D(); 195 196 sal_Int32 & Value( int i, int k ); 197 }; 198 199 IntArray2D::IntArray2D( int nDim1, int nDim2 ) 200 { 201 n1 = nDim1; 202 n2 = nDim2; 203 pData = new sal_Int32[n1 * n2]; 204 } 205 206 IntArray2D::~IntArray2D() 207 { 208 delete[] pData; 209 } 210 211 sal_Int32 & IntArray2D::Value( int i, int k ) 212 { 213 DBG_ASSERT( 0 <= i && i < n1, "first index out of range" ); 214 DBG_ASSERT( 0 <= k && k < n2, "first index out of range" ); 215 DBG_ASSERT( i * n2 + k < n1 * n2, "index out of range" ); 216 return pData[ i * n2 + k ]; 217 } 218 219 220 sal_Int32 LevDistance( const OUString &rTxt1, const OUString &rTxt2 ) 221 { 222 sal_Int32 nLen1 = rTxt1.getLength(); 223 sal_Int32 nLen2 = rTxt2.getLength(); 224 225 if (nLen1 == 0) 226 return nLen2; 227 if (nLen2 == 0) 228 return nLen1; 229 230 IntArray2D aData( nLen1 + 1, nLen2 + 1 ); 231 232 sal_Int32 i, k; 233 for (i = 0; i <= nLen1; ++i) 234 aData.Value(i, 0) = i; 235 for (k = 0; k <= nLen2; ++k) 236 aData.Value(0, k) = k; 237 for (i = 1; i <= nLen1; ++i) 238 { 239 for (k = 1; k <= nLen2; ++k) 240 { 241 sal_Unicode c1i = rTxt1.getStr()[i - 1]; 242 sal_Unicode c2k = rTxt2.getStr()[k - 1]; 243 sal_Int32 nCost = c1i == c2k ? 0 : 1; 244 sal_Int32 nNew = Minimum( aData.Value(i-1, k ) + 1, 245 aData.Value(i , k-1) + 1, 246 aData.Value(i-1, k-1) + nCost ); 247 // take transposition (exchange with left or right char) in account 248 if (2 < i && 2 < k) 249 { 250 int nT = aData.Value(i-2, k-2) + 1; 251 if (rTxt1.getStr()[i - 2] != c1i) 252 ++nT; 253 if (rTxt2.getStr()[k - 2] != c2k) 254 ++nT; 255 if (nT < nNew) 256 nNew = nT; 257 } 258 259 aData.Value(i, k) = nNew; 260 } 261 } 262 sal_Int32 nDist = aData.Value(nLen1, nLen2); 263 return nDist; 264 } 265 266 /////////////////////////////////////////////////////////////////////////// 267 268 sal_Bool IsUseDicList( const PropertyValues &rProperties, 269 const uno::Reference< XPropertySet > &rxProp ) 270 { 271 sal_Bool bRes = sal_True; 272 273 sal_Int32 nLen = rProperties.getLength(); 274 const PropertyValue *pVal = rProperties.getConstArray(); 275 sal_Int32 i; 276 277 for ( i = 0; i < nLen; ++i) 278 { 279 if (UPH_IS_USE_DICTIONARY_LIST == pVal[i].Handle) 280 { 281 pVal[i].Value >>= bRes; 282 break; 283 } 284 } 285 if (i >= nLen) // no temporary value found in 'rProperties' 286 { 287 uno::Reference< XFastPropertySet > xFast( rxProp, UNO_QUERY ); 288 if (xFast.is()) 289 xFast->getFastPropertyValue( UPH_IS_USE_DICTIONARY_LIST ) >>= bRes; 290 } 291 292 return bRes; 293 } 294 295 296 sal_Bool IsIgnoreControlChars( const PropertyValues &rProperties, 297 const uno::Reference< XPropertySet > &rxProp ) 298 { 299 sal_Bool bRes = sal_True; 300 301 sal_Int32 nLen = rProperties.getLength(); 302 const PropertyValue *pVal = rProperties.getConstArray(); 303 sal_Int32 i; 304 305 for ( i = 0; i < nLen; ++i) 306 { 307 if (UPH_IS_IGNORE_CONTROL_CHARACTERS == pVal[i].Handle) 308 { 309 pVal[i].Value >>= bRes; 310 break; 311 } 312 } 313 if (i >= nLen) // no temporary value found in 'rProperties' 314 { 315 uno::Reference< XFastPropertySet > xFast( rxProp, UNO_QUERY ); 316 if (xFast.is()) 317 xFast->getFastPropertyValue( UPH_IS_IGNORE_CONTROL_CHARACTERS ) >>= bRes; 318 } 319 320 return bRes; 321 } 322 323 324 static sal_Bool lcl_HasHyphInfo( const uno::Reference<XDictionaryEntry> &xEntry ) 325 { 326 sal_Bool bRes = sal_False; 327 if (xEntry.is()) 328 { 329 // there has to be (at least one) '=' denoting a hyphenation position 330 // and it must not be before any character of the word 331 sal_Int32 nIdx = xEntry->getDictionaryWord().indexOf( '=' ); 332 bRes = nIdx != -1 && nIdx != 0; 333 } 334 return bRes; 335 } 336 337 338 uno::Reference< XDictionaryEntry > SearchDicList( 339 const uno::Reference< XDictionaryList > &xDicList, 340 const OUString &rWord, sal_Int16 nLanguage, 341 sal_Bool bSearchPosDics, sal_Bool bSearchSpellEntry ) 342 { 343 MutexGuard aGuard( GetLinguMutex() ); 344 345 uno::Reference< XDictionaryEntry > xEntry; 346 347 if (!xDicList.is()) 348 return xEntry; 349 350 const uno::Sequence< uno::Reference< XDictionary > > 351 aDics( xDicList->getDictionaries() ); 352 const uno::Reference< XDictionary > 353 *pDic = aDics.getConstArray(); 354 sal_Int32 nDics = xDicList->getCount(); 355 356 sal_Int32 i; 357 for (i = 0; i < nDics; i++) 358 { 359 uno::Reference< XDictionary > axDic( pDic[i], UNO_QUERY ); 360 361 DictionaryType eType = axDic->getDictionaryType(); 362 sal_Int16 nLang = LocaleToLanguage( axDic->getLocale() ); 363 364 if ( axDic.is() && axDic->isActive() 365 && (nLang == nLanguage || nLang == LANGUAGE_NONE) ) 366 { 367 DBG_ASSERT( eType != DictionaryType_MIXED, 368 "lng : unexpected dictionary type" ); 369 370 if ( (!bSearchPosDics && eType == DictionaryType_NEGATIVE) 371 || ( bSearchPosDics && eType == DictionaryType_POSITIVE)) 372 { 373 if ( (xEntry = axDic->getEntry( rWord )).is() ) 374 { 375 if (bSearchSpellEntry || lcl_HasHyphInfo( xEntry )) 376 break; 377 } 378 xEntry = 0; 379 } 380 } 381 } 382 383 return xEntry; 384 } 385 386 387 sal_Bool SaveDictionaries( const uno::Reference< XDictionaryList > &xDicList ) 388 { 389 if (!xDicList.is()) 390 return sal_True; 391 392 sal_Bool bRet = sal_True; 393 394 Sequence< uno::Reference< XDictionary > > aDics( xDicList->getDictionaries() ); 395 const uno::Reference< XDictionary > *pDic = aDics.getConstArray(); 396 sal_Int32 nCount = aDics.getLength(); 397 for (sal_Int32 i = 0; i < nCount; i++) 398 { 399 try 400 { 401 uno::Reference< frame::XStorable > xStor( pDic[i], UNO_QUERY ); 402 if (xStor.is()) 403 { 404 if (!xStor->isReadonly() && xStor->hasLocation()) 405 xStor->store(); 406 } 407 } 408 catch(uno::Exception &) 409 { 410 bRet = sal_False; 411 } 412 } 413 414 return bRet; 415 } 416 417 418 sal_uInt8 AddEntryToDic( 419 uno::Reference< XDictionary > &rxDic, 420 const OUString &rWord, sal_Bool bIsNeg, 421 const OUString &rRplcTxt, sal_Int16 /* nRplcLang */, 422 sal_Bool bStripDot ) 423 { 424 if (!rxDic.is()) 425 return DIC_ERR_NOT_EXISTS; 426 427 OUString aTmp( rWord ); 428 if (bStripDot) 429 { 430 sal_Int32 nLen = rWord.getLength(); 431 if (nLen > 0 && '.' == rWord[ nLen - 1]) 432 { 433 // remove trailing '.' 434 // (this is the official way to do this :-( ) 435 aTmp = aTmp.copy( 0, nLen - 1 ); 436 } 437 } 438 sal_Bool bAddOk = rxDic->add( aTmp, bIsNeg, rRplcTxt ); 439 440 sal_uInt8 nRes = DIC_ERR_NONE; 441 if (!bAddOk) 442 { 443 if (rxDic->isFull()) 444 nRes = DIC_ERR_FULL; 445 else 446 { 447 uno::Reference< frame::XStorable > xStor( rxDic, UNO_QUERY ); 448 if (xStor.is() && xStor->isReadonly()) 449 nRes = DIC_ERR_READONLY; 450 else 451 nRes = DIC_ERR_UNKNOWN; 452 } 453 } 454 455 return nRes; 456 } 457 458 459 /////////////////////////////////////////////////////////////////////////// 460 461 LanguageType LocaleToLanguage( const Locale& rLocale ) 462 { 463 // empty Locale -> LANGUAGE_NONE 464 if ( rLocale.Language.getLength() == 0 ) 465 return LANGUAGE_NONE; 466 467 return MsLangId::convertLocaleToLanguage( rLocale ); 468 } 469 470 471 Locale& LanguageToLocale( Locale& rLocale, LanguageType eLang ) 472 { 473 if ( eLang != LANGUAGE_NONE /* && eLang != LANGUAGE_SYSTEM */) 474 MsLangId::convertLanguageToLocale( eLang, rLocale ); 475 476 return rLocale; 477 } 478 479 Locale CreateLocale( LanguageType eLang ) 480 { 481 Locale aLocale; 482 if ( eLang != LANGUAGE_NONE /* && eLang != LANGUAGE_SYSTEM */) 483 return MsLangId::convertLanguageToLocale( eLang ); 484 485 return aLocale; 486 } 487 488 uno::Sequence< Locale > LangSeqToLocaleSeq( const uno::Sequence< sal_Int16 > &rLangSeq ) 489 { 490 const sal_Int16 *pLang = rLangSeq.getConstArray(); 491 sal_Int32 nCount = rLangSeq.getLength(); 492 493 uno::Sequence< Locale > aLocales( nCount ); 494 Locale *pLocale = aLocales.getArray(); 495 for (sal_Int32 i = 0; i < nCount; ++i) 496 { 497 LanguageToLocale( pLocale[i], pLang[ i ] ); 498 } 499 500 return aLocales; 501 } 502 503 uno::Sequence< sal_Int16 > 504 LocaleSeqToLangSeq( uno::Sequence< Locale > &rLocaleSeq ) 505 { 506 const Locale *pLocale = rLocaleSeq.getConstArray(); 507 sal_Int32 nCount = rLocaleSeq.getLength(); 508 509 uno::Sequence< sal_Int16 > aLangs( nCount ); 510 sal_Int16 *pLang = aLangs.getArray(); 511 for (sal_Int32 i = 0; i < nCount; ++i) 512 { 513 pLang[i] = LocaleToLanguage( pLocale[i] ); 514 } 515 516 return aLangs; 517 } 518 519 /////////////////////////////////////////////////////////////////////////// 520 521 sal_Bool IsReadOnly( const String &rURL, sal_Bool *pbExist ) 522 { 523 sal_Bool bRes = sal_False; 524 sal_Bool bExists = sal_False; 525 526 if (rURL.Len() > 0) 527 { 528 try 529 { 530 uno::Reference< ::com::sun::star::ucb::XCommandEnvironment > xCmdEnv; 531 ::ucbhelper::Content aContent( rURL, xCmdEnv ); 532 533 bExists = aContent.isDocument(); 534 if (bExists) 535 { 536 Any aAny( aContent.getPropertyValue( A2OU( "IsReadOnly" ) ) ); 537 aAny >>= bRes; 538 } 539 } 540 catch (Exception &) 541 { 542 bRes = sal_True; 543 } 544 } 545 546 if (pbExist) 547 *pbExist = bExists; 548 return bRes; 549 } 550 551 /////////////////////////////////////////////////////////////////////////// 552 553 554 static sal_Bool GetAltSpelling( sal_Int16 &rnChgPos, sal_Int16 &rnChgLen, OUString &rRplc, 555 uno::Reference< XHyphenatedWord > &rxHyphWord ) 556 { 557 sal_Bool bRes = rxHyphWord->isAlternativeSpelling(); 558 if (bRes) 559 { 560 OUString aWord( rxHyphWord->getWord() ), 561 aHyphenatedWord( rxHyphWord->getHyphenatedWord() ); 562 sal_Int16 nHyphenationPos = rxHyphWord->getHyphenationPos(); 563 /*sal_Int16 nHyphenPos = rxHyphWord->getHyphenPos()*/; 564 const sal_Unicode *pWord = aWord.getStr(), 565 *pAltWord = aHyphenatedWord.getStr(); 566 567 // at least char changes directly left or right to the hyphen 568 // should(!) be handled properly... 569 //! nHyphenationPos and nHyphenPos differ at most by 1 (see above) 570 //! Beware: eg "Schiffahrt" in German (pre spelling reform) 571 //! proves to be a bit nasty (nChgPosLeft and nChgPosRight overlap 572 //! to an extend.) 573 574 // find first different char from left 575 sal_Int32 nPosL = 0, 576 nAltPosL = 0; 577 for (sal_Int16 i = 0 ; pWord[ nPosL ] == pAltWord[ nAltPosL ]; nPosL++, nAltPosL++, i++) 578 { 579 // restrict changes area beginning to the right to 580 // the char immediately following the hyphen. 581 //! serves to insert the additional "f" in "Schiffahrt" at 582 //! position 5 rather than position 6. 583 if (i >= nHyphenationPos + 1) 584 break; 585 } 586 587 // find first different char from right 588 sal_Int32 nPosR = aWord.getLength() - 1, 589 nAltPosR = aHyphenatedWord.getLength() - 1; 590 for ( ; nPosR >= nPosL && nAltPosR >= nAltPosL 591 && pWord[ nPosR ] == pAltWord[ nAltPosR ]; 592 nPosR--, nAltPosR--) 593 ; 594 595 rnChgPos = sal::static_int_cast< sal_Int16 >(nPosL); 596 rnChgLen = sal::static_int_cast< sal_Int16 >(nPosR - nPosL + 1); 597 DBG_ASSERT( rnChgLen >= 0, "nChgLen < 0"); 598 599 sal_Int32 nTxtStart = nPosL; 600 sal_Int32 nTxtLen = nAltPosL - nPosL + 1; 601 rRplc = aHyphenatedWord.copy( nTxtStart, nTxtLen ); 602 } 603 return bRes; 604 } 605 606 607 static sal_Int16 GetOrigWordPos( const OUString &rOrigWord, sal_Int16 nPos ) 608 { 609 sal_Int32 nLen = rOrigWord.getLength(); 610 sal_Int32 i = -1; 611 while (nPos >= 0 && i++ < nLen) 612 { 613 sal_Unicode cChar = rOrigWord[i]; 614 sal_Bool bSkip = IsHyphen( cChar ) || IsControlChar( cChar ); 615 if (!bSkip) 616 --nPos; 617 } 618 return sal::static_int_cast< sal_Int16 >((0 <= i && i < nLen) ? i : -1); 619 } 620 621 622 sal_Int32 GetPosInWordToCheck( const OUString &rTxt, sal_Int32 nPos ) 623 { 624 sal_Int32 nRes = -1; 625 sal_Int32 nLen = rTxt.getLength(); 626 if (0 <= nPos && nPos < nLen) 627 { 628 nRes = 0; 629 for (sal_Int32 i = 0; i < nPos; ++i) 630 { 631 sal_Unicode cChar = rTxt[i]; 632 sal_Bool bSkip = IsHyphen( cChar ) || IsControlChar( cChar ); 633 if (!bSkip) 634 ++nRes; 635 } 636 } 637 return nRes; 638 } 639 640 641 uno::Reference< XHyphenatedWord > RebuildHyphensAndControlChars( 642 const OUString &rOrigWord, 643 uno::Reference< XHyphenatedWord > &rxHyphWord ) 644 { 645 uno::Reference< XHyphenatedWord > xRes; 646 if (rOrigWord.getLength() && rxHyphWord.is()) 647 { 648 sal_Int16 nChgPos = 0, 649 nChgLen = 0; 650 OUString aRplc; 651 sal_Bool bAltSpelling = GetAltSpelling( nChgPos, nChgLen, aRplc, rxHyphWord ); 652 #if OSL_DEBUG_LEVEL > 1 653 OUString aWord( rxHyphWord->getWord() ); 654 #endif 655 656 OUString aOrigHyphenatedWord; 657 sal_Int16 nOrigHyphenPos = -1; 658 sal_Int16 nOrigHyphenationPos = -1; 659 if (!bAltSpelling) 660 { 661 aOrigHyphenatedWord = rOrigWord; 662 nOrigHyphenPos = GetOrigWordPos( rOrigWord, rxHyphWord->getHyphenPos() ); 663 nOrigHyphenationPos = GetOrigWordPos( rOrigWord, rxHyphWord->getHyphenationPos() ); 664 } 665 else 666 { 667 //! should at least work with the German words 668 //! B�-c-k-er and Sc-hif-fah-rt 669 670 OUString aLeft, aRight; 671 sal_Int16 nPos = GetOrigWordPos( rOrigWord, nChgPos ); 672 673 // get words like Sc-hif-fah-rt to work correct 674 sal_Int16 nHyphenationPos = rxHyphWord->getHyphenationPos(); 675 if (nChgPos > nHyphenationPos) 676 --nPos; 677 678 aLeft = rOrigWord.copy( 0, nPos ); 679 aRight = rOrigWord.copy( nPos + nChgLen ); 680 681 aOrigHyphenatedWord = aLeft; 682 aOrigHyphenatedWord += aRplc; 683 aOrigHyphenatedWord += aRight; 684 685 nOrigHyphenPos = sal::static_int_cast< sal_Int16 >(aLeft.getLength() + 686 rxHyphWord->getHyphenPos() - nChgPos); 687 nOrigHyphenationPos = GetOrigWordPos( rOrigWord, nHyphenationPos ); 688 } 689 690 if (nOrigHyphenPos == -1 || nOrigHyphenationPos == -1) 691 { 692 DBG_ASSERT( 0, "failed to get nOrigHyphenPos or nOrigHyphenationPos" ); 693 } 694 else 695 { 696 sal_Int16 nLang = LocaleToLanguage( rxHyphWord->getLocale() ); 697 xRes = new HyphenatedWord( 698 rOrigWord, nLang, nOrigHyphenationPos, 699 aOrigHyphenatedWord, nOrigHyphenPos ); 700 } 701 702 } 703 return xRes; 704 } 705 706 707 /////////////////////////////////////////////////////////////////////////// 708 709 710 static CharClass & lcl_GetCharClass() 711 { 712 static CharClass aCC( CreateLocale( LANGUAGE_ENGLISH_US ) ); 713 return aCC; 714 } 715 716 717 osl::Mutex & lcl_GetCharClassMutex() 718 { 719 static osl::Mutex aMutex; 720 return aMutex; 721 } 722 723 724 sal_Bool IsUpper( const String &rText, xub_StrLen nPos, xub_StrLen nLen, sal_Int16 nLanguage ) 725 { 726 MutexGuard aGuard( lcl_GetCharClassMutex() ); 727 728 CharClass &rCC = lcl_GetCharClass(); 729 rCC.setLocale( CreateLocale( nLanguage ) ); 730 sal_Int32 nFlags = rCC.getStringType( rText, nPos, nLen ); 731 return (nFlags & KCharacterType::UPPER) 732 && !(nFlags & KCharacterType::LOWER); 733 } 734 735 736 sal_Bool IsLower( const String &rText, xub_StrLen nPos, xub_StrLen nLen, sal_Int16 nLanguage ) 737 { 738 MutexGuard aGuard( lcl_GetCharClassMutex() ); 739 740 CharClass &rCC = lcl_GetCharClass(); 741 rCC.setLocale( CreateLocale( nLanguage ) ); 742 sal_Int32 nFlags = rCC.getStringType( rText, nPos, nLen ); 743 return (nFlags & KCharacterType::LOWER) 744 && !(nFlags & KCharacterType::UPPER); 745 } 746 747 748 String ToLower( const String &rText, sal_Int16 nLanguage ) 749 { 750 MutexGuard aGuard( lcl_GetCharClassMutex() ); 751 752 CharClass &rCC = lcl_GetCharClass(); 753 rCC.setLocale( CreateLocale( nLanguage ) ); 754 return rCC.lower( rText ); 755 } 756 757 758 String ToUpper( const String &rText, sal_Int16 nLanguage ) 759 { 760 MutexGuard aGuard( lcl_GetCharClassMutex() ); 761 762 CharClass &rCC = lcl_GetCharClass(); 763 rCC.setLocale( CreateLocale( nLanguage ) ); 764 return rCC.upper( rText ); 765 } 766 767 768 String ToTitle( const String &rText, sal_Int16 nLanguage ) 769 { 770 MutexGuard aGuard( lcl_GetCharClassMutex() ); 771 772 CharClass &rCC = lcl_GetCharClass(); 773 rCC.setLocale( CreateLocale( nLanguage ) ); 774 return rCC.toTitle( rText, 0, rText.Len() ); 775 } 776 777 778 sal_Unicode ToLower( const sal_Unicode cChar, sal_Int16 nLanguage ) 779 { 780 MutexGuard aGuard( lcl_GetCharClassMutex() ); 781 782 CharClass &rCC = lcl_GetCharClass(); 783 rCC.setLocale( CreateLocale( nLanguage ) ); 784 return rCC.lower( cChar ).GetChar(0); 785 } 786 787 788 sal_Unicode ToUpper( const sal_Unicode cChar, sal_Int16 nLanguage ) 789 { 790 MutexGuard aGuard( lcl_GetCharClassMutex() ); 791 792 CharClass &rCC = lcl_GetCharClass(); 793 rCC.setLocale( CreateLocale( nLanguage ) ); 794 return rCC.upper( cChar ).GetChar(0); 795 } 796 797 // sorted(!) array of unicode ranges for code points that are exclusively(!) used as numbers 798 // and thus may NOT not be part of names or words like the Chinese/Japanese number characters 799 static const sal_uInt32 the_aDigitZeroes [] = 800 { 801 0x00000030, //0039 ; Decimal # Nd [10] DIGIT ZERO..DIGIT NINE 802 0x00000660, //0669 ; Decimal # Nd [10] ARABIC-INDIC DIGIT ZERO..ARABIC-INDIC DIGIT NINE 803 0x000006F0, //06F9 ; Decimal # Nd [10] EXTENDED ARABIC-INDIC DIGIT ZERO..EXTENDED ARABIC-INDIC DIGIT NINE 804 0x000007C0, //07C9 ; Decimal # Nd [10] NKO DIGIT ZERO..NKO DIGIT NINE 805 0x00000966, //096F ; Decimal # Nd [10] DEVANAGARI DIGIT ZERO..DEVANAGARI DIGIT NINE 806 0x000009E6, //09EF ; Decimal # Nd [10] BENGALI DIGIT ZERO..BENGALI DIGIT NINE 807 0x00000A66, //0A6F ; Decimal # Nd [10] GURMUKHI DIGIT ZERO..GURMUKHI DIGIT NINE 808 0x00000AE6, //0AEF ; Decimal # Nd [10] GUJARATI DIGIT ZERO..GUJARATI DIGIT NINE 809 0x00000B66, //0B6F ; Decimal # Nd [10] ORIYA DIGIT ZERO..ORIYA DIGIT NINE 810 0x00000BE6, //0BEF ; Decimal # Nd [10] TAMIL DIGIT ZERO..TAMIL DIGIT NINE 811 0x00000C66, //0C6F ; Decimal # Nd [10] TELUGU DIGIT ZERO..TELUGU DIGIT NINE 812 0x00000CE6, //0CEF ; Decimal # Nd [10] KANNADA DIGIT ZERO..KANNADA DIGIT NINE 813 0x00000D66, //0D6F ; Decimal # Nd [10] MALAYALAM DIGIT ZERO..MALAYALAM DIGIT NINE 814 0x00000E50, //0E59 ; Decimal # Nd [10] THAI DIGIT ZERO..THAI DIGIT NINE 815 0x00000ED0, //0ED9 ; Decimal # Nd [10] LAO DIGIT ZERO..LAO DIGIT NINE 816 0x00000F20, //0F29 ; Decimal # Nd [10] TIBETAN DIGIT ZERO..TIBETAN DIGIT NINE 817 0x00001040, //1049 ; Decimal # Nd [10] MYANMAR DIGIT ZERO..MYANMAR DIGIT NINE 818 0x00001090, //1099 ; Decimal # Nd [10] MYANMAR SHAN DIGIT ZERO..MYANMAR SHAN DIGIT NINE 819 0x000017E0, //17E9 ; Decimal # Nd [10] KHMER DIGIT ZERO..KHMER DIGIT NINE 820 0x00001810, //1819 ; Decimal # Nd [10] MONGOLIAN DIGIT ZERO..MONGOLIAN DIGIT NINE 821 0x00001946, //194F ; Decimal # Nd [10] LIMBU DIGIT ZERO..LIMBU DIGIT NINE 822 0x000019D0, //19D9 ; Decimal # Nd [10] NEW TAI LUE DIGIT ZERO..NEW TAI LUE DIGIT NINE 823 0x00001B50, //1B59 ; Decimal # Nd [10] BALINESE DIGIT ZERO..BALINESE DIGIT NINE 824 0x00001BB0, //1BB9 ; Decimal # Nd [10] SUNDANESE DIGIT ZERO..SUNDANESE DIGIT NINE 825 0x00001C40, //1C49 ; Decimal # Nd [10] LEPCHA DIGIT ZERO..LEPCHA DIGIT NINE 826 0x00001C50, //1C59 ; Decimal # Nd [10] OL CHIKI DIGIT ZERO..OL CHIKI DIGIT NINE 827 0x0000A620, //A629 ; Decimal # Nd [10] VAI DIGIT ZERO..VAI DIGIT NINE 828 0x0000A8D0, //A8D9 ; Decimal # Nd [10] SAURASHTRA DIGIT ZERO..SAURASHTRA DIGIT NINE 829 0x0000A900, //A909 ; Decimal # Nd [10] KAYAH LI DIGIT ZERO..KAYAH LI DIGIT NINE 830 0x0000AA50, //AA59 ; Decimal # Nd [10] CHAM DIGIT ZERO..CHAM DIGIT NINE 831 0x0000FF10, //FF19 ; Decimal # Nd [10] FULLWIDTH DIGIT ZERO..FULLWIDTH DIGIT NINE 832 0x000104A0, //104A9 ; Decimal # Nd [10] OSMANYA DIGIT ZERO..OSMANYA DIGIT NINE 833 0x0001D7CE //1D7FF ; Decimal # Nd [50] MATHEMATICAL BOLD DIGIT ZERO..MATHEMATICAL MONOSPACE DIGIT NINE 834 }; 835 836 sal_Bool HasDigits( const OUString &rText ) 837 { 838 static const int nNumDigitZeroes = sizeof(the_aDigitZeroes) / sizeof(the_aDigitZeroes[0]); 839 const sal_Int32 nLen = rText.getLength(); 840 841 sal_Int32 i = 0; 842 while (i < nLen) // for all characters ... 843 { 844 const sal_uInt32 nCodePoint = rText.iterateCodePoints( &i ); // handle unicode surrogates correctly... 845 for (int j = 0; j < nNumDigitZeroes; ++j) // ... check in all 0..9 ranges 846 { 847 sal_uInt32 nDigitZero = the_aDigitZeroes[ j ]; 848 if (nDigitZero > nCodePoint) 849 break; 850 if (/*nDigitZero <= nCodePoint &&*/ nCodePoint <= nDigitZero + 9) 851 return sal_True; 852 } 853 } 854 return sal_False; 855 } 856 857 858 sal_Bool IsNumeric( const String &rText ) 859 { 860 sal_Bool bRes = sal_False; 861 xub_StrLen nLen = rText.Len(); 862 if (nLen) 863 { 864 bRes = sal_True; 865 xub_StrLen i = 0; 866 while (i < nLen) 867 { 868 sal_Unicode cChar = rText.GetChar( i++ ); 869 if ( !((sal_Unicode)'0' <= cChar && cChar <= (sal_Unicode)'9') ) 870 { 871 bRes = sal_False; 872 break; 873 } 874 } 875 } 876 return bRes; 877 } 878 879 880 /////////////////////////////////////////////////////////////////////////// 881 882 uno::Reference< XInterface > GetOneInstanceService( const char *pServiceName ) 883 { 884 uno::Reference< XInterface > xRef; 885 886 if (pServiceName) 887 { 888 uno::Reference< XMultiServiceFactory > xMgr( getProcessServiceFactory() ); 889 if (xMgr.is()) 890 { 891 try 892 { 893 xRef = xMgr->createInstance( A2OU( pServiceName ) ); 894 } 895 catch (uno::Exception &) 896 { 897 DBG_ASSERT( 0, "createInstance failed" ); 898 } 899 } 900 } 901 902 return xRef; 903 } 904 905 uno::Reference< XPropertySet > GetLinguProperties() 906 { 907 return uno::Reference< XPropertySet > ( 908 GetOneInstanceService( SN_LINGU_PROPERTIES ), UNO_QUERY ); 909 } 910 911 uno::Reference< XSearchableDictionaryList > GetSearchableDictionaryList() 912 { 913 return uno::Reference< XSearchableDictionaryList > ( 914 GetOneInstanceService( SN_DICTIONARY_LIST ), UNO_QUERY ); 915 } 916 917 uno::Reference< XDictionaryList > GetDictionaryList() 918 { 919 return uno::Reference< XDictionaryList > ( 920 GetOneInstanceService( SN_DICTIONARY_LIST ), UNO_QUERY ); 921 } 922 923 uno::Reference< XDictionary > GetIgnoreAllList() 924 { 925 uno::Reference< XDictionary > xRes; 926 uno::Reference< XDictionaryList > xDL( GetDictionaryList() ); 927 if (xDL.is()) 928 xRes = xDL->getDictionaryByName( A2OU("IgnoreAllList") ); 929 return xRes; 930 } 931 932 /////////////////////////////////////////////////////////////////////////// 933 934 AppExitListener::AppExitListener() 935 { 936 // add object to Desktop EventListeners in order to properly call 937 // the AtExit function at appliction exit. 938 uno::Reference< XMultiServiceFactory > xMgr = getProcessServiceFactory(); 939 940 if (xMgr.is()) 941 { 942 try 943 { 944 xDesktop = uno::Reference< frame::XDesktop >( 945 xMgr->createInstance( A2OU( SN_DESKTOP ) ), UNO_QUERY ); 946 } 947 catch (uno::Exception &) 948 { 949 DBG_ASSERT( 0, "createInstance failed" ); 950 } 951 } 952 } 953 954 AppExitListener::~AppExitListener() 955 { 956 } 957 958 959 void AppExitListener::Activate() 960 { 961 if (xDesktop.is()) 962 xDesktop->addTerminateListener( this ); 963 } 964 965 966 void AppExitListener::Deactivate() 967 { 968 if (xDesktop.is()) 969 xDesktop->removeTerminateListener( this ); 970 } 971 972 973 void SAL_CALL 974 AppExitListener::disposing( const EventObject& rEvtSource ) 975 throw(RuntimeException) 976 { 977 MutexGuard aGuard( GetLinguMutex() ); 978 979 if (xDesktop.is() && rEvtSource.Source == xDesktop) 980 { 981 xDesktop = NULL; //! release reference to desktop 982 } 983 } 984 985 986 void SAL_CALL 987 AppExitListener::queryTermination( const EventObject& /*rEvtSource*/ ) 988 throw(frame::TerminationVetoException, RuntimeException) 989 { 990 //MutexGuard aGuard( GetLinguMutex() ); 991 } 992 993 994 void SAL_CALL 995 AppExitListener::notifyTermination( const EventObject& rEvtSource ) 996 throw(RuntimeException) 997 { 998 MutexGuard aGuard( GetLinguMutex() ); 999 1000 if (xDesktop.is() && rEvtSource.Source == xDesktop) 1001 { 1002 AtExit(); 1003 } 1004 } 1005 1006 /////////////////////////////////////////////////////////////////////////// 1007 1008 } // namespace linguistic 1009 1010