/* * SPDX-FileCopyrightText: 2012 Aleix Pol Gonzalez * * SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL */ #include "AbstractResource.h" #include "AbstractResourcesBackend.h" #include "libdiscover_debug.h" #include #include #include #include #include #include #include #include AbstractResource::AbstractResource(AbstractResourcesBackend *parent) : QObject(parent) { connect(this, &AbstractResource::stateChanged, this, &AbstractResource::sizeChanged); connect(this, &AbstractResource::stateChanged, this, &AbstractResource::versionsChanged); connect(this, &AbstractResource::stateChanged, this, &AbstractResource::reportNewState); } AbstractResource::~AbstractResource() = default; QUrl AbstractResource::homepage() { return QUrl(); } QUrl AbstractResource::helpURL() { return QUrl(); } QUrl AbstractResource::bugURL() { return QUrl(); } QUrl AbstractResource::donationURL() { return QUrl(); } QUrl AbstractResource::contributeURL() { return {}; } void AbstractResource::addMetadata(const QLatin1StringView &key, const QJsonValue &value) { m_metadata.insert(key, value); } QJsonValue AbstractResource::getMetadata(const QLatin1StringView &key) { return m_metadata.value(key); } bool AbstractResource::canUpgrade() { return state() == Upgradeable; } bool AbstractResource::isInstalled() { return state() >= Installed; } void AbstractResource::fetchScreenshots() { Q_EMIT screenshotsFetched({}); } QStringList AbstractResource::mimetypes() const { return QStringList(); } AbstractResourcesBackend *AbstractResource::backend() const { return static_cast(parent()); } QString AbstractResource::status() { switch (state()) { case Broken: return i18n("Broken"); case None: return i18n("Available"); case Installed: return i18n("Installed"); case Upgradeable: return i18n("Upgradeable"); } return QString(); } QString AbstractResource::sizeDescription() { return KFormat().formatByteSize(size()); } QCollatorSortKey AbstractResource::nameSortKey() { if (!m_collatorKey) { static QCollator collator; m_collatorKey.reset(new QCollatorSortKey(collator.sortKey(name()))); } return *m_collatorKey; } Rating AbstractResource::rating() const { if (auto reviewsBackend = backend()->reviewsBackend()) { return reviewsBackend->ratingForApplication(const_cast(this)); } return {}; } QStringList AbstractResource::extends() const { return {}; } QString AbstractResource::appstreamId() const { return {}; } void AbstractResource::reportNewState() { if (backend()->isFetching()) { return; } static const QVector properties = { "state", "status", "canUpgrade", "size", "sizeDescription", "installedVersion", "availableVersion", }; Q_EMIT backend()->resourcesChanged(this, properties); } static bool shouldFilter(AbstractResource *resource, const CategoryFilter &filter) { bool ret = true; switch (filter.type) { case CategoryFilter::CategoryNameFilter: ret = resource->hasCategory(std::get(filter.value)); break; case CategoryFilter::PkgSectionFilter: ret = resource->section() == std::get(filter.value); break; case CategoryFilter::PkgWildcardFilter: { QString wildcard = std::get(filter.value); wildcard.remove(QLatin1Char('*')); ret = resource->packageName().contains(wildcard); break; } case CategoryFilter::AppstreamIdWildcardFilter: { QString wildcard = std::get(filter.value); wildcard.remove(QLatin1Char('*')); ret = resource->appstreamId().contains(wildcard); break; } case CategoryFilter::PkgNameFilter: // Only useful in the not filters ret = resource->packageName() == std::get(filter.value); break; case CategoryFilter::AndFilter: { const auto filters = std::get>(filter.value); ret = std::all_of(filters.begin(), filters.end(), [resource](const CategoryFilter &filter) { return shouldFilter(resource, filter); }); break; } case CategoryFilter::OrFilter: { const auto filters = std::get>(filter.value); ret = std::any_of(filters.begin(), filters.end(), [resource](const CategoryFilter &filter) { return shouldFilter(resource, filter); }); break; } case CategoryFilter::NotFilter: { const auto filters = std::get>(filter.value); ret = !std::any_of(filters.begin(), filters.end(), [resource](const CategoryFilter &filter) { return shouldFilter(resource, filter); }); break; } } return ret; } bool AbstractResource::categoryMatches(Category *cat) { return shouldFilter(this, cat->filter()); } static QSet walkCategories(AbstractResource *resource, const QVector &categories) { QSet ret; for (auto category : categories) { if (resource->categoryMatches(category)) { const auto subcats = walkCategories(resource, category->subCategories()); if (subcats.isEmpty()) { ret += category; } else { ret += subcats; } } } return ret; } QSet AbstractResource::categoryObjects(const QVector &categories) const { return walkCategories(const_cast(this), categories); } QUrl AbstractResource::url() const { const QString asid = appstreamId(); return asid.isEmpty() ? QUrl(backend()->name() + QStringLiteral("://") + packageName()) : QUrl(QStringLiteral("appstream://") + asid); } QString AbstractResource::displayOrigin() const { return origin(); } QString AbstractResource::executeLabel() const { return i18n("Launch"); } QString AbstractResource::upgradeText() const { const auto installed = installedVersion(); const auto available = availableVersion(); if (installed == available) { // Update of the same version; show when old and new are // the same (common with Flatpak runtimes) return i18nc("@info 'Refresh' is used as a noun here, and %1 is an app's version number", "Refresh of version %1", available); } else if (!installed.isEmpty() && !available.isEmpty()) { // Old and new version numbers // This thing with \u009C is a fancy feature in QML text handling: // when the string will be elided, it shows the string after // the last \u009C. This allows us to show a smaller string // when there's now enough room // All of this is mostly for the benefit of KDE Neon users, // since the version strings there are really really long return i18nc("Do not translate or alter \\u009C", "%1 → %2\u009C%1 → %2\u009C%2", installed, available); } else { // Available version only, for when the installed version // isn't available for some reason return available; } } QString AbstractResource::versionString() { const QString version = isInstalled() ? installedVersion() : availableVersion(); if (version.isEmpty()) { return {}; } return version; } QString AbstractResource::contentRatingDescription() const { return {}; } uint AbstractResource::contentRatingMinimumAge() const { return 0; } QStringList AbstractResource::topObjects() const { return {}; } QStringList AbstractResource::bottomObjects() const { return {}; } bool AbstractResource::hasResolvedIcon() const { return true; } void AbstractResource::resolveIcon() { } #include "moc_AbstractResource.cpp"