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"