From 12e0991465eb2768a4a488e28517e64d25df458f Mon Sep 17 00:00:00 2001 From: Stephan Witt Date: Wed, 11 Jan 2012 17:05:18 +0000 Subject: [PATCH] backport changes to fix #7884: detect missing dictionaries, add default dictionary location for hunspell, act on preference changes git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/branches/BRANCH_2_0_X@40599 a592a061-630c-0410-9148-cb99ea01b6c8 --- src/AppleSpellChecker.cpp | 19 +++++++- src/AppleSpellChecker.h | 1 + src/AspellChecker.cpp | 23 +++++++++- src/AspellChecker.h | 1 + src/EnchantChecker.cpp | 11 ++++- src/EnchantChecker.h | 1 + src/HunspellChecker.cpp | 62 ++++++++++++++++++++++++--- src/HunspellChecker.h | 1 + src/SpellChecker.h | 8 +++- src/frontends/qt4/GuiSpellchecker.cpp | 11 +++++ src/frontends/qt4/Menus.cpp | 3 ++ status.20x | 7 +++ 12 files changed, 137 insertions(+), 11 deletions(-) diff --git a/src/AppleSpellChecker.cpp b/src/AppleSpellChecker.cpp index 5e6240125f..cb80a60bd1 100644 --- a/src/AppleSpellChecker.cpp +++ b/src/AppleSpellChecker.cpp @@ -31,7 +31,8 @@ struct AppleSpellChecker::Private SpellChecker::Result toResult(SpellCheckResult status); string toString(SpellCheckResult status); - + int numDictionaries() const; + /// the speller AppleSpeller speller; @@ -82,7 +83,7 @@ string AppleSpellChecker::Private::toString(SpellCheckResult status) SpellChecker::Result AppleSpellChecker::check(WordLangTuple const & word) { if (!hasDictionary(word.lang())) - return WORD_OK; + return NO_DICTIONARY; string const word_str = to_utf8(word.word()); string const lang = d->languageMap[word.lang()->lang()]; @@ -168,6 +169,20 @@ bool AppleSpellChecker::hasDictionary(Language const * lang) const } +int AppleSpellChecker::numDictionaries() const +{ + int result = 0; + map::const_iterator it = d->languageMap.begin(); + map::const_iterator et = d->languageMap.end(); + + for (; it != et; ++it) { + string const langmap = it->second; + result += langmap.empty() ? 0 : 1; + } + return result; +} + + int AppleSpellChecker::numMisspelledWords() const { return AppleSpeller_numMisspelledWords(d->speller); diff --git a/src/AppleSpellChecker.h b/src/AppleSpellChecker.h index 25c205aafc..e41ff3729d 100644 --- a/src/AppleSpellChecker.h +++ b/src/AppleSpellChecker.h @@ -30,6 +30,7 @@ public: void remove(WordLangTuple const &); void accept(WordLangTuple const &); bool hasDictionary(Language const * lang) const; + int numDictionaries() const; bool canCheckParagraph() const { return true; } int numMisspelledWords() const; void misspelledWord(int index, int & start, int & length) const; diff --git a/src/AspellChecker.cpp b/src/AspellChecker.cpp index c549980e03..a03dc65759 100644 --- a/src/AspellChecker.cpp +++ b/src/AspellChecker.cpp @@ -65,6 +65,7 @@ struct AspellChecker::Private bool isValidDictionary(AspellConfig * config, string const & lang, string const & variety); + int numDictionaries() const; bool checkAspellData(AspellConfig * config, string const & basepath, string const & datapath, string const & dictpath, string const & lang, string const & variety); @@ -313,6 +314,20 @@ AspellSpeller * AspellChecker::Private::speller(Language const * lang) } +int AspellChecker::Private::numDictionaries() const +{ + int result = 0; + Spellers::const_iterator it = spellers_.begin(); + Spellers::const_iterator et = spellers_.end(); + + for (; it != et; ++it) { + Speller aspell = it->second; + result += aspell.e_speller != 0; + } + return result; +} + + string AspellChecker::Private::toAspellWord(docstring const & word) const { size_t mpos; @@ -406,7 +421,7 @@ SpellChecker::Result AspellChecker::check(WordLangTuple const & word) AspellSpeller * m = d->speller(word.lang()); if (!m) - return WORD_OK; + return NO_DICTIONARY; if (word.word().empty()) // MSVC compiled Aspell doesn't like it. @@ -494,6 +509,12 @@ bool AspellChecker::hasDictionary(Language const * lang) const } +int AspellChecker::numDictionaries() const +{ + return d->numDictionaries(); +} + + docstring const AspellChecker::error() { Spellers::iterator it = d->spellers_.begin(); diff --git a/src/AspellChecker.h b/src/AspellChecker.h index dba55dc877..c2208498ec 100644 --- a/src/AspellChecker.h +++ b/src/AspellChecker.h @@ -31,6 +31,7 @@ public: void remove(WordLangTuple const &); void accept(WordLangTuple const &); bool hasDictionary(Language const * lang) const; + int numDictionaries() const; docstring const error(); void advanceChangeNumber(); //@} diff --git a/src/EnchantChecker.cpp b/src/EnchantChecker.cpp index cbccc34aae..61127108a4 100644 --- a/src/EnchantChecker.cpp +++ b/src/EnchantChecker.cpp @@ -112,7 +112,10 @@ SpellChecker::Result EnchantChecker::check(WordLangTuple const & word) { enchant::Dict * m = d->speller(word.lang()->code()); - if (!m || word.word().empty()) + if (!m) + return NO_DICTIONARY; + + if (word.word().empty()) return WORD_OK; string utf8word = to_utf8(word.word()); @@ -188,6 +191,12 @@ bool EnchantChecker::hasDictionary(Language const * lang) const } +int EnchantChecker::numDictionaries() const +{ + return d->spellers_.size(); +} + + docstring const EnchantChecker::error() { return docstring(); diff --git a/src/EnchantChecker.h b/src/EnchantChecker.h index 30cad28436..fc1b70b13a 100644 --- a/src/EnchantChecker.h +++ b/src/EnchantChecker.h @@ -37,6 +37,7 @@ public: void remove(WordLangTuple const &); void accept(WordLangTuple const &); bool hasDictionary(Language const * lang) const; + int numDictionaries() const; docstring const error(); void advanceChangeNumber(); ///@} diff --git a/src/HunspellChecker.cpp b/src/HunspellChecker.cpp index b2803c9679..d044889107 100644 --- a/src/HunspellChecker.cpp +++ b/src/HunspellChecker.cpp @@ -55,10 +55,13 @@ struct HunspellChecker::Private Private(); ~Private(); + void cleanCache(); + void setUserPath(std::string path); const string dictPath(int selector); bool haveLanguageFiles(string const & hpath); bool haveDictionary(Language const * lang, string & hpath); bool haveDictionary(Language const * lang); + int numDictionaries() const; Hunspell * addSpeller(Language const * lang, string & hpath); Hunspell * addSpeller(Language const * lang); Hunspell * speller(Language const * lang); @@ -74,31 +77,53 @@ struct HunspellChecker::Private IgnoreList ignored_; /// LangPersonalWordList personal_; + /// + std::string user_path_; /// the location below system/user directory /// there the aff+dic files lookup will happen const string dictDirectory(void) const { return "dicts"; } - int maxLookupSelector(void) const { return 3; } + int maxLookupSelector(void) const { return 4; } const string HunspellDictionaryName(Language const * lang) { return lang->variety().empty() ? lang->code() : lang->code() + "-" + lang->variety(); } + const string osPackageDictDirectory(void) { + return "/usr/share/myspell"; + } }; HunspellChecker::Private::Private() { + setUserPath(lyxrc.hunspelldir_path); } HunspellChecker::Private::~Private() +{ + cleanCache(); +} + + +void HunspellChecker::Private::setUserPath(std::string path) +{ + if (user_path_ != lyxrc.hunspelldir_path) { + cleanCache(); + user_path_ = path; + } +} + + +void HunspellChecker::Private::cleanCache() { Spellers::iterator it = spellers_.begin(); Spellers::iterator end = spellers_.end(); for (; it != end; ++it) { - if ( 0 != it->second) delete it->second; + delete it->second; + it->second = 0; } LangPersonalWordList::const_iterator pdit = personal_.begin(); @@ -125,6 +150,9 @@ bool HunspellChecker::Private::haveLanguageFiles(string const & hpath) const string HunspellChecker::Private::dictPath(int selector) { switch (selector) { + case 3: + return addName(osPackageDictDirectory(),dictDirectory()); + break; case 2: return addName(package().system_support().absFileName(),dictDirectory()); break; @@ -132,7 +160,7 @@ const string HunspellChecker::Private::dictPath(int selector) return addName(package().user_support().absFileName(),dictDirectory()); break; default: - return lyxrc.hunspelldir_path; + return user_path_; } } @@ -167,6 +195,8 @@ bool HunspellChecker::Private::haveDictionary(Language const * lang, string & hp bool HunspellChecker::Private::haveDictionary(Language const * lang) { bool result = false; + + setUserPath(lyxrc.hunspelldir_path); for ( int p = 0; !result && p < maxLookupSelector(); p++ ) { string lpath = dictPath(p); result = haveDictionary(lang, lpath); @@ -181,10 +211,11 @@ bool HunspellChecker::Private::haveDictionary(Language const * lang) Hunspell * HunspellChecker::Private::speller(Language const * lang) { + setUserPath(lyxrc.hunspelldir_path); Spellers::iterator it = spellers_.find(lang->lang()); - if (it != spellers_.end()) + if (it != spellers_.end()) { return it->second; - + } return addSpeller(lang); } @@ -228,6 +259,19 @@ Hunspell * HunspellChecker::Private::addSpeller(Language const * lang) } +int HunspellChecker::Private::numDictionaries() const +{ + int result = 0; + Spellers::const_iterator it = spellers_.begin(); + Spellers::const_iterator et = spellers_.end(); + + for (; it != et; ++it) { + result += it->second != 0; + } + return result; +} + + bool HunspellChecker::Private::isIgnored(WordLangTuple const & wl) const { IgnoreList::const_iterator it = ignored_.begin(); @@ -298,7 +342,7 @@ SpellChecker::Result HunspellChecker::check(WordLangTuple const & wl) Hunspell * h = d->speller(wl.lang()); if (!h) - return WORD_OK; + return NO_DICTIONARY; int info; string const encoding = h->get_dic_encoding(); @@ -377,6 +421,12 @@ bool HunspellChecker::hasDictionary(Language const * lang) const } +int HunspellChecker::numDictionaries() const +{ + return d->numDictionaries(); +} + + docstring const HunspellChecker::error() { return docstring(); diff --git a/src/HunspellChecker.h b/src/HunspellChecker.h index 8e12672b9d..ca28d01d64 100644 --- a/src/HunspellChecker.h +++ b/src/HunspellChecker.h @@ -31,6 +31,7 @@ public: void remove(WordLangTuple const &); void accept(WordLangTuple const &); bool hasDictionary(Language const * lang) const; + int numDictionaries() const; docstring const error(); void advanceChangeNumber(); ///@} diff --git a/src/SpellChecker.h b/src/SpellChecker.h index f94f5c5f3f..f87ef122b9 100644 --- a/src/SpellChecker.h +++ b/src/SpellChecker.h @@ -42,7 +42,9 @@ public: /// number of other ignored "word" IGNORED_WORD, /// number of personal dictionary "word" - LEARNED_WORD + LEARNED_WORD, + /// missing dictionary for language + NO_DICTIONARY }; virtual ~SpellChecker() {} @@ -51,6 +53,7 @@ public: static bool misspelled(Result res) { return res != WORD_OK && res != IGNORED_WORD + && res != NO_DICTIONARY && res != LEARNED_WORD; } /// check the given word of the given lang code and return the result @@ -71,6 +74,9 @@ public: /// check if dictionary exists virtual bool hasDictionary(Language const *) const = 0; + /// how many valid dictionaries were found + virtual int numDictionaries() const = 0; + /// if speller can spell check whole paragraph return true virtual bool canCheckParagraph() const { return false; } diff --git a/src/frontends/qt4/GuiSpellchecker.cpp b/src/frontends/qt4/GuiSpellchecker.cpp index 5e7305e75a..da8cca1ad3 100644 --- a/src/frontends/qt4/GuiSpellchecker.cpp +++ b/src/frontends/qt4/GuiSpellchecker.cpp @@ -375,6 +375,17 @@ void SpellcheckerWidget::Private::check() BufferView * bv = gv_->documentBufferView(); if (!bv || bv->buffer().text().empty()) return; + SpellChecker * speller = theSpellChecker(); + if (speller && !speller->hasDictionary(bv->buffer().language())) { + int dsize = speller->numDictionaries(); + if (0 == dsize) { + dv_->hide(); + QMessageBox::information(p, + qt_("Spell Checker"), + qt_("Spell checker has no dictionaries.")); + return; + } + } DocIterator from = bv->cursor(); DocIterator to; diff --git a/src/frontends/qt4/Menus.cpp b/src/frontends/qt4/Menus.cpp index 6cc3195f3e..c79471d4b9 100644 --- a/src/frontends/qt4/Menus.cpp +++ b/src/frontends/qt4/Menus.cpp @@ -808,6 +808,9 @@ void MenuDefinition::expandSpellingSuggestions(BufferView const * bv) FuncRequest(LFUN_SPELLING_REMOVE, arg))); } break; + case SpellChecker::NO_DICTIONARY: + LYXERR(Debug::GUI, "No dictionary for language " + from_ascii(wl.lang()->lang())); + // FALLTHROUGH case SpellChecker::WORD_OK: case SpellChecker::COMPOUND_WORD: case SpellChecker::ROOT_FOUND: diff --git a/status.20x b/status.20x index 3d9d597f4a..d1978797ae 100644 --- a/status.20x +++ b/status.20x @@ -65,6 +65,11 @@ What's new - Display some commands from mathtools.sty natively (bug 7949). +- Add the directory /usr/share/myspell as default location for dictionary + lookup of hunspell spell checker backend (a common location on linux). + Detect value change of preferences path to hunspell dictionaries + to avoid the need for a restart. This is related to bug 7884. + * DOCUMENTATION AND LOCALIZATION @@ -158,6 +163,8 @@ What's new - Fix tabbar visibility in fullscreen mode when opening/closing files (bug 7963). +- Show a message box if the current spell checker has no dictionaries (bug 7884). + * DOCUMENTATION AND LOCALIZATION -- 2.39.5