1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: sspellimp.cxx,v $
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>
44 #include <sspellimp.hxx>
47 #include "lngprops.hxx"
48 #include "spelldta.hxx"
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() )
81 SpellChecker::~SpellChecker()
84 pPropHelper
->RemoveAsPropListener();
88 PropertyHelper_Spell
& SpellChecker::GetPropHelper_Impl()
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
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() );
120 sal_Bool SAL_CALL
SpellChecker::hasLocale(const Locale
& rLocale
)
121 throw(RuntimeException
)
123 MutexGuard
aGuard( GetLinguMutex() );
126 if (!aSuppLocales
.getLength())
128 INT32 nLen
= aSuppLocales
.getLength();
129 for (INT32 i
= 0; i
< nLen
; ++i
)
131 const Locale
*pLocale
= aSuppLocales
.getConstArray();
132 if (rLocale
== pLocale
[i
])
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.
153 String
aTmp( rWord
);
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
;
167 sal_Unicode cChar
= aTmp
.GetChar( 0 );
168 if (cChar
== (sal_Unicode
) 's' || cChar
== (sal_Unicode
) 'S')
169 nRes
= SpellFailure::CAPTION_ERROR
;
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())
187 if (!hasLocale( rLocale
))
188 #ifdef LINGU_EXCEPTIONS
189 throw( IllegalArgumentException() );
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
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
);
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
)
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
);
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
),
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' );
257 SpellAlternatives
*pAlt
= new SpellAlternatives
;
258 pAlt
->SetWordLanguage( aTmp
, nLang
);
259 pAlt
->SetFailureType( SpellFailure::SPELLING_ERROR
);
260 pAlt
->SetAlternatives( aStr
);
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
);
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())
292 if (!hasLocale( rLocale
))
293 #ifdef LINGU_EXCEPTIONS
294 throw( IllegalArgumentException() );
299 Reference
< XSpellAlternatives
> xAlt
;
300 if (!isValid( rWord
, rLocale
, rProperties
))
302 xAlt
= GetProposals( rWord
, rLocale
);
308 Reference
< XInterface
> SAL_CALL
SpellChecker_CreateInstance(
309 const Reference
< XMultiServiceFactory
> & rSMgr
)
312 Reference
< XInterface
> xService
= (cppu::OWeakObject
*) new SpellChecker
;
318 SpellChecker::addLinguServiceEventListener(
319 const Reference
< XLinguServiceEventListener
>& rxLstnr
)
320 throw(RuntimeException
)
322 MutexGuard
aGuard( GetLinguMutex() );
325 if (!bDisposing
&& rxLstnr
.is())
327 bRes
= GetPropHelper().addLinguServiceEventListener( rxLstnr
);
334 SpellChecker::removeLinguServiceEventListener(
335 const Reference
< XLinguServiceEventListener
>& rxLstnr
)
336 throw(RuntimeException
)
338 MutexGuard
aGuard( GetLinguMutex() );
341 if (!bDisposing
&& rxLstnr
.is())
343 DBG_ASSERT( xPropHelper
.is(), "xPropHelper non existent" );
344 bRes
= GetPropHelper().removeLinguServiceEventListener( rxLstnr
);
351 SpellChecker::getServiceDisplayName( const Locale
& rLocale
)
352 throw(RuntimeException
)
354 MutexGuard
aGuard( GetLinguMutex() );
355 return A2OU( "OpenOffice example spellchecker" );
360 SpellChecker::initialize( const Sequence
< Any
>& rArguments
)
361 throw(Exception
, RuntimeException
)
363 MutexGuard
aGuard( GetLinguMutex() );
367 INT32 nLen
= rArguments
.getLength();
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
383 DBG_ERROR( "wrong number of arguments in sequence" );
389 SpellChecker::dispose()
390 throw(RuntimeException
)
392 MutexGuard
aGuard( GetLinguMutex() );
397 EventObject
aEvtObj( (XSpellChecker
*) this );
398 aEvtListeners
.disposeAndClear( aEvtObj
);
404 SpellChecker::addEventListener( const Reference
< XEventListener
>& rxListener
)
405 throw(RuntimeException
)
407 MutexGuard
aGuard( GetLinguMutex() );
409 if (!bDisposing
&& rxListener
.is())
410 aEvtListeners
.addInterface( rxListener
);
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
)
451 Sequence
< OUString
> SAL_CALL
SpellChecker::getSupportedServiceNames()
452 throw(RuntimeException
)
454 MutexGuard
aGuard( GetLinguMutex() );
455 return getSupportedServiceNames_Static();
459 Sequence
< OUString
> SpellChecker::getSupportedServiceNames_Static()
462 MutexGuard
aGuard( GetLinguMutex() );
464 Sequence
< OUString
> aSNS( 1 ); // auch mehr als 1 Service moeglich
465 aSNS
.getArray()[0] = A2OU( SN_SPELLCHECKER
);
470 sal_Bool SAL_CALL
SpellChecker_writeInfo(
471 void * /*pServiceManager*/, registry::XRegistryKey
* pRegistryKey
)
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
] );
494 void * SAL_CALL
SpellChecker_getFactory( const sal_Char
* pImplName
,
495 XMultiServiceFactory
* pServiceManager
, void * )
498 if ( !SpellChecker::getImplementationName_Static().compareToAscii( pImplName
) )
500 Reference
< XSingleServiceFactory
> xFactory
=
501 cppu::createOneInstanceFactory(
503 SpellChecker::getImplementationName_Static(),
504 SpellChecker_CreateInstance
,
505 SpellChecker::getSupportedServiceNames_Static());
506 // acquire, because we return an interface pointer instead of a reference
508 pRet
= xFactory
.get();
514 ///////////////////////////////////////////////////////////////////////////