diff --git a/src/core/engine.cpp b/src/core/engine.cpp index ad32d0dc..10a9dff3 100644 --- a/src/core/engine.cpp +++ b/src/core/engine.cpp @@ -1,688 +1,670 @@ /* knewstuff3/engine.cpp Copyright (c) 2007 Josef Spillner Copyright (C) 2007-2010 Frederik Gladhorn Copyright (c) 2009 Jeremy Whiting Copyright (c) 2010 Matthias Fuchs This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . */ #include "engine.h" #include "../entry.h" #include "installation.h" #include "xmlloader.h" #include "imageloader_p.h" #include #include #include #include #include #include #include #include #include #include #if defined(Q_OS_WIN) #include #include #endif // libattica #include #include // own #include "../attica/atticaprovider_p.h" #include "cache.h" #include "../staticxml/staticxmlprovider_p.h" using namespace KNSCore; typedef QHash EngineProviderLoaderHash; Q_GLOBAL_STATIC(QThreadStorage, s_engineProviderLoaders) class EnginePrivate { public: QList categoriesMetadata; + Attica::ProviderManager *m_atticaProviderManager = nullptr; }; -// BCI: Add a real d-pointer -typedef QHash EnginePrivateHash; -Q_GLOBAL_STATIC(EnginePrivateHash, d_func) -static EnginePrivate *d(const Engine* engine) -{ - EnginePrivate* ret = d_func()->value(engine); - if (!ret) { - ret = new EnginePrivate; - d_func()->insert(engine, ret); - } - return ret; -} -static void delete_d(const Engine* engine) -{ - if (auto d = d_func()) { - delete d->take(engine); - } -} - Engine::Engine(QObject *parent) : QObject(parent) , m_installation(new Installation) , m_cache() , m_searchTimer(new QTimer) - , m_atticaProviderManager(nullptr) + , d(new EnginePrivate) , m_currentPage(-1) , m_pageSize(20) , m_numDataJobs(0) , m_numPictureJobs(0) , m_numInstallJobs(0) , m_initialized(false) { m_searchTimer->setSingleShot(true); m_searchTimer->setInterval(1000); connect(m_searchTimer, &QTimer::timeout, this, &Engine::slotSearchTimerExpired); connect(m_installation, &Installation::signalInstallationFinished, this, &Engine::slotInstallationFinished); connect(m_installation, &Installation::signalInstallationFailed, this, &Engine::slotInstallationFailed); } Engine::~Engine() { if (m_cache) { m_cache->writeRegistry(); } - delete m_atticaProviderManager; + delete d->m_atticaProviderManager; delete m_searchTimer; delete m_installation; - delete_d(this); + delete d; } bool Engine::init(const QString &configfile) { qCDebug(KNEWSTUFFCORE) << "Initializing KNSCore::Engine from '" << configfile << "'"; emit signalBusy(i18n("Initializing")); KConfig conf(configfile); if (conf.accessMode() == KConfig::NoAccess) { emit signalError(i18n("Configuration file exists, but cannot be opened: \"%1\"", configfile)); qCritical() << "The knsrc file '" << configfile << "' was found but could not be opened."; return false; } KConfigGroup group; if (conf.hasGroup("KNewStuff3")) { qCDebug(KNEWSTUFFCORE) << "Loading KNewStuff3 config: " << configfile; group = conf.group("KNewStuff3"); } else if (conf.hasGroup("KNewStuff2")) { qCDebug(KNEWSTUFFCORE) << "Loading KNewStuff2 config: " << configfile; group = conf.group("KNewStuff2"); } else { emit signalError(i18n("Configuration file is invalid: \"%1\"", configfile)); qCritical() << configfile << " doesn't contain a KNewStuff3 section."; return false; } m_categories = group.readEntry("Categories", QStringList()); m_adoptionCommand = group.readEntry("AdoptionCommand", QString()); qCDebug(KNEWSTUFFCORE) << "Categories: " << m_categories; m_providerFileUrl = group.readEntry("ProvidersUrl", QString()); const QString configFileName = QFileInfo(QDir::isAbsolutePath(configfile) ? configfile : QStandardPaths::locate(QStandardPaths::GenericConfigLocation, configfile)).baseName(); // let installation read install specific config if (!m_installation->readConfig(group)) { return false; } connect(m_installation, &Installation::signalEntryChanged, this, &Engine::slotEntryChanged); m_cache = Cache::getCache(configFileName); connect(this, &Engine::signalEntryChanged, m_cache.data(), &Cache::registerChangedEntry); m_cache->readRegistry(); m_initialized = true; // load the providers loadProviders(); return true; } QStringList Engine::categories() const { return m_categories; } QStringList Engine::categoriesFilter() const { return m_currentRequest.categories; } QList Engine::categoriesMetadata() { - return d(this)->categoriesMetadata; + return d->categoriesMetadata; } void Engine::loadProviders() { if (m_providerFileUrl.isEmpty()) { // it would be nicer to move the attica stuff into its own class qCDebug(KNEWSTUFFCORE) << "Using OCS default providers"; - delete m_atticaProviderManager; - m_atticaProviderManager = new Attica::ProviderManager; - connect(m_atticaProviderManager, &Attica::ProviderManager::providerAdded, this, &Engine::atticaProviderLoaded); - m_atticaProviderManager->loadDefaultProviders(); + delete d->m_atticaProviderManager; + d->m_atticaProviderManager = new Attica::ProviderManager; + connect(d->m_atticaProviderManager, &Attica::ProviderManager::providerAdded, this, &Engine::atticaProviderLoaded); + d->m_atticaProviderManager->loadDefaultProviders(); } else { qCDebug(KNEWSTUFFCORE) << "loading providers from " << m_providerFileUrl; emit signalBusy(i18n("Loading provider information")); XmlLoader *loader = s_engineProviderLoaders()->localData().value(m_providerFileUrl); if (!loader) { qCDebug(KNEWSTUFFCORE) << "No xml loader for this url yet, so create one and temporarily store that" << m_providerFileUrl; loader = new XmlLoader(this); s_engineProviderLoaders()->localData().insert(m_providerFileUrl, loader); connect(loader, &XmlLoader::signalLoaded, this, [this](){ s_engineProviderLoaders()->localData().remove(m_providerFileUrl); }); connect(loader, &XmlLoader::signalFailed, this, [this](){ s_engineProviderLoaders()->localData().remove(m_providerFileUrl); }); loader->load(QUrl(m_providerFileUrl)); } connect(loader, &XmlLoader::signalLoaded, this, &Engine::slotProviderFileLoaded); connect(loader, &XmlLoader::signalFailed, this, &Engine::slotProvidersFailed); } } void Engine::slotProviderFileLoaded(const QDomDocument &doc) { qCDebug(KNEWSTUFFCORE) << "slotProvidersLoaded"; bool isAtticaProviderFile = false; // get each provider element, and create a provider object from it QDomElement providers = doc.documentElement(); if (providers.tagName() == QLatin1String("providers")) { isAtticaProviderFile = true; } else if (providers.tagName() != QLatin1String("ghnsproviders") && providers.tagName() != QLatin1String("knewstuffproviders")) { qWarning() << "No document in providers.xml."; emit signalError(i18n("Could not load get hot new stuff providers from file: %1", m_providerFileUrl)); return; } QDomElement n = providers.firstChildElement(QStringLiteral("provider")); while (!n.isNull()) { qCDebug(KNEWSTUFFCORE) << "Provider attributes: " << n.attribute(QStringLiteral("type")); QSharedPointer provider; if (isAtticaProviderFile || n.attribute(QStringLiteral("type")).toLower() == QLatin1String("rest")) { provider = QSharedPointer (new AtticaProvider(m_categories)); connect(provider.data(), &Provider::categoriesMetadataLoded, this, [this](const QList &categories){ - d(this)->categoriesMetadata = categories; + d->categoriesMetadata = categories; emit signalCategoriesMetadataLoded(categories); }); } else { provider = QSharedPointer (new StaticXmlProvider); } if (provider->setProviderXML(n)) { addProvider(provider); } else { emit signalError(i18n("Error initializing provider.")); } n = n.nextSiblingElement(); } emit signalBusy(i18n("Loading data")); } void Engine::atticaProviderLoaded(const Attica::Provider &atticaProvider) { qCDebug(KNEWSTUFFCORE) << "atticaProviderLoaded called"; if (!atticaProvider.hasContentService()) { qCDebug(KNEWSTUFFCORE) << "Found provider: " << atticaProvider.baseUrl() << " but it does not support content"; return; } QSharedPointer provider = QSharedPointer (new AtticaProvider(atticaProvider, m_categories)); connect(provider.data(), &Provider::categoriesMetadataLoded, this, [this](const QList &categories){ - d(this)->categoriesMetadata = categories; + d->categoriesMetadata = categories; emit signalCategoriesMetadataLoded(categories); }); addProvider(provider); } void Engine::addProvider(QSharedPointer provider) { qCDebug(KNEWSTUFFCORE) << "Engine addProvider called with provider with id " << provider->id(); m_providers.insert(provider->id(), provider); connect(provider.data(), &Provider::providerInitialized, this, &Engine::providerInitialized); connect(provider.data(), &Provider::loadingFinished, this, &Engine::slotEntriesLoaded); connect(provider.data(), &Provider::entryDetailsLoaded, this, &Engine::slotEntryDetailsLoaded); connect(provider.data(), &Provider::payloadLinkLoaded, this, &Engine::downloadLinkLoaded); connect(provider.data(), &Provider::signalError, this, &Engine::signalError); connect(provider.data(), &Provider::signalInformation, this, &Engine::signalIdle); } void Engine::providerJobStarted(KJob *job) { emit jobStarted(job, i18n("Loading data from provider")); } void Engine::slotProvidersFailed() { emit signalError(i18n("Loading of providers from file: %1 failed", m_providerFileUrl)); } void Engine::providerInitialized(Provider *p) { qCDebug(KNEWSTUFFCORE) << "providerInitialized" << p->name(); p->setCachedEntries(m_cache->registryForProvider(p->id())); updateStatus(); foreach (const QSharedPointer &p, m_providers) { if (!p->isInitialized()) { return; } } emit signalProvidersLoaded(); } void Engine::slotEntriesLoaded(const KNSCore::Provider::SearchRequest &request, KNSCore::EntryInternal::List entries) { m_currentPage = qMax(request.page, m_currentPage); qCDebug(KNEWSTUFFCORE) << "loaded page " << request.page << "current page" << m_currentPage << "count:" << entries.count(); if (request.filter == Provider::Updates) { emit signalUpdateableEntriesLoaded(entries); } else { m_cache->insertRequest(request, entries); emit signalEntriesLoaded(entries); } --m_numDataJobs; updateStatus(); } void Engine::reloadEntries() { emit signalResetView(); m_currentPage = -1; m_currentRequest.pageSize = m_pageSize; m_currentRequest.page = 0; m_numDataJobs = 0; foreach (const QSharedPointer &p, m_providers) { if (p->isInitialized()) { if (m_currentRequest.filter == Provider::Installed) { // when asking for installed entries, never use the cache p->loadEntries(m_currentRequest); } else { // take entries from cache until there are no more EntryInternal::List cache; EntryInternal::List lastCache = m_cache->requestFromCache(m_currentRequest); while (!lastCache.isEmpty()) { qCDebug(KNEWSTUFFCORE) << "From cache"; cache << lastCache; m_currentPage = m_currentRequest.page; ++m_currentRequest.page; lastCache = m_cache->requestFromCache(m_currentRequest); } // Since the cache has no more pages, reset the request's page if (m_currentPage >= 0) { m_currentRequest.page = m_currentPage; } if (!cache.isEmpty()) { emit signalEntriesLoaded(cache); } else { qCDebug(KNEWSTUFFCORE) << "From provider"; p->loadEntries(m_currentRequest); ++m_numDataJobs; updateStatus(); } } } } } void Engine::setCategoriesFilter(const QStringList &categories) { m_currentRequest.categories = categories; reloadEntries(); } void Engine::setSortMode(Provider::SortMode mode) { if (m_currentRequest.sortMode != mode) { m_currentRequest.page = -1; } m_currentRequest.sortMode = mode; reloadEntries(); } void KNSCore::Engine::setFilter(Provider::Filter filter) { if (m_currentRequest.filter != filter) { m_currentRequest.page = -1; } m_currentRequest.filter = filter; reloadEntries(); } void KNSCore::Engine::fetchEntryById(const QString& id) { m_searchTimer->stop(); m_currentRequest = KNSCore::Provider::SearchRequest(KNSCore::Provider::Newest, KNSCore::Provider::ExactEntryId, id); m_currentRequest.pageSize = m_pageSize; EntryInternal::List cache = m_cache->requestFromCache(m_currentRequest); if (!cache.isEmpty()) { reloadEntries(); } else { m_searchTimer->start(); } } void Engine::setSearchTerm(const QString &searchString) { m_searchTimer->stop(); m_currentRequest.searchTerm = searchString; EntryInternal::List cache = m_cache->requestFromCache(m_currentRequest); if (!cache.isEmpty()) { reloadEntries(); } else { m_searchTimer->start(); } } void Engine::slotSearchTimerExpired() { reloadEntries(); } void Engine::requestMoreData() { qCDebug(KNEWSTUFFCORE) << "Get more data! current page: " << m_currentPage << " requested: " << m_currentRequest.page; if (m_currentPage < m_currentRequest.page) { return; } m_currentRequest.page++; doRequest(); } void Engine::requestData(int page, int pageSize) { m_currentRequest.page = page; m_currentRequest.pageSize = pageSize; doRequest(); } void Engine::doRequest() { foreach (const QSharedPointer &p, m_providers) { if (p->isInitialized()) { p->loadEntries(m_currentRequest); ++m_numDataJobs; updateStatus(); } } } void Engine::install(KNSCore::EntryInternal entry, int linkId) { if (entry.status() == KNS3::Entry::Updateable) { entry.setStatus(KNS3::Entry::Updating); } else { entry.setStatus(KNS3::Entry::Installing); } emit signalEntryChanged(entry); qCDebug(KNEWSTUFFCORE) << "Install " << entry.name() << " from: " << entry.providerId(); QSharedPointer p = m_providers.value(entry.providerId()); if (p) { p->loadPayloadLink(entry, linkId); ++m_numInstallJobs; updateStatus(); } } void Engine::slotInstallationFinished() { --m_numInstallJobs; updateStatus(); } void Engine::slotInstallationFailed(const QString &message) { --m_numInstallJobs; emit signalError(message); } void Engine::slotEntryDetailsLoaded(const KNSCore::EntryInternal &entry) { emit signalEntryDetailsLoaded(entry); } void Engine::downloadLinkLoaded(const KNSCore::EntryInternal &entry) { m_installation->install(entry); } void Engine::uninstall(KNSCore::EntryInternal entry) { KNSCore::EntryInternal::List list = m_cache->registryForProvider(entry.providerId()); //we have to use the cached entry here, not the entry from the provider //since that does not contain the list of installed files KNSCore::EntryInternal actualEntryForUninstall; foreach (const KNSCore::EntryInternal &eInt, list) { if (eInt.uniqueId() == entry.uniqueId()) { actualEntryForUninstall = eInt; break; } } if (!actualEntryForUninstall.isValid()) { qCDebug(KNEWSTUFFCORE) << "could not find a cached entry with following id:" << entry.uniqueId() << " -> using the non-cached version"; return; } entry.setStatus(KNS3::Entry::Installing); actualEntryForUninstall.setStatus(KNS3::Entry::Installing); emit signalEntryChanged(entry); qCDebug(KNEWSTUFFCORE) << "about to uninstall entry " << entry.uniqueId(); // FIXME: change the status? m_installation->uninstall(actualEntryForUninstall); entry.setStatus(KNS3::Entry::Deleted); //status for actual entry gets set in m_installation->uninstall() emit signalEntryChanged(entry); } void Engine::loadDetails(const KNSCore::EntryInternal &entry) { QSharedPointer p = m_providers.value(entry.providerId()); p->loadEntryDetails(entry); } void Engine::loadPreview(const KNSCore::EntryInternal &entry, EntryInternal::PreviewType type) { qCDebug(KNEWSTUFFCORE) << "START preview: " << entry.name() << type; ImageLoader *l = new ImageLoader(entry, type, this); connect(l, &ImageLoader::signalPreviewLoaded, this, &Engine::slotPreviewLoaded); connect(l, &ImageLoader::signalError, this, [this](const KNSCore::EntryInternal &entry, EntryInternal::PreviewType type, const QString &errorText) { qCDebug(KNEWSTUFFCORE) << "ERROR preview: " << errorText << entry.name() << type; --m_numPictureJobs; updateStatus(); }); l->start(); ++m_numPictureJobs; updateStatus(); } void Engine::slotPreviewLoaded(const KNSCore::EntryInternal &entry, EntryInternal::PreviewType type) { qCDebug(KNEWSTUFFCORE) << "FINISH preview: " << entry.name() << type; emit signalEntryPreviewLoaded(entry, type); --m_numPictureJobs; updateStatus(); } void Engine::contactAuthor(const EntryInternal &entry) { if (!entry.author().email().isEmpty()) { // invoke mail with the address of the author QUrl mailUrl; mailUrl.setScheme(QStringLiteral("mailto")); mailUrl.setPath(entry.author().email()); QUrlQuery query; query.addQueryItem(QStringLiteral("subject"), i18n("Re: %1", entry.name())); mailUrl.setQuery(query); QDesktopServices::openUrl(mailUrl); } else if (!entry.author().homepage().isEmpty()) { QDesktopServices::openUrl(QUrl(entry.author().homepage())); } } void Engine::slotEntryChanged(const KNSCore::EntryInternal &entry) { emit signalEntryChanged(entry); } bool Engine::userCanVote(const EntryInternal &entry) { QSharedPointer p = m_providers.value(entry.providerId()); return p->userCanVote(); } void Engine::vote(const EntryInternal &entry, uint rating) { QSharedPointer p = m_providers.value(entry.providerId()); p->vote(entry, rating); } bool Engine::userCanBecomeFan(const EntryInternal &entry) { QSharedPointer p = m_providers.value(entry.providerId()); return p->userCanBecomeFan(); } void Engine::becomeFan(const EntryInternal &entry) { QSharedPointer p = m_providers.value(entry.providerId()); p->becomeFan(entry); } void Engine::updateStatus() { if (m_numDataJobs > 0) { emit signalBusy(i18n("Loading data")); } else if (m_numPictureJobs > 0) { emit signalBusy(i18np("Loading one preview", "Loading %1 previews", m_numPictureJobs)); } else if (m_numInstallJobs > 0) { emit signalBusy(i18n("Installing")); } else { emit signalIdle(QString()); } } void Engine::checkForUpdates() { foreach (QSharedPointer p, m_providers) { Provider::SearchRequest request(KNSCore::Provider::Newest, KNSCore::Provider::Updates); p->loadEntries(request); } } void KNSCore::Engine::checkForInstalled() { foreach (QSharedPointer p, m_providers) { Provider::SearchRequest request(KNSCore::Provider::Newest, KNSCore::Provider::Installed); request.page = 0; request.pageSize = m_pageSize; p->loadEntries(request); } } /** * we look for the directory where all the resources got installed. * assuming it was extracted into a directory */ static QDir sharedDir(QStringList dirs, const QString &rootPath) { while(!dirs.isEmpty()) { const QString currentPath = QDir::cleanPath(dirs.takeLast()); if (!currentPath.startsWith(rootPath)) continue; const QFileInfo current(currentPath); if (!current.isDir()) continue; const QDir dir = current.dir(); if (dir.path()==(rootPath+dir.dirName())) { return dir; } } return {}; } QString Engine::adoptionCommand(const KNSCore::EntryInternal& entry) const { auto adoption = m_adoptionCommand; if(adoption.isEmpty()) return {}; const QLatin1String dirReplace("%d"); if (adoption.contains(dirReplace)) { QString installPath = sharedDir(entry.installedFiles(), m_installation->targetInstallationPath()).path(); adoption.replace(dirReplace, installPath); } const QLatin1String fileReplace("%f"); QStringList ret; if (adoption.contains(fileReplace)) { if (entry.installedFiles().isEmpty()) { qCWarning(KNEWSTUFFCORE) << "no installed files to adopt"; } else if (entry.installedFiles().count() != 1) { qCWarning(KNEWSTUFFCORE) << "can only adopt one file, will be using the first" << entry.installedFiles().at(0); } adoption.replace(fileReplace, entry.installedFiles().at(0)); } return adoption; } bool KNSCore::Engine::hasAdoptionCommand() const { return !m_adoptionCommand.isEmpty(); } void KNSCore::Engine::setPageSize(int pageSize) { m_pageSize = pageSize; } diff --git a/src/core/engine.h b/src/core/engine.h index 41ded879..8cb5019e 100644 --- a/src/core/engine.h +++ b/src/core/engine.h @@ -1,406 +1,408 @@ /* knewstuff3/engine.h. Copyright (c) 2007 Josef Spillner Copyright (C) 2007-2010 Frederik Gladhorn Copyright (c) 2009 Jeremy Whiting This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . */ #ifndef KNEWSTUFF3_ENGINE_P_H #define KNEWSTUFF3_ENGINE_P_H #include #include #include #include #include "provider.h" #include "entryinternal.h" #include "knewstuffcore_export.h" class QTimer; class KJob; +class EnginePrivate; namespace Attica { class ProviderManager; class Provider; } /** * Contains the core functionality for handling interaction with NewStuff providers. * The entrypoint for most things will be the creation of an instance of KNSCore::Engine * which will other classes then either use or get instantiated from directly. * * NOTE: When implementing anything on top of KNSCore, without using either KNS3 or the * Qt Quick components, you will need to implement a custom QuestionListener (see that * class for instructions) * * @see KNSCore::Engine * @see KNSCore::ItemsModel * @see KNSCore::QuestionListener */ namespace KNSCore { class Cache; class Installation; /** * KNewStuff engine. * An engine keeps track of data which is available locally and remote * and offers high-level synchronization calls as well as upload and download * primitives using an underlying GHNS protocol. */ class KNEWSTUFFCORE_EXPORT Engine : public QObject { Q_OBJECT public: /** * Constructor. */ explicit Engine(QObject *parent = nullptr); /** * Destructor. Frees up all the memory again which might be taken * by cached entries and providers. */ ~Engine(); /** * Initializes the engine. This step is application-specific and relies * on an external configuration file, which determines all the details * about the initialization. * * @param configfile KNewStuff2 configuration file (*.knsrc) * @return \b true if any valid configuration was found, \b false otherwise */ bool init(const QString &configfile); /** * Installs an entry's payload file. This includes verification, if * necessary, as well as decompression and other steps according to the * application's *.knsrc file. * * @param entry Entry to be installed * * @see signalInstallationFinished * @see signalInstallationFailed */ void install(KNSCore::EntryInternal entry, int linkId = 1); /** * Uninstalls an entry. It reverses the steps which were performed * during the installation. * * @param entry The entry to deinstall */ void uninstall(KNSCore::EntryInternal entry); /** * Attempt to load a specific preview for the specified entry. * * @param entry The entry to fetch a preview for * @param type The particular preview to fetch * * @see signalEntryPreviewLoaded(KNSCore::EntryInternal, KNSCore::EntryInternal::PreviewType); * @see signalPreviewFailed(); */ void loadPreview(const KNSCore::EntryInternal &entry, EntryInternal::PreviewType type); /** * Get the full details of a specific entry * * @param entry The entry to get full details for * * @see Entry::signalEntryDetailsLoaded(KNSCore::EntryInternal) */ void loadDetails(const KNSCore::EntryInternal &entry); /** * Set the order the search results are returned in. * * Search requests default to showing the newest entries first. * * Note: This will automatically launch a search, which means * you do not need to call requestData manually. * * @see KNSCore::Provider::SearchRequest * @param mode The order you want search results to come back in. */ void setSortMode(Provider::SortMode mode); /** * Set a filter for results (defaults to none), which will allow you * to show only installed entries, installed entries which have updates, * or a specific item with a specified ID. The latter further requires * the search term to be the exact ID of the entry you wish to retrieve. * * Note: This will automatically launch a search, which means * you do not need to call requestData manually. * * @see fetchEntryById(QString) * @see setSearchTerm(QString) * @param filter The type of results you wish to see */ void setFilter(Provider::Filter filter); /** * Set the categories that will be included in searches * * Note: This will automatically launch a search, which means * you do not need to call requestData manually. * * @see KNSCore::Engine::categories() * @param categories A list of strings of categories */ void setCategoriesFilter(const QStringList &categories); /** * Sets a string search term. * * Note: This will automatically launch a search, which means * you do not need to call requestData manually. * * @param searchString The search term you wish to search for */ void setSearchTerm(const QString &searchString); void reloadEntries(); void requestMoreData(); void requestData(int page, int pageSize); /** * Request for packages that are installed and need update * * These will be reported through the signal @see signalUpdateableEntriesLoaded(). */ void checkForUpdates(); /** * Requests installed packages with an up to date state * * @see signalEntriesLoaded() */ void checkForInstalled(); /** * Convenience method to launch a search for one specific entry. * * @note it will reset the engine state * * @param id The ID of the entry you wish to fetch */ void fetchEntryById(const QString &id); /** * Try to contact the author of the entry by email or showing their homepage. */ void contactAuthor(const EntryInternal &entry); /** * Whether or not a user is able to vote on the passed entry. * * @param entry The entry to check votability on * @return True if the user is able to vote on the entry */ bool userCanVote(const EntryInternal &entry); /** * Cast a vote on the passed entry. * * @param entry The entry to vote on * @param rating A number from 0 to 100, 50 being neutral, 0 being most negative and 100 being most positive. */ void vote(const EntryInternal &entry, uint rating); /** * Whether or not the user is allowed to become a fan of * a particular entry. * Not all providers (and consequently entries) support the fan functionality * and you can use this function to determine this ability. * @param entry The entry the user might wish to be a fan of * @return Whether or not it is possible for the user to become a fan of that entry */ bool userCanBecomeFan(const EntryInternal &entry); /** * This will mark the user who is currently authenticated as a fan * of the entry passed to the function. * @param entry The entry the user wants to be a fan of */ void becomeFan(const EntryInternal &entry); // FIXME There is currently no exposed API to remove the fan status /** * The list of the server-side names of the categories handled by this * engine instance. This corresponds directly to the list of categories * in your knsrc file. This is not supposed to be used as user-facing * strings - @see categoriesMetadata() for that. * * @return The categories which this instance of Engine handles */ QStringList categories() const; /** * The list of categories searches will actually show results from. This * is a subset of the categories() list. * * @see KNSCore::Engine::setCategoriesFilter(QString) */ QStringList categoriesFilter() const; /** * The list of metadata for the categories handled by this engine instance. * If you wish to show the categories to the user, this is the data to use. * The category name is the string used to set categories for the filter, * and also what is returned by both categories() and categoriesFilter(). * The human-readable name is displayName, and the only thing which should * be shown to the user. * * @return The metadata for all categories handled by this engine */ QList categoriesMetadata(); /** * The adoption command can be used to allow a user to make use of an entry's * installed data. For example, this command might be used to ask the system to * switch to a wallpaper or icon theme which was installed with KNS. * * The following is how this might look in a knsrc file. The example shows how * an external tool is called on the installed file represented by %d. *
        AdoptionCommand=/usr/lib64/libexec/plasma-changeicons %d
      * 
* * @param entry The entry to return an adoption command for * @return The command to run to adopt this entry's installed data */ QString adoptionCommand(const KNSCore::EntryInternal &entry) const; /** * Whether or not an adoption command exists for this engine * * @see adoptionCommand(KNSCore::EntryInternal) * @return True if an adoption command exists */ bool hasAdoptionCommand() const; /** * Set the page size for requests not made explicitly with requestData(int,int) * @param pageSize the default number of entries to request from the provider * @see requestData(int,int) */ void setPageSize(int pageSize); Q_SIGNALS: /** * Indicates a message to be added to the ui's log, or sent to a messagebox */ void signalMessage(const QString &message); void signalProvidersLoaded(); void signalEntriesLoaded(const KNSCore::EntryInternal::List &entries); void signalUpdateableEntriesLoaded(const KNSCore::EntryInternal::List &entries); void signalEntryChanged(const KNSCore::EntryInternal &entry); void signalEntryDetailsLoaded(const KNSCore::EntryInternal &entry); // a new search result is there, clear the list of items void signalResetView(); void signalEntryPreviewLoaded(const KNSCore::EntryInternal &, KNSCore::EntryInternal::PreviewType); void signalPreviewFailed(); void signalEntryUploadFinished(); void signalEntryUploadFailed(); void signalDownloadDialogDone(KNSCore::EntryInternal::List); void jobStarted(KJob *, const QString &); void signalError(const QString &); void signalBusy(const QString &); void signalIdle(const QString &); void signalCategoriesMetadataLoded(const QList &categories); private Q_SLOTS: // the .knsrc file was loaded void slotProviderFileLoaded(const QDomDocument &doc); // instead of getting providers from knsrc, use what was configured in ocs systemsettings void atticaProviderLoaded(const Attica::Provider &provider); // loading the .knsrc file failed void slotProvidersFailed(); // called when a provider is ready to work void providerInitialized(KNSCore::Provider *); void slotEntriesLoaded(const KNSCore::Provider::SearchRequest &, KNSCore::EntryInternal::List); void slotEntryDetailsLoaded(const KNSCore::EntryInternal &entry); void slotPreviewLoaded(const KNSCore::EntryInternal &entry, KNSCore::EntryInternal::PreviewType type); void slotSearchTimerExpired(); void slotEntryChanged(const KNSCore::EntryInternal &entry); void slotInstallationFinished(); void slotInstallationFailed(const QString &message); void downloadLinkLoaded(const KNSCore::EntryInternal &entry); void providerJobStarted(KJob *); private: /** * load providers from the providersurl in the knsrc file * creates providers based on their type and adds them to the list of providers */ void loadProviders(); /** Add a provider and connect it to the right slots */ void addProvider(QSharedPointer provider); void updateStatus(); void doRequest(); //FIXME KF6: move all of this in EnginePrivate // handle installation of entries Installation *m_installation; // read/write cache of entries QSharedPointer m_cache; QTimer *m_searchTimer; // The url of the file containing information about content providers QString m_providerFileUrl; // Categories from knsrc file QStringList m_categories; QHash > m_providers; QString m_adoptionCommand; // the current request from providers Provider::SearchRequest m_currentRequest; - Attica::ProviderManager *m_atticaProviderManager; + + EnginePrivate * const d; // the page that is currently displayed, so it is not requested repeatedly int m_currentPage; // when requesting entries from a provider, how many to ask for int m_pageSize; int m_numDataJobs; int m_numPictureJobs; int m_numInstallJobs; // If the provider is ready to be used bool m_initialized; Q_DISABLE_COPY(Engine) }; } #endif