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")