experimental ability to purge articles from individual feeds - available with feed context menu and main menu Feeds submenu

This commit is contained in:
Martin Rotter 2025-01-07 15:03:03 +01:00
parent a352b7551e
commit 7722065544
9 changed files with 84 additions and 0 deletions

View file

@ -15,6 +15,7 @@ void DatabaseCleaner::purgeDatabaseData(CleanerOrders which_data) {
// Inform everyone about the start of the process.
emit purgeStarted();
bool result = true;
const int difference = 99 / 12;
int progress = 0;
@ -22,51 +23,61 @@ void DatabaseCleaner::purgeDatabaseData(CleanerOrders which_data) {
if (which_data.m_removeReadMessages) {
progress += difference;
emit purgeProgress(progress, tr("Removing read articles..."));
// Remove read messages.
result &= purgeReadMessages(database);
progress += difference;
emit purgeProgress(progress, tr("Read articles purged..."));
}
if (which_data.m_removeRecycleBin) {
progress += difference;
emit purgeProgress(progress, tr("Purging recycle bin..."));
// Remove read messages.
result &= purgeRecycleBin(database);
progress += difference;
emit purgeProgress(progress, tr("Recycle bin purged..."));
}
if (which_data.m_removeOldMessages) {
progress += difference;
emit purgeProgress(progress, tr("Removing old articles..."));
// Remove old messages.
result &= purgeOldMessages(database, which_data.m_barrierForRemovingOldMessagesInDays);
progress += difference;
emit purgeProgress(progress, tr("Old articles purged..."));
}
if (which_data.m_removeStarredMessages) {
progress += difference;
emit purgeProgress(progress, tr("Removing starred articles..."));
// Remove old messages.
result &= purgeStarredMessages(database);
progress += difference;
emit purgeProgress(progress, tr("Starred articles purged..."));
}
if (which_data.m_shrinkDatabase) {
progress += difference;
emit purgeProgress(progress, tr("Shrinking database file..."));
// Call driver-specific vacuuming function.
result &= qApp->database()->driver()->vacuumDatabase();
progress += difference;
emit purgeProgress(progress, tr("Database file shrinked..."));
}

View file

@ -634,6 +634,27 @@ bool DatabaseQueries::removeUnwantedArticlesFromFeed(const QSqlDatabase& db,
return rows_deleted > 0;
}
bool DatabaseQueries::purgeFeedMessages(const QSqlDatabase& database, const Feed* feed) {
QSqlQuery q(database);
q.setForwardOnly(true);
q.prepare(QSL("DELETE FROM Messages "
"WHERE "
" Messages.account_id = :account_id AND "
" Messages.feed = :feed AND "
" Messages.is_important = 0"));
q.bindValue(QSL(":feed"), feed->customId());
q.bindValue(QSL(":account_id"), feed->getParentServiceRoot()->accountId());
if (!q.exec()) {
throw ApplicationException(q.lastError().text());
}
else {
return q.numRowsAffected() > 0;
}
}
bool DatabaseQueries::purgeMessage(const QSqlDatabase& db, int message_id) {
QSqlQuery q(db);

View file

@ -76,6 +76,7 @@ class RSSGUARD_DLLSPEC DatabaseQueries {
const Feed::ArticleIgnoreLimit& feed_setup,
const Feed::ArticleIgnoreLimit& app_setup);
static bool purgeFeedMessages(const QSqlDatabase& database, const Feed* feed);
static bool purgeMessage(const QSqlDatabase& db, int message_id);
static bool purgeImportantMessages(const QSqlDatabase& db);
static bool purgeReadMessages(const QSqlDatabase& db);

View file

@ -195,6 +195,7 @@ QList<QAction*> FormMain::allActions() const {
actions << m_ui->m_actionMarkSelectedItemsAsRead;
actions << m_ui->m_actionMarkSelectedItemsAsUnread;
actions << m_ui->m_actionClearSelectedItems;
actions << m_ui->m_actionPurgeSelectedItems;
actions << m_ui->m_actionClearAllItems;
actions << m_ui->m_actionShowOnlyUnreadItems;
actions << m_ui->m_actionSortFeedsAlphabetically;
@ -499,6 +500,7 @@ void FormMain::updateFeedButtonsAvailability() {
m_ui->m_actionBackupDatabaseSettings->setEnabled(!critical_action_running);
m_ui->m_actionCleanupDatabase->setEnabled(!critical_action_running);
m_ui->m_actionClearSelectedItems->setEnabled(anything_selected);
m_ui->m_actionPurgeSelectedItems->setEnabled(feed_selected);
m_ui->m_actionDeleteSelectedItem->setEnabled(!critical_action_running && anything_selected);
m_ui->m_actionEditSelectedItem->setEnabled(!critical_action_running && anything_selected);
m_ui->m_actionEditChildFeeds->setEnabled(!critical_action_running && (service_selected || category_selected));
@ -605,6 +607,7 @@ void FormMain::setupIcons() {
m_ui->m_actionUpdateSelectedItemsWithCustomTimers->setIcon(icon_theme_factory->fromTheme(QSL("download"),
QSL("browser-download")));
m_ui->m_actionClearSelectedItems->setIcon(icon_theme_factory->fromTheme(QSL("mail-mark-junk")));
m_ui->m_actionPurgeSelectedItems->setIcon(icon_theme_factory->fromTheme(QSL("edit-clear")));
m_ui->m_actionClearAllItems->setIcon(icon_theme_factory->fromTheme(QSL("mail-mark-junk")));
m_ui->m_actionDeleteSelectedItem->setIcon(icon_theme_factory->fromTheme(QSL("list-remove")));
m_ui->m_actionDeleteSelectedMessages->setIcon(icon_theme_factory->fromTheme(QSL("mail-mark-junk")));
@ -925,6 +928,10 @@ void FormMain::createConnections() {
&QAction::triggered,
tabWidget()->feedMessageViewer()->feedsView(),
&FeedsView::clearSelectedItems);
connect(m_ui->m_actionPurgeSelectedItems,
&QAction::triggered,
tabWidget()->feedMessageViewer()->feedsView(),
&FeedsView::purgeSelectedFeeds);
connect(m_ui->m_actionClearAllItems,
&QAction::triggered,
tabWidget()->feedMessageViewer()->feedsView(),

View file

@ -151,6 +151,7 @@
<addaction name="m_actionCopyUrlSelectedFeed"/>
<addaction name="m_actionMarkSelectedItemsAsRead"/>
<addaction name="m_actionMarkSelectedItemsAsUnread"/>
<addaction name="m_actionPurgeSelectedItems"/>
<addaction name="m_actionClearSelectedItems"/>
<addaction name="separator"/>
<addaction name="m_actionFocusSearchFeeds"/>
@ -960,6 +961,11 @@
<string>&amp;Pause automatic feed fetching</string>
</property>
</action>
<action name="m_actionPurgeSelectedItems">
<property name="text">
<string>&amp;Purge selected feeds</string>
</property>
</action>
</widget>
<customwidgets>
<customwidget>

View file

@ -254,6 +254,23 @@ void FeedsView::clearSelectedItems() {
}
}
void FeedsView::purgeSelectedFeeds() {
if (MsgBox::show(nullptr,
QMessageBox::Icon::Question,
tr("Are you sure?"),
tr("Do you really want to purge all non-starred articles from selected feeds?"),
{},
{},
QMessageBox::StandardButton::Yes | QMessageBox::StandardButton::No,
QMessageBox::StandardButton::No) != QMessageBox::StandardButton::Yes) {
return;
}
for (auto* it : selectedFeeds(true)) {
it->purgeArticles();
}
}
void FeedsView::clearAllItems() {
if (MsgBox::show(nullptr,
QMessageBox::Icon::Question,

View file

@ -61,6 +61,7 @@ class RSSGUARD_DLLSPEC FeedsView : public BaseTreeView {
// Feed clearers.
void clearSelectedItems();
void clearAllItems();
void purgeSelectedFeeds();
// Base manipulators.
void editItems(const QList<RootItem*>& items);

View file

@ -113,6 +113,24 @@ QVariant Feed::data(int column, int role) const {
}
}
void Feed::purgeArticles() {
auto database = qApp->database()->driver()->connection(metaObject()->className());
try {
bool anything_purged = DatabaseQueries::purgeFeedMessages(database, this);
if (anything_purged) {
getParentServiceRoot()->updateCounts(true);
getParentServiceRoot()->itemChanged(getParentServiceRoot()->getSubTree());
getParentServiceRoot()->requestReloadMessageList(false);
}
}
catch (const ApplicationException& ex) {
qCriticalNN << LOGSEC_CORE << "Purging of articles from feed" << QUOTE_W_SPACE(customId())
<< "failed with error:" << QUOTE_W_SPACE_DOT(ex.message());
}
}
int Feed::autoUpdateInterval() const {
return m_autoUpdateInterval;
}

View file

@ -71,6 +71,8 @@ class RSSGUARD_DLLSPEC Feed : public RootItem {
virtual bool isFetching() const;
virtual QVariant data(int column, int role) const;
void purgeArticles();
void setCountOfAllMessages(int count_all_messages);
void setCountOfUnreadMessages(int count_unread_messages);