KNewStuff

quickengine.cpp
1/*
2 SPDX-FileCopyrightText: 2016 Dan Leinir Turthra Jensen <admin@leinir.dk>
3
4 SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
5*/
6
7#include "quickengine.h"
8#include "cache.h"
9#include "errorcode.h"
10#include "imageloader_p.h"
11#include "installation_p.h"
12#include "knewstuffquick_debug.h"
13#include "quicksettings.h"
14
15#include <KLocalizedString>
16#include <QQmlInfo>
17#include <QTimer>
18
19#include "categoriesmodel.h"
20#include "quickquestionlistener.h"
21#include "searchpresetmodel.h"
22
23#include "../core/enginebase_p.h"
24#include "../core/providerbase_p.h"
25#include "../core/providercore.h"
26#include "../core/providercore_p.h"
27
28// Could be made :public EngineBasePrivate so we don't have two distinct d pointers
29class EnginePrivate
30{
31public:
32 bool isValid = false;
33 CategoriesModel *categoriesModel = nullptr;
34 SearchPresetModel *searchPresetModel = nullptr;
35 QString configFile;
36 QTimer searchTimer;
37 Engine::BusyState busyState;
38 QString busyMessage;
39 // the current request from providers
40 KNSCore::SearchRequest currentRequest;
41 KNSCore::SearchRequest storedRequest;
42 // the page that is currently displayed, so it is not requested repeatedly
43 int currentPage = -1;
44
45 // when requesting entries from a provider, how many to ask for
46 int pageSize = 20;
47
48 int numDataJobs = 0;
49 int numPictureJobs = 0;
50 int numInstallJobs = 0;
51};
52
53Engine::Engine(QObject *parent)
54 : KNSCore::EngineBase(parent)
55 , d(new EnginePrivate)
56 , dd(KNSCore::EngineBase::d.get())
57{
58 connect(this, &KNSCore::EngineBase::providerAdded, this, [this](auto core) {
59 connect(core->d->base, &KNSCore::ProviderBase::entriesLoaded, this, [this](const auto &request, const auto &entries) {
60 d->currentPage = qMax<int>(request.page(), d->currentPage);
61 qCDebug(KNEWSTUFFQUICK) << "loaded page " << request.page() << "current page" << d->currentPage << "count:" << entries.count();
62
63 if (request.filter() != KNSCore::Filter::Updates) {
64 dd->cache->insertRequest(request, entries);
65 }
66 Q_EMIT signalEntriesLoaded(entries);
67
68 --d->numDataJobs;
69 updateStatus();
70 });
71 connect(core->d->base, &KNSCore::ProviderBase::entryDetailsLoaded, this, [this](const auto &entry) {
72 --d->numDataJobs;
73 updateStatus();
74 Q_EMIT signalEntryEvent(entry, KNSCore::Entry::DetailsLoadedEvent);
75 });
76 });
77
78 const auto setBusy = [this](Engine::BusyState state, const QString &msg) {
79 setBusyState(state);
80 d->busyMessage = msg;
81 };
82 setBusy(BusyOperation::Initializing, i18n("Loading data")); // For the user this should be the same as initializing
83
84 KNewStuffQuick::QuickQuestionListener::instance();
85 d->categoriesModel = new CategoriesModel(this);
86 connect(d->categoriesModel, &QAbstractListModel::modelReset, this, &Engine::categoriesChanged);
87 d->searchPresetModel = new SearchPresetModel(this);
88 connect(d->searchPresetModel, &QAbstractListModel::modelReset, this, &Engine::searchPresetModelChanged);
89
90 d->searchTimer.setSingleShot(true);
91 d->searchTimer.setInterval(1000);
92 connect(&d->searchTimer, &QTimer::timeout, this, &Engine::reloadEntries);
93 connect(installation(), &KNSCore::Installation::signalInstallationFinished, this, [this]() {
94 --d->numInstallJobs;
95 updateStatus();
96 });
97 connect(installation(), &KNSCore::Installation::signalInstallationFailed, this, [this](const QString &message) {
98 --d->numInstallJobs;
99 Q_EMIT signalErrorCode(KNSCore::ErrorCode::InstallationError, message, QVariant());
100 });
101 connect(this, &EngineBase::signalProvidersLoaded, this, &Engine::updateStatus);
102 connect(this, &EngineBase::signalProvidersLoaded, this, [this]() {
103 d->currentRequest = KNSCore::SearchRequest(d->currentRequest.sortMode(),
104 d->currentRequest.filter(),
105 d->currentRequest.searchTerm(),
106 EngineBase::categories(),
107 d->currentRequest.page(),
108 d->currentRequest.pageSize());
109 });
110
111 connect(this,
113 this,
114 [setBusy, this](const KNSCore::ErrorCode::ErrorCode &error, const QString &message, const QVariant &metadata) {
115 Q_EMIT errorCode(error, message, metadata);
116 if (error == KNSCore::ErrorCode::ProviderError || error == KNSCore::ErrorCode::ConfigFileError) {
117 // This means loading the config or providers file failed entirely and we cannot complete the
118 // initialisation. It also means the engine is done loading, but that nothing will
119 // work, and we need to inform the user of this.
120 setBusy({}, QString());
121 }
122
123 // Emit the signal later, currently QML is not connected to the slot
124 if (error == KNSCore::ErrorCode::ConfigFileError) {
125 QTimer::singleShot(0, [this, error, message, metadata]() {
126 Q_EMIT errorCode(error, message, metadata);
127 });
128 }
129 });
130
131 connect(this, &Engine::signalEntryEvent, this, [this](const KNSCore::Entry &entry, KNSCore::Entry::EntryEvent event) {
132 // Just forward the event but not do anything more
133 Q_EMIT entryEvent(entry, event);
134 });
135 //
136 // And finally, let's just make sure we don't miss out the various things here getting changed
137 // In other words, when we're asked to reset the view, actually do that
138 connect(this, &Engine::signalResetView, this, &Engine::categoriesFilterChanged);
139 connect(this, &Engine::signalResetView, this, &Engine::filterChanged);
140 connect(this, &Engine::signalResetView, this, &Engine::sortOrderChanged);
141 connect(this, &Engine::signalResetView, this, &Engine::searchTermChanged);
142}
143
144bool Engine::init(const QString &configfile)
145{
146 const bool valid = EngineBase::init(configfile);
147 if (valid) {
148 connect(this, &Engine::signalEntryEvent, dd->cache.get(), [this](const KNSCore::Entry &entry, KNSCore::Entry::EntryEvent event) {
149 if (event == KNSCore::Entry::StatusChangedEvent) {
150 dd->cache->registerChangedEntry(entry);
151 }
152 });
153 const auto slotEntryChanged = [this](const KNSCore::Entry &entry) {
155 };
156 // Don't connect KNSCore::Installation::signalEntryChanged as is already forwarded to
157 // Transaction, which in turn is forwarded to our slotEntryChanged, so avoids a double emission
158 connect(dd->cache.get(), &KNSCore::Cache2::entryChanged, this, slotEntryChanged);
159 }
160 return valid;
161}
162void Engine::updateStatus()
163{
164 QString busyMessage;
165 BusyState state;
166 if (d->numPictureJobs > 0) {
167 // If it is loading previews or data is irrelevant for the user
168 busyMessage = i18n("Loading data");
169 state |= BusyOperation::LoadingPreview;
170 }
171 if (d->numInstallJobs > 0) {
172 busyMessage = i18n("Installing");
173 state |= BusyOperation::InstallingEntry;
174 }
175 if (d->numDataJobs > 0) {
176 busyMessage = i18n("Loading data");
177 state |= BusyOperation::LoadingData;
178 }
179 d->busyMessage = busyMessage;
180 setBusyState(state);
181}
182
183bool Engine::needsLazyLoadSpinner()
184{
185 return d->numDataJobs > 0 || d->numPictureJobs;
186}
187
188Engine::~Engine() = default;
189
190void Engine::setBusyState(BusyState state)
191{
192 d->busyState = state;
194}
196{
197 return d->busyState;
198}
199QString Engine::busyMessage() const
200{
201 return d->busyMessage;
202}
203
204QString Engine::configFile() const
205{
206 return d->configFile;
207}
208
209void Engine::setConfigFile(const QString &newFile)
210{
211 if (d->configFile != newFile) {
212 d->configFile = newFile;
213 Q_EMIT configFileChanged();
214
215 if (KNewStuffQuick::Settings::instance()->allowedByKiosk()) {
216 d->isValid = init(newFile);
217 Q_EMIT categoriesFilterChanged();
218 Q_EMIT filterChanged();
219 Q_EMIT sortOrderChanged();
220 Q_EMIT searchTermChanged();
221 } else {
222 // This is not an error message in the proper sense, and the message is not intended to look like an error (as there is really
223 // nothing the user can do to fix it, and we just tell them so they're not wondering what's wrong)
225 KNSCore::ErrorCode::ConfigFileError,
226 i18nc("An informational message which is shown to inform the user they are not authorized to use GetHotNewStuff functionality",
227 "You are not authorized to Get Hot New Stuff. If you think this is in error, please contact the person in charge of your permissions."),
228 QVariant());
229 }
230 }
231}
232
233CategoriesModel *Engine::categories() const
234{
235 return d->categoriesModel;
236}
237
238QStringList Engine::categoriesFilter() const
239{
240 return d->currentRequest.categories();
241}
242
243void Engine::setCategoriesFilter(const QStringList &newCategoriesFilter)
244{
245 if (d->currentRequest.categories() != newCategoriesFilter) {
246 d->currentRequest = KNSCore::SearchRequest(d->currentRequest.sortMode(),
247 d->currentRequest.filter(),
248 d->currentRequest.searchTerm(),
249 newCategoriesFilter,
250 d->currentRequest.page(),
251 d->currentRequest.pageSize());
252 reloadEntries();
253 Q_EMIT categoriesFilterChanged();
254 }
255}
256
257#if KNEWSTUFFCORE_BUILD_DEPRECATED_SINCE(6, 9)
258KNSCore::Provider::Filter Engine::filter() const
259{
260 return [filter = filter2()] {
261 switch (filter) {
262 case KNSCore::Filter::None:
263 return KNSCore::Provider::None;
264 case KNSCore::Filter::Installed:
265 return KNSCore::Provider::Installed;
266 case KNSCore::Filter::Updates:
267 return KNSCore::Provider::Updates;
268 case KNSCore::Filter::ExactEntryId:
269 return KNSCore::Provider::ExactEntryId;
270 }
271 return KNSCore::Provider::None;
272 }();
273}
274#endif
275
276#if KNEWSTUFFCORE_BUILD_DEPRECATED_SINCE(6, 9)
277void Engine::setFilter(KNSCore::Provider::Filter newFilter_)
278{
279 setFilter2([newFilter_] {
280 switch (newFilter_) {
281 case KNSCore::Provider::None:
282 return KNSCore::Filter::None;
283 case KNSCore::Provider::Installed:
284 return KNSCore::Filter::Installed;
285 case KNSCore::Provider::Updates:
286 return KNSCore::Filter::Updates;
287 case KNSCore::Provider::ExactEntryId:
288 return KNSCore::Filter::ExactEntryId;
289 }
290 return KNSCore::Filter::None;
291 }());
292}
293#endif
294
295KNSCore::Filter Engine::filter2() const
296{
297 return d->currentRequest.filter();
298}
299
300void Engine::setFilter2(KNSCore::Filter newFilter)
301{
302 if (d->currentRequest.filter() != newFilter) {
303 d->currentRequest = KNSCore::SearchRequest(d->currentRequest.sortMode(),
304 newFilter,
305 d->currentRequest.searchTerm(),
306 d->currentRequest.categories(),
307 d->currentRequest.page(),
308 d->currentRequest.pageSize());
309 reloadEntries();
310 Q_EMIT filterChanged();
311 }
312}
313
314#if KNEWSTUFFCORE_BUILD_DEPRECATED_SINCE(6, 9)
315KNSCore::Provider::SortMode Engine::sortOrder() const
316{
317 return [mode = sortOrder2()] {
318 switch (mode) {
319 case KNSCore::SortMode::Newest:
320 return KNSCore::Provider::Newest;
321 case KNSCore::SortMode::Alphabetical:
322 return KNSCore::Provider::Alphabetical;
323 case KNSCore::SortMode::Rating:
324 return KNSCore::Provider::Rating;
325 case KNSCore::SortMode::Downloads:
326 return KNSCore::Provider::Downloads;
327 }
328 return KNSCore::Provider::Rating;
329 }();
330}
331#endif
332
333#if KNEWSTUFFCORE_BUILD_DEPRECATED_SINCE(6, 9)
334void Engine::setSortOrder(KNSCore::Provider::SortMode mode_)
335{
336 setSortOrder2([mode_] {
337 switch (mode_) {
338 case KNSCore::Provider::Newest:
339 return KNSCore::SortMode::Newest;
340 case KNSCore::Provider::Alphabetical:
341 return KNSCore::SortMode::Alphabetical;
342 case KNSCore::Provider::Rating:
343 return KNSCore::SortMode::Rating;
344 case KNSCore::Provider::Downloads:
345 return KNSCore::SortMode::Downloads;
346 }
347 return KNSCore::SortMode::Rating;
348 }());
349}
350#endif
351
352KNSCore::SortMode Engine::sortOrder2() const
353{
354 return d->currentRequest.sortMode();
355}
356
357void Engine::setSortOrder2(KNSCore::SortMode mode)
358{
359 if (d->currentRequest.sortMode() != mode) {
360 d->currentRequest = KNSCore::SearchRequest(mode,
361 d->currentRequest.filter(),
362 d->currentRequest.searchTerm(),
363 d->currentRequest.categories(),
364 d->currentRequest.page(),
365 d->currentRequest.pageSize());
366 reloadEntries();
367 Q_EMIT sortOrderChanged();
368 }
369}
370
371QString Engine::searchTerm() const
372{
373 return d->currentRequest.searchTerm();
374}
375
376void Engine::setSearchTerm(const QString &searchTerm)
377{
378 if (d->isValid && d->currentRequest.searchTerm() != searchTerm) {
379 d->currentRequest = KNSCore::SearchRequest(d->currentRequest.sortMode(),
380 d->currentRequest.filter(),
381 searchTerm,
382 d->currentRequest.categories(),
383 d->currentRequest.page(),
384 d->currentRequest.pageSize());
385 Q_EMIT searchTermChanged();
386 }
387 KNSCore::Entry::List cacheEntries = dd->cache->requestFromCache(d->currentRequest);
388 if (!cacheEntries.isEmpty()) {
389 reloadEntries();
390 } else {
391 d->searchTimer.start();
392 }
393}
394
395SearchPresetModel *Engine::searchPresetModel() const
396{
397 return d->searchPresetModel;
398}
399
400bool Engine::isValid()
401{
402 return d->isValid;
403}
404
405void Engine::updateEntryContents(const KNSCore::Entry &entry)
406{
407 const auto core = dd->providerCores.value(entry.providerId());
408 if (!core) {
409 qCWarning(KNEWSTUFFQUICK) << "Provider was not found" << entry.providerId();
410 return;
411 }
412
413 const auto base = core->d->base;
414 if (!base->isInitialized()) {
415 qCWarning(KNEWSTUFFQUICK) << "Provider was not initialized" << base << entry.providerId();
416 return;
417 }
418
419 base->loadEntryDetails(entry);
420}
421
422void Engine::reloadEntries()
423{
424 Q_EMIT signalResetView();
425 d->currentPage = -1;
426 d->currentRequest = KNSCore::SearchRequest(d->currentRequest.sortMode(),
427 d->currentRequest.filter(),
428 d->currentRequest.searchTerm(),
429 d->currentRequest.categories(),
430 0,
431 d->currentRequest.pageSize());
432 d->numDataJobs = 0;
433
434 const auto providersList = dd->providerCores;
435 for (const auto &core : providersList) {
436 const auto &base = core->d->base;
437 if (base->isInitialized()) {
438 if (d->currentRequest.filter() == KNSCore::Filter::Installed || d->currentRequest.filter() == KNSCore::Filter::Updates) {
439 // when asking for installed entries, never use the cache
440 base->loadEntries(d->currentRequest);
441 } else {
442 // take entries from cache until there are no more
443 KNSCore::Entry::List cacheEntries;
444 KNSCore::Entry::List lastCache = dd->cache->requestFromCache(d->currentRequest);
445 while (!lastCache.isEmpty()) {
446 qCDebug(KNEWSTUFFQUICK) << "From cache";
447 cacheEntries << lastCache;
448
449 d->currentPage = d->currentRequest.page();
450 d->currentRequest = d->currentRequest.nextPage();
451 lastCache = dd->cache->requestFromCache(d->currentRequest);
452 }
453
454 // Since the cache has no more pages, reset the request's page
455 if (d->currentPage >= 0) {
456 d->currentRequest = KNSCore::SearchRequest(d->currentRequest.sortMode(),
457 d->currentRequest.filter(),
458 d->currentRequest.searchTerm(),
459 d->currentRequest.categories(),
460 d->currentPage,
461 d->currentRequest.pageSize());
462 }
463
464 if (!cacheEntries.isEmpty()) {
465 Q_EMIT signalEntriesLoaded(cacheEntries);
466 } else {
467 qCDebug(KNEWSTUFFQUICK) << "From provider";
468 base->loadEntries(d->currentRequest);
469
470 ++d->numDataJobs;
471 updateStatus();
472 }
473 }
474 }
475 }
476}
477
478void Engine::loadPreview(const KNSCore::Entry &entry, KNSCore::Entry::PreviewType type)
479{
480 qCDebug(KNEWSTUFFQUICK) << "START preview: " << entry.name() << type;
481 auto l = new KNSCore::ImageLoader(entry, type, this);
482 connect(l, &KNSCore::ImageLoader::signalPreviewLoaded, this, [this](const KNSCore::Entry &entry, KNSCore::Entry::PreviewType type) {
483 qCDebug(KNEWSTUFFQUICK) << "FINISH preview: " << entry.name() << type;
484 Q_EMIT signalEntryPreviewLoaded(entry, type);
485 --d->numPictureJobs;
486 updateStatus();
487 });
488 connect(l, &KNSCore::ImageLoader::signalError, this, [this](const KNSCore::Entry &entry, KNSCore::Entry::PreviewType type, const QString &errorText) {
489 Q_EMIT signalErrorCode(KNSCore::ErrorCode::ImageError, errorText, QVariantList() << entry.name() << type);
490 qCDebug(KNEWSTUFFQUICK) << "ERROR preview: " << errorText << entry.name() << type;
491 --d->numPictureJobs;
492 updateStatus();
493 });
494 l->start();
495 ++d->numPictureJobs;
496 updateStatus();
497}
498
500{
501 registerTransaction(KNSCore::Transaction::adopt(this, entry));
502}
503
504#if KNEWSTUFFCORE_BUILD_DEPRECATED_SINCE(6, 9)
505void Engine::install(const KNSCore::Entry &entry, int linkId)
506{
507 qmlWarning(this) << "org.kde.newstuff.core.Engine.install is deprecated. Use installLinkId or installLatest";
508 auto transaction = KNSCore::Transaction::install(this, entry, linkId);
509 registerTransaction(transaction);
510 if (!transaction->isFinished()) {
511 ++d->numInstallJobs;
512 }
513}
514#endif
515
516void Engine::installLinkId(const KNSCore::Entry &entry, quint8 linkId)
517{
518 auto transaction = KNSCore::Transaction::installLinkId(this, entry, linkId);
519 registerTransaction(transaction);
520 if (!transaction->isFinished()) {
521 ++d->numInstallJobs;
522 }
523}
524
526{
527 auto transaction = KNSCore::Transaction::installLatest(this, entry);
528 registerTransaction(transaction);
529 if (!transaction->isFinished()) {
530 ++d->numInstallJobs;
531 }
532}
533
535{
536 registerTransaction(KNSCore::Transaction::uninstall(this, entry));
537}
538void Engine::registerTransaction(KNSCore::Transaction *transaction)
539{
540 connect(transaction, &KNSCore::Transaction::signalErrorCode, this, &EngineBase::signalErrorCode);
541 connect(transaction, &KNSCore::Transaction::signalMessage, this, &EngineBase::signalMessage);
543}
544
545void Engine::requestMoreData()
546{
547 qCDebug(KNEWSTUFFQUICK) << "Get more data! current page: " << d->currentPage << " requested: " << d->currentRequest.page();
548
549 if (d->currentPage < d->currentRequest.page()) {
550 return;
551 }
552
553 d->currentRequest = d->currentRequest.nextPage();
554 doRequest();
555}
556
557void Engine::doRequest()
558{
559 const auto cores = dd->providerCores;
560 for (const auto &core : cores) {
561 const auto &base = core->d->base;
562 if (base->isInitialized()) {
563 base->loadEntries(d->currentRequest);
564 ++d->numDataJobs;
565 updateStatus();
566 }
567 }
568}
569
570void Engine::revalidateCacheEntries()
571{
572 // This gets called from QML, because in QtQuick we reuse the engine, BUG: 417985
573 // We can't handle this in the cache, because it can't access the configuration of the engine
574 if (dd->cache) {
575 const auto cores = dd->providerCores;
576 for (const auto &core : cores) {
577 const auto &base = core->d->base;
578 if (base && base->isInitialized()) {
579 const KNSCore::Entry::List cacheBefore = dd->cache->registryForProvider(base->id());
580 dd->cache->removeDeletedEntries();
581 const KNSCore::Entry::List cacheAfter = dd->cache->registryForProvider(base->id());
582 // If the user has deleted them in the background we have to update the state to deleted
583 for (const auto &oldCachedEntry : cacheBefore) {
584 if (!cacheAfter.contains(oldCachedEntry)) {
585 KNSCore::Entry removedEntry = oldCachedEntry;
586 removedEntry.setEntryDeleted();
588 }
589 }
590 }
591 }
592 }
593}
594
595void Engine::restoreSearch()
596{
597 d->searchTimer.stop();
598 d->currentRequest = d->storedRequest;
599 if (dd->cache) {
600 KNSCore::Entry::List cacheEntries = dd->cache->requestFromCache(d->currentRequest);
601 if (!cacheEntries.isEmpty()) {
602 reloadEntries();
603 } else {
604 d->searchTimer.start();
605 }
606 } else {
607 qCWarning(KNEWSTUFFQUICK) << "Attempted to call restoreSearch() without a correctly initialized engine. You will likely get unexpected behaviour.";
608 }
609}
610
611void Engine::storeSearch()
612{
613 d->storedRequest = d->currentRequest;
614}
A model which shows the categories found in an Engine.
void signalEntryEvent(const KNSCore::Entry &entry, KNSCore::Entry::EntryEvent event)
void errorCode(KNSCore::ErrorCode::ErrorCode errorCode, const QString &message, const QVariant &metadata)
Fires in the case of any critical or serious errors, such as network or API problems.
void setSortOrder(KNSCore::Provider::SortMode newSortOrder)
Q_INVOKABLE void installLinkId(const KNSCore::Entry &entry, quint8 linkId)
Performs an install on the given entry.
Q_INVOKABLE void install(const KNSCore::Entry &entry, int linkId=1)
Installs an entry's payload file.
Q_INVOKABLE void adoptEntry(const KNSCore::Entry &entry)
Adopt an entry using the adoption command.
void setFilter(KNSCore::Provider::Filter filter)
Q_SIGNAL void busyStateChanged()
Signal gets emitted when the busy state changes.
Q_INVOKABLE void installLatest(const KNSCore::Entry &entry)
Performs an install of the latest version on the given entry.
BusyState busyState
Current state of the engine, the state con contain multiple operations an empty BusyState represents ...
Definition quickengine.h:52
Q_INVOKABLE void uninstall(const KNSCore::Entry &entry)
Uninstalls an entry.
void signalErrorCode(KNSCore::ErrorCode::ErrorCode errorCode, const QString &message, const QVariant &metadata)
Fires in the case of any critical or serious errors, such as network or API problems.
KNewStuff data entry container.
Definition entry.h:48
@ StatusChangedEvent
Used when an event's status is set (use Entry::status() to get the new status)
Definition entry.h:122
void setEntryDeleted()
Definition entry.cpp:700
A search request.
KNewStuff Transaction.
Definition transaction.h:38
static Transaction * install(EngineBase *engine, const Entry &entry, int linkId=1)
Performs an install on the given entry from the engine.
void signalEntryEvent(const KNSCore::Entry &entry, KNSCore::Entry::EntryEvent event)
Informs about how the entry has changed.
void signalMessage(const QString &message)
Provides the message to update our users about how the Transaction progressed.
void signalErrorCode(KNSCore::ErrorCode::ErrorCode errorCode, const QString &message, const QVariant &metadata)
Fires in the case of any critical or serious errors, such as network or API problems.
static Transaction * installLatest(EngineBase *engine, const Entry &entry)
Performs an install of the latest version on the given entry from the engine.
static Transaction * installLinkId(EngineBase *engine, const Entry &entry, quint8 linkId)
Performs an install on the given entry from the engine.
static Transaction * adopt(EngineBase *engine, const Entry &entry)
Adopt the entry from engine using the adoption command.
static Transaction * uninstall(EngineBase *engine, const Entry &entry)
Uninstalls the given entry from the engine.
The SearchPresetModel class.
QString i18nc(const char *context, const char *text, const TYPE &arg...)
QString i18n(const char *text, const TYPE &arg...)
Type type(const QSqlDatabase &db)
KIOCORE_EXPORT TransferJob * get(const QUrl &url, LoadType reload=NoReload, JobFlags flags=DefaultFlags)
bool contains(const AT &value) const const
bool isEmpty() const const
Q_EMITQ_EMIT
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
virtual bool event(QEvent *e)
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)
void timeout()
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Mon Nov 18 2024 12:20:03 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.