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