diff --git a/src/librssguard/core/feedsmodel.cpp b/src/librssguard/core/feedsmodel.cpp
index a29e9fed8..b95758d01 100644
--- a/src/librssguard/core/feedsmodel.cpp
+++ b/src/librssguard/core/feedsmodel.cpp
@@ -455,6 +455,18 @@ void FeedsModel::changeSortOrder(RootItem* item, bool move_top, bool move_bottom
DatabaseQueries::moveItem(item, move_top, move_bottom, new_sort_order, db);
}
+void FeedsModel::sortDirectDescendants(RootItem* item, RootItem::Kind kind_to_sort) {
+ auto childs = item->childItems(kind_to_sort);
+
+ std::sort(childs.begin(), childs.end(), [](RootItem* lhs, RootItem* rhs) {
+ return lhs->title().compare(rhs->title(), Qt::CaseSensitivity::CaseInsensitive) < 0;
+ });
+
+ for (RootItem* it : childs) {
+ changeSortOrder(it, false, true);
+ }
+}
+
void FeedsModel::loadActivatedServiceAccounts() {
auto serv = qApp->feedReader()->feedServices();
diff --git a/src/librssguard/core/feedsmodel.h b/src/librssguard/core/feedsmodel.h
index 39e0c65c0..540f9b92d 100644
--- a/src/librssguard/core/feedsmodel.h
+++ b/src/librssguard/core/feedsmodel.h
@@ -107,6 +107,10 @@ class RSSGUARD_DLLSPEC FeedsModel : public QAbstractItemModel {
void changeSortOrder(RootItem* item, bool move_top, bool move_bottom, int new_sort_order = {});
+ // Takes direct descendants (but only categories or feeds)
+ // and rearranges them alphabetically.
+ void sortDirectDescendants(RootItem* item, RootItem::Kind kind_to_sort);
+
// Feeds operations.
bool markItemRead(RootItem* item, RootItem::ReadStatus read);
bool markItemCleared(RootItem* item, bool clean_read_only);
diff --git a/src/librssguard/gui/dialogs/formmain.cpp b/src/librssguard/gui/dialogs/formmain.cpp
index ccdb3c961..1e7028bb3 100644
--- a/src/librssguard/gui/dialogs/formmain.cpp
+++ b/src/librssguard/gui/dialogs/formmain.cpp
@@ -480,6 +480,8 @@ void FormMain::updateFeedButtonsAvailability() {
const bool service_selected = anything_selected && selected_item->kind() == RootItem::Kind::ServiceRoot;
const bool manual_feed_sort = !m_ui->m_actionSortFeedsAlphabetically->isChecked();
+ m_ui->m_actionRearrangeFeeds->setEnabled(manual_feed_sort && (service_selected || category_selected));
+ m_ui->m_actionRearrangeCategories->setEnabled(manual_feed_sort && (service_selected || category_selected));
m_ui->m_actionStopRunningItemsUpdate->setEnabled(is_update_running);
m_ui->m_actionBackupDatabaseSettings->setEnabled(!critical_action_running);
m_ui->m_actionCleanupDatabase->setEnabled(!critical_action_running);
@@ -892,6 +894,15 @@ void FormMain::createConnections() {
&QAction::triggered,
tabWidget()->feedMessageViewer()->feedsView(),
&FeedsView::updateSelectedItems);
+ connect(m_ui->m_actionRearrangeCategories,
+ &QAction::triggered,
+ tabWidget()->feedMessageViewer()->feedsView(),
+ &FeedsView::rearrangeCategoriesOfSelectedItem);
+ connect(m_ui->m_actionRearrangeFeeds,
+ &QAction::triggered,
+ tabWidget()->feedMessageViewer()->feedsView(),
+ &FeedsView::rearrangeFeedsOfSelectedItem);
+
connect(m_ui->m_actionUpdateAllItems, &QAction::triggered, qApp->feedReader(), &FeedReader::updateAllFeeds);
connect(m_ui->m_actionUpdateSelectedItemsWithCustomTimers,
&QAction::triggered,
diff --git a/src/librssguard/gui/dialogs/formmain.ui b/src/librssguard/gui/dialogs/formmain.ui
old mode 100644
new mode 100755
index 5c857a368..16cebce67
--- a/src/librssguard/gui/dialogs/formmain.ui
+++ b/src/librssguard/gui/dialogs/formmain.ui
@@ -128,6 +128,9 @@
+
+
+
@@ -918,6 +921,16 @@
Scroll &down browser
+
+
+ Rearrange &subcategories alphabetically
+
+
+
+
+ Rearrange &feeds alphabetically
+
+
diff --git a/src/librssguard/gui/feedsview.cpp b/src/librssguard/gui/feedsview.cpp
index c93dff8ce..2af3cf463 100644
--- a/src/librssguard/gui/feedsview.cpp
+++ b/src/librssguard/gui/feedsview.cpp
@@ -315,6 +315,16 @@ void FeedsView::moveSelectedItemDown() {
m_proxyModel->invalidate();
}
+void FeedsView::rearrangeCategoriesOfSelectedItem() {
+ m_sourceModel->sortDirectDescendants(selectedItem(), RootItem::Kind::Category);
+ m_proxyModel->invalidate();
+}
+
+void FeedsView::rearrangeFeedsOfSelectedItem() {
+ m_sourceModel->sortDirectDescendants(selectedItem(), RootItem::Kind::Feed);
+ m_proxyModel->invalidate();
+}
+
void FeedsView::markSelectedItemReadStatus(RootItem::ReadStatus read) {
m_sourceModel->markItemRead(selectedItem(), read);
}
@@ -469,6 +479,8 @@ QMenu* FeedsView::initializeContextMenuService(RootItem* clicked_item) {
qApp->mainForm()->m_ui->m_actionViewSelectedItemsNewspaperMode,
qApp->mainForm()->m_ui->m_actionExpandCollapseItem,
qApp->mainForm()->m_ui->m_actionExpandCollapseItemRecursively,
+ qApp->mainForm()->m_ui->m_actionRearrangeCategories,
+ qApp->mainForm()->m_ui->m_actionRearrangeFeeds,
qApp->mainForm()->m_ui->m_actionMarkSelectedItemsAsRead,
qApp->mainForm()->m_ui->m_actionMarkSelectedItemsAsUnread,
qApp->mainForm()->m_ui->m_actionDeleteSelectedItem});
@@ -691,6 +703,8 @@ QMenu* FeedsView::initializeContextMenuCategories(RootItem* clicked_item) {
qApp->mainForm()->m_ui->m_actionViewSelectedItemsNewspaperMode,
qApp->mainForm()->m_ui->m_actionExpandCollapseItem,
qApp->mainForm()->m_ui->m_actionExpandCollapseItemRecursively,
+ qApp->mainForm()->m_ui->m_actionRearrangeCategories,
+ qApp->mainForm()->m_ui->m_actionRearrangeFeeds,
qApp->mainForm()->m_ui->m_actionMarkSelectedItemsAsRead,
qApp->mainForm()->m_ui->m_actionMarkSelectedItemsAsUnread,
qApp->mainForm()->m_ui->m_actionDeleteSelectedItem});
diff --git a/src/librssguard/gui/feedsview.h b/src/librssguard/gui/feedsview.h
index 02ebfd87c..eae1fc1ef 100644
--- a/src/librssguard/gui/feedsview.h
+++ b/src/librssguard/gui/feedsview.h
@@ -72,6 +72,8 @@ class RSSGUARD_DLLSPEC FeedsView : public BaseTreeView {
void moveSelectedItemTop();
void moveSelectedItemBottom();
void moveSelectedItemDown();
+ void rearrangeCategoriesOfSelectedItem();
+ void rearrangeFeedsOfSelectedItem();
// Selects next/previous item (feed/category) in the list.
void selectNextItem();
diff --git a/src/librssguard/services/abstract/rootitem.cpp b/src/librssguard/services/abstract/rootitem.cpp
index 52f6df9d7..ca7fb431f 100644
--- a/src/librssguard/services/abstract/rootitem.cpp
+++ b/src/librssguard/services/abstract/rootitem.cpp
@@ -639,3 +639,13 @@ RootItem::Kind operator|(RootItem::Kind a, RootItem::Kind b) {
RootItem::Kind operator&(RootItem::Kind a, RootItem::Kind b) {
return static_cast(static_cast(a) & static_cast(b));
}
+
+QList RootItem::childItems(Kind kind) const {
+ auto linq = boolinq::from(m_childItems)
+ .where([=](RootItem* it) {
+ return it->kind() == kind;
+ })
+ .toStdList();
+
+ return FROM_STD_LIST(QList, linq);
+}
diff --git a/src/librssguard/services/abstract/rootitem.h b/src/librssguard/services/abstract/rootitem.h
index de0fdf681..2a5a39a1a 100644
--- a/src/librssguard/services/abstract/rootitem.h
+++ b/src/librssguard/services/abstract/rootitem.h
@@ -112,6 +112,8 @@ class RSSGUARD_DLLSPEC RootItem : public QObject {
RootItem* child(int row);
int childCount() const;
void appendChild(RootItem* child);
+
+ QList childItems(RootItem::Kind kind) const;
QList childItems() const;
QList& childItems();