File indexing completed on 2024-04-28 05:49:28

0001 /* This file is part of the KDE project
0002    SPDX-FileCopyrightText: 2001 Christoph Cullmann <cullmann@kde.org>
0003    SPDX-FileCopyrightText: 2002 Joseph Wenninger <jowenn@kde.org>
0004    SPDX-FileCopyrightText: 2007 Mirko Stocker <me@misto.ch>
0005 
0006    For the addScrollablePage original
0007    SPDX-FileCopyrightText: 2003 Benjamin C Meyer <ben+kdelibs at meyerhome dot net>
0008    SPDX-FileCopyrightText: 2003 Waldo Bastian <bastian@kde.org>
0009    SPDX-FileCopyrightText: 2004 Michael Brade <brade@kde.org>
0010    SPDX-FileCopyrightText: 2021 Ahmad Samir <a.samirh78@gmail.com>
0011 
0012    SPDX-License-Identifier: LGPL-2.0-only
0013 */
0014 
0015 #include "kateconfigdialog.h"
0016 
0017 #include "kateapp.h"
0018 #include "kateconfigplugindialogpage.h"
0019 #include "katedebug.h"
0020 #include "katedocmanager.h"
0021 #include "katemainwindow.h"
0022 #include "katepluginmanager.h"
0023 #include "katequickopenmodel.h"
0024 #include "katesessionmanager.h"
0025 #include "kateviewmanager.h"
0026 
0027 #include <KConfigGroup>
0028 #include <KLocalizedString>
0029 #include <KMessageBox>
0030 #include <KPluralHandlingSpinBox>
0031 #include <KSharedConfig>
0032 #include <kwidgetsaddons_version.h>
0033 
0034 #include <QCheckBox>
0035 #include <QComboBox>
0036 #include <QDesktopServices>
0037 #include <QDialogButtonBox>
0038 #include <QFrame>
0039 #include <QGroupBox>
0040 #include <QLabel>
0041 #include <QLineEdit>
0042 #include <QListView>
0043 #include <QPainter>
0044 #include <QScreen>
0045 #include <QScrollArea>
0046 #include <QScrollBar>
0047 #include <QTimer>
0048 #include <QVBoxLayout>
0049 
0050 KateConfigDialog::KateConfigDialog(KateMainWindow *parent)
0051     : KPageDialog(parent)
0052     , m_mainWindow(parent)
0053 {
0054     setWindowTitle(i18n("Configure"));
0055     setWindowIcon(QIcon::fromTheme(QStringLiteral("configure")));
0056     setStandardButtons(QDialogButtonBox::Ok | QDialogButtonBox::Apply | QDialogButtonBox::Cancel | QDialogButtonBox::Help);
0057 
0058     // we may have a lot of pages on Kate, we want small icons for the list
0059     if (KateApp::isKate()) {
0060         setFaceType(KPageDialog::FlatList);
0061     } else {
0062         setFaceType(KPageDialog::List);
0063     }
0064 
0065     const auto listViews = findChildren<QListView *>();
0066     for (auto *lv : listViews) {
0067         if (qstrcmp(lv->metaObject()->className(), "KDEPrivate::KPageListView") == 0) {
0068             m_sideBar = lv;
0069             break;
0070         }
0071     }
0072     if (!m_sideBar) {
0073         qWarning() << "Unable to find config dialog sidebar listview!!";
0074     }
0075 
0076     // first: add the KTextEditor config pages
0077     // rational: most people want to alter e.g. the fonts, the colors or some other editor stuff first
0078     addEditorPages();
0079 
0080     // second: add out own config pages
0081     // this includes all plugin config pages, added to the bottom
0082     addBehaviorPage();
0083     addSessionPage();
0084     addFeedbackPage();
0085 
0086     // no plugins for KWrite
0087     if (KateApp::isKate()) {
0088         addPluginsPage();
0089         addPluginPages();
0090     }
0091 
0092     // ensure no stray signals already set this!
0093     m_dataChanged = false;
0094     buttonBox()->button(QDialogButtonBox::Apply)->setEnabled(false);
0095 
0096     // handle dialog actions
0097     connect(this, &KateConfigDialog::accepted, this, &KateConfigDialog::slotApply);
0098     connect(buttonBox()->button(QDialogButtonBox::Apply), &QPushButton::clicked, this, &KateConfigDialog::slotApply);
0099     connect(buttonBox()->button(QDialogButtonBox::Help), &QPushButton::clicked, this, &KateConfigDialog::slotHelp);
0100 }
0101 
0102 QSize KateConfigDialog::sizeHint() const
0103 {
0104     // start with a bit enlarged default size hint to minimize changes of useless scrollbars
0105     QSize size = KPageDialog::sizeHint() * 1.3;
0106 
0107     // enlarge it to half of the main window size, if that is larger
0108     size = size.expandedTo(m_mainWindow->size() * 0.5);
0109 
0110     // return bounded size to available real screen space
0111     return size.boundedTo(screen()->availableSize() * 0.9);
0112 }
0113 
0114 void KateConfigDialog::addBehaviorPage()
0115 {
0116     KSharedConfig::Ptr config = KSharedConfig::openConfig();
0117     KConfigGroup cgGeneral = KConfigGroup(config, QStringLiteral("General"));
0118 
0119     QFrame *generalFrame = new QFrame;
0120     KPageWidgetItem *item = addScrollablePage(generalFrame, i18n("Behavior"));
0121     m_allPages.insert(item);
0122     item->setHeader(i18n("Behavior Options"));
0123     item->setIcon(QIcon::fromTheme(QStringLiteral("preferences-system-windows-behavior")));
0124 
0125     QVBoxLayout *layout = new QVBoxLayout(generalFrame);
0126 
0127     // GROUP with the one below: "Behavior"
0128     QGroupBox *buttonGroup = new QGroupBox(i18n("&Behavior"), generalFrame);
0129     QVBoxLayout *vbox = new QVBoxLayout;
0130     layout->addWidget(buttonGroup);
0131 
0132     // shall we try to behave like some SDI application
0133     m_sdiMode = new QCheckBox(i18n("Open each document in its own window"), buttonGroup);
0134     m_sdiMode->setChecked(cgGeneral.readEntry("SDI Mode", false));
0135     m_sdiMode->setToolTip(
0136         i18n("If enabled, each document will be opened in its own window. "
0137              "If not enabled, each document will be opened in a new tab in the current window."));
0138     connect(m_sdiMode, &QCheckBox::toggled, this, &KateConfigDialog::slotChanged);
0139     vbox->addWidget(m_sdiMode);
0140 
0141     QHBoxLayout *hlayout = nullptr;
0142     QLabel *label = nullptr;
0143 
0144     if (KateApp::isKate()) {
0145         hlayout = new QHBoxLayout;
0146         label = new QLabel(i18n("&Switch to output view upon message type:"), buttonGroup);
0147         hlayout->addWidget(label);
0148         m_messageTypes = new QComboBox(buttonGroup);
0149         hlayout->addWidget(m_messageTypes);
0150         label->setBuddy(m_messageTypes);
0151         m_messageTypes->addItems({i18n("Never"), i18n("Error"), i18n("Warning"), i18n("Info"), i18n("Log")});
0152         m_messageTypes->setCurrentIndex(cgGeneral.readEntry("Show output view for message type", 1));
0153         connect(m_messageTypes, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, &KateConfigDialog::slotChanged);
0154         vbox->addLayout(hlayout);
0155 
0156         hlayout = new QHBoxLayout;
0157         label = new QLabel(i18n("&Limit output view history:"), buttonGroup);
0158         hlayout->addWidget(label);
0159         m_outputHistoryLimit = new QSpinBox(buttonGroup);
0160         hlayout->addWidget(m_outputHistoryLimit);
0161         label->setBuddy(m_outputHistoryLimit);
0162         m_outputHistoryLimit->setRange(-1, 10000);
0163         m_outputHistoryLimit->setSpecialValueText(i18n("Unlimited"));
0164         m_outputHistoryLimit->setValue(cgGeneral.readEntry("Output History Limit", 100));
0165         connect(m_outputHistoryLimit, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), this, &KateConfigDialog::slotChanged);
0166         vbox->addLayout(hlayout);
0167     }
0168 
0169     // modified files notification
0170     m_modNotifications = new QCheckBox(i18n("Use a separate &dialog for handling externally modified files"), buttonGroup);
0171     m_modNotifications->setChecked(m_mainWindow->modNotificationEnabled());
0172     m_modNotifications->setToolTip(
0173         i18n("If enabled, a modal dialog will be used to show all of the modified files. "
0174              "If not enabled, you will be individually asked what to do for each modified file "
0175              "only when that file's view receives focus."));
0176     connect(m_modNotifications, &QCheckBox::toggled, this, &KateConfigDialog::slotChanged);
0177 
0178     vbox->addWidget(m_modNotifications);
0179     buttonGroup->setLayout(vbox);
0180 
0181     if (KateApp::isKate()) {
0182         QGroupBox *buttonGroup = new QGroupBox(i18n("&Sidebars"), generalFrame);
0183         layout->addWidget(buttonGroup);
0184         QVBoxLayout *vbox = new QVBoxLayout;
0185         m_syncSectionSizeWithSidebarTabs = new QCheckBox(i18n("Sync section size with tab positions"), buttonGroup);
0186         m_syncSectionSizeWithSidebarTabs->setChecked(cgGeneral.readEntry("Sync section size with tab positions", false));
0187         m_syncSectionSizeWithSidebarTabs->setToolTip(
0188             i18n("When enabled the section size will be determined by the position of the tabs.\n"
0189                  "This option does not affect the bottom sidebar."));
0190         connect(m_syncSectionSizeWithSidebarTabs, &QCheckBox::toggled, this, &KateConfigDialog::slotChanged);
0191         vbox->addWidget(m_syncSectionSizeWithSidebarTabs);
0192 
0193         m_showTextForLeftRightSidebars = new QCheckBox(i18n("Show text for left and right sidebar buttons"), buttonGroup);
0194         m_showTextForLeftRightSidebars->setChecked(cgGeneral.readEntry("Show text for left and right sidebar", false));
0195         connect(m_showTextForLeftRightSidebars, &QCheckBox::toggled, this, &KateConfigDialog::slotChanged);
0196         vbox->addWidget(m_showTextForLeftRightSidebars);
0197 
0198         label = new QLabel(i18n("Icon size for left and right sidebar buttons"), buttonGroup);
0199         m_leftRightSidebarsIconSize = new QSpinBox(buttonGroup);
0200         m_leftRightSidebarsIconSize->setMinimum(16);
0201         m_leftRightSidebarsIconSize->setMaximum(48);
0202         m_leftRightSidebarsIconSize->setValue(cgGeneral.readEntry("Icon size for left and right sidebar buttons", 32));
0203         connect(m_leftRightSidebarsIconSize, &QSpinBox::textChanged, this, &KateConfigDialog::slotChanged);
0204         hlayout = new QHBoxLayout;
0205         hlayout->addWidget(label);
0206         hlayout->addWidget(m_leftRightSidebarsIconSize);
0207         vbox->addLayout(hlayout);
0208 
0209         connect(m_showTextForLeftRightSidebars, &QCheckBox::toggled, this, [l = QPointer(label), this](bool v) {
0210             m_leftRightSidebarsIconSize->setEnabled(!v);
0211             l->setEnabled(!v);
0212         });
0213         buttonGroup->setLayout(vbox);
0214     }
0215 
0216     // tabbar => we allow to configure some limit on number of tabs to show
0217     buttonGroup = new QGroupBox(i18n("&Tabs"), generalFrame);
0218     vbox = new QVBoxLayout;
0219     buttonGroup->setLayout(vbox);
0220     hlayout = new QHBoxLayout;
0221     label = new QLabel(i18n("&Limit number of tabs:"), buttonGroup);
0222     hlayout->addWidget(label);
0223     m_tabLimit = new QSpinBox(buttonGroup);
0224     hlayout->addWidget(m_tabLimit);
0225     label->setBuddy(m_tabLimit);
0226     m_tabLimit->setRange(0, 256);
0227     m_tabLimit->setSpecialValueText(i18n("Unlimited"));
0228     m_tabLimit->setValue(cgGeneral.readEntry("Tabbar Tab Limit", 0));
0229     connect(m_tabLimit, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), this, &KateConfigDialog::slotChanged);
0230     vbox->addLayout(hlayout);
0231     label =
0232         new QLabel(i18n("A high limit can increase the window size, please enable 'Allow tab scrolling' to prevent it. Unlimited tabs are always scrollable."));
0233     label->setWordWrap(true);
0234     vbox->addWidget(label);
0235 
0236     m_autoHideTabs = new QCheckBox(i18n("&Auto hide tabs"), buttonGroup);
0237     m_autoHideTabs->setChecked(cgGeneral.readEntry("Auto Hide Tabs", KateApp::isKWrite()));
0238     m_autoHideTabs->setToolTip(i18n("When checked tabs will be hidden if only one document is open."));
0239     connect(m_autoHideTabs, &QCheckBox::toggled, this, &KateConfigDialog::slotChanged);
0240     vbox->addWidget(m_autoHideTabs);
0241 
0242     m_showTabCloseButton = new QCheckBox(i18n("&Show close button"), buttonGroup);
0243     m_showTabCloseButton->setChecked(cgGeneral.readEntry("Show Tabs Close Button", true));
0244     m_showTabCloseButton->setToolTip(i18n("When checked each tab will display a close button."));
0245     connect(m_showTabCloseButton, &QCheckBox::toggled, this, &KateConfigDialog::slotChanged);
0246     vbox->addWidget(m_showTabCloseButton);
0247 
0248     m_expandTabs = new QCheckBox(i18n("&Expand tabs"), buttonGroup);
0249     m_expandTabs->setChecked(cgGeneral.readEntry("Expand Tabs", false));
0250     m_expandTabs->setToolTip(i18n("When checked tabs take as much size as possible."));
0251     connect(m_expandTabs, &QCheckBox::toggled, this, &KateConfigDialog::slotChanged);
0252     vbox->addWidget(m_expandTabs);
0253 
0254     m_tabDoubleClickNewDocument = new QCheckBox(i18n("&Double click opens a new document"), buttonGroup);
0255     m_tabDoubleClickNewDocument->setChecked(cgGeneral.readEntry("Tab Double Click New Document", true));
0256     m_tabDoubleClickNewDocument->setToolTip(i18n("When checked double click opens a new document."));
0257     connect(m_tabDoubleClickNewDocument, &QCheckBox::toggled, this, &KateConfigDialog::slotChanged);
0258     vbox->addWidget(m_tabDoubleClickNewDocument);
0259 
0260     m_tabMiddleClickCloseDocument = new QCheckBox(i18n("&Middle click closes a document"), buttonGroup);
0261     m_tabMiddleClickCloseDocument->setChecked(cgGeneral.readEntry("Tab Middle Click Close Document", true));
0262     m_tabMiddleClickCloseDocument->setToolTip(i18n("When checked middle click closes a document."));
0263     connect(m_tabMiddleClickCloseDocument, &QCheckBox::toggled, this, &KateConfigDialog::slotChanged);
0264     vbox->addWidget(m_tabMiddleClickCloseDocument);
0265 
0266     m_tabsScrollable = new QCheckBox(i18n("Allow tab scrolling"), this);
0267     m_tabsScrollable->setChecked(cgGeneral.readEntry("Allow Tab Scrolling", true));
0268     m_tabsScrollable->setToolTip(i18n("When checked this will allow scrolling in tab bar when number of tabs is large."));
0269     connect(m_tabsScrollable, &QCheckBox::toggled, this, &KateConfigDialog::slotChanged);
0270     vbox->addWidget(m_tabsScrollable);
0271 
0272     m_tabsElided = new QCheckBox(i18n("Elide tab text"), this);
0273     m_tabsElided->setChecked(cgGeneral.readEntry("Elide Tab Text", false));
0274     m_tabsElided->setToolTip(i18n("When checked tab text might be elided if its too long."));
0275     connect(m_tabsElided, &QCheckBox::toggled, this, &KateConfigDialog::slotChanged);
0276     vbox->addWidget(m_tabsElided);
0277 
0278     m_openNewTabInFrontOfCurrent = new QCheckBox(i18n("Open new tab to the right of current tab."), this);
0279     m_openNewTabInFrontOfCurrent->setChecked(cgGeneral.readEntry("Open New Tab To The Right Of Current", false));
0280     m_openNewTabInFrontOfCurrent->setToolTip(i18n("If unchecked the new tab will open at the end."));
0281     connect(m_openNewTabInFrontOfCurrent, &QCheckBox::toggled, this, &KateConfigDialog::slotChanged);
0282     vbox->addWidget(m_openNewTabInFrontOfCurrent);
0283 
0284     layout->addWidget(buttonGroup);
0285 
0286     buttonGroup = new QGroupBox(i18n("&Mouse"), generalFrame);
0287     vbox = new QVBoxLayout;
0288     layout->addWidget(buttonGroup);
0289 
0290     hlayout = new QHBoxLayout;
0291     label = new QLabel(i18n("&Backward button pressed:"), buttonGroup);
0292     hlayout->addWidget(label);
0293     m_mouseBackActions = new QComboBox(buttonGroup);
0294     hlayout->addWidget(m_mouseBackActions);
0295     label->setBuddy(m_mouseBackActions);
0296     m_mouseBackActions->addItems({i18n("Previous tab"), i18n("History back")});
0297     m_mouseBackActions->setCurrentIndex(cgGeneral.readEntry("Mouse back button action", 0));
0298     connect(m_mouseBackActions, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, &KateConfigDialog::slotChanged);
0299     vbox->addLayout(hlayout);
0300 
0301     hlayout = new QHBoxLayout;
0302     label = new QLabel(i18n("&Forward button pressed:"), buttonGroup);
0303     hlayout->addWidget(label);
0304     m_mouseForwardActions = new QComboBox(buttonGroup);
0305     hlayout->addWidget(m_mouseForwardActions);
0306     label->setBuddy(m_mouseForwardActions);
0307     m_mouseForwardActions->addItems({i18n("Next tab"), i18n("History forward")});
0308     m_mouseForwardActions->setCurrentIndex(cgGeneral.readEntry("Mouse forward button action", 0));
0309     connect(m_mouseForwardActions, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, &KateConfigDialog::slotChanged);
0310     vbox->addLayout(hlayout);
0311 
0312     buttonGroup->setLayout(vbox);
0313 
0314     /** DIFF **/
0315     buttonGroup = new QGroupBox(i18n("Diff"), generalFrame);
0316     vbox = new QVBoxLayout(buttonGroup);
0317     hlayout = new QHBoxLayout;
0318     vbox->addLayout(hlayout);
0319     layout->addWidget(buttonGroup);
0320     m_diffStyle = new QComboBox;
0321     m_diffStyle->addItem(i18n("Side By Side"));
0322     m_diffStyle->addItem(i18n("Unified"));
0323     m_diffStyle->addItem(i18n("Raw"));
0324     hlayout->addWidget(new QLabel(i18n("Diff Style:")));
0325     hlayout->addWidget(m_diffStyle);
0326     m_diffStyle->setCurrentIndex(cgGeneral.readEntry("Diff Show Style", 0));
0327     connect(m_diffStyle, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, &KateConfigDialog::slotChanged);
0328 
0329     buttonGroup = new QGroupBox(i18n("Navigation Bar"), generalFrame);
0330     vbox = new QVBoxLayout(buttonGroup);
0331     hlayout = new QHBoxLayout;
0332     vbox->addLayout(hlayout);
0333     layout->addWidget(buttonGroup);
0334     m_urlBarShowSymbols = new QCheckBox(i18n("Show current symbol in navigation bar"));
0335     hlayout->addWidget(m_urlBarShowSymbols);
0336     m_urlBarShowSymbols->setChecked(cgGeneral.readEntry("Show Symbol In Navigation Bar", true));
0337     connect(m_urlBarShowSymbols, &QCheckBox::toggled, this, &KateConfigDialog::slotChanged);
0338 
0339     buttonGroup = new QGroupBox(i18n("Diagnostics"), generalFrame);
0340     vbox = new QVBoxLayout(buttonGroup);
0341     hlayout = new QHBoxLayout;
0342     vbox->addLayout(hlayout);
0343     layout->addWidget(buttonGroup);
0344     label = new QLabel(i18n("Diagnostics limit:"), buttonGroup);
0345     m_diagnosticsLimit = new QSpinBox(buttonGroup);
0346     m_diagnosticsLimit->setRange(-1, 50000);
0347     m_diagnosticsLimit->setSpecialValueText(i18n("Unlimited"));
0348     m_diagnosticsLimit->setValue(cgGeneral.readEntry("Diagnostics Limit", 12000));
0349     m_diagnosticsLimit->setToolTip(i18n("Max number of diagnostics allowed in the Diagnostics toolview."));
0350     label->setBuddy(m_diagnosticsLimit);
0351     hlayout->addWidget(label);
0352     hlayout->addWidget(m_diagnosticsLimit);
0353     connect(m_diagnosticsLimit, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), this, &KateConfigDialog::slotChanged);
0354 
0355     layout->addStretch(1); // :-] works correct without autoadd
0356 }
0357 
0358 void KateConfigDialog::addSessionPage()
0359 {
0360     KSharedConfig::Ptr config = KSharedConfig::openConfig();
0361     KConfigGroup cgGeneral = KConfigGroup(config, QStringLiteral("General"));
0362 
0363     QWidget *sessionsPage = new QWidget();
0364     auto item = addScrollablePage(sessionsPage, i18n("Session"));
0365     m_allPages.insert(item);
0366     item->setHeader(i18n("Session Management"));
0367     item->setIcon(QIcon::fromTheme(QStringLiteral("view-history")));
0368 
0369     sessionConfigUi.setupUi(sessionsPage);
0370 
0371     // save meta infos
0372     sessionConfigUi.saveMetaInfos->setChecked(KateApp::self()->documentManager()->getSaveMetaInfos());
0373     connect(sessionConfigUi.saveMetaInfos, &QGroupBox::toggled, this, &KateConfigDialog::slotChanged);
0374 
0375     // meta infos days
0376     sessionConfigUi.daysMetaInfos->setMaximum(180);
0377     sessionConfigUi.daysMetaInfos->setSpecialValueText(i18nc("The special case of 'Delete unused meta-information after'", "(never)"));
0378     sessionConfigUi.daysMetaInfos->setSuffix(ki18ncp("The suffix of 'Delete unused meta-information after'", " day", " days"));
0379     sessionConfigUi.daysMetaInfos->setValue(KateApp::self()->documentManager()->getDaysMetaInfos());
0380     connect(sessionConfigUi.daysMetaInfos,
0381             static_cast<void (KPluralHandlingSpinBox::*)(int)>(&KPluralHandlingSpinBox::valueChanged),
0382             this,
0383             &KateConfigDialog::slotChanged);
0384 
0385     // restore view  config
0386     sessionConfigUi.restoreVC->setChecked(cgGeneral.readEntry("Restore Window Configuration", true));
0387     connect(sessionConfigUi.restoreVC, &QCheckBox::toggled, this, &KateConfigDialog::slotChanged);
0388 
0389     sessionConfigUi.spinBoxRecentFilesCount->setValue(recentFilesMaxCount());
0390     connect(sessionConfigUi.spinBoxRecentFilesCount, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), this, &KateConfigDialog::slotChanged);
0391 
0392     QString sesStart(cgGeneral.readEntry("Startup Session", "manual"));
0393     if (sesStart == QLatin1String("new")) {
0394         sessionConfigUi.startNewSessionRadioButton->setChecked(true);
0395     } else if (sesStart == QLatin1String("last")) {
0396         sessionConfigUi.loadLastUserSessionRadioButton->setChecked(true);
0397     } else {
0398         sessionConfigUi.manuallyChooseSessionRadioButton->setChecked(true);
0399     }
0400 
0401     connect(sessionConfigUi.startNewSessionRadioButton, &QRadioButton::toggled, this, &KateConfigDialog::slotChanged);
0402     connect(sessionConfigUi.loadLastUserSessionRadioButton, &QRadioButton::toggled, this, &KateConfigDialog::slotChanged);
0403     connect(sessionConfigUi.manuallyChooseSessionRadioButton, &QRadioButton::toggled, this, &KateConfigDialog::slotChanged);
0404 
0405     // New main windows open always a new document if none there
0406     sessionConfigUi.showWelcomeViewForNewWindow->setChecked(cgGeneral.readEntry("Show welcome view for new window", true));
0407     connect(sessionConfigUi.showWelcomeViewForNewWindow, &QCheckBox::toggled, this, &KateConfigDialog::slotChanged);
0408 
0409     // When a window is closed, close all documents only visible in that window, too
0410     sessionConfigUi.winClosesDocuments->setChecked(cgGeneral.readEntry("Close documents with window", true));
0411     sessionConfigUi.winClosesDocuments->setToolTip(i18n("When a window is closed the documents opened only in this window are closed as well."));
0412     connect(sessionConfigUi.winClosesDocuments, &QCheckBox::toggled, this, &KateConfigDialog::slotChanged);
0413 
0414     // Closing last file closes Kate
0415     sessionConfigUi.modCloseAfterLast->setChecked(m_mainWindow->modCloseAfterLast());
0416     connect(sessionConfigUi.modCloseAfterLast, &QCheckBox::toggled, this, &KateConfigDialog::slotChanged);
0417 
0418     // stash unsave changes
0419     sessionConfigUi.stashNewUnsavedFiles->setChecked(KateApp::self()->stashManager()->stashNewUnsavedFiles());
0420     sessionConfigUi.stashUnsavedFilesChanges->setChecked(KateApp::self()->stashManager()->stashUnsavedChanges());
0421     connect(sessionConfigUi.stashNewUnsavedFiles, &QRadioButton::toggled, this, &KateConfigDialog::slotChanged);
0422     connect(sessionConfigUi.stashUnsavedFilesChanges, &QRadioButton::toggled, this, &KateConfigDialog::slotChanged);
0423 
0424     // simplify the session page for KWrite
0425     if (KateApp::isKWrite()) {
0426         sessionConfigUi.gbAppStartup->hide();
0427         sessionConfigUi.restoreVC->hide();
0428         sessionConfigUi.label_4->hide();
0429         sessionConfigUi.stashNewUnsavedFiles->hide();
0430         sessionConfigUi.stashUnsavedFilesChanges->hide();
0431         sessionConfigUi.label->hide();
0432     }
0433 }
0434 
0435 void KateConfigDialog::addPluginsPage()
0436 {
0437     QFrame *page = new QFrame(this);
0438     QVBoxLayout *vlayout = new QVBoxLayout(page);
0439     vlayout->setContentsMargins(0, 0, 0, 0);
0440     vlayout->setSpacing(0);
0441 
0442     m_configPluginPage = new KateConfigPluginPage(page, this);
0443     vlayout->addWidget(m_configPluginPage);
0444     connect(m_configPluginPage, &KateConfigPluginPage::changed, this, &KateConfigDialog::slotChanged);
0445 
0446     auto item = addScrollablePage(page, i18n("Plugins"));
0447     m_allPages.insert(item);
0448     item->setHeader(i18n("Plugin Manager"));
0449     item->setIcon(QIcon::fromTheme(QStringLiteral("preferences-plugin")));
0450 }
0451 
0452 void KateConfigDialog::addFeedbackPage()
0453 {
0454 #ifdef WITH_KUSERFEEDBACK
0455     // KUserFeedback Config
0456     auto page = new QFrame(this);
0457     auto vlayout = new QVBoxLayout(page);
0458     vlayout->setContentsMargins(0, 0, 0, 0);
0459     vlayout->setSpacing(0);
0460 
0461     m_userFeedbackWidget = new KUserFeedback::FeedbackConfigWidget(page);
0462     m_userFeedbackWidget->setFeedbackProvider(&KateApp::self()->userFeedbackProvider());
0463     connect(m_userFeedbackWidget, &KUserFeedback::FeedbackConfigWidget::configurationChanged, this, &KateConfigDialog::slotChanged);
0464     vlayout->addWidget(m_userFeedbackWidget);
0465 
0466     auto item = addScrollablePage(page, i18n("User Feedback"));
0467     m_allPages.insert(item);
0468     item->setHeader(i18n("User Feedback"));
0469     item->setIcon(QIcon::fromTheme(QStringLiteral("preferences-desktop-locale")));
0470 #endif
0471 }
0472 
0473 void KateConfigDialog::addPluginPages()
0474 {
0475     const KatePluginList &pluginList(KateApp::self()->pluginManager()->pluginList());
0476     for (const KatePluginInfo &plugin : pluginList) {
0477         if (plugin.plugin) {
0478             addPluginPage(plugin.plugin);
0479         }
0480     }
0481 }
0482 
0483 void KateConfigDialog::addEditorPages()
0484 {
0485     for (int i = 0; i < KTextEditor::Editor::instance()->configPages(); ++i) {
0486         KTextEditor::ConfigPage *page = KTextEditor::Editor::instance()->configPage(i, this);
0487         connect(page, &KTextEditor::ConfigPage::changed, this, &KateConfigDialog::slotChanged);
0488         m_editorPages.push_back(page);
0489         KPageWidgetItem *item = addScrollablePage(page, page->name());
0490         item->setHeader(page->fullName());
0491         item->setIcon(page->icon());
0492         m_allPages.insert(item);
0493     }
0494 }
0495 
0496 void KateConfigDialog::addPluginPage(KTextEditor::Plugin *plugin)
0497 {
0498     for (int i = 0; i < plugin->configPages(); i++) {
0499         KTextEditor::ConfigPage *cp = plugin->configPage(i, this);
0500         KPageWidgetItem *item = addScrollablePage(cp, cp->name());
0501         item->setHeader(cp->fullName());
0502         item->setIcon(cp->icon());
0503 
0504         PluginPageListItem info;
0505         info.plugin = plugin;
0506         info.pluginPage = cp;
0507         info.idInPlugin = i;
0508         info.pageWidgetItem = item;
0509         connect(info.pluginPage, &KTextEditor::ConfigPage::changed, this, &KateConfigDialog::slotChanged);
0510         m_pluginPages.insert(item, info);
0511         m_allPages.insert(item);
0512     }
0513 }
0514 
0515 void KateConfigDialog::removePluginPage(KTextEditor::Plugin *plugin)
0516 {
0517     std::vector<KPageWidgetItem *> remove;
0518     for (QHash<KPageWidgetItem *, PluginPageListItem>::const_iterator it = m_pluginPages.constBegin(); it != m_pluginPages.constEnd(); ++it) {
0519         const PluginPageListItem &pli = it.value();
0520 
0521         if (pli.plugin == plugin) {
0522             remove.push_back(it.key());
0523         }
0524     }
0525 
0526     qCDebug(LOG_KATE) << remove.size();
0527     while (!remove.empty()) {
0528         KPageWidgetItem *wItem = remove.back();
0529         remove.pop_back();
0530         PluginPageListItem item = m_pluginPages.take(wItem);
0531         m_allPages.remove(wItem);
0532         delete item.pluginPage;
0533         removePage(wItem);
0534     }
0535 }
0536 
0537 void KateConfigDialog::slotApply()
0538 {
0539     KSharedConfig::Ptr config = KSharedConfig::openConfig();
0540 
0541     // if data changed apply the kate app stuff
0542     if (m_dataChanged) {
0543         // apply plugin load state changes
0544         if (m_configPluginPage) {
0545             m_configPluginPage->slotApply();
0546         }
0547 
0548         KConfigGroup cg(config, QStringLiteral("General"));
0549 
0550         cg.writeEntry("SDI Mode", m_sdiMode->isChecked());
0551 
0552         // only there for kate
0553         if (m_syncSectionSizeWithSidebarTabs) {
0554             cg.writeEntry("Sync section size with tab positions", m_syncSectionSizeWithSidebarTabs->isChecked());
0555         }
0556         if (m_showTextForLeftRightSidebars) {
0557             cg.writeEntry("Show text for left and right sidebar", m_showTextForLeftRightSidebars->isChecked());
0558         }
0559         if (m_leftRightSidebarsIconSize) {
0560             cg.writeEntry("Icon size for left and right sidebar buttons", m_leftRightSidebarsIconSize->value());
0561         }
0562 
0563         cg.writeEntry("Restore Window Configuration", sessionConfigUi.restoreVC->isChecked());
0564 
0565         cg.writeEntry("Recent File List Entry Count", sessionConfigUi.spinBoxRecentFilesCount->value());
0566 
0567         if (sessionConfigUi.startNewSessionRadioButton->isChecked()) {
0568             cg.writeEntry("Startup Session", "new");
0569         } else if (sessionConfigUi.loadLastUserSessionRadioButton->isChecked()) {
0570             cg.writeEntry("Startup Session", "last");
0571         } else {
0572             cg.writeEntry("Startup Session", "manual");
0573         }
0574 
0575         cg.writeEntry("Save Meta Infos", sessionConfigUi.saveMetaInfos->isChecked());
0576         KateApp::self()->documentManager()->setSaveMetaInfos(sessionConfigUi.saveMetaInfos->isChecked());
0577 
0578         cg.writeEntry("Days Meta Infos", sessionConfigUi.daysMetaInfos->value());
0579         KateApp::self()->documentManager()->setDaysMetaInfos(sessionConfigUi.daysMetaInfos->value());
0580 
0581         cg.writeEntry("Show welcome view for new window", sessionConfigUi.showWelcomeViewForNewWindow->isChecked());
0582 
0583         cg.writeEntry("Close documents with window", sessionConfigUi.winClosesDocuments->isChecked());
0584 
0585         cg.writeEntry("Close After Last", sessionConfigUi.modCloseAfterLast->isChecked());
0586         m_mainWindow->setModCloseAfterLast(sessionConfigUi.modCloseAfterLast->isChecked());
0587 
0588         if (m_messageTypes && m_outputHistoryLimit) {
0589             cg.writeEntry("Show output view for message type", m_messageTypes->currentIndex());
0590             cg.writeEntry("Output History Limit", m_outputHistoryLimit->value());
0591         }
0592 
0593         cg.writeEntry("Mouse back button action", m_mouseBackActions->currentIndex());
0594         cg.writeEntry("Mouse forward button action", m_mouseForwardActions->currentIndex());
0595 
0596         cg.writeEntry("Stash unsaved file changes", sessionConfigUi.stashUnsavedFilesChanges->isChecked());
0597         KateApp::self()->stashManager()->setStashUnsavedChanges(sessionConfigUi.stashUnsavedFilesChanges->isChecked());
0598         cg.writeEntry("Stash new unsaved files", sessionConfigUi.stashNewUnsavedFiles->isChecked());
0599         KateApp::self()->stashManager()->setStashNewUnsavedFiles(sessionConfigUi.stashNewUnsavedFiles->isChecked());
0600 
0601         cg.writeEntry("Modified Notification", m_modNotifications->isChecked());
0602         m_mainWindow->setModNotificationEnabled(m_modNotifications->isChecked());
0603 
0604         cg.writeEntry("Tabbar Tab Limit", m_tabLimit->value());
0605 
0606         cg.writeEntry("Auto Hide Tabs", m_autoHideTabs->isChecked());
0607 
0608         cg.writeEntry("Show Tabs Close Button", m_showTabCloseButton->isChecked());
0609 
0610         cg.writeEntry("Expand Tabs", m_expandTabs->isChecked());
0611 
0612         cg.writeEntry("Tab Double Click New Document", m_tabDoubleClickNewDocument->isChecked());
0613         cg.writeEntry("Tab Middle Click Close Document", m_tabMiddleClickCloseDocument->isChecked());
0614 
0615         cg.writeEntry("Allow Tab Scrolling", m_tabsScrollable->isChecked());
0616         cg.writeEntry("Elide Tab Text", m_tabsElided->isChecked());
0617         cg.writeEntry("Open New Tab To The Right Of Current", m_openNewTabInFrontOfCurrent->isChecked());
0618 
0619         cg.writeEntry("Diff Show Style", m_diffStyle->currentIndex());
0620 
0621         cg.writeEntry("Show Symbol In Navigation Bar", m_urlBarShowSymbols->isChecked());
0622 
0623         cg.writeEntry("Diagnostics Limit", m_diagnosticsLimit->value());
0624 
0625         // patch document modified warn state
0626         const QList<KTextEditor::Document *> &docs = KateApp::self()->documentManager()->documentList();
0627         for (KTextEditor::Document *doc : docs) {
0628             doc->setModifiedOnDiskWarning(!m_modNotifications->isChecked());
0629         }
0630 
0631         m_mainWindow->saveOptions();
0632 
0633         // save plugin config !!
0634         KateSessionManager *sessionmanager = KateApp::self()->sessionManager();
0635         KConfig *sessionConfig = sessionmanager->activeSession()->config();
0636         KateApp::self()->pluginManager()->writeConfig(sessionConfig);
0637 
0638 #ifdef WITH_KUSERFEEDBACK
0639         // set current active mode + write back the config for future starts
0640         KateApp::self()->userFeedbackProvider().setTelemetryMode(m_userFeedbackWidget->telemetryMode());
0641         KateApp::self()->userFeedbackProvider().setSurveyInterval(m_userFeedbackWidget->surveyInterval());
0642 #endif
0643     }
0644 
0645     for (const PluginPageListItem &plugin : qAsConst(m_pluginPages)) {
0646         if (plugin.pluginPage) {
0647             plugin.pluginPage->apply();
0648         }
0649     }
0650 
0651     // apply ktexteditor pages
0652     for (KTextEditor::ConfigPage *page : m_editorPages) {
0653         page->apply();
0654     }
0655 
0656     config->sync();
0657 
0658     // emit config change
0659     if (m_dataChanged) {
0660         KateApp::self()->configurationChanged();
0661     }
0662 
0663     m_dataChanged = false;
0664     buttonBox()->button(QDialogButtonBox::Apply)->setEnabled(false);
0665 }
0666 
0667 void KateConfigDialog::slotChanged()
0668 {
0669     m_dataChanged = true;
0670     buttonBox()->button(QDialogButtonBox::Apply)->setEnabled(true);
0671 }
0672 
0673 void KateConfigDialog::showAppPluginPage(KTextEditor::Plugin *p, int id)
0674 {
0675     for (const PluginPageListItem &plugin : qAsConst(m_pluginPages)) {
0676         if ((plugin.plugin == p) && (id == plugin.idInPlugin)) {
0677             setCurrentPage(plugin.pageWidgetItem);
0678             break;
0679         }
0680     }
0681 }
0682 
0683 void KateConfigDialog::slotHelp()
0684 {
0685     QDesktopServices::openUrl(QUrl(QStringLiteral("help:/")));
0686 }
0687 
0688 int KateConfigDialog::recentFilesMaxCount()
0689 {
0690     int maxItems = KConfigGroup(KSharedConfig::openConfig(), QStringLiteral("General")).readEntry("Recent File List Entry Count", 10);
0691     return maxItems;
0692 }
0693 
0694 void KateConfigDialog::closeEvent(QCloseEvent *event)
0695 {
0696     if (!m_dataChanged) {
0697         event->accept();
0698         return;
0699     }
0700 
0701     const auto response = KMessageBox::warningTwoActionsCancel(this,
0702                                                                i18n("You have unsaved changes. Do you want to apply the changes or discard them?"),
0703                                                                i18n("Warning"),
0704                                                                KStandardGuiItem::save(),
0705                                                                KStandardGuiItem::discard(),
0706                                                                KStandardGuiItem::cancel());
0707     switch (response) {
0708     case KMessageBox::PrimaryAction:
0709         slotApply();
0710         Q_FALLTHROUGH();
0711     case KMessageBox::SecondaryAction:
0712         event->accept();
0713         break;
0714     case KMessageBox::Cancel:
0715         event->ignore();
0716         break;
0717     default:
0718         break;
0719     }
0720 }
0721 
0722 KPageWidgetItem *KateConfigDialog::addScrollablePage(QWidget *page, const QString &itemName)
0723 {
0724     // inspired by KPageWidgetItem *KConfigDialogPrivate::addPageInternal(QWidget *page, const QString &itemName, const QString &pixmapName, const QString
0725     // &header)
0726     QWidget *frame = new QWidget;
0727     QVBoxLayout *boxLayout = new QVBoxLayout(frame);
0728     boxLayout->setContentsMargins(0, 0, 0, 0);
0729     boxLayout->setContentsMargins(0, 0, 0, 0);
0730 
0731     QScrollArea *scroll = new QScrollArea;
0732     scroll->setFrameShape(QFrame::NoFrame);
0733     scroll->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);
0734     scroll->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
0735     scroll->setWidget(page);
0736     scroll->setWidgetResizable(true);
0737     scroll->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
0738 
0739     boxLayout->addWidget(scroll);
0740     return addPage(frame, itemName);
0741 }
0742 
0743 #include "moc_kateconfigdialog.cpp"