diff --git a/src/gui/rss/rss.ui b/src/gui/rss/rss.ui
index 7d0d348bb..d83b562fa 100644
--- a/src/gui/rss/rss.ui
+++ b/src/gui/rss/rss.ui
@@ -116,16 +116,12 @@
- 50
- false
+ 75
+ true
- <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
-<html><head><meta name="qrichtext" content="1" /><style type="text/css">
-p, li { white-space: pre-wrap; }
-</style></head><body style=" font-family:'Sans'; font-size:10pt; font-weight:400; font-style:normal;">
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Torrents:</span> <span style=" font-style:italic;">(double-click to download)</span></p></body></html>
+ Torrents: (double-click to download)
@@ -139,7 +135,7 @@ p, li { white-space: pre-wrap; }
Qt::CustomContextMenu
- QAbstractItemView::SingleSelection
+ QAbstractItemView::ExtendedSelection
QAbstractItemView::SelectItems
diff --git a/src/gui/rss/rss_imp.cpp b/src/gui/rss/rss_imp.cpp
index f31edc1fb..613288a2d 100644
--- a/src/gui/rss/rss_imp.cpp
+++ b/src/gui/rss/rss_imp.cpp
@@ -112,20 +112,31 @@ void RSSImp::displayItemsListMenu(const QPoint&)
{
QMenu myItemListMenu(this);
QList selectedItems = listArticles->selectedItems();
- if (selectedItems.size() > 0) {
- bool has_attachment = false;
- foreach (const QListWidgetItem* item, selectedItems) {
- if (m_feedList->getRSSItemFromUrl(item->data(Article::FeedUrlRole).toString())
- ->getItem(item->data(Article::IdRole).toString())->hasAttachment()) {
- has_attachment = true;
- break;
- }
- }
- if (has_attachment)
- myItemListMenu.addAction(actionDownload_torrent);
- myItemListMenu.addAction(actionOpen_news_URL);
+ if (selectedItems.size() <= 0)
+ return;
+
+ bool hasTorrent = false;
+ bool hasLink = false;
+ foreach (const QListWidgetItem* item, selectedItems) {
+ if (!item) continue;
+ RssFeedPtr feed = m_feedList->getRSSItemFromUrl(item->data(Article::FeedUrlRole).toString());
+ if (!feed) continue;
+ RssArticlePtr article = feed->getItem(item->data(Article::IdRole).toString());
+ if (!article) continue;
+
+ if (!article->torrentUrl().isEmpty())
+ hasTorrent = true;
+ if (!article->link().isEmpty())
+ hasLink = true;
+ if (hasTorrent && hasLink)
+ break;
}
- myItemListMenu.exec(QCursor::pos());
+ if (hasTorrent)
+ myItemListMenu.addAction(actionDownload_torrent);
+ if (hasLink)
+ myItemListMenu.addAction(actionOpen_news_URL);
+ if (hasTorrent || hasLink)
+ myItemListMenu.exec(QCursor::pos());
}
void RSSImp::on_actionManage_cookies_triggered()
@@ -238,21 +249,13 @@ void RSSImp::deleteSelectedItems()
QList selectedItems = m_feedList->selectedItems();
if (selectedItems.isEmpty())
return;
+ if ((selectedItems.size() == 1) && (selectedItems.first() == m_feedList->stickyUnreadItem()))
+ return;
- int ret;
- if (selectedItems.size() > 1) {
- ret = QMessageBox::question(this, tr("Are you sure? -- qBittorrent"), tr("Are you sure you want to delete these elements from the list?"),
- tr("&Yes"), tr("&No"),
- QString(), 0, 1);
- }
- else {
- if (selectedItems.first() == m_feedList->stickyUnreadItem())
- return;
- ret = QMessageBox::question(this, tr("Are you sure? -- qBittorrent"), tr("Are you sure you want to delete this element from the list?"),
- tr("&Yes"), tr("&No"),
- QString(), 0, 1);
- }
- if (ret)
+ QMessageBox::StandardButton answer = QMessageBox::question(this, tr("Deletion confirmation"),
+ tr("Are you sure you want to delete the selected RSS feeds?"),
+ QMessageBox::Yes|QMessageBox::No, QMessageBox::No);
+ if (answer == QMessageBox::No)
return;
foreach (QTreeWidgetItem* item, selectedItems) {
@@ -337,31 +340,57 @@ void RSSImp::refreshAllFeeds()
void RSSImp::downloadSelectedTorrents()
{
QList selected_items = listArticles->selectedItems();
- foreach (const QListWidgetItem* item, selected_items) {
+ if (selected_items.size() <= 0)
+ return;
+ foreach (QListWidgetItem* item, selected_items) {
if (!item) continue;
RssFeedPtr feed = m_feedList->getRSSItemFromUrl(item->data(Article::FeedUrlRole).toString());
if (!feed) continue;
RssArticlePtr article = feed->getItem(item->data(Article::IdRole).toString());
if (!article) continue;
+ // Mark as read
+ article->markAsRead();
+ item->setData(Article::ColorRole, QVariant(QColor("grey")));
+ item->setData(Article::IconRole, QVariant(QIcon(":/icons/sphere.png")));
+
+ if (article->torrentUrl().isEmpty())
+ continue;
if (Preferences::instance()->useAdditionDialog())
AddNewTorrentDialog::show(article->torrentUrl());
else
BitTorrent::Session::instance()->addTorrent(article->torrentUrl());
}
+ // Decrement feed nb unread news
+ updateItemInfos(m_feedList->stickyUnreadItem());
+ updateItemInfos(m_feedList->getTreeItemFromUrl(selected_items.first()->data(Article::FeedUrlRole).toString()));
}
// open the url of the selected RSS articles in the Web browser
void RSSImp::openSelectedArticlesUrls()
{
QList selected_items = listArticles->selectedItems();
- foreach (const QListWidgetItem* item, selected_items) {
- RssArticlePtr news = m_feedList->getRSSItemFromUrl(item->data(Article::FeedUrlRole).toString())
- ->getItem(item->data(Article::IdRole).toString());
- const QString link = news->link();
+ if (selected_items.size() <= 0)
+ return;
+ foreach (QListWidgetItem* item, selected_items) {
+ if (!item) continue;
+ RssFeedPtr feed = m_feedList->getRSSItemFromUrl(item->data(Article::FeedUrlRole).toString());
+ if (!feed) continue;
+ RssArticlePtr article = feed->getItem(item->data(Article::IdRole).toString());
+ if (!article) continue;
+
+ // Mark as read
+ article->markAsRead();
+ item->setData(Article::ColorRole, QVariant(QColor("grey")));
+ item->setData(Article::IconRole, QVariant(QIcon(":/icons/sphere.png")));
+
+ const QString link = article->link();
if (!link.isEmpty())
QDesktopServices::openUrl(QUrl(link));
}
+ // Decrement feed nb unread news
+ updateItemInfos(m_feedList->stickyUnreadItem());
+ updateItemInfos(m_feedList->getTreeItemFromUrl(selected_items.first()->data(Article::FeedUrlRole).toString()));
}
//right-click on stream : give it an alias
@@ -538,21 +567,11 @@ void RSSImp::refreshTextBrowser()
{
QList selection = listArticles->selectedItems();
if (selection.empty()) return;
- Q_ASSERT(selection.size() == 1);
QListWidgetItem *item = selection.first();
Q_ASSERT(item);
if (item == m_currentArticle) return;
- // Stop displaying previous news if necessary
- if (m_feedList->currentFeed() == m_feedList->stickyUnreadItem()) {
- if (m_currentArticle) {
- disconnect(listArticles, SIGNAL(itemSelectionChanged()), this, SLOT(refreshTextBrowser()));
- listArticles->removeItemWidget(m_currentArticle);
- Q_ASSERT(m_currentArticle);
- delete m_currentArticle;
- connect(listArticles, SIGNAL(itemSelectionChanged()), this, SLOT(refreshTextBrowser()));
- }
- m_currentArticle = item;
- }
+ m_currentArticle = item;
+
RssFeedPtr stream = m_feedList->getRSSItemFromUrl(item->data(Article::FeedUrlRole).toString());
RssArticlePtr article = stream->getItem(item->data(Article::IdRole).toString());
QString html;
@@ -675,14 +694,11 @@ void RSSImp::onFeedContentChanged(const QString& url)
qDebug() << Q_FUNC_INFO << url;
QTreeWidgetItem *item = m_feedList->getTreeItemFromUrl(url);
// If the feed is selected, update the displayed news
- if (m_feedList->currentItem() == item ) {
+ if (m_feedList->currentItem() == item)
populateArticleList(item);
- }
- else {
- // Update unread items
- if (m_feedList->currentItem() == m_feedList->stickyUnreadItem())
- populateArticleList(m_feedList->stickyUnreadItem());
- }
+ // Update unread items
+ else if (m_feedList->currentItem() == m_feedList->stickyUnreadItem())
+ populateArticleList(m_feedList->stickyUnreadItem());
}
void RSSImp::updateRefreshInterval(uint val)
@@ -715,8 +731,6 @@ RSSImp::RSSImp(QWidget *parent):
m_feedList = new FeedListWidget(splitter_h, m_rssManager);
splitter_h->insertWidget(0, m_feedList);
- listArticles->setSelectionBehavior(QAbstractItemView::SelectItems);
- listArticles->setSelectionMode(QAbstractItemView::SingleSelection);
editHotkey = new QShortcut(QKeySequence("F2"), m_feedList, 0, 0, Qt::WidgetShortcut);
connect(editHotkey, SIGNAL(activated()), SLOT(renameSelectedRssFile()));
connect(m_feedList, SIGNAL(doubleClicked(QModelIndex)), SLOT(renameSelectedRssFile()));
diff --git a/src/gui/rss/rssarticle.cpp b/src/gui/rss/rssarticle.cpp
index a0262c1de..fbc7218bf 100644
--- a/src/gui/rss/rssarticle.cpp
+++ b/src/gui/rss/rssarticle.cpp
@@ -82,7 +82,7 @@ const QString& RssArticle::author() const {
}
const QString& RssArticle::torrentUrl() const {
- return m_torrentUrl.isEmpty() ? m_link : m_torrentUrl;
+ return m_torrentUrl;
}
const QString& RssArticle::link() const {
@@ -123,6 +123,6 @@ const QString& RssArticle::title() const
}
void RssArticle::handleTorrentDownloadSuccess(const QString &url) {
- if (url == m_torrentUrl || url == m_link)
+ if (url == m_torrentUrl)
markAsRead();
}
diff --git a/src/gui/rss/rssfeed.cpp b/src/gui/rss/rssfeed.cpp
index 837f5470b..6587e9123 100644
--- a/src/gui/rss/rssfeed.cpp
+++ b/src/gui/rss/rssfeed.cpp
@@ -364,6 +364,12 @@ void RssFeed::downloadArticleTorrentIfMatching(RssDownloadRuleList* rules, const
rules->saveRulesToStorage();
// Download the torrent
const QString& torrent_url = article->torrentUrl();
+ if (torrent_url.isEmpty()) {
+ Logger::instance()->addMessage(tr("Automatic download %1 from %2 RSS feed failed because it doesn't contain a torrent or a magnet link...").arg(article->title()).arg(displayName()), Log::WARNING);
+ article->markAsRead();
+ return;
+ }
+
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);
connect(article.data(), SIGNAL(articleWasRead()), SLOT(handleArticleStateChanged()), Qt::UniqueConnection);
diff --git a/src/gui/rss/rssparser.cpp b/src/gui/rss/rssparser.cpp
index 9f9b87207..fb0932d59 100644
--- a/src/gui/rss/rssparser.cpp
+++ b/src/gui/rss/rssparser.cpp
@@ -254,24 +254,32 @@ void RssParser::parseRssArticle(QXmlStreamReader& xml, const QString& feedUrl)
if (xml.isStartElement()) {
if (xml.name() == "title")
- article["title"] = xml.readElementText();
+ article["title"] = xml.readElementText().trimmed();
else if (xml.name() == "enclosure") {
if (xml.attributes().value("type") == "application/x-bittorrent")
article["torrent_url"] = xml.attributes().value("url").toString();
}
- else if (xml.name() == "link")
- article["news_link"] = xml.readElementText();
+ else if (xml.name() == "link") {
+ QString link = xml.readElementText().trimmed();
+ if (link.startsWith("magnet:", Qt::CaseInsensitive))
+ article["torrent_url"] = link; // magnet link instead of a news URL
+ else
+ article["news_link"] = link;
+ }
else if (xml.name() == "description")
- article["description"] = xml.readElementText();
+ article["description"] = xml.readElementText().trimmed();
else if (xml.name() == "pubDate")
- article["date"] = parseDate(xml.readElementText());
+ article["date"] = parseDate(xml.readElementText().trimmed());
else if (xml.name() == "author")
- article["author"] = xml.readElementText();
+ article["author"] = xml.readElementText().trimmed();
else if (xml.name() == "guid")
- article["id"] = xml.readElementText();
+ article["id"] = xml.readElementText().trimmed();
}
}
+ if (!article.contains("torrent_url") && article.contains("news_link"))
+ article["torrent_url"] = article["news_link"];
+
if (!article.contains("id")) {
// Item does not have a guid, fall back to some other identifier
const QString link = article.value("news_link").toString();
@@ -338,20 +346,21 @@ void RssParser::parseAtomArticle(QXmlStreamReader& xml, const QString& feedUrl,
// Workaround for CDATA (QString cannot parse html escapes on it's own)
QTextDocument doc;
doc.setHtml(xml.readElementText());
- article["title"] = doc.toPlainText();
+ article["title"] = doc.toPlainText().trimmed();
}
else if (xml.name() == "link") {
- QString theLink = ( xml.attributes().isEmpty() ?
- xml.readElementText() :
- xml.attributes().value("href").toString() );
+ QString link = ( xml.attributes().isEmpty() ?
+ xml.readElementText().trimmed() :
+ xml.attributes().value("href").toString() );
+
+ if (link.startsWith("magnet:", Qt::CaseInsensitive))
+ article["torrent_url"] = link; // magnet link instead of a news URL
+ else
+ // Atom feeds can have relative links, work around this and
+ // take the stress of figuring article full URI from UI
+ // Assemble full URI
+ article["news_link"] = ( baseUrl.isEmpty() ? link : baseUrl + link );
- // Atom feeds can have relative links, work around this and
- // take the stress of figuring article full URI from UI
-
- // Assemble full URI
- article["news_link"] = ( baseUrl.isEmpty() ?
- theLink :
- baseUrl + theLink );
}
else if (xml.name() == "summary" || xml.name() == "content"){
if(double_content) { // Duplicate content -> ignore
@@ -367,13 +376,13 @@ void RssParser::parseAtomArticle(QXmlStreamReader& xml, const QString& feedUrl,
// Actually works great for non-broken content too
QString feedText = xml.readElementText(QXmlStreamReader::IncludeChildElements);
if (!feedText.isEmpty())
- article["description"] = feedText;
+ article["description"] = feedText.trimmed();
double_content = true;
}
else if (xml.name() == "updated"){
// ATOM uses standard compliant date, don't do fancy stuff
- QDateTime articleDate = QDateTime::fromString(xml.readElementText(), Qt::ISODate);
+ QDateTime articleDate = QDateTime::fromString(xml.readElementText().trimmed(), Qt::ISODate);
article["date"] = ( articleDate.isValid() ?
articleDate :
QDateTime::currentDateTime() );
@@ -382,15 +391,18 @@ void RssParser::parseAtomArticle(QXmlStreamReader& xml, const QString& feedUrl,
xml.readNext();
while(xml.name() != "author") {
if(xml.name() == "name")
- article["author"] = xml.readElementText();
+ article["author"] = xml.readElementText().trimmed();
xml.readNext();
}
}
else if (xml.name() == "id")
- article["id"] = xml.readElementText();
+ article["id"] = xml.readElementText().trimmed();
}
}
+ if (!article.contains("torrent_url") && article.contains("news_link"))
+ article["torrent_url"] = article["news_link"];
+
if (!article.contains("id")) {
// Item does not have a guid, fall back to some other identifier
const QString link = article.value("news_link").toString();