File indexing completed on 2024-05-05 03:57:55

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