feat(Spellchecking): Update Spellchecker

Closes: #3443
This commit is contained in:
B.Melnik 2021-09-10 15:38:10 +03:00 committed by Michał
parent ec0b962bad
commit cd82993bed
3 changed files with 84 additions and 103 deletions

View File

@ -21,7 +21,11 @@ macro(add_target name type)
set_target_properties(${name} PROPERTIES CXX_STANDARD 11 AUTOMOC ON) set_target_properties(${name} PROPERTIES CXX_STANDARD 11 AUTOMOC ON)
if(APPLE)
target_include_directories(${name} PUBLIC include include/Qt ${CMAKE_SOURCE_DIR}/../../bottles/hunspell/include)
else()
target_include_directories(${name} PUBLIC include include/Qt) target_include_directories(${name} PUBLIC include include/Qt)
endif()
target_link_libraries(${name} PRIVATE Qt5::Core Qt5::Gui Qt5::Widgets Qt5::Qml Qt5::Quick Qt5::Network) target_link_libraries(${name} PRIVATE Qt5::Core Qt5::Gui Qt5::Widgets Qt5::Qml Qt5::Quick Qt5::Network)

View File

@ -11,12 +11,12 @@ class Hunspell;
#endif #endif
class QTextCodec; class QTextCodec;
class SpellChecker : public QSyntaxHighlighter class SpellChecker : public QObject
{ {
Q_OBJECT Q_OBJECT
Q_PROPERTY(QString text READ text WRITE setText NOTIFY textChanged) Q_PROPERTY(QString lang READ lang WRITE setLang NOTIFY langChanged)
Q_PROPERTY(QString displayText READ displayText NOTIFY displayTextChanged) Q_PROPERTY(QString userDict READ userDict WRITE setUserDict NOTIFY userDictChanged)
Q_PROPERTY(QQuickTextDocument* document READ textDocument WRITE setTextDocument NOTIFY textDocumentChanged)
public: public:
explicit SpellChecker(QObject *parent = nullptr); explicit SpellChecker(QObject *parent = nullptr);
~SpellChecker(); ~SpellChecker();
@ -25,30 +25,24 @@ public:
Q_INVOKABLE QVariantList suggest(const QString &word); Q_INVOKABLE QVariantList suggest(const QString &word);
Q_INVOKABLE void ignoreWord(const QString &word); Q_INVOKABLE void ignoreWord(const QString &word);
Q_INVOKABLE void addToUserWordlist(const QString &word); Q_INVOKABLE void addToUserWordlist(const QString &word);
Q_INVOKABLE bool isInit() const;
void setText(const QString& text); const QString& lang() const;
const QString& text() const; void setLang(const QString& lang);
const QString& displayText() const; const QString& userDict() const;
void setUserDict(const QString& userDict);
QQuickTextDocument* textDocument() const;
void setTextDocument(QQuickTextDocument* document);
signals: signals:
void textChanged(); void langChanged();
void displayTextChanged(); void userDictChanged();
void textDocumentChanged();
protected:
void highlightBlock(const QString &text) final;
private: private:
void makeDisplayText(const QString& text); void initHunspell();
private: private:
QString m_text; QString m_lang;
QString m_displayText; QString m_userDict;
QString m_dictionaryPath;
QQuickTextDocument *m_document; QQuickTextDocument *m_document;
#ifdef Q_OS_MACOS #ifdef Q_OS_MACOS

View File

@ -1,6 +1,9 @@
#include "DosSpellchecker.h" #include "../include/DOtherSide/DosSpellchecker.h"
#ifdef Q_OS_MACOS
#include "hunspell/hunspell.hxx"
#endif
#include "hunspell.hxx"
#include <QTextCodec> #include <QTextCodec>
#include <QFile> #include <QFile>
#include <QDebug> #include <QDebug>
@ -13,13 +16,49 @@
#include <QInputMethod> #include <QInputMethod>
SpellChecker::SpellChecker(QObject *parent) SpellChecker::SpellChecker(QObject *parent)
: QSyntaxHighlighter(parent) : QObject(parent)
{
auto language = QLocale::system().bcp47Name();
#ifdef Q_OS_MACOS #ifdef Q_OS_MACOS
QString dictFile = QApplication::applicationDirPath() + + "/dictionaries/" + language + "/index.dic"; , m_hunspell(nullptr)
QString affixFile = QApplication::applicationDirPath() + + "/dictionaries/" + language + "/index.aff"; #endif
, m_userDict("userDict_")
{
}
SpellChecker::~SpellChecker()
{
#ifdef Q_OS_MACOS
delete m_hunspell;
#endif
}
bool SpellChecker::spell(const QString &word)
{
#ifdef Q_OS_MACOS
return m_hunspell->spell(m_codec->fromUnicode(word).toStdString());
#else
return true;
#endif
}
bool SpellChecker::isInit() const
{
#ifdef Q_OS_MACOS
return !m_hunspell;
#else
return true;
#endif
}
void SpellChecker::initHunspell()
{
#ifdef Q_OS_MACOS
if (m_hunspell) {
delete m_hunspell;
}
QString dictFile = QApplication::applicationDirPath() + "/dictionaries/" + m_lang + "/index.dic";
QString affixFile = QApplication::applicationDirPath() + "/dictionaries/" + m_lang + "/index.aff";
QByteArray dictFilePathBA = dictFile.toLocal8Bit(); QByteArray dictFilePathBA = dictFile.toLocal8Bit();
QByteArray affixFilePathBA = affixFile.toLocal8Bit(); QByteArray affixFilePathBA = affixFile.toLocal8Bit();
m_hunspell = new Hunspell(affixFilePathBA.constData(), m_hunspell = new Hunspell(affixFilePathBA.constData(),
@ -49,7 +88,7 @@ SpellChecker::SpellChecker(QObject *parent)
} }
m_codec = QTextCodec::codecForName(encoding.toLatin1().constData()); m_codec = QTextCodec::codecForName(encoding.toLatin1().constData());
QString userDict = "userDict_" + language + ".txt"; QString userDict = m_userDict + m_lang + ".txt";
if (!userDict.isEmpty()) { if (!userDict.isEmpty()) {
QFile userDictonaryFile(userDict); QFile userDictonaryFile(userDict);
@ -70,22 +109,6 @@ SpellChecker::SpellChecker(QObject *parent)
#endif #endif
} }
SpellChecker::~SpellChecker()
{
#ifdef Q_OS_MACOS
delete m_hunspell;
#endif
}
bool SpellChecker::spell(const QString &word)
{
#ifdef Q_OS_MACOS
return m_hunspell->spell(m_codec->fromUnicode(word).toStdString());
#else
return true;
#endif
}
QVariantList SpellChecker::suggest(const QString &word) QVariantList SpellChecker::suggest(const QString &word)
{ {
int numSuggestions = 0; int numSuggestions = 0;
@ -117,9 +140,7 @@ void SpellChecker::ignoreWord(const QString &word)
void SpellChecker::addToUserWordlist(const QString &word) void SpellChecker::addToUserWordlist(const QString &word)
{ {
#ifdef Q_OS_MACOS #ifdef Q_OS_MACOS
auto language = QLocale::scriptToString(QLocale::system().script()); QString userDict = m_userDict + m_lang + ".txt";
QString userDict = "userDict_" + language + ".txt";
if (!userDict.isEmpty()) { if (!userDict.isEmpty()) {
QFile userDictonaryFile(userDict); QFile userDictonaryFile(userDict);
if (userDictonaryFile.open(QIODevice::Append)) { if (userDictonaryFile.open(QIODevice::Append)) {
@ -136,67 +157,29 @@ void SpellChecker::addToUserWordlist(const QString &word)
#endif #endif
} }
void SpellChecker::setText(const QString &text) const QString& SpellChecker::lang() const
{ {
if (m_text != text) { return m_lang;
m_text = text; }
emit textChanged();
makeDisplayText(m_text); void SpellChecker::setLang(const QString& lang)
{
if (m_lang != lang) {
m_lang = lang;
initHunspell();
emit langChanged();
} }
} }
const QString &SpellChecker::text() const const QString& SpellChecker::userDict() const
{ {
return m_text; return m_userDict;
} }
const QString &SpellChecker::displayText() const void SpellChecker::setUserDict(const QString& userDict)
{ {
return m_displayText; if (m_userDict != userDict) {
} m_userDict = userDict;
emit userDictChanged();
QQuickTextDocument *SpellChecker::textDocument() const
{
return m_document;
}
void SpellChecker::setTextDocument(QQuickTextDocument *document)
{
if (m_document != document) {
m_document = document;
setDocument(m_document->textDocument());
emit textDocumentChanged();
} }
} }
void SpellChecker::highlightBlock(const QString &text)
{
QTextCharFormat format;
format.setFontUnderline(true);
QRegularExpression expression("\\S+");
QRegularExpressionMatchIterator i = expression.globalMatch(text);
while(i.hasNext()) {
QRegularExpressionMatch match = i.next();
if (!spell(match.captured())) {
setFormat(match.capturedStart(), match.capturedLength(), format);
}
}
}
void SpellChecker::makeDisplayText(const QString &text)
{
auto words = text.split(" ");
QString gPattern = "<u style=\"color: red;\">%1</u>";
m_displayText = ""; // todo optimize delta
for (const auto& word: qAsConst(words)) {
if (!spell(word)) {
m_displayText.append(" " + gPattern.arg(word));
} else {
m_displayText.append(" " + word);
}
}
emit displayTextChanged();
}