mirror of
https://github.com/qbittorrent/qBittorrent.git
synced 2025-12-18 06:28:03 -06:00
RSS items are now displayed as soon as they have been parsed instead of displaying all of them in one batch once the whole feed is parsed. First step to address issue #34.
717 lines
28 KiB
C++
717 lines
28 KiB
C++
/*
|
|
* Bittorrent Client using Qt4 and libtorrent.
|
|
* Copyright (C) 2006 Christophe Dumez, Arnaud Demaiziere
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License
|
|
* as published by the Free Software Foundation; either version 2
|
|
* of the License, or (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
*
|
|
* In addition, as a special exception, the copyright holders give permission to
|
|
* link this program with the OpenSSL project's "OpenSSL" library (or with
|
|
* modified versions of it that use the same license as the "OpenSSL" library),
|
|
* and distribute the linked executables. You must obey the GNU General Public
|
|
* License in all respects for all of the code used other than "OpenSSL". If you
|
|
* modify file(s), you may extend this exception to your version of the file(s),
|
|
* but you are not obligated to do so. If you do not wish to do so, delete this
|
|
* exception statement from your version.
|
|
*
|
|
* Contact : chris@qbittorrent.org arnaud@qbittorrent.org
|
|
*/
|
|
|
|
#include <QDesktopServices>
|
|
#include <QInputDialog>
|
|
#include <QMenu>
|
|
#include <QStandardItemModel>
|
|
#include <QMessageBox>
|
|
#include <QString>
|
|
#include <QClipboard>
|
|
#include <QDragMoveEvent>
|
|
|
|
#include "rss_imp.h"
|
|
#include "feedlistwidget.h"
|
|
#include "qbtsession.h"
|
|
#include "cookiesdlg.h"
|
|
#include "preferences.h"
|
|
#include "rsssettingsdlg.h"
|
|
#include "rssmanager.h"
|
|
#include "rssfolder.h"
|
|
#include "rssarticle.h"
|
|
#include "rssfeed.h"
|
|
#include "rsssettings.h"
|
|
#include "automatedrssdownloader.h"
|
|
#include "iconprovider.h"
|
|
|
|
namespace Article {
|
|
enum ArticleRoles {
|
|
TitleRole = Qt::DisplayRole,
|
|
IconRole = Qt::DecorationRole,
|
|
ColorRole = Qt::ForegroundRole,
|
|
IdRole = Qt::UserRole + 1,
|
|
FeedUrlRole = Qt::UserRole + 2
|
|
};
|
|
}
|
|
|
|
// display a right-click menu
|
|
void RSSImp::displayRSSListMenu(const QPoint& pos) {
|
|
if (!m_feedList->indexAt(pos).isValid()) {
|
|
// No item under the mouse, clear selection
|
|
m_feedList->clearSelection();
|
|
}
|
|
QMenu myRSSListMenu(this);
|
|
QList<QTreeWidgetItem*> selectedItems = m_feedList->selectedItems();
|
|
if (selectedItems.size() > 0) {
|
|
myRSSListMenu.addAction(actionUpdate);
|
|
myRSSListMenu.addAction(actionMark_items_read);
|
|
myRSSListMenu.addSeparator();
|
|
if (selectedItems.size() == 1) {
|
|
if (m_feedList->getRSSItem(selectedItems.first()) != m_rssManager) {
|
|
myRSSListMenu.addAction(actionRename);
|
|
myRSSListMenu.addAction(actionDelete);
|
|
myRSSListMenu.addSeparator();
|
|
if (m_feedList->isFolder(selectedItems.first())) {
|
|
myRSSListMenu.addAction(actionNew_folder);
|
|
} else {
|
|
myRSSListMenu.addAction(actionManage_cookies);
|
|
}
|
|
}
|
|
}
|
|
myRSSListMenu.addAction(actionNew_subscription);
|
|
if (m_feedList->isFeed(selectedItems.first())) {
|
|
myRSSListMenu.addSeparator();
|
|
myRSSListMenu.addAction(actionCopy_feed_URL);
|
|
}
|
|
}else{
|
|
myRSSListMenu.addAction(actionNew_subscription);
|
|
myRSSListMenu.addAction(actionNew_folder);
|
|
myRSSListMenu.addSeparator();
|
|
myRSSListMenu.addAction(actionUpdate_all_feeds);
|
|
}
|
|
myRSSListMenu.exec(QCursor::pos());
|
|
}
|
|
|
|
void RSSImp::displayItemsListMenu(const QPoint&) {
|
|
QMenu myItemListMenu(this);
|
|
QList<QListWidgetItem*> selectedItems = listArticles->selectedItems();
|
|
if (selectedItems.size() > 0) {
|
|
bool has_attachment = false;
|
|
foreach (const QListWidgetItem *item, selectedItems) {
|
|
qDebug("text(3) URL: %s", qPrintable(item->data(Article::FeedUrlRole).toString()));
|
|
qDebug("text(2) TITLE: %s", qPrintable(item->data(Article::TitleRole).toString()));
|
|
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);
|
|
}
|
|
myItemListMenu.exec(QCursor::pos());
|
|
}
|
|
|
|
void RSSImp::on_actionManage_cookies_triggered() {
|
|
Q_ASSERT(!m_feedList->selectedItems().empty());
|
|
// Get feed hostname
|
|
QString feed_url = m_feedList->getItemID(m_feedList->selectedItems().first());
|
|
QString feed_hostname = QUrl::fromEncoded(feed_url.toUtf8()).host();
|
|
qDebug("RSS Feed hostname is: %s", qPrintable(feed_hostname));
|
|
Q_ASSERT(!feed_hostname.isEmpty());
|
|
bool ok = false;
|
|
RssSettings settings;
|
|
QList<QByteArray> raw_cookies = CookiesDlg::askForCookies(this, settings.getHostNameCookies(feed_hostname), &ok);
|
|
if (ok) {
|
|
qDebug() << "Settings cookies for host name: " << feed_hostname;
|
|
settings.setHostNameCookies(feed_hostname, raw_cookies);
|
|
}
|
|
}
|
|
|
|
void RSSImp::askNewFolder() {
|
|
QTreeWidgetItem *parent_item = 0;
|
|
RssFolderPtr rss_parent;
|
|
if (m_feedList->selectedItems().size() > 0) {
|
|
parent_item = m_feedList->selectedItems().at(0);
|
|
rss_parent = qSharedPointerDynamicCast<RssFolder>(m_feedList->getRSSItem(parent_item));
|
|
Q_ASSERT(rss_parent);
|
|
} else {
|
|
rss_parent = m_rssManager;
|
|
}
|
|
bool ok;
|
|
QString new_name = QInputDialog::getText(this, tr("Please choose a folder name"), tr("Folder name:"), QLineEdit::Normal, tr("New folder"), &ok);
|
|
if (ok) {
|
|
RssFolderPtr new_folder = rss_parent->addFolder(new_name);
|
|
QTreeWidgetItem* folder_item;
|
|
if (parent_item)
|
|
folder_item = new QTreeWidgetItem(parent_item);
|
|
else
|
|
folder_item = new QTreeWidgetItem(m_feedList);
|
|
// Notify TreeWidget
|
|
m_feedList->itemAdded(folder_item, new_folder);
|
|
// Set Text
|
|
folder_item->setText(0, new_folder->displayName() + QString::fromUtf8(" (0)"));
|
|
folder_item->setData(0,Qt::DecorationRole, QVariant(IconProvider::instance()->getIcon("inode-directory")));
|
|
// Expand parent folder to display new folder
|
|
if (parent_item)
|
|
parent_item->setExpanded(true);
|
|
m_rssManager->saveStreamList();
|
|
}
|
|
}
|
|
|
|
void RSSImp::displayOverwriteError(const QString &filename) {
|
|
QMessageBox::warning(this, tr("Overwrite attempt"),
|
|
tr("You cannot overwrite %1 item.", "You cannot overwrite myFolder item.").arg(filename),
|
|
QMessageBox::Ok);
|
|
}
|
|
|
|
// add a stream by a button
|
|
void RSSImp::on_newFeedButton_clicked() {
|
|
// Determine parent folder for new feed
|
|
QTreeWidgetItem *parent_item = 0;
|
|
QList<QTreeWidgetItem *> selected_items = m_feedList->selectedItems();
|
|
if (!selected_items.empty()) {
|
|
parent_item = selected_items.first();
|
|
// Consider the case where the user clicked on Unread item
|
|
if (parent_item == m_feedList->stickyUnreadItem()) {
|
|
parent_item = 0;
|
|
} else {
|
|
if (!m_feedList->isFolder(parent_item))
|
|
parent_item = parent_item->parent();
|
|
}
|
|
}
|
|
RssFolderPtr rss_parent;
|
|
if (parent_item) {
|
|
rss_parent = qSharedPointerCast<RssFolder>(m_feedList->getRSSItem(parent_item));
|
|
} else {
|
|
rss_parent = m_rssManager;
|
|
}
|
|
// Ask for feed URL
|
|
bool ok;
|
|
QString clip_txt = qApp->clipboard()->text();
|
|
QString default_url = "http://";
|
|
if (clip_txt.startsWith("http://", Qt::CaseInsensitive) || clip_txt.startsWith("https://", Qt::CaseInsensitive) || clip_txt.startsWith("ftp://", Qt::CaseInsensitive)) {
|
|
default_url = clip_txt;
|
|
}
|
|
QString newUrl = QInputDialog::getText(this, tr("Please type a rss stream url"), tr("Stream URL:"), QLineEdit::Normal, default_url, &ok);
|
|
if (ok) {
|
|
newUrl = newUrl.trimmed();
|
|
if (!newUrl.isEmpty()) {
|
|
if (m_feedList->hasFeed(newUrl)) {
|
|
QMessageBox::warning(this, tr("qBittorrent"),
|
|
tr("This rss feed is already in the list."),
|
|
QMessageBox::Ok);
|
|
return;
|
|
}
|
|
RssFeedPtr stream = rss_parent->addStream(m_rssManager.data(), newUrl);
|
|
// Create TreeWidget item
|
|
QTreeWidgetItem* item;
|
|
if (parent_item)
|
|
item = new QTreeWidgetItem(parent_item);
|
|
else
|
|
item = new QTreeWidgetItem(m_feedList);
|
|
// Notify TreeWidget
|
|
m_feedList->itemAdded(item, stream);
|
|
// Set text
|
|
item->setText(0, stream->displayName() + QString::fromUtf8(" (0)"));
|
|
item->setData(0,Qt::DecorationRole, QVariant(QIcon(":/Icons/loading.png")));
|
|
stream->refresh();
|
|
m_rssManager->saveStreamList();
|
|
}
|
|
}
|
|
}
|
|
|
|
// delete a stream by a button
|
|
void RSSImp::deleteSelectedItems() {
|
|
QList<QTreeWidgetItem*> selectedItems = m_feedList->selectedItems();
|
|
if (selectedItems.size() == 0) 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
|
|
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) {
|
|
foreach (QTreeWidgetItem *item, selectedItems) {
|
|
if (m_feedList->currentFeed() == item) {
|
|
textBrowser->clear();
|
|
m_currentArticle = 0;
|
|
listArticles->clear();
|
|
}
|
|
RssFilePtr rss_item = m_feedList->getRSSItem(item);
|
|
QTreeWidgetItem * parent = item->parent();
|
|
// Notify TreeWidget
|
|
m_feedList->itemAboutToBeRemoved(item);
|
|
// Actually delete the item
|
|
rss_item->parent()->removeChild(rss_item->id());
|
|
delete item;
|
|
// Update parents count
|
|
while (parent && parent != m_feedList->invisibleRootItem()) {
|
|
updateItemInfos (parent);
|
|
parent = parent->parent();
|
|
}
|
|
}
|
|
m_rssManager->saveStreamList();
|
|
// Update Unread items
|
|
updateItemInfos(m_feedList->stickyUnreadItem());
|
|
}
|
|
}
|
|
|
|
void RSSImp::loadFoldersOpenState() {
|
|
QIniSettings settings("qBittorrent", "qBittorrent");
|
|
settings.beginGroup("Rss");
|
|
QStringList open_folders = settings.value("open_folders", QStringList()).toStringList();
|
|
settings.endGroup();
|
|
foreach (QString var_path, open_folders) {
|
|
QStringList path = var_path.split("\\");
|
|
QTreeWidgetItem *parent = 0;
|
|
foreach (QString name, path) {
|
|
int nbChildren = 0;
|
|
if (parent)
|
|
nbChildren = parent->childCount();
|
|
else
|
|
nbChildren = m_feedList->topLevelItemCount();
|
|
for (int i=0; i<nbChildren; ++i) {
|
|
QTreeWidgetItem* child;
|
|
if (parent)
|
|
child = parent->child(i);
|
|
else
|
|
child = m_feedList->topLevelItem(i);
|
|
if (m_feedList->getRSSItem(child)->id() == name) {
|
|
parent = child;
|
|
parent->setExpanded(true);
|
|
qDebug("expanding folder %s", qPrintable(name));
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void RSSImp::saveFoldersOpenState() {
|
|
QStringList open_folders;
|
|
QList<QTreeWidgetItem*> items = m_feedList->getAllOpenFolders();
|
|
foreach (QTreeWidgetItem* item, items) {
|
|
QString path = m_feedList->getItemPath(item).join("\\");
|
|
qDebug("saving open folder: %s", qPrintable(path));
|
|
open_folders << path;
|
|
}
|
|
QIniSettings settings("qBittorrent", "qBittorrent");
|
|
settings.beginGroup("Rss");
|
|
settings.setValue("open_folders", open_folders);
|
|
settings.endGroup();
|
|
}
|
|
|
|
// refresh all streams by a button
|
|
void RSSImp::on_updateAllButton_clicked() {
|
|
foreach (QTreeWidgetItem *item, m_feedList->getAllFeedItems()) {
|
|
item->setData(0,Qt::DecorationRole, QVariant(QIcon(":/Icons/loading.png")));
|
|
}
|
|
m_rssManager->refresh();
|
|
}
|
|
|
|
void RSSImp::downloadTorrent() {
|
|
QList<QListWidgetItem *> selected_items = listArticles->selectedItems();
|
|
foreach (const QListWidgetItem* item, selected_items) {
|
|
RssArticlePtr article = m_feedList->getRSSItemFromUrl(item->data(Article::FeedUrlRole).toString())
|
|
->getItem(item->data(Article::IdRole).toString());
|
|
|
|
QString torrentLink;
|
|
if (article->hasAttachment())
|
|
torrentLink = article->torrentUrl();
|
|
else
|
|
torrentLink = article->link();
|
|
|
|
// Check if it is a magnet link
|
|
if (torrentLink.startsWith("magnet:", Qt::CaseInsensitive))
|
|
QBtSession::instance()->addMagnetInteractive(torrentLink);
|
|
else {
|
|
// Load possible cookies
|
|
QList<QNetworkCookie> cookies;
|
|
QString feed_url = m_feedList->getItemID(m_feedList->selectedItems().first());
|
|
QString feed_hostname = QUrl::fromEncoded(feed_url.toUtf8()).host();
|
|
const QList<QByteArray> raw_cookies = RssSettings().getHostNameCookies(feed_hostname);
|
|
foreach (const QByteArray& raw_cookie, raw_cookies) {
|
|
QList<QByteArray> cookie_parts = raw_cookie.split('=');
|
|
if (cookie_parts.size() == 2) {
|
|
qDebug("Loading cookie: %s = %s", cookie_parts.first().constData(), cookie_parts.last().constData());
|
|
cookies << QNetworkCookie(cookie_parts.first(), cookie_parts.last());
|
|
}
|
|
}
|
|
qDebug("Loaded %d cookies for RSS item\n", cookies.size());
|
|
|
|
QBtSession::instance()->downloadFromUrl(torrentLink, cookies);
|
|
}
|
|
}
|
|
}
|
|
|
|
// open the url of the news in a browser
|
|
void RSSImp::openNewsUrl() {
|
|
QList<QListWidgetItem *> 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 (!link.isEmpty())
|
|
QDesktopServices::openUrl(QUrl(link));
|
|
}
|
|
}
|
|
|
|
//right-click on stream : give it an alias
|
|
void RSSImp::renameFiles() {
|
|
QList<QTreeWidgetItem*> selectedItems = m_feedList->selectedItems();
|
|
Q_ASSERT(selectedItems.size() == 1);
|
|
QTreeWidgetItem *item = selectedItems.at(0);
|
|
RssFilePtr rss_item = m_feedList->getRSSItem(item);
|
|
bool ok;
|
|
QString newName;
|
|
do {
|
|
newName = QInputDialog::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)) {
|
|
QMessageBox::warning(0, tr("Name already in use"), tr("This name is already used by another item, please choose another one."));
|
|
ok = false;
|
|
}
|
|
} else {
|
|
return;
|
|
}
|
|
}while(!ok);
|
|
// Rename item
|
|
rss_item->rename(newName);
|
|
// Update TreeWidget
|
|
updateItemInfos(item);
|
|
}
|
|
|
|
//right-click on stream : refresh it
|
|
void RSSImp::refreshSelectedItems() {
|
|
QList<QTreeWidgetItem*> selectedItems = m_feedList->selectedItems();
|
|
foreach (QTreeWidgetItem* item, selectedItems) {
|
|
RssFilePtr file = m_feedList->getRSSItem(item);
|
|
// Update icons
|
|
if (item == m_feedList->stickyUnreadItem()) {
|
|
foreach (QTreeWidgetItem *feed, m_feedList->getAllFeedItems()) {
|
|
feed->setData(0, Qt::DecorationRole, QVariant(QIcon(":/Icons/loading.png")));
|
|
}
|
|
file->refresh();
|
|
break;
|
|
} else {
|
|
if (qSharedPointerDynamicCast<RssFeed>(file)) {
|
|
item->setData(0, Qt::DecorationRole, QVariant(QIcon(":/Icons/loading.png")));
|
|
} else if (qSharedPointerDynamicCast<RssFolder>(file)) {
|
|
// Update feeds in the folder
|
|
foreach (QTreeWidgetItem *feed, m_feedList->getAllFeedItems(item)) {
|
|
feed->setData(0, Qt::DecorationRole, QVariant(QIcon(":/Icons/loading.png")));
|
|
}
|
|
}
|
|
}
|
|
// Actually refresh
|
|
file->refresh();
|
|
}
|
|
}
|
|
|
|
void RSSImp::copySelectedFeedsURL() {
|
|
QStringList URLs;
|
|
QList<QTreeWidgetItem*> selectedItems = m_feedList->selectedItems();
|
|
QTreeWidgetItem* item;
|
|
foreach (item, selectedItems) {
|
|
if (m_feedList->isFeed(item))
|
|
URLs << m_feedList->getItemID(item);
|
|
}
|
|
qApp->clipboard()->setText(URLs.join("\n"));
|
|
}
|
|
|
|
void RSSImp::on_markReadButton_clicked() {
|
|
QList<QTreeWidgetItem*> selectedItems = m_feedList->selectedItems();
|
|
QTreeWidgetItem* item;
|
|
foreach (item, selectedItems) {
|
|
RssFilePtr rss_item = m_feedList->getRSSItem(item);
|
|
rss_item->markAsRead();
|
|
updateItemInfos(item);
|
|
}
|
|
if (selectedItems.size())
|
|
refreshArticleList(m_feedList->currentItem());
|
|
}
|
|
|
|
void RSSImp::fillFeedsList(QTreeWidgetItem *parent, const RssFolderPtr& rss_parent) {
|
|
QList<RssFilePtr> children;
|
|
if (parent) {
|
|
children = rss_parent->getContent();
|
|
} else {
|
|
children = m_rssManager->getContent();
|
|
}
|
|
foreach (const RssFilePtr& rss_child, children) {
|
|
QTreeWidgetItem* item;
|
|
if (!parent)
|
|
item = new QTreeWidgetItem(m_feedList);
|
|
else
|
|
item = new QTreeWidgetItem(parent);
|
|
item->setData(0, Qt::DisplayRole, QVariant(rss_child->displayName()+ QString::fromUtf8(" (")+QString::number(rss_child->unreadCount(), 10)+QString(")")));
|
|
// Notify TreeWidget of item addition
|
|
m_feedList->itemAdded(item, rss_child);
|
|
// Set Icon
|
|
if (qSharedPointerDynamicCast<RssFeed>(rss_child)) {
|
|
item->setData(0,Qt::DecorationRole, QVariant(QIcon(QString::fromUtf8(":/Icons/loading.png"))));
|
|
} else if (RssFolderPtr folder = qSharedPointerDynamicCast<RssFolder>(rss_child)) {
|
|
item->setData(0,Qt::DecorationRole, QVariant(IconProvider::instance()->getIcon("inode-directory")));
|
|
// Recurvive call to load sub folders/files
|
|
fillFeedsList(item, folder);
|
|
}
|
|
}
|
|
}
|
|
|
|
// fills the newsList
|
|
void RSSImp::refreshArticleList(QTreeWidgetItem* item) {
|
|
if (!item) {
|
|
listArticles->clear();
|
|
return;
|
|
}
|
|
|
|
RssFilePtr rss_item = m_feedList->getRSSItem(item);
|
|
if (!rss_item) return;
|
|
|
|
qDebug("Getting the list of news");
|
|
RssArticleList news;
|
|
if (rss_item == m_rssManager)
|
|
news = rss_item->unreadArticleList();
|
|
else if (rss_item)
|
|
news = rss_item->articleList();
|
|
// Sort
|
|
RssManager::sortArticleListByDateDesc(news);
|
|
// Clear the list first
|
|
textBrowser->clear();
|
|
m_currentArticle = 0;
|
|
listArticles->clear();
|
|
qDebug("Got the list of news");
|
|
foreach (const RssArticlePtr &article, news) {
|
|
QListWidgetItem* it = new QListWidgetItem(listArticles);
|
|
it->setData(Article::TitleRole, article->title());
|
|
it->setData(Article::FeedUrlRole, article->parent()->url());
|
|
it->setData(Article::IdRole, article->guid());
|
|
if (article->isRead()) {
|
|
it->setData(Article::ColorRole, QVariant(QColor("grey")));
|
|
it->setData(Article::IconRole, QVariant(QIcon(":/Icons/sphere.png")));
|
|
}else{
|
|
it->setData(Article::ColorRole, QVariant(QColor("blue")));
|
|
it->setData(Article::IconRole, QVariant(QIcon(":/Icons/sphere2.png")));
|
|
}
|
|
}
|
|
qDebug("Added all news to the GUI");
|
|
qDebug("First news selected");
|
|
}
|
|
|
|
// display a news
|
|
void RSSImp::refreshTextBrowser() {
|
|
QList<QListWidgetItem*> 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;
|
|
}
|
|
RssFeedPtr stream = m_feedList->getRSSItemFromUrl(item->data(Article::FeedUrlRole).toString());
|
|
RssArticlePtr article = stream->getItem(item->data(Article::IdRole).toString());
|
|
QString html;
|
|
html += "<div style='border: 2px solid red; margin-left: 5px; margin-right: 5px; margin-bottom: 5px;'>";
|
|
html += "<div style='background-color: #678db2; font-weight: bold; color: #fff;'>"+article->title() + "</div>";
|
|
if (article->date().isValid()) {
|
|
html += "<div style='background-color: #efefef;'><b>"+tr("Date: ")+"</b>"+article->date().toLocalTime().toString(Qt::SystemLocaleLongDate)+"</div>";
|
|
}
|
|
if (!article->author().isEmpty()) {
|
|
html += "<div style='background-color: #efefef;'><b>"+tr("Author: ")+"</b>"+article->author()+"</div>";
|
|
}
|
|
html += "</div>";
|
|
html += "<divstyle='margin-left: 5px; margin-right: 5px;'>"+article->description()+"</div>";
|
|
textBrowser->setHtml(html);
|
|
article->markAsRead();
|
|
item->setData(Article::ColorRole, QVariant(QColor("grey")));
|
|
item->setData(Article::IconRole, QVariant(QIcon(":/Icons/sphere.png")));
|
|
// Decrement feed nb unread news
|
|
updateItemInfos(m_feedList->stickyUnreadItem());
|
|
updateItemInfos(m_feedList->getTreeItemFromUrl(item->data(Article::FeedUrlRole).toString()));
|
|
}
|
|
|
|
void RSSImp::saveSlidersPosition() {
|
|
// Remember sliders positions
|
|
QIniSettings settings("qBittorrent", "qBittorrent");
|
|
settings.setValue("rss/splitter_h", splitter_h->saveState());
|
|
settings.setValue("rss/splitter_v", splitter_v->saveState());
|
|
qDebug("Splitters position saved");
|
|
}
|
|
|
|
void RSSImp::restoreSlidersPosition() {
|
|
QIniSettings settings("qBittorrent", "qBittorrent");
|
|
QByteArray pos_h = settings.value("rss/splitter_h", QByteArray()).toByteArray();
|
|
if (!pos_h.isNull()) {
|
|
splitter_h->restoreState(pos_h);
|
|
}
|
|
QByteArray pos_v = settings.value("rss/splitter_v", QByteArray()).toByteArray();
|
|
if (!pos_v.isNull()) {
|
|
splitter_v->restoreState(pos_v);
|
|
}
|
|
}
|
|
|
|
void RSSImp::updateItemsInfos(const QList<QTreeWidgetItem *> &items) {
|
|
foreach (QTreeWidgetItem* item, items) {
|
|
updateItemInfos(item);
|
|
}
|
|
}
|
|
|
|
void RSSImp::updateItemInfos(QTreeWidgetItem *item) {
|
|
RssFilePtr rss_item = m_feedList->getRSSItem(item);
|
|
if (!rss_item)
|
|
return;
|
|
|
|
QString name;
|
|
if (rss_item == m_rssManager)
|
|
name = tr("Unread");
|
|
else
|
|
name = rss_item->displayName();
|
|
item->setText(0, name + QString::fromUtf8(" (") + QString::number(rss_item->unreadCount(), 10)+ QString(")"));
|
|
// If item has a parent, update it too
|
|
if (item->parent())
|
|
updateItemInfos(item->parent());
|
|
}
|
|
|
|
void RSSImp::updateFeedIcon(const QString &url, const QString &icon_path) {
|
|
QTreeWidgetItem *item = m_feedList->getTreeItemFromUrl(url);
|
|
item->setData(0,Qt::DecorationRole, QVariant(QIcon(icon_path)));
|
|
}
|
|
|
|
void RSSImp::updateFeedInfos(const QString &url, const QString &display_name, uint nbUnread) {
|
|
qDebug() << Q_FUNC_INFO << display_name;
|
|
QTreeWidgetItem *item = m_feedList->getTreeItemFromUrl(url);
|
|
RssFeedPtr stream = qSharedPointerCast<RssFeed>(m_feedList->getRSSItem(item));
|
|
item->setText(0, display_name + QString::fromUtf8(" (") + QString::number(nbUnread, 10)+ QString(")"));
|
|
if (!stream->isLoading())
|
|
item->setData(0,Qt::DecorationRole, QVariant(QIcon(stream->icon())));
|
|
// Update parent
|
|
if (item->parent())
|
|
updateItemInfos(item->parent());
|
|
// Update Unread item
|
|
updateItemInfos(m_feedList->stickyUnreadItem());
|
|
// If the feed is selected, update the displayed news
|
|
if (m_feedList->currentItem() == item ) {
|
|
refreshArticleList(item);
|
|
} else {
|
|
// Update unread items
|
|
if (m_feedList->currentItem() == m_feedList->stickyUnreadItem()) {
|
|
refreshArticleList(m_feedList->stickyUnreadItem());
|
|
}
|
|
}
|
|
}
|
|
|
|
void RSSImp::updateRefreshInterval(uint val) {
|
|
m_rssManager->updateRefreshInterval(val);
|
|
}
|
|
|
|
RSSImp::RSSImp(QWidget *parent) : QWidget(parent), m_rssManager(new RssManager) {
|
|
setupUi(this);
|
|
// Icons
|
|
actionCopy_feed_URL->setIcon(IconProvider::instance()->getIcon("edit-copy"));
|
|
actionDelete->setIcon(IconProvider::instance()->getIcon("edit-delete"));
|
|
actionDownload_torrent->setIcon(IconProvider::instance()->getIcon("download"));
|
|
actionManage_cookies->setIcon(IconProvider::instance()->getIcon("preferences-web-browser-cookies"));
|
|
actionMark_items_read->setIcon(IconProvider::instance()->getIcon("mail-mark-read"));
|
|
actionNew_folder->setIcon(IconProvider::instance()->getIcon("folder-new"));
|
|
actionNew_subscription->setIcon(IconProvider::instance()->getIcon("list-add"));
|
|
actionOpen_news_URL->setIcon(IconProvider::instance()->getIcon("application-x-mswinurl"));
|
|
actionRename->setIcon(IconProvider::instance()->getIcon("edit-rename"));
|
|
actionUpdate->setIcon(IconProvider::instance()->getIcon("view-refresh"));
|
|
actionUpdate_all_feeds->setIcon(IconProvider::instance()->getIcon("view-refresh"));
|
|
newFeedButton->setIcon(IconProvider::instance()->getIcon("list-add"));
|
|
markReadButton->setIcon(IconProvider::instance()->getIcon("mail-mark-read"));
|
|
updateAllButton->setIcon(IconProvider::instance()->getIcon("view-refresh"));
|
|
rssDownloaderBtn->setIcon(IconProvider::instance()->getIcon("download"));
|
|
settingsButton->setIcon(IconProvider::instance()->getIcon("preferences-system"));
|
|
|
|
m_feedList = new FeedListWidget(splitter_h, m_rssManager);
|
|
splitter_h->insertWidget(0, m_feedList);
|
|
listArticles->setSelectionBehavior(QAbstractItemView::SelectItems);
|
|
listArticles->setSelectionMode(QAbstractItemView::SingleSelection);
|
|
|
|
m_rssManager->loadStreamList();
|
|
fillFeedsList();
|
|
refreshArticleList(m_feedList->currentItem());
|
|
|
|
loadFoldersOpenState();
|
|
connect(m_rssManager.data(), SIGNAL(feedInfosChanged(QString, QString, unsigned int)), this, SLOT(updateFeedInfos(QString, QString, unsigned int)));
|
|
connect(m_rssManager.data(), SIGNAL(feedIconChanged(QString, QString)), this, SLOT(updateFeedIcon(QString, QString)));
|
|
|
|
connect(m_feedList, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(displayRSSListMenu(const QPoint&)));
|
|
connect(listArticles, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(displayItemsListMenu(const QPoint&)));
|
|
|
|
// Feeds list actions
|
|
connect(actionDelete, SIGNAL(triggered()), this, SLOT(deleteSelectedItems()));
|
|
connect(actionRename, SIGNAL(triggered()), this, SLOT(renameFiles()));
|
|
connect(actionUpdate, SIGNAL(triggered()), this, SLOT(refreshSelectedItems()));
|
|
connect(actionNew_folder, SIGNAL(triggered()), this, SLOT(askNewFolder()));
|
|
connect(actionNew_subscription, SIGNAL(triggered()), this, SLOT(on_newFeedButton_clicked()));
|
|
connect(actionUpdate_all_feeds, SIGNAL(triggered()), this, SLOT(on_updateAllButton_clicked()));
|
|
connect(actionCopy_feed_URL, SIGNAL(triggered()), this, SLOT(copySelectedFeedsURL()));
|
|
connect(actionMark_items_read, SIGNAL(triggered()), this, SLOT(on_markReadButton_clicked()));
|
|
// News list actions
|
|
connect(actionOpen_news_URL, SIGNAL(triggered()), this, SLOT(openNewsUrl()));
|
|
connect(actionDownload_torrent, SIGNAL(triggered()), this, SLOT(downloadTorrent()));
|
|
|
|
connect(m_feedList, SIGNAL(currentItemChanged(QTreeWidgetItem*,QTreeWidgetItem*)), this, SLOT(refreshArticleList(QTreeWidgetItem*)));
|
|
connect(m_feedList, SIGNAL(foldersAltered(QList<QTreeWidgetItem*>)), this, SLOT(updateItemsInfos(QList<QTreeWidgetItem*>)));
|
|
connect(m_feedList, SIGNAL(overwriteAttempt(QString)), this, SLOT(displayOverwriteError(QString)));
|
|
|
|
connect(listArticles, SIGNAL(itemSelectionChanged()), this, SLOT(refreshTextBrowser()));
|
|
connect(listArticles, SIGNAL(itemDoubleClicked(QListWidgetItem *)), this, SLOT(downloadTorrent()));
|
|
|
|
// Refresh all feeds
|
|
m_rssManager->refresh();
|
|
// Restore sliders position
|
|
restoreSlidersPosition();
|
|
// Bind saveSliders slots
|
|
connect(splitter_v, SIGNAL(splitterMoved(int, int)), this, SLOT(saveSlidersPosition()));
|
|
connect(splitter_h, SIGNAL(splitterMoved(int, int)), this, SLOT(saveSlidersPosition()));
|
|
|
|
qDebug("RSSImp constructed");
|
|
}
|
|
|
|
RSSImp::~RSSImp() {
|
|
qDebug("Deleting RSSImp...");
|
|
saveFoldersOpenState();
|
|
delete m_feedList;
|
|
qDebug("RSSImp deleted");
|
|
}
|
|
|
|
|
|
void RSSImp::on_settingsButton_clicked() {
|
|
RssSettingsDlg dlg(this);
|
|
if (dlg.exec())
|
|
updateRefreshInterval(RssSettings().getRSSRefreshInterval());
|
|
}
|
|
|
|
void RSSImp::on_rssDownloaderBtn_clicked()
|
|
{
|
|
AutomatedRssDownloader dlg(m_rssManager, this);
|
|
dlg.exec();
|
|
if (dlg.isRssDownloaderEnabled())
|
|
on_updateAllButton_clicked();
|
|
}
|