mirror of
https://github.com/qbittorrent/qBittorrent.git
synced 2025-12-20 15:37:26 -06:00
Redesign RSS subsystem
This commit is contained in:
@@ -641,8 +641,8 @@ void AddNewTorrentDialog::accept()
|
||||
if (m_contentModel)
|
||||
params.filePriorities = m_contentModel->model()->getFilePriorities();
|
||||
|
||||
params.addPaused = !ui->startTorrentCheckBox->isChecked();
|
||||
params.createSubfolder = ui->createSubfolderCheckBox->isChecked();
|
||||
params.addPaused = TriStateBool(!ui->startTorrentCheckBox->isChecked());
|
||||
params.createSubfolder = !ui->startTorrentCheckBox->isChecked();
|
||||
|
||||
QString savePath = ui->savePathComboBox->itemData(ui->savePathComboBox->currentIndex()).toString();
|
||||
if (ui->comboTTM->currentIndex() != 1) { // 0 is Manual mode and 1 is Automatic mode. Handle all non 1 values as manual mode.
|
||||
|
||||
@@ -2,7 +2,6 @@ INCLUDEPATH += $$PWD
|
||||
|
||||
include(lineedit/lineedit.pri)
|
||||
include(properties/properties.pri)
|
||||
include(rss/rss.pri)
|
||||
include(powermanagement/powermanagement.pri)
|
||||
unix:!macx:dbus: include(qtnotify/qtnotify.pri)
|
||||
|
||||
@@ -52,7 +51,12 @@ HEADERS += \
|
||||
$$PWD/cookiesdialog.h \
|
||||
$$PWD/categoryfiltermodel.h \
|
||||
$$PWD/categoryfilterwidget.h \
|
||||
$$PWD/banlistoptions.h
|
||||
$$PWD/banlistoptions.h \
|
||||
$$PWD/rss/rsswidget.h \
|
||||
$$PWD/rss/articlelistwidget.h \
|
||||
$$PWD/rss/feedlistwidget.h \
|
||||
$$PWD/rss/automatedrssdownloader.h \
|
||||
$$PWD/rss/htmlbrowser.h
|
||||
|
||||
SOURCES += \
|
||||
$$PWD/mainwindow.cpp \
|
||||
@@ -95,7 +99,12 @@ SOURCES += \
|
||||
$$PWD/cookiesdialog.cpp \
|
||||
$$PWD/categoryfiltermodel.cpp \
|
||||
$$PWD/categoryfilterwidget.cpp \
|
||||
$$PWD/banlistoptions.cpp
|
||||
$$PWD/banlistoptions.cpp \
|
||||
$$PWD/rss/rsswidget.cpp \
|
||||
$$PWD/rss/articlelistwidget.cpp \
|
||||
$$PWD/rss/feedlistwidget.cpp \
|
||||
$$PWD/rss/automatedrssdownloader.cpp \
|
||||
$$PWD/rss/htmlbrowser.cpp
|
||||
|
||||
win32|macx {
|
||||
HEADERS += $$PWD/programupdater.h
|
||||
@@ -123,6 +132,8 @@ FORMS += \
|
||||
$$PWD/search/pluginsourcedlg.ui \
|
||||
$$PWD/search/searchtab.ui \
|
||||
$$PWD/cookiesdialog.ui \
|
||||
$$PWD/banlistoptions.ui
|
||||
$$PWD/banlistoptions.ui \
|
||||
$$PWD/rss/rsswidget.ui \
|
||||
$$PWD/rss/automatedrssdownloader.ui
|
||||
|
||||
RESOURCES += $$PWD/about.qrc
|
||||
|
||||
@@ -64,6 +64,8 @@
|
||||
#include "base/bittorrent/session.h"
|
||||
#include "base/bittorrent/sessionstatus.h"
|
||||
#include "base/bittorrent/torrenthandle.h"
|
||||
#include "base/rss/rss_folder.h"
|
||||
#include "base/rss/rss_session.h"
|
||||
|
||||
#include "application.h"
|
||||
#if defined(Q_OS_WIN) || defined(Q_OS_MAC)
|
||||
@@ -86,7 +88,7 @@
|
||||
#include "transferlistfilterswidget.h"
|
||||
#include "propertieswidget.h"
|
||||
#include "statusbar.h"
|
||||
#include "rss_imp.h"
|
||||
#include "rss/rsswidget.h"
|
||||
#include "about_imp.h"
|
||||
#include "optionsdlg.h"
|
||||
#include "trackerlogin.h"
|
||||
@@ -296,7 +298,7 @@ MainWindow::MainWindow(QWidget *parent)
|
||||
// View settings
|
||||
m_ui->actionTopToolBar->setChecked(pref->isToolbarDisplayed());
|
||||
m_ui->actionSpeedInTitleBar->setChecked(pref->speedInTitleBar());
|
||||
m_ui->actionRSSReader->setChecked(pref->isRSSEnabled());
|
||||
m_ui->actionRSSReader->setChecked(pref->isRSSWidgetEnabled());
|
||||
m_ui->actionSearchWidget->setChecked(pref->isSearchEnabled());
|
||||
m_ui->actionExecutionLogs->setChecked(isExecutionLogEnabled());
|
||||
|
||||
@@ -600,14 +602,19 @@ void MainWindow::on_actionLock_triggered()
|
||||
hide();
|
||||
}
|
||||
|
||||
void MainWindow::handleRSSUnreadCountUpdated(int count)
|
||||
{
|
||||
m_tabs->setTabText(m_tabs->indexOf(m_rssWidget), tr("RSS (%1)").arg(count));
|
||||
}
|
||||
|
||||
void MainWindow::displayRSSTab(bool enable)
|
||||
{
|
||||
if (enable) {
|
||||
// RSS tab
|
||||
if (!m_rssWidget) {
|
||||
m_rssWidget = new RSSImp(m_tabs);
|
||||
connect(m_rssWidget, SIGNAL(updateRSSCount(int)), this, SLOT(updateRSSTabLabel(int)));
|
||||
int indexTab = m_tabs->addTab(m_rssWidget, tr("RSS (%1)").arg(0));
|
||||
m_rssWidget = new RSSWidget(m_tabs);
|
||||
connect(m_rssWidget.data(), &RSSWidget::unreadCountUpdated, this, &MainWindow::handleRSSUnreadCountUpdated);
|
||||
int indexTab = m_tabs->addTab(m_rssWidget, tr("RSS (%1)").arg(RSS::Session::instance()->rootFolder()->unreadCount()));
|
||||
m_tabs->setTabIcon(indexTab, GuiIconProvider::instance()->getIcon("application-rss+xml"));
|
||||
}
|
||||
}
|
||||
@@ -616,11 +623,6 @@ void MainWindow::displayRSSTab(bool enable)
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::updateRSSTabLabel(int count)
|
||||
{
|
||||
m_tabs->setTabText(m_tabs->indexOf(m_rssWidget), tr("RSS (%1)").arg(count));
|
||||
}
|
||||
|
||||
void MainWindow::displaySearchTab(bool enable)
|
||||
{
|
||||
Preferences::instance()->setSearchEnabled(enable);
|
||||
@@ -685,6 +687,10 @@ void MainWindow::cleanup()
|
||||
{
|
||||
writeSettings();
|
||||
|
||||
// delete RSSWidget explicitly to avoid crash in
|
||||
// handleRSSUnreadCountUpdated() at application shutdown
|
||||
delete m_rssWidget;
|
||||
|
||||
delete m_executableWatcher;
|
||||
if (m_systrayCreator)
|
||||
m_systrayCreator->stop();
|
||||
@@ -1502,7 +1508,7 @@ void MainWindow::on_actionSpeedInTitleBar_triggered()
|
||||
|
||||
void MainWindow::on_actionRSSReader_triggered()
|
||||
{
|
||||
Preferences::instance()->setRSSEnabled(m_ui->actionRSSReader->isChecked());
|
||||
Preferences::instance()->setRSSWidgetVisible(m_ui->actionRSSReader->isChecked());
|
||||
displayRSSTab(m_ui->actionRSSReader->isChecked());
|
||||
}
|
||||
|
||||
|
||||
@@ -44,7 +44,7 @@ class QTimer;
|
||||
|
||||
class downloadFromURL;
|
||||
class SearchWidget;
|
||||
class RSSImp;
|
||||
class RSSWidget;
|
||||
class about;
|
||||
class OptionsDialog;
|
||||
class TransferListWidget;
|
||||
@@ -138,7 +138,6 @@ private slots:
|
||||
#if defined(Q_OS_WIN) || defined(Q_OS_MAC)
|
||||
void handleUpdateCheckFinished(bool updateAvailable, QString newVersion, bool invokedByUser);
|
||||
#endif
|
||||
void updateRSSTabLabel(int count);
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
void pythonDownloadSuccess(const QString &url, const QString &filePath);
|
||||
@@ -151,6 +150,7 @@ private slots:
|
||||
void downloadFromURLList(const QStringList &urlList);
|
||||
void updateAltSpeedsBtn(bool alternative);
|
||||
void updateNbTorrents();
|
||||
void handleRSSUnreadCountUpdated(int count);
|
||||
|
||||
void on_actionSearchWidget_triggered();
|
||||
void on_actionRSSReader_triggered();
|
||||
@@ -211,7 +211,7 @@ private:
|
||||
QList<QPair<BitTorrent::TorrentHandle *, QString >> m_unauthenticatedTrackers; // Still needed?
|
||||
// GUI related
|
||||
bool m_posInitialized;
|
||||
QTabWidget *m_tabs;
|
||||
QPointer<QTabWidget> m_tabs;
|
||||
StatusBar *m_statusBar;
|
||||
QPointer<OptionsDialog> m_options;
|
||||
QPointer<about> m_aboutDlg;
|
||||
@@ -235,7 +235,7 @@ private:
|
||||
QAction *m_prioSeparatorMenu;
|
||||
QSplitter *m_splitter;
|
||||
QPointer<SearchWidget> m_searchWidget;
|
||||
QPointer<RSSImp> m_rssWidget;
|
||||
QPointer<RSSWidget> m_rssWidget;
|
||||
QPointer<ExecutionLog> m_executionLog;
|
||||
// Power Management
|
||||
PowerManagement *m_pwr;
|
||||
|
||||
@@ -54,6 +54,8 @@
|
||||
#include "base/net/portforwarder.h"
|
||||
#include "base/net/proxyconfigurationmanager.h"
|
||||
#include "base/preferences.h"
|
||||
#include "base/rss/rss_autodownloader.h"
|
||||
#include "base/rss/rss_session.h"
|
||||
#include "base/scanfoldersmodel.h"
|
||||
#include "base/torrentfileguard.h"
|
||||
#include "base/unicodestrings.h"
|
||||
@@ -61,6 +63,7 @@
|
||||
#include "base/utils/random.h"
|
||||
#include "addnewtorrentdialog.h"
|
||||
#include "advancedsettings.h"
|
||||
#include "rss/automatedrssdownloader.h"
|
||||
#include "banlistoptions.h"
|
||||
#include "guiiconprovider.h"
|
||||
#include "scanfoldersdelegate.h"
|
||||
@@ -84,6 +87,7 @@ OptionsDialog::OptionsDialog(QWidget *parent)
|
||||
m_ui->tabSelection->item(TAB_CONNECTION)->setIcon(GuiIconProvider::instance()->getIcon("network-wired"));
|
||||
m_ui->tabSelection->item(TAB_DOWNLOADS)->setIcon(GuiIconProvider::instance()->getIcon("folder-download"));
|
||||
m_ui->tabSelection->item(TAB_SPEED)->setIcon(GuiIconProvider::instance()->getIcon("speedometer", "chronometer"));
|
||||
m_ui->tabSelection->item(TAB_RSS)->setIcon(GuiIconProvider::instance()->getIcon("rss-config", "application-rss+xml"));
|
||||
#ifndef DISABLE_WEBUI
|
||||
m_ui->tabSelection->item(TAB_WEBUI)->setIcon(GuiIconProvider::instance()->getIcon("network-server"));
|
||||
#else
|
||||
@@ -335,6 +339,15 @@ OptionsDialog::OptionsDialog(QWidget *parent)
|
||||
connect(m_ui->DNSUsernameTxt, SIGNAL(textChanged(QString)), SLOT(enableApplyButton()));
|
||||
connect(m_ui->DNSPasswordTxt, SIGNAL(textChanged(QString)), SLOT(enableApplyButton()));
|
||||
#endif
|
||||
|
||||
// RSS tab
|
||||
connect(m_ui->checkRSSEnable, &QCheckBox::toggled, this, &OptionsDialog::enableApplyButton);
|
||||
connect(m_ui->checkRSSAutoDownloaderEnable, &QCheckBox::toggled, this, &OptionsDialog::enableApplyButton);
|
||||
connect(m_ui->spinRSSRefreshInterval, static_cast<void(QSpinBox::*)(int)>(&QSpinBox::valueChanged)
|
||||
, this, &OptionsDialog::enableApplyButton);
|
||||
connect(m_ui->spinRSSMaxArticlesPerFeed, static_cast<void(QSpinBox::*)(int)>(&QSpinBox::valueChanged), this, &OptionsDialog::enableApplyButton);
|
||||
connect(m_ui->btnEditRules, &QPushButton::clicked, [this]() { AutomatedRssDownloader(this).exec(); });
|
||||
|
||||
// Disable apply Button
|
||||
applyButton->setEnabled(false);
|
||||
// Tab selection mechanism
|
||||
@@ -500,6 +513,11 @@ void OptionsDialog::saveOptions()
|
||||
app->setFileLoggerEnabled(m_ui->checkFileLog->isChecked());
|
||||
// End General preferences
|
||||
|
||||
RSS::Session::instance()->setRefreshInterval(m_ui->spinRSSRefreshInterval->value());
|
||||
RSS::Session::instance()->setMaxArticlesPerFeed(m_ui->spinRSSMaxArticlesPerFeed->value());
|
||||
RSS::Session::instance()->setProcessingEnabled(m_ui->checkRSSEnable->isChecked());
|
||||
RSS::AutoDownloader::instance()->setProcessingEnabled(m_ui->checkRSSAutoDownloaderEnable->isChecked());
|
||||
|
||||
auto session = BitTorrent::Session::instance();
|
||||
|
||||
// Downloads preferences
|
||||
@@ -712,6 +730,11 @@ void OptionsDialog::loadOptions()
|
||||
m_ui->comboFileLogAgeType->setCurrentIndex(app->fileLoggerAgeType());
|
||||
// End General preferences
|
||||
|
||||
m_ui->checkRSSEnable->setChecked(RSS::Session::instance()->isProcessingEnabled());
|
||||
m_ui->checkRSSAutoDownloaderEnable->setChecked(RSS::AutoDownloader::instance()->isProcessingEnabled());
|
||||
m_ui->spinRSSRefreshInterval->setValue(RSS::Session::instance()->refreshInterval());
|
||||
m_ui->spinRSSMaxArticlesPerFeed->setValue(RSS::Session::instance()->maxArticlesPerFeed());
|
||||
|
||||
auto session = BitTorrent::Session::instance();
|
||||
|
||||
// Downloads preferences
|
||||
|
||||
@@ -68,6 +68,7 @@ private:
|
||||
TAB_CONNECTION,
|
||||
TAB_SPEED,
|
||||
TAB_BITTORRENT,
|
||||
TAB_RSS,
|
||||
TAB_WEBUI,
|
||||
TAB_ADVANCED
|
||||
};
|
||||
|
||||
@@ -45,7 +45,7 @@
|
||||
<enum>QListView::IconMode</enum>
|
||||
</property>
|
||||
<property name="currentRow">
|
||||
<number>0</number>
|
||||
<number>-1</number>
|
||||
</property>
|
||||
<item>
|
||||
<property name="text">
|
||||
@@ -72,6 +72,11 @@
|
||||
<string>BitTorrent</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>RSS</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Web UI</string>
|
||||
@@ -117,8 +122,8 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>497</width>
|
||||
<height>880</height>
|
||||
<width>470</width>
|
||||
<height>783</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_9">
|
||||
@@ -673,8 +678,8 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>586</width>
|
||||
<height>1118</height>
|
||||
<width>470</width>
|
||||
<height>994</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
@@ -1358,8 +1363,8 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>457</width>
|
||||
<height>672</height>
|
||||
<width>470</width>
|
||||
<height>619</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_20">
|
||||
@@ -1838,8 +1843,8 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>388</width>
|
||||
<height>452</height>
|
||||
<width>487</width>
|
||||
<height>542</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_5">
|
||||
@@ -2225,8 +2230,8 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>574</width>
|
||||
<height>534</height>
|
||||
<width>487</width>
|
||||
<height>542</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_7">
|
||||
@@ -2598,6 +2603,125 @@
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="tabRSSPage">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_25">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupRSSReader">
|
||||
<property name="title">
|
||||
<string>RSS Reader</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_26">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="checkRSSEnable">
|
||||
<property name="text">
|
||||
<string>Enable fetching RSS feeds</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QGridLayout" name="gridLayout_5">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_11">
|
||||
<property name="text">
|
||||
<string>Feeds refresh interval:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_12">
|
||||
<property name="text">
|
||||
<string>Maximum number of articles per feed:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QSpinBox" name="spinRSSRefreshInterval">
|
||||
<property name="suffix">
|
||||
<string> min</string>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>999999</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>5</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QSpinBox" name="spinRSSMaxArticlesPerFeed">
|
||||
<property name="maximum">
|
||||
<number>9999</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>100</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<spacer name="horizontalSpacer_6">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupRSSAutoDownloader">
|
||||
<property name="title">
|
||||
<string>RSS Torrent Auto Downloader</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_21">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="checkRSSAutoDownloaderEnable">
|
||||
<property name="text">
|
||||
<string>Enable auto downloading of RSS torrents</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btnEditRules">
|
||||
<property name="text">
|
||||
<string>Edit auto downloading rules...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer_5">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="tabWebuiPage">
|
||||
<layout class="QVBoxLayout" name="tabWebuiPageLayout">
|
||||
<property name="leftMargin">
|
||||
@@ -2622,8 +2746,8 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>438</width>
|
||||
<height>543</height>
|
||||
<width>487</width>
|
||||
<height>542</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_23">
|
||||
|
||||
117
src/gui/rss/articlelistwidget.cpp
Normal file
117
src/gui/rss/articlelistwidget.cpp
Normal file
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
* Bittorrent Client using Qt and libtorrent.
|
||||
* Copyright (C) 2017 Vladimir Golovnev <glassez@yandex.ru>
|
||||
*
|
||||
* 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 "articlelistwidget.h"
|
||||
|
||||
#include <QListWidgetItem>
|
||||
|
||||
#include "base/rss/rss_article.h"
|
||||
#include "base/rss/rss_item.h"
|
||||
|
||||
ArticleListWidget::ArticleListWidget(QWidget *parent)
|
||||
: QListWidget(parent)
|
||||
{
|
||||
setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
setSelectionMode(QAbstractItemView::ExtendedSelection);
|
||||
}
|
||||
|
||||
RSS::Article *ArticleListWidget::getRSSArticle(QListWidgetItem *item) const
|
||||
{
|
||||
Q_ASSERT(item);
|
||||
return reinterpret_cast<RSS::Article *>(item->data(Qt::UserRole).value<quintptr>());
|
||||
}
|
||||
|
||||
QListWidgetItem *ArticleListWidget::mapRSSArticle(RSS::Article *rssArticle) const
|
||||
{
|
||||
return m_rssArticleToListItemMapping.value(rssArticle);
|
||||
}
|
||||
|
||||
void ArticleListWidget::setRSSItem(RSS::Item *rssItem, bool unreadOnly)
|
||||
{
|
||||
// Clear the list first
|
||||
clear();
|
||||
if (m_rssItem)
|
||||
m_rssItem->disconnect(this);
|
||||
|
||||
m_unreadOnly = unreadOnly;
|
||||
m_rssItem = rssItem;
|
||||
if (!m_rssItem) return;
|
||||
|
||||
m_rssItem = rssItem;
|
||||
connect(m_rssItem, &RSS::Item::newArticle, this, &ArticleListWidget::handleArticleAdded);
|
||||
connect(m_rssItem, &RSS::Item::articleRead, this, &ArticleListWidget::handleArticleRead);
|
||||
connect(m_rssItem, &RSS::Item::articleAboutToBeRemoved, this, &ArticleListWidget::handleArticleAboutToBeRemoved);
|
||||
|
||||
foreach (auto article, rssItem->articles()) {
|
||||
if (!(m_unreadOnly && article->isRead()))
|
||||
addItem(createItem(article));
|
||||
}
|
||||
}
|
||||
|
||||
void ArticleListWidget::handleArticleAdded(RSS::Article *rssArticle)
|
||||
{
|
||||
if (!(m_unreadOnly && rssArticle->isRead()))
|
||||
addItem(createItem(rssArticle));
|
||||
}
|
||||
|
||||
void ArticleListWidget::handleArticleRead(RSS::Article *rssArticle)
|
||||
{
|
||||
if (m_unreadOnly) {
|
||||
delete m_rssArticleToListItemMapping.take(rssArticle);
|
||||
}
|
||||
else {
|
||||
auto item = mapRSSArticle(rssArticle);
|
||||
item->setData(Qt::ForegroundRole, QColor("grey"));
|
||||
item->setData(Qt::DecorationRole, QIcon(":/icons/sphere.png"));
|
||||
}
|
||||
}
|
||||
|
||||
void ArticleListWidget::handleArticleAboutToBeRemoved(RSS::Article *rssArticle)
|
||||
{
|
||||
delete m_rssArticleToListItemMapping.take(rssArticle);
|
||||
}
|
||||
|
||||
QListWidgetItem *ArticleListWidget::createItem(RSS::Article *article)
|
||||
{
|
||||
Q_ASSERT(article);
|
||||
QListWidgetItem *item = new QListWidgetItem;
|
||||
|
||||
item->setData(Qt::DisplayRole, article->title());
|
||||
item->setData(Qt::UserRole, reinterpret_cast<quintptr>(article));
|
||||
if (article->isRead()) {
|
||||
item->setData(Qt::ForegroundRole, QColor("grey"));
|
||||
item->setData(Qt::DecorationRole, QIcon(":/icons/sphere.png"));
|
||||
}
|
||||
else {
|
||||
item->setData(Qt::ForegroundRole, QColor("blue"));
|
||||
item->setData(Qt::DecorationRole, QIcon(":/icons/sphere2.png"));
|
||||
}
|
||||
|
||||
m_rssArticleToListItemMapping.insert(article, item);
|
||||
return item;
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Bittorrent Client using Qt4 and libtorrent.
|
||||
* Copyright (C) 2010 Christophe Dumez
|
||||
* Bittorrent Client using Qt and libtorrent.
|
||||
* Copyright (C) 2017 Vladimir Golovnev <glassez@yandex.ru>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
@@ -24,35 +24,43 @@
|
||||
* 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
|
||||
*/
|
||||
|
||||
#ifndef RSSSETTINGSDLG_H
|
||||
#define RSSSETTINGSDLG_H
|
||||
#ifndef ARTICLELISTWIDGET_H
|
||||
#define ARTICLELISTWIDGET_H
|
||||
|
||||
#include <QDialog>
|
||||
#include <QHash>
|
||||
#include <QListWidget>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
namespace Ui {
|
||||
class RssSettingsDlg;
|
||||
namespace RSS
|
||||
{
|
||||
class Article;
|
||||
class Item;
|
||||
}
|
||||
QT_END_NAMESPACE
|
||||
|
||||
class RssSettingsDlg : public QDialog
|
||||
class ArticleListWidget: public QListWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit RssSettingsDlg(QWidget *parent = 0);
|
||||
~RssSettingsDlg();
|
||||
explicit ArticleListWidget(QWidget *parent);
|
||||
|
||||
protected slots:
|
||||
void on_buttonBox_accepted();
|
||||
RSS::Article *getRSSArticle(QListWidgetItem *item) const;
|
||||
QListWidgetItem *mapRSSArticle(RSS::Article *rssArticle) const;
|
||||
|
||||
void setRSSItem(RSS::Item *rssItem, bool unreadOnly = false);
|
||||
|
||||
private slots:
|
||||
void handleArticleAdded(RSS::Article *rssArticle);
|
||||
void handleArticleRead(RSS::Article *rssArticle);
|
||||
void handleArticleAboutToBeRemoved(RSS::Article *rssArticle);
|
||||
|
||||
private:
|
||||
Ui::RssSettingsDlg *ui;
|
||||
QListWidgetItem *createItem(RSS::Article *article);
|
||||
|
||||
RSS::Item *m_rssItem = nullptr;
|
||||
bool m_unreadOnly = false;
|
||||
QHash<RSS::Article *, QListWidgetItem *> m_rssArticleToListItemMapping;
|
||||
};
|
||||
|
||||
#endif // RSSSETTINGS_H
|
||||
#endif // ARTICLELISTWIDGET_H
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,7 @@
|
||||
/*
|
||||
* Bittorrent Client using Qt4 and libtorrent.
|
||||
* Copyright (C) 2010 Christophe Dumez
|
||||
* Bittorrent Client using Qt and libtorrent.
|
||||
* Copyright (C) 2017 Vladimir Golovnev <glassez@yandex.ru>
|
||||
* Copyright (C) 2010 Christophe Dumez <chris@qbittorrent.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
@@ -24,99 +25,85 @@
|
||||
* 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
|
||||
*/
|
||||
|
||||
#ifndef AUTOMATEDRSSDOWNLOADER_H
|
||||
#define AUTOMATEDRSSDOWNLOADER_H
|
||||
|
||||
#include <QDialog>
|
||||
#include <QHideEvent>
|
||||
#include <QHash>
|
||||
#include <QPair>
|
||||
#include <QSet>
|
||||
#include <QShortcut>
|
||||
#include <QShowEvent>
|
||||
#include <QString>
|
||||
#include <QWeakPointer>
|
||||
|
||||
#include "base/rss/rssdownloadrule.h"
|
||||
#include "base/rss/rss_autodownloadrule.h"
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
namespace Ui
|
||||
{
|
||||
class AutomatedRssDownloader;
|
||||
}
|
||||
QT_END_NAMESPACE
|
||||
|
||||
namespace Rss
|
||||
{
|
||||
class DownloadRuleList;
|
||||
class Manager;
|
||||
}
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QListWidgetItem;
|
||||
class QRegularExpression;
|
||||
QT_END_NAMESPACE
|
||||
class QShortcut;
|
||||
|
||||
namespace RSS
|
||||
{
|
||||
class Feed;
|
||||
}
|
||||
|
||||
class AutomatedRssDownloader: public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit AutomatedRssDownloader(const QWeakPointer<Rss::Manager> &manager, QWidget *parent = 0);
|
||||
~AutomatedRssDownloader();
|
||||
bool isRssDownloaderEnabled() const;
|
||||
|
||||
protected:
|
||||
virtual void showEvent(QShowEvent *event) override;
|
||||
virtual void hideEvent(QHideEvent *event) override;
|
||||
|
||||
protected slots:
|
||||
void loadSettings();
|
||||
void saveSettings();
|
||||
void loadRulesList();
|
||||
void handleRuleCheckStateChange(QListWidgetItem *rule_item);
|
||||
void handleFeedCheckStateChange(QListWidgetItem *feed_item);
|
||||
void updateRuleDefinitionBox(QListWidgetItem *selected = 0);
|
||||
void clearRuleDefinitionBox();
|
||||
void saveEditedRule();
|
||||
void loadFeedList();
|
||||
void updateFeedList(QListWidgetItem *selected = 0);
|
||||
explicit AutomatedRssDownloader(QWidget *parent = nullptr);
|
||||
~AutomatedRssDownloader() override;
|
||||
|
||||
private slots:
|
||||
void displayRulesListMenu(const QPoint &pos);
|
||||
void on_addRuleBtn_clicked();
|
||||
void on_removeRuleBtn_clicked();
|
||||
void on_browseSP_clicked();
|
||||
void on_exportBtn_clicked();
|
||||
void on_importBtn_clicked();
|
||||
|
||||
void handleRuleCheckStateChange(QListWidgetItem *ruleItem);
|
||||
void handleFeedCheckStateChange(QListWidgetItem *feedItem);
|
||||
void displayRulesListMenu();
|
||||
void renameSelectedRule();
|
||||
void updateMatchingArticles();
|
||||
void updateRuleDefinitionBox();
|
||||
void updateFieldsToolTips(bool regex);
|
||||
void updateMustLineValidity();
|
||||
void updateMustNotLineValidity();
|
||||
void updateEpisodeFilterValidity();
|
||||
void onFinished(int result);
|
||||
void handleRuleDefinitionChanged();
|
||||
void handleRuleAdded(const QString &ruleName);
|
||||
void handleRuleRenamed(const QString &ruleName, const QString &oldRuleName);
|
||||
void handleRuleChanged(const QString &ruleName);
|
||||
void handleRuleAboutToBeRemoved(const QString &ruleName);
|
||||
|
||||
void handleProcessingStateChanged(bool enabled);
|
||||
|
||||
private:
|
||||
Rss::DownloadRulePtr getCurrentRule() const;
|
||||
void loadSettings();
|
||||
void saveSettings();
|
||||
void createRuleItem(const RSS::AutoDownloadRule &rule);
|
||||
void initCategoryCombobox();
|
||||
void addFeedArticlesToTree(const Rss::FeedPtr &feed, const QStringList &articles);
|
||||
void disconnectRuleFeedSlots();
|
||||
void connectRuleFeedSlots();
|
||||
void clearRuleDefinitionBox();
|
||||
void updateEditedRule();
|
||||
void updateMatchingArticles();
|
||||
void saveEditedRule();
|
||||
void loadFeedList();
|
||||
void updateFeedList();
|
||||
void addFeedArticlesToTree(RSS::Feed *feed, const QStringList &articles);
|
||||
|
||||
private:
|
||||
Ui::AutomatedRssDownloader *ui;
|
||||
QWeakPointer<Rss::Manager> m_manager;
|
||||
QListWidgetItem *m_editedRule;
|
||||
Rss::DownloadRuleList *m_ruleList;
|
||||
Rss::DownloadRuleList *m_editableRuleList;
|
||||
Ui::AutomatedRssDownloader *m_ui;
|
||||
QListWidgetItem *m_currentRuleItem;
|
||||
QShortcut *m_editHotkey;
|
||||
QShortcut *m_deleteHotkey;
|
||||
QSet<QPair<QString, QString>> m_treeListEntries;
|
||||
RSS::AutoDownloadRule m_currentRule;
|
||||
QHash<QString, QListWidgetItem *> m_itemsByRuleName;
|
||||
QRegularExpression *m_episodeRegex;
|
||||
QShortcut *editHotkey;
|
||||
QShortcut *deleteHotkey;
|
||||
QSet<QPair<QString, QString >> m_treeListEntries;
|
||||
};
|
||||
|
||||
#endif // AUTOMATEDRSSDOWNLOADER_H
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>816</width>
|
||||
<height>537</height>
|
||||
<height>523</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
@@ -15,20 +15,31 @@
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_5">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="checkEnableDownloader">
|
||||
<widget class="QLabel" name="labelWarn">
|
||||
<property name="font">
|
||||
<font>
|
||||
<weight>75</weight>
|
||||
<bold>true</bold>
|
||||
<italic>true</italic>
|
||||
</font>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">color: red;</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Enable Automated RSS Downloader</string>
|
||||
<string>Auto downloading of RSS torrents is disabled now! You can enable it in application settings.</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSplitter" name="hsplitter">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
@@ -249,12 +260,12 @@
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSpinBox" name="spinIgnorePeriod">
|
||||
<property name="specialValueText">
|
||||
<string>Disabled</string>
|
||||
</property>
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="specialValueText">
|
||||
<string>Disabled</string>
|
||||
</property>
|
||||
<property name="suffix">
|
||||
<string> days</string>
|
||||
</property>
|
||||
@@ -374,6 +385,9 @@
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_4">
|
||||
<item>
|
||||
<widget class="QPushButton" name="importBtn">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>&Import...</string>
|
||||
</property>
|
||||
@@ -381,6 +395,9 @@
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="exportBtn">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>&Export...</string>
|
||||
</property>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
/*
|
||||
* Bittorrent Client using Qt4 and libtorrent.
|
||||
* Copyright (C) 2010 Christophe Dumez
|
||||
* Bittorrent Client using Qt and libtorrent.
|
||||
* Copyright (C) 2017 Vladimir Golovnev <glassez@yandex.ru>
|
||||
* Copyright (C) 2010 Christophe Dumez <chris@qbittorrent.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
@@ -24,213 +25,241 @@
|
||||
* 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 "base/rss/rssmanager.h"
|
||||
#include "base/rss/rssfolder.h"
|
||||
#include "base/rss/rssfeed.h"
|
||||
#include "guiiconprovider.h"
|
||||
#include "feedlistwidget.h"
|
||||
|
||||
FeedListWidget::FeedListWidget(QWidget *parent, const Rss::ManagerPtr& rssmanager)
|
||||
#include <QDragMoveEvent>
|
||||
#include <QDropEvent>
|
||||
#include <QTreeWidgetItem>
|
||||
|
||||
#include "base/rss/rss_article.h"
|
||||
#include "base/rss/rss_feed.h"
|
||||
#include "base/rss/rss_folder.h"
|
||||
#include "base/rss/rss_session.h"
|
||||
#include "guiiconprovider.h"
|
||||
|
||||
FeedListWidget::FeedListWidget(QWidget *parent)
|
||||
: QTreeWidget(parent)
|
||||
, m_rssManager(rssmanager)
|
||||
, m_currentFeed(nullptr)
|
||||
{
|
||||
setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
setDragDropMode(QAbstractItemView::InternalMove);
|
||||
setSelectionMode(QAbstractItemView::ExtendedSelection);
|
||||
setColumnCount(1);
|
||||
headerItem()->setText(0, tr("RSS feeds"));
|
||||
m_unreadStickyItem = new QTreeWidgetItem(this);
|
||||
m_unreadStickyItem->setText(0, tr("Unread") + QString::fromUtf8(" (") + QString::number(rssmanager->rootFolder()->unreadCount()) + QString(")"));
|
||||
m_unreadStickyItem->setData(0,Qt::DecorationRole, GuiIconProvider::instance()->getIcon("mail-folder-inbox"));
|
||||
itemAdded(m_unreadStickyItem, rssmanager->rootFolder());
|
||||
connect(this, SIGNAL(currentItemChanged(QTreeWidgetItem*,QTreeWidgetItem*)), SLOT(updateCurrentFeed(QTreeWidgetItem*)));
|
||||
setCurrentItem(m_unreadStickyItem);
|
||||
setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
setDragDropMode(QAbstractItemView::InternalMove);
|
||||
setSelectionMode(QAbstractItemView::ExtendedSelection);
|
||||
setColumnCount(1);
|
||||
headerItem()->setText(0, tr("RSS feeds"));
|
||||
|
||||
connect(RSS::Session::instance(), &RSS::Session::itemAdded, this, &FeedListWidget::handleItemAdded);
|
||||
connect(RSS::Session::instance(), &RSS::Session::feedStateChanged, this, &FeedListWidget::handleFeedStateChanged);
|
||||
connect(RSS::Session::instance(), &RSS::Session::feedIconLoaded, this, &FeedListWidget::handleFeedIconLoaded);
|
||||
connect(RSS::Session::instance(), &RSS::Session::itemPathChanged, this, &FeedListWidget::handleItemPathChanged);
|
||||
connect(RSS::Session::instance(), &RSS::Session::itemAboutToBeRemoved, this, &FeedListWidget::handleItemAboutToBeRemoved);
|
||||
|
||||
m_rssToTreeItemMapping[RSS::Session::instance()->rootFolder()] = invisibleRootItem();
|
||||
|
||||
m_unreadStickyItem = new QTreeWidgetItem(this);
|
||||
m_unreadStickyItem->setData(0, Qt::UserRole, reinterpret_cast<quintptr>(RSS::Session::instance()->rootFolder()));
|
||||
m_unreadStickyItem->setText(0, tr("Unread (%1)").arg(RSS::Session::instance()->rootFolder()->unreadCount()));
|
||||
m_unreadStickyItem->setData(0, Qt::DecorationRole, GuiIconProvider::instance()->getIcon("mail-folder-inbox"));
|
||||
|
||||
connect(RSS::Session::instance()->rootFolder(), &RSS::Item::unreadCountChanged, this, &FeedListWidget::handleItemUnreadCountChanged);
|
||||
|
||||
setSortingEnabled(false);
|
||||
fill(nullptr, RSS::Session::instance()->rootFolder());
|
||||
setSortingEnabled(true);
|
||||
|
||||
// setCurrentItem(m_unreadStickyItem);
|
||||
}
|
||||
|
||||
FeedListWidget::~FeedListWidget() {
|
||||
delete m_unreadStickyItem;
|
||||
FeedListWidget::~FeedListWidget()
|
||||
{
|
||||
delete m_unreadStickyItem;
|
||||
}
|
||||
|
||||
void FeedListWidget::itemAdded(QTreeWidgetItem *item, const Rss::FilePtr& file) {
|
||||
m_rssMapping[item] = file;
|
||||
if (Rss::FeedPtr feed = qSharedPointerDynamicCast<Rss::Feed>(file)) {
|
||||
m_feedsItems[feed->id()] = item;
|
||||
}
|
||||
void FeedListWidget::handleItemAdded(RSS::Item *rssItem)
|
||||
{
|
||||
auto parentItem = m_rssToTreeItemMapping.value(
|
||||
RSS::Session::instance()->itemByPath(RSS::Item::parentPath(rssItem->path())));
|
||||
createItem(rssItem, parentItem);
|
||||
}
|
||||
|
||||
void FeedListWidget::itemAboutToBeRemoved(QTreeWidgetItem *item) {
|
||||
Rss::FilePtr file = m_rssMapping.take(item);
|
||||
if (Rss::FeedPtr feed = qSharedPointerDynamicCast<Rss::Feed>(file)) {
|
||||
m_feedsItems.remove(feed->id());
|
||||
} else if (Rss::FolderPtr folder = qSharedPointerDynamicCast<Rss::Folder>(file)) {
|
||||
Rss::FeedList feeds = folder->getAllFeeds();
|
||||
foreach (const Rss::FeedPtr& feed, feeds) {
|
||||
m_feedsItems.remove(feed->id());
|
||||
}
|
||||
}
|
||||
}
|
||||
void FeedListWidget::handleFeedStateChanged(RSS::Feed *feed)
|
||||
{
|
||||
QTreeWidgetItem *item = m_rssToTreeItemMapping.value(feed);
|
||||
Q_ASSERT(item);
|
||||
|
||||
bool FeedListWidget::hasFeed(const QString &url) const {
|
||||
return m_feedsItems.contains(QUrl(url).toString());
|
||||
}
|
||||
|
||||
QList<QTreeWidgetItem*> FeedListWidget::getAllFeedItems() const {
|
||||
return m_feedsItems.values();
|
||||
}
|
||||
|
||||
QTreeWidgetItem* FeedListWidget::stickyUnreadItem() const {
|
||||
return m_unreadStickyItem;
|
||||
}
|
||||
|
||||
QStringList FeedListWidget::getItemPath(QTreeWidgetItem* item) const {
|
||||
QStringList path;
|
||||
if (item) {
|
||||
if (item->parent())
|
||||
path << getItemPath(item->parent());
|
||||
path.append(getRSSItem(item)->id());
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
QList<QTreeWidgetItem*> FeedListWidget::getAllOpenFolders(QTreeWidgetItem *parent) const {
|
||||
QList<QTreeWidgetItem*> open_folders;
|
||||
int nbChildren;
|
||||
if (parent)
|
||||
nbChildren = parent->childCount();
|
||||
else
|
||||
nbChildren = topLevelItemCount();
|
||||
for (int i=0; i<nbChildren; ++i) {
|
||||
QTreeWidgetItem *item;
|
||||
if (parent)
|
||||
item = parent->child(i);
|
||||
QIcon icon;
|
||||
if (feed->isLoading())
|
||||
icon = QIcon(QStringLiteral(":/icons/loading.png"));
|
||||
else if (feed->hasError())
|
||||
icon = GuiIconProvider::instance()->getIcon(QStringLiteral("unavailable"));
|
||||
else if (!feed->iconPath().isEmpty())
|
||||
icon = QIcon(feed->iconPath());
|
||||
else
|
||||
item = topLevelItem(i);
|
||||
if (isFolder(item) && item->isExpanded()) {
|
||||
QList<QTreeWidgetItem*> open_subfolders = getAllOpenFolders(item);
|
||||
if (!open_subfolders.empty()) {
|
||||
open_folders << open_subfolders;
|
||||
} else {
|
||||
open_folders << item;
|
||||
}
|
||||
}
|
||||
}
|
||||
return open_folders;
|
||||
icon = GuiIconProvider::instance()->getIcon(QStringLiteral("application-rss+xml"));
|
||||
item->setData(0, Qt::DecorationRole, icon);
|
||||
}
|
||||
|
||||
QList<QTreeWidgetItem*> FeedListWidget::getAllFeedItems(QTreeWidgetItem* folder) {
|
||||
QList<QTreeWidgetItem*> feeds;
|
||||
const int nbChildren = folder->childCount();
|
||||
for (int i=0; i<nbChildren; ++i) {
|
||||
QTreeWidgetItem *item = folder->child(i);
|
||||
if (isFeed(item)) {
|
||||
feeds << item;
|
||||
} else {
|
||||
feeds << getAllFeedItems(item);
|
||||
void FeedListWidget::handleFeedIconLoaded(RSS::Feed *feed)
|
||||
{
|
||||
if (!feed->isLoading() && !feed->hasError()) {
|
||||
QTreeWidgetItem *item = m_rssToTreeItemMapping.value(feed);
|
||||
Q_ASSERT(item);
|
||||
|
||||
item->setData(0, Qt::DecorationRole, QIcon(feed->iconPath()));
|
||||
}
|
||||
}
|
||||
return feeds;
|
||||
}
|
||||
|
||||
Rss::FilePtr FeedListWidget::getRSSItem(QTreeWidgetItem *item) const {
|
||||
return m_rssMapping.value(item, Rss::FilePtr());
|
||||
void FeedListWidget::handleItemUnreadCountChanged(RSS::Item *rssItem)
|
||||
{
|
||||
if (rssItem == RSS::Session::instance()->rootFolder()) {
|
||||
m_unreadStickyItem->setText(0, tr("Unread (%1)").arg(RSS::Session::instance()->rootFolder()->unreadCount()));
|
||||
}
|
||||
else {
|
||||
QTreeWidgetItem *item = mapRSSItem(rssItem);
|
||||
Q_ASSERT(item);
|
||||
item->setData(0, Qt::DisplayRole, QString("%1 (%2)").arg(rssItem->name()).arg(rssItem->unreadCount()));
|
||||
}
|
||||
}
|
||||
|
||||
void FeedListWidget::handleItemPathChanged(RSS::Item *rssItem)
|
||||
{
|
||||
QTreeWidgetItem *item = mapRSSItem(rssItem);
|
||||
Q_ASSERT(item);
|
||||
|
||||
item->setData(0, Qt::DisplayRole, QString("%1 (%2)").arg(rssItem->name()).arg(rssItem->unreadCount()));
|
||||
|
||||
RSS::Item *parentRssItem = RSS::Session::instance()->itemByPath(RSS::Item::parentPath(rssItem->path()));
|
||||
QTreeWidgetItem *parentItem = mapRSSItem(parentRssItem);
|
||||
Q_ASSERT(parentItem);
|
||||
|
||||
parentItem->addChild(item);
|
||||
}
|
||||
|
||||
void FeedListWidget::handleItemAboutToBeRemoved(RSS::Item *rssItem)
|
||||
{
|
||||
delete m_rssToTreeItemMapping.take(rssItem);
|
||||
}
|
||||
|
||||
QTreeWidgetItem *FeedListWidget::stickyUnreadItem() const
|
||||
{
|
||||
return m_unreadStickyItem;
|
||||
}
|
||||
|
||||
QList<QTreeWidgetItem *> FeedListWidget::getAllOpenedFolders(QTreeWidgetItem *parent) const
|
||||
{
|
||||
QList<QTreeWidgetItem *> openedFolders;
|
||||
int nbChildren = (parent ? parent->childCount() : topLevelItemCount());
|
||||
for (int i = 0; i < nbChildren; ++i) {
|
||||
QTreeWidgetItem *item (parent ? parent->child(i) : topLevelItem(i));
|
||||
if (isFolder(item) && item->isExpanded()) {
|
||||
QList<QTreeWidgetItem *> openedSubfolders = getAllOpenedFolders(item);
|
||||
if (!openedSubfolders.empty())
|
||||
openedFolders << openedSubfolders;
|
||||
else
|
||||
openedFolders << item;
|
||||
}
|
||||
}
|
||||
return openedFolders;
|
||||
}
|
||||
|
||||
RSS::Item *FeedListWidget::getRSSItem(QTreeWidgetItem *item) const
|
||||
{
|
||||
return reinterpret_cast<RSS::Item *>(item->data(0, Qt::UserRole).value<quintptr>());
|
||||
}
|
||||
|
||||
QTreeWidgetItem *FeedListWidget::mapRSSItem(RSS::Item *rssItem) const
|
||||
{
|
||||
return m_rssToTreeItemMapping.value(rssItem);
|
||||
}
|
||||
|
||||
QString FeedListWidget::itemPath(QTreeWidgetItem *item) const
|
||||
{
|
||||
return getRSSItem(item)->path();
|
||||
}
|
||||
|
||||
bool FeedListWidget::isFeed(QTreeWidgetItem *item) const
|
||||
{
|
||||
return (qSharedPointerDynamicCast<Rss::Feed>(m_rssMapping.value(item)) != NULL);
|
||||
return qobject_cast<RSS::Feed *>(getRSSItem(item));
|
||||
}
|
||||
|
||||
bool FeedListWidget::isFolder(QTreeWidgetItem *item) const
|
||||
{
|
||||
return (qSharedPointerDynamicCast<Rss::Folder>(m_rssMapping.value(item)) != NULL);
|
||||
return qobject_cast<RSS::Folder *>(getRSSItem(item));
|
||||
}
|
||||
|
||||
QString FeedListWidget::getItemID(QTreeWidgetItem *item) const {
|
||||
return m_rssMapping.value(item)->id();
|
||||
void FeedListWidget::dragMoveEvent(QDragMoveEvent *event)
|
||||
{
|
||||
QTreeWidget::dragMoveEvent(event);
|
||||
|
||||
QTreeWidgetItem *item = itemAt(event->pos());
|
||||
// Prohibit dropping onto global unread counter
|
||||
if (item == m_unreadStickyItem)
|
||||
event->ignore();
|
||||
// Prohibit dragging of global unread counter
|
||||
else if (selectedItems().contains(m_unreadStickyItem))
|
||||
event->ignore();
|
||||
// Prohibit dropping onto feeds
|
||||
else if (item && isFeed(item))
|
||||
event->ignore();
|
||||
}
|
||||
|
||||
QTreeWidgetItem* FeedListWidget::getTreeItemFromUrl(const QString &url) const {
|
||||
return m_feedsItems.value(url, 0);
|
||||
}
|
||||
void FeedListWidget::dropEvent(QDropEvent *event)
|
||||
{
|
||||
QTreeWidgetItem *destFolderItem = itemAt(event->pos());
|
||||
RSS::Folder *destFolder = (destFolderItem
|
||||
? static_cast<RSS::Folder *>(getRSSItem(destFolderItem))
|
||||
: RSS::Session::instance()->rootFolder());
|
||||
|
||||
Rss::FeedPtr FeedListWidget::getRSSItemFromUrl(const QString &url) const {
|
||||
return qSharedPointerDynamicCast<Rss::Feed>(getRSSItem(getTreeItemFromUrl(url)));
|
||||
}
|
||||
|
||||
QTreeWidgetItem* FeedListWidget::currentItem() const {
|
||||
return m_currentFeed;
|
||||
}
|
||||
|
||||
QTreeWidgetItem* FeedListWidget::currentFeed() const {
|
||||
return m_currentFeed;
|
||||
}
|
||||
|
||||
void FeedListWidget::updateCurrentFeed(QTreeWidgetItem* new_item) {
|
||||
if (!new_item) return;
|
||||
if (!m_rssMapping.contains(new_item)) return;
|
||||
if (isFeed(new_item) || new_item == m_unreadStickyItem)
|
||||
m_currentFeed = new_item;
|
||||
}
|
||||
|
||||
void FeedListWidget::dragMoveEvent(QDragMoveEvent * event) {
|
||||
QTreeWidget::dragMoveEvent(event);
|
||||
|
||||
QTreeWidgetItem *item = itemAt(event->pos());
|
||||
// Prohibit dropping onto global unread counter
|
||||
if (item == m_unreadStickyItem) {
|
||||
event->ignore();
|
||||
return;
|
||||
}
|
||||
// Prohibit dragging of global unread counter
|
||||
if (selectedItems().contains(m_unreadStickyItem)) {
|
||||
event->ignore();
|
||||
return;
|
||||
}
|
||||
// Prohibit dropping onto feeds
|
||||
if (item && isFeed(item)) {
|
||||
event->ignore();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void FeedListWidget::dropEvent(QDropEvent *event) {
|
||||
qDebug("dropEvent");
|
||||
QList<QTreeWidgetItem*> folders_altered;
|
||||
QTreeWidgetItem *dest_folder_item = itemAt(event->pos());
|
||||
Rss::FolderPtr dest_folder;
|
||||
if (dest_folder_item) {
|
||||
dest_folder = qSharedPointerCast<Rss::Folder>(getRSSItem(dest_folder_item));
|
||||
folders_altered << dest_folder_item;
|
||||
} else {
|
||||
dest_folder = m_rssManager->rootFolder();
|
||||
}
|
||||
QList<QTreeWidgetItem *> src_items = selectedItems();
|
||||
// Check if there is not going to overwrite another file
|
||||
foreach (QTreeWidgetItem *src_item, src_items) {
|
||||
Rss::FilePtr file = getRSSItem(src_item);
|
||||
if (dest_folder->hasChild(file->id())) {
|
||||
QTreeWidget::dropEvent(event);
|
||||
return;
|
||||
// move as much items as possible
|
||||
foreach (QTreeWidgetItem *srcItem, selectedItems()) {
|
||||
auto rssItem = getRSSItem(srcItem);
|
||||
RSS::Session::instance()->moveItem(rssItem, RSS::Item::joinPath(destFolder->path(), rssItem->name()));
|
||||
}
|
||||
|
||||
QTreeWidget::dropEvent(event);
|
||||
if (destFolderItem)
|
||||
destFolderItem->setExpanded(true);
|
||||
}
|
||||
|
||||
QTreeWidgetItem *FeedListWidget::createItem(RSS::Item *rssItem, QTreeWidgetItem *parentItem)
|
||||
{
|
||||
QTreeWidgetItem *item = new QTreeWidgetItem;
|
||||
item->setData(0, Qt::DisplayRole, QString("%1 (%2)").arg(rssItem->name()).arg(rssItem->unreadCount()));
|
||||
item->setData(0, Qt::UserRole, reinterpret_cast<quintptr>(rssItem));
|
||||
m_rssToTreeItemMapping[rssItem] = item;
|
||||
|
||||
QIcon icon;
|
||||
if (auto feed = qobject_cast<RSS::Feed *>(rssItem)) {
|
||||
if (feed->isLoading())
|
||||
icon = QIcon(QStringLiteral(":/icons/loading.png"));
|
||||
else if (feed->hasError())
|
||||
icon = GuiIconProvider::instance()->getIcon(QStringLiteral("unavailable"));
|
||||
else if (!feed->iconPath().isEmpty())
|
||||
icon = QIcon(feed->iconPath());
|
||||
else
|
||||
icon = GuiIconProvider::instance()->getIcon(QStringLiteral("application-rss+xml"));
|
||||
}
|
||||
else {
|
||||
icon = GuiIconProvider::instance()->getIcon("inode-directory");
|
||||
}
|
||||
item->setData(0, Qt::DecorationRole, icon);
|
||||
|
||||
connect(rssItem, &RSS::Item::unreadCountChanged, this, &FeedListWidget::handleItemUnreadCountChanged);
|
||||
|
||||
if (!parentItem || (parentItem == m_unreadStickyItem))
|
||||
addTopLevelItem(item);
|
||||
else
|
||||
parentItem->addChild(item);
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
void FeedListWidget::fill(QTreeWidgetItem *parent, RSS::Folder *rssParent)
|
||||
{
|
||||
foreach (auto rssItem, rssParent->items()) {
|
||||
QTreeWidgetItem *item = createItem(rssItem, parent);
|
||||
// Recursive call if this is a folder.
|
||||
if (auto folder = qobject_cast<RSS::Folder *>(rssItem))
|
||||
fill(item, folder);
|
||||
}
|
||||
}
|
||||
// Proceed with the move
|
||||
foreach (QTreeWidgetItem *src_item, src_items) {
|
||||
QTreeWidgetItem *parent_folder = src_item->parent();
|
||||
if (parent_folder && !folders_altered.contains(parent_folder))
|
||||
folders_altered << parent_folder;
|
||||
// Actually move the file
|
||||
Rss::FilePtr file = getRSSItem(src_item);
|
||||
m_rssManager->moveFile(file, dest_folder);
|
||||
}
|
||||
QTreeWidget::dropEvent(event);
|
||||
if (dest_folder_item)
|
||||
dest_folder_item->setExpanded(true);
|
||||
// Emit signal for update
|
||||
if (!folders_altered.empty())
|
||||
emit foldersAltered(folders_altered);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
/*
|
||||
* Bittorrent Client using Qt4 and libtorrent.
|
||||
* Copyright (C) 2010 Christophe Dumez
|
||||
* Bittorrent Client using Qt and libtorrent.
|
||||
* Copyright (C) 2017 Vladimir Golovnev <glassez@yandex.ru>
|
||||
* Copyright (C) 2010 Christophe Dumez <chris@qbittorrent.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
@@ -24,67 +25,54 @@
|
||||
* 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
|
||||
*/
|
||||
|
||||
#ifndef FEEDLIST_H
|
||||
#define FEEDLIST_H
|
||||
#ifndef FEEDLISTWIDGET_H
|
||||
#define FEEDLISTWIDGET_H
|
||||
|
||||
#include <QTreeWidget>
|
||||
#include <QTreeWidgetItem>
|
||||
#include <QDropEvent>
|
||||
#include <QDragMoveEvent>
|
||||
#include <QStringList>
|
||||
#include <QHash>
|
||||
#include <QUrl>
|
||||
#include <QTreeWidget>
|
||||
|
||||
#include "base/rss/rssfile.h"
|
||||
#include "base/rss/rssfeed.h"
|
||||
#include "base/rss/rssmanager.h"
|
||||
namespace RSS
|
||||
{
|
||||
class Article;
|
||||
class Feed;
|
||||
class Folder;
|
||||
class Item;
|
||||
}
|
||||
|
||||
class FeedListWidget: public QTreeWidget {
|
||||
Q_OBJECT
|
||||
class FeedListWidget: public QTreeWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
FeedListWidget(QWidget *parent, const Rss::ManagerPtr& rssManager);
|
||||
~FeedListWidget();
|
||||
explicit FeedListWidget(QWidget *parent);
|
||||
~FeedListWidget();
|
||||
|
||||
bool hasFeed(const QString &url) const;
|
||||
QList<QTreeWidgetItem*> getAllFeedItems() const;
|
||||
QTreeWidgetItem* stickyUnreadItem() const;
|
||||
QStringList getItemPath(QTreeWidgetItem* item) const;
|
||||
QList<QTreeWidgetItem*> getAllOpenFolders(QTreeWidgetItem *parent=0) const;
|
||||
QList<QTreeWidgetItem*> getAllFeedItems(QTreeWidgetItem* folder);
|
||||
Rss::FilePtr getRSSItem(QTreeWidgetItem *item) const;
|
||||
bool isFeed(QTreeWidgetItem *item) const;
|
||||
bool isFolder(QTreeWidgetItem *item) const;
|
||||
QString getItemID(QTreeWidgetItem *item) const;
|
||||
QTreeWidgetItem* getTreeItemFromUrl(const QString &url) const;
|
||||
Rss::FeedPtr getRSSItemFromUrl(const QString &url) const;
|
||||
QTreeWidgetItem* currentItem() const;
|
||||
QTreeWidgetItem* currentFeed() const;
|
||||
|
||||
public slots:
|
||||
void itemAdded(QTreeWidgetItem *item, const Rss::FilePtr& file);
|
||||
void itemAboutToBeRemoved(QTreeWidgetItem *item);
|
||||
|
||||
signals:
|
||||
void foldersAltered(const QList<QTreeWidgetItem*> &folders);
|
||||
QTreeWidgetItem *stickyUnreadItem() const;
|
||||
QList<QTreeWidgetItem *> getAllOpenedFolders(QTreeWidgetItem *parent = nullptr) const;
|
||||
RSS::Item *getRSSItem(QTreeWidgetItem *item) const;
|
||||
QTreeWidgetItem *mapRSSItem(RSS::Item *rssItem) const;
|
||||
QString itemPath(QTreeWidgetItem *item) const;
|
||||
bool isFeed(QTreeWidgetItem *item) const;
|
||||
bool isFolder(QTreeWidgetItem *item) const;
|
||||
|
||||
private slots:
|
||||
void updateCurrentFeed(QTreeWidgetItem* new_item);
|
||||
|
||||
protected:
|
||||
void dragMoveEvent(QDragMoveEvent * event);
|
||||
void dropEvent(QDropEvent *event);
|
||||
void handleItemAdded(RSS::Item *rssItem);
|
||||
void handleFeedStateChanged(RSS::Feed *feed);
|
||||
void handleFeedIconLoaded(RSS::Feed *feed);
|
||||
void handleItemUnreadCountChanged(RSS::Item *rssItem);
|
||||
void handleItemPathChanged(RSS::Item *rssItem);
|
||||
void handleItemAboutToBeRemoved(RSS::Item *rssItem);
|
||||
|
||||
private:
|
||||
Rss::ManagerPtr m_rssManager;
|
||||
QHash<QTreeWidgetItem*, Rss::FilePtr> m_rssMapping;
|
||||
QHash<QString, QTreeWidgetItem*> m_feedsItems;
|
||||
QTreeWidgetItem* m_currentFeed;
|
||||
QTreeWidgetItem *m_unreadStickyItem;
|
||||
void dragMoveEvent(QDragMoveEvent *event);
|
||||
void dropEvent(QDropEvent *event);
|
||||
QTreeWidgetItem *createItem(RSS::Item *rssItem, QTreeWidgetItem *parentItem = nullptr);
|
||||
void fill(QTreeWidgetItem *parent, RSS::Folder *rssParent);
|
||||
|
||||
QHash<RSS::Item *, QTreeWidgetItem *> m_rssToTreeItemMapping;
|
||||
QTreeWidgetItem *m_unreadStickyItem;
|
||||
};
|
||||
|
||||
#endif // FEEDLIST_H
|
||||
#endif // FEEDLISTWIDGET_H
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
INCLUDEPATH += $$PWD
|
||||
|
||||
HEADERS += $$PWD/rss_imp.h \
|
||||
$$PWD/rsssettingsdlg.h \
|
||||
$$PWD/feedlistwidget.h \
|
||||
$$PWD/automatedrssdownloader.h \
|
||||
$$PWD/htmlbrowser.h
|
||||
|
||||
SOURCES += $$PWD/rss_imp.cpp \
|
||||
$$PWD/rsssettingsdlg.cpp \
|
||||
$$PWD/feedlistwidget.cpp \
|
||||
$$PWD/automatedrssdownloader.cpp \
|
||||
$$PWD/htmlbrowser.cpp
|
||||
|
||||
FORMS += $$PWD/rss.ui \
|
||||
$$PWD/rsssettingsdlg.ui \
|
||||
$$PWD/automatedrssdownloader.ui
|
||||
@@ -1,806 +0,0 @@
|
||||
/*
|
||||
* 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 "rss_imp.h"
|
||||
|
||||
#include <QDesktopServices>
|
||||
#include <QMenu>
|
||||
#include <QStandardItemModel>
|
||||
#include <QMessageBox>
|
||||
#include <QString>
|
||||
#include <QClipboard>
|
||||
#include <QDragMoveEvent>
|
||||
#include <QDebug>
|
||||
|
||||
#include "feedlistwidget.h"
|
||||
#include "base/bittorrent/session.h"
|
||||
#include "base/net/downloadmanager.h"
|
||||
#include "base/preferences.h"
|
||||
#include "rsssettingsdlg.h"
|
||||
#include "base/rss/rssmanager.h"
|
||||
#include "base/rss/rssfolder.h"
|
||||
#include "base/rss/rssarticle.h"
|
||||
#include "base/rss/rssfeed.h"
|
||||
#include "automatedrssdownloader.h"
|
||||
#include "guiiconprovider.h"
|
||||
#include "autoexpandabledialog.h"
|
||||
#include "addnewtorrentdialog.h"
|
||||
|
||||
#include "ui_rss.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(m_ui->actionUpdate);
|
||||
myRSSListMenu.addAction(m_ui->actionMark_items_read);
|
||||
myRSSListMenu.addSeparator();
|
||||
if (selectedItems.size() == 1) {
|
||||
if (m_feedList->getRSSItem(selectedItems.first()) != m_rssManager->rootFolder()) {
|
||||
myRSSListMenu.addAction(m_ui->actionRename);
|
||||
myRSSListMenu.addAction(m_ui->actionDelete);
|
||||
myRSSListMenu.addSeparator();
|
||||
if (m_feedList->isFolder(selectedItems.first()))
|
||||
myRSSListMenu.addAction(m_ui->actionNew_folder);
|
||||
}
|
||||
}
|
||||
else {
|
||||
myRSSListMenu.addAction(m_ui->actionDelete);
|
||||
myRSSListMenu.addSeparator();
|
||||
}
|
||||
myRSSListMenu.addAction(m_ui->actionNew_subscription);
|
||||
if (m_feedList->isFeed(selectedItems.first())) {
|
||||
myRSSListMenu.addSeparator();
|
||||
myRSSListMenu.addAction(m_ui->actionCopy_feed_URL);
|
||||
}
|
||||
}
|
||||
else {
|
||||
myRSSListMenu.addAction(m_ui->actionNew_subscription);
|
||||
myRSSListMenu.addAction(m_ui->actionNew_folder);
|
||||
myRSSListMenu.addSeparator();
|
||||
myRSSListMenu.addAction(m_ui->actionUpdate_all_feeds);
|
||||
}
|
||||
myRSSListMenu.exec(QCursor::pos());
|
||||
}
|
||||
|
||||
void RSSImp::displayItemsListMenu(const QPoint &)
|
||||
{
|
||||
QMenu myItemListMenu(this);
|
||||
QList<QListWidgetItem * > selectedItems = m_ui->listArticles->selectedItems();
|
||||
if (selectedItems.size() <= 0)
|
||||
return;
|
||||
|
||||
bool hasTorrent = false;
|
||||
bool hasLink = false;
|
||||
foreach (const QListWidgetItem *item, selectedItems) {
|
||||
if (!item) continue;
|
||||
Rss::FeedPtr feed = m_feedList->getRSSItemFromUrl(item->data(Article::FeedUrlRole).toString());
|
||||
if (!feed) continue;
|
||||
Rss::ArticlePtr 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;
|
||||
}
|
||||
if (hasTorrent)
|
||||
myItemListMenu.addAction(m_ui->actionDownload_torrent);
|
||||
if (hasLink)
|
||||
myItemListMenu.addAction(m_ui->actionOpen_news_URL);
|
||||
if (hasTorrent || hasLink)
|
||||
myItemListMenu.exec(QCursor::pos());
|
||||
}
|
||||
|
||||
void RSSImp::askNewFolder()
|
||||
{
|
||||
QTreeWidgetItem *parent_item = 0;
|
||||
Rss::FolderPtr rss_parent;
|
||||
if (m_feedList->selectedItems().size() > 0) {
|
||||
parent_item = m_feedList->selectedItems().at(0);
|
||||
rss_parent = qSharedPointerDynamicCast<Rss::Folder>(m_feedList->getRSSItem(parent_item));
|
||||
Q_ASSERT(rss_parent);
|
||||
}
|
||||
else {
|
||||
rss_parent = m_rssManager->rootFolder();
|
||||
}
|
||||
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 || rss_parent->hasChild(new_name))
|
||||
return;
|
||||
|
||||
Rss::FolderPtr newFolder(new Rss::Folder(new_name));
|
||||
rss_parent->addFile(newFolder);
|
||||
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_feedList->setCurrentItem(folderItem);
|
||||
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();
|
||||
}
|
||||
Rss::FolderPtr rss_parent;
|
||||
if (parent_item)
|
||||
rss_parent = qSharedPointerCast<Rss::Folder>(m_feedList->getRSSItem(parent_item));
|
||||
else
|
||||
rss_parent = m_rssManager->rootFolder();
|
||||
// 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;
|
||||
}
|
||||
|
||||
Rss::FeedPtr stream(new Rss::Feed(newUrl, m_rssManager.data()));
|
||||
rss_parent->addFile(stream);
|
||||
// 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);
|
||||
// Expand parent folder to display new feed
|
||||
if (parent_item)
|
||||
parent_item->setExpanded(true);
|
||||
m_feedList->setCurrentItem(item);
|
||||
m_rssManager->saveStreamList();
|
||||
}
|
||||
|
||||
// delete a stream by a button
|
||||
void RSSImp::deleteSelectedItems()
|
||||
{
|
||||
QList<QTreeWidgetItem * > selectedItems = m_feedList->selectedItems();
|
||||
if (selectedItems.isEmpty())
|
||||
return;
|
||||
if ((selectedItems.size() == 1) && (selectedItems.first() == m_feedList->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;
|
||||
|
||||
QList<QString> deleted;
|
||||
|
||||
foreach (QTreeWidgetItem *item, selectedItems) {
|
||||
if (item == m_feedList->stickyUnreadItem())
|
||||
continue;
|
||||
Rss::FilePtr rss_item = m_feedList->getRSSItem(item);
|
||||
QTreeWidgetItem *parent = item->parent();
|
||||
// Notify TreeWidget
|
||||
m_feedList->itemAboutToBeRemoved(item);
|
||||
// Actually delete the item
|
||||
rss_item->parentFolder()->removeChild(rss_item->id());
|
||||
deleted << rss_item->id();
|
||||
delete item;
|
||||
// Update parents count
|
||||
while (parent && (parent != m_feedList->invisibleRootItem())) {
|
||||
updateItemInfos(parent);
|
||||
parent = parent->parent();
|
||||
}
|
||||
}
|
||||
m_rssManager->saveStreamList();
|
||||
|
||||
foreach (const QString &feed_id, deleted)
|
||||
m_rssManager->forwardFeedInfosChanged(feed_id, "", 0);
|
||||
|
||||
// Update Unread items
|
||||
updateItemInfos(m_feedList->stickyUnreadItem());
|
||||
if (m_feedList->currentItem() == m_feedList->stickyUnreadItem())
|
||||
populateArticleList(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 = m_ui->listArticles->selectedItems();
|
||||
if (selected_items.size() <= 0)
|
||||
return;
|
||||
foreach (QListWidgetItem *item, selected_items) {
|
||||
if (!item) continue;
|
||||
Rss::FeedPtr feed = m_feedList->getRSSItemFromUrl(item->data(Article::FeedUrlRole).toString());
|
||||
if (!feed) continue;
|
||||
Rss::ArticlePtr 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 (AddNewTorrentDialog::isEnabled())
|
||||
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<QListWidgetItem * > selected_items = m_ui->listArticles->selectedItems();
|
||||
if (selected_items.size() <= 0)
|
||||
return;
|
||||
foreach (QListWidgetItem *item, selected_items) {
|
||||
if (!item) continue;
|
||||
Rss::FeedPtr feed = m_feedList->getRSSItemFromUrl(item->data(Article::FeedUrlRole).toString());
|
||||
if (!feed) continue;
|
||||
Rss::ArticlePtr 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
|
||||
void RSSImp::renameSelectedRssFile()
|
||||
{
|
||||
QList<QTreeWidgetItem * > selectedItems = m_feedList->selectedItems();
|
||||
if (selectedItems.size() != 1)
|
||||
return;
|
||||
QTreeWidgetItem *item = selectedItems.first();
|
||||
if (item == m_feedList->stickyUnreadItem())
|
||||
return;
|
||||
Rss::FilePtr 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->parentFolder()->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);
|
||||
m_rssManager->saveStreamList();
|
||||
// Update TreeWidget
|
||||
updateItemInfos(item);
|
||||
}
|
||||
|
||||
// right-click on stream : refresh it
|
||||
void RSSImp::refreshSelectedItems()
|
||||
{
|
||||
QList<QTreeWidgetItem * > selectedItems = m_feedList->selectedItems();
|
||||
foreach (QTreeWidgetItem *item, selectedItems) {
|
||||
Rss::FilePtr file = m_feedList->getRSSItem(item);
|
||||
// Update icons
|
||||
if (item == m_feedList->stickyUnreadItem()) {
|
||||
refreshAllFeeds();
|
||||
return;
|
||||
}
|
||||
else {
|
||||
if (!file->refresh())
|
||||
continue;
|
||||
// Update UI
|
||||
if (qSharedPointerDynamicCast<Rss::Feed>(file)) {
|
||||
item->setData(0, Qt::DecorationRole, QVariant(QIcon(":/icons/loading.png")));
|
||||
}
|
||||
else if (qSharedPointerDynamicCast<Rss::Folder>(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) {
|
||||
Rss::FilePtr 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 Rss::FilePtr &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, QIcon(rssFile->iconPath()));
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
void RSSImp::fillFeedsList(QTreeWidgetItem *parent, const Rss::FolderPtr &rss_parent)
|
||||
{
|
||||
QList<Rss::FilePtr> children;
|
||||
if (parent)
|
||||
children = rss_parent->getContent();
|
||||
else
|
||||
children = m_rssManager->rootFolder()->getContent();
|
||||
foreach (const Rss::FilePtr &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 (Rss::FolderPtr folder = qSharedPointerDynamicCast<Rss::Folder>(rssFile))
|
||||
fillFeedsList(item, folder);
|
||||
}
|
||||
}
|
||||
|
||||
QListWidgetItem *RSSImp::createArticleListItem(const Rss::ArticlePtr &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) {
|
||||
m_ui->listArticles->clear();
|
||||
return;
|
||||
}
|
||||
|
||||
Rss::FilePtr rss_item = m_feedList->getRSSItem(item);
|
||||
if (!rss_item)
|
||||
return;
|
||||
|
||||
// Clear the list first
|
||||
m_ui->textBrowser->clear();
|
||||
m_currentArticle = 0;
|
||||
m_ui->listArticles->clear();
|
||||
|
||||
qDebug("Getting the list of news");
|
||||
Rss::ArticleList articles;
|
||||
if (rss_item == m_rssManager->rootFolder())
|
||||
articles = rss_item->unreadArticleListByDateDesc();
|
||||
else
|
||||
articles = rss_item->articleListByDateDesc();
|
||||
|
||||
qDebug("Got the list of news");
|
||||
foreach (const Rss::ArticlePtr &article, articles) {
|
||||
QListWidgetItem *articleItem = createArticleListItem(article);
|
||||
m_ui->listArticles->addItem(articleItem);
|
||||
}
|
||||
qDebug("Added all news to the GUI");
|
||||
}
|
||||
|
||||
// display a news
|
||||
void RSSImp::refreshTextBrowser()
|
||||
{
|
||||
QList<QListWidgetItem * > selection = m_ui->listArticles->selectedItems();
|
||||
if (selection.empty()) return;
|
||||
QListWidgetItem *item = selection.first();
|
||||
Q_ASSERT(item);
|
||||
if (item == m_currentArticle) return;
|
||||
m_currentArticle = item;
|
||||
|
||||
Rss::FeedPtr feed = m_feedList->getRSSItemFromUrl(item->data(Article::FeedUrlRole).toString());
|
||||
if (!feed) return;
|
||||
Rss::ArticlePtr article = feed->getItem(item->data(Article::IdRole).toString());
|
||||
if (!article) return;
|
||||
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>";
|
||||
m_ui->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->setRssSideSplitterState(m_ui->splitterSide->saveState());
|
||||
pref->setRssMainSplitterState(m_ui->splitterMain->saveState());
|
||||
qDebug("Splitters position saved");
|
||||
}
|
||||
|
||||
void RSSImp::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 RSSImp::updateItemsInfos(const QList<QTreeWidgetItem *> &items)
|
||||
{
|
||||
foreach (QTreeWidgetItem *item, items)
|
||||
updateItemInfos(item);
|
||||
}
|
||||
|
||||
void RSSImp::updateItemInfos(QTreeWidgetItem *item)
|
||||
{
|
||||
Rss::FilePtr rss_item = m_feedList->getRSSItem(item);
|
||||
if (!rss_item)
|
||||
return;
|
||||
|
||||
QString name;
|
||||
if (rss_item == m_rssManager->rootFolder()) {
|
||||
name = tr("Unread");
|
||||
emit updateRSSCount(rss_item->unreadCount());
|
||||
}
|
||||
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);
|
||||
|
||||
if (item)
|
||||
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);
|
||||
|
||||
if (item) {
|
||||
Rss::FeedPtr stream = qSharedPointerCast<Rss::Feed>(m_feedList->getRSSItem(item));
|
||||
item->setText(0, display_name + QString::fromUtf8(" (") + QString::number(nbUnread) + QString(")"));
|
||||
if (!stream->isLoading())
|
||||
item->setData(0, Qt::DecorationRole, QIcon(stream->iconPath()));
|
||||
// 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);
|
||||
// Update unread items
|
||||
else 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_ui(new Ui::RSS())
|
||||
, m_rssManager(new Rss::Manager)
|
||||
{
|
||||
m_ui->setupUi(this);
|
||||
// Icons
|
||||
m_ui->actionCopy_feed_URL->setIcon(GuiIconProvider::instance()->getIcon("edit-copy"));
|
||||
m_ui->actionDelete->setIcon(GuiIconProvider::instance()->getIcon("edit-delete"));
|
||||
m_ui->actionDownload_torrent->setIcon(GuiIconProvider::instance()->getIcon("download"));
|
||||
m_ui->actionMark_items_read->setIcon(GuiIconProvider::instance()->getIcon("mail-mark-read"));
|
||||
m_ui->actionNew_folder->setIcon(GuiIconProvider::instance()->getIcon("folder-new"));
|
||||
m_ui->actionNew_subscription->setIcon(GuiIconProvider::instance()->getIcon("list-add"));
|
||||
m_ui->actionOpen_news_URL->setIcon(GuiIconProvider::instance()->getIcon("application-x-mswinurl"));
|
||||
m_ui->actionRename->setIcon(GuiIconProvider::instance()->getIcon("edit-rename"));
|
||||
m_ui->actionUpdate->setIcon(GuiIconProvider::instance()->getIcon("view-refresh"));
|
||||
m_ui->actionUpdate_all_feeds->setIcon(GuiIconProvider::instance()->getIcon("view-refresh"));
|
||||
m_ui->newFeedButton->setIcon(GuiIconProvider::instance()->getIcon("list-add"));
|
||||
m_ui->markReadButton->setIcon(GuiIconProvider::instance()->getIcon("mail-mark-read"));
|
||||
m_ui->updateAllButton->setIcon(GuiIconProvider::instance()->getIcon("view-refresh"));
|
||||
m_ui->rssDownloaderBtn->setIcon(GuiIconProvider::instance()->getIcon("download"));
|
||||
m_ui->settingsButton->setIcon(GuiIconProvider::instance()->getIcon("configure", "preferences-system"));
|
||||
|
||||
m_feedList = new FeedListWidget(m_ui->splitterSide, m_rssManager);
|
||||
m_ui->splitterSide->insertWidget(0, m_feedList);
|
||||
editHotkey = new QShortcut(Qt::Key_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::Delete, m_feedList, 0, 0, Qt::WidgetShortcut);
|
||||
connect(deleteHotkey, SIGNAL(activated()), SLOT(deleteSelectedItems()));
|
||||
|
||||
m_rssManager->loadStreamList();
|
||||
m_feedList->setSortingEnabled(false);
|
||||
fillFeedsList();
|
||||
m_feedList->setSortingEnabled(true);
|
||||
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(m_ui->listArticles, SIGNAL(customContextMenuRequested(const QPoint&)), SLOT(displayItemsListMenu(const QPoint&)));
|
||||
|
||||
// Feeds list actions
|
||||
connect(m_ui->actionDelete, SIGNAL(triggered()), this, SLOT(deleteSelectedItems()));
|
||||
connect(m_ui->actionRename, SIGNAL(triggered()), this, SLOT(renameSelectedRssFile()));
|
||||
connect(m_ui->actionUpdate, SIGNAL(triggered()), this, SLOT(refreshSelectedItems()));
|
||||
connect(m_ui->actionNew_folder, SIGNAL(triggered()), this, SLOT(askNewFolder()));
|
||||
connect(m_ui->actionNew_subscription, SIGNAL(triggered()), this, SLOT(on_newFeedButton_clicked()));
|
||||
connect(m_ui->actionUpdate_all_feeds, SIGNAL(triggered()), this, SLOT(refreshAllFeeds()));
|
||||
connect(m_ui->updateAllButton, SIGNAL(clicked()), SLOT(refreshAllFeeds()));
|
||||
connect(m_ui->actionCopy_feed_URL, SIGNAL(triggered()), this, SLOT(copySelectedFeedsURL()));
|
||||
connect(m_ui->actionMark_items_read, SIGNAL(triggered()), this, SLOT(on_markReadButton_clicked()));
|
||||
// News list actions
|
||||
connect(m_ui->actionOpen_news_URL, SIGNAL(triggered()), this, SLOT(openSelectedArticlesUrls()));
|
||||
connect(m_ui->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(m_ui->listArticles, SIGNAL(itemSelectionChanged()), this, SLOT(refreshTextBrowser()));
|
||||
connect(m_ui->listArticles, SIGNAL(itemDoubleClicked(QListWidgetItem *)), this, SLOT(downloadSelectedTorrents()));
|
||||
|
||||
// Restore sliders position
|
||||
restoreSlidersPosition();
|
||||
// Bind saveSliders slots
|
||||
connect(m_ui->splitterMain, SIGNAL(splitterMoved(int,int)), this, SLOT(saveSlidersPosition()));
|
||||
connect(m_ui->splitterSide, SIGNAL(splitterMoved(int,int)), this, SLOT(saveSlidersPosition()));
|
||||
|
||||
qDebug("RSSImp constructed");
|
||||
}
|
||||
|
||||
RSSImp::~RSSImp()
|
||||
{
|
||||
qDebug("Deleting RSSImp...");
|
||||
saveFoldersOpenState();
|
||||
delete editHotkey;
|
||||
delete deleteHotkey;
|
||||
delete m_feedList;
|
||||
delete m_ui;
|
||||
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->rootFolder()->recheckRssItemsForDownload();
|
||||
refreshAllFeeds();
|
||||
}
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
/*
|
||||
* Bittorrent Client using Qt4 and libtorrent.
|
||||
* Copyright (C) 2010 Christophe Dumez
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
#include "rsssettingsdlg.h"
|
||||
#include "ui_rsssettingsdlg.h"
|
||||
|
||||
#include "base/preferences.h"
|
||||
#include "base/utils/misc.h"
|
||||
#include "guiiconprovider.h"
|
||||
|
||||
RssSettingsDlg::RssSettingsDlg(QWidget *parent) :
|
||||
QDialog(parent),
|
||||
ui(new Ui::RssSettingsDlg)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
ui->rssIcon->setPixmap(GuiIconProvider::instance()->getIcon("application-rss+xml").pixmap(Utils::Misc::largeIconSize()));
|
||||
// Load settings
|
||||
const Preferences* const pref = Preferences::instance();
|
||||
ui->spinRSSRefresh->setValue(pref->getRSSRefreshInterval());
|
||||
ui->spinRSSMaxArticlesPerFeed->setValue(pref->getRSSMaxArticlesPerFeed());
|
||||
}
|
||||
|
||||
RssSettingsDlg::~RssSettingsDlg()
|
||||
{
|
||||
qDebug("Deleting the RSS settings dialog");
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void RssSettingsDlg::on_buttonBox_accepted() {
|
||||
// Save settings
|
||||
Preferences* const pref = Preferences::instance();
|
||||
pref->setRSSRefreshInterval(ui->spinRSSRefresh->value());
|
||||
pref->setRSSMaxArticlesPerFeed(ui->spinRSSMaxArticlesPerFeed->value());
|
||||
}
|
||||
@@ -1,126 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>RssSettingsDlg</class>
|
||||
<widget class="QDialog" name="RssSettingsDlg">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>415</width>
|
||||
<height>123</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>RSS Reader Settings</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="1">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>RSS feeds refresh interval:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2">
|
||||
<widget class="QSpinBox" name="spinRSSRefresh">
|
||||
<property name="suffix">
|
||||
<string> min</string>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>999999</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>5</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>Maximum number of articles per feed:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<widget class="QSpinBox" name="spinRSSMaxArticlesPerFeed">
|
||||
<property name="maximum">
|
||||
<number>9999</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>100</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0" rowspan="2">
|
||||
<widget class="QLabel" name="rssIcon"/>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources>
|
||||
<include location="../../icons.qrc"/>
|
||||
</resources>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>accepted()</signal>
|
||||
<receiver>RssSettingsDlg</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>248</x>
|
||||
<y>254</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>157</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>rejected()</signal>
|
||||
<receiver>RssSettingsDlg</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>316</x>
|
||||
<y>260</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>286</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
||||
533
src/gui/rss/rsswidget.cpp
Normal file
533
src/gui/rss/rsswidget.cpp
Normal file
@@ -0,0 +1,533 @@
|
||||
/*
|
||||
* 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 <QDebug>
|
||||
#include <QDesktopServices>
|
||||
#include <QDragMoveEvent>
|
||||
#include <QMenu>
|
||||
#include <QMessageBox>
|
||||
#include <QStandardItemModel>
|
||||
#include <QString>
|
||||
|
||||
#include "base/bittorrent/session.h"
|
||||
#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"
|
||||
#include "base/utils/misc.h"
|
||||
#include "addnewtorrentdialog.h"
|
||||
#include "articlelistwidget.h"
|
||||
#include "autoexpandabledialog.h"
|
||||
#include "automatedrssdownloader.h"
|
||||
#include "feedlistwidget.h"
|
||||
#include "guiiconprovider.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(GuiIconProvider::instance()->getIcon("edit-copy"));
|
||||
m_ui->actionDelete->setIcon(GuiIconProvider::instance()->getIcon("edit-delete"));
|
||||
m_ui->actionDownloadTorrent->setIcon(GuiIconProvider::instance()->getIcon("download"));
|
||||
m_ui->actionMarkItemsRead->setIcon(GuiIconProvider::instance()->getIcon("mail-mark-read"));
|
||||
m_ui->actionNewFolder->setIcon(GuiIconProvider::instance()->getIcon("folder-new"));
|
||||
m_ui->actionNewSubscription->setIcon(GuiIconProvider::instance()->getIcon("list-add"));
|
||||
m_ui->actionOpenNewsURL->setIcon(GuiIconProvider::instance()->getIcon("application-x-mswinurl"));
|
||||
m_ui->actionRename->setIcon(GuiIconProvider::instance()->getIcon("edit-rename"));
|
||||
m_ui->actionUpdate->setIcon(GuiIconProvider::instance()->getIcon("view-refresh"));
|
||||
m_ui->actionUpdateAllFeeds->setIcon(GuiIconProvider::instance()->getIcon("view-refresh"));
|
||||
m_ui->newFeedButton->setIcon(GuiIconProvider::instance()->getIcon("list-add"));
|
||||
m_ui->markReadButton->setIcon(GuiIconProvider::instance()->getIcon("mail-mark-read"));
|
||||
m_ui->updateAllButton->setIcon(GuiIconProvider::instance()->getIcon("view-refresh"));
|
||||
m_ui->rssDownloaderBtn->setIcon(GuiIconProvider::instance()->getIcon("download"));
|
||||
|
||||
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());
|
||||
|
||||
m_editHotkey = new QShortcut(Qt::Key_F2, m_feedListWidget, 0, 0, Qt::WidgetShortcut);
|
||||
connect(m_editHotkey, &QShortcut::activated, this, &RSSWidget::renameSelectedRSSItem);
|
||||
m_deleteHotkey = new QShortcut(QKeySequence::Delete, m_feedListWidget, 0, 0, Qt::WidgetShortcut);
|
||||
connect(m_deleteHotkey, &QShortcut::activated, this, &RSSWidget::deleteSelectedItems);
|
||||
|
||||
// Feeds list actions
|
||||
connect(m_ui->actionDelete, &QAction::triggered, this, &RSSWidget::deleteSelectedItems);
|
||||
connect(m_ui->actionRename, &QAction::triggered, this, &RSSWidget::renameSelectedRSSItem);
|
||||
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_editHotkey;
|
||||
delete m_deleteHotkey;
|
||||
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 myRSSListMenu(this);
|
||||
QList<QTreeWidgetItem *> selectedItems = m_feedListWidget->selectedItems();
|
||||
if (selectedItems.size() > 0) {
|
||||
myRSSListMenu.addAction(m_ui->actionUpdate);
|
||||
myRSSListMenu.addAction(m_ui->actionMarkItemsRead);
|
||||
myRSSListMenu.addSeparator();
|
||||
if (selectedItems.size() == 1) {
|
||||
if (selectedItems.first() != m_feedListWidget->stickyUnreadItem()) {
|
||||
myRSSListMenu.addAction(m_ui->actionRename);
|
||||
myRSSListMenu.addAction(m_ui->actionDelete);
|
||||
myRSSListMenu.addSeparator();
|
||||
if (m_feedListWidget->isFolder(selectedItems.first()))
|
||||
myRSSListMenu.addAction(m_ui->actionNewFolder);
|
||||
}
|
||||
}
|
||||
else {
|
||||
myRSSListMenu.addAction(m_ui->actionDelete);
|
||||
myRSSListMenu.addSeparator();
|
||||
}
|
||||
myRSSListMenu.addAction(m_ui->actionNewSubscription);
|
||||
if (m_feedListWidget->isFeed(selectedItems.first())) {
|
||||
myRSSListMenu.addSeparator();
|
||||
myRSSListMenu.addAction(m_ui->actionCopyFeedURL);
|
||||
}
|
||||
}
|
||||
else {
|
||||
myRSSListMenu.addAction(m_ui->actionNewSubscription);
|
||||
myRSSListMenu.addAction(m_ui->actionNewFolder);
|
||||
myRSSListMenu.addSeparator();
|
||||
myRSSListMenu.addAction(m_ui->actionUpdateAllFeeds);
|
||||
}
|
||||
myRSSListMenu.exec(QCursor::pos());
|
||||
}
|
||||
|
||||
void RSSWidget::displayItemsListMenu(const QPoint &)
|
||||
{
|
||||
bool hasTorrent = false;
|
||||
bool hasLink = false;
|
||||
foreach (const QListWidgetItem *item, m_articleListWidget->selectedItems()) {
|
||||
auto article = reinterpret_cast<RSS::Article *>(item->data(Qt::UserRole).value<quintptr>());
|
||||
Q_ASSERT(article);
|
||||
|
||||
if (!article->torrentUrl().isEmpty())
|
||||
hasTorrent = true;
|
||||
if (!article->link().isEmpty())
|
||||
hasLink = true;
|
||||
if (hasTorrent && hasLink)
|
||||
break;
|
||||
}
|
||||
|
||||
QMenu myItemListMenu(this);
|
||||
if (hasTorrent)
|
||||
myItemListMenu.addAction(m_ui->actionDownloadTorrent);
|
||||
if (hasLink)
|
||||
myItemListMenu.addAction(m_ui->actionOpenNewsURL);
|
||||
if (hasTorrent || hasLink)
|
||||
myItemListMenu.exec(QCursor::pos());
|
||||
}
|
||||
|
||||
void RSSWidget::askNewFolder()
|
||||
{
|
||||
bool ok;
|
||||
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();
|
||||
if (!selectedItems.empty()) {
|
||||
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 == m_feedListWidget->stickyUnreadItem())
|
||||
? RSS::Session::instance()->rootFolder()
|
||||
: qobject_cast<RSS::Folder *>(m_feedListWidget->getRSSItem(destItem)));
|
||||
|
||||
QString error;
|
||||
const QString newFolderPath = RSS::Item::joinPath(rssDestFolder->path(), newName);
|
||||
if (!RSS::Session::instance()->addFolder(newFolderPath, &error))
|
||||
QMessageBox::warning(this, "qBittorrent", error, QMessageBox::Ok);
|
||||
|
||||
// Expand destination folder to display new feed
|
||||
if (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(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 = (Utils::Misc::isUrl(clipText) ? clipText : "http://");
|
||||
|
||||
bool ok;
|
||||
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();
|
||||
if (!selectedItems.empty()) {
|
||||
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)));
|
||||
|
||||
QString error;
|
||||
// NOTE: We still add feed using legacy way (with URL as feed name)
|
||||
const QString newFeedPath = RSS::Item::joinPath(rssDestFolder->path(), newURL);
|
||||
if (!RSS::Session::instance()->addFeed(newURL, newFeedPath, &error))
|
||||
QMessageBox::warning(this, "qBittorrent", error, QMessageBox::Ok);
|
||||
|
||||
// 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()
|
||||
{
|
||||
QList<QTreeWidgetItem *> selectedItems = m_feedListWidget->selectedItems();
|
||||
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;
|
||||
|
||||
foreach (QTreeWidgetItem *item, selectedItems)
|
||||
if (item != m_feedListWidget->stickyUnreadItem())
|
||||
RSS::Session::instance()->removeItem(m_feedListWidget->itemPath(item));
|
||||
}
|
||||
|
||||
void RSSWidget::loadFoldersOpenState()
|
||||
{
|
||||
const QStringList openedFolders = Preferences::instance()->getRssOpenFolders();
|
||||
foreach (const QString &varPath, openedFolders) {
|
||||
QTreeWidgetItem *parent = nullptr;
|
||||
foreach (const QString &name, varPath.split("\\")) {
|
||||
int nbChildren = (parent ? parent->childCount() : m_feedListWidget->topLevelItemCount());
|
||||
for (int i = 0; i < nbChildren; ++i) {
|
||||
QTreeWidgetItem *child = (parent ? parent->child(i) : m_feedListWidget->topLevelItem(i));
|
||||
if (m_feedListWidget->getRSSItem(child)->name() == name) {
|
||||
parent = child;
|
||||
parent->setExpanded(true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RSSWidget::saveFoldersOpenState()
|
||||
{
|
||||
QStringList openedFolders;
|
||||
foreach (QTreeWidgetItem *item, m_feedListWidget->getAllOpenedFolders())
|
||||
openedFolders << m_feedListWidget->itemPath(item);
|
||||
Preferences::instance()->setRssOpenFolders(openedFolders);
|
||||
}
|
||||
|
||||
void RSSWidget::refreshAllFeeds()
|
||||
{
|
||||
RSS::Session::instance()->refresh();
|
||||
}
|
||||
|
||||
void RSSWidget::downloadSelectedTorrents()
|
||||
{
|
||||
foreach (QListWidgetItem *item, m_articleListWidget->selectedItems()) {
|
||||
auto article = reinterpret_cast<RSS::Article *>(item->data(Qt::UserRole).value<quintptr>());
|
||||
Q_ASSERT(article);
|
||||
|
||||
// Mark as read
|
||||
article->markAsRead();
|
||||
|
||||
if (!article->torrentUrl().isEmpty()) {
|
||||
if (AddNewTorrentDialog::isEnabled())
|
||||
AddNewTorrentDialog::show(article->torrentUrl());
|
||||
else
|
||||
BitTorrent::Session::instance()->addTorrent(article->torrentUrl());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// open the url of the selected RSS articles in the Web browser
|
||||
void RSSWidget::openSelectedArticlesUrls()
|
||||
{
|
||||
foreach (QListWidgetItem *item, m_articleListWidget->selectedItems()) {
|
||||
auto article = reinterpret_cast<RSS::Article *>(item->data(Qt::UserRole).value<quintptr>());
|
||||
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());
|
||||
bool ok;
|
||||
do {
|
||||
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;
|
||||
|
||||
QString error;
|
||||
if (!RSS::Session::instance()->moveItem(rssItem, RSS::Item::joinPath(parentPath, newName), &error)) {
|
||||
QMessageBox::warning(0, tr("Rename failed"), error);
|
||||
ok = false;
|
||||
}
|
||||
} while (!ok);
|
||||
}
|
||||
|
||||
void RSSWidget::refreshSelectedItems()
|
||||
{
|
||||
foreach (QTreeWidgetItem *item, m_feedListWidget->selectedItems()) {
|
||||
if (item == m_feedListWidget->stickyUnreadItem()) {
|
||||
refreshAllFeeds();
|
||||
return;
|
||||
}
|
||||
|
||||
m_feedListWidget->getRSSItem(item)->refresh();
|
||||
}
|
||||
}
|
||||
|
||||
void RSSWidget::copySelectedFeedsURL()
|
||||
{
|
||||
QStringList URLs;
|
||||
foreach (QTreeWidgetItem *item, m_feedListWidget->selectedItems()) {
|
||||
if (auto feed = qobject_cast<RSS::Feed *>(m_feedListWidget->getRSSItem(item)))
|
||||
URLs << feed->url();
|
||||
}
|
||||
qApp->clipboard()->setText(URLs.join("\n"));
|
||||
}
|
||||
|
||||
void RSSWidget::handleCurrentFeedItemChanged(QTreeWidgetItem *currentItem)
|
||||
{
|
||||
if (!currentItem) {
|
||||
m_articleListWidget->clear();
|
||||
return;
|
||||
}
|
||||
|
||||
m_articleListWidget->setRSSItem(m_feedListWidget->getRSSItem(currentItem)
|
||||
, (currentItem == m_feedListWidget->stickyUnreadItem()));
|
||||
}
|
||||
|
||||
void RSSWidget::on_markReadButton_clicked()
|
||||
{
|
||||
foreach (QTreeWidgetItem *item, m_feedListWidget->selectedItems()) {
|
||||
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();
|
||||
|
||||
if (previousItem) {
|
||||
auto article = m_articleListWidget->getRSSArticle(previousItem);
|
||||
Q_ASSERT(article);
|
||||
article->markAsRead();
|
||||
}
|
||||
|
||||
if (!currentItem) return;
|
||||
|
||||
auto article = m_articleListWidget->getRSSArticle(currentItem);
|
||||
Q_ASSERT(article);
|
||||
|
||||
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>";
|
||||
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(uint val)
|
||||
{
|
||||
RSS::Session::instance()->setRefreshInterval(val);
|
||||
}
|
||||
|
||||
void RSSWidget::on_rssDownloaderBtn_clicked()
|
||||
{
|
||||
AutomatedRssDownloader(this).exec();
|
||||
}
|
||||
|
||||
void RSSWidget::handleSessionProcessingStateChanged(bool enabled)
|
||||
{
|
||||
m_ui->labelWarn->setVisible(!enabled);
|
||||
}
|
||||
|
||||
void RSSWidget::handleUnreadCountChanged()
|
||||
{
|
||||
emit unreadCountUpdated(RSS::Session::instance()->rootFolder()->unreadCount());
|
||||
}
|
||||
@@ -1,6 +1,8 @@
|
||||
/*
|
||||
* Bittorrent Client using Qt4 and libtorrent.
|
||||
* Copyright (C) 2006 Christophe Dumez, Arnaud Demaiziere
|
||||
* 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
|
||||
@@ -24,46 +26,38 @@
|
||||
* 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
|
||||
*/
|
||||
#ifndef __RSS_IMP_H__
|
||||
#define __RSS_IMP_H__
|
||||
|
||||
#define REFRESH_MAX_LATENCY 600000
|
||||
#ifndef RSSWIDGET_H
|
||||
#define RSSWIDGET_H
|
||||
|
||||
#include <QPointer>
|
||||
#include <QShortcut>
|
||||
|
||||
#include "base/rss/rssfolder.h"
|
||||
#include "base/rss/rssmanager.h"
|
||||
|
||||
class ArticleListWidget;
|
||||
class FeedListWidget;
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QListWidgetItem;
|
||||
class QTreeWidgetItem;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
namespace Ui
|
||||
{
|
||||
class RSS;
|
||||
class RSSWidget;
|
||||
}
|
||||
|
||||
class RSSImp: public QWidget
|
||||
class RSSWidget: public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
RSSImp(QWidget * parent);
|
||||
~RSSImp();
|
||||
RSSWidget(QWidget *parent);
|
||||
~RSSWidget();
|
||||
|
||||
public slots:
|
||||
void deleteSelectedItems();
|
||||
void updateRefreshInterval(uint val);
|
||||
|
||||
signals:
|
||||
void updateRSSCount(int);
|
||||
void unreadCountUpdated(int count);
|
||||
|
||||
private slots:
|
||||
void on_newFeedButton_clicked();
|
||||
@@ -71,38 +65,28 @@ private slots:
|
||||
void on_markReadButton_clicked();
|
||||
void displayRSSListMenu(const QPoint &);
|
||||
void displayItemsListMenu(const QPoint &);
|
||||
void renameSelectedRssFile();
|
||||
void renameSelectedRSSItem();
|
||||
void refreshSelectedItems();
|
||||
void copySelectedFeedsURL();
|
||||
void populateArticleList(QTreeWidgetItem *item);
|
||||
void refreshTextBrowser();
|
||||
void updateFeedIcon(const QString &url, const QString &icon_path);
|
||||
void updateFeedInfos(const QString &url, const QString &display_name, uint nbUnread);
|
||||
void onFeedContentChanged(const QString &url);
|
||||
void updateItemsInfos(const QList<QTreeWidgetItem *> &items);
|
||||
void updateItemInfos(QTreeWidgetItem *item);
|
||||
void handleCurrentFeedItemChanged(QTreeWidgetItem *currentItem);
|
||||
void handleCurrentArticleItemChanged(QListWidgetItem *currentItem, QListWidgetItem *previousItem);
|
||||
void openSelectedArticlesUrls();
|
||||
void downloadSelectedTorrents();
|
||||
void fillFeedsList(QTreeWidgetItem *parent = 0, const Rss::FolderPtr &rss_parent = Rss::FolderPtr());
|
||||
void saveSlidersPosition();
|
||||
void restoreSlidersPosition();
|
||||
void askNewFolder();
|
||||
void saveFoldersOpenState();
|
||||
void loadFoldersOpenState();
|
||||
void on_settingsButton_clicked();
|
||||
void on_rssDownloaderBtn_clicked();
|
||||
void handleSessionProcessingStateChanged(bool enabled);
|
||||
void handleUnreadCountChanged();
|
||||
|
||||
private:
|
||||
static QListWidgetItem *createArticleListItem(const Rss::ArticlePtr &article);
|
||||
static QTreeWidgetItem *createFolderListItem(const Rss::FilePtr &rssFile);
|
||||
|
||||
private:
|
||||
Ui::RSS *m_ui;
|
||||
Rss::ManagerPtr m_rssManager;
|
||||
FeedListWidget *m_feedList;
|
||||
QListWidgetItem *m_currentArticle;
|
||||
QShortcut *editHotkey;
|
||||
QShortcut *deleteHotkey;
|
||||
Ui::RSSWidget *m_ui;
|
||||
ArticleListWidget *m_articleListWidget;
|
||||
FeedListWidget *m_feedListWidget;
|
||||
QShortcut *m_editHotkey;
|
||||
QShortcut *m_deleteHotkey;
|
||||
};
|
||||
|
||||
#endif
|
||||
#endif // RSSWIDGET_H
|
||||
@@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>RSS</class>
|
||||
<widget class="QWidget" name="RSS">
|
||||
<class>RSSWidget</class>
|
||||
<widget class="QWidget" name="RSSWidget">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
@@ -17,6 +17,24 @@
|
||||
<string>Search</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<widget class="QLabel" name="labelWarn">
|
||||
<property name="font">
|
||||
<font>
|
||||
<italic>true</italic>
|
||||
</font>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">color: red;</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Fetching of RSS feeds is disabled now! You can enable it in application settings.</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
@@ -63,13 +81,6 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="settingsButton">
|
||||
<property name="text">
|
||||
<string>Settings...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
@@ -109,14 +120,6 @@
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<widget class="QListWidget" name="listArticles">
|
||||
<property name="contextMenuPolicy">
|
||||
<enum>Qt::CustomContextMenu</enum>
|
||||
</property>
|
||||
<property name="selectionMode">
|
||||
<enum>QAbstractItemView::ExtendedSelection</enum>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="HtmlBrowser" name="textBrowser">
|
||||
<property name="openExternalLinks">
|
||||
<bool>true</bool>
|
||||
@@ -153,12 +156,12 @@
|
||||
<string>Update</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionNew_subscription">
|
||||
<action name="actionNewSubscription">
|
||||
<property name="text">
|
||||
<string>New subscription...</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionUpdate_all_feeds">
|
||||
<action name="actionUpdateAllFeeds">
|
||||
<property name="text">
|
||||
<string>Update all feeds</string>
|
||||
</property>
|
||||
@@ -166,7 +169,7 @@
|
||||
<string>Update all feeds</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionMark_items_read">
|
||||
<action name="actionMarkItemsRead">
|
||||
<property name="text">
|
||||
<string>Mark items read</string>
|
||||
</property>
|
||||
@@ -174,22 +177,22 @@
|
||||
<string>Mark items read</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionDownload_torrent">
|
||||
<action name="actionDownloadTorrent">
|
||||
<property name="text">
|
||||
<string>Download torrent</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionOpen_news_URL">
|
||||
<action name="actionOpenNewsURL">
|
||||
<property name="text">
|
||||
<string>Open news URL</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionCopy_feed_URL">
|
||||
<action name="actionCopyFeedURL">
|
||||
<property name="text">
|
||||
<string>Copy feed URL</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionNew_folder">
|
||||
<action name="actionNewFolder">
|
||||
<property name="text">
|
||||
<string>New folder...</string>
|
||||
</property>
|
||||
@@ -199,7 +202,7 @@
|
||||
<customwidget>
|
||||
<class>HtmlBrowser</class>
|
||||
<extends>QTextBrowser</extends>
|
||||
<header>htmlbrowser.h</header>
|
||||
<header>gui/rss/htmlbrowser.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
Reference in New Issue
Block a user