KNewStuff

quickitemsmodel.cpp
1 /*
2  * Copyright (C) 2016 Dan Leinir Turthra Jensen <[email protected]>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) version 3, or any
8  * later version accepted by the membership of KDE e.V. (or its
9  * successor approved by the membership of KDE e.V.), which shall
10  * act as a proxy defined in Section 6 of version 3 of the license.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library. If not, see <http://www.gnu.org/licenses/>.
19  *
20  */
21 
22 #include "quickitemsmodel.h"
23 #include "quickengine.h"
24 #include "knewstuffquick_debug.h"
25 
26 #include "itemsmodel.h"
27 #include "engine.h"
28 #include "downloadlinkinfo.h"
29 #include "core/commentsmodel.h"
30 
31 #include <KLocalizedString>
32 #include <KShell>
33 #include <QProcess>
34 
35 class ItemsModel::Private {
36 public:
37  Private(ItemsModel *qq)
38  : q(qq)
39  , model(nullptr)
40  , engine(nullptr)
41  , coreEngine(nullptr)
42  {}
43  ~Private()
44  {
45  }
46  ItemsModel *q;
47  KNSCore::ItemsModel *model;
48  Engine *engine;
49  KNSCore::Engine *coreEngine;
50 
52 
53  bool isLoadingData{false};
54 
55  bool initModel()
56  {
57  if (model) {
58  return true;
59  }
60  if (!coreEngine) {
61  return false;
62  }
63  model = new KNSCore::ItemsModel(coreEngine, q);
64 
65  q->connect(coreEngine, &KNSCore::Engine::signalBusy, q, [=](){ isLoadingData = true; emit q->isLoadingDataChanged(); });
66  q->connect(coreEngine, &KNSCore::Engine::signalIdle, q, [=](){ isLoadingData = false; emit q->isLoadingDataChanged(); });
67 
68  q->connect(coreEngine, &KNSCore::Engine::signalProvidersLoaded, coreEngine, &KNSCore::Engine::reloadEntries);
69  // Entries have been fetched and should be shown:
70  q->connect(coreEngine, &KNSCore::Engine::signalEntriesLoaded, model, [this](const KNSCore::EntryInternal::List& entries){
71  if (coreEngine->filter() != KNSCore::Provider::Updates) {
72  model->slotEntriesLoaded(entries);
73  }
74  });
75  q->connect(coreEngine, &KNSCore::Engine::signalUpdateableEntriesLoaded, model, [this](const KNSCore::EntryInternal::List& entries){
76  if (coreEngine->filter() == KNSCore::Provider::Updates) {
77  model->slotEntriesLoaded(entries);
78  }
79  });
80 
81  // An entry has changes - eg because it was installed
82  q->connect(coreEngine, &KNSCore::Engine::signalEntryChanged, model, &KNSCore::ItemsModel::slotEntryChanged);
83  q->connect(coreEngine, &KNSCore::Engine::signalEntryChanged, q, [=](const KNSCore::EntryInternal &entry){
84  emit q->entryChanged(model->row(entry));
85  });
86 
87  q->connect(coreEngine, &KNSCore::Engine::signalResetView, model, &KNSCore::ItemsModel::clearEntries);
88  q->connect(coreEngine, &KNSCore::Engine::signalEntryPreviewLoaded, model, &KNSCore::ItemsModel::slotEntryPreviewLoaded);
89 
90  q->connect(model, &KNSCore::ItemsModel::rowsInserted, q, &ItemsModel::rowsInserted);
91  q->connect(model, &KNSCore::ItemsModel::rowsRemoved, q, &ItemsModel::rowsRemoved);
92  q->connect(model, &KNSCore::ItemsModel::dataChanged, q, &ItemsModel::dataChanged);
93  q->connect(model, &KNSCore::ItemsModel::modelReset, q, &ItemsModel::modelReset);
94  return true;
95  }
96 };
97 
98 ItemsModel::ItemsModel(QObject *parent)
99  : QAbstractListModel(parent)
100  , d(new Private(this))
101 {
102 }
103 
104 ItemsModel::~ItemsModel()
105 {
106  delete d;
107 }
108 
109 QHash<int, QByteArray> ItemsModel::roleNames() const
110 {
111  static const QHash<int, QByteArray> roles = QHash<int, QByteArray>{
112  {Qt::DisplayRole, "display"},
113  {NameRole, "name"},
114  {UniqueIdRole, "uniqueId"},
115  {CategoryRole, "category"},
116  {HomepageRole, "homepage"},
117  {AuthorRole, "author"},
118  {LicenseRole, "license"},
119  {ShortSummaryRole, "shortSummary"},
120  {SummaryRole, "summary"},
121  {ChangelogRole, "changelog"},
122  {VersionRole, "version"},
123  {ReleaseDateRole, "releaseDate"},
124  {UpdateVersionRole, "updateVersion"},
125  {UpdateReleaseDateRole, "updateReleaseDate"},
126  {PayloadRole, "payload"},
127  {Qt::DecorationRole, "decoration"},
128  {PreviewsSmallRole, "previewsSmall"},
129  {PreviewsRole, "previews"},
130  {InstalledFilesRole, "installedFiles"},
131  {UnInstalledFilesRole, "uninstalledFiles"},
132  {RatingRole, "rating"},
133  {NumberOfCommentsRole, "numberOfComments"},
134  {DownloadCountRole, "downloadCount"},
135  {NumberFansRole, "numberFans"},
136  {NumberKnowledgebaseEntriesRole, "numberKnowledgebaseEntries"},
137  {KnowledgebaseLinkRole, "knowledgebaseLink"},
138  {DownloadLinksRole, "downloadLinks"},
139  {DonationLinkRole, "donationLink"},
140  {ProviderIdRole, "providerId"},
141  {SourceRole, "source"},
142  {StatusRole, "status"}
143  };
144  return roles;
145 }
146 
147 int ItemsModel::rowCount(const QModelIndex& parent) const
148 {
149  if (parent.isValid())
150  return 0;
151  if (d->initModel())
152  return d->model->rowCount(QModelIndex());
153  return 0;
154 }
155 
156 QVariant ItemsModel::data(const QModelIndex &index, int role) const
157 {
158  QVariant data;
159  if (index.isValid() && d->initModel())
160  {
161  KNSCore::EntryInternal entry = d->model->data(d->model->index(index.row()), Qt::UserRole).value<KNSCore::EntryInternal>();
162  switch (role)
163  {
164  case NameRole:
165  case Qt::DisplayRole:
166  data.setValue<QString>(entry.name());
167  break;
168  case UniqueIdRole:
169  data.setValue<QString>(entry.uniqueId());
170  break;
171  case CategoryRole:
172  data.setValue<QString>(entry.category());
173  break;
174  case HomepageRole:
175  data.setValue<QUrl>(entry.homepage());
176  break;
177  case AuthorRole:
178  {
179  KNSCore::Author author = entry.author();
180  QVariantMap returnAuthor;
181  returnAuthor[QStringLiteral("id")] = author.id();
182  returnAuthor[QStringLiteral("name")] = author.name();
183  returnAuthor[QStringLiteral("email")] = author.email();
184  returnAuthor[QStringLiteral("homepage")] = author.homepage();
185  returnAuthor[QStringLiteral("jabber")] = author.jabber();
186  returnAuthor[QStringLiteral("avatarUrl")] = author.avatarUrl();
187  returnAuthor[QStringLiteral("description")] = author.description();
188  data.setValue<>(returnAuthor);
189  }
190  break;
191  case LicenseRole:
192  data.setValue<QString>(entry.license());
193  break;
194  case ShortSummaryRole:
195  data.setValue<QString>(entry.shortSummary());
196  break;
197  case SummaryRole:
198  data.setValue<QString>(entry.summary());
199  break;
200  case ChangelogRole:
201  data.setValue<QString>(entry.changelog());
202  break;
203  case VersionRole:
204  data.setValue<QString>(entry.version());
205  break;
206  case ReleaseDateRole:
207  data.setValue<QDate>(entry.releaseDate());
208  break;
209  case UpdateVersionRole:
210  data.setValue<QString>(entry.updateVersion());
211  break;
212  case UpdateReleaseDateRole:
213  data.setValue<QDate>(entry.updateReleaseDate());
214  break;
215  case PayloadRole:
216  data.setValue<QString>(entry.payload());
217  break;
218  case Qt::DecorationRole:
219  data.setValue<QString>(entry.previewUrl(KNSCore::EntryInternal::PreviewSmall1));
220  break;
221  case PreviewsSmallRole:
222  {
223  QStringList previews;
224  previews << entry.previewUrl(KNSCore::EntryInternal::PreviewSmall1);
225  previews << entry.previewUrl(KNSCore::EntryInternal::PreviewSmall2);
226  previews << entry.previewUrl(KNSCore::EntryInternal::PreviewSmall3);
227  while(!previews.isEmpty() && previews.last().isEmpty()) {
228  previews.takeLast();
229  }
230  data.setValue<QStringList>(previews);
231  }
232  break;
233  case PreviewsRole:
234  {
235  QStringList previews;
236  previews << entry.previewUrl(KNSCore::EntryInternal::PreviewBig1);
237  previews << entry.previewUrl(KNSCore::EntryInternal::PreviewBig2);
238  previews << entry.previewUrl(KNSCore::EntryInternal::PreviewBig3);
239  while(!previews.isEmpty() && previews.last().isEmpty()) {
240  previews.takeLast();
241  }
242  data.setValue<QStringList>(previews);
243  }
244  break;
245  case InstalledFilesRole:
246  data.setValue<QStringList>(entry.installedFiles());
247  break;
248  case UnInstalledFilesRole:
249  data.setValue<QStringList>(entry.uninstalledFiles());
250  break;
251  case RatingRole:
252  data.setValue<int>(entry.rating());
253  break;
254  case NumberOfCommentsRole:
255  data.setValue<int>(entry.numberOfComments());
256  break;
257  case DownloadCountRole:
258  data.setValue<int>(entry.downloadCount());
259  break;
260  case NumberFansRole:
261  data.setValue<int>(entry.numberFans());
262  break;
263  case NumberKnowledgebaseEntriesRole:
264  data.setValue<int>(entry.numberKnowledgebaseEntries());
265  break;
266  case KnowledgebaseLinkRole:
267  data.setValue<QString>(entry.knowledgebaseLink());
268  break;
269  case DownloadLinksRole:
270  {
271  // This would be good to cache... but it also needs marking as dirty, somehow...
274  for(const KNSCore::EntryInternal::DownloadLinkInformation &link : dllinks)
275  {
276  DownloadLinkInfo *info = new DownloadLinkInfo();
277  info->setData(link);
278  list.append(info);
279  }
280  data.setValue<QObjectList>(list);
281  }
282  break;
283  case DonationLinkRole:
284  data.setValue<QString>(entry.donationLink());
285  break;
286  case ProviderIdRole:
287  data.setValue<QString>(entry.providerId());
288  break;
289  case SourceRole:
290  {
291  KNSCore::EntryInternal::Source src = entry.source();
292  switch(src)
293  {
294  case KNSCore::EntryInternal::Cache:
295  data.setValue<QString>(QStringLiteral("Cache"));
296  break;
297  case KNSCore::EntryInternal::Online:
298  data.setValue<QString>(QStringLiteral("Online"));
299  break;
300  case KNSCore::EntryInternal::Registry:
301  data.setValue<QString>(QStringLiteral("Registry"));
302  break;
303  default:
304  data.setValue<QString>(QStringLiteral("Unknown source - shouldn't be possible"));
305  break;
306  }
307  }
308  break;
309  case StatusRole:
310  {
312  switch(status)
313  {
314  case KNS3::Entry::Downloadable:
315  data.setValue<ItemsModel::ItemStatus>(ItemsModel::DownloadableStatus);
316  break;
317  case KNS3::Entry::Installed:
318  data.setValue<ItemsModel::ItemStatus>(ItemsModel::InstalledStatus);
319  break;
320  case KNS3::Entry::Updateable:
321  data.setValue<ItemsModel::ItemStatus>(ItemsModel::UpdateableStatus);
322  break;
323  case KNS3::Entry::Deleted:
324  data.setValue<ItemsModel::ItemStatus>(ItemsModel::DeletedStatus);
325  break;
326  case KNS3::Entry::Installing:
327  data.setValue<ItemsModel::ItemStatus>(ItemsModel::InstallingStatus);
328  break;
329  case KNS3::Entry::Updating:
330  data.setValue<ItemsModel::ItemStatus>(ItemsModel::UpdatingStatus);
331  break;
332  case KNS3::Entry::Invalid:
333  default:
334  data.setValue<ItemsModel::ItemStatus>(ItemsModel::InvalidStatus);
335  break;
336  }
337  }
338  break;
339  case CommentsModelRole:
340  {
341  KNSCore::CommentsModel *commentsModel{nullptr};
342  if (!d->commentsModels.contains(entry.uniqueId())) {
343  commentsModel = d->coreEngine->commentsForEntry(entry);
344  d->commentsModels[entry.uniqueId()] = commentsModel;
345  } else {
346  commentsModel = d->commentsModels[entry.uniqueId()];
347  }
348  data.setValue<QObject*>(commentsModel);
349  }
350  break;
351  default:
352  data.setValue<QString>(QStringLiteral("Unknown role"));
353  break;
354  }
355  }
356  return data;
357 }
358 
359 bool ItemsModel::canFetchMore(const QModelIndex &parent) const
360 {
361  if (!parent.isValid() && d->coreEngine && d->coreEngine->categoriesMetadata().count() > 0) {
362  return true;
363  }
364  return false;
365 }
366 
367 void ItemsModel::fetchMore(const QModelIndex &parent)
368 {
369  if (parent.isValid() || !d->coreEngine) {
370  return;
371  }
372  d->coreEngine->requestMoreData();
373 }
374 
376 {
377  return d->engine;
378 }
379 
380 void ItemsModel::setEngine(QObject *newEngine)
381 {
382  if (d->engine != newEngine) {
383  beginResetModel();
384  d->engine = qobject_cast<Engine*>(newEngine);
385  d->model->deleteLater();
386  d->model = nullptr;
387  d->coreEngine = nullptr;
388  if (d->engine) {
389  d->coreEngine = qobject_cast<KNSCore::Engine*>(d->engine->engine());
390  }
391  connect(d->engine, &Engine::engineChanged, this, [this](){
392  beginResetModel();
393  d->model->deleteLater();
394  d->model = nullptr;
395  d->coreEngine = qobject_cast<KNSCore::Engine*>(d->engine->engine());
396  endResetModel();
397  });
398  emit engineChanged();
399  endResetModel();
400  }
401 }
402 
403 bool ItemsModel::isLoadingData() const
404 {
405  return d->isLoadingData;
406 }
407 
408 void ItemsModel::installItem(int index, int linkId)
409 {
410  if (d->coreEngine) {
411  KNSCore::EntryInternal entry = d->model->data(d->model->index(index), Qt::UserRole).value<KNSCore::EntryInternal>();
412  if(entry.isValid()) {
413  d->coreEngine->install(entry, linkId);
414  }
415  }
416 }
417 
418 void ItemsModel::updateItem(int index)
419 {
420  installItem(index, AutoDetectLinkId);
421 }
422 
424 {
425  if (d->coreEngine) {
426  KNSCore::EntryInternal entry = d->model->data(d->model->index(index), Qt::UserRole).value<KNSCore::EntryInternal>();
427  if(entry.isValid()) {
428  d->coreEngine->uninstall(entry);
429  }
430  }
431 }
432 
433 void ItemsModel::adoptItem(int index)
434 {
435  if (d->coreEngine) {
436  KNSCore::EntryInternal entry = d->model->data(d->model->index(index), Qt::UserRole).value<KNSCore::EntryInternal>();
437  if (entry.isValid()) {
438  QStringList args = KShell::splitArgs(d->coreEngine->adoptionCommand(entry));
439  qCDebug(KNEWSTUFFQUICK) << "executing AdoptionCommand" << args;
440  QProcess::startDetached(args.takeFirst(), args);
441  d->engine->idleMessage(i18n("Using %1", entry.name()));
442  }
443  }
444 }
QString donationLink() const
A string representing the URL for a website where the user can donate to the author of this entry...
One downloadable item as contained within one content item.
int numberFans() const
How many people have marked themselves as fans of this entry.
QString summary() const
Retrieve a (potentially very long) description of the object.
QString uniqueId() const
Get the object&#39;s unique ID.
Author author() const
Retrieve the author of the object.
int downloadCount() const
Retrieve the download count for the object, which has been determined by its hosting sites and thus m...
bool startDetached(qint64 *pid)
QString shortSummary() const
Retrieve a short description of what the object is all about (should be very short) ...
bool isLoadingData() const
Whether or not the model is fetching information from a remote location.
Q_INVOKABLE void installItem(int index, int linkId)
This will install (or update, if already installed) the item at the given index.
QDate releaseDate() const
Retrieve the date of the object&#39;s publication.
Source
Source of the entry, A entry&#39;s data is coming from either cache, or an online provider this helps the...
Definition: entryinternal.h:70
Encapsulates a KNSCore::Engine for use in Qt Quick.
Definition: quickengine.h:38
QUrl avatarUrl() const
Retrieve the url of the user&#39;s avatar image.
KNewStuff author information.
Definition: core/author.h:40
bool isValid() const const
QString id() const
Retrieve the author&#39;s user ID.
Definition: core/author.cpp:83
QString payload() const
Retrieve the file name of the object.
QString version() const
Retrieve the version string of the object.
Q_SIGNAL void isLoadingDataChanged()
Fired when the isLoadingData value changes.
void dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector< int > &roles)
QUrl homepage() const
A link to a website containing information about this entry.
QList< DownloadLinkInformation > downloadLinkInformationList() const
A list of downloadable data for this entry.
bool isEmpty() const const
QStringList installedFiles() const
Retrieve the locally installed files.
DisplayRole
int row() const const
QString description() const
Retrieve the user&#39;s description text.
A model which takes care of the comments for a single EntryInternal.
QString category() const
Retrieve the category of the data object.
QString homepage() const
Retrieve the author&#39;s homepage.
QDate updateReleaseDate() const
Retrieve the date of the newer version that is available as update.
KCOREADDONS_EXPORT QStringList splitArgs(const QString &cmd, Options flags=NoOptions, Errors *err=nullptr)
void rowsRemoved(const QModelIndex &parent, int first, int last)
Q_INVOKABLE void adoptItem(int index)
Run the adoption command on an already installed item.
QString previewUrl(PreviewType type=PreviewSmall1) const
Retrieve the file name of an image containing a preview of the object.
Provider::Filter filter() const
The result filter set on the current request.
Definition: engine.cpp:442
A model which shows the contents found in an Engine.
Status
Status of the entry.
Definition: entry.h:57
void setValue(const T &value)
QString i18n(const char *text, const TYPE &arg...)
Q_SIGNAL void entryChanged(int index)
Fired when an entry&#39;s data changes.
T takeLast()
int numberKnowledgebaseEntries() const
The number of entries in the knowledgebase for this entry.
QObject engine
The NewStuffQuickEngine to show items from.
KNewStuff data entry container.
Definition: entryinternal.h:60
int rating() const
Retrieve the rating for the object, which has been determined by its users and thus might change over...
T & last()
int numberOfComments() const
KNewStuff engine.
Definition: engine.h:70
QStringList uninstalledFiles() const
Retrieve the locally uninstalled files.
QString updateVersion() const
Retrieve the version string of the object that is available as update.
Q_INVOKABLE void uninstallItem(int index)
Uninstall an already installed item.
QString knowledgebaseLink() const
The link for the knowledgebase for this entry.
KNS3::Entry::Status status() const
Retrieves the entry&#39;s status.
void rowsInserted(const QModelIndex &parent, int first, int last)
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
QString name() const
Retrieve the name of the data object.
QString jabber() const
Retrieve the author&#39;s jabber address.
T qobject_cast(QObject *object)
QObject * parent() const const
QString license() const
Retrieve the license name of the object.
QString email() const
Retrieve the author&#39;s email address.
QString providerId() const
The id of the provider this entry belongs to.
Q_INVOKABLE void updateItem(int index)
This will request an update of the given item.
typedef QObjectList
KIOFILEWIDGETS_EXPORT QStringList list(const QString &fileClass)
QString name() const
Retrieve the author&#39;s name.
Definition: core/author.cpp:93
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Sun Aug 9 2020 22:43:40 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.