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_lingucomponent.hxx" 26 27 #include <com/sun/star/uno/Reference.h> 28 #include <com/sun/star/linguistic2/XSearchableDictionaryList.hpp> 29 30 #include <com/sun/star/linguistic2/SpellFailure.hpp> 31 #include <cppuhelper/factory.hxx> // helper for factories 32 #include <com/sun/star/registry/XRegistryKey.hpp> 33 #include <tools/debug.hxx> 34 #include <unotools/processfactory.hxx> 35 #include <osl/mutex.hxx> 36 #include <com/sun/star/ucb/XSimpleFileAccess.hpp> 37 38 #include <lingutil.hxx> 39 #include <hunspell.hxx> 40 #include <sspellimp.hxx> 41 42 #include <linguistic/lngprops.hxx> 43 #include <linguistic/spelldta.hxx> 44 #include <i18npool/mslangid.hxx> 45 #include <unotools/pathoptions.hxx> 46 #include <unotools/lingucfg.hxx> 47 #include <unotools/useroptions.hxx> 48 #include <osl/file.hxx> 49 #include <rtl/ustrbuf.hxx> 50 #include <rtl/textenc.h> 51 52 #include <list> 53 #include <set> 54 #include <string.h> 55 56 using namespace utl; 57 using namespace osl; 58 using namespace rtl; 59 using namespace com::sun::star; 60 using namespace com::sun::star::beans; 61 using namespace com::sun::star::lang; 62 using namespace com::sun::star::uno; 63 using namespace com::sun::star::linguistic2; 64 using namespace linguistic; 65 66 // XML-header of SPELLML queries 67 #define SPELLML_HEADER "<?xml?>" 68 69 /////////////////////////////////////////////////////////////////////////// 70 71 SpellChecker::SpellChecker() : 72 aEvtListeners ( GetLinguMutex() ) 73 { 74 aDicts = NULL; 75 aDEncs = NULL; 76 aDLocs = NULL; 77 aDNames = NULL; 78 bDisposing = sal_False; 79 pPropHelper = NULL; 80 numdict = 0; 81 } 82 83 84 SpellChecker::~SpellChecker() 85 { 86 if (aDicts) 87 { 88 for (int i = 0; i < numdict; i++) 89 { 90 if (aDicts[i]) delete aDicts[i]; 91 aDicts[i] = NULL; 92 } 93 delete[] aDicts; 94 } 95 aDicts = NULL; 96 numdict = 0; 97 if (aDEncs) delete[] aDEncs; 98 aDEncs = NULL; 99 if (aDLocs) delete[] aDLocs; 100 aDLocs = NULL; 101 if (aDNames) delete[] aDNames; 102 aDNames = NULL; 103 if (pPropHelper) 104 pPropHelper->RemoveAsPropListener(); 105 } 106 107 108 PropertyHelper_Spell & SpellChecker::GetPropHelper_Impl() 109 { 110 if (!pPropHelper) 111 { 112 Reference< XPropertySet > xPropSet( GetLinguProperties(), UNO_QUERY ); 113 114 pPropHelper = new PropertyHelper_Spell( (XSpellChecker *) this, xPropSet ); 115 xPropHelper = pPropHelper; 116 pPropHelper->AddAsPropListener(); //! after a reference is established 117 } 118 return *pPropHelper; 119 } 120 121 122 Sequence< Locale > SAL_CALL SpellChecker::getLocales() 123 throw(RuntimeException) 124 { 125 MutexGuard aGuard( GetLinguMutex() ); 126 127 // this routine should return the locales supported by the installed 128 // dictionaries. 129 130 if (!numdict) 131 { 132 SvtLinguConfig aLinguCfg; 133 134 // get list of extension dictionaries-to-use 135 // (or better speaking: the list of dictionaries using the 136 // new configuration entries). 137 std::list< SvtLinguConfigDictionaryEntry > aDics; 138 uno::Sequence< rtl::OUString > aFormatList; 139 aLinguCfg.GetSupportedDictionaryFormatsFor( A2OU("SpellCheckers"), 140 A2OU("org.openoffice.lingu.MySpellSpellChecker"), aFormatList ); 141 sal_Int32 nLen = aFormatList.getLength(); 142 for (sal_Int32 i = 0; i < nLen; ++i) 143 { 144 std::vector< SvtLinguConfigDictionaryEntry > aTmpDic( 145 aLinguCfg.GetActiveDictionariesByFormat( aFormatList[i] ) ); 146 aDics.insert( aDics.end(), aTmpDic.begin(), aTmpDic.end() ); 147 } 148 149 //!! for compatibility with old dictionaries (the ones not using extensions 150 //!! or new configuration entries, but still using the dictionary.lst file) 151 //!! Get the list of old style spell checking dictionaries to use... 152 std::vector< SvtLinguConfigDictionaryEntry > aOldStyleDics( 153 GetOldStyleDics( "DICT" ) ); 154 155 // to prefer dictionaries with configuration entries we will only 156 // use those old style dictionaries that add a language that 157 // is not yet supported by the list od new style dictionaries 158 MergeNewStyleDicsAndOldStyleDics( aDics, aOldStyleDics ); 159 160 numdict = aDics.size(); 161 if (numdict) 162 { 163 uno::Reference< lang::XMultiServiceFactory > xServiceFactory( utl::getProcessServiceFactory() ); 164 uno::Reference< ucb::XSimpleFileAccess > xAccess; 165 try 166 { 167 xAccess.set( xServiceFactory->createInstance( 168 A2OU( "com.sun.star.ucb.SimpleFileAccess" ) ), uno::UNO_QUERY_THROW ); 169 } 170 catch (uno::Exception & e) 171 { 172 DBG_ASSERT( 0, "failed to get input stream" ); 173 (void) e; 174 } 175 // get supported locales from the dictionaries-to-use... 176 sal_Int32 k = 0; 177 std::set< rtl::OUString, lt_rtl_OUString > aLocaleNamesSet; 178 std::list< SvtLinguConfigDictionaryEntry >::const_iterator aDictIt; 179 for (aDictIt = aDics.begin(); aDictIt != aDics.end(); ++aDictIt) 180 { 181 uno::Sequence< rtl::OUString > aLocaleNames( aDictIt->aLocaleNames ); 182 uno::Sequence< rtl::OUString > aLocations( aDictIt->aLocations ); 183 sal_Int32 nLen2 = aLocaleNames.getLength(); 184 for (k = 0; k < nLen2; ++k) 185 { 186 if (xAccess.is() && xAccess->exists(aLocations[k])) 187 { 188 aLocaleNamesSet.insert( aLocaleNames[k] ); 189 } 190 } 191 } 192 // ... and add them to the resulting sequence 193 aSuppLocales.realloc( aLocaleNamesSet.size() ); 194 std::set< rtl::OUString, lt_rtl_OUString >::const_iterator aItB; 195 k = 0; 196 for (aItB = aLocaleNamesSet.begin(); aItB != aLocaleNamesSet.end(); ++aItB) 197 { 198 Locale aTmp( MsLangId::convertLanguageToLocale( 199 MsLangId::convertIsoStringToLanguage( *aItB ))); 200 aSuppLocales[k++] = aTmp; 201 } 202 203 //! For each dictionary and each locale we need a seperate entry. 204 //! If this results in more than one dictionary per locale than (for now) 205 //! it is undefined which dictionary gets used. 206 //! In the future the implementation should support using several dictionaries 207 //! for one locale. 208 numdict = 0; 209 for (aDictIt = aDics.begin(); aDictIt != aDics.end(); ++aDictIt) 210 numdict = numdict + aDictIt->aLocaleNames.getLength(); 211 212 // add dictionary information 213 aDicts = new Hunspell* [numdict]; 214 aDEncs = new rtl_TextEncoding [numdict]; 215 aDLocs = new Locale [numdict]; 216 aDNames = new OUString [numdict]; 217 k = 0; 218 for (aDictIt = aDics.begin(); aDictIt != aDics.end(); ++aDictIt) 219 { 220 if (aDictIt->aLocaleNames.getLength() > 0 && 221 aDictIt->aLocations.getLength() > 0) 222 { 223 uno::Sequence< rtl::OUString > aLocaleNames( aDictIt->aLocaleNames ); 224 sal_Int32 nLocales = aLocaleNames.getLength(); 225 226 // currently only one language per dictionary is supported in the actual implementation... 227 // Thus here we work-around this by adding the same dictionary several times. 228 // Once for each of it's supported locales. 229 for (sal_Int32 i = 0; i < nLocales; ++i) 230 { 231 aDicts[k] = NULL; 232 aDEncs[k] = RTL_TEXTENCODING_DONTKNOW; 233 aDLocs[k] = MsLangId::convertLanguageToLocale( 234 MsLangId::convertIsoStringToLanguage( aLocaleNames[i] )); 235 // also both files have to be in the same directory and the 236 // file names must only differ in the extension (.aff/.dic). 237 // Thus we use the first location only and strip the extension part. 238 rtl::OUString aLocation = aDictIt->aLocations[0]; 239 sal_Int32 nPos = aLocation.lastIndexOf( '.' ); 240 aLocation = aLocation.copy( 0, nPos ); 241 aDNames[k] = aLocation; 242 243 ++k; 244 } 245 } 246 } 247 DBG_ASSERT( k == numdict, "index mismatch?" ); 248 } 249 else 250 { 251 /* no dictionary found so register no dictionaries */ 252 numdict = 0; 253 aDicts = NULL; 254 aDEncs = NULL; 255 aDLocs = NULL; 256 aDNames = NULL; 257 aSuppLocales.realloc(0); 258 } 259 } 260 261 return aSuppLocales; 262 } 263 264 265 sal_Bool SAL_CALL SpellChecker::hasLocale(const Locale& rLocale) 266 throw(RuntimeException) 267 { 268 MutexGuard aGuard( GetLinguMutex() ); 269 270 sal_Bool bRes = sal_False; 271 if (!aSuppLocales.getLength()) 272 getLocales(); 273 274 sal_Int32 nLen = aSuppLocales.getLength(); 275 for (sal_Int32 i = 0; i < nLen; ++i) 276 { 277 const Locale *pLocale = aSuppLocales.getConstArray(); 278 if (rLocale == pLocale[i]) 279 { 280 bRes = sal_True; 281 break; 282 } 283 } 284 return bRes; 285 } 286 287 288 sal_Int16 SpellChecker::GetSpellFailure( const OUString &rWord, const Locale &rLocale ) 289 { 290 Hunspell * pMS = NULL; 291 rtl_TextEncoding eEnc = RTL_TEXTENCODING_DONTKNOW; 292 293 // initialize a myspell object for each dictionary once 294 // (note: mutex is held higher up in isValid) 295 296 sal_Int16 nRes = -1; 297 298 // first handle smart quotes both single and double 299 OUStringBuffer rBuf(rWord); 300 sal_Int32 n = rBuf.getLength(); 301 sal_Unicode c; 302 for (sal_Int32 ix=0; ix < n; ix++) 303 { 304 c = rBuf.charAt(ix); 305 if ((c == 0x201C) || (c == 0x201D)) 306 rBuf.setCharAt(ix,(sal_Unicode)0x0022); 307 if ((c == 0x2018) || (c == 0x2019)) 308 rBuf.setCharAt(ix,(sal_Unicode)0x0027); 309 } 310 OUString nWord(rBuf.makeStringAndClear()); 311 312 if (n) 313 { 314 for (sal_Int32 i = 0; i < numdict; ++i) 315 { 316 pMS = NULL; 317 eEnc = RTL_TEXTENCODING_DONTKNOW; 318 319 if (rLocale == aDLocs[i]) 320 { 321 if (!aDicts[i]) 322 { 323 OUString dicpath = aDNames[i] + A2OU(".dic"); 324 OUString affpath = aDNames[i] + A2OU(".aff"); 325 OUString dict; 326 OUString aff; 327 osl::FileBase::getSystemPathFromFileURL(dicpath,dict); 328 osl::FileBase::getSystemPathFromFileURL(affpath,aff); 329 OString aTmpaff(OU2ENC(aff,osl_getThreadTextEncoding())); 330 OString aTmpdict(OU2ENC(dict,osl_getThreadTextEncoding())); 331 332 #if defined(WNT) 333 // workaround for Windows specifc problem that the 334 // path length in calls to 'fopen' is limted to somewhat 335 // about 120+ characters which will usually be exceed when 336 // using dictionaries as extensions. 337 aTmpaff = Win_GetShortPathName( aff ); 338 aTmpdict = Win_GetShortPathName( dict ); 339 #endif 340 341 aDicts[i] = new Hunspell(aTmpaff.getStr(),aTmpdict.getStr()); 342 aDEncs[i] = RTL_TEXTENCODING_DONTKNOW; 343 if (aDicts[i]) 344 aDEncs[i] = getTextEncodingFromCharset(aDicts[i]->get_dic_encoding()); 345 } 346 pMS = aDicts[i]; 347 eEnc = aDEncs[i]; 348 } 349 350 if (pMS) 351 { 352 // we don't want to work with a default text encoding since following incorrect 353 // results may occur only for specific text and thus may be hard to notice. 354 // Thus better always make a clean exit here if the text encoding is in question. 355 // Hopefully something not working at all will raise proper attention quickly. ;-) 356 DBG_ASSERT( eEnc != RTL_TEXTENCODING_DONTKNOW, "failed to get text encoding! (maybe incorrect encoding string in file)" ); 357 if (eEnc == RTL_TEXTENCODING_DONTKNOW) 358 return -1; 359 360 OString aWrd(OU2ENC(nWord,eEnc)); 361 int rVal = pMS->spell((char*)aWrd.getStr()); 362 if (rVal != 1) 363 nRes = SpellFailure::SPELLING_ERROR; 364 else 365 return -1; 366 pMS = NULL; 367 } 368 } 369 } 370 371 return nRes; 372 } 373 374 375 sal_Bool SAL_CALL SpellChecker::isValid( const OUString& rWord, const Locale& rLocale, 376 const PropertyValues& rProperties ) 377 throw(IllegalArgumentException, RuntimeException) 378 { 379 MutexGuard aGuard( GetLinguMutex() ); 380 381 if (rLocale == Locale() || !rWord.getLength()) 382 return sal_True; 383 384 if (!hasLocale( rLocale )) 385 #ifdef LINGU_EXCEPTIONS 386 throw( IllegalArgumentException() ); 387 #else 388 return sal_True; 389 #endif 390 391 // return sal_False to process SPELLML requests (they are longer than the header) 392 if (rWord.match(A2OU(SPELLML_HEADER), 0) && (rWord.getLength() > 10)) return sal_False; 393 394 // Get property values to be used. 395 // These are be the default values set in the SN_LINGU_PROPERTIES 396 // PropertySet which are overridden by the supplied ones from the 397 // last argument. 398 // You'll probably like to use a simplier solution than the provided 399 // one using the PropertyHelper_Spell. 400 401 PropertyHelper_Spell &rHelper = GetPropHelper(); 402 rHelper.SetTmpPropVals( rProperties ); 403 404 sal_Int16 nFailure = GetSpellFailure( rWord, rLocale ); 405 if (nFailure != -1 && !rWord.match(A2OU(SPELLML_HEADER), 0)) 406 { 407 sal_Int16 nLang = LocaleToLanguage( rLocale ); 408 // postprocess result for errors that should be ignored 409 const bool bIgnoreError = 410 (!rHelper.IsSpellUpperCase() && IsUpper( rWord, nLang )) || 411 (!rHelper.IsSpellWithDigits() && HasDigits( rWord )) || 412 (!rHelper.IsSpellCapitalization() && nFailure == SpellFailure::CAPTION_ERROR); 413 if (bIgnoreError) 414 nFailure = -1; 415 } 416 417 return (nFailure == -1); 418 } 419 420 421 Reference< XSpellAlternatives > 422 SpellChecker::GetProposals( const OUString &rWord, const Locale &rLocale ) 423 { 424 // Retrieves the return values for the 'spell' function call in case 425 // of a misspelled word. 426 // Especially it may give a list of suggested (correct) words: 427 428 Reference< XSpellAlternatives > xRes; 429 // note: mutex is held by higher up by spell which covers both 430 431 Hunspell* pMS = NULL; 432 rtl_TextEncoding eEnc = RTL_TEXTENCODING_DONTKNOW; 433 int count = 0; 434 int numsug = 0; 435 436 // first handle smart quotes (single and double) 437 OUStringBuffer rBuf(rWord); 438 sal_Int32 n = rBuf.getLength(); 439 sal_Unicode c; 440 for (sal_Int32 ix=0; ix < n; ix++) 441 { 442 c = rBuf.charAt(ix); 443 if ((c == 0x201C) || (c == 0x201D)) 444 rBuf.setCharAt(ix,(sal_Unicode)0x0022); 445 if ((c == 0x2018) || (c == 0x2019)) 446 rBuf.setCharAt(ix,(sal_Unicode)0x0027); 447 } 448 OUString nWord(rBuf.makeStringAndClear()); 449 450 if (n) 451 { 452 sal_Int16 nLang = LocaleToLanguage( rLocale ); 453 454 Sequence< OUString > aStr( 0 ); 455 456 for (int i =0; i < numdict; i++) 457 { 458 pMS = NULL; 459 eEnc = RTL_TEXTENCODING_DONTKNOW; 460 count = 0; 461 462 if (rLocale == aDLocs[i]) 463 { 464 pMS = aDicts[i]; 465 eEnc = aDEncs[i]; 466 } 467 468 if (pMS) 469 { 470 char ** suglst = NULL; 471 OString aWrd(OU2ENC(nWord,eEnc)); 472 count = pMS->suggest(&suglst, (const char *) aWrd.getStr()); 473 474 if (count) 475 { 476 aStr.realloc( numsug + count ); 477 OUString *pStr = aStr.getArray(); 478 for (int ii=0; ii < count; ++ii) 479 { 480 OUString cvtwrd(suglst[ii],strlen(suglst[ii]),eEnc); 481 pStr[numsug + ii] = cvtwrd; 482 } 483 pMS->free_list(&suglst, count); 484 numsug += count; 485 } 486 } 487 } 488 489 // now return an empty alternative for no suggestions or the list of alternatives if some found 490 SpellAlternatives *pAlt = new SpellAlternatives; 491 String aTmp(rWord); 492 pAlt->SetWordLanguage( aTmp, nLang ); 493 pAlt->SetFailureType( SpellFailure::SPELLING_ERROR ); 494 pAlt->SetAlternatives( aStr ); 495 xRes = pAlt; 496 return xRes; 497 } 498 return xRes; 499 } 500 501 502 Reference< XSpellAlternatives > SAL_CALL SpellChecker::spell( 503 const OUString& rWord, const Locale& rLocale, 504 const PropertyValues& rProperties ) 505 throw(IllegalArgumentException, RuntimeException) 506 { 507 MutexGuard aGuard( GetLinguMutex() ); 508 509 if (rLocale == Locale() || !rWord.getLength()) 510 return NULL; 511 512 if (!hasLocale( rLocale )) 513 #ifdef LINGU_EXCEPTIONS 514 throw( IllegalArgumentException() ); 515 #else 516 return NULL; 517 #endif 518 519 Reference< XSpellAlternatives > xAlt; 520 if (!isValid( rWord, rLocale, rProperties )) 521 { 522 xAlt = GetProposals( rWord, rLocale ); 523 } 524 return xAlt; 525 } 526 527 528 Reference< XInterface > SAL_CALL SpellChecker_CreateInstance( 529 const Reference< XMultiServiceFactory > & /*rSMgr*/ ) 530 throw(Exception) 531 { 532 533 Reference< XInterface > xService = (cppu::OWeakObject*) new SpellChecker; 534 return xService; 535 } 536 537 538 sal_Bool SAL_CALL SpellChecker::addLinguServiceEventListener( 539 const Reference< XLinguServiceEventListener >& rxLstnr ) 540 throw(RuntimeException) 541 { 542 MutexGuard aGuard( GetLinguMutex() ); 543 544 sal_Bool bRes = sal_False; 545 if (!bDisposing && rxLstnr.is()) 546 { 547 bRes = GetPropHelper().addLinguServiceEventListener( rxLstnr ); 548 } 549 return bRes; 550 } 551 552 553 sal_Bool SAL_CALL SpellChecker::removeLinguServiceEventListener( 554 const Reference< XLinguServiceEventListener >& rxLstnr ) 555 throw(RuntimeException) 556 { 557 MutexGuard aGuard( GetLinguMutex() ); 558 559 sal_Bool bRes = sal_False; 560 if (!bDisposing && rxLstnr.is()) 561 { 562 DBG_ASSERT( xPropHelper.is(), "xPropHelper non existent" ); 563 bRes = GetPropHelper().removeLinguServiceEventListener( rxLstnr ); 564 } 565 return bRes; 566 } 567 568 569 OUString SAL_CALL SpellChecker::getServiceDisplayName( const Locale& /*rLocale*/ ) 570 throw(RuntimeException) 571 { 572 MutexGuard aGuard( GetLinguMutex() ); 573 return A2OU( "Hunspell SpellChecker" ); 574 } 575 576 577 void SAL_CALL SpellChecker::initialize( const Sequence< Any >& rArguments ) 578 throw(Exception, RuntimeException) 579 { 580 MutexGuard aGuard( GetLinguMutex() ); 581 582 if (!pPropHelper) 583 { 584 sal_Int32 nLen = rArguments.getLength(); 585 if (2 == nLen) 586 { 587 Reference< XPropertySet > xPropSet; 588 rArguments.getConstArray()[0] >>= xPropSet; 589 //rArguments.getConstArray()[1] >>= xDicList; 590 591 //! Pointer allows for access of the non-UNO functions. 592 //! And the reference to the UNO-functions while increasing 593 //! the ref-count and will implicitly free the memory 594 //! when the object is not longer used. 595 pPropHelper = new PropertyHelper_Spell( (XSpellChecker *) this, xPropSet ); 596 xPropHelper = pPropHelper; 597 pPropHelper->AddAsPropListener(); //! after a reference is established 598 } 599 else 600 { 601 DBG_ERROR( "wrong number of arguments in sequence" ); 602 } 603 } 604 } 605 606 607 void SAL_CALL SpellChecker::dispose() 608 throw(RuntimeException) 609 { 610 MutexGuard aGuard( GetLinguMutex() ); 611 612 if (!bDisposing) 613 { 614 bDisposing = sal_True; 615 EventObject aEvtObj( (XSpellChecker *) this ); 616 aEvtListeners.disposeAndClear( aEvtObj ); 617 } 618 } 619 620 621 void SAL_CALL SpellChecker::addEventListener( const Reference< XEventListener >& rxListener ) 622 throw(RuntimeException) 623 { 624 MutexGuard aGuard( GetLinguMutex() ); 625 626 if (!bDisposing && rxListener.is()) 627 aEvtListeners.addInterface( rxListener ); 628 } 629 630 631 void SAL_CALL SpellChecker::removeEventListener( const Reference< XEventListener >& rxListener ) 632 throw(RuntimeException) 633 { 634 MutexGuard aGuard( GetLinguMutex() ); 635 636 if (!bDisposing && rxListener.is()) 637 aEvtListeners.removeInterface( rxListener ); 638 } 639 640 641 /////////////////////////////////////////////////////////////////////////// 642 // Service specific part 643 // 644 645 OUString SAL_CALL SpellChecker::getImplementationName() 646 throw(RuntimeException) 647 { 648 MutexGuard aGuard( GetLinguMutex() ); 649 650 return getImplementationName_Static(); 651 } 652 653 654 sal_Bool SAL_CALL SpellChecker::supportsService( const OUString& ServiceName ) 655 throw(RuntimeException) 656 { 657 MutexGuard aGuard( GetLinguMutex() ); 658 659 Sequence< OUString > aSNL = getSupportedServiceNames(); 660 const OUString * pArray = aSNL.getConstArray(); 661 for( sal_Int32 i = 0; i < aSNL.getLength(); i++ ) 662 if( pArray[i] == ServiceName ) 663 return sal_True; 664 return sal_False; 665 } 666 667 668 Sequence< OUString > SAL_CALL SpellChecker::getSupportedServiceNames() 669 throw(RuntimeException) 670 { 671 MutexGuard aGuard( GetLinguMutex() ); 672 673 return getSupportedServiceNames_Static(); 674 } 675 676 677 Sequence< OUString > SpellChecker::getSupportedServiceNames_Static() 678 throw() 679 { 680 MutexGuard aGuard( GetLinguMutex() ); 681 682 Sequence< OUString > aSNS( 1 ); // auch mehr als 1 Service moeglich 683 aSNS.getArray()[0] = A2OU( SN_SPELLCHECKER ); 684 return aSNS; 685 } 686 687 void * SAL_CALL SpellChecker_getFactory( const sal_Char * pImplName, 688 XMultiServiceFactory * pServiceManager, void * ) 689 { 690 void * pRet = 0; 691 if ( !SpellChecker::getImplementationName_Static().compareToAscii( pImplName ) ) 692 { 693 Reference< XSingleServiceFactory > xFactory = 694 cppu::createOneInstanceFactory( 695 pServiceManager, 696 SpellChecker::getImplementationName_Static(), 697 SpellChecker_CreateInstance, 698 SpellChecker::getSupportedServiceNames_Static()); 699 // acquire, because we return an interface pointer instead of a reference 700 xFactory->acquire(); 701 pRet = xFactory.get(); 702 } 703 return pRet; 704 } 705 706 707 /////////////////////////////////////////////////////////////////////////// 708