diff --git a/src/base/preferences.cpp b/src/base/preferences.cpp index c8cd49d1d..24cdba49c 100644 --- a/src/base/preferences.cpp +++ b/src/base/preferences.cpp @@ -451,6 +451,19 @@ void Preferences::setPreventFromSuspendWhenSeeding(const bool b) setValue(u"Preferences/General/PreventFromSuspendWhenSeeding"_s, b); } +bool Preferences::usePerStatusSortOrder() const +{ + return value(u"Preferences/General/UsePerStatusSortOrder"_s, false); +} + +void Preferences::setUsePerStatusSortOrder(const bool use) +{ + if (use == usePerStatusSortOrder()) + return; + + setValue(u"Preferences/General/UsePerStatusSortOrder"_s, use); +} + #ifdef Q_OS_WIN bool Preferences::WinStartup() const { diff --git a/src/base/preferences.h b/src/base/preferences.h index 0da55ab99..d76a2627c 100644 --- a/src/base/preferences.h +++ b/src/base/preferences.h @@ -166,6 +166,9 @@ public: int getActionOnDblClOnTorrentFn() const; void setActionOnDblClOnTorrentFn(int act); + bool usePerStatusSortOrder() const; + void setUsePerStatusSortOrder(bool use); + // Connection options QTime getSchedulerStartTime() const; void setSchedulerStartTime(const QTime &time); diff --git a/src/base/torrentfilter.h b/src/base/torrentfilter.h index 39fd3e06f..280db3302 100644 --- a/src/base/torrentfilter.h +++ b/src/base/torrentfilter.h @@ -100,6 +100,7 @@ public: bool setType(Type type); + Type getType() const { return m_type; } bool setTypeByName(const QString &filter); bool setTorrentIDSet(const std::optional &idSet); bool setCategory(const std::optional &category); diff --git a/src/gui/optionsdialog.cpp b/src/gui/optionsdialog.cpp index ad2eb348b..59429e825 100644 --- a/src/gui/optionsdialog.cpp +++ b/src/gui/optionsdialog.cpp @@ -361,6 +361,7 @@ void OptionsDialog::loadBehaviorTabOptions() m_ui->checkBoxFreeDiskSpaceStatusBar->setChecked(pref->isStatusbarFreeDiskSpaceDisplayed()); m_ui->checkBoxExternalIPStatusBar->setChecked(pref->isStatusbarExternalIPDisplayed()); m_ui->checkBoxPerformanceWarning->setChecked(session->isPerformanceWarningEnabled()); + m_ui->checkBoxPerFilterSorting->setChecked(pref->usePerStatusSortOrder()); connect(m_ui->comboLanguage, qComboBoxCurrentIndexChanged, this, &ThisType::enableApplyButton); @@ -453,6 +454,7 @@ void OptionsDialog::loadBehaviorTabOptions() connect(m_ui->checkBoxFreeDiskSpaceStatusBar, &QAbstractButton::toggled, this, &ThisType::enableApplyButton); connect(m_ui->checkBoxExternalIPStatusBar, &QAbstractButton::toggled, this, &ThisType::enableApplyButton); connect(m_ui->checkBoxPerformanceWarning, &QAbstractButton::toggled, this, &ThisType::enableApplyButton); + connect(m_ui->checkBoxPerFilterSorting, &QAbstractButton::toggled, this, &ThisType::enableApplyButton); } void OptionsDialog::saveBehaviorTabOptions() const @@ -548,6 +550,7 @@ void OptionsDialog::saveBehaviorTabOptions() const pref->setStatusbarFreeDiskSpaceDisplayed(m_ui->checkBoxFreeDiskSpaceStatusBar->isChecked()); pref->setStatusbarExternalIPDisplayed(m_ui->checkBoxExternalIPStatusBar->isChecked()); + pref->setUsePerStatusSortOrder(m_ui->checkBoxPerFilterSorting->isChecked()); session->setPerformanceWarningEnabled(m_ui->checkBoxPerformanceWarning->isChecked()); } diff --git a/src/gui/optionsdialog.ui b/src/gui/optionsdialog.ui index a0afed167..81dd10aca 100644 --- a/src/gui/optionsdialog.ui +++ b/src/gui/optionsdialog.ui @@ -871,6 +871,13 @@ + + + + Use Per-Status Sorting + + + diff --git a/src/gui/transferlistsortmodel.cpp b/src/gui/transferlistsortmodel.cpp index 782aead74..5a2eb04d9 100644 --- a/src/gui/transferlistsortmodel.cpp +++ b/src/gui/transferlistsortmodel.cpp @@ -123,6 +123,11 @@ void TransferListSortModel::sort(const int column, const Qt::SortOrder order) QSortFilterProxyModel::sort(column, order); } +TorrentFilter::Type TransferListSortModel::getType() const +{ + return m_filter.getType(); +} + void TransferListSortModel::setStatusFilter(const TorrentFilter::Type filter) { if (m_filter.setType(filter)) diff --git a/src/gui/transferlistsortmodel.h b/src/gui/transferlistsortmodel.h index 3b3a59694..b791a04a9 100644 --- a/src/gui/transferlistsortmodel.h +++ b/src/gui/transferlistsortmodel.h @@ -56,6 +56,7 @@ public: void disableTagFilter(); void setTrackerFilter(const QSet &torrentIDs); void disableTrackerFilter(); + TorrentFilter::Type getType() const; private: int compare(const QModelIndex &left, const QModelIndex &right) const; diff --git a/src/gui/transferlistwidget.cpp b/src/gui/transferlistwidget.cpp index b2ed64ee7..7811bf0d6 100644 --- a/src/gui/transferlistwidget.cpp +++ b/src/gui/transferlistwidget.cpp @@ -1339,7 +1339,26 @@ void TransferListWidget::applyFilter(const QString &name, const TransferListMode void TransferListWidget::applyStatusFilter(const int filterIndex) { const auto filterType = static_cast(filterIndex); + //Save sort order for old filter + const bool usePerFilterSort = Preferences::instance()->usePerStatusSortOrder(); + const TorrentFilter::Type filter = m_sortFilterModel->getType(); + const int column = m_sortFilterModel->sortColumn(); + if (column != -1 && usePerFilterSort) + { + m_statusSortPairs[filter] = qMakePair(column, m_sortFilterModel->sortOrder()); + } + m_sortFilterModel->setStatusFilter(((filterType >= TorrentFilter::All) && (filterType < TorrentFilter::_Count)) ? filterType : TorrentFilter::All); + + // Load sort for new status filter + if (m_statusSortPairs.contains(filterType) && usePerFilterSort) + { + const QPair sortPair = m_statusSortPairs.value(filterType); + m_sortFilterModel->sort(sortPair.first, sortPair.second); + // Rows are sorted correctly, but header state does not reflect actual sort setting + header()->setSortIndicator(sortPair.first, sortPair.second); + } + // Select first item if nothing is selected if (selectionModel()->selectedRows(0).empty() && (m_sortFilterModel->rowCount() > 0)) { diff --git a/src/gui/transferlistwidget.h b/src/gui/transferlistwidget.h index 097dd809a..f62080f2b 100644 --- a/src/gui/transferlistwidget.h +++ b/src/gui/transferlistwidget.h @@ -35,6 +35,7 @@ #include #include "base/bittorrent/infohash.h" +#include "base/torrentfilter.h" #include "guiapplicationcomponent.h" #include "transferlistmodel.h" @@ -137,6 +138,7 @@ private: void applyToSelectedTorrents(const std::function &fn); QList getVisibleTorrents() const; int visibleColumnsCount() const; + QHash> m_statusSortPairs; TransferListModel *m_listModel = nullptr; TransferListSortModel *m_sortFilterModel = nullptr; diff --git a/src/webui/api/appcontroller.cpp b/src/webui/api/appcontroller.cpp index e2e465acd..378b3ced3 100644 --- a/src/webui/api/appcontroller.cpp +++ b/src/webui/api/appcontroller.cpp @@ -144,6 +144,7 @@ void AppController::preferencesAction() data[u"locale"_s] = pref->getLocale(); data[u"performance_warning"_s] = session->isPerformanceWarningEnabled(); data[u"status_bar_external_ip"_s] = pref->isStatusbarExternalIPDisplayed(); + data[u"per_status_sorting"_s] = pref->usePerStatusSortOrder(); // Transfer List data[u"confirm_torrent_deletion"_s] = pref->confirmTorrentDeletion(); // Log file @@ -537,6 +538,8 @@ void AppController::setPreferencesAction() pref->setStatusbarExternalIPDisplayed(it.value().toBool()); if (hasKey(u"performance_warning"_s)) session->setPerformanceWarningEnabled(it.value().toBool()); + if (hasKey(u"per_status_sorting"_s)) + pref->setUsePerStatusSortOrder(it.value().toBool()); // Transfer List if (hasKey(u"confirm_torrent_deletion"_s)) pref->setConfirmTorrentDeletion(it.value().toBool()); diff --git a/src/webui/www/private/scripts/client.js b/src/webui/www/private/scripts/client.js index 4c17cb5b1..bbe1f72c1 100644 --- a/src/webui/www/private/scripts/client.js +++ b/src/webui/www/private/scripts/client.js @@ -352,8 +352,24 @@ window.addEventListener("DOMContentLoaded", (event) => { setStatusFilter = (name) => { const currentHash = torrentsTable.getCurrentTorrentID(); + const usePerFilterSorting = window.qBittorrent.Cache.preferences.get().per_status_sorting; + // Save current sorting for this filter. + if ((torrentsTable.getSortedColumn()) && usePerFilterSorting) { + LocalPreferences.set(`selected_filter_sort_${selectedStatus}`, torrentsTable.getSortedColumn()); + LocalPreferences.set(`selected_filter_sort_reverse_${selectedStatus}`, (torrentsTable.reverseSort ?? "0")); + } LocalPreferences.set("selected_filter", name); + + // If there is a saved sorting column, load it. + const sortColumn = LocalPreferences.get(`selected_filter_sort_${name}`); + if ((sortColumn !== null) && usePerFilterSorting) { + torrentsTable.setSortedColumn( + sortColumn, + LocalPreferences.get(`selected_filter_sort_reverse_${name}`, "0") + ); + } + selectedStatus = name; highlightSelectedStatus(); updateMainData(); diff --git a/src/webui/www/private/scripts/dynamicTable.js b/src/webui/www/private/scripts/dynamicTable.js index aacdb5f5d..7baeecba4 100644 --- a/src/webui/www/private/scripts/dynamicTable.js +++ b/src/webui/www/private/scripts/dynamicTable.js @@ -687,7 +687,7 @@ window.qBittorrent.DynamicTable ??= (() => { const oldColumn = this.sortedColumn; this.sortedColumn = column; this.reverseSort = reverse ?? "0"; - this.setSortedColumnIcon(column, oldColumn, false); + this.setSortedColumnIcon(column, oldColumn, (reverse === "1")); } else { // Toggle sort order diff --git a/src/webui/www/private/views/preferences.html b/src/webui/www/private/views/preferences.html index b2e81856f..69e3f7c09 100644 --- a/src/webui/www/private/views/preferences.html +++ b/src/webui/www/private/views/preferences.html @@ -109,6 +109,11 @@ +
+ + +
+
QBT_TR(Custom WebUI settings)QBT_TR[CONTEXT=OptionsDialog]
@@ -2236,6 +2241,7 @@ Use ';' to split multiple entries. Can use wildcard '*'.)QBT_TR[CONTEXT=OptionsD updateColoSchemeSelect(); document.getElementById("statusBarExternalIP").checked = pref.status_bar_external_ip; document.getElementById("performanceWarning").checked = pref.performance_warning; + document.getElementById("perStatusSorting").checked = pref.per_status_sorting; document.getElementById("displayFullURLTrackerColumn").checked = (LocalPreferences.get("full_url_tracker_column", "false") === "true"); document.getElementById("useVirtualList").checked = (LocalPreferences.get("use_virtual_list", "false") === "true"); document.getElementById("hideZeroFiltersCheckbox").checked = (LocalPreferences.get("hide_zero_status_filters", "false") === "true"); @@ -2670,6 +2676,7 @@ Use ';' to split multiple entries. Can use wildcard '*'.)QBT_TR[CONTEXT=OptionsD LocalPreferences.set("color_scheme", "dark"); settings["status_bar_external_ip"] = document.getElementById("statusBarExternalIP").checked; settings["performance_warning"] = document.getElementById("performanceWarning").checked; + settings["per_status_sorting"] = document.getElementById("perStatusSorting").checked; LocalPreferences.set("full_url_tracker_column", document.getElementById("displayFullURLTrackerColumn").checked.toString()); LocalPreferences.set("use_virtual_list", document.getElementById("useVirtualList").checked.toString()); LocalPreferences.set("hide_zero_status_filters", document.getElementById("hideZeroFiltersCheckbox").checked.toString());