]> git.lyx.org Git - lyx.git/blobdiff - src/frontends/controllers/ControlSpellchecker.C
fix crash due to invalidated iterator
[lyx.git] / src / frontends / controllers / ControlSpellchecker.C
index 9f8098806af4f0686625bf04a9e8935823d702f6..7e0c88d281d247a926c71ca8c48e638e65ac2387 100644 (file)
 #include "lyxrc.h"
 #include "paragraph.h"
 
-#include "ispell.h"
-#ifdef USE_PSPELL
-# include "pspell.h"
-#else
-#ifdef USE_ASPELL
+#if defined(USE_ASPELL)
 # include "aspell_local.h"
+#elif defined(USE_PSPELL)
+# include "pspell.h"
 #endif
+
+#if defined(USE_ISPELL)
+# include "ispell.h"
+#else
+# include "SpellBase.h"
 #endif
 
 #include "support/textutils.h"
-#include "support/tostr.h"
+#include "support/convert.h"
 
 #include "frontends/Alert.h"
 
@@ -51,7 +54,7 @@ namespace frontend {
 
 
 ControlSpellchecker::ControlSpellchecker(Dialog & parent)
-       : Dialog::Controller(parent),
+       : Dialog::Controller(parent), exitEarly_(false),
          oldval_(0), newvalue_(0), count_(0)
 {}
 
@@ -68,19 +71,22 @@ SpellBase * getSpeller(BufferParams const & bp)
                      ? lyxrc.isp_alt_lang
                      : bp.language->code();
 
-#ifdef USE_ASPELL
+#if defined(USE_ASPELL)
        if (lyxrc.use_spell_lib)
                return new ASpell(bp, lang);
-#endif
-#ifdef USE_PSPELL
+#elif defined(USE_PSPELL)
        if (lyxrc.use_spell_lib)
                return new PSpell(bp, lang);
 #endif
 
+#if defined(USE_ISPELL)
        lang = (lyxrc.isp_use_alt_lang) ?
                lyxrc.isp_alt_lang : bp.language->lang();
 
        return new ISpell(bp, lang);
+#else
+       return new SpellBase;
+#endif
 }
 
 } // namespace anon
@@ -91,6 +97,8 @@ bool ControlSpellchecker::initialiseParams(std::string const &)
        lyxerr[Debug::GUI] << "Spellchecker::initialiseParams" << endl;
 
        speller_.reset(getSpeller(kernel().buffer().params()));
+       if (!speller_.get())
+               return false;
 
        // reset values to initial
        oldval_ = 0;
@@ -100,8 +108,9 @@ bool ControlSpellchecker::initialiseParams(std::string const &)
        bool const success = speller_->error().empty();
 
        if (!success) {
-               Alert::error(_("The spell-checker could not be started"),
-                            speller_->error());
+               Alert::error(_("Spellchecker error"),
+                            _("The spellchecker could not be started\n")
+                            + speller_->error());
                speller_.reset(0);
        }
 
@@ -123,9 +132,9 @@ bool isLetter(DocIterator const & cur)
        return cur.inTexted()
                && cur.inset().allowSpellCheck()
                && cur.pos() != cur.lastpos()
-               && (cur.paragraph().isLetter(cur.pos()) 
+               && (cur.paragraph().isLetter(cur.pos())
                    // We want to pass the ' and escape chars to ispell
-                   || contains(lyxrc.isp_esc_chars + '\'', 
+                   || contains(lyxrc.isp_esc_chars + '\'',
                                cur.paragraph().getChar(cur.pos())))
                && !isDeletedText(cur.paragraph(), cur.pos());
 }
@@ -138,7 +147,7 @@ WordLangTuple nextWord(DocIterator & cur, ptrdiff_t & progress,
        bool ignoreword = false;
        string word, lang_code;
 
-       while(cur.size()) {
+       while (cur.depth()) {
                if (isLetter(cur)) {
                        if (!inword) {
                                inword = true;
@@ -147,22 +156,22 @@ WordLangTuple nextWord(DocIterator & cur, ptrdiff_t & progress,
                                lang_code = cur.paragraph().getFontSettings(bp, cur.pos()).language()->code();
                        }
                        // Insets like optional hyphens and ligature
-                       // break are part of a word. 
+                       // break are part of a word.
                        if (!cur.paragraph().isInset(cur.pos())) {
-                               Paragraph::value_type const c = 
+                               Paragraph::value_type const c =
                                        cur.paragraph().getChar(cur.pos());
                                word += c;
                                if (IsDigit(c))
                                        ignoreword = true;
-                       } 
+                       }
                } else { // !isLetter(cur)
-                       if (inword) 
-                               if (!ignoreword)
+                       if (inword)
+                               if (!word.empty() && !ignoreword)
                                        return WordLangTuple(word, lang_code);
                                else
                                        inword = false;
                }
-               
+
                cur.forwardPos();
                ++progress;
        }
@@ -176,11 +185,14 @@ WordLangTuple nextWord(DocIterator & cur, ptrdiff_t & progress,
 
 void ControlSpellchecker::check()
 {
-       lyxerr[Debug::GUI] << "spell check a word" << endl;
+       lyxerr[Debug::GUI] << "Check the spelling of a word" << endl;
 
        SpellBase::Result res = SpellBase::OK;
 
        DocIterator cur = kernel().bufferview()->cursor();
+       while (cur && cur.pos() && isLetter(cur)) {
+               cur.backwardPos();
+       }
 
        ptrdiff_t start = 0, total = 0;
        DocIterator it = DocIterator(kernel().buffer().inset());
@@ -190,17 +202,18 @@ void ControlSpellchecker::check()
        for (total = start; it; it.forwardPos())
                ++total;
 
-       for (; cur && isLetter(cur); cur.forwardPos())
-               ++start;
-
        BufferParams & bufferparams = kernel().buffer().params();
+       exitEarly_ = false;
 
-       while (res == SpellBase::OK || res == SpellBase::IGNORE) {
+       while (res == SpellBase::OK || res == SpellBase::IGNORED_WORD) {
                word_ = nextWord(cur, start, bufferparams);
 
                // end of document
-               if (getWord().empty())
-                       break;
+               if (getWord().empty()) {
+                       showSummary();
+                       exitEarly_ = true;
+                       return;
+               }
 
                ++count_;
 
@@ -227,17 +240,15 @@ void ControlSpellchecker::check()
 
        lyxerr[Debug::GUI] << "Found word \"" << getWord() << "\"" << endl;
 
-       if (getWord().empty()) {
-               showSummary();
-               return;
-       }
-
        int const size = getWord().size();
        cur.pos() -= size;
        kernel().bufferview()->putSelectionAt(cur, size, false);
+       // if we used a lfun like in find/replace, dispatch would do
+       // that for us
+       kernel().bufferview()->update();
 
        // set suggestions
-       if (res != SpellBase::OK && res != SpellBase::IGNORE) {
+       if (res != SpellBase::OK && res != SpellBase::IGNORED_WORD) {
                lyxerr[Debug::GUI] << "Found a word needing checking." << endl;
                dialog().view().partialUpdate(SPELL_FOUND_WORD);
        }
@@ -249,14 +260,17 @@ bool ControlSpellchecker::checkAlive()
        if (speller_->alive() && speller_->error().empty())
                return true;
 
-       string message = speller_->error();
-       if (message.empty())
-               message = _("The spell-checker has died for some reason.\n"
-                        "Maybe it has been killed.");
+       string message;
+       if (speller_->error().empty())
+               message = _("The spellchecker has died for some reason.\n"
+                           "Maybe it has been killed.");
+       else
+               message = _("The spellchecker has failed.\n") 
+                       + speller_->error();
 
        dialog().CancelButton();
 
-       Alert::error(_("The spell-checker has failed"), message);
+       Alert::error(_("The spellchecker has failed"), message);
        return false;
 }
 
@@ -270,12 +284,12 @@ void ControlSpellchecker::showSummary()
 
        string message;
        if (count_ != 1)
-               message = bformat(_("%1$s words checked."), tostr(count_));
+               message = bformat(_("%1$d words checked."), count_);
        else
                message = _("One word checked.");
 
        dialog().CancelButton();
-       Alert::information(_("Spell-checking is complete"), message);
+       Alert::information(_("Spelling check completed"), message);
 }