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
6 SPDX-License-Identifier: LGPL-2.0-or-later
7*/
8
9#ifndef KCONFIGDIALOGMANAGER_H
10#define KCONFIGDIALOGMANAGER_H
11
12#include <kconfigwidgets_export.h>
13
14#include <QHash>
15#include <QObject>
16#include <memory>
17
18class KConfigDialogManagerPrivate;
19
20class KCoreConfigSkeleton;
21class KConfigSkeleton;
22class KConfigSkeletonItem;
23class QWidget;
24
25/*!
26 * \class KConfigDialogManager
27 * \inmodule KConfigWidgets
28 *
29 * \brief Provides a means of automatically retrieving,
30 * saving and resetting KConfigSkeleton based settings in a dialog.
31 *
32 * The KConfigDialogManager class provides a means of automatically
33 * retrieving, saving and resetting basic settings.
34 * It also can emit signals when settings have been changed
35 * (settings were saved) or modified (the user changes a checkbox
36 * from on to off).
37 *
38 * The object names of the widgets to be managed have to correspond to the names of the
39 * configuration entries in the KConfigSkeleton object plus an additional
40 * "kcfg_" prefix. For example a widget with the object name "kcfg_MyOption"
41 * would be associated to the configuration entry "MyOption".
42 *
43 * The widget classes of Qt and KDE Frameworks are supported out of the box,
44 * for other widgets see below:
45 *
46 * \section1 Using Custom Widgets
47 * Custom widget classes are supported if they have a Q_PROPERTY defined for the
48 * property representing the value edited by the widget. By default the property
49 * is used for which "USER true" is set. For using another property, see below.
50 *
51 * Example:
52 *
53 * A class ColorEditWidget is used in the settings UI to select a color. The
54 * color value is set and read as type QColor. For that it has a definition of
55 * the value property similar to this:
56 * \code
57 * Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged USER true)
58 * \endcode
59 * And of course it has the definition and implementation of the respective
60 * read & write methods and the notify signal.
61 * This class then can be used directly with KConfigDialogManager and does not need
62 * further setup.
63 *
64 * \section1 Using Other Properties than The USER Property
65 * To use a widget's property that is not the USER property, the property to use
66 * can be selected by setting onto the widget instance a property with the key
67 * "kcfg_property" and as the value the name of the property:
68 * \code
69 * ColorEditWidget *myWidget = new ColorEditWidget;
70 * myWidget->setProperty("kcfg_property", QByteArray("redColorPart"));
71 * \endcode
72 * This selection of the property to use is just valid for this widget instance.
73 * When using a UI file, the "kcfg_property" property can also be set using Qt Designer.
74 *
75 * \section1 Configuring Classes to use Other Properties Globally
76 * Alternatively a non-USER property can be defined for a widget class globally
77 * by registering it for the class in the KConfigDialogManager::propertyMap().
78 * This global registration has lower priority than any "kcfg_property" property
79 * set on a class instance though, so the latter overrules this global setting.
80 * Note: setting the property in the propertyMap affects any instances of that
81 * widget class in the current application, so use only when needed and prefer
82 * instead the "kcfg_property" property. Especially with software with many
83 * libraries and 3rd-party plugins in one process there is a chance of
84 * conflicting settings.
85 *
86 * Example:
87 *
88 * If the ColorEditWidget has another property redColor defined by
89 * \code
90 * Q_PROPERTY(int redColorPart READ redColorPart WRITE setRedColorPart NOTIFY redColorPartChanged)
91 * \endcode
92 * and this one should be used in the settings, call somewhere in the code before
93 * using the settings:
94 * \code
95 * KConfigDialogManager::propertyMap()->insert("ColorEditWidget", QByteArray("redColorPart"));
96 * \endcode
97 *
98 * \section1 Using Different Signals than The NOTIFY Signal
99 * If some non-default signal should be used, e.g. because the property to use does not
100 * have a NOTIFY setting, for a given widget instance the signal to use can be set
101 * by a property with the key "kcfg_propertyNotify" and as the value the signal signature.
102 * This will take priority over the signal noted by NOTIFY for the chosen property
103 * as well as the content of KConfigDialogManager::changedMap(). Since 5.32.
104 *
105 * Example:
106 *
107 * If for a class OtherColorEditWidget there was no NOTIFY set on the USER property,
108 * but some signal colorSelected(QColor) defined which would be good enough to reflect
109 * the settings change, defined by
110 * \code
111 * Q_PROPERTY(QColor color READ color WRITE setColor USER true)
112 * Q_SIGNALS:
113 * void colorSelected(const QColor &color);
114 * \endcode
115 * the signal to use would be defined by this:
116 * \code
117 * OtherColorEditWidget *myWidget = new OtherColorEditWidget;
118 * myWidget->setProperty("kcfg_propertyNotify", QByteArray(SIGNAL(colorSelected(QColor))));
119 * \endcode
120 */
121class KCONFIGWIDGETS_EXPORT KConfigDialogManager : public QObject
122{
123 Q_OBJECT
124
125Q_SIGNALS:
126 /*!
127 * One or more of the settings have been saved (such as when the user
128 * clicks on the Apply button). This is only emitted by updateSettings()
129 * whenever one or more setting were changed and consequently saved.
130 */
131 void settingsChanged(); // clazy:exclude=overloaded-signal
132
133 /*!
134 * If retrieveSettings() was told to track changes then if
135 * any known setting was changed this signal will be emitted. Note
136 * that a settings can be modified several times and might go back to the
137 * original saved state. hasChanged() will tell you if anything has
138 * actually changed from the saved values.
139 */
140 void widgetModified();
141
142public:
143 /*!
144 * Constructor.
145 *
146 * \a parent Dialog widget to manage
147 *
148 * \a conf Object that contains settings
149 */
150 KConfigDialogManager(QWidget *parent, KCoreConfigSkeleton *conf);
151
152 ~KConfigDialogManager() override;
153
154 /*!
155 * Add additional widgets to manage
156 *
157 * \a widget Additional widget to manage, including all its children
158 */
159 void addWidget(QWidget *widget);
160
161 /*!
162 * Returns whether the current state of the known widgets are
163 * different from the state in the config object.
164 */
165 bool hasChanged() const;
166
167 /*!
168 * Returns whether the current state of the known widgets are
169 * the same as the default state in the config object.
170 */
171 bool isDefault() const;
172
173 /*!
174 * Retrieve the map between widgets class names and the
175 * USER properties used for the configuration values.
176 */
177 static QHash<QString, QByteArray> *propertyMap();
178
179public Q_SLOTS:
180 /*!
181 * Traverse the specified widgets, saving the settings of all known
182 * widgets in the settings object.
183 *
184 * Example use: User clicks Ok or Apply button in a configure dialog.
185 */
186 void updateSettings();
187
188 /*!
189 * Traverse the specified widgets, sets the state of all known
190 * widgets according to the state in the settings object.
191 *
192 * Example use: Initialisation of dialog.
193 *
194 * Example use: User clicks Reset button in a configure dialog.
195 */
196 void updateWidgets();
197
198 /*!
199 * Traverse the specified widgets, sets the state of all known
200 * widgets according to the default state in the settings object.
201 *
202 * Example use: User clicks Defaults button in a configure dialog.
203 */
204 void updateWidgetsDefault();
205
206 /*!
207 * Show or hide an indicator when settings have changed from their default value.
208 * Update all widgets to show or hide the indicator accordingly.
209 *
210 * \since 5.73
211 */
212 void setDefaultsIndicatorsVisible(bool enabled);
213
214protected:
215 /*!
216 * \a trackChanges If any changes by the widgets should be tracked
217 * set true. This causes the emitting the modified() signal when
218 * something changes.
219 */
220 void init(bool trackChanges);
221
222 /*!
223 * Recursive function that finds all known children.
224 *
225 * Goes through the children of widget and if any are known and not being
226 * ignored, stores them in currentGroup. Also checks if the widget
227 * should be disabled because it is set immutable.
228 *
229 * \a widget Parent of the children to look at.
230 *
231 * \a trackChanges If \c true then tracks any changes to the children of
232 * widget that are known.
233 * Returns bool: if a widget was set to something other than its default.
234 */
235 bool parseChildren(const QWidget *widget, bool trackChanges);
236
237 /*!
238 * Finds the USER property name using Qt's MetaProperty system, and caches
239 * it in the property map (the cache could be retrieved by propertyMap() ).
240 */
241 QByteArray getUserProperty(const QWidget *widget) const;
242
243 /*!
244 * Find the property to use for a widget by querying the "kcfg_property"
245 * property of the widget. Like a widget can use a property other than the
246 * USER property.
247 * \since 4.3
248 */
249 QByteArray getCustomProperty(const QWidget *widget) const;
250
251 /*!
252 * Finds the changed signal of the USER property using Qt's MetaProperty system.
253 * \since 5.32
254 */
255 QByteArray getUserPropertyChangedSignal(const QWidget *widget) const;
256
257 /*!
258 * Find the changed signal of the property to use for a widget by querying
259 * the "kcfg_propertyNotify" property of the widget. Like a widget can use a
260 * property change signal other than the one for USER property, if there even is one.
261 * \since 5.32
262 */
263 QByteArray getCustomPropertyChangedSignal(const QWidget *widget) const;
264
265 /*!
266 * Set a property
267 */
268 void setProperty(QWidget *w, const QVariant &v);
269
270 /*!
271 * Retrieve a property
272 */
273 QVariant property(QWidget *w) const;
274
275 /*!
276 * Setup secondary widget properties
277 */
278 void setupWidget(QWidget *widget, KConfigSkeletonItem *item);
279
280 /*!
281 * Initializes the property maps
282 */
283 static void initMaps();
284
285private:
286 std::unique_ptr<KConfigDialogManagerPrivate> const d;
287 friend class KConfigDialogManagerPrivate;
288
289 Q_DISABLE_COPY(KConfigDialogManager)
290 Q_PRIVATE_SLOT(d, void onWidgetModified())
291};
292
293#endif // KCONFIGDIALOGMANAGER_H
294

source code of kconfigwidgets/src/kconfigdialogmanager.h