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