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 asigned 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
GetLngSvcMgr_Impl()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
Thesaurus()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
~Thesaurus()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
GetPropHelper_Impl()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
getLocales()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 seperate 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
hasLocale(const Locale & rLocale)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
queryMeanings(const OUString & qTerm,const Locale & rLocale,const PropertyValues & rProperties)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
Thesaurus_CreateInstance(const Reference<XMultiServiceFactory> &)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
getServiceDisplayName(const Locale &)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
initialize(const Sequence<Any> & rArguments)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
capitalType(const OUString & aTerm,CharClass * pCC)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
makeLowerCase(const OUString & aTerm,CharClass * pCC)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
makeUpperCase(const OUString & aTerm,CharClass * pCC)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
makeInitCap(const OUString & aTerm,CharClass * pCC)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
dispose()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
addEventListener(const Reference<XEventListener> & rxListener)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
removeEventListener(const Reference<XEventListener> & rxListener)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
getImplementationName()711 OUString SAL_CALL Thesaurus::getImplementationName()
712 throw(RuntimeException)
713 {
714 MutexGuard aGuard( GetLinguMutex() );
715 return getImplementationName_Static();
716 }
717
718
supportsService(const OUString & ServiceName)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
getSupportedServiceNames()733 Sequence< OUString > SAL_CALL Thesaurus::getSupportedServiceNames()
734 throw(RuntimeException)
735 {
736 MutexGuard aGuard( GetLinguMutex() );
737 return getSupportedServiceNames_Static();
738 }
739
740
getSupportedServiceNames_Static()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
Thesaurus_getFactory(const sal_Char * pImplName,XMultiServiceFactory * pServiceManager,void *)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