Skip to content

Commit

Permalink
Display feeds as tree in RSS downloader
Browse files Browse the repository at this point in the history
  • Loading branch information
Pioooooo committed Sep 23, 2023
1 parent f3b6882 commit 3ebc37d
Show file tree
Hide file tree
Showing 3 changed files with 108 additions and 45 deletions.
141 changes: 98 additions & 43 deletions src/gui/rss/automatedrssdownloader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ AutomatedRssDownloader::AutomatedRssDownloader(QWidget *parent)
m_ui->mainSplitter->setCollapsible(0, false);
m_ui->mainSplitter->setCollapsible(1, false);
m_ui->mainSplitter->setCollapsible(2, true); // Only the preview list is collapsible
m_ui->listFeeds->setHeaderHidden(true);

connect(m_ui->checkRegex, &QAbstractButton::toggled, this, &AutomatedRssDownloader::updateFieldsToolTips);
connect(m_ui->ruleList, &QWidget::customContextMenuRequested, this, &AutomatedRssDownloader::displayRulesListMenu);
Expand Down Expand Up @@ -136,7 +137,7 @@ AutomatedRssDownloader::AutomatedRssDownloader(QWidget *parent)
connect(m_ui->spinIgnorePeriod, qOverload<int>(&QSpinBox::valueChanged)
, this, &AutomatedRssDownloader::handleRuleDefinitionChanged);

connect(m_ui->listFeeds, &QListWidget::itemChanged, this, &AutomatedRssDownloader::handleFeedCheckStateChange);
connect(m_ui->listFeeds, &QTreeWidget::itemChanged, this, &AutomatedRssDownloader::handleFeedCheckStateChange);

connect(m_ui->ruleList, &QListWidget::itemSelectionChanged, this, &AutomatedRssDownloader::updateRuleDefinitionBox);
connect(m_ui->ruleList, &QListWidget::itemChanged, this, &AutomatedRssDownloader::handleRuleCheckStateChange);
Expand Down Expand Up @@ -204,15 +205,60 @@ void AutomatedRssDownloader::createRuleItem(const RSS::AutoDownloadRule &rule)
void AutomatedRssDownloader::loadFeedList()
{
const QSignalBlocker feedListSignalBlocker(m_ui->listFeeds);
loadFeedTree(nullptr, RSS::Session::instance()->rootFolder());

for (const auto *feed : asConst(RSS::Session::instance()->feeds()))
updateFeedList();
}

QTreeWidgetItem * AutomatedRssDownloader::createFeedTreeItem(const RSS::Item *rssItem, QTreeWidgetItem *parentItem)
{
auto *item = new QTreeWidgetItem;
item->setData(0, Qt::DisplayRole, rssItem->name());
item->setData(0, Qt::UserRole, QVariant::fromValue(rssItem));
item->setFlags(item->flags() | Qt::ItemIsUserCheckable | Qt::ItemIsAutoTristate);
item->setCheckState(0, Qt::Unchecked); // Init state for folders as we don't manually set them later

if (!parentItem)
m_ui->listFeeds->addTopLevelItem(item);
else
parentItem->addChild(item);
return item;
}

void AutomatedRssDownloader::loadFeedTree(QTreeWidgetItem *parent, const RSS::Folder *rssParent)
{
for (const auto *rssItem : asConst(rssParent->items()))
{
QListWidgetItem *item = new QListWidgetItem(feed->name(), m_ui->listFeeds);
item->setData(Qt::UserRole, feed->url());
item->setFlags(item->flags() | Qt::ItemIsUserCheckable | Qt::ItemIsAutoTristate);
QTreeWidgetItem *item = createFeedTreeItem(rssItem, parent);

// Recursive call if this is a folder.
if (const auto *folder = qobject_cast<const RSS::Folder *>(rssItem))
loadFeedTree(item, folder);
}
}

updateFeedList();
QList<QTreeWidgetItem *> AutomatedRssDownloader::getAllFeedTreeItems(QTreeWidgetItem *parent) const
{
QList<QTreeWidgetItem *> feedItems;
int nbChildren = (parent ? parent->childCount() : m_ui->listFeeds->topLevelItemCount());
for (int i = 0; i < nbChildren; ++i)
{
QTreeWidgetItem *item (parent ? parent->child(i) : m_ui->listFeeds->topLevelItem(i));
if (qobject_cast<RSS::Feed *>(item->data(0, Qt::UserRole).value<RSS::Item *>()))
feedItems << item;
else
feedItems << getAllFeedTreeItems(item);
}
return feedItems;
}

void AutomatedRssDownloader::sortTreeRecursively(QTreeWidgetItem *item)
{
for (int i = 0; i < item->childCount(); i++) {
QTreeWidgetItem *child = item->child(i);
sortTreeRecursively(child);
}
item->sortChildren(0, Qt::AscendingOrder);
}

void AutomatedRssDownloader::updateFeedList()
Expand All @@ -228,33 +274,37 @@ void AutomatedRssDownloader::updateFeedList()

bool enable = !selection.isEmpty();

for (int i = 0; i < m_ui->listFeeds->count(); ++i)
for (int i = 0; i < m_ui->listFeeds->topLevelItemCount(); ++i)
m_ui->listFeeds->topLevelItem(i)->setHidden(!enable);

for (QTreeWidgetItem* item: asConst(getAllFeedTreeItems()))
{
QListWidgetItem *item = m_ui->listFeeds->item(i);
const QString feedURL = item->data(Qt::UserRole).toString();
item->setHidden(!enable);
if (auto rssItem = qobject_cast<const RSS::Feed *>(item->data(0, Qt::UserRole).value<RSS::Item *>()))
{
const QString feedURL = rssItem->url();
item->setHidden(!enable);

bool allEnabled = true;
bool anyEnabled = false;
bool allEnabled = true;
bool anyEnabled = false;

for (const QListWidgetItem *ruleItem : asConst(selection))
{
const auto rule = RSS::AutoDownloader::instance()->ruleByName(ruleItem->text());
if (rule.feedURLs().contains(feedURL))
anyEnabled = true;
for (const QListWidgetItem *ruleItem : asConst(selection))
{
const auto rule = RSS::AutoDownloader::instance()->ruleByName(ruleItem->text());
if (rule.feedURLs().contains(feedURL))
anyEnabled = true;
else
allEnabled = false;
}
if (anyEnabled && allEnabled)
item->setCheckState(0, Qt::Checked);
else if (anyEnabled)
item->setCheckState(0, Qt::PartiallyChecked);
else
allEnabled = false;
item->setCheckState(0, Qt::Unchecked);
}

if (anyEnabled && allEnabled)
item->setCheckState(Qt::Checked);
else if (anyEnabled)
item->setCheckState(Qt::PartiallyChecked);
else
item->setCheckState(Qt::Unchecked);
}

m_ui->listFeeds->sortItems();
sortTreeRecursively(m_ui->listFeeds->invisibleRootItem());
m_ui->lblListFeeds->setEnabled(enable);
m_ui->listFeeds->setEnabled(enable);
}
Expand Down Expand Up @@ -569,25 +619,30 @@ void AutomatedRssDownloader::clearSelectedRuleDownloadedEpisodeList()
}
}

void AutomatedRssDownloader::handleFeedCheckStateChange(QListWidgetItem *feedItem)
void AutomatedRssDownloader::handleFeedCheckStateChange(QTreeWidgetItem *feedItem, int column)
{
const QString feedURL = feedItem->data(Qt::UserRole).toString();
for (QListWidgetItem *ruleItem : asConst(m_ui->ruleList->selectedItems()))
Q_ASSERT(column == 0);
const RSS::Item *rssItem = feedItem->data(0, Qt::UserRole).value<const RSS::Item *>();
if (auto *feed = qobject_cast<const RSS::Feed *>(rssItem))
{
RSS::AutoDownloadRule rule = (ruleItem == m_currentRuleItem
? m_currentRule
: RSS::AutoDownloader::instance()->ruleByName(ruleItem->text()));
QStringList affectedFeeds = rule.feedURLs();
if ((feedItem->checkState() == Qt::Checked) && !affectedFeeds.contains(feedURL))
affectedFeeds << feedURL;
else if ((feedItem->checkState() == Qt::Unchecked) && affectedFeeds.contains(feedURL))
affectedFeeds.removeOne(feedURL);

rule.setFeedURLs(affectedFeeds);
if (ruleItem != m_currentRuleItem)
RSS::AutoDownloader::instance()->setRule(rule);
else
m_currentRule = rule;
const QString feedURL = feed->url();
for (QListWidgetItem *ruleItem : asConst(m_ui->ruleList->selectedItems()))
{
RSS::AutoDownloadRule rule = (ruleItem == m_currentRuleItem
? m_currentRule
: RSS::AutoDownloader::instance()->ruleByName(ruleItem->text()));
QStringList affectedFeeds = rule.feedURLs();
if ((feedItem->checkState(0) == Qt::Checked) && !affectedFeeds.contains(feedURL))
affectedFeeds << feedURL;
else if ((feedItem->checkState(0) == Qt::Unchecked) && affectedFeeds.contains(feedURL))
affectedFeeds.removeOne(feedURL);

rule.setFeedURLs(affectedFeeds);
if (ruleItem != m_currentRuleItem)
RSS::AutoDownloader::instance()->setRule(rule);
else
m_currentRule = rule;
}
}

handleRuleDefinitionChanged();
Expand Down
10 changes: 9 additions & 1 deletion src/gui/rss/automatedrssdownloader.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,16 +34,20 @@
#include <QDialog>
#include <QHash>
#include <QSet>
#include <QList>

#include "base/rss/rss_autodownloadrule.h"
#include "base/settingvalue.h"

class QListWidgetItem;
class QTreeWidgetItem;
class QRegularExpression;

namespace RSS
{
class Feed;
class Folder;
class Item;
}

namespace Ui
Expand All @@ -69,7 +73,7 @@ private slots:
void onImportBtnClicked();
void onRenameRuleBtnClicked();
void handleRuleCheckStateChange(QListWidgetItem *ruleItem);
void handleFeedCheckStateChange(QListWidgetItem *feedItem);
void handleFeedCheckStateChange(QTreeWidgetItem *feedItem, int column);
void displayRulesListMenu();
void renameSelectedRule();
void updateRuleDefinitionBox();
Expand All @@ -95,6 +99,10 @@ private slots:
void updateMatchingArticles();
void saveEditedRule();
void loadFeedList();
QTreeWidgetItem *createFeedTreeItem(const RSS::Item *rssItem, QTreeWidgetItem *parentItem);
QList<QTreeWidgetItem *>getAllFeedTreeItems(QTreeWidgetItem *parent = nullptr) const;
void loadFeedTree(QTreeWidgetItem *parent, const RSS::Folder *rssParent);
void sortTreeRecursively(QTreeWidgetItem *item);
void updateFeedList();
void addFeedArticlesToTree(RSS::Feed *feed, const QStringList &articles);

Expand Down
2 changes: 1 addition & 1 deletion src/gui/rss/automatedrssdownloader.ui
Original file line number Diff line number Diff line change
Expand Up @@ -356,7 +356,7 @@ Supports the formats: S01E01, 1x1, 2017.12.31 and 31.12.2017 (Date formats also
</widget>
</item>
<item>
<widget class="QListWidget" name="listFeeds"/>
<widget class="QTreeWidget" name="listFeeds"/>
</item>
</layout>
</widget>
Expand Down

0 comments on commit 3ebc37d

Please sign in to comment.