1
0
mirror of https://github.com/d47081/qBittorrent.git synced 2025-02-02 18:04:32 +00:00
qBittorrent/src/gui/rss/rsswidget.cpp

598 lines
24 KiB
C++
Raw Normal View History

2017-03-07 16:10:42 +03:00
/*
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2017 Vladimir Golovnev <glassez@yandex.ru>
* Copyright (C) 2006 Christophe Dumez <chris@qbittorrent.org>
* Copyright (C) 2006 Arnaud Demaiziere <arnaud@qbittorrent.org>
*
* 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.
*/
#include "rsswidget.h"
#include <QClipboard>
#include <QDesktopServices>
#include <QDragMoveEvent>
#include <QMenu>
#include <QMessageBox>
#include <QRegularExpression>
2019-06-02 12:13:34 +03:00
#include <QShortcut>
2017-03-07 16:10:42 +03:00
#include <QString>
#include "base/bittorrent/session.h"
#include "base/global.h"
2017-03-07 16:10:42 +03:00
#include "base/net/downloadmanager.h"
#include "base/preferences.h"
#include "base/rss/rss_article.h"
#include "base/rss/rss_feed.h"
#include "base/rss/rss_folder.h"
#include "base/rss/rss_session.h"
2020-04-30 10:53:43 +03:00
#include "gui/addnewtorrentdialog.h"
#include "gui/autoexpandabledialog.h"
#include "gui/uithememanager.h"
2017-03-07 16:10:42 +03:00
#include "articlelistwidget.h"
#include "automatedrssdownloader.h"
#include "feedlistwidget.h"
#include "ui_rsswidget.h"
RSSWidget::RSSWidget(QWidget *parent)
: QWidget(parent)
, m_ui(new Ui::RSSWidget)
{
m_ui->setupUi(this);
// Icons
m_ui->actionCopyFeedURL->setIcon(UIThemeManager::instance()->getIcon(u"edit-copy"_qs));
m_ui->actionDelete->setIcon(UIThemeManager::instance()->getIcon(u"edit-clear"_qs));
m_ui->actionDownloadTorrent->setIcon(UIThemeManager::instance()->getIcon(u"downloading"_qs, u"download"_qs));
m_ui->actionEditFeedURL->setIcon(UIThemeManager::instance()->getIcon(u"edit-rename"_qs));
m_ui->actionMarkItemsRead->setIcon(UIThemeManager::instance()->getIcon(u"task-complete"_qs, u"mail-mark-read"_qs));
m_ui->actionNewFolder->setIcon(UIThemeManager::instance()->getIcon(u"folder-new"_qs));
m_ui->actionNewSubscription->setIcon(UIThemeManager::instance()->getIcon(u"list-add"_qs));
m_ui->actionOpenNewsURL->setIcon(UIThemeManager::instance()->getIcon(u"application-url"_qs));
m_ui->actionRename->setIcon(UIThemeManager::instance()->getIcon(u"edit-rename"_qs));
m_ui->actionUpdate->setIcon(UIThemeManager::instance()->getIcon(u"view-refresh"_qs));
m_ui->actionUpdateAllFeeds->setIcon(UIThemeManager::instance()->getIcon(u"view-refresh"_qs));
#ifndef Q_OS_MACOS
m_ui->newFeedButton->setIcon(UIThemeManager::instance()->getIcon(u"list-add"_qs));
m_ui->markReadButton->setIcon(UIThemeManager::instance()->getIcon(u"task-complete"_qs, u"mail-mark-read"_qs));
m_ui->updateAllButton->setIcon(UIThemeManager::instance()->getIcon(u"view-refresh"_qs));
m_ui->rssDownloaderBtn->setIcon(UIThemeManager::instance()->getIcon(u"downloading"_qs, u"download"_qs));
2017-06-12 22:47:28 +03:00
#endif
2017-03-07 16:10:42 +03:00
m_articleListWidget = new ArticleListWidget(m_ui->splitterMain);
m_ui->splitterMain->insertWidget(0, m_articleListWidget);
connect(m_articleListWidget, &ArticleListWidget::customContextMenuRequested, this, &RSSWidget::displayItemsListMenu);
connect(m_articleListWidget, &ArticleListWidget::currentItemChanged, this, &RSSWidget::handleCurrentArticleItemChanged);
connect(m_articleListWidget, &ArticleListWidget::itemDoubleClicked, this, &RSSWidget::downloadSelectedTorrents);
m_feedListWidget = new FeedListWidget(m_ui->splitterSide);
m_ui->splitterSide->insertWidget(0, m_feedListWidget);
connect(m_feedListWidget, &QAbstractItemView::doubleClicked, this, &RSSWidget::renameSelectedRSSItem);
connect(m_feedListWidget, &QTreeWidget::currentItemChanged, this, &RSSWidget::handleCurrentFeedItemChanged);
connect(m_feedListWidget, &QWidget::customContextMenuRequested, this, &RSSWidget::displayRSSListMenu);
loadFoldersOpenState();
m_feedListWidget->setCurrentItem(m_feedListWidget->stickyUnreadItem());
const auto *editHotkey = new QShortcut(Qt::Key_F2, m_feedListWidget, nullptr, nullptr, Qt::WidgetShortcut);
connect(editHotkey, &QShortcut::activated, this, &RSSWidget::renameSelectedRSSItem);
const auto *deleteHotkey = new QShortcut(QKeySequence::Delete, m_feedListWidget, nullptr, nullptr, Qt::WidgetShortcut);
connect(deleteHotkey, &QShortcut::activated, this, &RSSWidget::deleteSelectedItems);
2017-03-07 16:10:42 +03:00
// Feeds list actions
connect(m_ui->actionDelete, &QAction::triggered, this, &RSSWidget::deleteSelectedItems);
connect(m_ui->actionRename, &QAction::triggered, this, &RSSWidget::renameSelectedRSSItem);
connect(m_ui->actionEditFeedURL, &QAction::triggered, this, &RSSWidget::editSelectedRSSFeedURL);
2017-03-07 16:10:42 +03:00
connect(m_ui->actionUpdate, &QAction::triggered, this, &RSSWidget::refreshSelectedItems);
connect(m_ui->actionNewFolder, &QAction::triggered, this, &RSSWidget::askNewFolder);
connect(m_ui->actionNewSubscription, &QAction::triggered, this, &RSSWidget::on_newFeedButton_clicked);
connect(m_ui->actionUpdateAllFeeds, &QAction::triggered, this, &RSSWidget::refreshAllFeeds);
connect(m_ui->updateAllButton, &QAbstractButton::clicked, this, &RSSWidget::refreshAllFeeds);
connect(m_ui->actionCopyFeedURL, &QAction::triggered, this, &RSSWidget::copySelectedFeedsURL);
connect(m_ui->actionMarkItemsRead, &QAction::triggered, this, &RSSWidget::on_markReadButton_clicked);
// News list actions
connect(m_ui->actionOpenNewsURL, &QAction::triggered, this, &RSSWidget::openSelectedArticlesUrls);
connect(m_ui->actionDownloadTorrent, &QAction::triggered, this, &RSSWidget::downloadSelectedTorrents);
// Restore sliders position
restoreSlidersPosition();
// Bind saveSliders slots
connect(m_ui->splitterMain, &QSplitter::splitterMoved, this, &RSSWidget::saveSlidersPosition);
connect(m_ui->splitterSide, &QSplitter::splitterMoved, this, &RSSWidget::saveSlidersPosition);
if (RSS::Session::instance()->isProcessingEnabled())
m_ui->labelWarn->hide();
connect(RSS::Session::instance(), &RSS::Session::processingStateChanged
, this, &RSSWidget::handleSessionProcessingStateChanged);
connect(RSS::Session::instance()->rootFolder(), &RSS::Folder::unreadCountChanged
, this, &RSSWidget::handleUnreadCountChanged);
}
RSSWidget::~RSSWidget()
{
// we need it here to properly mark latest article
// as read without having additional code
m_articleListWidget->clear();
saveFoldersOpenState();
delete m_feedListWidget;
delete m_ui;
}
// display a right-click menu
void RSSWidget::displayRSSListMenu(const QPoint &pos)
{
if (!m_feedListWidget->indexAt(pos).isValid())
// No item under the mouse, clear selection
m_feedListWidget->clearSelection();
QMenu *menu = new QMenu(this);
menu->setAttribute(Qt::WA_DeleteOnClose);
const QList<QTreeWidgetItem *> selectedItems = m_feedListWidget->selectedItems();
2020-11-16 10:02:11 +03:00
if (!selectedItems.isEmpty())
{
menu->addAction(m_ui->actionUpdate);
menu->addAction(m_ui->actionMarkItemsRead);
menu->addSeparator();
2020-11-16 10:02:11 +03:00
if (selectedItems.size() == 1)
{
QTreeWidgetItem *selectedItem = selectedItems.first();
if (selectedItem != m_feedListWidget->stickyUnreadItem())
2020-11-16 10:02:11 +03:00
{
menu->addAction(m_ui->actionRename);
if (m_feedListWidget->isFeed(selectedItem))
menu->addAction(m_ui->actionEditFeedURL);
menu->addAction(m_ui->actionDelete);
menu->addSeparator();
if (m_feedListWidget->isFolder(selectedItem))
menu->addAction(m_ui->actionNewFolder);
2017-03-07 16:10:42 +03:00
}
}
2020-11-16 10:02:11 +03:00
else
{
menu->addAction(m_ui->actionDelete);
menu->addSeparator();
2017-03-07 16:10:42 +03:00
}
menu->addAction(m_ui->actionNewSubscription);
2020-11-16 10:02:11 +03:00
if (m_feedListWidget->isFeed(selectedItems.first()))
{
menu->addSeparator();
menu->addAction(m_ui->actionCopyFeedURL);
2017-03-07 16:10:42 +03:00
}
}
2020-11-16 10:02:11 +03:00
else
{
menu->addAction(m_ui->actionNewSubscription);
menu->addAction(m_ui->actionNewFolder);
menu->addSeparator();
menu->addAction(m_ui->actionUpdateAllFeeds);
2017-03-07 16:10:42 +03:00
}
menu->popup(QCursor::pos());
2017-03-07 16:10:42 +03:00
}
2022-01-21 17:31:31 +08:00
void RSSWidget::displayItemsListMenu()
2017-03-07 16:10:42 +03:00
{
bool hasTorrent = false;
bool hasLink = false;
2020-11-16 10:02:11 +03:00
for (const QListWidgetItem *item : asConst(m_articleListWidget->selectedItems()))
{
auto *article = item->data(Qt::UserRole).value<RSS::Article *>();
2017-03-07 16:10:42 +03:00
Q_ASSERT(article);
if (!article->torrentUrl().isEmpty())
hasTorrent = true;
if (!article->link().isEmpty())
hasLink = true;
if (hasTorrent && hasLink)
break;
}
QMenu *myItemListMenu = new QMenu(this);
myItemListMenu->setAttribute(Qt::WA_DeleteOnClose);
2017-03-07 16:10:42 +03:00
if (hasTorrent)
myItemListMenu->addAction(m_ui->actionDownloadTorrent);
2017-03-07 16:10:42 +03:00
if (hasLink)
myItemListMenu->addAction(m_ui->actionOpenNewsURL);
if (!myItemListMenu->isEmpty())
myItemListMenu->popup(QCursor::pos());
2017-03-07 16:10:42 +03:00
}
void RSSWidget::askNewFolder()
{
2020-03-06 15:04:29 +08:00
bool ok = false;
2017-03-07 16:10:42 +03:00
QString newName = AutoExpandableDialog::getText(
this, tr("Please choose a folder name"), tr("Folder name:"), QLineEdit::Normal
, tr("New folder"), &ok);
if (!ok) return;
newName = newName.trimmed();
if (newName.isEmpty()) return;
// Determine destination folder for new item
QTreeWidgetItem *destItem = nullptr;
QList<QTreeWidgetItem *> selectedItems = m_feedListWidget->selectedItems();
2020-11-16 10:02:11 +03:00
if (!selectedItems.empty())
{
2017-03-07 16:10:42 +03:00
destItem = selectedItems.first();
if (!m_feedListWidget->isFolder(destItem))
destItem = destItem->parent();
}
// Consider the case where the user clicked on Unread item
2017-04-24 21:05:27 +03:00
RSS::Folder *rssDestFolder = ((!destItem || (destItem == m_feedListWidget->stickyUnreadItem()))
2017-03-07 16:10:42 +03:00
? RSS::Session::instance()->rootFolder()
: qobject_cast<RSS::Folder *>(m_feedListWidget->getRSSItem(destItem)));
const QString newFolderPath = RSS::Item::joinPath(rssDestFolder->path(), newName);
const nonstd::expected<void, QString> result = RSS::Session::instance()->addFolder(newFolderPath);
if (!result)
QMessageBox::warning(this, u"qBittorrent"_qs, result.error(), QMessageBox::Ok);
2017-03-07 16:10:42 +03:00
// Expand destination folder to display new feed
2017-04-24 21:05:27 +03:00
if (destItem && (destItem != m_feedListWidget->stickyUnreadItem()))
2017-03-07 16:10:42 +03:00
destItem->setExpanded(true);
// As new RSS items are added synchronously, we can do the following here.
m_feedListWidget->setCurrentItem(m_feedListWidget->mapRSSItem(RSS::Session::instance()->itemByPath(newFolderPath)));
}
// add a stream by a button
void RSSWidget::on_newFeedButton_clicked()
{
// Ask for feed URL
const QString clipText = qApp->clipboard()->text();
const QString defaultURL = Net::DownloadManager::hasSupportedScheme(clipText) ? clipText : u"http://"_qs;
2017-03-07 16:10:42 +03:00
2020-03-06 15:04:29 +08:00
bool ok = false;
2017-03-07 16:10:42 +03:00
QString newURL = AutoExpandableDialog::getText(
this, tr("Please type a RSS feed URL"), tr("Feed URL:"), QLineEdit::Normal, defaultURL, &ok);
if (!ok) return;
newURL = newURL.trimmed();
if (newURL.isEmpty()) return;
// Determine destination folder for new item
QTreeWidgetItem *destItem = nullptr;
QList<QTreeWidgetItem *> selectedItems = m_feedListWidget->selectedItems();
2020-11-16 10:02:11 +03:00
if (!selectedItems.empty())
{
2017-03-07 16:10:42 +03:00
destItem = selectedItems.first();
if (!m_feedListWidget->isFolder(destItem))
destItem = destItem->parent();
}
// Consider the case where the user clicked on Unread item
RSS::Folder *rssDestFolder = ((!destItem || (destItem == m_feedListWidget->stickyUnreadItem()))
? RSS::Session::instance()->rootFolder()
: qobject_cast<RSS::Folder *>(m_feedListWidget->getRSSItem(destItem)));
// NOTE: We still add feed using legacy way (with URL as feed name)
const QString newFeedPath = RSS::Item::joinPath(rssDestFolder->path(), newURL);
const nonstd::expected<void, QString> result = RSS::Session::instance()->addFeed(newURL, newFeedPath);
if (!result)
QMessageBox::warning(this, u"qBittorrent"_qs, result.error(), QMessageBox::Ok);
2017-03-07 16:10:42 +03:00
// Expand destination folder to display new feed
if (destItem && (destItem != m_feedListWidget->stickyUnreadItem()))
destItem->setExpanded(true);
// As new RSS items are added synchronously, we can do the following here.
m_feedListWidget->setCurrentItem(m_feedListWidget->mapRSSItem(RSS::Session::instance()->itemByPath(newFeedPath)));
}
void RSSWidget::deleteSelectedItems()
{
const QList<QTreeWidgetItem *> selectedItems = m_feedListWidget->selectedItems();
2017-03-07 16:10:42 +03:00
if (selectedItems.isEmpty())
return;
if ((selectedItems.size() == 1) && (selectedItems.first() == m_feedListWidget->stickyUnreadItem()))
return;
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;
for (QTreeWidgetItem *item : selectedItems)
2017-03-07 16:10:42 +03:00
if (item != m_feedListWidget->stickyUnreadItem())
RSS::Session::instance()->removeItem(m_feedListWidget->itemPath(item));
}
void RSSWidget::loadFoldersOpenState()
{
const QStringList openedFolders = Preferences::instance()->getRssOpenFolders();
2020-11-16 10:02:11 +03:00
for (const QString &varPath : openedFolders)
{
2017-03-07 16:10:42 +03:00
QTreeWidgetItem *parent = nullptr;
for (const QString &name : asConst(varPath.split(u'\\')))
2020-11-16 10:02:11 +03:00
{
2017-03-07 16:10:42 +03:00
int nbChildren = (parent ? parent->childCount() : m_feedListWidget->topLevelItemCount());
2020-11-16 10:02:11 +03:00
for (int i = 0; i < nbChildren; ++i)
{
2017-03-07 16:10:42 +03:00
QTreeWidgetItem *child = (parent ? parent->child(i) : m_feedListWidget->topLevelItem(i));
2020-11-16 10:02:11 +03:00
if (m_feedListWidget->getRSSItem(child)->name() == name)
{
2017-03-07 16:10:42 +03:00
parent = child;
parent->setExpanded(true);
break;
}
}
}
}
}
void RSSWidget::saveFoldersOpenState()
{
QStringList openedFolders;
for (QTreeWidgetItem *item : asConst(m_feedListWidget->getAllOpenedFolders()))
2017-03-07 16:10:42 +03:00
openedFolders << m_feedListWidget->itemPath(item);
Preferences::instance()->setRssOpenFolders(openedFolders);
}
void RSSWidget::refreshAllFeeds()
{
RSS::Session::instance()->refresh();
}
void RSSWidget::downloadSelectedTorrents()
{
2020-11-16 10:02:11 +03:00
for (QListWidgetItem *item : asConst(m_articleListWidget->selectedItems()))
{
auto *article = item->data(Qt::UserRole).value<RSS::Article *>();
2017-03-07 16:10:42 +03:00
Q_ASSERT(article);
// Mark as read
article->markAsRead();
2020-11-16 10:02:11 +03:00
if (!article->torrentUrl().isEmpty())
{
2017-03-07 16:10:42 +03:00
if (AddNewTorrentDialog::isEnabled())
AddNewTorrentDialog::show(article->torrentUrl(), window());
2017-03-07 16:10:42 +03:00
else
BitTorrent::Session::instance()->addTorrent(article->torrentUrl());
}
}
}
// open the url of the selected RSS articles in the Web browser
void RSSWidget::openSelectedArticlesUrls()
{
2020-11-16 10:02:11 +03:00
for (QListWidgetItem *item : asConst(m_articleListWidget->selectedItems()))
{
auto *article = item->data(Qt::UserRole).value<RSS::Article *>();
2017-03-07 16:10:42 +03:00
Q_ASSERT(article);
// Mark as read
article->markAsRead();
if (!article->link().isEmpty())
QDesktopServices::openUrl(QUrl(article->link()));
}
}
void RSSWidget::renameSelectedRSSItem()
{
QList<QTreeWidgetItem *> selectedItems = m_feedListWidget->selectedItems();
if (selectedItems.size() != 1) return;
QTreeWidgetItem *item = selectedItems.first();
if (item == m_feedListWidget->stickyUnreadItem())
return;
RSS::Item *rssItem = m_feedListWidget->getRSSItem(item);
const QString parentPath = RSS::Item::parentPath(rssItem->path());
2020-03-06 15:04:29 +08:00
bool ok = false;
2020-11-16 10:02:11 +03:00
do
{
2017-03-07 16:10:42 +03:00
QString newName = AutoExpandableDialog::getText(
this, tr("Please choose a new name for this RSS feed"), tr("New feed name:")
, QLineEdit::Normal, rssItem->name(), &ok);
// Check if name is already taken
if (!ok) return;
const nonstd::expected<void, QString> result = RSS::Session::instance()->moveItem(rssItem, RSS::Item::joinPath(parentPath, newName));
if (!result)
2020-11-16 10:02:11 +03:00
{
QMessageBox::warning(nullptr, tr("Rename failed"), result.error());
2017-03-07 16:10:42 +03:00
ok = false;
}
} while (!ok);
}
void RSSWidget::editSelectedRSSFeedURL()
{
QList<QTreeWidgetItem *> selectedItems = m_feedListWidget->selectedItems();
if (selectedItems.size() != 1)
return;
QTreeWidgetItem *item = selectedItems.first();
RSS::Feed *rssFeed = qobject_cast<RSS::Feed *>(m_feedListWidget->getRSSItem(item));
Q_ASSERT(rssFeed);
if (Q_UNLIKELY(!rssFeed))
return;
bool ok = false;
QString newURL = AutoExpandableDialog::getText(this, tr("Please type a RSS feed URL")
, tr("Feed URL:"), QLineEdit::Normal, rssFeed->url(), &ok).trimmed();
if (!ok || newURL.isEmpty())
return;
const nonstd::expected<void, QString> result = RSS::Session::instance()->setFeedURL(rssFeed, newURL);
if (!result)
QMessageBox::warning(this, u"qBittorrent"_qs, result.error(), QMessageBox::Ok);
}
2017-03-07 16:10:42 +03:00
void RSSWidget::refreshSelectedItems()
{
2020-11-16 10:02:11 +03:00
for (QTreeWidgetItem *item : asConst(m_feedListWidget->selectedItems()))
{
if (item == m_feedListWidget->stickyUnreadItem())
{
2017-03-07 16:10:42 +03:00
refreshAllFeeds();
return;
}
m_feedListWidget->getRSSItem(item)->refresh();
}
}
void RSSWidget::copySelectedFeedsURL()
{
QStringList URLs;
2020-11-16 10:02:11 +03:00
for (QTreeWidgetItem *item : asConst(m_feedListWidget->selectedItems()))
{
if (auto *feed = qobject_cast<RSS::Feed *>(m_feedListWidget->getRSSItem(item)))
2017-03-07 16:10:42 +03:00
URLs << feed->url();
}
qApp->clipboard()->setText(URLs.join(u'\n'));
2017-03-07 16:10:42 +03:00
}
void RSSWidget::handleCurrentFeedItemChanged(QTreeWidgetItem *currentItem)
{
m_articleListWidget->setRSSItem(m_feedListWidget->getRSSItem(currentItem)
, (currentItem == m_feedListWidget->stickyUnreadItem()));
}
void RSSWidget::on_markReadButton_clicked()
{
2020-11-16 10:02:11 +03:00
for (QTreeWidgetItem *item : asConst(m_feedListWidget->selectedItems()))
{
2017-03-07 16:10:42 +03:00
m_feedListWidget->getRSSItem(item)->markAsRead();
if (item == m_feedListWidget->stickyUnreadItem())
break; // all items was read
}
}
// display a news
void RSSWidget::handleCurrentArticleItemChanged(QListWidgetItem *currentItem, QListWidgetItem *previousItem)
{
m_ui->textBrowser->clear();
2020-11-16 10:02:11 +03:00
if (previousItem)
{
auto *article = m_articleListWidget->getRSSArticle(previousItem);
2017-03-07 16:10:42 +03:00
Q_ASSERT(article);
article->markAsRead();
}
if (!currentItem) return;
auto *article = m_articleListWidget->getRSSArticle(currentItem);
2017-03-07 16:10:42 +03:00
Q_ASSERT(article);
2020-08-02 12:11:01 +05:30
const QString highlightedBaseColor = m_ui->textBrowser->palette().color(QPalette::Highlight).name();
const QString highlightedBaseTextColor = m_ui->textBrowser->palette().color(QPalette::HighlightedText).name();
const QString alternateBaseColor = m_ui->textBrowser->palette().color(QPalette::AlternateBase).name();
QString html =
u"<div style='border: 2px solid red; margin-left: 5px; margin-right: 5px; margin-bottom: 5px;'>" +
u"<div style='background-color: \"%1\"; font-weight: bold; color: \"%2\";'>%3</div>"_qs.arg(highlightedBaseColor, highlightedBaseTextColor, article->title());
2017-03-07 16:10:42 +03:00
if (article->date().isValid())
html += u"<div style='background-color: \"%1\";'><b>%2</b>%3</div>"_qs.arg(alternateBaseColor, tr("Date: "), QLocale::system().toString(article->date().toLocalTime()));
2017-03-07 16:10:42 +03:00
if (!article->author().isEmpty())
html += u"<div style='background-color: \"%1\";'><b>%2</b>%3</div>"_qs.arg(alternateBaseColor, tr("Author: "), article->author());
html += u"</div>"
u"<div style='margin-left: 5px; margin-right: 5px;'>";
2020-11-16 10:02:11 +03:00
if (Qt::mightBeRichText(article->description()))
{
2017-03-07 16:10:42 +03:00
html += article->description();
}
2020-11-16 10:02:11 +03:00
else
{
2017-03-07 16:10:42 +03:00
QString description = article->description();
QRegularExpression rx;
2017-03-07 16:10:42 +03:00
// If description is plain text, replace BBCode tags with HTML and wrap everything in <pre></pre> so it looks nice
rx.setPatternOptions(QRegularExpression::InvertedGreedinessOption
| QRegularExpression::CaseInsensitiveOption);
2017-03-07 16:10:42 +03:00
rx.setPattern(u"\\[img\\](.+)\\[/img\\]"_qs);
description = description.replace(rx, u"<img src=\"\\1\">"_qs);
2017-03-07 16:10:42 +03:00
rx.setPattern(u"\\[url=(\")?(.+)\\1\\]"_qs);
description = description.replace(rx, u"<a href=\"\\2\">"_qs);
description = description.replace(u"[/url]"_qs, u"</a>"_qs, Qt::CaseInsensitive);
2017-03-07 16:10:42 +03:00
rx.setPattern(u"\\[(/)?([bius])\\]"_qs);
description = description.replace(rx, u"<\\1\\2>"_qs);
2017-03-07 16:10:42 +03:00
rx.setPattern(u"\\[color=(\")?(.+)\\1\\]"_qs);
description = description.replace(rx, u"<span style=\"color:\\2\">"_qs);
description = description.replace(u"[/color]"_qs, u"</span>"_qs, Qt::CaseInsensitive);
2017-03-07 16:10:42 +03:00
rx.setPattern(u"\\[size=(\")?(.+)\\d\\1\\]"_qs);
description = description.replace(rx, u"<span style=\"font-size:\\2px\">"_qs);
description = description.replace(u"[/size]"_qs, u"</span>"_qs, Qt::CaseInsensitive);
2017-03-07 16:10:42 +03:00
html += u"<pre>" + description + u"</pre>";
2017-03-07 16:10:42 +03:00
}
html += u"</div>";
2017-03-07 16:10:42 +03:00
m_ui->textBrowser->setHtml(html);
}
void RSSWidget::saveSlidersPosition()
{
// Remember sliders positions
Preferences *const pref = Preferences::instance();
pref->setRssSideSplitterState(m_ui->splitterSide->saveState());
pref->setRssMainSplitterState(m_ui->splitterMain->saveState());
}
void RSSWidget::restoreSlidersPosition()
{
const Preferences *const pref = Preferences::instance();
const QByteArray stateSide = pref->getRssSideSplitterState();
if (!stateSide.isEmpty())
m_ui->splitterSide->restoreState(stateSide);
const QByteArray stateMain = pref->getRssMainSplitterState();
if (!stateMain.isEmpty())
m_ui->splitterMain->restoreState(stateMain);
}
void RSSWidget::updateRefreshInterval(int val) const
2017-03-07 16:10:42 +03:00
{
RSS::Session::instance()->setRefreshInterval(val);
}
void RSSWidget::on_rssDownloaderBtn_clicked()
{
auto *downloader = new AutomatedRssDownloader(this);
downloader->setAttribute(Qt::WA_DeleteOnClose);
downloader->open();
2017-03-07 16:10:42 +03:00
}
void RSSWidget::handleSessionProcessingStateChanged(bool enabled)
{
m_ui->labelWarn->setVisible(!enabled);
}
void RSSWidget::handleUnreadCountChanged()
{
emit unreadCountUpdated(RSS::Session::instance()->rootFolder()->unreadCount());
}