mirror of
https://git.lyx.org/repos/lyx.git
synced 2024-11-09 18:31:04 +00:00
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
This commit is contained in:
parent
b5ef74803d
commit
12e0991465
@ -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<string, string>::const_iterator it = d->languageMap.begin();
|
||||
map<string, string>::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);
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
|
@ -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();
|
||||
//@}
|
||||
|
@ -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();
|
||||
|
@ -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();
|
||||
///@}
|
||||
|
@ -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();
|
||||
|
@ -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();
|
||||
///@}
|
||||
|
@ -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; }
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user