diff --git a/libdiscover/backends/KNSBackend/KNSResource.cpp b/libdiscover/backends/KNSBackend/KNSResource.cpp index 0c15242c..2f77b206 100644 --- a/libdiscover/backends/KNSBackend/KNSResource.cpp +++ b/libdiscover/backends/KNSBackend/KNSResource.cpp @@ -1,236 +1,236 @@ /*************************************************************************** * Copyright © 2012 Aleix Pol Gonzalez * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License as * * published by the Free Software Foundation; either version 2 of * * the License or (at your option) version 3 or any later version * * accepted by the membership of KDE e.V. (or its successor approved * * by the membership of KDE e.V.), which shall act as a proxy * * defined in Section 14 of version 3 of the license. * * * * This program 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 General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see . * ***************************************************************************/ #include "KNSResource.h" #include "KNSBackend.h" #include #include #include #include #include #include KNSResource::KNSResource(const KNSCore::EntryInternal& entry, QStringList categories, KNSBackend* parent) : AbstractResource(parent) , m_categories(std::move(categories)) , m_entry(entry) , m_lastStatus(entry.status()) { connect(this, &KNSResource::stateChanged, parent, &KNSBackend::updatesCountChanged); } KNSResource::~KNSResource() = default; AbstractResource::State KNSResource::state() { switch(m_entry.status()) { case KNS3::Entry::Invalid: return Broken; case KNS3::Entry::Downloadable: return None; case KNS3::Entry::Installed: return Installed; case KNS3::Entry::Updateable: return Upgradeable; case KNS3::Entry::Deleted: case KNS3::Entry::Installing: case KNS3::Entry::Updating: return None; } return None; } KNSBackend * KNSResource::knsBackend() const { return qobject_cast(parent()); } QVariant KNSResource::icon() const { const QString thumbnail = m_entry.previewUrl(KNSCore::EntryInternal::PreviewSmall1); return thumbnail.isEmpty() ? knsBackend()->iconName() : m_entry.previewUrl(KNSCore::EntryInternal::PreviewSmall1); } QString KNSResource::comment() { QString ret = m_entry.shortSummary(); if(ret.isEmpty()) { ret = m_entry.summary(); int newLine = ret.indexOf(QLatin1Char('\n')); if(newLine>0) { ret=ret.left(newLine); } ret = ret.replace(QRegularExpression(QStringLiteral("\\[/?[a-z]*\\]")), QString()); ret = ret.remove(QRegularExpression(QStringLiteral("<[^>]*>"))); } return ret; } QString KNSResource::longDescription() { QString ret = m_entry.summary(); if (m_entry.shortSummary().isEmpty()) { const int newLine = ret.indexOf(QLatin1Char('\n')); if (newLine<0) ret.clear(); else ret = ret.mid(newLine+1).trimmed(); } ret = ret.replace(QLatin1Char('\r'), QString()); ret = ret.replace(QStringLiteral("[li]"), QStringLiteral("\n* ")); ret = ret.replace(QRegularExpression(QStringLiteral("\\[/?[a-z]*\\]")), QString()); return ret; } QString KNSResource::name() const { return m_entry.name(); } QString KNSResource::packageName() const { return m_entry.uniqueId(); } QStringList KNSResource::categories() { return m_categories; } QUrl KNSResource::homepage() { return m_entry.homepage(); } void KNSResource::setEntry(const KNSCore::EntryInternal& entry) { const bool diff = entry.status() != m_lastStatus; m_entry = entry; if (diff) { m_lastStatus = entry.status(); Q_EMIT stateChanged(); } } KNSCore::EntryInternal KNSResource::entry() const { return m_entry; } QString KNSResource::license() { return m_entry.license(); } int KNSResource::size() { const auto downloadInfo = m_entry.downloadLinkInformationList(); return downloadInfo.isEmpty() ? 0 : downloadInfo.at(0).size; } QString KNSResource::installedVersion() const { return m_entry.version(); } QString KNSResource::availableVersion() const { return !m_entry.updateVersion().isEmpty() ? m_entry.updateVersion() : m_entry.version(); } QString KNSResource::origin() const { return m_entry.providerId(); } QString KNSResource::section() { return m_entry.category(); } static void appendIfValid(QList& list, const QUrl &value, const QUrl &fallback = {}) { if (!list.contains(value)) { if (value.isValid() && !value.isEmpty()) list << value; else if (!fallback.isEmpty()) appendIfValid(list, fallback); } } void KNSResource::fetchScreenshots() { QList preview; appendIfValid(preview, QUrl(m_entry.previewUrl(KNSCore::EntryInternal::PreviewSmall1))); appendIfValid(preview, QUrl(m_entry.previewUrl(KNSCore::EntryInternal::PreviewSmall2))); appendIfValid(preview, QUrl(m_entry.previewUrl(KNSCore::EntryInternal::PreviewSmall3))); QList screenshots; appendIfValid(screenshots, QUrl(m_entry.previewUrl(KNSCore::EntryInternal::PreviewBig1)), QUrl(m_entry.previewUrl(KNSCore::EntryInternal::PreviewSmall1))); appendIfValid(screenshots, QUrl(m_entry.previewUrl(KNSCore::EntryInternal::PreviewBig2)), QUrl(m_entry.previewUrl(KNSCore::EntryInternal::PreviewSmall2))); appendIfValid(screenshots, QUrl(m_entry.previewUrl(KNSCore::EntryInternal::PreviewBig3)), QUrl(m_entry.previewUrl(KNSCore::EntryInternal::PreviewSmall3))); emit screenshotsFetched(preview, screenshots); } void KNSResource::fetchChangelog() { emit changelogFetched(m_entry.changelog()); } QStringList KNSResource::extends() const { return knsBackend()->extends(); } QStringList KNSResource::executables() const { if (knsBackend()->engine()->hasAdoptionCommand()) return {knsBackend()->engine()->adoptionCommand(m_entry)}; else return {}; } QUrl KNSResource::url() const { return QUrl(QStringLiteral("kns://")+knsBackend()->name() + QLatin1Char('/') + QUrl(m_entry.providerId()).host() + QLatin1Char('/') + m_entry.uniqueId()); } void KNSResource::invokeApplication() const { QStringList exes = executables(); if(!exes.isEmpty()) { const QString exe = exes.constFirst(); auto args = KShell::splitArgs(exe); QProcess::startDetached(args.takeFirst(), args); } else { qWarning() << "cannot execute" << packageName(); } } QString KNSResource::executeLabel() const { return i18n("Use"); } QDate KNSResource::releaseDate() const { - return m_entry.releaseDate(); + return m_entry.updateReleaseDate().isNull() ? m_entry.releaseDate() : m_entry.updateReleaseDate(); } diff --git a/libdiscover/resources/AbstractResource.h b/libdiscover/resources/AbstractResource.h index b5998a9f..febf4e50 100644 --- a/libdiscover/resources/AbstractResource.h +++ b/libdiscover/resources/AbstractResource.h @@ -1,234 +1,237 @@ /*************************************************************************** * Copyright © 2012 Aleix Pol Gonzalez * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License as * * published by the Free Software Foundation; either version 2 of * * the License or (at your option) version 3 or any later version * * accepted by the membership of KDE e.V. (or its successor approved * * by the membership of KDE e.V.), which shall act as a proxy * * defined in Section 14 of version 3 of the license. * * * * This program 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 General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see . * ***************************************************************************/ #ifndef ABSTRACTRESOURCE_H #define ABSTRACTRESOURCE_H #include #include #include #include #include #include #include #include #include "discovercommon_export.h" #include "PackageState.h" class Category; class Rating; class AbstractResourcesBackend; /** * \class AbstractResource AbstractResource.h "AbstractResource.h" * * \brief This is the base class of all resources. * * Each backend must reimplement its own resource class which needs to derive from this one. */ class DISCOVERCOMMON_EXPORT AbstractResource : public QObject { Q_OBJECT Q_PROPERTY(QString name READ name CONSTANT) Q_PROPERTY(QString packageName READ packageName CONSTANT) Q_PROPERTY(QString comment READ comment CONSTANT) Q_PROPERTY(QVariant icon READ icon NOTIFY iconChanged) Q_PROPERTY(bool canExecute READ canExecute CONSTANT) Q_PROPERTY(State state READ state NOTIFY stateChanged) Q_PROPERTY(QString status READ status NOTIFY stateChanged) Q_PROPERTY(QStringList category READ categories CONSTANT) Q_PROPERTY(bool isTechnical READ isTechnical CONSTANT) Q_PROPERTY(QUrl homepage READ homepage CONSTANT) Q_PROPERTY(QUrl helpURL READ helpURL CONSTANT) Q_PROPERTY(QUrl bugURL READ bugURL CONSTANT) Q_PROPERTY(QUrl donationURL READ donationURL CONSTANT) Q_PROPERTY(bool canUpgrade READ canUpgrade NOTIFY stateChanged) Q_PROPERTY(bool isInstalled READ isInstalled NOTIFY stateChanged) Q_PROPERTY(QString license READ license CONSTANT) Q_PROPERTY(QString longDescription READ longDescription CONSTANT) Q_PROPERTY(QString origin READ origin CONSTANT) Q_PROPERTY(QString displayOrigin READ displayOrigin CONSTANT) Q_PROPERTY(int size READ size NOTIFY sizeChanged) Q_PROPERTY(QString sizeDescription READ sizeDescription NOTIFY sizeChanged) Q_PROPERTY(QString installedVersion READ installedVersion NOTIFY stateChanged) Q_PROPERTY(QString availableVersion READ availableVersion NOTIFY stateChanged) Q_PROPERTY(QString section READ section CONSTANT) Q_PROPERTY(QStringList mimetypes READ mimetypes CONSTANT) Q_PROPERTY(AbstractResourcesBackend* backend READ backend CONSTANT) Q_PROPERTY(Rating* rating READ rating NOTIFY ratingFetched) Q_PROPERTY(QString appstreamId READ appstreamId CONSTANT) Q_PROPERTY(QString categoryDisplay READ categoryDisplay CONSTANT) Q_PROPERTY(QUrl url READ url CONSTANT) Q_PROPERTY(QString executeLabel READ executeLabel CONSTANT) Q_PROPERTY(QString sourceIcon READ sourceIcon CONSTANT) Q_PROPERTY(QDate releaseDate READ releaseDate NOTIFY stateChanged) public: /** * This describes the state of the resource */ enum State { /** * When the resource is somehow broken */ Broken, /** * This means that the resource is neither installed nor broken */ None, /** * The resource is installed and up-to-date */ Installed, /** * The resource is installed and an update is available */ Upgradeable }; Q_ENUM(State) /** * Constructs the AbstractResource with its corresponding backend */ explicit AbstractResource(AbstractResourcesBackend* parent); ~AbstractResource() override; ///used as internal identification of a resource virtual QString packageName() const = 0; ///resource name to be displayed virtual QString name() const = 0; ///short description of the resource virtual QString comment() = 0; ///xdg-compatible icon name to represent the resource, url or QIcon virtual QVariant icon() const = 0; ///@returns whether invokeApplication makes something /// false if not overridden virtual bool canExecute() const = 0; ///executes the resource, if applies. Q_SCRIPTABLE virtual void invokeApplication() const = 0; virtual State state() = 0; virtual QStringList categories() = 0; ///@returns a URL that points to the app's website virtual QUrl homepage(); ///@returns a URL that points to the app's online documentation virtual QUrl helpURL(); ///@returns a URL that points to the place where you can file a bug virtual QUrl bugURL(); ///@returns a URL that points to the place where you can donate money to the app developer virtual QUrl donationURL(); virtual bool isTechnical() const; virtual int size() = 0; virtual QString sizeDescription(); virtual QString license() = 0; virtual QString installedVersion() const = 0; virtual QString availableVersion() const = 0; virtual QString longDescription() = 0; virtual QString origin() const = 0; QString displayOrigin() const; virtual QString section() = 0; ///@returns what kind of mime types the resource can consume virtual QStringList mimetypes() const; virtual QList addonsInformation() = 0; virtual QStringList extends() const; virtual QString appstreamId() const; void addMetadata(const QString &key, const QJsonValue &value); QJsonValue getMetadata(const QString &key); bool canUpgrade(); bool isInstalled(); ///@returns a user-readable explaination of the resource status ///by default, it will specify what state() is returning virtual QString status(); AbstractResourcesBackend* backend() const; /** * @returns a name sort key for faster sorting */ QCollatorSortKey nameSortKey(); /** * Convenience method to fetch the resource's rating * * @returns the rating for the resource or null if not available */ Rating* rating() const; /** * @returns a string defining the categories the resource belongs to */ QString categoryDisplay() const; bool categoryMatches(Category* cat); QSet categoryObjects(const QVector& cats) const; /** * @returns a url that uniquely identifies the application */ virtual QUrl url() const; virtual QString executeLabel() const; virtual QString sourceIcon() const = 0; + /** + * @returns the date of the resource's most recent release + */ virtual QDate releaseDate() const = 0; public Q_SLOTS: virtual void fetchScreenshots(); virtual void fetchChangelog() = 0; Q_SIGNALS: void iconChanged(); void sizeChanged(); void stateChanged(); void ratingFetched(); ///response to the fetchScreenshots method ///@p thumbnails and @p screenshots should have the same number of elements void screenshotsFetched(const QList& thumbnails, const QList& screenshots); void changelogFetched(const QString& changelog); private: void reportNewState(); // TODO: make it std::optional or make QCollatorSortKey() QScopedPointer m_collatorKey; QJsonObject m_metadata; }; Q_DECLARE_METATYPE(QVector) #endif // ABSTRACTRESOURCE_H