cf12defd28
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
359 lines
12 KiB
C++
359 lines
12 KiB
C++
/*
|
|
This file is part of the KDE libraries
|
|
SPDX-FileCopyrightText: 2003 Benjamin C Meyer <ben+kdelibs at meyerhome dot net>
|
|
SPDX-FileCopyrightText: 2003 Waldo Bastian <bastian@kde.org>
|
|
SPDX-FileCopyrightText: 2004 Michael Brade <brade@kde.org>
|
|
SPDX-FileCopyrightText: 2021 Ahmad Samir <a.samirh78@gmail.com>
|
|
|
|
SPDX-License-Identifier: LGPL-2.0-or-later
|
|
*/
|
|
|
|
#include "kconfigdialog.h"
|
|
|
|
#include <KCoreConfigSkeleton>
|
|
#include <KLocalizedString>
|
|
#include <KPageWidgetModel>
|
|
#include <kconfigdialogmanager.h>
|
|
#include <khelpclient.h>
|
|
|
|
#include <QDialogButtonBox>
|
|
#include <QIcon>
|
|
#include <QPushButton>
|
|
#include <QScrollArea>
|
|
#include <QScrollBar>
|
|
#include <QVBoxLayout>
|
|
|
|
#include <vector>
|
|
|
|
class KConfigDialogPrivate
|
|
{
|
|
public:
|
|
KConfigDialogPrivate(const QString &name, KCoreConfigSkeleton *config, KConfigDialog *qq)
|
|
: q(qq)
|
|
{
|
|
const QString dialogName = !name.isEmpty() ? name : QString::asprintf("SettingsDialog-%p", static_cast<void *>(q));
|
|
|
|
q->setObjectName(dialogName);
|
|
q->setWindowTitle(i18nc("@title:window", "Configure"));
|
|
q->setFaceType(KPageDialog::List);
|
|
s_openDialogs.push_back({dialogName, q});
|
|
|
|
QDialogButtonBox *buttonBox = q->buttonBox();
|
|
buttonBox->setStandardButtons(QDialogButtonBox::RestoreDefaults | QDialogButtonBox::Ok | QDialogButtonBox::Apply | QDialogButtonBox::Cancel
|
|
| QDialogButtonBox::Help);
|
|
QObject::connect(buttonBox->button(QDialogButtonBox::Ok), &QAbstractButton::clicked, q, &KConfigDialog::updateSettings);
|
|
QObject::connect(buttonBox->button(QDialogButtonBox::Apply), &QAbstractButton::clicked, q, &KConfigDialog::updateSettings);
|
|
QObject::connect(buttonBox->button(QDialogButtonBox::Apply), &QAbstractButton::clicked, q, [this]() {
|
|
updateButtons();
|
|
});
|
|
QObject::connect(buttonBox->button(QDialogButtonBox::Cancel), &QAbstractButton::clicked, q, &KConfigDialog::updateWidgets);
|
|
QObject::connect(buttonBox->button(QDialogButtonBox::RestoreDefaults), &QAbstractButton::clicked, q, &KConfigDialog::updateWidgetsDefault);
|
|
QObject::connect(buttonBox->button(QDialogButtonBox::RestoreDefaults), &QAbstractButton::clicked, q, [this]() {
|
|
updateButtons();
|
|
});
|
|
QObject::connect(buttonBox->button(QDialogButtonBox::Help), &QAbstractButton::clicked, q, &KConfigDialog::showHelp);
|
|
|
|
QObject::connect(q, &KPageDialog::pageRemoved, q, &KConfigDialog::onPageRemoved);
|
|
|
|
manager = new KConfigDialogManager(q, config);
|
|
setupManagerConnections(manager);
|
|
|
|
if (QPushButton *applyButton = q->buttonBox()->button(QDialogButtonBox::Apply)) {
|
|
applyButton->setEnabled(false);
|
|
};
|
|
}
|
|
|
|
KPageWidgetItem *addPageInternal(QWidget *page, const QString &itemName, const QString &pixmapName, const QString &header);
|
|
|
|
void setupManagerConnections(KConfigDialogManager *manager);
|
|
|
|
void updateApplyButton();
|
|
void updateDefaultsButton();
|
|
void updateButtons();
|
|
void settingsChangedSlot();
|
|
|
|
KConfigDialog *const q;
|
|
QString mAnchor;
|
|
QString mHelpApp;
|
|
bool shown = false;
|
|
KConfigDialogManager *manager = nullptr;
|
|
|
|
struct WidgetManager {
|
|
QWidget *widget = nullptr;
|
|
KConfigDialogManager *manager = nullptr;
|
|
};
|
|
std::vector<WidgetManager> m_managerForPage;
|
|
|
|
/**
|
|
* The list of existing dialogs.
|
|
*/
|
|
struct OpenDialogInfo {
|
|
QString dialogName;
|
|
KConfigDialog *dialog = nullptr;
|
|
};
|
|
static std::vector<OpenDialogInfo> s_openDialogs;
|
|
};
|
|
|
|
std::vector<KConfigDialogPrivate::OpenDialogInfo> KConfigDialogPrivate::s_openDialogs;
|
|
|
|
KConfigDialog::KConfigDialog(QWidget *parent, const QString &name, KCoreConfigSkeleton *config)
|
|
: KPageDialog(parent)
|
|
, d(new KConfigDialogPrivate(name, config, this))
|
|
{
|
|
}
|
|
|
|
KConfigDialog::~KConfigDialog()
|
|
{
|
|
auto &openDlgs = KConfigDialogPrivate::s_openDialogs;
|
|
const QString currentObjectName = objectName();
|
|
auto it = std::find_if(openDlgs.cbegin(), openDlgs.cend(), [=](const KConfigDialogPrivate::OpenDialogInfo &info) {
|
|
return currentObjectName == info.dialogName;
|
|
});
|
|
|
|
if (it != openDlgs.cend()) {
|
|
openDlgs.erase(it);
|
|
}
|
|
}
|
|
|
|
KPageWidgetItem *KConfigDialog::addPage(QWidget *page, const QString &itemName, const QString &pixmapName, const QString &header, bool manage)
|
|
{
|
|
Q_ASSERT(page);
|
|
if (!page) {
|
|
return nullptr;
|
|
}
|
|
|
|
KPageWidgetItem *item = d->addPageInternal(page, itemName, pixmapName, header);
|
|
if (manage) {
|
|
d->manager->addWidget(page);
|
|
}
|
|
|
|
if (d->shown && manage) {
|
|
// update the default button if the dialog is shown
|
|
QPushButton *defaultButton = buttonBox()->button(QDialogButtonBox::RestoreDefaults);
|
|
if (defaultButton) {
|
|
bool is_default = defaultButton->isEnabled() && d->manager->isDefault();
|
|
defaultButton->setEnabled(!is_default);
|
|
}
|
|
}
|
|
return item;
|
|
}
|
|
|
|
KPageWidgetItem *KConfigDialog::addPage(QWidget *page, KCoreConfigSkeleton *config, const QString &itemName, const QString &pixmapName, const QString &header)
|
|
{
|
|
Q_ASSERT(page);
|
|
if (!page) {
|
|
return nullptr;
|
|
}
|
|
|
|
KPageWidgetItem *item = d->addPageInternal(page, itemName, pixmapName, header);
|
|
auto *manager = new KConfigDialogManager(page, config);
|
|
d->m_managerForPage.push_back({page, manager});
|
|
d->setupManagerConnections(manager);
|
|
|
|
if (d->shown) {
|
|
// update the default button if the dialog is shown
|
|
QPushButton *defaultButton = buttonBox()->button(QDialogButtonBox::RestoreDefaults);
|
|
if (defaultButton) {
|
|
const bool is_default = defaultButton->isEnabled() && manager->isDefault();
|
|
defaultButton->setEnabled(!is_default);
|
|
}
|
|
}
|
|
return item;
|
|
}
|
|
|
|
KPageWidgetItem *KConfigDialogPrivate::addPageInternal(QWidget *page, const QString &itemName, const QString &pixmapName, const QString &header)
|
|
{
|
|
QWidget *frame = new QWidget(q);
|
|
QVBoxLayout *boxLayout = new QVBoxLayout(frame);
|
|
boxLayout->setContentsMargins(0, 0, 0, 0);
|
|
boxLayout->setContentsMargins(0, 0, 0, 0);
|
|
|
|
QScrollArea *scroll = new QScrollArea(q);
|
|
scroll->setFrameShape(QFrame::NoFrame);
|
|
scroll->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);
|
|
scroll->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
|
|
scroll->setWidget(page);
|
|
scroll->setWidgetResizable(true);
|
|
scroll->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
|
|
|
|
if (page->minimumSizeHint().height() > scroll->sizeHint().height() - 2) {
|
|
if (page->sizeHint().width() < scroll->sizeHint().width() + 2) {
|
|
// QScrollArea is planning only a vertical scroll bar,
|
|
// try to avoid the horizontal one by reserving space for the vertical one.
|
|
// Currently KPageViewPrivate::_k_modelChanged() queries the minimumSizeHint().
|
|
// We can only set the minimumSize(), so this approach relies on QStackedWidget size calculation.
|
|
scroll->setMinimumWidth(scroll->sizeHint().width() + qBound(0, scroll->verticalScrollBar()->sizeHint().width(), 200) + 4);
|
|
}
|
|
}
|
|
|
|
boxLayout->addWidget(scroll);
|
|
KPageWidgetItem *item = new KPageWidgetItem(frame, itemName);
|
|
item->setHeader(header);
|
|
if (!pixmapName.isEmpty()) {
|
|
item->setIcon(QIcon::fromTheme(pixmapName));
|
|
}
|
|
|
|
q->KPageDialog::addPage(item);
|
|
return item;
|
|
}
|
|
|
|
void KConfigDialogPrivate::setupManagerConnections(KConfigDialogManager *manager)
|
|
{
|
|
q->connect(manager, qOverload<>(&KConfigDialogManager::settingsChanged), q, [this]() {
|
|
settingsChangedSlot();
|
|
});
|
|
q->connect(manager, &KConfigDialogManager::widgetModified, q, [this]() {
|
|
updateButtons();
|
|
});
|
|
|
|
QDialogButtonBox *buttonBox = q->buttonBox();
|
|
q->connect(buttonBox->button(QDialogButtonBox::Ok), &QPushButton::clicked, manager, &KConfigDialogManager::updateSettings);
|
|
q->connect(buttonBox->button(QDialogButtonBox::Apply), &QPushButton::clicked, manager, &KConfigDialogManager::updateSettings);
|
|
q->connect(buttonBox->button(QDialogButtonBox::Cancel), &QPushButton::clicked, manager, &KConfigDialogManager::updateWidgets);
|
|
q->connect(buttonBox->button(QDialogButtonBox::RestoreDefaults), &QPushButton::clicked, manager, &KConfigDialogManager::updateWidgetsDefault);
|
|
}
|
|
|
|
void KConfigDialogPrivate::updateApplyButton()
|
|
{
|
|
QPushButton *applyButton = q->buttonBox()->button(QDialogButtonBox::Apply);
|
|
if (!applyButton) {
|
|
return;
|
|
}
|
|
|
|
const bool hasManagerChanged = std::any_of(m_managerForPage.cbegin(), m_managerForPage.cend(), [](const WidgetManager &widgetManager) {
|
|
return widgetManager.manager->hasChanged();
|
|
});
|
|
|
|
applyButton->setEnabled(manager->hasChanged() || q->hasChanged() || hasManagerChanged);
|
|
}
|
|
|
|
void KConfigDialogPrivate::updateDefaultsButton()
|
|
{
|
|
QPushButton *restoreDefaultsButton = q->buttonBox()->button(QDialogButtonBox::RestoreDefaults);
|
|
if (!restoreDefaultsButton) {
|
|
return;
|
|
}
|
|
|
|
const bool isManagerDefaulted = std::all_of(m_managerForPage.cbegin(), m_managerForPage.cend(), [](const WidgetManager &widgetManager) {
|
|
return widgetManager.manager->isDefault();
|
|
});
|
|
|
|
restoreDefaultsButton->setDisabled(manager->isDefault() && q->isDefault() && isManagerDefaulted);
|
|
}
|
|
|
|
void KConfigDialog::onPageRemoved(KPageWidgetItem *item)
|
|
{
|
|
auto it = std::find_if(d->m_managerForPage.cbegin(), d->m_managerForPage.cend(), [item](const KConfigDialogPrivate::WidgetManager &wm) {
|
|
return item->widget()->isAncestorOf(wm.widget);
|
|
});
|
|
|
|
if (it != d->m_managerForPage.cend()) { // There is a manager for this page, so remove it
|
|
delete it->manager;
|
|
d->m_managerForPage.erase(it);
|
|
d->updateButtons();
|
|
}
|
|
}
|
|
|
|
KConfigDialog *KConfigDialog::exists(const QString &name)
|
|
{
|
|
auto &openDlgs = KConfigDialogPrivate::s_openDialogs;
|
|
auto it = std::find_if(openDlgs.cbegin(), openDlgs.cend(), [name](const KConfigDialogPrivate::OpenDialogInfo &info) {
|
|
return name == info.dialogName;
|
|
});
|
|
|
|
return it != openDlgs.cend() ? it->dialog : nullptr;
|
|
}
|
|
|
|
bool KConfigDialog::showDialog(const QString &name)
|
|
{
|
|
KConfigDialog *dialog = exists(name);
|
|
if (dialog) {
|
|
dialog->show();
|
|
}
|
|
return (dialog != nullptr);
|
|
}
|
|
|
|
void KConfigDialogPrivate::updateButtons()
|
|
{
|
|
static bool only_once = false;
|
|
if (only_once) {
|
|
return;
|
|
}
|
|
only_once = true;
|
|
|
|
updateApplyButton();
|
|
updateDefaultsButton();
|
|
|
|
Q_EMIT q->widgetModified();
|
|
only_once = false;
|
|
}
|
|
|
|
void KConfigDialogPrivate::settingsChangedSlot()
|
|
{
|
|
// Update the buttons
|
|
updateButtons();
|
|
Q_EMIT q->settingsChanged(q->objectName());
|
|
}
|
|
|
|
void KConfigDialog::showEvent(QShowEvent *e)
|
|
{
|
|
if (!d->shown) {
|
|
updateWidgets();
|
|
d->manager->updateWidgets();
|
|
for (auto [widget, manager] : d->m_managerForPage) {
|
|
manager->updateWidgets();
|
|
}
|
|
|
|
d->updateApplyButton();
|
|
d->updateDefaultsButton();
|
|
|
|
d->shown = true;
|
|
}
|
|
KPageDialog::showEvent(e);
|
|
}
|
|
|
|
void KConfigDialog::updateSettings()
|
|
{
|
|
}
|
|
|
|
void KConfigDialog::updateWidgets()
|
|
{
|
|
}
|
|
|
|
void KConfigDialog::updateWidgetsDefault()
|
|
{
|
|
}
|
|
|
|
bool KConfigDialog::hasChanged()
|
|
{
|
|
return false;
|
|
}
|
|
|
|
bool KConfigDialog::isDefault()
|
|
{
|
|
return true;
|
|
}
|
|
|
|
void KConfigDialog::updateButtons()
|
|
{
|
|
d->updateButtons();
|
|
}
|
|
|
|
void KConfigDialog::settingsChangedSlot()
|
|
{
|
|
d->settingsChangedSlot();
|
|
}
|
|
|
|
void KConfigDialog::setHelp(const QString &anchor, const QString &appname)
|
|
{
|
|
d->mAnchor = anchor;
|
|
d->mHelpApp = appname;
|
|
}
|
|
|
|
void KConfigDialog::showHelp()
|
|
{
|
|
KHelpClient::invokeHelp(d->mAnchor, d->mHelpApp);
|
|
}
|
|
|
|
#include "moc_kconfigdialog.cpp"
|