diff options
| author | 2014-12-29 22:45:17 +0000 | |
|---|---|---|
| committer | 2014-12-29 22:45:17 +0000 | |
| commit | 79eb97350014ba8a3d3cf024a6cf21e12f2672f3 (patch) | |
| tree | 781fc544447a9d28ca363c2fb6cd1c9fdb2d66d7 /src/modules | |
| parent | Merge patch by TheReign (diff) | |
| download | KVIrc-79eb97350014ba8a3d3cf024a6cf21e12f2672f3.tar.gz KVIrc-79eb97350014ba8a3d3cf024a6cf21e12f2672f3.tar.bz2 KVIrc-79eb97350014ba8a3d3cf024a6cf21e12f2672f3.zip | |
Fix #24. Add spell checking support using Enchant library (wrapper for Aspell, Hunspell, and others).
Thanks to alexzulu and S658P for inspiration, and to Pragma for code review.
git-svn-id: https://svn.kvirc.de/svn/trunk/kvirc@6416 17fca916-40b9-46aa-a4ea-0a15b648b75c
Diffstat (limited to 'src/modules')
| -rw-r--r-- | src/modules/CMakeLists.txt | 4 | ||||
| -rw-r--r-- | src/modules/options/OptionsWidget_textEncoding.cpp | 93 | ||||
| -rw-r--r-- | src/modules/options/OptionsWidget_textEncoding.h | 2 | ||||
| -rw-r--r-- | src/modules/spellchecker/CMakeLists.txt | 8 | ||||
| -rw-r--r-- | src/modules/spellchecker/libkvispellchecker.cpp | 157 |
5 files changed, 252 insertions, 12 deletions
diff --git a/src/modules/CMakeLists.txt b/src/modules/CMakeLists.txt index 57468051d..3ab0c1f29 100644 --- a/src/modules/CMakeLists.txt +++ b/src/modules/CMakeLists.txt @@ -52,6 +52,10 @@ if(COMPILE_PYTHON_SUPPORT) subdirs(python) endif() +if(COMPILE_ENCHANT_SUPPORT) + subdirs(spellchecker) +endif() + if(APPLE) # This is a dirty trick ensure we get some code executed after the last module gets installed subdirs(zzz_afterlastmodule) diff --git a/src/modules/options/OptionsWidget_textEncoding.cpp b/src/modules/options/OptionsWidget_textEncoding.cpp index eeaac0411..e6f8f7ab2 100644 --- a/src/modules/options/OptionsWidget_textEncoding.cpp +++ b/src/modules/options/OptionsWidget_textEncoding.cpp @@ -30,9 +30,11 @@ #include "KviQString.h" #include "KviApplication.h" #include "KviFileUtils.h" +#include "KviKvsScript.h" #include <QDir> #include <QMessageBox> +#include <QHeaderView> QString g_szPrevSettedLocale; @@ -42,19 +44,23 @@ OptionsWidget_textEncoding::OptionsWidget_textEncoding(QWidget * parent) setObjectName("textencoding_options_widget"); createLayout(); + KviTalGroupBox* gbox = addGroupBox(0,0,0,0,Qt::Horizontal,__tr2qs_ctx("Encoding","options")); + QGridLayout* grid = new QGridLayout; + gbox->setLayout(grid); + //server encoding - addLabel(0,0,0,0,__tr2qs_ctx("Default server encoding:","options")); + grid->addWidget(addLabel(gbox,__tr2qs_ctx("Default server encoding:","options")),0,0); - m_pSrvEncodingCombo = new QComboBox(this); - addWidgetToLayout(m_pSrvEncodingCombo,1,0,1,0); + m_pSrvEncodingCombo = new QComboBox(gbox); + grid->addWidget(m_pSrvEncodingCombo,0,1); m_pSrvEncodingCombo->addItem(__tr2qs_ctx("Use Language Encoding","options")); //text encoding - addLabel(0,1,0,1,__tr2qs_ctx("Default text encoding:","options")); + grid->addWidget(addLabel(gbox,__tr2qs_ctx("Default text encoding:","options")),1,0); - m_pTextEncodingCombo = new QComboBox(this); - addWidgetToLayout(m_pTextEncodingCombo,1,1,1,1); + m_pTextEncodingCombo = new QComboBox(gbox); + grid->addWidget(m_pTextEncodingCombo,1,1); m_pTextEncodingCombo->addItem(__tr2qs_ctx("Use Language Encoding","options")); @@ -78,14 +84,17 @@ OptionsWidget_textEncoding::OptionsWidget_textEncoding(QWidget * parent) m_pTextEncodingCombo->setCurrentIndex(iTextMatch); m_pSrvEncodingCombo->setCurrentIndex(iSrvMatch); - addLabel(0,2,0,2,__tr2qs_ctx("Force language:","options")); + gbox = addGroupBox(0,1,0,1,Qt::Horizontal,__tr2qs_ctx("Language","options")); + grid = new QGridLayout; + gbox->setLayout(grid); + + grid->addWidget(addLabel(gbox,__tr2qs_ctx("Force language:","options")),0,0); - m_pForcedLocaleCombo = new QComboBox(this); + m_pForcedLocaleCombo = new QComboBox(gbox); - addWidgetToLayout(m_pForcedLocaleCombo,1,2,1,2); + grid->addWidget(m_pForcedLocaleCombo,0,1); - QLabel * l = new QLabel(__tr2qs_ctx("<b>Note:</b> You need to restart KVirc to apply a language changing","options"),this); - addWidgetToLayout(l,0,3,1,3); + grid->addWidget(addLabel(gbox,__tr2qs_ctx("<b>Note:</b> You need to restart KVirc to apply a language changing","options")),1,0,1,2); m_pForcedLocaleCombo->addItem(__tr2qs_ctx("Automatic detection","options")); m_pForcedLocaleCombo->addItem(__tr2qs_ctx("en","options")); @@ -124,7 +133,56 @@ OptionsWidget_textEncoding::OptionsWidget_textEncoding(QWidget * parent) m_pForcedLocaleCombo->setCurrentIndex(1); else m_pForcedLocaleCombo->setCurrentIndex(iMatch); - addRowSpacer(0,4,1,4); + +#ifdef COMPILE_ENCHANT_SUPPORT + { + gbox = addGroupBox(0,2,0,2,Qt::Horizontal,__tr2qs_ctx("Spell checker dictionaries","options")); + + KviKvsVariant availableDictionaries; + KviKvsScript::evaluate("$spellchecker.availableDictionaries", NULL, NULL, &availableDictionaries); + const KviPointerHashTable<QString, KviKvsVariant>* hashTable = availableDictionaries.hash()->dict(); + KviPointerHashTableIterator<QString, KviKvsVariant> iter(*hashTable); + QMap<QString, QString> dictMap; + for (bool b = iter.moveFirst(); b; b = iter.moveNext()) { + QString szDescription; + iter.current()->asString(szDescription); + dictMap[iter.currentKey()] = szDescription; + } + + m_pSpellCheckerDictionaries = new QTableWidget(gbox); + m_pSpellCheckerDictionaries->setRowCount(dictMap.size()); + m_pSpellCheckerDictionaries->setColumnCount(2); + QStringList header; + header << __tr2qs_ctx("Language code", "options"); + header << __tr2qs_ctx("Provided by", "options"); + m_pSpellCheckerDictionaries->setHorizontalHeaderLabels(header); +#if (QT_VERSION >= 0x050000) + m_pSpellCheckerDictionaries->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch); +#else + m_pSpellCheckerDictionaries->horizontalHeader()->setResizeMode(QHeaderView::Stretch); +#endif + m_pSpellCheckerDictionaries->setSelectionBehavior(QAbstractItemView::SelectRows); + m_pSpellCheckerDictionaries->setSelectionMode(QAbstractItemView::SingleSelection); + m_pSpellCheckerDictionaries->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + + int row = 0; + for (QMap<QString, QString>::iterator it = dictMap.begin(); it != dictMap.end(); ++it, ++row) { + QTableWidgetItem* itemLang = new QTableWidgetItem(it.key()); + itemLang->setCheckState(KVI_OPTION_STRINGLIST(KviOption_stringlistSpellCheckerDictionaries).contains(it.key()) ? Qt::Checked : Qt::Unchecked); + itemLang->setFlags(itemLang->flags() & ~Qt::ItemIsEditable); + m_pSpellCheckerDictionaries->setItem(row,0,itemLang); + + QTableWidgetItem* itemDesc = new QTableWidgetItem(it.value()); + itemDesc->setFlags(itemDesc->flags() & ~Qt::ItemIsEditable); + m_pSpellCheckerDictionaries->setItem(row,1,itemDesc); + } + + m_pSpellCheckerDictionaries->resizeColumnsToContents(); + m_pSpellCheckerDictionaries->resizeRowsToContents(); + } +#else + addRowSpacer(0,2,0,2); +#endif } OptionsWidget_textEncoding::~OptionsWidget_textEncoding() @@ -166,5 +224,16 @@ void OptionsWidget_textEncoding::commit() } /* if(!KviQString::equalCI(m_pForcedLocaleCombo->text(idx),m_szLanguage)) QMessageBox::information(0,"KVIrc",__tr2qs_ctx("You need to restart KVirc to apply a language changing","options"),QMessageBox::Ok);*/ + +#ifdef COMPILE_ENCHANT_SUPPORT + QStringList wantedDictionaries; + for (int i = 0; i < m_pSpellCheckerDictionaries->rowCount(); ++i) { + if (m_pSpellCheckerDictionaries->item(i,0)->checkState() == Qt::Checked) { + wantedDictionaries << m_pSpellCheckerDictionaries->item(i,0)->text(); + } + } + KVI_OPTION_STRINGLIST(KviOption_stringlistSpellCheckerDictionaries) = wantedDictionaries; + KviKvsScript::run("spellchecker.reloadDictionaries", NULL); +#endif } diff --git a/src/modules/options/OptionsWidget_textEncoding.h b/src/modules/options/OptionsWidget_textEncoding.h index 964ad606f..a16169c39 100644 --- a/src/modules/options/OptionsWidget_textEncoding.h +++ b/src/modules/options/OptionsWidget_textEncoding.h @@ -27,6 +27,7 @@ #include "KviOptionsWidget.h" #include <QComboBox> +#include <QTableWidget> #define KVI_OPTIONS_WIDGET_ICON_OptionsWidget_textEncoding KviIconManager::TextEncoding #define KVI_OPTIONS_WIDGET_NAME_OptionsWidget_textEncoding __tr2qs_no_lookup("Language") @@ -45,6 +46,7 @@ protected: QComboBox * m_pTextEncodingCombo; QComboBox * m_pSrvEncodingCombo; QComboBox * m_pForcedLocaleCombo; + QTableWidget * m_pSpellCheckerDictionaries; public: virtual void commit(); }; diff --git a/src/modules/spellchecker/CMakeLists.txt b/src/modules/spellchecker/CMakeLists.txt new file mode 100644 index 000000000..34b241e0e --- /dev/null +++ b/src/modules/spellchecker/CMakeLists.txt @@ -0,0 +1,8 @@ +# CMakeLists for src/modules/avatar + +set(kvispellchecker_SRCS + libkvispellchecker.cpp +) + +set(kvi_module_name kvispellchecker) +include(${CMAKE_SOURCE_DIR}/cmake/module.rules.txt) diff --git a/src/modules/spellchecker/libkvispellchecker.cpp b/src/modules/spellchecker/libkvispellchecker.cpp new file mode 100644 index 000000000..0a384d77a --- /dev/null +++ b/src/modules/spellchecker/libkvispellchecker.cpp @@ -0,0 +1,157 @@ +//============================================================================= +// +// File : libkvispellchecker.cpp +// Creation date : Thu Dec 26 2014 15:12:12 GMT by Alexey Sokolov +// +// This file is part of the KVIrc IRC client distribution +// Copyright © 2014 Alexey Sokolov <sokolov@google.com> +// +// 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 2 +// of the License, or (at your opinion) 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, write to the Free Software Foundation, +// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//============================================================================= + +#include "KviModule.h" +#include "KviOptions.h" +#include <enchant.h> + +static EnchantBroker* g_pEnchantBroker = NULL; +static KviPointerList<EnchantDict>* g_pEnchantDicts = NULL; + +/* + @doc: spellchecker.available_dictionaries + @type: + function + @title: + $spellchecker.available_dictionaries + @short: + Return available dictionaries. + @syntax: + <hash> $spellchecker.available_dictionaries + @description: + This function returns a hash. For every supported dictionary, key is the language code, + value is name of provider for that language (e.g. Aspell). +*/ +static void spellchecker_enumerate_dicts(const char* szLang, const char* /*szName*/, + const char* szDesc, const char* /*szFile*/, void* pData) { + KviKvsHash* pHash = reinterpret_cast<KviKvsHash*>(pData); + pHash->set(szLang, new KviKvsVariant(szDesc)); +} +static bool spellchecker_kvs_available_dictionaries(KviKvsModuleFunctionCall* c) { + KVSM_PARAMETERS_BEGIN(c) + KVSM_PARAMETERS_END(c) + KviKvsHash* pHash = new KviKvsHash; + enchant_broker_list_dicts(g_pEnchantBroker, spellchecker_enumerate_dicts, pHash); + c->returnValue()->setHash(pHash); + return true; +} + +/* + @doc: spellchecker.check + @type: + function + @title: + $spellchecker.check + @short: + Check a single work for spelling mistakes. + @syntax: + <bool> $spellchecker.check(<word:string>) + @description: + This function returns true if the word is spelled correctly. +*/ +static bool spellchecker_kvs_check(KviKvsModuleFunctionCall* c) { + QString szWord; + KVSM_PARAMETERS_BEGIN(c) + KVSM_PARAMETER("word", KVS_PT_STRING, 0, szWord) + KVSM_PARAMETERS_END(c) + QByteArray utf8 = szWord.toUtf8(); + bool bResult = g_pEnchantDicts->isEmpty(); + KviPointerListIterator<EnchantDict> it(*g_pEnchantDicts); + for (bool b = it.moveFirst(); b; b = it.moveNext()) { + bResult |= enchant_dict_check(*it, utf8.data(), utf8.size()) == 0; + } + c->returnValue()->setBoolean(bResult); + return true; +} + +static void spellchecker_reload_dicts() { + while (!g_pEnchantDicts->isEmpty()) { + enchant_broker_free_dict(g_pEnchantBroker, g_pEnchantDicts->takeFirst()); + } + const QStringList& wantedDictionaries = KVI_OPTION_STRINGLIST(KviOption_stringlistSpellCheckerDictionaries); + foreach(QString szLang, wantedDictionaries) { + EnchantDict* pDict = enchant_broker_request_dict(g_pEnchantBroker, szLang.toUtf8().data()); + if (pDict) { + g_pEnchantDicts->append(pDict); + } else { + qDebug("Can't load spellchecker dictionary %s: %s", szLang.toUtf8().data(), enchant_broker_get_error(g_pEnchantBroker)); + } + } +} + +/* + @doc: spellchecker.reloadDictionaries + @type: + command + @title: + spellchecker.reloadDictionaries + @short: + Reload spell checker dictionaries + @syntax: + spellchecker.reloadDictionaries + @description: + Reload spell checker dictionaries +*/ +static bool spellchecker_kvs_reload_dictionaries(KviKvsModuleCommandCall * c) +{ + KVSM_PARAMETERS_BEGIN(c) + KVSM_PARAMETERS_END(c) + spellchecker_reload_dicts(); + return true; +} + +static bool spellchecker_module_init(KviModule* m) { + g_pEnchantBroker = enchant_broker_init(); + g_pEnchantDicts = new KviPointerList<EnchantDict>(/* bAutoDelete = */ false); + + spellchecker_reload_dicts(); + + KVSM_REGISTER_SIMPLE_COMMAND(m, "reloadDictionaries", spellchecker_kvs_reload_dictionaries); + KVSM_REGISTER_FUNCTION(m, "availableDictionaries", spellchecker_kvs_available_dictionaries); + KVSM_REGISTER_FUNCTION(m, "check", spellchecker_kvs_check); + return true; +} + +static bool spellchecker_module_cleanup(KviModule*) { + while (!g_pEnchantDicts->isEmpty()) { + enchant_broker_free_dict(g_pEnchantBroker, g_pEnchantDicts->takeFirst()); + } + delete g_pEnchantDicts; + g_pEnchantDicts = NULL; + enchant_broker_free(g_pEnchantBroker); + g_pEnchantBroker = NULL; + return true; +} + +KVIRC_MODULE( + "SpellChecker", // module name + "4.0.0", // module version + "Copyright (C) 2014 Alexey Sokolov (sokolov at google dot com)", // author & (C) + "Spell checker", + spellchecker_module_init, + 0, + 0, + spellchecker_module_cleanup, + 0 +) |
