KNewStuff

quickitemsmodel.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 "quickitemsmodel.h"
8#include "core/commentsmodel.h"
9#include "downloadlinkinfo.h"
10#include "itemsmodel.h"
11#include "quickengine.h"
12
13#include <KShell>
14#include <QProcess>
15
16class ItemsModelPrivate
17{
18public:
19 ItemsModelPrivate(ItemsModel *qq)
20 : q(qq)
21 , model(nullptr)
22 , engine(nullptr)
23 {
24 }
25 ItemsModel *q;
26 KNSCore::ItemsModel *model;
27 Engine *engine;
28
30
31 bool initModel()
32 {
33 if (model) {
34 return true;
35 }
36 if (!engine) {
37 return false;
38 }
39 model = new KNSCore::ItemsModel(engine, q);
40
41 q->connect(engine, &Engine::signalProvidersLoaded, engine, &Engine::reloadEntries);
42 // Entries have been fetched and should be shown:
43 q->connect(engine, &Engine::signalEntriesLoaded, model, [this](const KNSCore::Entry::List &entries) {
44 model->slotEntriesLoaded(entries);
45 });
46 q->connect(engine, &Engine::entryEvent, model, [this](const KNSCore::Entry &entry, KNSCore::Entry::EntryEvent event) {
47 if (event == KNSCore::Entry::DetailsLoadedEvent && engine->filter() != KNSCore::Provider::Installed
48 && engine->filter() != KNSCore::Provider::Updates) {
49 model->slotEntriesLoaded(KNSCore::Entry::List{entry});
50 }
51 });
52
53 // Check if we need intermediate states
54 q->connect(engine, &Engine::entryEvent, q, [this](const KNSCore::Entry &entry, KNSCore::Entry::EntryEvent event) {
55 onEntryEvent(entry, event);
56 });
57 q->connect(engine, &Engine::signalResetView, model, &KNSCore::ItemsModel::clearEntries);
58
59 q->connect(model, &KNSCore::ItemsModel::loadPreview, engine, &Engine::loadPreview);
60 q->connect(engine, &Engine::entryPreviewLoaded, model, &KNSCore::ItemsModel::slotEntryPreviewLoaded);
61
67 return true;
68 }
69
70 void onEntryEvent(const KNSCore::Entry &entry, KNSCore::Entry::EntryEvent event)
71 {
73 model->slotEntryChanged(entry);
74 Q_EMIT q->entryChanged(entry);
75
76 // If we update/uninstall an entry we have to update the UI, see BUG: 425135
77 if (engine->filter() == KNSCore::Provider::Updates && entry.status() != KNSCore::Entry::Updateable && entry.status() != KNSCore::Entry::Updating) {
78 model->removeEntry(entry);
79 } else if (engine->filter() == KNSCore::Provider::Installed && entry.status() == KNSCore::Entry::Deleted) {
80 model->removeEntry(entry);
81 }
82 }
83
85 model->slotEntryChanged(entry);
86 Q_EMIT q->entryChanged(entry);
87 }
88 }
89};
90
91ItemsModel::ItemsModel(QObject *parent)
92 : QAbstractListModel(parent)
93 , d(new ItemsModelPrivate(this))
94{
95}
96
97ItemsModel::~ItemsModel() = default;
98
99QHash<int, QByteArray> ItemsModel::roleNames() const
100{
102 {Qt::DisplayRole, "display"},
103 {NameRole, "name"},
104 {UniqueIdRole, "uniqueId"},
105 {CategoryRole, "category"},
106 {HomepageRole, "homepage"},
107 {AuthorRole, "author"},
108 {LicenseRole, "license"},
109 {ShortSummaryRole, "shortSummary"},
110 {SummaryRole, "summary"},
111 {ChangelogRole, "changelog"},
112 {VersionRole, "version"},
113 {ReleaseDateRole, "releaseDate"},
114 {UpdateVersionRole, "updateVersion"},
115 {UpdateReleaseDateRole, "updateReleaseDate"},
116 {PayloadRole, "payload"},
117 {Qt::DecorationRole, "decoration"},
118 {PreviewsSmallRole, "previewsSmall"},
119 {PreviewsRole, "previews"},
120 {InstalledFilesRole, "installedFiles"},
121 {UnInstalledFilesRole, "uninstalledFiles"},
122 {RatingRole, "rating"},
123 {NumberOfCommentsRole, "numberOfComments"},
124 {DownloadCountRole, "downloadCount"},
125 {NumberFansRole, "numberFans"},
126 {NumberKnowledgebaseEntriesRole, "numberKnowledgebaseEntries"},
127 {KnowledgebaseLinkRole, "knowledgebaseLink"},
128 {DownloadLinksRole, "downloadLinks"},
129 {DonationLinkRole, "donationLink"},
130 {ProviderIdRole, "providerId"},
131 {SourceRole, "source"},
132 {EntryRole, "entry"},
133 };
134 return roles;
135}
136
137int ItemsModel::rowCount(const QModelIndex &parent) const
138{
139 if (parent.isValid()) {
140 return 0;
141 }
142 if (d->initModel()) {
143 return d->model->rowCount(QModelIndex());
144 }
145 return 0;
146}
147
148QVariant ItemsModel::data(const QModelIndex &index, int role) const
149{
150 if (index.isValid() && d->initModel()) {
151 KNSCore::Entry entry = d->model->data(d->model->index(index.row()), Qt::UserRole).value<KNSCore::Entry>();
152 switch (role) {
153 case NameRole:
154 case Qt::DisplayRole:
155 return entry.name();
156 case EntryRole:
157 return QVariant::fromValue(entry);
158 case UniqueIdRole:
159 return entry.uniqueId();
160 case CategoryRole:
161 return entry.category();
162 case HomepageRole:
163 return entry.homepage();
164 break;
165 case AuthorRole: {
166 KNSCore::Author author = entry.author();
167 QVariantMap returnAuthor;
168 returnAuthor[QStringLiteral("id")] = author.id();
169 returnAuthor[QStringLiteral("name")] = author.name();
170 returnAuthor[QStringLiteral("email")] = author.email();
171 returnAuthor[QStringLiteral("homepage")] = author.homepage();
172 returnAuthor[QStringLiteral("jabber")] = author.jabber();
173 returnAuthor[QStringLiteral("avatarUrl")] = author.avatarUrl();
174 returnAuthor[QStringLiteral("description")] = author.description();
175 return returnAuthor;
176 } break;
177 case LicenseRole:
178 return entry.license();
179 case ShortSummaryRole:
180 return entry.shortSummary();
181 case SummaryRole:
182 return entry.summary();
183 case ChangelogRole:
184 return entry.changelog();
185 case VersionRole:
186 return entry.version();
187 case ReleaseDateRole:
188 return entry.releaseDate();
189 case UpdateVersionRole:
190 return entry.updateVersion();
191 case UpdateReleaseDateRole:
192 return entry.updateReleaseDate();
193 case PayloadRole:
194 return entry.payload();
196 return entry.previewUrl(KNSCore::Entry::PreviewSmall1);
197 case PreviewsSmallRole: {
198 QStringList previews;
199 previews << entry.previewUrl(KNSCore::Entry::PreviewSmall1);
200 previews << entry.previewUrl(KNSCore::Entry::PreviewSmall2);
201 previews << entry.previewUrl(KNSCore::Entry::PreviewSmall3);
202 while (!previews.isEmpty() && previews.last().isEmpty()) {
203 previews.takeLast();
204 }
205 return previews;
206 }
207 case PreviewsRole: {
208 QStringList previews;
209 previews << entry.previewUrl(KNSCore::Entry::PreviewBig1);
210 previews << entry.previewUrl(KNSCore::Entry::PreviewBig2);
211 previews << entry.previewUrl(KNSCore::Entry::PreviewBig3);
212 while (!previews.isEmpty() && previews.last().isEmpty()) {
213 previews.takeLast();
214 }
215 return previews;
216 }
218 return entry.installedFiles();
219 case UnInstalledFilesRole:
220 return entry.uninstalledFiles();
221 case RatingRole:
222 return entry.rating();
223 case NumberOfCommentsRole:
224 return entry.numberOfComments();
225 case DownloadCountRole:
226 return entry.downloadCount();
227 case NumberFansRole:
228 return entry.numberFans();
229 case NumberKnowledgebaseEntriesRole:
230 return entry.numberKnowledgebaseEntries();
231 case KnowledgebaseLinkRole:
232 return entry.knowledgebaseLink();
233 case DownloadLinksRole: {
234 // This would be good to cache... but it also needs marking as dirty, somehow...
236 QVariantList list;
237 for (const KNSCore::Entry::DownloadLinkInformation &link : dllinks) {
239 }
240 if (list.isEmpty() && !entry.payload().isEmpty()) {
241 KNSCore::Entry::DownloadLinkInformation data;
242 data.descriptionLink = entry.payload();
244 }
245 return QVariant::fromValue(list);
246 }
247 case DonationLinkRole:
248 return entry.donationLink();
249 case ProviderIdRole:
250 return entry.providerId();
251 case SourceRole: {
252 KNSCore::Entry::Source src = entry.source();
253 switch (src) {
254 case KNSCore::Entry::Cache:
255 return QStringLiteral("Cache");
256 case KNSCore::Entry::Online:
257 return QStringLiteral("Online");
258 case KNSCore::Entry::Registry:
259 return QStringLiteral("Registry");
260 default:
261 return QStringLiteral("Unknown source - shouldn't be possible");
262 }
263 }
264 case CommentsModelRole: {
265 KNSCore::CommentsModel *commentsModel{nullptr};
266 if (!d->commentsModels.contains(entry.uniqueId())) {
267 commentsModel = new KNSCore::CommentsModel(d->engine);
268 commentsModel->setEntry(entry);
269 d->commentsModels[entry.uniqueId()] = commentsModel;
270 } else {
271 commentsModel = d->commentsModels[entry.uniqueId()];
272 }
273 return QVariant::fromValue(commentsModel);
274 }
275 default:
276 return QStringLiteral("Unknown role");
277 }
278 }
279 return QVariant();
280}
281
282bool ItemsModel::canFetchMore(const QModelIndex &parent) const
283{
284 return !parent.isValid() && d->engine && d->engine->categoriesMetadata().count() > 0;
285}
286
287void ItemsModel::fetchMore(const QModelIndex &parent)
288{
289 if (parent.isValid() || !d->engine) {
290 return;
291 }
292 d->engine->requestMoreData();
293}
294
296{
297 return d->engine;
298}
299
300void ItemsModel::setEngine(Engine *newEngine)
301{
302 if (d->engine != newEngine) {
304 d->engine = newEngine;
305 if (d->model) {
306 d->model->deleteLater();
307 d->model = nullptr;
308 }
309 Q_EMIT engineChanged();
311 }
312}
313
314int ItemsModel::indexOfEntryId(const QString &providerId, const QString &entryId)
315{
316 int idx{-1};
317 if (d->engine && d->model) {
318 for (int i = 0; i < rowCount(); ++i) {
319 KNSCore::Entry testEntry = d->model->data(d->model->index(i), Qt::UserRole).value<KNSCore::Entry>();
320 if (providerId == testEntry.providerId() && entryId == testEntry.uniqueId()) {
321 idx = i;
322 break;
323 }
324 }
325 }
326 return idx;
327}
328
329#include "moc_quickitemsmodel.cpp"
One downloadable item as contained within one content item.
KNSCore::EngineBase for interfacing with QML.
Definition quickengine.h:29
void entryEvent(const KNSCore::Entry &entry, KNSCore::Entry::EntryEvent event)
This is fired for events related directly to a single Entry instance The intermediate states Updating...
A model which shows the contents found in an Engine.
Q_INVOKABLE int indexOfEntryId(const QString &providerId, const QString &entryId)
Get the index of an entry based on that entry's unique ID.
@ PreviewsRole
< this will return a list here, rather than be tied so tightly to the remote api
@ InstalledFilesRole
< this will return a list here, rather than be tied so tightly to the remote api
Q_SIGNAL void entryChanged(const KNSCore::Entry &entry)
Fired when an entry's data changes.
Engine * engine
The NewStuffQuickEngine to show items from.
KNewStuff author information.
Definition core/author.h:32
QUrl avatarUrl() const
Retrieve the url of the user's avatar image.
QString homepage() const
Retrieve the author's homepage.
QString id() const
Retrieve the author's user ID.
QString description() const
Retrieve the user's description text.
QString jabber() const
Retrieve the author's jabber address.
A model which takes care of the comments for a single Entry.
KNewStuff data entry container.
Definition entry.h:48
QDate releaseDate() const
Retrieve the date of the object's publication.
Definition entry.cpp:176
QList< DownloadLinkInformation > downloadLinkInformationList() const
A list of downloadable data for this entry.
Definition entry.cpp:354
@ StatusChangedEvent
Used when an event's status is set (use Entry::status() to get the new status)
Definition entry.h:122
@ DetailsLoadedEvent
Used when more details have been added to an existing entry (such as the full description),...
Definition entry.h:124
QString updateVersion() const
Retrieve the version string of the object that is available as update.
Definition entry.cpp:206
QString knowledgebaseLink() const
The link for the knowledgebase for this entry.
Definition entry.cpp:295
QStringList installedFiles() const
Retrieve the locally installed files.
Definition entry.cpp:339
QString payload() const
Retrieve the file name of the object.
Definition entry.cpp:186
QString category() const
Retrieve the category of the data object.
Definition entry.cpp:96
QDate updateReleaseDate() const
Retrieve the date of the newer version that is available as update.
Definition entry.cpp:196
QString previewUrl(PreviewType type=PreviewSmall1) const
Retrieve the file name of an image containing a preview of the object.
Definition entry.cpp:216
int numberKnowledgebaseEntries() const
The number of entries in the knowledgebase for this entry.
Definition entry.cpp:286
QString version() const
Retrieve the version string of the object.
Definition entry.cpp:166
Source
Source of the entry, A entry's data is coming from either cache, or an online provider this helps the...
Definition entry.h:94
QStringList uninstalledFiles() const
Retrieve the locally uninstalled files.
Definition entry.cpp:344
int numberFans() const
How many people have marked themselves as fans of this entry.
Definition entry.cpp:266
QString license() const
Retrieve the license name of the object.
Definition entry.cpp:126
KIOCORE_EXPORT QStringList list(const QString &fileClass)
void dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QList< int > &roles)
void modelAboutToBeReset()
void rowsInserted(const QModelIndex &parent, int first, int last)
void rowsRemoved(const QModelIndex &parent, int first, int last)
virtual QModelIndex index(int row, int column, const QModelIndex &parent) const const override
void append(QList< T > &&value)
bool isEmpty() const const
T & last()
value_type takeLast()
bool isValid() const const
int row() const const
Q_EMITQ_EMIT
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
QObject * parent() const const
bool isEmpty() const const
DisplayRole
QVariant fromValue(T &&value)
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Fri Nov 29 2024 11:53:59 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.