Libksieve

sievescriptdebuggerfrontendwidget.cpp
1 /*
2  Copyright (C) 2015-2020 Laurent Montel <[email protected]>
3 
4  This library is free software; you can redistribute it and/or
5  modify it under the terms of the GNU Library General Public
6  License as published by the Free Software Foundation; either
7  version 2 of the License, or (at your option) any later version.
8 
9  This library is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  Library General Public License for more details.
13 
14  You should have received a copy of the GNU Library General Public License
15  along with this library; see the file COPYING.LIB. If not, write to
16  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17  Boston, MA 02110-1301, USA.
18 */
19 
20 #include "sievescriptdebuggerfrontendwidget.h"
21 #include "sievescriptdebuggertextedit.h"
22 #include "sievescriptdebuggerwarning.h"
23 #include "sievescriptdebuggerresulteditor.h"
24 
25 #include <QScrollBar>
26 #include <QVBoxLayout>
27 #include <QSplitter>
28 #include <QTemporaryFile>
29 #include <QProcess>
30 #include <QTextStream>
31 #include <QFormLayout>
32 #include "editor/sievetexteditwidget.h"
33 #include "editor/sievetextedit.h"
34 #include <KPIMTextEdit/PlainTextEditorWidget>
35 #include <KPIMTextEdit/TextToSpeechWidget>
36 #include <Libkdepim/LineEditCatchReturnKey>
37 #include <QLabel>
38 #include <KUrlRequester>
39 #include <KLineEdit>
40 #include <KLocalizedString>
41 #include <QDate>
42 
43 using namespace KSieveUi;
44 
45 SieveScriptDebuggerFrontEndWidget::SieveScriptDebuggerFrontEndWidget(QWidget *parent)
46  : QWidget(parent)
47 {
48  QVBoxLayout *mainLayout = new QVBoxLayout(this);
49  mainLayout->setContentsMargins(0, 0, 0, 0);
50 
51  QFormLayout *formLayout = new QFormLayout;
52  mainLayout->addLayout(formLayout);
53 
54  QLabel *emailLab = new QLabel(i18n("Email path:"), this);
55  emailLab->setObjectName(QStringLiteral("emaillab"));
56 
57  mEmailPath = new KUrlRequester(this);
58  mEmailPath->setObjectName(QStringLiteral("emailpath"));
59  mEmailPath->lineEdit()->setTrapReturnKey(true);
60  mEmailPath->lineEdit()->setClearButtonEnabled(true);
61  connect(mEmailPath->lineEdit(), &KLineEdit::textChanged, this, &SieveScriptDebuggerFrontEndWidget::slotEmailChanged);
62 
63  formLayout->addRow(emailLab, mEmailPath);
64 
65  QHBoxLayout *extensionLayout = new QHBoxLayout;
66  mainLayout->addLayout(extensionLayout);
67 
68  QLabel *extensionLab = new QLabel(i18n("Extension:"));
69  extensionLab->setObjectName(QStringLiteral("extensionlab"));
70 
71  mExtension = new QLineEdit(this);
72  mExtension->setObjectName(QStringLiteral("extension"));
73  mExtension->setPlaceholderText(i18n("Activate extension with \"+<name of extension>\", deactivate it with \"-<name of extension>\""));
74  mExtension->setClearButtonEnabled(true);
75  new KPIM::LineEditCatchReturnKey(mExtension, this);
76 
77  formLayout->addRow(extensionLab, mExtension);
78 
79  mSplitter = new QSplitter(Qt::Vertical);
80  mSplitter->setObjectName(QStringLiteral("splitter"));
81  mainLayout->addWidget(mSplitter);
82 
83  QWidget *sieveEditorWidget = new QWidget(this);
84  QVBoxLayout *vboxSieveEditorLayout = new QVBoxLayout;
85  sieveEditorWidget->setLayout(vboxSieveEditorLayout);
86  vboxSieveEditorLayout->setContentsMargins(0, 0, 0, 0);
87 
89  textToSpeechWidget->setObjectName(QStringLiteral("texttospeechwidget"));
90  vboxSieveEditorLayout->addWidget(textToSpeechWidget);
91 
92  KSieveUi::SieveScriptDebuggerTextEdit *textEdit = new KSieveUi::SieveScriptDebuggerTextEdit(this);
93  connect(textEdit, &KSieveUi::SieveScriptDebuggerTextEdit::textChanged, this, &SieveScriptDebuggerFrontEndWidget::slotScriptTextChanged);
94  mSieveTextEditWidget = new KSieveUi::SieveTextEditWidget(textEdit, this);
95  mSieveTextEditWidget->setObjectName(QStringLiteral("sievetexteditwidget"));
96  vboxSieveEditorLayout->addWidget(mSieveTextEditWidget);
97  connect(mSieveTextEditWidget->textEdit(), &SieveTextEdit::say, textToSpeechWidget, &KPIMTextEdit::TextToSpeechWidget::say);
98 
99  mSplitter->addWidget(sieveEditorWidget);
100  mSplitter->setChildrenCollapsible(false);
101 
102  mSieveTestResult = new KPIMTextEdit::PlainTextEditorWidget(new KSieveUi::SieveScriptDebuggerResultEditor(this), this);
103  mSieveTestResult->setObjectName(QStringLiteral("sievetextresult"));
104  mSieveTestResult->editor()->setPlaceholderText(i18n("Display check script result..."));
105  mSieveTestResult->setReadOnly(true);
106  mSplitter->addWidget(mSieveTestResult);
107 
108  mSieveScriptDebuggerWarning = new KSieveUi::SieveScriptDebuggerWarning(this);
109  mSieveScriptDebuggerWarning->setObjectName(QStringLiteral("sievescriptdebuggerwarning"));
110  mainLayout->addWidget(mSieveScriptDebuggerWarning);
111 
112  connect(this, &SieveScriptDebuggerFrontEndWidget::debugScriptButtonClicked, this, &SieveScriptDebuggerFrontEndWidget::slotDebugScript);
113 }
114 
115 SieveScriptDebuggerFrontEndWidget::~SieveScriptDebuggerFrontEndWidget()
116 {
117  disconnect(mSieveTextEditWidget->textEdit(), &KSieveUi::SieveScriptDebuggerTextEdit::textChanged, this, &SieveScriptDebuggerFrontEndWidget::slotScriptTextChanged);
118 }
119 
120 void SieveScriptDebuggerFrontEndWidget::updateDebugButton()
121 {
122  Q_EMIT debugButtonEnabled(!mSieveTextEditWidget->textEdit()->document()->isEmpty() && !mEmailPath->lineEdit()->text().trimmed().isEmpty());
123 }
124 
125 void SieveScriptDebuggerFrontEndWidget::slotScriptTextChanged()
126 {
127  updateDebugButton();
128  Q_EMIT scriptTextChanged();
129 }
130 
131 void SieveScriptDebuggerFrontEndWidget::setSplitterSizes(const QList<int> &sizes)
132 {
133  mSplitter->setSizes(sizes);
134 }
135 
136 QList<int> SieveScriptDebuggerFrontEndWidget::splitterSizes() const
137 {
138  return mSplitter->sizes();
139 }
140 
141 void SieveScriptDebuggerFrontEndWidget::slotEmailChanged(const QString &text)
142 {
143  Q_UNUSED(text);
144  updateDebugButton();
145 }
146 
147 void SieveScriptDebuggerFrontEndWidget::slotDebugScript()
148 {
149  if (mSieveTextEditWidget->textEdit()->toPlainText().trimmed().isEmpty()) {
150  mSieveScriptDebuggerWarning->setErrorMessage(i18n("Script text is empty."));
151  return;
152  }
153  if (!mEmailPath->url().isLocalFile()) {
154  mSieveScriptDebuggerWarning->setWarningMessage(i18n("Email file must be installed locally."));
155  return;
156  }
157 
158  QTemporaryFile *temporaryFile = new QTemporaryFile();
159  if (!temporaryFile->open()) {
160  mSieveScriptDebuggerWarning->setErrorMessage(i18n("Failed to open temporary file."));
161  delete temporaryFile;
162  return;
163  }
164  Q_EMIT debugButtonEnabled(false);
165  QTextStream stream(temporaryFile);
166  stream << mSieveTextEditWidget->textEdit()->toPlainText();
167  temporaryFile->flush();
168  mProcess = new QProcess(this);
169  temporaryFile->setParent(mProcess);
170 
171  QString extensionList;
172  if (!mExtension->text().trimmed().isEmpty()) {
173  extensionList = QStringLiteral("-x \"%1\"").arg(mExtension->text());
174  }
175 
176  QStringList arguments;
177  if (!extensionList.isEmpty()) {
178  arguments << extensionList;
179  }
180 
181  arguments << temporaryFile->fileName() << mEmailPath->url().toLocalFile();
182  mProcess->start(QStringLiteral("sieve-test"), QStringList() << arguments);
183  connect(mProcess, &QProcess::readyReadStandardOutput, this, &SieveScriptDebuggerFrontEndWidget::slotReadStandardOutput);
184  connect(mProcess, &QProcess::readyReadStandardError, this, &SieveScriptDebuggerFrontEndWidget::slotReadErrorOutput);
185  connect(mProcess, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished), this, &SieveScriptDebuggerFrontEndWidget::slotDebugFinished);
186  mSieveTestResult->editor()->appendPlainText(QStringLiteral("--------------------------------------"));
187  mSieveTestResult->editor()->appendPlainText(QLocale().toString(QDateTime::currentDateTime()));
188  mSieveTestResult->editor()->appendPlainText(QStringLiteral("\n"));
189  if (!mProcess->waitForStarted()) {
190  delete mProcess;
191  mProcess = nullptr;
192  Q_EMIT debugButtonEnabled(true);
193  }
194 }
195 
196 void SieveScriptDebuggerFrontEndWidget::slotReadStandardOutput()
197 {
198  const QByteArray result = mProcess->readAllStandardOutput();
199  mSieveTestResult->editor()->appendPlainText(QString::fromLocal8Bit(result));
200 }
201 
202 void SieveScriptDebuggerFrontEndWidget::slotReadErrorOutput()
203 {
204  const QByteArray result = mProcess->readAllStandardError();
205  mSieveTestResult->editor()->appendPlainText(QString::fromLocal8Bit(result));
206 }
207 
208 void SieveScriptDebuggerFrontEndWidget::slotDebugFinished()
209 {
210  delete mProcess;
211  mProcess = nullptr;
212  Q_EMIT debugButtonEnabled(true);
213 }
214 
215 QString SieveScriptDebuggerFrontEndWidget::script() const
216 {
217  return mSieveTextEditWidget->textEdit()->toPlainText();
218 }
219 
220 void SieveScriptDebuggerFrontEndWidget::setScript(const QString &script)
221 {
222  mSieveTextEditWidget->textEdit()->setPlainText(script);
223  mSieveTextEditWidget->textEdit()->verticalScrollBar()->setValue(mSieveTextEditWidget->textEdit()->verticalScrollBar()->maximum());
224 }
225 
226 bool SieveScriptDebuggerFrontEndWidget::canAccept() const
227 {
228  const QString script = mSieveTextEditWidget->textEdit()->toPlainText();
229  if (script.contains(QLatin1String("debug_log")) || script.contains(QLatin1String("vnd.dovecot.debug"))) {
230  mSieveScriptDebuggerWarning->setErrorMessage(i18n("Script still contains debug method. Remove it please."));
231  return false;
232  }
233  mSieveScriptDebuggerWarning->hide();
234  return true;
235 }
void readyReadStandardError()
void setContentsMargins(int left, int top, int right, int bottom)
void textChanged()
bool flush()
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)
void addWidget(QWidget *widget, int stretch, Qt::Alignment alignment)
QString fromLocal8Bit(const char *str, int size)
void setLayout(QLayout *layout)
void setObjectName(const QString &name)
bool isEmpty() const const
void finished(int exitCode)
void addRow(QWidget *label, QWidget *field)
void setParent(QObject *parent)
bool contains(QChar ch, Qt::CaseSensitivity cs) const const
virtual QString fileName() const const override
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
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-2020 The KDE developers.
Generated on Fri Jun 5 2020 23:09:20 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.