bump product version to 5.0.4.1
[LibreOffice.git] / linguistic / workben / sspellimp.cxx
blobb7fb2cb88e2316fd1ab00e2afa6187f9a89749bc
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <com/sun/star/uno/Reference.h>
21 #include <com/sun/star/linguistic2/XSearchableDictionaryList.hpp>
22 #include <com/sun/star/linguistic2/SpellFailure.hpp>
23 #include <com/sun/star/registry/XRegistryKey.hpp>
24 #include <comphelper/string.hxx>
25 #include <cppuhelper/factory.hxx>
26 #include <cppuhelper/supportsservice.hxx>
27 #include <tools/debug.hxx>
28 #include <osl/mutex.hxx>
30 #include <sspellimp.hxx>
32 #include "linguistic/lngprops.hxx"
33 #include "linguistic/spelldta.hxx"
35 using namespace utl;
36 using namespace osl;
37 using namespace com::sun::star;
38 using namespace com::sun::star::beans;
39 using namespace com::sun::star::lang;
40 using namespace com::sun::star::uno;
41 using namespace com::sun::star::linguistic2;
42 using namespace linguistic;
46 sal_Bool operator == ( const Locale &rL1, const Locale &rL2 )
48 return rL1.Language == rL2.Language &&
49 rL1.Country == rL2.Country &&
50 rL1.Variant == rL2.Variant;
55 SpellChecker::SpellChecker() :
56 aEvtListeners ( GetLinguMutex() )
58 bDisposing = sal_False;
59 pPropHelper = NULL;
63 SpellChecker::~SpellChecker()
65 if (pPropHelper)
66 pPropHelper->RemoveAsPropListener();
70 PropertyHelper_Spell & SpellChecker::GetPropHelper_Impl()
72 if (!pPropHelper)
74 Reference< XLinguProperties > xPropSet = GetLinguProperties();
76 pPropHelper = new PropertyHelper_Spell( (XSpellChecker *) this, xPropSet );
77 xPropHelper = pPropHelper;
78 pPropHelper->AddAsPropListener(); //! after a reference is established
80 return *pPropHelper;
84 Sequence< Locale > SAL_CALL SpellChecker::getLocales()
85 throw(RuntimeException)
87 MutexGuard aGuard( GetLinguMutex() );
89 if (!aSuppLocales.getLength())
91 aSuppLocales.realloc( 3 );
92 Locale *pLocale = aSuppLocales.getArray();
93 pLocale[0] = Locale( "en", "US", OUString() );
94 pLocale[1] = Locale( "de", "DE", OUString() );
95 pLocale[2] = Locale( "de", "CH", OUString() );
98 return aSuppLocales;
102 sal_Bool SAL_CALL SpellChecker::hasLocale(const Locale& rLocale)
103 throw(RuntimeException)
105 MutexGuard aGuard( GetLinguMutex() );
107 sal_Bool bRes = sal_False;
108 if (!aSuppLocales.getLength())
109 getLocales();
110 sal_Int32 nLen = aSuppLocales.getLength();
111 for (sal_Int32 i = 0; i < nLen; ++i)
113 const Locale *pLocale = aSuppLocales.getConstArray();
114 if (rLocale == pLocale[i])
116 bRes = sal_True;
117 break;
120 return bRes;
124 sal_Int16 SpellChecker::GetSpellFailure( const OUString &rWord, const Locale & )
126 // Checks whether a word is OK in a given language (Locale) or not, and
127 // provides a failure type for the incorrect ones.
128 // - words with "liss" (case sensitiv) as substring will be negative.
129 // - words with 'x' or 'X' will have incorrect spelling.
130 // - words with 's' or 'S' as first letter will have the wrong caption.
131 // - all other words will be OK.
133 sal_Int16 nRes = -1;
135 String aTmp( rWord );
136 if (aTmp.Len())
138 if (-1 != aTmp.indexOf( "liss" ))
140 nRes = SpellFailure::IS_NEGATIVE_WORD;
142 else if (-1 != aTmp.indexOf( (sal_Unicode) 'x' ) ||
143 -1 != aTmp.indexOf( (sal_Unicode) 'X' ))
145 nRes = SpellFailure::SPELLING_ERROR;
147 else
149 sal_Unicode cChar = aTmp.GetChar( 0 );
150 if (cChar == (sal_Unicode) 's' || cChar == (sal_Unicode) 'S')
151 nRes = SpellFailure::CAPTION_ERROR;
155 return nRes;
159 sal_Bool SAL_CALL
160 SpellChecker::isValid( const OUString& rWord, const Locale& rLocale,
161 const PropertyValues& rProperties )
162 throw(IllegalArgumentException, RuntimeException)
164 MutexGuard aGuard( GetLinguMutex() );
166 if (rLocale == Locale() || !rWord.getLength())
167 return sal_True;
169 if (!hasLocale( rLocale ))
170 #ifdef LINGU_EXCEPTIONS
171 throw( IllegalArgumentException() );
172 #else
173 return sal_True;
174 #endif
176 // Get property values to be used.
177 // These are be the default values set in the SN_LINGU_PROPERTIES
178 // PropertySet which are overridden by the supplied ones from the
179 // last argument.
180 // You'll probably like to use a simpler solution than the provided
181 // one using the PropertyHelper_Spell.
182 PropertyHelper_Spell &rHelper = GetPropHelper();
183 rHelper.SetTmpPropVals( rProperties );
185 sal_Int16 nFailure = GetSpellFailure( rWord, rLocale );
186 if (nFailure != -1)
188 sal_Int16 nLang = LinguLocaleToLanguage( rLocale );
189 // postprocess result for errors that should be ignored
190 if ( (!rHelper.IsSpellUpperCase() && IsUpper( rWord, nLang ))
191 || (!rHelper.IsSpellWithDigits() && HasDigits( rWord ))
192 || (!rHelper.IsSpellCapitalization()
193 && nFailure == SpellFailure::CAPTION_ERROR)
195 nFailure = -1;
197 return nFailure == -1;
201 Reference< XSpellAlternatives >
202 SpellChecker::GetProposals( const OUString &rWord, const Locale &rLocale )
204 // Retrieves the return values for the 'spell' function call in case
205 // of a misspelled word.
206 // Especially it may give a list of suggested (correct) words:
207 // - a "liss" substring will be replaced by "liz".
208 // - 'x' or 'X' will be replaced by 'u' or 'U' for the first proposal
209 // and they will be removed from the word for the second proposal.
210 // - 's' or 'S' as first letter will be changed to the other caption.
212 Reference< XSpellAlternatives > xRes;
214 String aTmp( rWord );
215 if (aTmp.Len())
217 sal_Int16 nLang = LinguLocaleToLanguage( rLocale );
219 if (-1 != aTmp.indexOf( "liss" ))
221 aTmp.SearchAndReplaceAllAscii( "liss", "liz" );
222 xRes = new SpellAlternatives( aTmp, nLang,
223 SpellFailure::IS_NEGATIVE_WORD, ::com::sun::star::uno::Sequence< OUString >() );
225 else if (-1 != aTmp.indexOf( (sal_Unicode) 'x' ) ||
226 -1 != aTmp.indexOf( (sal_Unicode) 'X' ))
228 Sequence< OUString > aStr( 2 );
229 OUString *pStr = aStr.getArray();
230 String aAlt1( aTmp ),
231 aAlt2( aTmp );
232 aAlt1.SearchAndReplaceAll( (sal_Unicode) 'x', (sal_Unicode) 'u');
233 aAlt1.SearchAndReplaceAll( (sal_Unicode) 'X', (sal_Unicode) 'U');
234 aAlt2 = comphelper::string::remove(aAlt2, 'x');
235 aAlt2 = comphelper::string::remove(aAlt2, 'X');
236 pStr[0] = aAlt1;
237 pStr[1] = aAlt2;
239 SpellAlternatives *pAlt = new SpellAlternatives;
240 pAlt->SetWordLanguage( aTmp, nLang );
241 pAlt->SetFailureType( SpellFailure::SPELLING_ERROR );
242 pAlt->SetAlternatives( aStr );
244 xRes = pAlt;
246 else
248 sal_Unicode cChar = aTmp.GetChar( 0 );
249 if (cChar == (sal_Unicode) 's' || cChar == (sal_Unicode) 'S')
251 sal_Unicode cNewChar = cChar == (sal_Unicode) 's' ?
252 (sal_Unicode) 'S': (sal_Unicode) 's';
253 aTmp.GetBufferAccess()[0] = cNewChar;
254 xRes = new SpellAlternatives( aTmp, nLang,
255 SpellFailure::CAPTION_ERROR, ::com::sun::star::uno::Sequence< OUString >() );
260 return xRes;
264 Reference< XSpellAlternatives > SAL_CALL
265 SpellChecker::spell( const OUString& rWord, const Locale& rLocale,
266 const PropertyValues& rProperties )
267 throw(IllegalArgumentException, RuntimeException)
269 MutexGuard aGuard( GetLinguMutex() );
271 if (rLocale == Locale() || !rWord.getLength())
272 return NULL;
274 if (!hasLocale( rLocale ))
275 #ifdef LINGU_EXCEPTIONS
276 throw( IllegalArgumentException() );
277 #else
278 return NULL;
279 #endif
281 Reference< XSpellAlternatives > xAlt;
282 if (!isValid( rWord, rLocale, rProperties ))
284 xAlt = GetProposals( rWord, rLocale );
286 return xAlt;
290 Reference< XInterface > SAL_CALL SpellChecker_CreateInstance(
291 const Reference< XMultiServiceFactory > & )
292 throw(Exception)
294 Reference< XInterface > xService = (cppu::OWeakObject*) new SpellChecker;
295 return xService;
299 sal_Bool SAL_CALL
300 SpellChecker::addLinguServiceEventListener(
301 const Reference< XLinguServiceEventListener >& rxLstnr )
302 throw(RuntimeException)
304 MutexGuard aGuard( GetLinguMutex() );
306 sal_Bool bRes = sal_False;
307 if (!bDisposing && rxLstnr.is())
309 bRes = GetPropHelper().addLinguServiceEventListener( rxLstnr );
311 return bRes;
315 sal_Bool SAL_CALL
316 SpellChecker::removeLinguServiceEventListener(
317 const Reference< XLinguServiceEventListener >& rxLstnr )
318 throw(RuntimeException)
320 MutexGuard aGuard( GetLinguMutex() );
322 sal_Bool bRes = sal_False;
323 if (!bDisposing && rxLstnr.is())
325 DBG_ASSERT( xPropHelper.is(), "xPropHelper non existent" );
326 bRes = GetPropHelper().removeLinguServiceEventListener( rxLstnr );
328 return bRes;
332 OUString SAL_CALL
333 SpellChecker::getServiceDisplayName( const Locale& )
334 throw(RuntimeException)
336 MutexGuard aGuard( GetLinguMutex() );
337 return OUString( "OpenOffice example spellchecker" );
341 void SAL_CALL
342 SpellChecker::initialize( const Sequence< Any >& rArguments )
343 throw(Exception, RuntimeException)
345 MutexGuard aGuard( GetLinguMutex() );
347 if (!pPropHelper)
349 sal_Int32 nLen = rArguments.getLength();
350 if (2 == nLen)
352 Reference< XPropertySet > xPropSet;
353 rArguments.getConstArray()[0] >>= xPropSet;
355 //! Pointer allows for access of the non-UNO functions.
356 //! And the reference to the UNO-functions while increasing
357 //! the ref-count and will implicitly free the memory
358 //! when the object is not longer used.
359 pPropHelper = new PropertyHelper_Spell( (XSpellChecker *) this, xPropSet );
360 xPropHelper = pPropHelper;
361 pPropHelper->AddAsPropListener(); //! after a reference is established
363 else
364 OSL_FAIL( "wrong number of arguments in sequence" );
369 void SAL_CALL
370 SpellChecker::dispose()
371 throw(RuntimeException)
373 MutexGuard aGuard( GetLinguMutex() );
375 if (!bDisposing)
377 bDisposing = sal_True;
378 EventObject aEvtObj( (XSpellChecker *) this );
379 aEvtListeners.disposeAndClear( aEvtObj );
384 void SAL_CALL
385 SpellChecker::addEventListener( const Reference< XEventListener >& rxListener )
386 throw(RuntimeException)
388 MutexGuard aGuard( GetLinguMutex() );
390 if (!bDisposing && rxListener.is())
391 aEvtListeners.addInterface( rxListener );
395 void SAL_CALL
396 SpellChecker::removeEventListener( const Reference< XEventListener >& rxListener )
397 throw(RuntimeException)
399 MutexGuard aGuard( GetLinguMutex() );
401 if (!bDisposing && rxListener.is())
402 aEvtListeners.removeInterface( rxListener );
406 // Service specific part
408 OUString SAL_CALL SpellChecker::getImplementationName()
409 throw(RuntimeException)
411 MutexGuard aGuard( GetLinguMutex() );
412 return getImplementationName_Static();
416 sal_Bool SAL_CALL SpellChecker::supportsService( const OUString& ServiceName )
417 throw(RuntimeException)
419 return cppu::supportsService(this, ServiceName);
422 Sequence< OUString > SAL_CALL SpellChecker::getSupportedServiceNames()
423 throw(RuntimeException)
425 MutexGuard aGuard( GetLinguMutex() );
426 return getSupportedServiceNames_Static();
430 Sequence< OUString > SpellChecker::getSupportedServiceNames_Static()
431 throw()
433 MutexGuard aGuard( GetLinguMutex() );
435 Sequence< OUString > aSNS( 1 ); // more than 1 service possible
436 aSNS.getArray()[0] = SN_SPELLCHECKER;
437 return aSNS;
441 sal_Bool SAL_CALL SpellChecker_writeInfo(
442 void * /*pServiceManager*/, registry::XRegistryKey * pRegistryKey )
446 OUString aImpl( "/" + SpellChecker::getImplementationName_Static().getStr() +
447 "/UNO/SERVICES" );
449 Reference< registry::XRegistryKey > xNewKey =
450 pRegistryKey->createKey( aImpl );
451 Sequence< OUString > aServices =
452 SpellChecker::getSupportedServiceNames_Static();
453 for( sal_Int32 i = 0; i < aServices.getLength(); i++ )
454 xNewKey->createKey( aServices.getConstArray()[i] );
456 return sal_True;
458 catch(Exception &)
460 return sal_False;
465 void * SAL_CALL SpellChecker_getFactory( const sal_Char * pImplName,
466 XMultiServiceFactory * pServiceManager, void * )
468 void * pRet = 0;
469 if ( SpellChecker::getImplementationName_Static().equalsAscii( pImplName ) )
471 Reference< XSingleServiceFactory > xFactory =
472 cppu::createOneInstanceFactory(
473 pServiceManager,
474 SpellChecker::getImplementationName_Static(),
475 SpellChecker_CreateInstance,
476 SpellChecker::getSupportedServiceNames_Static());
477 // acquire, because we return an interface pointer instead of a reference
478 xFactory->acquire();
479 pRet = xFactory.get();
481 return pRet;
486 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */