diff --git a/src/gui/transferlistwidget.cpp b/src/gui/transferlistwidget.cpp index b4006b399..441b3151d 100644 --- a/src/gui/transferlistwidget.cpp +++ b/src/gui/transferlistwidget.cpp @@ -501,6 +501,17 @@ QVector TransferListWidget::getSelectedTorrents() c return torrents; } +QVector TransferListWidget::getVisibleTorrents() const +{ + const int visibleTorrentsCount = m_sortFilterModel->rowCount(); + + QVector torrents; + torrents.reserve(visibleTorrentsCount); + for (int i = 0; i < visibleTorrentsCount; ++i) + torrents << m_listModel->torrentHandle(mapToSource(m_sortFilterModel->index(i, 0))); + return torrents; +} + void TransferListWidget::setSelectedTorrentsLocation() { const QVector torrents = getSelectedTorrents(); @@ -547,11 +558,8 @@ void TransferListWidget::forceStartSelectedTorrents() void TransferListWidget::startVisibleTorrents() { - for (int i = 0; i < m_sortFilterModel->rowCount(); ++i) { - BitTorrent::TorrentHandle *const torrent = m_listModel->torrentHandle(mapToSource(m_sortFilterModel->index(i, 0))); - if (torrent) - torrent->resume(); - } + for (BitTorrent::TorrentHandle *const torrent : asConst(getVisibleTorrents())) + torrent->resume(); } void TransferListWidget::pauseSelectedTorrents() @@ -562,11 +570,8 @@ void TransferListWidget::pauseSelectedTorrents() void TransferListWidget::pauseVisibleTorrents() { - for (int i = 0; i < m_sortFilterModel->rowCount(); ++i) { - BitTorrent::TorrentHandle *const torrent = m_listModel->torrentHandle(mapToSource(m_sortFilterModel->index(i, 0))); - if (torrent) - torrent->pause(); - } + for (BitTorrent::TorrentHandle *const torrent : asConst(getVisibleTorrents())) + torrent->pause(); } void TransferListWidget::softDeleteSelectedTorrents() @@ -589,9 +594,11 @@ void TransferListWidget::deleteSelectedTorrents(const bool deleteLocalFiles) if (Preferences::instance()->confirmTorrentDeletion()) { auto *dialog = new DeletionConfirmationDialog(this, torrents.size(), torrents[0]->name(), deleteLocalFiles); dialog->setAttribute(Qt::WA_DeleteOnClose); - connect(dialog, &DeletionConfirmationDialog::accepted, this, [dialog, torrents]() + connect(dialog, &DeletionConfirmationDialog::accepted, this, [this, dialog]() { - removeTorrents(torrents, dialog->isDeleteFileSelected()); + // Some torrents might be removed when waiting for user input, so refetch the torrent list + // NOTE: this will only work when dialog is modal + removeTorrents(getSelectedTorrents(), dialog->isDeleteFileSelected()); }); dialog->open(); } @@ -602,18 +609,17 @@ void TransferListWidget::deleteSelectedTorrents(const bool deleteLocalFiles) void TransferListWidget::deleteVisibleTorrents() { - if (m_sortFilterModel->rowCount() <= 0) return; - - QVector torrents; - for (int i = 0; i < m_sortFilterModel->rowCount(); ++i) - torrents << m_listModel->torrentHandle(mapToSource(m_sortFilterModel->index(i, 0))); + const QVector torrents = getVisibleTorrents(); + if (torrents.empty()) return; if (Preferences::instance()->confirmTorrentDeletion()) { auto *dialog = new DeletionConfirmationDialog(this, torrents.size(), torrents[0]->name(), false); dialog->setAttribute(Qt::WA_DeleteOnClose); - connect(dialog, &DeletionConfirmationDialog::accepted, this, [dialog, torrents]() + connect(dialog, &DeletionConfirmationDialog::accepted, this, [this, dialog]() { - removeTorrents(torrents, dialog->isDeleteFileSelected()); + // Some torrents might be removed when waiting for user input, so refetch the torrent list + // NOTE: this will only work when dialog is modal + removeTorrents(getVisibleTorrents(), dialog->isDeleteFileSelected()); }); dialog->open(); } diff --git a/src/gui/transferlistwidget.h b/src/gui/transferlistwidget.h index 889ae0d1c..166c8fcd9 100644 --- a/src/gui/transferlistwidget.h +++ b/src/gui/transferlistwidget.h @@ -141,6 +141,7 @@ private: void confirmRemoveAllTagsForSelection(); QStringList askTagsForSelection(const QString &dialogTitle); void applyToSelectedTorrents(const std::function &fn); + QVector getVisibleTorrents() const; // supposed to be used with qss only QColor unknownStateForeground() const; diff --git a/src/webui/api/torrentscontroller.cpp b/src/webui/api/torrentscontroller.cpp index d5b92a57c..787c071a4 100644 --- a/src/webui/api/torrentscontroller.cpp +++ b/src/webui/api/torrentscontroller.cpp @@ -320,11 +320,12 @@ void TorrentsController::propertiesAction() requireParams({"hash"}); const QString hash {params()["hash"]}; - QJsonObject dataDict; BitTorrent::TorrentHandle *const torrent = BitTorrent::Session::instance()->findTorrent(hash); if (!torrent) throw APIError(APIErrorType::NotFound); + QJsonObject dataDict; + dataDict[KEY_PROP_TIME_ELAPSED] = torrent->activeTime(); dataDict[KEY_PROP_SEEDING_TIME] = torrent->seedingTime(); dataDict[KEY_PROP_ETA] = static_cast(torrent->eta()); @@ -422,11 +423,11 @@ void TorrentsController::webseedsAction() requireParams({"hash"}); const QString hash {params()["hash"]}; - QJsonArray webSeedList; BitTorrent::TorrentHandle *const torrent = BitTorrent::Session::instance()->findTorrent(hash); if (!torrent) throw APIError(APIErrorType::NotFound); + QJsonArray webSeedList; for (const QUrl &webseed : asConst(torrent->urlSeeds())) { webSeedList.append(QJsonObject { {KEY_WEBSEED_URL, webseed.toString()} @@ -451,11 +452,11 @@ void TorrentsController::filesAction() requireParams({"hash"}); const QString hash {params()["hash"]}; - QJsonArray fileList; const BitTorrent::TorrentHandle *const torrent = BitTorrent::Session::instance()->findTorrent(hash); if (!torrent) throw APIError(APIErrorType::NotFound); + QJsonArray fileList; if (torrent->hasMetadata()) { const QVector priorities = torrent->filePriorities(); const QVector fp = torrent->filesProgress(); @@ -494,11 +495,11 @@ void TorrentsController::pieceHashesAction() requireParams({"hash"}); const QString hash {params()["hash"]}; - QJsonArray pieceHashes; BitTorrent::TorrentHandle *const torrent = BitTorrent::Session::instance()->findTorrent(hash); if (!torrent) throw APIError(APIErrorType::NotFound); + QJsonArray pieceHashes; const QVector hashes = torrent->info().pieceHashes(); for (const QByteArray &hash : hashes) pieceHashes.append(QString(hash.toHex())); @@ -516,11 +517,11 @@ void TorrentsController::pieceStatesAction() requireParams({"hash"}); const QString hash {params()["hash"]}; - QJsonArray pieceStates; BitTorrent::TorrentHandle *const torrent = BitTorrent::Session::instance()->findTorrent(hash); if (!torrent) throw APIError(APIErrorType::NotFound); + QJsonArray pieceStates; const QBitArray states = torrent->pieces(); for (int i = 0; i < states.size(); ++i) pieceStates.append(static_cast(states[i]) * 2); @@ -609,7 +610,6 @@ void TorrentsController::addTrackersAction() requireParams({"hash", "urls"}); const QString hash = params()["hash"]; - BitTorrent::TorrentHandle *const torrent = BitTorrent::Session::instance()->findTorrent(hash); if (!torrent) throw APIError(APIErrorType::NotFound); @@ -669,12 +669,12 @@ void TorrentsController::removeTrackersAction() requireParams({"hash", "urls"}); const QString hash = params()["hash"]; - const QStringList urls = params()["urls"].split('|'); - BitTorrent::TorrentHandle *const torrent = BitTorrent::Session::instance()->findTorrent(hash); if (!torrent) throw APIError(APIErrorType::NotFound); + const QStringList urls = params()["urls"].split('|'); + const QVector trackers = torrent->trackers(); QVector remainingTrackers; remainingTrackers.reserve(trackers.size());