File indexing completed on 2024-05-12 16:01:52

0001 /**************************************************************************
0002 **
0003 ** This file is part of Qt Creator
0004 **
0005 ** SPDX-FileCopyrightText: 2011 Nokia Corporation and /or its subsidiary(-ies).
0006 **
0007 ** Contact: Nokia Corporation (qt-info@nokia.com)
0008 **
0009 **
0010 ** SPDX-License-Identifier: LGPL-2.1-only
0011 **
0012 ** In addition, as a special exception, Nokia gives you certain additional
0013 ** rights. These rights are described in the Nokia Qt LGPL Exception
0014 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
0015 **
0016 ** Other Usage
0017 **
0018 ** Alternatively, this file may be used in accordance with the terms and
0019 ** conditions contained in a signed written agreement between you and Nokia.
0020 **
0021 ** If you have questions regarding the use of this file, please contact
0022 ** Nokia at qt-info@nokia.com.
0023 **
0024 **************************************************************************/
0025 
0026 #include "KisMultiFeedRSSModel.h"
0027 
0028 #include <QTimer>
0029 #include <QThread>
0030 #include <QXmlStreamReader>
0031 #include <QCoreApplication>
0032 #include <QLocale>
0033 #include <QFile>
0034 #include <QTextBlock>
0035 #include <QTextDocument>
0036 
0037 #include <QNetworkRequest>
0038 #include <QNetworkReply>
0039 #include <KisNetworkAccessManager.h>
0040 
0041 #include <KisRssReader.h>
0042 
0043 MultiFeedRssModel::MultiFeedRssModel(QObject *parent) :
0044     QAbstractListModel(parent),
0045     m_networkAccessManager(new KisNetworkAccessManager),
0046     m_articleCount(0)
0047 {
0048     initialize();
0049 }
0050 
0051 MultiFeedRssModel::MultiFeedRssModel(KisNetworkAccessManager* nam, QObject* parent)
0052     : QAbstractListModel(parent),
0053       m_networkAccessManager(nam),
0054       m_articleCount(0)
0055 {
0056     initialize();
0057 }
0058 
0059 
0060 MultiFeedRssModel::~MultiFeedRssModel()
0061 {
0062     delete m_networkAccessManager;
0063 }
0064 
0065 QHash<int, QByteArray> MultiFeedRssModel::roleNames() const
0066 {
0067     QHash<int, QByteArray> roleNames;
0068     roleNames[KisRssReader::RssRoles::TitleRole] = "title";
0069     roleNames[KisRssReader::RssRoles::DescriptionRole] = "description";
0070     roleNames[KisRssReader::RssRoles::PubDateRole] = "pubDate";
0071     roleNames[KisRssReader::RssRoles::LinkRole] = "link";
0072     roleNames[KisRssReader::RssRoles::CategoryRole] = "category";
0073     roleNames[KisRssReader::RssRoles::BlogNameRole] = "blogName";
0074     roleNames[KisRssReader::RssRoles::BlogIconRole] = "blogIcon";
0075     return roleNames;
0076 }
0077 
0078 void MultiFeedRssModel::addFeed(const QString& feed)
0079 {
0080     if (m_sites.contains(feed)) {
0081         // do not add the feed twice
0082         return;
0083     }
0084 
0085     m_sites << feed;
0086     const QUrl feedUrl(feed);
0087     m_networkAccessManager->getUrl(feedUrl);
0088 }
0089 
0090 bool sortForPubDate(const RssItem& item1, const RssItem& item2)
0091 {
0092     return item1.pubDate > item2.pubDate;
0093 }
0094 
0095 void MultiFeedRssModel::appendFeedData(QNetworkReply *reply)
0096 {
0097     beginResetModel();
0098     KisRssReader reader;
0099     m_aggregatedFeed.append(reader.parse(reply));
0100     sortAggregatedFeed();
0101     setArticleCount(m_aggregatedFeed.size());
0102     endResetModel();
0103 
0104     emit feedDataChanged();
0105 }
0106 
0107 void MultiFeedRssModel::sortAggregatedFeed()
0108 {
0109     std::sort(m_aggregatedFeed.begin(), m_aggregatedFeed.end(), sortForPubDate);
0110 }
0111 
0112 void MultiFeedRssModel::initialize()
0113 {
0114     connect(m_networkAccessManager, SIGNAL(finished(QNetworkReply*)),
0115             SLOT(appendFeedData(QNetworkReply*)), Qt::QueuedConnection);
0116 }
0117 
0118 void MultiFeedRssModel::removeFeed(const QString &feed)
0119 {
0120     bool isRemoved = m_sites.removeOne(feed);
0121     if (isRemoved) {
0122         beginResetModel();
0123         QMutableListIterator<RssItem> it(m_aggregatedFeed);
0124         while (it.hasNext()) {
0125             RssItem item = it.next();
0126             if (item.source == feed)
0127                 it.remove();
0128         }
0129         setArticleCount(m_aggregatedFeed.size());
0130         endResetModel();
0131 
0132         emit feedDataChanged();
0133     }
0134 }
0135 
0136 int MultiFeedRssModel::rowCount(const QModelIndex &) const
0137 {
0138     return m_aggregatedFeed.size();
0139 }
0140 
0141 QVariant MultiFeedRssModel::data(const QModelIndex &index, int role) const
0142 {
0143 
0144     RssItem item = m_aggregatedFeed.at(index.row());
0145 
0146     switch (role) {
0147     case Qt::DisplayRole:
0148     {
0149         QTextDocument doc;
0150         doc.setHtml(item.description);
0151         // Extract the first text block, which is the `<p>` element containing
0152         // the shortened post text, excluding the "This post [...] appeared
0153         // first on [...]" text.
0154         QString text = doc.firstBlock().text();
0155         if (text.length() > 92) {
0156             text.truncate(90);
0157             text.append("...");
0158         }
0159         return QString("<b><a href=\"" + item.link + "\">" + item.title + "</a></b>"
0160                "<br><small>(" + item.pubDate.toLocalTime().toString(Qt::DefaultLocaleShortDate) + ") "
0161                "<p style=\"margin-top: 4px\">" + text + "</p></small>");
0162     }
0163     case KisRssReader::RssRoles::TitleRole:
0164         return item.title;
0165     case KisRssReader::RssRoles::DescriptionRole:
0166         return item.description;
0167     case KisRssReader::RssRoles::PubDateRole:
0168         return item.pubDate.toString("dd-MM-yyyy hh:mm");
0169     case KisRssReader::RssRoles::LinkRole:
0170         return item.link;
0171     case KisRssReader::RssRoles::CategoryRole:
0172         return item.category;
0173     case KisRssReader::RssRoles::BlogNameRole:
0174         return item.blogName;
0175     case KisRssReader::RssRoles::BlogIconRole:
0176         return item.blogIcon;
0177     }
0178 
0179     return QVariant();
0180 }