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 <cppuhelper/factory.hxx> // helper for factories 29 #include <com/sun/star/registry/XRegistryKey.hpp> 30 #include <com/sun/star/beans/XPropertySet.hpp> 31 #include <i18npool/mslangid.hxx> 32 #include <tools/debug.hxx> 33 #include <unotools/processfactory.hxx> 34 #include <osl/mutex.hxx> 35 #include <unotools/pathoptions.hxx> 36 #include <unotools/lingucfg.hxx> 37 38 #include <rtl/string.hxx> 39 #include <rtl/ustrbuf.hxx> 40 #include <rtl/textenc.h> 41 42 #include "nthesimp.hxx" 43 #include <linguistic/misc.hxx> 44 #include <linguistic/lngprops.hxx> 45 #include "nthesdta.hxx" 46 47 #include <list> 48 #include <set> 49 #include <string.h> 50 51 // values assigned to capitalization types 52 #define CAPTYPE_UNKNOWN 0 53 #define CAPTYPE_NOCAP 1 54 #define CAPTYPE_INITCAP 2 55 #define CAPTYPE_ALLCAP 3 56 #define CAPTYPE_MIXED 4 57 58 // XML-header to query SPELLML support 59 #define SPELLML_SUPPORT "<?xml?>" 60 61 using namespace utl; 62 using namespace osl; 63 using namespace rtl; 64 using namespace com::sun::star; 65 using namespace com::sun::star::beans; 66 using namespace com::sun::star::lang; 67 using namespace com::sun::star::uno; 68 using namespace com::sun::star::linguistic2; 69 using namespace linguistic; 70 71 72 73 /////////////////////////////////////////////////////////////////////////// 74 75 static uno::Reference< XLinguServiceManager > GetLngSvcMgr_Impl() 76 { 77 uno::Reference< XLinguServiceManager > xRes; 78 uno::Reference< XMultiServiceFactory > xMgr = getProcessServiceFactory(); 79 if (xMgr.is()) 80 { 81 xRes = uno::Reference< XLinguServiceManager > ( xMgr->createInstance( 82 OUString( RTL_CONSTASCII_USTRINGPARAM( 83 "com.sun.star.linguistic2.LinguServiceManager" ) ) ), UNO_QUERY ) ; 84 } 85 return xRes; 86 } 87 88 Thesaurus::Thesaurus() : 89 aEvtListeners ( GetLinguMutex() ) 90 { 91 bDisposing = sal_False; 92 pPropHelper = NULL; 93 aThes = NULL; 94 aCharSetInfo = NULL; 95 aTEncs = NULL; 96 aTLocs = NULL; 97 aTNames = NULL; 98 numthes = 0; 99 } 100 101 102 Thesaurus::~Thesaurus() 103 { 104 105 if (aThes) 106 { 107 for (int i = 0; i < numthes; i++) 108 { 109 if (aThes[i]) delete aThes[i]; 110 aThes[i] = NULL; 111 } 112 delete[] aThes; 113 } 114 aThes = NULL; 115 if (aCharSetInfo) 116 { 117 for (int i = 0; i < numthes; i++) 118 { 119 if (aCharSetInfo[i]) delete aCharSetInfo[i]; 120 aCharSetInfo[i] = NULL; 121 } 122 delete[] aCharSetInfo; 123 } 124 aCharSetInfo = NULL; 125 numthes = 0; 126 if (aTEncs) delete[] aTEncs; 127 aTEncs = NULL; 128 if (aTLocs) delete[] aTLocs; 129 aTLocs = NULL; 130 if (aTNames) delete[] aTNames; 131 aTNames = NULL; 132 133 if (pPropHelper) 134 pPropHelper->RemoveAsPropListener(); 135 } 136 137 138 PropertyHelper_Thes & Thesaurus::GetPropHelper_Impl() 139 { 140 if (!pPropHelper) 141 { 142 Reference< XPropertySet > xPropSet( GetLinguProperties(), UNO_QUERY ); 143 144 pPropHelper = new PropertyHelper_Thes( (XThesaurus *) this, xPropSet ); 145 xPropHelper = pPropHelper; 146 pPropHelper->AddAsPropListener(); //! after a reference is established 147 } 148 return *pPropHelper; 149 } 150 151 152 Sequence< Locale > SAL_CALL Thesaurus::getLocales() 153 throw(RuntimeException) 154 { 155 MutexGuard aGuard( GetLinguMutex() ); 156 157 // this routine should return the locales supported by the installed 158 // dictionaries. 159 160 if (!numthes) 161 { 162 SvtLinguConfig aLinguCfg; 163 164 // get list of dictionaries-to-use 165 std::list< SvtLinguConfigDictionaryEntry > aDics; 166 uno::Sequence< rtl::OUString > aFormatList; 167 aLinguCfg.GetSupportedDictionaryFormatsFor( A2OU("Thesauri"), 168 A2OU("org.openoffice.lingu.new.Thesaurus"), aFormatList ); 169 sal_Int32 nLen = aFormatList.getLength(); 170 for (sal_Int32 i = 0; i < nLen; ++i) 171 { 172 std::vector< SvtLinguConfigDictionaryEntry > aTmpDic( 173 aLinguCfg.GetActiveDictionariesByFormat( aFormatList[i] ) ); 174 aDics.insert( aDics.end(), aTmpDic.begin(), aTmpDic.end() ); 175 } 176 177 //!! for compatibility with old dictionaries (the ones not using extensions 178 //!! or new configuration entries, but still using the dictionary.lst file) 179 //!! Get the list of old style spell checking dictionaries to use... 180 std::vector< SvtLinguConfigDictionaryEntry > aOldStyleDics( 181 GetOldStyleDics( "THES" ) ); 182 183 // to prefer dictionaries with configuration entries we will only 184 // use those old style dictionaries that add a language that 185 // is not yet supported by the list od new style dictionaries 186 MergeNewStyleDicsAndOldStyleDics( aDics, aOldStyleDics ); 187 188 numthes = aDics.size(); 189 if (numthes) 190 { 191 // get supported locales from the dictionaries-to-use... 192 sal_Int32 k = 0; 193 std::set< rtl::OUString, lt_rtl_OUString > aLocaleNamesSet; 194 std::list< SvtLinguConfigDictionaryEntry >::const_iterator aDictIt; 195 for (aDictIt = aDics.begin(); aDictIt != aDics.end(); ++aDictIt) 196 { 197 uno::Sequence< rtl::OUString > aLocaleNames( aDictIt->aLocaleNames ); 198 sal_Int32 nLen2 = aLocaleNames.getLength(); 199 for (k = 0; k < nLen2; ++k) 200 { 201 aLocaleNamesSet.insert( aLocaleNames[k] ); 202 } 203 } 204 // ... and add them to the resulting sequence 205 aSuppLocales.realloc( aLocaleNamesSet.size() ); 206 std::set< rtl::OUString, lt_rtl_OUString >::const_iterator aItB; 207 k = 0; 208 for (aItB = aLocaleNamesSet.begin(); aItB != aLocaleNamesSet.end(); ++aItB) 209 { 210 Locale aTmp( MsLangId::convertLanguageToLocale( 211 MsLangId::convertIsoStringToLanguage( *aItB ))); 212 aSuppLocales[k++] = aTmp; 213 } 214 215 //! For each dictionary and each locale we need a separate entry. 216 //! If this results in more than one dictionary per locale than (for now) 217 //! it is undefined which dictionary gets used. 218 //! In the future the implementation should support using several dictionaries 219 //! for one locale. 220 numthes = 0; 221 for (aDictIt = aDics.begin(); aDictIt != aDics.end(); ++aDictIt) 222 numthes = numthes + aDictIt->aLocaleNames.getLength(); 223 224 // add dictionary information 225 aThes = new MyThes* [numthes]; 226 aTEncs = new rtl_TextEncoding [numthes]; 227 aTLocs = new Locale [numthes]; 228 aTNames = new OUString [numthes]; 229 aCharSetInfo = new CharClass* [numthes]; 230 231 k = 0; 232 for (aDictIt = aDics.begin(); aDictIt != aDics.end(); ++aDictIt) 233 { 234 if (aDictIt->aLocaleNames.getLength() > 0 && 235 aDictIt->aLocations.getLength() > 0) 236 { 237 uno::Sequence< rtl::OUString > aLocaleNames( aDictIt->aLocaleNames ); 238 sal_Int32 nLocales = aLocaleNames.getLength(); 239 240 // currently only one language per dictionary is supported in the actual implementation... 241 // Thus here we work-around this by adding the same dictionary several times. 242 // Once for each of it's supported locales. 243 for (sal_Int32 i = 0; i < nLocales; ++i) 244 { 245 aThes[k] = NULL; 246 aTEncs[k] = RTL_TEXTENCODING_DONTKNOW; 247 aTLocs[k] = MsLangId::convertLanguageToLocale( 248 MsLangId::convertIsoStringToLanguage( aDictIt->aLocaleNames[i] )); 249 aCharSetInfo[k] = new CharClass( aTLocs[k] ); 250 // also both files have to be in the same directory and the 251 // file names must only differ in the extension (.aff/.dic). 252 // Thus we use the first location only and strip the extension part. 253 rtl::OUString aLocation = aDictIt->aLocations[0]; 254 sal_Int32 nPos = aLocation.lastIndexOf( '.' ); 255 aLocation = aLocation.copy( 0, nPos ); 256 aTNames[k] = aLocation; 257 258 ++k; 259 } 260 } 261 } 262 DBG_ASSERT( k == numthes, "index mismatch?" ); 263 } 264 else 265 { 266 /* no dictionary found so register no dictionaries */ 267 numthes = 0; 268 aThes = NULL; 269 aTEncs = NULL; 270 aTLocs = NULL; 271 aTNames = NULL; 272 aCharSetInfo = NULL; 273 aSuppLocales.realloc(0); 274 } 275 } 276 277 return aSuppLocales; 278 } 279 280 281 282 sal_Bool SAL_CALL Thesaurus::hasLocale(const Locale& rLocale) 283 throw(RuntimeException) 284 { 285 MutexGuard aGuard( GetLinguMutex() ); 286 287 sal_Bool bRes = sal_False; 288 if (!aSuppLocales.getLength()) 289 getLocales(); 290 sal_Int32 nLen = aSuppLocales.getLength(); 291 for (sal_Int32 i = 0; i < nLen; ++i) 292 { 293 const Locale *pLocale = aSuppLocales.getConstArray(); 294 if (rLocale == pLocale[i]) 295 { 296 bRes = sal_True; 297 break; 298 } 299 } 300 return bRes; 301 } 302 303 304 Sequence < Reference < ::com::sun::star::linguistic2::XMeaning > > SAL_CALL Thesaurus::queryMeanings( 305 const OUString& qTerm, const Locale& rLocale, 306 const PropertyValues& rProperties) 307 throw(IllegalArgumentException, RuntimeException) 308 { 309 MutexGuard aGuard( GetLinguMutex() ); 310 311 uno::Sequence< Reference< XMeaning > > aMeanings( 1 ); 312 uno::Sequence< Reference< XMeaning > > noMeanings( 0 ); 313 uno::Reference< XLinguServiceManager > xLngSvcMgr( GetLngSvcMgr_Impl() ); 314 uno::Reference< XSpellChecker1 > xSpell; 315 316 OUString rTerm(qTerm); 317 OUString pTerm(qTerm); 318 sal_uInt16 ct = CAPTYPE_UNKNOWN; 319 sal_Int32 stem = 0; 320 sal_Int32 stem2 = 0; 321 322 sal_Int16 nLanguage = LocaleToLanguage( rLocale ); 323 324 if (nLanguage == LANGUAGE_NONE || !rTerm.getLength()) 325 return noMeanings; 326 327 if (!hasLocale( rLocale )) 328 #ifdef LINGU_EXCEPTIONS 329 throw( IllegalArgumentException() ); 330 #else 331 return noMeanings; 332 #endif 333 334 if (prevTerm == qTerm && prevLocale == nLanguage) 335 return prevMeanings; 336 337 mentry * pmean = NULL; 338 sal_Int32 nmean = 0; 339 340 PropertyHelper_Thes &rHelper = GetPropHelper(); 341 rHelper.SetTmpPropVals( rProperties ); 342 343 MyThes * pTH = NULL; 344 rtl_TextEncoding eEnc = RTL_TEXTENCODING_DONTKNOW; 345 CharClass * pCC = NULL; 346 347 // find the first thesaurus that matches the locale 348 for (int i =0; i < numthes; i++) 349 { 350 if (rLocale == aTLocs[i]) 351 { 352 // open up and intialize this thesaurus if need be 353 if (!aThes[i]) 354 { 355 OUString datpath = aTNames[i] + A2OU(".dat"); 356 OUString idxpath = aTNames[i] + A2OU(".idx"); 357 OUString ndat; 358 OUString nidx; 359 osl::FileBase::getSystemPathFromFileURL(datpath,ndat); 360 osl::FileBase::getSystemPathFromFileURL(idxpath,nidx); 361 OString aTmpidx(OU2ENC(nidx,osl_getThreadTextEncoding())); 362 OString aTmpdat(OU2ENC(ndat,osl_getThreadTextEncoding())); 363 364 #if defined(WNT) 365 // workaround for Windows specifc problem that the 366 // path length in calls to 'fopen' is limted to somewhat 367 // about 120+ characters which will usually be exceed when 368 // using dictionaries as extensions. 369 aTmpidx = Win_GetShortPathName( nidx ); 370 aTmpdat = Win_GetShortPathName( ndat ); 371 #endif 372 373 aThes[i] = new MyThes(aTmpidx.getStr(),aTmpdat.getStr()); 374 if (aThes[i]) 375 aTEncs[i] = getTextEncodingFromCharset(aThes[i]->get_th_encoding()); 376 } 377 pTH = aThes[i]; 378 eEnc = aTEncs[i]; 379 pCC = aCharSetInfo[i]; 380 381 if (pTH) 382 break; 383 } 384 } 385 386 // we don't want to work with a default text encoding since following incorrect 387 // results may occur only for specific text and thus may be hard to notice. 388 // Thus better always make a clean exit here if the text encoding is in question. 389 // Hopefully something not working at all will raise proper attention quickly. ;-) 390 DBG_ASSERT( eEnc != RTL_TEXTENCODING_DONTKNOW, "failed to get text encoding! (maybe incorrect encoding string in file)" ); 391 if (eEnc == RTL_TEXTENCODING_DONTKNOW) 392 return noMeanings; 393 394 while (pTH) 395 { 396 // convert word to all lower case for searching 397 if (!stem) 398 ct = capitalType(rTerm, pCC); 399 OUString nTerm(makeLowerCase(rTerm, pCC)); 400 OString aTmp( OU2ENC(nTerm, eEnc) ); 401 nmean = pTH->Lookup(aTmp.getStr(),aTmp.getLength(),&pmean); 402 403 if (nmean) 404 aMeanings.realloc( nmean ); 405 406 mentry * pe = pmean; 407 OUString codeTerm = qTerm; 408 Reference< XSpellAlternatives > xTmpRes2; 409 410 if (stem) 411 { 412 xTmpRes2 = xSpell->spell( A2OU("<?xml?><query type='analyze'><word>") + 413 pTerm + A2OU("</word></query>"), nLanguage, rProperties ); 414 if (xTmpRes2.is()) 415 { 416 Sequence<OUString>seq = xTmpRes2->getAlternatives(); 417 if (seq.getLength() > 0) 418 { 419 codeTerm = seq[0]; 420 stem2 = 1; 421 } 422 #if 0 423 OString o = OUStringToOString(codeTerm, RTL_TEXTENCODING_UTF8); 424 fprintf(stderr, "CODETERM: %s\n", o.pData->buffer); 425 #endif 426 } 427 } 428 429 for (int j = 0; j < nmean; j++) 430 { 431 int count = pe->count; 432 if (count) 433 { 434 Sequence< OUString > aStr( count ); 435 OUString *pStr = aStr.getArray(); 436 437 for (int i=0; i < count; i++) 438 { 439 OUString sTerm(pe->psyns[i],strlen(pe->psyns[i]),eEnc ); 440 sal_Int32 catpos = sTerm.indexOf('('); 441 sal_Int32 catpos2 = 0; 442 OUString catst; 443 OUString catst2; 444 if (catpos > 2) 445 { 446 // remove category name for affixation and casing 447 catst = A2OU(" ") + sTerm.copy(catpos); 448 sTerm = sTerm.copy(0, catpos); 449 sTerm = sTerm.trim(); 450 } 451 // generate synonyms with affixes 452 if (stem && stem2) 453 { 454 Reference< XSpellAlternatives > xTmpRes; 455 xTmpRes = xSpell->spell( A2OU("<?xml?><query type='generate'><word>") + 456 sTerm + A2OU("</word>") + codeTerm + A2OU("</query>"), nLanguage, rProperties ); 457 if (xTmpRes.is()) 458 { 459 Sequence<OUString>seq = xTmpRes->getAlternatives(); 460 if (seq.getLength() > 0) 461 sTerm = seq[0]; 462 } 463 } 464 if (catpos2) 465 sTerm = catst2 + sTerm; 466 467 sal_uInt16 ct1 = capitalType(sTerm, pCC); 468 if (CAPTYPE_MIXED == ct1) 469 ct = ct1; 470 OUString cTerm; 471 switch (ct) 472 { 473 case CAPTYPE_ALLCAP: 474 cTerm = makeUpperCase(sTerm, pCC); 475 break; 476 case CAPTYPE_INITCAP: 477 cTerm = makeInitCap(sTerm, pCC); 478 break; 479 default: 480 cTerm = sTerm; 481 break; 482 } 483 OUString aAlt( cTerm + catst); 484 pStr[i] = aAlt; 485 } 486 #if 0 487 Meaning * pMn = new Meaning(rTerm,nLanguage,rHelper); 488 #endif 489 Meaning * pMn = new Meaning(rTerm,nLanguage); 490 OUString dTerm(pe->defn,strlen(pe->defn),eEnc ); 491 pMn->SetMeaning(dTerm); 492 pMn->SetSynonyms(aStr); 493 Reference<XMeaning>* pMeaning = aMeanings.getArray(); 494 pMeaning[j] = pMn; 495 } 496 pe++; 497 } 498 pTH->CleanUpAfterLookup(&pmean,nmean); 499 500 if (nmean) 501 { 502 prevTerm = qTerm; 503 prevMeanings = aMeanings; 504 prevLocale = nLanguage; 505 return aMeanings; 506 } 507 508 if (stem || !xLngSvcMgr.is()) 509 return noMeanings; 510 stem = 1; 511 512 xSpell = uno::Reference< XSpellChecker1 >( xLngSvcMgr->getSpellChecker(), UNO_QUERY ); 513 if (!xSpell.is() || !xSpell->isValid( A2OU(SPELLML_SUPPORT), nLanguage, rProperties )) 514 return noMeanings; 515 Reference< XSpellAlternatives > xTmpRes; 516 xTmpRes = xSpell->spell( A2OU("<?xml?><query type='stem'><word>") + 517 rTerm + A2OU("</word></query>"), nLanguage, rProperties ); 518 if (xTmpRes.is()) 519 { 520 Sequence<OUString>seq = xTmpRes->getAlternatives(); 521 #if 0 522 for (int i = 0; i < seq.getLength(); i++) 523 { 524 OString o = OUStringToOString(seq[i], RTL_TEXTENCODING_UTF8); 525 fprintf(stderr, "%d: %s\n", i + 1, o.pData->buffer); 526 } 527 #endif 528 if (seq.getLength() > 0) 529 { 530 rTerm = seq[0]; // XXX Use only the first stem 531 continue; 532 } 533 } 534 535 // stem the last word of the synonym (for categories after affixation) 536 rTerm = rTerm.trim(); 537 sal_Int32 pos = rTerm.lastIndexOf(' '); 538 if (!pos) 539 return noMeanings; 540 xTmpRes = xSpell->spell( A2OU("<?xml?><query type='stem'><word>") + 541 rTerm.copy(pos + 1) + A2OU("</word></query>"), nLanguage, rProperties ); 542 if (xTmpRes.is()) 543 { 544 Sequence<OUString>seq = xTmpRes->getAlternatives(); 545 if (seq.getLength() > 0) 546 { 547 pTerm = rTerm.copy(pos + 1); 548 rTerm = rTerm.copy(0, pos + 1) + seq[0]; 549 #if 0 550 for (int i = 0; i < seq.getLength(); i++) 551 { 552 OString o = OUStringToOString(seq[i], RTL_TEXTENCODING_UTF8); 553 fprintf(stderr, "%d: %s\n", i + 1, o.pData->buffer); 554 } 555 #endif 556 continue; 557 } 558 } 559 break; 560 } 561 return noMeanings; 562 } 563 564 565 Reference< XInterface > SAL_CALL Thesaurus_CreateInstance( 566 const Reference< XMultiServiceFactory > & /*rSMgr*/ ) 567 throw(Exception) 568 { 569 Reference< XInterface > xService = (cppu::OWeakObject*) new Thesaurus; 570 return xService; 571 } 572 573 574 OUString SAL_CALL Thesaurus::getServiceDisplayName( const Locale& /*rLocale*/ ) 575 throw(RuntimeException) 576 { 577 MutexGuard aGuard( GetLinguMutex() ); 578 return A2OU( "OpenOffice.org New Thesaurus" ); 579 } 580 581 582 void SAL_CALL Thesaurus::initialize( const Sequence< Any >& rArguments ) 583 throw(Exception, RuntimeException) 584 { 585 MutexGuard aGuard( GetLinguMutex() ); 586 587 if (!pPropHelper) 588 { 589 sal_Int32 nLen = rArguments.getLength(); 590 if (1 == nLen) 591 { 592 Reference< XPropertySet > xPropSet; 593 rArguments.getConstArray()[0] >>= xPropSet; 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_Thes( (XThesaurus *) this, xPropSet ); 600 xPropHelper = pPropHelper; 601 pPropHelper->AddAsPropListener(); //! after a reference is established 602 } 603 else 604 DBG_ERROR( "wrong number of arguments in sequence" ); 605 } 606 } 607 608 609 610 sal_uInt16 SAL_CALL Thesaurus::capitalType(const OUString& aTerm, CharClass * pCC) 611 { 612 sal_Int32 tlen = aTerm.getLength(); 613 if ((pCC) && (tlen)) 614 { 615 String aStr(aTerm); 616 sal_Int32 nc = 0; 617 for (sal_uInt16 tindex = 0; tindex < tlen; tindex++) 618 { 619 if (pCC->getCharacterType(aStr,tindex) & 620 ::com::sun::star::i18n::KCharacterType::UPPER) nc++; 621 } 622 623 if (nc == 0) 624 return (sal_uInt16) CAPTYPE_NOCAP; 625 if (nc == tlen) 626 return (sal_uInt16) CAPTYPE_ALLCAP; 627 if ((nc == 1) && (pCC->getCharacterType(aStr,0) & 628 ::com::sun::star::i18n::KCharacterType::UPPER)) 629 return (sal_uInt16) CAPTYPE_INITCAP; 630 631 return (sal_uInt16) CAPTYPE_MIXED; 632 } 633 return (sal_uInt16) CAPTYPE_UNKNOWN; 634 } 635 636 637 638 OUString SAL_CALL Thesaurus::makeLowerCase(const OUString& aTerm, CharClass * pCC) 639 { 640 if (pCC) 641 return pCC->toLower_rtl(aTerm, 0, aTerm.getLength()); 642 return aTerm; 643 } 644 645 646 OUString SAL_CALL Thesaurus::makeUpperCase(const OUString& aTerm, CharClass * pCC) 647 { 648 if (pCC) 649 return pCC->toUpper_rtl(aTerm, 0, aTerm.getLength()); 650 return aTerm; 651 } 652 653 654 OUString SAL_CALL Thesaurus::makeInitCap(const OUString& aTerm, CharClass * pCC) 655 { 656 sal_Int32 tlen = aTerm.getLength(); 657 if ((pCC) && (tlen)) 658 { 659 OUString bTemp = aTerm.copy(0,1); 660 if (tlen > 1) 661 { 662 return ( pCC->toUpper_rtl(bTemp, 0, 1) 663 + pCC->toLower_rtl(aTerm,1,(tlen-1)) ); 664 } 665 666 return pCC->toUpper_rtl(bTemp, 0, 1); 667 } 668 return aTerm; 669 } 670 671 672 673 void SAL_CALL Thesaurus::dispose() 674 throw(RuntimeException) 675 { 676 MutexGuard aGuard( GetLinguMutex() ); 677 678 if (!bDisposing) 679 { 680 bDisposing = sal_True; 681 EventObject aEvtObj( (XThesaurus *) this ); 682 aEvtListeners.disposeAndClear( aEvtObj ); 683 } 684 } 685 686 687 void SAL_CALL Thesaurus::addEventListener( const Reference< XEventListener >& rxListener ) 688 throw(RuntimeException) 689 { 690 MutexGuard aGuard( GetLinguMutex() ); 691 692 if (!bDisposing && rxListener.is()) 693 aEvtListeners.addInterface( rxListener ); 694 } 695 696 697 void SAL_CALL Thesaurus::removeEventListener( const Reference< XEventListener >& rxListener ) 698 throw(RuntimeException) 699 { 700 MutexGuard aGuard( GetLinguMutex() ); 701 702 if (!bDisposing && rxListener.is()) 703 aEvtListeners.removeInterface( rxListener ); 704 } 705 706 707 /////////////////////////////////////////////////////////////////////////// 708 // Service specific part 709 // 710 711 OUString SAL_CALL Thesaurus::getImplementationName() 712 throw(RuntimeException) 713 { 714 MutexGuard aGuard( GetLinguMutex() ); 715 return getImplementationName_Static(); 716 } 717 718 719 sal_Bool SAL_CALL Thesaurus::supportsService( const OUString& ServiceName ) 720 throw(RuntimeException) 721 { 722 MutexGuard aGuard( GetLinguMutex() ); 723 724 Sequence< OUString > aSNL = getSupportedServiceNames(); 725 const OUString * pArray = aSNL.getConstArray(); 726 for( sal_Int32 i = 0; i < aSNL.getLength(); i++ ) 727 if( pArray[i] == ServiceName ) 728 return sal_True; 729 return sal_False; 730 } 731 732 733 Sequence< OUString > SAL_CALL Thesaurus::getSupportedServiceNames() 734 throw(RuntimeException) 735 { 736 MutexGuard aGuard( GetLinguMutex() ); 737 return getSupportedServiceNames_Static(); 738 } 739 740 741 Sequence< OUString > Thesaurus::getSupportedServiceNames_Static() 742 throw() 743 { 744 MutexGuard aGuard( GetLinguMutex() ); 745 746 Sequence< OUString > aSNS( 1 ); // auch mehr als 1 Service moeglich 747 aSNS.getArray()[0] = A2OU( SN_THESAURUS ); 748 return aSNS; 749 } 750 751 void * SAL_CALL Thesaurus_getFactory( const sal_Char * pImplName, 752 XMultiServiceFactory * pServiceManager, void * ) 753 { 754 void * pRet = 0; 755 if ( !Thesaurus::getImplementationName_Static().compareToAscii( pImplName ) ) 756 { 757 758 Reference< XSingleServiceFactory > xFactory = 759 cppu::createOneInstanceFactory( 760 pServiceManager, 761 Thesaurus::getImplementationName_Static(), 762 Thesaurus_CreateInstance, 763 Thesaurus::getSupportedServiceNames_Static()); 764 // acquire, because we return an interface pointer instead of a reference 765 xFactory->acquire(); 766 pRet = xFactory.get(); 767 } 768 return pRet; 769 } 770 771 772 /////////////////////////////////////////////////////////////////////////// 773 774 775 #undef CAPTYPE_UNKNOWN 776 #undef CAPTYPE_NOCAP 777 #undef CAPTYPE_INITCAP 778 #undef CAPTYPE_ALLCAP 779 #undef CAPTYPE_MIXED 780