diff --git a/src/librssguard/database/databasecleaner.cpp b/src/librssguard/database/databasecleaner.cpp index e183d1d94..9c5034983 100644 --- a/src/librssguard/database/databasecleaner.cpp +++ b/src/librssguard/database/databasecleaner.cpp @@ -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...")); } diff --git a/src/librssguard/database/databasequeries.cpp b/src/librssguard/database/databasequeries.cpp index c37ade358..eea1d04d5 100644 --- a/src/librssguard/database/databasequeries.cpp +++ b/src/librssguard/database/databasequeries.cpp @@ -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); diff --git a/src/librssguard/database/databasequeries.h b/src/librssguard/database/databasequeries.h index df143b7ce..1fdf7475a 100644 --- a/src/librssguard/database/databasequeries.h +++ b/src/librssguard/database/databasequeries.h @@ -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); diff --git a/src/librssguard/gui/dialogs/formmain.cpp b/src/librssguard/gui/dialogs/formmain.cpp index 67885d305..fa071ead7 100644 --- a/src/librssguard/gui/dialogs/formmain.cpp +++ b/src/librssguard/gui/dialogs/formmain.cpp @@ -195,6 +195,7 @@ QList 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(), diff --git a/src/librssguard/gui/dialogs/formmain.ui b/src/librssguard/gui/dialogs/formmain.ui index e053ed71b..6a67d38cc 100644 --- a/src/librssguard/gui/dialogs/formmain.ui +++ b/src/librssguard/gui/dialogs/formmain.ui @@ -151,6 +151,7 @@ + @@ -960,6 +961,11 @@ &Pause automatic feed fetching + + + &Purge selected feeds + + diff --git a/src/librssguard/gui/feedsview.cpp b/src/librssguard/gui/feedsview.cpp index 324cd6b7f..75e06e964 100644 --- a/src/librssguard/gui/feedsview.cpp +++ b/src/librssguard/gui/feedsview.cpp @@ -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, diff --git a/src/librssguard/gui/feedsview.h b/src/librssguard/gui/feedsview.h index a57caee9f..c91f3bb0f 100644 --- a/src/librssguard/gui/feedsview.h +++ b/src/librssguard/gui/feedsview.h @@ -61,6 +61,7 @@ class RSSGUARD_DLLSPEC FeedsView : public BaseTreeView { // Feed clearers. void clearSelectedItems(); void clearAllItems(); + void purgeSelectedFeeds(); // Base manipulators. void editItems(const QList& items); diff --git a/src/librssguard/services/abstract/feed.cpp b/src/librssguard/services/abstract/feed.cpp index 9d3e971bf..515f3d7e2 100644 --- a/src/librssguard/services/abstract/feed.cpp +++ b/src/librssguard/services/abstract/feed.cpp @@ -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; } diff --git a/src/librssguard/services/abstract/feed.h b/src/librssguard/services/abstract/feed.h index 787e4ece9..6111872a3 100644 --- a/src/librssguard/services/abstract/feed.h +++ b/src/librssguard/services/abstract/feed.h @@ -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);