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 31 32 #include <cppuhelper/factory.hxx> // helper for factories 33 #include <com/sun/star/registry/XRegistryKey.hpp> 34 #include <com/sun/star/linguistic2/XSearchableDictionaryList.hpp> 35 #include <com/sun/star/linguistic2/XHyphenatedWord.hpp> 36 #include <rtl/ustrbuf.hxx> 37 #include <i18npool/lang.h> 38 #include <unotools/localedatawrapper.hxx> 39 #include <tools/debug.hxx> 40 #include <svl/lngmisc.hxx> 41 #include <unotools/processfactory.hxx> 42 #include <osl/mutex.hxx> 43 44 #include "hyphdsp.hxx" 45 #include "linguistic/hyphdta.hxx" 46 #include "linguistic/lngprops.hxx" 47 #include "lngsvcmgr.hxx" 48 49 50 using namespace utl; 51 using namespace osl; 52 using namespace rtl; 53 using namespace com::sun::star; 54 using namespace com::sun::star::beans; 55 using namespace com::sun::star::lang; 56 using namespace com::sun::star::uno; 57 using namespace com::sun::star::linguistic2; 58 using namespace linguistic; 59 60 /////////////////////////////////////////////////////////////////////////// 61 62 HyphenatorDispatcher::HyphenatorDispatcher( LngSvcMgr &rLngSvcMgr ) : 63 rMgr (rLngSvcMgr) 64 { 65 } 66 67 68 HyphenatorDispatcher::~HyphenatorDispatcher() 69 { 70 ClearSvcList(); 71 } 72 73 74 void HyphenatorDispatcher::ClearSvcList() 75 { 76 // release memory for each table entry 77 HyphSvcByLangMap_t aTmp; 78 aSvcMap.swap( aTmp ); 79 } 80 81 82 Reference<XHyphenatedWord> HyphenatorDispatcher::buildHyphWord( 83 const OUString rOrigWord, 84 const Reference<XDictionaryEntry> &xEntry, 85 sal_Int16 nLang, sal_Int16 nMaxLeading ) 86 { 87 MutexGuard aGuard( GetLinguMutex() ); 88 89 Reference< XHyphenatedWord > xRes; 90 91 if (xEntry.is()) 92 { 93 OUString aText( xEntry->getDictionaryWord() ); 94 sal_Int32 nTextLen = aText.getLength(); 95 96 // trailing '=' means "hyphenation should not be possible" 97 if (nTextLen > 0 && aText[ nTextLen - 1 ] != '=') 98 { 99 sal_Int16 nHyphenationPos = -1; 100 101 OUStringBuffer aTmp( nTextLen ); 102 sal_Bool bSkip = sal_False; 103 sal_Int32 nHyphIdx = -1; 104 sal_Int32 nLeading = 0; 105 for (sal_Int32 i = 0; i < nTextLen; i++) 106 { 107 sal_Unicode cTmp = aText[i]; 108 if (cTmp != '=') 109 { 110 aTmp.append( cTmp ); 111 nLeading++; 112 bSkip = sal_False; 113 nHyphIdx++; 114 } 115 else 116 { 117 if (!bSkip && nHyphIdx >= 0) 118 { 119 if (nLeading <= nMaxLeading) 120 nHyphenationPos = (sal_Int16) nHyphIdx; 121 } 122 bSkip = sal_True; //! multiple '=' should count as one only 123 } 124 } 125 126 if (nHyphenationPos > 0) 127 { 128 aText = aTmp.makeStringAndClear(); 129 130 #if OSL_DEBUG_LEVEL > 1 131 { 132 if (aText != rOrigWord) 133 { 134 // both words should only differ by a having a trailing '.' 135 // character or not... 136 OUString aShorter, aLonger; 137 if (aText.getLength() <= rOrigWord.getLength()) 138 { 139 aShorter = aText; 140 aLonger = rOrigWord; 141 } 142 else 143 { 144 aShorter = rOrigWord; 145 aLonger = aText; 146 } 147 xub_StrLen nS = sal::static_int_cast< xub_StrLen >( aShorter.getLength() ); 148 xub_StrLen nL = sal::static_int_cast< xub_StrLen >( aLonger.getLength() ); 149 if (nS > 0 && nL > 0) 150 { 151 DBG_ASSERT( (nS + 1 == nL) && aLonger[nL-1] == (sal_Unicode) '.', 152 "HyphenatorDispatcher::buildHyphWord: unexpected difference between words!" ); 153 } 154 } 155 } 156 #endif 157 //! take care of #i22591# 158 aText = rOrigWord; 159 160 DBG_ASSERT( aText == rOrigWord, "failed to " ); 161 xRes = new HyphenatedWord( aText, nLang, nHyphenationPos, 162 aText, nHyphenationPos ); 163 } 164 } 165 } 166 167 return xRes; 168 } 169 170 171 Reference< XPossibleHyphens > HyphenatorDispatcher::buildPossHyphens( 172 const Reference< XDictionaryEntry > &xEntry, sal_Int16 nLanguage ) 173 { 174 MutexGuard aGuard( GetLinguMutex() ); 175 176 Reference<XPossibleHyphens> xRes; 177 178 if (xEntry.is()) 179 { 180 // text with hyphenation info 181 OUString aText( xEntry->getDictionaryWord() ); 182 sal_Int32 nTextLen = aText.getLength(); 183 184 // trailing '=' means "hyphenation should not be possible" 185 if (nTextLen > 0 && aText[ nTextLen - 1 ] != '=') 186 { 187 // sequence to hold hyphenation positions 188 Sequence< sal_Int16 > aHyphPos( nTextLen ); 189 sal_Int16 *pPos = aHyphPos.getArray(); 190 sal_Int32 nHyphCount = 0; 191 192 OUStringBuffer aTmp( nTextLen ); 193 sal_Bool bSkip = sal_False; 194 sal_Int32 nHyphIdx = -1; 195 for (sal_Int32 i = 0; i < nTextLen; i++) 196 { 197 sal_Unicode cTmp = aText[i]; 198 if (cTmp != '=') 199 { 200 aTmp.append( cTmp ); 201 bSkip = sal_False; 202 nHyphIdx++; 203 } 204 else 205 { 206 if (!bSkip && nHyphIdx >= 0) 207 pPos[ nHyphCount++ ] = (sal_Int16) nHyphIdx; 208 bSkip = sal_True; //! multiple '=' should count as one only 209 } 210 } 211 212 // ignore (multiple) trailing '=' 213 if (bSkip && nHyphIdx >= 0) 214 { 215 nHyphCount--; 216 } 217 DBG_ASSERT( nHyphCount >= 0, "lng : invalid hyphenation count"); 218 219 if (nHyphCount > 0) 220 { 221 aHyphPos.realloc( nHyphCount ); 222 xRes = new PossibleHyphens( aTmp.makeStringAndClear(), nLanguage, 223 aText, aHyphPos ); 224 } 225 } 226 } 227 228 return xRes; 229 } 230 231 232 Sequence< Locale > SAL_CALL HyphenatorDispatcher::getLocales() 233 throw(RuntimeException) 234 { 235 MutexGuard aGuard( GetLinguMutex() ); 236 237 Sequence< Locale > aLocales( static_cast< sal_Int32 >(aSvcMap.size()) ); 238 Locale *pLocales = aLocales.getArray(); 239 HyphSvcByLangMap_t::const_iterator aIt; 240 for (aIt = aSvcMap.begin(); aIt != aSvcMap.end(); ++aIt) 241 { 242 *pLocales++ = CreateLocale( aIt->first ); 243 } 244 return aLocales; 245 } 246 247 248 sal_Bool SAL_CALL HyphenatorDispatcher::hasLocale(const Locale& rLocale) 249 throw(RuntimeException) 250 { 251 MutexGuard aGuard( GetLinguMutex() ); 252 HyphSvcByLangMap_t::const_iterator aIt( aSvcMap.find( LocaleToLanguage( rLocale ) ) ); 253 return aIt != aSvcMap.end(); 254 } 255 256 257 Reference< XHyphenatedWord > SAL_CALL 258 HyphenatorDispatcher::hyphenate( 259 const OUString& rWord, const Locale& rLocale, sal_Int16 nMaxLeading, 260 const PropertyValues& rProperties ) 261 throw(IllegalArgumentException, RuntimeException) 262 { 263 MutexGuard aGuard( GetLinguMutex() ); 264 265 Reference< XHyphenatedWord > xRes; 266 267 sal_Int32 nWordLen = rWord.getLength(); 268 sal_Int16 nLanguage = LocaleToLanguage( rLocale ); 269 if (nLanguage == LANGUAGE_NONE || !nWordLen || 270 nMaxLeading == 0 || nMaxLeading == nWordLen) 271 return xRes; 272 273 // search for entry with that language 274 HyphSvcByLangMap_t::iterator aIt( aSvcMap.find( nLanguage ) ); 275 LangSvcEntries_Hyph *pEntry = aIt != aSvcMap.end() ? aIt->second.get() : NULL; 276 277 sal_Bool bWordModified = sal_False; 278 if (!pEntry || (nMaxLeading < 0 || nMaxLeading > nWordLen)) 279 { 280 #ifdef LINGU_EXCEPTIONS 281 throw IllegalArgumentException(); 282 #else 283 return NULL; 284 #endif 285 } 286 else 287 { 288 OUString aChkWord( rWord ); 289 290 // replace typographical apostroph by ascii apostroph 291 String aSingleQuote( GetLocaleDataWrapper( nLanguage ).getQuotationMarkEnd() ); 292 DBG_ASSERT( 1 == aSingleQuote.Len(), "unexpectend length of quotation mark" ); 293 if (aSingleQuote.Len()) 294 aChkWord = aChkWord.replace( aSingleQuote.GetChar(0), '\'' ); 295 296 bWordModified |= RemoveHyphens( aChkWord ); 297 if (IsIgnoreControlChars( rProperties, GetPropSet() )) 298 bWordModified |= RemoveControlChars( aChkWord ); 299 sal_Int16 nChkMaxLeading = (sal_Int16) GetPosInWordToCheck( rWord, nMaxLeading ); 300 301 // check for results from (positive) dictionaries which have precedence! 302 Reference< XDictionaryEntry > xEntry; 303 304 if (GetDicList().is() && IsUseDicList( rProperties, GetPropSet() )) 305 { 306 xEntry = GetDicList()->queryDictionaryEntry( aChkWord, rLocale, 307 sal_True, sal_False ); 308 } 309 310 if (xEntry.is()) 311 { 312 //! because queryDictionaryEntry (in the end DictionaryNeo::getEntry) 313 //! does not distinguish betwee "XYZ" and "XYZ." in order to avoid 314 //! to require them as different entry we have to supply the 315 //! original word here as well so it can be used in th result 316 //! otherwise a strange effect may occur (see #i22591#) 317 xRes = buildHyphWord( rWord, xEntry, nLanguage, nChkMaxLeading ); 318 } 319 else 320 { 321 sal_Int32 nLen = pEntry->aSvcImplNames.getLength() > 0 ? 1 : 0; 322 DBG_ASSERT( pEntry->nLastTriedSvcIndex < nLen, 323 "lng : index out of range"); 324 325 sal_Int32 i = 0; 326 Reference< XHyphenator > xHyph; 327 if (pEntry->aSvcRefs.getLength() > 0) 328 xHyph = pEntry->aSvcRefs[0]; 329 330 // try already instantiated service 331 if (i <= pEntry->nLastTriedSvcIndex) 332 { 333 if (xHyph.is() && xHyph->hasLocale( rLocale )) 334 xRes = xHyph->hyphenate( aChkWord, rLocale, nChkMaxLeading, 335 rProperties ); 336 ++i; 337 } 338 else if (pEntry->nLastTriedSvcIndex < nLen - 1) 339 // instantiate services and try it 340 { 341 // const OUString *pImplNames = pEntry->aSvcImplNames.getConstArray(); 342 Reference< XHyphenator > *pRef = pEntry->aSvcRefs.getArray(); 343 344 Reference< XMultiServiceFactory > xMgr( getProcessServiceFactory() ); 345 if (xMgr.is()) 346 { 347 // build service initialization argument 348 Sequence< Any > aArgs(2); 349 aArgs.getArray()[0] <<= GetPropSet(); 350 //! The dispatcher searches the dictionary-list 351 //! thus the service needs not to now about it 352 //aArgs.getArray()[1] <<= GetDicList(); 353 354 // create specific service via it's implementation name 355 try 356 { 357 xHyph = Reference< XHyphenator >( 358 xMgr->createInstanceWithArguments( 359 pEntry->aSvcImplNames[0], aArgs ), UNO_QUERY ); 360 } 361 catch (uno::Exception &) 362 { 363 DBG_ASSERT( 0, "createInstanceWithArguments failed" ); 364 } 365 pRef [i] = xHyph; 366 367 Reference< XLinguServiceEventBroadcaster > 368 xBroadcaster( xHyph, UNO_QUERY ); 369 if (xBroadcaster.is()) 370 rMgr.AddLngSvcEvtBroadcaster( xBroadcaster ); 371 372 if (xHyph.is() && xHyph->hasLocale( rLocale )) 373 xRes = xHyph->hyphenate( aChkWord, rLocale, nChkMaxLeading, 374 rProperties ); 375 376 pEntry->nLastTriedSvcIndex = (sal_Int16) i; 377 ++i; 378 379 // if language is not supported by the services 380 // remove it from the list. 381 if (xHyph.is() && !xHyph->hasLocale( rLocale )) 382 aSvcMap.erase( nLanguage ); 383 } 384 } 385 } // if (xEntry.is()) 386 } 387 388 if (bWordModified && xRes.is()) 389 xRes = RebuildHyphensAndControlChars( rWord, xRes ); 390 391 if (xRes.is() && xRes->getWord() != rWord) 392 { 393 xRes = new HyphenatedWord( rWord, nLanguage, xRes->getHyphenationPos(), 394 xRes->getHyphenatedWord(), 395 xRes->getHyphenPos() ); 396 } 397 398 return xRes; 399 } 400 401 402 Reference< XHyphenatedWord > SAL_CALL 403 HyphenatorDispatcher::queryAlternativeSpelling( 404 const OUString& rWord, const Locale& rLocale, sal_Int16 nIndex, 405 const PropertyValues& rProperties ) 406 throw(IllegalArgumentException, RuntimeException) 407 { 408 MutexGuard aGuard( GetLinguMutex() ); 409 410 Reference< XHyphenatedWord > xRes; 411 412 sal_Int32 nWordLen = rWord.getLength(); 413 sal_Int16 nLanguage = LocaleToLanguage( rLocale ); 414 if (nLanguage == LANGUAGE_NONE || !nWordLen) 415 return xRes; 416 417 // search for entry with that language 418 HyphSvcByLangMap_t::iterator aIt( aSvcMap.find( nLanguage ) ); 419 LangSvcEntries_Hyph *pEntry = aIt != aSvcMap.end() ? aIt->second.get() : NULL; 420 421 sal_Bool bWordModified = sal_False; 422 if (!pEntry || !(0 <= nIndex && nIndex <= nWordLen - 2)) 423 { 424 #ifdef LINGU_EXCEPTIONS 425 throw IllegalArgumentException(); 426 #else 427 return NULL; 428 #endif 429 } 430 else 431 { 432 OUString aChkWord( rWord ); 433 434 // replace typographical apostroph by ascii apostroph 435 String aSingleQuote( GetLocaleDataWrapper( nLanguage ).getQuotationMarkEnd() ); 436 DBG_ASSERT( 1 == aSingleQuote.Len(), "unexpectend length of quotation mark" ); 437 if (aSingleQuote.Len()) 438 aChkWord = aChkWord.replace( aSingleQuote.GetChar(0), '\'' ); 439 440 bWordModified |= RemoveHyphens( aChkWord ); 441 if (IsIgnoreControlChars( rProperties, GetPropSet() )) 442 bWordModified |= RemoveControlChars( aChkWord ); 443 sal_Int16 nChkIndex = (sal_Int16) GetPosInWordToCheck( rWord, nIndex ); 444 445 // check for results from (positive) dictionaries which have precedence! 446 Reference< XDictionaryEntry > xEntry; 447 448 if (GetDicList().is() && IsUseDicList( rProperties, GetPropSet() )) 449 { 450 xEntry = GetDicList()->queryDictionaryEntry( aChkWord, rLocale, 451 sal_True, sal_False ); 452 } 453 454 if (xEntry.is()) 455 { 456 //! alternative spellings not yet supported by dictionaries 457 } 458 else 459 { 460 sal_Int32 nLen = pEntry->aSvcImplNames.getLength() > 0 ? 1 : 0; 461 DBG_ASSERT( pEntry->nLastTriedSvcIndex < nLen, 462 "lng : index out of range"); 463 464 sal_Int32 i = 0; 465 Reference< XHyphenator > xHyph; 466 if (pEntry->aSvcRefs.getLength() > 0) 467 xHyph = pEntry->aSvcRefs[0]; 468 469 // try already instantiated service 470 if (i <= pEntry->nLastTriedSvcIndex) 471 { 472 if (xHyph.is() && xHyph->hasLocale( rLocale )) 473 xRes = xHyph->queryAlternativeSpelling( aChkWord, rLocale, 474 nChkIndex, rProperties ); 475 ++i; 476 } 477 else if (pEntry->nLastTriedSvcIndex < nLen - 1) 478 // instantiate services and try it 479 { 480 // const OUString *pImplNames = pEntry->aSvcImplNames.getConstArray(); 481 Reference< XHyphenator > *pRef = pEntry->aSvcRefs.getArray(); 482 483 Reference< XMultiServiceFactory > xMgr( getProcessServiceFactory() ); 484 if (xMgr.is()) 485 { 486 // build service initialization argument 487 Sequence< Any > aArgs(2); 488 aArgs.getArray()[0] <<= GetPropSet(); 489 //! The dispatcher searches the dictionary-list 490 //! thus the service needs not to now about it 491 //aArgs.getArray()[1] <<= GetDicList(); 492 493 // create specific service via it's implementation name 494 try 495 { 496 xHyph = Reference< XHyphenator >( 497 xMgr->createInstanceWithArguments( 498 pEntry->aSvcImplNames[0], aArgs ), UNO_QUERY ); 499 } 500 catch (uno::Exception &) 501 { 502 DBG_ASSERT( 0, "createInstanceWithArguments failed" ); 503 } 504 pRef [i] = xHyph; 505 506 Reference< XLinguServiceEventBroadcaster > 507 xBroadcaster( xHyph, UNO_QUERY ); 508 if (xBroadcaster.is()) 509 rMgr.AddLngSvcEvtBroadcaster( xBroadcaster ); 510 511 if (xHyph.is() && xHyph->hasLocale( rLocale )) 512 xRes = xHyph->queryAlternativeSpelling( aChkWord, rLocale, 513 nChkIndex, rProperties ); 514 515 pEntry->nLastTriedSvcIndex = (sal_Int16) i; 516 ++i; 517 518 // if language is not supported by the services 519 // remove it from the list. 520 if (xHyph.is() && !xHyph->hasLocale( rLocale )) 521 aSvcMap.erase( nLanguage ); 522 } 523 } 524 } // if (xEntry.is()) 525 } 526 527 if (bWordModified && xRes.is()) 528 xRes = RebuildHyphensAndControlChars( rWord, xRes ); 529 530 if (xRes.is() && xRes->getWord() != rWord) 531 { 532 xRes = new HyphenatedWord( rWord, nLanguage, xRes->getHyphenationPos(), 533 xRes->getHyphenatedWord(), 534 xRes->getHyphenPos() ); 535 } 536 537 return xRes; 538 } 539 540 541 Reference< XPossibleHyphens > SAL_CALL 542 HyphenatorDispatcher::createPossibleHyphens( 543 const OUString& rWord, const Locale& rLocale, 544 const PropertyValues& rProperties ) 545 throw(IllegalArgumentException, RuntimeException) 546 { 547 MutexGuard aGuard( GetLinguMutex() ); 548 549 Reference< XPossibleHyphens > xRes; 550 551 sal_Int16 nLanguage = LocaleToLanguage( rLocale ); 552 if (nLanguage == LANGUAGE_NONE || !rWord.getLength()) 553 return xRes; 554 555 // search for entry with that language 556 HyphSvcByLangMap_t::iterator aIt( aSvcMap.find( nLanguage ) ); 557 LangSvcEntries_Hyph *pEntry = aIt != aSvcMap.end() ? aIt->second.get() : NULL; 558 559 if (!pEntry) 560 { 561 #ifdef LINGU_EXCEPTIONS 562 throw IllegalArgumentException(); 563 #endif 564 } 565 else 566 { 567 OUString aChkWord( rWord ); 568 569 // replace typographical apostroph by ascii apostroph 570 String aSingleQuote( GetLocaleDataWrapper( nLanguage ).getQuotationMarkEnd() ); 571 DBG_ASSERT( 1 == aSingleQuote.Len(), "unexpectend length of quotation mark" ); 572 if (aSingleQuote.Len()) 573 aChkWord = aChkWord.replace( aSingleQuote.GetChar(0), '\'' ); 574 575 RemoveHyphens( aChkWord ); 576 if (IsIgnoreControlChars( rProperties, GetPropSet() )) 577 RemoveControlChars( aChkWord ); 578 579 // check for results from (positive) dictionaries which have precedence! 580 Reference< XDictionaryEntry > xEntry; 581 582 if (GetDicList().is() && IsUseDicList( rProperties, GetPropSet() )) 583 { 584 xEntry = GetDicList()->queryDictionaryEntry( aChkWord, rLocale, 585 sal_True, sal_False ); 586 } 587 588 if (xEntry.is()) 589 { 590 xRes = buildPossHyphens( xEntry, nLanguage ); 591 } 592 else 593 { 594 sal_Int32 nLen = pEntry->aSvcImplNames.getLength() > 0 ? 1 : 0; 595 DBG_ASSERT( pEntry->nLastTriedSvcIndex < nLen, 596 "lng : index out of range"); 597 598 sal_Int32 i = 0; 599 Reference< XHyphenator > xHyph; 600 if (pEntry->aSvcRefs.getLength() > 0) 601 xHyph = pEntry->aSvcRefs[0]; 602 603 // try already instantiated service 604 if (i <= pEntry->nLastTriedSvcIndex) 605 { 606 if (xHyph.is() && xHyph->hasLocale( rLocale )) 607 xRes = xHyph->createPossibleHyphens( aChkWord, rLocale, 608 rProperties ); 609 ++i; 610 } 611 else if (pEntry->nLastTriedSvcIndex < nLen - 1) 612 // instantiate services and try it 613 { 614 // const OUString *pImplNames = pEntry->aSvcImplNames.getConstArray(); 615 Reference< XHyphenator > *pRef = pEntry->aSvcRefs.getArray(); 616 617 Reference< XMultiServiceFactory > xMgr( getProcessServiceFactory() ); 618 if (xMgr.is()) 619 { 620 // build service initialization argument 621 Sequence< Any > aArgs(2); 622 aArgs.getArray()[0] <<= GetPropSet(); 623 //! The dispatcher searches the dictionary-list 624 //! thus the service needs not to now about it 625 //aArgs.getArray()[1] <<= GetDicList(); 626 627 // create specific service via it's implementation name 628 try 629 { 630 xHyph = Reference< XHyphenator >( 631 xMgr->createInstanceWithArguments( 632 pEntry->aSvcImplNames[0], aArgs ), UNO_QUERY ); 633 } 634 catch (uno::Exception &) 635 { 636 DBG_ASSERT( 0, "createWithArguments failed" ); 637 } 638 pRef [i] = xHyph; 639 640 Reference< XLinguServiceEventBroadcaster > 641 xBroadcaster( xHyph, UNO_QUERY ); 642 if (xBroadcaster.is()) 643 rMgr.AddLngSvcEvtBroadcaster( xBroadcaster ); 644 645 if (xHyph.is() && xHyph->hasLocale( rLocale )) 646 xRes = xHyph->createPossibleHyphens( aChkWord, rLocale, 647 rProperties ); 648 649 pEntry->nLastTriedSvcIndex = (sal_Int16) i; 650 ++i; 651 652 // if language is not supported by the services 653 // remove it from the list. 654 if (xHyph.is() && !xHyph->hasLocale( rLocale )) 655 aSvcMap.erase( nLanguage ); 656 } 657 } 658 } // if (xEntry.is()) 659 } 660 661 if (xRes.is() && xRes->getWord() != rWord) 662 { 663 xRes = new PossibleHyphens( rWord, nLanguage, 664 xRes->getPossibleHyphens(), 665 xRes->getHyphenationPositions() ); 666 } 667 668 return xRes; 669 } 670 671 672 void HyphenatorDispatcher::SetServiceList( const Locale &rLocale, 673 const Sequence< OUString > &rSvcImplNames ) 674 { 675 MutexGuard aGuard( GetLinguMutex() ); 676 677 sal_Int16 nLanguage = LocaleToLanguage( rLocale ); 678 679 sal_Int32 nLen = rSvcImplNames.getLength(); 680 if (0 == nLen) 681 // remove entry 682 aSvcMap.erase( nLanguage ); 683 else 684 { 685 // modify/add entry 686 LangSvcEntries_Hyph *pEntry = aSvcMap[ nLanguage ].get(); 687 // only one hypenator can be in use for a language... 688 //const OUString &rSvcImplName = rSvcImplNames.getConstArray()[0]; 689 if (pEntry) 690 { 691 pEntry->Clear(); 692 pEntry->aSvcImplNames = rSvcImplNames; 693 pEntry->aSvcImplNames.realloc(1); 694 pEntry->aSvcRefs = Sequence< Reference < XHyphenator > > ( 1 ); 695 } 696 else 697 { 698 boost::shared_ptr< LangSvcEntries_Hyph > pTmpEntry( new LangSvcEntries_Hyph( rSvcImplNames[0] ) ); 699 pTmpEntry->aSvcRefs = Sequence< Reference < XHyphenator > >( 1 ); 700 aSvcMap[ nLanguage ] = pTmpEntry; 701 } 702 } 703 } 704 705 706 Sequence< OUString > 707 HyphenatorDispatcher::GetServiceList( const Locale &rLocale ) const 708 { 709 MutexGuard aGuard( GetLinguMutex() ); 710 711 Sequence< OUString > aRes; 712 713 // search for entry with that language and use data from that 714 sal_Int16 nLanguage = LocaleToLanguage( rLocale ); 715 HyphenatorDispatcher *pThis = (HyphenatorDispatcher *) this; 716 const HyphSvcByLangMap_t::iterator aIt( pThis->aSvcMap.find( nLanguage ) ); 717 const LangSvcEntries_Hyph *pEntry = aIt != aSvcMap.end() ? aIt->second.get() : NULL; 718 if (pEntry) 719 { 720 aRes = pEntry->aSvcImplNames; 721 if (aRes.getLength() > 0) 722 aRes.realloc(1); 723 } 724 725 return aRes; 726 } 727 728 729 LinguDispatcher::DspType HyphenatorDispatcher::GetDspType() const 730 { 731 return DSP_HYPH; 732 } 733 734 735 /////////////////////////////////////////////////////////////////////////// 736 737