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