mirror of
https://github.com/d47081/qBittorrent.git
synced 2025-01-23 13:04:23 +00:00
Redesign RSS base classes.
This commit is contained in:
parent
6f7ae728eb
commit
28ed981082
@ -43,7 +43,7 @@ HEADERS += \
|
|||||||
$$PWD/rss/rssarticle.h \
|
$$PWD/rss/rssarticle.h \
|
||||||
$$PWD/rss/rssdownloadrule.h \
|
$$PWD/rss/rssdownloadrule.h \
|
||||||
$$PWD/rss/rssdownloadrulelist.h \
|
$$PWD/rss/rssdownloadrulelist.h \
|
||||||
$$PWD/rss/rssparser.h \
|
$$PWD/rss/private/rssparser.h \
|
||||||
$$PWD/utils/fs.h \
|
$$PWD/utils/fs.h \
|
||||||
$$PWD/utils/gzip.h \
|
$$PWD/utils/gzip.h \
|
||||||
$$PWD/utils/misc.h \
|
$$PWD/utils/misc.h \
|
||||||
@ -94,7 +94,7 @@ SOURCES += \
|
|||||||
$$PWD/rss/rssdownloadrule.cpp \
|
$$PWD/rss/rssdownloadrule.cpp \
|
||||||
$$PWD/rss/rssdownloadrulelist.cpp \
|
$$PWD/rss/rssdownloadrulelist.cpp \
|
||||||
$$PWD/rss/rssfile.cpp \
|
$$PWD/rss/rssfile.cpp \
|
||||||
$$PWD/rss/rssparser.cpp \
|
$$PWD/rss/private/rssparser.cpp \
|
||||||
$$PWD/utils/fs.cpp \
|
$$PWD/utils/fs.cpp \
|
||||||
$$PWD/utils/gzip.cpp \
|
$$PWD/utils/gzip.cpp \
|
||||||
$$PWD/utils/misc.cpp \
|
$$PWD/utils/misc.cpp \
|
||||||
|
@ -29,22 +29,27 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
|
#include <QDateTime>
|
||||||
#include <QFile>
|
#include <QFile>
|
||||||
#include <QRegExp>
|
#include <QRegExp>
|
||||||
#include <QStringList>
|
#include <QStringList>
|
||||||
#include <QVariant>
|
#include <QVariant>
|
||||||
|
#include <QXmlStreamReader>
|
||||||
|
|
||||||
#include "base/utils/fs.h"
|
#include "base/utils/fs.h"
|
||||||
#include "rssparser.h"
|
#include "rssparser.h"
|
||||||
|
|
||||||
namespace Rss
|
namespace Rss
|
||||||
|
{
|
||||||
|
namespace Private
|
||||||
{
|
{
|
||||||
struct ParsingJob
|
struct ParsingJob
|
||||||
{
|
{
|
||||||
QString feedUrl;
|
QString feedUrl;
|
||||||
QString filePath;
|
QByteArray feedData;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static const char shortDay[][4] = {
|
static const char shortDay[][4] = {
|
||||||
"Mon", "Tue", "Wed",
|
"Mon", "Tue", "Wed",
|
||||||
@ -64,7 +69,7 @@ static const char shortMonth[][4] = {
|
|||||||
"Sep", "Oct", "Nov", "Dec"
|
"Sep", "Oct", "Nov", "Dec"
|
||||||
};
|
};
|
||||||
|
|
||||||
using namespace Rss;
|
using namespace Rss::Private;
|
||||||
|
|
||||||
Parser::Parser(QObject *parent)
|
Parser::Parser(QObject *parent)
|
||||||
: QThread(parent)
|
: QThread(parent)
|
||||||
@ -227,11 +232,11 @@ QDateTime Parser::parseDate(const QString &string)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Parser::parseRssFile(const QString &feedUrl, const QString &filePath)
|
void Parser::parseFeedData(const QString &feedUrl, const QByteArray &feedData)
|
||||||
{
|
{
|
||||||
qDebug() << Q_FUNC_INFO << feedUrl << filePath;
|
qDebug() << Q_FUNC_INFO << feedUrl;
|
||||||
m_mutex.lock();
|
m_mutex.lock();
|
||||||
ParsingJob job = { feedUrl, Utils::Fs::fromNativePath(filePath) };
|
ParsingJob job = { feedUrl, feedData };
|
||||||
m_queue.enqueue(job);
|
m_queue.enqueue(job);
|
||||||
// Wake up thread.
|
// Wake up thread.
|
||||||
if (m_queue.count() == 1) {
|
if (m_queue.count() == 1) {
|
||||||
@ -487,14 +492,9 @@ void Parser::parseAtomChannel(QXmlStreamReader &xml, const QString &feedUrl)
|
|||||||
// read and create items from a rss document
|
// read and create items from a rss document
|
||||||
void Parser::parseFeed(const ParsingJob &job)
|
void Parser::parseFeed(const ParsingJob &job)
|
||||||
{
|
{
|
||||||
qDebug() << Q_FUNC_INFO << job.feedUrl << job.filePath;
|
qDebug() << Q_FUNC_INFO << job.feedUrl;
|
||||||
QFile fileRss(job.filePath);
|
|
||||||
if (!fileRss.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
|
||||||
reportFailure(job, tr("Failed to open downloaded RSS file."));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
QXmlStreamReader xml(&fileRss);
|
QXmlStreamReader xml(job.feedData);
|
||||||
bool foundChannel = false;
|
bool foundChannel = false;
|
||||||
while (xml.readNextStartElement()) {
|
while (xml.readNextStartElement()) {
|
||||||
if (xml.name() == "rss") {
|
if (xml.name() == "rss") {
|
||||||
@ -533,14 +533,10 @@ void Parser::parseFeed(const ParsingJob &job)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clean up
|
|
||||||
fileRss.close();
|
|
||||||
emit feedParsingFinished(job.feedUrl, QString());
|
emit feedParsingFinished(job.feedUrl, QString());
|
||||||
Utils::Fs::forceRemove(job.filePath);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Parser::reportFailure(const ParsingJob &job, const QString &error)
|
void Parser::reportFailure(const ParsingJob &job, const QString &error)
|
||||||
{
|
{
|
||||||
emit feedParsingFinished(job.feedUrl, error);
|
emit feedParsingFinished(job.feedUrl, error);
|
||||||
Utils::Fs::forceRemove(job.filePath);
|
|
||||||
}
|
}
|
@ -31,14 +31,18 @@
|
|||||||
#ifndef RSSPARSER_H
|
#ifndef RSSPARSER_H
|
||||||
#define RSSPARSER_H
|
#define RSSPARSER_H
|
||||||
|
|
||||||
|
#include <QHash>
|
||||||
#include <QMutex>
|
#include <QMutex>
|
||||||
#include <QQueue>
|
#include <QQueue>
|
||||||
#include <QThread>
|
#include <QThread>
|
||||||
|
#include <QVariantHash>
|
||||||
#include <QWaitCondition>
|
#include <QWaitCondition>
|
||||||
|
|
||||||
#include "rssarticle.h"
|
class QXmlStreamReader;
|
||||||
|
|
||||||
namespace Rss
|
namespace Rss
|
||||||
|
{
|
||||||
|
namespace Private
|
||||||
{
|
{
|
||||||
struct ParsingJob;
|
struct ParsingJob;
|
||||||
|
|
||||||
@ -48,22 +52,21 @@ namespace Rss
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
explicit Parser(QObject *parent = 0);
|
explicit Parser(QObject *parent = 0);
|
||||||
virtual ~Parser();
|
~Parser();
|
||||||
|
|
||||||
|
void parseFeedData(const QString &feedUrl, const QByteArray &feedData);
|
||||||
|
void clearFeedData(const QString &feedUrl);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void newArticle(const QString &feedUrl, const QVariantHash &rssArticle);
|
void newArticle(const QString &feedUrl, const QVariantHash &rssArticle);
|
||||||
void feedTitle(const QString &feedUrl, const QString &title);
|
void feedTitle(const QString &feedUrl, const QString &title);
|
||||||
void feedParsingFinished(const QString &feedUrl, const QString &error);
|
void feedParsingFinished(const QString &feedUrl, const QString &error);
|
||||||
|
|
||||||
public slots:
|
|
||||||
void parseRssFile(const QString &feedUrl, const QString &filePath);
|
|
||||||
void clearFeedData(const QString &feedUrl);
|
|
||||||
|
|
||||||
protected:
|
|
||||||
virtual void run();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void run() override;
|
||||||
|
|
||||||
static QDateTime parseDate(const QString &string);
|
static QDateTime parseDate(const QString &string);
|
||||||
|
|
||||||
void parseRssArticle(QXmlStreamReader &xml, const QString &feedUrl);
|
void parseRssArticle(QXmlStreamReader &xml, const QString &feedUrl);
|
||||||
void parseRSSChannel(QXmlStreamReader &xml, const QString &feedUrl);
|
void parseRSSChannel(QXmlStreamReader &xml, const QString &feedUrl);
|
||||||
void parseAtomArticle(QXmlStreamReader &xml, const QString &feedUrl, const QString &baseUrl);
|
void parseAtomArticle(QXmlStreamReader &xml, const QString &feedUrl, const QString &baseUrl);
|
||||||
@ -78,5 +81,6 @@ namespace Rss
|
|||||||
QHash<QString/*feedUrl*/, QString/*lastBuildDate*/> m_lastBuildDates; // Optimization
|
QHash<QString/*feedUrl*/, QString/*lastBuildDate*/> m_lastBuildDates; // Optimization
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#endif // RSSPARSER_H
|
#endif // RSSPARSER_H
|
@ -120,13 +120,11 @@ bool Article::isRead() const
|
|||||||
|
|
||||||
void Article::markAsRead()
|
void Article::markAsRead()
|
||||||
{
|
{
|
||||||
if (m_read) return;
|
if (!m_read) {
|
||||||
|
|
||||||
m_read = true;
|
m_read = true;
|
||||||
m_parent->decrementUnreadCount();
|
|
||||||
m_parent->markAsDirty();
|
|
||||||
emit articleWasRead();
|
emit articleWasRead();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const QString &Article::guid() const
|
const QString &Article::guid() const
|
||||||
{
|
{
|
||||||
|
@ -32,7 +32,6 @@
|
|||||||
#ifndef RSSARTICLE_H
|
#ifndef RSSARTICLE_H
|
||||||
#define RSSARTICLE_H
|
#define RSSARTICLE_H
|
||||||
|
|
||||||
#include <QXmlStreamReader>
|
|
||||||
#include <QDateTime>
|
#include <QDateTime>
|
||||||
#include <QVariantHash>
|
#include <QVariantHash>
|
||||||
#include <QSharedPointer>
|
#include <QSharedPointer>
|
||||||
|
@ -40,9 +40,9 @@
|
|||||||
#include "base/utils/fs.h"
|
#include "base/utils/fs.h"
|
||||||
#include "base/net/downloadmanager.h"
|
#include "base/net/downloadmanager.h"
|
||||||
#include "base/net/downloadhandler.h"
|
#include "base/net/downloadhandler.h"
|
||||||
|
#include "private/rssparser.h"
|
||||||
#include "rssdownloadrulelist.h"
|
#include "rssdownloadrulelist.h"
|
||||||
#include "rssarticle.h"
|
#include "rssarticle.h"
|
||||||
#include "rssparser.h"
|
|
||||||
#include "rssfolder.h"
|
#include "rssfolder.h"
|
||||||
#include "rssmanager.h"
|
#include "rssmanager.h"
|
||||||
#include "rssfeed.h"
|
#include "rssfeed.h"
|
||||||
@ -57,9 +57,8 @@ namespace Rss
|
|||||||
|
|
||||||
using namespace Rss;
|
using namespace Rss;
|
||||||
|
|
||||||
Feed::Feed(Manager *manager, Folder *parent, const QString &url)
|
Feed::Feed(const QString &url, Manager *manager)
|
||||||
: m_manager(manager)
|
: m_manager(manager)
|
||||||
, m_parent(parent)
|
|
||||||
, m_url (QUrl::fromEncoded(url.toUtf8()).toString())
|
, m_url (QUrl::fromEncoded(url.toUtf8()).toString())
|
||||||
, m_icon(":/icons/oxygen/application-rss+xml.png")
|
, m_icon(":/icons/oxygen/application-rss+xml.png")
|
||||||
, m_unreadCount(0)
|
, m_unreadCount(0)
|
||||||
@ -69,34 +68,26 @@ Feed::Feed(Manager *manager, Folder *parent, const QString &url)
|
|||||||
{
|
{
|
||||||
qDebug() << Q_FUNC_INFO << m_url;
|
qDebug() << Q_FUNC_INFO << m_url;
|
||||||
// Listen for new RSS downloads
|
// Listen for new RSS downloads
|
||||||
connect(manager->rssParser(), SIGNAL(feedTitle(QString,QString)), SLOT(handleFeedTitle(QString,QString)));
|
Private::Parser *const parser = m_manager->rssParser();
|
||||||
connect(manager->rssParser(), SIGNAL(newArticle(QString,QVariantHash)), SLOT(handleNewArticle(QString,QVariantHash)));
|
connect(parser, SIGNAL(feedTitle(QString,QString)), SLOT(handleFeedTitle(QString,QString)));
|
||||||
connect(manager->rssParser(), SIGNAL(feedParsingFinished(QString,QString)), SLOT(handleFeedParsingFinished(QString,QString)));
|
connect(parser, SIGNAL(newArticle(QString,QVariantHash)), SLOT(handleNewArticle(QString,QVariantHash)));
|
||||||
|
connect(parser, SIGNAL(feedParsingFinished(QString,QString)), SLOT(handleParsingFinished(QString,QString)));
|
||||||
|
|
||||||
// Download the RSS Feed icon
|
// Download the RSS Feed icon
|
||||||
Net::DownloadHandler *handler = Net::DownloadManager::instance()->downloadUrl(iconUrl(), true);
|
Net::DownloadHandler *handler = Net::DownloadManager::instance()->downloadUrl(iconUrl(), true);
|
||||||
connect(handler, SIGNAL(downloadFinished(QString, QString)), this, SLOT(handleFinishedDownload(QString, QString)));
|
connect(handler, SIGNAL(downloadFinished(QString, QString)), this, SLOT(handleIconDownloadFinished(QString, QString)));
|
||||||
connect(handler, SIGNAL(downloadFailed(QString, QString)), this, SLOT(handleDownloadFailure(QString, QString)));
|
|
||||||
m_iconUrl = handler->url();
|
|
||||||
|
|
||||||
// Load old RSS articles
|
// Load old RSS articles
|
||||||
loadItemsFromDisk();
|
loadItemsFromDisk();
|
||||||
|
|
||||||
|
refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
Feed::~Feed()
|
Feed::~Feed()
|
||||||
{
|
{
|
||||||
if (!m_icon.startsWith(":/") && QFile::exists(m_icon))
|
if (!m_icon.startsWith(":/") && QFile::exists(m_icon))
|
||||||
Utils::Fs::forceRemove(m_icon);
|
Utils::Fs::forceRemove(m_icon);
|
||||||
}
|
m_manager->rssParser()->clearFeedData(m_url);
|
||||||
|
|
||||||
Folder *Feed::parent() const
|
|
||||||
{
|
|
||||||
return m_parent;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Feed::setParent(Folder *parent)
|
|
||||||
{
|
|
||||||
m_parent = parent;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Feed::saveItemsToDisk()
|
void Feed::saveItemsToDisk()
|
||||||
@ -104,7 +95,7 @@ void Feed::saveItemsToDisk()
|
|||||||
qDebug() << Q_FUNC_INFO << m_url;
|
qDebug() << Q_FUNC_INFO << m_url;
|
||||||
if (!m_dirty) return;
|
if (!m_dirty) return;
|
||||||
|
|
||||||
markAsDirty(false);
|
m_dirty = false;
|
||||||
|
|
||||||
QIniSettings qBTRSS("qBittorrent", "qBittorrent-rss");
|
QIniSettings qBTRSS("qBittorrent", "qBittorrent-rss");
|
||||||
QVariantList oldItems;
|
QVariantList oldItems;
|
||||||
@ -140,13 +131,15 @@ void Feed::addArticle(const ArticlePtr &article)
|
|||||||
int maxArticles = Preferences::instance()->getRSSMaxArticlesPerFeed();
|
int maxArticles = Preferences::instance()->getRSSMaxArticlesPerFeed();
|
||||||
|
|
||||||
if (!m_articles.contains(article->guid())) {
|
if (!m_articles.contains(article->guid())) {
|
||||||
markAsDirty();
|
m_dirty = true;
|
||||||
|
|
||||||
// Update unreadCount
|
// Update unreadCount
|
||||||
if (!article->isRead())
|
if (!article->isRead())
|
||||||
++m_unreadCount;
|
++m_unreadCount;
|
||||||
// Insert in hash table
|
// Insert in hash table
|
||||||
m_articles[article->guid()] = article;
|
m_articles[article->guid()] = article;
|
||||||
|
if (!article->isRead()) // Optimization
|
||||||
|
connect(article.data(), SIGNAL(articleWasRead()), SLOT(handleArticleRead()), Qt::UniqueConnection);
|
||||||
// Insertion sort
|
// Insertion sort
|
||||||
ArticleList::Iterator lowerBound = qLowerBound(m_articlesByDate.begin(), m_articlesByDate.end(), article, articleDateRecentThan);
|
ArticleList::Iterator lowerBound = qLowerBound(m_articlesByDate.begin(), m_articlesByDate.end(), article, articleDateRecentThan);
|
||||||
m_articlesByDate.insert(lowerBound, article);
|
m_articlesByDate.insert(lowerBound, article);
|
||||||
@ -162,7 +155,7 @@ void Feed::addArticle(const ArticlePtr &article)
|
|||||||
// Check if article was inserted at the end of the list and will break max_articles limit
|
// Check if article was inserted at the end of the list and will break max_articles limit
|
||||||
if (Preferences::instance()->isRssDownloadingEnabled()) {
|
if (Preferences::instance()->isRssDownloadingEnabled()) {
|
||||||
if ((lbIndex < maxArticles) && !article->isRead())
|
if ((lbIndex < maxArticles) && !article->isRead())
|
||||||
downloadArticleTorrentIfMatching(m_manager->downloadRules(), article);
|
downloadArticleTorrentIfMatching(article);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -172,7 +165,7 @@ void Feed::addArticle(const ArticlePtr &article)
|
|||||||
ArticlePtr skipped = m_articles.value(article->guid(), ArticlePtr());
|
ArticlePtr skipped = m_articles.value(article->guid(), ArticlePtr());
|
||||||
if (skipped) {
|
if (skipped) {
|
||||||
if (!skipped->isRead())
|
if (!skipped->isRead())
|
||||||
downloadArticleTorrentIfMatching(m_manager->downloadRules(), skipped);
|
downloadArticleTorrentIfMatching(skipped);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -186,10 +179,9 @@ bool Feed::refresh()
|
|||||||
}
|
}
|
||||||
m_loading = true;
|
m_loading = true;
|
||||||
// Download the RSS again
|
// Download the RSS again
|
||||||
Net::DownloadHandler *handler = Net::DownloadManager::instance()->downloadUrl(m_url, true);
|
Net::DownloadHandler *handler = Net::DownloadManager::instance()->downloadUrl(m_url);
|
||||||
connect(handler, SIGNAL(downloadFinished(QString, QString)), this, SLOT(handleFinishedDownload(QString, QString)));
|
connect(handler, SIGNAL(downloadFinished(QString, QByteArray)), this, SLOT(handleRssDownloadFinished(QString, QByteArray)));
|
||||||
connect(handler, SIGNAL(downloadFailed(QString, QString)), this, SLOT(handleDownloadFailure(QString, QString)));
|
connect(handler, SIGNAL(downloadFailed(QString, QString)), this, SLOT(handleRssDownloadFailed(QString, QString)));
|
||||||
m_url = handler->url(); // sync URL encoding
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -290,11 +282,6 @@ void Feed::markAsRead()
|
|||||||
m_manager->forwardFeedInfosChanged(m_url, displayName(), 0);
|
m_manager->forwardFeedInfosChanged(m_url, displayName(), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Feed::markAsDirty(bool dirty)
|
|
||||||
{
|
|
||||||
m_dirty = dirty;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint Feed::unreadCount() const
|
uint Feed::unreadCount() const
|
||||||
{
|
{
|
||||||
return m_unreadCount;
|
return m_unreadCount;
|
||||||
@ -327,28 +314,27 @@ ArticleList Feed::unreadArticleListByDateDesc() const
|
|||||||
QString Feed::iconUrl() const
|
QString Feed::iconUrl() const
|
||||||
{
|
{
|
||||||
// XXX: This works for most sites but it is not perfect
|
// XXX: This works for most sites but it is not perfect
|
||||||
return QString("http://") + QUrl(m_url).host() + QString("/favicon.ico");
|
return QString("http://%1/favicon.ico").arg(QUrl(m_url).host());
|
||||||
}
|
}
|
||||||
|
|
||||||
// read and store the downloaded rss' informations
|
void Feed::handleIconDownloadFinished(const QString &url, const QString &filePath)
|
||||||
void Feed::handleFinishedDownload(const QString &url, const QString &filePath)
|
|
||||||
{
|
{
|
||||||
if (url == m_url) {
|
Q_UNUSED(url);
|
||||||
qDebug() << Q_FUNC_INFO << "Successfully downloaded RSS feed at" << url;
|
|
||||||
// Parse the download RSS
|
|
||||||
m_manager->rssParser()->parseRssFile(m_url, filePath);
|
|
||||||
}
|
|
||||||
else if (url == m_iconUrl) {
|
|
||||||
m_icon = filePath;
|
m_icon = filePath;
|
||||||
qDebug() << Q_FUNC_INFO << "icon path:" << m_icon;
|
qDebug() << Q_FUNC_INFO << "icon path:" << m_icon;
|
||||||
m_manager->forwardFeedIconChanged(m_url, m_icon);
|
m_manager->forwardFeedIconChanged(m_url, m_icon);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Feed::handleRssDownloadFinished(const QString &url, const QByteArray &data)
|
||||||
|
{
|
||||||
|
qDebug() << Q_FUNC_INFO << "Successfully downloaded RSS feed at" << url;
|
||||||
|
// Parse the download RSS
|
||||||
|
m_manager->rssParser()->parseFeedData(m_url, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Feed::handleDownloadFailure(const QString &url, const QString &error)
|
void Feed::handleRssDownloadFailed(const QString &url, const QString &error)
|
||||||
{
|
{
|
||||||
if (url != m_url) return;
|
|
||||||
|
|
||||||
m_inErrorState = true;
|
m_inErrorState = true;
|
||||||
m_loading = false;
|
m_loading = false;
|
||||||
m_manager->forwardFeedInfosChanged(m_url, displayName(), m_unreadCount);
|
m_manager->forwardFeedInfosChanged(m_url, displayName(), m_unreadCount);
|
||||||
@ -368,9 +354,10 @@ void Feed::handleFeedTitle(const QString &feedUrl, const QString &title)
|
|||||||
m_manager->forwardFeedInfosChanged(feedUrl, title, m_unreadCount);
|
m_manager->forwardFeedInfosChanged(feedUrl, title, m_unreadCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Feed::downloadArticleTorrentIfMatching(DownloadRuleList *rules, const ArticlePtr &article)
|
void Feed::downloadArticleTorrentIfMatching(const ArticlePtr &article)
|
||||||
{
|
{
|
||||||
Q_ASSERT(Preferences::instance()->isRssDownloadingEnabled());
|
Q_ASSERT(Preferences::instance()->isRssDownloadingEnabled());
|
||||||
|
DownloadRuleList *rules = m_manager->downloadRules();
|
||||||
DownloadRulePtr matchingRule = rules->findMatchingRule(m_url, article->title());
|
DownloadRulePtr matchingRule = rules->findMatchingRule(m_url, article->title());
|
||||||
if (!matchingRule) return;
|
if (!matchingRule) return;
|
||||||
|
|
||||||
@ -378,7 +365,6 @@ void Feed::downloadArticleTorrentIfMatching(DownloadRuleList *rules, const Artic
|
|||||||
QDateTime lastMatch = matchingRule->lastMatch();
|
QDateTime lastMatch = matchingRule->lastMatch();
|
||||||
if (lastMatch.isValid()) {
|
if (lastMatch.isValid()) {
|
||||||
if (QDateTime::currentDateTime() < lastMatch.addDays(matchingRule->ignoreDays())) {
|
if (QDateTime::currentDateTime() < lastMatch.addDays(matchingRule->ignoreDays())) {
|
||||||
connect(article.data(), SIGNAL(articleWasRead()), SLOT(handleArticleStateChanged()), Qt::UniqueConnection);
|
|
||||||
article->markAsRead();
|
article->markAsRead();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -396,8 +382,7 @@ void Feed::downloadArticleTorrentIfMatching(DownloadRuleList *rules, const Artic
|
|||||||
}
|
}
|
||||||
|
|
||||||
Logger::instance()->addMessage(tr("Automatically downloading '%1' torrent from '%2' RSS feed...").arg(article->title()).arg(displayName()));
|
Logger::instance()->addMessage(tr("Automatically downloading '%1' torrent from '%2' RSS feed...").arg(article->title()).arg(displayName()));
|
||||||
connect(BitTorrent::Session::instance(), SIGNAL(downloadFromUrlFinished(QString)), article.data(), SLOT(handleTorrentDownloadSuccess(const QString &)), Qt::UniqueConnection);
|
if (BitTorrent::MagnetUri(torrentUrl).isValid())
|
||||||
if (BitTorrent::MagnetUri(torrent_url).isValid())
|
|
||||||
article->markAsRead();
|
article->markAsRead();
|
||||||
else
|
else
|
||||||
connect(BitTorrent::Session::instance(), SIGNAL(downloadFromUrlFinished(QString)), article.data(), SLOT(handleTorrentDownloadSuccess(const QString&)), Qt::UniqueConnection);
|
connect(BitTorrent::Session::instance(), SIGNAL(downloadFromUrlFinished(QString)), article.data(), SLOT(handleTorrentDownloadSuccess(const QString&)), Qt::UniqueConnection);
|
||||||
@ -415,10 +400,9 @@ void Feed::downloadArticleTorrentIfMatching(DownloadRuleList *rules, const Artic
|
|||||||
void Feed::recheckRssItemsForDownload()
|
void Feed::recheckRssItemsForDownload()
|
||||||
{
|
{
|
||||||
Q_ASSERT(Preferences::instance()->isRssDownloadingEnabled());
|
Q_ASSERT(Preferences::instance()->isRssDownloadingEnabled());
|
||||||
DownloadRuleList *rules = m_manager->downloadRules();
|
|
||||||
foreach (const ArticlePtr &article, m_articlesByDate) {
|
foreach (const ArticlePtr &article, m_articlesByDate) {
|
||||||
if (!article->isRead())
|
if (!article->isRead())
|
||||||
downloadArticleTorrentIfMatching(rules, article);
|
downloadArticleTorrentIfMatching(article);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -440,7 +424,7 @@ void Feed::handleNewArticle(const QString &feedUrl, const QVariantHash &articleD
|
|||||||
//m_manager->forwardFeedContentChanged(m_url);
|
//m_manager->forwardFeedContentChanged(m_url);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Feed::handleFeedParsingFinished(const QString &feedUrl, const QString &error)
|
void Feed::handleParsingFinished(const QString &feedUrl, const QString &error)
|
||||||
{
|
{
|
||||||
if (feedUrl != m_url) return;
|
if (feedUrl != m_url) return;
|
||||||
|
|
||||||
@ -459,12 +443,9 @@ void Feed::handleFeedParsingFinished(const QString &feedUrl, const QString &erro
|
|||||||
saveItemsToDisk();
|
saveItemsToDisk();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Feed::handleArticleStateChanged()
|
void Feed::handleArticleRead()
|
||||||
{
|
|
||||||
m_manager->forwardFeedInfosChanged(m_url, displayName(), m_unreadCount);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Feed::decrementUnreadCount()
|
|
||||||
{
|
{
|
||||||
--m_unreadCount;
|
--m_unreadCount;
|
||||||
|
m_dirty = true;
|
||||||
|
m_manager->forwardFeedInfosChanged(m_url, displayName(), m_unreadCount);
|
||||||
}
|
}
|
||||||
|
@ -58,11 +58,9 @@ namespace Rss
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Feed(Manager *manager, Folder *parent, const QString &url);
|
Feed(const QString &url, Manager *manager);
|
||||||
~Feed();
|
~Feed();
|
||||||
|
|
||||||
Folder *parent() const;
|
|
||||||
void setParent(Folder *parent);
|
|
||||||
bool refresh();
|
bool refresh();
|
||||||
QString id() const;
|
QString id() const;
|
||||||
void removeAllSettings();
|
void removeAllSettings();
|
||||||
@ -78,38 +76,35 @@ namespace Rss
|
|||||||
ArticlePtr getItem(const QString &guid) const;
|
ArticlePtr getItem(const QString &guid) const;
|
||||||
uint count() const;
|
uint count() const;
|
||||||
void markAsRead();
|
void markAsRead();
|
||||||
void markAsDirty(bool dirty = true);
|
|
||||||
uint unreadCount() const;
|
uint unreadCount() const;
|
||||||
ArticleList articleListByDateDesc() const;
|
ArticleList articleListByDateDesc() const;
|
||||||
const ArticleHash &articleHash() const;
|
const ArticleHash &articleHash() const;
|
||||||
ArticleList unreadArticleListByDateDesc() const;
|
ArticleList unreadArticleListByDateDesc() const;
|
||||||
void decrementUnreadCount();
|
|
||||||
void recheckRssItemsForDownload();
|
void recheckRssItemsForDownload();
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void handleFinishedDownload(const QString &url, const QString &filePath);
|
void handleIconDownloadFinished(const QString &url, const QString &filePath);
|
||||||
void handleDownloadFailure(const QString &url, const QString &error);
|
void handleRssDownloadFinished(const QString &url, const QByteArray &data);
|
||||||
|
void handleRssDownloadFailed(const QString &url, const QString &error);
|
||||||
void handleFeedTitle(const QString &feedUrl, const QString &title);
|
void handleFeedTitle(const QString &feedUrl, const QString &title);
|
||||||
void handleNewArticle(const QString &feedUrl, const QVariantHash &article);
|
void handleNewArticle(const QString &feedUrl, const QVariantHash &article);
|
||||||
void handleFeedParsingFinished(const QString &feedUrl, const QString &error);
|
void handleParsingFinished(const QString &feedUrl, const QString &error);
|
||||||
void handleArticleStateChanged();
|
void handleArticleRead();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QString iconUrl() const;
|
QString iconUrl() const;
|
||||||
void loadItemsFromDisk();
|
void loadItemsFromDisk();
|
||||||
void addArticle(const ArticlePtr &article);
|
void addArticle(const ArticlePtr &article);
|
||||||
void downloadArticleTorrentIfMatching(DownloadRuleList *rules, const ArticlePtr &article);
|
void downloadArticleTorrentIfMatching(const ArticlePtr &article);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Manager *m_manager;
|
Manager *m_manager;
|
||||||
ArticleHash m_articles;
|
ArticleHash m_articles;
|
||||||
ArticleList m_articlesByDate; // Articles sorted by date (more recent first)
|
ArticleList m_articlesByDate; // Articles sorted by date (more recent first)
|
||||||
Folder *m_parent;
|
|
||||||
QString m_title;
|
QString m_title;
|
||||||
QString m_url;
|
QString m_url;
|
||||||
QString m_alias;
|
QString m_alias;
|
||||||
QString m_icon;
|
QString m_icon;
|
||||||
QString m_iconUrl;
|
|
||||||
uint m_unreadCount;
|
uint m_unreadCount;
|
||||||
bool m_dirty;
|
bool m_dirty;
|
||||||
bool m_inErrorState;
|
bool m_inErrorState;
|
||||||
|
@ -36,11 +36,16 @@ using namespace Rss;
|
|||||||
|
|
||||||
File::~File() {}
|
File::~File() {}
|
||||||
|
|
||||||
|
Folder *File::parentFolder() const
|
||||||
|
{
|
||||||
|
return m_parent;
|
||||||
|
}
|
||||||
|
|
||||||
QStringList File::pathHierarchy() const
|
QStringList File::pathHierarchy() const
|
||||||
{
|
{
|
||||||
QStringList path;
|
QStringList path;
|
||||||
if (parent())
|
if (m_parent)
|
||||||
path << parent()->pathHierarchy();
|
path << m_parent->pathHierarchy();
|
||||||
path << id();
|
path << id();
|
||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
|
@ -55,25 +55,27 @@ namespace Rss
|
|||||||
public:
|
public:
|
||||||
virtual ~File();
|
virtual ~File();
|
||||||
|
|
||||||
virtual uint unreadCount() const = 0;
|
|
||||||
virtual QString displayName() const = 0;
|
|
||||||
virtual QString id() const = 0;
|
virtual QString id() const = 0;
|
||||||
|
virtual QString displayName() const = 0;
|
||||||
|
virtual uint unreadCount() const = 0;
|
||||||
virtual QString iconPath() const = 0;
|
virtual QString iconPath() const = 0;
|
||||||
virtual void rename(const QString &newName) = 0;
|
|
||||||
virtual void markAsRead() = 0;
|
|
||||||
virtual Folder *parent() const = 0;
|
|
||||||
virtual void setParent(Folder *parent) = 0;
|
|
||||||
virtual bool refresh() = 0;
|
|
||||||
virtual ArticleList articleListByDateDesc() const = 0;
|
virtual ArticleList articleListByDateDesc() const = 0;
|
||||||
virtual ArticleList unreadArticleListByDateDesc() const = 0;
|
virtual ArticleList unreadArticleListByDateDesc() const = 0;
|
||||||
|
|
||||||
|
virtual void rename(const QString &newName) = 0;
|
||||||
|
virtual void markAsRead() = 0;
|
||||||
|
virtual bool refresh() = 0;
|
||||||
virtual void removeAllSettings() = 0;
|
virtual void removeAllSettings() = 0;
|
||||||
virtual void saveItemsToDisk() = 0;
|
virtual void saveItemsToDisk() = 0;
|
||||||
virtual void recheckRssItemsForDownload() = 0;
|
virtual void recheckRssItemsForDownload() = 0;
|
||||||
|
|
||||||
|
Folder *parentFolder() const;
|
||||||
QStringList pathHierarchy() const;
|
QStringList pathHierarchy() const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
uint m_unreadCount;
|
friend class Folder;
|
||||||
|
|
||||||
|
Folder *m_parent = nullptr;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,24 +40,11 @@
|
|||||||
|
|
||||||
using namespace Rss;
|
using namespace Rss;
|
||||||
|
|
||||||
Folder::Folder(Folder *parent, const QString &name)
|
Folder::Folder(const QString &name)
|
||||||
: m_parent(parent)
|
: m_name(name)
|
||||||
, m_name(name)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
Folder::~Folder() {}
|
|
||||||
|
|
||||||
Folder *Folder::parent() const
|
|
||||||
{
|
|
||||||
return m_parent;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Folder::setParent(Folder *parent)
|
|
||||||
{
|
|
||||||
m_parent = parent;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint Folder::unreadCount() const
|
uint Folder::unreadCount() const
|
||||||
{
|
{
|
||||||
uint nbUnread = 0;
|
uint nbUnread = 0;
|
||||||
@ -78,31 +65,6 @@ void Folder::removeChild(const QString &childId)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FolderPtr Folder::addFolder(const QString &name)
|
|
||||||
{
|
|
||||||
FolderPtr subfolder;
|
|
||||||
if (!m_children.contains(name)) {
|
|
||||||
subfolder = FolderPtr(new Folder(this, name));
|
|
||||||
m_children[name] = subfolder;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
subfolder = qSharedPointerDynamicCast<Folder>(m_children.value(name));
|
|
||||||
}
|
|
||||||
return subfolder;
|
|
||||||
}
|
|
||||||
|
|
||||||
FeedPtr Folder::addStream(Manager *manager, const QString &url)
|
|
||||||
{
|
|
||||||
qDebug() << Q_FUNC_INFO << manager << url;
|
|
||||||
FeedPtr stream(new Feed(manager, this, url));
|
|
||||||
Q_ASSERT(stream);
|
|
||||||
qDebug() << "Stream URL is " << stream->url();
|
|
||||||
Q_ASSERT(!m_children.contains(stream->url()));
|
|
||||||
m_children[stream->url()] = stream;
|
|
||||||
stream->refresh();
|
|
||||||
return stream;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Refresh All Children
|
// Refresh All Children
|
||||||
bool Folder::refresh()
|
bool Folder::refresh()
|
||||||
{
|
{
|
||||||
@ -176,7 +138,8 @@ void Folder::rename(const QString &newName)
|
|||||||
Q_ASSERT(!m_parent->hasChild(newName));
|
Q_ASSERT(!m_parent->hasChild(newName));
|
||||||
if (!m_parent->hasChild(newName)) {
|
if (!m_parent->hasChild(newName)) {
|
||||||
// Update parent
|
// Update parent
|
||||||
m_parent->renameChildFolder(m_name, newName);
|
FilePtr folder = m_parent->m_children.take(m_name);
|
||||||
|
m_parent->m_children[newName] = folder;
|
||||||
// Actually rename
|
// Actually rename
|
||||||
m_name = newName;
|
m_name = newName;
|
||||||
}
|
}
|
||||||
@ -224,20 +187,17 @@ QHash<QString, FeedPtr> Folder::getAllFeedsAsHash() const
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Folder::addFile(const FilePtr &item)
|
bool Folder::addFile(const FilePtr &item)
|
||||||
{
|
{
|
||||||
if (FeedPtr feed = qSharedPointerDynamicCast<Feed>(item)) {
|
Q_ASSERT(!m_children.contains(item->id()));
|
||||||
Q_ASSERT(!m_children.contains(feed->url()));
|
if (!m_children.contains(item->id())) {
|
||||||
m_children[feed->url()] = item;
|
m_children[item->id()] = item;
|
||||||
qDebug("Added feed %s to folder ./%s", qPrintable(feed->url()), qPrintable(m_name));
|
|
||||||
}
|
|
||||||
else if (FolderPtr folder = qSharedPointerDynamicCast<Folder>(item)) {
|
|
||||||
Q_ASSERT(!m_children.contains(folder->displayName()));
|
|
||||||
m_children[folder->displayName()] = item;
|
|
||||||
qDebug("Added folder %s to folder ./%s", qPrintable(folder->displayName()), qPrintable(m_name));
|
|
||||||
}
|
|
||||||
// Update parent
|
// Update parent
|
||||||
item->setParent(this);
|
item->m_parent = this;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Folder::removeAllItems()
|
void Folder::removeAllItems()
|
||||||
@ -245,6 +205,11 @@ void Folder::removeAllItems()
|
|||||||
m_children.clear();
|
m_children.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FilePtr Folder::child(const QString &childId)
|
||||||
|
{
|
||||||
|
return m_children.value(childId);
|
||||||
|
}
|
||||||
|
|
||||||
void Folder::removeAllSettings()
|
void Folder::removeAllSettings()
|
||||||
{
|
{
|
||||||
FileHash::ConstIterator it = m_children.begin();
|
FileHash::ConstIterator it = m_children.begin();
|
||||||
@ -274,13 +239,6 @@ bool Folder::hasChild(const QString &childId)
|
|||||||
return m_children.contains(childId);
|
return m_children.contains(childId);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Folder::renameChildFolder(const QString &oldName, const QString &newName)
|
|
||||||
{
|
|
||||||
Q_ASSERT(m_children.contains(oldName));
|
|
||||||
FilePtr folder = m_children.take(oldName);
|
|
||||||
m_children[newName] = folder;
|
|
||||||
}
|
|
||||||
|
|
||||||
FilePtr Folder::takeChild(const QString &childId)
|
FilePtr Folder::takeChild(const QString &childId)
|
||||||
{
|
{
|
||||||
return m_children.take(childId);
|
return m_children.take(childId);
|
||||||
|
@ -48,19 +48,12 @@ namespace Rss
|
|||||||
typedef QSharedPointer<Folder> FolderPtr;
|
typedef QSharedPointer<Folder> FolderPtr;
|
||||||
typedef QList<FeedPtr> FeedList;
|
typedef QList<FeedPtr> FeedList;
|
||||||
|
|
||||||
class Folder: public QObject, public File
|
class Folder: public File
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit Folder(Folder *parent = 0, const QString &name = QString());
|
explicit Folder(const QString &name = QString());
|
||||||
~Folder();
|
|
||||||
|
|
||||||
Folder *parent() const;
|
|
||||||
void setParent(Folder *parent);
|
|
||||||
uint unreadCount() const;
|
uint unreadCount() const;
|
||||||
FeedPtr addStream(Manager *manager, const QString &url);
|
|
||||||
FolderPtr addFolder(const QString &name);
|
|
||||||
uint getNbFeeds() const;
|
uint getNbFeeds() const;
|
||||||
FileList getContent() const;
|
FileList getContent() const;
|
||||||
FeedList getAllFeeds() const;
|
FeedList getAllFeeds() const;
|
||||||
@ -71,22 +64,20 @@ namespace Rss
|
|||||||
bool hasChild(const QString &childId);
|
bool hasChild(const QString &childId);
|
||||||
ArticleList articleListByDateDesc() const;
|
ArticleList articleListByDateDesc() const;
|
||||||
ArticleList unreadArticleListByDateDesc() const;
|
ArticleList unreadArticleListByDateDesc() const;
|
||||||
void removeAllSettings();
|
|
||||||
void saveItemsToDisk();
|
|
||||||
void removeAllItems();
|
|
||||||
void renameChildFolder(const QString &oldName, const QString &newName);
|
|
||||||
FilePtr takeChild(const QString &childId);
|
|
||||||
void recheckRssItemsForDownload();
|
|
||||||
|
|
||||||
public slots:
|
|
||||||
bool refresh();
|
|
||||||
void addFile(const FilePtr &item);
|
|
||||||
void removeChild(const QString &childId);
|
|
||||||
void rename(const QString &newName);
|
void rename(const QString &newName);
|
||||||
void markAsRead();
|
void markAsRead();
|
||||||
|
bool refresh();
|
||||||
|
void removeAllSettings();
|
||||||
|
void saveItemsToDisk();
|
||||||
|
void recheckRssItemsForDownload();
|
||||||
|
void removeAllItems();
|
||||||
|
FilePtr child(const QString &childId);
|
||||||
|
FilePtr takeChild(const QString &childId);
|
||||||
|
bool addFile(const FilePtr &item);
|
||||||
|
void removeChild(const QString &childId);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Folder *m_parent;
|
|
||||||
QString m_name;
|
QString m_name;
|
||||||
FileHash m_children;
|
FileHash m_children;
|
||||||
};
|
};
|
||||||
|
@ -33,19 +33,23 @@
|
|||||||
|
|
||||||
#include "base/logger.h"
|
#include "base/logger.h"
|
||||||
#include "base/preferences.h"
|
#include "base/preferences.h"
|
||||||
|
#include "private/rssparser.h"
|
||||||
|
#include "rssfolder.h"
|
||||||
#include "rssfeed.h"
|
#include "rssfeed.h"
|
||||||
#include "rssarticle.h"
|
#include "rssarticle.h"
|
||||||
#include "rssdownloadrulelist.h"
|
#include "rssdownloadrulelist.h"
|
||||||
#include "rssparser.h"
|
|
||||||
#include "rssmanager.h"
|
#include "rssmanager.h"
|
||||||
|
|
||||||
static const int MSECS_PER_MIN = 60000;
|
static const int MSECS_PER_MIN = 60000;
|
||||||
|
|
||||||
using namespace Rss;
|
using namespace Rss;
|
||||||
|
using namespace Rss::Private;
|
||||||
|
|
||||||
Manager::Manager()
|
Manager::Manager(QObject *parent)
|
||||||
: m_downloadRules(new DownloadRuleList)
|
: QObject(parent)
|
||||||
|
, m_downloadRules(new DownloadRuleList)
|
||||||
, m_rssParser(new Parser(this))
|
, m_rssParser(new Parser(this))
|
||||||
|
, m_rootFolder(new Folder)
|
||||||
{
|
{
|
||||||
connect(&m_refreshTimer, SIGNAL(timeout()), SLOT(refresh()));
|
connect(&m_refreshTimer, SIGNAL(timeout()), SLOT(refresh()));
|
||||||
m_refreshInterval = Preferences::instance()->getRSSRefreshInterval();
|
m_refreshInterval = Preferences::instance()->getRSSRefreshInterval();
|
||||||
@ -57,16 +61,12 @@ Manager::~Manager()
|
|||||||
qDebug("Deleting RSSManager...");
|
qDebug("Deleting RSSManager...");
|
||||||
delete m_downloadRules;
|
delete m_downloadRules;
|
||||||
delete m_rssParser;
|
delete m_rssParser;
|
||||||
saveItemsToDisk();
|
m_rootFolder->saveItemsToDisk();
|
||||||
saveStreamList();
|
saveStreamList();
|
||||||
|
m_rootFolder.clear();
|
||||||
qDebug("RSSManager deleted");
|
qDebug("RSSManager deleted");
|
||||||
}
|
}
|
||||||
|
|
||||||
Parser *Manager::rssParser() const
|
|
||||||
{
|
|
||||||
return m_rssParser;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Manager::updateRefreshInterval(uint val)
|
void Manager::updateRefreshInterval(uint val)
|
||||||
{
|
{
|
||||||
if (m_refreshInterval != val) {
|
if (m_refreshInterval != val) {
|
||||||
@ -95,14 +95,22 @@ void Manager::loadStreamList()
|
|||||||
const QString feedUrl = path.takeLast();
|
const QString feedUrl = path.takeLast();
|
||||||
qDebug() << "Feed URL:" << feedUrl;
|
qDebug() << "Feed URL:" << feedUrl;
|
||||||
// Create feed path (if it does not exists)
|
// Create feed path (if it does not exists)
|
||||||
Folder *feedParent = this;
|
FolderPtr feedParent = m_rootFolder;
|
||||||
foreach (const QString &folderName, path) {
|
foreach (const QString &folderName, path) {
|
||||||
|
if (!feedParent->hasChild(folderName)) {
|
||||||
qDebug() << "Adding parent folder:" << folderName;
|
qDebug() << "Adding parent folder:" << folderName;
|
||||||
feedParent = feedParent->addFolder(folderName).data();
|
FolderPtr folder(new Folder(folderName));
|
||||||
|
feedParent->addFile(folder);
|
||||||
|
feedParent = folder;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
feedParent = qSharedPointerDynamicCast<Folder>(feedParent->child(folderName));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// Create feed
|
// Create feed
|
||||||
qDebug() << "Adding feed to parent folder";
|
qDebug() << "Adding feed to parent folder";
|
||||||
FeedPtr stream = feedParent->addStream(this, feedUrl);
|
FeedPtr stream(new Feed(feedUrl, this));
|
||||||
|
feedParent->addFile(stream);
|
||||||
const QString &alias = aliases[i];
|
const QString &alias = aliases[i];
|
||||||
if (!alias.isEmpty())
|
if (!alias.isEmpty())
|
||||||
stream->rename(alias);
|
stream->rename(alias);
|
||||||
@ -128,7 +136,7 @@ void Manager::forwardFeedIconChanged(const QString &url, const QString &iconPath
|
|||||||
|
|
||||||
void Manager::moveFile(const FilePtr &file, const FolderPtr &destinationFolder)
|
void Manager::moveFile(const FilePtr &file, const FolderPtr &destinationFolder)
|
||||||
{
|
{
|
||||||
Folder *srcFolder = file->parent();
|
Folder *srcFolder = file->parentFolder();
|
||||||
if (destinationFolder != srcFolder) {
|
if (destinationFolder != srcFolder) {
|
||||||
// Remove reference in old folder
|
// Remove reference in old folder
|
||||||
srcFolder->takeChild(file->id());
|
srcFolder->takeChild(file->id());
|
||||||
@ -144,7 +152,7 @@ void Manager::saveStreamList() const
|
|||||||
{
|
{
|
||||||
QStringList streamsUrl;
|
QStringList streamsUrl;
|
||||||
QStringList aliases;
|
QStringList aliases;
|
||||||
FeedList streams = getAllFeeds();
|
FeedList streams = m_rootFolder->getAllFeeds();
|
||||||
foreach (const FeedPtr &stream, streams) {
|
foreach (const FeedPtr &stream, streams) {
|
||||||
// This backslash has nothing to do with path handling
|
// This backslash has nothing to do with path handling
|
||||||
QString streamPath = stream->pathHierarchy().join("\\");
|
QString streamPath = stream->pathHierarchy().join("\\");
|
||||||
@ -164,3 +172,18 @@ DownloadRuleList *Manager::downloadRules() const
|
|||||||
Q_ASSERT(m_downloadRules);
|
Q_ASSERT(m_downloadRules);
|
||||||
return m_downloadRules;
|
return m_downloadRules;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FolderPtr Manager::rootFolder() const
|
||||||
|
{
|
||||||
|
return m_rootFolder;
|
||||||
|
}
|
||||||
|
|
||||||
|
Parser *Manager::rssParser() const
|
||||||
|
{
|
||||||
|
return m_rssParser;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Manager::refresh()
|
||||||
|
{
|
||||||
|
m_rootFolder->refresh();
|
||||||
|
}
|
||||||
|
@ -32,31 +32,44 @@
|
|||||||
#ifndef RSSMANAGER_H
|
#ifndef RSSMANAGER_H
|
||||||
#define RSSMANAGER_H
|
#define RSSMANAGER_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
#include <QSharedPointer>
|
#include <QSharedPointer>
|
||||||
|
|
||||||
#include "rssfolder.h"
|
|
||||||
|
|
||||||
namespace Rss
|
namespace Rss
|
||||||
{
|
{
|
||||||
class DownloadRuleList;
|
class DownloadRuleList;
|
||||||
class Parser;
|
class File;
|
||||||
|
class Folder;
|
||||||
|
class Feed;
|
||||||
class Manager;
|
class Manager;
|
||||||
|
|
||||||
|
typedef QSharedPointer<File> FilePtr;
|
||||||
|
typedef QSharedPointer<Folder> FolderPtr;
|
||||||
|
typedef QSharedPointer<Feed> FeedPtr;
|
||||||
|
|
||||||
|
namespace Private
|
||||||
|
{
|
||||||
|
class Parser;
|
||||||
|
}
|
||||||
|
|
||||||
typedef QSharedPointer<Manager> ManagerPtr;
|
typedef QSharedPointer<Manager> ManagerPtr;
|
||||||
|
|
||||||
class Manager: public Folder
|
class Manager: public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Manager();
|
explicit Manager(QObject *parent = 0);
|
||||||
~Manager();
|
~Manager();
|
||||||
|
|
||||||
Parser *rssParser() const;
|
|
||||||
DownloadRuleList *downloadRules() const;
|
DownloadRuleList *downloadRules() const;
|
||||||
|
FolderPtr rootFolder() const;
|
||||||
|
|
||||||
|
Private::Parser *rssParser() const;
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
|
void refresh();
|
||||||
void loadStreamList();
|
void loadStreamList();
|
||||||
void saveStreamList() const;
|
void saveStreamList() const;
|
||||||
void forwardFeedContentChanged(const QString &url);
|
void forwardFeedContentChanged(const QString &url);
|
||||||
@ -74,7 +87,8 @@ namespace Rss
|
|||||||
QTimer m_refreshTimer;
|
QTimer m_refreshTimer;
|
||||||
uint m_refreshInterval;
|
uint m_refreshInterval;
|
||||||
DownloadRuleList *m_downloadRules;
|
DownloadRuleList *m_downloadRules;
|
||||||
Parser *m_rssParser;
|
Private::Parser *m_rssParser;
|
||||||
|
FolderPtr m_rootFolder;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -39,6 +39,7 @@
|
|||||||
#include "base/rss/rssdownloadrulelist.h"
|
#include "base/rss/rssdownloadrulelist.h"
|
||||||
#include "base/preferences.h"
|
#include "base/preferences.h"
|
||||||
#include "base/rss/rssmanager.h"
|
#include "base/rss/rssmanager.h"
|
||||||
|
#include "base/rss/rssfolder.h"
|
||||||
#include "base/rss/rssfeed.h"
|
#include "base/rss/rssfeed.h"
|
||||||
#include "guiiconprovider.h"
|
#include "guiiconprovider.h"
|
||||||
#include "autoexpandabledialog.h"
|
#include "autoexpandabledialog.h"
|
||||||
@ -524,7 +525,7 @@ void AutomatedRssDownloader::updateMatchingArticles()
|
|||||||
Rss::ManagerPtr manager = m_manager.toStrongRef();
|
Rss::ManagerPtr manager = m_manager.toStrongRef();
|
||||||
if (!manager)
|
if (!manager)
|
||||||
return;
|
return;
|
||||||
const QHash<QString, Rss::FeedPtr> all_feeds = manager->getAllFeedsAsHash();
|
const QHash<QString, Rss::FeedPtr> all_feeds = manager->rootFolder()->getAllFeedsAsHash();
|
||||||
|
|
||||||
saveEditedRule();
|
saveEditedRule();
|
||||||
foreach (const QListWidgetItem *rule_item, ui->listRules->selectedItems()) {
|
foreach (const QListWidgetItem *rule_item, ui->listRules->selectedItems()) {
|
||||||
|
@ -29,6 +29,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "base/rss/rssmanager.h"
|
#include "base/rss/rssmanager.h"
|
||||||
|
#include "base/rss/rssfolder.h"
|
||||||
#include "base/rss/rssfeed.h"
|
#include "base/rss/rssfeed.h"
|
||||||
#include "guiiconprovider.h"
|
#include "guiiconprovider.h"
|
||||||
#include "feedlistwidget.h"
|
#include "feedlistwidget.h"
|
||||||
@ -40,9 +41,9 @@ FeedListWidget::FeedListWidget(QWidget *parent, const Rss::ManagerPtr& rssmanage
|
|||||||
setColumnCount(1);
|
setColumnCount(1);
|
||||||
headerItem()->setText(0, tr("RSS feeds"));
|
headerItem()->setText(0, tr("RSS feeds"));
|
||||||
m_unreadStickyItem = new QTreeWidgetItem(this);
|
m_unreadStickyItem = new QTreeWidgetItem(this);
|
||||||
m_unreadStickyItem->setText(0, tr("Unread") + QString::fromUtf8(" (") + QString::number(rssmanager->unreadCount())+ QString(")"));
|
m_unreadStickyItem->setText(0, tr("Unread") + QString::fromUtf8(" (") + QString::number(rssmanager->rootFolder()->unreadCount()) + QString(")"));
|
||||||
m_unreadStickyItem->setData(0,Qt::DecorationRole, GuiIconProvider::instance()->getIcon("mail-folder-inbox"));
|
m_unreadStickyItem->setData(0,Qt::DecorationRole, GuiIconProvider::instance()->getIcon("mail-folder-inbox"));
|
||||||
itemAdded(m_unreadStickyItem, rssmanager);
|
itemAdded(m_unreadStickyItem, rssmanager->rootFolder());
|
||||||
connect(this, SIGNAL(currentItemChanged(QTreeWidgetItem*,QTreeWidgetItem*)), SLOT(updateCurrentFeed(QTreeWidgetItem*)));
|
connect(this, SIGNAL(currentItemChanged(QTreeWidgetItem*,QTreeWidgetItem*)), SLOT(updateCurrentFeed(QTreeWidgetItem*)));
|
||||||
setCurrentItem(m_unreadStickyItem);
|
setCurrentItem(m_unreadStickyItem);
|
||||||
}
|
}
|
||||||
@ -202,7 +203,7 @@ void FeedListWidget::dropEvent(QDropEvent *event) {
|
|||||||
dest_folder = qSharedPointerCast<Rss::Folder>(getRSSItem(dest_folder_item));
|
dest_folder = qSharedPointerCast<Rss::Folder>(getRSSItem(dest_folder_item));
|
||||||
folders_altered << dest_folder_item;
|
folders_altered << dest_folder_item;
|
||||||
} else {
|
} else {
|
||||||
dest_folder = m_rssManager;
|
dest_folder = m_rssManager->rootFolder();
|
||||||
}
|
}
|
||||||
QList<QTreeWidgetItem *> src_items = selectedItems();
|
QList<QTreeWidgetItem *> src_items = selectedItems();
|
||||||
// Check if there is not going to overwrite another file
|
// Check if there is not going to overwrite another file
|
||||||
|
@ -47,7 +47,6 @@
|
|||||||
#include "base/rss/rssmanager.h"
|
#include "base/rss/rssmanager.h"
|
||||||
#include "base/rss/rssfolder.h"
|
#include "base/rss/rssfolder.h"
|
||||||
#include "base/rss/rssarticle.h"
|
#include "base/rss/rssarticle.h"
|
||||||
#include "base/rss/rssparser.h"
|
|
||||||
#include "base/rss/rssfeed.h"
|
#include "base/rss/rssfeed.h"
|
||||||
#include "automatedrssdownloader.h"
|
#include "automatedrssdownloader.h"
|
||||||
#include "guiiconprovider.h"
|
#include "guiiconprovider.h"
|
||||||
@ -79,7 +78,7 @@ void RSSImp::displayRSSListMenu(const QPoint& pos)
|
|||||||
myRSSListMenu.addAction(actionMark_items_read);
|
myRSSListMenu.addAction(actionMark_items_read);
|
||||||
myRSSListMenu.addSeparator();
|
myRSSListMenu.addSeparator();
|
||||||
if (selectedItems.size() == 1) {
|
if (selectedItems.size() == 1) {
|
||||||
if (m_feedList->getRSSItem(selectedItems.first()) != m_rssManager) {
|
if (m_feedList->getRSSItem(selectedItems.first()) != m_rssManager->rootFolder()) {
|
||||||
myRSSListMenu.addAction(actionRename);
|
myRSSListMenu.addAction(actionRename);
|
||||||
myRSSListMenu.addAction(actionDelete);
|
myRSSListMenu.addAction(actionDelete);
|
||||||
myRSSListMenu.addSeparator();
|
myRSSListMenu.addSeparator();
|
||||||
@ -167,14 +166,15 @@ void RSSImp::askNewFolder()
|
|||||||
Q_ASSERT(rss_parent);
|
Q_ASSERT(rss_parent);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
rss_parent = m_rssManager;
|
rss_parent = m_rssManager->rootFolder();
|
||||||
}
|
}
|
||||||
bool ok;
|
bool ok;
|
||||||
QString new_name = AutoExpandableDialog::getText(this, tr("Please choose a folder name"), tr("Folder name:"), QLineEdit::Normal, tr("New folder"), &ok);
|
QString new_name = AutoExpandableDialog::getText(this, tr("Please choose a folder name"), tr("Folder name:"), QLineEdit::Normal, tr("New folder"), &ok);
|
||||||
if (!ok)
|
if (!ok || rss_parent->hasChild(new_name))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Rss::FolderPtr newFolder = rss_parent->addFolder(new_name);
|
Rss::FolderPtr newFolder(new Rss::Folder(new_name));
|
||||||
|
rss_parent->addFile(newFolder);
|
||||||
QTreeWidgetItem* folderItem = createFolderListItem(newFolder);
|
QTreeWidgetItem* folderItem = createFolderListItem(newFolder);
|
||||||
if (parent_item)
|
if (parent_item)
|
||||||
parent_item->addChild(folderItem);
|
parent_item->addChild(folderItem);
|
||||||
@ -207,7 +207,7 @@ void RSSImp::on_newFeedButton_clicked()
|
|||||||
if (parent_item)
|
if (parent_item)
|
||||||
rss_parent = qSharedPointerCast<Rss::Folder>(m_feedList->getRSSItem(parent_item));
|
rss_parent = qSharedPointerCast<Rss::Folder>(m_feedList->getRSSItem(parent_item));
|
||||||
else
|
else
|
||||||
rss_parent = m_rssManager;
|
rss_parent = m_rssManager->rootFolder();
|
||||||
// Ask for feed URL
|
// Ask for feed URL
|
||||||
bool ok;
|
bool ok;
|
||||||
QString clip_txt = qApp->clipboard()->text();
|
QString clip_txt = qApp->clipboard()->text();
|
||||||
@ -229,7 +229,9 @@ void RSSImp::on_newFeedButton_clicked()
|
|||||||
QMessageBox::Ok);
|
QMessageBox::Ok);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Rss::FeedPtr stream = rss_parent->addStream(m_rssManager.data(), newUrl);
|
|
||||||
|
Rss::FeedPtr stream(new Rss::Feed(newUrl, m_rssManager.data()));
|
||||||
|
rss_parent->addFile(stream);
|
||||||
// Create TreeWidget item
|
// Create TreeWidget item
|
||||||
QTreeWidgetItem* item = createFolderListItem(stream);
|
QTreeWidgetItem* item = createFolderListItem(stream);
|
||||||
if (parent_item)
|
if (parent_item)
|
||||||
@ -265,17 +267,13 @@ void RSSImp::deleteSelectedItems()
|
|||||||
// Notify TreeWidget
|
// Notify TreeWidget
|
||||||
m_feedList->itemAboutToBeRemoved(item);
|
m_feedList->itemAboutToBeRemoved(item);
|
||||||
// Actually delete the item
|
// Actually delete the item
|
||||||
rss_item->parent()->removeChild(rss_item->id());
|
rss_item->parentFolder()->removeChild(rss_item->id());
|
||||||
delete item;
|
delete item;
|
||||||
// Update parents count
|
// Update parents count
|
||||||
while (parent && parent != m_feedList->invisibleRootItem()) {
|
while (parent && (parent != m_feedList->invisibleRootItem())) {
|
||||||
updateItemInfos(parent);
|
updateItemInfos(parent);
|
||||||
parent = parent->parent();
|
parent = parent->parent();
|
||||||
}
|
}
|
||||||
// Clear feed data from RSS parser (possible caching).
|
|
||||||
Rss::Feed* rssFeed = dynamic_cast<Rss::Feed*>(rss_item.data());
|
|
||||||
if (rssFeed)
|
|
||||||
m_rssManager->rssParser()->clearFeedData(rssFeed->url());
|
|
||||||
}
|
}
|
||||||
m_rssManager->saveStreamList();
|
m_rssManager->saveStreamList();
|
||||||
// Update Unread items
|
// Update Unread items
|
||||||
@ -406,7 +404,7 @@ void RSSImp::renameSelectedRssFile()
|
|||||||
newName = AutoExpandableDialog::getText(this, tr("Please choose a new name for this RSS feed"), tr("New feed name:"), QLineEdit::Normal, m_feedList->getRSSItem(item)->displayName(), &ok);
|
newName = AutoExpandableDialog::getText(this, tr("Please choose a new name for this RSS feed"), tr("New feed name:"), QLineEdit::Normal, m_feedList->getRSSItem(item)->displayName(), &ok);
|
||||||
// Check if name is already taken
|
// Check if name is already taken
|
||||||
if (ok) {
|
if (ok) {
|
||||||
if (rss_item->parent()->hasChild(newName)) {
|
if (rss_item->parentFolder()->hasChild(newName)) {
|
||||||
QMessageBox::warning(0, tr("Name already in use"), tr("This name is already used by another item, please choose another one."));
|
QMessageBox::warning(0, tr("Name already in use"), tr("This name is already used by another item, please choose another one."));
|
||||||
ok = false;
|
ok = false;
|
||||||
}
|
}
|
||||||
@ -489,7 +487,7 @@ void RSSImp::fillFeedsList(QTreeWidgetItem* parent, const Rss::FolderPtr& rss_pa
|
|||||||
if (parent)
|
if (parent)
|
||||||
children = rss_parent->getContent();
|
children = rss_parent->getContent();
|
||||||
else
|
else
|
||||||
children = m_rssManager->getContent();
|
children = m_rssManager->rootFolder()->getContent();
|
||||||
foreach (const Rss::FilePtr& rssFile, children) {
|
foreach (const Rss::FilePtr& rssFile, children) {
|
||||||
QTreeWidgetItem* item = createFolderListItem(rssFile);
|
QTreeWidgetItem* item = createFolderListItem(rssFile);
|
||||||
Q_ASSERT(item);
|
Q_ASSERT(item);
|
||||||
@ -546,7 +544,7 @@ void RSSImp::populateArticleList(QTreeWidgetItem* item)
|
|||||||
|
|
||||||
qDebug("Getting the list of news");
|
qDebug("Getting the list of news");
|
||||||
Rss::ArticleList articles;
|
Rss::ArticleList articles;
|
||||||
if (rss_item == m_rssManager)
|
if (rss_item == m_rssManager->rootFolder())
|
||||||
articles = rss_item->unreadArticleListByDateDesc();
|
articles = rss_item->unreadArticleListByDateDesc();
|
||||||
else
|
else
|
||||||
articles = rss_item->articleListByDateDesc();
|
articles = rss_item->articleListByDateDesc();
|
||||||
@ -655,7 +653,7 @@ void RSSImp::updateItemInfos(QTreeWidgetItem *item)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
QString name;
|
QString name;
|
||||||
if (rss_item == m_rssManager) {
|
if (rss_item == m_rssManager->rootFolder()) {
|
||||||
name = tr("Unread");
|
name = tr("Unread");
|
||||||
emit updateRSSCount(rss_item->unreadCount());
|
emit updateRSSCount(rss_item->unreadCount());
|
||||||
}
|
}
|
||||||
@ -799,7 +797,7 @@ void RSSImp::on_rssDownloaderBtn_clicked()
|
|||||||
AutomatedRssDownloader dlg(m_rssManager, this);
|
AutomatedRssDownloader dlg(m_rssManager, this);
|
||||||
dlg.exec();
|
dlg.exec();
|
||||||
if (dlg.isRssDownloaderEnabled()) {
|
if (dlg.isRssDownloaderEnabled()) {
|
||||||
m_rssManager->recheckRssItemsForDownload();
|
m_rssManager->rootFolder()->recheckRssItemsForDownload();
|
||||||
refreshAllFeeds();
|
refreshAllFeeds();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user