#7884 add check for missing dictionaries when spell check starts and popup a message box to tell the user this problem if there are no dictionaries; add /usr/share/myspell for hunspell dictionary lookup

git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@40568 a592a061-630c-0410-9148-cb99ea01b6c8
This commit is contained in:
Stephan Witt 2012-01-04 22:02:07 +00:00
parent 9402ad6f61
commit c91e2c59f4
9 changed files with 119 additions and 10 deletions

View File

@ -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);

View File

@ -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;

View File

@ -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();

View File

@ -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();
//@}

View File

@ -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();

View File

@ -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();
///@}

View File

@ -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; }

View File

@ -485,6 +485,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) {
hide();
QMessageBox::information(p,
qt_("Spell Checker"),
qt_("Spell checker has no dictionaries."));
return;
}
}
DocIterator from = bv->cursor();
DocIterator to = isCurrentBuffer(from) ? end_ : doc_iterator_end(&bv->buffer());

View File

@ -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: