Members of the KDE Community are recommended to subscribe to the kde-community mailing list at https://mail.kde.org/mailman/listinfo/kde-community to allow them to participate in important discussions and receive other important announcements

Commit 83140173 authored by Laurent Montel's avatar Laurent Montel 😁

Make grammalecte working

parent 6db6e168
......@@ -52,7 +52,7 @@ option(KDEPIMADDONS_BUILD_EXAMPLES "Build the kdepim-addons example applications
option(KDEPIM_ENTERPRISE_BUILD "Enable features specific to the enterprise branch, which are normally disabled. Also, it disables many components not needed for Kontact such as the Kolab client." FALSE)
option(KMAIL_EDITORCONVERTERPLUGIN_TEMPLATE_BUILD "Build the kmail editor converter plugin." FALSE)
option(KMAIL_GRAMMALECTEPLUGIN_BUILD "Build grammalecte plugin (very experimental." FALSE)
option(KMAIL_LANGUAGETOOLPLUGIN_BUILD "Build languagetool plugin (very experimental)." FALSE)
find_package(Qt5 ${QT_REQUIRED_VERSION} CONFIG REQUIRED WebEngine WebEngineWidgets Widgets Test)
......@@ -81,7 +81,7 @@ set(LIBKLEO_LIB_VERSION "5.10.40")
set(AKONADI_LIB_VERSION "5.10.40")
set(INCIDENCEEDITOR_LIB_VERSION "5.10.40")
set(KTNEF_LIB_VERSION "5.10.40")
set(MESSAGELIB_LIB_VERSION "5.10.47")
set(MESSAGELIB_LIB_VERSION "5.10.49")
set(AKONADICALENDAR_LIB_VERSION "5.10.40")
set(CALENDAR_UTILS_VERSION "5.10.40")
set(KPIMTEXTEDIT_LIB_VERSION "5.10.40")
......
......@@ -3,6 +3,4 @@ add_subdirectory(editorplugins)
add_subdirectory(editorsendcheckplugins)
add_subdirectory(editorinitplugins)
add_subdirectory(editorconvertertextplugins)
if(KMAIL_GRAMMALECTEPLUGIN_BUILD)
add_subdirectory(grammarplugins)
endif()
add_subdirectory(grammarplugins)
add_subdirectory(grammalecte)
add_subdirectory(languagetool)
if (KMAIL_LANGUAGETOOLPLUGIN_BUILD)
add_subdirectory(languagetool)
endif()
......@@ -33,10 +33,9 @@ GrammalecteConfigDialogTest::GrammalecteConfigDialogTest(QObject *parent)
void GrammalecteConfigDialogTest::shouldHaveDefaultValue()
{
GrammalecteConfigDialog w;
GrammalecteConfigDialog w(nullptr, true);
QVERIFY(!w.windowTitle().isEmpty());
QVBoxLayout *mainLayout = w.findChild<QVBoxLayout *>(QStringLiteral("mainlayout"));
QVERIFY(mainLayout);
......
......@@ -32,7 +32,7 @@ GrammalecteConfigWidgetTest::GrammalecteConfigWidgetTest(QObject *parent)
void GrammalecteConfigWidgetTest::shouldHaveDefaultValue()
{
GrammalecteConfigWidget w;
GrammalecteConfigWidget w(nullptr, true);
QVBoxLayout *mainLayout = w.findChild<QVBoxLayout *>(QStringLiteral("mainlayout"));
QVERIFY(mainLayout);
QCOMPARE(mainLayout->margin(), 0);
......
......@@ -20,13 +20,14 @@
#include "grammalectegenerateconfigoptionjobtest.h"
#include "grammalectegenerateconfigoptionjob.h"
#include <QStandardPaths>
#include <QTest>
QTEST_MAIN(GrammalecteGenerateConfigOptionJobTest)
GrammalecteGenerateConfigOptionJobTest::GrammalecteGenerateConfigOptionJobTest(QObject *parent)
: QObject(parent)
{
QStandardPaths::setTestModeEnabled(true);
}
void GrammalecteGenerateConfigOptionJobTest::shouldHaveDefaultValue()
......
......@@ -20,13 +20,14 @@
#include "grammalectegrammarerrortest.h"
#include "grammalectegrammarerror.h"
#include <QJsonDocument>
#include <QStandardPaths>
#include <QTest>
QTEST_MAIN(GrammalecteGrammarErrorTest)
GrammalecteGrammarErrorTest::GrammalecteGrammarErrorTest(QObject *parent)
: QObject(parent)
{
QStandardPaths::setTestModeEnabled(true);
}
void GrammalecteGrammarErrorTest::shouldHaveDefaultValue()
......
......@@ -22,12 +22,13 @@
#include "grammalecteparser.h"
#include <QJsonDocument>
#include <QTest>
#include <QStandardPaths>
QTEST_MAIN(GrammalecteParserTest)
GrammalecteParserTest::GrammalecteParserTest(QObject *parent)
: QObject(parent)
{
QStandardPaths::setTestModeEnabled(true);
}
void GrammalecteParserTest::shouldParseJson_data()
......
......@@ -20,11 +20,12 @@
#include "grammarresultjobtest.h"
#include "grammarresultjob.h"
#include <QTest>
#include <QStandardPaths>
QTEST_MAIN(GrammarResultJobTest)
GrammarResultJobTest::GrammarResultJobTest(QObject *parent)
: QObject(parent)
{
QStandardPaths::setTestModeEnabled(true);
}
void GrammarResultJobTest::shouldHaveDefaultValue()
......@@ -40,13 +41,15 @@ void GrammarResultJobTest::shouldHaveDefaultValue()
void GrammarResultJobTest::shouldBeAbleToStart()
{
GrammarResultJob job;
//Args can be empty if we use default values
QVERIFY(!job.canStart());
job.setText(QStringLiteral("ff"));
QVERIFY(!job.canStart());
job.setPythonPath(QStringLiteral("ff"));
QVERIFY(!job.canStart());
job.setGrammarlecteCliPath(QStringLiteral("ff"));
QVERIFY(!job.canStart());
QVERIFY(job.canStart());
job.setArguments(QStringList() << QStringLiteral("ff"));
QVERIFY(job.canStart());
}
......@@ -20,12 +20,13 @@
#include "grammarresulttextedittest.h"
#include "grammarresulttextedit.h"
#include <QTest>
#include <QStandardPaths>
QTEST_MAIN(GrammarResultTextEditTest)
GrammarResultTextEditTest::GrammarResultTextEditTest(QObject *parent)
: QObject(parent)
{
QStandardPaths::setTestModeEnabled(true);
}
void GrammarResultTextEditTest::shouldHaveDefaultValue()
......
......@@ -19,6 +19,7 @@
#include "grammalecteinterface.h"
#include "grammarresultwidget.h"
#include "grammalecteplugin_debug.h"
#include <KPIMTextEdit/RichTextComposer>
......@@ -27,6 +28,7 @@
#include <KActionCollection>
#include <QHBoxLayout>
#include <QTextBlock>
GrammalecteInterface::GrammalecteInterface(KActionCollection *ac, QWidget *parent)
......@@ -35,6 +37,7 @@ GrammalecteInterface::GrammalecteInterface(KActionCollection *ac, QWidget *paren
QHBoxLayout *layout = new QHBoxLayout(this);
layout->setMargin(0);
mGrammarResultWidget = new GrammarResultWidget(this);
connect(mGrammarResultWidget, &GrammarResultWidget::replaceText, this, &GrammalecteInterface::slotReplaceText);
layout->addWidget(mGrammarResultWidget);
createAction(ac);
......@@ -45,14 +48,29 @@ GrammalecteInterface::~GrammalecteInterface()
}
void GrammalecteInterface::slotReplaceText(const MessageComposer::PluginGrammarAction &act)
{
if (richTextEditor()) {
QTextBlock block = richTextEditor()->document()->findBlockByNumber(act.blockId() - 1);
if (block.isValid()) {
QTextCursor cur(block);
const int position = cur.position();
cur.setPosition(position + act.start());
cur.setPosition(position + act.end(), QTextCursor::KeepAnchor);
cur.insertText(act.replacement());
}
}
}
void GrammalecteInterface::slotActivateGrammalecte(bool state)
{
if (state) {
mGrammarResultWidget->show();
if (richTextEditor()) {
mGrammarResultWidget->setText(richTextEditor()->toPlainText());
mGrammarResultWidget->checkGrammar();
} else {
qCWarning(KMAIL_EDITOR_GRAMMALECTE_PLUGIN_LOG) << "richtexteditor not setted, it's a bug";
}
Q_EMIT activateView(this);
} else {
......
......@@ -32,6 +32,7 @@ public:
KToggleAction *action() const override;
private:
void slotReplaceText(const MessageComposer::PluginGrammarAction &act);
void slotActivateGrammalecte(bool state);
void createAction(KActionCollection *ac);
GrammarResultWidget *mGrammarResultWidget = nullptr;
......
......@@ -21,6 +21,7 @@ target_link_libraries(libkmailgrammalecte
KF5::ConfigCore
KF5::WidgetsAddons
KF5::KIOWidgets
KF5::MessageComposer
)
set_target_properties(libkmailgrammalecte
......
......@@ -25,14 +25,14 @@
#include <KConfigGroup>
#include <KSharedConfig>
GrammalecteConfigDialog::GrammalecteConfigDialog(QWidget *parent)
GrammalecteConfigDialog::GrammalecteConfigDialog(QWidget *parent, bool disableMessageBox)
: QDialog(parent)
{
setWindowTitle(i18n("Configure Grammalecte"));
QVBoxLayout *mainLayout = new QVBoxLayout(this);
mainLayout->setObjectName(QStringLiteral("mainlayout"));
mConfigWidget = new GrammalecteConfigWidget(this);
mConfigWidget = new GrammalecteConfigWidget(this, disableMessageBox);
mConfigWidget->setObjectName(QStringLiteral("configwidget"));
mainLayout->addWidget(mConfigWidget);
......
......@@ -26,7 +26,7 @@ class LIBKMAILGRAMMALECTE_EXPORT GrammalecteConfigDialog : public QDialog
{
Q_OBJECT
public:
explicit GrammalecteConfigDialog(QWidget *parent = nullptr);
explicit GrammalecteConfigDialog(QWidget *parent = nullptr, bool disableMessageBox = false);
~GrammalecteConfigDialog();
private:
void writeConfig();
......
......@@ -22,19 +22,18 @@
#include <KMessageBox>
#include <KLocalizedString>
#include <KConfigGroup>
#include <KSharedConfig>
#include <QVBoxLayout>
#include <QTabWidget>
#include <QCheckBox>
#include <QScrollArea>
#include <QFormLayout>
#include <QVariant>
#include <KUrlRequester>
GrammalecteConfigWidget::GrammalecteConfigWidget(QWidget *parent)
GrammalecteConfigWidget::GrammalecteConfigWidget(QWidget *parent, bool disableMessageBox)
: QWidget(parent)
, mDisableDialogBox(disableMessageBox)
{
QVBoxLayout *mainLayout = new QVBoxLayout(this);
mainLayout->setObjectName(QStringLiteral("mainlayout"));
......@@ -66,7 +65,9 @@ void GrammalecteConfigWidget::loadGrammarSettings()
void GrammalecteConfigWidget::slotGetSettingsError()
{
KMessageBox::error(this, i18n("Error during Extracting Options"), i18n("Impossible to get options. Please verify that you have grammalected installed."));
if (!mDisableDialogBox) {
KMessageBox::error(this, i18n("Impossible to get options. Please verify that you have grammalected installed."), i18n("Error during Extracting Options"));
}
}
void GrammalecteConfigWidget::slotGetSettingsFinished(const QVector<GrammalecteGenerateConfigOptionJob::Option> &result)
......@@ -102,7 +103,6 @@ QWidget *GrammalecteConfigWidget::addGeneralTab()
QWidget *w = new QWidget(this);
w->setObjectName(QStringLiteral("general"));
QFormLayout *lay = new QFormLayout(w);
lay->setMargin(0);
lay->setObjectName(QStringLiteral("generallayout"));
......@@ -119,22 +119,21 @@ QWidget *GrammalecteConfigWidget::addGeneralTab()
void GrammalecteConfigWidget::loadSettings()
{
KConfigGroup grp(KSharedConfig::openConfig(), "Grammalecte");
mPythonPath->setText(grp.readEntry(QStringLiteral("pythonpath")));
mGrammalectePath->setText(grp.readEntry(QStringLiteral("grammalectepath")));
mSaveOptions = grp.readEntry(QStringLiteral("options"), QStringList());
mPythonPath->setText(GrammalecteManager::self()->pythonPath());
mGrammalectePath->setText(GrammalecteManager::self()->grammalectePath());
mSaveOptions = GrammalecteManager::self()->options();
}
void GrammalecteConfigWidget::saveSettings()
{
KConfigGroup grp(KSharedConfig::openConfig(), "Grammalecte");
grp.writeEntry(QStringLiteral("pythonpath"), mPythonPath->text());
grp.writeEntry(QStringLiteral("grammalectepath"), mGrammalectePath->text());
QStringList result;
for (QCheckBox *checkBox : qAsConst(mListOptions)) {
if (checkBox->isChecked()) {
result += checkBox->property("optionname").toString();
}
}
grp.writeEntry(QStringLiteral("options"), result);
GrammalecteManager::self()->setPythonPath(mPythonPath->text());
GrammalecteManager::self()->setGrammalectePath(mGrammalectePath->text());
GrammalecteManager::self()->setOptions(result);
GrammalecteManager::self()->saveSettings();
}
......@@ -29,14 +29,15 @@ class LIBKMAILGRAMMALECTE_EXPORT GrammalecteConfigWidget : public QWidget
{
Q_OBJECT
public:
explicit GrammalecteConfigWidget(QWidget *parent = nullptr);
explicit GrammalecteConfigWidget(QWidget *parent = nullptr, bool disableMessageBox = false);
~GrammalecteConfigWidget();
void loadSettings();
void saveSettings();
private:
void slotGetSettingsFinished(const QVector<GrammalecteGenerateConfigOptionJob::Option> &result);
void loadGrammarSettings();
void slotGetSettingsFinished(const QVector<GrammalecteGenerateConfigOptionJob::Option> &result);
void slotGetSettingsError();
QStringList mSaveOptions;
QList<QCheckBox *> mListOptions;
QWidget *addGeneralTab();
......@@ -44,6 +45,7 @@ private:
QWidget *mGrammarTabWidget = nullptr;
KUrlRequester *mPythonPath = nullptr;
KUrlRequester *mGrammalectePath = nullptr;
bool mDisableDialogBox = false;
};
#endif // GRAMMALECTECONFIGWIDGET_H
......@@ -39,6 +39,25 @@ GrammalecteManager *GrammalecteManager::self()
return &s_self;
}
void GrammalecteManager::saveSettings()
{
KConfigGroup grp(KSharedConfig::openConfig(), "Grammalecte");
grp.writeEntry(QStringLiteral("pythonpath"), mPythonPath);
grp.writeEntry(QStringLiteral("grammalectepath"), mGrammalectePath);
grp.writeEntry(QStringLiteral("options"), mOptions);
}
QStringList GrammalecteManager::options() const
{
return mOptions;
}
void GrammalecteManager::setOptions(const QStringList &saveOptions)
{
mOptions = saveOptions;
}
void GrammalecteManager::loadSettings()
{
KConfigGroup grp(KSharedConfig::openConfig(), "Grammalecte");
......@@ -47,6 +66,7 @@ void GrammalecteManager::loadSettings()
mPythonPath = QStandardPaths::findExecutable(QStringLiteral("python3"));
}
mGrammalectePath = grp.readEntry(QStringLiteral("grammalectepath"));
mOptions = grp.readEntry(QStringLiteral("options"), QStringList());
}
QString GrammalecteManager::pythonPath() const
......
......@@ -37,9 +37,14 @@ public:
void setPythonPath(const QString &pythonPath);
void setGrammalectePath(const QString &grammalectePath);
Q_REQUIRED_RESULT QStringList options() const;
void setOptions(const QStringList &saveOptions);
void loadSettings();
void saveSettings();
private:
QStringList mOptions;
QString mPythonPath;
QString mGrammalectePath;
};
......
......@@ -46,7 +46,14 @@ void GrammarResultJob::start()
file->close();
mProcess->setProgram(mPythonPath);
mProcess->setArguments(QStringList() << mGrammarlecteCliPath << mArguments << QStringLiteral("-f") << file->fileName());
QStringList args;
args << mGrammarlecteCliPath;
if (!mArguments.isEmpty()) {
args << QStringLiteral("-on") << mArguments;
}
args << QStringLiteral("-f") << file->fileName() << QStringLiteral("-j");
mProcess->setArguments(args);
qDebug() << " args " << args;
connect(mProcess, QOverload<int,QProcess::ExitStatus>::of(&QProcess::finished), this, &GrammarResultJob::slotFinished);
connect(mProcess, QOverload<QProcess::ProcessError>::of(&QProcess::error),
this, &GrammarResultJob::receivedError);
......@@ -133,7 +140,7 @@ static bool hasNotEmptyText(const QString &text)
bool GrammarResultJob::canStart() const
{
if (hasNotEmptyText(mText) && !mGrammarlecteCliPath.isEmpty() && !mPythonPath.isEmpty() && !mArguments.isEmpty()) {
if (hasNotEmptyText(mText) && !mGrammarlecteCliPath.isEmpty() && !mPythonPath.isEmpty()/* && !mArguments.isEmpty()*/) {
return true;
}
return false;
......
......@@ -19,8 +19,13 @@
#include "grammarresulttextedit.h"
#include <MessageComposer/PluginEditorGrammarCustomToolsViewInterface>
#include "libgrammalecte_debug.h"
#include <KLocalizedString>
#include <QMenu>
#include <QAction>
#include <QTextBlock>
#include <QTextDocument>
......@@ -48,6 +53,13 @@ void GrammarResultTextEdit::applyGrammarResult(const QVector<GrammalecteGrammarE
//Verify color
format.setBackground(info.color().isValid() ? info.color() : QColor(Qt::red));
format.setToolTip(info.error());
//TODO
MessageComposer::PluginGrammarAction act;
act.setEnd(info.end());
act.setStart(info.begin());
act.setSuggestions(info.suggestions());
act.setBlockId(info.blockId());
format.setProperty(ReplaceFormatInfo, QVariant::fromValue(act));
cur.setPosition(position + info.begin());
cur.setPosition(position + info.end(), QTextCursor::KeepAnchor);
cur.mergeCharFormat(format);
......@@ -56,5 +68,41 @@ void GrammarResultTextEdit::applyGrammarResult(const QVector<GrammalecteGrammarE
}
}
}
//TODO add popupmenu
//Replace text
void GrammarResultTextEdit::contextMenuEvent(QContextMenuEvent *event)
{
QMenu *popup = createStandardContextMenu();
if (popup) {
QTextCursor cursor = cursorForPosition(event->pos());
if (cursor.charFormat().hasProperty(ReplaceFormatInfo)) {
const MessageComposer::PluginGrammarAction act = cursor.charFormat().property(ReplaceFormatInfo).value<MessageComposer::PluginGrammarAction>();
//qDebug() << " property " << act;
popup->addSeparator();
QMenu *popupReplacement = popup->addMenu(i18n("Replacement"));
for (const QString &str : act.suggestions()) {
QAction *actReplacement = popupReplacement->addAction(str);
connect(actReplacement, &QAction::triggered, this, [this, act, str]() {slotReplaceWord(act, str);});
}
}
popup->exec(event->globalPos());
delete popup;
}
}
void GrammarResultTextEdit::slotReplaceWord(const MessageComposer::PluginGrammarAction &act, const QString &replacementWord)
{
MessageComposer::PluginGrammarAction actWithReplacement = act;
actWithReplacement.setReplacement(replacementWord);
QTextBlock block = document()->findBlockByNumber(act.blockId() - 1);
if (block.isValid()) {
QTextCursor cur(block);
const int position = cur.position();
cur.setPosition(position + act.start());
cur.setPosition(position + act.end(), QTextCursor::KeepAnchor);
QTextCharFormat format;
cur.insertText(replacementWord, format);
}
Q_EMIT replaceText(actWithReplacement);
}
......@@ -23,14 +23,29 @@
#include <QTextEdit>
#include "grammalectegrammarerror.h"
#include "libgrammalect_private_export.h"
namespace MessageComposer {
class PluginGrammarAction;
}
class LIBGRAMMALECTPRIVATE_TESTS_EXPORT GrammarResultTextEdit : public QTextEdit
{
Q_OBJECT
public:
explicit GrammarResultTextEdit(QWidget *parent = nullptr);
~GrammarResultTextEdit();
~GrammarResultTextEdit() override;
void applyGrammarResult(const QVector<GrammalecteGrammarError> &infos);
protected:
void contextMenuEvent(QContextMenuEvent *event) override;
Q_SIGNALS:
void replaceText(const MessageComposer::PluginGrammarAction &act);
private:
void slotReplaceWord(const MessageComposer::PluginGrammarAction &act, const QString &replacementWord);
enum TextInfo {
ReplaceFormatInfo = QTextFormat::UserProperty + 1
};
};
#endif // GRAMMARRESULTTEXTEDIT_H
......@@ -20,7 +20,11 @@
#include "grammarresulttextedit.h"
#include "grammarresultwidget.h"
#include "grammalectemanager.h"
#include "grammarresultjob.h"
#include "grammalecteparser.h"
#include <QHBoxLayout>
#include <QJsonDocument>
#include <QTextEdit>
GrammarResultWidget::GrammarResultWidget(QWidget *parent)
......@@ -31,6 +35,7 @@ GrammarResultWidget::GrammarResultWidget(QWidget *parent)
mainLayout->setMargin(0);
mResult = new GrammarResultTextEdit(this);
mResult->setObjectName(QStringLiteral("grammarResult"));
connect(mResult, &GrammarResultTextEdit::replaceText, this, &GrammarResultWidget::replaceText);
mainLayout->addWidget(mResult);
}
......@@ -39,6 +44,25 @@ GrammarResultWidget::~GrammarResultWidget()
}
void GrammarResultWidget::checkGrammar()
{
GrammarResultJob *job = new GrammarResultJob(this);
job->setPythonPath(GrammalecteManager::self()->pythonPath());
job->setGrammarlecteCliPath(GrammalecteManager::self()->grammalectePath());
job->setArguments(GrammalecteManager::self()->options());
job->setText(mResult->toPlainText());
connect(job, &GrammarResultJob::finished, this, &GrammarResultWidget::slotCheckGrammarFinished);
job->start();
}
void GrammarResultWidget::slotCheckGrammarFinished(const QString &result)
{
GrammalecteParser parser;
const QJsonDocument doc = QJsonDocument::fromJson(result.toUtf8());
const QJsonObject fields = doc.object();
applyGrammarResult(parser.parseResult(fields));
}
void GrammarResultWidget::setText(const QString &str)
{
mResult->setText(str);
......
......@@ -23,6 +23,9 @@
#include <QWidget>
#include "libkmailgrammalecte_export.h"
#include "grammalectegrammarerror.h"
namespace MessageComposer {
class PluginGrammarAction;
}
class GrammarResultTextEdit;
class LIBKMAILGRAMMALECTE_EXPORT GrammarResultWidget : public QWidget
{
......@@ -31,8 +34,12 @@ public:
explicit GrammarResultWidget(QWidget *parent = nullptr);
~GrammarResultWidget();
void setText(const QString &str);
void checkGrammar();
void applyGrammarResult(const QVector<GrammalecteGrammarError> &infos);
Q_SIGNALS:
void replaceText(const MessageComposer::PluginGrammarAction &act);
private:
void slotCheckGrammarFinished(const QString &result);
GrammarResultTextEdit *mResult = nullptr;
};
......
......@@ -73,7 +73,6 @@ void GrammalecteWidget::slotCheckGrammar()
GrammarResultJob *job = new GrammarResultJob(this);
job->setPythonPath(QStringLiteral("/usr/bin/python3"));
job->setGrammarlecteCliPath(QStringLiteral("/compile/kde5/framework/kde/pim/grammalecte/grammalecte-cli.py"));
job->setArguments(QStringList() << QStringLiteral("-j"));
job->setText(mInput->toPlainText());
connect(job, &GrammarResultJob::finished, this, &GrammalecteWidget::slotResultFinished);
job->start();
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment