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