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