bump product version to 4.1.6.2
[LibreOffice.git] / linguistic / workben / sspellimp.cxx
blob775c2fab20de65e3e761689a3e1fa4252b6303f9
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> // helper for factories
26 #include <tools/debug.hxx>
27 #include <osl/mutex.hxx>
29 #include <sspellimp.hxx>
31 #include "linguistic/lngprops.hxx"
32 #include "linguistic/spelldta.hxx"
34 using namespace utl;
35 using namespace osl;
36 using namespace com::sun::star;
37 using namespace com::sun::star::beans;
38 using namespace com::sun::star::lang;
39 using namespace com::sun::star::uno;
40 using namespace com::sun::star::linguistic2;
41 using namespace linguistic;
45 sal_Bool operator == ( const Locale &rL1, const Locale &rL2 )
47 return rL1.Language == rL2.Language &&
48 rL1.Country == rL2.Country &&
49 rL1.Variant == rL2.Variant;
54 SpellChecker::SpellChecker() :
55 aEvtListeners ( GetLinguMutex() )
57 bDisposing = sal_False;
58 pPropHelper = NULL;
62 SpellChecker::~SpellChecker()
64 if (pPropHelper)
65 pPropHelper->RemoveAsPropListener();
69 PropertyHelper_Spell & SpellChecker::GetPropHelper_Impl()
71 if (!pPropHelper)
73 Reference< XLinguProperties > xPropSet = GetLinguProperties();
75 pPropHelper = new PropertyHelper_Spell( (XSpellChecker *) this, xPropSet );
76 xPropHelper = pPropHelper;
77 pPropHelper->AddAsPropListener(); //! after a reference is established
79 return *pPropHelper;
83 Sequence< Locale > SAL_CALL SpellChecker::getLocales()
84 throw(RuntimeException)
86 MutexGuard aGuard( GetLinguMutex() );
88 if (!aSuppLocales.getLength())
90 aSuppLocales.realloc( 3 );
91 Locale *pLocale = aSuppLocales.getArray();
92 pLocale[0] = Locale( "en", "US", OUString() );
93 pLocale[1] = Locale( "de", "DE", OUString() );
94 pLocale[2] = Locale( "de", "CH"), OUString() );
97 return aSuppLocales;
101 sal_Bool SAL_CALL SpellChecker::hasLocale(const Locale& rLocale)
102 throw(RuntimeException)
104 MutexGuard aGuard( GetLinguMutex() );
106 sal_Bool bRes = sal_False;
107 if (!aSuppLocales.getLength())
108 getLocales();
109 sal_Int32 nLen = aSuppLocales.getLength();
110 for (sal_Int32 i = 0; i < nLen; ++i)
112 const Locale *pLocale = aSuppLocales.getConstArray();
113 if (rLocale == pLocale[i])
115 bRes = sal_True;
116 break;
119 return bRes;
123 sal_Int16 SpellChecker::GetSpellFailure( const OUString &rWord, const Locale & )
125 // Checks whether a word is OK in a given language (Locale) or not, and
126 // provides a failure type for the incorrect ones.
127 // - words with "liss" (case sensitiv) as substring will be negative.
128 // - words with 'x' or 'X' will have incorrect spelling.
129 // - words with 's' or 'S' as first letter will have the wrong caption.
130 // - all other words will be OK.
132 sal_Int16 nRes = -1;
134 String aTmp( rWord );
135 if (aTmp.Len())
137 if (STRING_NOTFOUND != aTmp.SearchAscii( "liss" ))
139 nRes = SpellFailure::IS_NEGATIVE_WORD;
141 else if (STRING_NOTFOUND != aTmp.Search( (sal_Unicode) 'x' ) ||
142 STRING_NOTFOUND != aTmp.Search( (sal_Unicode) 'X' ))
144 nRes = SpellFailure::SPELLING_ERROR;
146 else
148 sal_Unicode cChar = aTmp.GetChar( 0 );
149 if (cChar == (sal_Unicode) 's' || cChar == (sal_Unicode) 'S')
150 nRes = SpellFailure::CAPTION_ERROR;
154 return nRes;
158 sal_Bool SAL_CALL
159 SpellChecker::isValid( const OUString& rWord, const Locale& rLocale,
160 const PropertyValues& rProperties )
161 throw(IllegalArgumentException, RuntimeException)
163 MutexGuard aGuard( GetLinguMutex() );
165 if (rLocale == Locale() || !rWord.getLength())
166 return sal_True;
168 if (!hasLocale( rLocale ))
169 #ifdef LINGU_EXCEPTIONS
170 throw( IllegalArgumentException() );
171 #else
172 return sal_True;
173 #endif
175 // Get property values to be used.
176 // These are be the default values set in the SN_LINGU_PROPERTIES
177 // PropertySet which are overridden by the supplied ones from the
178 // last argument.
179 // You'll probably like to use a simplier solution than the provided
180 // one using the PropertyHelper_Spell.
181 PropertyHelper_Spell &rHelper = GetPropHelper();
182 rHelper.SetTmpPropVals( rProperties );
184 sal_Int16 nFailure = GetSpellFailure( rWord, rLocale );
185 if (nFailure != -1)
187 sal_Int16 nLang = LinguLocaleToLanguage( rLocale );
188 // postprocess result for errors that should be ignored
189 if ( (!rHelper.IsSpellUpperCase() && IsUpper( rWord, nLang ))
190 || (!rHelper.IsSpellWithDigits() && HasDigits( rWord ))
191 || (!rHelper.IsSpellCapitalization()
192 && nFailure == SpellFailure::CAPTION_ERROR)
194 nFailure = -1;
196 return nFailure == -1;
200 Reference< XSpellAlternatives >
201 SpellChecker::GetProposals( const OUString &rWord, const Locale &rLocale )
203 // Retrieves the return values for the 'spell' function call in case
204 // of a misspelled word.
205 // Especially it may give a list of suggested (correct) words:
206 // - a "liss" substring will be replaced by "liz".
207 // - 'x' or 'X' will be replaced by 'u' or 'U' for the first proposal
208 // and they will be removed from the word for the second proposal.
209 // - 's' or 'S' as first letter will be changed to the other caption.
211 Reference< XSpellAlternatives > xRes;
213 String aTmp( rWord );
214 if (aTmp.Len())
216 sal_Int16 nLang = LinguLocaleToLanguage( rLocale );
218 if (STRING_NOTFOUND != aTmp.SearchAscii( "liss" ))
220 aTmp.SearchAndReplaceAllAscii( "liss", "liz" );
221 xRes = new SpellAlternatives( aTmp, nLang,
222 SpellFailure::IS_NEGATIVE_WORD, ::com::sun::star::uno::Sequence< OUString >() );
224 else if (STRING_NOTFOUND != aTmp.Search( (sal_Unicode) 'x' ) ||
225 STRING_NOTFOUND != aTmp.Search( (sal_Unicode) 'X' ))
227 Sequence< OUString > aStr( 2 );
228 OUString *pStr = aStr.getArray();
229 String aAlt1( aTmp ),
230 aAlt2( aTmp );
231 aAlt1.SearchAndReplaceAll( (sal_Unicode) 'x', (sal_Unicode) 'u');
232 aAlt1.SearchAndReplaceAll( (sal_Unicode) 'X', (sal_Unicode) 'U');
233 aAlt2 = comphelper::string::remove(aAlt2, 'x');
234 aAlt2 = comphelper::string::remove(aAlt2, 'X');
235 pStr[0] = aAlt1;
236 pStr[1] = aAlt2;
238 SpellAlternatives *pAlt = new SpellAlternatives;
239 pAlt->SetWordLanguage( aTmp, nLang );
240 pAlt->SetFailureType( SpellFailure::SPELLING_ERROR );
241 pAlt->SetAlternatives( aStr );
243 xRes = pAlt;
245 else
247 sal_Unicode cChar = aTmp.GetChar( 0 );
248 if (cChar == (sal_Unicode) 's' || cChar == (sal_Unicode) 'S')
250 sal_Unicode cNewChar = cChar == (sal_Unicode) 's' ?
251 (sal_Unicode) 'S': (sal_Unicode) 's';
252 aTmp.GetBufferAccess()[0] = cNewChar;
253 xRes = new SpellAlternatives( aTmp, nLang,
254 SpellFailure::CAPTION_ERROR, ::com::sun::star::uno::Sequence< OUString >() );
259 return xRes;
263 Reference< XSpellAlternatives > SAL_CALL
264 SpellChecker::spell( const OUString& rWord, const Locale& rLocale,
265 const PropertyValues& rProperties )
266 throw(IllegalArgumentException, RuntimeException)
268 MutexGuard aGuard( GetLinguMutex() );
270 if (rLocale == Locale() || !rWord.getLength())
271 return NULL;
273 if (!hasLocale( rLocale ))
274 #ifdef LINGU_EXCEPTIONS
275 throw( IllegalArgumentException() );
276 #else
277 return NULL;
278 #endif
280 Reference< XSpellAlternatives > xAlt;
281 if (!isValid( rWord, rLocale, rProperties ))
283 xAlt = GetProposals( rWord, rLocale );
285 return xAlt;
289 Reference< XInterface > SAL_CALL SpellChecker_CreateInstance(
290 const Reference< XMultiServiceFactory > & )
291 throw(Exception)
293 Reference< XInterface > xService = (cppu::OWeakObject*) new SpellChecker;
294 return xService;
298 sal_Bool SAL_CALL
299 SpellChecker::addLinguServiceEventListener(
300 const Reference< XLinguServiceEventListener >& rxLstnr )
301 throw(RuntimeException)
303 MutexGuard aGuard( GetLinguMutex() );
305 sal_Bool bRes = sal_False;
306 if (!bDisposing && rxLstnr.is())
308 bRes = GetPropHelper().addLinguServiceEventListener( rxLstnr );
310 return bRes;
314 sal_Bool SAL_CALL
315 SpellChecker::removeLinguServiceEventListener(
316 const Reference< XLinguServiceEventListener >& rxLstnr )
317 throw(RuntimeException)
319 MutexGuard aGuard( GetLinguMutex() );
321 sal_Bool bRes = sal_False;
322 if (!bDisposing && rxLstnr.is())
324 DBG_ASSERT( xPropHelper.is(), "xPropHelper non existent" );
325 bRes = GetPropHelper().removeLinguServiceEventListener( rxLstnr );
327 return bRes;
331 OUString SAL_CALL
332 SpellChecker::getServiceDisplayName( const Locale& )
333 throw(RuntimeException)
335 MutexGuard aGuard( GetLinguMutex() );
336 return OUString( "OpenOffice example spellchecker" );
340 void SAL_CALL
341 SpellChecker::initialize( const Sequence< Any >& rArguments )
342 throw(Exception, RuntimeException)
344 MutexGuard aGuard( GetLinguMutex() );
346 if (!pPropHelper)
348 sal_Int32 nLen = rArguments.getLength();
349 if (2 == nLen)
351 Reference< XPropertySet > xPropSet;
352 rArguments.getConstArray()[0] >>= xPropSet;
354 //! Pointer allows for access of the non-UNO functions.
355 //! And the reference to the UNO-functions while increasing
356 //! the ref-count and will implicitly free the memory
357 //! when the object is not longer used.
358 pPropHelper = new PropertyHelper_Spell( (XSpellChecker *) this, xPropSet );
359 xPropHelper = pPropHelper;
360 pPropHelper->AddAsPropListener(); //! after a reference is established
362 else
363 OSL_FAIL( "wrong number of arguments in sequence" );
368 void SAL_CALL
369 SpellChecker::dispose()
370 throw(RuntimeException)
372 MutexGuard aGuard( GetLinguMutex() );
374 if (!bDisposing)
376 bDisposing = sal_True;
377 EventObject aEvtObj( (XSpellChecker *) this );
378 aEvtListeners.disposeAndClear( aEvtObj );
383 void SAL_CALL
384 SpellChecker::addEventListener( const Reference< XEventListener >& rxListener )
385 throw(RuntimeException)
387 MutexGuard aGuard( GetLinguMutex() );
389 if (!bDisposing && rxListener.is())
390 aEvtListeners.addInterface( rxListener );
394 void SAL_CALL
395 SpellChecker::removeEventListener( const Reference< XEventListener >& rxListener )
396 throw(RuntimeException)
398 MutexGuard aGuard( GetLinguMutex() );
400 if (!bDisposing && rxListener.is())
401 aEvtListeners.removeInterface( rxListener );
405 // Service specific part
407 OUString SAL_CALL SpellChecker::getImplementationName()
408 throw(RuntimeException)
410 MutexGuard aGuard( GetLinguMutex() );
411 return getImplementationName_Static();
415 sal_Bool SAL_CALL SpellChecker::supportsService( const OUString& ServiceName )
416 throw(RuntimeException)
418 MutexGuard aGuard( GetLinguMutex() );
420 Sequence< OUString > aSNL = getSupportedServiceNames();
421 const OUString * pArray = aSNL.getConstArray();
422 for( sal_Int32 i = 0; i < aSNL.getLength(); i++ )
423 if( pArray[i] == ServiceName )
424 return sal_True;
425 return sal_False;
429 Sequence< OUString > SAL_CALL SpellChecker::getSupportedServiceNames()
430 throw(RuntimeException)
432 MutexGuard aGuard( GetLinguMutex() );
433 return getSupportedServiceNames_Static();
437 Sequence< OUString > SpellChecker::getSupportedServiceNames_Static()
438 throw()
440 MutexGuard aGuard( GetLinguMutex() );
442 Sequence< OUString > aSNS( 1 ); // more than 1 service possible
443 aSNS.getArray()[0] = SN_SPELLCHECKER;
444 return aSNS;
448 sal_Bool SAL_CALL SpellChecker_writeInfo(
449 void * /*pServiceManager*/, registry::XRegistryKey * pRegistryKey )
453 OUString aImpl( "/" + SpellChecker::getImplementationName_Static().getStr() +
454 "/UNO/SERVICES" );
456 Reference< registry::XRegistryKey > xNewKey =
457 pRegistryKey->createKey( aImpl );
458 Sequence< OUString > aServices =
459 SpellChecker::getSupportedServiceNames_Static();
460 for( sal_Int32 i = 0; i < aServices.getLength(); i++ )
461 xNewKey->createKey( aServices.getConstArray()[i] );
463 return sal_True;
465 catch(Exception &)
467 return sal_False;
472 void * SAL_CALL SpellChecker_getFactory( const sal_Char * pImplName,
473 XMultiServiceFactory * pServiceManager, void * )
475 void * pRet = 0;
476 if ( !SpellChecker::getImplementationName_Static().compareToAscii( pImplName ) )
478 Reference< XSingleServiceFactory > xFactory =
479 cppu::createOneInstanceFactory(
480 pServiceManager,
481 SpellChecker::getImplementationName_Static(),
482 SpellChecker_CreateInstance,
483 SpellChecker::getSupportedServiceNames_Static());
484 // acquire, because we return an interface pointer instead of a reference
485 xFactory->acquire();
486 pRet = xFactory.get();
488 return pRet;
493 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */