mirror of
https://git.FreeBSD.org/ports.git
synced 2024-11-27 00:57:50 +00:00
- Update `net-im/psi' to version 1.4
- Replace current 2015 Hunspell implementation (by Sergey Ilinykh and Vitaly Tonkacheyev) with 2009 one by Alexander Tsvyashchenko, which turned out to be better alternative: * Much faster (suggestions appear almost instantly vs. several hundreds milliseconds with the original implementation) * Better multilanguage support (tested with English and Russian) * Ability to limit number of suggestions in the settings dialog * Working "add word to the dictionary" feature Obtained from: http://endl.ch/content/psi-spell-checking-hunspell-support
This commit is contained in:
parent
751dfb9495
commit
59494c0dce
Notes:
svn2git
2021-03-31 03:12:20 +00:00
svn path=/head/; revision=498280
@ -2,8 +2,7 @@
|
||||
# $FreeBSD$
|
||||
|
||||
PORTNAME= psi
|
||||
DISTVERSION= 1.3
|
||||
PORTREVISION= 4
|
||||
PORTVERSION= 1.4
|
||||
CATEGORIES= net-im
|
||||
MASTER_SITES= SF/${PORTNAME}/Psi/${PORTVERSION}
|
||||
|
||||
@ -43,6 +42,9 @@ ENCHANT_LIB_DEPENDS= libenchant.so:textproc/enchant
|
||||
ENCHANT_CMAKE_BOOL= USE_ENCHANT
|
||||
|
||||
post-patch:
|
||||
# Replace original Hunspell implementation with better alternative
|
||||
@${CP} ${FILESDIR}/hunspellchecker.* \
|
||||
${WRKSRC}/src/libpsi/tools/spellchecker
|
||||
# Avoid conflict with C++20 <version> by adding .txt suffix
|
||||
@${MV} ${WRKSRC}/version ${WRKSRC}/version.txt
|
||||
@${REINPLACE_CMD} -i .c++20 's,SOURCE_DIR}/version,&.txt,' \
|
||||
|
@ -1,3 +1,3 @@
|
||||
TIMESTAMP = 1508773121
|
||||
SHA256 (psi-1.3.tar.xz) = 59debd16e61ab1d4ff88aca9f41b9caaaca8395f1576418fb99214d5e2c6fa8b
|
||||
SIZE (psi-1.3.tar.xz) = 2143076
|
||||
TIMESTAMP = 1541113245
|
||||
SHA256 (psi-1.4.tar.xz) = 761934c1c62daf69215f085ba24d7f9cd4db05ef0ad735383d68fb03d21571ad
|
||||
SIZE (psi-1.4.tar.xz) = 2119840
|
||||
|
215
net-im/psi/files/hunspellchecker.cpp
Normal file
215
net-im/psi/files/hunspellchecker.cpp
Normal file
@ -0,0 +1,215 @@
|
||||
/*
|
||||
* hunspellchecker.cpp
|
||||
*
|
||||
* Copyright (C) 2009 Alexander Tsvyashchenko
|
||||
*
|
||||
* 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 option) any later version.
|
||||
*
|
||||
* You can also redistribute and/or modify this program under the
|
||||
* terms of the Psi License, specified in the accompanied COPYING
|
||||
* file, as published by the Psi Project; either dated January 1st,
|
||||
* 2005, 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 library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include <QDir>
|
||||
#include <QCoreApplication>
|
||||
#include <QtDebug>
|
||||
#include <QTextCodec>
|
||||
|
||||
#include <hunspell/hunspell.hxx>
|
||||
#include "hunspellchecker.h"
|
||||
|
||||
HunSpellChecker::HunSpellChecker()
|
||||
{
|
||||
QStringList dict_paths(getDictSearchPaths());
|
||||
|
||||
for (QStringList::const_iterator dict_path_it = dict_paths.begin(); dict_path_it != dict_paths.end(); ++dict_path_it) {
|
||||
// Get all affixes present in given path.
|
||||
QStringList affixes = QDir(*dict_path_it).entryList(QStringList("*.aff"), QDir::Files);
|
||||
|
||||
for (QStringList::const_iterator affix_it = affixes.begin(); affix_it != affixes.end(); ++affix_it) {
|
||||
QString base_name(QFileInfo(*affix_it).baseName());
|
||||
int sep_pos = base_name.indexOf("_");
|
||||
QString lang = sep_pos != -1 ? base_name.left(sep_pos) : base_name;
|
||||
|
||||
if (!all_langs_.contains(lang))
|
||||
all_langs_.append(lang);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void HunSpellChecker::clearSpellers()
|
||||
{
|
||||
for (HunSpellers::const_iterator it = spellers_.begin(); it != spellers_.end(); ++it)
|
||||
delete it.value().speller;
|
||||
|
||||
spellers_.clear();
|
||||
}
|
||||
|
||||
HunSpellChecker::~HunSpellChecker()
|
||||
{
|
||||
clearSpellers();
|
||||
}
|
||||
|
||||
bool HunSpellChecker::isCorrect(const QString& word)
|
||||
{
|
||||
if (!spellers_.empty()) {
|
||||
for (HunSpellers::const_iterator it = spellers_.begin(); it != spellers_.end(); ++it) {
|
||||
QByteArray word_enc = it.value().codec -> fromUnicode(word);
|
||||
if (it.value().speller -> spell(word_enc.constData()) != 0)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
QList<QString> HunSpellChecker::suggestions(const QString& word, const QString& lang, unsigned max_sugs)
|
||||
{
|
||||
QList<QString> words;
|
||||
|
||||
HunSpellers::const_iterator it = spellers_.find(lang);
|
||||
|
||||
if (it != spellers_.end()) {
|
||||
char** suggestions;
|
||||
QByteArray word_enc = it.value().codec -> fromUnicode(word);
|
||||
|
||||
if (int sugs_num = it.value().speller -> suggest(&suggestions, word_enc.constData())) {
|
||||
int sugs_out = max_sugs ? std::min((int)max_sugs, sugs_num) : sugs_num;
|
||||
for (int i = 0; i < sugs_out; ++i) {
|
||||
words << it.value().codec -> toUnicode(suggestions[i]);
|
||||
}
|
||||
it.value().speller -> free_list(&suggestions, sugs_num);
|
||||
}
|
||||
}
|
||||
|
||||
return words;
|
||||
}
|
||||
|
||||
// FIXME: hunspell keeps added words in memory only!
|
||||
// To survive program exit they have to be saved/restored manually,
|
||||
// which is not done here.
|
||||
bool HunSpellChecker::add(const QString& word, const QString& lang)
|
||||
{
|
||||
QString trimmed_word = word.trimmed();
|
||||
HunSpellers::const_iterator it = spellers_.find(lang);
|
||||
|
||||
if(!trimmed_word.isEmpty() && it != spellers_.end()) {
|
||||
QByteArray word_enc = it.value().codec -> fromUnicode(trimmed_word);
|
||||
it.value().speller -> add(word_enc.constData());
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool HunSpellChecker::available() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool HunSpellChecker::writable() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
QList<QString> HunSpellChecker::getAllLanguages() const
|
||||
{
|
||||
return all_langs_;
|
||||
}
|
||||
|
||||
QList<QString> HunSpellChecker::getDictSearchPaths() const
|
||||
{
|
||||
QStringList dict_paths(QString("%1/hunspell").arg(QCoreApplication::applicationDirPath()));
|
||||
|
||||
// Paths taken from hunspell-1.2.8/src/tools/hunspell.cxx
|
||||
#ifdef Q_OS_WIN32
|
||||
dict_paths << "C:/Hunspell";
|
||||
#else
|
||||
dict_paths <<
|
||||
"/usr/local/share/hunspell" <<
|
||||
"/usr/share/myspell" <<
|
||||
"/usr/share/myspell/dicts";
|
||||
#endif
|
||||
|
||||
return dict_paths;
|
||||
}
|
||||
|
||||
void HunSpellChecker::setActiveLanguages(const QList<QString>& langs)
|
||||
{
|
||||
// Free all spellers not needed anymore.
|
||||
for (HunSpellers::iterator it = spellers_.begin(); it != spellers_.end(); )
|
||||
{
|
||||
if (!langs.contains(it.key()))
|
||||
{
|
||||
delete it.value().speller;
|
||||
it = spellers_.erase(it);
|
||||
}
|
||||
else
|
||||
++it;
|
||||
}
|
||||
|
||||
QStringList dict_paths(getDictSearchPaths());
|
||||
|
||||
for (QStringList::const_iterator dict_path_it = dict_paths.begin(); dict_path_it != dict_paths.end(); ++dict_path_it)
|
||||
{
|
||||
for (QStringList::const_iterator lang_it = langs.begin(); lang_it != langs.end(); ++lang_it)
|
||||
{
|
||||
// Load dictionaries only for those languages that are not present already.
|
||||
if (spellers_.contains(*lang_it))
|
||||
continue;
|
||||
|
||||
// Get all affixes with names beginning with the specified language.
|
||||
QStringList affixes = QDir(*dict_path_it).entryList(QStringList(QString("%1*.aff").arg(*lang_it)), QDir::Files);
|
||||
|
||||
for (QStringList::const_iterator affix_it = affixes.begin(); affix_it != affixes.end(); ++affix_it)
|
||||
{
|
||||
QString base_name(QFileInfo(*affix_it).completeBaseName());
|
||||
|
||||
// Get all dictionaries with names beginning with the affix name.
|
||||
QStringList dicts_all = QDir(*dict_path_it).entryList(QStringList(QString("%1*.dic").arg(base_name)), QDir::Files),
|
||||
dicts_to_add;
|
||||
|
||||
// Add all dictionaries except those that have corresponding more specific affix name: those should be
|
||||
// handled separately, together with its affix file.
|
||||
//
|
||||
// So, for example, having en.aff, en.dic, en_XX.dic, en_YY.aff, en_YY.dic we should get in the result two
|
||||
// hunspell objects, one with affix en.aff and dictionaries en.dic and en_XX.dic and the other one with
|
||||
// affix en_YY.aff and dictionary en_YY.dic
|
||||
for (QStringList::const_iterator dict_it = dicts_all.begin(); dict_it != dicts_all.end(); ++dict_it)
|
||||
{
|
||||
QString matching_affix(QString("%1.aff").arg(QFileInfo(*dict_it).completeBaseName()));
|
||||
|
||||
if (matching_affix == *affix_it || !affixes.contains(matching_affix))
|
||||
dicts_to_add << *dict_it;
|
||||
}
|
||||
|
||||
if (dicts_to_add.size())
|
||||
{
|
||||
Hunspell* speller = new Hunspell(
|
||||
QString("%1/%2").arg(*dict_path_it, *affix_it).toLocal8Bit().constData(),
|
||||
QString("%1/%2").arg(*dict_path_it, dicts_to_add[0]).toLocal8Bit().constData()
|
||||
);
|
||||
|
||||
for (int i = 1; i < dicts_to_add.size(); ++i)
|
||||
speller -> add_dic(QString("%1/%2").arg(*dict_path_it, dicts_to_add[i]).toLocal8Bit().constData());
|
||||
|
||||
spellers_.insert(*lang_it, HunSpellInfo(speller, QTextCodec::codecForName(speller -> get_dic_encoding())));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
71
net-im/psi/files/hunspellchecker.h
Normal file
71
net-im/psi/files/hunspellchecker.h
Normal file
@ -0,0 +1,71 @@
|
||||
/*
|
||||
* hunspellchecker.h
|
||||
*
|
||||
* Copyright (C) 2009 Alexander Tsvyashchenko
|
||||
*
|
||||
* 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 option) any later version.
|
||||
*
|
||||
* You can also redistribute and/or modify this program under the
|
||||
* terms of the Psi License, specified in the accompanied COPYING
|
||||
* file, as published by the Psi Project; either dated January 1st,
|
||||
* 2005, 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 library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef HUNSPELLCHECKER_H
|
||||
#define HUNSPELLCHECKER_H
|
||||
|
||||
#include <QList>
|
||||
#include <QString>
|
||||
#include <QMap>
|
||||
|
||||
#include "spellchecker.h"
|
||||
|
||||
class Hunspell;
|
||||
|
||||
class HunSpellChecker : public SpellChecker
|
||||
{
|
||||
public:
|
||||
HunSpellChecker();
|
||||
~HunSpellChecker();
|
||||
virtual QList<QString> suggestions(const QString&, const QString& lang, unsigned max_sugs);
|
||||
virtual bool isCorrect(const QString&);
|
||||
virtual bool add(const QString& word, const QString& lang);
|
||||
virtual bool available() const;
|
||||
virtual bool writable() const;
|
||||
virtual QList<QString> getAllLanguages() const;
|
||||
virtual void setActiveLanguages(const QList<QString>&);
|
||||
|
||||
private:
|
||||
struct HunSpellInfo
|
||||
{
|
||||
QTextCodec* codec;
|
||||
Hunspell* speller;
|
||||
|
||||
HunSpellInfo(Hunspell* speller, QTextCodec* codec):
|
||||
speller(speller), codec(codec) {}
|
||||
};
|
||||
|
||||
typedef QMap<QString, HunSpellInfo> HunSpellers;
|
||||
|
||||
HunSpellers spellers_;
|
||||
QList<QString> all_langs_;
|
||||
|
||||
private:
|
||||
void clearSpellers();
|
||||
QList<QString> getDictSearchPaths() const;
|
||||
};
|
||||
|
||||
#endif
|
@ -1,15 +0,0 @@
|
||||
From 4b838c04fa90ab56974bc4c57aaf7d4e80b8fff8 Mon Sep 17 00:00:00 2001
|
||||
From: Vitozz <thetvg@gmail.com>
|
||||
Date: Mon, 28 May 2018 20:45:04 +0300
|
||||
Subject: [PATCH] Try to fix build with qt-5.11
|
||||
|
||||
--- src/accountmanagedlg.cpp.orig
|
||||
+++ src/accountmanagedlg.cpp
|
||||
@@ -28,6 +28,7 @@
|
||||
#include <QTimer>
|
||||
#include <QHeaderView>
|
||||
#include <QDropEvent>
|
||||
+#include <QButtonGroup>
|
||||
|
||||
#include "psicon.h"
|
||||
#include "psiaccount.h"
|
@ -0,0 +1,37 @@
|
||||
--- src/libpsi/tools/spellchecker/spellchecker.cpp.orig 2018-11-02 00:37:04 UTC
|
||||
+++ src/libpsi/tools/spellchecker/spellchecker.cpp
|
||||
@@ -48,7 +48,7 @@ SpellChecker* SpellChecker::instance()
|
||||
#elif defined(HAVE_ASPELL)
|
||||
instance_ = new ASpellChecker();
|
||||
#elif defined(HAVE_HUNSPELL)
|
||||
- instance_ = new HunspellChecker();
|
||||
+ instance_ = new HunSpellChecker();
|
||||
#else
|
||||
instance_ = new SpellChecker();
|
||||
#endif
|
||||
@@ -80,14 +80,23 @@ bool SpellChecker::isCorrect(const QString&)
|
||||
return true;
|
||||
}
|
||||
|
||||
-QList<QString> SpellChecker::suggestions(const QString&)
|
||||
+QList<QString> SpellChecker::suggestions(const QString&, const QString&, unsigned)
|
||||
{
|
||||
return QList<QString>();
|
||||
}
|
||||
|
||||
-bool SpellChecker::add(const QString&)
|
||||
+bool SpellChecker::add(const QString&, const QString&)
|
||||
{
|
||||
return false;
|
||||
+}
|
||||
+
|
||||
+QList<QString> SpellChecker::getAllLanguages() const
|
||||
+{
|
||||
+ return QList<QString>();
|
||||
+}
|
||||
+
|
||||
+void SpellChecker::setActiveLanguages(const QList<QString>&)
|
||||
+{
|
||||
}
|
||||
|
||||
SpellChecker* SpellChecker::instance_ = NULL;
|
@ -0,0 +1,19 @@
|
||||
--- src/libpsi/tools/spellchecker/spellchecker.h.orig 2018-11-02 00:37:04 UTC
|
||||
+++ src/libpsi/tools/spellchecker/spellchecker.h
|
||||
@@ -37,12 +37,11 @@ class SpellChecker : public QObject (public)
|
||||
static SpellChecker* instance();
|
||||
virtual bool available() const;
|
||||
virtual bool writable() const;
|
||||
- virtual QList<QString> suggestions(const QString&);
|
||||
+ virtual QList<QString> suggestions(const QString& word, const QString& lang, unsigned max_sugs);
|
||||
virtual bool isCorrect(const QString&);
|
||||
- virtual bool add(const QString&);
|
||||
-
|
||||
- virtual void setActiveLanguages(const QList<QString>& ) {}
|
||||
- virtual QList<QString> getAllLanguages() const { return QList<QString>(); }
|
||||
+ virtual bool add(const QString& word, const QString& lang);
|
||||
+ virtual QList<QString> getAllLanguages() const;
|
||||
+ virtual void setActiveLanguages(const QList<QString>&);
|
||||
|
||||
protected:
|
||||
SpellChecker();
|
116
net-im/psi/files/patch-src_msgmle.cpp
Normal file
116
net-im/psi/files/patch-src_msgmle.cpp
Normal file
@ -0,0 +1,116 @@
|
||||
--- src/msgmle.cpp.orig 2018-11-02 00:15:39 UTC
|
||||
+++ src/msgmle.cpp
|
||||
@@ -257,12 +257,36 @@ bool ChatEdit::checkSpellingGloballyEnabled()
|
||||
return (SpellChecker::instance()->available() && PsiOptions::instance()->getOption("options.ui.spell-check.enabled").toBool());
|
||||
}
|
||||
|
||||
+QStringList ChatEdit::checkSpellingActiveLanguages()
|
||||
+{
|
||||
+ return PsiOptions::instance()->getOption("options.ui.spell-check.langs").toString().split(QRegExp("\\s+|,|\\:"), QString::SkipEmptyParts);
|
||||
+}
|
||||
+
|
||||
+unsigned ChatEdit::checkSpellingMaxSuggestions()
|
||||
+{
|
||||
+ return PsiOptions::instance()->getOption("options.ui.spell-check.maxsugs").toString().toInt();
|
||||
+}
|
||||
+
|
||||
void ChatEdit::setCheckSpelling(bool b)
|
||||
{
|
||||
check_spelling_ = b;
|
||||
if (check_spelling_) {
|
||||
if (!spellhighlighter_)
|
||||
spellhighlighter_ = new SpellHighlighter(document());
|
||||
+ all_langs_ = SpellChecker::instance()->getAllLanguages();
|
||||
+ langs_ = checkSpellingActiveLanguages();
|
||||
+ // No langs specified in options?
|
||||
+ if (langs_.isEmpty()) {
|
||||
+ QString env_lang(getenv("LANG"));
|
||||
+ // Let's try to use the language specified in environment ...
|
||||
+ if (!env_lang.isEmpty() && all_langs_.contains(env_lang))
|
||||
+ langs_.append(env_lang);
|
||||
+ else // ... still no luck? Will use all available languages then.
|
||||
+ langs_ = all_langs_;
|
||||
+ }
|
||||
+ SpellChecker::instance()->setActiveLanguages(langs_);
|
||||
+ // If zero, means no limit (empty option also translates to zero).
|
||||
+ max_sugs_ = checkSpellingMaxSuggestions();
|
||||
}
|
||||
else {
|
||||
delete spellhighlighter_;
|
||||
@@ -335,19 +359,34 @@ void ChatEdit::contextMenuEvent(QContextMenuEvent *e)
|
||||
tc.movePosition(QTextCursor::EndOfWord, QTextCursor::KeepAnchor);
|
||||
QString selected_word = tc.selectedText();
|
||||
if (!selected_word.isEmpty() && !QRegExp("\\d+").exactMatch(selected_word) && !SpellChecker::instance()->isCorrect(selected_word)) {
|
||||
- QList<QString> suggestions = SpellChecker::instance()->suggestions(selected_word);
|
||||
- if (!suggestions.isEmpty() || SpellChecker::instance()->writable()) {
|
||||
- QMenu spell_menu;
|
||||
+ QMenu spell_menu;
|
||||
+ foreach (QString lang, langs_) {
|
||||
+ QList<QString> suggestions = SpellChecker::instance()->suggestions(selected_word, lang, max_sugs_);
|
||||
if (!suggestions.isEmpty()) {
|
||||
+ QAction* lang_name = spell_menu.addAction(tr("Language") + ": " + lang);
|
||||
+ lang_name->setDisabled(true);
|
||||
foreach(QString suggestion, suggestions) {
|
||||
QAction* act_suggestion = spell_menu.addAction(suggestion);
|
||||
connect(act_suggestion,SIGNAL(triggered()),SLOT(applySuggestion()));
|
||||
}
|
||||
spell_menu.addSeparator();
|
||||
}
|
||||
+ }
|
||||
+ if (!spell_menu.isEmpty() || SpellChecker::instance()->writable() || !all_langs_.isEmpty()) {
|
||||
if (SpellChecker::instance()->writable()) {
|
||||
- QAction* act_add = spell_menu.addAction(tr("Add to dictionary"));
|
||||
- connect(act_add,SIGNAL(triggered()),SLOT(addToDictionary()));
|
||||
+ foreach (QString lang, langs_) {
|
||||
+ QAction* act_add = spell_menu.addAction(tr("Add to dictionary") + ": " + lang);
|
||||
+ act_add->setData(lang);
|
||||
+ connect(act_add,SIGNAL(triggered()),SLOT(addToDictionary()));
|
||||
+ }
|
||||
+ spell_menu.addSeparator();
|
||||
+ foreach (QString lang, all_langs_) {
|
||||
+ QAction* act_lang_sel = spell_menu.addAction(tr("Use language") + ": " + lang);
|
||||
+ act_lang_sel->setCheckable(true);
|
||||
+ act_lang_sel->setChecked(langs_.contains(lang));
|
||||
+ act_lang_sel->setData(lang);
|
||||
+ connect(act_lang_sel,SIGNAL(triggered()),SLOT(changedUseLang()));
|
||||
+ }
|
||||
}
|
||||
spell_menu.exec(QCursor::pos());
|
||||
e->accept();
|
||||
@@ -397,18 +436,35 @@ void ChatEdit::applySuggestion()
|
||||
*/
|
||||
void ChatEdit::addToDictionary()
|
||||
{
|
||||
+ QAction* action = static_cast<QAction*>(sender());
|
||||
QTextCursor tc = cursorForPosition(last_click_);
|
||||
int current_position = textCursor().position();
|
||||
|
||||
// Get the selected word
|
||||
tc.movePosition(QTextCursor::StartOfWord, QTextCursor::MoveAnchor);
|
||||
tc.movePosition(QTextCursor::EndOfWord, QTextCursor::KeepAnchor);
|
||||
- SpellChecker::instance()->add(tc.selectedText());
|
||||
+ SpellChecker::instance()->add(tc.selectedText(), action->data().toString());
|
||||
|
||||
// Put the cursor where it belongs
|
||||
tc.clearSelection();
|
||||
tc.setPosition(current_position);
|
||||
setTextCursor(tc);
|
||||
+
|
||||
+ spellhighlighter_->rehighlight();
|
||||
+}
|
||||
+
|
||||
+void ChatEdit::changedUseLang()
|
||||
+{
|
||||
+ QAction* action = static_cast<QAction*>(sender());
|
||||
+ QString lang = action->data().toString();
|
||||
+
|
||||
+ if (langs_.contains(lang))
|
||||
+ langs_.removeAt(langs_.indexOf(lang));
|
||||
+ else
|
||||
+ langs_.append(lang);
|
||||
+
|
||||
+ SpellChecker::instance()->setActiveLanguages(langs_);
|
||||
+ spellhighlighter_->rehighlight();
|
||||
}
|
||||
|
||||
void ChatEdit::optionsChanged()
|
28
net-im/psi/files/patch-src_msgmle.h
Normal file
28
net-im/psi/files/patch-src_msgmle.h
Normal file
@ -0,0 +1,28 @@
|
||||
--- src/msgmle.h.orig 2018-11-02 00:15:39 UTC
|
||||
+++ src/msgmle.h
|
||||
@@ -54,6 +54,8 @@ class ChatEdit : public QTextEdit (public)
|
||||
void setFont(const QFont &);
|
||||
|
||||
static bool checkSpellingGloballyEnabled();
|
||||
+ static QStringList checkSpellingActiveLanguages();
|
||||
+ static unsigned checkSpellingMaxSuggestions();
|
||||
void setCheckSpelling(bool);
|
||||
XMPP::HTMLElement toHTMLElement();
|
||||
bool isCorrection() { return correction; }
|
||||
@@ -71,6 +73,7 @@ public slots:
|
||||
protected slots:
|
||||
void applySuggestion();
|
||||
void addToDictionary();
|
||||
+ void changedUseLang();
|
||||
void optionsChanged();
|
||||
void showHistoryMessageNext();
|
||||
void showHistoryMessagePrev();
|
||||
@@ -91,6 +94,8 @@ protected slots: (protected)
|
||||
private:
|
||||
QWidget *dialog_;
|
||||
bool check_spelling_;
|
||||
+ QList<QString> langs_, all_langs_;
|
||||
+ unsigned max_sugs_;
|
||||
SpellHighlighter* spellhighlighter_;
|
||||
QPoint last_click_;
|
||||
int previous_position_;
|
66
net-im/psi/files/patch-src_options_opt__advanced.cpp
Normal file
66
net-im/psi/files/patch-src_options_opt__advanced.cpp
Normal file
@ -0,0 +1,66 @@
|
||||
--- src/options/opt_advanced.cpp.orig 2018-11-02 00:15:39 UTC
|
||||
+++ src/options/opt_advanced.cpp
|
||||
@@ -45,6 +45,8 @@ QWidget *OptionsTabAdvanced::widget()
|
||||
#endif
|
||||
|
||||
d->ck_spell->setEnabled(SpellChecker::instance()->available());
|
||||
+ d->le_spellLangs->setEnabled(SpellChecker::instance()->available());
|
||||
+ d->le_spellMaxSugs->setEnabled(SpellChecker::instance()->available());
|
||||
|
||||
d->ck_messageevents->setWhatsThis(
|
||||
tr("Enables the sending and requesting of message events such as "
|
||||
@@ -60,6 +62,12 @@ QWidget *OptionsTabAdvanced::widget()
|
||||
tr("Enables remote controlling your client from other locations"));
|
||||
d->ck_spell->setWhatsThis(
|
||||
tr("Check this option if you want your spelling to be checked"));
|
||||
+ d->le_spellLangs->setWhatsThis(
|
||||
+ tr("List here all languages you want your spell checker to use"
|
||||
+ " when checking your spelling."));
|
||||
+ d->le_spellMaxSugs->setWhatsThis(
|
||||
+ tr("Maximal number of suggestion words per language you want to see"
|
||||
+ " in context menu when the word is misspelled."));
|
||||
d->ck_contactsMessageFormatting->setWhatsThis(
|
||||
tr("If enabled, Psi will display incoming messages formatted in the style specified by the contact"));
|
||||
d->ck_autocopy->setWhatsThis(
|
||||
@@ -99,6 +107,10 @@ QWidget *OptionsTabAdvanced::widget()
|
||||
connect(d->ck_messageevents,SIGNAL(toggled(bool)),d->ck_sendComposingEvents,SLOT(setEnabled(bool)));
|
||||
d->ck_inactiveevents->setEnabled(d->ck_messageevents->isChecked());
|
||||
d->ck_sendComposingEvents->setEnabled(d->ck_messageevents->isChecked());
|
||||
+ connect(d->ck_spell,SIGNAL(toggled(bool)),d->le_spellLangs,SLOT(setEnabled(bool)));
|
||||
+ connect(d->ck_spell,SIGNAL(toggled(bool)),d->le_spellMaxSugs,SLOT(setEnabled(bool)));
|
||||
+ d->le_spellLangs->setEnabled(d->ck_spell->isChecked());
|
||||
+ d->le_spellMaxSugs->setEnabled(d->ck_spell->isChecked());
|
||||
|
||||
return w;
|
||||
}
|
||||
@@ -116,8 +128,11 @@ void OptionsTabAdvanced::applyOptions()
|
||||
PsiOptions::instance()->setOption("options.ui.notifications.send-receipts", d->ck_sendReceipts->isChecked());
|
||||
PsiOptions::instance()->setOption("options.messages.dont-send-composing-events", d->ck_sendComposingEvents->isChecked());
|
||||
PsiOptions::instance()->setOption("options.external-control.adhoc-remote-control.enable", d->ck_rc->isChecked());
|
||||
- if ( SpellChecker::instance()->available() )
|
||||
+ if ( SpellChecker::instance()->available() ) {
|
||||
PsiOptions::instance()->setOption("options.ui.spell-check.enabled",d->ck_spell->isChecked());
|
||||
+ PsiOptions::instance()->setOption("options.ui.spell-check.langs", d->le_spellLangs->text());
|
||||
+ PsiOptions::instance()->setOption("options.ui.spell-check.maxsugs", d->le_spellMaxSugs->text());
|
||||
+ }
|
||||
PsiOptions::instance()->setOption("options.html.chat.render", d->ck_contactsMessageFormatting->isChecked());
|
||||
PsiOptions::instance()->setOption("options.ui.automatically-copy-selected-text", d->ck_autocopy->isChecked());
|
||||
PsiOptions::instance()->setOption("options.ui.contactlist.use-single-click", d->ck_singleclick->isChecked());
|
||||
@@ -145,10 +160,15 @@ void OptionsTabAdvanced::restoreOptions()
|
||||
d->ck_sendReceipts->setChecked( PsiOptions::instance()->getOption("options.ui.notifications.send-receipts").toBool() );
|
||||
d->ck_sendComposingEvents->setChecked( PsiOptions::instance()->getOption("options.messages.dont-send-composing-events").toBool() );
|
||||
d->ck_rc->setChecked( PsiOptions::instance()->getOption("options.external-control.adhoc-remote-control.enable").toBool() );
|
||||
- if ( !SpellChecker::instance()->available() )
|
||||
+ if ( !SpellChecker::instance()->available() ) {
|
||||
d->ck_spell->setChecked(false);
|
||||
- else
|
||||
+ d->le_spellLangs->setText("");
|
||||
+ d->le_spellMaxSugs->setText("");
|
||||
+ } else {
|
||||
d->ck_spell->setChecked(PsiOptions::instance()->getOption("options.ui.spell-check.enabled").toBool());
|
||||
+ d->le_spellLangs->setText(PsiOptions::instance()->getOption("options.ui.spell-check.langs").toString());
|
||||
+ d->le_spellMaxSugs->setText(PsiOptions::instance()->getOption("options.ui.spell-check.maxsugs").toString());
|
||||
+ }
|
||||
d->ck_contactsMessageFormatting->setChecked(PsiOptions::instance()->getOption("options.html.chat.render").toBool());
|
||||
d->ck_autocopy->setChecked( PsiOptions::instance()->getOption("options.ui.automatically-copy-selected-text").toBool() );
|
||||
d->ck_singleclick->setChecked( PsiOptions::instance()->getOption("options.ui.contactlist.use-single-click").toBool() );
|
29
net-im/psi/files/patch-src_options_opt__advanced.ui
Normal file
29
net-im/psi/files/patch-src_options_opt__advanced.ui
Normal file
@ -0,0 +1,29 @@
|
||||
--- src/options/opt_advanced.ui.orig 2018-11-02 00:15:39 UTC
|
||||
+++ src/options/opt_advanced.ui
|
||||
@@ -72,6 +72,26 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
+ <widget class="QLabel" name="TextLabel3" >
|
||||
+ <property name="text" >
|
||||
+ <string>List of active spellchecker languages:</string>
|
||||
+ </property>
|
||||
+ </widget>
|
||||
+ </item>
|
||||
+ <item>
|
||||
+ <widget class="QLineEdit" name="le_spellLangs" />
|
||||
+ </item>
|
||||
+ <item>
|
||||
+ <widget class="QLabel" name="TextLabel4" >
|
||||
+ <property name="text" >
|
||||
+ <string>Maximum suggestions per language:</string>
|
||||
+ </property>
|
||||
+ </widget>
|
||||
+ </item>
|
||||
+ <item>
|
||||
+ <widget class="QLineEdit" name="le_spellMaxSugs" />
|
||||
+ </item>
|
||||
+ <item>
|
||||
<widget class="QCheckBox" name="ck_contactsMessageFormatting" >
|
||||
<property name="text" >
|
||||
<string>Use contacts' message formatting</string>
|
Loading…
Reference in New Issue
Block a user