KConfigWidgets

kconfigdialogmanager.h
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 <[email protected]>
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 
18 class KConfigDialogManagerPrivate;
19 
21 class KConfigSkeleton;
23 class 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. For supporting also KDE Frameworks versions older than 5.32 see
63  * below for how to register the property change signal.
64  * @endparblock
65  *
66  * @par Using Other Properties than The USER Property
67  * @parblock
68  * To use a widget's property that is not the USER property, the property to use
69  * can be selected by setting onto the widget instance a property with the key
70  * "kcfg_property" and as the value the name of the property:
71  * \code
72  * ColorEditWidget *myWidget = new ColorEditWidget;
73  * myWidget->setProperty("kcfg_property", QByteArray("redColorPart"));
74  * \endcode
75  * This selection of the property to use is just valid for this widget instance.
76  * When using a UI file, the "kcfg_property" property can also be set using Qt Designer.
77  * @endparblock
78  *
79  * @par Configuring Classes to use Other Properties Globally
80  * @parblock
81  * Alternatively a non-USER property can be defined for a widget class globally
82  * by registering it for the class in the KConfigDialogManager::propertyMap().
83  * This global registration has lower priority than any "kcfg_property" property
84  * set on a class instance though, so the latter overrules this global setting.
85  * Note: setting the property in the propertyMap affects any instances of that
86  * widget class in the current application, so use only when needed and prefer
87  * instead the "kcfg_property" property. Especially with software with many
88  * libraries and 3rd-party plugins in one process there is a chance of
89  * conflicting settings.
90  *
91  * Example:
92  *
93  * If the ColorEditWidget has another property redColor defined by
94  * \code
95  * Q_PROPERTY(int redColorPart READ redColorPart WRITE setRedColorPart NOTIFY redColorPartChanged)
96  * \endcode
97  * and this one should be used in the settings, call somewhere in the code before
98  * using the settings:
99  * \code
100  * KConfigDialogManager::propertyMap()->insert("ColorEditWidget", QByteArray("redColorPart"));
101  * \endcode
102  * @endparblock
103  *
104  * @par Using Different Signals than The NOTIFY Signal
105  * @parblock
106  * If some non-default signal should be used, e.g. because the property to use does not
107  * have a NOTIFY setting, for a given widget instance the signal to use can be set
108  * by a property with the key "kcfg_propertyNotify" and as the value the signal signature.
109  * This will take priority over the signal noted by NOTIFY for the chosen property
110  * as well as the content of KConfigDialogManager::changedMap(). Since 5.32.
111  *
112  * Example:
113  *
114  * If for a class OtherColorEditWidget there was no NOTIFY set on the USER property,
115  * but some signal colorSelected(QColor) defined which would be good enough to reflect
116  * the settings change, defined by
117  * \code
118  * Q_PROPERTY(QColor color READ color WRITE setColor USER true)
119  * Q_SIGNALS:
120  * void colorSelected(const QColor &color);
121  * \endcode
122  * the signal to use would be defined by this:
123  * \code
124  * OtherColorEditWidget *myWidget = new OtherColorEditWidget;
125  * myWidget->setProperty("kcfg_propertyNotify", QByteArray(SIGNAL(colorSelected(QColor))));
126  * \endcode
127  * @endparblock
128  *
129  * @par Supporting Older Versions of KDE Frameworks
130  * @parblock
131  * Before version 5.32 of KDE Frameworks, the signal notifying about a change
132  * of the property value in the widget had to be manually registered for any
133  * custom widget, using KConfigDialogManager::changedMap(). The same also had
134  * to be done for custom signals with widgets from Qt and KDE Frameworks.
135  * So for code which needs to also work with older versions of the KDE Frameworks,
136  * this still needs to be done.
137  * Starting with version 5.32, where the new signal handling is effective, the
138  * signal registered via KConfigDialogManager::changedMap() will take precedence over
139  * the one read from the Q_PROPERTY declaration, but is overridden for a given
140  * widget instance by the "kcfg_propertyNotify" property.
141  *
142  * Examples:
143  *
144  * For the class ColorEditWidget from the previous example this will register
145  * the change signal as needed:
146  * \code
147  * KConfigDialogManager::changedMap()->insert("ColorEditWidget", QByteArray(SIGNAL(colorChanged(QColor))));
148  * \endcode
149  * For KDE Framework versions starting with 5.32 this will override then the signal
150  * as read from the USER property, but as it is the same signal, nothing will break.
151  *
152  * If wants to reduce conflicts and also only add code to the build as needed,
153  * one would add both a buildtime switch and a runtime switch like
154  * \code
155  * #include <kconfigwidgets_version.h>
156  * #include <kcoreaddons.h>
157  * // [...]
158  * #if KCONFIGWIDGETS_VERSION < QT_VERSION_CHECK(5,32,0)
159  * if (KCoreAddons::version() < QT_VERSION_CHECK(5,32,0)) {
160  * KConfigDialogManager::changedMap()->insert("ColorEditWidget", QByteArray(SIGNAL(colorChanged(QColor))));
161  * }
162  * #endif
163  * \endcode
164  * so support for the old variant would be only used when running against an older
165  * KDE Frameworks, and this again only built in if also compiled against an older version.
166  * Note: KCoreAddons::version() needs at least KDE Frameworks 5.20 though.
167  *
168  * For the class OtherColorEditWidget from the previous example for the support of
169  * also older KDE Frameworks versions the change signal would be registered by this:
170  * \code
171  * KConfigDialogManager::changedMap()->insert("OtherColorEditWidget", QByteArray(SIGNAL(colorSelected(QColor))));
172  * OtherColorEditWidget *myWidget = new OtherColorEditWidget;
173  * myWidget->setProperty("kcfg_propertyNotify", QByteArray(SIGNAL(colorSelected(QColor))));
174  * \endcode
175  * Here for KDE Framework versions before 5.32 the "kcfg_propertyNotify" property would
176  * be ignored and the signal taken from KConfigDialogManager::changedMap(), while
177  * for newer versions it is taken from that property, which then overrides the latter.
178  * But as it is the same signal, nothing will break.
179  *
180  * Again, using KConfigDialogManager::changedMap could be made to depend on the version,
181  * so for newer versions any global conflicts are avoided:
182  * \code
183  * #include <kconfigwidgets_version.h>
184  * #include <kcoreaddons.h>
185  * // [...]
186  * #if KCONFIGWIDGETS_VERSION < QT_VERSION_CHECK(5,32,0)
187  * if (KCoreAddons::version() < QT_VERSION_CHECK(5,32,0)) {
188  * KConfigDialogManager::changedMap()->insert("OtherColorEditWidget", QByteArray(SIGNAL(colorSelected(QColor))));
189  * }
190  * #endif
191  * OtherColorEditWidget *myWidget = new OtherColorEditWidget;
192  * myWidget->setProperty("kcfg_propertyNotify", QByteArray(SIGNAL(colorSelected(QColor))));
193  * \endcode
194  * @endparblock
195  *
196  * @author Benjamin C Meyer <ben+kdelibs at meyerhome dot net>
197  * @author Waldo Bastian <[email protected]>
198  */
199 class KCONFIGWIDGETS_EXPORT KConfigDialogManager : public QObject
200 {
201  Q_OBJECT
202 
203 Q_SIGNALS:
204  /**
205  * One or more of the settings have been saved (such as when the user
206  * clicks on the Apply button). This is only emitted by updateSettings()
207  * whenever one or more setting were changed and consequently saved.
208  */
209  void settingsChanged(); // clazy:exclude=overloaded-signal
210 
211 #if KCONFIGWIDGETS_ENABLE_DEPRECATED_SINCE(5, 82)
212  /**
213  * TODO: Verify
214  * One or more of the settings have been changed.
215  * @param widget - The widget group (pass in via addWidget()) that
216  * contains the one or more modified setting.
217  * @see settingsChanged()
218  *
219  * @deprecated since 5.82, use the KConfigDialogManager::settingsChanged() signal instead.
220  */
221  KCONFIGWIDGETS_DEPRECATED_VERSION(5, 82, "Use the KConfigDialogManager::settingsChanged() signal instead.")
222  void settingsChanged(QWidget *widget); // clazy:exclude=overloaded-signal
223 #endif
224 
225  /**
226  * If retrieveSettings() was told to track changes then if
227  * any known setting was changed this signal will be emitted. Note
228  * that a settings can be modified several times and might go back to the
229  * original saved state. hasChanged() will tell you if anything has
230  * actually changed from the saved values.
231  */
232  void widgetModified();
233 
234 public:
235  /**
236  * Constructor.
237  * @param parent Dialog widget to manage
238  * @param conf Object that contains settings
239  */
241 
242 #if KCONFIGWIDGETS_ENABLE_DEPRECATED_SINCE(5, 84)
243  // No deprecation warning by compiler here, as the replacement will be
244  // automatically picked by the compiler in the future, being the method
245  // overload using the base-class of the argument type.
246  // Avoids the need to do extra-casting right now on the caller side.
247  /**
248  * Constructor.
249  * @param parent Dialog widget to manage
250  * @param conf Object that contains settings
251  * @deprecated since 5.84, use KConfigDialogManager(QWidget *parent, KCoreConfigSkeleton *conf)
252  */
254 #endif
255 
256  /**
257  * Destructor.
258  */
259  ~KConfigDialogManager() override;
260 
261  /**
262  * Add additional widgets to manage
263  * @param widget Additional widget to manage, including all its children
264  */
265  void addWidget(QWidget *widget);
266 
267  /**
268  * Returns whether the current state of the known widgets are
269  * different from the state in the config object.
270  */
271  bool hasChanged() const;
272 
273  /**
274  * Returns whether the current state of the known widgets are
275  * the same as the default state in the config object.
276  */
277  bool isDefault() const;
278 
279  /**
280  * Retrieve the map between widgets class names and the
281  * USER properties used for the configuration values.
282  */
283  static QHash<QString, QByteArray> *propertyMap();
284 
285 #if KCONFIGWIDGETS_ENABLE_DEPRECATED_SINCE(5, 32)
286  /**
287  * Retrieve the map between widgets class names and signals that are listened
288  * to detect changes in the configuration values.
289  * @deprecated Since 5.32, rely on the property change signal noted
290  * by @c NOTIFY of the used property in the class definition
291  * instead of setting it in this map. Or set the
292  * "kcfg_propertyNotify" property on the widget instance.
293  */
294  KCONFIGWIDGETS_DEPRECATED_VERSION(5, 32, "See API docs")
295  static QHash<QString, QByteArray> *changedMap();
296 #endif
297 
298 public Q_SLOTS:
299  /**
300  * Traverse the specified widgets, saving the settings of all known
301  * widgets in the settings object.
302  *
303  * Example use: User clicks Ok or Apply button in a configure dialog.
304  */
305  void updateSettings();
306 
307  /**
308  * Traverse the specified widgets, sets the state of all known
309  * widgets according to the state in the settings object.
310  *
311  * Example use: Initialisation of dialog.
312  * Example use: User clicks Reset button in a configure dialog.
313  */
314  void updateWidgets();
315 
316  /**
317  * Traverse the specified widgets, sets the state of all known
318  * widgets according to the default state in the settings object.
319  *
320  * Example use: User clicks Defaults button in a configure dialog.
321  */
322  void updateWidgetsDefault();
323 
324  /**
325  * Show or hide an indicator when settings have changed from their default value.
326  * Update all widgets to show or hide the indicator accordingly.
327  *
328  * @since 5.73
329  */
330  void setDefaultsIndicatorsVisible(bool enabled);
331 
332 protected:
333  /**
334  * @param trackChanges - If any changes by the widgets should be tracked
335  * set true. This causes the emitting the modified() signal when
336  * something changes.
337  * TODO: @return bool - True if any setting was changed from the default.
338  */
339  void init(bool trackChanges);
340 
341  /**
342  * Recursive function that finds all known children.
343  * Goes through the children of widget and if any are known and not being
344  * ignored, stores them in currentGroup. Also checks if the widget
345  * should be disabled because it is set immutable.
346  * @param widget - Parent of the children to look at.
347  * @param trackChanges - If true then tracks any changes to the children of
348  * widget that are known.
349  * @return bool - If a widget was set to something other than its default.
350  */
351  bool parseChildren(const QWidget *widget, bool trackChanges);
352 
353  /**
354  * Finds the USER property name using Qt's MetaProperty system, and caches
355  * it in the property map (the cache could be retrieved by propertyMap() ).
356  */
357  QByteArray getUserProperty(const QWidget *widget) const;
358 
359  /**
360  * Find the property to use for a widget by querying the "kcfg_property"
361  * property of the widget. Like a widget can use a property other than the
362  * USER property.
363  * @since 4.3
364  */
365  QByteArray getCustomProperty(const QWidget *widget) const;
366 
367  /**
368  * Finds the changed signal of the USER property using Qt's MetaProperty system.
369  * @since 5.32
370  */
371  QByteArray getUserPropertyChangedSignal(const QWidget *widget) const;
372 
373  /**
374  * Find the changed signal of the property to use for a widget by querying
375  * the "kcfg_propertyNotify" property of the widget. Like a widget can use a
376  * property change signal other than the one for USER property, if there even is one.
377  * @since 5.32
378  */
379  QByteArray getCustomPropertyChangedSignal(const QWidget *widget) const;
380 
381  /**
382  * Set a property
383  */
384  void setProperty(QWidget *w, const QVariant &v);
385 
386  /**
387  * Retrieve a property
388  */
389  QVariant property(QWidget *w) const;
390 
391  /**
392  * Setup secondary widget properties
393  */
394  void setupWidget(QWidget *widget, KConfigSkeletonItem *item);
395 
396  /**
397  * Initializes the property maps
398  */
399  static void initMaps();
400 
401 private:
402  /**
403  * KConfigDialogManager KConfigDialogManagerPrivate class.
404  */
405  std::unique_ptr<KConfigDialogManagerPrivate> const d;
406  friend class KConfigDialogManagerPrivate;
407 
409  Q_PRIVATE_SLOT(d, void onWidgetModified())
410 };
411 
412 #endif // KCONFIGDIALOGMANAGER_H
Q_SLOTSQ_SLOTS
Q_SIGNALSQ_SIGNALS
Provides a means of automatically retrieving, saving and resetting KConfigSkeleton based settings in ...
bool setProperty(const char *name, const QVariant &value)
Q_DISABLE_COPY(Class)
QVariant property(const char *name) const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Sun Dec 3 2023 04:14:26 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.