File indexing completed on 2024-05-12 05:29:03

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