File indexing completed on 2024-05-05 16:17:39

0001 /*
0002     This file is part of the KDE libraries
0003     SPDX-FileCopyrightText: 2002, 2003 Anders Lund <anders.lund@lund.tdcadsl.dk>
0004     SPDX-FileCopyrightText: 2003 Christoph Cullmann <cullmann@kde.org>
0005     SPDX-FileCopyrightText: 2001 Joseph Wenninger <jowenn@kde.org>
0006     SPDX-FileCopyrightText: 2006 Dominik Haumann <dhdev@gmx.de>
0007     SPDX-FileCopyrightText: 2007 Mirko Stocker <me@misto.ch>
0008     SPDX-FileCopyrightText: 2009 Michel Ludwig <michel.ludwig@kdemail.net>
0009     SPDX-FileCopyrightText: 2009 Erlend Hamberg <ehamberg@gmail.com>
0010 
0011     Based on work of:
0012     SPDX-FileCopyrightText: 1999 Jochen Wilhelmy <digisnap@cs.tu-berlin.de>
0013 
0014     SPDX-License-Identifier: LGPL-2.0-only
0015 */
0016 
0017 // BEGIN Includes
0018 #include "katedialogs.h"
0019 
0020 #include <ktexteditor/message.h>
0021 #include <ktexteditor_version.h>
0022 
0023 #include "kateautoindent.h"
0024 #include "katebuffer.h"
0025 #include "kateconfig.h"
0026 #include "katedocument.h"
0027 #include "kateglobal.h"
0028 #include "katemodeconfigpage.h"
0029 #include "kateview.h"
0030 #include "spellcheck/spellcheck.h"
0031 
0032 // auto generated ui files
0033 #include "ui_bordersappearanceconfigwidget.h"
0034 #include "ui_completionconfigtab.h"
0035 #include "ui_editconfigwidget.h"
0036 #include "ui_indentationconfigwidget.h"
0037 #include "ui_navigationconfigwidget.h"
0038 #include "ui_opensaveconfigadvwidget.h"
0039 #include "ui_opensaveconfigwidget.h"
0040 #include "ui_spellcheckconfigwidget.h"
0041 #include "ui_statusbarconfigwidget.h"
0042 #include "ui_textareaappearanceconfigwidget.h"
0043 
0044 #include <KIO/Job>
0045 #include <KIO/JobUiDelegateFactory>
0046 #include <KIO/OpenUrlJob>
0047 
0048 #include "kateabstractinputmodefactory.h"
0049 #include "katepartdebug.h"
0050 #include <KActionCollection>
0051 #include <KCharsets>
0052 #include <KColorCombo>
0053 #include <KFontRequester>
0054 #include <KMessageBox>
0055 #include <KProcess>
0056 #include <KSeparator>
0057 
0058 #include <QCheckBox>
0059 #include <QClipboard>
0060 #include <QComboBox>
0061 #include <QDomDocument>
0062 #include <QFile>
0063 #include <QFileDialog>
0064 #include <QGroupBox>
0065 #include <QKeyEvent>
0066 #include <QLabel>
0067 #include <QLayout>
0068 #include <QMap>
0069 #include <QPainter>
0070 #include <QRadioButton>
0071 #include <QSettings>
0072 #include <QSlider>
0073 #include <QSpinBox>
0074 #include <QStringList>
0075 #include <QTabBar>
0076 #include <QTemporaryFile>
0077 #include <QTextCodec>
0078 #include <QTextStream>
0079 #include <QToolButton>
0080 #include <QWhatsThis>
0081 
0082 // END
0083 
0084 // BEGIN KateIndentConfigTab
0085 KateIndentConfigTab::KateIndentConfigTab(QWidget *parent)
0086     : KateConfigPage(parent)
0087 {
0088     // This will let us have more separation between this page and
0089     // the QTabWidget edge (ereslibre)
0090     QVBoxLayout *layout = new QVBoxLayout(this);
0091     QWidget *newWidget = new QWidget(this);
0092 
0093     ui = new Ui::IndentationConfigWidget();
0094     ui->setupUi(newWidget);
0095 
0096     ui->cmbMode->addItems(KateAutoIndent::listModes());
0097 
0098     // FIXME Give ui->label a more descriptive name, it's these "More..." info about tab key action
0099     ui->label->setTextInteractionFlags(Qt::LinksAccessibleByMouse | Qt::LinksAccessibleByKeyboard);
0100     connect(ui->label, &QLabel::linkActivated, this, &KateIndentConfigTab::showWhatsThis);
0101 
0102     // "What's This?" help can be found in the ui file
0103 
0104     reload();
0105 
0106     observeChanges(ui->chkAutoDetectIndent);
0107     observeChanges(ui->chkBackspaceUnindents);
0108     observeChanges(ui->chkIndentPaste);
0109     observeChanges(ui->chkKeepExtraSpaces);
0110     observeChanges(ui->cmbMode);
0111     observeChanges(ui->rbIndentMixed);
0112     observeChanges(ui->rbIndentWithSpaces);
0113     observeChanges(ui->rbIndentWithTabs);
0114     connect(ui->rbIndentWithTabs, &QAbstractButton::toggled, ui->sbIndentWidth, &QWidget::setDisabled);
0115     connect(ui->rbIndentWithTabs, &QAbstractButton::toggled, this, &KateIndentConfigTab::slotChanged); // FIXME See slot below
0116     observeChanges(ui->rbTabAdvances);
0117     observeChanges(ui->rbTabIndents);
0118     observeChanges(ui->rbTabSmart);
0119     observeChanges(ui->sbIndentWidth);
0120     observeChanges(ui->sbTabWidth);
0121 
0122     layout->addWidget(newWidget);
0123 }
0124 
0125 KateIndentConfigTab::~KateIndentConfigTab()
0126 {
0127     delete ui;
0128 }
0129 
0130 void KateIndentConfigTab::slotChanged()
0131 {
0132     // FIXME Make it working without this quirk
0133     // When the value is not copied it will silently set back to "Tabs & Spaces"
0134     if (ui->rbIndentWithTabs->isChecked()) {
0135         ui->sbIndentWidth->setValue(ui->sbTabWidth->value());
0136     }
0137 }
0138 
0139 // NOTE Should we have more use of such info stuff, consider to make it part
0140 // of KateConfigPage and add a similar function like observeChanges(..)
0141 void KateIndentConfigTab::showWhatsThis(const QString &text)
0142 {
0143     QWhatsThis::showText(QCursor::pos(), text);
0144 }
0145 
0146 void KateIndentConfigTab::apply()
0147 {
0148     // nothing changed, no need to apply stuff
0149     if (!hasChanged()) {
0150         return;
0151     }
0152     m_changed = false;
0153 
0154     KateDocumentConfig::global()->configStart();
0155 
0156     KateDocumentConfig::global()->setBackspaceIndents(ui->chkBackspaceUnindents->isChecked());
0157     KateDocumentConfig::global()->setIndentPastedText(ui->chkIndentPaste->isChecked());
0158     KateDocumentConfig::global()->setIndentationMode(KateAutoIndent::modeName(ui->cmbMode->currentIndex()));
0159     KateDocumentConfig::global()->setIndentationWidth(ui->sbIndentWidth->value());
0160     KateDocumentConfig::global()->setKeepExtraSpaces(ui->chkKeepExtraSpaces->isChecked());
0161     KateDocumentConfig::global()->setReplaceTabsDyn(ui->rbIndentWithSpaces->isChecked());
0162     KateDocumentConfig::global()->setTabWidth(ui->sbTabWidth->value());
0163     KateDocumentConfig::global()->setAutoDetectIndent(ui->chkAutoDetectIndent->isChecked());
0164 
0165     if (ui->rbTabAdvances->isChecked()) {
0166         KateDocumentConfig::global()->setTabHandling(KateDocumentConfig::tabInsertsTab);
0167     } else if (ui->rbTabIndents->isChecked()) {
0168         KateDocumentConfig::global()->setTabHandling(KateDocumentConfig::tabIndents);
0169     } else {
0170         KateDocumentConfig::global()->setTabHandling(KateDocumentConfig::tabSmart);
0171     }
0172 
0173     KateDocumentConfig::global()->configEnd();
0174 }
0175 
0176 void KateIndentConfigTab::reload()
0177 {
0178     ui->chkBackspaceUnindents->setChecked(KateDocumentConfig::global()->backspaceIndents());
0179     ui->chkIndentPaste->setChecked(KateDocumentConfig::global()->indentPastedText());
0180     ui->chkKeepExtraSpaces->setChecked(KateDocumentConfig::global()->keepExtraSpaces());
0181 
0182     ui->chkAutoDetectIndent->setChecked(KateDocumentConfig::global()->autoDetectIndent());
0183     ui->sbIndentWidth->setSuffix(ki18np(" character", " characters"));
0184     ui->sbIndentWidth->setValue(KateDocumentConfig::global()->indentationWidth());
0185     ui->sbTabWidth->setSuffix(ki18np(" character", " characters"));
0186     ui->sbTabWidth->setValue(KateDocumentConfig::global()->tabWidth());
0187 
0188     ui->rbTabAdvances->setChecked(KateDocumentConfig::global()->tabHandling() == KateDocumentConfig::tabInsertsTab);
0189     ui->rbTabIndents->setChecked(KateDocumentConfig::global()->tabHandling() == KateDocumentConfig::tabIndents);
0190     ui->rbTabSmart->setChecked(KateDocumentConfig::global()->tabHandling() == KateDocumentConfig::tabSmart);
0191 
0192     ui->cmbMode->setCurrentIndex(KateAutoIndent::modeNumber(KateDocumentConfig::global()->indentationMode()));
0193 
0194     if (KateDocumentConfig::global()->replaceTabsDyn()) {
0195         ui->rbIndentWithSpaces->setChecked(true);
0196     } else {
0197         if (KateDocumentConfig::global()->indentationWidth() == KateDocumentConfig::global()->tabWidth()) {
0198             ui->rbIndentWithTabs->setChecked(true);
0199         } else {
0200             ui->rbIndentMixed->setChecked(true);
0201         }
0202     }
0203 
0204     ui->sbIndentWidth->setEnabled(!ui->rbIndentWithTabs->isChecked());
0205 }
0206 
0207 QString KateIndentConfigTab::name() const
0208 {
0209     return i18n("Indentation");
0210 }
0211 
0212 // END KateIndentConfigTab
0213 
0214 // BEGIN KateCompletionConfigTab
0215 KateCompletionConfigTab::KateCompletionConfigTab(QWidget *parent)
0216     : KateConfigPage(parent)
0217 {
0218     // This will let us have more separation between this page and
0219     // the QTabWidget edge (ereslibre)
0220     QVBoxLayout *layout = new QVBoxLayout(this);
0221     QWidget *newWidget = new QWidget(this);
0222 
0223     ui = new Ui::CompletionConfigTab();
0224     ui->setupUi(newWidget);
0225 
0226     // "What's This?" help can be found in the ui file
0227 
0228     reload();
0229 
0230     observeChanges(ui->chkAutoCompletionEnabled);
0231     observeChanges(ui->chkAutoSelectFirstEntry);
0232     observeChanges(ui->chkTabCompletion);
0233     observeChanges(ui->gbKeywordCompletion);
0234     observeChanges(ui->gbShowDoc);
0235     observeChanges(ui->gbWordCompletion);
0236     observeChanges(ui->minimalWordLength);
0237     observeChanges(ui->removeTail);
0238 
0239     layout->addWidget(newWidget);
0240 }
0241 
0242 KateCompletionConfigTab::~KateCompletionConfigTab()
0243 {
0244     delete ui;
0245 }
0246 
0247 void KateCompletionConfigTab::showWhatsThis(const QString &text) // NOTE Not used atm, remove? See also KateIndentConfigTab::showWhatsThis
0248 {
0249     QWhatsThis::showText(QCursor::pos(), text);
0250 }
0251 
0252 void KateCompletionConfigTab::apply()
0253 {
0254     // nothing changed, no need to apply stuff
0255     if (!hasChanged()) {
0256         return;
0257     }
0258     m_changed = false;
0259 
0260     KateViewConfig::global()->configStart();
0261 
0262     KateViewConfig::global()->setValue(KateViewConfig::AutomaticCompletionInvocation, ui->chkAutoCompletionEnabled->isChecked());
0263     KateViewConfig::global()->setValue(KateViewConfig::AutomaticCompletionPreselectFirst, ui->chkAutoSelectFirstEntry->isChecked());
0264     KateViewConfig::global()->setValue(KateViewConfig::TabCompletion, ui->chkTabCompletion->isChecked());
0265     KateViewConfig::global()->setValue(KateViewConfig::KeywordCompletion, ui->gbKeywordCompletion->isChecked());
0266     KateViewConfig::global()->setValue(KateViewConfig::WordCompletion, ui->gbWordCompletion->isChecked());
0267     KateViewConfig::global()->setValue(KateViewConfig::WordCompletionMinimalWordLength, ui->minimalWordLength->value());
0268     KateViewConfig::global()->setValue(KateViewConfig::WordCompletionRemoveTail, ui->removeTail->isChecked());
0269     KateViewConfig::global()->setValue(KateViewConfig::ShowDocWithCompletion, ui->gbShowDoc->isChecked());
0270 
0271     KateViewConfig::global()->configEnd();
0272 }
0273 
0274 void KateCompletionConfigTab::reload()
0275 {
0276     ui->chkAutoCompletionEnabled->setChecked(KateViewConfig::global()->automaticCompletionInvocation());
0277     ui->chkAutoSelectFirstEntry->setChecked(KateViewConfig::global()->automaticCompletionPreselectFirst());
0278     ui->chkTabCompletion->setChecked(KateViewConfig::global()->tabCompletion());
0279 
0280     ui->gbKeywordCompletion->setChecked(KateViewConfig::global()->keywordCompletion());
0281     ui->gbWordCompletion->setChecked(KateViewConfig::global()->wordCompletion());
0282     ui->gbShowDoc->setChecked(KateViewConfig::global()->showDocWithCompletion());
0283 
0284     ui->minimalWordLength->setValue(KateViewConfig::global()->wordCompletionMinimalWordLength());
0285     ui->removeTail->setChecked(KateViewConfig::global()->wordCompletionRemoveTail());
0286 }
0287 
0288 QString KateCompletionConfigTab::name() const
0289 {
0290     return i18n("Auto Completion");
0291 }
0292 
0293 // END KateCompletionConfigTab
0294 
0295 // BEGIN KateSpellCheckConfigTab
0296 KateSpellCheckConfigTab::KateSpellCheckConfigTab(QWidget *parent)
0297     : KateConfigPage(parent)
0298 {
0299     // This will let us have more separation between this page and
0300     // the QTabWidget edge (ereslibre)
0301     QVBoxLayout *layout = new QVBoxLayout(this);
0302     QWidget *newWidget = new QWidget(this);
0303 
0304     ui = new Ui::SpellCheckConfigWidget();
0305     ui->setupUi(newWidget);
0306 
0307     // "What's This?" help can be found in the ui file
0308 
0309     reload();
0310 
0311     m_sonnetConfigWidget = new Sonnet::ConfigWidget(this);
0312     connect(m_sonnetConfigWidget, &Sonnet::ConfigWidget::configChanged, this, &KateSpellCheckConfigTab::slotChanged);
0313     layout->addWidget(m_sonnetConfigWidget);
0314 
0315     layout->addWidget(newWidget);
0316 }
0317 
0318 KateSpellCheckConfigTab::~KateSpellCheckConfigTab()
0319 {
0320     delete ui;
0321 }
0322 
0323 void KateSpellCheckConfigTab::showWhatsThis(const QString &text) // NOTE Not used atm, remove? See also KateIndentConfigTab::showWhatsThis
0324 {
0325     QWhatsThis::showText(QCursor::pos(), text);
0326 }
0327 
0328 void KateSpellCheckConfigTab::apply()
0329 {
0330     if (!hasChanged()) {
0331         // nothing changed, no need to apply stuff
0332         return;
0333     }
0334     m_changed = false;
0335 
0336     // WARNING: this is slightly hackish, but it's currently the only way to
0337     //          do it, see also the KTextEdit class
0338     KateDocumentConfig::global()->configStart();
0339     m_sonnetConfigWidget->save();
0340     QSettings settings(QStringLiteral("KDE"), QStringLiteral("Sonnet"));
0341     KateDocumentConfig::global()->setOnTheFlySpellCheck(settings.value(QStringLiteral("checkerEnabledByDefault"), false).toBool());
0342     KateDocumentConfig::global()->configEnd();
0343 
0344     const auto docs = KTextEditor::EditorPrivate::self()->kateDocuments();
0345     for (KTextEditor::DocumentPrivate *doc : docs) {
0346         doc->refreshOnTheFlyCheck();
0347     }
0348 }
0349 
0350 void KateSpellCheckConfigTab::reload()
0351 {
0352     // does nothing
0353 }
0354 
0355 QString KateSpellCheckConfigTab::name() const
0356 {
0357     return i18n("Spellcheck");
0358 }
0359 
0360 // END KateSpellCheckConfigTab
0361 
0362 // BEGIN KateNavigationConfigTab
0363 KateNavigationConfigTab::KateNavigationConfigTab(QWidget *parent)
0364     : KateConfigPage(parent)
0365 {
0366     // This will let us having more separation between this page and
0367     // the QTabWidget edge (ereslibre)
0368     QVBoxLayout *layout = new QVBoxLayout(this);
0369     QWidget *newWidget = new QWidget(this);
0370 
0371     ui = new Ui::NavigationConfigWidget();
0372     ui->setupUi(newWidget);
0373 
0374     initMulticursorModifierComboBox();
0375 
0376     // "What's This?" help can be found in the ui file
0377 
0378     reload();
0379 
0380     observeChanges(ui->cbTextSelectionMode);
0381     observeChanges(ui->chkBackspaceRemoveComposed);
0382     observeChanges(ui->chkPagingMovesCursor);
0383     observeChanges(ui->chkScrollPastEnd);
0384     observeChanges(ui->chkSmartHome);
0385     observeChanges(ui->sbAutoCenterCursor);
0386     observeChanges(ui->chkCamelCursor);
0387     observeChanges(ui->cmbMultiCursorModifier);
0388 
0389     layout->addWidget(newWidget);
0390 }
0391 
0392 KateNavigationConfigTab::~KateNavigationConfigTab()
0393 {
0394     delete ui;
0395 }
0396 
0397 void KateNavigationConfigTab::initMulticursorModifierComboBox()
0398 {
0399     // On macOS, the ControlModifier value corresponds to the Command keys on the
0400     // keyboard, and the MetaModifier value corresponds to the Control keys.
0401     auto *c = ui->cmbMultiCursorModifier;
0402 
0403 #ifndef Q_OS_DARWIN
0404     c->insertItem(0, i18n("Alt"), (int)Qt::ALT);
0405     c->insertItem(1, i18n("Ctrl"), (int)Qt::CTRL);
0406     c->insertItem(2, i18n("Meta"), (int)Qt::META);
0407     c->insertItem(3, i18n("Ctrl + Alt"), (int)(Qt::CTRL | Qt::ALT));
0408     c->insertItem(4, i18n("Meta + Alt"), (int)(Qt::META | Qt::ALT));
0409     c->insertItem(5, i18n("Ctrl + Meta"), (int)(Qt::CTRL | Qt::META));
0410 #else
0411     c->insertItem(0, i18n("Alt"), (int)Qt::ALT);
0412     c->insertItem(1, i18n("Cmd"), (int)Qt::CTRL);
0413     c->insertItem(2, i18n("Ctrl"), (int)Qt::META);
0414     c->insertItem(3, i18n("Cmd + Alt"), (int)(Qt::CTRL | Qt::ALT));
0415     c->insertItem(4, i18n("Ctrl + Alt"), (int)(Qt::META | Qt::ALT));
0416     c->insertItem(5, i18n("Cmd + Ctrl"), (int)(Qt::CTRL | Qt::META));
0417 #endif
0418 }
0419 
0420 void KateNavigationConfigTab::apply()
0421 {
0422     // nothing changed, no need to apply stuff
0423     if (!hasChanged()) {
0424         return;
0425     }
0426     m_changed = false;
0427 
0428     KateViewConfig::global()->configStart();
0429     KateDocumentConfig::global()->configStart();
0430 
0431     KateDocumentConfig::global()->setPageUpDownMovesCursor(ui->chkPagingMovesCursor->isChecked());
0432     KateDocumentConfig::global()->setSmartHome(ui->chkSmartHome->isChecked());
0433     KateDocumentConfig::global()->setCamelCursor(ui->chkCamelCursor->isChecked());
0434 
0435     KateViewConfig::global()->setValue(KateViewConfig::AutoCenterLines, ui->sbAutoCenterCursor->value());
0436     KateViewConfig::global()->setValue(KateViewConfig::BackspaceRemoveComposedCharacters, ui->chkBackspaceRemoveComposed->isChecked());
0437     KateViewConfig::global()->setValue(KateViewConfig::PersistentSelection, ui->cbTextSelectionMode->currentIndex() == 1);
0438     KateViewConfig::global()->setValue(KateViewConfig::ScrollPastEnd, ui->chkScrollPastEnd->isChecked());
0439 
0440     const int modifers = ui->cmbMultiCursorModifier->currentData().toInt();
0441     KateViewConfig::global()->setMultiCursorModifiers(Qt::KeyboardModifiers(modifers));
0442 
0443     KateDocumentConfig::global()->configEnd();
0444     KateViewConfig::global()->configEnd();
0445 }
0446 
0447 void KateNavigationConfigTab::reload()
0448 {
0449     ui->cbTextSelectionMode->setCurrentIndex(KateViewConfig::global()->persistentSelection() ? 1 : 0);
0450 
0451     ui->chkBackspaceRemoveComposed->setChecked(KateViewConfig::global()->backspaceRemoveComposed());
0452     ui->chkPagingMovesCursor->setChecked(KateDocumentConfig::global()->pageUpDownMovesCursor());
0453     ui->chkScrollPastEnd->setChecked(KateViewConfig::global()->scrollPastEnd());
0454     ui->chkSmartHome->setChecked(KateDocumentConfig::global()->smartHome());
0455     ui->chkCamelCursor->setChecked(KateDocumentConfig::global()->camelCursor());
0456 
0457     ui->sbAutoCenterCursor->setValue(KateViewConfig::global()->autoCenterLines());
0458 
0459     const int mods = KateViewConfig::global()->multiCursorModifiers();
0460     const auto count = ui->cmbMultiCursorModifier->count();
0461     for (int i = 0; i < count; ++i) {
0462         int idxMods = ui->cmbMultiCursorModifier->itemData(i).toInt();
0463         if (idxMods == mods) {
0464             ui->cmbMultiCursorModifier->setCurrentIndex(i);
0465             break;
0466         }
0467     }
0468 }
0469 
0470 QString KateNavigationConfigTab::name() const
0471 {
0472     return i18n("Text Navigation");
0473 }
0474 
0475 // END KateNavigationConfigTab
0476 
0477 // BEGIN KateEditGeneralConfigTab
0478 KateEditGeneralConfigTab::KateEditGeneralConfigTab(QWidget *parent)
0479     : KateConfigPage(parent)
0480 {
0481     QVBoxLayout *layout = new QVBoxLayout(this);
0482     QWidget *newWidget = new QWidget(this);
0483     ui = new Ui::EditConfigWidget();
0484     ui->setupUi(newWidget);
0485 
0486     for (const auto &fact : KTextEditor::EditorPrivate::self()->inputModeFactories()) {
0487         ui->cmbInputMode->addItem(fact->name(), static_cast<int>(fact->inputMode()));
0488     }
0489 
0490     // "What's This?" Help is in the ui-files
0491 
0492     reload();
0493 
0494     observeChanges(ui->chkAutoBrackets);
0495     observeChanges(ui->chkMousePasteAtCursorPosition);
0496     observeChanges(ui->chkShowStaticWordWrapMarker);
0497     observeChanges(ui->chkTextDragAndDrop);
0498     observeChanges(ui->chkSmartCopyCut);
0499     observeChanges(ui->sbClipboardHistoryEntries);
0500     observeChanges(ui->chkStaticWordWrap);
0501     observeChanges(ui->cmbEncloseSelection);
0502     ui->lblBracketHelp->setFont(QFontDatabase::systemFont(QFontDatabase::SmallestReadableFont));
0503     connect(ui->cmbEncloseSelection->lineEdit(), &QLineEdit::editingFinished, [=] {
0504         const int index = ui->cmbEncloseSelection->currentIndex();
0505         const QString text = ui->cmbEncloseSelection->currentText();
0506         // Text removed? Remove item, but don't remove default data!
0507         if (index >= UserData && text.isEmpty()) {
0508             ui->cmbEncloseSelection->removeItem(index);
0509             slotChanged();
0510 
0511             // Not already there? Add new item! For whatever reason it isn't done automatically
0512         } else if (ui->cmbEncloseSelection->findText(text) < 0) {
0513             ui->cmbEncloseSelection->addItem(text);
0514             slotChanged();
0515         }
0516         ui->cmbEncloseSelection->setCurrentIndex(ui->cmbEncloseSelection->findText(text));
0517     });
0518     observeChanges(ui->cmbInputMode);
0519     observeChanges(ui->sbWordWrap);
0520 
0521     layout->addWidget(newWidget);
0522 }
0523 
0524 KateEditGeneralConfigTab::~KateEditGeneralConfigTab()
0525 {
0526     delete ui;
0527 }
0528 
0529 void KateEditGeneralConfigTab::apply()
0530 {
0531     // nothing changed, no need to apply stuff
0532     if (!hasChanged()) {
0533         return;
0534     }
0535     m_changed = false;
0536 
0537     KateViewConfig::global()->configStart();
0538     KateDocumentConfig::global()->configStart();
0539 
0540     KateDocumentConfig::global()->setWordWrap(ui->chkStaticWordWrap->isChecked());
0541     KateDocumentConfig::global()->setWordWrapAt(ui->sbWordWrap->value());
0542 
0543     KateRendererConfig::global()->setWordWrapMarker(ui->chkShowStaticWordWrapMarker->isChecked());
0544 
0545     KateViewConfig::global()->setValue(KateViewConfig::AutoBrackets, ui->chkAutoBrackets->isChecked());
0546     KateViewConfig::global()->setValue(KateViewConfig::CharsToEncloseSelection, ui->cmbEncloseSelection->currentText());
0547     QStringList userLetters;
0548     for (int i = UserData; i < ui->cmbEncloseSelection->count(); ++i) {
0549         userLetters.append(ui->cmbEncloseSelection->itemText(i));
0550     }
0551     KateViewConfig::global()->setValue(KateViewConfig::UserSetsOfCharsToEncloseSelection, userLetters);
0552     KateViewConfig::global()->setValue(KateViewConfig::InputMode, ui->cmbInputMode->currentData().toInt());
0553     KateViewConfig::global()->setValue(KateViewConfig::MousePasteAtCursorPosition, ui->chkMousePasteAtCursorPosition->isChecked());
0554     KateViewConfig::global()->setValue(KateViewConfig::TextDragAndDrop, ui->chkTextDragAndDrop->isChecked());
0555     KateViewConfig::global()->setValue(KateViewConfig::SmartCopyCut, ui->chkSmartCopyCut->isChecked());
0556     KateViewConfig::global()->setValue(KateViewConfig::ClipboardHistoryEntries, ui->sbClipboardHistoryEntries->value());
0557 
0558     KateDocumentConfig::global()->configEnd();
0559     KateViewConfig::global()->configEnd();
0560 }
0561 
0562 void KateEditGeneralConfigTab::reload()
0563 {
0564     ui->chkAutoBrackets->setChecked(KateViewConfig::global()->autoBrackets());
0565     ui->chkMousePasteAtCursorPosition->setChecked(KateViewConfig::global()->mousePasteAtCursorPosition());
0566     ui->chkShowStaticWordWrapMarker->setChecked(KateRendererConfig::global()->wordWrapMarker());
0567     ui->chkTextDragAndDrop->setChecked(KateViewConfig::global()->textDragAndDrop());
0568     ui->chkSmartCopyCut->setChecked(KateViewConfig::global()->smartCopyCut());
0569     ui->chkStaticWordWrap->setChecked(KateDocumentConfig::global()->wordWrap());
0570     ui->sbClipboardHistoryEntries->setValue(KateViewConfig::global()->clipboardHistoryEntries());
0571 
0572     ui->sbWordWrap->setSuffix(ki18ncp("Wrap words at (value is at 20 or larger)", " character", " characters"));
0573     ui->sbWordWrap->setValue(KateDocumentConfig::global()->wordWrapAt());
0574 
0575     ui->cmbEncloseSelection->clear();
0576     ui->cmbEncloseSelection->lineEdit()->setClearButtonEnabled(true);
0577     ui->cmbEncloseSelection->lineEdit()->setPlaceholderText(i18n("Feature is not active"));
0578     ui->cmbEncloseSelection->addItem(QString(), None);
0579     ui->cmbEncloseSelection->setItemData(0, i18n("Disable Feature"), Qt::ToolTipRole);
0580     ui->cmbEncloseSelection->addItem(QStringLiteral("`*_~"), MarkDown);
0581     ui->cmbEncloseSelection->setItemData(1, i18n("May be handy with Markdown"), Qt::ToolTipRole);
0582     ui->cmbEncloseSelection->addItem(QStringLiteral("<>(){}[]'\""), MirrorChar);
0583     ui->cmbEncloseSelection->setItemData(2, i18n("Mirror characters, similar but not exactly like auto brackets"), Qt::ToolTipRole);
0584     ui->cmbEncloseSelection->addItem(QStringLiteral("´`_.:|#@~*!?$%/=,;-+^°§&"), NonLetters);
0585     ui->cmbEncloseSelection->setItemData(3, i18n("Non letter character"), Qt::ToolTipRole);
0586     const QStringList userLetters = KateViewConfig::global()->value(KateViewConfig::UserSetsOfCharsToEncloseSelection).toStringList();
0587     for (int i = 0; i < userLetters.size(); ++i) {
0588         ui->cmbEncloseSelection->addItem(userLetters.at(i), UserData + i);
0589     }
0590     ui->cmbEncloseSelection->setCurrentIndex(ui->cmbEncloseSelection->findText(KateViewConfig::global()->charsToEncloseSelection()));
0591 
0592     const int id = static_cast<int>(KateViewConfig::global()->inputMode());
0593     ui->cmbInputMode->setCurrentIndex(ui->cmbInputMode->findData(id));
0594 }
0595 
0596 QString KateEditGeneralConfigTab::name() const
0597 {
0598     return i18n("General");
0599 }
0600 
0601 // END KateEditGeneralConfigTab
0602 
0603 // BEGIN KateEditConfigTab
0604 KateEditConfigTab::KateEditConfigTab(QWidget *parent)
0605     : KateConfigPage(parent)
0606     , editConfigTab(new KateEditGeneralConfigTab(this))
0607     , navigationConfigTab(new KateNavigationConfigTab(this))
0608     , indentConfigTab(new KateIndentConfigTab(this))
0609     , completionConfigTab(new KateCompletionConfigTab(this))
0610     , spellCheckConfigTab(new KateSpellCheckConfigTab(this))
0611 {
0612     QVBoxLayout *layout = new QVBoxLayout(this);
0613     layout->setContentsMargins(0, 0, 0, 0);
0614     QTabWidget *tabWidget = new QTabWidget(this);
0615 
0616     // add all tabs
0617     tabWidget->insertTab(0, editConfigTab, editConfigTab->name());
0618     tabWidget->insertTab(1, navigationConfigTab, navigationConfigTab->name());
0619     tabWidget->insertTab(2, indentConfigTab, indentConfigTab->name());
0620     tabWidget->insertTab(3, completionConfigTab, completionConfigTab->name());
0621     tabWidget->insertTab(4, spellCheckConfigTab, spellCheckConfigTab->name());
0622 
0623     observeChanges(editConfigTab);
0624     observeChanges(navigationConfigTab);
0625     observeChanges(indentConfigTab);
0626     observeChanges(completionConfigTab);
0627     observeChanges(spellCheckConfigTab);
0628 
0629     int i = tabWidget->count();
0630     for (const auto &factory : KTextEditor::EditorPrivate::self()->inputModeFactories()) {
0631         KateConfigPage *tab = factory->createConfigPage(this);
0632         if (tab) {
0633             m_inputModeConfigTabs << tab;
0634             tabWidget->insertTab(i, tab, tab->name());
0635             observeChanges(tab);
0636             i++;
0637         }
0638     }
0639 
0640     layout->addWidget(tabWidget);
0641 }
0642 
0643 KateEditConfigTab::~KateEditConfigTab()
0644 {
0645     qDeleteAll(m_inputModeConfigTabs);
0646 }
0647 
0648 void KateEditConfigTab::apply()
0649 {
0650     // try to update the rest of tabs
0651     editConfigTab->apply();
0652     navigationConfigTab->apply();
0653     indentConfigTab->apply();
0654     completionConfigTab->apply();
0655     spellCheckConfigTab->apply();
0656     for (KateConfigPage *tab : std::as_const(m_inputModeConfigTabs)) {
0657         tab->apply();
0658     }
0659 }
0660 
0661 void KateEditConfigTab::reload()
0662 {
0663     editConfigTab->reload();
0664     navigationConfigTab->reload();
0665     indentConfigTab->reload();
0666     completionConfigTab->reload();
0667     spellCheckConfigTab->reload();
0668     for (KateConfigPage *tab : std::as_const(m_inputModeConfigTabs)) {
0669         tab->reload();
0670     }
0671 }
0672 
0673 void KateEditConfigTab::reset()
0674 {
0675     editConfigTab->reset();
0676     navigationConfigTab->reset();
0677     indentConfigTab->reset();
0678     completionConfigTab->reset();
0679     spellCheckConfigTab->reset();
0680     for (KateConfigPage *tab : std::as_const(m_inputModeConfigTabs)) {
0681         tab->reset();
0682     }
0683 }
0684 
0685 void KateEditConfigTab::defaults()
0686 {
0687     editConfigTab->defaults();
0688     navigationConfigTab->defaults();
0689     indentConfigTab->defaults();
0690     completionConfigTab->defaults();
0691     spellCheckConfigTab->defaults();
0692     for (KateConfigPage *tab : std::as_const(m_inputModeConfigTabs)) {
0693         tab->defaults();
0694     }
0695 }
0696 
0697 QString KateEditConfigTab::name() const
0698 {
0699     return i18n("Editing");
0700 }
0701 
0702 QString KateEditConfigTab::fullName() const
0703 {
0704     return i18n("Editing Options");
0705 }
0706 
0707 QIcon KateEditConfigTab::icon() const
0708 {
0709     return QIcon::fromTheme(QStringLiteral("accessories-text-editor"));
0710 }
0711 
0712 // END KateEditConfigTab
0713 
0714 // BEGIN KateViewDefaultsConfig
0715 KateViewDefaultsConfig::KateViewDefaultsConfig(QWidget *parent)
0716     : KateConfigPage(parent)
0717     , textareaUi(new Ui::TextareaAppearanceConfigWidget())
0718     , bordersUi(new Ui::BordersAppearanceConfigWidget())
0719     , statusBarUi(new Ui::StatusbarConfigWidget())
0720 {
0721     QLayout *layout = new QVBoxLayout(this);
0722     QTabWidget *tabWidget = new QTabWidget(this);
0723     layout->addWidget(tabWidget);
0724     layout->setContentsMargins(0, 0, 0, 0);
0725 
0726     QWidget *textareaTab = new QWidget(tabWidget);
0727     textareaUi->setupUi(textareaTab);
0728     tabWidget->addTab(textareaTab, i18n("General"));
0729 
0730     QWidget *bordersTab = new QWidget(tabWidget);
0731     bordersUi->setupUi(bordersTab);
0732     tabWidget->addTab(bordersTab, i18n("Borders"));
0733 
0734     QWidget *statusbarTab = new QWidget(tabWidget);
0735     statusBarUi->setupUi(statusbarTab);
0736     tabWidget->addTab(statusbarTab, i18n("Statusbar"));
0737 
0738     textareaUi->cmbDynamicWordWrapIndicator->addItem(i18n("Off"));
0739     textareaUi->cmbDynamicWordWrapIndicator->addItem(i18n("Follow Line Numbers"));
0740     textareaUi->cmbDynamicWordWrapIndicator->addItem(i18n("Always On"));
0741 
0742     // "What's This?" help is in the ui-file
0743 
0744     reload();
0745 
0746     observeChanges(textareaUi->kfontrequester);
0747 
0748     observeChanges(textareaUi->chkAnimateBracketMatching);
0749     observeChanges(textareaUi->chkDynWrapAnywhere);
0750     observeChanges(textareaUi->chkDynWrapAtStaticMarker);
0751     observeChanges(textareaUi->chkFoldFirstLine);
0752     observeChanges(textareaUi->chkShowBracketMatchPreview);
0753     observeChanges(textareaUi->chkShowIndentationLines);
0754     observeChanges(textareaUi->chkShowLineCount);
0755     observeChanges(textareaUi->chkShowTabs);
0756     observeChanges(textareaUi->chkShowWholeBracketExpression);
0757     observeChanges(textareaUi->chkShowWordCount);
0758     observeChanges(textareaUi->cmbDynamicWordWrapIndicator);
0759     observeChanges(textareaUi->cbxWordWrap);
0760     observeChanges(textareaUi->chkFocusFrame);
0761     observeChanges(textareaUi->spbLineHeightMultiplier);
0762     auto a = [ui = textareaUi, cbx = textareaUi->cbxWordWrap]() {
0763         ui->chkDynWrapAtStaticMarker->setEnabled(cbx->isChecked());
0764         ui->chkDynWrapAnywhere->setEnabled(cbx->isChecked());
0765         ui->cmbDynamicWordWrapIndicator->setEnabled(cbx->isChecked());
0766         ui->sbDynamicWordWrapDepth->setEnabled(cbx->isChecked());
0767     };
0768     connect(textareaUi->cbxWordWrap, &QCheckBox::stateChanged, this, a);
0769     a();
0770     auto b = [cbx = textareaUi->cbxIndentWrappedLines, sb = textareaUi->sbDynamicWordWrapDepth]() {
0771         sb->setEnabled(cbx->isChecked());
0772     };
0773     b();
0774     connect(textareaUi->cbxIndentWrappedLines, &QCheckBox::stateChanged, this, b);
0775     observeChanges(textareaUi->cbxIndentWrappedLines);
0776     observeChanges(textareaUi->sbDynamicWordWrapDepth);
0777     observeChanges(textareaUi->sliSetMarkerSize);
0778     observeChanges(textareaUi->spacesComboBox);
0779 
0780     observeChanges(bordersUi->chkIconBorder);
0781     observeChanges(bordersUi->chkLineNumbers);
0782     observeChanges(bordersUi->chkScrollbarMarks);
0783     observeChanges(bordersUi->chkScrollbarMiniMap);
0784     observeChanges(bordersUi->chkScrollbarMiniMapAll);
0785     bordersUi->chkScrollbarMiniMapAll->hide(); // this is temporary until the feature is done
0786     observeChanges(bordersUi->chkScrollbarPreview);
0787     observeChanges(bordersUi->chkShowFoldingMarkers);
0788     observeChanges(bordersUi->chkShowFoldingPreview);
0789     observeChanges(bordersUi->chkShowLineModification);
0790     observeChanges(bordersUi->cmbShowScrollbars);
0791     observeChanges(bordersUi->rbSortBookmarksByCreation);
0792     observeChanges(bordersUi->rbSortBookmarksByPosition);
0793     observeChanges(bordersUi->spBoxMiniMapWidth);
0794     observeChanges(bordersUi->cmbFoldingArrowVisiblity);
0795 
0796     // statusBarUi
0797     observeChanges(statusBarUi->cbShowActiveDictionary);
0798     observeChanges(statusBarUi->cbShowHighlightingMode);
0799     observeChanges(statusBarUi->cbShowInputMode);
0800     observeChanges(statusBarUi->cbShowLineColumn);
0801     observeChanges(statusBarUi->cbShowTabSetting);
0802     observeChanges(statusBarUi->cbShowEncoding);
0803     observeChanges(statusBarUi->cbShowEOL);
0804 }
0805 
0806 KateViewDefaultsConfig::~KateViewDefaultsConfig()
0807 {
0808     delete bordersUi;
0809     delete textareaUi;
0810     delete statusBarUi;
0811 }
0812 
0813 void KateViewDefaultsConfig::apply()
0814 {
0815     // nothing changed, no need to apply stuff
0816     if (!hasChanged()) {
0817         return;
0818     }
0819     m_changed = false;
0820 
0821     KateViewConfig::global()->configStart();
0822     KateRendererConfig::global()->configStart();
0823 
0824     KateDocumentConfig::global()->setMarkerSize(textareaUi->sliSetMarkerSize->value());
0825     KateDocumentConfig::global()->setShowSpaces(KateDocumentConfig::WhitespaceRendering(textareaUi->spacesComboBox->currentIndex()));
0826     KateDocumentConfig::global()->setShowTabs(textareaUi->chkShowTabs->isChecked());
0827 
0828     KateRendererConfig::global()->setFont(textareaUi->kfontrequester->font());
0829     KateRendererConfig::global()->setAnimateBracketMatching(textareaUi->chkAnimateBracketMatching->isChecked());
0830     KateRendererConfig::global()->setShowIndentationLines(textareaUi->chkShowIndentationLines->isChecked());
0831     KateRendererConfig::global()->setShowWholeBracketExpression(textareaUi->chkShowWholeBracketExpression->isChecked());
0832     KateRendererConfig::global()->setLineHeightMultiplier(textareaUi->spbLineHeightMultiplier->value());
0833 
0834     KateViewConfig::global()->setDynWordWrap(textareaUi->cbxWordWrap->isChecked());
0835     KateViewConfig::global()->setShowWordCount(textareaUi->chkShowWordCount->isChecked());
0836     KateViewConfig::global()->setValue(KateViewConfig::BookmarkSorting, bordersUi->rbSortBookmarksByPosition->isChecked() ? 0 : 1);
0837     if (!textareaUi->cbxIndentWrappedLines->isChecked()) {
0838         KateViewConfig::global()->setValue(KateViewConfig::DynWordWrapAlignIndent, 0);
0839     } else {
0840         KateViewConfig::global()->setValue(KateViewConfig::DynWordWrapAlignIndent, textareaUi->sbDynamicWordWrapDepth->value());
0841     }
0842     KateViewConfig::global()->setValue(KateViewConfig::DynWordWrapIndicators, textareaUi->cmbDynamicWordWrapIndicator->currentIndex());
0843     KateViewConfig::global()->setValue(KateViewConfig::DynWrapAnywhere, textareaUi->chkDynWrapAnywhere->isChecked());
0844     KateViewConfig::global()->setValue(KateViewConfig::DynWrapAtStaticMarker, textareaUi->chkDynWrapAtStaticMarker->isChecked());
0845     KateViewConfig::global()->setValue(KateViewConfig::FoldFirstLine, textareaUi->chkFoldFirstLine->isChecked());
0846     KateViewConfig::global()->setValue(KateViewConfig::ScrollBarMiniMapWidth, bordersUi->spBoxMiniMapWidth->value());
0847     KateViewConfig::global()->setValue(KateViewConfig::ShowBracketMatchPreview, textareaUi->chkShowBracketMatchPreview->isChecked());
0848     KateViewConfig::global()->setValue(KateViewConfig::ShowFocusFrame, textareaUi->chkFocusFrame->isChecked());
0849     KateViewConfig::global()->setValue(KateViewConfig::ShowFoldingBar, bordersUi->chkShowFoldingMarkers->isChecked());
0850     KateViewConfig::global()->setValue(KateViewConfig::ShowFoldingPreview, bordersUi->chkShowFoldingPreview->isChecked());
0851     KateViewConfig::global()->setValue(KateViewConfig::ShowIconBar, bordersUi->chkIconBorder->isChecked());
0852     KateViewConfig::global()->setValue(KateViewConfig::ShowLineCount, textareaUi->chkShowLineCount->isChecked());
0853     KateViewConfig::global()->setValue(KateViewConfig::ShowLineModification, bordersUi->chkShowLineModification->isChecked());
0854     KateViewConfig::global()->setValue(KateViewConfig::ShowLineNumbers, bordersUi->chkLineNumbers->isChecked());
0855     KateViewConfig::global()->setValue(KateViewConfig::ShowScrollBarMarks, bordersUi->chkScrollbarMarks->isChecked());
0856     KateViewConfig::global()->setValue(KateViewConfig::ShowScrollBarMiniMap, bordersUi->chkScrollbarMiniMap->isChecked());
0857     KateViewConfig::global()->setValue(KateViewConfig::ShowScrollBarMiniMapAll, bordersUi->chkScrollbarMiniMapAll->isChecked());
0858     KateViewConfig::global()->setValue(KateViewConfig::ShowScrollBarPreview, bordersUi->chkScrollbarPreview->isChecked());
0859     KateViewConfig::global()->setValue(KateViewConfig::ShowScrollbars, bordersUi->cmbShowScrollbars->currentIndex());
0860     bool showOnHoverOnly = bordersUi->cmbFoldingArrowVisiblity->currentIndex() == 0;
0861     KateViewConfig::global()->setValue(KateViewConfig::ShowFoldingOnHoverOnly, showOnHoverOnly);
0862 
0863     // Statusbar stuff
0864     KateViewConfig::global()->setValue(KateViewConfig::ShowStatusbarDictionary, statusBarUi->cbShowActiveDictionary->isChecked());
0865     KateViewConfig::global()->setValue(KateViewConfig::ShowStatusbarHighlightingMode, statusBarUi->cbShowHighlightingMode->isChecked());
0866     KateViewConfig::global()->setValue(KateViewConfig::ShowStatusbarInputMode, statusBarUi->cbShowInputMode->isChecked());
0867     KateViewConfig::global()->setValue(KateViewConfig::ShowStatusbarLineColumn, statusBarUi->cbShowLineColumn->isChecked());
0868     KateViewConfig::global()->setValue(KateViewConfig::ShowStatusbarTabSettings, statusBarUi->cbShowTabSetting->isChecked());
0869     KateViewConfig::global()->setValue(KateViewConfig::ShowStatusbarFileEncoding, statusBarUi->cbShowEncoding->isChecked());
0870     KateViewConfig::global()->setValue(KateViewConfig::ShowStatusbarEOL, statusBarUi->cbShowEOL->isChecked());
0871 
0872     KateRendererConfig::global()->configEnd();
0873     KateViewConfig::global()->configEnd();
0874 }
0875 
0876 void KateViewDefaultsConfig::reload()
0877 {
0878     bordersUi->chkIconBorder->setChecked(KateViewConfig::global()->iconBar());
0879     bordersUi->chkLineNumbers->setChecked(KateViewConfig::global()->lineNumbers());
0880     bordersUi->chkScrollbarMarks->setChecked(KateViewConfig::global()->scrollBarMarks());
0881     bordersUi->chkScrollbarMiniMap->setChecked(KateViewConfig::global()->scrollBarMiniMap());
0882     bordersUi->chkScrollbarMiniMapAll->setChecked(KateViewConfig::global()->scrollBarMiniMapAll());
0883     bordersUi->chkScrollbarPreview->setChecked(KateViewConfig::global()->scrollBarPreview());
0884     bordersUi->chkShowFoldingMarkers->setChecked(KateViewConfig::global()->foldingBar());
0885     bordersUi->chkShowFoldingPreview->setChecked(KateViewConfig::global()->foldingPreview());
0886     bordersUi->chkShowLineModification->setChecked(KateViewConfig::global()->lineModification());
0887     bordersUi->cmbShowScrollbars->setCurrentIndex(KateViewConfig::global()->showScrollbars());
0888     bordersUi->rbSortBookmarksByCreation->setChecked(KateViewConfig::global()->bookmarkSort() == 1);
0889     bordersUi->rbSortBookmarksByPosition->setChecked(KateViewConfig::global()->bookmarkSort() == 0);
0890     bordersUi->spBoxMiniMapWidth->setValue(KateViewConfig::global()->scrollBarMiniMapWidth());
0891     bordersUi->cmbFoldingArrowVisiblity->setCurrentIndex(KateViewConfig::global()->showFoldingOnHoverOnly() ? 0 : 1);
0892 
0893     textareaUi->kfontrequester->setFont(KateRendererConfig::global()->baseFont());
0894 
0895     textareaUi->chkAnimateBracketMatching->setChecked(KateRendererConfig::global()->animateBracketMatching());
0896     textareaUi->chkDynWrapAnywhere->setChecked(KateViewConfig::global()->dynWrapAnywhere());
0897     textareaUi->chkDynWrapAtStaticMarker->setChecked(KateViewConfig::global()->dynWrapAtStaticMarker());
0898     textareaUi->chkFoldFirstLine->setChecked(KateViewConfig::global()->foldFirstLine());
0899     textareaUi->chkShowBracketMatchPreview->setChecked(KateViewConfig::global()->value(KateViewConfig::ShowBracketMatchPreview).toBool());
0900     textareaUi->chkShowIndentationLines->setChecked(KateRendererConfig::global()->showIndentationLines());
0901     textareaUi->chkShowLineCount->setChecked(KateViewConfig::global()->showLineCount());
0902     textareaUi->chkShowTabs->setChecked(KateDocumentConfig::global()->showTabs());
0903     textareaUi->chkShowWholeBracketExpression->setChecked(KateRendererConfig::global()->showWholeBracketExpression());
0904     textareaUi->chkShowWordCount->setChecked(KateViewConfig::global()->showWordCount());
0905     textareaUi->cmbDynamicWordWrapIndicator->setCurrentIndex(KateViewConfig::global()->dynWordWrapIndicators());
0906     textareaUi->cbxWordWrap->setChecked(KateViewConfig::global()->dynWordWrap());
0907     textareaUi->cbxIndentWrappedLines->setChecked(KateViewConfig::global()->dynWordWrapAlignIndent() != 0);
0908     textareaUi->sbDynamicWordWrapDepth->setValue(KateViewConfig::global()->dynWordWrapAlignIndent());
0909     textareaUi->sliSetMarkerSize->setValue(KateDocumentConfig::global()->markerSize());
0910     textareaUi->spacesComboBox->setCurrentIndex(KateDocumentConfig::global()->showSpaces());
0911     textareaUi->chkFocusFrame->setChecked(KateViewConfig::global()->showFocusFrame());
0912     textareaUi->spbLineHeightMultiplier->setValue(KateRendererConfig::global()->lineHeightMultiplier());
0913 
0914     statusBarUi->cbShowLineColumn->setChecked(KateViewConfig::global()->value(KateViewConfig::ShowStatusbarLineColumn).toBool());
0915     statusBarUi->cbShowActiveDictionary->setChecked(KateViewConfig::global()->value(KateViewConfig::ShowStatusbarDictionary).toBool());
0916     statusBarUi->cbShowTabSetting->setChecked(KateViewConfig::global()->value(KateViewConfig::ShowStatusbarTabSettings).toBool());
0917     statusBarUi->cbShowHighlightingMode->setChecked(KateViewConfig::global()->value(KateViewConfig::ShowStatusbarHighlightingMode).toBool());
0918     statusBarUi->cbShowInputMode->setChecked(KateViewConfig::global()->value(KateViewConfig::ShowStatusbarInputMode).toBool());
0919     statusBarUi->cbShowEncoding->setChecked(KateViewConfig::global()->value(KateViewConfig::ShowStatusbarFileEncoding).toBool());
0920     statusBarUi->cbShowEOL->setChecked(KateViewConfig::global()->value(KateViewConfig::ShowStatusbarEOL).toBool());
0921 }
0922 
0923 void KateViewDefaultsConfig::reset()
0924 {
0925 }
0926 
0927 void KateViewDefaultsConfig::defaults()
0928 {
0929 }
0930 
0931 QString KateViewDefaultsConfig::name() const
0932 {
0933     return i18n("Appearance");
0934 }
0935 
0936 QString KateViewDefaultsConfig::fullName() const
0937 {
0938     return i18n("Appearance");
0939 }
0940 
0941 QIcon KateViewDefaultsConfig::icon() const
0942 {
0943     return QIcon::fromTheme(QStringLiteral("preferences-desktop-theme"));
0944 }
0945 
0946 // END KateViewDefaultsConfig
0947 
0948 // BEGIN KateSaveConfigTab
0949 KateSaveConfigTab::KateSaveConfigTab(QWidget *parent)
0950     : KateConfigPage(parent)
0951     , modeConfigPage(new ModeConfigPage(this))
0952 {
0953     // FIXME: Is really needed to move all this code below to another class,
0954     // since it is another tab itself on the config dialog. This means we should
0955     // initialize, add and work with as we do with modeConfigPage (ereslibre)
0956     QVBoxLayout *layout = new QVBoxLayout(this);
0957     layout->setContentsMargins(0, 0, 0, 0);
0958     QTabWidget *tabWidget = new QTabWidget(this);
0959 
0960     QWidget *tmpWidget = new QWidget(tabWidget);
0961     QVBoxLayout *internalLayout = new QVBoxLayout(tmpWidget);
0962     QWidget *newWidget = new QWidget(tabWidget);
0963     ui = new Ui::OpenSaveConfigWidget();
0964     ui->setupUi(newWidget);
0965 
0966     QWidget *tmpWidget2 = new QWidget(tabWidget);
0967     QVBoxLayout *internalLayout2 = new QVBoxLayout(tmpWidget2);
0968     QWidget *newWidget2 = new QWidget(tabWidget);
0969     uiadv = new Ui::OpenSaveConfigAdvWidget();
0970     uiadv->setupUi(newWidget2);
0971     uiadv->lblExplanatory->setText(i18n("%1 backs up unsaved files to \"swap files.\" Swap files allow %1 to recover your work in the case of a system crash. Disabling swap files may cause data loss in case of a system crash.", QCoreApplication::applicationName()));
0972     uiadv->lblExplanatory->setFont(QFontDatabase::systemFont(QFontDatabase::SmallestReadableFont));
0973 
0974     // "What's This?" help can be found in the ui file
0975 
0976     reload();
0977 
0978     observeChanges(ui->cbRemoveTrailingSpaces);
0979     observeChanges(ui->chkDetectEOL);
0980     observeChanges(ui->chkEnableBOM);
0981     observeChanges(ui->chkNewLineAtEof);
0982     observeChanges(ui->cmbEOL);
0983     observeChanges(ui->cmbEncoding);
0984     observeChanges(ui->cmbEncodingDetection);
0985     observeChanges(ui->cmbEncodingFallback);
0986     observeChanges(ui->lineLengthLimit);
0987     observeChanges(ui->gbAutoSave);
0988     observeChanges(ui->cbAutoSaveOnFocus);
0989     observeChanges(ui->spbAutoSaveInterval);
0990 
0991     observeChanges(uiadv->chkAutoReloadVersionControl);
0992 
0993     observeChanges(uiadv->chkBackupLocalFiles);
0994     observeChanges(uiadv->chkBackupRemoteFiles);
0995     observeChanges(uiadv->cmbSwapFileMode);
0996     connect(uiadv->cmbSwapFileMode, qOverload<int>(&QComboBox::currentIndexChanged), this, &KateSaveConfigTab::swapFileModeChanged);
0997 
0998     observeChanges(uiadv->edtBackupPrefix);
0999     observeChanges(uiadv->edtBackupSuffix);
1000     observeChanges(uiadv->kurlSwapDirectory);
1001     observeChanges(uiadv->spbSwapFileSync);
1002 
1003     internalLayout->addWidget(newWidget);
1004     internalLayout2->addWidget(newWidget2);
1005 
1006     // add all tabs
1007     tabWidget->insertTab(0, tmpWidget, i18n("General"));
1008     tabWidget->insertTab(1, tmpWidget2, i18n("Advanced"));
1009     tabWidget->insertTab(2, modeConfigPage, modeConfigPage->name());
1010 
1011     observeChanges(modeConfigPage);
1012 
1013     layout->addWidget(tabWidget);
1014 
1015     // support variable expansion in backup prefix/suffix
1016     KTextEditor::Editor::instance()->addVariableExpansion({uiadv->edtBackupPrefix, uiadv->edtBackupSuffix},
1017                                                           {QStringLiteral("Date:Locale"),
1018                                                            QStringLiteral("Date:ISO"),
1019                                                            QStringLiteral("Date:"),
1020                                                            QStringLiteral("Time:Locale"),
1021                                                            QStringLiteral("Time:ISO"),
1022                                                            QStringLiteral("Time:"),
1023                                                            QStringLiteral("ENV:"),
1024                                                            QStringLiteral("JS:"),
1025                                                            QStringLiteral("UUID")});
1026 }
1027 
1028 KateSaveConfigTab::~KateSaveConfigTab()
1029 {
1030     delete uiadv;
1031     delete ui;
1032 }
1033 
1034 void KateSaveConfigTab::swapFileModeChanged(int idx)
1035 {
1036     const KateDocumentConfig::SwapFileMode mode = static_cast<KateDocumentConfig::SwapFileMode>(idx);
1037     switch (mode) {
1038     case KateDocumentConfig::DisableSwapFile:
1039         uiadv->lblSwapDirectory->setEnabled(false);
1040         uiadv->kurlSwapDirectory->setEnabled(false);
1041         uiadv->lblSwapFileSync->setEnabled(false);
1042         uiadv->spbSwapFileSync->setEnabled(false);
1043         break;
1044     case KateDocumentConfig::EnableSwapFile:
1045         uiadv->lblSwapDirectory->setEnabled(false);
1046         uiadv->kurlSwapDirectory->setEnabled(false);
1047         uiadv->lblSwapFileSync->setEnabled(true);
1048         uiadv->spbSwapFileSync->setEnabled(true);
1049         break;
1050     case KateDocumentConfig::SwapFilePresetDirectory:
1051         uiadv->lblSwapDirectory->setEnabled(true);
1052         uiadv->kurlSwapDirectory->setEnabled(true);
1053         uiadv->lblSwapFileSync->setEnabled(true);
1054         uiadv->spbSwapFileSync->setEnabled(true);
1055         break;
1056     }
1057 }
1058 
1059 void KateSaveConfigTab::apply()
1060 {
1061     modeConfigPage->apply();
1062 
1063     // nothing changed, no need to apply stuff
1064     if (!hasChanged()) {
1065         return;
1066     }
1067     m_changed = false;
1068 
1069     KateGlobalConfig::global()->configStart();
1070     KateDocumentConfig::global()->configStart();
1071 
1072     if (uiadv->edtBackupSuffix->text().isEmpty() && uiadv->edtBackupPrefix->text().isEmpty()) {
1073         KMessageBox::information(this, i18n("You did not provide a backup suffix or prefix. Using default suffix: '~'"), i18n("No Backup Suffix or Prefix"));
1074         uiadv->edtBackupSuffix->setText(QStringLiteral("~"));
1075     }
1076 
1077     KateDocumentConfig::global()->setBackupOnSaveLocal(uiadv->chkBackupLocalFiles->isChecked());
1078     KateDocumentConfig::global()->setBackupOnSaveRemote(uiadv->chkBackupRemoteFiles->isChecked());
1079     KateDocumentConfig::global()->setBackupPrefix(uiadv->edtBackupPrefix->text());
1080     KateDocumentConfig::global()->setBackupSuffix(uiadv->edtBackupSuffix->text());
1081 
1082     KateDocumentConfig::global()->setSwapFileMode(uiadv->cmbSwapFileMode->currentIndex());
1083     KateDocumentConfig::global()->setSwapDirectory(uiadv->kurlSwapDirectory->url().toLocalFile());
1084     KateDocumentConfig::global()->setSwapSyncInterval(uiadv->spbSwapFileSync->value());
1085 
1086     KateDocumentConfig::global()->setRemoveSpaces(ui->cbRemoveTrailingSpaces->currentIndex());
1087 
1088     KateDocumentConfig::global()->setNewLineAtEof(ui->chkNewLineAtEof->isChecked());
1089 
1090     // set both standard and fallback encoding
1091     KateDocumentConfig::global()->setEncoding(KCharsets::charsets()->encodingForName(ui->cmbEncoding->currentText()));
1092 
1093     KateGlobalConfig::global()->setProberType((KEncodingProber::ProberType)ui->cmbEncodingDetection->currentIndex());
1094     KateGlobalConfig::global()->setFallbackEncoding(KCharsets::charsets()->encodingForName(ui->cmbEncodingFallback->currentText()));
1095 
1096     KateDocumentConfig::global()->setEol(ui->cmbEOL->currentIndex());
1097     KateDocumentConfig::global()->setAllowEolDetection(ui->chkDetectEOL->isChecked());
1098     KateDocumentConfig::global()->setBom(ui->chkEnableBOM->isChecked());
1099 
1100     KateDocumentConfig::global()->setLineLengthLimit(ui->lineLengthLimit->value());
1101 
1102     KateDocumentConfig::global()->setValue(KateDocumentConfig::AutoSave, ui->gbAutoSave->isChecked());
1103     KateDocumentConfig::global()->setValue(KateDocumentConfig::AutoSaveOnFocusOut, ui->cbAutoSaveOnFocus->isChecked());
1104     KateDocumentConfig::global()->setValue(KateDocumentConfig::AutoSaveInteral, ui->spbAutoSaveInterval->value());
1105 
1106     KateDocumentConfig::global()->setValue(KateDocumentConfig::AutoReloadIfStateIsInVersionControl, uiadv->chkAutoReloadVersionControl->isChecked());
1107 
1108     KateDocumentConfig::global()->configEnd();
1109     KateGlobalConfig::global()->configEnd();
1110 }
1111 
1112 void KateSaveConfigTab::reload()
1113 {
1114     modeConfigPage->reload();
1115 
1116     // encodings
1117     ui->cmbEncoding->clear();
1118     ui->cmbEncodingFallback->clear();
1119     QStringList encodings(KCharsets::charsets()->descriptiveEncodingNames());
1120     int insert = 0;
1121     for (int i = 0; i < encodings.count(); i++) {
1122         QTextCodec *codecForEnc = QTextCodec::codecForName(KCharsets::charsets()->encodingForName(encodings[i]).toUtf8());
1123 
1124         if (codecForEnc) {
1125             ui->cmbEncoding->addItem(encodings[i]);
1126             ui->cmbEncodingFallback->addItem(encodings[i]);
1127 
1128             if (codecForEnc == KateDocumentConfig::global()->codec()) {
1129                 ui->cmbEncoding->setCurrentIndex(insert);
1130             }
1131 
1132             if (codecForEnc == KateGlobalConfig::global()->fallbackCodec()) {
1133                 // adjust index for fallback config, has no default!
1134                 ui->cmbEncodingFallback->setCurrentIndex(insert);
1135             }
1136 
1137             insert++;
1138         }
1139     }
1140 
1141     // encoding detection
1142     ui->cmbEncodingDetection->clear();
1143     bool found = false;
1144     for (int i = 0; !KEncodingProber::nameForProberType((KEncodingProber::ProberType)i).isEmpty(); ++i) {
1145         ui->cmbEncodingDetection->addItem(KEncodingProber::nameForProberType((KEncodingProber::ProberType)i));
1146         if (i == KateGlobalConfig::global()->proberType()) {
1147             ui->cmbEncodingDetection->setCurrentIndex(ui->cmbEncodingDetection->count() - 1);
1148             found = true;
1149         }
1150     }
1151     if (!found) {
1152         ui->cmbEncodingDetection->setCurrentIndex(KEncodingProber::Universal);
1153     }
1154 
1155     // eol
1156     ui->cmbEOL->setCurrentIndex(KateDocumentConfig::global()->eol());
1157     ui->chkDetectEOL->setChecked(KateDocumentConfig::global()->allowEolDetection());
1158     ui->chkEnableBOM->setChecked(KateDocumentConfig::global()->bom());
1159     ui->lineLengthLimit->setValue(KateDocumentConfig::global()->lineLengthLimit());
1160 
1161     ui->cbRemoveTrailingSpaces->setCurrentIndex(KateDocumentConfig::global()->removeSpaces());
1162     ui->chkNewLineAtEof->setChecked(KateDocumentConfig::global()->newLineAtEof());
1163 
1164     // other stuff
1165     uiadv->chkBackupLocalFiles->setChecked(KateDocumentConfig::global()->backupOnSaveLocal());
1166     uiadv->chkBackupRemoteFiles->setChecked(KateDocumentConfig::global()->backupOnSaveRemote());
1167     uiadv->edtBackupPrefix->setText(KateDocumentConfig::global()->backupPrefix());
1168     uiadv->edtBackupSuffix->setText(KateDocumentConfig::global()->backupSuffix());
1169 
1170     uiadv->cmbSwapFileMode->setCurrentIndex(KateDocumentConfig::global()->swapFileMode());
1171     uiadv->kurlSwapDirectory->setUrl(QUrl::fromLocalFile(KateDocumentConfig::global()->swapDirectory()));
1172     uiadv->spbSwapFileSync->setValue(KateDocumentConfig::global()->swapSyncInterval());
1173     swapFileModeChanged(KateDocumentConfig::global()->swapFileMode());
1174 
1175     ui->gbAutoSave->setChecked(KateDocumentConfig::global()->autoSave());
1176     ui->cbAutoSaveOnFocus->setChecked(KateDocumentConfig::global()->autoSaveOnFocusOut());
1177     ui->spbAutoSaveInterval->setValue(KateDocumentConfig::global()->autoSaveInterval());
1178 
1179     uiadv->chkAutoReloadVersionControl->setChecked(KateDocumentConfig::global()->value(KateDocumentConfig::AutoReloadIfStateIsInVersionControl).toBool());
1180 }
1181 
1182 void KateSaveConfigTab::reset()
1183 {
1184     modeConfigPage->reset();
1185 }
1186 
1187 void KateSaveConfigTab::defaults()
1188 {
1189     modeConfigPage->defaults();
1190 
1191     ui->cbRemoveTrailingSpaces->setCurrentIndex(0);
1192 
1193     uiadv->chkBackupLocalFiles->setChecked(true);
1194     uiadv->chkBackupRemoteFiles->setChecked(false);
1195     uiadv->edtBackupPrefix->setText(QString());
1196     uiadv->edtBackupSuffix->setText(QStringLiteral("~"));
1197 
1198     uiadv->cmbSwapFileMode->setCurrentIndex(1);
1199     uiadv->kurlSwapDirectory->setDisabled(true);
1200     uiadv->lblSwapDirectory->setDisabled(true);
1201     uiadv->spbSwapFileSync->setValue(15);
1202 }
1203 
1204 QString KateSaveConfigTab::name() const
1205 {
1206     return i18n("Open/Save");
1207 }
1208 
1209 QString KateSaveConfigTab::fullName() const
1210 {
1211     return i18n("File Opening & Saving");
1212 }
1213 
1214 QIcon KateSaveConfigTab::icon() const
1215 {
1216     return QIcon::fromTheme(QStringLiteral("document-save"));
1217 }
1218 
1219 // END KateSaveConfigTab
1220 
1221 // BEGIN KateGotoBar
1222 KateGotoBar::KateGotoBar(KTextEditor::View *view, QWidget *parent)
1223     : KateViewBarWidget(true, parent)
1224     , m_view(view)
1225 {
1226     Q_ASSERT(m_view != nullptr); // this bar widget is pointless w/o a view
1227 
1228     QHBoxLayout *topLayout = new QHBoxLayout(centralWidget());
1229     topLayout->setContentsMargins(0, 0, 0, 0);
1230 
1231     QToolButton *btn = new QToolButton(this);
1232     btn->setAutoRaise(true);
1233     btn->setMinimumSize(QSize(1, btn->minimumSizeHint().height()));
1234     btn->setText(i18n("&Line:"));
1235     btn->setToolTip(i18n("Go to line number from clipboard"));
1236     connect(btn, &QToolButton::clicked, this, &KateGotoBar::gotoClipboard);
1237     topLayout->addWidget(btn);
1238 
1239     m_gotoRange = new QSpinBox(this);
1240     topLayout->addWidget(m_gotoRange, 1);
1241     topLayout->setStretchFactor(m_gotoRange, 0);
1242 
1243     btn = new QToolButton(this);
1244     btn->setAutoRaise(true);
1245     btn->setMinimumSize(QSize(1, btn->minimumSizeHint().height()));
1246     btn->setText(i18n("Go to"));
1247     btn->setIcon(QIcon::fromTheme(QStringLiteral("go-jump")));
1248     btn->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
1249     connect(btn, &QToolButton::clicked, this, &KateGotoBar::gotoLine);
1250     topLayout->addWidget(btn);
1251 
1252     btn = m_modifiedUp = new QToolButton(this);
1253     btn->setAutoRaise(true);
1254     btn->setMinimumSize(QSize(1, btn->minimumSizeHint().height()));
1255     btn->setDefaultAction(m_view->action("modified_line_up"));
1256     btn->setIcon(QIcon::fromTheme(QStringLiteral("go-up-search")));
1257     btn->setText(QString());
1258     btn->installEventFilter(this);
1259     topLayout->addWidget(btn);
1260 
1261     btn = m_modifiedDown = new QToolButton(this);
1262     btn->setAutoRaise(true);
1263     btn->setMinimumSize(QSize(1, btn->minimumSizeHint().height()));
1264     btn->setDefaultAction(m_view->action("modified_line_down"));
1265     btn->setIcon(QIcon::fromTheme(QStringLiteral("go-down-search")));
1266     btn->setText(QString());
1267     btn->installEventFilter(this);
1268     topLayout->addWidget(btn);
1269 
1270     topLayout->addStretch();
1271 
1272     setFocusProxy(m_gotoRange);
1273 }
1274 
1275 void KateGotoBar::showEvent(QShowEvent *event)
1276 {
1277     Q_UNUSED(event)
1278     // Catch rare cases where the bar is visible while document is edited
1279     connect(m_view->document(), &KTextEditor::Document::textChanged, this, &KateGotoBar::updateData);
1280 }
1281 
1282 void KateGotoBar::closed()
1283 {
1284     disconnect(m_view->document(), &KTextEditor::Document::textChanged, this, &KateGotoBar::updateData);
1285 }
1286 
1287 bool KateGotoBar::eventFilter(QObject *object, QEvent *event)
1288 {
1289     if (object == m_modifiedUp || object == m_modifiedDown) {
1290         if (event->type() != QEvent::Wheel) {
1291             return false;
1292         }
1293 
1294         int delta = static_cast<QWheelEvent *>(event)->angleDelta().y();
1295         // Reset m_wheelDelta when scroll direction change
1296         if (m_wheelDelta != 0 && (m_wheelDelta < 0) != (delta < 0)) {
1297             m_wheelDelta = 0;
1298         }
1299 
1300         m_wheelDelta += delta;
1301 
1302         if (m_wheelDelta >= 120) {
1303             m_wheelDelta = 0;
1304             m_modifiedUp->click();
1305         } else if (m_wheelDelta <= -120) {
1306             m_wheelDelta = 0;
1307             m_modifiedDown->click();
1308         }
1309     }
1310 
1311     return false;
1312 }
1313 
1314 void KateGotoBar::gotoClipboard()
1315 {
1316     static const QRegularExpression rx(QStringLiteral("-?\\d+"));
1317     bool ok = false;
1318     const int lineNo = rx.match(QApplication::clipboard()->text(QClipboard::Selection)).captured().toInt(&ok);
1319     if (!ok) {
1320         return;
1321     }
1322     if (lineNo >= m_gotoRange->minimum() && lineNo <= m_gotoRange->maximum()) {
1323         m_gotoRange->setValue(lineNo);
1324         gotoLine();
1325     } else {
1326         QPointer<KTextEditor::Message> message = new KTextEditor::Message(i18n("No valid line number found in clipboard"));
1327         message->setWordWrap(true);
1328         message->setAutoHide(2000);
1329         message->setPosition(KTextEditor::Message::BottomInView);
1330         message->setView(m_view), m_view->document()->postMessage(message);
1331     }
1332 }
1333 
1334 void KateGotoBar::updateData()
1335 {
1336     int lines = m_view->document()->lines();
1337     m_gotoRange->setMinimum(-lines);
1338     m_gotoRange->setMaximum(lines);
1339     if (!isVisible()) {
1340         m_gotoRange->setValue(m_view->cursorPosition().line() + 1);
1341         m_gotoRange->adjustSize(); // ### does not respect the range :-(
1342     }
1343 
1344     m_gotoRange->selectAll();
1345 }
1346 
1347 void KateGotoBar::keyPressEvent(QKeyEvent *event)
1348 {
1349     int key = event->key();
1350     if (key == Qt::Key_Return || key == Qt::Key_Enter) {
1351         gotoLine();
1352         return;
1353     }
1354     KateViewBarWidget::keyPressEvent(event);
1355 }
1356 
1357 void KateGotoBar::gotoLine()
1358 {
1359     KTextEditor::ViewPrivate *kv = qobject_cast<KTextEditor::ViewPrivate *>(m_view);
1360     if (kv && kv->selection() && !kv->config()->persistentSelection()) {
1361         kv->clearSelection();
1362     }
1363 
1364     int gotoValue = m_gotoRange->value();
1365     if (gotoValue < 0) {
1366         gotoValue += m_view->document()->lines();
1367     } else if (gotoValue > 0) {
1368         gotoValue -= 1;
1369     }
1370 
1371     m_view->setCursorPosition(KTextEditor::Cursor(gotoValue, 0));
1372     m_view->setFocus();
1373     Q_EMIT hideMe();
1374 }
1375 // END KateGotoBar
1376 
1377 // BEGIN KateDictionaryBar
1378 KateDictionaryBar::KateDictionaryBar(KTextEditor::ViewPrivate *view, QWidget *parent)
1379     : KateViewBarWidget(true, parent)
1380     , m_view(view)
1381 {
1382     Q_ASSERT(m_view != nullptr); // this bar widget is pointless w/o a view
1383 
1384     QHBoxLayout *topLayout = new QHBoxLayout(centralWidget());
1385     topLayout->setContentsMargins(0, 0, 0, 0);
1386     // topLayout->setSpacing(spacingHint());
1387     m_dictionaryComboBox = new Sonnet::DictionaryComboBox(centralWidget());
1388     connect(m_dictionaryComboBox, &Sonnet::DictionaryComboBox::dictionaryChanged, this, &KateDictionaryBar::dictionaryChanged);
1389     connect(view->doc(), &KTextEditor::DocumentPrivate::defaultDictionaryChanged, this, &KateDictionaryBar::updateData);
1390     QLabel *label = new QLabel(i18n("Dictionary:"), centralWidget());
1391     label->setBuddy(m_dictionaryComboBox);
1392 
1393     topLayout->addWidget(label);
1394     topLayout->addWidget(m_dictionaryComboBox, 1);
1395     topLayout->setStretchFactor(m_dictionaryComboBox, 0);
1396     topLayout->addStretch();
1397 }
1398 
1399 KateDictionaryBar::~KateDictionaryBar()
1400 {
1401 }
1402 
1403 void KateDictionaryBar::updateData()
1404 {
1405     KTextEditor::DocumentPrivate *document = m_view->doc();
1406     QString dictionary = document->defaultDictionary();
1407     if (dictionary.isEmpty()) {
1408         dictionary = Sonnet::Speller().defaultLanguage();
1409     }
1410     m_dictionaryComboBox->setCurrentByDictionary(dictionary);
1411 }
1412 
1413 void KateDictionaryBar::dictionaryChanged(const QString &dictionary)
1414 {
1415     const KTextEditor::Range selection = m_view->selectionRange();
1416     if (selection.isValid() && !selection.isEmpty()) {
1417         const bool blockmode = m_view->blockSelection();
1418         m_view->doc()->setDictionary(dictionary, selection, blockmode);
1419     } else {
1420         m_view->doc()->setDefaultDictionary(dictionary);
1421     }
1422 }
1423 
1424 // END KateGotoBar
1425 
1426 // BEGIN KateModOnHdPrompt
1427 KateModOnHdPrompt::KateModOnHdPrompt(KTextEditor::DocumentPrivate *doc, KTextEditor::ModificationInterface::ModifiedOnDiskReason modtype, const QString &reason)
1428     : QObject(doc)
1429     , m_doc(doc)
1430     , m_modtype(modtype)
1431     , m_fullDiffPath(QStandardPaths::findExecutable(QStringLiteral("diff")))
1432     , m_proc(nullptr)
1433     , m_diffFile(nullptr)
1434     , m_diffAction(nullptr)
1435 {
1436     m_message = new KTextEditor::Message(reason, KTextEditor::Message::Information);
1437     m_message->setPosition(KTextEditor::Message::AboveView);
1438     m_message->setWordWrap(true);
1439 
1440     // If the file isn't deleted, present a diff button
1441     const bool onDiskDeleted = modtype == KTextEditor::ModificationInterface::OnDiskDeleted;
1442     if (!onDiskDeleted) {
1443         QAction *aAutoReload = new QAction(i18n("Enable Auto Reload"), this);
1444         aAutoReload->setIcon(QIcon::fromTheme(QStringLiteral("view-refresh")));
1445         aAutoReload->setToolTip(i18n("Will never again warn about on disk changes but always reload."));
1446         m_message->addAction(aAutoReload, false);
1447         connect(aAutoReload, &QAction::triggered, this, &KateModOnHdPrompt::autoReloadTriggered);
1448 
1449         if (!m_fullDiffPath.isEmpty()) {
1450             m_diffAction = new QAction(i18n("View &Difference"), this);
1451             m_diffAction->setIcon(QIcon::fromTheme(QStringLiteral("document-multiple")));
1452             m_diffAction->setToolTip(i18n("Shows a diff of the changes"));
1453             m_message->addAction(m_diffAction, false);
1454             connect(m_diffAction, &QAction::triggered, this, &KateModOnHdPrompt::slotDiff);
1455         }
1456 
1457         QAction *aReload = new QAction(i18n("&Reload"), this);
1458         aReload->setIcon(QIcon::fromTheme(QStringLiteral("view-refresh")));
1459         aReload->setToolTip(i18n("Reload the file from disk. Unsaved changes will be lost."));
1460         m_message->addAction(aReload);
1461         connect(aReload, &QAction::triggered, this, &KateModOnHdPrompt::reloadTriggered);
1462     } else {
1463         QAction *closeFile = new QAction(i18nc("@action:button closes the opened file", "&Close File"), this);
1464         closeFile->setIcon(QIcon::fromTheme(QStringLiteral("document-close")));
1465         closeFile->setToolTip(i18n("Close the file, discarding its content."));
1466         m_message->addAction(closeFile, false);
1467         connect(closeFile, &QAction::triggered, this, &KateModOnHdPrompt::closeTriggered);
1468 
1469         QAction *aSaveAs = new QAction(i18n("&Save As..."), this);
1470         aSaveAs->setIcon(QIcon::fromTheme(QStringLiteral("document-save-as")));
1471         aSaveAs->setToolTip(i18n("Lets you select a location and save the file again."));
1472         m_message->addAction(aSaveAs, false);
1473         connect(aSaveAs, &QAction::triggered, this, &KateModOnHdPrompt::saveAsTriggered);
1474     }
1475 
1476     QAction *aIgnore = new QAction(i18n("&Ignore"), this);
1477     aIgnore->setToolTip(i18n("Ignores the changes on disk without any action."));
1478     aIgnore->setIcon(QIcon::fromTheme(QStringLiteral("dialog-cancel")));
1479     m_message->addAction(aIgnore);
1480     connect(aIgnore, &QAction::triggered, this, &KateModOnHdPrompt::ignoreTriggered);
1481 
1482     m_doc->postMessage(m_message);
1483 }
1484 
1485 KateModOnHdPrompt::~KateModOnHdPrompt()
1486 {
1487     delete m_proc;
1488     m_proc = nullptr;
1489     if (m_diffFile) {
1490         m_diffFile->setAutoRemove(true);
1491         delete m_diffFile;
1492         m_diffFile = nullptr;
1493     }
1494     delete m_message;
1495 }
1496 
1497 void KateModOnHdPrompt::slotDiff()
1498 {
1499     if (m_diffFile) {
1500         return;
1501     }
1502 
1503     m_diffFile = new QTemporaryFile(QDir::temp().filePath(QLatin1String("XXXXXX.diff")));
1504     m_diffFile->open();
1505 
1506     // Start a KProcess that creates a diff
1507     m_proc = new KProcess(this);
1508     m_proc->setOutputChannelMode(KProcess::MergedChannels);
1509     *m_proc << m_fullDiffPath << QStringLiteral("-u") << QStringLiteral("-") << m_doc->url().toLocalFile();
1510     connect(m_proc, &KProcess::readyRead, this, &KateModOnHdPrompt::slotDataAvailable);
1511     connect(m_proc, &KProcess::finished, this, &KateModOnHdPrompt::slotPDone);
1512 
1513     // disable the diff button, to hinder the user to run it twice.
1514     m_diffAction->setEnabled(false);
1515 
1516     m_proc->start();
1517 
1518     QTextStream ts(m_proc);
1519     int lastln = m_doc->lines() - 1;
1520     for (int l = 0; l < lastln; ++l) {
1521         ts << m_doc->line(l) << '\n';
1522     }
1523     ts << m_doc->line(lastln);
1524     ts.flush();
1525     m_proc->closeWriteChannel();
1526 }
1527 
1528 void KateModOnHdPrompt::slotDataAvailable()
1529 {
1530     m_diffFile->write(m_proc->readAll());
1531 }
1532 
1533 void KateModOnHdPrompt::slotPDone()
1534 {
1535     m_diffAction->setEnabled(true);
1536 
1537     const QProcess::ExitStatus es = m_proc->exitStatus();
1538     delete m_proc;
1539     m_proc = nullptr;
1540 
1541     if (es != QProcess::NormalExit) {
1542         KMessageBox::error(m_doc->activeView(),
1543                            i18n("The diff command failed. Please make sure that "
1544                                 "diff(1) is installed and in your PATH."),
1545                            i18n("Error Creating Diff"));
1546         delete m_diffFile;
1547         m_diffFile = nullptr;
1548         return;
1549     }
1550 
1551     if (m_diffFile->size() == 0) {
1552         KMessageBox::information(m_doc->activeView(), i18n("The files are identical."), i18n("Diff Output"));
1553         delete m_diffFile;
1554         m_diffFile = nullptr;
1555         return;
1556     }
1557 
1558     m_diffFile->setAutoRemove(false);
1559     QUrl url = QUrl::fromLocalFile(m_diffFile->fileName());
1560     delete m_diffFile;
1561     m_diffFile = nullptr;
1562 
1563     KIO::OpenUrlJob *job = new KIO::OpenUrlJob(url, QStringLiteral("text/x-patch"));
1564     job->setUiDelegate(KIO::createDefaultJobUiDelegate(KJobUiDelegate::AutoHandlingEnabled, m_doc->activeView()));
1565     job->setDeleteTemporaryFile(true); // delete the file, once the client exits
1566     job->start();
1567 }
1568 
1569 // END KateModOnHdPrompt
1570 
1571 #include "moc_katedialogs.cpp"