KConfigWidgets

kconfigdialog.cpp
1/*
2 This file is part of the KDE libraries
3 SPDX-FileCopyrightText: 2003 Benjamin C Meyer <ben+kdelibs at meyerhome dot net>
4 SPDX-FileCopyrightText: 2003 Waldo Bastian <bastian@kde.org>
5 SPDX-FileCopyrightText: 2004 Michael Brade <brade@kde.org>
6 SPDX-FileCopyrightText: 2021 Ahmad Samir <a.samirh78@gmail.com>
7
8 SPDX-License-Identifier: LGPL-2.0-or-later
9*/
10
11#include "kconfigdialog.h"
12
13#include <KCoreConfigSkeleton>
14#include <KLocalizedString>
15#include <KPageWidgetModel>
16#include <kconfigdialogmanager.h>
17#include <khelpclient.h>
18
19#include <QDialogButtonBox>
20#include <QIcon>
21#include <QPushButton>
22#include <QScrollArea>
23#include <QScrollBar>
24#include <QVBoxLayout>
25
26#include <vector>
27
28class KConfigDialogPrivate
29{
30public:
31 KConfigDialogPrivate(const QString &name, KCoreConfigSkeleton *config, KConfigDialog *qq)
32 : q(qq)
33 {
34 const QString dialogName = !name.isEmpty() ? name : QString::asprintf("SettingsDialog-%p", static_cast<void *>(q));
35
36 q->setObjectName(dialogName);
37 q->setWindowTitle(i18nc("@title:window", "Configure"));
39 s_openDialogs.push_back({dialogName, q});
40
41 QDialogButtonBox *buttonBox = q->buttonBox();
47 updateButtons();
48 });
52 updateButtons();
53 });
55
56 QObject::connect(q, &KPageDialog::pageRemoved, q, &KConfigDialog::onPageRemoved);
57
58 manager = new KConfigDialogManager(q, config);
59 setupManagerConnections(manager);
60
61 if (QPushButton *applyButton = q->buttonBox()->button(QDialogButtonBox::Apply)) {
62 applyButton->setEnabled(false);
63 };
64 }
65
66 KPageWidgetItem *addPageInternal(QWidget *page, const QString &itemName, const QString &pixmapName, const QString &header);
67
68 void setupManagerConnections(KConfigDialogManager *manager);
69
70 void updateApplyButton();
71 void updateDefaultsButton();
72 void updateButtons();
73 void settingsChangedSlot();
74
75 KConfigDialog *const q;
76 QString mAnchor;
77 QString mHelpApp;
78 bool shown = false;
79 KConfigDialogManager *manager = nullptr;
80
81 struct WidgetManager {
82 QWidget *widget = nullptr;
83 KConfigDialogManager *manager = nullptr;
84 };
85 std::vector<WidgetManager> m_managerForPage;
86
87 /**
88 * The list of existing dialogs.
89 */
90 struct OpenDialogInfo {
91 QString dialogName;
92 KConfigDialog *dialog = nullptr;
93 };
94 static std::vector<OpenDialogInfo> s_openDialogs;
95};
96
97std::vector<KConfigDialogPrivate::OpenDialogInfo> KConfigDialogPrivate::s_openDialogs;
98
100 : KPageDialog(parent)
101 , d(new KConfigDialogPrivate(name, config, this))
102{
103}
104
106{
107 auto &openDlgs = KConfigDialogPrivate::s_openDialogs;
108 const QString currentObjectName = objectName();
109 auto it = std::find_if(openDlgs.cbegin(), openDlgs.cend(), [=](const KConfigDialogPrivate::OpenDialogInfo &info) {
110 return currentObjectName == info.dialogName;
111 });
112
113 if (it != openDlgs.cend()) {
114 openDlgs.erase(it);
115 }
116}
117
118KPageWidgetItem *KConfigDialog::addPage(QWidget *page, const QString &itemName, const QString &pixmapName, const QString &header, bool manage)
119{
120 Q_ASSERT(page);
121 if (!page) {
122 return nullptr;
123 }
124
125 KPageWidgetItem *item = d->addPageInternal(page, itemName, pixmapName, header);
126 if (manage) {
127 d->manager->addWidget(page);
128 }
129
130 if (d->shown && manage) {
131 // update the default button if the dialog is shown
133 if (defaultButton) {
134 bool is_default = defaultButton->isEnabled() && d->manager->isDefault();
135 defaultButton->setEnabled(!is_default);
136 }
137 }
138 return item;
139}
140
141KPageWidgetItem *KConfigDialog::addPage(QWidget *page, KCoreConfigSkeleton *config, const QString &itemName, const QString &pixmapName, const QString &header)
142{
143 Q_ASSERT(page);
144 if (!page) {
145 return nullptr;
146 }
147
148 KPageWidgetItem *item = d->addPageInternal(page, itemName, pixmapName, header);
149 auto *manager = new KConfigDialogManager(page, config);
150 d->m_managerForPage.push_back({page, manager});
151 d->setupManagerConnections(manager);
152
153 if (d->shown) {
154 // update the default button if the dialog is shown
156 if (defaultButton) {
157 const bool is_default = defaultButton->isEnabled() && manager->isDefault();
158 defaultButton->setEnabled(!is_default);
159 }
160 }
161 return item;
162}
163
164KPageWidgetItem *KConfigDialogPrivate::addPageInternal(QWidget *page, const QString &itemName, const QString &pixmapName, const QString &header)
165{
166 QWidget *frame = new QWidget(q);
167 QVBoxLayout *boxLayout = new QVBoxLayout(frame);
168 boxLayout->setContentsMargins(0, 0, 0, 0);
169 boxLayout->setContentsMargins(0, 0, 0, 0);
170
171 QScrollArea *scroll = new QScrollArea(q);
175 scroll->setWidget(page);
176 scroll->setWidgetResizable(true);
178
179 if (page->minimumSizeHint().height() > scroll->sizeHint().height() - 2) {
180 if (page->sizeHint().width() < scroll->sizeHint().width() + 2) {
181 // QScrollArea is planning only a vertical scroll bar,
182 // try to avoid the horizontal one by reserving space for the vertical one.
183 // Currently KPageViewPrivate::_k_modelChanged() queries the minimumSizeHint().
184 // We can only set the minimumSize(), so this approach relies on QStackedWidget size calculation.
185 scroll->setMinimumWidth(scroll->sizeHint().width() + qBound(0, scroll->verticalScrollBar()->sizeHint().width(), 200) + 4);
186 }
187 }
188
189 boxLayout->addWidget(scroll);
190 KPageWidgetItem *item = new KPageWidgetItem(frame, itemName);
191 item->setHeader(header);
192 if (!pixmapName.isEmpty()) {
193 item->setIcon(QIcon::fromTheme(pixmapName));
194 }
195
196 q->KPageDialog::addPage(item);
197 return item;
198}
199
200void KConfigDialogPrivate::setupManagerConnections(KConfigDialogManager *manager)
201{
202 q->connect(manager, qOverload<>(&KConfigDialogManager::settingsChanged), q, [this]() {
203 settingsChangedSlot();
204 });
205 q->connect(manager, &KConfigDialogManager::widgetModified, q, [this]() {
206 updateButtons();
207 });
208
209 QDialogButtonBox *buttonBox = q->buttonBox();
214}
215
216void KConfigDialogPrivate::updateApplyButton()
217{
219 if (!applyButton) {
220 return;
221 }
222
223 const bool hasManagerChanged = std::any_of(m_managerForPage.cbegin(), m_managerForPage.cend(), [](const WidgetManager &widgetManager) {
224 return widgetManager.manager->hasChanged();
225 });
226
227 applyButton->setEnabled(manager->hasChanged() || q->hasChanged() || hasManagerChanged);
228}
229
230void KConfigDialogPrivate::updateDefaultsButton()
231{
232 QPushButton *restoreDefaultsButton = q->buttonBox()->button(QDialogButtonBox::RestoreDefaults);
233 if (!restoreDefaultsButton) {
234 return;
235 }
236
237 const bool isManagerDefaulted = std::all_of(m_managerForPage.cbegin(), m_managerForPage.cend(), [](const WidgetManager &widgetManager) {
238 return widgetManager.manager->isDefault();
239 });
240
241 restoreDefaultsButton->setDisabled(manager->isDefault() && q->isDefault() && isManagerDefaulted);
242}
243
244void KConfigDialog::onPageRemoved(KPageWidgetItem *item)
245{
246 auto it = std::find_if(d->m_managerForPage.cbegin(), d->m_managerForPage.cend(), [item](const KConfigDialogPrivate::WidgetManager &wm) {
247 return item->widget()->isAncestorOf(wm.widget);
248 });
249
250 if (it != d->m_managerForPage.cend()) { // There is a manager for this page, so remove it
251 delete it->manager;
252 d->m_managerForPage.erase(it);
253 d->updateButtons();
254 }
255}
256
258{
259 auto &openDlgs = KConfigDialogPrivate::s_openDialogs;
260 auto it = std::find_if(openDlgs.cbegin(), openDlgs.cend(), [name](const KConfigDialogPrivate::OpenDialogInfo &info) {
261 return name == info.dialogName;
262 });
263
264 return it != openDlgs.cend() ? it->dialog : nullptr;
265}
266
268{
269 KConfigDialog *dialog = exists(name);
270 if (dialog) {
271 dialog->show();
272 }
273 return (dialog != nullptr);
274}
275
276void KConfigDialogPrivate::updateButtons()
277{
278 static bool only_once = false;
279 if (only_once) {
280 return;
281 }
282 only_once = true;
283
284 updateApplyButton();
285 updateDefaultsButton();
286
287 Q_EMIT q->widgetModified();
288 only_once = false;
289}
290
291void KConfigDialogPrivate::settingsChangedSlot()
292{
293 // Update the buttons
294 updateButtons();
295 Q_EMIT q->settingsChanged(q->objectName());
296}
297
299{
300 if (!d->shown) {
302 d->manager->updateWidgets();
303 for (auto [widget, manager] : d->m_managerForPage) {
304 manager->updateWidgets();
305 }
306
307 d->updateApplyButton();
308 d->updateDefaultsButton();
309
310 d->shown = true;
311 }
313}
314
318
322
326
328{
329 return false;
330}
331
333{
334 return true;
335}
336
338{
339 d->updateButtons();
340}
341
343{
344 d->settingsChangedSlot();
345}
346
347void KConfigDialog::setHelp(const QString &anchor, const QString &appname)
348{
349 d->mAnchor = anchor;
350 d->mHelpApp = appname;
351}
352
354{
355 KHelpClient::invokeHelp(d->mAnchor, d->mHelpApp);
356}
357
358#include "moc_kconfigdialog.cpp"
Provides a means of automatically retrieving, saving and resetting KConfigSkeleton based settings in ...
void updateWidgetsDefault()
Traverse the specified widgets, sets the state of all known widgets according to the default state in...
void widgetModified()
If retrieveSettings() was told to track changes then if any known setting was changed this signal wil...
void settingsChanged()
One or more of the settings have been saved (such as when the user clicks on the Apply button).
void updateWidgets()
Traverse the specified widgets, sets the state of all known widgets according to the state in the set...
bool hasChanged() const
Returns whether the current state of the known widgets are different from the state in the config obj...
void updateSettings()
Traverse the specified widgets, saving the settings of all known widgets in the settings object.
bool isDefault() const
Returns whether the current state of the known widgets are the same as the default state in the confi...
Standard KDE configuration dialog class.
virtual bool isDefault()
Returns whether the current state of the dialog is the same as the default configuration.
KConfigDialog(QWidget *parent, const QString &name, KCoreConfigSkeleton *config)
static bool showDialog(const QString &name)
Attempts to show the dialog with the name 'name'.
KPageWidgetItem * addPage(QWidget *page, const QString &itemName, const QString &pixmapName=QString(), const QString &header=QString(), bool manage=true)
Adds page to the dialog and to KConfigDialogManager.
virtual void showHelp()
Displays help for this config dialog.
void settingsChangedSlot()
Some setting was changed.
~KConfigDialog() override
Deconstructor, removes name from the list of open dialogs.
virtual void updateSettings()
Update the settings from the dialog.
void showEvent(QShowEvent *e) override
static KConfigDialog * exists(const QString &name)
See if a dialog with the name 'name' already exists.
virtual bool hasChanged()
Returns whether the current state of the dialog is different from the current configuration.
void widgetModified()
A widget in the dialog was modified.
virtual void updateWidgets()
Update the dialog based on the settings.
void updateButtons()
Updates the Apply and Default buttons.
void settingsChanged(const QString &dialogName)
One or more of the settings have been permanently changed such as if the user clicked on the Apply or...
void setHelp(const QString &anchor, const QString &appname=QString())
Sets the help path and topic.
virtual void updateWidgetsDefault()
Update the dialog based on the default settings.
QDialogButtonBox * buttonBox()
void pageRemoved(KPageWidgetItem *page)
void setFaceType(FaceType faceType)
void setIcon(const QIcon &icon)
void setHeader(const QString &header)
QString i18nc(const char *context, const char *text, const TYPE &arg...)
void invokeHelp(const QString &anchor=QString(), const QString &appname=QString())
Invokes the KHelpCenter HTML help viewer from docbook sources.
QString name(StandardAction id)
void clicked(bool checked)
void setHorizontalScrollBarPolicy(Qt::ScrollBarPolicy)
QScrollBar * verticalScrollBar() const const
void setVerticalScrollBarPolicy(Qt::ScrollBarPolicy)
void addWidget(QWidget *widget, int stretch, Qt::Alignment alignment)
virtual void showEvent(QShowEvent *event) override
QPushButton * button(StandardButton which) const const
void setStandardButtons(StandardButtons buttons)
void setFrameShape(Shape)
QIcon fromTheme(const QString &name)
void setContentsMargins(const QMargins &margins)
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
void setObjectName(QAnyStringView name)
void setWidget(QWidget *widget)
virtual QSize sizeHint() const const override
void setWidgetResizable(bool resizable)
virtual QSize sizeHint() const const override
int height() const const
int width() const const
QString asprintf(const char *cformat,...)
bool isEmpty() const const
ScrollBarAsNeeded
bool isEnabled() const const
void setMinimumWidth(int minw)
void setDisabled(bool disable)
void show()
void setSizePolicy(QSizePolicy)
void setWindowTitle(const QString &)
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Mon Nov 18 2024 12:07:46 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.