1 | /* |
2 | SPDX-FileCopyrightText: 2007 Josef Spillner <spillner@kde.org> |
3 | SPDX-FileCopyrightText: 2007-2010 Frederik Gladhorn <gladhorn@kde.org> |
4 | SPDX-FileCopyrightText: 2009 Jeremy Whiting <jpwhiting@kde.org> |
5 | |
6 | SPDX-License-Identifier: LGPL-2.1-or-later |
7 | */ |
8 | |
9 | #ifndef KNEWSTUFF3_ENGINEBASE_H |
10 | #define KNEWSTUFF3_ENGINEBASE_H |
11 | |
12 | #include <QHash> |
13 | #include <QMetaEnum> |
14 | #include <QObject> |
15 | #include <QSharedPointer> |
16 | #include <QString> |
17 | |
18 | #include "categorymetadata.h" |
19 | #include "entry.h" |
20 | #include "errorcode.h" |
21 | #include "knewstuffcore_export.h" |
22 | #include "provider.h" |
23 | #include "searchpreset.h" |
24 | |
25 | #include <memory> |
26 | |
27 | class KJob; |
28 | class EnginePrivate; |
29 | class QDomDocument; |
30 | class SearchPresetModel; |
31 | |
32 | namespace Attica |
33 | { |
34 | class Provider; |
35 | } |
36 | |
37 | /*! |
38 | * \namespace KNSCore |
39 | * \inmodule KNewStuffCore |
40 | * |
41 | * \brief The KNewStuff core. |
42 | */ |
43 | namespace KNSCore |
44 | { |
45 | class Cache; |
46 | class ; |
47 | class ResultsStream; |
48 | class EngineBasePrivate; |
49 | class Installation; |
50 | class SearchRequest; |
51 | class ProviderCore; |
52 | |
53 | /*! |
54 | * \class KNSCore::EngineBase |
55 | * \inmodule KNewStuffCore |
56 | * |
57 | * \brief KNewStuff engine. |
58 | * |
59 | * An engine keeps track of data which is available locally and remote |
60 | * and offers high-level synchronization calls as well as upload and download |
61 | * primitives using an underlying GHNS protocol. |
62 | * |
63 | * This is a base class for different engine implementations |
64 | */ |
65 | class KNEWSTUFFCORE_EXPORT EngineBase : public QObject |
66 | { |
67 | Q_OBJECT |
68 | |
69 | /*! |
70 | * \qmlproperty string EngineBase::useLabel |
71 | * Text that should be displayed for the adoption button, this defaults to "Use" |
72 | * \since 5.77 |
73 | */ |
74 | /*! |
75 | * \property KNSCore::EngineBase::useLabel |
76 | * Text that should be displayed for the adoption button, this defaults to "Use" |
77 | * \since 5.77 |
78 | */ |
79 | Q_PROPERTY(QString useLabel READ useLabel NOTIFY useLabelChanged) |
80 | |
81 | /*! |
82 | * \qmlproperty bool EngineBase::uploadEnabled |
83 | * Whether or not the configuration says that the providers are expected to support uploading. |
84 | * As it stands, this is used to determine whether or not to show the Upload... action where |
85 | * that is displayed (primarily NewStuff.Page). |
86 | * \since 5.85 |
87 | */ |
88 | /*! |
89 | * \property KNSCore::EngineBase::uploadEnabled |
90 | * Whether or not the configuration says that the providers are expected to support uploading. |
91 | * As it stands, this is used to determine whether or not to show the Upload... action where |
92 | * that is displayed (primarily NewStuff.Page). |
93 | * \since 5.85 |
94 | */ |
95 | Q_PROPERTY(bool uploadEnabled READ uploadEnabled NOTIFY uploadEnabledChanged) |
96 | |
97 | /*! |
98 | * \qmlproperty list<string> EngineBase::providerIDs |
99 | * \since 5.85 |
100 | */ |
101 | /*! |
102 | * \property KNSCore::EngineBase::providerIDs |
103 | * \since 5.85 |
104 | */ |
105 | Q_PROPERTY(QStringList providerIDs READ providerIDs NOTIFY providersChanged) |
106 | |
107 | /*! |
108 | * \qmlproperty ContentWarningType EngineBase::contentWarningType |
109 | */ |
110 | /*! |
111 | * \property KNSCore::EngineBase::contentWarningType |
112 | */ |
113 | Q_PROPERTY(ContentWarningType contentWarningType READ contentWarningType NOTIFY contentWarningTypeChanged) |
114 | |
115 | public: |
116 | /*! |
117 | * |
118 | */ |
119 | EngineBase(QObject *parent = nullptr); |
120 | ~EngineBase() override; |
121 | Q_DISABLE_COPY_MOVE(EngineBase) |
122 | |
123 | /*! |
124 | * List of all available config files. This list will contain no duplicated filenames. |
125 | * The returned file paths are absolute. |
126 | * \since 5.83 |
127 | */ |
128 | static QStringList availableConfigFiles(); |
129 | |
130 | /*! |
131 | * Initializes the engine. This step is application-specific and relies |
132 | * on an external configuration file, which determines all the details |
133 | * about the initialization. |
134 | * |
135 | * \a configfile KNewStuff2 configuration file (*.knsrc) |
136 | * |
137 | * Returns \b true if any valid configuration was found, \b false otherwise |
138 | */ |
139 | virtual bool init(const QString &configfile); |
140 | |
141 | /*! |
142 | * The name as defined by the knsrc file |
143 | * Returns The name associated with the engine's configuration file |
144 | * \since 5.63 |
145 | */ |
146 | QString name() const; |
147 | |
148 | /*! |
149 | * Text that should be displayed for the adoption button, this defaults to i18n("Use") |
150 | * \since 5.77 |
151 | */ |
152 | QString useLabel() const; |
153 | |
154 | /*! |
155 | * Signal gets emitted when the useLabel property changes |
156 | * \since 5.77 |
157 | */ |
158 | Q_SIGNAL void useLabelChanged(); |
159 | |
160 | /*! |
161 | * Whether or not the configuration says that the providers are expected to support uploading. |
162 | * Returns True if the providers are expected to support uploading |
163 | * \since 5.85 |
164 | */ |
165 | bool uploadEnabled() const; |
166 | |
167 | /*! |
168 | * Fired when the uploadEnabled property changes |
169 | * \since 5.85 |
170 | */ |
171 | Q_SIGNAL void uploadEnabledChanged(); |
172 | |
173 | /*! |
174 | * The list of the server-side names of the categories handled by this |
175 | * engine instance. This corresponds directly to the list of categories |
176 | * in your knsrc file. This is not supposed to be used as user-facing |
177 | * strings - see categoriesMetadata() for that. |
178 | * |
179 | * Returns The categories which this instance of Engine handles |
180 | */ |
181 | QStringList categories() const; |
182 | |
183 | #if KNEWSTUFFCORE_ENABLE_DEPRECATED_SINCE(6, 9) |
184 | /*! |
185 | * Get the entries cache for this engine (note that it may be null if the engine is |
186 | * not yet initialized). |
187 | * |
188 | * Returns the cache for this engine (or null if the engine is not initialized) |
189 | * \since 5.74 |
190 | * \deprecated[6.9] |
191 | * |
192 | * Do not use the cache directly |
193 | */ |
194 | KNEWSTUFFCORE_DEPRECATED_VERSION(6, 9, "Do not use the cache directly" ) |
195 | QSharedPointer<Cache> cache() const; |
196 | #endif |
197 | |
198 | #if KNEWSTUFFCORE_ENABLE_DEPRECATED_SINCE(6, 9) |
199 | /*! |
200 | * \deprecated[6.9] |
201 | * Use categoriesMetadata2 |
202 | */ |
203 | KNEWSTUFFCORE_DEPRECATED_VERSION(6, 9, "Use categoriesMetadata2" ) |
204 | QList<Provider::CategoryMetadata> categoriesMetadata(); |
205 | #endif |
206 | /*! |
207 | * The list of metadata for the categories handled by this engine instance. |
208 | * If you wish to show the categories to the user, this is the data to use. |
209 | * The category name is the string used to set categories for the filter, |
210 | * and also what is returned by both categories() and categoriesFilter(). |
211 | * The human-readable name is displayName, and the only thing which should |
212 | * be shown to the user. |
213 | * |
214 | * Returns The metadata for all categories handled by this engine |
215 | */ |
216 | QList<CategoryMetadata> categoriesMetadata2(); |
217 | |
218 | #if KNEWSTUFFCORE_ENABLE_DEPRECATED_SINCE(6, 9) |
219 | /*! |
220 | * \deprecated[6.9] |
221 | * Use searchPresets2 |
222 | */ |
223 | KNEWSTUFFCORE_DEPRECATED_VERSION(6, 9, "Use searchPresets2" ) |
224 | QList<Provider::SearchPreset> searchPresets(); |
225 | #endif |
226 | /*! |
227 | * \since 6.9 |
228 | */ |
229 | QList<SearchPreset> searchPresets2(); |
230 | |
231 | /*! |
232 | * Returns the list of attica (OCS) providers this engine is connected to |
233 | * \since 5.92 |
234 | */ |
235 | QList<Attica::Provider *> atticaProviders() const; |
236 | |
237 | /*! |
238 | * Set a filter for results, which filters out all entries which do not match |
239 | * the filter, as applied to the tags for the entry. This filters only on the |
240 | * tags specified for the entry itself. To filter the downloadlinks, use |
241 | * setDownloadTagFilter(QStringList). |
242 | * |
243 | * \note The default filter if one is not set from your knsrc file will filter |
244 | * out entries marked as ghns_excluded=1. To retain this when setting a custom |
245 | * filter, add "ghns_excluded!=1" as one of the filters. |
246 | * |
247 | * \note Some tags provided by OCS do not supply a value (and are simply passed |
248 | * as a key). These will be interpreted as having the value 1 for filtering |
249 | * purposes. An example of this might be ghns_excluded, which in reality will |
250 | * generally be passed through ocs as "ghns_excluded" rather than "ghns_excluded=1" |
251 | * |
252 | * \note As tags are metadata, they are provided in the form of adjectives. They |
253 | * are never supplied as action verbs or instructions (as an example, a good tag |
254 | * to suggest that for example a wallpaper is painted would be "painted" as opposed |
255 | * to "paint", and another example might be that an item should be "excluded" as |
256 | * opposed to "exclude"). |
257 | * |
258 | * == Examples of use == |
259 | * Value for tag "tagname" must be exactly "tagdata": |
260 | * tagname==tagdata |
261 | * |
262 | * Value for tag "tagname" must be different from "tagdata": |
263 | * tagname!=tagdata |
264 | * |
265 | * == KNSRC entry == |
266 | * A tag filter line in a .knsrc file, which is a comma separated list of |
267 | * tag/value pairs, might look like: |
268 | * |
269 | * TagFilter=ghns_excluded!=1,data##mimetype==application/cbr+zip,data##mimetype==application/cbr+rar |
270 | * which would honour the exclusion and filter out anything that does not |
271 | * include a comic book archive in either zip or rar format in one or more |
272 | * of the download items. |
273 | * Notice in particular that there are two data##mimetype entries. Use this |
274 | * for when a tag may have multiple values. |
275 | * |
276 | * TagFilter=application##architecture==x86_64 |
277 | * which would not honour the exclusion, and would filter out all entries |
278 | * which do not mark themselves as having a 64bit application binary in at |
279 | * least one download item. |
280 | * |
281 | * The value does not current support wildcards. The list should be considered |
282 | * a binary AND operation (that is, all filter entries must match for the data |
283 | * entry to be included in the return data) |
284 | * |
285 | * \a filter The filter in the form of a list of strings |
286 | * |
287 | * \sa setDownloadTagFilter |
288 | * \since 5.51 |
289 | */ |
290 | void setTagFilter(const QStringList &filter); |
291 | |
292 | /*! |
293 | * Returns the current tag filter list |
294 | * \sa setTagFilter |
295 | * \since 5.51 |
296 | */ |
297 | QStringList tagFilter() const; |
298 | |
299 | /*! |
300 | * Adds a single filter entry to the entry tag filter. The filter should be in |
301 | * the same form as the filter lines in the list used by setTagFilter(QStringList) |
302 | * |
303 | * \a filter The filter in the form of a string |
304 | * |
305 | * \sa setTagFilter |
306 | * \since 5.51 |
307 | */ |
308 | void addTagFilter(const QString &filter); |
309 | |
310 | /*! |
311 | * Sets a filter to be applied to the downloads for an entry. The logic is the |
312 | * same as used in setTagFilter(QStringList), but vitally, only one downloadlink |
313 | * is required to match the filter for the list to be valid. If you do not wish |
314 | * to show the others in your client, you must hide them yourself. |
315 | * |
316 | * For an entry to be accepted when a download tag filter is set, it must also |
317 | * be accepted by the entry filter (so, for example, while a list of downloads |
318 | * might be accepted, if the entry has ghns_excluded set, and the default entry |
319 | * filter is set, the entry will still be filtered out). |
320 | * |
321 | * In your knsrc file, set DownloadTagFilter to the filter you wish to apply, |
322 | * using the same logic as described for the entry tagfilter. |
323 | * |
324 | * \a filter The filter in the form of a list of strings |
325 | * |
326 | * \sa setTagFilter |
327 | * \since 5.51 |
328 | */ |
329 | void setDownloadTagFilter(const QStringList &filter); |
330 | |
331 | /*! |
332 | * Returns the current downloadlink tag filter list |
333 | * \sa setDownloadTagFilter |
334 | * \since 5.51 |
335 | */ |
336 | QStringList downloadTagFilter() const; |
337 | |
338 | /*! |
339 | * Add a single filter entry to the download tag filter. The filter should be in |
340 | * the same form as the filter lines in the list used by setDownloadsTagFilter(QStringList) |
341 | * |
342 | * \a filter The filter in the form of a string |
343 | * |
344 | * \sa setTagFilter |
345 | * \sa setDownloadTagFilter |
346 | * \since 5.51 |
347 | */ |
348 | void addDownloadTagFilter(const QString &filter); |
349 | |
350 | /*! |
351 | * Whether or not a user is able to vote on the passed entry. |
352 | * |
353 | * \a entry The entry to check votability on |
354 | * |
355 | * Returns True if the user is able to vote on the entry |
356 | */ |
357 | bool userCanVote(const Entry &entry); |
358 | |
359 | /*! |
360 | * Cast a vote on the passed entry. |
361 | * |
362 | * \a entry The entry to vote on |
363 | * |
364 | * \a rating A number from 0 to 100, 50 being neutral, 0 being most negative and 100 being most positive. |
365 | * |
366 | */ |
367 | void vote(const Entry &entry, uint rating); |
368 | |
369 | /*! |
370 | * Whether or not the user is allowed to become a fan of |
371 | * a particular entry. |
372 | * Not all providers (and consequently entries) support the fan functionality |
373 | * and you can use this function to determine this ability. |
374 | * |
375 | * \a entry The entry the user might wish to be a fan of |
376 | * |
377 | * Returns Whether or not it is possible for the user to become a fan of that entry |
378 | */ |
379 | bool userCanBecomeFan(const Entry &entry); |
380 | |
381 | /*! |
382 | * This will mark the user who is currently authenticated as a fan |
383 | * of the entry passed to the function. |
384 | * |
385 | * \a entry The entry the user wants to be a fan of |
386 | */ |
387 | void becomeFan(const Entry &entry); |
388 | // FIXME There is currently no exposed API to remove the fan status |
389 | |
390 | #if KNEWSTUFFCORE_ENABLE_DEPRECATED_SINCE(6, 9) |
391 | /*! |
392 | * The Provider instance with the passed ID |
393 | * |
394 | * \a providerId The ID of the Provider to fetch |
395 | * |
396 | * Returns the Provider with the passed ID, or null if non such Provider exists |
397 | * \since 5.63 |
398 | * \deprecated[6.9] |
399 | * Do not write provider-specific code |
400 | */ |
401 | KNEWSTUFFCORE_DEPRECATED_VERSION(6, 9, "Do not write provider-specific code" ) |
402 | QSharedPointer<Provider> provider(const QString &providerId) const; |
403 | #endif |
404 | |
405 | #if KNEWSTUFFCORE_ENABLE_DEPRECATED_SINCE(6, 9) |
406 | /*! |
407 | * Return the first provider in the providers list (usually the default provider) |
408 | * \since 5.63 |
409 | * \deprecated[6.9] |
410 | * Do not write provider-specific code |
411 | */ |
412 | KNEWSTUFFCORE_DEPRECATED_VERSION(6, 9, "Do not write provider-specific code" ) |
413 | QSharedPointer<Provider> defaultProvider() const; |
414 | #endif |
415 | |
416 | /*! |
417 | * The IDs of all providers known by this engine. Use this in combination with |
418 | * provider(const QString&) to iterate over all providers. |
419 | * Returns The string IDs of all known providers |
420 | * \since 5.85 |
421 | */ |
422 | QStringList providerIDs() const; |
423 | |
424 | /*! |
425 | * Whether or not an adoption command exists for this engine |
426 | * |
427 | * Returns True if an adoption command exists |
428 | */ |
429 | bool hasAdoptionCommand() const; |
430 | |
431 | #if KNEWSTUFFCORE_ENABLE_DEPRECATED_SINCE(6, 9) |
432 | /** |
433 | * Returns a stream object that will fulfill the @p request. |
434 | * |
435 | * @since 6.0 |
436 | * @deprecated since 6.9 Use the new search function |
437 | */ |
438 | KNEWSTUFFCORE_DEPRECATED_VERSION(6, 9, "Use the new search function" ) |
439 | ResultsStream *search(const KNSCore::Provider::SearchRequest &request); |
440 | #endif |
441 | |
442 | /** |
443 | * Returns a stream object that will fulfill the @p request. |
444 | * |
445 | * @since 6.9 |
446 | */ |
447 | ResultsStream *search(const KNSCore::SearchRequest &request); |
448 | |
449 | /*! |
450 | * \enum KNSCore::EngineBase::ContentWarningType |
451 | * |
452 | * \brief The ContentWarningType enum |
453 | * |
454 | * \value Static |
455 | * Content consists of static assets only. |
456 | * Installation should not pose a security risk. |
457 | * |
458 | * \value Executables |
459 | * Content may contain scripts or other executable code. |
460 | * Users should be warned to treat it like any other program. |
461 | * |
462 | * \since 6.1 |
463 | */ |
464 | enum class ContentWarningType { |
465 | Static, |
466 | Executables |
467 | }; |
468 | Q_ENUM(ContentWarningType) |
469 | |
470 | /*! |
471 | * \brief The level of warning that should be presented to the user |
472 | * \since 6.1 |
473 | * \sa ContentWarningType |
474 | */ |
475 | ContentWarningType contentWarningType() const; |
476 | |
477 | /*! |
478 | * Emitted after the initial config load |
479 | * \since 6.1 |
480 | */ |
481 | Q_SIGNAL void contentWarningTypeChanged(); |
482 | |
483 | Q_SIGNALS: |
484 | /*! |
485 | * Indicates a \a message to be added to the ui's log, or sent to a messagebox |
486 | */ |
487 | void signalMessage(const QString &message); |
488 | |
489 | void signalProvidersLoaded(); |
490 | |
491 | /*! |
492 | * Fires in the case of any critical or serious errors, such as network or API problems. |
493 | * |
494 | * \a errorCode Represents the specific type of error which has occurred |
495 | * |
496 | * \a message A human-readable message which can be shown to the end user |
497 | * |
498 | * \a metadata Any additional data which might be helpful to further work out the details of the error (see KNSCore::Entry::ErrorCode for the |
499 | * metadata details) |
500 | * |
501 | * \sa KNSCore::ErrorCode |
502 | * \since 5.53 |
503 | */ |
504 | void signalErrorCode(KNSCore::ErrorCode::ErrorCode errorCode, const QString &message, const QVariant &metadata); |
505 | |
506 | #if KNEWSTUFFCORE_ENABLE_DEPRECATED_SINCE(6, 9) |
507 | /*! |
508 | * \deprecated[6.9] |
509 | * Use variant with new argument type |
510 | */ |
511 | KNEWSTUFFCORE_DEPRECATED_VERSION(6, 9, "Use variant with new argument type" ) |
512 | void signalCategoriesMetadataLoded(const QList<Provider::CategoryMetadata> &categories); |
513 | #endif |
514 | /*! |
515 | * |
516 | */ |
517 | void signalCategoriesMetadataLoaded(const QList<KNSCore::CategoryMetadata> &categories); |
518 | |
519 | #if KNEWSTUFFCORE_ENABLE_DEPRECATED_SINCE(6, 9) |
520 | /*! |
521 | * Fires when the engine has loaded search presets. These represent interesting |
522 | * searches for the user, such as recommendations. |
523 | * \since 5.83 |
524 | * \deprecated[6.9] |
525 | * Use variant with new argument type |
526 | */ |
527 | KNEWSTUFFCORE_DEPRECATED_VERSION(6, 9, "Use variant with new argument type" ) |
528 | void signalSearchPresetsLoaded(const QList<Provider::SearchPreset> &presets); |
529 | #endif |
530 | |
531 | /*! |
532 | * Fires when the engine has loaded search presets. These represent interesting |
533 | * searches for the user, such as recommendations. |
534 | * \since 6.9 |
535 | */ |
536 | void signalSearchPresetsLoaded(const QList<KNSCore::SearchPreset> &presets); |
537 | |
538 | #if KNEWSTUFFCORE_ENABLE_DEPRECATED_SINCE(6, 9) |
539 | /*! |
540 | * Fired whenever the list of providers changes |
541 | * \since 5.85 |
542 | * \deprecated[6.9] |
543 | * Use providerAdded signal |
544 | */ |
545 | KNEWSTUFFCORE_DEPRECATED_VERSION(6, 9, "Use providerAdded signal" ) |
546 | void providersChanged(); |
547 | #endif |
548 | |
549 | /*! |
550 | * |
551 | */ |
552 | void loadingProvider(); |
553 | |
554 | /*! |
555 | * |
556 | */ |
557 | void providerAdded(KNSCore::ProviderCore *provider); |
558 | |
559 | private: |
560 | // the .knsrc file was loaded |
561 | void slotProviderFileLoaded(const QDomDocument &doc); |
562 | // instead of getting providers from knsrc, use what was configured in ocs systemsettings |
563 | void atticaProviderLoaded(const Attica::Provider &provider); |
564 | // called when a provider is ready to work |
565 | void providerInitialized(KNSCore::Provider *); |
566 | |
567 | // loading the .knsrc file failed |
568 | void slotProvidersFailed(); |
569 | |
570 | /* |
571 | * load providers from the providersurl in the knsrc file |
572 | * creates providers based on their type and adds them to the list of providers |
573 | */ |
574 | void loadProviders(); |
575 | |
576 | protected: |
577 | #if KNEWSTUFFCORE_ENABLE_DEPRECATED_SINCE(6, 9) |
578 | /*! |
579 | * Add a provider and connect it to the right slots |
580 | * \deprecated[6.9] |
581 | * Use providerAdded signal |
582 | */ |
583 | KNEWSTUFFCORE_DEPRECATED_VERSION(6, 9, "Use providerAdded signal" ) |
584 | virtual void addProvider(QSharedPointer<KNSCore::Provider> provider); |
585 | #endif |
586 | virtual void updateStatus(); |
587 | |
588 | friend class ResultsStream; |
589 | friend class Transaction; |
590 | friend class TransactionPrivate; |
591 | friend class EngineBasePrivate; |
592 | friend class ::SearchPresetModel; |
593 | Installation *installation() const; // Needed for quick engine |
594 | #if KNEWSTUFFCORE_ENABLE_DEPRECATED_SINCE(6, 9) |
595 | /*! |
596 | * \deprecated[6.9] |
597 | * Do not write provider-specific code |
598 | */ |
599 | KNEWSTUFFCORE_DEPRECATED_VERSION(6, 9, "Do not write provider-specific code" ) |
600 | QList<QSharedPointer<Provider>> providers() const; |
601 | #endif |
602 | // FIXME KF7: make this private and declare QuickEngine a friend. this cannot be used from the outside! |
603 | std::unique_ptr<EngineBasePrivate> d; |
604 | }; |
605 | |
606 | } |
607 | |
608 | #endif |
609 | |