From ae74a1b9144007b3f9f8bdba4bab2f06dd3b3236 Mon Sep 17 00:00:00 2001 From: "Stiliyan Tonev (Bark)" Date: Thu, 9 Jan 2025 11:40:32 +0200 Subject: [PATCH 01/17] Feat: Add column that displays the percent of selected data from a torrent. --- src/gui/transferlistmodel.cpp | 6 +++++- src/gui/transferlistmodel.h | 1 + src/gui/transferlistsortmodel.cpp | 2 +- src/gui/transferlistwidget.cpp | 1 + src/webui/www/private/scripts/dynamicTable.js | 1 + 5 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/gui/transferlistmodel.cpp b/src/gui/transferlistmodel.cpp index 0298db047..f710dcd4d 100644 --- a/src/gui/transferlistmodel.cpp +++ b/src/gui/transferlistmodel.cpp @@ -194,6 +194,7 @@ QVariant TransferListModel::headerData(const int section, const Qt::Orientation case TR_INFOHASH_V2: return tr("Info Hash v2", "i.e: torrent info hash v2"); case TR_REANNOUNCE: return tr("Reannounce In", "Indicates the time until next trackers reannounce"); case TR_PRIVATE: return tr("Private", "Flags private torrents"); + case TR_PERCENT_SELECTED: return tr("% Selected", "Percentage of torrent selected"); default: return {}; } } @@ -443,8 +444,9 @@ QString TransferListModel::displayValue(const BitTorrent::Torrent *torrent, cons return reannounceString(torrent->nextAnnounce()); case TR_PRIVATE: return privateString(torrent->isPrivate(), torrent->hasMetadata()); + case TR_PERCENT_SELECTED: + return QString::number((torrent->wantedSize() * 100) / torrent->totalSize()) + u'%'; } - return {}; } @@ -526,6 +528,8 @@ QVariant TransferListModel::internalValue(const BitTorrent::Torrent *torrent, co return torrent->nextAnnounce(); case TR_PRIVATE: return (torrent->hasMetadata() ? torrent->isPrivate() : QVariant()); + case TR_PERCENT_SELECTED: + return (torrent->wantedSize() * 100) / torrent->totalSize(); } return {}; diff --git a/src/gui/transferlistmodel.h b/src/gui/transferlistmodel.h index 306beee0b..04f0b155d 100644 --- a/src/gui/transferlistmodel.h +++ b/src/gui/transferlistmodel.h @@ -87,6 +87,7 @@ public: TR_INFOHASH_V2, TR_REANNOUNCE, TR_PRIVATE, + TR_PERCENT_SELECTED, NB_COLUMNS }; diff --git a/src/gui/transferlistsortmodel.cpp b/src/gui/transferlistsortmodel.cpp index 782aead74..a097c4e1b 100644 --- a/src/gui/transferlistsortmodel.cpp +++ b/src/gui/transferlistsortmodel.cpp @@ -208,6 +208,7 @@ int TransferListSortModel::compare(const QModelIndex &left, const QModelIndex &r case TransferListModel::TR_RATIO: case TransferListModel::TR_RATIO_LIMIT: case TransferListModel::TR_POPULARITY: + case TransferListModel::TR_PERCENT_SELECTED: return customCompare(leftValue.toReal(), rightValue.toReal()); case TransferListModel::TR_STATUS: @@ -241,7 +242,6 @@ int TransferListSortModel::compare(const QModelIndex &left, const QModelIndex &r const auto totalR = right.data(TransferListModel::AdditionalUnderlyingDataRole).toInt(); return threeWayCompare(totalL, totalR); } - default: Q_ASSERT_X(false, Q_FUNC_INFO, "Missing comparison case"); break; diff --git a/src/gui/transferlistwidget.cpp b/src/gui/transferlistwidget.cpp index 6fb71bfaa..4f15b34a6 100644 --- a/src/gui/transferlistwidget.cpp +++ b/src/gui/transferlistwidget.cpp @@ -192,6 +192,7 @@ TransferListWidget::TransferListWidget(IGUIApplication *app, QWidget *parent) setColumnHidden(TransferListModel::TR_TOTAL_SIZE, true); setColumnHidden(TransferListModel::TR_REANNOUNCE, true); setColumnHidden(TransferListModel::TR_PRIVATE, true); + setColumnHidden(TransferListModel::TR_PERCENT_SELECTED, true); } //Ensure that at least one column is visible at all times diff --git a/src/webui/www/private/scripts/dynamicTable.js b/src/webui/www/private/scripts/dynamicTable.js index b0fa1a02e..3c7a828c4 100644 --- a/src/webui/www/private/scripts/dynamicTable.js +++ b/src/webui/www/private/scripts/dynamicTable.js @@ -1145,6 +1145,7 @@ window.qBittorrent.DynamicTable ??= (() => { this.newColumn("infohash_v2", "", "QBT_TR(Info Hash v2)QBT_TR[CONTEXT=TransferListModel]", 100, false); this.newColumn("reannounce", "", "QBT_TR(Reannounce In)QBT_TR[CONTEXT=TransferListModel]", 100, false); this.newColumn("private", "", "QBT_TR(Private)QBT_TR[CONTEXT=TransferListModel]", 100, false); + this.newColumn("percent_selected", "", "QBT_TR(Percent Selected)QBT_TR[CONTEXT=TransferListModel]", 100, false); this.columns["state_icon"].dataProperties[0] = "state"; this.columns["name"].dataProperties.push("state"); From 22e139d48d0a4eaa6e337b827f37bb202f61e573 Mon Sep 17 00:00:00 2001 From: "Stiliyan Tonev (Bark)" Date: Thu, 9 Jan 2025 11:42:15 +0200 Subject: [PATCH 02/17] return previosly deleted empty lines --- src/gui/transferlistmodel.cpp | 1 + src/gui/transferlistsortmodel.cpp | 1 + 2 files changed, 2 insertions(+) diff --git a/src/gui/transferlistmodel.cpp b/src/gui/transferlistmodel.cpp index f710dcd4d..dcc83dba5 100644 --- a/src/gui/transferlistmodel.cpp +++ b/src/gui/transferlistmodel.cpp @@ -447,6 +447,7 @@ QString TransferListModel::displayValue(const BitTorrent::Torrent *torrent, cons case TR_PERCENT_SELECTED: return QString::number((torrent->wantedSize() * 100) / torrent->totalSize()) + u'%'; } + return {}; } diff --git a/src/gui/transferlistsortmodel.cpp b/src/gui/transferlistsortmodel.cpp index a097c4e1b..ff0ad35a1 100644 --- a/src/gui/transferlistsortmodel.cpp +++ b/src/gui/transferlistsortmodel.cpp @@ -242,6 +242,7 @@ int TransferListSortModel::compare(const QModelIndex &left, const QModelIndex &r const auto totalR = right.data(TransferListModel::AdditionalUnderlyingDataRole).toInt(); return threeWayCompare(totalL, totalR); } + default: Q_ASSERT_X(false, Q_FUNC_INFO, "Missing comparison case"); break; From 44b0a59fde43b857b2379d7530cb6703941bcf88 Mon Sep 17 00:00:00 2001 From: "Stiliyan Tonev (Bark)" Date: Fri, 10 Jan 2025 10:43:21 +0200 Subject: [PATCH 03/17] Add metadata check and address PR comments. --- src/gui/transferlistmodel.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/gui/transferlistmodel.cpp b/src/gui/transferlistmodel.cpp index dcc83dba5..ecfe1842b 100644 --- a/src/gui/transferlistmodel.cpp +++ b/src/gui/transferlistmodel.cpp @@ -194,7 +194,7 @@ QVariant TransferListModel::headerData(const int section, const Qt::Orientation case TR_INFOHASH_V2: return tr("Info Hash v2", "i.e: torrent info hash v2"); case TR_REANNOUNCE: return tr("Reannounce In", "Indicates the time until next trackers reannounce"); case TR_PRIVATE: return tr("Private", "Flags private torrents"); - case TR_PERCENT_SELECTED: return tr("% Selected", "Percentage of torrent selected"); + case TR_PERCENT_SELECTED: return tr("% Selected Data", "Percentage of selected data to download."); default: return {}; } } @@ -445,6 +445,8 @@ QString TransferListModel::displayValue(const BitTorrent::Torrent *torrent, cons case TR_PRIVATE: return privateString(torrent->isPrivate(), torrent->hasMetadata()); case TR_PERCENT_SELECTED: + if (!torrent->hasMetadata()) + return tr("N/A"); return QString::number((torrent->wantedSize() * 100) / torrent->totalSize()) + u'%'; } @@ -530,6 +532,8 @@ QVariant TransferListModel::internalValue(const BitTorrent::Torrent *torrent, co case TR_PRIVATE: return (torrent->hasMetadata() ? torrent->isPrivate() : QVariant()); case TR_PERCENT_SELECTED: + if (!torrent->hasMetadata()) + return 0; return (torrent->wantedSize() * 100) / torrent->totalSize(); } From b70d8248540a9bed15c1675f6fbc521570426344 Mon Sep 17 00:00:00 2001 From: "Stiliyan Tonev (Bark)" Date: Fri, 10 Jan 2025 14:34:02 +0200 Subject: [PATCH 04/17] Pass number to WebUI instead of text and use float when comparing. --- src/gui/transferlistsortmodel.cpp | 4 +++- src/webui/api/serialize/serialize_torrent.cpp | 8 ++++++++ src/webui/www/private/scripts/dynamicTable.js | 12 ++++++++++++ 3 files changed, 23 insertions(+), 1 deletion(-) diff --git a/src/gui/transferlistsortmodel.cpp b/src/gui/transferlistsortmodel.cpp index ff0ad35a1..45199553d 100644 --- a/src/gui/transferlistsortmodel.cpp +++ b/src/gui/transferlistsortmodel.cpp @@ -208,7 +208,6 @@ int TransferListSortModel::compare(const QModelIndex &left, const QModelIndex &r case TransferListModel::TR_RATIO: case TransferListModel::TR_RATIO_LIMIT: case TransferListModel::TR_POPULARITY: - case TransferListModel::TR_PERCENT_SELECTED: return customCompare(leftValue.toReal(), rightValue.toReal()); case TransferListModel::TR_STATUS: @@ -243,6 +242,9 @@ int TransferListSortModel::compare(const QModelIndex &left, const QModelIndex &r return threeWayCompare(totalL, totalR); } + case TransferListModel::TR_PERCENT_SELECTED: + return customCompare(leftValue.toFloat(), rightValue.toFloat()); + default: Q_ASSERT_X(false, Q_FUNC_INFO, "Missing comparison case"); break; diff --git a/src/webui/api/serialize/serialize_torrent.cpp b/src/webui/api/serialize/serialize_torrent.cpp index 94c83a934..1515b55c7 100644 --- a/src/webui/api/serialize/serialize_torrent.cpp +++ b/src/webui/api/serialize/serialize_torrent.cpp @@ -178,6 +178,14 @@ QVariantMap serialize(const BitTorrent::Torrent &torrent) {KEY_TORRENT_LAST_ACTIVITY_TIME, getLastActivityTime()}, {KEY_TORRENT_AVAILABILITY, torrent.distributedCopies()}, {KEY_TORRENT_REANNOUNCE, torrent.nextAnnounce()}, +<<<<<<< HEAD {KEY_TORRENT_COMMENT, torrent.comment()} +======= + {KEY_TORRENT_COMMENT, torrent.comment()}, + {KEY_TORRENT_PRIVATE, (torrent.hasMetadata() ? torrent.isPrivate() : QVariant())}, + {KEY_TORRENT_TOTAL_SIZE, torrent.totalSize()}, + {KEY_TORRENT_HAS_METADATA, torrent.hasMetadata()}, + {KEY_TORRENT_PERCENT_SELECTED, torrent.hasMetadata() ? (torrent.wantedSize() * 100) / torrent.totalSize() : -1}, +>>>>>>> ba7b726ce (Pass number to WebUI instead of text and use float when comparing.) }; } diff --git a/src/webui/www/private/scripts/dynamicTable.js b/src/webui/www/private/scripts/dynamicTable.js index 3c7a828c4..6173942ce 100644 --- a/src/webui/www/private/scripts/dynamicTable.js +++ b/src/webui/www/private/scripts/dynamicTable.js @@ -1555,6 +1555,18 @@ window.qBittorrent.DynamicTable ??= (() => { td.textContent = string; td.title = string; }; + + // percent_selected + this.columns["percent_selected"].updateTd = function(td, row) { + if (this.getRowValue(row) === -1) { + td.textContent = "QBT_TR(N/A)QBT_TR[CONTEXT=TrackerListWidget]"; + td.title = "QBT_TR(N/A)QBT_TR[CONTEXT=TrackerListWidget]"; + return; + } + const value = window.qBittorrent.Misc.toFixedPointString(this.getRowValue(row), 2) + "%"; + td.textContent = value; + td.title = value; + }; } applyFilter(row, filterName, category, tag, trackerHost, filterTerms) { From aec3d827fc2ea15c5dc7e3bf030ec30f68db1854 Mon Sep 17 00:00:00 2001 From: "Stiliyan Tonev (Bark)" Date: Mon, 13 Jan 2025 16:24:58 +0200 Subject: [PATCH 05/17] Shorten column name --- src/gui/transferlistmodel.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/transferlistmodel.cpp b/src/gui/transferlistmodel.cpp index ecfe1842b..27e8f0322 100644 --- a/src/gui/transferlistmodel.cpp +++ b/src/gui/transferlistmodel.cpp @@ -194,7 +194,7 @@ QVariant TransferListModel::headerData(const int section, const Qt::Orientation case TR_INFOHASH_V2: return tr("Info Hash v2", "i.e: torrent info hash v2"); case TR_REANNOUNCE: return tr("Reannounce In", "Indicates the time until next trackers reannounce"); case TR_PRIVATE: return tr("Private", "Flags private torrents"); - case TR_PERCENT_SELECTED: return tr("% Selected Data", "Percentage of selected data to download."); + case TR_PERCENT_SELECTED: return tr("%", "Percentage of selected data to download."); default: return {}; } } From 91b4c0596a1f5061a2af0dbdac95134a84b319be Mon Sep 17 00:00:00 2001 From: "Stiliyan Tonev (Bark)" Date: Sat, 18 Jan 2025 09:49:46 +0200 Subject: [PATCH 06/17] Add tooltip and change webui column name. --- src/gui/transferlistmodel.cpp | 1 + src/webui/www/private/scripts/dynamicTable.js | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/gui/transferlistmodel.cpp b/src/gui/transferlistmodel.cpp index 27e8f0322..0b8771820 100644 --- a/src/gui/transferlistmodel.cpp +++ b/src/gui/transferlistmodel.cpp @@ -203,6 +203,7 @@ QVariant TransferListModel::headerData(const int section, const Qt::Orientation switch (section) { case TR_POPULARITY: return tr("Ratio / Time Active (in months), indicates how popular the torrent is"); + case TR_PERCENT_SELECTED: return tr("Wanted / Total size, indicates percentage of selected data to download."); default: return {}; } } diff --git a/src/webui/www/private/scripts/dynamicTable.js b/src/webui/www/private/scripts/dynamicTable.js index 6173942ce..5692d2b7e 100644 --- a/src/webui/www/private/scripts/dynamicTable.js +++ b/src/webui/www/private/scripts/dynamicTable.js @@ -1145,7 +1145,7 @@ window.qBittorrent.DynamicTable ??= (() => { this.newColumn("infohash_v2", "", "QBT_TR(Info Hash v2)QBT_TR[CONTEXT=TransferListModel]", 100, false); this.newColumn("reannounce", "", "QBT_TR(Reannounce In)QBT_TR[CONTEXT=TransferListModel]", 100, false); this.newColumn("private", "", "QBT_TR(Private)QBT_TR[CONTEXT=TransferListModel]", 100, false); - this.newColumn("percent_selected", "", "QBT_TR(Percent Selected)QBT_TR[CONTEXT=TransferListModel]", 100, false); + this.newColumn("percent_selected", "", "QBT_TR(%)QBT_TR[CONTEXT=TransferListModel]", 100, false); this.columns["state_icon"].dataProperties[0] = "state"; this.columns["name"].dataProperties.push("state"); From 8627058ff76842ad93f33064b13659d4e2c6a9e9 Mon Sep 17 00:00:00 2001 From: "Stiliyan Tonev (Bark)" Date: Mon, 31 Mar 2025 11:44:26 +0300 Subject: [PATCH 07/17] fix: use template instead of string concat, as suggested by linters. --- src/webui/www/private/scripts/dynamicTable.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/webui/www/private/scripts/dynamicTable.js b/src/webui/www/private/scripts/dynamicTable.js index 5692d2b7e..4d84d8ee3 100644 --- a/src/webui/www/private/scripts/dynamicTable.js +++ b/src/webui/www/private/scripts/dynamicTable.js @@ -1563,7 +1563,7 @@ window.qBittorrent.DynamicTable ??= (() => { td.title = "QBT_TR(N/A)QBT_TR[CONTEXT=TrackerListWidget]"; return; } - const value = window.qBittorrent.Misc.toFixedPointString(this.getRowValue(row), 2) + "%"; + const value = `${window.qBittorrent.Misc.toFixedPointString(this.getRowValue(row), 2) }%`; td.textContent = value; td.title = value; }; From 631197c4467a4c2c24018faa0db851013a165063 Mon Sep 17 00:00:00 2001 From: "Stiliyan Tonev (Bark)" Date: Tue, 22 Apr 2025 12:49:26 +0300 Subject: [PATCH 08/17] Resolve PR review comments. * Rebase and bump WEB version. * Use variable for row value in JS. * Prefer ternary operator instead of `if` clause. * use `static_cast` in order to work with real/decimal numbers. --- src/gui/transferlistmodel.cpp | 12 ++++-------- src/gui/transferlistsortmodel.cpp | 4 +--- src/webui/api/serialize/serialize_torrent.cpp | 8 -------- src/webui/www/private/scripts/dynamicTable.js | 5 +++-- 4 files changed, 8 insertions(+), 21 deletions(-) diff --git a/src/gui/transferlistmodel.cpp b/src/gui/transferlistmodel.cpp index 0b8771820..60e721922 100644 --- a/src/gui/transferlistmodel.cpp +++ b/src/gui/transferlistmodel.cpp @@ -194,7 +194,7 @@ QVariant TransferListModel::headerData(const int section, const Qt::Orientation case TR_INFOHASH_V2: return tr("Info Hash v2", "i.e: torrent info hash v2"); case TR_REANNOUNCE: return tr("Reannounce In", "Indicates the time until next trackers reannounce"); case TR_PRIVATE: return tr("Private", "Flags private torrents"); - case TR_PERCENT_SELECTED: return tr("%", "Percentage of selected data to download."); + case TR_PERCENT_SELECTED: return tr("%", "Percentage of selected data to download"); default: return {}; } } @@ -203,7 +203,7 @@ QVariant TransferListModel::headerData(const int section, const Qt::Orientation switch (section) { case TR_POPULARITY: return tr("Ratio / Time Active (in months), indicates how popular the torrent is"); - case TR_PERCENT_SELECTED: return tr("Wanted / Total size, indicates percentage of selected data to download."); + case TR_PERCENT_SELECTED: return tr("Wanted / Total size, indicates percentage of selected data to download"); default: return {}; } } @@ -446,9 +446,7 @@ QString TransferListModel::displayValue(const BitTorrent::Torrent *torrent, cons case TR_PRIVATE: return privateString(torrent->isPrivate(), torrent->hasMetadata()); case TR_PERCENT_SELECTED: - if (!torrent->hasMetadata()) - return tr("N/A"); - return QString::number((torrent->wantedSize() * 100) / torrent->totalSize()) + u'%'; + return torrent->hasMetadata() ? QString::number((static_cast(torrent->wantedSize()) * 100) / torrent->totalSize(), 'f', 2) + u'%' : tr("N/A"); } return {}; @@ -533,9 +531,7 @@ QVariant TransferListModel::internalValue(const BitTorrent::Torrent *torrent, co case TR_PRIVATE: return (torrent->hasMetadata() ? torrent->isPrivate() : QVariant()); case TR_PERCENT_SELECTED: - if (!torrent->hasMetadata()) - return 0; - return (torrent->wantedSize() * 100) / torrent->totalSize(); + return torrent->hasMetadata() ? (static_cast(torrent->wantedSize()) * 100) / torrent->totalSize() : 0; } return {}; diff --git a/src/gui/transferlistsortmodel.cpp b/src/gui/transferlistsortmodel.cpp index 45199553d..e71e00c5c 100644 --- a/src/gui/transferlistsortmodel.cpp +++ b/src/gui/transferlistsortmodel.cpp @@ -207,6 +207,7 @@ int TransferListSortModel::compare(const QModelIndex &left, const QModelIndex &r case TransferListModel::TR_PROGRESS: case TransferListModel::TR_RATIO: case TransferListModel::TR_RATIO_LIMIT: + case TransferListModel::TR_PERCENT_SELECTED: case TransferListModel::TR_POPULARITY: return customCompare(leftValue.toReal(), rightValue.toReal()); @@ -242,9 +243,6 @@ int TransferListSortModel::compare(const QModelIndex &left, const QModelIndex &r return threeWayCompare(totalL, totalR); } - case TransferListModel::TR_PERCENT_SELECTED: - return customCompare(leftValue.toFloat(), rightValue.toFloat()); - default: Q_ASSERT_X(false, Q_FUNC_INFO, "Missing comparison case"); break; diff --git a/src/webui/api/serialize/serialize_torrent.cpp b/src/webui/api/serialize/serialize_torrent.cpp index 1515b55c7..94c83a934 100644 --- a/src/webui/api/serialize/serialize_torrent.cpp +++ b/src/webui/api/serialize/serialize_torrent.cpp @@ -178,14 +178,6 @@ QVariantMap serialize(const BitTorrent::Torrent &torrent) {KEY_TORRENT_LAST_ACTIVITY_TIME, getLastActivityTime()}, {KEY_TORRENT_AVAILABILITY, torrent.distributedCopies()}, {KEY_TORRENT_REANNOUNCE, torrent.nextAnnounce()}, -<<<<<<< HEAD {KEY_TORRENT_COMMENT, torrent.comment()} -======= - {KEY_TORRENT_COMMENT, torrent.comment()}, - {KEY_TORRENT_PRIVATE, (torrent.hasMetadata() ? torrent.isPrivate() : QVariant())}, - {KEY_TORRENT_TOTAL_SIZE, torrent.totalSize()}, - {KEY_TORRENT_HAS_METADATA, torrent.hasMetadata()}, - {KEY_TORRENT_PERCENT_SELECTED, torrent.hasMetadata() ? (torrent.wantedSize() * 100) / torrent.totalSize() : -1}, ->>>>>>> ba7b726ce (Pass number to WebUI instead of text and use float when comparing.) }; } diff --git a/src/webui/www/private/scripts/dynamicTable.js b/src/webui/www/private/scripts/dynamicTable.js index 4d84d8ee3..7e4330228 100644 --- a/src/webui/www/private/scripts/dynamicTable.js +++ b/src/webui/www/private/scripts/dynamicTable.js @@ -1558,12 +1558,13 @@ window.qBittorrent.DynamicTable ??= (() => { // percent_selected this.columns["percent_selected"].updateTd = function(td, row) { - if (this.getRowValue(row) === -1) { + const percent = this.getRowValue(row); + if (percent === -1) { td.textContent = "QBT_TR(N/A)QBT_TR[CONTEXT=TrackerListWidget]"; td.title = "QBT_TR(N/A)QBT_TR[CONTEXT=TrackerListWidget]"; return; } - const value = `${window.qBittorrent.Misc.toFixedPointString(this.getRowValue(row), 2) }%`; + const value = `${window.qBittorrent.Misc.toFixedPointString(percent, 2) }%`; td.textContent = value; td.title = value; }; From 489ed9bcdc47249b953401ed6404db746f14c0ea Mon Sep 17 00:00:00 2001 From: "Stiliyan Tonev (Bark)" Date: Wed, 30 Apr 2025 15:29:04 +0300 Subject: [PATCH 09/17] fix issues pointed out in PR. * Multiple space in `js` left over after "linting"-it * Wrap percent + % symbol in brackets in order to separate it from the default value. * Multiple occurrences of unsorted `case` statements. --- src/gui/transferlistmodel.cpp | 8 ++++---- src/gui/transferlistsortmodel.cpp | 4 ++-- src/webui/www/private/scripts/dynamicTable.js | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/gui/transferlistmodel.cpp b/src/gui/transferlistmodel.cpp index 60e721922..1e9324cfc 100644 --- a/src/gui/transferlistmodel.cpp +++ b/src/gui/transferlistmodel.cpp @@ -193,8 +193,8 @@ QVariant TransferListModel::headerData(const int section, const Qt::Orientation case TR_INFOHASH_V1: return tr("Info Hash v1", "i.e: torrent info hash v1"); case TR_INFOHASH_V2: return tr("Info Hash v2", "i.e: torrent info hash v2"); case TR_REANNOUNCE: return tr("Reannounce In", "Indicates the time until next trackers reannounce"); - case TR_PRIVATE: return tr("Private", "Flags private torrents"); case TR_PERCENT_SELECTED: return tr("%", "Percentage of selected data to download"); + case TR_PRIVATE: return tr("Private", "Flags private torrents"); default: return {}; } } @@ -443,10 +443,10 @@ QString TransferListModel::displayValue(const BitTorrent::Torrent *torrent, cons return hashString(torrent->infoHash().v2()); case TR_REANNOUNCE: return reannounceString(torrent->nextAnnounce()); + case TR_PERCENT_SELECTED: + return torrent->hasMetadata() ? (QString::number((static_cast(torrent->wantedSize()) * 100) / torrent->totalSize(), 'f', 2) + u'%') : tr("N/A"); case TR_PRIVATE: return privateString(torrent->isPrivate(), torrent->hasMetadata()); - case TR_PERCENT_SELECTED: - return torrent->hasMetadata() ? QString::number((static_cast(torrent->wantedSize()) * 100) / torrent->totalSize(), 'f', 2) + u'%' : tr("N/A"); } return {}; @@ -531,7 +531,7 @@ QVariant TransferListModel::internalValue(const BitTorrent::Torrent *torrent, co case TR_PRIVATE: return (torrent->hasMetadata() ? torrent->isPrivate() : QVariant()); case TR_PERCENT_SELECTED: - return torrent->hasMetadata() ? (static_cast(torrent->wantedSize()) * 100) / torrent->totalSize() : 0; + return torrent->hasMetadata() ? ((static_cast(torrent->wantedSize()) * 100) / torrent->totalSize()) : 0; } return {}; diff --git a/src/gui/transferlistsortmodel.cpp b/src/gui/transferlistsortmodel.cpp index e71e00c5c..7a2eb13b0 100644 --- a/src/gui/transferlistsortmodel.cpp +++ b/src/gui/transferlistsortmodel.cpp @@ -204,11 +204,11 @@ int TransferListSortModel::compare(const QModelIndex &left, const QModelIndex &r return customCompare(leftValue.toLongLong(), rightValue.toLongLong()); case TransferListModel::TR_AVAILABILITY: + case TransferListModel::TR_PERCENT_SELECTED: + case TransferListModel::TR_POPULARITY: case TransferListModel::TR_PROGRESS: case TransferListModel::TR_RATIO: case TransferListModel::TR_RATIO_LIMIT: - case TransferListModel::TR_PERCENT_SELECTED: - case TransferListModel::TR_POPULARITY: return customCompare(leftValue.toReal(), rightValue.toReal()); case TransferListModel::TR_STATUS: diff --git a/src/webui/www/private/scripts/dynamicTable.js b/src/webui/www/private/scripts/dynamicTable.js index 7e4330228..5a3e7d645 100644 --- a/src/webui/www/private/scripts/dynamicTable.js +++ b/src/webui/www/private/scripts/dynamicTable.js @@ -1564,7 +1564,7 @@ window.qBittorrent.DynamicTable ??= (() => { td.title = "QBT_TR(N/A)QBT_TR[CONTEXT=TrackerListWidget]"; return; } - const value = `${window.qBittorrent.Misc.toFixedPointString(percent, 2) }%`; + const value = `${window.qBittorrent.Misc.toFixedPointString(percent, 2)}%`; td.textContent = value; td.title = value; }; From 5c3d32563049a64585acb883043db0afe2208af2 Mon Sep 17 00:00:00 2001 From: "Stiliyan Tonev (Bark)" Date: Fri, 9 May 2025 11:04:18 +0300 Subject: [PATCH 10/17] Fix case order --- src/gui/transferlistmodel.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/transferlistmodel.cpp b/src/gui/transferlistmodel.cpp index 1e9324cfc..229a9dd95 100644 --- a/src/gui/transferlistmodel.cpp +++ b/src/gui/transferlistmodel.cpp @@ -202,8 +202,8 @@ QVariant TransferListModel::headerData(const int section, const Qt::Orientation { switch (section) { - case TR_POPULARITY: return tr("Ratio / Time Active (in months), indicates how popular the torrent is"); case TR_PERCENT_SELECTED: return tr("Wanted / Total size, indicates percentage of selected data to download"); + case TR_POPULARITY: return tr("Ratio / Time Active (in months), indicates how popular the torrent is"); default: return {}; } } From 81cc05addf6fad73c60b87ccd6bff87f525a3860 Mon Sep 17 00:00:00 2001 From: "Stiliyan Tonev (Bark)" Date: Tue, 27 May 2025 11:44:38 +0300 Subject: [PATCH 11/17] refact: Remove new field from serializer and calculate in JS. --- src/webui/www/private/scripts/dynamicTable.js | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/webui/www/private/scripts/dynamicTable.js b/src/webui/www/private/scripts/dynamicTable.js index 5a3e7d645..603ea13b8 100644 --- a/src/webui/www/private/scripts/dynamicTable.js +++ b/src/webui/www/private/scripts/dynamicTable.js @@ -1005,8 +1005,7 @@ window.qBittorrent.DynamicTable ??= (() => { tds[i].style.width = `${this.columns[i].width}px`; tds[i].style.maxWidth = `${this.columns[i].width}px`; } - if (this.columns[i].dataProperties.some(prop => Object.hasOwn(data, prop))) - this.columns[i].updateTd(tds[i], row); + this.columns[i].updateTd(tds[i], row); } row["data"] = {}; } @@ -1558,7 +1557,13 @@ window.qBittorrent.DynamicTable ??= (() => { // percent_selected this.columns["percent_selected"].updateTd = function(td, row) { - const percent = this.getRowValue(row); + const fullData = row["full_data"]; + if (fullData["has_metadata"] === false) { + td.textContent = "QBT_TR(N/A)QBT_TR[CONTEXT=TrackerListWidget]"; + td.title = "QBT_TR(N/A)QBT_TR[CONTEXT=TrackerListWidget]"; + return; + } + const percent = (fullData["size"] / fullData["total_size"]) * 100; if (percent === -1) { td.textContent = "QBT_TR(N/A)QBT_TR[CONTEXT=TrackerListWidget]"; td.title = "QBT_TR(N/A)QBT_TR[CONTEXT=TrackerListWidget]"; From b9d3805a6500bb7f9c3ec8925078ef3e88a68814 Mon Sep 17 00:00:00 2001 From: "Stiliyan Tonev (Bark)" Date: Tue, 27 May 2025 14:12:57 +0300 Subject: [PATCH 12/17] refact: Return removed if and apply suggested improvements --- src/webui/www/private/scripts/dynamicTable.js | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/webui/www/private/scripts/dynamicTable.js b/src/webui/www/private/scripts/dynamicTable.js index 603ea13b8..f02ae0c8d 100644 --- a/src/webui/www/private/scripts/dynamicTable.js +++ b/src/webui/www/private/scripts/dynamicTable.js @@ -1005,7 +1005,8 @@ window.qBittorrent.DynamicTable ??= (() => { tds[i].style.width = `${this.columns[i].width}px`; tds[i].style.maxWidth = `${this.columns[i].width}px`; } - this.columns[i].updateTd(tds[i], row); + if (this.columns[i].dataProperties.some(prop => Object.hasOwn(data, prop))) + this.columns[i].updateTd(tds[i], row); } row["data"] = {}; } @@ -1151,6 +1152,7 @@ window.qBittorrent.DynamicTable ??= (() => { this.columns["num_seeds"].dataProperties.push("num_complete"); this.columns["num_leechs"].dataProperties.push("num_incomplete"); this.columns["time_active"].dataProperties.push("seeding_time"); + this.columns["percent_selected"].dataProperties = ["size", "total_size", "has_metadata"]; this.initColumnsFunctions(); } @@ -1557,13 +1559,15 @@ window.qBittorrent.DynamicTable ??= (() => { // percent_selected this.columns["percent_selected"].updateTd = function(td, row) { - const fullData = row["full_data"]; - if (fullData["has_metadata"] === false) { + const size = this.getRowValue(row, 0); + const totalSize = this.getRowValue(row, 1); + const hasMetadata = this.getRowValue(row, 2); + if (hasMetadata === false) { td.textContent = "QBT_TR(N/A)QBT_TR[CONTEXT=TrackerListWidget]"; td.title = "QBT_TR(N/A)QBT_TR[CONTEXT=TrackerListWidget]"; return; } - const percent = (fullData["size"] / fullData["total_size"]) * 100; + const percent = (size / totalSize) * 100; if (percent === -1) { td.textContent = "QBT_TR(N/A)QBT_TR[CONTEXT=TrackerListWidget]"; td.title = "QBT_TR(N/A)QBT_TR[CONTEXT=TrackerListWidget]"; From f20935b5c18cd91d2b38628f09cb3a2fea14feed Mon Sep 17 00:00:00 2001 From: "Stiliyan Tonev (Bark)" Date: Tue, 3 Jun 2025 14:06:25 +0300 Subject: [PATCH 13/17] refact: Changes regarding PR. * Rename column from `%` to `Size %`. * Fix broken row comparison/sorting for this column. * Reorder `dataProperties` as advised. * Reorder `if` and variable declarations, so we don't declare variables earlier than needed. --- src/gui/transferlistmodel.cpp | 2 +- src/webui/www/private/scripts/dynamicTable.js | 28 +++++++++++++++---- 2 files changed, 24 insertions(+), 6 deletions(-) diff --git a/src/gui/transferlistmodel.cpp b/src/gui/transferlistmodel.cpp index 229a9dd95..a446f412e 100644 --- a/src/gui/transferlistmodel.cpp +++ b/src/gui/transferlistmodel.cpp @@ -193,7 +193,7 @@ QVariant TransferListModel::headerData(const int section, const Qt::Orientation case TR_INFOHASH_V1: return tr("Info Hash v1", "i.e: torrent info hash v1"); case TR_INFOHASH_V2: return tr("Info Hash v2", "i.e: torrent info hash v2"); case TR_REANNOUNCE: return tr("Reannounce In", "Indicates the time until next trackers reannounce"); - case TR_PERCENT_SELECTED: return tr("%", "Percentage of selected data to download"); + case TR_PERCENT_SELECTED: return tr("Size %", "Percentage of selected data to download"); case TR_PRIVATE: return tr("Private", "Flags private torrents"); default: return {}; } diff --git a/src/webui/www/private/scripts/dynamicTable.js b/src/webui/www/private/scripts/dynamicTable.js index f02ae0c8d..3036a99da 100644 --- a/src/webui/www/private/scripts/dynamicTable.js +++ b/src/webui/www/private/scripts/dynamicTable.js @@ -1145,14 +1145,14 @@ window.qBittorrent.DynamicTable ??= (() => { this.newColumn("infohash_v2", "", "QBT_TR(Info Hash v2)QBT_TR[CONTEXT=TransferListModel]", 100, false); this.newColumn("reannounce", "", "QBT_TR(Reannounce In)QBT_TR[CONTEXT=TransferListModel]", 100, false); this.newColumn("private", "", "QBT_TR(Private)QBT_TR[CONTEXT=TransferListModel]", 100, false); - this.newColumn("percent_selected", "", "QBT_TR(%)QBT_TR[CONTEXT=TransferListModel]", 100, false); + this.newColumn("percent_selected", "", "QBT_TR(Size %)QBT_TR[CONTEXT=TransferListModel]", 100, false); this.columns["state_icon"].dataProperties[0] = "state"; this.columns["name"].dataProperties.push("state"); this.columns["num_seeds"].dataProperties.push("num_complete"); this.columns["num_leechs"].dataProperties.push("num_incomplete"); this.columns["time_active"].dataProperties.push("seeding_time"); - this.columns["percent_selected"].dataProperties = ["size", "total_size", "has_metadata"]; + this.columns["percent_selected"].dataProperties = ["has_metadata", "size", "total_size"]; this.initColumnsFunctions(); } @@ -1559,14 +1559,14 @@ window.qBittorrent.DynamicTable ??= (() => { // percent_selected this.columns["percent_selected"].updateTd = function(td, row) { - const size = this.getRowValue(row, 0); - const totalSize = this.getRowValue(row, 1); - const hasMetadata = this.getRowValue(row, 2); + const hasMetadata = this.getRowValue(row, 0); if (hasMetadata === false) { td.textContent = "QBT_TR(N/A)QBT_TR[CONTEXT=TrackerListWidget]"; td.title = "QBT_TR(N/A)QBT_TR[CONTEXT=TrackerListWidget]"; return; } + const size = this.getRowValue(row, 1); + const totalSize = this.getRowValue(row, 2); const percent = (size / totalSize) * 100; if (percent === -1) { td.textContent = "QBT_TR(N/A)QBT_TR[CONTEXT=TrackerListWidget]"; @@ -1577,6 +1577,24 @@ window.qBittorrent.DynamicTable ??= (() => { td.textContent = value; td.title = value; }; + this.columns["percent_selected"].compareRows = function(row1, row2) { + let percent1 = 0; + let percent2 = 0; + const hasMetadata1 = this.getRowValue(row1, 0); + if (hasMetadata1 !== false) { + const size1 = this.getRowValue(row1, 1); + const totalSize1 = this.getRowValue(row1, 2); + percent1 = (size1 / totalSize1) * 100; + } + const hasMetadata2 = this.getRowValue(row2, 0); + if (hasMetadata2 !== false) { + const size2 = this.getRowValue(row2, 1); + const totalSize2 = this.getRowValue(row2, 2); + percent2 = (size2 / totalSize2) * 100; + } + + return compareNumbers(percent1, percent2); + }; } applyFilter(row, filterName, category, tag, trackerHost, filterTerms) { From 1a9006c1d07f4725c3182e1613e1f48364825499 Mon Sep 17 00:00:00 2001 From: "Stiliyan Tonev (Bark)" Date: Tue, 3 Jun 2025 15:07:09 +0300 Subject: [PATCH 14/17] refact: Rename column to 'Selected' --- src/gui/transferlistmodel.cpp | 2 +- src/webui/www/private/scripts/dynamicTable.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/gui/transferlistmodel.cpp b/src/gui/transferlistmodel.cpp index a446f412e..83508d6f9 100644 --- a/src/gui/transferlistmodel.cpp +++ b/src/gui/transferlistmodel.cpp @@ -193,7 +193,7 @@ QVariant TransferListModel::headerData(const int section, const Qt::Orientation case TR_INFOHASH_V1: return tr("Info Hash v1", "i.e: torrent info hash v1"); case TR_INFOHASH_V2: return tr("Info Hash v2", "i.e: torrent info hash v2"); case TR_REANNOUNCE: return tr("Reannounce In", "Indicates the time until next trackers reannounce"); - case TR_PERCENT_SELECTED: return tr("Size %", "Percentage of selected data to download"); + case TR_PERCENT_SELECTED: return tr("Selected", "Percentage of selected data to download"); case TR_PRIVATE: return tr("Private", "Flags private torrents"); default: return {}; } diff --git a/src/webui/www/private/scripts/dynamicTable.js b/src/webui/www/private/scripts/dynamicTable.js index 3036a99da..c5b2e6390 100644 --- a/src/webui/www/private/scripts/dynamicTable.js +++ b/src/webui/www/private/scripts/dynamicTable.js @@ -1145,7 +1145,7 @@ window.qBittorrent.DynamicTable ??= (() => { this.newColumn("infohash_v2", "", "QBT_TR(Info Hash v2)QBT_TR[CONTEXT=TransferListModel]", 100, false); this.newColumn("reannounce", "", "QBT_TR(Reannounce In)QBT_TR[CONTEXT=TransferListModel]", 100, false); this.newColumn("private", "", "QBT_TR(Private)QBT_TR[CONTEXT=TransferListModel]", 100, false); - this.newColumn("percent_selected", "", "QBT_TR(Size %)QBT_TR[CONTEXT=TransferListModel]", 100, false); + this.newColumn("percent_selected", "", "QBT_TR(Selected)QBT_TR[CONTEXT=TransferListModel]", 100, false); this.columns["state_icon"].dataProperties[0] = "state"; this.columns["name"].dataProperties.push("state"); From f4b0c41c65eb5740bea768ee44db6440b12fb772 Mon Sep 17 00:00:00 2001 From: "Stiliyan Tonev (Bark)" Date: Tue, 10 Jun 2025 14:12:48 +0300 Subject: [PATCH 15/17] refact: Coding standard and additional checks * Add checks regarding `totalSize` so we don't get a division by 0 exception (Infinity more like) --- src/webui/www/private/scripts/dynamicTable.js | 42 +++++++++++-------- 1 file changed, 24 insertions(+), 18 deletions(-) diff --git a/src/webui/www/private/scripts/dynamicTable.js b/src/webui/www/private/scripts/dynamicTable.js index c5b2e6390..03ffebe40 100644 --- a/src/webui/www/private/scripts/dynamicTable.js +++ b/src/webui/www/private/scripts/dynamicTable.js @@ -1567,33 +1567,39 @@ window.qBittorrent.DynamicTable ??= (() => { } const size = this.getRowValue(row, 1); const totalSize = this.getRowValue(row, 2); - const percent = (size / totalSize) * 100; - if (percent === -1) { + if (totalSize <= 0) { td.textContent = "QBT_TR(N/A)QBT_TR[CONTEXT=TrackerListWidget]"; td.title = "QBT_TR(N/A)QBT_TR[CONTEXT=TrackerListWidget]"; return; } + const percent = (size / totalSize) * 100; const value = `${window.qBittorrent.Misc.toFixedPointString(percent, 2)}%`; td.textContent = value; td.title = value; }; - this.columns["percent_selected"].compareRows = function(row1, row2) { - let percent1 = 0; - let percent2 = 0; - const hasMetadata1 = this.getRowValue(row1, 0); - if (hasMetadata1 !== false) { - const size1 = this.getRowValue(row1, 1); - const totalSize1 = this.getRowValue(row1, 2); - percent1 = (size1 / totalSize1) * 100; - } - const hasMetadata2 = this.getRowValue(row2, 0); - if (hasMetadata2 !== false) { - const size2 = this.getRowValue(row2, 1); - const totalSize2 = this.getRowValue(row2, 2); - percent2 = (size2 / totalSize2) * 100; - } - return compareNumbers(percent1, percent2); + this.columns["percent_selected"].compareRows = function(row1, row2) { + const hasMetadata1 = this.getRowValue(row1, 0); + const hasMetadata2 = this.getRowValue(row2, 0); + + if (hasMetadata1 === true && hasMetadata2 === false) + return -1; + if (hasMetadata1 === false && hasMetadata2 === true) + return 1; + + const size1 = this.getRowValue(row1, 1); + const totalSize1 = this.getRowValue(row1, 2); + if (totalSize1 <= 0) + return 1; + const ratio1 = (size1 / totalSize1) * 100; + + const size2 = this.getRowValue(row2, 1); + const totalSize2 = this.getRowValue(row2, 2); + if (totalSize2 <= 0) + return -1; + const ratio2 = (size2 / totalSize2) * 100; + + return compareNumbers(ratio1, ratio2); }; } From 26b75fcebd994284ec87106baf3fe45bb8417cd5 Mon Sep 17 00:00:00 2001 From: "Stiliyan Tonev (Bark)" Date: Tue, 10 Jun 2025 15:17:22 +0300 Subject: [PATCH 16/17] fix: fixing mixing of === and && regarding linter --- src/webui/www/private/scripts/dynamicTable.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/webui/www/private/scripts/dynamicTable.js b/src/webui/www/private/scripts/dynamicTable.js index 03ffebe40..eb0247649 100644 --- a/src/webui/www/private/scripts/dynamicTable.js +++ b/src/webui/www/private/scripts/dynamicTable.js @@ -1582,9 +1582,9 @@ window.qBittorrent.DynamicTable ??= (() => { const hasMetadata1 = this.getRowValue(row1, 0); const hasMetadata2 = this.getRowValue(row2, 0); - if (hasMetadata1 === true && hasMetadata2 === false) + if ((hasMetadata1 === true) && (hasMetadata2 === false)) return -1; - if (hasMetadata1 === false && hasMetadata2 === true) + if ((hasMetadata1 === false) && (hasMetadata2 === true)) return 1; const size1 = this.getRowValue(row1, 1); From 8440d8e6c9b30eb27714c955eb6d5877b33ac58c Mon Sep 17 00:00:00 2001 From: "Stiliyan Tonev (Bark)" Date: Wed, 11 Jun 2025 13:48:58 +0300 Subject: [PATCH 17/17] refact: use short form comparison --- src/webui/www/private/scripts/dynamicTable.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/webui/www/private/scripts/dynamicTable.js b/src/webui/www/private/scripts/dynamicTable.js index eb0247649..eed4ee962 100644 --- a/src/webui/www/private/scripts/dynamicTable.js +++ b/src/webui/www/private/scripts/dynamicTable.js @@ -1560,7 +1560,7 @@ window.qBittorrent.DynamicTable ??= (() => { // percent_selected this.columns["percent_selected"].updateTd = function(td, row) { const hasMetadata = this.getRowValue(row, 0); - if (hasMetadata === false) { + if (!hasMetadata) { td.textContent = "QBT_TR(N/A)QBT_TR[CONTEXT=TrackerListWidget]"; td.title = "QBT_TR(N/A)QBT_TR[CONTEXT=TrackerListWidget]"; return; @@ -1582,9 +1582,9 @@ window.qBittorrent.DynamicTable ??= (() => { const hasMetadata1 = this.getRowValue(row1, 0); const hasMetadata2 = this.getRowValue(row2, 0); - if ((hasMetadata1 === true) && (hasMetadata2 === false)) + if (hasMetadata1 && !hasMetadata2) return -1; - if ((hasMetadata1 === false) && (hasMetadata2 === true)) + if (!hasMetadata1 && hasMetadata2) return 1; const size1 = this.getRowValue(row1, 1);