File indexing completed on 2024-05-05 03:53:26

0001 /*
0002     SPDX-FileCopyrightText: 1999 Matthias Hoelzer-Kluepfel <hoelzer@kde.org>
0003     SPDX-FileCopyrightText: 2001 Michael Goffioul <kdeprint@swing.be>
0004     SPDX-FileCopyrightText: 2004 Frans Englich <frans.englich@telia.com>
0005     SPDX-FileCopyrightText: 2009 Dario Freddi <drf@kde.org>
0006     SPDX-FileCopyrightText: 2015 Marco Martin <mart@kde.org>
0007     SPDX-FileCopyrightText: 2023 Alexander Lohnau <alexander.lohnau@gmx.de>
0008 
0009     SPDX-License-Identifier: LGPL-2.0-or-later
0010 */
0011 
0012 #ifndef KQUICKCONFIGMODULE_H
0013 #define KQUICKCONFIGMODULE_H
0014 
0015 #include "kcmutilsquick_export.h"
0016 
0017 #include <QObject>
0018 #include <QQmlComponent>
0019 #include <QStringList>
0020 #include <QVariant>
0021 
0022 #include <KPluginFactory>
0023 #include <KPluginMetaData>
0024 
0025 #include <memory>
0026 #include <qqmlintegration.h>
0027 
0028 #include "kabstractconfigmodule.h"
0029 #include "kquickconfigmoduleloader.h"
0030 
0031 class QQuickItem;
0032 class QQmlEngine;
0033 class KQuickConfigModulePrivate;
0034 
0035 /**
0036  * @class KQuickConfigModule kquickconfigmodule.h KQuickConfigModule
0037  *
0038  * The base class for QtQuick configuration modules.
0039  * Configuration modules are realized as plugins that are dynamically loaded.
0040  *
0041  * All the necessary glue logic and the GUI bells and whistles
0042  * are provided by the control center and must not concern
0043  * the module author.
0044  *
0045  * To write a config module, you have to create a C++ plugin
0046  * and an accompaning QML user interface.
0047  *
0048  * To allow KCMUtils to load your ConfigModule subclass, you must create a KPluginFactory implementation.
0049  *
0050  * \code
0051  * #include <KPluginFactory>
0052  *
0053  * K_PLUGIN_CLASS_WITH_JSON(MyConfigModule, "yourmetadata.json")
0054  * \endcode
0055  *
0056  * The constructor of the ConfigModule then looks like this:
0057  * \code
0058  * YourConfigModule::YourConfigModule(QObject *parent, const KPluginMetaData &metaData)
0059  *   : KQuickConfigModule(parent, metaData)
0060  * {
0061  * }
0062  * \endcode
0063  *
0064  * The QML part must be in the KPackage format, installed under share/kpackage/kcms.
0065  * @see KPackage::Package
0066  *
0067  * The package must have the same name as the plugin filename, to be installed
0068  * by CMake with the command:
0069  * \code
0070  * kpackage_install_package(packagedir kcm_yourconfigmodule kcms)
0071  * \endcode
0072  * The "packagedir" is the subdirectory in the source tree where the package sources are
0073  * located, and "kcm_yourconfigmodule" is id of the plugin.
0074  * Finally "kcms" is the literal string "kcms", so that the package is
0075  * installed as a configuration module (and not some other kind of package).
0076  *
0077  * The QML part can access all the properties of ConfigModule (together with the properties
0078  * defined in its subclass) by accessing to the global object "kcm", or with the
0079  * import of "org.kde.kcmutils" the ConfigModule attached property.
0080  *
0081  * \code
0082  * import QtQuick
0083  * import org.kde.kcmutils
0084  * import org.kde.kirigami as Kirigami
0085  *
0086  * Item {
0087  *     // implicit size will be used as initial size when loaded in kcmshell6
0088  *     implicitWidth: Kirigami.Units.gridUnit * 30
0089  *     implicitHeight: Kirigami.Units.gridUnit * 30
0090  *
0091  *     ConfigModule.buttons: ConfigModule.Help | ConfigModule.Apply
0092  *
0093  *     Label {
0094  *         text: kcm.needsSave
0095  *     }
0096  * }
0097  * \endcode
0098  *
0099  * See https://develop.kde.org/docs/extend/kcm/ for more detailed documentation.
0100  * @since 6.0
0101  */
0102 class KCMUTILSQUICK_EXPORT KQuickConfigModule : public KAbstractConfigModule
0103 {
0104     Q_OBJECT
0105 
0106     Q_PROPERTY(QQuickItem *mainUi READ mainUi CONSTANT)
0107     Q_PROPERTY(int columnWidth READ columnWidth WRITE setColumnWidth NOTIFY columnWidthChanged)
0108     Q_PROPERTY(int depth READ depth NOTIFY depthChanged)
0109     Q_PROPERTY(int currentIndex READ currentIndex WRITE setCurrentIndex NOTIFY currentIndexChanged)
0110 
0111     QML_NAMED_ELEMENT(ConfigModule)
0112 
0113 public:
0114     /**
0115      * Destroys the module.
0116      */
0117     ~KQuickConfigModule() override;
0118 
0119     /**
0120      * @return the qml engine that built the main config UI
0121      */
0122     std::shared_ptr<QQmlEngine> engine() const;
0123 
0124     /**
0125      * The error string in case the mainUi failed to load.
0126      */
0127     QString errorString() const;
0128 
0129     // QML property accessors
0130 
0131     /**
0132      * @return The main UI for this configuration module. It's a QQuickItem coming from
0133      * the QML package named the same as the KAboutData's component name for
0134      * this config module
0135      */
0136     QQuickItem *mainUi();
0137 
0138     /*
0139      * @return a subpage at a given depth
0140      * @note This does not include the mainUi. i.e a depth of 2 is a mainUi and one subPage
0141      * at index 0
0142      */
0143     QQuickItem *subPage(int index) const;
0144 
0145     /**
0146      * returns the width the kcm wants in column mode.
0147      * If a columnWidth is valid ( > 0 ) and less than the systemsettings' view width,
0148      * more than one will be visible at once, and the first page will be a sidebar to the last page pushed.
0149      * As default, this is -1 which will make the shell always show only one page at a time.
0150      */
0151     int columnWidth() const;
0152 
0153     /**
0154      * Sets the column width we want.
0155      */
0156     void setColumnWidth(int width);
0157 
0158     /**
0159      * @returns how many pages this kcm has.
0160      * It is guaranteed to be at least 1 (the main ui) plus how many times a new page has been pushed without pop
0161      */
0162     int depth() const;
0163 
0164     /**
0165      * Sets the current page index this kcm should display
0166      */
0167     void setCurrentIndex(int index);
0168 
0169     /**
0170      * @returns the index of the page this kcm should display
0171      */
0172     int currentIndex() const;
0173 
0174     static KQuickConfigModule *qmlAttachedProperties(QObject *object);
0175 
0176 public Q_SLOTS:
0177     /**
0178      * Push a new sub page in the KCM hierarchy: pages will be seen as a Kirigami PageRow
0179      */
0180     void push(const QString &fileName, const QVariantMap &initialProperties = QVariantMap());
0181 
0182     /**
0183      *
0184      */
0185     void push(QQuickItem *item);
0186 
0187     /**
0188      * pop the last page of the KCM hierarchy, the page is destroyed
0189      */
0190     void pop();
0191 
0192     /**
0193      * remove and return the last page of the KCM hierarchy:
0194      * the popped page won't be deleted, it's the caller's responsibility to manage the lifetime of the returned item
0195      * @returns the last page if any, nullptr otherwise
0196      */
0197     QQuickItem *takeLast();
0198 
0199 Q_SIGNALS:
0200 
0201     // QML NOTIFY signaling
0202 
0203     /**
0204      * Emitted when a new sub page is pushed
0205      */
0206     void pagePushed(QQuickItem *page);
0207 
0208     /**
0209      * Emitted when a sub page is popped
0210      */
0211     // RFC: page argument?
0212     void pageRemoved();
0213 
0214     /**
0215      * Emitted when the wanted column width of the kcm changes
0216      */
0217     void columnWidthChanged(int width);
0218 
0219     /**
0220      * Emitted when the current page changed
0221      */
0222     void currentIndexChanged(int index);
0223 
0224     /**
0225      * Emitted when the number of pages changed
0226      */
0227     void depthChanged(int index);
0228 
0229     /**
0230      * Emitted when the main Ui has loaded successfully and `mainUi()` is available
0231      */
0232     void mainUiReady();
0233 
0234 protected:
0235     /**
0236      * Base class for all QtQuick config modules.
0237      * Use KQuickConfigModuleLoader to instantiate this class
0238      *
0239      * @note do not emit changed signals here, since they are not yet connected to any slot.
0240      */
0241     explicit KQuickConfigModule(QObject *parent, const KPluginMetaData &metaData);
0242 
0243 private:
0244     void setInternalEngine(const std::shared_ptr<QQmlEngine> &engine);
0245     friend KPluginFactory::Result<KQuickConfigModule>
0246     KQuickConfigModuleLoader::loadModule(const KPluginMetaData &metaData, QObject *parent, const QVariantList &args, const std::shared_ptr<QQmlEngine> &engine);
0247     const std::unique_ptr<KQuickConfigModulePrivate> d;
0248 };
0249 
0250 QML_DECLARE_TYPEINFO(KQuickConfigModule, QML_HAS_ATTACHED_PROPERTIES)
0251 
0252 #endif // KQUICKCONFIGMODULE_H