From 006ad23d0d6b49f26df9050ba72c12ad6967686e Mon Sep 17 00:00:00 2001 From: Vladimir Golovnev Date: Wed, 26 Jul 2023 18:19:32 +0300 Subject: [PATCH] Map selected indexes to source before modify the data Changing the data may affect the layout of the sort/filter model, which in turn may invalidate the indexes previously obtained from selection model before we process them all. Therefore, we must map all the selected indexes to source before start processing them. PR #19372. Closes #19359. --- src/gui/transferlistwidget.cpp | 36 +++++++++++++++++++++++++--------- src/gui/transferlistwidget.h | 1 + 2 files changed, 28 insertions(+), 9 deletions(-) diff --git a/src/gui/transferlistwidget.cpp b/src/gui/transferlistwidget.cpp index d44c83f8f..b165025d6 100644 --- a/src/gui/transferlistwidget.cpp +++ b/src/gui/transferlistwidget.cpp @@ -253,6 +253,16 @@ QModelIndex TransferListWidget::mapToSource(const QModelIndex &index) const return index; } +QModelIndexList TransferListWidget::mapToSource(const QModelIndexList &indexes) const +{ + QModelIndexList result; + result.reserve(indexes.size()); + for (const QModelIndex &index : indexes) + result.append(mapToSource(index)); + + return result; +} + QModelIndex TransferListWidget::mapFromSource(const QModelIndex &index) const { Q_ASSERT(index.isValid()); @@ -263,11 +273,13 @@ QModelIndex TransferListWidget::mapFromSource(const QModelIndex &index) const void TransferListWidget::torrentDoubleClicked() { const QModelIndexList selectedIndexes = selectionModel()->selectedRows(); - if ((selectedIndexes.size() != 1) || !selectedIndexes.first().isValid()) return; + if ((selectedIndexes.size() != 1) || !selectedIndexes.first().isValid()) + return; const QModelIndex index = m_listModel->index(mapToSource(selectedIndexes.first()).row()); BitTorrent::Torrent *const torrent = m_listModel->torrentHandle(index); - if (!torrent) return; + if (!torrent) + return; int action; if (torrent->isFinished()) @@ -871,9 +883,13 @@ QStringList TransferListWidget::askTagsForSelection(const QString &dialogTitle) void TransferListWidget::applyToSelectedTorrents(const std::function &fn) { - for (const QModelIndex &index : asConst(selectionModel()->selectedRows())) + // Changing the data may affect the layout of the sort/filter model, which in turn may invalidate + // the indexes previously obtained from selection model before we process them all. + // Therefore, we must map all the selected indexes to source before start processing them. + const QModelIndexList sourceRows = mapToSource(selectionModel()->selectedRows()); + for (const QModelIndex &index : sourceRows) { - BitTorrent::Torrent *const torrent = m_listModel->torrentHandle(mapToSource(index)); + BitTorrent::Torrent *const torrent = m_listModel->torrentHandle(index); Q_ASSERT(torrent); fn(torrent); } @@ -882,11 +898,13 @@ void TransferListWidget::applyToSelectedTorrents(const std::functionselectedRows(); - if ((selectedIndexes.size() != 1) || !selectedIndexes.first().isValid()) return; + if ((selectedIndexes.size() != 1) || !selectedIndexes.first().isValid()) + return; const QModelIndex mi = m_listModel->index(mapToSource(selectedIndexes.first()).row(), TransferListModel::TR_NAME); BitTorrent::Torrent *const torrent = m_listModel->torrentHandle(mi); - if (!torrent) return; + if (!torrent) + return; // Ask for a new Name bool ok = false; @@ -901,8 +919,7 @@ void TransferListWidget::renameSelectedTorrent() void TransferListWidget::setSelectionCategory(const QString &category) { - for (const QModelIndex &index : asConst(selectionModel()->selectedRows())) - m_listModel->setData(m_listModel->index(mapToSource(index).row(), TransferListModel::TR_CATEGORY), category, Qt::DisplayRole); + applyToSelectedTorrents([&category](BitTorrent::Torrent *torrent) { torrent->setCategory(category); }); } void TransferListWidget::addSelectionTag(const QString &tag) @@ -923,7 +940,8 @@ void TransferListWidget::clearSelectionTags() void TransferListWidget::displayListMenu() { const QModelIndexList selectedIndexes = selectionModel()->selectedRows(); - if (selectedIndexes.isEmpty()) return; + if (selectedIndexes.isEmpty()) + return; auto *listMenu = new QMenu(this); listMenu->setAttribute(Qt::WA_DeleteOnClose); diff --git a/src/gui/transferlistwidget.h b/src/gui/transferlistwidget.h index 205b21246..ad9b0f37b 100644 --- a/src/gui/transferlistwidget.h +++ b/src/gui/transferlistwidget.h @@ -119,6 +119,7 @@ private slots: private: void wheelEvent(QWheelEvent *event) override; QModelIndex mapToSource(const QModelIndex &index) const; + QModelIndexList mapToSource(const QModelIndexList &indexes) const; QModelIndex mapFromSource(const QModelIndex &index) const; bool loadSettings(); QVector getSelectedTorrents() const;