File indexing completed on 2024-04-21 11:34:52

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 "entryinternal.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     Engine *engine = nullptr;
0027 
0028     EntryInternal 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::Engine 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             Q_EMIT provider->loadComments(entry, commentsPerPage, pageToLoad);
0089         }
0090     }
0091 };
0092 }
0093 
0094 KNSCore::CommentsModel::CommentsModel(Engine *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     // clang-format off
0106     static const QHash<int, QByteArray> roles{
0107         {IdRole, "id"},
0108         {SubjectRole, "subject"},
0109         {TextRole, "text"},
0110         {ChildCountRole, "childCound"},
0111         {UsernameRole, "username"},
0112         {DateRole, "date"},
0113         {ScoreRole, "score"},
0114         {ParentIndexRole, "parentIndex"},
0115         {DepthRole, "depth"}
0116     };
0117     // clang-format on
0118     return roles;
0119 }
0120 
0121 QVariant KNSCore::CommentsModel::data(const QModelIndex &index, int role) const
0122 {
0123     QVariant value;
0124     if (checkIndex(index)) {
0125         std::shared_ptr<KNSCore::Comment> comment = d->comments[index.row()];
0126         switch (role) {
0127         case IdRole:
0128             value.setValue(comment->id);
0129             break;
0130         case SubjectRole:
0131             value.setValue(comment->subject);
0132             break;
0133         case TextRole:
0134             value.setValue(comment->text);
0135             break;
0136         case ChildCountRole:
0137             value.setValue(comment->childCount);
0138             break;
0139         case UsernameRole:
0140             value.setValue(comment->username);
0141             break;
0142         case DateRole:
0143             value.setValue(comment->date);
0144             break;
0145         case ScoreRole:
0146             value.setValue(comment->score);
0147             break;
0148         case ParentIndexRole: {
0149             int idx{-1};
0150             if (comment->parent) {
0151                 idx = d->comments.indexOf(comment->parent);
0152             }
0153             value.setValue(idx);
0154         } break;
0155         case DepthRole: {
0156             int depth{0};
0157             if (comment->parent) {
0158                 std::shared_ptr<KNSCore::Comment> child = comment->parent;
0159                 while (child) {
0160                     ++depth;
0161                     child = child->parent;
0162                 }
0163             }
0164             value.setValue(depth);
0165             break;
0166         }
0167         default:
0168             value.setValue(i18nc("The value returned for an unknown role when requesting data from the model.", "Unknown CommentsModel role"));
0169             break;
0170         }
0171     }
0172     return value;
0173 }
0174 
0175 int KNSCore::CommentsModel::rowCount(const QModelIndex &parent) const
0176 {
0177     if (parent.isValid()) {
0178         return 0;
0179     }
0180     return d->comments.count();
0181 }
0182 
0183 bool KNSCore::CommentsModel::canFetchMore(const QModelIndex &parent) const
0184 {
0185     if (parent.isValid()) {
0186         return false;
0187     }
0188     if (d->entry.numberOfComments() > d->comments.count()) {
0189         return true;
0190     }
0191     return false;
0192 }
0193 
0194 void KNSCore::CommentsModel::fetchMore(const QModelIndex &parent)
0195 {
0196     if (parent.isValid()) {
0197         return;
0198     }
0199     d->fetch();
0200 }
0201 
0202 const KNSCore::EntryInternal &KNSCore::CommentsModel::entry() const
0203 {
0204     return d->entry;
0205 }
0206 
0207 void KNSCore::CommentsModel::setEntry(const KNSCore::EntryInternal &newEntry)
0208 {
0209     d->entry = newEntry;
0210     d->fetch(CommentsModelPrivate::ClearModel);
0211     Q_EMIT entryChanged();
0212 }
0213 
0214 #include "moc_commentsmodel.cpp"