1
0
mirror of https://github.com/d47081/qBittorrent.git synced 2025-01-11 07:18:08 +00:00

Fix possible rule saving issue

Matching articles are now previewable in the rss downloader dialog
Make sure Rss downloading is enabled before checking for matching rules
This commit is contained in:
Christophe Dumez 2010-11-13 19:36:46 +00:00
parent 345222cf42
commit c387c15eb0
18 changed files with 174 additions and 48 deletions

View File

@ -131,7 +131,7 @@ GUI::GUI(QWidget *parent, QStringList torrentCmdLine) : QMainWindow(parent), for
// Fix Tool bar layout // Fix Tool bar layout
toolBar->layout()->setSpacing(7); toolBar->layout()->setSpacing(7);
// Creating Bittorrent session // Creating Bittorrent session
BTSession = new QBtSession(); BTSession = QBtSession::instance();
connect(BTSession, SIGNAL(fullDiskError(QTorrentHandle&, QString)), this, SLOT(fullDiskError(QTorrentHandle&, QString))); connect(BTSession, SIGNAL(fullDiskError(QTorrentHandle&, QString)), this, SLOT(fullDiskError(QTorrentHandle&, QString)));
connect(BTSession, SIGNAL(finishedTorrent(QTorrentHandle&)), this, SLOT(finishedTorrent(QTorrentHandle&))); connect(BTSession, SIGNAL(finishedTorrent(QTorrentHandle&)), this, SLOT(finishedTorrent(QTorrentHandle&)));
connect(BTSession, SIGNAL(trackerAuthenticationRequired(QTorrentHandle&)), this, SLOT(trackerAuthenticationRequired(QTorrentHandle&))); connect(BTSession, SIGNAL(trackerAuthenticationRequired(QTorrentHandle&)), this, SLOT(trackerAuthenticationRequired(QTorrentHandle&)));
@ -277,11 +277,6 @@ GUI::~GUI() {
// Workaround to avoid bug http://bugreports.qt.nokia.com/browse/QTBUG-7305 // Workaround to avoid bug http://bugreports.qt.nokia.com/browse/QTBUG-7305
setUnifiedTitleAndToolBarOnMac(false); setUnifiedTitleAndToolBarOnMac(false);
#endif #endif
// Async deletion of Bittorrent session as early as possible
// in order to speed up exit
session_proxy sp;
if(BTSession)
sp = BTSession->asyncDeletion();
// Some saving // Some saving
properties->saveSettings(); properties->saveSettings();
disconnect(tabs, SIGNAL(currentChanged(int)), this, SLOT(tab_changed(int))); disconnect(tabs, SIGNAL(currentChanged(int)), this, SLOT(tab_changed(int)));
@ -328,7 +323,7 @@ GUI::~GUI() {
delete switchRSSShortcut; delete switchRSSShortcut;
// Delete BTSession objects // Delete BTSession objects
qDebug("Deleting BTSession"); qDebug("Deleting BTSession");
delete BTSession; QBtSession::drop();
// May freeze for a few seconds after the next line // May freeze for a few seconds after the next line
// because the Bittorrent session proxy will // because the Bittorrent session proxy will
// actually be deleted now and destruction // actually be deleted now and destruction

View File

@ -44,7 +44,7 @@ public:
// Enable Web UI // Enable Web UI
Preferences::setWebUiEnabled(true); Preferences::setWebUiEnabled(true);
// Instanciate Bittorrent Object // Instanciate Bittorrent Object
BTSession = new QBtSession(); BTSession = QBtSession::instance();
connect(BTSession, SIGNAL(newConsoleMessage(QString)), this, SLOT(displayConsoleMessage(QString))); connect(BTSession, SIGNAL(newConsoleMessage(QString)), this, SLOT(displayConsoleMessage(QString)));
// Resume unfinished torrents // Resume unfinished torrents
BTSession->startUpTorrents(); BTSession->startUpTorrents();
@ -61,7 +61,7 @@ public:
} }
~HeadlessLoader() { ~HeadlessLoader() {
delete BTSession; QBtSession::drop();
} }
public slots: public slots:

View File

@ -68,6 +68,8 @@
#include <boost/filesystem/exception.hpp> #include <boost/filesystem/exception.hpp>
#include <queue> #include <queue>
QBtSession* QBtSession::m_instance = 0;
const int MAX_TRACKER_ERRORS = 2; const int MAX_TRACKER_ERRORS = 2;
const float MAX_RATIO = 100.; const float MAX_RATIO = 100.;
enum VersionType { NORMAL,ALPHA,BETA,RELEASE_CANDIDATE,DEVEL }; enum VersionType { NORMAL,ALPHA,BETA,RELEASE_CANDIDATE,DEVEL };
@ -2628,3 +2630,17 @@ void QBtSession::startUpTorrents() {
settings.setValue("ported_to_new_savepath_system", true); settings.setValue("ported_to_new_savepath_system", true);
qDebug("Unfinished torrents resumed"); qDebug("Unfinished torrents resumed");
} }
QBtSession * QBtSession::instance()
{
if(!m_instance) {
m_instance = new QBtSession;
}
return m_instance;
}
void QBtSession::drop()
{
if(m_instance)
delete m_instance;
}

View File

@ -66,9 +66,13 @@ class QBtSession : public QObject {
Q_OBJECT Q_OBJECT
Q_DISABLE_COPY(QBtSession) Q_DISABLE_COPY(QBtSession)
private:
explicit QBtSession();
static QBtSession* m_instance;
public: public:
// Constructor / Destructor static QBtSession* instance();
QBtSession(); static void drop();
~QBtSession(); ~QBtSession();
QTorrentHandle getTorrentHandle(QString hash) const; QTorrentHandle getTorrentHandle(QString hash) const;
std::vector<torrent_handle> getTorrents() const; std::vector<torrent_handle> getTorrents() const;

View File

@ -41,6 +41,8 @@
#include "rssdownloadrulelist.h" #include "rssdownloadrulelist.h"
#include "preferences.h" #include "preferences.h"
#include "qinisettings.h" #include "qinisettings.h"
#include "rssmanager.h"
#include "rssfeed.h"
AutomatedRssDownloader::AutomatedRssDownloader(QWidget *parent) : AutomatedRssDownloader::AutomatedRssDownloader(QWidget *parent) :
QDialog(parent), QDialog(parent),
@ -49,6 +51,8 @@ AutomatedRssDownloader::AutomatedRssDownloader(QWidget *parent) :
ui->setupUi(this); ui->setupUi(this);
ui->listRules->setSortingEnabled(true); ui->listRules->setSortingEnabled(true);
ui->listRules->setSelectionMode(QAbstractItemView::ExtendedSelection); ui->listRules->setSelectionMode(QAbstractItemView::ExtendedSelection);
ui->treeMatchingArticles->setSortingEnabled(true);
connect(ui->listRules, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(displayRulesListMenu(const QPoint&))); connect(ui->listRules, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(displayRulesListMenu(const QPoint&)));
m_ruleList = RssDownloadRuleList::instance(); m_ruleList = RssDownloadRuleList::instance();
initLabelCombobox(); initLabelCombobox();
@ -58,6 +62,9 @@ AutomatedRssDownloader::AutomatedRssDownloader(QWidget *parent) :
connect(ui->listRules, SIGNAL(itemSelectionChanged()), SLOT(updateRuleDefinitionBox())); connect(ui->listRules, SIGNAL(itemSelectionChanged()), SLOT(updateRuleDefinitionBox()));
connect(ui->listRules, SIGNAL(itemSelectionChanged()), SLOT(updateFeedList())); connect(ui->listRules, SIGNAL(itemSelectionChanged()), SLOT(updateFeedList()));
connect(ui->listFeeds, SIGNAL(itemChanged(QListWidgetItem*)), SLOT(handleFeedCheckStateChange(QListWidgetItem*))); connect(ui->listFeeds, SIGNAL(itemChanged(QListWidgetItem*)), SLOT(handleFeedCheckStateChange(QListWidgetItem*)));
// Update matching articles when necessary
connect(ui->lineContains, SIGNAL(textEdited(QString)), SLOT(updateMatchingArticles()));
connect(ui->lineNotContains, SIGNAL(textEdited(QString)), SLOT(updateMatchingArticles()));
updateRuleDefinitionBox(); updateRuleDefinitionBox();
updateFeedList(); updateFeedList();
} }
@ -149,6 +156,7 @@ void AutomatedRssDownloader::updateFeedList()
} }
ui->listFeeds->setEnabled(!ui->listRules->selectedItems().isEmpty()); ui->listFeeds->setEnabled(!ui->listRules->selectedItems().isEmpty());
connect(ui->listFeeds, SIGNAL(itemChanged(QListWidgetItem*)), SLOT(handleFeedCheckStateChange(QListWidgetItem*))); connect(ui->listFeeds, SIGNAL(itemChanged(QListWidgetItem*)), SLOT(handleFeedCheckStateChange(QListWidgetItem*)));
updateMatchingArticles();
} }
bool AutomatedRssDownloader::isRssDownloaderEnabled() const bool AutomatedRssDownloader::isRssDownloaderEnabled() const
@ -224,7 +232,11 @@ void AutomatedRssDownloader::saveCurrentRule(QListWidgetItem * item)
{ {
qDebug() << Q_FUNC_INFO << item; qDebug() << Q_FUNC_INFO << item;
if(!item) return; if(!item) return;
if(!ui->listRules->findItems(item->text(), Qt::MatchExactly).isEmpty()) return; if(ui->listRules->findItems(item->text(), Qt::MatchExactly).isEmpty()) {
qDebug() << "Could not find rule" << item->text() << "in the UI list";
qDebug() << "Probably removed the item, no need to save it";
return;
}
RssDownloadRule rule = m_ruleList->getRule(item->text()); RssDownloadRule rule = m_ruleList->getRule(item->text());
if(!rule.isValid()) { if(!rule.isValid()) {
rule.setName(item->text()); rule.setName(item->text());
@ -263,6 +275,7 @@ void AutomatedRssDownloader::on_addRuleBtn_clicked()
QListWidgetItem * item = new QListWidgetItem(rule, ui->listRules); QListWidgetItem * item = new QListWidgetItem(rule, ui->listRules);
item->setFlags(item->flags()|Qt::ItemIsUserCheckable); item->setFlags(item->flags()|Qt::ItemIsUserCheckable);
item->setCheckState(Qt::Checked); // Enable as a default item->setCheckState(Qt::Checked); // Enable as a default
ui->listRules->clearSelection();
ui->listRules->setCurrentItem(item); ui->listRules->setCurrentItem(item);
} }
@ -402,6 +415,54 @@ void AutomatedRssDownloader::handleFeedCheckStateChange(QListWidgetItem *feed_it
m_ruleList->saveRule(rule); m_ruleList->saveRule(rule);
} }
} }
// Update Matching articles
updateMatchingArticles();
}
void AutomatedRssDownloader::updateMatchingArticles()
{
ui->treeMatchingArticles->clear();
if(ui->ruleDefBox->isEnabled()) {
saveCurrentRule(ui->listRules->currentItem());
}
const QHash<QString, RssFeed*> all_feeds = RssManager::instance()->getAllFeedsAsHash();
foreach(const QListWidgetItem *rule_item, ui->listRules->selectedItems()) {
RssDownloadRule rule = m_ruleList->getRule(rule_item->text());
if(!rule.isValid()) continue;
foreach(const QString &feed_url, rule.rssFeeds()) {
Q_ASSERT(all_feeds.contains(feed_url));
const RssFeed *feed = all_feeds.value(feed_url);
const QStringList matching_articles = rule.findMatchingArticles(feed);
if(!matching_articles.isEmpty())
addFeedArticlesToTree(feed, matching_articles);
}
}
}
void AutomatedRssDownloader::addFeedArticlesToTree(const RssFeed *feed, const QStringList &articles)
{
// Check if this feed is already in the tree
QTreeWidgetItem *treeFeedItem = 0;
for(int i=0; i<ui->treeMatchingArticles->topLevelItemCount(); ++i) {
QTreeWidgetItem *item = ui->treeMatchingArticles->topLevelItem(i);
if(item->data(0, Qt::UserRole).toString() == feed->getUrl()) {
treeFeedItem = item;
break;
}
}
// If there is none, create it
if(!treeFeedItem) {
treeFeedItem = new QTreeWidgetItem(QStringList() << feed->getName());
treeFeedItem->setData(0, Qt::UserRole, feed->getUrl());
ui->treeMatchingArticles->addTopLevelItem(treeFeedItem);
}
// Insert the articles
foreach(const QString &art, articles) {
QTreeWidgetItem *item = new QTreeWidgetItem(QStringList() << art);
treeFeedItem->addChild(item);
}
ui->treeMatchingArticles->expandItem(treeFeedItem);
} }

View File

@ -70,10 +70,12 @@ private slots:
void on_exportBtn_clicked(); void on_exportBtn_clicked();
void on_importBtn_clicked(); void on_importBtn_clicked();
void renameSelectedRule(); void renameSelectedRule();
void updateMatchingArticles();
private: private:
RssDownloadRule getCurrentRule() const; RssDownloadRule getCurrentRule() const;
void initLabelCombobox(); void initLabelCombobox();
void addFeedArticlesToTree(const RssFeed *feed, const QStringList& articles);
private: private:
Ui::AutomatedRssDownloader *ui; Ui::AutomatedRssDownloader *ui;

View File

@ -266,10 +266,15 @@
</widget> </widget>
</item> </item>
<item> <item>
<widget class="QListWidget" name="listMatchingArticles"> <widget class="QTreeWidget" name="treeMatchingArticles">
<property name="enabled"> <attribute name="headerVisible">
<bool>false</bool> <bool>false</bool>
</property> </attribute>
<column>
<property name="text">
<string notr="true">1</string>
</property>
</column>
</widget> </widget>
</item> </item>
</layout> </layout>

View File

@ -580,7 +580,7 @@ void RSSImp::updateRefreshInterval(unsigned int val) {
RSSImp::RSSImp(QBtSession *BTSession) : QWidget(), BTSession(BTSession){ RSSImp::RSSImp(QBtSession *BTSession) : QWidget(), BTSession(BTSession){
setupUi(this); setupUi(this);
rssmanager = new RssManager(BTSession); rssmanager = RssManager::instance();
listStreams = new FeedListWidget(splitter_h, rssmanager); listStreams = new FeedListWidget(splitter_h, rssmanager);
splitter_h->insertWidget(0, listStreams); splitter_h->insertWidget(0, listStreams);
@ -634,7 +634,7 @@ RSSImp::~RSSImp(){
qDebug("Deleting RSSImp..."); qDebug("Deleting RSSImp...");
saveFoldersOpenState(); saveFoldersOpenState();
delete listStreams; delete listStreams;
delete rssmanager; RssManager::drop();
qDebug("RSSImp deleted"); qDebug("RSSImp deleted");
} }

View File

@ -252,10 +252,6 @@ bool RssArticle::has_attachment() const {
return !torrent_url.isEmpty(); return !torrent_url.isEmpty();
} }
QString RssArticle::getId() const {
return id;
}
QHash<QString, QVariant> RssArticle::toHash() const { QHash<QString, QVariant> RssArticle::toHash() const {
QHash<QString, QVariant> item; QHash<QString, QVariant> item;
item["title"] = title; item["title"] = title;
@ -282,10 +278,6 @@ bool RssArticle::isValid() const {
return is_valid; return is_valid;
} }
QString RssArticle::getTitle() const{
return title;
}
QString RssArticle::getAuthor() const { QString RssArticle::getAuthor() const {
return author; return author;
} }

View File

@ -48,12 +48,12 @@ public:
QDateTime _date, QString _author, bool _read); QDateTime _date, QString _author, bool _read);
~RssArticle(); ~RssArticle();
bool has_attachment() const; bool has_attachment() const;
QString getId() const; inline QString getId() const { return id; }
QHash<QString, QVariant> toHash() const; QHash<QString, QVariant> toHash() const;
static RssArticle* fromHash(RssFeed* parent, const QHash<QString, QVariant> &h); static RssArticle* fromHash(RssFeed* parent, const QHash<QString, QVariant> &h);
RssFeed* getParent() const; RssFeed* getParent() const;
bool isValid() const; bool isValid() const;
QString getTitle() const; inline QString getTitle() const { return title; }
QString getAuthor() const; QString getAuthor() const;
QString getTorrentUrl() const; QString getTorrentUrl() const;
QString getLink() const; QString getLink() const;

View File

@ -34,6 +34,8 @@
#include "rssdownloadrule.h" #include "rssdownloadrule.h"
#include "preferences.h" #include "preferences.h"
#include "qinisettings.h" #include "qinisettings.h"
#include "rssfeed.h"
#include "rssarticle.h"
RssDownloadRule::RssDownloadRule() RssDownloadRule::RssDownloadRule()
{ {
@ -123,3 +125,13 @@ void RssDownloadRule::setSavePath(const QString &save_path)
else else
m_savePath = QString(); m_savePath = QString();
} }
QStringList RssDownloadRule::findMatchingArticles(const RssFeed *feed) const
{
QStringList ret;
foreach(const RssArticle *art, feed->values()) {
if(matches(art->getTitle()))
ret << art->getTitle();
}
return ret;
}

View File

@ -34,6 +34,8 @@
#include <QStringList> #include <QStringList>
#include <QVariantHash> #include <QVariantHash>
class RssFeed;
class RssDownloadRule class RssDownloadRule
{ {
@ -58,6 +60,7 @@ public:
inline bool isValid() const { return !m_name.isEmpty(); } inline bool isValid() const { return !m_name.isEmpty(); }
inline QString mustContain() const { return m_mustContain.join(" "); } inline QString mustContain() const { return m_mustContain.join(" "); }
inline QString mustNotContain() const { return m_mustNotContain.join(" "); } inline QString mustNotContain() const { return m_mustNotContain.join(" "); }
QStringList findMatchingArticles(const RssFeed* feed) const;
// Operators // Operators
bool operator==(const RssDownloadRule &other); bool operator==(const RssDownloadRule &other);

View File

@ -33,6 +33,7 @@
#include <QDebug> #include <QDebug>
#include "rssdownloadrulelist.h" #include "rssdownloadrulelist.h"
#include "rsssettings.h"
#include "qinisettings.h" #include "qinisettings.h"
RssDownloadRuleList* RssDownloadRuleList::m_instance = 0; RssDownloadRuleList* RssDownloadRuleList::m_instance = 0;
@ -56,6 +57,7 @@ void RssDownloadRuleList::drop()
RssDownloadRule RssDownloadRuleList::findMatchingRule(const QString &feed_url, const QString &article_title) const RssDownloadRule RssDownloadRuleList::findMatchingRule(const QString &feed_url, const QString &article_title) const
{ {
Q_ASSERT(RssSettings::isRssDownloadingEnabled());
QStringList rule_names = feedRules(feed_url); QStringList rule_names = feedRules(feed_url);
foreach(const QString &rule_name, rule_names) { foreach(const QString &rule_name, rule_names) {
RssDownloadRule rule = m_rules[rule_name]; RssDownloadRule rule = m_rules[rule_name];
@ -127,6 +129,7 @@ void RssDownloadRuleList::loadRulesFromVariantHash(const QVariantHash &h)
void RssDownloadRuleList::saveRule(const RssDownloadRule &rule) void RssDownloadRuleList::saveRule(const RssDownloadRule &rule)
{ {
qDebug() << Q_FUNC_INFO << rule.name();
Q_ASSERT(rule.isValid()); Q_ASSERT(rule.isValid());
if(m_rules.contains(rule.name())) { if(m_rules.contains(rule.name())) {
removeRule(rule.name()); removeRule(rule.name());

View File

@ -290,21 +290,23 @@ short RssFeed::readDoc(QIODevice* device) {
resizeList(); resizeList();
// RSS Feed Downloader // RSS Feed Downloader
foreach(RssArticle* item, values()) { if(RssSettings::isRssDownloadingEnabled()) {
if(item->isRead()) continue; foreach(RssArticle* item, values()) {
QString torrent_url; if(item->isRead()) continue;
if(item->has_attachment()) QString torrent_url;
torrent_url = item->getTorrentUrl(); if(item->has_attachment())
else torrent_url = item->getTorrentUrl();
torrent_url = item->getLink(); else
// Check if the item should be automatically downloaded torrent_url = item->getLink();
const RssDownloadRule matching_rule = RssDownloadRuleList::instance()->findMatchingRule(url, item->getTitle()); // Check if the item should be automatically downloaded
if(matching_rule.isValid()) { const RssDownloadRule matching_rule = RssDownloadRuleList::instance()->findMatchingRule(url, item->getTitle());
// Download the torrent if(matching_rule.isValid()) {
BTSession->addConsoleMessage(tr("Automatically downloading %1 torrent from %2 RSS feed...").arg(item->getTitle()).arg(getName())); // Download the torrent
BTSession->downloadUrlAndSkipDialog(torrent_url, matching_rule.savePath(), matching_rule.label()); BTSession->addConsoleMessage(tr("Automatically downloading %1 torrent from %2 RSS feed...").arg(item->getTitle()).arg(getName()));
// Item was downloaded, consider it as Read BTSession->downloadUrlAndSkipDialog(torrent_url, matching_rule.savePath(), matching_rule.label());
item->setRead(); // Item was downloaded, consider it as Read
item->setRead();
}
} }
} }
return 0; return 0;

View File

@ -256,16 +256,27 @@ QList<RssFeed*> RssFolder::getAllFeeds() const {
QList<RssFeed*> streams; QList<RssFeed*> streams;
foreach(RssFile *item, this->values()) { foreach(RssFile *item, this->values()) {
if(item->getType() == RssFile::FEED) { if(item->getType() == RssFile::FEED) {
streams << ((RssFeed*)item); streams << static_cast<RssFeed*>(item);
} else { } else {
foreach(RssFeed* stream, ((RssFolder*)item)->getAllFeeds()) { streams << static_cast<RssFolder*>(item)->getAllFeeds();
streams << stream;
}
} }
} }
return streams; return streams;
} }
QHash<QString, RssFeed*> RssFolder::getAllFeedsAsHash() const {
QHash<QString, RssFeed*> ret;
foreach(RssFile *item, this->values()) {
if(item->getType() == RssFile::FEED) {
RssFeed* feed = static_cast<RssFeed*>(item);
ret[feed->getUrl()] = feed;
} else {
ret.unite(static_cast<RssFolder*>(item)->getAllFeedsAsHash());
}
}
return ret;
}
void RssFolder::addFile(RssFile * item) { void RssFolder::addFile(RssFile * item) {
if(item->getType() == RssFile::FEED) { if(item->getType() == RssFile::FEED) {
Q_ASSERT(!this->contains(((RssFeed*)item)->getUrl())); Q_ASSERT(!this->contains(((RssFeed*)item)->getUrl()));

View File

@ -57,6 +57,7 @@ public:
unsigned int getNbFeeds() const; unsigned int getNbFeeds() const;
QList<RssFile*> getContent() const; QList<RssFile*> getContent() const;
QList<RssFeed*> getAllFeeds() const; QList<RssFeed*> getAllFeeds() const;
QHash<QString, RssFeed*> getAllFeedsAsHash() const;
QString getName() const; QString getName() const;
QString getID() const; QString getID() const;
bool hasChild(QString ID); bool hasChild(QString ID);

View File

@ -35,7 +35,9 @@
#include "rssarticle.h" #include "rssarticle.h"
#include "rssdownloadrulelist.h" #include "rssdownloadrulelist.h"
RssManager::RssManager(QBtSession *BTSession): RssFolder(0, this, BTSession, QString::null) { RssManager* RssManager::m_instance = 0;
RssManager::RssManager(): RssFolder(0, this, QBtSession::instance(), QString::null) {
loadStreamList(); loadStreamList();
connect(&newsRefresher, SIGNAL(timeout()), this, SLOT(refreshAll())); connect(&newsRefresher, SIGNAL(timeout()), this, SLOT(refreshAll()));
refreshInterval = RssSettings::getRSSRefreshInterval(); refreshInterval = RssSettings::getRSSRefreshInterval();
@ -137,3 +139,16 @@ QList<RssArticle*> RssManager::sortNewsList(const QList<RssArticle*>& news_list)
} }
return new_list; return new_list;
} }
RssManager * RssManager::instance()
{
if(!m_instance)
m_instance = new RssManager;
return m_instance;
}
void RssManager::drop()
{
if(m_instance)
delete m_instance;
}

View File

@ -37,9 +37,13 @@
class RssManager: public RssFolder { class RssManager: public RssFolder {
Q_OBJECT Q_OBJECT
private:
explicit RssManager();
static RssManager* m_instance;
public: public:
RssManager(QBtSession *BTSession); static RssManager* instance();
static void drop();
~RssManager(); ~RssManager();
static void insertSortElem(QList<RssArticle*> &list, RssArticle *item); static void insertSortElem(QList<RssArticle*> &list, RssArticle *item);
static QList<RssArticle*> sortNewsList(const QList<RssArticle*>& news_list); static QList<RssArticle*> sortNewsList(const QList<RssArticle*>& news_list);