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