File indexing completed on 2024-05-12 09:55:40

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     layout->addStretch(1); // :-] works correct without autoadd
0340 }
0341 
0342 void KateConfigDialog::addSessionPage()
0343 {
0344     KSharedConfig::Ptr config = KSharedConfig::openConfig();
0345     KConfigGroup cgGeneral = KConfigGroup(config, QStringLiteral("General"));
0346 
0347     QWidget *sessionsPage = new QWidget();
0348     auto item = addScrollablePage(sessionsPage, i18n("Session"));
0349     m_allPages.insert(item);
0350     item->setHeader(i18n("Session Management"));
0351     item->setIcon(QIcon::fromTheme(QStringLiteral("view-history")));
0352 
0353     sessionConfigUi.setupUi(sessionsPage);
0354 
0355     // save meta infos
0356     sessionConfigUi.saveMetaInfos->setChecked(KateApp::self()->documentManager()->getSaveMetaInfos());
0357     connect(sessionConfigUi.saveMetaInfos, &QGroupBox::toggled, this, &KateConfigDialog::slotChanged);
0358 
0359     // meta infos days
0360     sessionConfigUi.daysMetaInfos->setMaximum(180);
0361     sessionConfigUi.daysMetaInfos->setSpecialValueText(i18nc("The special case of 'Delete unused meta-information after'", "(never)"));
0362     sessionConfigUi.daysMetaInfos->setSuffix(ki18ncp("The suffix of 'Delete unused meta-information after'", " day", " days"));
0363     sessionConfigUi.daysMetaInfos->setValue(KateApp::self()->documentManager()->getDaysMetaInfos());
0364     connect(sessionConfigUi.daysMetaInfos,
0365             static_cast<void (KPluralHandlingSpinBox::*)(int)>(&KPluralHandlingSpinBox::valueChanged),
0366             this,
0367             &KateConfigDialog::slotChanged);
0368 
0369     // restore view  config
0370     sessionConfigUi.restoreVC->setChecked(cgGeneral.readEntry("Restore Window Configuration", true));
0371     connect(sessionConfigUi.restoreVC, &QCheckBox::toggled, this, &KateConfigDialog::slotChanged);
0372 
0373     sessionConfigUi.spinBoxRecentFilesCount->setValue(recentFilesMaxCount());
0374     connect(sessionConfigUi.spinBoxRecentFilesCount, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), this, &KateConfigDialog::slotChanged);
0375 
0376     QString sesStart(cgGeneral.readEntry("Startup Session", "manual"));
0377     if (sesStart == QLatin1String("new")) {
0378         sessionConfigUi.startNewSessionRadioButton->setChecked(true);
0379     } else if (sesStart == QLatin1String("last")) {
0380         sessionConfigUi.loadLastUserSessionRadioButton->setChecked(true);
0381     } else {
0382         sessionConfigUi.manuallyChooseSessionRadioButton->setChecked(true);
0383     }
0384 
0385     connect(sessionConfigUi.startNewSessionRadioButton, &QRadioButton::toggled, this, &KateConfigDialog::slotChanged);
0386     connect(sessionConfigUi.loadLastUserSessionRadioButton, &QRadioButton::toggled, this, &KateConfigDialog::slotChanged);
0387     connect(sessionConfigUi.manuallyChooseSessionRadioButton, &QRadioButton::toggled, this, &KateConfigDialog::slotChanged);
0388 
0389     // New main windows open always a new document if none there
0390     sessionConfigUi.showWelcomeViewForNewWindow->setChecked(cgGeneral.readEntry("Show welcome view for new window", true));
0391     connect(sessionConfigUi.showWelcomeViewForNewWindow, &QCheckBox::toggled, this, &KateConfigDialog::slotChanged);
0392 
0393     // When a window is closed, close all documents only visible in that window, too
0394     sessionConfigUi.winClosesDocuments->setChecked(cgGeneral.readEntry("Close documents with window", true));
0395     sessionConfigUi.winClosesDocuments->setToolTip(i18n("When a window is closed the documents opened only in this window are closed as well."));
0396     connect(sessionConfigUi.winClosesDocuments, &QCheckBox::toggled, this, &KateConfigDialog::slotChanged);
0397 
0398     // Closing last file closes Kate
0399     sessionConfigUi.modCloseAfterLast->setChecked(m_mainWindow->modCloseAfterLast());
0400     connect(sessionConfigUi.modCloseAfterLast, &QCheckBox::toggled, this, &KateConfigDialog::slotChanged);
0401 
0402     // stash unsave changes
0403     sessionConfigUi.stashNewUnsavedFiles->setChecked(KateApp::self()->stashManager()->stashNewUnsavedFiles());
0404     sessionConfigUi.stashUnsavedFilesChanges->setChecked(KateApp::self()->stashManager()->stashUnsavedChanges());
0405     connect(sessionConfigUi.stashNewUnsavedFiles, &QRadioButton::toggled, this, &KateConfigDialog::slotChanged);
0406     connect(sessionConfigUi.stashUnsavedFilesChanges, &QRadioButton::toggled, this, &KateConfigDialog::slotChanged);
0407 
0408     // simplify the session page for KWrite
0409     if (KateApp::isKWrite()) {
0410         sessionConfigUi.gbAppStartup->hide();
0411         sessionConfigUi.restoreVC->hide();
0412         sessionConfigUi.label_4->hide();
0413         sessionConfigUi.stashNewUnsavedFiles->hide();
0414         sessionConfigUi.stashUnsavedFilesChanges->hide();
0415         sessionConfigUi.label->hide();
0416     }
0417 }
0418 
0419 void KateConfigDialog::addPluginsPage()
0420 {
0421     QFrame *page = new QFrame(this);
0422     QVBoxLayout *vlayout = new QVBoxLayout(page);
0423     vlayout->setContentsMargins(0, 0, 0, 0);
0424     vlayout->setSpacing(0);
0425 
0426     m_configPluginPage = new KateConfigPluginPage(page, this);
0427     vlayout->addWidget(m_configPluginPage);
0428     connect(m_configPluginPage, &KateConfigPluginPage::changed, this, &KateConfigDialog::slotChanged);
0429 
0430     auto item = addScrollablePage(page, i18n("Plugins"));
0431     m_allPages.insert(item);
0432     item->setHeader(i18n("Plugin Manager"));
0433     item->setIcon(QIcon::fromTheme(QStringLiteral("preferences-plugin")));
0434 }
0435 
0436 void KateConfigDialog::addFeedbackPage()
0437 {
0438 #ifdef WITH_KUSERFEEDBACK
0439     // KUserFeedback Config
0440     auto page = new QFrame(this);
0441     auto vlayout = new QVBoxLayout(page);
0442     vlayout->setContentsMargins(0, 0, 0, 0);
0443     vlayout->setSpacing(0);
0444 
0445     m_userFeedbackWidget = new KUserFeedback::FeedbackConfigWidget(page);
0446     m_userFeedbackWidget->setFeedbackProvider(&KateApp::self()->userFeedbackProvider());
0447     connect(m_userFeedbackWidget, &KUserFeedback::FeedbackConfigWidget::configurationChanged, this, &KateConfigDialog::slotChanged);
0448     vlayout->addWidget(m_userFeedbackWidget);
0449 
0450     auto item = addScrollablePage(page, i18n("User Feedback"));
0451     m_allPages.insert(item);
0452     item->setHeader(i18n("User Feedback"));
0453     item->setIcon(QIcon::fromTheme(QStringLiteral("preferences-desktop-locale")));
0454 #endif
0455 }
0456 
0457 void KateConfigDialog::addPluginPages()
0458 {
0459     const KatePluginList &pluginList(KateApp::self()->pluginManager()->pluginList());
0460     for (const KatePluginInfo &plugin : pluginList) {
0461         if (plugin.plugin) {
0462             addPluginPage(plugin.plugin);
0463         }
0464     }
0465 }
0466 
0467 void KateConfigDialog::addEditorPages()
0468 {
0469     for (int i = 0; i < KTextEditor::Editor::instance()->configPages(); ++i) {
0470         KTextEditor::ConfigPage *page = KTextEditor::Editor::instance()->configPage(i, this);
0471         connect(page, &KTextEditor::ConfigPage::changed, this, &KateConfigDialog::slotChanged);
0472         m_editorPages.push_back(page);
0473         KPageWidgetItem *item = addScrollablePage(page, page->name());
0474         item->setHeader(page->fullName());
0475         item->setIcon(page->icon());
0476         m_allPages.insert(item);
0477     }
0478 }
0479 
0480 void KateConfigDialog::addPluginPage(KTextEditor::Plugin *plugin)
0481 {
0482     for (int i = 0; i < plugin->configPages(); i++) {
0483         KTextEditor::ConfigPage *cp = plugin->configPage(i, this);
0484         KPageWidgetItem *item = addScrollablePage(cp, cp->name());
0485         item->setHeader(cp->fullName());
0486         item->setIcon(cp->icon());
0487 
0488         PluginPageListItem info;
0489         info.plugin = plugin;
0490         info.pluginPage = cp;
0491         info.idInPlugin = i;
0492         info.pageWidgetItem = item;
0493         connect(info.pluginPage, &KTextEditor::ConfigPage::changed, this, &KateConfigDialog::slotChanged);
0494         m_pluginPages.insert(item, info);
0495         m_allPages.insert(item);
0496     }
0497 }
0498 
0499 void KateConfigDialog::removePluginPage(KTextEditor::Plugin *plugin)
0500 {
0501     std::vector<KPageWidgetItem *> remove;
0502     for (QHash<KPageWidgetItem *, PluginPageListItem>::const_iterator it = m_pluginPages.constBegin(); it != m_pluginPages.constEnd(); ++it) {
0503         const PluginPageListItem &pli = it.value();
0504 
0505         if (pli.plugin == plugin) {
0506             remove.push_back(it.key());
0507         }
0508     }
0509 
0510     qCDebug(LOG_KATE) << remove.size();
0511     while (!remove.empty()) {
0512         KPageWidgetItem *wItem = remove.back();
0513         remove.pop_back();
0514         PluginPageListItem item = m_pluginPages.take(wItem);
0515         m_allPages.remove(wItem);
0516         delete item.pluginPage;
0517         removePage(wItem);
0518     }
0519 }
0520 
0521 void KateConfigDialog::slotApply()
0522 {
0523     KSharedConfig::Ptr config = KSharedConfig::openConfig();
0524 
0525     // if data changed apply the kate app stuff
0526     if (m_dataChanged) {
0527         // apply plugin load state changes
0528         if (m_configPluginPage) {
0529             m_configPluginPage->slotApply();
0530         }
0531 
0532         KConfigGroup cg(config, QStringLiteral("General"));
0533 
0534         cg.writeEntry("SDI Mode", m_sdiMode->isChecked());
0535 
0536         // only there for kate
0537         if (m_syncSectionSizeWithSidebarTabs) {
0538             cg.writeEntry("Sync section size with tab positions", m_syncSectionSizeWithSidebarTabs->isChecked());
0539         }
0540         if (m_showTextForLeftRightSidebars) {
0541             cg.writeEntry("Show text for left and right sidebar", m_showTextForLeftRightSidebars->isChecked());
0542         }
0543         if (m_leftRightSidebarsIconSize) {
0544             cg.writeEntry("Icon size for left and right sidebar buttons", m_leftRightSidebarsIconSize->value());
0545         }
0546 
0547         cg.writeEntry("Restore Window Configuration", sessionConfigUi.restoreVC->isChecked());
0548 
0549         cg.writeEntry("Recent File List Entry Count", sessionConfigUi.spinBoxRecentFilesCount->value());
0550 
0551         if (sessionConfigUi.startNewSessionRadioButton->isChecked()) {
0552             cg.writeEntry("Startup Session", "new");
0553         } else if (sessionConfigUi.loadLastUserSessionRadioButton->isChecked()) {
0554             cg.writeEntry("Startup Session", "last");
0555         } else {
0556             cg.writeEntry("Startup Session", "manual");
0557         }
0558 
0559         cg.writeEntry("Save Meta Infos", sessionConfigUi.saveMetaInfos->isChecked());
0560         KateApp::self()->documentManager()->setSaveMetaInfos(sessionConfigUi.saveMetaInfos->isChecked());
0561 
0562         cg.writeEntry("Days Meta Infos", sessionConfigUi.daysMetaInfos->value());
0563         KateApp::self()->documentManager()->setDaysMetaInfos(sessionConfigUi.daysMetaInfos->value());
0564 
0565         cg.writeEntry("Show welcome view for new window", sessionConfigUi.showWelcomeViewForNewWindow->isChecked());
0566 
0567         cg.writeEntry("Close documents with window", sessionConfigUi.winClosesDocuments->isChecked());
0568 
0569         cg.writeEntry("Close After Last", sessionConfigUi.modCloseAfterLast->isChecked());
0570         m_mainWindow->setModCloseAfterLast(sessionConfigUi.modCloseAfterLast->isChecked());
0571 
0572         if (m_messageTypes && m_outputHistoryLimit) {
0573             cg.writeEntry("Show output view for message type", m_messageTypes->currentIndex());
0574             cg.writeEntry("Output History Limit", m_outputHistoryLimit->value());
0575         }
0576 
0577         cg.writeEntry("Mouse back button action", m_mouseBackActions->currentIndex());
0578         cg.writeEntry("Mouse forward button action", m_mouseForwardActions->currentIndex());
0579 
0580         cg.writeEntry("Stash unsaved file changes", sessionConfigUi.stashUnsavedFilesChanges->isChecked());
0581         KateApp::self()->stashManager()->setStashUnsavedChanges(sessionConfigUi.stashUnsavedFilesChanges->isChecked());
0582         cg.writeEntry("Stash new unsaved files", sessionConfigUi.stashNewUnsavedFiles->isChecked());
0583         KateApp::self()->stashManager()->setStashNewUnsavedFiles(sessionConfigUi.stashNewUnsavedFiles->isChecked());
0584 
0585         cg.writeEntry("Modified Notification", m_modNotifications->isChecked());
0586         m_mainWindow->setModNotificationEnabled(m_modNotifications->isChecked());
0587 
0588         cg.writeEntry("Tabbar Tab Limit", m_tabLimit->value());
0589 
0590         cg.writeEntry("Auto Hide Tabs", m_autoHideTabs->isChecked());
0591 
0592         cg.writeEntry("Show Tabs Close Button", m_showTabCloseButton->isChecked());
0593 
0594         cg.writeEntry("Expand Tabs", m_expandTabs->isChecked());
0595 
0596         cg.writeEntry("Tab Double Click New Document", m_tabDoubleClickNewDocument->isChecked());
0597         cg.writeEntry("Tab Middle Click Close Document", m_tabMiddleClickCloseDocument->isChecked());
0598 
0599         cg.writeEntry("Allow Tab Scrolling", m_tabsScrollable->isChecked());
0600         cg.writeEntry("Elide Tab Text", m_tabsElided->isChecked());
0601         cg.writeEntry("Open New Tab To The Right Of Current", m_openNewTabInFrontOfCurrent->isChecked());
0602 
0603         cg.writeEntry("Diff Show Style", m_diffStyle->currentIndex());
0604 
0605         cg.writeEntry("Show Symbol In Navigation Bar", m_urlBarShowSymbols->isChecked());
0606 
0607         // patch document modified warn state
0608         const QList<KTextEditor::Document *> &docs = KateApp::self()->documentManager()->documentList();
0609         for (KTextEditor::Document *doc : docs) {
0610             doc->setModifiedOnDiskWarning(!m_modNotifications->isChecked());
0611         }
0612 
0613         m_mainWindow->saveOptions();
0614 
0615         // save plugin config !!
0616         KateSessionManager *sessionmanager = KateApp::self()->sessionManager();
0617         KConfig *sessionConfig = sessionmanager->activeSession()->config();
0618         KateApp::self()->pluginManager()->writeConfig(sessionConfig);
0619 
0620 #ifdef WITH_KUSERFEEDBACK
0621         // set current active mode + write back the config for future starts
0622         KateApp::self()->userFeedbackProvider().setTelemetryMode(m_userFeedbackWidget->telemetryMode());
0623         KateApp::self()->userFeedbackProvider().setSurveyInterval(m_userFeedbackWidget->surveyInterval());
0624 #endif
0625     }
0626 
0627     for (const PluginPageListItem &plugin : qAsConst(m_pluginPages)) {
0628         if (plugin.pluginPage) {
0629             plugin.pluginPage->apply();
0630         }
0631     }
0632 
0633     // apply ktexteditor pages
0634     for (KTextEditor::ConfigPage *page : m_editorPages) {
0635         page->apply();
0636     }
0637 
0638     config->sync();
0639 
0640     // emit config change
0641     if (m_dataChanged) {
0642         KateApp::self()->configurationChanged();
0643     }
0644 
0645     m_dataChanged = false;
0646     buttonBox()->button(QDialogButtonBox::Apply)->setEnabled(false);
0647 }
0648 
0649 void KateConfigDialog::slotChanged()
0650 {
0651     m_dataChanged = true;
0652     buttonBox()->button(QDialogButtonBox::Apply)->setEnabled(true);
0653 }
0654 
0655 void KateConfigDialog::showAppPluginPage(KTextEditor::Plugin *p, int id)
0656 {
0657     for (const PluginPageListItem &plugin : qAsConst(m_pluginPages)) {
0658         if ((plugin.plugin == p) && (id == plugin.idInPlugin)) {
0659             setCurrentPage(plugin.pageWidgetItem);
0660             break;
0661         }
0662     }
0663 }
0664 
0665 void KateConfigDialog::slotHelp()
0666 {
0667     QDesktopServices::openUrl(QUrl(QStringLiteral("help:/")));
0668 }
0669 
0670 int KateConfigDialog::recentFilesMaxCount()
0671 {
0672     int maxItems = KConfigGroup(KSharedConfig::openConfig(), QStringLiteral("General")).readEntry("Recent File List Entry Count", 10);
0673     return maxItems;
0674 }
0675 
0676 void KateConfigDialog::closeEvent(QCloseEvent *event)
0677 {
0678     if (!m_dataChanged) {
0679         event->accept();
0680         return;
0681     }
0682 
0683     const auto response = KMessageBox::warningTwoActionsCancel(this,
0684                                                                i18n("You have unsaved changes. Do you want to apply the changes or discard them?"),
0685                                                                i18n("Warning"),
0686                                                                KStandardGuiItem::save(),
0687                                                                KStandardGuiItem::discard(),
0688                                                                KStandardGuiItem::cancel());
0689     switch (response) {
0690     case KMessageBox::PrimaryAction:
0691         slotApply();
0692         Q_FALLTHROUGH();
0693     case KMessageBox::SecondaryAction:
0694         event->accept();
0695         break;
0696     case KMessageBox::Cancel:
0697         event->ignore();
0698         break;
0699     default:
0700         break;
0701     }
0702 }
0703 
0704 KPageWidgetItem *KateConfigDialog::addScrollablePage(QWidget *page, const QString &itemName)
0705 {
0706     // inspired by KPageWidgetItem *KConfigDialogPrivate::addPageInternal(QWidget *page, const QString &itemName, const QString &pixmapName, const QString
0707     // &header)
0708     QWidget *frame = new QWidget;
0709     QVBoxLayout *boxLayout = new QVBoxLayout(frame);
0710     boxLayout->setContentsMargins(0, 0, 0, 0);
0711     boxLayout->setContentsMargins(0, 0, 0, 0);
0712 
0713     QScrollArea *scroll = new QScrollArea;
0714     scroll->setFrameShape(QFrame::NoFrame);
0715     scroll->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);
0716     scroll->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
0717     scroll->setWidget(page);
0718     scroll->setWidgetResizable(true);
0719     scroll->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
0720 
0721     boxLayout->addWidget(scroll);
0722     return addPage(frame, itemName);
0723 }
0724 
0725 #include "moc_kateconfigdialog.cpp"