File indexing completed on 2024-05-05 17:33:20

0001 /*
0002  *   SPDX-FileCopyrightText: 2012 Aleix Pol Gonzalez <aleixpol@blue-systems.com>
0003  *
0004  *   SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
0005  */
0006 
0007 #pragma once
0008 
0009 #include <QObject>
0010 #include <QPair>
0011 #include <QVariantList>
0012 #include <QVector>
0013 
0014 #include "AbstractResource.h"
0015 #include "DiscoverAction.h"
0016 #include "Transaction/AddonList.h"
0017 
0018 #include "discovercommon_export.h"
0019 
0020 class Transaction;
0021 class Category;
0022 class AbstractReviewsBackend;
0023 class AbstractBackendUpdater;
0024 
0025 class DISCOVERCOMMON_EXPORT ResultsStream : public QObject
0026 {
0027     Q_OBJECT
0028 public:
0029     ResultsStream(const QString &objectName);
0030 
0031     /// assumes all the information is in @p resources
0032     ResultsStream(const QString &objectName, const QVector<AbstractResource *> &resources);
0033     ~ResultsStream() override;
0034 
0035     void finish();
0036 
0037 Q_SIGNALS:
0038     void resourcesFound(const QVector<AbstractResource *> &resources);
0039     void fetchMore();
0040 };
0041 
0042 class DISCOVERCOMMON_EXPORT InlineMessage : public QObject
0043 {
0044     Q_OBJECT
0045 public:
0046     // Keep in sync with Kirigami's in enums.h
0047     enum InlineMessageType {
0048         Information = 0,
0049         Positive,
0050         Warning,
0051         Error,
0052     };
0053     Q_ENUM(InlineMessageType)
0054     Q_PROPERTY(InlineMessageType type MEMBER type CONSTANT)
0055     Q_PROPERTY(QString iconName MEMBER iconName CONSTANT)
0056     Q_PROPERTY(QString message MEMBER message CONSTANT)
0057     Q_PROPERTY(QVariantList actions MEMBER actions CONSTANT)
0058 
0059     InlineMessage(InlineMessageType type, const QString &iconName, const QString &message, DiscoverAction *action = nullptr)
0060         : type(type)
0061         , iconName(iconName)
0062         , message(message)
0063         , actions(action ? QVariantList{QVariant::fromValue<QObject *>(action)} : QVariantList())
0064     {
0065     }
0066 
0067     InlineMessage(InlineMessageType type, const QString &iconName, const QString &message, const QVariantList &actions)
0068         : type(type)
0069         , iconName(iconName)
0070         , message(message)
0071         , actions(actions)
0072     {
0073     }
0074 
0075     InlineMessageType type;
0076     const QString iconName;
0077     const QString message;
0078     const QVariantList actions;
0079 };
0080 
0081 /**
0082  * \class AbstractResourcesBackend  AbstractResourcesBackend.h "AbstractResourcesBackend.h"
0083  *
0084  * \brief This is the base class of all resource backends.
0085  *
0086  * For writing basic new resource backends, we need to implement two classes: this and the
0087  * AbstractResource one. Basic questions on how to build your plugin with those classes
0088  * can be answered by looking at the dummy plugin.
0089  *
0090  * As this is the base class of a backend, we save all the created resources here and also
0091  * accept calls to install and remove applications or to cancel transactions.
0092  *
0093  * To show resources in Discover, we need to initialize all resources we want to show beforehand,
0094  * we should not create resources in the search function. When we reload the resources
0095  * (e.g. when initializing), the backend needs change the fetching property throughout the
0096  * process.
0097  */
0098 class DISCOVERCOMMON_EXPORT AbstractResourcesBackend : public QObject
0099 {
0100     Q_OBJECT
0101     Q_PROPERTY(QString name READ name CONSTANT)
0102     Q_PROPERTY(QString displayName READ displayName CONSTANT)
0103     Q_PROPERTY(AbstractReviewsBackend *reviewsBackend READ reviewsBackend CONSTANT)
0104     Q_PROPERTY(int updatesCount READ updatesCount NOTIFY updatesCountChanged)
0105     Q_PROPERTY(int fetchingUpdatesProgress READ fetchingUpdatesProgress NOTIFY fetchingUpdatesProgressChanged)
0106     Q_PROPERTY(bool hasSecurityUpdates READ hasSecurityUpdates NOTIFY updatesCountChanged)
0107     Q_PROPERTY(bool isFetching READ isFetching NOTIFY fetchingChanged)
0108     Q_PROPERTY(bool hasApplications READ hasApplications CONSTANT)
0109 public:
0110     /**
0111      * Constructs an AbstractResourcesBackend
0112      * @param parent the parent of the class (the object will be deleted when the parent gets deleted)
0113      */
0114     explicit AbstractResourcesBackend(QObject *parent = nullptr);
0115 
0116     /**
0117      * @returns true when the backend is in a valid state, which means it is able to work
0118      * You must return true here if you want the backend to be loaded.
0119      */
0120     virtual bool isValid() const = 0;
0121 
0122     struct Filters {
0123         Category *category = nullptr;
0124         AbstractResource::State state = AbstractResource::Broken;
0125         QString mimetype;
0126         QString search;
0127         QString extends;
0128         QUrl resourceUrl;
0129         QString origin;
0130         bool allBackends = false;
0131         bool filterMinimumState = true;
0132         AbstractResourcesBackend *backend = nullptr;
0133 
0134         bool isEmpty() const
0135         {
0136             return !category && state == AbstractResource::Broken && mimetype.isEmpty() && search.isEmpty() && extends.isEmpty() && resourceUrl.isEmpty()
0137                 && origin.isEmpty();
0138         }
0139 
0140         bool shouldFilter(AbstractResource *res) const;
0141         void filterJustInCase(QVector<AbstractResource *> &input) const;
0142     };
0143 
0144     /**
0145      * @returns a stream that will provide elements that match the search
0146      */
0147 
0148     virtual ResultsStream *search(const Filters &search) = 0; // FIXME: Probably provide a standard implementation?!
0149 
0150     /**
0151      * @returns the reviews backend of this AbstractResourcesBackend (which handles all ratings and reviews of resources)
0152      */
0153     virtual AbstractReviewsBackend *reviewsBackend() const = 0; // FIXME: Have a standard impl which returns 0?
0154 
0155     /**
0156      * @returns the class which is used by Discover to update the users system, if you are unsure what to do
0157      * just return the StandardBackendUpdater
0158      */
0159     virtual AbstractBackendUpdater *backendUpdater() const = 0; // FIXME: Standard impl returning the standard updater?
0160 
0161     /**
0162      * @returns the number of resources for which an update is available, it should only count technical packages
0163      */
0164     virtual int updatesCount() const = 0; // FIXME: Probably provide a standard implementation?!
0165 
0166     /**
0167      * @returns whether either of the updates contains a security fix
0168      */
0169     virtual bool hasSecurityUpdates() const
0170     {
0171         return false;
0172     }
0173 
0174     /**
0175      * Tells whether the backend is fetching resources
0176      */
0177     virtual bool isFetching() const = 0;
0178 
0179     /**
0180      * @returns the appstream ids that this backend extends
0181      */
0182     virtual QStringList extends() const;
0183 
0184     /** @returns the plugin's name */
0185     QString name() const;
0186 
0187     /** @internal only to be used by the factory */
0188     void setName(const QString &name);
0189 
0190     virtual QString displayName() const = 0;
0191 
0192     /**
0193      * emits a change for all rating properties
0194      */
0195     void emitRatingsReady();
0196 
0197     /**
0198      * @returns the root category tree
0199      */
0200     virtual QVector<Category *> category() const
0201     {
0202         return {};
0203     }
0204 
0205     virtual bool hasApplications() const
0206     {
0207         return false;
0208     }
0209 
0210     virtual int fetchingUpdatesProgress() const;
0211 
0212 public Q_SLOTS:
0213     /**
0214      * This gets called when the backend should install an application.
0215      * The AbstractResourcesBackend should create a Transaction object, is returned and
0216      * will be included in the TransactionModel
0217      * @param app the application to be installed
0218      * @param addons the addons which should be installed with the application
0219      * @returns the Transaction that keeps track of the installation process
0220      */
0221     virtual Transaction *installApplication(AbstractResource *app, const AddonList &addons) = 0;
0222 
0223     /**
0224      * Overloaded function, which simply does the same, except not installing any addons.
0225      */
0226     virtual Transaction *installApplication(AbstractResource *app);
0227 
0228     /**
0229      * This gets called when the backend should remove an application.
0230      * Like in the installApplication() method, we'll return the Transaction
0231      * responsible for the removal.
0232      *
0233      * @see installApplication
0234      * @param app the application to be removed
0235      * @returns the Transaction that keeps track of the removal process
0236      */
0237     virtual Transaction *removeApplication(AbstractResource *app) = 0;
0238 
0239     /**
0240      * Notifies the backend that the user wants the information to be up to date
0241      */
0242     virtual void checkForUpdates() = 0;
0243 
0244     /**
0245      * Provides a guess why a search might not have offered satisfactory results
0246      */
0247     Q_SCRIPTABLE virtual InlineMessage *explainDysfunction() const;
0248 
0249 Q_SIGNALS:
0250     /**
0251      * Notify of a change in the backend
0252      */
0253     void fetchingChanged();
0254 
0255     /**
0256      * This should be emitted when the number of upgradeable packages changed.
0257      */
0258     void updatesCountChanged();
0259     /**
0260      * This should be emitted when all data of the backends resources changed. Internally it will Q_EMIT
0261      * a signal in the model to show the view that all data of a certain backend changed.
0262      */
0263     void allDataChanged(const QVector<QByteArray> &propertyNames);
0264 
0265     /**
0266      * Allows to notify some @p properties in @p resource have changed
0267      */
0268     void resourcesChanged(AbstractResource *resource, const QVector<QByteArray> &properties);
0269     void resourceRemoved(AbstractResource *resource);
0270 
0271     void passiveMessage(const QString &message);
0272     void inlineMessageChanged(const QSharedPointer<InlineMessage> &inlineMessage);
0273     void fetchingUpdatesProgressChanged();
0274 
0275 private:
0276     QString m_name;
0277 };
0278 
0279 DISCOVERCOMMON_EXPORT QDebug operator<<(QDebug dbg, const AbstractResourcesBackend::Filters &filters);
0280 
0281 /**
0282  * @internal Workaround because QPluginLoader enforces 1 instance per plugin
0283  */
0284 class DISCOVERCOMMON_EXPORT AbstractResourcesBackendFactory : public QObject
0285 {
0286     Q_OBJECT
0287 public:
0288     virtual QVector<AbstractResourcesBackend *> newInstance(QObject *parent, const QString &name) const = 0;
0289 };
0290 
0291 #define DISCOVER_BACKEND_PLUGIN(ClassName)                                                                                                                     \
0292     class ClassName##Factory : public AbstractResourcesBackendFactory                                                                                          \
0293     {                                                                                                                                                          \
0294         Q_OBJECT                                                                                                                                               \
0295         Q_PLUGIN_METADATA(IID "org.kde.muon.AbstractResourcesBackendFactory")                                                                                  \
0296         Q_INTERFACES(AbstractResourcesBackendFactory)                                                                                                          \
0297     public:                                                                                                                                                    \
0298         QVector<AbstractResourcesBackend *> newInstance(QObject *parent, const QString &name) const override                                                   \
0299         {                                                                                                                                                      \
0300             auto c = new ClassName(parent);                                                                                                                    \
0301             c->setName(name);                                                                                                                                  \
0302             return {c};                                                                                                                                        \
0303         }                                                                                                                                                      \
0304     };
0305 
0306 Q_DECLARE_INTERFACE(AbstractResourcesBackendFactory, "org.kde.muon.AbstractResourcesBackendFactory")