#include <config.h>
#include "ControlSpellchecker.h"
-#include "ViewBase.h"
#include "buffer.h"
#include "bufferparams.h"
#include "BufferView.h"
-#include "bufferview_funcs.h"
+#include "cursor.h"
+#include "CutAndPaste.h"
#include "debug.h"
#include "gettext.h"
#include "language.h"
#include "lyxrc.h"
-
-#include "PosIterator.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/tostr.h"
+#include "support/textutils.h"
+#include "support/convert.h"
#include "frontends/Alert.h"
-
-using lyx::support::bformat;
-
using std::advance;
using std::distance;
using std::endl;
using std::string;
+namespace lyx {
+
+using support::bformat;
+using support::contains;
+
+namespace frontend {
+
-ControlSpellchecker::ControlSpellchecker(LyXView & lv, Dialogs & d)
- : ControlDialogBD(lv, d),
+ControlSpellchecker::ControlSpellchecker(Dialog & parent)
+ : Dialog::Controller(parent), exitEarly_(false),
oldval_(0), newvalue_(0), count_(0)
{}
{}
-void ControlSpellchecker::setParams()
-{
- lyxerr[Debug::GUI] << "spell setParams" << endl;
- startSession();
-}
-
-
-void ControlSpellchecker::clearParams()
-{
- lyxerr[Debug::GUI] << "spell clearParams" << endl;
- endSession();
-}
-
-
namespace {
-
SpellBase * getSpeller(BufferParams const & bp)
{
string lang = (lyxrc.isp_use_alt_lang)
? 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
-void ControlSpellchecker::startSession()
+bool ControlSpellchecker::initialiseParams(std::string const &)
{
- lyxerr[Debug::GUI] << "spell startSession" << endl;
+ lyxerr[Debug::GUI] << "Spellchecker::initialiseParams" << endl;
- if (speller_.get()) {
- lyxerr[Debug::GUI] << "startSession: speller exists" << endl;
- speller_.reset(0);
- return;
- }
-
- speller_.reset(getSpeller(buffer()->params()));
+ speller_.reset(getSpeller(kernel().buffer().params()));
+ if (!speller_.get())
+ return false;
// reset values to initial
oldval_ = 0;
newvalue_ = 0;
count_ = 0;
- emergency_exit_ = false;
- // start off the check
- if (speller_->error().empty()) {
- check();
- return;
- }
+ bool const success = speller_->error().empty();
- emergency_exit_ = true;
- string message = speller_->error();
- if (message.empty())
- message = _("The spell-checker could not be started.\n"
- "Maybe it is mis-configured.");
+ if (!success) {
+ Alert::error(_("Spellchecker error"),
+ _("The spellchecker could not be started\n")
+ + speller_->error());
+ speller_.reset(0);
+ }
- Alert::error(_("The spell-checker has failed"), message);
- speller_.reset(0);
+ return success;
}
-void ControlSpellchecker::endSession()
+void ControlSpellchecker::clearParams()
{
- lyxerr[Debug::GUI] << "spell endSession" << endl;
-
- emergency_exit_ = true;
-
- if (!speller_.get()) {
- lyxerr[Debug::GUI] << "endSession with no speller" << endl;
- return;
- }
-
+ lyxerr[Debug::GUI] << "Spellchecker::clearParams" << endl;
speller_.reset(0);
}
namespace {
-
-bool isLetter(PosIterator & cur)
+bool isLetter(DocIterator const & cur)
{
- return !cur.at_end()
- && cur.pit()->isLetter(cur.pos())
- && !isDeletedText(*cur.pit(), cur.pos())
- && (!cur.inset() || cur.inset()->allowSpellCheck());
+ return cur.inTexted()
+ && cur.inset().allowSpellCheck()
+ && cur.pos() != cur.lastpos()
+ && (cur.paragraph().isLetter(cur.pos())
+ // We want to pass the ' and escape chars to ispell
+ || contains(lyxrc.isp_esc_chars + '\'',
+ cur.paragraph().getChar(cur.pos())))
+ && !isDeletedText(cur.paragraph(), cur.pos());
}
-WordLangTuple nextWord(PosIterator & cur, PosIterator const & end,
- int & progress, BufferParams & bp)
+WordLangTuple nextWord(DocIterator & cur, ptrdiff_t & progress,
+ BufferParams & bp)
{
- // skip until we have real text (will jump paragraphs)
- for (; cur != end && !isLetter(cur); ++cur, ++progress);
-
- if (cur == end)
- return WordLangTuple(string(), string());
-
- string lang_code = cur.pit()->getFontSettings(bp, cur.pos()).language()->code();
- string str;
- // and find the end of the word (insets like optional hyphens
- // and ligature break are part of a word)
- for (; cur != end && isLetter(cur); ++cur, ++progress) {
- if (!cur.pit()->isInset(cur.pos()))
- str += cur.pit()->getChar(cur.pos());
+ bool inword = false;
+ bool ignoreword = false;
+ string word, lang_code;
+
+ while (cur.depth()) {
+ if (isLetter(cur)) {
+ if (!inword) {
+ inword = true;
+ ignoreword = false;
+ word.clear();
+ lang_code = cur.paragraph().getFontSettings(bp, cur.pos()).language()->code();
+ }
+ // Insets like optional hyphens and ligature
+ // break are part of a word.
+ if (!cur.paragraph().isInset(cur.pos())) {
+ Paragraph::value_type const c =
+ cur.paragraph().getChar(cur.pos());
+ word += c;
+ if (IsDigit(c))
+ ignoreword = true;
+ }
+ } else { // !isLetter(cur)
+ if (inword)
+ if (!word.empty() && !ignoreword)
+ return WordLangTuple(word, lang_code);
+ else
+ inword = false;
+ }
+
+ cur.forwardPos();
+ ++progress;
}
- return WordLangTuple(str, lang_code);
+ return WordLangTuple(string(), string());
}
-
-} //namespace anon
-
+} // namespace anon
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;
- PosIterator cur(*bufferview());
- PosIterator const beg = buffer()->pos_iterator_begin();
- PosIterator const end = buffer()->pos_iterator_end();
+ DocIterator cur = kernel().bufferview()->cursor();
+ while (cur && cur.pos() && isLetter(cur)) {
+ cur.backwardPos();
+ }
- int start = distance(beg, cur);
- int const total = start + distance(cur, end);
+ ptrdiff_t start = 0, total = 0;
+ DocIterator it = DocIterator(kernel().buffer().inset());
+ for (start = 0; it != cur; it.forwardPos())
+ ++start;
- if (cur != buffer()->pos_iterator_begin())
- for (; cur != end && isLetter(cur); ++cur, ++start);
+ for (total = start; it; it.forwardPos())
+ ++total;
- while (res == SpellBase::OK || res == SpellBase::IGNORE) {
- word_ = nextWord(cur, end, start, buffer()->params());
+ BufferParams & bufferparams = kernel().buffer().params();
+ exitEarly_ = false;
+
+ while (res == SpellBase::OK || res == SpellBase::IGNORED_WORD) {
+ word_ = nextWord(cur, start, bufferparams);
// end of document
- if (word_.word().empty())
- break;
+ if (getWord().empty()) {
+ showSummary();
+ exitEarly_ = true;
+ return;
+ }
++count_;
lyxerr[Debug::GUI] << "Updating spell progress." << endl;
oldval_ = newvalue_;
// set progress bar
- view().partialUpdate(SPELL_PROGRESSED);
+ dialog().view().partialUpdate(SPELL_PROGRESSED);
}
// speller might be dead ...
return;
}
- lyxerr[Debug::GUI] << "Found word \"" << word_.word() << "\"" << endl;
+ lyxerr[Debug::GUI] << "Found word \"" << getWord() << "\"" << endl;
- if (!word_.word().empty()) {
- int const size = word_.word().size();
- advance(cur, -size);
- bufferview()->putSelectionAt(cur, size, false);
- advance(cur, size);
- } else {
- showSummary();
- endSession();
- 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;
- view().partialUpdate(SPELL_FOUND_WORD);
+ dialog().view().partialUpdate(SPELL_FOUND_WORD);
}
}
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();
- view().hide();
- speller_.reset(0);
+ dialog().CancelButton();
- Alert::error(_("The spell-checker has failed"), message);
+ Alert::error(_("The spellchecker has failed"), message);
return false;
}
void ControlSpellchecker::showSummary()
{
if (!checkAlive() || count_ == 0) {
- view().hide();
+ dialog().CancelButton();
return;
}
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.");
- view().hide();
- Alert::information(_("Spell-checking is complete"), message);
+ dialog().CancelButton();
+ Alert::information(_("Spelling check completed"), message);
}
void ControlSpellchecker::replace(string const & replacement)
{
- bufferview()->replaceWord(replacement);
+ lyxerr << "ControlSpellchecker::replace("
+ << replacement << ")" << std::endl;
+ BufferView & bufferview = *kernel().bufferview();
+ cap::replaceWord(bufferview.cursor(), replacement);
+ kernel().buffer().markDirty();
+ bufferview.update();
// fix up the count
--count_;
check();
speller_->accept(word_);
check();
}
+
+} // namespace frontend
+} // namespace lyx