KNewStuff

core/commentsmodel.cpp
1 /*
2  SPDX-FileCopyrightText: 2019 Dan Leinir Turthra Jensen <[email protected]>
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 "entryinternal.h"
10 #include "knewstuffcore_debug.h"
11 
12 #include <KLocalizedString>
13 
14 #include <QTimer>
15 
16 namespace KNSCore
17 {
18 class CommentsModel::Private
19 {
20 public:
21  Private(CommentsModel *qq)
22  : q(qq)
23  {
24  }
25  CommentsModel *const q;
26  Engine *engine = nullptr;
27 
28  EntryInternal entry;
29 
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(1, q, [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::Engine 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(entry.providerId());
56  if (option == ClearModel) {
57  q->beginResetModel();
58  comments.clear();
59  provider->disconnect(q);
60  q->connect(provider.data(), &Provider::commentsLoaded, q, [=](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 : qAsConst(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(QModelIndex(), comments.count(), comments.count() + actualNewComments.count() - 1);
77  qCDebug(KNEWSTUFFCORE) << "Appending" << actualNewComments.count() << "new comments";
78  comments.append(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  Q_EMIT provider->loadComments(entry, commentsPerPage, pageToLoad);
89  }
90  }
91 };
92 }
93 
95  : QAbstractListModel(parent)
96  , d(new Private(this))
97 {
98  d->engine = parent;
99 }
100 
101 KNSCore::CommentsModel::~CommentsModel()
102 {
103  delete d;
104 }
105 
106 QHash<int, QByteArray> KNSCore::CommentsModel::roleNames() const
107 {
108  // clang-format off
109  static const QHash<int, QByteArray> roles{
110  {IdRole, "id"},
111  {SubjectRole, "subject"},
112  {TextRole, "text"},
113  {ChildCountRole, "childCound"},
114  {UsernameRole, "username"},
115  {DateRole, "date"},
116  {ScoreRole, "score"},
117  {ParentIndexRole, "parentIndex"},
118  {DepthRole, "depth"}
119  };
120  // clang-format on
121  return roles;
122 }
123 
124 QVariant KNSCore::CommentsModel::data(const QModelIndex &index, int role) const
125 {
126  QVariant value;
127  if (checkIndex(index)) {
128  std::shared_ptr<KNSCore::Comment> comment = d->comments[index.row()];
129  switch (role) {
130  case IdRole:
131  value.setValue(comment->id);
132  break;
133  case SubjectRole:
134  value.setValue(comment->subject);
135  break;
136  case TextRole:
137  value.setValue(comment->text);
138  break;
139  case ChildCountRole:
140  value.setValue(comment->childCount);
141  break;
142  case UsernameRole:
143  value.setValue(comment->username);
144  break;
145  case DateRole:
146  value.setValue(comment->date);
147  break;
148  case ScoreRole:
149  value.setValue(comment->score);
150  break;
151  case ParentIndexRole: {
152  int idx{-1};
153  if (comment->parent) {
154  idx = d->comments.indexOf(comment->parent);
155  }
156  value.setValue(idx);
157  } break;
158  case DepthRole: {
159  int depth{0};
160  if (comment->parent) {
161  std::shared_ptr<KNSCore::Comment> child = comment->parent;
162  while (child) {
163  ++depth;
164  child = child->parent;
165  }
166  }
167  value.setValue(depth);
168  break;
169  }
170  default:
171  value.setValue(i18nc("The value returned for an unknown role when requesting data from the model.", "Unknown CommentsModel role"));
172  break;
173  }
174  }
175  return value;
176 }
177 
178 int KNSCore::CommentsModel::rowCount(const QModelIndex &parent) const
179 {
180  if (parent.isValid())
181  return 0;
182  return d->comments.count();
183 }
184 
185 bool KNSCore::CommentsModel::canFetchMore(const QModelIndex &parent) const
186 {
187  if (parent.isValid())
188  return false;
189  if (d->entry.numberOfComments() > d->comments.count())
190  return true;
191  return false;
192 }
193 
194 void KNSCore::CommentsModel::fetchMore(const QModelIndex &parent)
195 {
196  if (parent.isValid())
197  return;
198  d->fetch();
199 }
200 
202 {
203  return d->entry;
204 }
205 
206 void KNSCore::CommentsModel::setEntry(const KNSCore::EntryInternal &newEntry)
207 {
208  d->entry = newEntry;
209  d->fetch(Private::ClearModel);
210  Q_EMIT entryChanged();
211 }
void clear()
bool checkIndex(const QModelIndex &index, QAbstractItemModel::CheckIndexOptions options) const const
CommentsModel(Engine *parent=nullptr)
Construct a new CommentsModel instance.
Contains the core functionality for handling interaction with NewStuff providers. ...
Encapsulates a KNSCore::Engine for use in Qt Quick.
Definition: quickengine.h:24
T * data() const const
KNSCore::EntryInternal entry
The Entry for which this model should handle comments.
bool isValid() const const
int count(const T &value) const const
void append(const T &value)
QString i18nc(const char *context, const char *text, const TYPE &arg...)
virtual QModelIndex index(int row, int column, const QModelIndex &parent) const const override
int row() const const
void commentsLoaded(const QList< std::shared_ptr< KNSCore::Comment >> comments)
Fired when new comments have been loaded.
void setValue(const T &value)
KNewStuff data entry container.
Definition: entryinternal.h:49
KNewStuff engine.
Definition: engine.h:59
QObject * parent() const const
Q_EMITQ_EMIT
This file is part of the KDE documentation.
Documentation copyright © 1996-2021 The KDE developers.
Generated on Wed May 12 2021 22:41:39 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.