1/*
2 SPDX-FileCopyrightText: 2019 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 "commentsmodel.h"
8
9#include "entry.h"
10#include "knewstuffcore_debug.h"
11
12#include <KLocalizedString>
13
14#include <QTimer>
15
16namespace KNSCore
17{
18class CommentsModelPrivate
19{
20public:
21 CommentsModelPrivate(CommentsModel *qq)
22 : q(qq)
23 {
24 }
25 CommentsModel *const q;
26 EngineBase *engine = nullptr;
27
28 Entry entry;
29
30 QList<std::shared_ptr<KNSCore::Comment>> comments;
31
32 enum FetchOptions {
33 NoOption,
34 ClearModel,
35 };
36 bool fetchThrottle = false;
37 void fetch(FetchOptions option = NoOption)
38 {
39 if (fetchThrottle) {
40 return;
41 }
42 fetchThrottle = true;
43 QTimer::singleShot(interval: 1, receiver: q, slot: [this]() {
44 fetchThrottle = false;
45 });
46 // Sanity checks, because we need a few things to be correct before we can actually fetch comments...
47 if (!engine) {
48 qCWarning(KNEWSTUFFCORE) << "CommentsModel must be parented on a KNSCore::EngineBase instance to be able to fetch comments";
49 }
50 if (!entry.isValid()) {
51 qCWarning(KNEWSTUFFCORE) << "Without an entry to fetch comments for, CommentsModel cannot fetch comments for it";
52 }
53
54 if (engine && entry.isValid()) {
55 QSharedPointer<Provider> provider = engine->provider(providerId: entry.providerId());
56 if (option == ClearModel) {
57 q->beginResetModel();
58 comments.clear();
59 provider->disconnect(receiver: q);
60 q->connect(sender: provider.data(), signal: &Provider::commentsLoaded, context: q, slot: [=](const QList<std::shared_ptr<KNSCore::Comment>> &newComments) {
61 QList<std::shared_ptr<KNSCore::Comment>> actualNewComments;
62 for (const std::shared_ptr<KNSCore::Comment> &comment : newComments) {
63 bool commentIsKnown = false;
64 for (const std::shared_ptr<KNSCore::Comment> &existingComment : std::as_const(t&: comments)) {
65 if (existingComment->id == comment->id) {
66 commentIsKnown = true;
67 break;
68 }
69 }
70 if (commentIsKnown) {
71 continue;
72 }
73 actualNewComments << comment;
74 }
75 if (actualNewComments.count() > 0) {
76 q->beginInsertRows(parent: QModelIndex(), first: comments.count(), last: comments.count() + actualNewComments.count() - 1);
77 qCDebug(KNEWSTUFFCORE) << "Appending" << actualNewComments.count() << "new comments";
78 comments.append(l: actualNewComments);
79 q->endInsertRows();
80 }
81 });
82 q->endResetModel();
83 }
84 int commentsPerPage = 100;
85 int pageToLoad = comments.count() / commentsPerPage;
86 qCDebug(KNEWSTUFFCORE) << "Loading comments, page" << pageToLoad << "with current comment count" << comments.count() << "out of a total of"
87 << entry.numberOfComments();
88 provider->loadComments(entry, commentsPerPage, pageToLoad);
89 }
90 }
91};
92}
93
94KNSCore::CommentsModel::CommentsModel(EngineBase *parent)
95 : QAbstractListModel(parent)
96 , d(new CommentsModelPrivate(this))
97{
98 d->engine = parent;
99}
100
101KNSCore::CommentsModel::~CommentsModel() = default;
102
103QHash<int, QByteArray> KNSCore::CommentsModel::roleNames() const
104{
105 static const QHash<int, QByteArray> roles{
106 {IdRole, "id"},
107 {SubjectRole, "subject"},
108 {TextRole, "text"},
109 {ChildCountRole, "childCound"},
110 {UsernameRole, "username"},
111 {DateRole, "date"},
112 {ScoreRole, "score"},
113 {ParentIndexRole, "parentIndex"},
114 {DepthRole, "depth"},
115 };
116 return roles;
117}
118
119QVariant KNSCore::CommentsModel::data(const QModelIndex &index, int role) const
120{
121 if (!checkIndex(index)) {
122 return QVariant();
123 }
124 const std::shared_ptr<KNSCore::Comment> comment = d->comments[index.row()];
125 switch (role) {
126 case IdRole:
127 return comment->id;
128 case SubjectRole:
129 return comment->subject;
130 case TextRole:
131 return comment->text;
132 case ChildCountRole:
133 return comment->childCount;
134 case UsernameRole:
135 return comment->username;
136 case DateRole:
137 return comment->date;
138 case ScoreRole:
139 return comment->score;
140 case ParentIndexRole:
141 return comment->parent ? d->comments.indexOf(t: comment->parent) : -1;
142 case DepthRole: {
143 int depth{0};
144 if (comment->parent) {
145 std::shared_ptr<KNSCore::Comment> child = comment->parent;
146 while (child) {
147 ++depth;
148 child = child->parent;
149 }
150 }
151 return depth;
152 }
153 default:
154 return i18nc("The value returned for an unknown role when requesting data from the model.", "Unknown CommentsModel role");
155 }
156}
157
158int KNSCore::CommentsModel::rowCount(const QModelIndex &parent) const
159{
160 if (parent.isValid()) {
161 return 0;
162 }
163 return d->comments.count();
164}
165
166bool KNSCore::CommentsModel::canFetchMore(const QModelIndex &parent) const
167{
168 if (parent.isValid()) {
169 return false;
170 }
171 if (d->entry.numberOfComments() > d->comments.count()) {
172 return true;
173 }
174 return false;
175}
176
177void KNSCore::CommentsModel::fetchMore(const QModelIndex &parent)
178{
179 if (parent.isValid()) {
180 return;
181 }
182 d->fetch();
183}
184
185const KNSCore::Entry &KNSCore::CommentsModel::entry() const
186{
187 return d->entry;
188}
189
190void KNSCore::CommentsModel::setEntry(const KNSCore::Entry &newEntry)
191{
192 d->entry = newEntry;
193 d->fetch(option: CommentsModelPrivate::ClearModel);
194 Q_EMIT entryChanged();
195}
196
197#include "moc_commentsmodel.cpp"
198

source code of knewstuff/src/core/commentsmodel.cpp