From 0a7773bec1c74161bb1c5e249e45814837b35339 Mon Sep 17 00:00:00 2001 From: nowrep Date: Tue, 5 Feb 2013 22:31:16 +0100 Subject: [PATCH] [spellcheck] Added dialog with spell check settings. --- .../qtwebkit/spellcheck/spellcheck.cpp | 2 +- .../qtwebkit/spellcheck/spellcheckdialog.cpp | 136 +++++++++++++++ .../qtwebkit/spellcheck/spellcheckdialog.h | 49 ++++++ .../qtwebkit/spellcheck/spellcheckdialog.ui | 161 ++++++++++++++++++ .../plugins/qtwebkit/spellcheck/speller.cpp | 97 +++++++++-- src/lib/plugins/qtwebkit/spellcheck/speller.h | 13 +- src/lib/webview/webview.cpp | 18 ++ src/lib/webview/webview.h | 1 + translations/empty.ts | 70 ++++++++ 9 files changed, 526 insertions(+), 21 deletions(-) create mode 100644 src/lib/plugins/qtwebkit/spellcheck/spellcheckdialog.cpp create mode 100644 src/lib/plugins/qtwebkit/spellcheck/spellcheckdialog.h create mode 100644 src/lib/plugins/qtwebkit/spellcheck/spellcheckdialog.ui diff --git a/src/lib/plugins/qtwebkit/spellcheck/spellcheck.cpp b/src/lib/plugins/qtwebkit/spellcheck/spellcheck.cpp index 551c6c791..6a7e2d7e6 100644 --- a/src/lib/plugins/qtwebkit/spellcheck/spellcheck.cpp +++ b/src/lib/plugins/qtwebkit/spellcheck/spellcheck.cpp @@ -30,7 +30,7 @@ SpellCheck::SpellCheck() bool SpellCheck::isContinousSpellCheckingEnabled() const { - return m_speller->isEnabled(); + return mApp->speller()->isEnabled(); } void SpellCheck::toggleContinousSpellChecking() diff --git a/src/lib/plugins/qtwebkit/spellcheck/spellcheckdialog.cpp b/src/lib/plugins/qtwebkit/spellcheck/spellcheckdialog.cpp new file mode 100644 index 000000000..1a5dc81f5 --- /dev/null +++ b/src/lib/plugins/qtwebkit/spellcheck/spellcheckdialog.cpp @@ -0,0 +1,136 @@ +/* ============================================================ +* QupZilla - WebKit based browser +* Copyright (C) 2013 David Rosca +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program 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 General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see . +* ============================================================ */ +#include "spellcheckdialog.h" +#include "ui_spellcheckdialog.h" +#include "settings.h" +#include "speller.h" +#include "mainapplication.h" + +#include +#include +#include +#include +#include + +SpellCheckDialog::SpellCheckDialog(QWidget* parent) + : QDialog(parent) + , ui(new Ui::SpellCheckDialog) + , m_listChanged(false) +{ + ui->setupUi(this); + + ui->dictPath->setText(mApp->speller()->dictionaryPath()); + + QFile file(mApp->currentProfilePath() + "userdictionary.txt"); + if (!file.open(QFile::ReadOnly)) { + qWarning() << "SpellCheckDialog: Cannot open file" << file.fileName() << "for reading!"; + } + else { + QString word; + QTextStream stream(&file); + + while (!stream.atEnd()) { + stream >> word; + word = word.trimmed(); + + if (!word.isEmpty()) { + ui->userDictList->insertItem(0, word); + } + } + + file.close(); + } + + connect(ui->changeDictPath, SIGNAL(clicked()), this, SLOT(changeDictionaryPath())); + connect(ui->add, SIGNAL(clicked()), this, SLOT(addUserWord())); + connect(ui->remove, SIGNAL(clicked()), this, SLOT(removeUserWord())); + connect(ui->buttonBox, SIGNAL(accepted()), this, SLOT(saveSettings())); + + ui->userDictList->setFocus(); +} + +void SpellCheckDialog::changeDictionaryPath() +{ + const QString &path = QFileDialog::getExistingDirectory(this, tr("Choose dictionary path..."), + ui->dictPath->text()); + + if (!path.isEmpty()) { + ui->dictPath->setText(path); + } +} + +void SpellCheckDialog::addUserWord() +{ + const QString &word = QInputDialog::getText(0, tr("Add new word..."), tr("Add new word:")); + + if (!word.isEmpty()) { + ui->userDictList->addItem(word); + ui->userDictList->setCurrentRow(ui->userDictList->count() - 1); + + m_listChanged = true; + } +} + +void SpellCheckDialog::removeUserWord() +{ + QListWidgetItem* item = ui->userDictList->currentItem(); + + if (!item) { + return; + } + + m_listChanged = true; + delete item; +} + +void SpellCheckDialog::saveSettings() +{ + // Save only when changed + + if (ui->dictPath->text() != mApp->speller()->dictionaryPath()) { + Settings settings; + settings.beginGroup("SpellCheck"); + settings.setValue("dictionaryPath", ui->dictPath->text()); + settings.endGroup(); + } + + if (!m_listChanged) { + return; + } + + QFile file(mApp->currentProfilePath() + "userdictionary.txt"); + if (!file.open(QFile::WriteOnly | QFile::Truncate)) { + qWarning() << "SpellCheckDialog: Cannot open file" << file.fileName() << "for reading!"; + return; + } + + QTextStream stream(&file); + int count = ui->userDictList->count(); + + for (int i = 0; i < count; ++i) { + const QString &word = ui->userDictList->item(i)->text(); + stream << word << endl; + } + + file.close(); +} + +SpellCheckDialog::~SpellCheckDialog() +{ + delete ui; +} diff --git a/src/lib/plugins/qtwebkit/spellcheck/spellcheckdialog.h b/src/lib/plugins/qtwebkit/spellcheck/spellcheckdialog.h new file mode 100644 index 000000000..9724d3268 --- /dev/null +++ b/src/lib/plugins/qtwebkit/spellcheck/spellcheckdialog.h @@ -0,0 +1,49 @@ +/* ============================================================ +* QupZilla - WebKit based browser +* Copyright (C) 2013 David Rosca +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program 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 General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see . +* ============================================================ */ +#ifndef SPELLCHECKDIALOG_H +#define SPELLCHECKDIALOG_H + +#include + +namespace Ui +{ +class SpellCheckDialog; +} + +class SpellCheckDialog : public QDialog +{ + Q_OBJECT + +public: + explicit SpellCheckDialog(QWidget* parent = 0); + ~SpellCheckDialog(); + +private slots: + void changeDictionaryPath(); + void addUserWord(); + void removeUserWord(); + + void saveSettings(); + +private: + Ui::SpellCheckDialog* ui; + + bool m_listChanged; +}; + +#endif // SPELLCHECKDIALOG_H diff --git a/src/lib/plugins/qtwebkit/spellcheck/spellcheckdialog.ui b/src/lib/plugins/qtwebkit/spellcheck/spellcheckdialog.ui new file mode 100644 index 000000000..18fa22c44 --- /dev/null +++ b/src/lib/plugins/qtwebkit/spellcheck/spellcheckdialog.ui @@ -0,0 +1,161 @@ + + + SpellCheckDialog + + + + 0 + 0 + 441 + 305 + + + + SpellCheck + + + + + + <html><head/><body><p><span style=" font-weight:600;">Dictionary path</span></p></body></html> + + + + + + + + + false + + + + + + + Change... + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 40 + 20 + + + + + + + + + + <b>User dictionary</b> + + + + + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + Add + + + + + + + Remove + + + + + + + + + + + + + Using Hunspell library + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + + + buttonBox + accepted() + SpellCheckDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + SpellCheckDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/src/lib/plugins/qtwebkit/spellcheck/speller.cpp b/src/lib/plugins/qtwebkit/spellcheck/speller.cpp index 4eef453be..cffae60be 100644 --- a/src/lib/plugins/qtwebkit/spellcheck/speller.cpp +++ b/src/lib/plugins/qtwebkit/spellcheck/speller.cpp @@ -61,7 +61,10 @@ void Speller::loadSettings() settings.endGroup(); m_userDictionary.setFileName(mApp->currentProfilePath() + "userdictionary.txt"); - initialize(); + + if (m_enabled) { + initialize(); + } } void Speller::initialize() @@ -112,9 +115,11 @@ Speller::Language Speller::language() const return m_language; } -QList Speller::availableLanguages() const +QList Speller::availableLanguages() { - QList languages; + if (!m_availableLanguages.isEmpty()) { + return m_availableLanguages; + } QDirIterator it(m_dictionaryPath, QStringList("*.dic"), QDir::Files); @@ -129,12 +134,12 @@ QList Speller::availableLanguages() const lang.code = it.fileInfo().baseName(); lang.name = nameForLanguage(lang.code); - if (!languages.contains(lang)) { - languages.append(lang); + if (!m_availableLanguages.contains(lang)) { + m_availableLanguages.append(lang); } } - return languages; + return m_availableLanguages; } QString Speller::dictionaryPath() const @@ -142,20 +147,12 @@ QString Speller::dictionaryPath() const return m_dictionaryPath; } -void Speller::showSettings(QWidget* parent) -{ - SpellCheckDialog dialog(parent); - - if (dialog.exec() == QDialog::Accepted) { - loadSettings(); - } -} - void Speller::populateContextMenu(QMenu* menu, const QWebHitTestResult &hitTest) { m_element = hitTest.element(); - if (m_element.isNull()) { + if (!m_enabled || m_element.isNull() || + m_element.attribute(QLatin1String("type")) == QLatin1String("password")) { return; } @@ -205,8 +202,8 @@ void Speller::addToDictionary() return; } - m_userDictionary.write(word.toUtf8()); - m_userDictionary.write("\n"); + QTextStream stream(&m_userDictionary); + stream << word << endl; m_userDictionary.close(); } } @@ -234,6 +231,33 @@ void Speller::replaceWord() } } +void Speller::showSettings() +{ + SpellCheckDialog dialog; + + if (dialog.exec() == QDialog::Accepted) { + loadSettings(); + } +} + +void Speller::changeLanguage() +{ + QAction* act = qobject_cast(sender()); + + if (!act) { + return; + } + + Language lang = act->data().value(); + + Settings settings; + settings.beginGroup("SpellCheck"); + settings.setValue("language", lang.code); + settings.endGroup(); + + loadSettings(); +} + void Speller::putWord(const QString &word) { if (!m_hunspell || !m_textCodec) { @@ -290,6 +314,43 @@ bool Speller::isValidWord(const QString &str) return false; } +void Speller::populateLanguagesMenu() +{ + QMenu* menu = qobject_cast(sender()); + + if (!menu || !menu->isEmpty()) { + return; + } + + const QList langs = availableLanguages(); + foreach(const Language & lang, langs) { + QAction* act = menu->addAction(lang.name, this, SLOT(changeLanguage())); + act->setCheckable(true); + act->setChecked(m_language == lang); + act->setData(QVariant::fromValue(lang)); + } + + if (menu->isEmpty()) { + QAction* act = menu->addAction(tr("Empty")); + act->setEnabled(false); + } + + menu->addSeparator(); + menu->addAction(tr("Settings"), this, SLOT(showSettings())); +} + +void Speller::toggleEnableSpellChecking() +{ + m_enabled = !m_enabled; + + Settings settings; + settings.beginGroup("SpellCheck"); + settings.setValue("enabled", m_enabled); + settings.endGroup(); + + loadSettings(); +} + bool Speller::dictionaryExists(const QString &path) const { return QFile(path + ".dic").exists() && diff --git a/src/lib/plugins/qtwebkit/spellcheck/speller.h b/src/lib/plugins/qtwebkit/spellcheck/speller.h index e8150706f..23cfef479 100644 --- a/src/lib/plugins/qtwebkit/spellcheck/speller.h +++ b/src/lib/plugins/qtwebkit/spellcheck/speller.h @@ -52,10 +52,9 @@ public: void loadSettings(); Language language() const; - QList availableLanguages() const; + QList availableLanguages(); QString dictionaryPath() const; - void showSettings(QWidget* parent); void populateContextMenu(QMenu* menu, const QWebHitTestResult &hitTest); bool isMisspelled(const QString &string); @@ -63,10 +62,17 @@ public: static bool isValidWord(const QString &str); +public slots: + void populateLanguagesMenu(); + void toggleEnableSpellChecking(); + private slots: void addToDictionary(); void replaceWord(); + void showSettings(); + void changeLanguage(); + private: void initialize(); void putWord(const QString &word); @@ -81,6 +87,7 @@ private: QFile m_userDictionary; Language m_language; + QList m_availableLanguages; bool m_enabled; // Replacing word @@ -89,4 +96,6 @@ private: int m_endPos; }; +Q_DECLARE_METATYPE(Speller::Language) + #endif // SPELLER_H diff --git a/src/lib/webview/webview.cpp b/src/lib/webview/webview.cpp index d5239c904..356411f4d 100644 --- a/src/lib/webview/webview.cpp +++ b/src/lib/webview/webview.cpp @@ -814,6 +814,8 @@ void WebView::createContextMenu(QMenu* menu, const QWebHitTestResult &hitTest, c if (hitTest.element().tagName().toLower() == QLatin1String("input")) { checkForForm(menu, hitTest.element()); } + + createSpellCheckContextMenu(menu); } if (!selectedText().isEmpty()) { @@ -1030,6 +1032,22 @@ void WebView::createMediaContextMenu(QMenu* menu, const QWebHitTestResult &hitTe menu->addAction(QIcon::fromTheme("document-save"), tr("Save Media To &Disk"), this, SLOT(downloadUrlToDisk()))->setData(videoUrl); } +void WebView::createSpellCheckContextMenu(QMenu* menu) +{ + menu->addSeparator(); + + QAction* act = menu->addAction(tr("Check &Spelling"), mApp->speller(), SLOT(toggleEnableSpellChecking())); + act->setCheckable(true); + act->setChecked(mApp->speller()->isEnabled()); + + if (mApp->speller()->isEnabled()) { + QMenu* men = menu->addMenu(tr("Languages")); + connect(men, SIGNAL(aboutToShow()), mApp->speller(), SLOT(populateLanguagesMenu())); + } + + menu->addSeparator(); +} + void WebView::pauseMedia() { bool paused = m_clickedElement.evaluateJavaScript("this.paused").toBool(); diff --git a/src/lib/webview/webview.h b/src/lib/webview/webview.h index 1eed1b4ce..cdaa7a373 100644 --- a/src/lib/webview/webview.h +++ b/src/lib/webview/webview.h @@ -142,6 +142,7 @@ protected: void createImageContextMenu(QMenu* menu, const QWebHitTestResult &hitTest); void createSelectedTextContextMenu(QMenu* menu, const QWebHitTestResult &hitTest); void createMediaContextMenu(QMenu* menu, const QWebHitTestResult &hitTest); + void createSpellCheckContextMenu(QMenu* menu); private slots: void pauseMedia(); diff --git a/translations/empty.ts b/translations/empty.ts index d501d0f17..a030cc200 100644 --- a/translations/empty.ts +++ b/translations/empty.ts @@ -4241,6 +4241,68 @@ After adding or removing certificate paths, it is neccessary to restart QupZilla + + SpellCheckDialog + + SpellCheck + + + + <html><head/><body><p><span style=" font-weight:600;">Dictionary path</span></p></body></html> + + + + Change... + + + + <b>User dictionary</b> + + + + Add + + + + Remove + + + + Using Hunspell library + + + + Choose dictionary path... + + + + Add new word... + + + + Add new word: + + + + + Speller + + No suggestions + + + + Add to dictionary + + + + Empty + + + + Settings + + + SqueezeLabelV2 @@ -4817,6 +4879,14 @@ After adding or removing certificate paths, it is neccessary to restart QupZilla Create Search Engine + + Check &Spelling + + + + Languages + + jsAlert