From 1f3bf75ffffa06b752e618b9b4b4c3f8055021e9 Mon Sep 17 00:00:00 2001 From: Chocobo1 Date: Sat, 17 Aug 2019 14:58:10 +0800 Subject: [PATCH 1/6] Better on-demand reloading of torrent data --- src/base/bittorrent/session.cpp | 6 +++++- src/base/bittorrent/session.h | 2 +- src/gui/transferlistmodel.cpp | 13 +++++++++++-- src/gui/transferlistmodel.h | 2 +- 4 files changed, 18 insertions(+), 5 deletions(-) diff --git a/src/base/bittorrent/session.cpp b/src/base/bittorrent/session.cpp index 0974ee5bc..2c9369c3c 100644 --- a/src/base/bittorrent/session.cpp +++ b/src/base/bittorrent/session.cpp @@ -4376,6 +4376,9 @@ void Session::handleSessionStatsAlert(const lt::session_stats_alert *p) void Session::handleStateUpdateAlert(const lt::state_update_alert *p) { + QVector updatedTorrents; + updatedTorrents.reserve(p->status.size()); + for (const lt::torrent_status &status : p->status) { TorrentHandle *const torrent = m_torrents.value(status.info_hash); @@ -4383,6 +4386,7 @@ void Session::handleStateUpdateAlert(const lt::state_update_alert *p) continue; torrent->handleStateUpdate(status); + updatedTorrents.push_back(torrent); } m_torrentStatusReport = TorrentStatusReport(); @@ -4405,7 +4409,7 @@ void Session::handleStateUpdateAlert(const lt::state_update_alert *p) ++m_torrentStatusReport.nbErrored; } - emit torrentsUpdated(); + emit torrentsUpdated(updatedTorrents); } namespace diff --git a/src/base/bittorrent/session.h b/src/base/bittorrent/session.h index 529f4e1b9..65959f6bb 100644 --- a/src/base/bittorrent/session.h +++ b/src/base/bittorrent/session.h @@ -450,7 +450,7 @@ namespace BitTorrent signals: void statsUpdated(); - void torrentsUpdated(); + void torrentsUpdated(const QVector &torrents); void addTorrentFailed(const QString &error); void torrentAdded(BitTorrent::TorrentHandle *const torrent); void torrentNew(BitTorrent::TorrentHandle *const torrent); diff --git a/src/gui/transferlistmodel.cpp b/src/gui/transferlistmodel.cpp index 66ea53667..2f21d3e48 100644 --- a/src/gui/transferlistmodel.cpp +++ b/src/gui/transferlistmodel.cpp @@ -315,9 +315,18 @@ void TransferListModel::handleTorrentStatusUpdated(BitTorrent::TorrentHandle *co emit dataChanged(index(row, 0), index(row, columnCount() - 1)); } -void TransferListModel::handleTorrentsUpdated() +void TransferListModel::handleTorrentsUpdated(const QVector &torrents) { - emit dataChanged(index(0, 0), index(rowCount() - 1, columnCount() - 1)); + const int columns = (columnCount() - 1); + + for (BitTorrent::TorrentHandle *const torrent : torrents) { + const int row = m_torrents.indexOf(torrent); + + if (row < 0) + continue; + + emit dataChanged(index(row, 0), index(row, columns)); + } } // Static functions diff --git a/src/gui/transferlistmodel.h b/src/gui/transferlistmodel.h index 38ee85427..10cbafc36 100644 --- a/src/gui/transferlistmodel.h +++ b/src/gui/transferlistmodel.h @@ -97,7 +97,7 @@ private slots: void addTorrent(BitTorrent::TorrentHandle *const torrent); void handleTorrentAboutToBeRemoved(BitTorrent::TorrentHandle *const torrent); void handleTorrentStatusUpdated(BitTorrent::TorrentHandle *const torrent); - void handleTorrentsUpdated(); + void handleTorrentsUpdated(const QVector &torrents); private: QList m_torrents; From e3483c62ca83499b54486590eaca9e48f6234f37 Mon Sep 17 00:00:00 2001 From: Chocobo1 Date: Sat, 17 Aug 2019 15:23:18 +0800 Subject: [PATCH 2/6] Remove explicit conversion to QVariant --- src/app/application.cpp | 2 +- src/gui/search/pluginselectdialog.cpp | 4 +-- src/gui/search/searchwidget.cpp | 12 +++---- src/gui/transferlistfilterswidget.cpp | 48 +++++++++++++-------------- 4 files changed, 33 insertions(+), 33 deletions(-) diff --git a/src/app/application.cpp b/src/app/application.cpp index 19b8823d2..3f7c177b9 100644 --- a/src/app/application.cpp +++ b/src/app/application.cpp @@ -203,7 +203,7 @@ void Application::setFileLoggerEnabled(const bool value) QString Application::fileLoggerPath() const { return settings()->loadValue(KEY_FILELOGGER_PATH, - QVariant(specialFolderLocation(SpecialFolder::Data) + LOG_FOLDER)).toString(); + {specialFolderLocation(SpecialFolder::Data) + LOG_FOLDER}).toString(); } void Application::setFileLoggerPath(const QString &path) diff --git a/src/gui/search/pluginselectdialog.cpp b/src/gui/search/pluginselectdialog.cpp index 7bfa2a6d3..f8c2a16d8 100644 --- a/src/gui/search/pluginselectdialog.cpp +++ b/src/gui/search/pluginselectdialog.cpp @@ -234,7 +234,7 @@ void PluginSelectDialog::setRowColor(const int row, const QString &color) { QTreeWidgetItem *item = m_ui->pluginsTree->topLevelItem(row); for (int i = 0; i < m_ui->pluginsTree->columnCount(); ++i) { - item->setData(i, Qt::ForegroundRole, QVariant(QColor(color))); + item->setData(i, Qt::ForegroundRole, QColor(color)); } } @@ -289,7 +289,7 @@ void PluginSelectDialog::addNewPlugin(const QString &pluginName) // Handle icon if (QFile::exists(plugin->iconPath)) { // Good, we already have the icon - item->setData(PLUGIN_NAME, Qt::DecorationRole, QVariant(QIcon(plugin->iconPath))); + item->setData(PLUGIN_NAME, Qt::DecorationRole, QIcon(plugin->iconPath)); } else { // Icon is missing, we must download it diff --git a/src/gui/search/searchwidget.cpp b/src/gui/search/searchwidget.cpp index c731f997e..7cef57390 100644 --- a/src/gui/search/searchwidget.cpp +++ b/src/gui/search/searchwidget.cpp @@ -144,7 +144,7 @@ SearchWidget::SearchWidget(MainWindow *mainWindow) void SearchWidget::fillCatCombobox() { m_ui->comboCategory->clear(); - m_ui->comboCategory->addItem(SearchPluginManager::categoryFullName("all"), QVariant("all")); + m_ui->comboCategory->addItem(SearchPluginManager::categoryFullName("all"), "all"); using QStrPair = QPair; QVector tmpList; @@ -154,7 +154,7 @@ void SearchWidget::fillCatCombobox() for (const QStrPair &p : asConst(tmpList)) { qDebug("Supported category: %s", qUtf8Printable(p.second)); - m_ui->comboCategory->addItem(p.first, QVariant(p.second)); + m_ui->comboCategory->addItem(p.first, p.second); } if (m_ui->comboCategory->count() > 1) @@ -164,9 +164,9 @@ void SearchWidget::fillCatCombobox() void SearchWidget::fillPluginComboBox() { m_ui->selectPlugin->clear(); - m_ui->selectPlugin->addItem(tr("Only enabled"), QVariant("enabled")); - m_ui->selectPlugin->addItem(tr("All plugins"), QVariant("all")); - m_ui->selectPlugin->addItem(tr("Select..."), QVariant("multi")); + m_ui->selectPlugin->addItem(tr("Only enabled"), "enabled"); + m_ui->selectPlugin->addItem(tr("All plugins"), "all"); + m_ui->selectPlugin->addItem(tr("Select..."), "multi"); using QStrPair = QPair; QVector tmpList; @@ -175,7 +175,7 @@ void SearchWidget::fillPluginComboBox() std::sort(tmpList.begin(), tmpList.end(), [](const QStrPair &l, const QStrPair &r) { return (l.first < r.first); } ); for (const QStrPair &p : asConst(tmpList)) - m_ui->selectPlugin->addItem(p.first, QVariant(p.second)); + m_ui->selectPlugin->addItem(p.first, p.second); if (m_ui->selectPlugin->count() > 3) m_ui->selectPlugin->insertSeparator(3); diff --git a/src/gui/transferlistfilterswidget.cpp b/src/gui/transferlistfilterswidget.cpp index 5e17ba8f6..36f556a2f 100644 --- a/src/gui/transferlistfilterswidget.cpp +++ b/src/gui/transferlistfilterswidget.cpp @@ -151,31 +151,31 @@ StatusFilterWidget::StatusFilterWidget(QWidget *parent, TransferListWidget *tran // Add status filters auto *all = new QListWidgetItem(this); - all->setData(Qt::DisplayRole, QVariant(tr("All (0)", "this is for the status filter"))); + all->setData(Qt::DisplayRole, tr("All (0)", "this is for the status filter")); all->setData(Qt::DecorationRole, QIcon(":/icons/skin/filterall.svg")); auto *downloading = new QListWidgetItem(this); - downloading->setData(Qt::DisplayRole, QVariant(tr("Downloading (0)"))); + downloading->setData(Qt::DisplayRole, tr("Downloading (0)")); downloading->setData(Qt::DecorationRole, QIcon(":/icons/skin/downloading.svg")); auto *seeding = new QListWidgetItem(this); - seeding->setData(Qt::DisplayRole, QVariant(tr("Seeding (0)"))); + seeding->setData(Qt::DisplayRole, tr("Seeding (0)")); seeding->setData(Qt::DecorationRole, QIcon(":/icons/skin/uploading.svg")); auto *completed = new QListWidgetItem(this); - completed->setData(Qt::DisplayRole, QVariant(tr("Completed (0)"))); + completed->setData(Qt::DisplayRole, tr("Completed (0)")); completed->setData(Qt::DecorationRole, QIcon(":/icons/skin/completed.svg")); auto *resumed = new QListWidgetItem(this); - resumed->setData(Qt::DisplayRole, QVariant(tr("Resumed (0)"))); + resumed->setData(Qt::DisplayRole, tr("Resumed (0)")); resumed->setData(Qt::DecorationRole, QIcon(":/icons/skin/resumed.svg")); auto *paused = new QListWidgetItem(this); - paused->setData(Qt::DisplayRole, QVariant(tr("Paused (0)"))); + paused->setData(Qt::DisplayRole, tr("Paused (0)")); paused->setData(Qt::DecorationRole, QIcon(":/icons/skin/paused.svg")); auto *active = new QListWidgetItem(this); - active->setData(Qt::DisplayRole, QVariant(tr("Active (0)"))); + active->setData(Qt::DisplayRole, tr("Active (0)")); active->setData(Qt::DecorationRole, QIcon(":/icons/skin/filteractive.svg")); auto *inactive = new QListWidgetItem(this); - inactive->setData(Qt::DisplayRole, QVariant(tr("Inactive (0)"))); + inactive->setData(Qt::DisplayRole, tr("Inactive (0)")); inactive->setData(Qt::DecorationRole, QIcon(":/icons/skin/filterinactive.svg")); auto *errored = new QListWidgetItem(this); - errored->setData(Qt::DisplayRole, QVariant(tr("Errored (0)"))); + errored->setData(Qt::DisplayRole, tr("Errored (0)")); errored->setData(Qt::DecorationRole, QIcon(":/icons/skin/error.svg")); const Preferences *const pref = Preferences::instance(); @@ -190,17 +190,17 @@ StatusFilterWidget::~StatusFilterWidget() void StatusFilterWidget::updateTorrentNumbers() { - auto report = BitTorrent::Session::instance()->torrentStatusReport(); + const BitTorrent::TorrentStatusReport report = BitTorrent::Session::instance()->torrentStatusReport(); - item(TorrentFilter::All)->setData(Qt::DisplayRole, QVariant(tr("All (%1)").arg(report.nbActive + report.nbInactive))); - item(TorrentFilter::Downloading)->setData(Qt::DisplayRole, QVariant(tr("Downloading (%1)").arg(report.nbDownloading))); - item(TorrentFilter::Seeding)->setData(Qt::DisplayRole, QVariant(tr("Seeding (%1)").arg(report.nbSeeding))); - item(TorrentFilter::Completed)->setData(Qt::DisplayRole, QVariant(tr("Completed (%1)").arg(report.nbCompleted))); - item(TorrentFilter::Paused)->setData(Qt::DisplayRole, QVariant(tr("Paused (%1)").arg(report.nbPaused))); - item(TorrentFilter::Resumed)->setData(Qt::DisplayRole, QVariant(tr("Resumed (%1)").arg(report.nbResumed))); - item(TorrentFilter::Active)->setData(Qt::DisplayRole, QVariant(tr("Active (%1)").arg(report.nbActive))); - item(TorrentFilter::Inactive)->setData(Qt::DisplayRole, QVariant(tr("Inactive (%1)").arg(report.nbInactive))); - item(TorrentFilter::Errored)->setData(Qt::DisplayRole, QVariant(tr("Errored (%1)").arg(report.nbErrored))); + item(TorrentFilter::All)->setData(Qt::DisplayRole, tr("All (%1)").arg(report.nbActive + report.nbInactive)); + item(TorrentFilter::Downloading)->setData(Qt::DisplayRole, tr("Downloading (%1)").arg(report.nbDownloading)); + item(TorrentFilter::Seeding)->setData(Qt::DisplayRole, tr("Seeding (%1)").arg(report.nbSeeding)); + item(TorrentFilter::Completed)->setData(Qt::DisplayRole, tr("Completed (%1)").arg(report.nbCompleted)); + item(TorrentFilter::Paused)->setData(Qt::DisplayRole, tr("Paused (%1)").arg(report.nbPaused)); + item(TorrentFilter::Resumed)->setData(Qt::DisplayRole, tr("Resumed (%1)").arg(report.nbResumed)); + item(TorrentFilter::Active)->setData(Qt::DisplayRole, tr("Active (%1)").arg(report.nbActive)); + item(TorrentFilter::Inactive)->setData(Qt::DisplayRole, tr("Inactive (%1)").arg(report.nbInactive)); + item(TorrentFilter::Errored)->setData(Qt::DisplayRole, tr("Errored (%1)").arg(report.nbErrored)); } void StatusFilterWidget::showMenu(const QPoint &) {} @@ -220,16 +220,16 @@ TrackerFiltersList::TrackerFiltersList(QWidget *parent, TransferListWidget *tran , m_downloadTrackerFavicon(downloadFavicon) { auto *allTrackers = new QListWidgetItem(this); - allTrackers->setData(Qt::DisplayRole, QVariant(tr("All (0)", "this is for the tracker filter"))); + allTrackers->setData(Qt::DisplayRole, tr("All (0)", "this is for the tracker filter")); allTrackers->setData(Qt::DecorationRole, UIThemeManager::instance()->getIcon("network-server")); auto *noTracker = new QListWidgetItem(this); - noTracker->setData(Qt::DisplayRole, QVariant(tr("Trackerless (0)"))); + noTracker->setData(Qt::DisplayRole, tr("Trackerless (0)")); noTracker->setData(Qt::DecorationRole, UIThemeManager::instance()->getIcon("network-server")); auto *errorTracker = new QListWidgetItem(this); - errorTracker->setData(Qt::DisplayRole, QVariant(tr("Error (0)"))); + errorTracker->setData(Qt::DisplayRole, tr("Error (0)")); errorTracker->setData(Qt::DecorationRole, style()->standardIcon(QStyle::SP_MessageBoxCritical)); auto *warningTracker = new QListWidgetItem(this); - warningTracker->setData(Qt::DisplayRole, QVariant(tr("Warning (0)"))); + warningTracker->setData(Qt::DisplayRole, tr("Warning (0)")); warningTracker->setData(Qt::DecorationRole, style()->standardIcon(QStyle::SP_MessageBoxWarning)); m_trackers.insert("", QStringList()); @@ -460,7 +460,7 @@ void TrackerFiltersList::handleFavicoDownloadFinished(const Net::DownloadResult Utils::Fs::forceRemove(result.filePath); } else { - trackerItem->setData(Qt::DecorationRole, QVariant(QIcon(result.filePath))); + trackerItem->setData(Qt::DecorationRole, QIcon(result.filePath)); m_iconPaths.append(result.filePath); } } From 9c964cdd978c6f5c113df9cc0ebd857a9ee4fd2f Mon Sep 17 00:00:00 2001 From: Chocobo1 Date: Sat, 17 Aug 2019 15:53:51 +0800 Subject: [PATCH 3/6] Fix using out-of-bounds of indexes --- src/gui/torrentcontentfiltermodel.cpp | 4 ++-- src/gui/torrentcontentmodel.cpp | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/gui/torrentcontentfiltermodel.cpp b/src/gui/torrentcontentfiltermodel.cpp index abb22ed4b..8f91b0711 100644 --- a/src/gui/torrentcontentfiltermodel.cpp +++ b/src/gui/torrentcontentfiltermodel.cpp @@ -107,7 +107,7 @@ void TorrentContentFilterModel::selectAll() for (int i = 0; i < rowCount(); ++i) setData(index(i, 0), Qt::Checked, Qt::CheckStateRole); - emit dataChanged(index(0,0), index(rowCount(), columnCount())); + emit dataChanged(index(0, 0), index((rowCount() - 1), (columnCount() - 1))); } void TorrentContentFilterModel::selectNone() @@ -115,7 +115,7 @@ void TorrentContentFilterModel::selectNone() for (int i = 0; i < rowCount(); ++i) setData(index(i, 0), Qt::Unchecked, Qt::CheckStateRole); - emit dataChanged(index(0,0), index(rowCount(), columnCount())); + emit dataChanged(index(0, 0), index((rowCount() - 1), (columnCount() - 1))); } bool TorrentContentFilterModel::hasFiltered(const QModelIndex &folder) const diff --git a/src/gui/torrentcontentmodel.cpp b/src/gui/torrentcontentmodel.cpp index e2ff20a04..9b4eff3dc 100644 --- a/src/gui/torrentcontentmodel.cpp +++ b/src/gui/torrentcontentmodel.cpp @@ -228,7 +228,7 @@ void TorrentContentModel::updateFilesProgress(const QVector &fp) // Update folders progress in the tree m_rootItem->recalculateProgress(); m_rootItem->recalculateAvailability(); - emit dataChanged(index(0, 0), index(rowCount(), columnCount())); + emit dataChanged(index(0, 0), index((rowCount() - 1), (columnCount() - 1))); } void TorrentContentModel::updateFilesPriorities(const QVector &fprio) @@ -241,7 +241,7 @@ void TorrentContentModel::updateFilesPriorities(const QVectorsetPriority(static_cast(fprio[i])); - emit dataChanged(index(0, 0), index(rowCount(), columnCount())); + emit dataChanged(index(0, 0), index((rowCount() - 1), (columnCount() - 1))); } void TorrentContentModel::updateFilesAvailability(const QVector &fa) @@ -255,7 +255,7 @@ void TorrentContentModel::updateFilesAvailability(const QVector &fa) m_filesIndex[i]->setAvailability(fa[i]); // Update folders progress in the tree m_rootItem->recalculateProgress(); - emit dataChanged(index(0, 0), index(rowCount(), columnCount())); + emit dataChanged(index(0, 0), index((rowCount() - 1), (columnCount() - 1))); } QVector TorrentContentModel::getFilePriorities() const @@ -302,7 +302,7 @@ bool TorrentContentModel::setData(const QModelIndex &index, const QVariant &valu // Update folders progress in the tree m_rootItem->recalculateProgress(); m_rootItem->recalculateAvailability(); - emit dataChanged(this->index(0, 0), this->index(rowCount() - 1, columnCount() - 1)); + emit dataChanged(this->index(0, 0), this->index((rowCount() - 1), (columnCount() - 1))); emit filteredFilesChanged(); } return true; @@ -502,12 +502,12 @@ void TorrentContentModel::selectAll() if (child->priority() == BitTorrent::DownloadPriority::Ignored) child->setPriority(BitTorrent::DownloadPriority::Normal); } - emit dataChanged(index(0, 0), index(rowCount(), columnCount())); + emit dataChanged(index(0, 0), index((rowCount() - 1), (columnCount() - 1))); } void TorrentContentModel::selectNone() { for (int i = 0; i < m_rootItem->childCount(); ++i) m_rootItem->child(i)->setPriority(BitTorrent::DownloadPriority::Ignored); - emit dataChanged(index(0, 0), index(rowCount(), columnCount())); + emit dataChanged(index(0, 0), index((rowCount() - 1), (columnCount() - 1))); } From 863c9f987681e29220f304079e04e0bc39a10a4d Mon Sep 17 00:00:00 2001 From: Chocobo1 Date: Sat, 17 Aug 2019 17:09:31 +0800 Subject: [PATCH 4/6] Speed up lookup operation in TransferListModel Previously lookup is O(n), add operation is O(n), remove operation is O(n). Now lookup is O(1), add operation is O(1), remove operation is O(n). n is the number of torrents already recorded. --- src/gui/transferlistmodel.cpp | 58 +++++++++++++++++++---------------- src/gui/transferlistmodel.h | 7 +++-- 2 files changed, 36 insertions(+), 29 deletions(-) diff --git a/src/gui/transferlistmodel.cpp b/src/gui/transferlistmodel.cpp index 2f21d3e48..0a65f220e 100644 --- a/src/gui/transferlistmodel.cpp +++ b/src/gui/transferlistmodel.cpp @@ -77,15 +77,13 @@ TransferListModel::TransferListModel(QObject *parent) connect(Session::instance(), &Session::torrentFinishedChecking, this, &TransferListModel::handleTorrentStatusUpdated); } -int TransferListModel::rowCount(const QModelIndex &index) const +int TransferListModel::rowCount(const QModelIndex &) const { - Q_UNUSED(index); - return m_torrents.size(); + return m_torrentList.size(); } -int TransferListModel::columnCount(const QModelIndex &parent) const +int TransferListModel::columnCount(const QModelIndex &) const { - Q_UNUSED(parent); return NB_COLUMNS; } @@ -164,7 +162,7 @@ QVariant TransferListModel::data(const QModelIndex &index, const int role) const { if (!index.isValid()) return {}; - const BitTorrent::TorrentHandle *torrent = m_torrents.value(index.row()); + const BitTorrent::TorrentHandle *torrent = m_torrentList.value(index.row()); if (!torrent) return {}; if ((role == Qt::DecorationRole) && (index.column() == TR_NAME)) @@ -251,11 +249,9 @@ QVariant TransferListModel::data(const QModelIndex &index, const int role) const bool TransferListModel::setData(const QModelIndex &index, const QVariant &value, int role) { - qDebug() << Q_FUNC_INFO << value; if (!index.isValid() || (role != Qt::DisplayRole)) return false; - qDebug("Index is valid and role is DisplayRole"); - BitTorrent::TorrentHandle *const torrent = m_torrents.value(index.row()); + BitTorrent::TorrentHandle *const torrent = m_torrentList.value(index.row()); if (!torrent) return false; // Category and Name columns can be edited @@ -275,12 +271,15 @@ bool TransferListModel::setData(const QModelIndex &index, const QVariant &value, void TransferListModel::addTorrent(BitTorrent::TorrentHandle *const torrent) { - if (!m_torrents.contains(torrent)) { - const int row = m_torrents.size(); - beginInsertRows(QModelIndex(), row, row); - m_torrents << torrent; - endInsertRows(); - } + if (m_torrentMap.contains(torrent)) + return; + + const int row = m_torrentList.size(); + + beginInsertRows({}, row, row); + m_torrentList << torrent; + m_torrentMap[torrent] = row; + endInsertRows(); } Qt::ItemFlags TransferListModel::flags(const QModelIndex &index) const @@ -295,32 +294,39 @@ BitTorrent::TorrentHandle *TransferListModel::torrentHandle(const QModelIndex &i { if (!index.isValid()) return nullptr; - return m_torrents.value(index.row()); + return m_torrentList.value(index.row()); } void TransferListModel::handleTorrentAboutToBeRemoved(BitTorrent::TorrentHandle *const torrent) { - const int row = m_torrents.indexOf(torrent); - if (row >= 0) { - beginRemoveRows(QModelIndex(), row, row); - m_torrents.removeAt(row); - endRemoveRows(); + const int row = m_torrentMap.value(torrent, -1); + if (row < 0) + return; + + beginRemoveRows({}, row, row); + m_torrentList.removeAt(row); + m_torrentMap.remove(torrent); + for (int &value : m_torrentMap) { + if (value > row) + --value; } + endRemoveRows(); } void TransferListModel::handleTorrentStatusUpdated(BitTorrent::TorrentHandle *const torrent) { - const int row = m_torrents.indexOf(torrent); - if (row >= 0) - emit dataChanged(index(row, 0), index(row, columnCount() - 1)); + const int row = m_torrentMap.value(torrent, -1); + if (row < 0) + return; + + emit dataChanged(index(row, 0), index(row, columnCount() - 1)); } void TransferListModel::handleTorrentsUpdated(const QVector &torrents) { const int columns = (columnCount() - 1); - for (BitTorrent::TorrentHandle *const torrent : torrents) { - const int row = m_torrents.indexOf(torrent); + const int row = m_torrentMap.value(torrent, -1); if (row < 0) continue; diff --git a/src/gui/transferlistmodel.h b/src/gui/transferlistmodel.h index 10cbafc36..22110b981 100644 --- a/src/gui/transferlistmodel.h +++ b/src/gui/transferlistmodel.h @@ -84,8 +84,8 @@ public: explicit TransferListModel(QObject *parent = nullptr); - int rowCount(const QModelIndex &index = {}) const override; - int columnCount(const QModelIndex &parent=QModelIndex()) const override; + int rowCount(const QModelIndex &parent = {}) const override; + int columnCount(const QModelIndex &parent = {}) const override; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; bool setData(const QModelIndex &index, const QVariant &value, int role) override; QVariant headerData(int section, Qt::Orientation orientation, int role) const override; @@ -100,7 +100,8 @@ private slots: void handleTorrentsUpdated(const QVector &torrents); private: - QList m_torrents; + QList m_torrentList; // maps row number to torrent handle + QHash m_torrentMap; // maps torrent handle to row number }; #endif // TRANSFERLISTMODEL_H From 72d1d5d2dd6d36308c49f83ed232aa414424cf11 Mon Sep 17 00:00:00 2001 From: Chocobo1 Date: Wed, 28 Aug 2019 15:32:21 +0800 Subject: [PATCH 5/6] Cut down number of signal emits --- src/gui/transferlistmodel.cpp | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/src/gui/transferlistmodel.cpp b/src/gui/transferlistmodel.cpp index 0a65f220e..370418779 100644 --- a/src/gui/transferlistmodel.cpp +++ b/src/gui/transferlistmodel.cpp @@ -325,13 +325,20 @@ void TransferListModel::handleTorrentStatusUpdated(BitTorrent::TorrentHandle *co void TransferListModel::handleTorrentsUpdated(const QVector &torrents) { const int columns = (columnCount() - 1); - for (BitTorrent::TorrentHandle *const torrent : torrents) { - const int row = m_torrentMap.value(torrent, -1); - if (row < 0) - continue; + if (torrents.size() <= (m_torrentList.size() * 0.5)) { + for (BitTorrent::TorrentHandle *const torrent : torrents) { + const int row = m_torrentMap.value(torrent, -1); - emit dataChanged(index(row, 0), index(row, columns)); + if (row < 0) + continue; + + emit dataChanged(index(row, 0), index(row, columns)); + } + } + else { + // save the overhead when more than half of the torrent list needs update + emit dataChanged(index(0, 0), index((rowCount() - 1), columns)); } } From b921d96f4b299e74e86a2cecf072b7d302d0b0f9 Mon Sep 17 00:00:00 2001 From: Chocobo1 Date: Wed, 28 Aug 2019 20:43:02 +0800 Subject: [PATCH 6/6] Use Q_ASSERT() to check invariants --- src/gui/transferlistmodel.cpp | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/src/gui/transferlistmodel.cpp b/src/gui/transferlistmodel.cpp index 370418779..99512be65 100644 --- a/src/gui/transferlistmodel.cpp +++ b/src/gui/transferlistmodel.cpp @@ -271,8 +271,7 @@ bool TransferListModel::setData(const QModelIndex &index, const QVariant &value, void TransferListModel::addTorrent(BitTorrent::TorrentHandle *const torrent) { - if (m_torrentMap.contains(torrent)) - return; + Q_ASSERT(!m_torrentMap.contains(torrent)); const int row = m_torrentList.size(); @@ -300,8 +299,7 @@ BitTorrent::TorrentHandle *TransferListModel::torrentHandle(const QModelIndex &i void TransferListModel::handleTorrentAboutToBeRemoved(BitTorrent::TorrentHandle *const torrent) { const int row = m_torrentMap.value(torrent, -1); - if (row < 0) - return; + Q_ASSERT(row >= 0); beginRemoveRows({}, row, row); m_torrentList.removeAt(row); @@ -316,8 +314,7 @@ void TransferListModel::handleTorrentAboutToBeRemoved(BitTorrent::TorrentHandle void TransferListModel::handleTorrentStatusUpdated(BitTorrent::TorrentHandle *const torrent) { const int row = m_torrentMap.value(torrent, -1); - if (row < 0) - return; + Q_ASSERT(row >= 0); emit dataChanged(index(row, 0), index(row, columnCount() - 1)); } @@ -329,9 +326,7 @@ void TransferListModel::handleTorrentsUpdated(const QVector= 0); emit dataChanged(index(row, 0), index(row, columns)); }