Libksieve

sievescriptdebuggerfrontendwidget.cpp
1 /*
2  SPDX-FileCopyrightText: 2015-2021 Laurent Montel <[email protected]>
3 
4  SPDX-License-Identifier: LGPL-2.0-or-later
5 */
6 
7 #include "sievescriptdebuggerfrontendwidget.h"
8 #include "sievescriptdebuggerresulteditor.h"
9 #include "sievescriptdebuggertextedit.h"
10 #include "sievescriptdebuggerwarning.h"
11 
12 #include "editor/sievetextedit.h"
13 #include "editor/sievetexteditwidget.h"
14 #include <KLineEdit>
15 #include <KLocalizedString>
16 #include <KPIMTextEdit/PlainTextEditorWidget>
17 #include <KPIMTextEdit/TextToSpeechWidget>
18 #include <KUrlRequester>
19 #include <Libkdepim/LineEditCatchReturnKey>
20 #include <QDate>
21 #include <QFormLayout>
22 #include <QLabel>
23 #include <QProcess>
24 #include <QScrollBar>
25 #include <QSplitter>
26 #include <QTemporaryFile>
27 #include <QTextStream>
28 #include <QVBoxLayout>
29 
30 using namespace KSieveUi;
31 
32 SieveScriptDebuggerFrontEndWidget::SieveScriptDebuggerFrontEndWidget(QWidget *parent)
33  : QWidget(parent)
34 {
35  auto mainLayout = new QVBoxLayout(this);
36  mainLayout->setContentsMargins({});
37 
38  auto formLayout = new QFormLayout;
39  mainLayout->addLayout(formLayout);
40 
41  auto emailLab = new QLabel(i18n("Email path:"), this);
42  emailLab->setObjectName(QStringLiteral("emaillab"));
43 
44  mEmailPath = new KUrlRequester(this);
45  mEmailPath->setObjectName(QStringLiteral("emailpath"));
46  mEmailPath->lineEdit()->setTrapReturnKey(true);
47  mEmailPath->lineEdit()->setClearButtonEnabled(true);
48  connect(mEmailPath->lineEdit(), &KLineEdit::textChanged, this, &SieveScriptDebuggerFrontEndWidget::slotEmailChanged);
49 
50  formLayout->addRow(emailLab, mEmailPath);
51 
52  auto extensionLayout = new QHBoxLayout;
53  mainLayout->addLayout(extensionLayout);
54 
55  auto extensionLab = new QLabel(i18n("Extension:"));
56  extensionLab->setObjectName(QStringLiteral("extensionlab"));
57 
58  mExtension = new QLineEdit(this);
59  mExtension->setObjectName(QStringLiteral("extension"));
60  mExtension->setPlaceholderText(i18n("Activate extension with \"+<name of extension>\", deactivate it with \"-<name of extension>\""));
61  mExtension->setClearButtonEnabled(true);
62  new KPIM::LineEditCatchReturnKey(mExtension, this);
63 
64  formLayout->addRow(extensionLab, mExtension);
65 
66  mSplitter = new QSplitter(Qt::Vertical);
67  mSplitter->setObjectName(QStringLiteral("splitter"));
68  mainLayout->addWidget(mSplitter);
69 
70  auto sieveEditorWidget = new QWidget(this);
71  auto vboxSieveEditorLayout = new QVBoxLayout;
72  sieveEditorWidget->setLayout(vboxSieveEditorLayout);
73  vboxSieveEditorLayout->setContentsMargins({});
74 
75  auto textToSpeechWidget = new KPIMTextEdit::TextToSpeechWidget(this);
76  textToSpeechWidget->setObjectName(QStringLiteral("texttospeechwidget"));
77  vboxSieveEditorLayout->addWidget(textToSpeechWidget);
78 
79  auto textEdit = new KSieveUi::SieveScriptDebuggerTextEdit(this);
80  connect(textEdit, &KSieveUi::SieveScriptDebuggerTextEdit::textChanged, this, &SieveScriptDebuggerFrontEndWidget::slotScriptTextChanged);
81  mSieveTextEditWidget = new KSieveUi::SieveTextEditWidget(textEdit, this);
82  mSieveTextEditWidget->setObjectName(QStringLiteral("sievetexteditwidget"));
83  vboxSieveEditorLayout->addWidget(mSieveTextEditWidget);
84  connect(mSieveTextEditWidget->textEdit(), &SieveTextEdit::say, textToSpeechWidget, &KPIMTextEdit::TextToSpeechWidget::say);
85 
86  mSplitter->addWidget(sieveEditorWidget);
87  mSplitter->setChildrenCollapsible(false);
88 
89  mSieveTestResult = new KPIMTextEdit::PlainTextEditorWidget(new KSieveUi::SieveScriptDebuggerResultEditor(this), this);
90  mSieveTestResult->setObjectName(QStringLiteral("sievetextresult"));
91  mSieveTestResult->editor()->setPlaceholderText(i18n("Display check script result..."));
92  mSieveTestResult->setReadOnly(true);
93  mSplitter->addWidget(mSieveTestResult);
94 
95  mSieveScriptDebuggerWarning = new KSieveUi::SieveScriptDebuggerWarning(this);
96  mSieveScriptDebuggerWarning->setObjectName(QStringLiteral("sievescriptdebuggerwarning"));
97  mainLayout->addWidget(mSieveScriptDebuggerWarning);
98 
99  connect(this, &SieveScriptDebuggerFrontEndWidget::debugScriptButtonClicked, this, &SieveScriptDebuggerFrontEndWidget::slotDebugScript);
100 }
101 
102 SieveScriptDebuggerFrontEndWidget::~SieveScriptDebuggerFrontEndWidget()
103 {
104  disconnect(mSieveTextEditWidget->textEdit(),
106  this,
107  &SieveScriptDebuggerFrontEndWidget::slotScriptTextChanged);
108 }
109 
110 void SieveScriptDebuggerFrontEndWidget::updateDebugButton()
111 {
112  Q_EMIT debugButtonEnabled(!mSieveTextEditWidget->textEdit()->document()->isEmpty() && !mEmailPath->lineEdit()->text().trimmed().isEmpty());
113 }
114 
115 void SieveScriptDebuggerFrontEndWidget::slotScriptTextChanged()
116 {
117  updateDebugButton();
118  Q_EMIT scriptTextChanged();
119 }
120 
121 void SieveScriptDebuggerFrontEndWidget::setSplitterSizes(const QList<int> &sizes)
122 {
123  mSplitter->setSizes(sizes);
124 }
125 
126 QList<int> SieveScriptDebuggerFrontEndWidget::splitterSizes() const
127 {
128  return mSplitter->sizes();
129 }
130 
131 void SieveScriptDebuggerFrontEndWidget::slotEmailChanged(const QString &text)
132 {
133  Q_UNUSED(text)
134  updateDebugButton();
135 }
136 
137 void SieveScriptDebuggerFrontEndWidget::slotDebugScript()
138 {
139  if (mSieveTextEditWidget->textEdit()->toPlainText().trimmed().isEmpty()) {
140  mSieveScriptDebuggerWarning->setErrorMessage(i18n("Script text is empty."));
141  return;
142  }
143  if (!mEmailPath->url().isLocalFile()) {
144  mSieveScriptDebuggerWarning->setWarningMessage(i18n("Email file must be installed locally."));
145  return;
146  }
147 
148  auto temporaryFile = new QTemporaryFile();
149  if (!temporaryFile->open()) {
150  mSieveScriptDebuggerWarning->setErrorMessage(i18n("Failed to open temporary file."));
151  delete temporaryFile;
152  return;
153  }
154  Q_EMIT debugButtonEnabled(false);
155  QTextStream stream(temporaryFile);
156  stream << mSieveTextEditWidget->textEdit()->toPlainText();
157  temporaryFile->flush();
158  mProcess = new QProcess(this);
159  temporaryFile->setParent(mProcess);
160 
161  QString extensionList;
162  if (!mExtension->text().trimmed().isEmpty()) {
163  extensionList = QStringLiteral("-x \"%1\"").arg(mExtension->text());
164  }
165 
166  QStringList arguments;
167  if (!extensionList.isEmpty()) {
168  arguments << extensionList;
169  }
170 
171  arguments << temporaryFile->fileName() << mEmailPath->url().toLocalFile();
172  mProcess->start(QStringLiteral("sieve-test"), QStringList() << arguments);
173  connect(mProcess, &QProcess::readyReadStandardOutput, this, &SieveScriptDebuggerFrontEndWidget::slotReadStandardOutput);
174  connect(mProcess, &QProcess::readyReadStandardError, this, &SieveScriptDebuggerFrontEndWidget::slotReadErrorOutput);
175  connect(mProcess, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished), this, &SieveScriptDebuggerFrontEndWidget::slotDebugFinished);
176  mSieveTestResult->editor()->appendPlainText(QStringLiteral("--------------------------------------"));
177  mSieveTestResult->editor()->appendPlainText(QLocale().toString(QDateTime::currentDateTime()));
178  mSieveTestResult->editor()->appendPlainText(QStringLiteral("\n"));
179  if (!mProcess->waitForStarted()) {
180  delete mProcess;
181  mProcess = nullptr;
182  Q_EMIT debugButtonEnabled(true);
183  }
184 }
185 
186 void SieveScriptDebuggerFrontEndWidget::slotReadStandardOutput()
187 {
188  const QByteArray result = mProcess->readAllStandardOutput();
189  mSieveTestResult->editor()->appendPlainText(QString::fromLocal8Bit(result));
190 }
191 
192 void SieveScriptDebuggerFrontEndWidget::slotReadErrorOutput()
193 {
194  const QByteArray result = mProcess->readAllStandardError();
195  mSieveTestResult->editor()->appendPlainText(QString::fromLocal8Bit(result));
196 }
197 
198 void SieveScriptDebuggerFrontEndWidget::slotDebugFinished()
199 {
200  delete mProcess;
201  mProcess = nullptr;
202  Q_EMIT debugButtonEnabled(true);
203 }
204 
205 QString SieveScriptDebuggerFrontEndWidget::script() const
206 {
207  return mSieveTextEditWidget->textEdit()->toPlainText();
208 }
209 
210 void SieveScriptDebuggerFrontEndWidget::setScript(const QString &script)
211 {
212  mSieveTextEditWidget->textEdit()->setPlainText(script);
213  mSieveTextEditWidget->textEdit()->verticalScrollBar()->setValue(mSieveTextEditWidget->textEdit()->verticalScrollBar()->maximum());
214 }
215 
216 bool SieveScriptDebuggerFrontEndWidget::canAccept() const
217 {
218  const QString script = mSieveTextEditWidget->textEdit()->toPlainText();
219  if (script.contains(QLatin1String("debug_log")) || script.contains(QLatin1String("vnd.dovecot.debug"))) {
220  mSieveScriptDebuggerWarning->setErrorMessage(i18n("Script still contains debug method. Remove it please."));
221  return false;
222  }
223  mSieveScriptDebuggerWarning->hide();
224  return true;
225 }
void readyReadStandardError()
void setContentsMargins(int left, int top, int right, int bottom)
void textChanged()
void result(KManageSieve::SieveJob *job, bool success, const QString &script, bool active)
This signal is emitted for all kind of jobs when they have finished.
void textChanged(const QString &text)
void readyReadStandardOutput()
bool disconnect(const QObject *sender, const char *signal, const QObject *receiver, const char *method)
QString fromLocal8Bit(const char *str, int size)
bool isEmpty() const const
void finished(int exitCode)
bool contains(QChar ch, Qt::CaseSensitivity cs) const const
QString i18n(const char *text, const TYPE &arg...)
QDateTime currentDateTime()
char * toString(const T &value)
QString arg(qlonglong a, int fieldWidth, int base, QChar fillChar) const const
Vertical
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
Q_EMITQ_EMIT
void addLayout(QLayout *layout, int stretch)
This file is part of the KDE documentation.
Documentation copyright © 1996-2021 The KDE developers.
Generated on Sat Apr 17 2021 23:09:34 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.