Version 3.6.0.4, tag libreoffice-3.6.0.4
[LibreOffice.git] / linguistic / workben / sspellimp.cxx
blobe281f1f88d159091720b2dc95eccd63128442e52
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*************************************************************************
4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 * Copyright 2000, 2010 Oracle and/or its affiliates.
8 * OpenOffice.org - a multi-platform office productivity suite
10 * This file is part of OpenOffice.org.
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.
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).
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.
27 ************************************************************************/
29 #include <com/sun/star/uno/Reference.h>
30 #include <com/sun/star/linguistic2/XSearchableDictionaryList.hpp>
31 #include <com/sun/star/linguistic2/SpellFailure.hpp>
32 #include <com/sun/star/registry/XRegistryKey.hpp>
33 #include <comphelper/string.hxx>
34 #include <cppuhelper/factory.hxx> // helper for factories
35 #include <tools/debug.hxx>
36 #include <osl/mutex.hxx>
38 #include <sspellimp.hxx>
40 #include "linguistic/lngprops.hxx"
41 #include "linguistic/spelldta.hxx"
43 using namespace utl;
44 using namespace osl;
45 using namespace com::sun::star;
46 using namespace com::sun::star::beans;
47 using namespace com::sun::star::lang;
48 using namespace com::sun::star::uno;
49 using namespace com::sun::star::linguistic2;
50 using namespace linguistic;
52 using ::rtl::OUString;
55 sal_Bool operator == ( const Locale &rL1, const Locale &rL2 )
57 return rL1.Language == rL2.Language &&
58 rL1.Country == rL2.Country &&
59 rL1.Variant == rL2.Variant;
64 SpellChecker::SpellChecker() :
65 aEvtListeners ( GetLinguMutex() )
67 bDisposing = sal_False;
68 pPropHelper = NULL;
72 SpellChecker::~SpellChecker()
74 if (pPropHelper)
75 pPropHelper->RemoveAsPropListener();
79 PropertyHelper_Spell & SpellChecker::GetPropHelper_Impl()
81 if (!pPropHelper)
83 Reference< XPropertySet > xPropSet( GetLinguProperties(), UNO_QUERY );
85 pPropHelper = new PropertyHelper_Spell( (XSpellChecker *) this, xPropSet );
86 xPropHelper = pPropHelper;
87 pPropHelper->AddAsPropListener(); //! after a reference is established
89 return *pPropHelper;
93 Sequence< Locale > SAL_CALL SpellChecker::getLocales()
94 throw(RuntimeException)
96 MutexGuard aGuard( GetLinguMutex() );
98 if (!aSuppLocales.getLength())
100 aSuppLocales.realloc( 3 );
101 Locale *pLocale = aSuppLocales.getArray();
102 pLocale[0] = Locale( A2OU("en"), A2OU("US"), OUString() );
103 pLocale[1] = Locale( A2OU("de"), A2OU("DE"), OUString() );
104 pLocale[2] = Locale( A2OU("de"), A2OU("CH"), OUString() );
107 return aSuppLocales;
111 sal_Bool SAL_CALL SpellChecker::hasLocale(const Locale& rLocale)
112 throw(RuntimeException)
114 MutexGuard aGuard( GetLinguMutex() );
116 sal_Bool bRes = sal_False;
117 if (!aSuppLocales.getLength())
118 getLocales();
119 sal_Int32 nLen = aSuppLocales.getLength();
120 for (sal_Int32 i = 0; i < nLen; ++i)
122 const Locale *pLocale = aSuppLocales.getConstArray();
123 if (rLocale == pLocale[i])
125 bRes = sal_True;
126 break;
129 return bRes;
133 sal_Int16 SpellChecker::GetSpellFailure( const OUString &rWord, const Locale & )
135 // Checks whether a word is OK in a given language (Locale) or not, and
136 // provides a failure type for the incorrect ones.
137 // - words with "liss" (case sensitiv) as substring will be negative.
138 // - words with 'x' or 'X' will have incorrect spelling.
139 // - words with 's' or 'S' as first letter will have the wrong caption.
140 // - all other words will be OK.
142 sal_Int16 nRes = -1;
144 String aTmp( rWord );
145 if (aTmp.Len())
147 if (STRING_NOTFOUND != aTmp.SearchAscii( "liss" ))
149 nRes = SpellFailure::IS_NEGATIVE_WORD;
151 else if (STRING_NOTFOUND != aTmp.Search( (sal_Unicode) 'x' ) ||
152 STRING_NOTFOUND != aTmp.Search( (sal_Unicode) 'X' ))
154 nRes = SpellFailure::SPELLING_ERROR;
156 else
158 sal_Unicode cChar = aTmp.GetChar( 0 );
159 if (cChar == (sal_Unicode) 's' || cChar == (sal_Unicode) 'S')
160 nRes = SpellFailure::CAPTION_ERROR;
164 return nRes;
168 sal_Bool SAL_CALL
169 SpellChecker::isValid( const OUString& rWord, const Locale& rLocale,
170 const PropertyValues& rProperties )
171 throw(IllegalArgumentException, RuntimeException)
173 MutexGuard aGuard( GetLinguMutex() );
175 if (rLocale == Locale() || !rWord.getLength())
176 return sal_True;
178 if (!hasLocale( rLocale ))
179 #ifdef LINGU_EXCEPTIONS
180 throw( IllegalArgumentException() );
181 #else
182 return sal_True;
183 #endif
185 // Get property values to be used.
186 // These are be the default values set in the SN_LINGU_PROPERTIES
187 // PropertySet which are overridden by the supplied ones from the
188 // last argument.
189 // You'll probably like to use a simplier solution than the provided
190 // one using the PropertyHelper_Spell.
191 PropertyHelper_Spell &rHelper = GetPropHelper();
192 rHelper.SetTmpPropVals( rProperties );
194 sal_Int16 nFailure = GetSpellFailure( rWord, rLocale );
195 if (nFailure != -1)
197 sal_Int16 nLang = LocaleToLanguage( rLocale );
198 // postprocess result for errors that should be ignored
199 if ( (!rHelper.IsSpellUpperCase() && IsUpper( rWord, nLang ))
200 || (!rHelper.IsSpellWithDigits() && HasDigits( rWord ))
201 || (!rHelper.IsSpellCapitalization()
202 && nFailure == SpellFailure::CAPTION_ERROR)
204 nFailure = -1;
206 return nFailure == -1;
210 Reference< XSpellAlternatives >
211 SpellChecker::GetProposals( const OUString &rWord, const Locale &rLocale )
213 // Retrieves the return values for the 'spell' function call in case
214 // of a misspelled word.
215 // Especially it may give a list of suggested (correct) words:
216 // - a "liss" substring will be replaced by "liz".
217 // - 'x' or 'X' will be replaced by 'u' or 'U' for the first proposal
218 // and they will be removed from the word for the second proposal.
219 // - 's' or 'S' as first letter will be changed to the other caption.
221 Reference< XSpellAlternatives > xRes;
223 String aTmp( rWord );
224 if (aTmp.Len())
226 sal_Int16 nLang = LocaleToLanguage( rLocale );
228 if (STRING_NOTFOUND != aTmp.SearchAscii( "liss" ))
230 aTmp.SearchAndReplaceAllAscii( "liss", A2OU("liz") );
231 xRes = new SpellAlternatives( aTmp, nLang,
232 SpellFailure::IS_NEGATIVE_WORD, ::com::sun::star::uno::Sequence< ::rtl::OUString >() );
234 else if (STRING_NOTFOUND != aTmp.Search( (sal_Unicode) 'x' ) ||
235 STRING_NOTFOUND != aTmp.Search( (sal_Unicode) 'X' ))
237 Sequence< OUString > aStr( 2 );
238 OUString *pStr = aStr.getArray();
239 String aAlt1( aTmp ),
240 aAlt2( aTmp );
241 aAlt1.SearchAndReplaceAll( (sal_Unicode) 'x', (sal_Unicode) 'u');
242 aAlt1.SearchAndReplaceAll( (sal_Unicode) 'X', (sal_Unicode) 'U');
243 aAlt2 = comphelper::string::remove(aAlt2, 'x');
244 aAlt2 = comphelper::string::remove(aAlt2, 'X');
245 pStr[0] = aAlt1;
246 pStr[1] = aAlt2;
248 SpellAlternatives *pAlt = new SpellAlternatives;
249 pAlt->SetWordLanguage( aTmp, nLang );
250 pAlt->SetFailureType( SpellFailure::SPELLING_ERROR );
251 pAlt->SetAlternatives( aStr );
253 xRes = pAlt;
255 else
257 sal_Unicode cChar = aTmp.GetChar( 0 );
258 if (cChar == (sal_Unicode) 's' || cChar == (sal_Unicode) 'S')
260 sal_Unicode cNewChar = cChar == (sal_Unicode) 's' ?
261 (sal_Unicode) 'S': (sal_Unicode) 's';
262 aTmp.GetBufferAccess()[0] = cNewChar;
263 xRes = new SpellAlternatives( aTmp, nLang,
264 SpellFailure::CAPTION_ERROR, ::com::sun::star::uno::Sequence< ::rtl::OUString >() );
269 return xRes;
273 Reference< XSpellAlternatives > SAL_CALL
274 SpellChecker::spell( const OUString& rWord, const Locale& rLocale,
275 const PropertyValues& rProperties )
276 throw(IllegalArgumentException, RuntimeException)
278 MutexGuard aGuard( GetLinguMutex() );
280 if (rLocale == Locale() || !rWord.getLength())
281 return NULL;
283 if (!hasLocale( rLocale ))
284 #ifdef LINGU_EXCEPTIONS
285 throw( IllegalArgumentException() );
286 #else
287 return NULL;
288 #endif
290 Reference< XSpellAlternatives > xAlt;
291 if (!isValid( rWord, rLocale, rProperties ))
293 xAlt = GetProposals( rWord, rLocale );
295 return xAlt;
299 Reference< XInterface > SAL_CALL SpellChecker_CreateInstance(
300 const Reference< XMultiServiceFactory > & )
301 throw(Exception)
303 Reference< XInterface > xService = (cppu::OWeakObject*) new SpellChecker;
304 return xService;
308 sal_Bool SAL_CALL
309 SpellChecker::addLinguServiceEventListener(
310 const Reference< XLinguServiceEventListener >& rxLstnr )
311 throw(RuntimeException)
313 MutexGuard aGuard( GetLinguMutex() );
315 sal_Bool bRes = sal_False;
316 if (!bDisposing && rxLstnr.is())
318 bRes = GetPropHelper().addLinguServiceEventListener( rxLstnr );
320 return bRes;
324 sal_Bool SAL_CALL
325 SpellChecker::removeLinguServiceEventListener(
326 const Reference< XLinguServiceEventListener >& rxLstnr )
327 throw(RuntimeException)
329 MutexGuard aGuard( GetLinguMutex() );
331 sal_Bool bRes = sal_False;
332 if (!bDisposing && rxLstnr.is())
334 DBG_ASSERT( xPropHelper.is(), "xPropHelper non existent" );
335 bRes = GetPropHelper().removeLinguServiceEventListener( rxLstnr );
337 return bRes;
341 OUString SAL_CALL
342 SpellChecker::getServiceDisplayName( const Locale& )
343 throw(RuntimeException)
345 MutexGuard aGuard( GetLinguMutex() );
346 return A2OU( "OpenOffice example spellchecker" );
350 void SAL_CALL
351 SpellChecker::initialize( const Sequence< Any >& rArguments )
352 throw(Exception, RuntimeException)
354 MutexGuard aGuard( GetLinguMutex() );
356 if (!pPropHelper)
358 sal_Int32 nLen = rArguments.getLength();
359 if (2 == nLen)
361 Reference< XPropertySet > xPropSet;
362 rArguments.getConstArray()[0] >>= xPropSet;
364 //! Pointer allows for access of the non-UNO functions.
365 //! And the reference to the UNO-functions while increasing
366 //! the ref-count and will implicitly free the memory
367 //! when the object is not longer used.
368 pPropHelper = new PropertyHelper_Spell( (XSpellChecker *) this, xPropSet );
369 xPropHelper = pPropHelper;
370 pPropHelper->AddAsPropListener(); //! after a reference is established
372 else
373 OSL_FAIL( "wrong number of arguments in sequence" );
378 void SAL_CALL
379 SpellChecker::dispose()
380 throw(RuntimeException)
382 MutexGuard aGuard( GetLinguMutex() );
384 if (!bDisposing)
386 bDisposing = sal_True;
387 EventObject aEvtObj( (XSpellChecker *) this );
388 aEvtListeners.disposeAndClear( aEvtObj );
393 void SAL_CALL
394 SpellChecker::addEventListener( const Reference< XEventListener >& rxListener )
395 throw(RuntimeException)
397 MutexGuard aGuard( GetLinguMutex() );
399 if (!bDisposing && rxListener.is())
400 aEvtListeners.addInterface( rxListener );
404 void SAL_CALL
405 SpellChecker::removeEventListener( const Reference< XEventListener >& rxListener )
406 throw(RuntimeException)
408 MutexGuard aGuard( GetLinguMutex() );
410 if (!bDisposing && rxListener.is())
411 aEvtListeners.removeInterface( rxListener );
415 // Service specific part
417 OUString SAL_CALL SpellChecker::getImplementationName()
418 throw(RuntimeException)
420 MutexGuard aGuard( GetLinguMutex() );
421 return getImplementationName_Static();
425 sal_Bool SAL_CALL SpellChecker::supportsService( const OUString& ServiceName )
426 throw(RuntimeException)
428 MutexGuard aGuard( GetLinguMutex() );
430 Sequence< OUString > aSNL = getSupportedServiceNames();
431 const OUString * pArray = aSNL.getConstArray();
432 for( sal_Int32 i = 0; i < aSNL.getLength(); i++ )
433 if( pArray[i] == ServiceName )
434 return sal_True;
435 return sal_False;
439 Sequence< OUString > SAL_CALL SpellChecker::getSupportedServiceNames()
440 throw(RuntimeException)
442 MutexGuard aGuard( GetLinguMutex() );
443 return getSupportedServiceNames_Static();
447 Sequence< OUString > SpellChecker::getSupportedServiceNames_Static()
448 throw()
450 MutexGuard aGuard( GetLinguMutex() );
452 Sequence< OUString > aSNS( 1 ); // more than 1 service possible
453 aSNS.getArray()[0] = A2OU( SN_SPELLCHECKER );
454 return aSNS;
458 sal_Bool SAL_CALL SpellChecker_writeInfo(
459 void * /*pServiceManager*/, registry::XRegistryKey * pRegistryKey )
463 String aImpl( '/' );
464 aImpl += SpellChecker::getImplementationName_Static().getStr();
465 aImpl.AppendAscii( "/UNO/SERVICES" );
466 Reference< registry::XRegistryKey > xNewKey =
467 pRegistryKey->createKey( aImpl );
468 Sequence< OUString > aServices =
469 SpellChecker::getSupportedServiceNames_Static();
470 for( sal_Int32 i = 0; i < aServices.getLength(); i++ )
471 xNewKey->createKey( aServices.getConstArray()[i] );
473 return sal_True;
475 catch(Exception &)
477 return sal_False;
482 void * SAL_CALL SpellChecker_getFactory( const sal_Char * pImplName,
483 XMultiServiceFactory * pServiceManager, void * )
485 void * pRet = 0;
486 if ( !SpellChecker::getImplementationName_Static().compareToAscii( pImplName ) )
488 Reference< XSingleServiceFactory > xFactory =
489 cppu::createOneInstanceFactory(
490 pServiceManager,
491 SpellChecker::getImplementationName_Static(),
492 SpellChecker_CreateInstance,
493 SpellChecker::getSupportedServiceNames_Static());
494 // acquire, because we return an interface pointer instead of a reference
495 xFactory->acquire();
496 pRet = xFactory.get();
498 return pRet;
503 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */