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: spelldsp.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"
34 #include <com/sun/star/uno/Reference.h>
35 #include <com/sun/star/linguistic2/XSearchableDictionaryList.hpp>
36 #include <com/sun/star/linguistic2/SpellFailure.hpp>
37 #include <com/sun/star/registry/XRegistryKey.hpp>
39 #include <cppuhelper/factory.hxx> // helper for factories
40 #include <unotools/localedatawrapper.hxx>
41 #include <unotools/processfactory.hxx>
42 #include <tools/debug.hxx>
43 #include <svtools/lngmisc.hxx>
44 #include <osl/mutex.hxx>
48 #include "spelldsp.hxx"
49 #include "spelldta.hxx"
50 #include "lngsvcmgr.hxx"
51 #include "lngprops.hxx"
57 using namespace com::sun::star
;
58 using namespace com::sun::star::beans
;
59 using namespace com::sun::star::lang
;
60 using namespace com::sun::star::uno
;
61 using namespace com::sun::star::linguistic2
;
62 using namespace linguistic
;
64 ///////////////////////////////////////////////////////////////////////////
65 // ProposalList: list of proposals for misspelled words
66 // The order of strings in the array should be left unchanged because the
67 // spellchecker should have put the more likely suggestions at the top.
68 // New entries will be added to the end but duplicates are to be avoided.
69 // Removing entries is done by assigning the empty string.
70 // The sequence is constructed from all non empty strings in the original
71 // while maintaining the order.
75 std::vector
< OUString
> aVec
;
77 BOOL
HasEntry( const OUString
&rText
) const;
79 // make copy c-tor and assignment operator private
80 ProposalList( const ProposalList
& );
81 ProposalList
& operator = ( const ProposalList
& );
86 //size_t Size() const { return aVec.size(); }
88 void Prepend( const OUString
&rText
);
89 void Append( const OUString
&rNew
);
90 void Append( const std::vector
< OUString
> &rNew
);
91 void Append( const Sequence
< OUString
> &rNew
);
92 void Remove( const OUString
&rText
);
93 Sequence
< OUString
> GetSequence() const;
97 BOOL
ProposalList::HasEntry( const OUString
&rText
) const
100 size_t nCnt
= aVec
.size();
101 for (size_t i
= 0; !bFound
&& i
< nCnt
; ++i
)
103 if (aVec
[i
] == rText
)
109 void ProposalList::Prepend( const OUString
&rText
)
111 if (!HasEntry( rText
))
112 aVec
.insert( aVec
.begin(), rText
);
115 void ProposalList::Append( const OUString
&rText
)
117 if (!HasEntry( rText
))
118 aVec
.push_back( rText
);
121 void ProposalList::Append( const std::vector
< OUString
> &rNew
)
123 size_t nLen
= rNew
.size();
124 for ( size_t i
= 0; i
< nLen
; ++i
)
126 const OUString
&rText
= rNew
[i
];
127 if (!HasEntry( rText
))
132 void ProposalList::Append( const Sequence
< OUString
> &rNew
)
134 INT32 nLen
= rNew
.getLength();
135 const OUString
*pNew
= rNew
.getConstArray();
136 for (INT32 i
= 0; i
< nLen
; ++i
)
138 const OUString
&rText
= pNew
[i
];
139 if (!HasEntry( rText
))
144 size_t ProposalList::Count() const
146 // returns the number of non-empty strings in the vector
149 size_t nLen
= aVec
.size();
150 for (size_t i
= 0; i
< nLen
; ++i
)
152 if (aVec
[i
].getLength() != 0)
158 Sequence
< OUString
> ProposalList::GetSequence() const
160 INT32 nCount
= Count();
162 Sequence
< OUString
> aRes( nCount
);
163 OUString
*pRes
= aRes
.getArray();
164 INT32 nLen
= aVec
.size();
165 for (INT32 i
= 0; i
< nLen
; ++i
)
167 const OUString
&rText
= aVec
[i
];
168 DBG_ASSERT( nIdx
< nCount
, "index our of range" );
169 if (nIdx
< nCount
&& rText
.getLength() > 0)
170 pRes
[ nIdx
++ ] = rText
;
175 void ProposalList::Remove( const OUString
&rText
)
177 size_t nLen
= aVec
.size();
178 for (size_t i
= 0; i
< nLen
; ++i
)
180 OUString
&rEntry
= aVec
[i
];
184 break; // there should be only one matching entry
190 ///////////////////////////////////////////////////////////////////////////
192 BOOL
SvcListHasLanguage(
193 const LangSvcEntries_Spell
&rEntry
,
194 LanguageType nLanguage
)
196 BOOL bHasLanguage
= FALSE
;
199 const Reference
< XSpellChecker
> *pRef
= rEntry
.aSvcRefs
.getConstArray();
200 sal_Int32 nLen
= rEntry
.aSvcRefs
.getLength();
201 for (INT32 k
= 0; k
< nLen
&& !bHasLanguage
; ++k
)
205 if (0 == aTmpLocale
.Language
.getLength())
206 aTmpLocale
= CreateLocale( nLanguage
);
207 bHasLanguage
= pRef
[k
]->hasLocale( aTmpLocale
);
214 ///////////////////////////////////////////////////////////////////////////
217 SpellCheckerDispatcher::SpellCheckerDispatcher( LngSvcMgr
&rLngSvcMgr
) :
224 SpellCheckerDispatcher::~SpellCheckerDispatcher()
231 void SpellCheckerDispatcher::ClearSvcList()
233 // release memory for each table entry
234 SpellSvcByLangMap_t aTmp
;
235 aSvcMap
.swap( aTmp
);
239 Sequence
< Locale
> SAL_CALL
SpellCheckerDispatcher::getLocales()
240 throw(RuntimeException
)
242 MutexGuard
aGuard( GetLinguMutex() );
244 Sequence
< Locale
> aLocales( static_cast< sal_Int32
>(aSvcMap
.size()) );
245 Locale
*pLocales
= aLocales
.getArray();
246 SpellSvcByLangMap_t::const_iterator aIt
;
247 for (aIt
= aSvcMap
.begin(); aIt
!= aSvcMap
.end(); ++aIt
)
249 *pLocales
++ = CreateLocale( aIt
->first
);
255 sal_Bool SAL_CALL
SpellCheckerDispatcher::hasLocale( const Locale
& rLocale
)
256 throw(RuntimeException
)
258 MutexGuard
aGuard( GetLinguMutex() );
259 SpellSvcByLangMap_t::const_iterator
aIt( aSvcMap
.find( LocaleToLanguage( rLocale
) ) );
260 return aIt
!= aSvcMap
.end();
265 SpellCheckerDispatcher::isValid( const OUString
& rWord
, const Locale
& rLocale
,
266 const PropertyValues
& rProperties
)
267 throw(IllegalArgumentException
, RuntimeException
)
269 MutexGuard
aGuard( GetLinguMutex() );
270 return isValid_Impl( rWord
, LocaleToLanguage( rLocale
), rProperties
, TRUE
);
274 Reference
< XSpellAlternatives
> SAL_CALL
275 SpellCheckerDispatcher::spell( const OUString
& rWord
, const Locale
& rLocale
,
276 const PropertyValues
& rProperties
)
277 throw(IllegalArgumentException
, RuntimeException
)
279 MutexGuard
aGuard( GetLinguMutex() );
280 return spell_Impl( rWord
, LocaleToLanguage( rLocale
), rProperties
, TRUE
);
284 // returns the overall result of cross-checking with all user-dictionaries
285 // including the IgnoreAll list
286 static Reference
< XDictionaryEntry
> lcl_GetRulingDictionaryEntry(
287 const OUString
&rWord
,
288 LanguageType nLanguage
)
290 Reference
< XDictionaryEntry
> xRes
;
292 // the order of winning from top to bottom is:
293 // 1) IgnoreAll list will always win
294 // 2) Negative dictionaries will win over positive dictionaries
295 Reference
< XDictionary
> xIgnoreAll( GetIgnoreAllList() );
297 xRes
= xIgnoreAll
->getEntry( rWord
);
300 Reference
< XDictionaryList
> xDList( GetDictionaryList() );
301 Reference
< XDictionaryEntry
> xNegEntry( SearchDicList( xDList
,
302 rWord
, nLanguage
, FALSE
, TRUE
) );
307 Reference
< XDictionaryEntry
> xPosEntry( SearchDicList( xDList
,
308 rWord
, nLanguage
, TRUE
, TRUE
) );
318 BOOL
SpellCheckerDispatcher::isValid_Impl(
319 const OUString
& rWord
,
320 LanguageType nLanguage
,
321 const PropertyValues
& rProperties
,
323 throw( RuntimeException
, IllegalArgumentException
)
325 MutexGuard
aGuard( GetLinguMutex() );
329 if (nLanguage
== LANGUAGE_NONE
|| !rWord
.getLength())
332 // search for entry with that language
333 LangSvcEntries_Spell
*pEntry
= aSvcMap
[ nLanguage
].get();
337 #ifdef LINGU_EXCEPTIONS
338 throw IllegalArgumentException();
343 OUString
aChkWord( rWord
);
344 Locale
aLocale( CreateLocale( nLanguage
) );
346 // replace typographical apostroph by ascii apostroph
347 String
aSingleQuote( GetLocaleDataWrapper( nLanguage
).getQuotationMarkEnd() );
348 DBG_ASSERT( 1 == aSingleQuote
.Len(), "unexpectend length of quotation mark" );
349 if (aSingleQuote
.Len())
350 aChkWord
= aChkWord
.replace( aSingleQuote
.GetChar(0), '\'' );
352 RemoveHyphens( aChkWord
);
353 if (IsIgnoreControlChars( rProperties
, GetPropSet() ))
354 RemoveControlChars( aChkWord
);
356 INT32 nLen
= pEntry
->aSvcRefs
.getLength();
357 DBG_ASSERT( nLen
== pEntry
->aSvcImplNames
.getLength(),
358 "lng : sequence length mismatch");
359 DBG_ASSERT( pEntry
->nLastTriedSvcIndex
< nLen
,
360 "lng : index out of range");
364 BOOL bTmpResValid
= FALSE
;
366 // try already instantiated services first
368 const Reference
< XSpellChecker
> *pRef
=
369 pEntry
->aSvcRefs
.getConstArray();
370 while (i
<= pEntry
->nLastTriedSvcIndex
371 && (!bTmpResValid
|| FALSE
== bTmpRes
))
374 if (pRef
[i
].is() && pRef
[i
]->hasLocale( aLocale
))
376 bTmpRes
= GetCache().CheckWord( aChkWord
, nLanguage
);
379 bTmpRes
= pRef
[i
]->isValid( aChkWord
, aLocale
, rProperties
);
381 // Add correct words to the cache.
382 // But not those that are correct only because of
383 // the temporary supplied settings.
384 if (bTmpRes
&& 0 == rProperties
.getLength())
385 GetCache().AddWord( aChkWord
, nLanguage
);
389 bTmpResValid
= FALSE
;
398 // if still no result instantiate new services and try those
399 if ((!bTmpResValid
|| FALSE
== bTmpRes
)
400 && pEntry
->nLastTriedSvcIndex
< nLen
- 1)
402 const OUString
*pImplNames
= pEntry
->aSvcImplNames
.getConstArray();
403 Reference
< XSpellChecker
> *pRef
= pEntry
->aSvcRefs
.getArray();
405 Reference
< XMultiServiceFactory
> xMgr( getProcessServiceFactory() );
408 // build service initialization argument
409 Sequence
< Any
> aArgs(2);
410 aArgs
.getArray()[0] <<= GetPropSet();
411 //! The dispatcher searches the dictionary-list
412 //! thus the service needs not to now about it
413 //aArgs.getArray()[1] <<= GetDicList();
415 while (i
< nLen
&& (!bTmpResValid
|| FALSE
== bTmpRes
))
417 // create specific service via it's implementation name
418 Reference
< XSpellChecker
> xSpell
;
421 xSpell
= Reference
< XSpellChecker
>(
422 xMgr
->createInstanceWithArguments(
423 pImplNames
[i
], aArgs
), UNO_QUERY
);
425 catch (uno::Exception
&)
427 DBG_ASSERT( 0, "createInstanceWithArguments failed" );
431 Reference
< XLinguServiceEventBroadcaster
>
432 xBroadcaster( xSpell
, UNO_QUERY
);
433 if (xBroadcaster
.is())
434 rMgr
.AddLngSvcEvtBroadcaster( xBroadcaster
);
437 if (xSpell
.is() && xSpell
->hasLocale( aLocale
))
439 bTmpRes
= GetCache().CheckWord( aChkWord
, nLanguage
);
442 bTmpRes
= xSpell
->isValid( aChkWord
, aLocale
, rProperties
);
444 // Add correct words to the cache.
445 // But not those that are correct only because of
446 // the temporary supplied settings.
447 if (bTmpRes
&& 0 == rProperties
.getLength())
448 GetCache().AddWord( aChkWord
, nLanguage
);
452 bTmpResValid
= FALSE
;
457 pEntry
->nLastTriedSvcIndex
= (INT16
) i
;
461 // if language is not supported by any of the services
462 // remove it from the list.
465 if (!SvcListHasLanguage( *pEntry
, nLanguage
))
466 aSvcMap
.erase( nLanguage
);
471 // cross-check against results from dictionaries which have precedence!
473 GetDicList().is() && IsUseDicList( rProperties
, GetPropSet() ))
475 Reference
< XDictionaryEntry
> xTmp( lcl_GetRulingDictionaryEntry( aChkWord
, nLanguage
) );
477 bRes
= !xTmp
->isNegative();
485 Reference
< XSpellAlternatives
> SpellCheckerDispatcher::spell_Impl(
486 const OUString
& rWord
,
487 LanguageType nLanguage
,
488 const PropertyValues
& rProperties
,
490 throw(IllegalArgumentException
, RuntimeException
)
492 MutexGuard
aGuard( GetLinguMutex() );
494 Reference
< XSpellAlternatives
> xRes
;
496 if (nLanguage
== LANGUAGE_NONE
|| !rWord
.getLength())
499 // search for entry with that language
500 LangSvcEntries_Spell
*pEntry
= aSvcMap
[ nLanguage
].get();
504 #ifdef LINGU_EXCEPTIONS
505 throw IllegalArgumentException();
510 OUString
aChkWord( rWord
);
511 Locale
aLocale( CreateLocale( nLanguage
) );
513 // replace typographical apostroph by ascii apostroph
514 String
aSingleQuote( GetLocaleDataWrapper( nLanguage
).getQuotationMarkEnd() );
515 DBG_ASSERT( 1 == aSingleQuote
.Len(), "unexpectend length of quotation mark" );
516 if (aSingleQuote
.Len())
517 aChkWord
= aChkWord
.replace( aSingleQuote
.GetChar(0), '\'' );
519 RemoveHyphens( aChkWord
);
520 if (IsIgnoreControlChars( rProperties
, GetPropSet() ))
521 RemoveControlChars( aChkWord
);
523 INT32 nLen
= pEntry
->aSvcRefs
.getLength();
524 DBG_ASSERT( nLen
== pEntry
->aSvcImplNames
.getLength(),
525 "lng : sequence length mismatch");
526 DBG_ASSERT( pEntry
->nLastTriedSvcIndex
< nLen
,
527 "lng : index out of range");
530 Reference
< XSpellAlternatives
> xTmpRes
;
531 BOOL bTmpResValid
= FALSE
;
533 // try already instantiated services first
535 const Reference
< XSpellChecker
> *pRef
= pEntry
->aSvcRefs
.getConstArray();
536 sal_Int32 nNumSugestions
= -1;
537 while (i
<= pEntry
->nLastTriedSvcIndex
538 && (!bTmpResValid
|| xTmpRes
.is()) )
541 if (pRef
[i
].is() && pRef
[i
]->hasLocale( aLocale
))
543 BOOL bOK
= GetCache().CheckWord( aChkWord
, nLanguage
);
548 xTmpRes
= pRef
[i
]->spell( aChkWord
, aLocale
, rProperties
);
550 // Add correct words to the cache.
551 // But not those that are correct only because of
552 // the temporary supplied settings.
553 if (!xTmpRes
.is() && 0 == rProperties
.getLength())
554 GetCache().AddWord( aChkWord
, nLanguage
);
558 bTmpResValid
= FALSE
;
560 // return first found result if the word is not known by any checker.
561 // But if that result has no suggestions use the first one that does
562 // provide suggestions for the misspelled word.
563 if (!xRes
.is() && bTmpResValid
)
568 nNumSugestions
= xRes
->getAlternatives().getLength();
570 sal_Int32 nTmpNumSugestions
= 0;
571 if (xTmpRes
.is() && bTmpResValid
)
572 nTmpNumSugestions
= xTmpRes
->getAlternatives().getLength();
573 if (xRes
.is() && nNumSugestions
== 0 && nTmpNumSugestions
> 0)
576 nNumSugestions
= nTmpNumSugestions
;
583 // if still no result instantiate new services and try those
584 if ((!bTmpResValid
|| xTmpRes
.is())
585 && pEntry
->nLastTriedSvcIndex
< nLen
- 1)
587 const OUString
*pImplNames
= pEntry
->aSvcImplNames
.getConstArray();
588 Reference
< XSpellChecker
> *pRef
= pEntry
->aSvcRefs
.getArray();
590 Reference
< XMultiServiceFactory
> xMgr( getProcessServiceFactory() );
593 // build service initialization argument
594 Sequence
< Any
> aArgs(2);
595 aArgs
.getArray()[0] <<= GetPropSet();
596 //! The dispatcher searches the dictionary-list
597 //! thus the service needs not to now about it
598 //aArgs.getArray()[1] <<= GetDicList();
600 sal_Int32 nNumSugestions
= -1;
601 while (i
< nLen
&& (!bTmpResValid
|| xTmpRes
.is()))
603 // create specific service via it's implementation name
604 Reference
< XSpellChecker
> xSpell
;
607 xSpell
= Reference
< XSpellChecker
>(
608 xMgr
->createInstanceWithArguments(
609 pImplNames
[i
], aArgs
), UNO_QUERY
);
611 catch (uno::Exception
&)
613 DBG_ASSERT( 0, "createInstanceWithArguments failed" );
617 Reference
< XLinguServiceEventBroadcaster
>
618 xBroadcaster( xSpell
, UNO_QUERY
);
619 if (xBroadcaster
.is())
620 rMgr
.AddLngSvcEvtBroadcaster( xBroadcaster
);
623 if (xSpell
.is() && xSpell
->hasLocale( aLocale
))
625 BOOL bOK
= GetCache().CheckWord( aChkWord
, nLanguage
);
630 xTmpRes
= xSpell
->spell( aChkWord
, aLocale
, rProperties
);
632 // Add correct words to the cache.
633 // But not those that are correct only because of
634 // the temporary supplied settings.
635 if (!xTmpRes
.is() && 0 == rProperties
.getLength())
636 GetCache().AddWord( aChkWord
, nLanguage
);
640 bTmpResValid
= FALSE
;
642 // return first found result if the word is not known by any checker.
643 // But if that result has no suggestions use the first one that does
644 // provide suggestions for the misspelled word.
645 if (!xRes
.is() && bTmpResValid
)
650 nNumSugestions
= xRes
->getAlternatives().getLength();
652 sal_Int32 nTmpNumSugestions
= 0;
653 if (xTmpRes
.is() && bTmpResValid
)
654 nTmpNumSugestions
= xTmpRes
->getAlternatives().getLength();
655 if (xRes
.is() && nNumSugestions
== 0 && nTmpNumSugestions
> 0)
658 nNumSugestions
= nTmpNumSugestions
;
661 pEntry
->nLastTriedSvcIndex
= (INT16
) i
;
665 // if language is not supported by any of the services
666 // remove it from the list.
669 if (!SvcListHasLanguage( *pEntry
, nLanguage
))
670 aSvcMap
.erase( nLanguage
);
675 // if word is finally found to be correct
676 // clear previously remembered alternatives
677 if (bTmpResValid
&& !xTmpRes
.is())
680 // list of proposals found (to be checked against entries of
681 // neagtive dictionaries)
682 ProposalList aProposalList
;
683 // Sequence< OUString > aProposals;
684 INT16 eFailureType
= -1; // no failure
687 aProposalList
.Append( xRes
->getAlternatives() );
688 // aProposals = xRes->getAlternatives();
689 eFailureType
= xRes
->getFailureType();
691 Reference
< XDictionaryList
> xDList
;
692 if (GetDicList().is() && IsUseDicList( rProperties
, GetPropSet() ))
693 xDList
= Reference
< XDictionaryList
>( GetDicList(), UNO_QUERY
);
695 // cross-check against results from user-dictionaries which have precedence!
696 if (bCheckDics
&& xDList
.is())
698 Reference
< XDictionaryEntry
> xTmp( lcl_GetRulingDictionaryEntry( aChkWord
, nLanguage
) );
701 if (xTmp
->isNegative()) // positive entry found
703 eFailureType
= SpellFailure::IS_NEGATIVE_WORD
;
705 // replacement text to be added to suggestions, if not empty
706 OUString
aAddRplcTxt( xTmp
->getReplacementText() );
708 // replacement text must not be in negative dictionary itself
709 if (aAddRplcTxt
.getLength() &&
710 !SearchDicList( xDList
, aAddRplcTxt
, nLanguage
, FALSE
, TRUE
).is())
712 aProposalList
.Prepend( aAddRplcTxt
);
715 else // positive entry found
718 eFailureType
= -1; // no failure
723 if (eFailureType
!= -1) // word misspelled or found in negative user-dictionary
725 // search suitable user-dictionaries for suggestions that are
726 // similar to the misspelled word
727 std::vector
< OUString
> aDicListProps
; // list of proposals from user-dictionaries
728 SearchSimilarText( aChkWord
, nLanguage
, xDList
, aDicListProps
);
729 aProposalList
.Append( aDicListProps
);
730 Sequence
< OUString
> aProposals
= aProposalList
.GetSequence();
732 // remove entries listed in negative dictionaries
733 // (we don't want to display suggestions that will be regarded as misspelledlater on)
734 if (bCheckDics
&& xDList
.is())
735 SeqRemoveNegEntries( aProposals
, xDList
, nLanguage
);
737 uno::Reference
< linguistic2::XSetSpellAlternatives
> xSetAlt( xRes
, uno::UNO_QUERY
);
740 xSetAlt
->setAlternatives( aProposals
);
741 xSetAlt
->setFailureType( eFailureType
);
747 DBG_ASSERT( 0, "XSetSpellAlternatives not implemented!" );
749 else if (aProposals
.getLength() > 0)
751 // no xRes but Proposals found from the user-dictionaries.
752 // Thus we need to create an xRes...
753 xRes
= new linguistic::SpellAlternatives( rWord
, nLanguage
,
754 SpellFailure::IS_NEGATIVE_WORD
, aProposals
);
763 uno::Sequence
< sal_Int16
> SAL_CALL
SpellCheckerDispatcher::getLanguages( )
764 throw (uno::RuntimeException
)
766 MutexGuard
aGuard( GetLinguMutex() );
767 uno::Sequence
< Locale
> aTmp( getLocales() );
768 uno::Sequence
< INT16
> aRes( LocaleSeqToLangSeq( aTmp
) );
773 sal_Bool SAL_CALL
SpellCheckerDispatcher::hasLanguage(
774 sal_Int16 nLanguage
)
775 throw (uno::RuntimeException
)
777 MutexGuard
aGuard( GetLinguMutex() );
778 Locale
aLocale( CreateLocale( nLanguage
) );
779 return hasLocale( aLocale
);
783 sal_Bool SAL_CALL
SpellCheckerDispatcher::isValid(
784 const OUString
& rWord
,
786 const uno::Sequence
< beans::PropertyValue
>& rProperties
)
787 throw (lang::IllegalArgumentException
, uno::RuntimeException
)
789 MutexGuard
aGuard( GetLinguMutex() );
790 Locale
aLocale( CreateLocale( nLanguage
) );
791 return isValid( rWord
, aLocale
, rProperties
);
795 uno::Reference
< linguistic2::XSpellAlternatives
> SAL_CALL
SpellCheckerDispatcher::spell(
796 const OUString
& rWord
,
798 const uno::Sequence
< beans::PropertyValue
>& rProperties
)
799 throw (lang::IllegalArgumentException
, uno::RuntimeException
)
801 MutexGuard
aGuard( GetLinguMutex() );
802 Locale
aLocale( CreateLocale( nLanguage
) );
803 return spell( rWord
, aLocale
, rProperties
);
807 void SpellCheckerDispatcher::SetServiceList( const Locale
&rLocale
,
808 const Sequence
< OUString
> &rSvcImplNames
)
810 MutexGuard
aGuard( GetLinguMutex() );
813 pCache
->Flush(); // new services may spell differently...
815 INT16 nLanguage
= LocaleToLanguage( rLocale
);
817 INT32 nLen
= rSvcImplNames
.getLength();
820 aSvcMap
.erase( nLanguage
);
824 LangSvcEntries_Spell
*pEntry
= aSvcMap
[ nLanguage
].get();
828 pEntry
->aSvcImplNames
= rSvcImplNames
;
829 pEntry
->aSvcRefs
= Sequence
< Reference
< XSpellChecker
> > ( nLen
);
833 boost::shared_ptr
< LangSvcEntries_Spell
> pTmpEntry( new LangSvcEntries_Spell( rSvcImplNames
) );
834 pTmpEntry
->aSvcRefs
= Sequence
< Reference
< XSpellChecker
> >( nLen
);
835 aSvcMap
[ nLanguage
] = pTmpEntry
;
842 SpellCheckerDispatcher::GetServiceList( const Locale
&rLocale
) const
844 MutexGuard
aGuard( GetLinguMutex() );
846 Sequence
< OUString
> aRes
;
848 // search for entry with that language and use data from that
849 INT16 nLanguage
= LocaleToLanguage( rLocale
);
850 SpellCheckerDispatcher
*pThis
= (SpellCheckerDispatcher
*) this;
851 const LangSvcEntries_Spell
*pEntry
= pThis
->aSvcMap
[ nLanguage
].get();
853 aRes
= pEntry
->aSvcImplNames
;
859 LinguDispatcher::DspType
SpellCheckerDispatcher::GetDspType() const
864 void SpellCheckerDispatcher::FlushSpellCache()
870 ///////////////////////////////////////////////////////////////////////////