1 /* SPDX-FileCopyrightText: 2013-2021 Laurent Montel <montel@kde.org>
2  *
3  * SPDX-License-Identifier: LGPL-2.0-or-later
4  */
5 
6 #include "sieveeditortextmodewidget.h"
7 #include "autocreatescripts/autocreatescriptdialog.h"
8 #include "editor/sieveeditortabwidget.h"
9 #include "editor/sievetextedit.h"
10 #include "editor/warningwidget/sieveeditorparsingmissingfeaturewarning.h"
11 #include "editor/warningwidget/sieveeditorwarning.h"
12 #include "sievescriptdebugger/sievescriptdebuggerdialog.h"
13 #include "templates/sievetemplatewidget.h"
14 
15 #include "scriptsparsing/parsingresultdialog.h"
16 #include "scriptsparsing/xmlprintingscriptbuilder.h"
17 
18 #include "KSplitterCollapserButton"
19 #include "webengine/sieveeditorhelphtmlwidget.h"
20 #include <KPIMTextEdit/PlainTextEditFindBar>
21 #include <KPIMTextEdit/PlainTextEditorWidget>
22 #include <KPIMTextEdit/SlideContainer>
23 #include <KPIMTextEdit/TextGotoLineWidget>
24 #include <KPIMTextEdit/TextToSpeechWidget>
25 
26 #include <ksieve/error.h>
27 #include <ksieve/parser.h>
28 #include <ksieve/scriptbuilder.h>
29 
30 #include <KConfigGroup>
31 #include <KLocalizedString>
32 #include <KMessageBox>
33 #include <KSharedConfig>
34 
35 #include <PimCommon/KPimPrintPreviewDialog>
36 #include <QPointer>
37 #include <QPrintDialog>
38 #include <QPrinter>
39 #include <QPushButton>
40 #include <QShortcut>
41 #include <QSplitter>
42 #include <QVBoxLayout>
43 
44 #include <cerrno>
45 #include <memory>
46 
47 using namespace KSieveUi;
48 
SieveEditorTextModeWidget(QWidget * parent)49 SieveEditorTextModeWidget::SieveEditorTextModeWidget(QWidget *parent)
50     : SieveEditorAbstractWidget(parent)
51 {
52     auto lay = new QVBoxLayout(this);
53     lay->setContentsMargins({});
54 
55     mMainSplitter = new QSplitter;
56     mMainSplitter->setOrientation(Qt::Vertical);
57     lay->addWidget(mMainSplitter);
58 
59     mTemplateSplitter = new QSplitter;
60     mTemplateSplitter->setOrientation(Qt::Horizontal);
61     //
62     mSieveTemplateWidget = new SieveTemplateWidget(i18n("Sieve Template:"));
63 
64     auto textEditWidget = new QWidget;
65     auto textEditLayout = new QVBoxLayout;
66     textEditLayout->setContentsMargins({});
67 
68     mEditorWidget = new QWidget;
69     auto editorWidgetLayout = new QVBoxLayout;
70     editorWidgetLayout->setContentsMargins({});
71     mEditorWidget->setLayout(editorWidgetLayout);
72 
73     mTabWidget = new SieveEditorTabWidget;
74     connect(mTabWidget, &SieveEditorTabWidget::currentChanged, this, &SieveEditorTextModeWidget::sieveEditorTabCurrentChanged);
75     connect(mTabWidget, &SieveEditorTabWidget::copyAvailable, this, &SieveEditorTextModeWidget::copyAvailable);
76     mTextToSpeechWidget = new KPIMTextEdit::TextToSpeechWidget(this);
77     editorWidgetLayout->addWidget(mTextToSpeechWidget);
78 
79     mTextEdit = new SieveTextEdit;
80     editorWidgetLayout->addWidget(mTextEdit);
81     connect(mTextEdit, &SieveTextEdit::textChanged, this, &SieveEditorTextModeWidget::valueChanged);
82     mTabWidget->addTab(mEditorWidget, i18n("Editor"));
83     mTabWidget->tabBar()->hide();
84     textEditLayout->addWidget(mTabWidget);
85     connect(mTextEdit, &SieveTextEdit::openHelp, mTabWidget, &SieveEditorTabWidget::slotAddHelpPage);
86     connect(mTextEdit, &SieveTextEdit::say, mTextToSpeechWidget, &KPIMTextEdit::TextToSpeechWidget::say);
87     connect(mTextEdit, &SieveTextEdit::editRule, this, &SieveEditorTextModeWidget::slotEditRule);
88     connect(mTextEdit, &SieveTextEdit::insertRule, this, &SieveEditorTextModeWidget::slotInsertRule);
89 
90     mGotoLineSliderContainer = new KPIMTextEdit::SlideContainer(this);
91     mGoToLine = new KPIMTextEdit::TextGoToLineWidget;
92     mGoToLine->hide();
93     mGotoLineSliderContainer->setContent(mGoToLine);
94     editorWidgetLayout->addWidget(mGotoLineSliderContainer);
95     connect(mGoToLine, &KPIMTextEdit::TextGoToLineWidget::hideGotoLine, mGotoLineSliderContainer, &KPIMTextEdit::SlideContainer::slideOut);
96 
97     connect(mGoToLine, &KPIMTextEdit::TextGoToLineWidget::moveToLine, this, &SieveEditorTextModeWidget::slotGoToLine);
98     connect(mTextEdit, &SieveTextEdit::blockCountChanged, mGoToLine, &KPIMTextEdit::TextGoToLineWidget::slotBlockCountChanged);
99 
100     mSliderContainer = new KPIMTextEdit::SlideContainer(this);
101     mFindBar = new KPIMTextEdit::PlainTextEditFindBar(mTextEdit, textEditWidget);
102     mFindBar->setHideWhenClose(false);
103     connect(mFindBar, &KPIMTextEdit::TextEditFindBarBase::hideFindBar, mSliderContainer, &KPIMTextEdit::SlideContainer::slideOut);
104     connect(mFindBar, &KPIMTextEdit::TextEditFindBarBase::displayMessageIndicator, mTextEdit, &KPIMTextEdit::PlainTextEditor::slotDisplayMessageIndicator);
105     mSliderContainer->setContent(mFindBar);
106     editorWidgetLayout->addWidget(mSliderContainer);
107 
108     mSieveEditorWarning = new SieveEditorWarning;
109     editorWidgetLayout->addWidget(mSieveEditorWarning);
110 
111     mSieveParsingWarning = new SieveEditorParsingMissingFeatureWarning(SieveEditorParsingMissingFeatureWarning::TextEditor);
112     connect(mSieveParsingWarning, &SieveEditorParsingMissingFeatureWarning::switchToGraphicalMode, this, &SieveEditorTextModeWidget::switchToGraphicalMode);
113     editorWidgetLayout->addWidget(mSieveParsingWarning);
114 
115     textEditWidget->setLayout(textEditLayout);
116 
117     mTemplateSplitter->addWidget(textEditWidget);
118     mTemplateSplitter->addWidget(mSieveTemplateWidget);
119     mTemplateSplitter->setCollapsible(0, false);
120     new KSplitterCollapserButton(mSieveTemplateWidget, mTemplateSplitter);
121 
122     connect(mSieveTemplateWidget, &SieveTemplateWidget::insertTemplate, mTextEdit, &SieveTextEdit::insertPlainText);
123 
124     //
125     connect(mTextEdit, &SieveTextEdit::findText, this, &SieveEditorTextModeWidget::slotFind);
126     connect(mTextEdit, &SieveTextEdit::replaceText, this, &SieveEditorTextModeWidget::slotReplace);
127 
128     mDebugTextEdit = new KPIMTextEdit::PlainTextEditorWidget;
129     mDebugTextEdit->editor()->setSearchSupport(false);
130     mDebugTextEdit->editor()->setReadOnly(true);
131     mDebugTextEdit->editor()->setPlaceholderText(i18n("Show result from \"check syntax\""));
132     mMainSplitter->addWidget(mTemplateSplitter);
133     mMainSplitter->addWidget(mDebugTextEdit);
134     mMainSplitter->setChildrenCollapsible(false);
135 
136     connect(mTextEdit, &SieveTextEdit::textChanged, this, &SieveEditorTextModeWidget::slotTextChanged);
137     connect(mTextEdit, &SieveTextEdit::undoAvailable, this, &SieveEditorTextModeWidget::undoAvailable);
138     connect(mTextEdit, &SieveTextEdit::redoAvailable, this, &SieveEditorTextModeWidget::redoAvailable);
139     connect(mTextEdit, &SieveTextEdit::copyAvailable, this, &SieveEditorTextModeWidget::copyAvailable);
140     readConfig();
141 
142     mTextEdit->setFocus();
143 }
144 
~SieveEditorTextModeWidget()145 SieveEditorTextModeWidget::~SieveEditorTextModeWidget()
146 {
147     disconnect(mTextEdit, &SieveTextEdit::textChanged, this, &SieveEditorTextModeWidget::slotTextChanged);
148     disconnect(mTextEdit, &SieveTextEdit::textChanged, this, &SieveEditorTextModeWidget::valueChanged);
149     writeConfig();
150 }
151 
writeConfig()152 void SieveEditorTextModeWidget::writeConfig()
153 {
154     KConfigGroup group(KSharedConfig::openStateConfig(), "SieveEditor");
155     group.writeEntry("mainSplitter", mMainSplitter->sizes());
156     group.writeEntry("templateSplitter", mTemplateSplitter->sizes());
157 }
158 
sieveCapabilities() const159 QStringList SieveEditorTextModeWidget::sieveCapabilities() const
160 {
161     return mSieveCapabilities;
162 }
163 
tabWidget() const164 SieveEditorTabWidget *SieveEditorTextModeWidget::tabWidget() const
165 {
166     return mTabWidget;
167 }
168 
readConfig()169 void SieveEditorTextModeWidget::readConfig()
170 {
171     KConfigGroup group(KSharedConfig::openStateConfig(), "SieveEditor");
172     const QList<int> size = {400, 100};
173 
174     mMainSplitter->setSizes(group.readEntry("mainSplitter", size));
175     mTemplateSplitter->setSizes(group.readEntry("templateSplitter", size));
176 }
177 
slotGoToLine(int line)178 void SieveEditorTextModeWidget::slotGoToLine(int line)
179 {
180     if (line > 0) {
181         QTextCursor cursor = mTextEdit->textCursor();
182         cursor.beginEditBlock();
183         cursor.movePosition(QTextCursor::Start);
184         cursor.movePosition(QTextCursor::Down, QTextCursor::MoveAnchor, (line - 1));
185         cursor.endEditBlock();
186         mTextEdit->setTextCursor(cursor);
187         mTextEdit->setFocus();
188     }
189 }
190 
slotShowGoToLine()191 void SieveEditorTextModeWidget::slotShowGoToLine()
192 {
193     mGoToLine->setMaximumLineCount(mTextEdit->document()->blockCount());
194     mGotoLineSliderContainer->slideIn();
195     mGoToLine->goToLine();
196 }
197 
generateXml()198 void SieveEditorTextModeWidget::generateXml()
199 {
200     const QByteArray script = mTextEdit->toPlainText().toUtf8();
201     KSieve::Parser parser(script.begin(), script.begin() + script.length());
202     KSieveUi::XMLPrintingScriptBuilder psb(2);
203     parser.setScriptBuilder(&psb);
204     const bool result = parser.parse();
205     QPointer<ParsingResultDialog> dlg = new ParsingResultDialog(this);
206     if (result) {
207         dlg->setResultParsing(psb.result());
208     } else {
209         dlg->setResultParsing(i18n("Error during parsing"));
210     }
211     dlg->exec();
212     delete dlg;
213 }
214 
slotEditRule(const QString & selectedText)215 void SieveEditorTextModeWidget::slotEditRule(const QString &selectedText)
216 {
217     const QByteArray script = selectedText.toUtf8();
218     KSieve::Parser parser(script.begin(), script.begin() + script.length());
219     KSieveUi::XMLPrintingScriptBuilder psb(2);
220     parser.setScriptBuilder(&psb);
221     const bool result = parser.parse();
222     if (result) {
223         QPointer<AutoCreateScriptDialog> dlg = new AutoCreateScriptDialog(this);
224         dlg->setSieveCapabilities(mSieveCapabilities);
225         dlg->setSieveImapAccountSettings(mSieveImapAccountSettings);
226         dlg->setListOfIncludeFile(mListOfIncludeFile);
227         QString error;
228         // qDebug() << " psb.result()" << psb.result();
229         dlg->loadScript(psb.result(), error);
230         if (dlg->exec()) {
231             QStringList requireModules;
232             const QString newScript = dlg->script(requireModules);
233             const QStringList needToAddRequire = insertNecessaryRequires(requireModules);
234             mTextEdit->insertPlainText(newScript);
235             insertRequires(needToAddRequire);
236         }
237         delete dlg;
238     } else {
239         KMessageBox::error(this, i18n("Selected text is not a full sieve script"), i18n("Parsing error"));
240     }
241 }
242 
insertRequires(const QStringList & needToAddRequire)243 void SieveEditorTextModeWidget::insertRequires(const QStringList &needToAddRequire)
244 {
245     if (!needToAddRequire.isEmpty()) {
246         QTextCursor textCursor = mTextEdit->textCursor();
247         textCursor.movePosition(QTextCursor::MoveOperation::Start);
248         textCursor.insertText(needToAddRequire.join(QLatin1Char('\n')) + QLatin1Char('\n'));
249     }
250 }
251 
insertNecessaryRequires(const QStringList & requireModules)252 QStringList SieveEditorTextModeWidget::insertNecessaryRequires(const QStringList &requireModules)
253 {
254     QStringList needToAddRequire;
255     const QString plainText = mTextEdit->toPlainText();
256     for (const QString &module : std::as_const(requireModules)) {
257         if (!plainText.contains(module)) {
258             needToAddRequire.append(module);
259         }
260     }
261     return needToAddRequire;
262 }
263 
slotInsertRule()264 void SieveEditorTextModeWidget::slotInsertRule()
265 {
266     QPointer<AutoCreateScriptDialog> dlg = new AutoCreateScriptDialog(this);
267     dlg->setSieveCapabilities(mSieveCapabilities);
268     dlg->setSieveImapAccountSettings(mSieveImapAccountSettings);
269     dlg->setListOfIncludeFile(mListOfIncludeFile);
270     if (dlg->exec()) {
271         QStringList requireModules;
272         const QString newScript = dlg->script(requireModules);
273         const QStringList needToAddRequire = insertNecessaryRequires(requireModules);
274         mTextEdit->insertPlainText(newScript);
275         insertRequires(needToAddRequire);
276     }
277     delete dlg;
278 }
279 
createRulesGraphically()280 void SieveEditorTextModeWidget::createRulesGraphically()
281 {
282     QPointer<AutoCreateScriptDialog> dlg = new AutoCreateScriptDialog(this);
283     dlg->setSieveCapabilities(mSieveCapabilities);
284     dlg->setSieveImapAccountSettings(mSieveImapAccountSettings);
285     dlg->setListOfIncludeFile(mListOfIncludeFile);
286     if (dlg->exec()) {
287         QStringList requireModules;
288         const QString script = dlg->script(requireModules);
289         const QStringList needToAddRequire = insertNecessaryRequires(requireModules);
290         QString newPlainText = mTextEdit->toPlainText() + script;
291         if (!needToAddRequire.isEmpty()) {
292             newPlainText.prepend(requireModules.join(QLatin1Char('\n')) + QLatin1Char('\n'));
293         }
294         mTextEdit->selectAll();
295 
296         mTextEdit->insertPlainText(newPlainText);
297     }
298     delete dlg;
299 }
300 
find()301 void SieveEditorTextModeWidget::find()
302 {
303     slotFind();
304 }
305 
replace()306 void SieveEditorTextModeWidget::replace()
307 {
308     slotReplace();
309 }
310 
undo()311 void SieveEditorTextModeWidget::undo()
312 {
313     const QWidget *w = mTabWidget->currentWidget();
314     if (w == mEditorWidget) {
315         mTextEdit->undo();
316     }
317 }
318 
redo()319 void SieveEditorTextModeWidget::redo()
320 {
321     const QWidget *w = mTabWidget->currentWidget();
322     if (w == mEditorWidget) {
323         mTextEdit->redo();
324     }
325 }
326 
paste()327 void SieveEditorTextModeWidget::paste()
328 {
329     const QWidget *w = mTabWidget->currentWidget();
330     if (w == mEditorWidget) {
331         mTextEdit->paste();
332     }
333 }
334 
cut()335 void SieveEditorTextModeWidget::cut()
336 {
337     const QWidget *w = mTabWidget->currentWidget();
338     if (w == mEditorWidget) {
339         mTextEdit->cut();
340     }
341 }
342 
copy()343 void SieveEditorTextModeWidget::copy()
344 {
345     QWidget *w = mTabWidget->currentWidget();
346     if (w == mEditorWidget) {
347         mTextEdit->copy();
348     } else if (auto page = qobject_cast<SieveEditorHelpHtmlWidget *>(w)) {
349         page->copy();
350     }
351 }
352 
selectAll()353 void SieveEditorTextModeWidget::selectAll()
354 {
355     QWidget *w = mTabWidget->currentWidget();
356     if (w == mEditorWidget) {
357         mTextEdit->selectAll();
358     } else if (auto page = qobject_cast<SieveEditorHelpHtmlWidget *>(w)) {
359         page->selectAll();
360     }
361 }
362 
isUndoAvailable() const363 bool SieveEditorTextModeWidget::isUndoAvailable() const
364 {
365     const QWidget *w = mTabWidget->currentWidget();
366     if (w == mEditorWidget) {
367         return mTextEdit->document()->isUndoAvailable();
368     }
369     return false;
370 }
371 
isRedoAvailable() const372 bool SieveEditorTextModeWidget::isRedoAvailable() const
373 {
374     const QWidget *w = mTabWidget->currentWidget();
375     if (w == mEditorWidget) {
376         return mTextEdit->document()->isRedoAvailable();
377     }
378     return false;
379 }
380 
hasSelection() const381 bool SieveEditorTextModeWidget::hasSelection() const
382 {
383     QWidget *w = mTabWidget->currentWidget();
384     if (w == mEditorWidget) {
385         return mTextEdit->textCursor().hasSelection();
386     } else if (auto page = qobject_cast<SieveEditorHelpHtmlWidget *>(w)) {
387         return page->hasSelection();
388     }
389     return false;
390 }
391 
zoomIn()392 void SieveEditorTextModeWidget::zoomIn()
393 {
394     QWidget *w = mTabWidget->currentWidget();
395     if (w == mEditorWidget) {
396         mTextEdit->zoomIn();
397     } else if (auto page = qobject_cast<SieveEditorHelpHtmlWidget *>(w)) {
398         page->zoomIn();
399     }
400 }
401 
zoomOut()402 void SieveEditorTextModeWidget::zoomOut()
403 {
404     QWidget *w = mTabWidget->currentWidget();
405     if (w == mEditorWidget) {
406         mTextEdit->zoomOut();
407     } else if (auto page = qobject_cast<SieveEditorHelpHtmlWidget *>(w)) {
408         page->zoomOut();
409     }
410 }
411 
isWordWrap() const412 bool SieveEditorTextModeWidget::isWordWrap() const
413 {
414     return mTextEdit->isWordWrap();
415 }
416 
print()417 void SieveEditorTextModeWidget::print()
418 {
419     const QWidget *w = mTabWidget->currentWidget();
420     if (w == mEditorWidget) {
421         QPrinter printer;
422 
423         std::unique_ptr<QPrintDialog> dlg(new QPrintDialog(&printer));
424 
425         bool restoreSpellCheck = mTextEdit->checkSpellingEnabled();
426         mTextEdit->setCheckSpellingEnabled(false);
427         if (dlg && dlg->exec() == QDialog::Accepted) {
428             mTextEdit->print(&printer);
429         }
430         mTextEdit->setCheckSpellingEnabled(restoreSpellCheck);
431     }
432 }
433 
printPreview()434 void SieveEditorTextModeWidget::printPreview()
435 {
436     const QWidget *w = mTabWidget->currentWidget();
437     if (w == mEditorWidget) {
438         bool restoreSpellCheck = mTextEdit->checkSpellingEnabled();
439         mTextEdit->setCheckSpellingEnabled(false);
440         QPointer<PimCommon::KPimPrintPreviewDialog> previewdlg = new PimCommon::KPimPrintPreviewDialog(this);
441         connect(previewdlg.data(), &QPrintPreviewDialog::paintRequested, this, [this](QPrinter *printer) {
442             mTextEdit->print(printer);
443         });
444         previewdlg->exec();
445         delete previewdlg;
446         mTextEdit->setCheckSpellingEnabled(restoreSpellCheck);
447     }
448 }
449 
wordWrap(bool state)450 void SieveEditorTextModeWidget::wordWrap(bool state)
451 {
452     mTextEdit->wordWrap(state);
453 }
454 
zoomReset()455 void SieveEditorTextModeWidget::zoomReset()
456 {
457     QWidget *w = mTabWidget->currentWidget();
458     if (w == mEditorWidget) {
459         mTextEdit->slotZoomReset();
460     } else if (auto page = qobject_cast<SieveEditorHelpHtmlWidget *>(w)) {
461         page->resetZoom();
462     }
463 }
464 
slotFind()465 void SieveEditorTextModeWidget::slotFind()
466 {
467     QWidget *w = mTabWidget->currentWidget();
468     if (w == mEditorWidget) {
469         if (mTextEdit->textCursor().hasSelection()) {
470             mFindBar->setText(mTextEdit->textCursor().selectedText());
471         }
472         mTextEdit->moveCursor(QTextCursor::Start);
473         mFindBar->showFind();
474         mSliderContainer->slideIn();
475         mFindBar->focusAndSetCursor();
476     } else if (auto page = qobject_cast<SieveEditorHelpHtmlWidget *>(w)) {
477         page->find();
478     }
479 }
480 
slotReplace()481 void SieveEditorTextModeWidget::slotReplace()
482 {
483     if (mTextEdit->textCursor().hasSelection()) {
484         mFindBar->setText(mTextEdit->textCursor().selectedText());
485     }
486     mFindBar->showReplace();
487     mSliderContainer->slideIn();
488     mFindBar->focusAndSetCursor();
489 }
490 
currentscript()491 QString SieveEditorTextModeWidget::currentscript()
492 {
493     return mTextEdit->toPlainText();
494 }
495 
setImportScript(const QString & script)496 void SieveEditorTextModeWidget::setImportScript(const QString &script)
497 {
498     mTextEdit->selectAll();
499     mTextEdit->insertPlainText(script);
500 }
501 
slotTextChanged()502 void SieveEditorTextModeWidget::slotTextChanged()
503 {
504     const bool enabled = !script().isEmpty();
505     Q_EMIT enableButtonOk(enabled);
506 }
507 
script() const508 QString SieveEditorTextModeWidget::script() const
509 {
510     return mTextEdit->toPlainText();
511 }
512 
setScript(const QString & script,bool clearUndoRedo)513 void SieveEditorTextModeWidget::setScript(const QString &script, bool clearUndoRedo)
514 {
515     if (clearUndoRedo) {
516         mTextEdit->setPlainText(script);
517     } else {
518         mTextEdit->selectAll();
519         mTextEdit->insertPlainText(script);
520     }
521 }
522 
setDebugScript(const QString & debug)523 void SieveEditorTextModeWidget::setDebugScript(const QString &debug)
524 {
525     mDebugTextEdit->editor()->clear();
526     mDebugTextEdit->editor()->appendHtml(debug);
527 }
528 
setListOfIncludeFile(const QStringList & listOfIncludeFile)529 void SieveEditorTextModeWidget::setListOfIncludeFile(const QStringList &listOfIncludeFile)
530 {
531     mListOfIncludeFile = listOfIncludeFile;
532 }
533 
setSieveCapabilities(const QStringList & capabilities)534 void SieveEditorTextModeWidget::setSieveCapabilities(const QStringList &capabilities)
535 {
536     mSieveCapabilities = capabilities;
537     mTextEdit->setSieveCapabilities(mSieveCapabilities);
538     mSieveTemplateWidget->setSieveCapabilities(mSieveCapabilities);
539 }
540 
showEditorWarning()541 void SieveEditorTextModeWidget::showEditorWarning()
542 {
543     mSieveEditorWarning->animatedShow();
544 }
545 
hideEditorWarning()546 void SieveEditorTextModeWidget::hideEditorWarning()
547 {
548     mSieveEditorWarning->animatedHide();
549     mSieveParsingWarning->animatedHide();
550 }
551 
showParsingEditorWarning()552 void SieveEditorTextModeWidget::showParsingEditorWarning()
553 {
554     mSieveParsingWarning->animatedShow();
555 }
556 
setParsingEditorWarningError(const QString & script,const QString & error)557 void SieveEditorTextModeWidget::setParsingEditorWarningError(const QString &script, const QString &error)
558 {
559     mSieveParsingWarning->setErrors(script, error);
560 }
561 
checkSpelling()562 void SieveEditorTextModeWidget::checkSpelling()
563 {
564     mTextEdit->slotCheckSpelling();
565 }
566 
comment()567 void SieveEditorTextModeWidget::comment()
568 {
569     mTextEdit->comment();
570 }
571 
uncomment()572 void SieveEditorTextModeWidget::uncomment()
573 {
574     mTextEdit->uncomment();
575 }
576 
setReadOnly(bool b)577 void SieveEditorTextModeWidget::setReadOnly(bool b)
578 {
579     mTextEdit->setReadOnly(b);
580 }
581 
upperCase()582 void SieveEditorTextModeWidget::upperCase()
583 {
584     mTextEdit->upperCase();
585 }
586 
lowerCase()587 void SieveEditorTextModeWidget::lowerCase()
588 {
589     mTextEdit->lowerCase();
590 }
591 
sentenceCase()592 void SieveEditorTextModeWidget::sentenceCase()
593 {
594     mTextEdit->sentenceCase();
595 }
596 
reverseCase()597 void SieveEditorTextModeWidget::reverseCase()
598 {
599     mTextEdit->reverseCase();
600 }
601 
currentHelpTitle() const602 QString SieveEditorTextModeWidget::currentHelpTitle() const
603 {
604     return mTabWidget->currentHelpTitle();
605 }
606 
currentHelpUrl() const607 QUrl SieveEditorTextModeWidget::currentHelpUrl() const
608 {
609     return mTabWidget->currentHelpUrl();
610 }
611 
openBookmarkUrl(const QUrl & url)612 void SieveEditorTextModeWidget::openBookmarkUrl(const QUrl &url)
613 {
614     mTabWidget->slotAddHelpPage(url);
615 }
616 
debugSieveScript()617 void SieveEditorTextModeWidget::debugSieveScript()
618 {
619     QPointer<KSieveUi::SieveScriptDebuggerDialog> dlg = new KSieveUi::SieveScriptDebuggerDialog(this);
620     dlg->setScript(mTextEdit->toPlainText());
621     if (dlg->exec()) {
622         const QString script = dlg->script();
623         mTextEdit->selectAll();
624         mTextEdit->insertPlainText(script);
625     }
626     delete dlg;
627 }
628 
isTextEditor() const629 bool SieveEditorTextModeWidget::isTextEditor() const
630 {
631     const QWidget *w = mTabWidget->currentWidget();
632     return w == mEditorWidget;
633 }
634 
printSupportEnabled() const635 bool SieveEditorTextModeWidget::printSupportEnabled() const
636 {
637     return isTextEditor();
638 }
639