diff --git a/include/linguistic/misc.hxx b/include/linguistic/misc.hxx index bc9a777dd4fa..f2db0d3ad5ed 100644 --- a/include/linguistic/misc.hxx +++ b/include/linguistic/misc.hxx @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -45,7 +46,6 @@ namespace osl { class Mutex; } class CharClass; class LocaleDataWrapper; - inline constexpr OUString SN_GRAMMARCHECKER = u"com.sun.star.linguistic2.Proofreader"_ustr; inline constexpr OUString SN_SPELLCHECKER = u"com.sun.star.linguistic2.SpellChecker"_ustr; inline constexpr OUString SN_HYPHENATOR = u"com.sun.star.linguistic2.Hyphenator"_ustr; @@ -54,6 +54,7 @@ inline constexpr OUString SN_THESAURUS = u"com.sun.star.linguistic2.Thesaurus"_u namespace linguistic { +class HyphenatedWord; // AddEntryToDic return values @@ -122,7 +123,7 @@ LNG_DLLPUBLIC OUString GetWritableDictionaryURL( std::u16string_view rDicName ) LNG_DLLPUBLIC sal_Int32 GetPosInWordToCheck( std::u16string_view rTxt, sal_Int32 nPos ); -css::uno::Reference< css::linguistic2::XHyphenatedWord > +rtl::Reference< HyphenatedWord > RebuildHyphensAndControlChars( const OUString &rOrigWord, css::uno::Reference< css::linguistic2::XHyphenatedWord > const &rxHyphWord ); diff --git a/linguistic/source/hyphdsp.cxx b/linguistic/source/hyphdsp.cxx index ee45990351bc..eaf49579339a 100644 --- a/linguistic/source/hyphdsp.cxx +++ b/linguistic/source/hyphdsp.cxx @@ -72,172 +72,169 @@ void HyphenatorDispatcher::ClearSvcList() } -Reference HyphenatorDispatcher::buildHyphWord( +rtl::Reference< HyphenatedWord > HyphenatorDispatcher::buildHyphWord( const OUString& rOrigWord, const Reference &xEntry, LanguageType nLang, sal_Int16 nMaxLeading ) { MutexGuard aGuard( GetLinguMutex() ); - Reference< XHyphenatedWord > xRes; + if (!xEntry.is()) + return nullptr; - if (xEntry.is()) + OUString aText( xEntry->getDictionaryWord() ); + sal_Int32 nTextLen = aText.getLength(); + + // trailing '=' means "hyphenation should not be possible" + if (nTextLen <= 0 || aText[ nTextLen - 1 ] == '=' || aText[ nTextLen - 1 ] == '[') + return nullptr; + + sal_Int16 nHyphenationPos = -1; + sal_Int16 nOrigHyphPos = -1; + + OUStringBuffer aTmp( nTextLen ); + bool bSkip = false; + bool bSkip2 = false; + sal_Int32 nHyphIdx = -1; + sal_Int32 nLeading = 0; + for (sal_Int32 i = 0; i < nTextLen; i++) { - OUString aText( xEntry->getDictionaryWord() ); - sal_Int32 nTextLen = aText.getLength(); - - // trailing '=' means "hyphenation should not be possible" - if (nTextLen > 0 && aText[ nTextLen - 1 ] != '=' && aText[ nTextLen - 1 ] != '[') + sal_Unicode cTmp = aText[i]; + if (cTmp == '[' || cTmp == ']') + bSkip2 = !bSkip2; + if (cTmp != '=' && !bSkip2 && cTmp != ']') { - sal_Int16 nHyphenationPos = -1; - sal_Int16 nOrigHyphPos = -1; - - OUStringBuffer aTmp( nTextLen ); - bool bSkip = false; - bool bSkip2 = false; - sal_Int32 nHyphIdx = -1; - sal_Int32 nLeading = 0; - for (sal_Int32 i = 0; i < nTextLen; i++) + aTmp.append( cTmp ); + nLeading++; + bSkip = false; + nHyphIdx++; + } + else + { + if (!bSkip && nHyphIdx >= 0) { - sal_Unicode cTmp = aText[i]; - if (cTmp == '[' || cTmp == ']') - bSkip2 = !bSkip2; - if (cTmp != '=' && !bSkip2 && cTmp != ']') - { - aTmp.append( cTmp ); - nLeading++; - bSkip = false; - nHyphIdx++; - } - else - { - if (!bSkip && nHyphIdx >= 0) - { - if (nLeading <= nMaxLeading) { - nHyphenationPos = static_cast(nHyphIdx); - nOrigHyphPos = i; - } - } - bSkip = true; //! multiple '=' should count as one only + if (nLeading <= nMaxLeading) { + nHyphenationPos = static_cast(nHyphIdx); + nOrigHyphPos = i; } } + bSkip = true; //! multiple '=' should count as one only + } + } + + if (nHyphenationPos <= 0) + return nullptr; - if (nHyphenationPos > 0) - { #if OSL_DEBUG_LEVEL > 0 - { - if (std::u16string_view(aTmp) != rOrigWord) - { - // both words should only differ by a having a trailing '.' - // character or not... - std::u16string_view aShorter(aTmp), aLonger(rOrigWord); - if (aTmp.getLength() > rOrigWord.getLength()) - std::swap(aShorter, aLonger); - sal_Int32 nS = aShorter.size(); - sal_Int32 nL = aLonger.size(); - if (nS > 0 && nL > 0) - { - assert( ((nS + 1 == nL) && aLonger[nL-1] == '.') && "HyphenatorDispatcher::buildHyphWord: unexpected difference between words!" ); - } - } - } -#endif - sal_Int32 nHyphenPos = -1; - if (aText[ nOrigHyphPos ] == '[') // alternative hyphenation - { - sal_Int16 split = 0; - sal_Unicode c = aText [ nOrigHyphPos + 1 ]; - sal_Int32 endhyphpat = aText.indexOf( ']', nOrigHyphPos ); - if ('0' <= c && c <= '9') - { - split = c - '0'; - nOrigHyphPos++; - } - if (endhyphpat > -1) - { - OUStringBuffer aTmp2 ( aTmp.copy(0, std::max (nHyphenationPos + 1 - split, 0) ) ); - aTmp2.append( aText.subView( nOrigHyphPos + 1, endhyphpat - nOrigHyphPos - 1) ); - nHyphenPos = aTmp2.getLength(); - aTmp2.append( aTmp.subView( nHyphenationPos + 1 ) ); - //! take care of #i22591# - if (rOrigWord[ rOrigWord.getLength() - 1 ] == '.') - aTmp2.append( '.' ); - aText = aTmp2.makeStringAndClear(); - } - } - if (nHyphenPos == -1) - aText = rOrigWord; - - xRes = new HyphenatedWord( rOrigWord, nLang, nHyphenationPos, - aText, (nHyphenPos > -1) ? nHyphenPos - 1 : nHyphenationPos); + { + if (std::u16string_view(aTmp) != rOrigWord) + { + // both words should only differ by a having a trailing '.' + // character or not... + std::u16string_view aShorter(aTmp), aLonger(rOrigWord); + if (aTmp.getLength() > rOrigWord.getLength()) + std::swap(aShorter, aLonger); + sal_Int32 nS = aShorter.size(); + sal_Int32 nL = aLonger.size(); + if (nS > 0 && nL > 0) + { + assert( ((nS + 1 == nL) && aLonger[nL-1] == '.') && "HyphenatorDispatcher::buildHyphWord: unexpected difference between words!" ); } } } +#endif + sal_Int32 nHyphenPos = -1; + if (aText[ nOrigHyphPos ] == '[') // alternative hyphenation + { + sal_Int16 split = 0; + sal_Unicode c = aText [ nOrigHyphPos + 1 ]; + sal_Int32 endhyphpat = aText.indexOf( ']', nOrigHyphPos ); + if ('0' <= c && c <= '9') + { + split = c - '0'; + nOrigHyphPos++; + } + if (endhyphpat > -1) + { + OUStringBuffer aTmp2 ( aTmp.copy(0, std::max (nHyphenationPos + 1 - split, 0) ) ); + aTmp2.append( aText.subView( nOrigHyphPos + 1, endhyphpat - nOrigHyphPos - 1) ); + nHyphenPos = aTmp2.getLength(); + aTmp2.append( aTmp.subView( nHyphenationPos + 1 ) ); + //! take care of #i22591# + if (rOrigWord[ rOrigWord.getLength() - 1 ] == '.') + aTmp2.append( '.' ); + aText = aTmp2.makeStringAndClear(); + } + } + if (nHyphenPos == -1) + aText = rOrigWord; + + rtl::Reference< HyphenatedWord > xRes = new HyphenatedWord( rOrigWord, nLang, nHyphenationPos, + aText, (nHyphenPos > -1) ? nHyphenPos - 1 : nHyphenationPos); + return xRes; } -Reference< XPossibleHyphens > HyphenatorDispatcher::buildPossHyphens( +rtl::Reference HyphenatorDispatcher::buildPossHyphens( const Reference< XDictionaryEntry > &xEntry, LanguageType nLanguage ) { MutexGuard aGuard( GetLinguMutex() ); - Reference xRes; + if (!xEntry.is()) + return nullptr; - if (xEntry.is()) + // text with hyphenation info + OUString aText( xEntry->getDictionaryWord() ); + sal_Int32 nTextLen = aText.getLength(); + + // trailing '=' means "hyphenation should not be possible" + if (nTextLen <= 0 || aText[ nTextLen - 1 ] == '=' || aText[ nTextLen - 1 ] == '[') + return nullptr; + + // sequence to hold hyphenation positions + Sequence< sal_Int16 > aHyphPos( nTextLen ); + sal_Int16 *pPos = aHyphPos.getArray(); + sal_Int32 nHyphCount = 0; + + OUStringBuffer aTmp( nTextLen ); + bool bSkip = false; + bool bSkip2 = false; + sal_Int32 nHyphIdx = -1; + for (sal_Int32 i = 0; i < nTextLen; i++) { - // text with hyphenation info - OUString aText( xEntry->getDictionaryWord() ); - sal_Int32 nTextLen = aText.getLength(); - - // trailing '=' means "hyphenation should not be possible" - if (nTextLen > 0 && aText[ nTextLen - 1 ] != '=' && aText[ nTextLen - 1 ] != '[') + sal_Unicode cTmp = aText[i]; + if (cTmp == '[' || cTmp == ']') + bSkip2 = !bSkip2; + if (cTmp != '=' && !bSkip2 && cTmp != ']') { - // sequence to hold hyphenation positions - Sequence< sal_Int16 > aHyphPos( nTextLen ); - sal_Int16 *pPos = aHyphPos.getArray(); - sal_Int32 nHyphCount = 0; - - OUStringBuffer aTmp( nTextLen ); - bool bSkip = false; - bool bSkip2 = false; - sal_Int32 nHyphIdx = -1; - for (sal_Int32 i = 0; i < nTextLen; i++) - { - sal_Unicode cTmp = aText[i]; - if (cTmp == '[' || cTmp == ']') - bSkip2 = !bSkip2; - if (cTmp != '=' && !bSkip2 && cTmp != ']') - { - aTmp.append( cTmp ); - bSkip = false; - nHyphIdx++; - } - else - { - if (!bSkip && nHyphIdx >= 0) - pPos[ nHyphCount++ ] = static_cast(nHyphIdx); - bSkip = true; //! multiple '=' should count as one only - } - } - - // ignore (multiple) trailing '=' - if (bSkip && nHyphIdx >= 0) - { - nHyphCount--; - } - DBG_ASSERT( nHyphCount >= 0, "lng : invalid hyphenation count"); - - if (nHyphCount > 0) - { - aHyphPos.realloc( nHyphCount ); - xRes = new PossibleHyphens( aTmp.makeStringAndClear(), nLanguage, - aText, aHyphPos ); - } + aTmp.append( cTmp ); + bSkip = false; + nHyphIdx++; + } + else + { + if (!bSkip && nHyphIdx >= 0) + pPos[ nHyphCount++ ] = static_cast(nHyphIdx); + bSkip = true; //! multiple '=' should count as one only } } + // ignore (multiple) trailing '=' + if (bSkip && nHyphIdx >= 0) + { + nHyphCount--; + } + DBG_ASSERT( nHyphCount >= 0, "lng : invalid hyphenation count"); + + if (nHyphCount <= 0) + return nullptr; + + aHyphPos.realloc( nHyphCount ); + rtl::Reference xRes = new PossibleHyphens( aTmp.makeStringAndClear(), nLanguage, + aText, aHyphPos ); + return xRes; } diff --git a/linguistic/source/hyphdsp.hxx b/linguistic/source/hyphdsp.hxx index 348969f1906d..58baaa52e5d3 100644 --- a/linguistic/source/hyphdsp.hxx +++ b/linguistic/source/hyphdsp.hxx @@ -32,7 +32,7 @@ #include "defs.hxx" class LngSvcMgr; - +namespace linguistic { class HyphenatedWord; class PossibleHyphens; } class HyphenatorDispatcher : public cppu::WeakImplHelper @@ -60,12 +60,12 @@ class HyphenatorDispatcher : void ClearSvcList(); - static css::uno::Reference< css::linguistic2::XHyphenatedWord> + static rtl::Reference< linguistic::HyphenatedWord > buildHyphWord( const OUString& rOrigWord, const css::uno::Reference< css::linguistic2::XDictionaryEntry> &xEntry, LanguageType nLang, sal_Int16 nMaxLeading ); - static css::uno::Reference< css::linguistic2::XPossibleHyphens > + static rtl::Reference< linguistic::PossibleHyphens > buildPossHyphens( const css::uno::Reference< css::linguistic2::XDictionaryEntry > &xEntry, LanguageType nLanguage ); diff --git a/linguistic/source/misc.cxx b/linguistic/source/misc.cxx index 088cde001f20..5b826d0ec758 100644 --- a/linguistic/source/misc.cxx +++ b/linguistic/source/misc.cxx @@ -498,63 +498,60 @@ sal_Int32 GetPosInWordToCheck( std::u16string_view rTxt, sal_Int32 nPos ) return nRes; } -uno::Reference< XHyphenatedWord > RebuildHyphensAndControlChars( +rtl::Reference< HyphenatedWord > RebuildHyphensAndControlChars( const OUString &rOrigWord, uno::Reference< XHyphenatedWord > const &rxHyphWord ) { - uno::Reference< XHyphenatedWord > xRes; - if (!rOrigWord.isEmpty() && rxHyphWord.is()) + if (rOrigWord.isEmpty() || !rxHyphWord.is()) + return nullptr; + + sal_Int16 nChgPos = 0, + nChgLen = 0; + OUString aRplc; + bool bAltSpelling = GetAltSpelling( nChgPos, nChgLen, aRplc, rxHyphWord ); + + OUString aOrigHyphenatedWord; + sal_Int16 nOrigHyphenPos = -1; + sal_Int16 nOrigHyphenationPos = -1; + if (!bAltSpelling) { - sal_Int16 nChgPos = 0, - nChgLen = 0; - OUString aRplc; - bool bAltSpelling = GetAltSpelling( nChgPos, nChgLen, aRplc, rxHyphWord ); - - OUString aOrigHyphenatedWord; - sal_Int16 nOrigHyphenPos = -1; - sal_Int16 nOrigHyphenationPos = -1; - if (!bAltSpelling) - { - aOrigHyphenatedWord = rOrigWord; - nOrigHyphenPos = GetOrigWordPos( rOrigWord, rxHyphWord->getHyphenPos() ); - nOrigHyphenationPos = GetOrigWordPos( rOrigWord, rxHyphWord->getHyphenationPos() ); - } - else - { - //! should at least work with the German words - //! B-"u-c-k-er and Sc-hif-fah-rt - - sal_Int16 nPos = GetOrigWordPos( rOrigWord, nChgPos ); - - // get words like Sc-hif-fah-rt to work correct - sal_Int16 nHyphenationPos = rxHyphWord->getHyphenationPos(); - if (nChgPos > nHyphenationPos) - --nPos; - - std::u16string_view aLeft = rOrigWord.subView( 0, nPos ); - std::u16string_view aRight = rOrigWord.subView( nPos ); // FIXME: changes at the right side - - aOrigHyphenatedWord = aLeft + aRplc + aRight; - - nOrigHyphenPos = sal::static_int_cast< sal_Int16 >(aLeft.size() + - rxHyphWord->getHyphenPos() - nChgPos); - nOrigHyphenationPos = GetOrigWordPos( rOrigWord, nHyphenationPos ); - } - - if (nOrigHyphenPos == -1 || nOrigHyphenationPos == -1) - { - SAL_WARN( "linguistic", "failed to get nOrigHyphenPos or nOrigHyphenationPos" ); - } - else - { - LanguageType nLang = LinguLocaleToLanguage( rxHyphWord->getLocale() ); - xRes = new HyphenatedWord( - rOrigWord, nLang, nOrigHyphenationPos, - aOrigHyphenatedWord, nOrigHyphenPos ); - } - + aOrigHyphenatedWord = rOrigWord; + nOrigHyphenPos = GetOrigWordPos( rOrigWord, rxHyphWord->getHyphenPos() ); + nOrigHyphenationPos = GetOrigWordPos( rOrigWord, rxHyphWord->getHyphenationPos() ); } - return xRes; + else + { + //! should at least work with the German words + //! B-"u-c-k-er and Sc-hif-fah-rt + + sal_Int16 nPos = GetOrigWordPos( rOrigWord, nChgPos ); + + // get words like Sc-hif-fah-rt to work correct + sal_Int16 nHyphenationPos = rxHyphWord->getHyphenationPos(); + if (nChgPos > nHyphenationPos) + --nPos; + + std::u16string_view aLeft = rOrigWord.subView( 0, nPos ); + std::u16string_view aRight = rOrigWord.subView( nPos ); // FIXME: changes at the right side + + aOrigHyphenatedWord = aLeft + aRplc + aRight; + + nOrigHyphenPos = sal::static_int_cast< sal_Int16 >(aLeft.size() + + rxHyphWord->getHyphenPos() - nChgPos); + nOrigHyphenationPos = GetOrigWordPos( rOrigWord, nHyphenationPos ); + } + + if (nOrigHyphenPos != -1 && nOrigHyphenationPos != -1) + { + SAL_WARN( "linguistic", "failed to get nOrigHyphenPos or nOrigHyphenationPos" ); + return nullptr; + } + + LanguageType nLang = LinguLocaleToLanguage( rxHyphWord->getLocale() ); + return new HyphenatedWord( + rOrigWord, nLang, nOrigHyphenationPos, + aOrigHyphenatedWord, nOrigHyphenPos ); + } bool IsUpper( const OUString &rText, sal_Int32 nPos, sal_Int32 nLen, LanguageType nLanguage ) diff --git a/linguistic/source/spelldsp.cxx b/linguistic/source/spelldsp.cxx index 0abdaa0489fe..c79a1fce09ba 100644 --- a/linguistic/source/spelldsp.cxx +++ b/linguistic/source/spelldsp.cxx @@ -424,299 +424,299 @@ Reference< XSpellAlternatives > SpellCheckerDispatcher::spell_Impl( { MutexGuard aGuard( GetLinguMutex() ); - Reference< XSpellAlternatives > xRes; - if (LinguIsUnspecified( nLanguage) || rWord.isEmpty()) - return xRes; + return nullptr; // search for entry with that language SpellSvcByLangMap_t::iterator aIt( m_aSvcMap.find( nLanguage ) ); LangSvcEntries_Spell *pEntry = aIt != m_aSvcMap.end() ? aIt->second.get() : nullptr; - if (pEntry) + if (!pEntry) + return nullptr; + + Reference< XSpellAlternatives > xRes; + + OUString aChkWord( rWord ); + Locale aLocale( LanguageTag::convertToLocale( nLanguage ) ); + + // replace typographical apostroph by ascii apostroph + OUString aSingleQuote( GetLocaleDataWrapper( nLanguage ).getQuotationMarkEnd() ); + DBG_ASSERT( 1 == aSingleQuote.getLength(), "unexpected length of quotation mark" ); + if (!aSingleQuote.isEmpty()) + aChkWord = aChkWord.replace( aSingleQuote[0], '\'' ); + + RemoveHyphens( aChkWord ); + if (IsIgnoreControlChars( rProperties, GetPropSet() )) + RemoveControlChars( aChkWord ); + + sal_Int32 nLen = pEntry->aSvcRefs.getLength(); + DBG_ASSERT( nLen == pEntry->aSvcImplNames.getLength(), + "lng : sequence length mismatch"); + DBG_ASSERT( pEntry->nLastTriedSvcIndex < nLen, + "lng : index out of range"); + + sal_Int32 i = 0; + Reference< XSpellAlternatives > xTmpRes; + bool bTmpResValid = false; + + // try already instantiated services first { - OUString aChkWord( rWord ); - Locale aLocale( LanguageTag::convertToLocale( nLanguage ) ); - - // replace typographical apostroph by ascii apostroph - OUString aSingleQuote( GetLocaleDataWrapper( nLanguage ).getQuotationMarkEnd() ); - DBG_ASSERT( 1 == aSingleQuote.getLength(), "unexpected length of quotation mark" ); - if (!aSingleQuote.isEmpty()) - aChkWord = aChkWord.replace( aSingleQuote[0], '\'' ); - - RemoveHyphens( aChkWord ); - if (IsIgnoreControlChars( rProperties, GetPropSet() )) - RemoveControlChars( aChkWord ); - - sal_Int32 nLen = pEntry->aSvcRefs.getLength(); - DBG_ASSERT( nLen == pEntry->aSvcImplNames.getLength(), - "lng : sequence length mismatch"); - DBG_ASSERT( pEntry->nLastTriedSvcIndex < nLen, - "lng : index out of range"); - - sal_Int32 i = 0; - Reference< XSpellAlternatives > xTmpRes; - bool bTmpResValid = false; - - // try already instantiated services first + const Reference< XSpellChecker > *pRef = pEntry->aSvcRefs.getConstArray(); + sal_Int32 nNumSuggestions = -1; + while (i <= pEntry->nLastTriedSvcIndex + && (!bTmpResValid || xTmpRes.is()) ) { - const Reference< XSpellChecker > *pRef = pEntry->aSvcRefs.getConstArray(); - sal_Int32 nNumSuggestions = -1; - while (i <= pEntry->nLastTriedSvcIndex - && (!bTmpResValid || xTmpRes.is()) ) + bTmpResValid = true; + if (pRef[i].is() && pRef[i]->hasLocale( aLocale )) { - bTmpResValid = true; - if (pRef[i].is() && pRef[i]->hasLocale( aLocale )) - { - bool bOK = GetCache().CheckWord( aChkWord, nLanguage ); - if (bOK) - xTmpRes = nullptr; - else - { - xTmpRes = pRef[i]->spell( aChkWord, aLocale, rProperties ); - - // Add correct words to the cache. - // But not those that are correct only because of - // the temporary supplied settings. - if (!xTmpRes.is() && !rProperties.hasElements()) - GetCache().AddWord( aChkWord, nLanguage ); - } - } + bool bOK = GetCache().CheckWord( aChkWord, nLanguage ); + if (bOK) + xTmpRes = nullptr; else - bTmpResValid = false; - - // return first found result if the word is not known by any checker. - // But if that result has no suggestions use the first one that does - // provide suggestions for the misspelled word. - if (!xRes.is() && bTmpResValid) { - xRes = xTmpRes; - nNumSuggestions = 0; - if (xRes.is()) - nNumSuggestions = xRes->getAlternatives().getLength(); - } - sal_Int32 nTmpNumSuggestions = 0; - if (xTmpRes.is() && bTmpResValid) - nTmpNumSuggestions = xTmpRes->getAlternatives().getLength(); - if (xRes.is() && nNumSuggestions == 0 && nTmpNumSuggestions > 0) - { - xRes = xTmpRes; - nNumSuggestions = nTmpNumSuggestions; - } + xTmpRes = pRef[i]->spell( aChkWord, aLocale, rProperties ); - ++i; - } - } - - // if still no result instantiate new services and try those - if ((!bTmpResValid || xTmpRes.is()) - && pEntry->nLastTriedSvcIndex < nLen - 1) - { - const OUString *pImplNames = pEntry->aSvcImplNames.getConstArray(); - Reference< XSpellChecker > *pRef = pEntry->aSvcRefs .getArray(); - - const Reference< XComponentContext >& xContext( - comphelper::getProcessComponentContext() ); - - // build service initialization argument - Sequence< Any > aArgs(2); - aArgs.getArray()[0] <<= GetPropSet(); - - sal_Int32 nNumSuggestions = -1; - while (i < nLen && (!bTmpResValid || xTmpRes.is())) - { - // create specific service via it's implementation name - Reference< XSpellChecker > xSpell; - try - { - xSpell.set( xContext->getServiceManager()->createInstanceWithArgumentsAndContext( - pImplNames[i], aArgs, xContext ), - UNO_QUERY ); - } - catch (uno::Exception &) - { - SAL_WARN( "linguistic", "createInstanceWithArguments failed" ); - } - pRef [i] = xSpell; - - Reference< XLinguServiceEventBroadcaster > - xBroadcaster( xSpell, UNO_QUERY ); - if (xBroadcaster.is()) - m_rMgr.AddLngSvcEvtBroadcaster( xBroadcaster ); - - bTmpResValid = true; - if (xSpell.is() && xSpell->hasLocale( aLocale )) - { - bool bOK = GetCache().CheckWord( aChkWord, nLanguage ); - if (bOK) - xTmpRes = nullptr; - else - { - xTmpRes = xSpell->spell( aChkWord, aLocale, rProperties ); - - // Add correct words to the cache. - // But not those that are correct only because of - // the temporary supplied settings. - if (!xTmpRes.is() && !rProperties.hasElements()) - GetCache().AddWord( aChkWord, nLanguage ); - } - } - else - bTmpResValid = false; - - // return first found result if the word is not known by any checker. - // But if that result has no suggestions use the first one that does - // provide suggestions for the misspelled word. - if (!xRes.is() && bTmpResValid) - { - xRes = xTmpRes; - nNumSuggestions = 0; - if (xRes.is()) - nNumSuggestions = xRes->getAlternatives().getLength(); - } - sal_Int32 nTmpNumSuggestions = 0; - if (xTmpRes.is() && bTmpResValid) - nTmpNumSuggestions = xTmpRes->getAlternatives().getLength(); - if (xRes.is() && nNumSuggestions == 0 && nTmpNumSuggestions > 0) - { - xRes = xTmpRes; - nNumSuggestions = nTmpNumSuggestions; - } - - pEntry->nLastTriedSvcIndex = static_cast(i); - ++i; - } - - // if language is not supported by any of the services - // remove it from the list. - if (i == nLen) - { - if (!SvcListHasLanguage( *pEntry, nLanguage )) - m_aSvcMap.erase( nLanguage ); - } - } - - // if word is finally found to be correct - // clear previously remembered alternatives - if (bTmpResValid && !xTmpRes.is()) - xRes = nullptr; - - // list of proposals found (to be checked against entries of - // negative dictionaries) - ProposalList aProposalList; - sal_Int16 eFailureType = -1; // no failure - if (xRes.is()) - { - aProposalList.Append( xRes->getAlternatives() ); - eFailureType = xRes->getFailureType(); - } - Reference< XSearchableDictionaryList > xDList; - if (GetDicList().is() && IsUseDicList( rProperties, GetPropSet() )) - xDList = GetDicList(); - - // cross-check against results from user-dictionaries which have precedence! - if (xDList.is()) - { - Reference< XDictionaryEntry > xTmp( lcl_GetRulingDictionaryEntry( aChkWord, nLanguage ) ); - if (xTmp.is()) - { - if (xTmp->isNegative()) // negative entry found - { - eFailureType = SpellFailure::IS_NEGATIVE_WORD; - - // replacement text to be added to suggestions, if not empty - OUString aAddRplcTxt( xTmp->getReplacementText() ); - - // replacement text must not be in negative dictionary itself - if (!aAddRplcTxt.isEmpty() && - !SearchDicList( xDList, aAddRplcTxt, nLanguage, false, true ).is()) - { - aProposalList.Prepend( aAddRplcTxt ); - } - } - else // positive entry found - { - xRes = nullptr; - eFailureType = -1; // no failure + // Add correct words to the cache. + // But not those that are correct only because of + // the temporary supplied settings. + if (!xTmpRes.is() && !rProperties.hasElements()) + GetCache().AddWord( aChkWord, nLanguage ); } } else + bTmpResValid = false; + + // return first found result if the word is not known by any checker. + // But if that result has no suggestions use the first one that does + // provide suggestions for the misspelled word. + if (!xRes.is() && bTmpResValid) { - setCharClass(LanguageTag(nLanguage)); - CapType ct = capitalType(aChkWord, m_oCharClass ? &*m_oCharClass : nullptr); - if (ct == CapType::INITCAP || ct == CapType::ALLCAP) + xRes = xTmpRes; + nNumSuggestions = 0; + if (xRes.is()) + nNumSuggestions = xRes->getAlternatives().getLength(); + } + sal_Int32 nTmpNumSuggestions = 0; + if (xTmpRes.is() && bTmpResValid) + nTmpNumSuggestions = xTmpRes->getAlternatives().getLength(); + if (xRes.is() && nNumSuggestions == 0 && nTmpNumSuggestions > 0) + { + xRes = xTmpRes; + nNumSuggestions = nTmpNumSuggestions; + } + + ++i; + } + } + + // if still no result instantiate new services and try those + if ((!bTmpResValid || xTmpRes.is()) + && pEntry->nLastTriedSvcIndex < nLen - 1) + { + const OUString *pImplNames = pEntry->aSvcImplNames.getConstArray(); + Reference< XSpellChecker > *pRef = pEntry->aSvcRefs .getArray(); + + const Reference< XComponentContext >& xContext( + comphelper::getProcessComponentContext() ); + + // build service initialization argument + Sequence< Any > aArgs(2); + aArgs.getArray()[0] <<= GetPropSet(); + + sal_Int32 nNumSuggestions = -1; + while (i < nLen && (!bTmpResValid || xTmpRes.is())) + { + // create specific service via it's implementation name + Reference< XSpellChecker > xSpell; + try + { + xSpell.set( xContext->getServiceManager()->createInstanceWithArgumentsAndContext( + pImplNames[i], aArgs, xContext ), + UNO_QUERY ); + } + catch (uno::Exception &) + { + SAL_WARN( "linguistic", "createInstanceWithArguments failed" ); + } + pRef [i] = xSpell; + + Reference< XLinguServiceEventBroadcaster > + xBroadcaster( xSpell, UNO_QUERY ); + if (xBroadcaster.is()) + m_rMgr.AddLngSvcEvtBroadcaster( xBroadcaster ); + + bTmpResValid = true; + if (xSpell.is() && xSpell->hasLocale( aLocale )) + { + bool bOK = GetCache().CheckWord( aChkWord, nLanguage ); + if (bOK) + xTmpRes = nullptr; + else { - Reference< XDictionaryEntry > xTmp2( lcl_GetRulingDictionaryEntry( makeLowerCase(aChkWord, m_oCharClass), nLanguage ) ); - if (xTmp2.is()) + xTmpRes = xSpell->spell( aChkWord, aLocale, rProperties ); + + // Add correct words to the cache. + // But not those that are correct only because of + // the temporary supplied settings. + if (!xTmpRes.is() && !rProperties.hasElements()) + GetCache().AddWord( aChkWord, nLanguage ); + } + } + else + bTmpResValid = false; + + // return first found result if the word is not known by any checker. + // But if that result has no suggestions use the first one that does + // provide suggestions for the misspelled word. + if (!xRes.is() && bTmpResValid) + { + xRes = xTmpRes; + nNumSuggestions = 0; + if (xRes.is()) + nNumSuggestions = xRes->getAlternatives().getLength(); + } + sal_Int32 nTmpNumSuggestions = 0; + if (xTmpRes.is() && bTmpResValid) + nTmpNumSuggestions = xTmpRes->getAlternatives().getLength(); + if (xRes.is() && nNumSuggestions == 0 && nTmpNumSuggestions > 0) + { + xRes = xTmpRes; + nNumSuggestions = nTmpNumSuggestions; + } + + pEntry->nLastTriedSvcIndex = static_cast(i); + ++i; + } + + // if language is not supported by any of the services + // remove it from the list. + if (i == nLen) + { + if (!SvcListHasLanguage( *pEntry, nLanguage )) + m_aSvcMap.erase( nLanguage ); + } + } + + // if word is finally found to be correct + // clear previously remembered alternatives + if (bTmpResValid && !xTmpRes.is()) + xRes = nullptr; + + // list of proposals found (to be checked against entries of + // negative dictionaries) + ProposalList aProposalList; + sal_Int16 eFailureType = -1; // no failure + if (xRes.is()) + { + aProposalList.Append( xRes->getAlternatives() ); + eFailureType = xRes->getFailureType(); + } + Reference< XSearchableDictionaryList > xDList; + if (GetDicList().is() && IsUseDicList( rProperties, GetPropSet() )) + xDList = GetDicList(); + + // cross-check against results from user-dictionaries which have precedence! + if (xDList.is()) + { + Reference< XDictionaryEntry > xTmp( lcl_GetRulingDictionaryEntry( aChkWord, nLanguage ) ); + if (xTmp.is()) + { + if (xTmp->isNegative()) // negative entry found + { + eFailureType = SpellFailure::IS_NEGATIVE_WORD; + + // replacement text to be added to suggestions, if not empty + OUString aAddRplcTxt( xTmp->getReplacementText() ); + + // replacement text must not be in negative dictionary itself + if (!aAddRplcTxt.isEmpty() && + !SearchDicList( xDList, aAddRplcTxt, nLanguage, false, true ).is()) + { + aProposalList.Prepend( aAddRplcTxt ); + } + } + else // positive entry found + { + xRes = nullptr; + eFailureType = -1; // no failure + } + } + else + { + setCharClass(LanguageTag(nLanguage)); + CapType ct = capitalType(aChkWord, m_oCharClass ? &*m_oCharClass : nullptr); + if (ct == CapType::INITCAP || ct == CapType::ALLCAP) + { + Reference< XDictionaryEntry > xTmp2( lcl_GetRulingDictionaryEntry( makeLowerCase(aChkWord, m_oCharClass), nLanguage ) ); + if (xTmp2.is()) + { + if (xTmp2->isNegative()) // negative entry found { - if (xTmp2->isNegative()) // negative entry found + eFailureType = SpellFailure::IS_NEGATIVE_WORD; + + // replacement text to be added to suggestions, if not empty + OUString aAddRplcTxt( xTmp2->getReplacementText() ); + + // replacement text must not be in negative dictionary itself + if (!aAddRplcTxt.isEmpty() && + !SearchDicList( xDList, aAddRplcTxt, nLanguage, false, true ).is()) { - eFailureType = SpellFailure::IS_NEGATIVE_WORD; - - // replacement text to be added to suggestions, if not empty - OUString aAddRplcTxt( xTmp2->getReplacementText() ); - - // replacement text must not be in negative dictionary itself - if (!aAddRplcTxt.isEmpty() && - !SearchDicList( xDList, aAddRplcTxt, nLanguage, false, true ).is()) + switch ( ct ) { - switch ( ct ) - { - case CapType::INITCAP: - aProposalList.Prepend( m_oCharClass->titlecase(aAddRplcTxt) ); - break; - case CapType::ALLCAP: - aProposalList.Prepend( m_oCharClass->uppercase(aAddRplcTxt) ); - break; - default: - /* can't happen because of if ct == above */ - break; - } + case CapType::INITCAP: + aProposalList.Prepend( m_oCharClass->titlecase(aAddRplcTxt) ); + break; + case CapType::ALLCAP: + aProposalList.Prepend( m_oCharClass->uppercase(aAddRplcTxt) ); + break; + default: + /* can't happen because of if ct == above */ + break; } } - else // positive entry found - { - xRes = nullptr; - eFailureType = -1; // no failure - } + } + else // positive entry found + { + xRes = nullptr; + eFailureType = -1; // no failure } } } } + } - if (eFailureType != -1) // word misspelled or found in negative user-dictionary + if (eFailureType != -1) // word misspelled or found in negative user-dictionary + { + // search suitable user-dictionaries for suggestions that are + // similar to the misspelled word + std::vector< OUString > aDicListProps; // list of proposals from user-dictionaries + SearchSimilarText( aChkWord, nLanguage, xDList, aDicListProps ); + aProposalList.Append( aDicListProps ); + std::vector< OUString > aProposals = aProposalList.GetVector(); + + // remove entries listed in negative dictionaries + // (we don't want to display suggestions that will be regarded as misspelled later on) + if (xDList.is()) + SeqRemoveNegEntries( aProposals, xDList, nLanguage ); + + uno::Reference< linguistic2::XSetSpellAlternatives > xSetAlt( xRes, uno::UNO_QUERY ); + if (xSetAlt.is()) { - // search suitable user-dictionaries for suggestions that are - // similar to the misspelled word - std::vector< OUString > aDicListProps; // list of proposals from user-dictionaries - SearchSimilarText( aChkWord, nLanguage, xDList, aDicListProps ); - aProposalList.Append( aDicListProps ); - std::vector< OUString > aProposals = aProposalList.GetVector(); - - // remove entries listed in negative dictionaries - // (we don't want to display suggestions that will be regarded as misspelled later on) - if (xDList.is()) - SeqRemoveNegEntries( aProposals, xDList, nLanguage ); - - uno::Reference< linguistic2::XSetSpellAlternatives > xSetAlt( xRes, uno::UNO_QUERY ); - if (xSetAlt.is()) + xSetAlt->setAlternatives( comphelper::containerToSequence(aProposals) ); + xSetAlt->setFailureType( eFailureType ); + } + else + { + if (xRes.is()) { - xSetAlt->setAlternatives( comphelper::containerToSequence(aProposals) ); - xSetAlt->setFailureType( eFailureType ); + SAL_WARN( "linguistic", "XSetSpellAlternatives not implemented!" ); } - else + else if (!aProposals.empty()) { - if (xRes.is()) - { - SAL_WARN( "linguistic", "XSetSpellAlternatives not implemented!" ); - } - else if (!aProposals.empty()) - { - // no xRes but Proposals found from the user-dictionaries. - // Thus we need to create an xRes... - xRes = new linguistic::SpellAlternatives( rWord, nLanguage, - comphelper::containerToSequence(aProposals) ); - } + // no xRes but Proposals found from the user-dictionaries. + // Thus we need to create an xRes... + xRes = new linguistic::SpellAlternatives( rWord, nLanguage, + comphelper::containerToSequence(aProposals) ); } } }