diff --git a/src/spellcheck/spellcheckbar.cpp b/src/spellcheck/spellcheckbar.cpp index 20132632..89ef7953 100644 --- a/src/spellcheck/spellcheckbar.cpp +++ b/src/spellcheck/spellcheckbar.cpp @@ -1,453 +1,454 @@ /** * Copyright (C) 2003 Zack Rusin * Copyright (C) 2009-2010 Michel Ludwig * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301 USA */ #include "spellcheckbar.h" #include "ui_spellcheckbar.h" #include #include "sonnet/backgroundchecker.h" #include "sonnet/speller.h" /* #include "sonnet/filter_p.h" #include "sonnet/settings_p.h" */ #include #include #include #include #include #include #include #include #include //to initially disable sorting in the suggestions listview #define NONSORTINGCOLUMN 2 class ReadOnlyStringListModel: public QStringListModel { public: ReadOnlyStringListModel(QObject *parent): QStringListModel(parent) {} Qt::ItemFlags flags(const QModelIndex &index) const override { Q_UNUSED(index); return Qt::ItemIsEnabled | Qt::ItemIsSelectable; } }; /** * Structure abstracts the word and its position in the * parent text. * * @author Zack Rusin * @short struct represents word */ struct Word { Word() {} Word(const QString &w, int st, bool e = false) : word(w), start(st), end(e) {} Word(const Word &other) : word(other.word), start(other.start), end(other.end) {} QString word; int start = 0; bool end = true; }; class SpellCheckBar::Private { public: Ui_SonnetUi ui; ReadOnlyStringListModel *suggestionsModel; QWidget *wdg; QDialogButtonBox *buttonBox; QProgressDialog *progressDialog; QString originalBuffer; Sonnet::BackgroundChecker *checker; Word currentWord; QMap replaceAllMap; bool restart;//used when text is distributed across several qtextedits, eg in KAider QMap dictsMap; int progressDialogTimeout; bool showCompletionMessageBox; bool spellCheckContinuedAfterReplacement; bool canceled; void deleteProgressDialog(bool directly) { if (progressDialog) { progressDialog->hide(); if (directly) { delete progressDialog; } else { progressDialog->deleteLater(); } progressDialog = nullptr; } } }; SpellCheckBar::SpellCheckBar(Sonnet::BackgroundChecker *checker, QWidget *parent) : KateViewBarWidget(true, parent), d(new Private) { d->checker = checker; d->canceled = false; d->showCompletionMessageBox = false; d->spellCheckContinuedAfterReplacement = true; d->progressDialogTimeout = -1; d->progressDialog = nullptr; initGui(); initConnections(); } SpellCheckBar::~SpellCheckBar() { delete d; } void SpellCheckBar::closed() { if (viewBar()) { viewBar()->removeBarWidget(this); } // called from hideMe, so don't call it again! d->canceled = true; d->deleteProgressDialog(false); // this method can be called in response to d->replaceAllMap.clear(); // pressing 'Cancel' on the dialog emit cancel(); emit spellCheckStatus(i18n("Spell check canceled.")); } void SpellCheckBar::initConnections() { connect(d->ui.m_addBtn, SIGNAL(clicked()), SLOT(slotAddWord())); connect(d->ui.m_replaceBtn, SIGNAL(clicked()), SLOT(slotReplaceWord())); connect(d->ui.m_replaceAllBtn, SIGNAL(clicked()), SLOT(slotReplaceAll())); connect(d->ui.m_skipBtn, SIGNAL(clicked()), SLOT(slotSkip())); connect(d->ui.m_skipAllBtn, SIGNAL(clicked()), SLOT(slotSkipAll())); connect(d->ui.m_suggestBtn, SIGNAL(clicked()), SLOT(slotSuggest())); connect(d->ui.m_language, SIGNAL(activated(QString)), SLOT(slotChangeLanguage(QString))); connect(d->checker, SIGNAL(misspelling(QString,int)), SLOT(slotMisspelling(QString,int))); connect(d->checker, SIGNAL(done()), SLOT(slotDone())); /* connect(d->ui.m_suggestions, SIGNAL(doubleClicked(QModelIndex)), SLOT(slotReplaceWord())); */ connect(d->ui.cmbReplacement, SIGNAL(returnPressed()), this, SLOT(slotReplaceWord())); connect(d->ui.m_autoCorrect, SIGNAL(clicked()), SLOT(slotAutocorrect())); // button use by kword/kpresenter // hide by default d->ui.m_autoCorrect->hide(); } void SpellCheckBar::initGui() { QVBoxLayout *layout = new QVBoxLayout; layout->setMargin(0); centralWidget()->setLayout(layout); d->wdg = new QWidget(this); d->ui.setupUi(d->wdg); layout->addWidget(d->wdg); setGuiEnabled(false); /* d->buttonBox = new QDialogButtonBox(this); d->buttonBox->setStandardButtons(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); layout->addWidget(d->buttonBox); */ //d->ui.m_suggestions->setSorting( NONSORTINGCOLUMN ); fillDictionaryComboBox(); d->restart = false; d->suggestionsModel = new ReadOnlyStringListModel(this); d->ui.cmbReplacement->setModel(d->suggestionsModel); } void SpellCheckBar::activeAutoCorrect(bool _active) { if (_active) { d->ui.m_autoCorrect->show(); } else { d->ui.m_autoCorrect->hide(); } } void SpellCheckBar::showProgressDialog(int timeout) { d->progressDialogTimeout = timeout; } void SpellCheckBar::showSpellCheckCompletionMessage(bool b) { d->showCompletionMessageBox = b; } void SpellCheckBar::setSpellCheckContinuedAfterReplacement(bool b) { d->spellCheckContinuedAfterReplacement = b; } void SpellCheckBar::slotAutocorrect() { setGuiEnabled(false); setProgressDialogVisible(true); emit autoCorrect(d->currentWord.word, d->ui.cmbReplacement->lineEdit()->text()); slotReplaceWord(); } void SpellCheckBar::setGuiEnabled(bool b) { d->wdg->setEnabled(b); } void SpellCheckBar::setProgressDialogVisible(bool b) { if (!b) { d->deleteProgressDialog(true); } else if (d->progressDialogTimeout >= 0) { if (d->progressDialog) { return; } d->progressDialog = new QProgressDialog(this); d->progressDialog->setLabelText(i18nc("progress label", "Spell checking in progress...")); d->progressDialog->setWindowTitle(i18nc("@title:window", "Check Spelling")); d->progressDialog->setModal(true); d->progressDialog->setAutoClose(false); d->progressDialog->setAutoReset(false); // create an 'indefinite' progress box as we currently cannot get progress feedback from // the speller d->progressDialog->reset(); d->progressDialog->setRange(0, 0); d->progressDialog->setValue(0); connect(d->progressDialog, SIGNAL(canceled()), this, SLOT(slotCancel())); d->progressDialog->setMinimumDuration(d->progressDialogTimeout); } } void SpellCheckBar::slotCancel() { hideMe(); } QString SpellCheckBar::originalBuffer() const { return d->originalBuffer; } QString SpellCheckBar::buffer() const { return d->checker->text(); } void SpellCheckBar::setBuffer(const QString &buf) { d->originalBuffer = buf; //it is possible to change buffer inside slot connected to done() signal d->restart = true; } void SpellCheckBar::fillDictionaryComboBox() { + // Since m_language is changed to DictionaryComboBox most code here is gone, + // So fillDictionaryComboBox() could be removed and code moved to initGui() + // because the call in show() looks obsolete Sonnet::Speller speller = d->checker->speller(); d->dictsMap = speller.availableDictionaries(); - QStringList langs = d->dictsMap.keys(); - d->ui.m_language->clear(); - d->ui.m_language->addItems(langs); + updateDictionaryComboBox(); } void SpellCheckBar::updateDictionaryComboBox() { Sonnet::Speller speller = d->checker->speller(); - d->ui.m_language->setCurrentIndex(d->dictsMap.values().indexOf(speller.language())); + d->ui.m_language->setCurrentByDictionary(speller.language()); } void SpellCheckBar::updateDialog(const QString &word) { d->ui.m_unknownWord->setText(word); //d->ui.m_contextLabel->setText(d->checker->currentContext()); const QStringList suggs = d->checker->suggest(word); if (suggs.isEmpty()) { d->ui.cmbReplacement->lineEdit()->clear(); } else { d->ui.cmbReplacement->lineEdit()->setText(suggs.first()); } fillSuggestions(suggs); } void SpellCheckBar::show() { d->canceled = false; fillDictionaryComboBox(); updateDictionaryComboBox(); if (d->originalBuffer.isEmpty()) { d->checker->start(); } else { d->checker->setText(d->originalBuffer); } setProgressDialogVisible(true); } void SpellCheckBar::slotAddWord() { setGuiEnabled(false); setProgressDialogVisible(true); d->checker->addWordToPersonal(d->currentWord.word); d->checker->continueChecking(); } void SpellCheckBar::slotReplaceWord() { setGuiEnabled(false); setProgressDialogVisible(true); const QString replacementText = d->ui.cmbReplacement->lineEdit()->text(); emit replace(d->currentWord.word, d->currentWord.start, replacementText); if (d->spellCheckContinuedAfterReplacement) { d->checker->replace(d->currentWord.start, d->currentWord.word, replacementText); d->checker->continueChecking(); } else { setProgressDialogVisible(false); d->checker->stop(); } } void SpellCheckBar::slotReplaceAll() { setGuiEnabled(false); setProgressDialogVisible(true); d->replaceAllMap.insert(d->currentWord.word, d->ui.cmbReplacement->lineEdit()->text()); slotReplaceWord(); } void SpellCheckBar::slotSkip() { setGuiEnabled(false); setProgressDialogVisible(true); d->checker->continueChecking(); } void SpellCheckBar::slotSkipAll() { setGuiEnabled(false); setProgressDialogVisible(true); //### do we want that or should we have a d->ignoreAll list? Sonnet::Speller speller = d->checker->speller(); speller.addToPersonal(d->currentWord.word); d->checker->setSpeller(speller); d->checker->continueChecking(); } void SpellCheckBar::slotSuggest() { QStringList suggs = d->checker->suggest(d->ui.cmbReplacement->lineEdit()->text()); fillSuggestions(suggs); } void SpellCheckBar::slotChangeLanguage(const QString &lang) { Sonnet::Speller speller = d->checker->speller(); QString languageCode = d->dictsMap[lang]; if (!languageCode.isEmpty()) { d->checker->changeLanguage(languageCode); slotSuggest(); emit languageChanged(languageCode); } } void SpellCheckBar::fillSuggestions(const QStringList &suggs) { d->suggestionsModel->setStringList(suggs); if (!suggs.isEmpty()) { d->ui.cmbReplacement->setCurrentIndex(0); } } void SpellCheckBar::slotMisspelling(const QString &word, int start) { setGuiEnabled(true); setProgressDialogVisible(false); emit misspelling(word, start); //NOTE this is HACK I had to introduce because BackgroundChecker lacks 'virtual' marks on methods //this dramatically reduces spellchecking time in Lokalize //as this doesn't fetch suggestions for words that are present in msgid if (!updatesEnabled()) { return; } d->currentWord = Word(word, start); if (d->replaceAllMap.contains(word)) { d->ui.cmbReplacement->lineEdit()->setText(d->replaceAllMap[ word ]); slotReplaceWord(); } else { updateDialog(word); } } void SpellCheckBar::slotDone() { d->restart = false; emit done(d->checker->text()); if (d->restart) { updateDictionaryComboBox(); d->checker->setText(d->originalBuffer); d->restart = false; } else { setProgressDialogVisible(false); emit spellCheckStatus(i18n("Spell check complete.")); hideMe(); if (!d->canceled && d->showCompletionMessageBox) { QMessageBox::information(this, i18n("Spell check complete."), i18nc("@title:window", "Check Spelling")); } } } diff --git a/src/spellcheck/spellcheckbar.ui b/src/spellcheck/spellcheckbar.ui index a185f82e..25275bdd 100644 --- a/src/spellcheck/spellcheckbar.ui +++ b/src/spellcheck/spellcheckbar.ui @@ -1,251 +1,256 @@ SonnetUi 0 0 740 101 0 0 <qt><p>This word was considered to be an "unknown word" because it does not match any entry in the dictionary currently in use. It may also be a word in a foreign language.</p> <p>If the word is not misspelled, you may add it to the dictionary by clicking <b>Add to Dictionary</b>. If you do not want to add the unknown word to the dictionary, but you want to leave it unchanged, click <b>Ignore</b> or <b>Ignore All</b>.</p> <p>However, if the word is misspelled, you can try to find the correct replacement in the list below. If you cannot find a replacement there, you may type it in the text box below, and click <b>Replace</b> or <b>Replace All</b>.</p> </qt> Unknown word: Unknown word <qt><p>This word was considered to be an "unknown word" because it does not match any entry in the dictionary currently in use. It may also be a word in a foreign language.</p> <p>If the word is not misspelled, you may add it to the dictionary by clicking <b>Add to Dictionary</b>. If you do not want to add the unknown word to the dictionary, but you want to leave it unchanged, click <b>Ignore</b> or <b>Ignore All</b>.</p> <p>However, if the word is misspelled, you can try to find the correct replacement in the list below. If you cannot find a replacement there, you may type it in the text box below, and click <b>Replace</b> or <b>Replace All</b>.</p> </qt> <b>misspelled</b> Qt::Horizontal 40 20 <qt> <p>The unknown word was detected and considered unknown because it is not included in the dictionary.<br> Click here if you consider the unknown word not to be misspelled, and you want to avoid wrongly detecting it again in the future. If you want to let it remain as is, but not add it to the dictionary, then click <b>Ignore</b> or <b>Ignore All</b> instead.</p> </qt> << Add to Dictionary <qt> <p>If the unknown word is misspelled, you should type the correction for your misspelled word here or select it from the list below.</p> <p>You can then click <b>Replace</b> if you want to correct only this occurrence of the word or <b>Replace All</b> if you want to correct all occurrences.</p> </qt> Replace with: 0 0 true true true S&uggest <qt> <p>Click here to replace this occurrence of the unknown text with the text in the edit box above (to the left).</p> </qt> &Replace <qt> <p>Click here to let this occurrence of the unknown word remain as is.</p> <p>This action is useful when the word is a name, an acronym, a foreign word or any other unknown word that you want to use but not add to the dictionary.</p> </qt> &Ignore <qt> <p>Select the language of the document you are proofing here.</p> </qt> &Language: m_language - + Language Selection <qt> <p>Select the language of the document you are proofing here.</p> </qt> Qt::Horizontal 40 20 <qt> <p>Click here to let all occurrences of the unknown word remain as they are.</p> <p>This action is useful when the word is a name, an acronym, a foreign word or any other unknown word that you want to use but not add to the dictionary.</p> </qt> Autocorrect <qt> <p>Click here to replace all occurrences of the unknown text with the text in the edit box above (to the left).</p> </qt> R&eplace All <qt> <p>Click here to let all occurrences of the unknown word remain as they are.</p> <p>This action is useful when the word is a name, an acronym, a foreign word or any other unknown word that you want to use but not add to the dictionary.</p> </qt> I&gnore All KComboBox QComboBox
kcombobox.h
+ + Sonnet::DictionaryComboBox + QComboBox +
sonnet/dictionarycombobox.h
+
m_addBtn m_suggestBtn m_replaceBtn m_replaceAllBtn m_skipAllBtn