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