File indexing completed on 2024-09-01 13:21:12
0001 /* 0002 This file is part of the KDE libraries 0003 SPDX-FileCopyrightText: 2003 Benjamin C Meyer <ben+kdelibs at meyerhome dot net> 0004 SPDX-FileCopyrightText: 2003 Waldo Bastian <bastian@kde.org> 0005 0006 SPDX-License-Identifier: LGPL-2.0-or-later 0007 */ 0008 0009 #ifndef KCONFIGDIALOGMANAGER_H 0010 #define KCONFIGDIALOGMANAGER_H 0011 0012 #include <kconfigwidgets_export.h> 0013 0014 #include <QHash> 0015 #include <QObject> 0016 #include <memory> 0017 0018 class KConfigDialogManagerPrivate; 0019 0020 class KCoreConfigSkeleton; 0021 class KConfigSkeleton; 0022 class KConfigSkeletonItem; 0023 class QWidget; 0024 0025 /** 0026 * @class KConfigDialogManager kconfigdialogmanager.h KConfigDialogManager 0027 * 0028 * @short Provides a means of automatically retrieving, 0029 * saving and resetting KConfigSkeleton based settings in a dialog. 0030 * 0031 * The KConfigDialogManager class provides a means of automatically 0032 * retrieving, saving and resetting basic settings. 0033 * It also can emit signals when settings have been changed 0034 * (settings were saved) or modified (the user changes a checkbox 0035 * from on to off). 0036 * 0037 * The object names of the widgets to be managed have to correspond to the names of the 0038 * configuration entries in the KConfigSkeleton object plus an additional 0039 * "kcfg_" prefix. For example a widget with the object name "kcfg_MyOption" 0040 * would be associated to the configuration entry "MyOption". 0041 * 0042 * The widget classes of Qt and KDE Frameworks are supported out of the box, 0043 * for other widgets see below: 0044 * 0045 * @par Using Custom Widgets 0046 * @parblock 0047 * Custom widget classes are supported if they have a Q_PROPERTY defined for the 0048 * property representing the value edited by the widget. By default the property 0049 * is used for which "USER true" is set. For using another property, see below. 0050 * 0051 * Example: 0052 * 0053 * A class ColorEditWidget is used in the settings UI to select a color. The 0054 * color value is set and read as type QColor. For that it has a definition of 0055 * the value property similar to this: 0056 * \code 0057 * Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged USER true) 0058 * \endcode 0059 * And of course it has the definition and implementation of the respective 0060 * read & write methods and the notify signal. 0061 * This class then can be used directly with KConfigDialogManager and does not need 0062 * further setup. For supporting also KDE Frameworks versions older than 5.32 see 0063 * below for how to register the property change signal. 0064 * @endparblock 0065 * 0066 * @par Using Other Properties than The USER Property 0067 * @parblock 0068 * To use a widget's property that is not the USER property, the property to use 0069 * can be selected by setting onto the widget instance a property with the key 0070 * "kcfg_property" and as the value the name of the property: 0071 * \code 0072 * ColorEditWidget *myWidget = new ColorEditWidget; 0073 * myWidget->setProperty("kcfg_property", QByteArray("redColorPart")); 0074 * \endcode 0075 * This selection of the property to use is just valid for this widget instance. 0076 * When using a UI file, the "kcfg_property" property can also be set using Qt Designer. 0077 * @endparblock 0078 * 0079 * @par Configuring Classes to use Other Properties Globally 0080 * @parblock 0081 * Alternatively a non-USER property can be defined for a widget class globally 0082 * by registering it for the class in the KConfigDialogManager::propertyMap(). 0083 * This global registration has lower priority than any "kcfg_property" property 0084 * set on a class instance though, so the latter overrules this global setting. 0085 * Note: setting the property in the propertyMap affects any instances of that 0086 * widget class in the current application, so use only when needed and prefer 0087 * instead the "kcfg_property" property. Especially with software with many 0088 * libraries and 3rd-party plugins in one process there is a chance of 0089 * conflicting settings. 0090 * 0091 * Example: 0092 * 0093 * If the ColorEditWidget has another property redColor defined by 0094 * \code 0095 * Q_PROPERTY(int redColorPart READ redColorPart WRITE setRedColorPart NOTIFY redColorPartChanged) 0096 * \endcode 0097 * and this one should be used in the settings, call somewhere in the code before 0098 * using the settings: 0099 * \code 0100 * KConfigDialogManager::propertyMap()->insert("ColorEditWidget", QByteArray("redColorPart")); 0101 * \endcode 0102 * @endparblock 0103 * 0104 * @par Using Different Signals than The NOTIFY Signal 0105 * @parblock 0106 * If some non-default signal should be used, e.g. because the property to use does not 0107 * have a NOTIFY setting, for a given widget instance the signal to use can be set 0108 * by a property with the key "kcfg_propertyNotify" and as the value the signal signature. 0109 * This will take priority over the signal noted by NOTIFY for the chosen property 0110 * as well as the content of KConfigDialogManager::changedMap(). Since 5.32. 0111 * 0112 * Example: 0113 * 0114 * If for a class OtherColorEditWidget there was no NOTIFY set on the USER property, 0115 * but some signal colorSelected(QColor) defined which would be good enough to reflect 0116 * the settings change, defined by 0117 * \code 0118 * Q_PROPERTY(QColor color READ color WRITE setColor USER true) 0119 * Q_SIGNALS: 0120 * void colorSelected(const QColor &color); 0121 * \endcode 0122 * the signal to use would be defined by this: 0123 * \code 0124 * OtherColorEditWidget *myWidget = new OtherColorEditWidget; 0125 * myWidget->setProperty("kcfg_propertyNotify", QByteArray(SIGNAL(colorSelected(QColor)))); 0126 * \endcode 0127 * @endparblock 0128 * 0129 * @par Supporting Older Versions of KDE Frameworks 0130 * @parblock 0131 * Before version 5.32 of KDE Frameworks, the signal notifying about a change 0132 * of the property value in the widget had to be manually registered for any 0133 * custom widget, using KConfigDialogManager::changedMap(). The same also had 0134 * to be done for custom signals with widgets from Qt and KDE Frameworks. 0135 * So for code which needs to also work with older versions of the KDE Frameworks, 0136 * this still needs to be done. 0137 * Starting with version 5.32, where the new signal handling is effective, the 0138 * signal registered via KConfigDialogManager::changedMap() will take precedence over 0139 * the one read from the Q_PROPERTY declaration, but is overridden for a given 0140 * widget instance by the "kcfg_propertyNotify" property. 0141 * 0142 * Examples: 0143 * 0144 * For the class ColorEditWidget from the previous example this will register 0145 * the change signal as needed: 0146 * \code 0147 * KConfigDialogManager::changedMap()->insert("ColorEditWidget", QByteArray(SIGNAL(colorChanged(QColor)))); 0148 * \endcode 0149 * For KDE Framework versions starting with 5.32 this will override then the signal 0150 * as read from the USER property, but as it is the same signal, nothing will break. 0151 * 0152 * If wants to reduce conflicts and also only add code to the build as needed, 0153 * one would add both a buildtime switch and a runtime switch like 0154 * \code 0155 * #include <kconfigwidgets_version.h> 0156 * #include <kcoreaddons.h> 0157 * // [...] 0158 * #if KCONFIGWIDGETS_VERSION < QT_VERSION_CHECK(5,32,0) 0159 * if (KCoreAddons::version() < QT_VERSION_CHECK(5,32,0)) { 0160 * KConfigDialogManager::changedMap()->insert("ColorEditWidget", QByteArray(SIGNAL(colorChanged(QColor)))); 0161 * } 0162 * #endif 0163 * \endcode 0164 * so support for the old variant would be only used when running against an older 0165 * KDE Frameworks, and this again only built in if also compiled against an older version. 0166 * Note: KCoreAddons::version() needs at least KDE Frameworks 5.20 though. 0167 * 0168 * For the class OtherColorEditWidget from the previous example for the support of 0169 * also older KDE Frameworks versions the change signal would be registered by this: 0170 * \code 0171 * KConfigDialogManager::changedMap()->insert("OtherColorEditWidget", QByteArray(SIGNAL(colorSelected(QColor)))); 0172 * OtherColorEditWidget *myWidget = new OtherColorEditWidget; 0173 * myWidget->setProperty("kcfg_propertyNotify", QByteArray(SIGNAL(colorSelected(QColor)))); 0174 * \endcode 0175 * Here for KDE Framework versions before 5.32 the "kcfg_propertyNotify" property would 0176 * be ignored and the signal taken from KConfigDialogManager::changedMap(), while 0177 * for newer versions it is taken from that property, which then overrides the latter. 0178 * But as it is the same signal, nothing will break. 0179 * 0180 * Again, using KConfigDialogManager::changedMap could be made to depend on the version, 0181 * so for newer versions any global conflicts are avoided: 0182 * \code 0183 * #include <kconfigwidgets_version.h> 0184 * #include <kcoreaddons.h> 0185 * // [...] 0186 * #if KCONFIGWIDGETS_VERSION < QT_VERSION_CHECK(5,32,0) 0187 * if (KCoreAddons::version() < QT_VERSION_CHECK(5,32,0)) { 0188 * KConfigDialogManager::changedMap()->insert("OtherColorEditWidget", QByteArray(SIGNAL(colorSelected(QColor)))); 0189 * } 0190 * #endif 0191 * OtherColorEditWidget *myWidget = new OtherColorEditWidget; 0192 * myWidget->setProperty("kcfg_propertyNotify", QByteArray(SIGNAL(colorSelected(QColor)))); 0193 * \endcode 0194 * @endparblock 0195 * 0196 * @author Benjamin C Meyer <ben+kdelibs at meyerhome dot net> 0197 * @author Waldo Bastian <bastian@kde.org> 0198 */ 0199 class KCONFIGWIDGETS_EXPORT KConfigDialogManager : public QObject 0200 { 0201 Q_OBJECT 0202 0203 Q_SIGNALS: 0204 /** 0205 * One or more of the settings have been saved (such as when the user 0206 * clicks on the Apply button). This is only emitted by updateSettings() 0207 * whenever one or more setting were changed and consequently saved. 0208 */ 0209 void settingsChanged(); // clazy:exclude=overloaded-signal 0210 0211 #if KCONFIGWIDGETS_ENABLE_DEPRECATED_SINCE(5, 82) 0212 /** 0213 * TODO: Verify 0214 * One or more of the settings have been changed. 0215 * @param widget - The widget group (pass in via addWidget()) that 0216 * contains the one or more modified setting. 0217 * @see settingsChanged() 0218 * 0219 * @deprecated since 5.82, use the KConfigDialogManager::settingsChanged() signal instead. 0220 */ 0221 KCONFIGWIDGETS_DEPRECATED_VERSION(5, 82, "Use the KConfigDialogManager::settingsChanged() signal instead.") 0222 void settingsChanged(QWidget *widget); // clazy:exclude=overloaded-signal 0223 #endif 0224 0225 /** 0226 * If retrieveSettings() was told to track changes then if 0227 * any known setting was changed this signal will be emitted. Note 0228 * that a settings can be modified several times and might go back to the 0229 * original saved state. hasChanged() will tell you if anything has 0230 * actually changed from the saved values. 0231 */ 0232 void widgetModified(); 0233 0234 public: 0235 /** 0236 * Constructor. 0237 * @param parent Dialog widget to manage 0238 * @param conf Object that contains settings 0239 */ 0240 KConfigDialogManager(QWidget *parent, KCoreConfigSkeleton *conf); 0241 0242 #if KCONFIGWIDGETS_ENABLE_DEPRECATED_SINCE(5, 84) 0243 // No deprecation warning by compiler here, as the replacement will be 0244 // automatically picked by the compiler in the future, being the method 0245 // overload using the base-class of the argument type. 0246 // Avoids the need to do extra-casting right now on the caller side. 0247 /** 0248 * Constructor. 0249 * @param parent Dialog widget to manage 0250 * @param conf Object that contains settings 0251 * @deprecated since 5.84, use KConfigDialogManager(QWidget *parent, KCoreConfigSkeleton *conf) 0252 */ 0253 KConfigDialogManager(QWidget *parent, KConfigSkeleton *conf); 0254 #endif 0255 0256 /** 0257 * Destructor. 0258 */ 0259 ~KConfigDialogManager() override; 0260 0261 /** 0262 * Add additional widgets to manage 0263 * @param widget Additional widget to manage, including all its children 0264 */ 0265 void addWidget(QWidget *widget); 0266 0267 /** 0268 * Returns whether the current state of the known widgets are 0269 * different from the state in the config object. 0270 */ 0271 bool hasChanged() const; 0272 0273 /** 0274 * Returns whether the current state of the known widgets are 0275 * the same as the default state in the config object. 0276 */ 0277 bool isDefault() const; 0278 0279 /** 0280 * Retrieve the map between widgets class names and the 0281 * USER properties used for the configuration values. 0282 */ 0283 static QHash<QString, QByteArray> *propertyMap(); 0284 0285 #if KCONFIGWIDGETS_ENABLE_DEPRECATED_SINCE(5, 32) 0286 /** 0287 * Retrieve the map between widgets class names and signals that are listened 0288 * to detect changes in the configuration values. 0289 * @deprecated Since 5.32, rely on the property change signal noted 0290 * by @c NOTIFY of the used property in the class definition 0291 * instead of setting it in this map. Or set the 0292 * "kcfg_propertyNotify" property on the widget instance. 0293 */ 0294 KCONFIGWIDGETS_DEPRECATED_VERSION(5, 32, "See API docs") 0295 static QHash<QString, QByteArray> *changedMap(); 0296 #endif 0297 0298 public Q_SLOTS: 0299 /** 0300 * Traverse the specified widgets, saving the settings of all known 0301 * widgets in the settings object. 0302 * 0303 * Example use: User clicks Ok or Apply button in a configure dialog. 0304 */ 0305 void updateSettings(); 0306 0307 /** 0308 * Traverse the specified widgets, sets the state of all known 0309 * widgets according to the state in the settings object. 0310 * 0311 * Example use: Initialisation of dialog. 0312 * Example use: User clicks Reset button in a configure dialog. 0313 */ 0314 void updateWidgets(); 0315 0316 /** 0317 * Traverse the specified widgets, sets the state of all known 0318 * widgets according to the default state in the settings object. 0319 * 0320 * Example use: User clicks Defaults button in a configure dialog. 0321 */ 0322 void updateWidgetsDefault(); 0323 0324 /** 0325 * Show or hide an indicator when settings have changed from their default value. 0326 * Update all widgets to show or hide the indicator accordingly. 0327 * 0328 * @since 5.73 0329 */ 0330 void setDefaultsIndicatorsVisible(bool enabled); 0331 0332 protected: 0333 /** 0334 * @param trackChanges - If any changes by the widgets should be tracked 0335 * set true. This causes the emitting the modified() signal when 0336 * something changes. 0337 * TODO: @return bool - True if any setting was changed from the default. 0338 */ 0339 void init(bool trackChanges); 0340 0341 /** 0342 * Recursive function that finds all known children. 0343 * Goes through the children of widget and if any are known and not being 0344 * ignored, stores them in currentGroup. Also checks if the widget 0345 * should be disabled because it is set immutable. 0346 * @param widget - Parent of the children to look at. 0347 * @param trackChanges - If true then tracks any changes to the children of 0348 * widget that are known. 0349 * @return bool - If a widget was set to something other than its default. 0350 */ 0351 bool parseChildren(const QWidget *widget, bool trackChanges); 0352 0353 /** 0354 * Finds the USER property name using Qt's MetaProperty system, and caches 0355 * it in the property map (the cache could be retrieved by propertyMap() ). 0356 */ 0357 QByteArray getUserProperty(const QWidget *widget) const; 0358 0359 /** 0360 * Find the property to use for a widget by querying the "kcfg_property" 0361 * property of the widget. Like a widget can use a property other than the 0362 * USER property. 0363 * @since 4.3 0364 */ 0365 QByteArray getCustomProperty(const QWidget *widget) const; 0366 0367 /** 0368 * Finds the changed signal of the USER property using Qt's MetaProperty system. 0369 * @since 5.32 0370 */ 0371 QByteArray getUserPropertyChangedSignal(const QWidget *widget) const; 0372 0373 /** 0374 * Find the changed signal of the property to use for a widget by querying 0375 * the "kcfg_propertyNotify" property of the widget. Like a widget can use a 0376 * property change signal other than the one for USER property, if there even is one. 0377 * @since 5.32 0378 */ 0379 QByteArray getCustomPropertyChangedSignal(const QWidget *widget) const; 0380 0381 /** 0382 * Set a property 0383 */ 0384 void setProperty(QWidget *w, const QVariant &v); 0385 0386 /** 0387 * Retrieve a property 0388 */ 0389 QVariant property(QWidget *w) const; 0390 0391 /** 0392 * Setup secondary widget properties 0393 */ 0394 void setupWidget(QWidget *widget, KConfigSkeletonItem *item); 0395 0396 /** 0397 * Initializes the property maps 0398 */ 0399 static void initMaps(); 0400 0401 private: 0402 /** 0403 * KConfigDialogManager KConfigDialogManagerPrivate class. 0404 */ 0405 std::unique_ptr<KConfigDialogManagerPrivate> const d; 0406 friend class KConfigDialogManagerPrivate; 0407 0408 Q_DISABLE_COPY(KConfigDialogManager) 0409 Q_PRIVATE_SLOT(d, void onWidgetModified()) 0410 }; 0411 0412 #endif // KCONFIGDIALOGMANAGER_H