Browse Source

Redesign RSS base classes.

adaptive-webui-19844
Vladimir Golovnev (Glassez) 9 years ago committed by Vladimir Golovnev (qlassez)
parent
commit
28ed981082
  1. 4
      src/base/base.pri
  2. 34
      src/base/rss/private/rssparser.cpp
  3. 66
      src/base/rss/private/rssparser.h
  4. 10
      src/base/rss/rssarticle.cpp
  5. 1
      src/base/rss/rssarticle.h
  6. 101
      src/base/rss/rssfeed.cpp
  7. 19
      src/base/rss/rssfeed.h
  8. 9
      src/base/rss/rssfile.cpp
  9. 16
      src/base/rss/rssfile.h
  10. 78
      src/base/rss/rssfolder.cpp
  11. 27
      src/base/rss/rssfolder.h
  12. 53
      src/base/rss/rssmanager.cpp
  13. 28
      src/base/rss/rssmanager.h
  14. 3
      src/gui/rss/automatedrssdownloader.cpp
  15. 7
      src/gui/rss/feedlistwidget.cpp
  16. 36
      src/gui/rss/rss_imp.cpp

4
src/base/base.pri

@ -43,7 +43,7 @@ HEADERS += \ @@ -43,7 +43,7 @@ HEADERS += \
$$PWD/rss/rssarticle.h \
$$PWD/rss/rssdownloadrule.h \
$$PWD/rss/rssdownloadrulelist.h \
$$PWD/rss/rssparser.h \
$$PWD/rss/private/rssparser.h \
$$PWD/utils/fs.h \
$$PWD/utils/gzip.h \
$$PWD/utils/misc.h \
@ -94,7 +94,7 @@ SOURCES += \ @@ -94,7 +94,7 @@ SOURCES += \
$$PWD/rss/rssdownloadrule.cpp \
$$PWD/rss/rssdownloadrulelist.cpp \
$$PWD/rss/rssfile.cpp \
$$PWD/rss/rssparser.cpp \
$$PWD/rss/private/rssparser.cpp \
$$PWD/utils/fs.cpp \
$$PWD/utils/gzip.cpp \
$$PWD/utils/misc.cpp \

34
src/base/rss/rssparser.cpp → src/base/rss/private/rssparser.cpp

@ -29,21 +29,26 @@ @@ -29,21 +29,26 @@
*/
#include <QDebug>
#include <QDateTime>
#include <QFile>
#include <QRegExp>
#include <QStringList>
#include <QVariant>
#include <QXmlStreamReader>
#include "base/utils/fs.h"
#include "rssparser.h"
namespace Rss
{
struct ParsingJob
namespace Private
{
QString feedUrl;
QString filePath;
};
struct ParsingJob
{
QString feedUrl;
QByteArray feedData;
};
}
}
static const char shortDay[][4] = {
@ -64,7 +69,7 @@ static const char shortMonth[][4] = { @@ -64,7 +69,7 @@ static const char shortMonth[][4] = {
"Sep", "Oct", "Nov", "Dec"
};
using namespace Rss;
using namespace Rss::Private;
Parser::Parser(QObject *parent)
: QThread(parent)
@ -227,11 +232,11 @@ QDateTime Parser::parseDate(const QString &string) @@ -227,11 +232,11 @@ QDateTime Parser::parseDate(const QString &string)
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();
ParsingJob job = { feedUrl, Utils::Fs::fromNativePath(filePath) };
ParsingJob job = { feedUrl, feedData };
m_queue.enqueue(job);
// Wake up thread.
if (m_queue.count() == 1) {
@ -487,14 +492,9 @@ void Parser::parseAtomChannel(QXmlStreamReader &xml, const QString &feedUrl) @@ -487,14 +492,9 @@ void Parser::parseAtomChannel(QXmlStreamReader &xml, const QString &feedUrl)
// read and create items from a rss document
void Parser::parseFeed(const ParsingJob &job)
{
qDebug() << Q_FUNC_INFO << job.feedUrl << job.filePath;
QFile fileRss(job.filePath);
if (!fileRss.open(QIODevice::ReadOnly | QIODevice::Text)) {
reportFailure(job, tr("Failed to open downloaded RSS file."));
return;
}
qDebug() << Q_FUNC_INFO << job.feedUrl;
QXmlStreamReader xml(&fileRss);
QXmlStreamReader xml(job.feedData);
bool foundChannel = false;
while (xml.readNextStartElement()) {
if (xml.name() == "rss") {
@ -533,14 +533,10 @@ void Parser::parseFeed(const ParsingJob &job) @@ -533,14 +533,10 @@ void Parser::parseFeed(const ParsingJob &job)
return;
}
// Clean up
fileRss.close();
emit feedParsingFinished(job.feedUrl, QString());
Utils::Fs::forceRemove(job.filePath);
}
void Parser::reportFailure(const ParsingJob &job, const QString &error)
{
emit feedParsingFinished(job.feedUrl, error);
Utils::Fs::forceRemove(job.filePath);
}

66
src/base/rss/rssparser.h → src/base/rss/private/rssparser.h

@ -31,52 +31,56 @@ @@ -31,52 +31,56 @@
#ifndef RSSPARSER_H
#define RSSPARSER_H
#include <QHash>
#include <QMutex>
#include <QQueue>
#include <QThread>
#include <QVariantHash>
#include <QWaitCondition>
#include "rssarticle.h"
class QXmlStreamReader;
namespace Rss
{
struct ParsingJob;
class Parser: public QThread
namespace Private
{
Q_OBJECT
struct ParsingJob;
class Parser: public QThread
{
Q_OBJECT
public:
explicit Parser(QObject *parent = 0);
~Parser();
public:
explicit Parser(QObject *parent = 0);
virtual ~Parser();
void parseFeedData(const QString &feedUrl, const QByteArray &feedData);
void clearFeedData(const QString &feedUrl);
signals:
void newArticle(const QString &feedUrl, const QVariantHash &rssArticle);
void feedTitle(const QString &feedUrl, const QString &title);
void feedParsingFinished(const QString &feedUrl, const QString &error);
signals:
void newArticle(const QString &feedUrl, const QVariantHash &rssArticle);
void feedTitle(const QString &feedUrl, const QString &title);
void feedParsingFinished(const QString &feedUrl, const QString &error);
public slots:
void parseRssFile(const QString &feedUrl, const QString &filePath);
void clearFeedData(const QString &feedUrl);
private:
void run() override;
protected:
virtual void run();
static QDateTime parseDate(const QString &string);
private:
static QDateTime parseDate(const QString &string);
void parseRssArticle(QXmlStreamReader &xml, const QString &feedUrl);
void parseRSSChannel(QXmlStreamReader &xml, const QString &feedUrl);
void parseAtomArticle(QXmlStreamReader &xml, const QString &feedUrl, const QString &baseUrl);
void parseAtomChannel(QXmlStreamReader &xml, const QString &feedUrl);
void parseFeed(const ParsingJob &job);
void reportFailure(const ParsingJob &job, const QString &error);
void parseRssArticle(QXmlStreamReader &xml, const QString &feedUrl);
void parseRSSChannel(QXmlStreamReader &xml, const QString &feedUrl);
void parseAtomArticle(QXmlStreamReader &xml, const QString &feedUrl, const QString &baseUrl);
void parseAtomChannel(QXmlStreamReader &xml, const QString &feedUrl);
void parseFeed(const ParsingJob &job);
void reportFailure(const ParsingJob &job, const QString &error);
bool m_running;
QMutex m_mutex;
QQueue<ParsingJob> m_queue;
QWaitCondition m_waitCondition;
QHash<QString/*feedUrl*/, QString/*lastBuildDate*/> m_lastBuildDates; // Optimization
};
bool m_running;
QMutex m_mutex;
QQueue<ParsingJob> m_queue;
QWaitCondition m_waitCondition;
QHash<QString/*feedUrl*/, QString/*lastBuildDate*/> m_lastBuildDates; // Optimization
};
}
}
#endif // RSSPARSER_H

10
src/base/rss/rssarticle.cpp

@ -120,12 +120,10 @@ bool Article::isRead() const @@ -120,12 +120,10 @@ bool Article::isRead() const
void Article::markAsRead()
{
if (m_read) return;
m_read = true;
m_parent->decrementUnreadCount();
m_parent->markAsDirty();
emit articleWasRead();
if (!m_read) {
m_read = true;
emit articleWasRead();
}
}
const QString &Article::guid() const

1
src/base/rss/rssarticle.h

@ -32,7 +32,6 @@ @@ -32,7 +32,6 @@
#ifndef RSSARTICLE_H
#define RSSARTICLE_H
#include <QXmlStreamReader>
#include <QDateTime>
#include <QVariantHash>
#include <QSharedPointer>

101
src/base/rss/rssfeed.cpp

@ -40,9 +40,9 @@ @@ -40,9 +40,9 @@
#include "base/utils/fs.h"
#include "base/net/downloadmanager.h"
#include "base/net/downloadhandler.h"
#include "private/rssparser.h"
#include "rssdownloadrulelist.h"
#include "rssarticle.h"
#include "rssparser.h"
#include "rssfolder.h"
#include "rssmanager.h"
#include "rssfeed.h"
@ -57,9 +57,8 @@ namespace Rss @@ -57,9 +57,8 @@ 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_parent(parent)
, m_url (QUrl::fromEncoded(url.toUtf8()).toString())
, m_icon(":/icons/oxygen/application-rss+xml.png")
, m_unreadCount(0)
@ -69,34 +68,26 @@ Feed::Feed(Manager *manager, Folder *parent, const QString &url) @@ -69,34 +68,26 @@ Feed::Feed(Manager *manager, Folder *parent, const QString &url)
{
qDebug() << Q_FUNC_INFO << m_url;
// Listen for new RSS downloads
connect(manager->rssParser(), SIGNAL(feedTitle(QString,QString)), SLOT(handleFeedTitle(QString,QString)));
connect(manager->rssParser(), SIGNAL(newArticle(QString,QVariantHash)), SLOT(handleNewArticle(QString,QVariantHash)));
connect(manager->rssParser(), SIGNAL(feedParsingFinished(QString,QString)), SLOT(handleFeedParsingFinished(QString,QString)));
Private::Parser *const parser = m_manager->rssParser();
connect(parser, SIGNAL(feedTitle(QString,QString)), SLOT(handleFeedTitle(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
Net::DownloadHandler *handler = Net::DownloadManager::instance()->downloadUrl(iconUrl(), true);
connect(handler, SIGNAL(downloadFinished(QString, QString)), this, SLOT(handleFinishedDownload(QString, QString)));
connect(handler, SIGNAL(downloadFailed(QString, QString)), this, SLOT(handleDownloadFailure(QString, QString)));
m_iconUrl = handler->url();
connect(handler, SIGNAL(downloadFinished(QString, QString)), this, SLOT(handleIconDownloadFinished(QString, QString)));
// Load old RSS articles
loadItemsFromDisk();
refresh();
}
Feed::~Feed()
{
if (!m_icon.startsWith(":/") && QFile::exists(m_icon))
Utils::Fs::forceRemove(m_icon);
}
Folder *Feed::parent() const
{
return m_parent;
}
void Feed::setParent(Folder *parent)
{
m_parent = parent;
m_manager->rssParser()->clearFeedData(m_url);
}
void Feed::saveItemsToDisk()
@ -104,7 +95,7 @@ void Feed::saveItemsToDisk() @@ -104,7 +95,7 @@ void Feed::saveItemsToDisk()
qDebug() << Q_FUNC_INFO << m_url;
if (!m_dirty) return;
markAsDirty(false);
m_dirty = false;
QIniSettings qBTRSS("qBittorrent", "qBittorrent-rss");
QVariantList oldItems;
@ -140,13 +131,15 @@ void Feed::addArticle(const ArticlePtr &article) @@ -140,13 +131,15 @@ void Feed::addArticle(const ArticlePtr &article)
int maxArticles = Preferences::instance()->getRSSMaxArticlesPerFeed();
if (!m_articles.contains(article->guid())) {
markAsDirty();
m_dirty = true;
// Update unreadCount
if (!article->isRead())
++m_unreadCount;
// Insert in hash table
m_articles[article->guid()] = article;
if (!article->isRead()) // Optimization
connect(article.data(), SIGNAL(articleWasRead()), SLOT(handleArticleRead()), Qt::UniqueConnection);
// Insertion sort
ArticleList::Iterator lowerBound = qLowerBound(m_articlesByDate.begin(), m_articlesByDate.end(), article, articleDateRecentThan);
m_articlesByDate.insert(lowerBound, article);
@ -162,7 +155,7 @@ void Feed::addArticle(const ArticlePtr &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
if (Preferences::instance()->isRssDownloadingEnabled()) {
if ((lbIndex < maxArticles) && !article->isRead())
downloadArticleTorrentIfMatching(m_manager->downloadRules(), article);
downloadArticleTorrentIfMatching(article);
}
}
else {
@ -172,7 +165,7 @@ void Feed::addArticle(const ArticlePtr &article) @@ -172,7 +165,7 @@ void Feed::addArticle(const ArticlePtr &article)
ArticlePtr skipped = m_articles.value(article->guid(), ArticlePtr());
if (skipped) {
if (!skipped->isRead())
downloadArticleTorrentIfMatching(m_manager->downloadRules(), skipped);
downloadArticleTorrentIfMatching(skipped);
}
}
}
@ -186,10 +179,9 @@ bool Feed::refresh() @@ -186,10 +179,9 @@ bool Feed::refresh()
}
m_loading = true;
// Download the RSS again
Net::DownloadHandler *handler = Net::DownloadManager::instance()->downloadUrl(m_url, true);
connect(handler, SIGNAL(downloadFinished(QString, QString)), this, SLOT(handleFinishedDownload(QString, QString)));
connect(handler, SIGNAL(downloadFailed(QString, QString)), this, SLOT(handleDownloadFailure(QString, QString)));
m_url = handler->url(); // sync URL encoding
Net::DownloadHandler *handler = Net::DownloadManager::instance()->downloadUrl(m_url);
connect(handler, SIGNAL(downloadFinished(QString, QByteArray)), this, SLOT(handleRssDownloadFinished(QString, QByteArray)));
connect(handler, SIGNAL(downloadFailed(QString, QString)), this, SLOT(handleRssDownloadFailed(QString, QString)));
return true;
}
@ -290,11 +282,6 @@ void Feed::markAsRead() @@ -290,11 +282,6 @@ void Feed::markAsRead()
m_manager->forwardFeedInfosChanged(m_url, displayName(), 0);
}
void Feed::markAsDirty(bool dirty)
{
m_dirty = dirty;
}
uint Feed::unreadCount() const
{
return m_unreadCount;
@ -327,28 +314,27 @@ ArticleList Feed::unreadArticleListByDateDesc() const @@ -327,28 +314,27 @@ ArticleList Feed::unreadArticleListByDateDesc() const
QString Feed::iconUrl() const
{
// 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::handleFinishedDownload(const QString &url, const QString &filePath)
void Feed::handleIconDownloadFinished(const QString &url, const QString &filePath)
{
if (url == m_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;
qDebug() << Q_FUNC_INFO << "icon path:" << m_icon;
m_manager->forwardFeedIconChanged(m_url, m_icon);
}
Q_UNUSED(url);
m_icon = filePath;
qDebug() << Q_FUNC_INFO << "icon path:" << m_icon;
m_manager->forwardFeedIconChanged(m_url, m_icon);
}
void Feed::handleDownloadFailure(const QString &url, const QString &error)
void Feed::handleRssDownloadFinished(const QString &url, const QByteArray &data)
{
if (url != m_url) return;
qDebug() << Q_FUNC_INFO << "Successfully downloaded RSS feed at" << url;
// Parse the download RSS
m_manager->rssParser()->parseFeedData(m_url, data);
}
void Feed::handleRssDownloadFailed(const QString &url, const QString &error)
{
m_inErrorState = true;
m_loading = false;
m_manager->forwardFeedInfosChanged(m_url, displayName(), m_unreadCount);
@ -368,9 +354,10 @@ void Feed::handleFeedTitle(const QString &feedUrl, const QString &title) @@ -368,9 +354,10 @@ void Feed::handleFeedTitle(const QString &feedUrl, const QString &title)
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());
DownloadRuleList *rules = m_manager->downloadRules();
DownloadRulePtr matchingRule = rules->findMatchingRule(m_url, article->title());
if (!matchingRule) return;
@ -378,7 +365,6 @@ void Feed::downloadArticleTorrentIfMatching(DownloadRuleList *rules, const Artic @@ -378,7 +365,6 @@ void Feed::downloadArticleTorrentIfMatching(DownloadRuleList *rules, const Artic
QDateTime lastMatch = matchingRule->lastMatch();
if (lastMatch.isValid()) {
if (QDateTime::currentDateTime() < lastMatch.addDays(matchingRule->ignoreDays())) {
connect(article.data(), SIGNAL(articleWasRead()), SLOT(handleArticleStateChanged()), Qt::UniqueConnection);
article->markAsRead();
return;
}
@ -396,8 +382,7 @@ void Feed::downloadArticleTorrentIfMatching(DownloadRuleList *rules, const Artic @@ -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()));
connect(BitTorrent::Session::instance(), SIGNAL(downloadFromUrlFinished(QString)), article.data(), SLOT(handleTorrentDownloadSuccess(const QString &)), Qt::UniqueConnection);
if (BitTorrent::MagnetUri(torrent_url).isValid())
if (BitTorrent::MagnetUri(torrentUrl).isValid())
article->markAsRead();
else
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 @@ -415,10 +400,9 @@ void Feed::downloadArticleTorrentIfMatching(DownloadRuleList *rules, const Artic
void Feed::recheckRssItemsForDownload()
{
Q_ASSERT(Preferences::instance()->isRssDownloadingEnabled());
DownloadRuleList *rules = m_manager->downloadRules();
foreach (const ArticlePtr &article, m_articlesByDate) {
if (!article->isRead())
downloadArticleTorrentIfMatching(rules, article);
downloadArticleTorrentIfMatching(article);
}
}
@ -440,7 +424,7 @@ void Feed::handleNewArticle(const QString &feedUrl, const QVariantHash &articleD @@ -440,7 +424,7 @@ void Feed::handleNewArticle(const QString &feedUrl, const QVariantHash &articleD
//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;
@ -459,12 +443,9 @@ void Feed::handleFeedParsingFinished(const QString &feedUrl, const QString &erro @@ -459,12 +443,9 @@ void Feed::handleFeedParsingFinished(const QString &feedUrl, const QString &erro
saveItemsToDisk();
}
void Feed::handleArticleStateChanged()
{
m_manager->forwardFeedInfosChanged(m_url, displayName(), m_unreadCount);
}
void Feed::decrementUnreadCount()
void Feed::handleArticleRead()
{
--m_unreadCount;
m_dirty = true;
m_manager->forwardFeedInfosChanged(m_url, displayName(), m_unreadCount);
}

19
src/base/rss/rssfeed.h

@ -58,11 +58,9 @@ namespace Rss @@ -58,11 +58,9 @@ namespace Rss
Q_OBJECT
public:
Feed(Manager *manager, Folder *parent, const QString &url);
Feed(const QString &url, Manager *manager);
~Feed();
Folder *parent() const;
void setParent(Folder *parent);
bool refresh();
QString id() const;
void removeAllSettings();
@ -78,38 +76,35 @@ namespace Rss @@ -78,38 +76,35 @@ namespace Rss
ArticlePtr getItem(const QString &guid) const;
uint count() const;
void markAsRead();
void markAsDirty(bool dirty = true);
uint unreadCount() const;
ArticleList articleListByDateDesc() const;
const ArticleHash &articleHash() const;
ArticleList unreadArticleListByDateDesc() const;
void decrementUnreadCount();
void recheckRssItemsForDownload();
private slots:
void handleFinishedDownload(const QString &url, const QString &filePath);
void handleDownloadFailure(const QString &url, const QString &error);
void handleIconDownloadFinished(const QString &url, const QString &filePath);
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 handleNewArticle(const QString &feedUrl, const QVariantHash &article);
void handleFeedParsingFinished(const QString &feedUrl, const QString &error);
void handleArticleStateChanged();
void handleParsingFinished(const QString &feedUrl, const QString &error);
void handleArticleRead();
private:
QString iconUrl() const;
void loadItemsFromDisk();
void addArticle(const ArticlePtr &article);
void downloadArticleTorrentIfMatching(DownloadRuleList *rules, const ArticlePtr &article);
void downloadArticleTorrentIfMatching(const ArticlePtr &article);
private:
Manager *m_manager;
ArticleHash m_articles;
ArticleList m_articlesByDate; // Articles sorted by date (more recent first)
Folder *m_parent;
QString m_title;
QString m_url;
QString m_alias;
QString m_icon;
QString m_iconUrl;
uint m_unreadCount;
bool m_dirty;
bool m_inErrorState;

9
src/base/rss/rssfile.cpp

@ -36,11 +36,16 @@ using namespace Rss; @@ -36,11 +36,16 @@ using namespace Rss;
File::~File() {}
Folder *File::parentFolder() const
{
return m_parent;
}
QStringList File::pathHierarchy() const
{
QStringList path;
if (parent())
path << parent()->pathHierarchy();
if (m_parent)
path << m_parent->pathHierarchy();
path << id();
return path;
}

16
src/base/rss/rssfile.h

@ -55,25 +55,27 @@ namespace Rss @@ -55,25 +55,27 @@ namespace Rss
public:
virtual ~File();
virtual uint unreadCount() const = 0;
virtual QString displayName() const = 0;
virtual QString id() const = 0;
virtual QString displayName() const = 0;
virtual uint unreadCount() const = 0;
virtual QString iconPath() const = 0;
virtual ArticleList articleListByDateDesc() const = 0;
virtual ArticleList unreadArticleListByDateDesc() 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 unreadArticleListByDateDesc() const = 0;
virtual void removeAllSettings() = 0;
virtual void saveItemsToDisk() = 0;
virtual void recheckRssItemsForDownload() = 0;
Folder *parentFolder() const;
QStringList pathHierarchy() const;
protected:
uint m_unreadCount;
friend class Folder;
Folder *m_parent = nullptr;
};
}

78
src/base/rss/rssfolder.cpp

@ -40,24 +40,11 @@ @@ -40,24 +40,11 @@
using namespace Rss;
Folder::Folder(Folder *parent, const QString &name)
: m_parent(parent)
, m_name(name)
Folder::Folder(const QString &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 nbUnread = 0;
@ -78,31 +65,6 @@ void Folder::removeChild(const QString &childId) @@ -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
bool Folder::refresh()
{
@ -176,7 +138,8 @@ void Folder::rename(const QString &newName) @@ -176,7 +138,8 @@ void Folder::rename(const QString &newName)
Q_ASSERT(!m_parent->hasChild(newName));
if (!m_parent->hasChild(newName)) {
// 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
m_name = newName;
}
@ -224,20 +187,17 @@ QHash<QString, FeedPtr> Folder::getAllFeedsAsHash() const @@ -224,20 +187,17 @@ QHash<QString, FeedPtr> Folder::getAllFeedsAsHash() const
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(feed->url()));
m_children[feed->url()] = 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));
Q_ASSERT(!m_children.contains(item->id()));
if (!m_children.contains(item->id())) {
m_children[item->id()] = item;
// Update parent
item->m_parent = this;
return true;
}
// Update parent
item->setParent(this);
return false;
}
void Folder::removeAllItems()
@ -245,6 +205,11 @@ void Folder::removeAllItems() @@ -245,6 +205,11 @@ void Folder::removeAllItems()
m_children.clear();
}
FilePtr Folder::child(const QString &childId)
{
return m_children.value(childId);
}
void Folder::removeAllSettings()
{
FileHash::ConstIterator it = m_children.begin();
@ -274,13 +239,6 @@ bool Folder::hasChild(const QString &childId) @@ -274,13 +239,6 @@ bool Folder::hasChild(const QString &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)
{
return m_children.take(childId);

27
src/base/rss/rssfolder.h

@ -48,19 +48,12 @@ namespace Rss @@ -48,19 +48,12 @@ namespace Rss
typedef QSharedPointer<Folder> FolderPtr;
typedef QList<FeedPtr> FeedList;
class Folder: public QObject, public File
class Folder: public File
{
Q_OBJECT
public:
explicit Folder(Folder *parent = 0, const QString &name = QString());
~Folder();
explicit Folder(const QString &name = QString());
Folder *parent() const;
void setParent(Folder *parent);
uint unreadCount() const;
FeedPtr addStream(Manager *manager, const QString &url);
FolderPtr addFolder(const QString &name);
uint getNbFeeds() const;
FileList getContent() const;
FeedList getAllFeeds() const;
@ -71,22 +64,20 @@ namespace Rss @@ -71,22 +64,20 @@ namespace Rss
bool hasChild(const QString &childId);
ArticleList articleListByDateDesc() const;
ArticleList unreadArticleListByDateDesc() const;
void rename(const QString &newName);
void markAsRead();
bool refresh();
void removeAllSettings();
void saveItemsToDisk();
void recheckRssItemsForDownload();
void removeAllItems();
void renameChildFolder(const QString &oldName, const QString &newName);
FilePtr child(const QString &childId);
FilePtr takeChild(const QString &childId);
void recheckRssItemsForDownload();
public slots:
bool refresh();
void addFile(const FilePtr &item);
bool addFile(const FilePtr &item);
void removeChild(const QString &childId);
void rename(const QString &newName);
void markAsRead();
private:
Folder *m_parent;
QString m_name;
FileHash m_children;
};

53
src/base/rss/rssmanager.cpp

@ -33,19 +33,23 @@ @@ -33,19 +33,23 @@
#include "base/logger.h"
#include "base/preferences.h"
#include "private/rssparser.h"
#include "rssfolder.h"
#include "rssfeed.h"
#include "rssarticle.h"
#include "rssdownloadrulelist.h"
#include "rssparser.h"
#include "rssmanager.h"
static const int MSECS_PER_MIN = 60000;
using namespace Rss;
using namespace Rss::Private;
Manager::Manager()
: m_downloadRules(new DownloadRuleList)
Manager::Manager(QObject *parent)
: QObject(parent)
, m_downloadRules(new DownloadRuleList)
, m_rssParser(new Parser(this))
, m_rootFolder(new Folder)
{
connect(&m_refreshTimer, SIGNAL(timeout()), SLOT(refresh()));
m_refreshInterval = Preferences::instance()->getRSSRefreshInterval();
@ -57,16 +61,12 @@ Manager::~Manager() @@ -57,16 +61,12 @@ Manager::~Manager()
qDebug("Deleting RSSManager...");
delete m_downloadRules;
delete m_rssParser;
saveItemsToDisk();
m_rootFolder->saveItemsToDisk();
saveStreamList();
m_rootFolder.clear();
qDebug("RSSManager deleted");
}
Parser *Manager::rssParser() const
{
return m_rssParser;
}
void Manager::updateRefreshInterval(uint val)
{
if (m_refreshInterval != val) {
@ -95,14 +95,22 @@ void Manager::loadStreamList() @@ -95,14 +95,22 @@ void Manager::loadStreamList()
const QString feedUrl = path.takeLast();
qDebug() << "Feed URL:" << feedUrl;
// Create feed path (if it does not exists)
Folder *feedParent = this;
FolderPtr feedParent = m_rootFolder;
foreach (const QString &folderName, path) {
qDebug() << "Adding parent folder:" << folderName;
feedParent = feedParent->addFolder(folderName).data();
if (!feedParent->hasChild(folderName)) {
qDebug() << "Adding parent folder:" << folderName;
FolderPtr folder(new Folder(folderName));
feedParent->addFile(folder);
feedParent = folder;
}
else {
feedParent = qSharedPointerDynamicCast<Folder>(feedParent->child(folderName));
}
}
// Create feed
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];
if (!alias.isEmpty())
stream->rename(alias);
@ -128,7 +136,7 @@ void Manager::forwardFeedIconChanged(const QString &url, const QString &iconPath @@ -128,7 +136,7 @@ void Manager::forwardFeedIconChanged(const QString &url, const QString &iconPath
void Manager::moveFile(const FilePtr &file, const FolderPtr &destinationFolder)
{
Folder *srcFolder = file->parent();
Folder *srcFolder = file->parentFolder();
if (destinationFolder != srcFolder) {
// Remove reference in old folder
srcFolder->takeChild(file->id());
@ -144,7 +152,7 @@ void Manager::saveStreamList() const @@ -144,7 +152,7 @@ void Manager::saveStreamList() const
{
QStringList streamsUrl;
QStringList aliases;
FeedList streams = getAllFeeds();
FeedList streams = m_rootFolder->getAllFeeds();
foreach (const FeedPtr &stream, streams) {
// This backslash has nothing to do with path handling
QString streamPath = stream->pathHierarchy().join("\\");
@ -164,3 +172,18 @@ DownloadRuleList *Manager::downloadRules() const @@ -164,3 +172,18 @@ DownloadRuleList *Manager::downloadRules() const
Q_ASSERT(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();
}

28
src/base/rss/rssmanager.h

@ -32,31 +32,44 @@ @@ -32,31 +32,44 @@
#ifndef RSSMANAGER_H
#define RSSMANAGER_H
#include <QObject>
#include <QTimer>
#include <QSharedPointer>
#include "rssfolder.h"
namespace Rss
{
class DownloadRuleList;
class Parser;
class File;
class Folder;
class Feed;
class Manager;
typedef QSharedPointer<File> FilePtr;
typedef QSharedPointer<Folder> FolderPtr;
typedef QSharedPointer<Feed> FeedPtr;
namespace Private
{
class Parser;
}
typedef QSharedPointer<Manager> ManagerPtr;
class Manager: public Folder
class Manager: public QObject
{
Q_OBJECT
public:
Manager();
explicit Manager(QObject *parent = 0);
~Manager();
Parser *rssParser() const;
DownloadRuleList *downloadRules() const;
FolderPtr rootFolder() const;
Private::Parser *rssParser() const;
public slots:
void refresh();
void loadStreamList();
void saveStreamList() const;
void forwardFeedContentChanged(const QString &url);
@ -74,7 +87,8 @@ namespace Rss @@ -74,7 +87,8 @@ namespace Rss
QTimer m_refreshTimer;
uint m_refreshInterval;
DownloadRuleList *m_downloadRules;
Parser *m_rssParser;
Private::Parser *m_rssParser;
FolderPtr m_rootFolder;
};
}

3
src/gui/rss/automatedrssdownloader.cpp

@ -39,6 +39,7 @@ @@ -39,6 +39,7 @@
#include "base/rss/rssdownloadrulelist.h"
#include "base/preferences.h"
#include "base/rss/rssmanager.h"
#include "base/rss/rssfolder.h"
#include "base/rss/rssfeed.h"
#include "guiiconprovider.h"
#include "autoexpandabledialog.h"
@ -524,7 +525,7 @@ void AutomatedRssDownloader::updateMatchingArticles() @@ -524,7 +525,7 @@ void AutomatedRssDownloader::updateMatchingArticles()
Rss::ManagerPtr manager = m_manager.toStrongRef();
if (!manager)
return;
const QHash<QString, Rss::FeedPtr> all_feeds = manager->getAllFeedsAsHash();
const QHash<QString, Rss::FeedPtr> all_feeds = manager->rootFolder()->getAllFeedsAsHash();
saveEditedRule();
foreach (const QListWidgetItem *rule_item, ui->listRules->selectedItems()) {

7
src/gui/rss/feedlistwidget.cpp

@ -29,6 +29,7 @@ @@ -29,6 +29,7 @@
*/
#include "base/rss/rssmanager.h"
#include "base/rss/rssfolder.h"
#include "base/rss/rssfeed.h"
#include "guiiconprovider.h"
#include "feedlistwidget.h"
@ -40,9 +41,9 @@ FeedListWidget::FeedListWidget(QWidget *parent, const Rss::ManagerPtr& rssmanage @@ -40,9 +41,9 @@ FeedListWidget::FeedListWidget(QWidget *parent, const Rss::ManagerPtr& rssmanage
setColumnCount(1);
headerItem()->setText(0, tr("RSS feeds"));
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"));
itemAdded(m_unreadStickyItem, rssmanager);
itemAdded(m_unreadStickyItem, rssmanager->rootFolder());
connect(this, SIGNAL(currentItemChanged(QTreeWidgetItem*,QTreeWidgetItem*)), SLOT(updateCurrentFeed(QTreeWidgetItem*)));
setCurrentItem(m_unreadStickyItem);
}
@ -202,7 +203,7 @@ void FeedListWidget::dropEvent(QDropEvent *event) { @@ -202,7 +203,7 @@ void FeedListWidget::dropEvent(QDropEvent *event) {
dest_folder = qSharedPointerCast<Rss::Folder>(getRSSItem(dest_folder_item));
folders_altered << dest_folder_item;
} else {
dest_folder = m_rssManager;
dest_folder = m_rssManager->rootFolder();
}
QList<QTreeWidgetItem *> src_items = selectedItems();
// Check if there is not going to overwrite another file

36
src/gui/rss/rss_imp.cpp

@ -47,7 +47,6 @@ @@ -47,7 +47,6 @@
#include "base/rss/rssmanager.h"
#include "base/rss/rssfolder.h"
#include "base/rss/rssarticle.h"
#include "base/rss/rssparser.h"
#include "base/rss/rssfeed.h"
#include "automatedrssdownloader.h"
#include "guiiconprovider.h"
@ -79,7 +78,7 @@ void RSSImp::displayRSSListMenu(const QPoint& pos) @@ -79,7 +78,7 @@ void RSSImp::displayRSSListMenu(const QPoint& pos)
myRSSListMenu.addAction(actionMark_items_read);
myRSSListMenu.addSeparator();
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(actionDelete);
myRSSListMenu.addSeparator();
@ -167,14 +166,15 @@ void RSSImp::askNewFolder() @@ -167,14 +166,15 @@ void RSSImp::askNewFolder()
Q_ASSERT(rss_parent);
}
else {
rss_parent = m_rssManager;
rss_parent = m_rssManager->rootFolder();
}
bool 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;
Rss::FolderPtr newFolder = rss_parent->addFolder(new_name);
Rss::FolderPtr newFolder(new Rss::Folder(new_name));
rss_parent->addFile(newFolder);
QTreeWidgetItem* folderItem = createFolderListItem(newFolder);
if (parent_item)
parent_item->addChild(folderItem);
@ -207,7 +207,7 @@ void RSSImp::on_newFeedButton_clicked() @@ -207,7 +207,7 @@ void RSSImp::on_newFeedButton_clicked()
if (parent_item)
rss_parent = qSharedPointerCast<Rss::Folder>(m_feedList->getRSSItem(parent_item));
else
rss_parent = m_rssManager;
rss_parent = m_rssManager->rootFolder();
// Ask for feed URL
bool ok;
QString clip_txt = qApp->clipboard()->text();
@ -229,7 +229,9 @@ void RSSImp::on_newFeedButton_clicked() @@ -229,7 +229,9 @@ void RSSImp::on_newFeedButton_clicked()
QMessageBox::Ok);
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
QTreeWidgetItem* item = createFolderListItem(stream);
if (parent_item)
@ -265,17 +267,13 @@ void RSSImp::deleteSelectedItems() @@ -265,17 +267,13 @@ void RSSImp::deleteSelectedItems()
// Notify TreeWidget
m_feedList->itemAboutToBeRemoved(item);
// Actually delete the item
rss_item->parent()->removeChild(rss_item->id());
rss_item->parentFolder()->removeChild(rss_item->id());
delete item;
// Update parents count
while (parent && parent != m_feedList->invisibleRootItem()) {
updateItemInfos (parent);
while (parent && (parent != m_feedList->invisibleRootItem())) {
updateItemInfos(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();
// Update Unread items
@ -406,7 +404,7 @@ void RSSImp::renameSelectedRssFile() @@ -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);
// Check if name is already taken
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."));
ok = false;
}
@ -489,7 +487,7 @@ void RSSImp::fillFeedsList(QTreeWidgetItem* parent, const Rss::FolderPtr& rss_pa @@ -489,7 +487,7 @@ void RSSImp::fillFeedsList(QTreeWidgetItem* parent, const Rss::FolderPtr& rss_pa
if (parent)
children = rss_parent->getContent();
else
children = m_rssManager->getContent();
children = m_rssManager->rootFolder()->getContent();
foreach (const Rss::FilePtr& rssFile, children) {
QTreeWidgetItem* item = createFolderListItem(rssFile);
Q_ASSERT(item);
@ -546,7 +544,7 @@ void RSSImp::populateArticleList(QTreeWidgetItem* item) @@ -546,7 +544,7 @@ void RSSImp::populateArticleList(QTreeWidgetItem* item)
qDebug("Getting the list of news");
Rss::ArticleList articles;
if (rss_item == m_rssManager)
if (rss_item == m_rssManager->rootFolder())
articles = rss_item->unreadArticleListByDateDesc();
else
articles = rss_item->articleListByDateDesc();
@ -655,7 +653,7 @@ void RSSImp::updateItemInfos(QTreeWidgetItem *item) @@ -655,7 +653,7 @@ void RSSImp::updateItemInfos(QTreeWidgetItem *item)
return;
QString name;
if (rss_item == m_rssManager) {
if (rss_item == m_rssManager->rootFolder()) {
name = tr("Unread");
emit updateRSSCount(rss_item->unreadCount());
}
@ -799,7 +797,7 @@ void RSSImp::on_rssDownloaderBtn_clicked() @@ -799,7 +797,7 @@ void RSSImp::on_rssDownloaderBtn_clicked()
AutomatedRssDownloader dlg(m_rssManager, this);
dlg.exec();
if (dlg.isRssDownloaderEnabled()) {
m_rssManager->recheckRssItemsForDownload();
m_rssManager->rootFolder()->recheckRssItemsForDownload();
refreshAllFeeds();
}
}

Loading…
Cancel
Save