Some work about adaptive color scheme for Web UI (PR #19901)
http://[316:c51a:62a3:8b9::4]/d4708/qBittorrent/src/branch/adaptive-webui
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
796 lines
30 KiB
796 lines
30 KiB
/* |
|
* 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 <QMenu> |
|
#include <QStandardItemModel> |
|
#include <QMessageBox> |
|
#include <QString> |
|
#include <QClipboard> |
|
#include <QDragMoveEvent> |
|
#include <QDebug> |
|
|
|
#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 "rssparser.h" |
|
#include "rssfeed.h" |
|
#include "automatedrssdownloader.h" |
|
#include "iconprovider.h" |
|
#include "autoexpandabledialog.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); |
|
} |
|
} |
|
else { |
|
myRSSListMenu.addAction(actionDelete); |
|
myRSSListMenu.addSeparator(); |
|
} |
|
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) { |
|
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; |
|
Preferences* const pref = Preferences::instance(); |
|
QList<QByteArray> raw_cookies = CookiesDlg::askForCookies(this, pref->getHostNameCookies(feed_hostname), &ok); |
|
if (ok) { |
|
qDebug() << "Settings cookies for host name: " << feed_hostname; |
|
pref->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 = AutoExpandableDialog::getText(this, tr("Please choose a folder name"), tr("Folder name:"), QLineEdit::Normal, tr("New folder"), &ok); |
|
if (!ok) |
|
return; |
|
|
|
RssFolderPtr newFolder = rss_parent->addFolder(new_name); |
|
QTreeWidgetItem* folderItem = createFolderListItem(newFolder); |
|
if (parent_item) |
|
parent_item->addChild(folderItem); |
|
else |
|
m_feedList->addTopLevelItem(folderItem); |
|
// Notify TreeWidget |
|
m_feedList->itemAdded(folderItem, newFolder); |
|
// Expand parent folder to display new folder |
|
if (parent_item) |
|
parent_item->setExpanded(true); |
|
m_rssManager->saveStreamList(); |
|
} |
|
|
|
// 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 = AutoExpandableDialog::getText(this, tr("Please type a rss stream url"), tr("Stream URL:"), QLineEdit::Normal, default_url, &ok); |
|
if (!ok) |
|
return; |
|
|
|
newUrl = newUrl.trimmed(); |
|
if (newUrl.isEmpty()) |
|
return; |
|
|
|
if (m_feedList->hasFeed(newUrl)) { |
|
QMessageBox::warning(this, "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 = createFolderListItem(stream); |
|
if (parent_item) |
|
parent_item->addChild(item); |
|
else |
|
m_feedList->addTopLevelItem(item); |
|
// Notify TreeWidget |
|
m_feedList->itemAdded(item, stream); |
|
|
|
stream->refresh(); |
|
m_rssManager->saveStreamList(); |
|
} |
|
|
|
// delete a stream by a button |
|
void RSSImp::deleteSelectedItems() |
|
{ |
|
QList<QTreeWidgetItem*> selectedItems = m_feedList->selectedItems(); |
|
if (selectedItems.isEmpty()) |
|
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) |
|
return; |
|
|
|
foreach (QTreeWidgetItem* item, selectedItems) { |
|
if (m_feedList->currentFeed() == item) { |
|
textBrowser->clear(); |
|
m_currentArticle = 0; |
|
listArticles->clear(); |
|
} |
|
if (item == m_feedList->stickyUnreadItem()) |
|
continue; |
|
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(); |
|
} |
|
// Clear feed data from RSS parser (possible caching). |
|
RssFeed* rssFeed = dynamic_cast<RssFeed*>(rss_item.data()); |
|
if (rssFeed) |
|
m_rssManager->rssParser()->clearFeedData(rssFeed->url()); |
|
} |
|
m_rssManager->saveStreamList(); |
|
// Update Unread items |
|
updateItemInfos(m_feedList->stickyUnreadItem()); |
|
} |
|
|
|
void RSSImp::loadFoldersOpenState() |
|
{ |
|
QStringList open_folders = Preferences::instance()->getRssOpenFolders(); |
|
foreach (const QString& var_path, open_folders) { |
|
QStringList path = var_path.split("\\"); |
|
QTreeWidgetItem* parent = 0; |
|
foreach (const 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; |
|
} |
|
Preferences::instance()->setRssOpenFolders(open_folders); |
|
} |
|
|
|
// refresh all streams by a button |
|
void RSSImp::refreshAllFeeds() |
|
{ |
|
foreach (QTreeWidgetItem* item, m_feedList->getAllFeedItems()) |
|
item->setData(0, Qt::DecorationRole, QVariant(QIcon(":/icons/loading.png"))); |
|
m_rssManager->refresh(); |
|
} |
|
|
|
void RSSImp::downloadSelectedTorrents() |
|
{ |
|
QList<QListWidgetItem*> selected_items = listArticles->selectedItems(); |
|
foreach (const 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; |
|
|
|
QString torrentLink = article->torrentUrl(); |
|
// Check if it is a magnet link |
|
if (torrentLink.startsWith("magnet:", Qt::CaseInsensitive)) { |
|
QBtSession::instance()->addMagnetInteractive(torrentLink); |
|
} |
|
else { |
|
// Load possible cookies |
|
QString feed_url = m_feedList->getItemID(m_feedList->selectedItems().first()); |
|
QString feed_hostname = QUrl::fromEncoded(feed_url.toUtf8()).host(); |
|
QList<QNetworkCookie> cookies = Preferences::instance()->getHostNameQNetworkCookies(feed_hostname); |
|
qDebug("Loaded %d cookies for RSS item\n", cookies.size()); |
|
QBtSession::instance()->downloadFromUrl(torrentLink, cookies); |
|
} |
|
} |
|
} |
|
|
|
// open the url of the selected RSS articles in the Web browser |
|
void RSSImp::openSelectedArticlesUrls() |
|
{ |
|
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::renameSelectedRssFile() |
|
{ |
|
QList<QTreeWidgetItem*> selectedItems = m_feedList->selectedItems(); |
|
if (selectedItems.size() != 1) |
|
return; |
|
QTreeWidgetItem* item = selectedItems.first(); |
|
if (item == m_feedList->stickyUnreadItem()) |
|
return; |
|
RssFilePtr rss_item = m_feedList->getRSSItem(item); |
|
bool ok; |
|
QString newName; |
|
do { |
|
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)) { |
|
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()) { |
|
refreshAllFeeds(); |
|
return; |
|
} |
|
else { |
|
if (!file->refresh()) |
|
continue; |
|
// Update UI |
|
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"))); |
|
} |
|
} |
|
} |
|
} |
|
|
|
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(); |
|
foreach (QTreeWidgetItem* item, selectedItems) { |
|
RssFilePtr rss_item = m_feedList->getRSSItem(item); |
|
Q_ASSERT(rss_item); |
|
rss_item->markAsRead(); |
|
updateItemInfos(item); |
|
} |
|
// Update article list |
|
if (!selectedItems.isEmpty()) |
|
populateArticleList(m_feedList->currentItem()); |
|
} |
|
|
|
QTreeWidgetItem* RSSImp::createFolderListItem(const RssFilePtr& rssFile) |
|
{ |
|
Q_ASSERT(rssFile); |
|
QTreeWidgetItem* item = new QTreeWidgetItem; |
|
item->setData(0, Qt::DisplayRole, QVariant(rssFile->displayName() + QString::fromUtf8(" (") + QString::number(rssFile->unreadCount()) + QString(")"))); |
|
item->setData(0, Qt::DecorationRole, rssFile->icon()); |
|
|
|
return item; |
|
} |
|
|
|
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& rssFile, children) { |
|
QTreeWidgetItem* item = createFolderListItem(rssFile); |
|
Q_ASSERT(item); |
|
if (parent) |
|
parent->addChild(item); |
|
else |
|
m_feedList->addTopLevelItem(item); |
|
|
|
// Notify TreeWidget of item addition |
|
m_feedList->itemAdded(item, rssFile); |
|
|
|
// Recursive call if this is a folder. |
|
if (RssFolderPtr folder = qSharedPointerDynamicCast<RssFolder>(rssFile)) |
|
fillFeedsList(item, folder); |
|
} |
|
} |
|
|
|
QListWidgetItem* RSSImp::createArticleListItem(const RssArticlePtr& article) |
|
{ |
|
Q_ASSERT(article); |
|
QListWidgetItem* item = new QListWidgetItem; |
|
|
|
item->setData(Article::TitleRole, article->title()); |
|
item->setData(Article::FeedUrlRole, article->parent()->url()); |
|
item->setData(Article::IdRole, article->guid()); |
|
if (article->isRead()) { |
|
item->setData(Article::ColorRole, QVariant(QColor("grey"))); |
|
item->setData(Article::IconRole, QVariant(QIcon(":/icons/sphere.png"))); |
|
} |
|
else { |
|
item->setData(Article::ColorRole, QVariant(QColor("blue"))); |
|
item->setData(Article::IconRole, QVariant(QIcon(":/icons/sphere2.png"))); |
|
} |
|
|
|
return item; |
|
} |
|
|
|
// fills the newsList |
|
void RSSImp::populateArticleList(QTreeWidgetItem* item) |
|
{ |
|
if (!item) { |
|
listArticles->clear(); |
|
return; |
|
} |
|
|
|
RssFilePtr rss_item = m_feedList->getRSSItem(item); |
|
if (!rss_item) |
|
return; |
|
|
|
// Clear the list first |
|
textBrowser->clear(); |
|
m_currentArticle = 0; |
|
listArticles->clear(); |
|
|
|
qDebug("Getting the list of news"); |
|
RssArticleList articles; |
|
if (rss_item == m_rssManager) |
|
articles = rss_item->unreadArticleListByDateDesc(); |
|
else |
|
articles = rss_item->articleListByDateDesc(); |
|
|
|
qDebug("Got the list of news"); |
|
foreach (const RssArticlePtr& article, articles) { |
|
QListWidgetItem* articleItem = createArticleListItem(article); |
|
listArticles->addItem(articleItem); |
|
} |
|
qDebug("Added all news to the GUI"); |
|
} |
|
|
|
// 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 += "<div style='margin-left: 5px; margin-right: 5px;'>"; |
|
if(Qt::mightBeRichText(article->description())) { |
|
html += article->description(); |
|
} |
|
else { |
|
QString description = article->description(); |
|
QRegExp rx; |
|
// If description is plain text, replace BBCode tags with HTML and wrap everything in <pre></pre> so it looks nice |
|
rx.setMinimal(true); |
|
rx.setCaseSensitivity(Qt::CaseInsensitive); |
|
|
|
rx.setPattern("\\[img\\](.+)\\[/img\\]"); |
|
description = description.replace(rx, "<img src=\"\\1\">"); |
|
|
|
rx.setPattern("\\[url=(\")?(.+)\\1\\]"); |
|
description = description.replace(rx, "<a href=\"\\2\">"); |
|
description = description.replace("[/url]", "</a>", Qt::CaseInsensitive); |
|
|
|
rx.setPattern("\\[(/)?([bius])\\]"); |
|
description = description.replace(rx, "<\\1\\2>"); |
|
|
|
rx.setPattern("\\[color=(\")?(.+)\\1\\]"); |
|
description = description.replace(rx, "<span style=\"color:\\2\">"); |
|
description = description.replace("[/color]", "</span>", Qt::CaseInsensitive); |
|
|
|
rx.setPattern("\\[size=(\")?(.+)\\d\\1\\]"); |
|
description = description.replace(rx, "<span style=\"font-size:\\2px\">"); |
|
description = description.replace("[/size]", "</span>", Qt::CaseInsensitive); |
|
|
|
html += "<pre>" + description + "</pre>"; |
|
} |
|
html += "</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 |
|
Preferences* const pref = Preferences::instance(); |
|
pref->setRssHSplitterState(splitter_h->saveState()); |
|
pref->setRssVSplitterState(splitter_v->saveState()); |
|
qDebug("Splitters position saved"); |
|
} |
|
|
|
void RSSImp::restoreSlidersPosition() |
|
{ |
|
const Preferences* const pref = Preferences::instance(); |
|
QByteArray pos_h = pref->getRssHSplitterState(); |
|
if (!pos_h.isNull()) |
|
splitter_h->restoreState(pos_h); |
|
QByteArray pos_v = pref->getRssVSplitterState(); |
|
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()) + QString(")")); |
|
// If item has a parent, update it too |
|
if (item->parent()) |
|
updateItemInfos(item->parent()); |
|
} |
|
|
|
void RSSImp::updateFeedIcon(const QString& url, const QString& iconPath) |
|
{ |
|
QTreeWidgetItem* item = m_feedList->getTreeItemFromUrl(url); |
|
item->setData(0, Qt::DecorationRole, QVariant(QIcon(iconPath))); |
|
} |
|
|
|
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) + QString(")")); |
|
if (!stream->isLoading()) |
|
item->setData(0, Qt::DecorationRole, QVariant(stream->icon())); |
|
// Update parent |
|
if (item->parent()) |
|
updateItemInfos(item->parent()); |
|
// Update Unread item |
|
updateItemInfos(m_feedList->stickyUnreadItem()); |
|
} |
|
|
|
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 ) { |
|
populateArticleList(item); |
|
} |
|
else { |
|
// Update unread items |
|
if (m_feedList->currentItem() == m_feedList->stickyUnreadItem()) |
|
populateArticleList(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); |
|
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())); |
|
deleteHotkey = new QShortcut(QKeySequence(QKeySequence::Delete), m_feedList, 0, 0, Qt::WidgetShortcut); |
|
connect(deleteHotkey, SIGNAL(activated()), SLOT(deleteSelectedItems())); |
|
|
|
m_rssManager->loadStreamList(); |
|
fillFeedsList(); |
|
populateArticleList(m_feedList->currentItem()); |
|
|
|
loadFoldersOpenState(); |
|
connect(m_rssManager.data(), SIGNAL(feedInfosChanged(QString, QString, unsigned int)), SLOT(updateFeedInfos(QString, QString, unsigned int))); |
|
connect(m_rssManager.data(), SIGNAL(feedContentChanged(QString)), SLOT(onFeedContentChanged(QString))); |
|
connect(m_rssManager.data(), SIGNAL(feedIconChanged(QString, QString)), SLOT(updateFeedIcon(QString, QString))); |
|
|
|
connect(m_feedList, SIGNAL(customContextMenuRequested(const QPoint &)), SLOT(displayRSSListMenu(const QPoint &))); |
|
connect(listArticles, SIGNAL(customContextMenuRequested(const QPoint &)), SLOT(displayItemsListMenu(const QPoint &))); |
|
|
|
// Feeds list actions |
|
connect(actionDelete, SIGNAL(triggered()), this, SLOT(deleteSelectedItems())); |
|
connect(actionRename, SIGNAL(triggered()), this, SLOT(renameSelectedRssFile())); |
|
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(refreshAllFeeds())); |
|
connect(updateAllButton, SIGNAL(clicked()), SLOT(refreshAllFeeds())); |
|
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(openSelectedArticlesUrls())); |
|
connect(actionDownload_torrent, SIGNAL(triggered()), this, SLOT(downloadSelectedTorrents())); |
|
|
|
connect(m_feedList, SIGNAL(currentItemChanged(QTreeWidgetItem*,QTreeWidgetItem*)), this, SLOT(populateArticleList(QTreeWidgetItem*))); |
|
connect(m_feedList, SIGNAL(foldersAltered(QList<QTreeWidgetItem*>)), this, SLOT(updateItemsInfos(QList<QTreeWidgetItem*>))); |
|
|
|
connect(listArticles, SIGNAL(itemSelectionChanged()), this, SLOT(refreshTextBrowser())); |
|
connect(listArticles, SIGNAL(itemDoubleClicked(QListWidgetItem *)), this, SLOT(downloadSelectedTorrents())); |
|
|
|
// 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 editHotkey; |
|
delete deleteHotkey; |
|
delete m_feedList; |
|
qDebug("RSSImp deleted"); |
|
} |
|
|
|
void RSSImp::on_settingsButton_clicked() |
|
{ |
|
RssSettingsDlg dlg(this); |
|
if (dlg.exec()) |
|
updateRefreshInterval(Preferences::instance()->getRSSRefreshInterval()); |
|
} |
|
|
|
void RSSImp::on_rssDownloaderBtn_clicked() |
|
{ |
|
AutomatedRssDownloader dlg(m_rssManager, this); |
|
dlg.exec(); |
|
if (dlg.isRssDownloaderEnabled()) { |
|
m_rssManager->recheckRssItemsForDownload(); |
|
refreshAllFeeds(); |
|
} |
|
}
|
|
|