From 60faba60ea622820249e8835990bdef7e2de8eac Mon Sep 17 00:00:00 2001 From: Chocobo1 Date: Sun, 21 Jul 2019 15:20:54 +0800 Subject: [PATCH 1/2] Add availability column Closes #1632. --- src/gui/transferlistdelegate.cpp | 12 ++++++++++++ src/gui/transferlistmodel.cpp | 7 +++++-- src/gui/transferlistmodel.h | 1 + src/webui/api/serialize/serialize_torrent.cpp | 1 + src/webui/api/serialize/serialize_torrent.h | 1 + src/webui/www/private/scripts/dynamicTable.js | 9 ++++++++- 6 files changed, 28 insertions(+), 3 deletions(-) diff --git a/src/gui/transferlistdelegate.cpp b/src/gui/transferlistdelegate.cpp index 59c9015cd..7cfbef768 100644 --- a/src/gui/transferlistdelegate.cpp +++ b/src/gui/transferlistdelegate.cpp @@ -192,6 +192,18 @@ void TransferListDelegate::paint(QPainter *painter, const QStyleOptionViewItem & QItemDelegate::drawDisplay(painter, opt, option.rect, elapsedString); } break; + + case TransferListModel::TR_AVAILABILITY: { + const qreal availability = index.data().toReal(); + if (hideValues && (availability <= 0)) + break; + + const QString availabilityStr = Utils::String::fromDouble(availability, 3); + opt.displayAlignment = (Qt::AlignRight | Qt::AlignVCenter); + QItemDelegate::drawDisplay(painter, opt, option.rect, availabilityStr); + } + break; + default: QItemDelegate::paint(painter, option, index); } diff --git a/src/gui/transferlistmodel.cpp b/src/gui/transferlistmodel.cpp index 8b571c895..7c79e8528 100644 --- a/src/gui/transferlistmodel.cpp +++ b/src/gui/transferlistmodel.cpp @@ -124,8 +124,8 @@ QVariant TransferListModel::headerData(int section, Qt::Orientation orientation, case TR_SEEN_COMPLETE_DATE: return tr("Last Seen Complete", "Indicates the time when the torrent was last seen complete/whole"); case TR_LAST_ACTIVITY: return tr("Last Activity", "Time passed since a chunk was downloaded/uploaded"); case TR_TOTAL_SIZE: return tr("Total Size", "i.e. Size including unwanted data"); - default: - return {}; + case TR_AVAILABILITY: return tr("Availability", "The number of distributed copies of the torrent"); + default: return {}; } } else if (role == Qt::TextAlignmentRole) { @@ -149,6 +149,7 @@ QVariant TransferListModel::headerData(int section, Qt::Orientation orientation, case TR_RATIO: case TR_QUEUE_POSITION: case TR_LAST_ACTIVITY: + case TR_AVAILABILITY: return QVariant(Qt::AlignRight | Qt::AlignVCenter); default: return QAbstractListModel::headerData(section, orientation, role); @@ -239,6 +240,8 @@ QVariant TransferListModel::data(const QModelIndex &index, int role) const if (torrent->isPaused() || torrent->isChecking()) return -1; return torrent->timeSinceActivity(); + case TR_AVAILABILITY: + return torrent->distributedCopies(); case TR_TOTAL_SIZE: return torrent->totalSize(); } diff --git a/src/gui/transferlistmodel.h b/src/gui/transferlistmodel.h index 6fee78a69..38ee85427 100644 --- a/src/gui/transferlistmodel.h +++ b/src/gui/transferlistmodel.h @@ -77,6 +77,7 @@ public: TR_RATIO_LIMIT, TR_SEEN_COMPLETE_DATE, TR_LAST_ACTIVITY, + TR_AVAILABILITY, NB_COLUMNS }; diff --git a/src/webui/api/serialize/serialize_torrent.cpp b/src/webui/api/serialize/serialize_torrent.cpp index ce0f7127b..655902607 100644 --- a/src/webui/api/serialize/serialize_torrent.cpp +++ b/src/webui/api/serialize/serialize_torrent.cpp @@ -125,6 +125,7 @@ QVariantMap serialize(const BitTorrent::TorrentHandle &torrent) ret[KEY_TORRENT_LAST_SEEN_COMPLETE_TIME] = torrent.lastSeenComplete().toTime_t(); ret[KEY_TORRENT_AUTO_TORRENT_MANAGEMENT] = torrent.isAutoTMMEnabled(); ret[KEY_TORRENT_TIME_ACTIVE] = torrent.activeTime(); + ret[KEY_TORRENT_AVAILABILITY] = torrent.distributedCopies(); if (torrent.isPaused() || torrent.isChecking()) { ret[KEY_TORRENT_LAST_ACTIVITY_TIME] = 0; diff --git a/src/webui/api/serialize/serialize_torrent.h b/src/webui/api/serialize/serialize_torrent.h index cb446ec76..b02c6574c 100644 --- a/src/webui/api/serialize/serialize_torrent.h +++ b/src/webui/api/serialize/serialize_torrent.h @@ -78,5 +78,6 @@ const char KEY_TORRENT_LAST_ACTIVITY_TIME[] = "last_activity"; const char KEY_TORRENT_TOTAL_SIZE[] = "total_size"; const char KEY_TORRENT_AUTO_TORRENT_MANAGEMENT[] = "auto_tmm"; const char KEY_TORRENT_TIME_ACTIVE[] = "time_active"; +const char KEY_TORRENT_AVAILABILITY[] = "availability"; QVariantMap serialize(const BitTorrent::TorrentHandle &torrent); diff --git a/src/webui/www/private/scripts/dynamicTable.js b/src/webui/www/private/scripts/dynamicTable.js index a3fc00421..0bd26e886 100644 --- a/src/webui/www/private/scripts/dynamicTable.js +++ b/src/webui/www/private/scripts/dynamicTable.js @@ -828,12 +828,12 @@ const TorrentsTable = new Class({ this.newColumn('max_ratio', '', 'QBT_TR(Ratio Limit)QBT_TR[CONTEXT=TransferListModel]', 100, false); this.newColumn('seen_complete', '', 'QBT_TR(Last Seen Complete)QBT_TR[CONTEXT=TransferListModel]', 100, false); this.newColumn('last_activity', '', 'QBT_TR(Last Activity)QBT_TR[CONTEXT=TransferListModel]', 100, false); + this.newColumn('availability', '', 'QBT_TR(Availability)QBT_TR[CONTEXT=TransferListModel]', 100, false); this.columns['state_icon'].onclick = ''; this.columns['state_icon'].dataProperties[0] = 'state'; this.columns['num_seeds'].dataProperties.push('num_complete'); - this.columns['num_leechs'].dataProperties.push('num_incomplete'); this.initColumnsFunctions(); @@ -1181,6 +1181,13 @@ const TorrentsTable = new Class({ td.set('html', time); td.set('title', time); }; + + // availability + this.columns['availability'].updateTd = function(td, row) { + const value = (Math.floor(1000 * this.getRowValue(row)) / 1000).toFixed(3); // Don't round up + td.set('html', value); + td.set('title', value); + }; }, applyFilter: function(row, filterName, categoryHash, tagHash, filterTerms) { From 19b8a52e44c78b0148c6619cdd2abcbef7254565 Mon Sep 17 00:00:00 2001 From: Chocobo1 Date: Mon, 22 Jul 2019 14:23:05 +0800 Subject: [PATCH 2/2] Add helper function to convert to fixed-point string --- src/webui/www/private/scripts/dynamicTable.js | 12 ++++-------- src/webui/www/private/scripts/misc.js | 6 ++++++ 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/webui/www/private/scripts/dynamicTable.js b/src/webui/www/private/scripts/dynamicTable.js index 0bd26e886..e4faa17c2 100644 --- a/src/webui/www/private/scripts/dynamicTable.js +++ b/src/webui/www/private/scripts/dynamicTable.js @@ -1092,13 +1092,9 @@ const TorrentsTable = new Class({ // ratio this.columns['ratio'].updateTd = function(td, row) { const ratio = this.getRowValue(row); - let html = null; - if (ratio == -1) - html = '∞'; - else - html = (Math.floor(100 * ratio) / 100).toFixed(2); //Don't round up - td.set('html', html); - td.set('title', html); + const string = (ratio === -1) ? '∞' : toFixedPointString(ratio, 2); + td.set('html', string); + td.set('title', string); }; // tags @@ -1184,7 +1180,7 @@ const TorrentsTable = new Class({ // availability this.columns['availability'].updateTd = function(td, row) { - const value = (Math.floor(1000 * this.getRowValue(row)) / 1000).toFixed(3); // Don't round up + const value = toFixedPointString(this.getRowValue(row), 3); td.set('html', value); td.set('title', value); }; diff --git a/src/webui/www/private/scripts/misc.js b/src/webui/www/private/scripts/misc.js index 537b7c908..589bb8548 100644 --- a/src/webui/www/private/scripts/misc.js +++ b/src/webui/www/private/scripts/misc.js @@ -161,3 +161,9 @@ function safeTrim(value) { throw e; } } + +function toFixedPointString(number, digits) { + // Do not round up number + const power = Math.pow(10, digits); + return (Math.floor(power * number) / power).toFixed(digits); +}