KTextEditor

katedialogs.cpp
1/*
2 This file is part of the KDE libraries
3 SPDX-FileCopyrightText: 2002, 2003 Anders Lund <anders.lund@lund.tdcadsl.dk>
4 SPDX-FileCopyrightText: 2003 Christoph Cullmann <cullmann@kde.org>
5 SPDX-FileCopyrightText: 2001 Joseph Wenninger <jowenn@kde.org>
6 SPDX-FileCopyrightText: 2006 Dominik Haumann <dhdev@gmx.de>
7 SPDX-FileCopyrightText: 2007 Mirko Stocker <me@misto.ch>
8 SPDX-FileCopyrightText: 2009 Michel Ludwig <michel.ludwig@kdemail.net>
9 SPDX-FileCopyrightText: 2009 Erlend Hamberg <ehamberg@gmail.com>
10
11 Based on work of:
12 SPDX-FileCopyrightText: 1999 Jochen Wilhelmy <digisnap@cs.tu-berlin.de>
13
14 SPDX-License-Identifier: LGPL-2.0-only
15*/
16
17// BEGIN Includes
18#include "katedialogs.h"
19
20#include <ktexteditor/message.h>
21#include <ktexteditor_version.h>
22
23#include "kateautoindent.h"
24#include "katebuffer.h"
25#include "kateconfig.h"
26#include "katedocument.h"
27#include "kateglobal.h"
28#include "katemodeconfigpage.h"
29#include "kateview.h"
30#include "spellcheck/spellcheck.h"
31
32// auto generated ui files
33#include "ui_bordersappearanceconfigwidget.h"
34#include "ui_completionconfigtab.h"
35#include "ui_editconfigwidget.h"
36#include "ui_indentationconfigwidget.h"
37#include "ui_navigationconfigwidget.h"
38#include "ui_opensaveconfigadvwidget.h"
39#include "ui_opensaveconfigwidget.h"
40#include "ui_spellcheckconfigwidget.h"
41#include "ui_statusbarconfigwidget.h"
42#include "ui_textareaappearanceconfigwidget.h"
43
44#include <KIO/Job>
45#include <KIO/JobUiDelegateFactory>
46#include <KIO/OpenUrlJob>
47
48#include "kateabstractinputmodefactory.h"
49#include "katepartdebug.h"
50#include <KActionCollection>
51#include <KCharsets>
52#include <KColorCombo>
53#include <KEncodingProber>
54#include <KFontRequester>
55#include <KLocalization>
56#include <KMessageBox>
57#include <KProcess>
58#include <KSeparator>
59
60#include <QCheckBox>
61#include <QClipboard>
62#include <QComboBox>
63#include <QDomDocument>
64#include <QFile>
65#include <QFileDialog>
66#include <QFontDatabase>
67#include <QGroupBox>
68#include <QKeyEvent>
69#include <QLabel>
70#include <QLayout>
71#include <QPainter>
72#include <QRadioButton>
73#include <QSettings>
74#include <QSlider>
75#include <QSpinBox>
76#include <QStringList>
77#include <QTabBar>
78#include <QTemporaryFile>
79#include <QTextStream>
80#include <QToolButton>
81#include <QWhatsThis>
82
83// END
84
85// BEGIN KateIndentConfigTab
86KateIndentConfigTab::KateIndentConfigTab(QWidget *parent)
87 : KateConfigPage(parent)
88{
89 // This will let us have more separation between this page and
90 // the QTabWidget edge (ereslibre)
91 QVBoxLayout *layout = new QVBoxLayout(this);
92 QWidget *newWidget = new QWidget(this);
93
94 ui = new Ui::IndentationConfigWidget();
95 ui->setupUi(newWidget);
96
97 ui->cmbMode->addItems(KateAutoIndent::listModes());
98
99 // FIXME Give ui->label a more descriptive name, it's these "More..." info about tab key action
100 ui->label->setTextInteractionFlags(Qt::LinksAccessibleByMouse | Qt::LinksAccessibleByKeyboard);
101 connect(ui->label, &QLabel::linkActivated, this, &KateIndentConfigTab::showWhatsThis);
102
103 // "What's This?" help can be found in the ui file
104
105 reload();
106
107 observeChanges(ui->chkAutoDetectIndent);
108 observeChanges(ui->chkBackspaceUnindents);
109 observeChanges(ui->chkIndentPaste);
110 observeChanges(ui->chkKeepExtraSpaces);
111 observeChanges(ui->cmbMode);
112 observeChanges(ui->rbIndentMixed);
113 observeChanges(ui->rbIndentWithSpaces);
114 observeChanges(ui->rbIndentWithTabs);
115 connect(ui->rbIndentWithTabs, &QAbstractButton::toggled, ui->sbIndentWidth, &QWidget::setDisabled);
116 connect(ui->rbIndentWithTabs, &QAbstractButton::toggled, this, &KateIndentConfigTab::slotChanged); // FIXME See slot below
117 observeChanges(ui->rbTabAdvances);
118 observeChanges(ui->rbTabIndents);
119 observeChanges(ui->rbTabSmart);
120 observeChanges(ui->sbIndentWidth);
121 observeChanges(ui->sbTabWidth);
122
123 layout->addWidget(newWidget);
124}
125
126KateIndentConfigTab::~KateIndentConfigTab()
127{
128 delete ui;
129}
130
131void KateIndentConfigTab::slotChanged()
132{
133 // FIXME Make it working without this quirk
134 // When the value is not copied it will silently set back to "Tabs & Spaces"
135 if (ui->rbIndentWithTabs->isChecked()) {
136 ui->sbIndentWidth->setValue(ui->sbTabWidth->value());
137 }
138}
139
140// NOTE Should we have more use of such info stuff, consider to make it part
141// of KateConfigPage and add a similar function like observeChanges(..)
142void KateIndentConfigTab::showWhatsThis(const QString &text)
143{
145}
146
147void KateIndentConfigTab::apply()
148{
149 // nothing changed, no need to apply stuff
150 if (!hasChanged()) {
151 return;
152 }
153 m_changed = false;
154
155 KateDocumentConfig::global()->configStart();
156
157 KateDocumentConfig::global()->setBackspaceIndents(ui->chkBackspaceUnindents->isChecked());
158 KateDocumentConfig::global()->setIndentPastedText(ui->chkIndentPaste->isChecked());
159 KateDocumentConfig::global()->setIndentationMode(KateAutoIndent::modeName(ui->cmbMode->currentIndex()));
160 KateDocumentConfig::global()->setIndentationWidth(ui->sbIndentWidth->value());
161 KateDocumentConfig::global()->setKeepExtraSpaces(ui->chkKeepExtraSpaces->isChecked());
162 KateDocumentConfig::global()->setReplaceTabsDyn(ui->rbIndentWithSpaces->isChecked());
163 KateDocumentConfig::global()->setTabWidth(ui->sbTabWidth->value());
164 KateDocumentConfig::global()->setAutoDetectIndent(ui->chkAutoDetectIndent->isChecked());
165
166 if (ui->rbTabAdvances->isChecked()) {
167 KateDocumentConfig::global()->setTabHandling(KateDocumentConfig::tabInsertsTab);
168 } else if (ui->rbTabIndents->isChecked()) {
169 KateDocumentConfig::global()->setTabHandling(KateDocumentConfig::tabIndents);
170 } else {
171 KateDocumentConfig::global()->setTabHandling(KateDocumentConfig::tabSmart);
172 }
173
174 KateDocumentConfig::global()->configEnd();
175}
176
177void KateIndentConfigTab::reload()
178{
179 ui->chkBackspaceUnindents->setChecked(KateDocumentConfig::global()->backspaceIndents());
180 ui->chkIndentPaste->setChecked(KateDocumentConfig::global()->indentPastedText());
181 ui->chkKeepExtraSpaces->setChecked(KateDocumentConfig::global()->keepExtraSpaces());
182
183 ui->chkAutoDetectIndent->setChecked(KateDocumentConfig::global()->autoDetectIndent());
184 KLocalization::setupSpinBoxFormatString(ui->sbIndentWidth, ki18np("%v character", "%v characters"));
185 ui->sbIndentWidth->setValue(KateDocumentConfig::global()->indentationWidth());
186 KLocalization::setupSpinBoxFormatString(ui->sbTabWidth, ki18np("%v character", "%v characters"));
187 ui->sbTabWidth->setValue(KateDocumentConfig::global()->tabWidth());
188
189 ui->rbTabAdvances->setChecked(KateDocumentConfig::global()->tabHandling() == KateDocumentConfig::tabInsertsTab);
190 ui->rbTabIndents->setChecked(KateDocumentConfig::global()->tabHandling() == KateDocumentConfig::tabIndents);
191 ui->rbTabSmart->setChecked(KateDocumentConfig::global()->tabHandling() == KateDocumentConfig::tabSmart);
192
193 ui->cmbMode->setCurrentIndex(KateAutoIndent::modeNumber(KateDocumentConfig::global()->indentationMode()));
194
195 if (KateDocumentConfig::global()->replaceTabsDyn()) {
196 ui->rbIndentWithSpaces->setChecked(true);
197 } else {
198 if (KateDocumentConfig::global()->indentationWidth() == KateDocumentConfig::global()->tabWidth()) {
199 ui->rbIndentWithTabs->setChecked(true);
200 } else {
201 ui->rbIndentMixed->setChecked(true);
202 }
203 }
204
205 ui->sbIndentWidth->setEnabled(!ui->rbIndentWithTabs->isChecked());
206}
207
208QString KateIndentConfigTab::name() const
209{
210 return i18n("Indentation");
211}
212
213// END KateIndentConfigTab
214
215// BEGIN KateCompletionConfigTab
216KateCompletionConfigTab::KateCompletionConfigTab(QWidget *parent)
217 : KateConfigPage(parent)
218{
219 // This will let us have more separation between this page and
220 // the QTabWidget edge (ereslibre)
221 QVBoxLayout *layout = new QVBoxLayout(this);
222 QWidget *newWidget = new QWidget(this);
223
224 ui = new Ui::CompletionConfigTab();
225 ui->setupUi(newWidget);
226
227 // "What's This?" help can be found in the ui file
228
229 reload();
230
231 observeChanges(ui->chkAutoCompletionEnabled);
232 observeChanges(ui->chkAutoSelectFirstEntry);
233 observeChanges(ui->chkTabCompletion);
234 observeChanges(ui->chkEnterCompletion);
235 observeChanges(ui->gbKeywordCompletion);
236 observeChanges(ui->gbShowDoc);
237 observeChanges(ui->gbWordCompletion);
238 observeChanges(ui->minimalWordLength);
239 observeChanges(ui->removeTail);
240
241 layout->addWidget(newWidget);
242}
243
244KateCompletionConfigTab::~KateCompletionConfigTab()
245{
246 delete ui;
247}
248
249void KateCompletionConfigTab::showWhatsThis(const QString &text) // NOTE Not used atm, remove? See also KateIndentConfigTab::showWhatsThis
250{
252}
253
254void KateCompletionConfigTab::apply()
255{
256 // nothing changed, no need to apply stuff
257 if (!hasChanged()) {
258 return;
259 }
260 m_changed = false;
261
262 KateViewConfig::global()->configStart();
263
264 KateViewConfig::global()->setValue(KateViewConfig::AutomaticCompletionInvocation, ui->chkAutoCompletionEnabled->isChecked());
265 KateViewConfig::global()->setValue(KateViewConfig::AutomaticCompletionPreselectFirst, ui->chkAutoSelectFirstEntry->isChecked());
266 KateViewConfig::global()->setValue(KateViewConfig::TabCompletion, ui->chkTabCompletion->isChecked());
267 KateViewConfig::global()->setValue(KateViewConfig::EnterToInsertCompletion, ui->chkEnterCompletion->isChecked());
268 KateViewConfig::global()->setValue(KateViewConfig::KeywordCompletion, ui->gbKeywordCompletion->isChecked());
269 KateViewConfig::global()->setValue(KateViewConfig::WordCompletion, ui->gbWordCompletion->isChecked());
270 KateViewConfig::global()->setValue(KateViewConfig::WordCompletionMinimalWordLength, ui->minimalWordLength->value());
271 KateViewConfig::global()->setValue(KateViewConfig::WordCompletionRemoveTail, ui->removeTail->isChecked());
272 KateViewConfig::global()->setValue(KateViewConfig::ShowDocWithCompletion, ui->gbShowDoc->isChecked());
273
274 KateViewConfig::global()->configEnd();
275}
276
277void KateCompletionConfigTab::reload()
278{
279 ui->chkAutoCompletionEnabled->setChecked(KateViewConfig::global()->automaticCompletionInvocation());
280 ui->chkAutoSelectFirstEntry->setChecked(KateViewConfig::global()->automaticCompletionPreselectFirst());
281 ui->chkTabCompletion->setChecked(KateViewConfig::global()->tabCompletion());
282 ui->chkEnterCompletion->setChecked(KateViewConfig::global()->value(KateViewConfig::EnterToInsertCompletion).toBool());
283
284 ui->gbKeywordCompletion->setChecked(KateViewConfig::global()->keywordCompletion());
285 ui->gbWordCompletion->setChecked(KateViewConfig::global()->wordCompletion());
286 ui->gbShowDoc->setChecked(KateViewConfig::global()->showDocWithCompletion());
287
288 ui->minimalWordLength->setValue(KateViewConfig::global()->wordCompletionMinimalWordLength());
289 ui->removeTail->setChecked(KateViewConfig::global()->wordCompletionRemoveTail());
290}
291
292QString KateCompletionConfigTab::name() const
293{
294 return i18n("Auto Completion");
295}
296
297// END KateCompletionConfigTab
298
299// BEGIN KateSpellCheckConfigTab
300KateSpellCheckConfigTab::KateSpellCheckConfigTab(QWidget *parent)
301 : KateConfigPage(parent)
302{
303 // This will let us have more separation between this page and
304 // the QTabWidget edge (ereslibre)
305 QVBoxLayout *layout = new QVBoxLayout(this);
306 QWidget *newWidget = new QWidget(this);
307
308 ui = new Ui::SpellCheckConfigWidget();
309 ui->setupUi(newWidget);
310
311 // "What's This?" help can be found in the ui file
312
313 reload();
314
315 m_sonnetConfigWidget = new Sonnet::ConfigWidget(this);
316 connect(m_sonnetConfigWidget, &Sonnet::ConfigWidget::configChanged, this, &KateSpellCheckConfigTab::slotChanged);
317 layout->addWidget(m_sonnetConfigWidget);
318
319 layout->addWidget(newWidget);
320}
321
322KateSpellCheckConfigTab::~KateSpellCheckConfigTab()
323{
324 delete ui;
325}
326
327void KateSpellCheckConfigTab::showWhatsThis(const QString &text) // NOTE Not used atm, remove? See also KateIndentConfigTab::showWhatsThis
328{
330}
331
332void KateSpellCheckConfigTab::apply()
333{
334 if (!hasChanged()) {
335 // nothing changed, no need to apply stuff
336 return;
337 }
338 m_changed = false;
339
340 // WARNING: this is slightly hackish, but it's currently the only way to
341 // do it, see also the KTextEdit class
342 KateDocumentConfig::global()->configStart();
343 m_sonnetConfigWidget->save();
344 QSettings settings(QStringLiteral("KDE"), QStringLiteral("Sonnet"));
345 KateDocumentConfig::global()->setOnTheFlySpellCheck(settings.value(QStringLiteral("checkerEnabledByDefault"), false).toBool());
346 KateDocumentConfig::global()->configEnd();
347
348 const auto docs = KTextEditor::EditorPrivate::self()->documents();
349 for (KTextEditor::Document *doc : docs) {
350 static_cast<KTextEditor::DocumentPrivate *>(doc)->refreshOnTheFlyCheck();
351 }
352}
353
354void KateSpellCheckConfigTab::reload()
355{
356 // does nothing
357}
358
359QString KateSpellCheckConfigTab::name() const
360{
361 return i18n("Spellcheck");
362}
363
364// END KateSpellCheckConfigTab
365
366// BEGIN KateNavigationConfigTab
367KateNavigationConfigTab::KateNavigationConfigTab(QWidget *parent)
368 : KateConfigPage(parent)
369{
370 // This will let us having more separation between this page and
371 // the QTabWidget edge (ereslibre)
372 QVBoxLayout *layout = new QVBoxLayout(this);
373 QWidget *newWidget = new QWidget(this);
374
375 ui = new Ui::NavigationConfigWidget();
376 ui->setupUi(newWidget);
377
378 initMulticursorModifierComboBox();
379
380 // "What's This?" help can be found in the ui file
381
382 reload();
383
384 observeChanges(ui->cbTextSelectionMode);
385 observeChanges(ui->chkBackspaceRemoveComposed);
386 observeChanges(ui->chkPagingMovesCursor);
387 observeChanges(ui->chkScrollPastEnd);
388 observeChanges(ui->chkSmartHome);
389 observeChanges(ui->sbAutoCenterCursor);
390 observeChanges(ui->chkCamelCursor);
391 observeChanges(ui->cmbMultiCursorModifier);
392
393 layout->addWidget(newWidget);
394}
395
396KateNavigationConfigTab::~KateNavigationConfigTab()
397{
398 delete ui;
399}
400
401void KateNavigationConfigTab::initMulticursorModifierComboBox()
402{
403 // On macOS, the ControlModifier value corresponds to the Command keys on the
404 // keyboard, and the MetaModifier value corresponds to the Control keys.
405 auto *c = ui->cmbMultiCursorModifier;
406
407#ifndef Q_OS_DARWIN
408 c->insertItem(0, i18n("Alt"), (int)Qt::ALT);
409 c->insertItem(1, i18n("Ctrl"), (int)Qt::CTRL);
410 c->insertItem(2, i18n("Meta"), (int)Qt::META);
411 c->insertItem(3, i18n("Ctrl + Alt"), (int)(Qt::CTRL | Qt::ALT));
412 c->insertItem(4, i18n("Meta + Alt"), (int)(Qt::META | Qt::ALT));
413 c->insertItem(5, i18n("Ctrl + Meta"), (int)(Qt::CTRL | Qt::META));
414#else
415 c->insertItem(0, i18n("Alt"), (int)Qt::ALT);
416 c->insertItem(1, i18n("Cmd"), (int)Qt::CTRL);
417 c->insertItem(2, i18n("Ctrl"), (int)Qt::META);
418 c->insertItem(3, i18n("Cmd + Alt"), (int)(Qt::CTRL | Qt::ALT));
419 c->insertItem(4, i18n("Ctrl + Alt"), (int)(Qt::META | Qt::ALT));
420 c->insertItem(5, i18n("Cmd + Ctrl"), (int)(Qt::CTRL | Qt::META));
421#endif
422}
423
424void KateNavigationConfigTab::apply()
425{
426 // nothing changed, no need to apply stuff
427 if (!hasChanged()) {
428 return;
429 }
430 m_changed = false;
431
432 KateViewConfig::global()->configStart();
433 KateDocumentConfig::global()->configStart();
434
435 KateDocumentConfig::global()->setPageUpDownMovesCursor(ui->chkPagingMovesCursor->isChecked());
436 KateDocumentConfig::global()->setSmartHome(ui->chkSmartHome->isChecked());
437 KateDocumentConfig::global()->setCamelCursor(ui->chkCamelCursor->isChecked());
438
439 KateViewConfig::global()->setValue(KateViewConfig::AutoCenterLines, ui->sbAutoCenterCursor->value());
440 KateViewConfig::global()->setValue(KateViewConfig::BackspaceRemoveComposedCharacters, ui->chkBackspaceRemoveComposed->isChecked());
441 KateViewConfig::global()->setValue(KateViewConfig::PersistentSelection, ui->cbTextSelectionMode->currentIndex() == 1);
442 KateViewConfig::global()->setValue(KateViewConfig::ScrollPastEnd, ui->chkScrollPastEnd->isChecked());
443
444 const int modifers = ui->cmbMultiCursorModifier->currentData().toInt();
445 KateViewConfig::global()->setMultiCursorModifiers(Qt::KeyboardModifiers(modifers));
446
447 KateDocumentConfig::global()->configEnd();
448 KateViewConfig::global()->configEnd();
449}
450
451void KateNavigationConfigTab::reload()
452{
453 ui->cbTextSelectionMode->setCurrentIndex(KateViewConfig::global()->persistentSelection() ? 1 : 0);
454
455 ui->chkBackspaceRemoveComposed->setChecked(KateViewConfig::global()->backspaceRemoveComposed());
456 ui->chkPagingMovesCursor->setChecked(KateDocumentConfig::global()->pageUpDownMovesCursor());
457 ui->chkScrollPastEnd->setChecked(KateViewConfig::global()->scrollPastEnd());
458 ui->chkSmartHome->setChecked(KateDocumentConfig::global()->smartHome());
459 ui->chkCamelCursor->setChecked(KateDocumentConfig::global()->camelCursor());
460
461 ui->sbAutoCenterCursor->setValue(KateViewConfig::global()->autoCenterLines());
462
463 const int mods = KateViewConfig::global()->multiCursorModifiers();
464 const auto count = ui->cmbMultiCursorModifier->count();
465 for (int i = 0; i < count; ++i) {
466 int idxMods = ui->cmbMultiCursorModifier->itemData(i).toInt();
467 if (idxMods == mods) {
468 ui->cmbMultiCursorModifier->setCurrentIndex(i);
469 break;
470 }
471 }
472}
473
474QString KateNavigationConfigTab::name() const
475{
476 return i18n("Text Navigation");
477}
478
479// END KateNavigationConfigTab
480
481// BEGIN KateEditGeneralConfigTab
482KateEditGeneralConfigTab::KateEditGeneralConfigTab(QWidget *parent)
483 : KateConfigPage(parent)
484{
485 QVBoxLayout *layout = new QVBoxLayout(this);
486 QWidget *newWidget = new QWidget(this);
487 ui = new Ui::EditConfigWidget();
488 ui->setupUi(newWidget);
489
490 for (const auto &fact : KTextEditor::EditorPrivate::self()->inputModeFactories()) {
491 ui->cmbInputMode->addItem(fact->name(), static_cast<int>(fact->inputMode()));
492 }
493
494 // "What's This?" Help is in the ui-files
495
496 reload();
497
498 observeChanges(ui->chkAutoBrackets);
499 observeChanges(ui->chkMousePasteAtCursorPosition);
500 observeChanges(ui->chkShowStaticWordWrapMarker);
501 observeChanges(ui->chkTextDragAndDrop);
502 observeChanges(ui->chkSmartCopyCut);
503 observeChanges(ui->sbClipboardHistoryEntries);
504 observeChanges(ui->chkStaticWordWrap);
505 observeChanges(ui->cmbEncloseSelection);
507 connect(ui->cmbEncloseSelection->lineEdit(), &QLineEdit::editingFinished, [this] {
508 const int index = ui->cmbEncloseSelection->currentIndex();
509 const QString text = ui->cmbEncloseSelection->currentText();
510 // Text removed? Remove item, but don't remove default data!
511 if (index >= UserData && text.isEmpty()) {
512 ui->cmbEncloseSelection->removeItem(index);
513 slotChanged();
514
515 // Not already there? Add new item! For whatever reason it isn't done automatically
516 } else if (ui->cmbEncloseSelection->findText(text) < 0) {
517 ui->cmbEncloseSelection->addItem(text);
518 slotChanged();
519 }
520 ui->cmbEncloseSelection->setCurrentIndex(ui->cmbEncloseSelection->findText(text));
521 });
522 observeChanges(ui->cmbInputMode);
523 observeChanges(ui->sbWordWrap);
524 observeChanges(ui->chkAccessibility);
525
526 layout->addWidget(newWidget);
527}
528
529KateEditGeneralConfigTab::~KateEditGeneralConfigTab()
530{
531 delete ui;
532}
533
534void KateEditGeneralConfigTab::apply()
535{
536 // nothing changed, no need to apply stuff
537 if (!hasChanged()) {
538 return;
539 }
540 m_changed = false;
541
542 KateViewConfig::global()->configStart();
543 KateDocumentConfig::global()->configStart();
544
545 KateDocumentConfig::global()->setWordWrap(ui->chkStaticWordWrap->isChecked());
546 KateDocumentConfig::global()->setWordWrapAt(ui->sbWordWrap->value());
547
548 KateRendererConfig::global()->setWordWrapMarker(ui->chkShowStaticWordWrapMarker->isChecked());
549
550 KateViewConfig::global()->setValue(KateViewConfig::AutoBrackets, ui->chkAutoBrackets->isChecked());
551 KateViewConfig::global()->setValue(KateViewConfig::CharsToEncloseSelection, ui->cmbEncloseSelection->currentText());
552 QStringList userLetters;
553 for (int i = UserData; i < ui->cmbEncloseSelection->count(); ++i) {
554 userLetters.append(ui->cmbEncloseSelection->itemText(i));
555 }
556 KateViewConfig::global()->setValue(KateViewConfig::UserSetsOfCharsToEncloseSelection, userLetters);
557 KateViewConfig::global()->setValue(KateViewConfig::InputMode, ui->cmbInputMode->currentData().toInt());
558 KateViewConfig::global()->setValue(KateViewConfig::MousePasteAtCursorPosition, ui->chkMousePasteAtCursorPosition->isChecked());
559 KateViewConfig::global()->setValue(KateViewConfig::TextDragAndDrop, ui->chkTextDragAndDrop->isChecked());
560 KateViewConfig::global()->setValue(KateViewConfig::SmartCopyCut, ui->chkSmartCopyCut->isChecked());
561 KateViewConfig::global()->setValue(KateViewConfig::ClipboardHistoryEntries, ui->sbClipboardHistoryEntries->value());
562 KateViewConfig::global()->setValue(KateViewConfig::EnableAccessibility, ui->chkAccessibility->isChecked());
563
564 KateDocumentConfig::global()->configEnd();
565 KateViewConfig::global()->configEnd();
566}
567
568void KateEditGeneralConfigTab::reload()
569{
570 ui->chkAutoBrackets->setChecked(KateViewConfig::global()->autoBrackets());
571 ui->chkMousePasteAtCursorPosition->setChecked(KateViewConfig::global()->mousePasteAtCursorPosition());
572 ui->chkShowStaticWordWrapMarker->setChecked(KateRendererConfig::global()->wordWrapMarker());
573 ui->chkTextDragAndDrop->setChecked(KateViewConfig::global()->textDragAndDrop());
574 ui->chkSmartCopyCut->setChecked(KateViewConfig::global()->smartCopyCut());
575 ui->chkStaticWordWrap->setChecked(KateDocumentConfig::global()->wordWrap());
576 ui->sbClipboardHistoryEntries->setValue(KateViewConfig::global()->clipboardHistoryEntries());
577
578 KLocalization::setupSpinBoxFormatString(ui->sbWordWrap, ki18ncp("Wrap words at (value is at 20 or larger)", "%v character", "%v characters"));
579 ui->sbWordWrap->setValue(KateDocumentConfig::global()->wordWrapAt());
580
581 ui->cmbEncloseSelection->clear();
582 ui->cmbEncloseSelection->lineEdit()->setClearButtonEnabled(true);
583 ui->cmbEncloseSelection->lineEdit()->setPlaceholderText(i18n("Feature is not active"));
584 ui->cmbEncloseSelection->addItem(QString(), None);
585 ui->cmbEncloseSelection->setItemData(0, i18n("Disable Feature"), Qt::ToolTipRole);
586 ui->cmbEncloseSelection->addItem(QStringLiteral("`*_~"), MarkDown);
587 ui->cmbEncloseSelection->setItemData(1, i18n("May be handy with Markdown"), Qt::ToolTipRole);
588 ui->cmbEncloseSelection->addItem(QStringLiteral("<>(){}[]'\""), MirrorChar);
589 ui->cmbEncloseSelection->setItemData(2, i18n("Mirror characters, similar but not exactly like auto brackets"), Qt::ToolTipRole);
590 ui->cmbEncloseSelection->addItem(QStringLiteral("´`_.:|#@~*!?$%/=,;-+^°§&"), NonLetters);
591 ui->cmbEncloseSelection->setItemData(3, i18n("Non letter character"), Qt::ToolTipRole);
592 const QStringList userLetters = KateViewConfig::global()->value(KateViewConfig::UserSetsOfCharsToEncloseSelection).toStringList();
593 for (int i = 0; i < userLetters.size(); ++i) {
594 ui->cmbEncloseSelection->addItem(userLetters.at(i), UserData + i);
595 }
596 ui->cmbEncloseSelection->setCurrentIndex(ui->cmbEncloseSelection->findText(KateViewConfig::global()->charsToEncloseSelection()));
597
598 const int id = static_cast<int>(KateViewConfig::global()->inputMode());
599 ui->cmbInputMode->setCurrentIndex(ui->cmbInputMode->findData(id));
600 ui->chkAccessibility->setChecked(KateViewConfig::global()->value(KateViewConfig::EnableAccessibility).toBool());
601}
602
603QString KateEditGeneralConfigTab::name() const
604{
605 return i18n("General");
606}
607
608// END KateEditGeneralConfigTab
609
610// BEGIN KateEditConfigTab
611KateEditConfigTab::KateEditConfigTab(QWidget *parent)
612 : KateConfigPage(parent)
613 , editConfigTab(new KateEditGeneralConfigTab(this))
614 , navigationConfigTab(new KateNavigationConfigTab(this))
615 , indentConfigTab(new KateIndentConfigTab(this))
616 , completionConfigTab(new KateCompletionConfigTab(this))
617 , spellCheckConfigTab(new KateSpellCheckConfigTab(this))
618{
619 QVBoxLayout *layout = new QVBoxLayout(this);
620 layout->setContentsMargins(0, 0, 0, 0);
621 QTabWidget *tabWidget = new QTabWidget(this);
622 tabWidget->setDocumentMode(true);
623
624 // add all tabs
625 tabWidget->insertTab(0, editConfigTab, editConfigTab->name());
626 tabWidget->insertTab(1, navigationConfigTab, navigationConfigTab->name());
627 tabWidget->insertTab(2, indentConfigTab, indentConfigTab->name());
628 tabWidget->insertTab(3, completionConfigTab, completionConfigTab->name());
629 tabWidget->insertTab(4, spellCheckConfigTab, spellCheckConfigTab->name());
630
631 observeChanges(editConfigTab);
632 observeChanges(navigationConfigTab);
633 observeChanges(indentConfigTab);
634 observeChanges(completionConfigTab);
635 observeChanges(spellCheckConfigTab);
636
637 int i = tabWidget->count();
638 for (const auto &factory : KTextEditor::EditorPrivate::self()->inputModeFactories()) {
639 KateConfigPage *tab = factory->createConfigPage(this);
640 if (tab) {
641 m_inputModeConfigTabs.push_back(tab);
642 tabWidget->insertTab(i, tab, tab->name());
643 observeChanges(tab);
644 i++;
645 }
646 }
647
648 layout->addWidget(tabWidget);
649}
650
651KateEditConfigTab::~KateEditConfigTab()
652{
653 qDeleteAll(m_inputModeConfigTabs);
654}
655
656void KateEditConfigTab::apply()
657{
658 // try to update the rest of tabs
659 editConfigTab->apply();
660 navigationConfigTab->apply();
661 indentConfigTab->apply();
662 completionConfigTab->apply();
663 spellCheckConfigTab->apply();
664 for (KateConfigPage *tab : m_inputModeConfigTabs) {
665 tab->apply();
666 }
667}
668
669void KateEditConfigTab::reload()
670{
671 editConfigTab->reload();
672 navigationConfigTab->reload();
673 indentConfigTab->reload();
674 completionConfigTab->reload();
675 spellCheckConfigTab->reload();
676 for (KateConfigPage *tab : m_inputModeConfigTabs) {
677 tab->reload();
678 }
679}
680
681void KateEditConfigTab::reset()
682{
683 editConfigTab->reset();
684 navigationConfigTab->reset();
685 indentConfigTab->reset();
686 completionConfigTab->reset();
687 spellCheckConfigTab->reset();
688 for (KateConfigPage *tab : m_inputModeConfigTabs) {
689 tab->reset();
690 }
691}
692
693void KateEditConfigTab::defaults()
694{
695 editConfigTab->defaults();
696 navigationConfigTab->defaults();
697 indentConfigTab->defaults();
698 completionConfigTab->defaults();
699 spellCheckConfigTab->defaults();
700 for (KateConfigPage *tab : m_inputModeConfigTabs) {
701 tab->defaults();
702 }
703}
704
705QString KateEditConfigTab::name() const
706{
707 return i18n("Editing");
708}
709
710QString KateEditConfigTab::fullName() const
711{
712 return i18n("Editing Options");
713}
714
715QIcon KateEditConfigTab::icon() const
716{
717 return QIcon::fromTheme(QStringLiteral("accessories-text-editor"));
718}
719
720// END KateEditConfigTab
721
722// BEGIN KateViewDefaultsConfig
723KateViewDefaultsConfig::KateViewDefaultsConfig(QWidget *parent)
724 : KateConfigPage(parent)
725 , textareaUi(new Ui::TextareaAppearanceConfigWidget())
726 , bordersUi(new Ui::BordersAppearanceConfigWidget())
727 , statusBarUi(new Ui::StatusbarConfigWidget())
728{
729 QLayout *layout = new QVBoxLayout(this);
730 QTabWidget *tabWidget = new QTabWidget(this);
731 tabWidget->setDocumentMode(true);
732 layout->addWidget(tabWidget);
733 layout->setContentsMargins(0, 0, 0, 0);
734
735 QWidget *textareaTab = new QWidget(tabWidget);
736 textareaUi->setupUi(textareaTab);
737 tabWidget->addTab(textareaTab, i18n("General"));
738
739 QWidget *bordersTab = new QWidget(tabWidget);
740 bordersUi->setupUi(bordersTab);
741 tabWidget->addTab(bordersTab, i18n("Borders"));
742
743 QWidget *statusbarTab = new QWidget(tabWidget);
744 statusBarUi->setupUi(statusbarTab);
745 tabWidget->addTab(statusbarTab, i18n("Statusbar"));
746
747 textareaUi->cmbDynamicWordWrapIndicator->addItem(i18n("Off"));
748 textareaUi->cmbDynamicWordWrapIndicator->addItem(i18n("Follow Line Numbers"));
749 textareaUi->cmbDynamicWordWrapIndicator->addItem(i18n("Always On"));
750
751 // "What's This?" help is in the ui-file
752
753 reload();
754
755 observeChanges(textareaUi->kfontrequester);
756
757 observeChanges(textareaUi->chkAnimateBracketMatching);
758 observeChanges(textareaUi->chkDynWrapAnywhere);
759 observeChanges(textareaUi->chkDynWrapAtStaticMarker);
760 observeChanges(textareaUi->chkFoldFirstLine);
761 observeChanges(textareaUi->chkShowBracketMatchPreview);
762 observeChanges(textareaUi->chkShowIndentationLines);
763 observeChanges(textareaUi->chkShowLineCount);
764 observeChanges(textareaUi->chkShowTabs);
765 observeChanges(textareaUi->chkShowWholeBracketExpression);
766 observeChanges(textareaUi->chkShowWordCount);
767 observeChanges(textareaUi->cmbDynamicWordWrapIndicator);
768 observeChanges(textareaUi->cbxWordWrap);
769 observeChanges(textareaUi->spbLineHeightMultiplier);
770 auto a = [ui = textareaUi, cbx = textareaUi->cbxWordWrap]() {
771 ui->chkDynWrapAtStaticMarker->setEnabled(cbx->isChecked());
772 ui->chkDynWrapAnywhere->setEnabled(cbx->isChecked());
773 ui->cmbDynamicWordWrapIndicator->setEnabled(cbx->isChecked());
774 ui->sbDynamicWordWrapDepth->setEnabled(cbx->isChecked());
775 };
776#if QT_VERSION < QT_VERSION_CHECK(6, 7, 0)
777 connect(textareaUi->cbxWordWrap, &QCheckBox::stateChanged, this, a);
778#else
779 connect(textareaUi->cbxWordWrap, &QCheckBox::checkStateChanged, this, a);
780#endif
781 a();
782 auto b = [cbx = textareaUi->cbxIndentWrappedLines, sb = textareaUi->sbDynamicWordWrapDepth]() {
783 sb->setEnabled(cbx->isChecked());
784 };
785 b();
786#if QT_VERSION < QT_VERSION_CHECK(6, 7, 0)
787 connect(textareaUi->cbxIndentWrappedLines, &QCheckBox::stateChanged, this, b);
788#else
789 connect(textareaUi->cbxIndentWrappedLines, &QCheckBox::checkStateChanged, this, b);
790#endif
791 observeChanges(textareaUi->cbxIndentWrappedLines);
792 observeChanges(textareaUi->sbDynamicWordWrapDepth);
793 observeChanges(textareaUi->sliSetMarkerSize);
794 observeChanges(textareaUi->spacesComboBox);
795
796 observeChanges(bordersUi->chkIconBorder);
797 observeChanges(bordersUi->chkLineNumbers);
798 observeChanges(bordersUi->chkScrollbarMarks);
799 observeChanges(bordersUi->chkScrollbarMiniMap);
800 observeChanges(bordersUi->chkScrollbarMiniMapAll);
801 bordersUi->chkScrollbarMiniMapAll->hide(); // this is temporary until the feature is done
802 observeChanges(bordersUi->chkScrollbarPreview);
803 observeChanges(bordersUi->chkShowFoldingMarkers);
804 observeChanges(bordersUi->chkShowFoldingPreview);
805 observeChanges(bordersUi->chkShowLineModification);
806 observeChanges(bordersUi->cmbShowScrollbars);
807 observeChanges(bordersUi->rbSortBookmarksByCreation);
808 observeChanges(bordersUi->rbSortBookmarksByPosition);
809 observeChanges(bordersUi->spBoxMiniMapWidth);
810 observeChanges(bordersUi->cmbFoldingArrowVisiblity);
811
812 // statusBarUi
813 observeChanges(statusBarUi->cbShowActiveDictionary);
814 observeChanges(statusBarUi->cbShowHighlightingMode);
815 observeChanges(statusBarUi->cbShowInputMode);
816 observeChanges(statusBarUi->cbShowLineColumn);
817 observeChanges(statusBarUi->cbShowTabSetting);
818 observeChanges(statusBarUi->cbShowEncoding);
819 observeChanges(statusBarUi->cbShowEOL);
820}
821
822KateViewDefaultsConfig::~KateViewDefaultsConfig()
823{
824 delete bordersUi;
825 delete textareaUi;
826 delete statusBarUi;
827}
828
829void KateViewDefaultsConfig::apply()
830{
831 // nothing changed, no need to apply stuff
832 if (!hasChanged()) {
833 return;
834 }
835 m_changed = false;
836
837 KateViewConfig::global()->configStart();
838 KateRendererConfig::global()->configStart();
839
840 KateDocumentConfig::global()->setMarkerSize(textareaUi->sliSetMarkerSize->value());
841 KateDocumentConfig::global()->setShowSpaces(KateDocumentConfig::WhitespaceRendering(textareaUi->spacesComboBox->currentIndex()));
842 KateDocumentConfig::global()->setShowTabs(textareaUi->chkShowTabs->isChecked());
843
844 KateRendererConfig::global()->setFont(textareaUi->kfontrequester->font());
845 KateRendererConfig::global()->setAnimateBracketMatching(textareaUi->chkAnimateBracketMatching->isChecked());
846 KateRendererConfig::global()->setShowIndentationLines(textareaUi->chkShowIndentationLines->isChecked());
847 KateRendererConfig::global()->setShowWholeBracketExpression(textareaUi->chkShowWholeBracketExpression->isChecked());
848 KateRendererConfig::global()->setLineHeightMultiplier(textareaUi->spbLineHeightMultiplier->value());
849
850 KateViewConfig::global()->setDynWordWrap(textareaUi->cbxWordWrap->isChecked());
851 KateViewConfig::global()->setShowWordCount(textareaUi->chkShowWordCount->isChecked());
852 KateViewConfig::global()->setValue(KateViewConfig::BookmarkSorting, bordersUi->rbSortBookmarksByPosition->isChecked() ? 0 : 1);
853 if (!textareaUi->cbxIndentWrappedLines->isChecked()) {
854 KateViewConfig::global()->setValue(KateViewConfig::DynWordWrapAlignIndent, 0);
855 } else {
856 KateViewConfig::global()->setValue(KateViewConfig::DynWordWrapAlignIndent, textareaUi->sbDynamicWordWrapDepth->value());
857 }
858 KateViewConfig::global()->setValue(KateViewConfig::DynWordWrapIndicators, textareaUi->cmbDynamicWordWrapIndicator->currentIndex());
859 KateViewConfig::global()->setValue(KateViewConfig::DynWrapAnywhere, textareaUi->chkDynWrapAnywhere->isChecked());
860 KateViewConfig::global()->setValue(KateViewConfig::DynWrapAtStaticMarker, textareaUi->chkDynWrapAtStaticMarker->isChecked());
861 KateViewConfig::global()->setValue(KateViewConfig::FoldFirstLine, textareaUi->chkFoldFirstLine->isChecked());
862 KateViewConfig::global()->setValue(KateViewConfig::ScrollBarMiniMapWidth, bordersUi->spBoxMiniMapWidth->value());
863 KateViewConfig::global()->setValue(KateViewConfig::ShowBracketMatchPreview, textareaUi->chkShowBracketMatchPreview->isChecked());
864 KateViewConfig::global()->setValue(KateViewConfig::ShowFoldingBar, bordersUi->chkShowFoldingMarkers->isChecked());
865 KateViewConfig::global()->setValue(KateViewConfig::ShowFoldingPreview, bordersUi->chkShowFoldingPreview->isChecked());
866 KateViewConfig::global()->setValue(KateViewConfig::ShowIconBar, bordersUi->chkIconBorder->isChecked());
867 KateViewConfig::global()->setValue(KateViewConfig::ShowLineCount, textareaUi->chkShowLineCount->isChecked());
868 KateViewConfig::global()->setValue(KateViewConfig::ShowLineModification, bordersUi->chkShowLineModification->isChecked());
869 KateViewConfig::global()->setValue(KateViewConfig::ShowLineNumbers, bordersUi->chkLineNumbers->isChecked());
870 KateViewConfig::global()->setValue(KateViewConfig::ShowScrollBarMarks, bordersUi->chkScrollbarMarks->isChecked());
871 KateViewConfig::global()->setValue(KateViewConfig::ShowScrollBarMiniMap, bordersUi->chkScrollbarMiniMap->isChecked());
872 KateViewConfig::global()->setValue(KateViewConfig::ShowScrollBarMiniMapAll, bordersUi->chkScrollbarMiniMapAll->isChecked());
873 KateViewConfig::global()->setValue(KateViewConfig::ShowScrollBarPreview, bordersUi->chkScrollbarPreview->isChecked());
874 KateViewConfig::global()->setValue(KateViewConfig::ShowScrollbars, bordersUi->cmbShowScrollbars->currentIndex());
875 bool showOnHoverOnly = bordersUi->cmbFoldingArrowVisiblity->currentIndex() == 0;
876 KateViewConfig::global()->setValue(KateViewConfig::ShowFoldingOnHoverOnly, showOnHoverOnly);
877
878 // Statusbar stuff
879 KateViewConfig::global()->setValue(KateViewConfig::ShowStatusbarDictionary, statusBarUi->cbShowActiveDictionary->isChecked());
880 KateViewConfig::global()->setValue(KateViewConfig::ShowStatusbarHighlightingMode, statusBarUi->cbShowHighlightingMode->isChecked());
881 KateViewConfig::global()->setValue(KateViewConfig::ShowStatusbarInputMode, statusBarUi->cbShowInputMode->isChecked());
882 KateViewConfig::global()->setValue(KateViewConfig::ShowStatusbarLineColumn, statusBarUi->cbShowLineColumn->isChecked());
883 KateViewConfig::global()->setValue(KateViewConfig::ShowStatusbarTabSettings, statusBarUi->cbShowTabSetting->isChecked());
884 KateViewConfig::global()->setValue(KateViewConfig::ShowStatusbarFileEncoding, statusBarUi->cbShowEncoding->isChecked());
885 KateViewConfig::global()->setValue(KateViewConfig::ShowStatusbarEOL, statusBarUi->cbShowEOL->isChecked());
886
887 KateRendererConfig::global()->configEnd();
888 KateViewConfig::global()->configEnd();
889}
890
891void KateViewDefaultsConfig::reload()
892{
893 bordersUi->chkIconBorder->setChecked(KateViewConfig::global()->iconBar());
894 bordersUi->chkLineNumbers->setChecked(KateViewConfig::global()->lineNumbers());
895 bordersUi->chkScrollbarMarks->setChecked(KateViewConfig::global()->scrollBarMarks());
896 bordersUi->chkScrollbarMiniMap->setChecked(KateViewConfig::global()->scrollBarMiniMap());
897 bordersUi->chkScrollbarMiniMapAll->setChecked(KateViewConfig::global()->scrollBarMiniMapAll());
898 bordersUi->chkScrollbarPreview->setChecked(KateViewConfig::global()->scrollBarPreview());
899 bordersUi->chkShowFoldingMarkers->setChecked(KateViewConfig::global()->foldingBar());
900 bordersUi->chkShowFoldingPreview->setChecked(KateViewConfig::global()->foldingPreview());
901 bordersUi->chkShowLineModification->setChecked(KateViewConfig::global()->lineModification());
902 bordersUi->cmbShowScrollbars->setCurrentIndex(KateViewConfig::global()->showScrollbars());
903 bordersUi->rbSortBookmarksByCreation->setChecked(KateViewConfig::global()->bookmarkSort() == 1);
904 bordersUi->rbSortBookmarksByPosition->setChecked(KateViewConfig::global()->bookmarkSort() == 0);
905 bordersUi->spBoxMiniMapWidth->setValue(KateViewConfig::global()->scrollBarMiniMapWidth());
906 bordersUi->cmbFoldingArrowVisiblity->setCurrentIndex(KateViewConfig::global()->showFoldingOnHoverOnly() ? 0 : 1);
907
908 textareaUi->kfontrequester->setFont(KateRendererConfig::global()->baseFont());
909
910 textareaUi->chkAnimateBracketMatching->setChecked(KateRendererConfig::global()->animateBracketMatching());
911 textareaUi->chkDynWrapAnywhere->setChecked(KateViewConfig::global()->dynWrapAnywhere());
912 textareaUi->chkDynWrapAtStaticMarker->setChecked(KateViewConfig::global()->dynWrapAtStaticMarker());
913 textareaUi->chkFoldFirstLine->setChecked(KateViewConfig::global()->foldFirstLine());
914 textareaUi->chkShowBracketMatchPreview->setChecked(KateViewConfig::global()->value(KateViewConfig::ShowBracketMatchPreview).toBool());
915 textareaUi->chkShowIndentationLines->setChecked(KateRendererConfig::global()->showIndentationLines());
916 textareaUi->chkShowLineCount->setChecked(KateViewConfig::global()->showLineCount());
917 textareaUi->chkShowTabs->setChecked(KateDocumentConfig::global()->showTabs());
918 textareaUi->chkShowWholeBracketExpression->setChecked(KateRendererConfig::global()->showWholeBracketExpression());
919 textareaUi->chkShowWordCount->setChecked(KateViewConfig::global()->showWordCount());
920 textareaUi->cmbDynamicWordWrapIndicator->setCurrentIndex(KateViewConfig::global()->dynWordWrapIndicators());
921 textareaUi->cbxWordWrap->setChecked(KateViewConfig::global()->dynWordWrap());
922 textareaUi->cbxIndentWrappedLines->setChecked(KateViewConfig::global()->dynWordWrapAlignIndent() != 0);
923 textareaUi->sbDynamicWordWrapDepth->setValue(KateViewConfig::global()->dynWordWrapAlignIndent());
924 textareaUi->sliSetMarkerSize->setValue(KateDocumentConfig::global()->markerSize());
925 textareaUi->spacesComboBox->setCurrentIndex(KateDocumentConfig::global()->showSpaces());
926 textareaUi->spbLineHeightMultiplier->setValue(KateRendererConfig::global()->lineHeightMultiplier());
927
928 statusBarUi->cbShowLineColumn->setChecked(KateViewConfig::global()->value(KateViewConfig::ShowStatusbarLineColumn).toBool());
929 statusBarUi->cbShowActiveDictionary->setChecked(KateViewConfig::global()->value(KateViewConfig::ShowStatusbarDictionary).toBool());
930 statusBarUi->cbShowTabSetting->setChecked(KateViewConfig::global()->value(KateViewConfig::ShowStatusbarTabSettings).toBool());
931 statusBarUi->cbShowHighlightingMode->setChecked(KateViewConfig::global()->value(KateViewConfig::ShowStatusbarHighlightingMode).toBool());
932 statusBarUi->cbShowInputMode->setChecked(KateViewConfig::global()->value(KateViewConfig::ShowStatusbarInputMode).toBool());
933 statusBarUi->cbShowEncoding->setChecked(KateViewConfig::global()->value(KateViewConfig::ShowStatusbarFileEncoding).toBool());
934 statusBarUi->cbShowEOL->setChecked(KateViewConfig::global()->value(KateViewConfig::ShowStatusbarEOL).toBool());
935}
936
937void KateViewDefaultsConfig::reset()
938{
939}
940
941void KateViewDefaultsConfig::defaults()
942{
943}
944
945QString KateViewDefaultsConfig::name() const
946{
947 return i18n("Appearance");
948}
949
950QString KateViewDefaultsConfig::fullName() const
951{
952 return i18n("Appearance");
953}
954
955QIcon KateViewDefaultsConfig::icon() const
956{
957 return QIcon::fromTheme(QStringLiteral("preferences-desktop-theme"));
958}
959
960// END KateViewDefaultsConfig
961
962// BEGIN KateSaveConfigTab
963KateSaveConfigTab::KateSaveConfigTab(QWidget *parent)
964 : KateConfigPage(parent)
965 , modeConfigPage(new ModeConfigPage(this))
966{
967 // FIXME: Is really needed to move all this code below to another class,
968 // since it is another tab itself on the config dialog. This means we should
969 // initialize, add and work with as we do with modeConfigPage (ereslibre)
970 QVBoxLayout *layout = new QVBoxLayout(this);
971 layout->setContentsMargins(0, 0, 0, 0);
972 QTabWidget *tabWidget = new QTabWidget(this);
973 tabWidget->setDocumentMode(true);
974
975 QWidget *tmpWidget = new QWidget(tabWidget);
976 QVBoxLayout *internalLayout = new QVBoxLayout(tmpWidget);
977 QWidget *newWidget = new QWidget(tabWidget);
978 ui = new Ui::OpenSaveConfigWidget();
979 ui->setupUi(newWidget);
980
981 QWidget *tmpWidget2 = new QWidget(tabWidget);
982 QVBoxLayout *internalLayout2 = new QVBoxLayout(tmpWidget2);
983 QWidget *newWidget2 = new QWidget(tabWidget);
984 uiadv = new Ui::OpenSaveConfigAdvWidget();
985 uiadv->setupUi(newWidget2);
986 uiadv->lblExplanatory->setText(
987 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 "
988 "cause data loss in case of a system crash.",
990 uiadv->lblExplanatory->setFont(QFontDatabase::systemFont(QFontDatabase::SmallestReadableFont));
991
992 // "What's This?" help can be found in the ui file
993
994 reload();
995
996 observeChanges(ui->cbRemoveTrailingSpaces);
997 observeChanges(ui->chkDetectEOL);
998 observeChanges(ui->chkEnableBOM);
999 observeChanges(ui->chkNewLineAtEof);
1000 observeChanges(ui->cmbEOL);
1001 observeChanges(ui->cmbEncoding);
1002 observeChanges(ui->cmbEncodingDetection);
1003 observeChanges(ui->cmbEncodingFallback);
1004 observeChanges(ui->lineLengthLimit);
1005 observeChanges(ui->gbAutoSave);
1006 observeChanges(ui->cbAutoSaveOnFocus);
1007 observeChanges(ui->spbAutoSaveInterval);
1008
1009 observeChanges(uiadv->chkAutoReloadVersionControl);
1010
1011 observeChanges(uiadv->chkBackupLocalFiles);
1012 observeChanges(uiadv->chkBackupRemoteFiles);
1013 observeChanges(uiadv->cmbSwapFileMode);
1014 connect(uiadv->cmbSwapFileMode, &QComboBox::currentIndexChanged, this, &KateSaveConfigTab::swapFileModeChanged);
1015
1016 observeChanges(uiadv->edtBackupPrefix);
1017 observeChanges(uiadv->edtBackupSuffix);
1018 observeChanges(uiadv->kurlSwapDirectory);
1019 observeChanges(uiadv->spbSwapFileSync);
1020 observeChanges(uiadv->chkEditorConfig);
1021
1022 internalLayout->addWidget(newWidget);
1023 internalLayout2->addWidget(newWidget2);
1024
1025 // add all tabs
1026 tabWidget->insertTab(0, tmpWidget, i18n("General"));
1027 tabWidget->insertTab(1, tmpWidget2, i18n("Advanced"));
1028 tabWidget->insertTab(2, modeConfigPage, modeConfigPage->name());
1029
1030 observeChanges(modeConfigPage);
1031
1032 layout->addWidget(tabWidget);
1033
1034 // support variable expansion in backup prefix/suffix
1035 KTextEditor::Editor::instance()->addVariableExpansion({uiadv->edtBackupPrefix, uiadv->edtBackupSuffix},
1036 {QStringLiteral("Date:Locale"),
1037 QStringLiteral("Date:ISO"),
1038 QStringLiteral("Date:"),
1039 QStringLiteral("Time:Locale"),
1040 QStringLiteral("Time:ISO"),
1041 QStringLiteral("Time:"),
1042 QStringLiteral("ENV:"),
1043 QStringLiteral("JS:"),
1044 QStringLiteral("UUID")});
1045}
1046
1047KateSaveConfigTab::~KateSaveConfigTab()
1048{
1049 delete uiadv;
1050 delete ui;
1051}
1052
1053void KateSaveConfigTab::swapFileModeChanged(int idx)
1054{
1055 const KateDocumentConfig::SwapFileMode mode = static_cast<KateDocumentConfig::SwapFileMode>(idx);
1056 switch (mode) {
1057 case KateDocumentConfig::DisableSwapFile:
1058 uiadv->lblSwapDirectory->setEnabled(false);
1059 uiadv->kurlSwapDirectory->setEnabled(false);
1060 uiadv->lblSwapFileSync->setEnabled(false);
1061 uiadv->spbSwapFileSync->setEnabled(false);
1062 break;
1063 case KateDocumentConfig::EnableSwapFile:
1064 uiadv->lblSwapDirectory->setEnabled(false);
1065 uiadv->kurlSwapDirectory->setEnabled(false);
1066 uiadv->lblSwapFileSync->setEnabled(true);
1067 uiadv->spbSwapFileSync->setEnabled(true);
1068 break;
1069 case KateDocumentConfig::SwapFilePresetDirectory:
1070 uiadv->lblSwapDirectory->setEnabled(true);
1071 uiadv->kurlSwapDirectory->setEnabled(true);
1072 uiadv->lblSwapFileSync->setEnabled(true);
1073 uiadv->spbSwapFileSync->setEnabled(true);
1074 break;
1075 }
1076}
1077
1078void KateSaveConfigTab::apply()
1079{
1080 modeConfigPage->apply();
1081
1082 // nothing changed, no need to apply stuff
1083 if (!hasChanged()) {
1084 return;
1085 }
1086 m_changed = false;
1087
1088 KateGlobalConfig::global()->configStart();
1089 KateDocumentConfig::global()->configStart();
1090
1091 if (uiadv->edtBackupSuffix->text().isEmpty() && uiadv->edtBackupPrefix->text().isEmpty()) {
1092 KMessageBox::information(this, i18n("You did not provide a backup suffix or prefix. Using default suffix: '~'"), i18n("No Backup Suffix or Prefix"));
1093 uiadv->edtBackupSuffix->setText(QStringLiteral("~"));
1094 }
1095
1096 KateDocumentConfig::global()->setBackupOnSaveLocal(uiadv->chkBackupLocalFiles->isChecked());
1097 KateDocumentConfig::global()->setBackupOnSaveRemote(uiadv->chkBackupRemoteFiles->isChecked());
1098 KateDocumentConfig::global()->setBackupPrefix(uiadv->edtBackupPrefix->text());
1099 KateDocumentConfig::global()->setBackupSuffix(uiadv->edtBackupSuffix->text());
1100
1101 KateDocumentConfig::global()->setSwapFileMode(uiadv->cmbSwapFileMode->currentIndex());
1102 KateDocumentConfig::global()->setSwapDirectory(uiadv->kurlSwapDirectory->url().toLocalFile());
1103 KateDocumentConfig::global()->setSwapSyncInterval(uiadv->spbSwapFileSync->value());
1104
1105 KateDocumentConfig::global()->setRemoveSpaces(ui->cbRemoveTrailingSpaces->currentIndex());
1106
1107 KateDocumentConfig::global()->setNewLineAtEof(ui->chkNewLineAtEof->isChecked());
1108
1109 // set both standard and fallback encoding
1110 KateDocumentConfig::global()->setEncoding(KCharsets::charsets()->encodingForName(ui->cmbEncoding->currentText()));
1111
1112 KateGlobalConfig::global()->setValue(KateGlobalConfig::EncodingProberType, (KEncodingProber::ProberType)ui->cmbEncodingDetection->currentIndex());
1113 KateGlobalConfig::global()->setFallbackEncoding(KCharsets::charsets()->encodingForName(ui->cmbEncodingFallback->currentText()));
1114
1115 KateDocumentConfig::global()->setEol(ui->cmbEOL->currentIndex());
1116 KateDocumentConfig::global()->setAllowEolDetection(ui->chkDetectEOL->isChecked());
1117 KateDocumentConfig::global()->setBom(ui->chkEnableBOM->isChecked());
1118
1119 KateDocumentConfig::global()->setLineLengthLimit(ui->lineLengthLimit->value());
1120
1121 KateDocumentConfig::global()->setValue(KateDocumentConfig::AutoSave, ui->gbAutoSave->isChecked());
1122 KateDocumentConfig::global()->setValue(KateDocumentConfig::AutoSaveOnFocusOut, ui->cbAutoSaveOnFocus->isChecked());
1123 KateDocumentConfig::global()->setValue(KateDocumentConfig::AutoSaveInteral, ui->spbAutoSaveInterval->value());
1124
1125 KateDocumentConfig::global()->setValue(KateDocumentConfig::AutoReloadIfStateIsInVersionControl, uiadv->chkAutoReloadVersionControl->isChecked());
1126 KateDocumentConfig::global()->setValue(KateDocumentConfig::UseEditorConfig, uiadv->chkEditorConfig->isChecked());
1127
1128 KateDocumentConfig::global()->configEnd();
1129 KateGlobalConfig::global()->configEnd();
1130}
1131
1132void KateSaveConfigTab::reload()
1133{
1134 modeConfigPage->reload();
1135
1136 // encodings
1137 ui->cmbEncoding->clear();
1138 ui->cmbEncodingFallback->clear();
1139 QStringList encodings(KCharsets::charsets()->descriptiveEncodingNames());
1140 for (int i = 0; i < encodings.count(); i++) {
1141 const auto encodingName = KCharsets::charsets()->encodingForName(encodings[i]);
1142
1143 ui->cmbEncoding->addItem(encodings[i]);
1144 ui->cmbEncodingFallback->addItem(encodings[i]);
1145
1146 if (encodingName == KateDocumentConfig::global()->encoding()) {
1147 ui->cmbEncoding->setCurrentIndex(i);
1148 }
1149
1150 if (encodingName == KateGlobalConfig::global()->fallbackEncoding()) {
1151 // adjust index for fallback config, has no default!
1152 ui->cmbEncodingFallback->setCurrentIndex(i);
1153 }
1154 }
1155
1156 // encoding detection
1157 ui->cmbEncodingDetection->clear();
1158 bool found = false;
1159 const auto proberType = (KEncodingProber::ProberType)KateGlobalConfig::global()->value(KateGlobalConfig::EncodingProberType).toInt();
1160 for (int i = 0; !KEncodingProber::nameForProberType((KEncodingProber::ProberType)i).isEmpty(); ++i) {
1161 ui->cmbEncodingDetection->addItem(KEncodingProber::nameForProberType((KEncodingProber::ProberType)i));
1162 if (i == proberType) {
1163 ui->cmbEncodingDetection->setCurrentIndex(ui->cmbEncodingDetection->count() - 1);
1164 found = true;
1165 }
1166 }
1167 if (!found) {
1168 ui->cmbEncodingDetection->setCurrentIndex(KEncodingProber::Universal);
1169 }
1170
1171 // eol
1172 ui->cmbEOL->setCurrentIndex(KateDocumentConfig::global()->eol());
1173 ui->chkDetectEOL->setChecked(KateDocumentConfig::global()->allowEolDetection());
1174 ui->chkEnableBOM->setChecked(KateDocumentConfig::global()->bom());
1175 ui->lineLengthLimit->setValue(KateDocumentConfig::global()->lineLengthLimit());
1176
1177 ui->cbRemoveTrailingSpaces->setCurrentIndex(KateDocumentConfig::global()->removeSpaces());
1178 ui->chkNewLineAtEof->setChecked(KateDocumentConfig::global()->newLineAtEof());
1179
1180 // other stuff
1181 uiadv->chkBackupLocalFiles->setChecked(KateDocumentConfig::global()->backupOnSaveLocal());
1182 uiadv->chkBackupRemoteFiles->setChecked(KateDocumentConfig::global()->backupOnSaveRemote());
1183 uiadv->edtBackupPrefix->setText(KateDocumentConfig::global()->backupPrefix());
1184 uiadv->edtBackupSuffix->setText(KateDocumentConfig::global()->backupSuffix());
1185
1186 uiadv->cmbSwapFileMode->setCurrentIndex(KateDocumentConfig::global()->swapFileMode());
1187 uiadv->kurlSwapDirectory->setUrl(QUrl::fromLocalFile(KateDocumentConfig::global()->swapDirectory()));
1188 uiadv->spbSwapFileSync->setValue(KateDocumentConfig::global()->swapSyncInterval());
1189 swapFileModeChanged(KateDocumentConfig::global()->swapFileMode());
1190
1191 ui->gbAutoSave->setChecked(KateDocumentConfig::global()->autoSave());
1192 ui->cbAutoSaveOnFocus->setChecked(KateDocumentConfig::global()->autoSaveOnFocusOut());
1193 ui->spbAutoSaveInterval->setValue(KateDocumentConfig::global()->autoSaveInterval());
1194
1195 uiadv->chkAutoReloadVersionControl->setChecked(KateDocumentConfig::global()->value(KateDocumentConfig::AutoReloadIfStateIsInVersionControl).toBool());
1196 uiadv->chkEditorConfig->setChecked(KateDocumentConfig::global()->value(KateDocumentConfig::UseEditorConfig).toBool());
1197}
1198
1199void KateSaveConfigTab::reset()
1200{
1201 modeConfigPage->reset();
1202}
1203
1204void KateSaveConfigTab::defaults()
1205{
1206 modeConfigPage->defaults();
1207
1208 ui->cbRemoveTrailingSpaces->setCurrentIndex(0);
1209
1210 uiadv->chkBackupLocalFiles->setChecked(true);
1211 uiadv->chkBackupRemoteFiles->setChecked(false);
1212 uiadv->edtBackupPrefix->setText(QString());
1213 uiadv->edtBackupSuffix->setText(QStringLiteral("~"));
1214
1215 uiadv->cmbSwapFileMode->setCurrentIndex(1);
1216 uiadv->kurlSwapDirectory->setDisabled(true);
1217 uiadv->lblSwapDirectory->setDisabled(true);
1218 uiadv->spbSwapFileSync->setValue(15);
1219}
1220
1221QString KateSaveConfigTab::name() const
1222{
1223 return i18n("Open/Save");
1224}
1225
1226QString KateSaveConfigTab::fullName() const
1227{
1228 return i18n("File Opening & Saving");
1229}
1230
1231QIcon KateSaveConfigTab::icon() const
1232{
1233 return QIcon::fromTheme(QStringLiteral("document-save"));
1234}
1235
1236// END KateSaveConfigTab
1237
1238// BEGIN KateGotoBar
1239KateGotoBar::KateGotoBar(KTextEditor::View *view, QWidget *parent)
1240 : KateViewBarWidget(true, parent)
1241 , m_view(view)
1242{
1243 Q_ASSERT(m_view != nullptr); // this bar widget is pointless w/o a view
1244
1245 QHBoxLayout *topLayout = new QHBoxLayout(centralWidget());
1246 topLayout->setContentsMargins(0, 0, 0, 0);
1247
1248 QToolButton *btn = new QToolButton(this);
1249 btn->setAutoRaise(true);
1250 btn->setMinimumSize(QSize(1, btn->minimumSizeHint().height()));
1251 btn->setText(i18n("&Line:"));
1252 btn->setToolTip(i18n("Go to line number from clipboard"));
1253 connect(btn, &QToolButton::clicked, this, &KateGotoBar::gotoClipboard);
1254 topLayout->addWidget(btn);
1255
1256 m_gotoRange = new QSpinBox(this);
1257 topLayout->addWidget(m_gotoRange, 1);
1258 topLayout->setStretchFactor(m_gotoRange, 0);
1259
1260 btn = new QToolButton(this);
1261 btn->setAutoRaise(true);
1262 btn->setMinimumSize(QSize(1, btn->minimumSizeHint().height()));
1263 btn->setText(i18n("Go to"));
1264 btn->setIcon(QIcon::fromTheme(QStringLiteral("go-jump")));
1266 connect(btn, &QToolButton::clicked, this, &KateGotoBar::gotoLine);
1267 topLayout->addWidget(btn);
1268
1269 btn = m_modifiedUp = new QToolButton(this);
1270 btn->setAutoRaise(true);
1271 btn->setMinimumSize(QSize(1, btn->minimumSizeHint().height()));
1272 btn->setDefaultAction(m_view->action(QStringLiteral("modified_line_up")));
1273 btn->setIcon(QIcon::fromTheme(QStringLiteral("go-up-search")));
1274 btn->setText(QString());
1275 btn->installEventFilter(this);
1276 topLayout->addWidget(btn);
1277
1278 btn = m_modifiedDown = new QToolButton(this);
1279 btn->setAutoRaise(true);
1280 btn->setMinimumSize(QSize(1, btn->minimumSizeHint().height()));
1281 btn->setDefaultAction(m_view->action(QStringLiteral("modified_line_down")));
1282 btn->setIcon(QIcon::fromTheme(QStringLiteral("go-down-search")));
1283 btn->setText(QString());
1284 btn->installEventFilter(this);
1285 topLayout->addWidget(btn);
1286
1287 topLayout->addStretch();
1288
1289 setFocusProxy(m_gotoRange);
1290}
1291
1292void KateGotoBar::showEvent(QShowEvent *event)
1293{
1294 Q_UNUSED(event)
1295 // Catch rare cases where the bar is visible while document is edited
1296 connect(m_view->document(), &KTextEditor::Document::textChanged, this, &KateGotoBar::updateData);
1297}
1298
1299void KateGotoBar::closed()
1300{
1301 disconnect(m_view->document(), &KTextEditor::Document::textChanged, this, &KateGotoBar::updateData);
1302}
1303
1304bool KateGotoBar::eventFilter(QObject *object, QEvent *event)
1305{
1306 if (object == m_modifiedUp || object == m_modifiedDown) {
1307 if (event->type() != QEvent::Wheel) {
1308 return false;
1309 }
1310
1311 int delta = static_cast<QWheelEvent *>(event)->angleDelta().y();
1312 // Reset m_wheelDelta when scroll direction change
1313 if (m_wheelDelta != 0 && (m_wheelDelta < 0) != (delta < 0)) {
1314 m_wheelDelta = 0;
1315 }
1316
1317 m_wheelDelta += delta;
1318
1319 if (m_wheelDelta >= 120) {
1320 m_wheelDelta = 0;
1321 m_modifiedUp->click();
1322 } else if (m_wheelDelta <= -120) {
1323 m_wheelDelta = 0;
1324 m_modifiedDown->click();
1325 }
1326 }
1327
1328 return false;
1329}
1330
1331void KateGotoBar::gotoClipboard()
1332{
1333 static const QRegularExpression rx(QStringLiteral("-?\\d+"));
1334 bool ok = false;
1335 const int lineNo = rx.match(QApplication::clipboard()->text(QClipboard::Selection)).captured().toInt(&ok);
1336 if (!ok) {
1337 return;
1338 }
1339 if (lineNo >= m_gotoRange->minimum() && lineNo <= m_gotoRange->maximum()) {
1340 m_gotoRange->setValue(lineNo);
1341 gotoLine();
1342 } else {
1343 QPointer<KTextEditor::Message> message = new KTextEditor::Message(i18n("No valid line number found in clipboard"));
1344 message->setWordWrap(true);
1345 message->setAutoHide(2000);
1346 message->setPosition(KTextEditor::Message::BottomInView);
1347 message->setView(m_view), m_view->document()->postMessage(message);
1348 }
1349}
1350
1351void KateGotoBar::updateData()
1352{
1353 int lines = m_view->document()->lines();
1354 m_gotoRange->setMinimum(-lines);
1355 m_gotoRange->setMaximum(lines);
1356 if (!isVisible()) {
1357 m_gotoRange->setValue(m_view->cursorPosition().line() + 1);
1358 m_gotoRange->adjustSize(); // ### does not respect the range :-(
1359 }
1360
1361 m_gotoRange->selectAll();
1362}
1363
1364void KateGotoBar::keyPressEvent(QKeyEvent *event)
1365{
1366 int key = event->key();
1367 if (key == Qt::Key_Return || key == Qt::Key_Enter) {
1368 gotoLine();
1369 return;
1370 }
1372}
1373
1374void KateGotoBar::gotoLine()
1375{
1376 KTextEditor::ViewPrivate *kv = qobject_cast<KTextEditor::ViewPrivate *>(m_view);
1377 if (kv && kv->selection() && !kv->config()->persistentSelection()) {
1378 kv->clearSelection();
1379 }
1380
1381 int gotoValue = m_gotoRange->value();
1382 if (gotoValue < 0) {
1383 gotoValue += m_view->document()->lines();
1384 } else if (gotoValue > 0) {
1385 gotoValue -= 1;
1386 }
1387
1388 m_view->setCursorPosition(KTextEditor::Cursor(gotoValue, 0));
1389 m_view->setFocus();
1390 Q_EMIT hideMe();
1391}
1392// END KateGotoBar
1393
1394// BEGIN KateDictionaryBar
1395KateDictionaryBar::KateDictionaryBar(KTextEditor::ViewPrivate *view, QWidget *parent)
1396 : KateViewBarWidget(true, parent)
1397 , m_view(view)
1398{
1399 Q_ASSERT(m_view != nullptr); // this bar widget is pointless w/o a view
1400
1401 QHBoxLayout *topLayout = new QHBoxLayout(centralWidget());
1402 topLayout->setContentsMargins(0, 0, 0, 0);
1403 // topLayout->setSpacing(spacingHint());
1404 m_dictionaryComboBox = new Sonnet::DictionaryComboBox(centralWidget());
1405 connect(m_dictionaryComboBox, &Sonnet::DictionaryComboBox::dictionaryChanged, this, &KateDictionaryBar::dictionaryChanged);
1406 connect(view->doc(), &KTextEditor::DocumentPrivate::defaultDictionaryChanged, this, &KateDictionaryBar::updateData);
1407 QLabel *label = new QLabel(i18n("Dictionary:"), centralWidget());
1408 label->setBuddy(m_dictionaryComboBox);
1409
1410 topLayout->addWidget(label);
1411 topLayout->addWidget(m_dictionaryComboBox, 1);
1412 topLayout->setStretchFactor(m_dictionaryComboBox, 0);
1413 topLayout->addStretch();
1414}
1415
1416KateDictionaryBar::~KateDictionaryBar()
1417{
1418}
1419
1420void KateDictionaryBar::updateData()
1421{
1422 KTextEditor::DocumentPrivate *document = m_view->doc();
1423 QString dictionary = document->defaultDictionary();
1424 if (dictionary.isEmpty()) {
1425 dictionary = Sonnet::Speller().defaultLanguage();
1426 }
1427 m_dictionaryComboBox->setCurrentByDictionary(dictionary);
1428}
1429
1430void KateDictionaryBar::dictionaryChanged(const QString &dictionary)
1431{
1432 const KTextEditor::Range selection = m_view->selectionRange();
1433 if (selection.isValid() && !selection.isEmpty()) {
1434 const bool blockmode = m_view->blockSelection();
1435 m_view->doc()->setDictionary(dictionary, selection, blockmode);
1436 } else {
1437 m_view->doc()->setDefaultDictionary(dictionary);
1438 }
1439}
1440
1441// END KateGotoBar
1442
1443// BEGIN KateModOnHdPrompt
1444KateModOnHdPrompt::KateModOnHdPrompt(KTextEditor::DocumentPrivate *doc, KTextEditor::Document::ModifiedOnDiskReason modtype, const QString &reason)
1445 : QObject(doc)
1446 , m_doc(doc)
1447 , m_message(new KTextEditor::Message(reason, KTextEditor::Message::Information))
1448 , m_fullDiffPath(QStandardPaths::findExecutable(QStringLiteral("diff")))
1449 , m_proc(nullptr)
1450 , m_diffFile(nullptr)
1451 , m_diffAction(nullptr)
1452{
1453 m_message->setPosition(KTextEditor::Message::AboveView);
1454 m_message->setWordWrap(true);
1455
1456 // If the file isn't deleted, present a diff button
1457 const bool onDiskDeleted = modtype == KTextEditor::Document::OnDiskDeleted;
1458 if (!onDiskDeleted) {
1459 QAction *aAutoReload = new QAction(i18n("Enable Auto Reload"), this);
1460 aAutoReload->setIcon(QIcon::fromTheme(QStringLiteral("view-refresh")));
1461 aAutoReload->setToolTip(
1462 i18n("Reloads and will automatically reload without warning about disk changes from now until you close either the tab or window."));
1463 m_message->addAction(aAutoReload, false);
1464 connect(aAutoReload, &QAction::triggered, this, &KateModOnHdPrompt::autoReloadTriggered);
1465
1466 if (!m_fullDiffPath.isEmpty()) {
1467 m_diffAction = new QAction(i18n("View &Difference"), this);
1468 m_diffAction->setIcon(QIcon::fromTheme(QStringLiteral("document-multiple")));
1469 m_diffAction->setToolTip(i18n("Shows a diff of the changes."));
1470 m_message->addAction(m_diffAction, false);
1471 connect(m_diffAction, &QAction::triggered, this, &KateModOnHdPrompt::slotDiff);
1472 }
1473
1474 QAction *aReload = new QAction(i18n("&Reload"), this);
1475 aReload->setIcon(QIcon::fromTheme(QStringLiteral("view-refresh")));
1476 aReload->setToolTip(i18n("Reloads the file from disk. Unsaved changes will be lost."));
1477 m_message->addAction(aReload);
1478 connect(aReload, &QAction::triggered, this, &KateModOnHdPrompt::reloadTriggered);
1479 } else {
1480 QAction *closeFile = new QAction(i18nc("@action:button closes the opened file", "&Close File"), this);
1481 closeFile->setIcon(QIcon::fromTheme(QStringLiteral("document-close")));
1482 closeFile->setToolTip(i18n("Closes the file, discarding its content."));
1483 m_message->addAction(closeFile, false);
1484 connect(closeFile, &QAction::triggered, this, &KateModOnHdPrompt::closeTriggered);
1485
1486 auto *aSaveAs = new QAction(i18nc("@action", "&Save As…"), this);
1487 aSaveAs->setIcon(QIcon::fromTheme(QStringLiteral("document-save-as")));
1488 aSaveAs->setToolTip(i18n("Lets you select a location and save the file again."));
1489 m_message->addAction(aSaveAs, false);
1490 connect(aSaveAs, &QAction::triggered, this, &KateModOnHdPrompt::saveAsTriggered);
1491 }
1492
1493 QAction *aIgnore = new QAction(i18n("&Ignore"), this);
1494 aIgnore->setToolTip(i18n("Ignores the changes on disk without any action."));
1495 aIgnore->setIcon(QIcon::fromTheme(QStringLiteral("dialog-cancel")));
1496 m_message->addAction(aIgnore);
1497 connect(aIgnore, &QAction::triggered, this, &KateModOnHdPrompt::ignoreTriggered);
1498
1499 m_doc->postMessage(m_message);
1500}
1501
1502KateModOnHdPrompt::~KateModOnHdPrompt()
1503{
1504 delete m_proc;
1505 m_proc = nullptr;
1506 if (m_diffFile) {
1507 m_diffFile->setAutoRemove(true);
1508 delete m_diffFile;
1509 m_diffFile = nullptr;
1510 }
1511 delete m_message;
1512}
1513
1514void KateModOnHdPrompt::slotDiff()
1515{
1516 if (m_diffFile) {
1517 return;
1518 }
1519
1520 m_diffFile = new QTemporaryFile(QDir::temp().filePath(QLatin1String("XXXXXX.diff")));
1521 m_diffFile->open();
1522
1523 // Start a KProcess that creates a diff
1524 m_proc = new KProcess(this);
1526 *m_proc << m_fullDiffPath << QStringLiteral("-u") << QStringLiteral("-") << m_doc->url().toLocalFile();
1527 connect(m_proc, &KProcess::readyRead, this, &KateModOnHdPrompt::slotDataAvailable);
1528 connect(m_proc, &KProcess::finished, this, &KateModOnHdPrompt::slotPDone);
1529
1530 // disable the diff button, to hinder the user to run it twice.
1531 m_diffAction->setEnabled(false);
1532
1533 m_proc->start();
1534
1535 QTextStream ts(m_proc);
1536 int lastln = m_doc->lines() - 1;
1537 for (int l = 0; l < lastln; ++l) {
1538 ts << m_doc->line(l) << '\n';
1539 }
1540 ts << m_doc->line(lastln);
1541 ts.flush();
1542 m_proc->closeWriteChannel();
1543}
1544
1545void KateModOnHdPrompt::slotDataAvailable()
1546{
1547 m_diffFile->write(m_proc->readAll());
1548}
1549
1550void KateModOnHdPrompt::slotPDone()
1551{
1552 m_diffAction->setEnabled(true);
1553
1554 const QProcess::ExitStatus es = m_proc->exitStatus();
1555 delete m_proc;
1556 m_proc = nullptr;
1557
1558 if (es != QProcess::NormalExit) {
1559 KMessageBox::error(m_doc->activeView(),
1560 i18n("The diff command failed. Please make sure that "
1561 "diff(1) is installed and in your PATH."),
1562 i18n("Error Creating Diff"));
1563 delete m_diffFile;
1564 m_diffFile = nullptr;
1565 return;
1566 }
1567
1568 if (m_diffFile->size() == 0) {
1569 KMessageBox::information(m_doc->activeView(), i18n("The files are identical."), i18n("Diff Output"));
1570 delete m_diffFile;
1571 m_diffFile = nullptr;
1572 return;
1573 }
1574
1575 m_diffFile->setAutoRemove(false);
1576 QUrl url = QUrl::fromLocalFile(m_diffFile->fileName());
1577 delete m_diffFile;
1578 m_diffFile = nullptr;
1579
1580 KIO::OpenUrlJob *job = new KIO::OpenUrlJob(url, QStringLiteral("text/x-patch"));
1582 job->setDeleteTemporaryFile(true); // delete the file, once the client exits
1583 job->start();
1584}
1585
1586// END KateModOnHdPrompt
1587
1588#include "moc_katedialogs.cpp"
QString encodingForName(const QString &descriptiveName) const
static KCharsets * charsets()
static QString nameForProberType(ProberType proberType)
void setDeleteTemporaryFile(bool b)
void start() override
void setUiDelegate(KJobUiDelegate *delegate)
void start()
void setOutputChannelMode(OutputChannelMode mode)
virtual void apply()=0
This slot is called whenever the button Apply or OK was clicked.
virtual void reset()=0
This slot is called whenever the button Reset was clicked.
virtual QString name() const =0
Get a readable name for the config page.
virtual void defaults()=0
Sets default options This slot is called whenever the button Defaults was clicked.
The Cursor represents a position in a Document.
Definition cursor.h:75
constexpr int line() const noexcept
Retrieve the line on which this cursor is situated.
Definition cursor.h:174
Backend of KTextEditor::Document related public KTextEditor interfaces.
QString line(int line) const override
Get a single text line.
int lines() const override
Get the count of lines of the document.
A KParts derived class representing a text document.
Definition document.h:284
void textChanged(KTextEditor::Document *document)
The document emits this signal whenever its text changes.
virtual int lines() const =0
Get the count of lines of the document.
virtual bool postMessage(Message *message)=0
Post message to the Document and its Views.
ModifiedOnDiskReason
Reasons why a document is modified on disk.
Definition document.h:1429
@ OnDiskDeleted
The file was deleted or moved on disk.
Definition document.h:1433
static KTextEditor::EditorPrivate * self()
Kate Part Internal stuff ;)
QList< KTextEditor::Document * > documents() override
Returns a list of all documents of this editor.
Definition kateglobal.h:99
static Editor * instance()
Accessor to get the Editor instance.
void addVariableExpansion(const QList< QWidget * > &widgets, const QStringList &variables=QStringList()) const
Adds a QAction to the widget in widgets that whenever focus is gained.
This class holds a Message to display in Views.
Definition message.h:94
@ AboveView
show message above view.
Definition message.h:119
@ BottomInView
show message as view overlay in the bottom right corner.
Definition message.h:125
An object representing a section of text, from one Cursor to another.
constexpr bool isEmpty() const noexcept
Returns true if this range contains no characters, ie.
constexpr bool isValid() const noexcept
Validity check.
A text widget with KXMLGUIClient that represents a Document.
Definition view.h:244
virtual bool setCursorPosition(Cursor position)=0
Set the view's new cursor to position.
virtual Document * document() const =0
Get the view's document, that means the view is a view of the returned document.
virtual Cursor cursorPosition() const =0
Get the view's current cursor position.
static uint modeNumber(const QString &name)
Maps name -> index.
const QString & modeName() const
mode name
static QStringList listModes()
List all possible modes by name, i.e.
void configEnd()
End a config change transaction, update the concerned KateDocumentConfig/KateDocumentConfig/KateDocum...
void configStart()
Start some config changes.
bool setValue(const int key, const QVariant &value)
Set a config value.
QVariant value(const int key) const
Get a config value.
void dictionaryChanged(const QString &dictionary)
void setCurrentByDictionary(const QString &dictionary)
KLocalizedString KI18N_EXPORT ki18np(const char *singular, const char *plural)
QString i18nc(const char *context, const char *text, const TYPE &arg...)
KLocalizedString KI18N_EXPORT ki18ncp(const char *context, const char *singular, const char *plural)
QString i18n(const char *text, const TYPE &arg...)
KIOCORE_EXPORT KJobUiDelegate * createDefaultJobUiDelegate()
void setupSpinBoxFormatString(T *spinBox, const KLocalizedString &formatString)
void information(QWidget *parent, const QString &text, const QString &title=QString(), const QString &dontShowAgainName=QString(), Options options=Notify)
void error(QWidget *parent, const QString &text, const QString &title, const KGuiItem &buttonOk, Options options=Notify)
const QList< QKeySequence > & reload()
QString label(StandardShortcut id)
The KTextEditor namespace contains all the public API that is required to use the KTextEditor compone...
void clicked(bool checked)
void setIcon(const QIcon &icon)
void setText(const QString &text)
void toggled(bool checked)
void setEnabled(bool)
void setIcon(const QIcon &icon)
void setToolTip(const QString &tip)
void triggered(bool checked)
void addStretch(int stretch)
void addWidget(QWidget *widget, int stretch, Qt::Alignment alignment)
bool setStretchFactor(QLayout *layout, int stretch)
void stateChanged(int state)
void currentIndexChanged(int index)
QPoint pos()
QDir temp()
virtual qint64 size() const const override
QFont systemFont(SystemFont type)
QClipboard * clipboard()
QIcon fromTheme(const QString &name)
QByteArray readAll()
void readyRead()
qint64 write(const QByteArray &data)
void linkActivated(const QString &link)
void addWidget(QWidget *w)
void setContentsMargins(const QMargins &margins)
void editingFinished()
void append(QList< T > &&value)
const_reference at(qsizetype i) const const
qsizetype size() const const
Q_EMITQ_EMIT
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
bool disconnect(const QMetaObject::Connection &connection)
void installEventFilter(QObject *filterObj)
T qobject_cast(QObject *object)
void closeWriteChannel()
QProcess::ExitStatus exitStatus() const const
void finished(int exitCode, QProcess::ExitStatus exitStatus)
int height() const const
void setMaximum(int max)
void setValue(int val)
bool isEmpty() const const
ToolTipRole
Key_Return
typedef KeyboardModifiers
LinksAccessibleByMouse
ToolButtonTextBesideIcon
QTextStream & bom(QTextStream &stream)
int addTab(QWidget *page, const QIcon &icon, const QString &label)
void setDocumentMode(bool set)
int insertTab(int index, QWidget *page, const QIcon &icon, const QString &label)
virtual QString fileName() const const override
void setAutoRemove(bool b)
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)
void setAutoRaise(bool enable)
virtual QSize minimumSizeHint() const const override
void setDefaultAction(QAction *action)
void setToolButtonStyle(Qt::ToolButtonStyle style)
QUrl fromLocalFile(const QString &localFile)
QString toLocalFile() const const
QStringList toStringList() const const
void showText(const QPoint &pos, const QString &text, QWidget *w)
void adjustSize()
virtual bool event(QEvent *event) override
virtual void keyPressEvent(QKeyEvent *event)
void setMinimumSize(const QSize &)
void setDisabled(bool disable)
void setFocus()
void setToolTip(const QString &)
bool isVisible() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Mon Nov 18 2024 12:11:26 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.