From: André Pönitz Date: Sat, 6 Oct 2007 19:51:03 +0000 (+0000) Subject: next one X-Git-Tag: 1.6.10~7974 X-Git-Url: https://git.lyx.org/gitweb/?a=commitdiff_plain;h=e093f9212b5fbb09811d2a27aa381105136e9cc5;hp=86af8a28118f486ee14c22a35351064d0a4a32a2;p=lyx.git next one git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@20797 a592a061-630c-0410-9148-cb99ea01b6c8 --- diff --git a/src/frontends/Dialogs.cpp b/src/frontends/Dialogs.cpp index 8f1969553d..9095d92369 100644 --- a/src/frontends/Dialogs.cpp +++ b/src/frontends/Dialogs.cpp @@ -194,7 +194,7 @@ void Dialogs::checkStatus() for(; it != end; ++it) { Dialog * const dialog = it->second.get(); - if (dialog->isVisibleView()) + if (dialog && dialog->isVisibleView()) dialog->checkStatus(); } } diff --git a/src/frontends/controllers/ControlSpellchecker.cpp b/src/frontends/controllers/ControlSpellchecker.cpp deleted file mode 100644 index 42e8897b0e..0000000000 --- a/src/frontends/controllers/ControlSpellchecker.cpp +++ /dev/null @@ -1,348 +0,0 @@ -/** - * \file ControlSpellchecker.cpp - * This file is part of LyX, the document processor. - * Licence details can be found in the file COPYING. - * - * \author Edwin Leuven - * - * Full author contact details are available in file CREDITS. - */ - -#include - -#include "ControlSpellchecker.h" - -#include "Buffer.h" -#include "BufferParams.h" -#include "BufferView.h" -#include "Cursor.h" -#include "CutAndPaste.h" -#include "debug.h" -#include "gettext.h" -#include "Language.h" -#include "LyXRC.h" -#include "Paragraph.h" - -#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/convert.h" -#include "support/docstring.h" - -#include "frontends/alert.h" -// FIXME: those two headers are needed because of the -// WorkArea::redraw() call below. -#include "frontends/LyXView.h" -#include "frontends/WorkArea.h" - -using std::advance; -using std::distance; -using std::endl; -using std::string; - -namespace lyx { - -using support::bformat; -using support::contains; - -namespace frontend { - - -ControlSpellchecker::ControlSpellchecker(Dialog & parent) - : Controller(parent), exitEarly_(false), - oldval_(0), newvalue_(0), count_(0), speller_(0) -{ -} - - -ControlSpellchecker::~ControlSpellchecker() -{ - delete speller_; -} - - -static SpellBase * getSpeller(BufferParams const & bp) -{ - string lang = (lyxrc.isp_use_alt_lang) - ? lyxrc.isp_alt_lang - : bp.language->code(); - -#if defined(USE_ASPELL) - if (lyxrc.use_spell_lib) - return new ASpell(bp, lang); -#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 -} - - -bool ControlSpellchecker::initialiseParams(std::string const &) -{ - LYXERR(Debug::GUI) << "Spellchecker::initialiseParams" << endl; - - speller_ = getSpeller(buffer().params()); - if (!speller_) - return false; - - // reset values to initial - oldval_ = 0; - newvalue_ = 0; - count_ = 0; - - bool const success = speller_->error().empty(); - - if (!success) { - Alert::error(_("Spellchecker error"), - _("The spellchecker could not be started\n") - + speller_->error()); - delete speller_; - speller_ = 0; - } - - return success; -} - - -void ControlSpellchecker::clearParams() -{ - LYXERR(Debug::GUI) << "Spellchecker::clearParams" << endl; - delete speller_; - speller_ = 0; -} - - -static bool isLetter(DocIterator const & dit) -{ - return dit.inTexted() - && dit.inset().allowSpellCheck() - && dit.pos() != dit.lastpos() - && (dit.paragraph().isLetter(dit.pos()) - // We want to pass the ' and escape chars to ispell - || contains(from_utf8(lyxrc.isp_esc_chars + '\''), - dit.paragraph().getChar(dit.pos()))) - && !dit.paragraph().isDeleted(dit.pos()); -} - - -static WordLangTuple nextWord(Cursor & cur, ptrdiff_t & progress) -{ - BufferParams const & bp = cur.bv().buffer().params(); - bool inword = false; - bool ignoreword = false; - cur.resetAnchor(); - docstring word; - string lang_code; - - while (cur.depth()) { - if (isLetter(cur)) { - if (!inword) { - inword = true; - ignoreword = false; - cur.resetAnchor(); - 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) { - cur.setSelection(); - return WordLangTuple(word, lang_code); - } - inword = false; - } - - cur.forwardPos(); - ++progress; - } - - return WordLangTuple(docstring(), string()); -} - - -void ControlSpellchecker::check() -{ - LYXERR(Debug::GUI) << "Check the spelling of a word" << endl; - - SpellBase::Result res = SpellBase::OK; - - Cursor cur = bufferview()->cursor(); - while (cur && cur.pos() && isLetter(cur)) - cur.backwardPos(); - - ptrdiff_t start = 0; - ptrdiff_t total = 0; - DocIterator it = DocIterator(buffer().inset()); - for (start = 0; it != cur; it.forwardPos()) - ++start; - - for (total = start; it; it.forwardPos()) - ++total; - - exitEarly_ = false; - - while (res == SpellBase::OK || res == SpellBase::IGNORED_WORD) { - word_ = nextWord(cur, start); - - // end of document - if (getWord().empty()) { - showSummary(); - exitEarly_ = true; - return; - } - - ++count_; - - // Update slider if and only if value has changed - float progress = total ? float(start)/total : 1; - newvalue_ = int(100.0 * progress); - if (newvalue_!= oldval_) { - LYXERR(Debug::GUI) << "Updating spell progress." << endl; - oldval_ = newvalue_; - // set progress bar - dialog().partialUpdateView(SPELL_PROGRESSED); - } - - // speller might be dead ... - if (!checkAlive()) - return; - - res = speller_->check(word_); - - // ... or it might just be reporting an error - if (!checkAlive()) - return; - } - - LYXERR(Debug::GUI) << "Found word \"" << to_utf8(getWord()) << "\"" << endl; - - int const size = cur.selEnd().pos() - cur.selBegin().pos(); - cur.pos() -= size; - bufferview()->putSelectionAt(cur, size, false); - // FIXME: if we used a lfun like in find/replace, dispatch would do - // that for us - bufferview()->update(); - // FIXME: this Controller is very badly designed... - lyxview().currentWorkArea()->redraw(); - - // set suggestions - if (res != SpellBase::OK && res != SpellBase::IGNORED_WORD) { - LYXERR(Debug::GUI) << "Found a word needing checking." << endl; - dialog().partialUpdateView(SPELL_FOUND_WORD); - } -} - - -bool ControlSpellchecker::checkAlive() -{ - if (speller_->alive() && speller_->error().empty()) - return true; - - docstring 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().slotClose(); - - Alert::error(_("The spellchecker has failed"), message); - return false; -} - - -void ControlSpellchecker::showSummary() -{ - if (!checkAlive() || count_ == 0) { - dialog().slotClose(); - return; - } - - docstring message; - if (count_ != 1) - message = bformat(_("%1$d words checked."), count_); - else - message = _("One word checked."); - - dialog().slotClose(); - Alert::information(_("Spelling check completed"), message); -} - - -void ControlSpellchecker::replace(docstring const & replacement) -{ - LYXERR(Debug::GUI) << "ControlSpellchecker::replace(" - << to_utf8(replacement) << ")" << std::endl; - cap::replaceSelectionWithString(bufferview()->cursor(), replacement, true); - buffer().markDirty(); - // If we used an LFUN, we would not need that - bufferview()->update(); - // fix up the count - --count_; - check(); -} - - -void ControlSpellchecker::replaceAll(docstring const & replacement) -{ - // TODO: add to list - replace(replacement); -} - - -void ControlSpellchecker::insert() -{ - speller_->insert(word_); - check(); -} - - -docstring const ControlSpellchecker::getSuggestion() const -{ - return speller_->nextMiss(); -} - - -docstring const ControlSpellchecker::getWord() const -{ - return word_.word(); -} - - -void ControlSpellchecker::ignoreAll() -{ - speller_->accept(word_); - check(); -} - -} // namespace frontend -} // namespace lyx diff --git a/src/frontends/controllers/ControlSpellchecker.h b/src/frontends/controllers/ControlSpellchecker.h deleted file mode 100644 index 28e314c518..0000000000 --- a/src/frontends/controllers/ControlSpellchecker.h +++ /dev/null @@ -1,104 +0,0 @@ -// -*- C++ -*- -/** - * \file ControlSpellchecker.h - * This file is part of LyX, the document processor. - * Licence details can be found in the file COPYING. - * - * \author Edwin Leuven - * - * Full author contact details are available in file CREDITS. - */ - -#ifndef CONTROLSPELLCHECKER_H -#define CONTROLSPELLCHECKER_H - -#include "Dialog.h" -#include "WordLangTuple.h" - - -namespace lyx { - -class SpellBase; - -namespace frontend { - -/** A controller for Spellchecker dialogs. - */ -class ControlSpellchecker : public Controller -{ -public: - enum State { - SPELL_PROGRESSED, //< update progress bar - SPELL_FOUND_WORD //< found a bad word - }; - - ControlSpellchecker(Dialog &); - ~ControlSpellchecker(); - /// - virtual bool initialiseParams(std::string const & data); - /// - virtual void clearParams(); - /// Not needed here - virtual void dispatchParams() {} - /// - virtual bool isBufferDependent() const { return true; } - /// - virtual bool exitEarly() const { return exitEarly_; } - - /// replace word with replacement - void replace(docstring const &); - - /// replace all occurances of word - void replaceAll(docstring const &); - - /// insert word in personal dictionary - void insert(); - - /// ignore all occurances of word - void ignoreAll(); - - /// check text until next misspelled/unknown word - /// returns true when finished - void check(); - - /// get suggestion - docstring const getSuggestion() const; - - /// get word - docstring const getWord() const; - - /// returns progress value - int getProgress() const { return oldval_; } - - /// returns word count - int getCount() const { return count_; } - -private: - /// give error message is spellchecker dies - bool checkAlive(); - - /// show count of checked words at normal exit - void showSummary(); - -private: - /// set to true when spellchecking is finished - bool exitEarly_; - - /// current word being checked and lang code - WordLangTuple word_; - - /// values for progress - int oldval_; - int newvalue_; - - /// word count - int count_; - - /// The actual spellchecker object - SpellBase * speller_; -}; - -} // namespace frontend -} // namespace lyx - -#endif // CONTROLSPELLCHECKER_H diff --git a/src/frontends/controllers/Makefile.am b/src/frontends/controllers/Makefile.am index 75587338c9..ffb999b38e 100644 --- a/src/frontends/controllers/Makefile.am +++ b/src/frontends/controllers/Makefile.am @@ -20,7 +20,6 @@ SOURCEFILES = \ ControlPrint.cpp \ ControlSearch.cpp \ ControlSendto.cpp \ - ControlSpellchecker.cpp \ ControlThesaurus.cpp \ ControlToc.cpp \ frontend_helpers.cpp @@ -38,7 +37,6 @@ HEADERFILES = \ ControlPrint.h \ ControlSearch.h \ ControlSendto.h \ - ControlSpellchecker.h \ ControlThesaurus.h \ ControlToc.h \ frontend_helpers.h diff --git a/src/frontends/qt4/Dialogs.cpp b/src/frontends/qt4/Dialogs.cpp index 65be9a6835..c98f957fcc 100644 --- a/src/frontends/qt4/Dialogs.cpp +++ b/src/frontends/qt4/Dialogs.cpp @@ -30,7 +30,6 @@ #include "GuiSearch.h" #include "GuiSendto.h" #include "GuiShowFile.h" -#include "GuiSpellchecker.h" #include "GuiToc.h" #include "GuiView.h" #include "TocWidget.h" @@ -141,110 +140,107 @@ Dialog * Dialogs::build(string const & name) { BOOST_ASSERT(isValidName(name)); - Dialog * dialog = 0; GuiViewBase & guiview = static_cast(lyxview_); - if (name == "aboutlyx") { - dialog = createGuiAbout(lyxview_); - } else if (name == "bibitem") { - dialog = new GuiBibitemDialog(lyxview_); - } else if (name == "bibtex") { - dialog = createGuiBibtex(lyxview_); - } else if (name == "box") { - dialog = createGuiBox(lyxview_); - } else if (name == "branch") { - dialog = createGuiBranch(lyxview_); - } else if (name == "changes") { - dialog = createGuiChanges(lyxview_); - } else if (name == "character") { - dialog = createGuiCharacter(lyxview_); - } else if (name == "citation") { - dialog = createGuiCitation(lyxview_); - } else if (name == "document") { - dialog = new GuiDocumentDialog(lyxview_); - } else if (name == "embedding") { - dialog = createGuiEmbeddedFiles(lyxview_); - } else if (name == "errorlist") { - dialog = createGuiErrorList(lyxview_); - } else if (name == "ert") { - dialog = createGuiERT(lyxview_); - } else if (name == "external") { - dialog = new GuiExternalDialog(lyxview_); - } else if (name == "file") { - dialog = createGuiShowFile(lyxview_); - } else if (name == "findreplace") { - dialog = new GuiSearchDialog(lyxview_); - } else if (name == "float") { - dialog = createGuiFloat(lyxview_); - } else if (name == "graphics") { - dialog = new GuiGraphicsDialog(lyxview_); - } else if (name == "include") { - dialog = createGuiInclude(lyxview_); - } else if (name == "index") { - dialog = new GuiIndexDialog(lyxview_); - } else if (name == "nomenclature") { - dialog = new GuiNomenclDialog(lyxview_); - } else if (name == "label") { - dialog = new GuiLabelDialog(lyxview_); - } else if (name == "log") { - dialog = createGuiLog(lyxview_); - } else if (name == "view-source") { - dialog = createGuiViewSource(lyxview_); - } else if (name == "mathdelimiter") { - dialog = new GuiDelimiterDialog(lyxview_); - } else if (name == "mathmatrix") { - dialog = new GuiMathMatrixDialog(lyxview_); - } else if (name == "note") { - dialog = createGuiNote(lyxview_); - } else if (name == "paragraph") { + if (name == "aboutlyx") + return createGuiAbout(lyxview_); + if (name == "bibitem") + return new GuiBibitemDialog(lyxview_); + if (name == "bibtex") + return createGuiBibtex(lyxview_); + if (name == "box") + return createGuiBox(lyxview_); + if (name == "branch") + return createGuiBranch(lyxview_); + if (name == "changes") + return createGuiChanges(lyxview_); + if (name == "character") + return createGuiCharacter(lyxview_); + if (name == "citation") + return createGuiCitation(lyxview_); + if (name == "document") + return new GuiDocumentDialog(lyxview_); + if (name == "embedding") + return createGuiEmbeddedFiles(lyxview_); + if (name == "errorlist") + return createGuiErrorList(lyxview_); + if (name == "ert") + return createGuiERT(lyxview_); + if (name == "external") + return new GuiExternalDialog(lyxview_); + if (name == "file") + return createGuiShowFile(lyxview_); + if (name == "findreplace") + return new GuiSearchDialog(lyxview_); + if (name == "float") + return createGuiFloat(lyxview_); + if (name == "graphics") + return new GuiGraphicsDialog(lyxview_); + if (name == "include") + return createGuiInclude(lyxview_); + if (name == "index") + return new GuiIndexDialog(lyxview_); + if (name == "nomenclature") + return new GuiNomenclDialog(lyxview_); + if (name == "label") + return new GuiLabelDialog(lyxview_); + if (name == "log") + return createGuiLog(lyxview_); + if (name == "view-source") + return createGuiViewSource(lyxview_); + if (name == "mathdelimiter") + return new GuiDelimiterDialog(lyxview_); + if (name == "mathmatrix") + return new GuiMathMatrixDialog(lyxview_); + if (name == "note") + return createGuiNote(lyxview_); + if (name == "paragraph") { #ifdef USE_DOCK_WIDGET - DockView * dv = - new DockView(guiview, name, - Qt::TopDockWidgetArea); + return new DockView(guiview, name, + Qt::TopDockWidgetArea); #else - DialogView * dv = - new DialogView(guiview, name); + return new DialogView(guiview, name); #endif - dialog = dv; - } else if (name == "prefs") { - dialog = new GuiPrefsDialog(lyxview_); - } else if (name == "print") { - dialog = new GuiPrintDialog(lyxview_); - } else if (name == "ref") { - dialog = createGuiRef(lyxview_); - } else if (name == "sendto") { - dialog = new GuiSendtoDialog(lyxview_); - } else if (name == "spellchecker") { - dialog = new GuiSpellcheckerDialog(lyxview_); - } else if (name == "tabular") { - dialog = createGuiTabular(lyxview_); - } else if (name == "tabularcreate") { - dialog = createGuiTabularCreate(lyxview_); - } else if (name == "texinfo") { - dialog = createGuiTexInfo(lyxview_); + } + if (name == "prefs") + return new GuiPrefsDialog(lyxview_); + if (name == "print") + return new GuiPrintDialog(lyxview_); + if (name == "ref") + return createGuiRef(lyxview_); + if (name == "sendto") + return new GuiSendtoDialog(lyxview_); + if (name == "spellchecker") + return createGuiSpellchecker(lyxview_); + if (name == "tabular") + return createGuiTabular(lyxview_); + if (name == "tabularcreate") + return createGuiTabularCreate(lyxview_); + if (name == "texinfo") + return createGuiTexInfo(lyxview_); #ifdef HAVE_LIBAIKSAURUS - } else if (name == "thesaurus") { - dialog = new GuiThesaurusDialog(lyxview_); + if (name == "thesaurus") + return new GuiThesaurusDialog(lyxview_); #endif - } else if (name == "toc") { + if (name == "toc") { #ifdef Q_WS_MACX // On Mac show as a drawer at the right - dialog = new DockView(guiview, name, + return new DockView(guiview, name, Qt::RightDockWidgetArea, Qt::Drawer); #else - dialog = new DockView(guiview, name); + return new DockView(guiview, name); #endif - } else if (name == "url") { - dialog = new GuiURLDialog(lyxview_); - } else if (name == "vspace") { - dialog = createGuiVSpace(lyxview_); - } else if (name == "wrap") { - dialog = createGuiWrap(lyxview_); - } else if (name == "listings") { - dialog = createGuiListings(lyxview_); } - - return dialog; + if (name == "url") + return new GuiURLDialog(lyxview_); + if (name == "vspace") + return createGuiVSpace(lyxview_); + if (name == "wrap") + return createGuiWrap(lyxview_); + if (name == "listings") + return createGuiListings(lyxview_); + + return 0; } diff --git a/src/frontends/qt4/GuiSpellchecker.cpp b/src/frontends/qt4/GuiSpellchecker.cpp index 52302e418b..2236de3ee5 100644 --- a/src/frontends/qt4/GuiSpellchecker.cpp +++ b/src/frontends/qt4/GuiSpellchecker.cpp @@ -4,6 +4,7 @@ * Licence details can be found in the file COPYING. * * \author John Levon + * \author Edwin Leuven * * Full author contact details are available in file CREDITS. */ @@ -12,9 +13,23 @@ #include "GuiSpellchecker.h" -#include "ControlSpellchecker.h" #include "qt_helpers.h" +#include "Buffer.h" +#include "BufferParams.h" +#include "BufferView.h" +#include "Cursor.h" +#include "CutAndPaste.h" +#include "debug.h" +#include "gettext.h" +#include "Language.h" +#include "LyXRC.h" +#include "Paragraph.h" + +#include "support/textutils.h" +#include "support/convert.h" +#include "support/docstring.h" + #include #include #include @@ -25,33 +40,54 @@ #include #include - +#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 "frontends/alert.h" +// FIXME: those two headers are needed because of the +// WorkArea::redraw() call below. +#include "frontends/LyXView.h" +#include "frontends/WorkArea.h" + +using std::advance; +using std::distance; +using std::endl; using std::string; + namespace lyx { namespace frontend { -GuiSpellcheckerDialog::GuiSpellcheckerDialog(LyXView & lv) - : GuiDialog(lv, "spellchecker") +using support::bformat; +using support::contains; + +GuiSpellchecker::GuiSpellchecker(LyXView & lv) + : GuiDialog(lv, "spellchecker"), Controller(this), exitEarly_(false), + oldval_(0), newvalue_(0), count_(0), speller_(0) { setupUi(this); setViewTitle(_("Spellchecker")); - setController(new ControlSpellchecker(*this)); + setController(this, false); connect(closePB, SIGNAL(clicked()), this, SLOT(slotClose())); + connect(replacePB, SIGNAL(clicked()), this, SLOT(replaceClicked())); + connect(ignorePB, SIGNAL(clicked()), this, SLOT(ignoreClicked())); + connect(replacePB_3, SIGNAL(clicked()), this, SLOT(acceptClicked())); + connect(addPB, SIGNAL(clicked()), this, SLOT(addClicked())); - connect(replaceCO, SIGNAL(highlighted(const QString &)), - this, SLOT(replaceChanged(const QString &))); - connect(replacePB, SIGNAL(clicked()), - this, SLOT(replaceClicked())); - connect(ignorePB, SIGNAL(clicked()), - this, SLOT(ignoreClicked())); - connect(replacePB_3, SIGNAL(clicked()), - this, SLOT(acceptClicked())); - connect(addPB, SIGNAL(clicked()), - this, SLOT(addClicked())); + connect(replaceCO, SIGNAL(highlighted(QString)), + this, SLOT(replaceChanged(QString))); connect(suggestionsLW, SIGNAL(itemDoubleClicked(QListWidgetItem*)), - this, SLOT(replaceClicked() ) ); + this, SLOT(replaceClicked())); connect(suggestionsLW, SIGNAL(itemClicked(QListWidgetItem*)), this, SLOT(suggestionChanged(QListWidgetItem*))); @@ -62,37 +98,13 @@ GuiSpellcheckerDialog::GuiSpellcheckerDialog(LyXView & lv) } -ControlSpellchecker & GuiSpellcheckerDialog::controller() +GuiSpellchecker::~GuiSpellchecker() { - return static_cast(GuiDialog::controller()); + delete speller_; } -void GuiSpellcheckerDialog::acceptClicked() -{ - accept(); -} - - -void GuiSpellcheckerDialog::addClicked() -{ - add(); -} - - -void GuiSpellcheckerDialog::replaceClicked() -{ - replace(); -} - - -void GuiSpellcheckerDialog::ignoreClicked() -{ - ignore(); -} - - -void GuiSpellcheckerDialog::suggestionChanged(QListWidgetItem * item) +void GuiSpellchecker::suggestionChanged(QListWidgetItem * item) { if (replaceCO->count() != 0) replaceCO->setItemText(0, item->text()); @@ -103,12 +115,12 @@ void GuiSpellcheckerDialog::suggestionChanged(QListWidgetItem * item) } -void GuiSpellcheckerDialog::replaceChanged(const QString & str) +void GuiSpellchecker::replaceChanged(const QString & str) { if (suggestionsLW->currentItem()->text() == str) return; - for (int i = 0; i < suggestionsLW->count(); ++i) { + for (int i = 0; i != suggestionsLW->count(); ++i) { if (suggestionsLW->item(i)->text() == str) { suggestionsLW->setCurrentRow(i); break; @@ -117,64 +129,64 @@ void GuiSpellcheckerDialog::replaceChanged(const QString & str) } -void GuiSpellcheckerDialog::closeEvent(QCloseEvent * e) +void GuiSpellchecker::closeEvent(QCloseEvent * e) { slotClose(); GuiDialog::closeEvent(e); } -void GuiSpellcheckerDialog::reject() +void GuiSpellchecker::reject() { slotClose(); QDialog::reject(); } -void GuiSpellcheckerDialog::updateContents() +void GuiSpellchecker::updateContents() { - if (isVisibleView() || controller().exitEarly()) - controller().check(); + if (isVisibleView() || exitEarly()) + check(); } -void GuiSpellcheckerDialog::accept() +void GuiSpellchecker::accept() { - controller().ignoreAll(); + ignoreAll(); } -void GuiSpellcheckerDialog::add() +void GuiSpellchecker::add() { - controller().insert(); + insert(); } -void GuiSpellcheckerDialog::ignore() +void GuiSpellchecker::ignore() { - controller().check(); + check(); } -void GuiSpellcheckerDialog::replace() +void GuiSpellchecker::replace() { - controller().replace(qstring_to_ucs4(replaceCO->currentText())); + replace(qstring_to_ucs4(replaceCO->currentText())); } -void GuiSpellcheckerDialog::partialUpdate(int state) +void GuiSpellchecker::partialUpdate(int state) { switch (state) { - case ControlSpellchecker::SPELL_PROGRESSED: - spellcheckPR->setValue(controller().getProgress()); + case SPELL_PROGRESSED: + spellcheckPR->setValue(getProgress()); break; - case ControlSpellchecker::SPELL_FOUND_WORD: { - wordED->setText(toqstr(controller().getWord())); + case SPELL_FOUND_WORD: { + wordED->setText(toqstr(getWord())); suggestionsLW->clear(); docstring w; - while (!(w = controller().getSuggestion()).empty()) + while (!(w = getSuggestion()).empty()) suggestionsLW->addItem(toqstr(w)); if (suggestionsLW->count() == 0) @@ -188,6 +200,283 @@ void GuiSpellcheckerDialog::partialUpdate(int state) } } + +static SpellBase * getSpeller(BufferParams const & bp) +{ + string lang = (lyxrc.isp_use_alt_lang) + ? lyxrc.isp_alt_lang + : bp.language->code(); + +#if defined(USE_ASPELL) + if (lyxrc.use_spell_lib) + return new ASpell(bp, lang); +#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 +} + + +bool GuiSpellchecker::initialiseParams(std::string const &) +{ + LYXERR(Debug::GUI) << "Spellchecker::initialiseParams" << endl; + + speller_ = getSpeller(buffer().params()); + if (!speller_) + return false; + + // reset values to initial + oldval_ = 0; + newvalue_ = 0; + count_ = 0; + + bool const success = speller_->error().empty(); + + if (!success) { + Alert::error(_("Spellchecker error"), + _("The spellchecker could not be started\n") + + speller_->error()); + delete speller_; + speller_ = 0; + } + + return success; +} + + +void GuiSpellchecker::clearParams() +{ + LYXERR(Debug::GUI) << "Spellchecker::clearParams" << endl; + delete speller_; + speller_ = 0; +} + + +static bool isLetter(DocIterator const & dit) +{ + return dit.inTexted() + && dit.inset().allowSpellCheck() + && dit.pos() != dit.lastpos() + && (dit.paragraph().isLetter(dit.pos()) + // We want to pass the ' and escape chars to ispell + || contains(from_utf8(lyxrc.isp_esc_chars + '\''), + dit.paragraph().getChar(dit.pos()))) + && !dit.paragraph().isDeleted(dit.pos()); +} + + +static WordLangTuple nextWord(Cursor & cur, ptrdiff_t & progress) +{ + BufferParams const & bp = cur.bv().buffer().params(); + bool inword = false; + bool ignoreword = false; + cur.resetAnchor(); + docstring word; + string lang_code; + + while (cur.depth()) { + if (isLetter(cur)) { + if (!inword) { + inword = true; + ignoreword = false; + cur.resetAnchor(); + 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) { + cur.setSelection(); + return WordLangTuple(word, lang_code); + } + inword = false; + } + + cur.forwardPos(); + ++progress; + } + + return WordLangTuple(docstring(), string()); +} + + +void GuiSpellchecker::check() +{ + LYXERR(Debug::GUI) << "Check the spelling of a word" << endl; + + SpellBase::Result res = SpellBase::OK; + + Cursor cur = bufferview()->cursor(); + while (cur && cur.pos() && isLetter(cur)) + cur.backwardPos(); + + ptrdiff_t start = 0; + ptrdiff_t total = 0; + DocIterator it = DocIterator(buffer().inset()); + for (start = 0; it != cur; it.forwardPos()) + ++start; + + for (total = start; it; it.forwardPos()) + ++total; + + exitEarly_ = false; + + while (res == SpellBase::OK || res == SpellBase::IGNORED_WORD) { + word_ = nextWord(cur, start); + + // end of document + if (getWord().empty()) { + showSummary(); + exitEarly_ = true; + return; + } + + ++count_; + + // Update slider if and only if value has changed + float progress = total ? float(start)/total : 1; + newvalue_ = int(100.0 * progress); + if (newvalue_!= oldval_) { + LYXERR(Debug::GUI) << "Updating spell progress." << endl; + oldval_ = newvalue_; + // set progress bar + dialog().partialUpdateView(SPELL_PROGRESSED); + } + + // speller might be dead ... + if (!checkAlive()) + return; + + res = speller_->check(word_); + + // ... or it might just be reporting an error + if (!checkAlive()) + return; + } + + LYXERR(Debug::GUI) << "Found word \"" << to_utf8(getWord()) << "\"" << endl; + + int const size = cur.selEnd().pos() - cur.selBegin().pos(); + cur.pos() -= size; + bufferview()->putSelectionAt(cur, size, false); + // FIXME: if we used a lfun like in find/replace, dispatch would do + // that for us + bufferview()->update(); + // FIXME: this Controller is very badly designed... + lyxview().currentWorkArea()->redraw(); + + // set suggestions + if (res != SpellBase::OK && res != SpellBase::IGNORED_WORD) { + LYXERR(Debug::GUI) << "Found a word needing checking." << endl; + dialog().partialUpdateView(SPELL_FOUND_WORD); + } +} + + +bool GuiSpellchecker::checkAlive() +{ + if (speller_->alive() && speller_->error().empty()) + return true; + + docstring 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().slotClose(); + + Alert::error(_("The spellchecker has failed"), message); + return false; +} + + +void GuiSpellchecker::showSummary() +{ + if (!checkAlive() || count_ == 0) { + dialog().slotClose(); + return; + } + + docstring message; + if (count_ != 1) + message = bformat(_("%1$d words checked."), count_); + else + message = _("One word checked."); + + dialog().slotClose(); + Alert::information(_("Spelling check completed"), message); +} + + +void GuiSpellchecker::replace(docstring const & replacement) +{ + LYXERR(Debug::GUI) << "GuiSpellchecker::replace(" + << to_utf8(replacement) << ")" << std::endl; + cap::replaceSelectionWithString(bufferview()->cursor(), replacement, true); + buffer().markDirty(); + // If we used an LFUN, we would not need that + bufferview()->update(); + // fix up the count + --count_; + check(); +} + + +void GuiSpellchecker::replaceAll(docstring const & replacement) +{ + // TODO: add to list + replace(replacement); +} + + +void GuiSpellchecker::insert() +{ + speller_->insert(word_); + check(); +} + + +docstring GuiSpellchecker::getSuggestion() const +{ + return speller_->nextMiss(); +} + + +docstring GuiSpellchecker::getWord() const +{ + return word_.word(); +} + + +void GuiSpellchecker::ignoreAll() +{ + speller_->accept(word_); + check(); +} + + +Dialog * createGuiSpellchecker(LyXView & lv) { return new GuiSpellchecker(lv); } + } // namespace frontend } // namespace lyx diff --git a/src/frontends/qt4/GuiSpellchecker.h b/src/frontends/qt4/GuiSpellchecker.h index 1a9ff470a8..52fa3719f3 100644 --- a/src/frontends/qt4/GuiSpellchecker.h +++ b/src/frontends/qt4/GuiSpellchecker.h @@ -6,6 +6,7 @@ * * \author John Levon * \author Kalle Dalheimer + * \author Edwin Leuven * * Full author contact details are available in file CREDITS. */ @@ -14,29 +15,35 @@ #define GUISPELLCHECKER_H #include "GuiDialog.h" -#include "ControlSpellchecker.h" #include "ui_SpellcheckerUi.h" +#include "Dialog.h" +#include "WordLangTuple.h" class QListWidgetItem; namespace lyx { + +class SpellBase; + namespace frontend { -class GuiSpellcheckerDialog : public GuiDialog, public Ui::SpellcheckerUi +class GuiSpellchecker + : public GuiDialog, public Ui::SpellcheckerUi, public Controller { Q_OBJECT public: - GuiSpellcheckerDialog(LyXView & lv); + GuiSpellchecker(LyXView & lv); + ~GuiSpellchecker(); public Q_SLOTS: void suggestionChanged(QListWidgetItem *); private Q_SLOTS: - void acceptClicked(); - void addClicked(); - void replaceClicked(); - void ignoreClicked(); + void accept(); + void add(); + void ignore(); + void replace(); void replaceChanged(const QString &); void reject(); @@ -46,14 +53,63 @@ private: /// update from controller void partialUpdate(int id); /// parent controller - ControlSpellchecker & controller(); - //// - void accept(); - void add(); - void ignore(); - void replace(); + Controller & controller() { return *this; } /// void updateContents(); + + /// + enum State { + SPELL_PROGRESSED, //< update progress bar + SPELL_FOUND_WORD //< found a bad word + }; + + /// + bool initialiseParams(std::string const & data); + /// + void clearParams(); + /// Not needed here + void dispatchParams() {} + /// + bool isBufferDependent() const { return true; } + /// + bool exitEarly() const { return exitEarly_; } + + /// replace word with replacement + void replace(docstring const &); + + /// replace all occurances of word + void replaceAll(docstring const &); + /// insert word in personal dictionary + void insert(); + /// ignore all occurances of word + void ignoreAll(); + /// check text until next misspelled/unknown word + /// returns true when finished + void check(); + /// get suggestion + docstring getSuggestion() const; + /// get word + docstring getWord() const; + /// returns progress value + int getProgress() const { return oldval_; } + /// returns word count + int getCount() const { return count_; } + /// give error message is spellchecker dies + bool checkAlive(); + /// show count of checked words at normal exit + void showSummary(); + + /// set to true when spellchecking is finished + bool exitEarly_; + /// current word being checked and lang code + WordLangTuple word_; + /// values for progress + int oldval_; + int newvalue_; + /// word count + int count_; + /// The actual spellchecker object + SpellBase * speller_; }; } // namespace frontend