X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2Ffrontends%2Fqt4%2FGuiSpellchecker.cpp;h=10edda44629b9b24705a5ed14d0113403dce9b3c;hb=425d092204118ea6c24c28e85fdf03fcf2bb51a4;hp=356b0becb4e624e28dd787b2471c96981fc230b9;hpb=a1cec91afaca91968b46e695533c10ad2a3f73d3;p=lyx.git diff --git a/src/frontends/qt4/GuiSpellchecker.cpp b/src/frontends/qt4/GuiSpellchecker.cpp index 356b0becb4..10edda4462 100644 --- a/src/frontends/qt4/GuiSpellchecker.cpp +++ b/src/frontends/qt4/GuiSpellchecker.cpp @@ -4,6 +4,8 @@ * Licence details can be found in the file COPYING. * * \author John Levon + * \author Edwin Leuven + * \author Abdelrazak Younes * * Full author contact details are available in file CREDITS. */ @@ -11,205 +13,306 @@ #include #include "GuiSpellchecker.h" -#include "Qt2BC.h" + #include "qt_helpers.h" -#include "controllers/ControlSpellchecker.h" +#include "ui_SpellcheckerUi.h" + +#include "Buffer.h" +#include "BufferParams.h" +#include "BufferView.h" +#include "buffer_funcs.h" +#include "Cursor.h" +#include "CutAndPaste.h" +#include "FuncRequest.h" +#include "Language.h" +#include "LyX.h" +#include "LyXRC.h" +#include "lyxfind.h" +#include "Paragraph.h" +#include "WordLangTuple.h" + +#include "support/debug.h" +#include "support/docstring.h" +#include "support/docstring_list.h" +#include "support/ExceptionMessage.h" +#include "support/gettext.h" +#include "support/lstrings.h" +#include "support/textutils.h" -#include -#include -#include -#include #include -#include -#include -#include -#include +#include + +#include "SpellChecker.h" +#include "frontends/alert.h" -using std::string; +using namespace std; +using namespace lyx::support; namespace lyx { namespace frontend { -///////////////////////////////////////////////////////////////////// -// -// GuiSpellCheckerDialog -// -///////////////////////////////////////////////////////////////////// - -GuiSpellcheckerDialog::GuiSpellcheckerDialog(GuiSpellchecker * form) - : form_(form) +struct GuiSpellchecker::Private { - setupUi(this); + Private() : progress_(0), count_(0) {} + Ui::SpellcheckerUi ui; + /// current word being checked and lang code + WordLangTuple word_; + /// values for progress + int total_; + int progress_; + /// word count + int count_; +}; + + +GuiSpellchecker::GuiSpellchecker(GuiView & lv) + : DockView(lv, "spellchecker", qt_("Spellchecker"), + Qt::RightDockWidgetArea), d(new GuiSpellchecker::Private) +{ + d->ui.setupUi(this); + + connect(d->ui.suggestionsLW, SIGNAL(itemDoubleClicked(QListWidgetItem*)), + this, SLOT(on_replacePB_clicked())); - connect(closePB, SIGNAL(clicked()), form, SLOT(slotClose())); + d->ui.wordED->setReadOnly(true); - 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(suggestionsLW, SIGNAL(itemDoubleClicked(QListWidgetItem*)), - this, SLOT(replaceClicked() ) ); - connect(suggestionsLW, SIGNAL(itemClicked(QListWidgetItem*)), - this, SLOT(suggestionChanged(QListWidgetItem*))); + d->ui.suggestionsLW->installEventFilter(this); } -void GuiSpellcheckerDialog::acceptClicked() +GuiSpellchecker::~GuiSpellchecker() { - form_->accept(); + delete d; } -void GuiSpellcheckerDialog::addClicked() -{ - form_->add(); -} -void GuiSpellcheckerDialog::replaceClicked() +void GuiSpellchecker::on_closePB_clicked() { - form_->replace(); + close(); } -void GuiSpellcheckerDialog::ignoreClicked() + +bool GuiSpellchecker::eventFilter(QObject *obj, QEvent *event) { - form_->ignore(); + if (obj == d->ui.suggestionsLW && event->type() == QEvent::KeyPress) { + QKeyEvent *e = static_cast (event); + if (e->key() == Qt::Key_Enter || e->key() == Qt::Key_Return) { + on_suggestionsLW_itemClicked(d->ui.suggestionsLW->currentItem()); + on_replacePB_clicked(); + return true; + } else if (e->key() == Qt::Key_Right) { + on_suggestionsLW_itemClicked(d->ui.suggestionsLW->currentItem()); + return true; + } + } + // standard event processing + return QWidget::eventFilter(obj, event); } -void GuiSpellcheckerDialog::suggestionChanged(QListWidgetItem * item) + +void GuiSpellchecker::on_suggestionsLW_itemClicked(QListWidgetItem * item) { - if (replaceCO->count() != 0) - replaceCO->setItemText(0, item->text()); + if (d->ui.replaceCO->count() != 0) + d->ui.replaceCO->setItemText(0, item->text()); else - replaceCO->addItem(item->text()); + d->ui.replaceCO->addItem(item->text()); - replaceCO->setCurrentIndex(0); + d->ui.replaceCO->setCurrentIndex(0); } -void GuiSpellcheckerDialog::replaceChanged(const QString & str) + +void GuiSpellchecker::on_replaceCO_highlighted(const QString & str) { - if (suggestionsLW->currentItem()->text() == str) + QListWidget * lw = d->ui.suggestionsLW; + if (lw->currentItem() && lw->currentItem()->text() == str) return; - for (int i = 0; i < suggestionsLW->count(); ++i) { - if (suggestionsLW->item(i)->text() == str) { - suggestionsLW->setCurrentRow(i); + for (int i = 0; i != lw->count(); ++i) { + if (lw->item(i)->text() == str) { + lw->setCurrentRow(i); break; } } } -void GuiSpellcheckerDialog::closeEvent(QCloseEvent * e) +void GuiSpellchecker::updateView() { - form_->slotWMHide(); - e->accept(); + if (hasFocus()) + check(); } -void GuiSpellcheckerDialog::reject() +void GuiSpellchecker::on_ignoreAllPB_clicked() { - form_->slotWMHide(); - QDialog::reject(); + /// replace all occurances of word + theSpellChecker()->accept(d->word_); + check(); } - -///////////////////////////////////////////////////////////////////// -// -// GuiSpellChecker -// -///////////////////////////////////////////////////////////////////// - -typedef QController > - SpellcheckerBase; - -GuiSpellchecker::GuiSpellchecker(Dialog & parent) - : SpellcheckerBase(parent, _("Spellchecker")) -{} - - -void GuiSpellchecker::build_dialog() +void GuiSpellchecker::on_addPB_clicked() { - dialog_.reset(new GuiSpellcheckerDialog(this)); - - bcview().setCancel(dialog_->closePB); - dialog_->wordED->setReadOnly(true); + /// insert word in personal dictionary + theSpellChecker()->insert(d->word_); + check(); } -void GuiSpellchecker::update_contents() +void GuiSpellchecker::on_ignorePB_clicked() { - if (isVisible() || controller().exitEarly()) - controller().check(); + dispatch(FuncRequest(LFUN_CHAR_FORWARD)); + check(); } -void GuiSpellchecker::accept() +void GuiSpellchecker::on_findNextPB_clicked() { - controller().ignoreAll(); + docstring const data = find2string( + qstring_to_ucs4(d->ui.wordED->text()), + true, true, true); + dispatch(FuncRequest(LFUN_WORD_FIND, data)); } -void GuiSpellchecker::add() +void GuiSpellchecker::on_replacePB_clicked() { - controller().insert(); + docstring const replacement = qstring_to_ucs4(d->ui.replaceCO->currentText()); + + LYXERR(Debug::GUI, "Replace (" << replacement << ")"); + BufferView * bv = const_cast(bufferview()); + if (!bv->cursor().inTexted()) + return; + cap::replaceSelectionWithString(bv->cursor(), replacement, true); + bv->buffer().markDirty(); + // If we used an LFUN, we would not need that + bv->processUpdateFlags(Update::Force | Update::FitCursor); + // fix up the count + --d->count_; + check(); } -void GuiSpellchecker::ignore() +void GuiSpellchecker::on_replaceAllPB_clicked() { - controller().check(); + docstring const data = replace2string( + qstring_to_ucs4(d->ui.replaceCO->currentText()), + qstring_to_ucs4(d->ui.wordED->text()), + true, true, true, true); + dispatch(FuncRequest(LFUN_WORD_REPLACE, data)); + check(); // continue spellchecking } -void GuiSpellchecker::replace() +void GuiSpellchecker::updateSuggestions(docstring_list & words) { - controller().replace(qstring_to_ucs4(dialog_->replaceCO->currentText())); + QString const suggestion = toqstr(d->word_.word()); + d->ui.wordED->setText(suggestion); + QListWidget * lw = d->ui.suggestionsLW; + lw->clear(); + + if (words.empty()) { + on_suggestionsLW_itemClicked(new QListWidgetItem(suggestion)); + return; + } + for (size_t i = 0; i != words.size(); ++i) + lw->addItem(toqstr(words[i])); + + on_suggestionsLW_itemClicked(lw->item(0)); + lw->setCurrentRow(0); } -void GuiSpellchecker::partialUpdate(int s) +bool GuiSpellchecker::initialiseParams(string const &) { - ControlSpellchecker::State const state = - static_cast(s); - - switch (state) { + LYXERR(Debug::GUI, "Spellchecker::initialiseParams"); - case ControlSpellchecker::SPELL_PROGRESSED: - dialog_->spellcheckPR->setValue(controller().getProgress()); - break; + if (!theSpellChecker()) + return false; - case ControlSpellchecker::SPELL_FOUND_WORD: { - dialog_->wordED->setText(toqstr(controller().getWord())); - dialog_->suggestionsLW->clear(); + DocIterator const begin = doc_iterator_begin(&buffer()); + Cursor const & cur = bufferview()->cursor(); + d->progress_ = countWords(begin, cur); + d->total_ = d->progress_ + countWords(cur, doc_iterator_end(&buffer())); + d->count_ = 0; + return true; +} - docstring w; - while (!(w = controller().getSuggestion()).empty()) { - dialog_->suggestionsLW->addItem(toqstr(w)); - } - if (dialog_->suggestionsLW->count() == 0) { - dialog_->suggestionChanged(new QListWidgetItem(dialog_->wordED->text())); - } else { - dialog_->suggestionChanged(dialog_->suggestionsLW->item(0)); +void GuiSpellchecker::check() +{ + LYXERR(Debug::GUI, "Check the spelling of a word"); + + DocIterator from = bufferview()->cursor(); + DocIterator to; + WordLangTuple word_lang; + docstring_list suggestions; + + int progress; + try { + progress = buffer().spellCheck(from, to, word_lang, suggestions); + } catch (ExceptionMessage const & message) { + if (message.type_ == WarningException) { + Alert::warning(message.title_, message.details_); + close(); + return; } + throw message; + } + LYXERR(Debug::GUI, "Found word \"" << word_lang.word() << "\""); + d->count_ += progress; + d->progress_ += progress; - dialog_->suggestionsLW->setCurrentRow(0); + // end of document + if (from == doc_iterator_end(&buffer())) { + showSummary(); + return; } - break; + if (!isVisible()) + show(); + + d->word_ = word_lang; + + int const progress_bar = d->total_ + ? int(100.0 * float(d->progress_)/d->total_) : 100; + LYXERR(Debug::GUI, "Updating spell progress."); + // set progress bar + d->ui.spellcheckPR->setValue(progress_bar); + // set suggestions + updateSuggestions(suggestions); + + // FIXME: if we used a lfun like in find/replace, dispatch would do + // that for us + int const size = to.pos() - from.pos(); + BufferView * bv = const_cast(bufferview()); + bv->putSelectionAt(from, size, false); +} + +void GuiSpellchecker::showSummary() +{ + if (d->count_ == 0) { + close(); + return; } + + docstring message; + if (d->count_ != 1) + message = bformat(_("%1$d words checked."), d->count_); + else + message = _("One word checked."); + + close(); + Alert::information(_("Spelling check completed"), message); } + +Dialog * createGuiSpellchecker(GuiView & lv) { return new GuiSpellchecker(lv); } + } // namespace frontend } // namespace lyx -#include "GuiSpellchecker_moc.cpp" +#include "moc_GuiSpellchecker.cpp"