diff options
author | László Németh <nemeth@numbertext.org> | 2017-11-09 16:03:21 +0100 |
---|---|---|
committer | László Németh <nemeth@numbertext.org> | 2017-11-17 17:33:00 +0100 |
commit | 95d9f596336ebf19dc367f618b3788a4ce0ba542 (patch) | |
tree | d33140f4cc24c4f0fd5f46f165906e2908e857f7 | |
parent | a7ec994689f8ea5985f6c8f94f17a4417978ff41 (diff) |
tdf#113739 add "Grammar By" feature to user dictionaries
Language-specific user dictionaries (en-US, de-DE, etc.)
have got a new "Grammar By" field to specify
optional automatic affixation and compounding of the
new words by adding an example dictionary word.
Test example:
Create an en-US user dictionary. Add the new word
"crowdfund" to it, also an example, the Hunspell
en-US dictionary word "fund" in the optional
"Grammar By" field.
This way, the word "crowdfund" will be recognized
by the spell checker with suffixes of the word "fund",
too: crowdfund’s, crowdfunds, crowdfunder, crowdfunders
and crowdfunding.
Hunspell dictionaries with compound flag usage (German,
Hungarian, etc.) can support automatic compounding of
the new words, too.
Change-Id: Id70dbee4544643967153f730ae64938e5cee0c82
Reviewed-on: https://gerrit.libreoffice.org/44562
Tested-by: Jenkins <ci@libreoffice.org>
Reviewed-by: László Németh <nemeth@numbertext.org>
-rw-r--r-- | cui/inc/strings.hrc | 1 | ||||
-rw-r--r-- | cui/source/inc/optdict.hxx | 1 | ||||
-rw-r--r-- | cui/source/options/optdict.cxx | 29 | ||||
-rw-r--r-- | linguistic/source/dicimp.cxx | 36 |
4 files changed, 59 insertions, 8 deletions
diff --git a/cui/inc/strings.hrc b/cui/inc/strings.hrc index 40270de92037..5909ef647c74 100644 --- a/cui/inc/strings.hrc +++ b/cui/inc/strings.hrc @@ -268,6 +268,7 @@ #define RID_SVXSTR_CHG_SMARTART NC_("RID_SVXSTR_CHG_SMARTART", "SmartArt to %PRODUCTNAME shapes or reverse") #define RID_SVXSTR_OPT_DOUBLE_DICTS NC_("RID_SVXSTR_OPT_DOUBLE_DICTS", "The specified name already exists.\nPlease enter a new name.") +#define RID_SVXSTR_OPT_GRAMMAR_BY NC_("RID_SVXSTR_OPT_GRAMMAR_BY", "~Grammar By") #define STR_MODIFY NC_("STR_MODIFY", "~Replace") #define RID_SVXSTR_CONFIRM_SET_LANGUAGE NC_("RID_SVXSTR_CONFIRM_SET_LANGUAGE", "Do you want to change the '%1' dictionary language?") diff --git a/cui/source/inc/optdict.hxx b/cui/source/inc/optdict.hxx index fb8cd6deb364..e2dc53bf9e6e 100644 --- a/cui/source/inc/optdict.hxx +++ b/cui/source/inc/optdict.hxx @@ -109,6 +109,7 @@ private: OUString sModify; OUString sNew; + OUString sReplaceFT_Text; css::uno::Sequence< css::uno::Reference< diff --git a/cui/source/options/optdict.cxx b/cui/source/options/optdict.cxx index c04584f08bb4..8b23f40c5445 100644 --- a/cui/source/options/optdict.cxx +++ b/cui/source/options/optdict.cxx @@ -227,6 +227,7 @@ SvxEditDictionaryDialog::SvxEditDictionaryDialog( get(pWordED,"word"); get(pReplaceFT,"replace_label"); + sReplaceFT_Text = pReplaceFT->GetText(); get(pReplaceED,"replace"); get(pWordsLB,"words"); pWordsLB->set_height_request(pWordsLB->GetTextHeight() * 8); @@ -484,7 +485,22 @@ void SvxEditDictionaryDialog::ShowWords_Impl( sal_uInt16 nId ) pWordED->SetText(aStr); pReplaceED->SetText(aStr); - if(xDic->getDictionaryType() != DictionaryType_POSITIVE) + bool bIsNegative = xDic->getDictionaryType() != DictionaryType_POSITIVE; + bool bLangNone = LanguageTag( + xDic->getLocale() ).getLanguageType() == LANGUAGE_NONE; + + // The label is "Replace By" only in negative dictionaries (forbidden + // words), otherwise "Grammar By" in language-specific dictionaries + // (where the optional second word is the sample word for + // the Hunspell based affixation/compounding of the new dictionary word) + if (bIsNegative) + { + pReplaceFT->SetText(sReplaceFT_Text); + } else if (!bLangNone) { + pReplaceFT->SetText(CuiResId(RID_SVXSTR_OPT_GRAMMAR_BY)); + } + + if(bIsNegative || !bLangNone) { nStaticTabs[0]=2; @@ -525,7 +541,7 @@ void SvxEditDictionaryDialog::ShowWords_Impl( sal_uInt16 nId ) { aStr = pEntry[i]->getDictionaryWord(); sal_uLong nPos = GetLBInsertPos( aStr ); - if(pEntry[i]->isNegative()) + if(!pEntry[i]->getReplacementText().isEmpty()) { aStr += "\t" + pEntry[i]->getReplacementText(); } @@ -608,11 +624,10 @@ bool SvxEditDictionaryDialog::NewDelHdl(void const * pBtn) { // make changes in dic - //! ...IsVisible should reflect whether the dictionary is a negativ - //! or not (hopefully...) - bool bIsNegEntry = pReplaceFT->IsVisible(); + bool bIsNegEntry = xDic->getDictionaryType() == DictionaryType_NEGATIVE; + OUString aRplcText; - if(bIsNegEntry) + if(!aReplaceStr.isEmpty()) aRplcText = aReplaceStr; if (_pEntry) // entry selected in pWordsLB ie action = modify entry @@ -635,7 +650,7 @@ bool SvxEditDictionaryDialog::NewDelHdl(void const * pBtn) pWordsLB->SetUpdateMode(false); sal_uLong _nPos = TREELIST_ENTRY_NOTFOUND; - if(pReplaceFT->IsVisible()) + if(!aReplaceStr.isEmpty()) { sEntry += "\t" + aReplaceStr; } diff --git a/linguistic/source/dicimp.cxx b/linguistic/source/dicimp.cxx index 1c985503c9f9..b5b1e840e94c 100644 --- a/linguistic/source/dicimp.cxx +++ b/linguistic/source/dicimp.cxx @@ -40,6 +40,9 @@ #include <com/sun/star/io/XInputStream.hpp> #include <com/sun/star/io/XOutputStream.hpp> +#include <com/sun/star/linguistic2/LinguServiceManager.hpp> +#include <com/sun/star/linguistic2/XSpellChecker1.hpp> + #include "defs.hxx" #include <algorithm> @@ -59,6 +62,9 @@ using namespace linguistic; #define MAX_HEADER_LENGTH 16 +// XML-header to query SPELLML support +#define SPELLML_SUPPORT "<?xml?>" + static const sal_Char* const pVerStr2 = "WBSWG2"; static const sal_Char* const pVerStr5 = "WBSWG5"; static const sal_Char* const pVerStr6 = "WBSWG6"; @@ -70,6 +76,13 @@ static const sal_Int16 DIC_VERSION_5 = 5; static const sal_Int16 DIC_VERSION_6 = 6; static const sal_Int16 DIC_VERSION_7 = 7; +static uno::Reference< XLinguServiceManager2 > GetLngSvcMgr_Impl() +{ + uno::Reference< XComponentContext > xContext( comphelper::getProcessComponentContext() ); + uno::Reference< XLinguServiceManager2 > xRes = LinguServiceManager::create( xContext ) ; + return xRes; +} + static bool getTag(const OString &rLine, const sal_Char *pTagName, OString &rTagValue) { @@ -359,7 +372,7 @@ static OString formatForSave(const uno::Reference< XDictionaryEntry > &xEntry, { OStringBuffer aStr(OUStringToOString(xEntry->getDictionaryWord(), eEnc)); - if (xEntry->isNegative()) + if (xEntry->isNegative() || !xEntry->getReplacementText().isEmpty()) { aStr.append("=="); aStr.append(OUStringToOString(xEntry->getReplacementText(), eEnc)); @@ -672,6 +685,27 @@ bool DictionaryNeo::addEntry_Impl(const uno::Reference< XDictionaryEntry >& xDic } } + // add word to the Hunspell dictionary using a sample word for affixation/compounding + if (xDicEntry.is() && !xDicEntry->isNegative() && !xDicEntry->getReplacementText().isEmpty()) { + uno::Reference< XLinguServiceManager2 > xLngSvcMgr( GetLngSvcMgr_Impl() ); + uno::Reference< XSpellChecker1 > xSpell; + Reference< XSpellAlternatives > xTmpRes; + xSpell.set( xLngSvcMgr->getSpellChecker(), UNO_QUERY ); + Sequence< css::beans::PropertyValue > aEmptySeq; + if (xSpell.is() && (xSpell->isValid( SPELLML_SUPPORT, (sal_uInt16)nLanguage, aEmptySeq ))) + { + // "Grammar By" sample word is a Hunspell dictionary word? + if (xSpell->isValid( xDicEntry->getReplacementText(), (sal_uInt16)nLanguage, aEmptySeq )) + { + xTmpRes = xSpell->spell( "<?xml?><query type='add'><word>" + + xDicEntry->getDictionaryWord() + "</word><word>" + xDicEntry->getReplacementText() + + "</word></query>", (sal_uInt16)nLanguage, aEmptySeq ); + bRes = true; + } else + bRes = false; + } + } + return bRes; } |