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/base/bittorrent/session.cpp b/src/base/bittorrent/session.cpp index 31035fabf..12c96fa77 100644 --- a/src/base/bittorrent/session.cpp +++ b/src/base/bittorrent/session.cpp @@ -4354,6 +4354,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); @@ -4361,6 +4364,7 @@ void Session::handleStateUpdateAlert(const lt::state_update_alert *p) continue; torrent->handleStateUpdate(status); + updatedTorrents.push_back(torrent); } m_torrentStatusReport = TorrentStatusReport(); @@ -4383,7 +4387,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/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/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))); } 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); } } diff --git a/src/gui/transferlistmodel.cpp b/src/gui/transferlistmodel.cpp index 66ea53667..99512be65 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,14 @@ 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(); - } + Q_ASSERT(!m_torrentMap.contains(torrent)); + + 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,29 +293,48 @@ 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); + Q_ASSERT(row >= 0); + + 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); + Q_ASSERT(row >= 0); + + 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); + + if (torrents.size() <= (m_torrentList.size() * 0.5)) { + for (BitTorrent::TorrentHandle *const torrent : torrents) { + const int row = m_torrentMap.value(torrent, -1); + Q_ASSERT(row >= 0); + + 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)); + } } // Static functions diff --git a/src/gui/transferlistmodel.h b/src/gui/transferlistmodel.h index 38ee85427..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; @@ -97,10 +97,11 @@ 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; + QList m_torrentList; // maps row number to torrent handle + QHash m_torrentMap; // maps torrent handle to row number }; #endif // TRANSFERLISTMODEL_H