File indexing completed on 2024-04-21 03:53:22

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.
0063  * @endparblock
0064  *
0065  * @par Using Other Properties than The USER Property
0066  * @parblock
0067  * To use a widget's property that is not the USER property, the property to use
0068  * can be selected by setting onto the widget instance a property with the key
0069  * "kcfg_property" and as the value the name of the property:
0070  * \code
0071  * ColorEditWidget *myWidget = new ColorEditWidget;
0072  * myWidget->setProperty("kcfg_property", QByteArray("redColorPart"));
0073  * \endcode
0074  * This selection of the property to use is just valid for this widget instance.
0075  * When using a UI file, the "kcfg_property" property can also be set using Qt Designer.
0076  * @endparblock
0077  *
0078  * @par Configuring Classes to use Other Properties Globally
0079  * @parblock
0080  * Alternatively a non-USER property can be defined for a widget class globally
0081  * by registering it for the class in the KConfigDialogManager::propertyMap().
0082  * This global registration has lower priority than any "kcfg_property" property
0083  * set on a class instance though, so the latter overrules this global setting.
0084  * Note: setting the property in the propertyMap affects any instances of that
0085  * widget class in the current application, so use only when needed and prefer
0086  * instead the "kcfg_property" property. Especially with software with many
0087  * libraries and 3rd-party plugins in one process there is a chance of
0088  * conflicting settings.
0089  *
0090  * Example:
0091  *
0092  * If the ColorEditWidget has another property redColor defined by
0093  * \code
0094  * Q_PROPERTY(int redColorPart READ redColorPart WRITE setRedColorPart NOTIFY redColorPartChanged)
0095  * \endcode
0096  * and this one should be used in the settings, call somewhere in the code before
0097  * using the settings:
0098  * \code
0099  * KConfigDialogManager::propertyMap()->insert("ColorEditWidget", QByteArray("redColorPart"));
0100  * \endcode
0101  * @endparblock
0102  *
0103  * @par Using Different Signals than The NOTIFY Signal
0104  * @parblock
0105  * If some non-default signal should be used, e.g. because the property to use does not
0106  * have a NOTIFY setting, for a given widget instance the signal to use can be set
0107  * by a property with the key "kcfg_propertyNotify" and as the value the signal signature.
0108  * This will take priority over the signal noted by NOTIFY for the chosen property
0109  * as well as the content of KConfigDialogManager::changedMap(). Since 5.32.
0110  *
0111  * Example:
0112  *
0113  * If for a class OtherColorEditWidget there was no NOTIFY set on the USER property,
0114  * but some signal colorSelected(QColor) defined which would be good enough to reflect
0115  * the settings change, defined by
0116  * \code
0117  * Q_PROPERTY(QColor color READ color WRITE setColor USER true)
0118  * Q_SIGNALS:
0119  *     void colorSelected(const QColor &color);
0120  * \endcode
0121  * the signal to use would be defined by this:
0122  * \code
0123  * OtherColorEditWidget *myWidget = new OtherColorEditWidget;
0124  * myWidget->setProperty("kcfg_propertyNotify", QByteArray(SIGNAL(colorSelected(QColor))));
0125  * \endcode
0126  * @endparblock
0127  *
0128  * @author Benjamin C Meyer <ben+kdelibs at meyerhome dot net>
0129  * @author Waldo Bastian <bastian@kde.org>
0130  */
0131 class KCONFIGWIDGETS_EXPORT KConfigDialogManager : public QObject
0132 {
0133     Q_OBJECT
0134 
0135 Q_SIGNALS:
0136     /**
0137      * One or more of the settings have been saved (such as when the user
0138      * clicks on the Apply button).  This is only emitted by updateSettings()
0139      * whenever one or more setting were changed and consequently saved.
0140      */
0141     void settingsChanged(); // clazy:exclude=overloaded-signal
0142 
0143     /**
0144      * If retrieveSettings() was told to track changes then if
0145      * any known setting was changed this signal will be emitted.  Note
0146      * that a settings can be modified several times and might go back to the
0147      * original saved state. hasChanged() will tell you if anything has
0148      * actually changed from the saved values.
0149      */
0150     void widgetModified();
0151 
0152 public:
0153     /**
0154      * Constructor.
0155      * @param parent  Dialog widget to manage
0156      * @param conf Object that contains settings
0157      */
0158     KConfigDialogManager(QWidget *parent, KCoreConfigSkeleton *conf);
0159 
0160     /**
0161      * Destructor.
0162      */
0163     ~KConfigDialogManager() override;
0164 
0165     /**
0166      * Add additional widgets to manage
0167      * @param widget Additional widget to manage, including all its children
0168      */
0169     void addWidget(QWidget *widget);
0170 
0171     /**
0172      * Returns whether the current state of the known widgets are
0173      * different from the state in the config object.
0174      */
0175     bool hasChanged() const;
0176 
0177     /**
0178      * Returns whether the current state of the known widgets are
0179      * the same as the default state in the config object.
0180      */
0181     bool isDefault() const;
0182 
0183     /**
0184      * Retrieve the map between widgets class names and the
0185      * USER properties used for the configuration values.
0186      */
0187     static QHash<QString, QByteArray> *propertyMap();
0188 
0189 public Q_SLOTS:
0190     /**
0191      * Traverse the specified widgets, saving the settings of all known
0192      * widgets in the settings object.
0193      *
0194      * Example use: User clicks Ok or Apply button in a configure dialog.
0195      */
0196     void updateSettings();
0197 
0198     /**
0199      * Traverse the specified widgets, sets the state of all known
0200      * widgets according to the state in the settings object.
0201      *
0202      * Example use: Initialisation of dialog.
0203      * Example use: User clicks Reset button in a configure dialog.
0204      */
0205     void updateWidgets();
0206 
0207     /**
0208      * Traverse the specified widgets, sets the state of all known
0209      * widgets according to the default state in the settings object.
0210      *
0211      * Example use: User clicks Defaults button in a configure dialog.
0212      */
0213     void updateWidgetsDefault();
0214 
0215     /**
0216      * Show or hide an indicator when settings have changed from their default value.
0217      * Update all widgets to show or hide the indicator accordingly.
0218      *
0219      * @since 5.73
0220      */
0221     void setDefaultsIndicatorsVisible(bool enabled);
0222 
0223 protected:
0224     /**
0225      * @param trackChanges - If any changes by the widgets should be tracked
0226      * set true.  This causes the emitting the modified() signal when
0227      * something changes.
0228      * TODO: @return bool - True if any setting was changed from the default.
0229      */
0230     void init(bool trackChanges);
0231 
0232     /**
0233      * Recursive function that finds all known children.
0234      * Goes through the children of widget and if any are known and not being
0235      * ignored, stores them in currentGroup.  Also checks if the widget
0236      * should be disabled because it is set immutable.
0237      * @param widget - Parent of the children to look at.
0238      * @param trackChanges - If true then tracks any changes to the children of
0239      * widget that are known.
0240      * @return bool - If a widget was set to something other than its default.
0241      */
0242     bool parseChildren(const QWidget *widget, bool trackChanges);
0243 
0244     /**
0245      * Finds the USER property name using Qt's MetaProperty system, and caches
0246      * it in the property map (the cache could be retrieved by propertyMap() ).
0247      */
0248     QByteArray getUserProperty(const QWidget *widget) const;
0249 
0250     /**
0251      * Find the property to use for a widget by querying the "kcfg_property"
0252      * property of the widget. Like a widget can use a property other than the
0253      * USER property.
0254      * @since 4.3
0255      */
0256     QByteArray getCustomProperty(const QWidget *widget) const;
0257 
0258     /**
0259      * Finds the changed signal of the USER property using Qt's MetaProperty system.
0260      * @since 5.32
0261      */
0262     QByteArray getUserPropertyChangedSignal(const QWidget *widget) const;
0263 
0264     /**
0265      * Find the changed signal of the property to use for a widget by querying
0266      * the "kcfg_propertyNotify" property of the widget. Like a widget can use a
0267      * property change signal other than the one for USER property, if there even is one.
0268      * @since 5.32
0269      */
0270     QByteArray getCustomPropertyChangedSignal(const QWidget *widget) const;
0271 
0272     /**
0273      * Set a property
0274      */
0275     void setProperty(QWidget *w, const QVariant &v);
0276 
0277     /**
0278      * Retrieve a property
0279      */
0280     QVariant property(QWidget *w) const;
0281 
0282     /**
0283      * Setup secondary widget properties
0284      */
0285     void setupWidget(QWidget *widget, KConfigSkeletonItem *item);
0286 
0287     /**
0288      * Initializes the property maps
0289      */
0290     static void initMaps();
0291 
0292 private:
0293     /**
0294      * KConfigDialogManager KConfigDialogManagerPrivate class.
0295      */
0296     std::unique_ptr<KConfigDialogManagerPrivate> const d;
0297     friend class KConfigDialogManagerPrivate;
0298 
0299     Q_DISABLE_COPY(KConfigDialogManager)
0300     Q_PRIVATE_SLOT(d, void onWidgetModified())
0301 };
0302 
0303 #endif // KCONFIGDIALOGMANAGER_H