update dev300-m58
[ooovba.git] / linguistic / workben / sspellimp.cxx
blob8cc3bfd8c1b3444805f6e37e01c814b36ad63e32
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: sspellimp.cxx,v $
10 * $Revision: 1.5 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_linguistic.hxx"
33 #include <com/sun/star/uno/Reference.h>
34 #include <com/sun/star/linguistic2/XSearchableDictionaryList.hpp>
36 #include <com/sun/star/linguistic2/SpellFailure.hpp>
37 #include <cppuhelper/factory.hxx> // helper for factories
38 #include <com/sun/star/registry/XRegistryKey.hpp>
39 #include <tools/debug.hxx>
40 #include <unotools/processfactory.hxx>
41 #include <osl/mutex.hxx>
43 #ifndef _SPELLIMP_HXX
44 #include <sspellimp.hxx>
45 #endif
47 #include "lngprops.hxx"
48 #include "spelldta.hxx"
50 using namespace utl;
51 using namespace osl;
52 using namespace rtl;
53 using namespace com::sun::star;
54 using namespace com::sun::star::beans;
55 using namespace com::sun::star::lang;
56 using namespace com::sun::star::uno;
57 using namespace com::sun::star::linguistic2;
58 using namespace linguistic;
61 ///////////////////////////////////////////////////////////////////////////
63 BOOL operator == ( const Locale &rL1, const Locale &rL2 )
65 return rL1.Language == rL2.Language &&
66 rL1.Country == rL2.Country &&
67 rL1.Variant == rL2.Variant;
70 ///////////////////////////////////////////////////////////////////////////
73 SpellChecker::SpellChecker() :
74 aEvtListeners ( GetLinguMutex() )
76 bDisposing = FALSE;
77 pPropHelper = NULL;
81 SpellChecker::~SpellChecker()
83 if (pPropHelper)
84 pPropHelper->RemoveAsPropListener();
88 PropertyHelper_Spell & SpellChecker::GetPropHelper_Impl()
90 if (!pPropHelper)
92 Reference< XPropertySet > xPropSet( GetLinguProperties(), UNO_QUERY );
94 pPropHelper = new PropertyHelper_Spell( (XSpellChecker *) this, xPropSet );
95 xPropHelper = pPropHelper;
96 pPropHelper->AddAsPropListener(); //! after a reference is established
98 return *pPropHelper;
102 Sequence< Locale > SAL_CALL SpellChecker::getLocales()
103 throw(RuntimeException)
105 MutexGuard aGuard( GetLinguMutex() );
107 if (!aSuppLocales.getLength())
109 aSuppLocales.realloc( 3 );
110 Locale *pLocale = aSuppLocales.getArray();
111 pLocale[0] = Locale( A2OU("en"), A2OU("US"), OUString() );
112 pLocale[1] = Locale( A2OU("de"), A2OU("DE"), OUString() );
113 pLocale[2] = Locale( A2OU("de"), A2OU("CH"), OUString() );
116 return aSuppLocales;
120 sal_Bool SAL_CALL SpellChecker::hasLocale(const Locale& rLocale)
121 throw(RuntimeException)
123 MutexGuard aGuard( GetLinguMutex() );
125 BOOL bRes = FALSE;
126 if (!aSuppLocales.getLength())
127 getLocales();
128 INT32 nLen = aSuppLocales.getLength();
129 for (INT32 i = 0; i < nLen; ++i)
131 const Locale *pLocale = aSuppLocales.getConstArray();
132 if (rLocale == pLocale[i])
134 bRes = TRUE;
135 break;
138 return bRes;
142 INT16 SpellChecker::GetSpellFailure( const OUString &rWord, const Locale &rLocale )
144 // Checks wether a word is OK in a given language (Locale) or not, and
145 // provides a failure type for the incorrect ones.
146 // - words with "liss" (case sensitiv) as substring will be negative.
147 // - words with 'x' or 'X' will have incorrect spelling.
148 // - words with 's' or 'S' as first letter will have the wrong caption.
149 // - all other words will be OK.
151 INT16 nRes = -1;
153 String aTmp( rWord );
154 if (aTmp.Len())
156 if (STRING_NOTFOUND != aTmp.SearchAscii( "liss" ))
158 nRes = SpellFailure::IS_NEGATIVE_WORD;
160 else if (STRING_NOTFOUND != aTmp.Search( (sal_Unicode) 'x' ) ||
161 STRING_NOTFOUND != aTmp.Search( (sal_Unicode) 'X' ))
163 nRes = SpellFailure::SPELLING_ERROR;
165 else
167 sal_Unicode cChar = aTmp.GetChar( 0 );
168 if (cChar == (sal_Unicode) 's' || cChar == (sal_Unicode) 'S')
169 nRes = SpellFailure::CAPTION_ERROR;
173 return nRes;
177 sal_Bool SAL_CALL
178 SpellChecker::isValid( const OUString& rWord, const Locale& rLocale,
179 const PropertyValues& rProperties )
180 throw(IllegalArgumentException, RuntimeException)
182 MutexGuard aGuard( GetLinguMutex() );
184 if (rLocale == Locale() || !rWord.getLength())
185 return TRUE;
187 if (!hasLocale( rLocale ))
188 #ifdef LINGU_EXCEPTIONS
189 throw( IllegalArgumentException() );
190 #else
191 return TRUE;
192 #endif
194 // Get property values to be used.
195 // These are be the default values set in the SN_LINGU_PROPERTIES
196 // PropertySet which are overridden by the supplied ones from the
197 // last argument.
198 // You'll probably like to use a simplier solution than the provided
199 // one using the PropertyHelper_Spell.
200 PropertyHelper_Spell &rHelper = GetPropHelper();
201 rHelper.SetTmpPropVals( rProperties );
203 INT16 nFailure = GetSpellFailure( rWord, rLocale );
204 if (nFailure != -1)
206 INT16 nLang = LocaleToLanguage( rLocale );
207 // postprocess result for errors that should be ignored
208 if ( (!rHelper.IsSpellUpperCase() && IsUpper( rWord, nLang ))
209 || (!rHelper.IsSpellWithDigits() && HasDigits( rWord ))
210 || (!rHelper.IsSpellCapitalization()
211 && nFailure == SpellFailure::CAPTION_ERROR)
213 nFailure = -1;
215 return nFailure == -1;
219 Reference< XSpellAlternatives >
220 SpellChecker::GetProposals( const OUString &rWord, const Locale &rLocale )
222 // Retrieves the return values for the 'spell' function call in case
223 // of a misspelled word.
224 // Especially it may give a list of suggested (correct) words:
225 // - a "liss" substring will be replaced by "liz".
226 // - 'x' or 'X' will be replaced by 'u' or 'U' for the first proposal
227 // and they will be removed from the word for the second proposal.
228 // - 's' or 'S' as first letter will be changed to the other caption.
230 Reference< XSpellAlternatives > xRes;
232 String aTmp( rWord );
233 if (aTmp.Len())
235 INT16 nLang = LocaleToLanguage( rLocale );
237 if (STRING_NOTFOUND != aTmp.SearchAscii( "liss" ))
239 aTmp.SearchAndReplaceAllAscii( "liss", A2OU("liz") );
240 xRes = new SpellAlternatives( aTmp, nLang,
241 SpellFailure::IS_NEGATIVE_WORD, aTmp );
243 else if (STRING_NOTFOUND != aTmp.Search( (sal_Unicode) 'x' ) ||
244 STRING_NOTFOUND != aTmp.Search( (sal_Unicode) 'X' ))
246 Sequence< OUString > aStr( 2 );
247 OUString *pStr = aStr.getArray();
248 String aAlt1( aTmp ),
249 aAlt2( aTmp );
250 aAlt1.SearchAndReplaceAll( (sal_Unicode) 'x', (sal_Unicode) 'u');
251 aAlt1.SearchAndReplaceAll( (sal_Unicode) 'X', (sal_Unicode) 'U');
252 aAlt2.EraseAllChars( (sal_Unicode) 'x' );
253 aAlt2.EraseAllChars( (sal_Unicode) 'X' );
254 pStr[0] = aAlt1;
255 pStr[1] = aAlt2;
257 SpellAlternatives *pAlt = new SpellAlternatives;
258 pAlt->SetWordLanguage( aTmp, nLang );
259 pAlt->SetFailureType( SpellFailure::SPELLING_ERROR );
260 pAlt->SetAlternatives( aStr );
262 xRes = pAlt;
264 else
266 sal_Unicode cChar = aTmp.GetChar( 0 );
267 if (cChar == (sal_Unicode) 's' || cChar == (sal_Unicode) 'S')
269 sal_Unicode cNewChar = cChar == (sal_Unicode) 's' ?
270 (sal_Unicode) 'S': (sal_Unicode) 's';
271 aTmp.GetBufferAccess()[0] = cNewChar;
272 xRes = new SpellAlternatives( aTmp, nLang,
273 SpellFailure::CAPTION_ERROR, aTmp );
278 return xRes;
282 Reference< XSpellAlternatives > SAL_CALL
283 SpellChecker::spell( const OUString& rWord, const Locale& rLocale,
284 const PropertyValues& rProperties )
285 throw(IllegalArgumentException, RuntimeException)
287 MutexGuard aGuard( GetLinguMutex() );
289 if (rLocale == Locale() || !rWord.getLength())
290 return NULL;
292 if (!hasLocale( rLocale ))
293 #ifdef LINGU_EXCEPTIONS
294 throw( IllegalArgumentException() );
295 #else
296 return NULL;
297 #endif
299 Reference< XSpellAlternatives > xAlt;
300 if (!isValid( rWord, rLocale, rProperties ))
302 xAlt = GetProposals( rWord, rLocale );
304 return xAlt;
308 Reference< XInterface > SAL_CALL SpellChecker_CreateInstance(
309 const Reference< XMultiServiceFactory > & rSMgr )
310 throw(Exception)
312 Reference< XInterface > xService = (cppu::OWeakObject*) new SpellChecker;
313 return xService;
317 sal_Bool SAL_CALL
318 SpellChecker::addLinguServiceEventListener(
319 const Reference< XLinguServiceEventListener >& rxLstnr )
320 throw(RuntimeException)
322 MutexGuard aGuard( GetLinguMutex() );
324 BOOL bRes = FALSE;
325 if (!bDisposing && rxLstnr.is())
327 bRes = GetPropHelper().addLinguServiceEventListener( rxLstnr );
329 return bRes;
333 sal_Bool SAL_CALL
334 SpellChecker::removeLinguServiceEventListener(
335 const Reference< XLinguServiceEventListener >& rxLstnr )
336 throw(RuntimeException)
338 MutexGuard aGuard( GetLinguMutex() );
340 BOOL bRes = FALSE;
341 if (!bDisposing && rxLstnr.is())
343 DBG_ASSERT( xPropHelper.is(), "xPropHelper non existent" );
344 bRes = GetPropHelper().removeLinguServiceEventListener( rxLstnr );
346 return bRes;
350 OUString SAL_CALL
351 SpellChecker::getServiceDisplayName( const Locale& rLocale )
352 throw(RuntimeException)
354 MutexGuard aGuard( GetLinguMutex() );
355 return A2OU( "OpenOffice example spellchecker" );
359 void SAL_CALL
360 SpellChecker::initialize( const Sequence< Any >& rArguments )
361 throw(Exception, RuntimeException)
363 MutexGuard aGuard( GetLinguMutex() );
365 if (!pPropHelper)
367 INT32 nLen = rArguments.getLength();
368 if (2 == nLen)
370 Reference< XPropertySet > xPropSet;
371 rArguments.getConstArray()[0] >>= xPropSet;
372 //rArguments.getConstArray()[1] >>= xDicList;
374 //! Pointer allows for access of the non-UNO functions.
375 //! And the reference to the UNO-functions while increasing
376 //! the ref-count and will implicitly free the memory
377 //! when the object is not longer used.
378 pPropHelper = new PropertyHelper_Spell( (XSpellChecker *) this, xPropSet );
379 xPropHelper = pPropHelper;
380 pPropHelper->AddAsPropListener(); //! after a reference is established
382 else
383 DBG_ERROR( "wrong number of arguments in sequence" );
388 void SAL_CALL
389 SpellChecker::dispose()
390 throw(RuntimeException)
392 MutexGuard aGuard( GetLinguMutex() );
394 if (!bDisposing)
396 bDisposing = TRUE;
397 EventObject aEvtObj( (XSpellChecker *) this );
398 aEvtListeners.disposeAndClear( aEvtObj );
403 void SAL_CALL
404 SpellChecker::addEventListener( const Reference< XEventListener >& rxListener )
405 throw(RuntimeException)
407 MutexGuard aGuard( GetLinguMutex() );
409 if (!bDisposing && rxListener.is())
410 aEvtListeners.addInterface( rxListener );
414 void SAL_CALL
415 SpellChecker::removeEventListener( const Reference< XEventListener >& rxListener )
416 throw(RuntimeException)
418 MutexGuard aGuard( GetLinguMutex() );
420 if (!bDisposing && rxListener.is())
421 aEvtListeners.removeInterface( rxListener );
425 ///////////////////////////////////////////////////////////////////////////
426 // Service specific part
429 OUString SAL_CALL SpellChecker::getImplementationName()
430 throw(RuntimeException)
432 MutexGuard aGuard( GetLinguMutex() );
433 return getImplementationName_Static();
437 sal_Bool SAL_CALL SpellChecker::supportsService( const OUString& ServiceName )
438 throw(RuntimeException)
440 MutexGuard aGuard( GetLinguMutex() );
442 Sequence< OUString > aSNL = getSupportedServiceNames();
443 const OUString * pArray = aSNL.getConstArray();
444 for( INT32 i = 0; i < aSNL.getLength(); i++ )
445 if( pArray[i] == ServiceName )
446 return TRUE;
447 return FALSE;
451 Sequence< OUString > SAL_CALL SpellChecker::getSupportedServiceNames()
452 throw(RuntimeException)
454 MutexGuard aGuard( GetLinguMutex() );
455 return getSupportedServiceNames_Static();
459 Sequence< OUString > SpellChecker::getSupportedServiceNames_Static()
460 throw()
462 MutexGuard aGuard( GetLinguMutex() );
464 Sequence< OUString > aSNS( 1 ); // auch mehr als 1 Service moeglich
465 aSNS.getArray()[0] = A2OU( SN_SPELLCHECKER );
466 return aSNS;
470 sal_Bool SAL_CALL SpellChecker_writeInfo(
471 void * /*pServiceManager*/, registry::XRegistryKey * pRegistryKey )
475 String aImpl( '/' );
476 aImpl += SpellChecker::getImplementationName_Static().getStr();
477 aImpl.AppendAscii( "/UNO/SERVICES" );
478 Reference< registry::XRegistryKey > xNewKey =
479 pRegistryKey->createKey( aImpl );
480 Sequence< OUString > aServices =
481 SpellChecker::getSupportedServiceNames_Static();
482 for( INT32 i = 0; i < aServices.getLength(); i++ )
483 xNewKey->createKey( aServices.getConstArray()[i] );
485 return sal_True;
487 catch(Exception &)
489 return sal_False;
494 void * SAL_CALL SpellChecker_getFactory( const sal_Char * pImplName,
495 XMultiServiceFactory * pServiceManager, void * )
497 void * pRet = 0;
498 if ( !SpellChecker::getImplementationName_Static().compareToAscii( pImplName ) )
500 Reference< XSingleServiceFactory > xFactory =
501 cppu::createOneInstanceFactory(
502 pServiceManager,
503 SpellChecker::getImplementationName_Static(),
504 SpellChecker_CreateInstance,
505 SpellChecker::getSupportedServiceNames_Static());
506 // acquire, because we return an interface pointer instead of a reference
507 xFactory->acquire();
508 pRet = xFactory.get();
510 return pRet;
514 ///////////////////////////////////////////////////////////////////////////