File indexing completed on 2024-03-24 03:59:12
0001 /* 0002 SPDX-FileCopyrightText: 2019 Dan Leinir Turthra Jensen <admin@leinir.dk> 0003 0004 SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL 0005 */ 0006 0007 #include "commentsmodel.h" 0008 0009 #include "entry.h" 0010 #include "knewstuffcore_debug.h" 0011 0012 #include <KLocalizedString> 0013 0014 #include <QTimer> 0015 0016 namespace KNSCore 0017 { 0018 class CommentsModelPrivate 0019 { 0020 public: 0021 CommentsModelPrivate(CommentsModel *qq) 0022 : q(qq) 0023 { 0024 } 0025 CommentsModel *const q; 0026 EngineBase *engine = nullptr; 0027 0028 Entry entry; 0029 0030 QList<std::shared_ptr<KNSCore::Comment>> comments; 0031 0032 enum FetchOptions { 0033 NoOption, 0034 ClearModel, 0035 }; 0036 bool fetchThrottle = false; 0037 void fetch(FetchOptions option = NoOption) 0038 { 0039 if (fetchThrottle) { 0040 return; 0041 } 0042 fetchThrottle = true; 0043 QTimer::singleShot(1, q, [this]() { 0044 fetchThrottle = false; 0045 }); 0046 // Sanity checks, because we need a few things to be correct before we can actually fetch comments... 0047 if (!engine) { 0048 qCWarning(KNEWSTUFFCORE) << "CommentsModel must be parented on a KNSCore::EngineBase instance to be able to fetch comments"; 0049 } 0050 if (!entry.isValid()) { 0051 qCWarning(KNEWSTUFFCORE) << "Without an entry to fetch comments for, CommentsModel cannot fetch comments for it"; 0052 } 0053 0054 if (engine && entry.isValid()) { 0055 QSharedPointer<Provider> provider = engine->provider(entry.providerId()); 0056 if (option == ClearModel) { 0057 q->beginResetModel(); 0058 comments.clear(); 0059 provider->disconnect(q); 0060 q->connect(provider.data(), &Provider::commentsLoaded, q, [=](const QList<std::shared_ptr<KNSCore::Comment>> &newComments) { 0061 QList<std::shared_ptr<KNSCore::Comment>> actualNewComments; 0062 for (const std::shared_ptr<KNSCore::Comment> &comment : newComments) { 0063 bool commentIsKnown = false; 0064 for (const std::shared_ptr<KNSCore::Comment> &existingComment : std::as_const(comments)) { 0065 if (existingComment->id == comment->id) { 0066 commentIsKnown = true; 0067 break; 0068 } 0069 } 0070 if (commentIsKnown) { 0071 continue; 0072 } 0073 actualNewComments << comment; 0074 } 0075 if (actualNewComments.count() > 0) { 0076 q->beginInsertRows(QModelIndex(), comments.count(), comments.count() + actualNewComments.count() - 1); 0077 qCDebug(KNEWSTUFFCORE) << "Appending" << actualNewComments.count() << "new comments"; 0078 comments.append(actualNewComments); 0079 q->endInsertRows(); 0080 } 0081 }); 0082 q->endResetModel(); 0083 } 0084 int commentsPerPage = 100; 0085 int pageToLoad = comments.count() / commentsPerPage; 0086 qCDebug(KNEWSTUFFCORE) << "Loading comments, page" << pageToLoad << "with current comment count" << comments.count() << "out of a total of" 0087 << entry.numberOfComments(); 0088 provider->loadComments(entry, commentsPerPage, pageToLoad); 0089 } 0090 } 0091 }; 0092 } 0093 0094 KNSCore::CommentsModel::CommentsModel(EngineBase *parent) 0095 : QAbstractListModel(parent) 0096 , d(new CommentsModelPrivate(this)) 0097 { 0098 d->engine = parent; 0099 } 0100 0101 KNSCore::CommentsModel::~CommentsModel() = default; 0102 0103 QHash<int, QByteArray> KNSCore::CommentsModel::roleNames() const 0104 { 0105 static const QHash<int, QByteArray> roles{ 0106 {IdRole, "id"}, 0107 {SubjectRole, "subject"}, 0108 {TextRole, "text"}, 0109 {ChildCountRole, "childCound"}, 0110 {UsernameRole, "username"}, 0111 {DateRole, "date"}, 0112 {ScoreRole, "score"}, 0113 {ParentIndexRole, "parentIndex"}, 0114 {DepthRole, "depth"}, 0115 }; 0116 return roles; 0117 } 0118 0119 QVariant KNSCore::CommentsModel::data(const QModelIndex &index, int role) const 0120 { 0121 if (!checkIndex(index)) { 0122 return QVariant(); 0123 } 0124 const std::shared_ptr<KNSCore::Comment> comment = d->comments[index.row()]; 0125 switch (role) { 0126 case IdRole: 0127 return comment->id; 0128 case SubjectRole: 0129 return comment->subject; 0130 case TextRole: 0131 return comment->text; 0132 case ChildCountRole: 0133 return comment->childCount; 0134 case UsernameRole: 0135 return comment->username; 0136 case DateRole: 0137 return comment->date; 0138 case ScoreRole: 0139 return comment->score; 0140 case ParentIndexRole: 0141 return comment->parent ? d->comments.indexOf(comment->parent) : -1; 0142 case DepthRole: { 0143 int depth{0}; 0144 if (comment->parent) { 0145 std::shared_ptr<KNSCore::Comment> child = comment->parent; 0146 while (child) { 0147 ++depth; 0148 child = child->parent; 0149 } 0150 } 0151 return depth; 0152 } 0153 default: 0154 return i18nc("The value returned for an unknown role when requesting data from the model.", "Unknown CommentsModel role"); 0155 } 0156 } 0157 0158 int KNSCore::CommentsModel::rowCount(const QModelIndex &parent) const 0159 { 0160 if (parent.isValid()) { 0161 return 0; 0162 } 0163 return d->comments.count(); 0164 } 0165 0166 bool KNSCore::CommentsModel::canFetchMore(const QModelIndex &parent) const 0167 { 0168 if (parent.isValid()) { 0169 return false; 0170 } 0171 if (d->entry.numberOfComments() > d->comments.count()) { 0172 return true; 0173 } 0174 return false; 0175 } 0176 0177 void KNSCore::CommentsModel::fetchMore(const QModelIndex &parent) 0178 { 0179 if (parent.isValid()) { 0180 return; 0181 } 0182 d->fetch(); 0183 } 0184 0185 const KNSCore::Entry &KNSCore::CommentsModel::entry() const 0186 { 0187 return d->entry; 0188 } 0189 0190 void KNSCore::CommentsModel::setEntry(const KNSCore::Entry &newEntry) 0191 { 0192 d->entry = newEntry; 0193 d->fetch(CommentsModelPrivate::ClearModel); 0194 Q_EMIT entryChanged(); 0195 } 0196 0197 #include "moc_commentsmodel.cpp"