1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 2 /* 3 * This file is part of the LibreOffice project. 4 * 5 * This Source Code Form is subject to the terms of the Mozilla Public 6 * License, v. 2.0. If a copy of the MPL was not distributed with this 7 * file, You can obtain one at http://mozilla.org/MPL/2.0/. 8 * 9 * This file incorporates work covered by the following license notice: 10 * 11 * Licensed to the Apache Software Foundation (ASF) under one or more 12 * contributor license agreements. See the NOTICE file distributed 13 * with this work for additional information regarding copyright 14 * ownership. The ASF licenses this file to you under the Apache 15 * License, Version 2.0 (the "License"); you may not use this file 16 * except in compliance with the License. You may obtain a copy of 17 * the License at http://www.apache.org/licenses/LICENSE-2.0 . 18 */ 19 20 21 #include <memory> 22 #include <editeng/unolingu.hxx> 23 #include <com/sun/star/frame/Desktop.hpp> 24 #include <com/sun/star/frame/XStorable.hpp> 25 #include <com/sun/star/lang/XEventListener.hpp> 26 #include <com/sun/star/linguistic2/XHyphenatedWord.hpp> 27 #include <com/sun/star/linguistic2/DictionaryList.hpp> 28 #include <com/sun/star/linguistic2/LinguServiceManager.hpp> 29 #include <com/sun/star/linguistic2/LinguProperties.hpp> 30 #include <com/sun/star/linguistic2/XSpellChecker1.hpp> 31 32 #include <comphelper/processfactory.hxx> 33 #include <cppuhelper/implbase.hxx> 34 #include <i18nlangtag/languagetag.hxx> 35 #include <unotools/lingucfg.hxx> 36 #include <utility> 37 #include <vcl/svapp.hxx> 38 #include <vcl/weld.hxx> 39 #include <linguistic/misc.hxx> 40 #include <editeng/eerdll.hxx> 41 #include <editeng/editrids.hrc> 42 #include <svtools/strings.hrc> 43 #include <unotools/resmgr.hxx> 44 #include <sal/log.hxx> 45 #include <osl/diagnose.h> 46 47 using namespace ::comphelper; 48 using namespace ::linguistic; 49 using namespace ::com::sun::star; 50 using namespace ::com::sun::star::util; 51 using namespace ::com::sun::star::uno; 52 using namespace ::com::sun::star::lang; 53 using namespace ::com::sun::star::beans; 54 using namespace ::com::sun::star::frame; 55 using namespace ::com::sun::star::linguistic2; 56 57 static uno::Reference< XLinguServiceManager2 > GetLngSvcMgr_Impl() 58 { 59 uno::Reference< XComponentContext > xContext = comphelper::getProcessComponentContext(); 60 uno::Reference< XLinguServiceManager2 > xRes = LinguServiceManager::create(xContext); 61 return xRes; 62 } 63 64 namespace { 65 66 //! Dummy implementation in order to avoid loading of lingu DLL 67 //! when only the XSupportedLocales interface is used. 68 //! The dummy accesses the real implementation (and thus loading the DLL) 69 //! when "real" work needs to be done only. 70 class ThesDummy_Impl : 71 public cppu::WeakImplHelper< XThesaurus > 72 { 73 uno::Reference< XThesaurus > xThes; // the real one... 74 std::unique_ptr<Sequence< lang::Locale >> pLocaleSeq; 75 76 void GetCfgLocales(); 77 78 void GetThes_Impl(); 79 80 public: 81 ThesDummy_Impl() {} 82 83 // XSupportedLocales 84 virtual css::uno::Sequence< css::lang::Locale > SAL_CALL 85 getLocales() override; 86 virtual sal_Bool SAL_CALL 87 hasLocale( const css::lang::Locale& rLocale ) override; 88 89 // XThesaurus 90 virtual css::uno::Sequence< 91 css::uno::Reference< css::linguistic2::XMeaning > > SAL_CALL 92 queryMeanings( const OUString& rTerm, 93 const css::lang::Locale& rLocale, 94 const css::uno::Sequence< css::beans::PropertyValue >& rProperties ) override; 95 }; 96 97 } 98 99 void ThesDummy_Impl::GetCfgLocales() 100 { 101 if (pLocaleSeq) 102 return; 103 104 SvtLinguConfig aCfg; 105 Sequence < OUString > aNodeNames( aCfg.GetNodeNames( "ServiceManager/ThesaurusList" ) ); 106 const OUString *pNodeNames = aNodeNames.getConstArray(); 107 sal_Int32 nLen = aNodeNames.getLength(); 108 pLocaleSeq.reset( new Sequence< lang::Locale >( nLen ) ); 109 lang::Locale *pLocale = pLocaleSeq->getArray(); 110 for (sal_Int32 i = 0; i < nLen; ++i) 111 { 112 pLocale[i] = LanguageTag::convertToLocaleWithFallback( pNodeNames[i] ); 113 } 114 } 115 116 117 void ThesDummy_Impl::GetThes_Impl() 118 { 119 if (!xThes.is()) 120 { 121 uno::Reference< XLinguServiceManager2 > xLngSvcMgr( GetLngSvcMgr_Impl() ); 122 xThes = xLngSvcMgr->getThesaurus(); 123 124 if (xThes.is()) 125 { 126 // no longer needed... 127 pLocaleSeq.reset(); 128 } 129 } 130 } 131 132 133 uno::Sequence< lang::Locale > SAL_CALL 134 ThesDummy_Impl::getLocales() 135 { 136 GetThes_Impl(); 137 if (xThes.is()) 138 return xThes->getLocales(); 139 else if (!pLocaleSeq) // if not already loaded save startup time by avoiding loading them now 140 GetCfgLocales(); 141 return *pLocaleSeq; 142 } 143 144 145 sal_Bool SAL_CALL 146 ThesDummy_Impl::hasLocale( const lang::Locale& rLocale ) 147 { 148 GetThes_Impl(); 149 if (xThes.is()) 150 return xThes->hasLocale( rLocale ); 151 else if (!pLocaleSeq) // if not already loaded save startup time by avoiding loading them now 152 GetCfgLocales(); 153 bool bFound = false; 154 sal_Int32 nLen = pLocaleSeq->getLength(); 155 const lang::Locale *pLocale = pLocaleSeq->getConstArray(); 156 const lang::Locale *pEnd = pLocale + nLen; 157 for ( ; pLocale < pEnd && !bFound; ++pLocale) 158 { 159 bFound = pLocale->Language == rLocale.Language && 160 pLocale->Country == rLocale.Country && 161 pLocale->Variant == rLocale.Variant; 162 } 163 return bFound; 164 } 165 166 167 uno::Sequence< uno::Reference< linguistic2::XMeaning > > SAL_CALL 168 ThesDummy_Impl::queryMeanings( 169 const OUString& rTerm, 170 const lang::Locale& rLocale, 171 const css::uno::Sequence< css::beans::PropertyValue >& rProperties ) 172 { 173 GetThes_Impl(); 174 uno::Sequence< uno::Reference< linguistic2::XMeaning > > aRes; 175 OSL_ENSURE( xThes.is(), "Thesaurus missing" ); 176 if (xThes.is()) 177 aRes = xThes->queryMeanings( rTerm, rLocale, rProperties ); 178 return aRes; 179 } 180 181 namespace { 182 183 //! Dummy implementation in order to avoid loading of lingu DLL. 184 //! The dummy accesses the real implementation (and thus loading the DLL) 185 //! when it needs to be done only. 186 class SpellDummy_Impl : 187 public cppu::WeakImplHelper< XSpellChecker1 > 188 { 189 uno::Reference< XSpellChecker1 > xSpell; // the real one... 190 191 void GetSpell_Impl(); 192 193 public: 194 195 // XSupportedLanguages (for XSpellChecker1) 196 virtual css::uno::Sequence< sal_Int16 > SAL_CALL 197 getLanguages() override; 198 virtual sal_Bool SAL_CALL 199 hasLanguage( sal_Int16 nLanguage ) override; 200 201 // XSpellChecker1 (same as XSpellChecker but sal_Int16 for language) 202 virtual sal_Bool SAL_CALL 203 isValid( const OUString& rWord, sal_Int16 nLanguage, 204 const css::uno::Sequence< css::beans::PropertyValue >& rProperties ) override; 205 virtual css::uno::Reference< css::linguistic2::XSpellAlternatives > SAL_CALL 206 spell( const OUString& rWord, sal_Int16 nLanguage, 207 const css::uno::Sequence< css::beans::PropertyValue >& rProperties ) override; 208 }; 209 210 } 211 212 void SpellDummy_Impl::GetSpell_Impl() 213 { 214 if (!xSpell.is()) 215 { 216 uno::Reference< XLinguServiceManager2 > xLngSvcMgr( GetLngSvcMgr_Impl() ); 217 xSpell.set( xLngSvcMgr->getSpellChecker(), UNO_QUERY ); 218 } 219 } 220 221 222 uno::Sequence< sal_Int16 > SAL_CALL 223 SpellDummy_Impl::getLanguages() 224 { 225 GetSpell_Impl(); 226 if (xSpell.is()) 227 return xSpell->getLanguages(); 228 else 229 return uno::Sequence< sal_Int16 >(); 230 } 231 232 233 sal_Bool SAL_CALL 234 SpellDummy_Impl::hasLanguage( sal_Int16 nLanguage ) 235 { 236 GetSpell_Impl(); 237 bool bRes = false; 238 if (xSpell.is()) 239 bRes = xSpell->hasLanguage( nLanguage ); 240 return bRes; 241 } 242 243 244 sal_Bool SAL_CALL 245 SpellDummy_Impl::isValid( const OUString& rWord, sal_Int16 nLanguage, 246 const css::uno::Sequence< css::beans::PropertyValue >& rProperties ) 247 { 248 GetSpell_Impl(); 249 bool bRes = true; 250 if (xSpell.is()) 251 bRes = xSpell->isValid( rWord, nLanguage, rProperties ); 252 return bRes; 253 } 254 255 256 uno::Reference< linguistic2::XSpellAlternatives > SAL_CALL 257 SpellDummy_Impl::spell( const OUString& rWord, sal_Int16 nLanguage, 258 const css::uno::Sequence< css::beans::PropertyValue >& rProperties ) 259 { 260 GetSpell_Impl(); 261 uno::Reference< linguistic2::XSpellAlternatives > xRes; 262 if (xSpell.is()) 263 xRes = xSpell->spell( rWord, nLanguage, rProperties ); 264 return xRes; 265 } 266 267 namespace { 268 269 //! Dummy implementation in order to avoid loading of lingu DLL. 270 //! The dummy accesses the real implementation (and thus loading the DLL) 271 //! when it needs to be done only. 272 class HyphDummy_Impl : 273 public cppu::WeakImplHelper< XHyphenator > 274 { 275 uno::Reference< XHyphenator > xHyph; // the real one... 276 277 void GetHyph_Impl(); 278 279 public: 280 281 // XSupportedLocales 282 virtual css::uno::Sequence< 283 css::lang::Locale > SAL_CALL 284 getLocales() override; 285 virtual sal_Bool SAL_CALL 286 hasLocale( const css::lang::Locale& rLocale ) override; 287 288 // XHyphenator 289 virtual css::uno::Reference< 290 css::linguistic2::XHyphenatedWord > SAL_CALL 291 hyphenate( const OUString& rWord, 292 const css::lang::Locale& rLocale, 293 sal_Int16 nMaxLeading, 294 const css::uno::Sequence< css::beans::PropertyValue >& rProperties ) override; 295 virtual css::uno::Reference< 296 css::linguistic2::XHyphenatedWord > SAL_CALL 297 queryAlternativeSpelling( const OUString& rWord, 298 const css::lang::Locale& rLocale, 299 sal_Int16 nIndex, 300 const css::uno::Sequence< css::beans::PropertyValue >& rProperties ) override; 301 virtual css::uno::Reference< 302 css::linguistic2::XPossibleHyphens > SAL_CALL 303 createPossibleHyphens( 304 const OUString& rWord, 305 const css::lang::Locale& rLocale, 306 const css::uno::Sequence< css::beans::PropertyValue >& rProperties ) override; 307 }; 308 309 } 310 311 void HyphDummy_Impl::GetHyph_Impl() 312 { 313 if (!xHyph.is()) 314 { 315 uno::Reference< XLinguServiceManager2 > xLngSvcMgr( GetLngSvcMgr_Impl() ); 316 xHyph = xLngSvcMgr->getHyphenator(); 317 } 318 } 319 320 321 uno::Sequence< lang::Locale > SAL_CALL 322 HyphDummy_Impl::getLocales() 323 { 324 GetHyph_Impl(); 325 if (xHyph.is()) 326 return xHyph->getLocales(); 327 else 328 return uno::Sequence< lang::Locale >(); 329 } 330 331 332 sal_Bool SAL_CALL 333 HyphDummy_Impl::hasLocale( const lang::Locale& rLocale ) 334 { 335 GetHyph_Impl(); 336 bool bRes = false; 337 if (xHyph.is()) 338 bRes = xHyph->hasLocale( rLocale ); 339 return bRes; 340 } 341 342 343 uno::Reference< linguistic2::XHyphenatedWord > SAL_CALL 344 HyphDummy_Impl::hyphenate( 345 const OUString& rWord, 346 const lang::Locale& rLocale, 347 sal_Int16 nMaxLeading, 348 const css::uno::Sequence< css::beans::PropertyValue >& rProperties ) 349 { 350 GetHyph_Impl(); 351 uno::Reference< linguistic2::XHyphenatedWord > xRes; 352 if (xHyph.is()) 353 xRes = xHyph->hyphenate( rWord, rLocale, nMaxLeading, rProperties ); 354 return xRes; 355 } 356 357 358 uno::Reference< linguistic2::XHyphenatedWord > SAL_CALL 359 HyphDummy_Impl::queryAlternativeSpelling( 360 const OUString& rWord, 361 const lang::Locale& rLocale, 362 sal_Int16 nIndex, 363 const css::uno::Sequence< css::beans::PropertyValue >& rProperties ) 364 { 365 GetHyph_Impl(); 366 uno::Reference< linguistic2::XHyphenatedWord > xRes; 367 if (xHyph.is()) 368 xRes = xHyph->queryAlternativeSpelling( rWord, rLocale, nIndex, rProperties ); 369 return xRes; 370 } 371 372 373 uno::Reference< linguistic2::XPossibleHyphens > SAL_CALL 374 HyphDummy_Impl::createPossibleHyphens( 375 const OUString& rWord, 376 const lang::Locale& rLocale, 377 const css::uno::Sequence< css::beans::PropertyValue >& rProperties ) 378 { 379 GetHyph_Impl(); 380 uno::Reference< linguistic2::XPossibleHyphens > xRes; 381 if (xHyph.is()) 382 xRes = xHyph->createPossibleHyphens( rWord, rLocale, rProperties ); 383 return xRes; 384 } 385 386 class LinguMgrExitLstnr : public cppu::WeakImplHelper<XEventListener> 387 { 388 uno::Reference< XDesktop2 > xDesktop; 389 390 static void AtExit(); 391 392 public: 393 LinguMgrExitLstnr(); 394 virtual ~LinguMgrExitLstnr() override; 395 396 // lang::XEventListener 397 virtual void SAL_CALL disposing(const EventObject& rSource) override; 398 }; 399 400 LinguMgrExitLstnr::LinguMgrExitLstnr() 401 { 402 // add object to frame::Desktop EventListeners in order to properly call 403 // the AtExit function at application exit. 404 405 uno::Reference< XComponentContext > xContext = getProcessComponentContext(); 406 xDesktop = Desktop::create( xContext ); 407 xDesktop->addEventListener( this ); 408 } 409 410 LinguMgrExitLstnr::~LinguMgrExitLstnr() 411 { 412 if (xDesktop.is()) 413 { 414 xDesktop->removeEventListener( this ); 415 xDesktop = nullptr; //! release reference to desktop 416 } 417 OSL_ENSURE(!xDesktop.is(), "reference to desktop should be released"); 418 } 419 420 void LinguMgrExitLstnr::disposing(const EventObject& rSource) 421 { 422 if (xDesktop.is() && rSource.Source == xDesktop) 423 { 424 xDesktop->removeEventListener( this ); 425 xDesktop = nullptr; //! release reference to desktop 426 427 AtExit(); 428 } 429 } 430 431 void LinguMgrExitLstnr::AtExit() 432 { 433 SolarMutexGuard g; 434 435 // release references 436 LinguMgr::xLngSvcMgr = nullptr; 437 LinguMgr::xSpell = nullptr; 438 LinguMgr::xHyph = nullptr; 439 LinguMgr::xThes = nullptr; 440 LinguMgr::xDicList = nullptr; 441 LinguMgr::xProp = nullptr; 442 LinguMgr::xIgnoreAll = nullptr; 443 LinguMgr::xChangeAll = nullptr; 444 445 LinguMgr::bExiting = true; 446 447 LinguMgr::pExitLstnr = nullptr; 448 } 449 450 451 rtl::Reference<LinguMgrExitLstnr> LinguMgr::pExitLstnr; 452 bool LinguMgr::bExiting = false; 453 uno::Reference< XLinguServiceManager2 > LinguMgr::xLngSvcMgr; 454 uno::Reference< XSpellChecker1 > LinguMgr::xSpell; 455 uno::Reference< XHyphenator > LinguMgr::xHyph; 456 uno::Reference< XThesaurus > LinguMgr::xThes; 457 uno::Reference< XSearchableDictionaryList > LinguMgr::xDicList; 458 uno::Reference< XLinguProperties > LinguMgr::xProp; 459 uno::Reference< XDictionary > LinguMgr::xIgnoreAll; 460 uno::Reference< XDictionary > LinguMgr::xChangeAll; 461 462 463 uno::Reference< XLinguServiceManager2 > LinguMgr::GetLngSvcMgr() 464 { 465 if (bExiting) 466 return nullptr; 467 468 if (!pExitLstnr) 469 pExitLstnr = new LinguMgrExitLstnr; 470 471 if (!xLngSvcMgr.is()) 472 xLngSvcMgr = GetLngSvcMgr_Impl(); 473 474 return xLngSvcMgr; 475 } 476 477 478 uno::Reference< XSpellChecker1 > LinguMgr::GetSpellChecker() 479 { 480 return xSpell.is() ? xSpell : GetSpell(); 481 } 482 483 uno::Reference< XHyphenator > LinguMgr::GetHyphenator() 484 { 485 return xHyph.is() ? xHyph : GetHyph(); 486 } 487 488 uno::Reference< XThesaurus > LinguMgr::GetThesaurus() 489 { 490 return xThes.is() ? xThes : GetThes(); 491 } 492 493 uno::Reference< XSearchableDictionaryList > LinguMgr::GetDictionaryList() 494 { 495 return xDicList.is() ? xDicList : GetDicList(); 496 } 497 498 uno::Reference< linguistic2::XLinguProperties > LinguMgr::GetLinguPropertySet() 499 { 500 return xProp.is() ? xProp : GetProp(); 501 } 502 503 uno::Reference< XDictionary > LinguMgr::GetStandardDic() 504 { 505 //! don't hold reference to this 506 //! (it may be removed from dictionary list and needs to be 507 //! created empty if accessed again) 508 return GetStandard(); 509 } 510 511 uno::Reference< XDictionary > LinguMgr::GetIgnoreAllList() 512 { 513 return xIgnoreAll.is() ? xIgnoreAll : GetIgnoreAll(); 514 } 515 516 uno::Reference< XDictionary > LinguMgr::GetChangeAllList() 517 { 518 return xChangeAll.is() ? xChangeAll : GetChangeAll(); 519 } 520 521 uno::Reference< XSpellChecker1 > LinguMgr::GetSpell() 522 { 523 if (bExiting) 524 return nullptr; 525 526 if (!pExitLstnr) 527 pExitLstnr = new LinguMgrExitLstnr; 528 529 //! use dummy implementation in order to avoid loading of lingu DLL 530 xSpell = new SpellDummy_Impl; 531 return xSpell; 532 } 533 534 uno::Reference< XHyphenator > LinguMgr::GetHyph() 535 { 536 if (bExiting) 537 return nullptr; 538 539 if (!pExitLstnr) 540 pExitLstnr = new LinguMgrExitLstnr; 541 542 //! use dummy implementation in order to avoid loading of lingu DLL 543 xHyph = new HyphDummy_Impl; 544 return xHyph; 545 } 546 547 uno::Reference< XThesaurus > LinguMgr::GetThes() 548 { 549 if (bExiting) 550 return nullptr; 551 552 if (!pExitLstnr) 553 pExitLstnr = new LinguMgrExitLstnr; 554 555 //! use dummy implementation in order to avoid loading of lingu DLL 556 //! when only the XSupportedLocales interface is used. 557 //! The dummy accesses the real implementation (and thus loading the DLL) 558 //! when "real" work needs to be done only. 559 xThes = new ThesDummy_Impl; 560 return xThes; 561 } 562 563 uno::Reference< XSearchableDictionaryList > LinguMgr::GetDicList() 564 { 565 if (bExiting) 566 return nullptr; 567 568 if (!pExitLstnr) 569 pExitLstnr = new LinguMgrExitLstnr; 570 571 xDicList = linguistic2::DictionaryList::create( getProcessComponentContext() ); 572 return xDicList; 573 } 574 575 uno::Reference< linguistic2::XLinguProperties > LinguMgr::GetProp() 576 { 577 if (bExiting) 578 return nullptr; 579 580 if (!pExitLstnr) 581 pExitLstnr = new LinguMgrExitLstnr; 582 583 xProp = linguistic2::LinguProperties::create( getProcessComponentContext() ); 584 return xProp; 585 } 586 587 uno::Reference< XDictionary > LinguMgr::GetIgnoreAll() 588 { 589 if (bExiting) 590 return nullptr; 591 592 if (!pExitLstnr) 593 pExitLstnr = new LinguMgrExitLstnr; 594 595 uno::Reference< XSearchableDictionaryList > xTmpDicList( GetDictionaryList() ); 596 if (xTmpDicList.is()) 597 { 598 std::locale loc(Translate::Create("svt")); 599 xIgnoreAll = xTmpDicList->getDictionaryByName( 600 Translate::get(STR_DESCRIPTION_IGNOREALLLIST, loc) ); 601 } 602 return xIgnoreAll; 603 } 604 605 uno::Reference< XDictionary > LinguMgr::GetChangeAll() 606 { 607 if (bExiting) 608 return nullptr; 609 610 if (!pExitLstnr) 611 pExitLstnr = new LinguMgrExitLstnr; 612 613 uno::Reference< XSearchableDictionaryList > _xDicList = GetDictionaryList(); 614 if (_xDicList.is()) 615 { 616 xChangeAll = _xDicList->createDictionary( 617 "ChangeAllList", 618 LanguageTag::convertToLocale( LANGUAGE_NONE ), 619 DictionaryType_NEGATIVE, OUString() ); 620 } 621 return xChangeAll; 622 } 623 624 uno::Reference< XDictionary > LinguMgr::GetStandard() 625 { 626 // Tries to return a dictionary which may hold positive entries is 627 // persistent and not read-only. 628 629 if (bExiting) 630 return nullptr; 631 632 uno::Reference< XSearchableDictionaryList > xTmpDicList( GetDictionaryList() ); 633 if (!xTmpDicList.is()) 634 return nullptr; 635 636 static const OUStringLiteral aDicName( u"standard.dic" ); 637 uno::Reference< XDictionary > xDic = xTmpDicList->getDictionaryByName( aDicName ); 638 if (!xDic.is()) 639 { 640 // try to create standard dictionary 641 uno::Reference< XDictionary > xTmp; 642 try 643 { 644 xTmp = xTmpDicList->createDictionary( aDicName, 645 LanguageTag::convertToLocale( LANGUAGE_NONE ), 646 DictionaryType_POSITIVE, 647 linguistic::GetWritableDictionaryURL( aDicName ) ); 648 } 649 catch(const css::uno::Exception &) 650 { 651 } 652 653 // add new dictionary to list 654 if (xTmp.is()) 655 { 656 xTmpDicList->addDictionary( xTmp ); 657 xTmp->setActive( true ); 658 } 659 xDic = xTmp; 660 } 661 #if OSL_DEBUG_LEVEL > 1 662 uno::Reference< XStorable > xStor( xDic, UNO_QUERY ); 663 OSL_ENSURE( xDic.is() && xDic->getDictionaryType() == DictionaryType_POSITIVE, 664 "wrong dictionary type"); 665 OSL_ENSURE( xDic.is() && LanguageTag( xDic->getLocale() ).getLanguageType() == LANGUAGE_NONE, 666 "wrong dictionary language"); 667 OSL_ENSURE( !xStor.is() || (xStor->hasLocation() && !xStor->isReadonly()), 668 "dictionary not editable" ); 669 #endif 670 671 return xDic; 672 } 673 674 SvxAlternativeSpelling SvxGetAltSpelling( 675 const css::uno::Reference< css::linguistic2::XHyphenatedWord > & rHyphWord ) 676 { 677 SvxAlternativeSpelling aRes; 678 if (rHyphWord.is() && rHyphWord->isAlternativeSpelling()) 679 { 680 OUString aWord( rHyphWord->getWord() ), 681 aAltWord( rHyphWord->getHyphenatedWord() ); 682 sal_Int16 nHyphenationPos = rHyphWord->getHyphenationPos(), 683 nHyphenPos = rHyphWord->getHyphenPos(); 684 sal_Int16 nLen = static_cast<sal_Int16>(aWord.getLength()); 685 sal_Int16 nAltLen = static_cast<sal_Int16>(aAltWord.getLength()); 686 const sal_Unicode *pWord = aWord.getStr(), 687 *pAltWord = aAltWord.getStr(); 688 689 // count number of chars from the left to the 690 // hyphenation pos / hyphen pos that are equal 691 sal_Int16 nL = 0; 692 while (nL <= nHyphenationPos && nL <= nHyphenPos 693 && pWord[ nL ] == pAltWord[ nL ]) 694 ++nL; 695 // count number of chars from the right to the 696 // hyphenation pos / hyphen pos that are equal 697 sal_Int16 nR = 0; 698 sal_Int32 nIdx = nLen - 1; 699 sal_Int32 nAltIdx = nAltLen - 1; 700 while (nIdx > nHyphenationPos && nAltIdx > nHyphenPos 701 && pWord[ nIdx-- ] == pAltWord[ nAltIdx-- ]) 702 ++nR; 703 704 aRes.aReplacement = aAltWord.copy( nL, nAltLen - nL - nR ); 705 aRes.nChangedPos = nL; 706 aRes.nChangedLength = nLen - nL - nR; 707 aRes.bIsAltSpelling = true; 708 } 709 return aRes; 710 } 711 712 713 SvxDicListChgClamp::SvxDicListChgClamp( uno::Reference< XSearchableDictionaryList > _xDicList ) : 714 xDicList (std::move( _xDicList )) 715 { 716 if (xDicList.is()) 717 { 718 xDicList->beginCollectEvents(); 719 } 720 } 721 722 SvxDicListChgClamp::~SvxDicListChgClamp() 723 { 724 if (xDicList.is()) 725 { 726 xDicList->endCollectEvents(); 727 } 728 } 729 730 short SvxDicError(weld::Window *pParent, linguistic::DictionaryError nError) 731 { 732 short nRes = 0; 733 if (linguistic::DictionaryError::NONE != nError) 734 { 735 TranslateId pRid; 736 switch (nError) 737 { 738 case linguistic::DictionaryError::FULL : pRid = RID_SVXSTR_DIC_ERR_FULL; break; 739 case linguistic::DictionaryError::READONLY : pRid = RID_SVXSTR_DIC_ERR_READONLY; break; 740 default: 741 pRid = RID_SVXSTR_DIC_ERR_UNKNOWN; 742 SAL_WARN("editeng", "unexpected case"); 743 } 744 std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(pParent, 745 VclMessageType::Info, VclButtonsType::Ok, 746 EditResId(pRid))); 747 nRes = xInfoBox->run(); 748 749 } 750 return nRes; 751 } 752 753 754 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ 755
