Changeset View
Changeset View
Standalone View
Standalone View
src/qtquick/quickitemsmodel.cpp
Show All 15 Lines | |||||
16 | * | 16 | * | ||
17 | * You should have received a copy of the GNU Lesser General Public | 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/>. | 18 | * License along with this library. If not, see <http://www.gnu.org/licenses/>. | ||
19 | * | 19 | * | ||
20 | */ | 20 | */ | ||
21 | 21 | | |||
22 | #include "quickitemsmodel.h" | 22 | #include "quickitemsmodel.h" | ||
23 | #include "quickengine.h" | 23 | #include "quickengine.h" | ||
24 | #include "knewstuffquick_debug.h" | ||||
24 | 25 | | |||
25 | #include "itemsmodel.h" | 26 | #include "itemsmodel.h" | ||
26 | #include "engine.h" | 27 | #include "engine.h" | ||
27 | #include "downloadlinkinfo.h" | 28 | #include "downloadlinkinfo.h" | ||
29 | #include "core/commentsmodel.h" | ||||
30 | | ||||
31 | #include <KLocalizedString> | ||||
32 | #include <KShell> | ||||
33 | #include <QProcess> | ||||
28 | 34 | | |||
29 | class ItemsModel::Private { | 35 | class ItemsModel::Private { | ||
30 | public: | 36 | public: | ||
31 | Private(ItemsModel* qq) | 37 | Private(ItemsModel *qq) | ||
32 | : q(qq) | 38 | : q(qq) | ||
33 | , model(nullptr) | 39 | , model(nullptr) | ||
34 | , engine(nullptr) | 40 | , engine(nullptr) | ||
41 | , coreEngine(nullptr) | ||||
35 | {} | 42 | {} | ||
43 | ~Private() | ||||
44 | { | ||||
45 | qDeleteAll(commentsModels); | ||||
46 | } | ||||
36 | ItemsModel* q; | 47 | ItemsModel *q; | ||
37 | KNSCore::ItemsModel* model; | 48 | KNSCore::ItemsModel *model; | ||
38 | KNSCore::Engine* engine; | 49 | Engine *engine; | ||
50 | KNSCore::Engine *coreEngine; | ||||
51 | | ||||
52 | QHash<QString, KNSCore::CommentsModel*> commentsModels; | ||||
39 | 53 | | |||
40 | bool initModel() | 54 | bool initModel() | ||
41 | { | 55 | { | ||
42 | if(model) { | 56 | if (model) { | ||
43 | return true; | 57 | return true; | ||
44 | } | 58 | } | ||
45 | if(!engine) { | 59 | if (!coreEngine) { | ||
46 | return false; | 60 | return false; | ||
47 | } | 61 | } | ||
48 | model = new KNSCore::ItemsModel(engine, q); | 62 | model = new KNSCore::ItemsModel(coreEngine, q); | ||
49 | 63 | | |||
50 | q->connect(engine, &KNSCore::Engine::signalProvidersLoaded, engine, &KNSCore::Engine::reloadEntries); | 64 | q->connect(coreEngine, &KNSCore::Engine::signalProvidersLoaded, coreEngine, &KNSCore::Engine::reloadEntries); | ||
51 | // Entries have been fetched and should be shown: | 65 | // Entries have been fetched and should be shown: | ||
52 | q->connect(engine, &KNSCore::Engine::signalEntriesLoaded, model, &KNSCore::ItemsModel::slotEntriesLoaded); | 66 | q->connect(coreEngine, &KNSCore::Engine::signalEntriesLoaded, model, &KNSCore::ItemsModel::slotEntriesLoaded); | ||
53 | 67 | | |||
54 | // An entry has changes - eg because it was installed | 68 | // An entry has changes - eg because it was installed | ||
55 | q->connect(engine, &KNSCore::Engine::signalEntryChanged, model, &KNSCore::ItemsModel::slotEntryChanged); | 69 | q->connect(coreEngine, &KNSCore::Engine::signalEntryChanged, model, &KNSCore::ItemsModel::slotEntryChanged); | ||
70 | q->connect(coreEngine, &KNSCore::Engine::signalEntryChanged, q, [=](const KNSCore::EntryInternal &entry){ | ||||
71 | emit q->entryChanged(model->row(entry)); | ||||
72 | }); | ||||
56 | 73 | | |||
57 | q->connect(engine, &KNSCore::Engine::signalResetView, model, &KNSCore::ItemsModel::clearEntries); | 74 | q->connect(coreEngine, &KNSCore::Engine::signalResetView, model, &KNSCore::ItemsModel::clearEntries); | ||
58 | q->connect(engine, &KNSCore::Engine::signalEntryPreviewLoaded, model, &KNSCore::ItemsModel::slotEntryPreviewLoaded); | 75 | q->connect(coreEngine, &KNSCore::Engine::signalEntryPreviewLoaded, model, &KNSCore::ItemsModel::slotEntryPreviewLoaded); | ||
59 | 76 | | |||
60 | q->connect(model, &KNSCore::ItemsModel::rowsInserted, q, &ItemsModel::rowsInserted); | 77 | q->connect(model, &KNSCore::ItemsModel::rowsInserted, q, &ItemsModel::rowsInserted); | ||
61 | q->connect(model, &KNSCore::ItemsModel::rowsRemoved, q, &ItemsModel::rowsRemoved); | 78 | q->connect(model, &KNSCore::ItemsModel::rowsRemoved, q, &ItemsModel::rowsRemoved); | ||
62 | q->connect(model, &KNSCore::ItemsModel::dataChanged, q, &ItemsModel::dataChanged); | 79 | q->connect(model, &KNSCore::ItemsModel::dataChanged, q, &ItemsModel::dataChanged); | ||
63 | q->connect(model, &KNSCore::ItemsModel::modelReset, q, &ItemsModel::modelReset); | 80 | q->connect(model, &KNSCore::ItemsModel::modelReset, q, &ItemsModel::modelReset); | ||
64 | return true; | 81 | return true; | ||
65 | } | 82 | } | ||
66 | }; | 83 | }; | ||
67 | 84 | | |||
68 | ItemsModel::ItemsModel(QObject* parent) | 85 | ItemsModel::ItemsModel(QObject *parent) | ||
69 | : QAbstractListModel(parent) | 86 | : QAbstractListModel(parent) | ||
70 | , d(new Private(this)) | 87 | , d(new Private(this)) | ||
71 | { | 88 | { | ||
72 | } | 89 | } | ||
73 | 90 | | |||
74 | ItemsModel::~ItemsModel() | 91 | ItemsModel::~ItemsModel() | ||
75 | { | 92 | { | ||
76 | delete d; | 93 | delete d; | ||
Show All 34 Lines | 98 | static const QHash<int, QByteArray> roles = QHash<int, QByteArray>{ | |||
111 | {SourceRole, "source"}, | 128 | {SourceRole, "source"}, | ||
112 | {StatusRole, "status"} | 129 | {StatusRole, "status"} | ||
113 | }; | 130 | }; | ||
114 | return roles; | 131 | return roles; | ||
115 | } | 132 | } | ||
116 | 133 | | |||
117 | int ItemsModel::rowCount(const QModelIndex& parent) const | 134 | int ItemsModel::rowCount(const QModelIndex& parent) const | ||
118 | { | 135 | { | ||
119 | if(parent.isValid()) | 136 | if (parent.isValid()) | ||
120 | return 0; | 137 | return 0; | ||
121 | if(d->initModel()) | 138 | if (d->initModel()) | ||
122 | return d->model->rowCount(QModelIndex()); | 139 | return d->model->rowCount(QModelIndex()); | ||
123 | return 0; | 140 | return 0; | ||
124 | } | 141 | } | ||
125 | 142 | | |||
126 | QVariant ItemsModel::data(const QModelIndex& index, int role) const | 143 | QVariant ItemsModel::data(const QModelIndex &index, int role) const | ||
127 | { | 144 | { | ||
128 | QVariant data; | 145 | QVariant data; | ||
129 | if(index.isValid() && d->initModel()) | 146 | if (index.isValid() && d->initModel()) | ||
130 | { | 147 | { | ||
131 | KNSCore::EntryInternal entry = d->model->data(d->model->index(index.row()), Qt::UserRole).value<KNSCore::EntryInternal>(); | 148 | KNSCore::EntryInternal entry = d->model->data(d->model->index(index.row()), Qt::UserRole).value<KNSCore::EntryInternal>(); | ||
132 | switch(role) | 149 | switch (role) | ||
133 | { | 150 | { | ||
134 | case NameRole: | 151 | case NameRole: | ||
135 | case Qt::DisplayRole: | 152 | case Qt::DisplayRole: | ||
136 | data.setValue<QString>(entry.name()); | 153 | data.setValue<QString>(entry.name()); | ||
137 | break; | 154 | break; | ||
138 | case UniqueIdRole: | 155 | case UniqueIdRole: | ||
139 | data.setValue<QString>(entry.uniqueId()); | 156 | data.setValue<QString>(entry.uniqueId()); | ||
140 | break; | 157 | break; | ||
141 | case CategoryRole: | 158 | case CategoryRole: | ||
142 | data.setValue<QString>(entry.category()); | 159 | data.setValue<QString>(entry.category()); | ||
143 | break; | 160 | break; | ||
144 | case HomepageRole: | 161 | case HomepageRole: | ||
145 | data.setValue<QUrl>(entry.homepage()); | 162 | data.setValue<QUrl>(entry.homepage()); | ||
146 | break; | 163 | break; | ||
147 | case AuthorRole: | 164 | case AuthorRole: | ||
148 | { | 165 | { | ||
149 | KNSCore::Author author = entry.author(); | 166 | KNSCore::Author author = entry.author(); | ||
150 | QVariantMap returnAuthor; | 167 | QVariantMap returnAuthor; | ||
168 | returnAuthor[QStringLiteral("id")] = author.id(); | ||||
151 | returnAuthor[QStringLiteral("name")] = author.name(); | 169 | returnAuthor[QStringLiteral("name")] = author.name(); | ||
152 | returnAuthor[QStringLiteral("email")] = author.email(); | 170 | returnAuthor[QStringLiteral("email")] = author.email(); | ||
153 | returnAuthor[QStringLiteral("homepage")] = author.homepage(); | 171 | returnAuthor[QStringLiteral("homepage")] = author.homepage(); | ||
154 | returnAuthor[QStringLiteral("jabber")] = author.jabber(); | 172 | returnAuthor[QStringLiteral("jabber")] = author.jabber(); | ||
173 | returnAuthor[QStringLiteral("avatarUrl")] = author.avatarUrl(); | ||||
174 | returnAuthor[QStringLiteral("description")] = author.description(); | ||||
155 | data.setValue<>(returnAuthor); | 175 | data.setValue<>(returnAuthor); | ||
156 | } | 176 | } | ||
157 | break; | 177 | break; | ||
158 | case LicenseRole: | 178 | case LicenseRole: | ||
159 | data.setValue<QString>(entry.license()); | 179 | data.setValue<QString>(entry.license()); | ||
160 | break; | 180 | break; | ||
161 | case ShortSummaryRole: | 181 | case ShortSummaryRole: | ||
162 | data.setValue<QString>(entry.shortSummary()); | 182 | data.setValue<QString>(entry.shortSummary()); | ||
▲ Show 20 Lines • Show All 70 Lines • ▼ Show 20 Line(s) | |||||
233 | case KnowledgebaseLinkRole: | 253 | case KnowledgebaseLinkRole: | ||
234 | data.setValue<QString>(entry.knowledgebaseLink()); | 254 | data.setValue<QString>(entry.knowledgebaseLink()); | ||
235 | break; | 255 | break; | ||
236 | case DownloadLinksRole: | 256 | case DownloadLinksRole: | ||
237 | { | 257 | { | ||
238 | // This would be good to cache... but it also needs marking as dirty, somehow... | 258 | // This would be good to cache... but it also needs marking as dirty, somehow... | ||
239 | const QList<KNSCore::EntryInternal::DownloadLinkInformation> dllinks = entry.downloadLinkInformationList(); | 259 | const QList<KNSCore::EntryInternal::DownloadLinkInformation> dllinks = entry.downloadLinkInformationList(); | ||
240 | QObjectList list; | 260 | QObjectList list; | ||
241 | for(const KNSCore::EntryInternal::DownloadLinkInformation& link : dllinks) | 261 | for(const KNSCore::EntryInternal::DownloadLinkInformation &link : dllinks) | ||
242 | { | 262 | { | ||
243 | DownloadLinkInfo* info = new DownloadLinkInfo(); | 263 | DownloadLinkInfo *info = new DownloadLinkInfo(); | ||
244 | info->setData(link); | 264 | info->setData(link); | ||
245 | list.append(info); | 265 | list.append(info); | ||
246 | } | 266 | } | ||
247 | data.setValue<QObjectList>(list); | 267 | data.setValue<QObjectList>(list); | ||
248 | } | 268 | } | ||
249 | break; | 269 | break; | ||
250 | case DonationLinkRole: | 270 | case DonationLinkRole: | ||
251 | data.setValue<QString>(entry.donationLink()); | 271 | data.setValue<QString>(entry.donationLink()); | ||
▲ Show 20 Lines • Show All 46 Lines • ▼ Show 20 Line(s) | 316 | case KNS3::Entry::Updating: | |||
298 | break; | 318 | break; | ||
299 | case KNS3::Entry::Invalid: | 319 | case KNS3::Entry::Invalid: | ||
300 | default: | 320 | default: | ||
301 | data.setValue<ItemsModel::ItemStatus>(ItemsModel::InvalidStatus); | 321 | data.setValue<ItemsModel::ItemStatus>(ItemsModel::InvalidStatus); | ||
302 | break; | 322 | break; | ||
303 | } | 323 | } | ||
304 | } | 324 | } | ||
305 | break; | 325 | break; | ||
326 | case CommentsModelRole: | ||||
327 | { | ||||
328 | KNSCore::CommentsModel *commentsModel{nullptr}; | ||||
329 | if (!d->commentsModels.contains(entry.uniqueId())) { | ||||
330 | commentsModel = d->coreEngine->commentsForEntry(entry); | ||||
331 | d->commentsModels[entry.uniqueId()] = commentsModel; | ||||
332 | } else { | ||||
333 | commentsModel = d->commentsModels[entry.uniqueId()]; | ||||
334 | } | ||||
335 | data.setValue<QObject*>(commentsModel); | ||||
336 | } | ||||
337 | break; | ||||
306 | default: | 338 | default: | ||
307 | data.setValue<QString>(QStringLiteral("Unknown role")); | 339 | data.setValue<QString>(QStringLiteral("Unknown role")); | ||
308 | break; | 340 | break; | ||
309 | } | 341 | } | ||
310 | } | 342 | } | ||
311 | return data; | 343 | return data; | ||
312 | } | 344 | } | ||
313 | 345 | | |||
314 | bool ItemsModel::canFetchMore(const QModelIndex& parent) const | 346 | bool ItemsModel::canFetchMore(const QModelIndex &parent) const | ||
315 | { | 347 | { | ||
316 | if(parent.isValid()) { | 348 | if (!parent.isValid() && d->coreEngine && d->coreEngine->categoriesMetadata().count() > 0) { | ||
317 | return false; | | |||
318 | } | | |||
319 | return true; | 349 | return true; | ||
320 | } | 350 | } | ||
351 | return false; | ||||
352 | } | ||||
321 | 353 | | |||
322 | void ItemsModel::fetchMore(const QModelIndex& parent) | 354 | void ItemsModel::fetchMore(const QModelIndex &parent) | ||
323 | { | 355 | { | ||
324 | if(parent.isValid()) { | 356 | if (parent.isValid() || !d->coreEngine) { | ||
325 | return; | 357 | return; | ||
326 | } | 358 | } | ||
327 | d->engine->requestMoreData(); | 359 | d->coreEngine->requestMoreData(); | ||
328 | } | 360 | } | ||
329 | 361 | | |||
330 | QObject * ItemsModel::engine() const | 362 | QObject *ItemsModel::engine() const | ||
331 | { | 363 | { | ||
332 | return d->engine; | 364 | return d->engine; | ||
333 | } | 365 | } | ||
334 | 366 | | |||
335 | void ItemsModel::setEngine(QObject* newEngine) | 367 | void ItemsModel::setEngine(QObject *newEngine) | ||
336 | { | 368 | { | ||
369 | if (d->engine != newEngine) { | ||||
337 | beginResetModel(); | 370 | beginResetModel(); | ||
338 | Engine* test = qobject_cast<Engine*>(newEngine); | 371 | d->engine = qobject_cast<Engine*>(newEngine); | ||
339 | if(test) { | 372 | d->model->deleteLater(); | ||
340 | d->engine = qobject_cast<KNSCore::Engine*>(test->engine()); | 373 | d->model = nullptr; | ||
341 | } | 374 | d->coreEngine = nullptr; | ||
342 | else { | 375 | if (d->engine) { | ||
343 | d->engine = qobject_cast<KNSCore::Engine*>(newEngine); | 376 | d->coreEngine = qobject_cast<KNSCore::Engine*>(d->engine->engine()); | ||
344 | } | 377 | } | ||
378 | connect(d->engine, &Engine::engineChanged, this, [this](){ | ||||
379 | beginResetModel(); | ||||
380 | d->model->deleteLater(); | ||||
381 | d->model = nullptr; | ||||
382 | d->coreEngine = qobject_cast<KNSCore::Engine*>(d->engine->engine()); | ||||
383 | endResetModel(); | ||||
384 | }); | ||||
345 | emit engineChanged(); | 385 | emit engineChanged(); | ||
346 | endResetModel(); | 386 | endResetModel(); | ||
347 | } | 387 | } | ||
388 | } | ||||
348 | 389 | | |||
349 | void ItemsModel::installItem(int index) | 390 | void ItemsModel::installItem(int index, int linkId) | ||
350 | { | 391 | { | ||
351 | if(d->engine) { | 392 | if (d->coreEngine) { | ||
352 | KNSCore::EntryInternal entry = d->model->data(d->model->index(index), Qt::UserRole).value<KNSCore::EntryInternal>(); | 393 | KNSCore::EntryInternal entry = d->model->data(d->model->index(index), Qt::UserRole).value<KNSCore::EntryInternal>(); | ||
353 | if(entry.isValid()) { | 394 | if(entry.isValid()) { | ||
354 | d->engine->install(entry); | 395 | d->coreEngine->install(entry, linkId); | ||
355 | } | 396 | } | ||
356 | } | 397 | } | ||
357 | } | 398 | } | ||
358 | 399 | | |||
359 | void ItemsModel::uninstallItem(int index) | 400 | void ItemsModel::uninstallItem(int index) | ||
360 | { | 401 | { | ||
361 | if(d->engine) { | 402 | if (d->coreEngine) { | ||
403 | KNSCore::EntryInternal entry = d->model->data(d->model->index(index), Qt::UserRole).value<KNSCore::EntryInternal>(); | ||||
404 | if(entry.isValid()) { | ||||
405 | d->coreEngine->uninstall(entry); | ||||
406 | } | ||||
407 | } | ||||
408 | } | ||||
409 | | ||||
410 | void ItemsModel::adoptItem(int index) | ||||
411 | { | ||||
412 | if (d->coreEngine) { | ||||
362 | KNSCore::EntryInternal entry = d->model->data(d->model->index(index), Qt::UserRole).value<KNSCore::EntryInternal>(); | 413 | KNSCore::EntryInternal entry = d->model->data(d->model->index(index), Qt::UserRole).value<KNSCore::EntryInternal>(); | ||
363 | if(entry.isValid()) { | 414 | if (entry.isValid()) { | ||
364 | d->engine->uninstall(entry); | 415 | QStringList args = KShell::splitArgs(d->coreEngine->adoptionCommand(entry)); | ||
416 | qCDebug(KNEWSTUFFQUICK) << "executing AdoptionCommand" << args; | ||||
417 | QProcess::startDetached(args.takeFirst(), args); | ||||
418 | d->engine->idleMessage(i18n("Using %1").arg(entry.name())); | ||||
365 | } | 419 | } | ||
366 | } | 420 | } | ||
367 | } | 421 | } |