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

source code of kconfigwidgets/src/kconfigdialogmanager.h