calc: on editing invalidation of view with different zoom is wrong
[LibreOffice.git] / linguistic / workben / sspellimp.cxx
blob04c5d03d6263a9cc6f616ddc26e7fcd8664c3539
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 <cppuhelper/factory.hxx>
25 #include <cppuhelper/supportsservice.hxx>
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;
44 sal_Bool operator == ( const Locale &rL1, const Locale &rL2 )
46 return rL1.Language == rL2.Language &&
47 rL1.Country == rL2.Country &&
48 rL1.Variant == rL2.Variant;
52 SpellChecker::SpellChecker() :
53 aEvtListeners ( GetLinguMutex() ),
54 pPropHelper(NULL),
55 bDisposing(sal_False)
60 SpellChecker::~SpellChecker()
62 if (pPropHelper)
63 pPropHelper->RemoveAsPropListener();
67 PropertyHelper_Spell & SpellChecker::GetPropHelper_Impl()
69 if (!pPropHelper)
71 Reference< XLinguProperties > xPropSet = GetLinguProperties();
73 pPropHelper = new PropertyHelper_Spell( (XSpellChecker *) this, xPropSet );
74 xPropHelper = pPropHelper;
75 pPropHelper->AddAsPropListener(); //! after a reference is established
77 return *pPropHelper;
81 Sequence< Locale > SAL_CALL SpellChecker::getLocales()
82 throw(RuntimeException)
84 MutexGuard aGuard( GetLinguMutex() );
86 if (!aSuppLocales.getLength())
88 aSuppLocales.realloc( 3 );
89 Locale *pLocale = aSuppLocales.getArray();
90 pLocale[0] = Locale( "en", "US", OUString() );
91 pLocale[1] = Locale( "de", "DE", OUString() );
92 pLocale[2] = Locale( "de", "CH", OUString() );
95 return aSuppLocales;
99 sal_Bool SAL_CALL SpellChecker::hasLocale(const Locale& rLocale)
100 throw(RuntimeException)
102 MutexGuard aGuard( GetLinguMutex() );
104 sal_Bool bRes = sal_False;
105 if (!aSuppLocales.getLength())
106 getLocales();
107 sal_Int32 nLen = aSuppLocales.getLength();
108 for (sal_Int32 i = 0; i < nLen; ++i)
110 const Locale *pLocale = aSuppLocales.getConstArray();
111 if (rLocale == pLocale[i])
113 bRes = sal_True;
114 break;
117 return bRes;
121 sal_Int16 SpellChecker::GetSpellFailure( const OUString &rWord, const Locale & )
123 // Checks whether a word is OK in a given language (Locale) or not, and
124 // provides a failure type for the incorrect ones.
125 // - words with "liss" (case sensitive) as substring will be negative.
126 // - words with 'x' or 'X' will have incorrect spelling.
127 // - words with 's' or 'S' as first letter will have the wrong caption.
128 // - all other words will be OK.
130 sal_Int16 nRes = -1;
132 String aTmp( rWord );
133 if (aTmp.Len())
135 if (-1 != aTmp.indexOf( "liss" ))
137 nRes = SpellFailure::IS_NEGATIVE_WORD;
139 else if (-1 != aTmp.indexOf( 'x' ) ||
140 -1 != aTmp.indexOf( 'X' ))
142 nRes = SpellFailure::SPELLING_ERROR;
144 else
146 sal_Unicode cChar = aTmp.GetChar( 0 );
147 if (cChar == 's' || cChar == 'S')
148 nRes = SpellFailure::CAPTION_ERROR;
152 return nRes;
156 sal_Bool SAL_CALL
157 SpellChecker::isValid( const OUString& rWord, const Locale& rLocale,
158 const PropertyValues& rProperties )
159 throw(IllegalArgumentException, RuntimeException)
161 MutexGuard aGuard( GetLinguMutex() );
163 if (rLocale == Locale() || !rWord.getLength())
164 return sal_True;
166 if (!hasLocale( rLocale ))
167 #ifdef LINGU_EXCEPTIONS
168 throw( IllegalArgumentException() );
169 #else
170 return sal_True;
171 #endif
173 // Get property values to be used.
174 // These are be the default values set in the SN_LINGU_PROPERTIES
175 // PropertySet which are overridden by the supplied ones from the
176 // last argument.
177 // You'll probably like to use a simpler solution than the provided
178 // one using the PropertyHelper_Spell.
179 PropertyHelper_Spell &rHelper = GetPropHelper();
180 rHelper.SetTmpPropVals( rProperties );
182 sal_Int16 nFailure = GetSpellFailure( rWord, rLocale );
183 if (nFailure != -1)
185 sal_Int16 nLang = LinguLocaleToLanguage( rLocale );
186 // postprocess result for errors that should be ignored
187 if ( (!rHelper.IsSpellUpperCase() && IsUpper( rWord, nLang ))
188 || (!rHelper.IsSpellWithDigits() && HasDigits( rWord ))
189 || (!rHelper.IsSpellCapitalization()
190 && nFailure == SpellFailure::CAPTION_ERROR)
192 nFailure = -1;
194 return nFailure == -1;
198 Reference< XSpellAlternatives >
199 SpellChecker::GetProposals( const OUString &rWord, const Locale &rLocale )
201 // Retrieves the return values for the 'spell' function call in case
202 // of a misspelled word.
203 // Especially it may give a list of suggested (correct) words:
204 // - a "liss" substring will be replaced by "liz".
205 // - 'x' or 'X' will be replaced by 'u' or 'U' for the first proposal
206 // and they will be removed from the word for the second proposal.
207 // - 's' or 'S' as first letter will be changed to the other caption.
209 Reference< XSpellAlternatives > xRes;
211 String aTmp( rWord );
212 if (aTmp.Len())
214 sal_Int16 nLang = LinguLocaleToLanguage( rLocale );
216 if (-1 != aTmp.indexOf( "liss" ))
218 aTmp.SearchAndReplaceAllAscii( "liss", "liz" );
219 xRes = new SpellAlternatives( aTmp, nLang,
220 SpellFailure::IS_NEGATIVE_WORD, css::uno::Sequence< OUString >() );
222 else if (-1 != aTmp.indexOf( 'x' ) ||
223 -1 != aTmp.indexOf( 'X' ))
225 Sequence< OUString > aStr( 2 );
226 OUString *pStr = aStr.getArray();
227 String aAlt1( aTmp ),
228 aAlt2( aTmp );
229 aAlt1.SearchAndReplaceAll( 'x', 'u');
230 aAlt1.SearchAndReplaceAll( 'X', 'U');
231 aAlt2 = aAlt2.replaceAll("x", "").replaceAll("X", "");
232 pStr[0] = aAlt1;
233 pStr[1] = aAlt2;
235 SpellAlternatives *pAlt = new SpellAlternatives;
236 pAlt->SetWordLanguage( aTmp, nLang );
237 pAlt->SetFailureType( SpellFailure::SPELLING_ERROR );
238 pAlt->SetAlternatives( aStr );
240 xRes = pAlt;
242 else
244 sal_Unicode cChar = aTmp.GetChar( 0 );
245 if (cChar == 's' || cChar == 'S')
247 sal_Unicode cNewChar = cChar == 's' ?
248 'S': 's';
249 aTmp.GetBufferAccess()[0] = cNewChar;
250 xRes = new SpellAlternatives( aTmp, nLang,
251 SpellFailure::CAPTION_ERROR, css::uno::Sequence< OUString >() );
256 return xRes;
260 Reference< XSpellAlternatives > SAL_CALL
261 SpellChecker::spell( const OUString& rWord, const Locale& rLocale,
262 const PropertyValues& rProperties )
263 throw(IllegalArgumentException, RuntimeException)
265 MutexGuard aGuard( GetLinguMutex() );
267 if (rLocale == Locale() || !rWord.getLength())
268 return NULL;
270 if (!hasLocale( rLocale ))
271 #ifdef LINGU_EXCEPTIONS
272 throw( IllegalArgumentException() );
273 #else
274 return NULL;
275 #endif
277 Reference< XSpellAlternatives > xAlt;
278 if (!isValid( rWord, rLocale, rProperties ))
280 xAlt = GetProposals( rWord, rLocale );
282 return xAlt;
286 Reference< XInterface > SAL_CALL SpellChecker_CreateInstance(
287 const Reference< XMultiServiceFactory > & )
288 throw(Exception)
290 Reference< XInterface > xService = (cppu::OWeakObject*) new SpellChecker;
291 return xService;
295 sal_Bool SAL_CALL
296 SpellChecker::addLinguServiceEventListener(
297 const Reference< XLinguServiceEventListener >& rxLstnr )
298 throw(RuntimeException)
300 MutexGuard aGuard( GetLinguMutex() );
302 sal_Bool bRes = sal_False;
303 if (!bDisposing && rxLstnr.is())
305 bRes = GetPropHelper().addLinguServiceEventListener( rxLstnr );
307 return bRes;
311 sal_Bool SAL_CALL
312 SpellChecker::removeLinguServiceEventListener(
313 const Reference< XLinguServiceEventListener >& rxLstnr )
314 throw(RuntimeException)
316 MutexGuard aGuard( GetLinguMutex() );
318 sal_Bool bRes = sal_False;
319 if (!bDisposing && rxLstnr.is())
321 DBG_ASSERT( xPropHelper.is(), "xPropHelper non existent" );
322 bRes = GetPropHelper().removeLinguServiceEventListener( rxLstnr );
324 return bRes;
328 OUString SAL_CALL
329 SpellChecker::getServiceDisplayName( const Locale& )
330 throw(RuntimeException)
332 MutexGuard aGuard( GetLinguMutex() );
333 return OUString( "OpenOffice example spellchecker" );
337 void SAL_CALL
338 SpellChecker::initialize( const Sequence< Any >& rArguments )
339 throw(Exception, RuntimeException)
341 MutexGuard aGuard( GetLinguMutex() );
343 if (!pPropHelper)
345 sal_Int32 nLen = rArguments.getLength();
346 if (2 == nLen)
348 Reference< XPropertySet > xPropSet;
349 rArguments.getConstArray()[0] >>= xPropSet;
351 //! Pointer allows for access of the non-UNO functions.
352 //! And the reference to the UNO-functions while increasing
353 //! the ref-count and will implicitly free the memory
354 //! when the object is no longer used.
355 pPropHelper = new PropertyHelper_Spell( (XSpellChecker *) this, xPropSet );
356 xPropHelper = pPropHelper;
357 pPropHelper->AddAsPropListener(); //! after a reference is established
359 else
360 OSL_FAIL( "wrong number of arguments in sequence" );
365 void SAL_CALL
366 SpellChecker::dispose()
367 throw(RuntimeException)
369 MutexGuard aGuard( GetLinguMutex() );
371 if (!bDisposing)
373 bDisposing = sal_True;
374 EventObject aEvtObj( (XSpellChecker *) this );
375 aEvtListeners.disposeAndClear( aEvtObj );
380 void SAL_CALL
381 SpellChecker::addEventListener( const Reference< XEventListener >& rxListener )
382 throw(RuntimeException)
384 MutexGuard aGuard( GetLinguMutex() );
386 if (!bDisposing && rxListener.is())
387 aEvtListeners.addInterface( rxListener );
391 void SAL_CALL
392 SpellChecker::removeEventListener( const Reference< XEventListener >& rxListener )
393 throw(RuntimeException)
395 MutexGuard aGuard( GetLinguMutex() );
397 if (!bDisposing && rxListener.is())
398 aEvtListeners.removeInterface( rxListener );
402 // Service specific part
404 OUString SAL_CALL SpellChecker::getImplementationName()
405 throw(RuntimeException)
407 return getImplementationName_Static();
411 sal_Bool SAL_CALL SpellChecker::supportsService( const OUString& ServiceName )
412 throw(RuntimeException)
414 return cppu::supportsService(this, ServiceName);
417 Sequence< OUString > SAL_CALL SpellChecker::getSupportedServiceNames()
418 throw(RuntimeException)
420 return getSupportedServiceNames_Static();
424 Sequence< OUString > SpellChecker::getSupportedServiceNames_Static()
425 throw()
427 Sequence< OUString > aSNS { SN_SPELLCHECKER };
428 return aSNS;
432 sal_Bool SAL_CALL SpellChecker_writeInfo(
433 void * /*pServiceManager*/, registry::XRegistryKey * pRegistryKey )
437 OUString aImpl( "/" + SpellChecker::getImplementationName_Static().getStr() +
438 "/UNO/SERVICES" );
440 Reference< registry::XRegistryKey > xNewKey =
441 pRegistryKey->createKey( aImpl );
442 Sequence< OUString > aServices =
443 SpellChecker::getSupportedServiceNames_Static();
444 for( sal_Int32 i = 0; i < aServices.getLength(); i++ )
445 xNewKey->createKey( aServices.getConstArray()[i] );
447 return sal_True;
449 catch(Exception &)
451 return sal_False;
456 void * SAL_CALL SpellChecker_getFactory( const char * pImplName,
457 XMultiServiceFactory * pServiceManager, void * )
459 void * pRet = 0;
460 if ( SpellChecker::getImplementationName_Static().equalsAscii( pImplName ) )
462 Reference< XSingleServiceFactory > xFactory =
463 cppu::createOneInstanceFactory(
464 pServiceManager,
465 SpellChecker::getImplementationName_Static(),
466 SpellChecker_CreateInstance,
467 SpellChecker::getSupportedServiceNames_Static());
468 // acquire, because we return an interface pointer instead of a reference
469 xFactory->acquire();
470 pRet = xFactory.get();
472 return pRet;
476 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */