mirror of
https://github.com/d47081/qBittorrent.git
synced 2025-01-23 13:04:23 +00:00
Merge pull request #17786 from Chocobo1/selection
Fix torrent content checkboxes not updated properly
This commit is contained in:
commit
bc0d906adc
@ -110,17 +110,13 @@ bool TorrentContentFilterModel::lessThan(const QModelIndex &left, const QModelIn
|
|||||||
void TorrentContentFilterModel::selectAll()
|
void TorrentContentFilterModel::selectAll()
|
||||||
{
|
{
|
||||||
for (int i = 0; i < rowCount(); ++i)
|
for (int i = 0; i < rowCount(); ++i)
|
||||||
setData(index(i, 0), Qt::Checked, Qt::CheckStateRole);
|
setData(index(i, TorrentContentModelItem::COL_NAME), Qt::Checked, Qt::CheckStateRole);
|
||||||
|
|
||||||
emit dataChanged(index(0, 0), index((rowCount() - 1), (columnCount() - 1)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TorrentContentFilterModel::selectNone()
|
void TorrentContentFilterModel::selectNone()
|
||||||
{
|
{
|
||||||
for (int i = 0; i < rowCount(); ++i)
|
for (int i = 0; i < rowCount(); ++i)
|
||||||
setData(index(i, 0), Qt::Unchecked, Qt::CheckStateRole);
|
setData(index(i, TorrentContentModelItem::COL_NAME), Qt::Unchecked, Qt::CheckStateRole);
|
||||||
|
|
||||||
emit dataChanged(index(0, 0), index((rowCount() - 1), (columnCount() - 1)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TorrentContentFilterModel::hasFiltered(const QModelIndex &folder) const
|
bool TorrentContentFilterModel::hasFiltered(const QModelIndex &folder) const
|
||||||
|
@ -220,7 +220,7 @@ void TorrentContentModel::updateFilesProgress(const QVector<qreal> &fp)
|
|||||||
// Update folders progress in the tree
|
// Update folders progress in the tree
|
||||||
m_rootItem->recalculateProgress();
|
m_rootItem->recalculateProgress();
|
||||||
m_rootItem->recalculateAvailability();
|
m_rootItem->recalculateAvailability();
|
||||||
emit dataChanged(index(0, 0), index((rowCount() - 1), (columnCount() - 1)));
|
notifyModelUpdate(index(0, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
void TorrentContentModel::updateFilesPriorities(const QVector<BitTorrent::DownloadPriority> &fprio)
|
void TorrentContentModel::updateFilesPriorities(const QVector<BitTorrent::DownloadPriority> &fprio)
|
||||||
@ -233,7 +233,7 @@ void TorrentContentModel::updateFilesPriorities(const QVector<BitTorrent::Downlo
|
|||||||
emit layoutAboutToBeChanged();
|
emit layoutAboutToBeChanged();
|
||||||
for (int i = 0; i < fprio.size(); ++i)
|
for (int i = 0; i < fprio.size(); ++i)
|
||||||
m_filesIndex[i]->setPriority(static_cast<BitTorrent::DownloadPriority>(fprio[i]));
|
m_filesIndex[i]->setPriority(static_cast<BitTorrent::DownloadPriority>(fprio[i]));
|
||||||
emit dataChanged(index(0, 0), index((rowCount() - 1), (columnCount() - 1)));
|
notifyModelUpdate(index(0, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
void TorrentContentModel::updateFilesAvailability(const QVector<qreal> &fa)
|
void TorrentContentModel::updateFilesAvailability(const QVector<qreal> &fa)
|
||||||
@ -247,7 +247,7 @@ void TorrentContentModel::updateFilesAvailability(const QVector<qreal> &fa)
|
|||||||
m_filesIndex[i]->setAvailability(fa[i]);
|
m_filesIndex[i]->setAvailability(fa[i]);
|
||||||
// Update folders progress in the tree
|
// Update folders progress in the tree
|
||||||
m_rootItem->recalculateProgress();
|
m_rootItem->recalculateProgress();
|
||||||
emit dataChanged(index(0, 0), index((rowCount() - 1), (columnCount() - 1)));
|
notifyModelUpdate(index(0, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
QVector<BitTorrent::DownloadPriority> TorrentContentModel::getFilePriorities() const
|
QVector<BitTorrent::DownloadPriority> TorrentContentModel::getFilePriorities() const
|
||||||
@ -269,66 +269,83 @@ bool TorrentContentModel::allFiltered() const
|
|||||||
|
|
||||||
int TorrentContentModel::columnCount(const QModelIndex &parent) const
|
int TorrentContentModel::columnCount(const QModelIndex &parent) const
|
||||||
{
|
{
|
||||||
if (parent.isValid())
|
Q_UNUSED(parent);
|
||||||
return static_cast<TorrentContentModelItem*>(parent.internalPointer())->columnCount();
|
return TorrentContentModelItem::NB_COL;
|
||||||
|
|
||||||
return m_rootItem->columnCount();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TorrentContentModel::setData(const QModelIndex &index, const QVariant &value, int role)
|
bool TorrentContentModel::setData(const QModelIndex &index, const QVariant &value, const int role)
|
||||||
{
|
{
|
||||||
if (!index.isValid())
|
if (!index.isValid())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if ((index.column() == TorrentContentModelItem::COL_NAME) && (role == Qt::CheckStateRole))
|
if ((index.column() == TorrentContentModelItem::COL_NAME) && (role == Qt::CheckStateRole))
|
||||||
{
|
{
|
||||||
auto *item = static_cast<TorrentContentModelItem*>(index.internalPointer());
|
auto *item = static_cast<TorrentContentModelItem *>(index.internalPointer());
|
||||||
qDebug("setData(%s, %d)", qUtf8Printable(item->name()), value.toInt());
|
|
||||||
|
|
||||||
BitTorrent::DownloadPriority prio = BitTorrent::DownloadPriority::Normal;
|
const BitTorrent::DownloadPriority currentPrio = item->priority();
|
||||||
if (value.toInt() == Qt::PartiallyChecked)
|
const auto checkState = static_cast<Qt::CheckState>(value.toInt());
|
||||||
prio = BitTorrent::DownloadPriority::Mixed;
|
const BitTorrent::DownloadPriority newPrio = (checkState == Qt::PartiallyChecked)
|
||||||
else if (value.toInt() == Qt::Unchecked)
|
? BitTorrent::DownloadPriority::Mixed
|
||||||
prio = BitTorrent::DownloadPriority::Ignored;
|
: ((checkState == Qt::Unchecked)
|
||||||
|
? BitTorrent::DownloadPriority::Ignored
|
||||||
|
: BitTorrent::DownloadPriority::Normal);
|
||||||
|
|
||||||
if (item->priority() != prio)
|
if (currentPrio != newPrio)
|
||||||
{
|
{
|
||||||
item->setPriority(prio);
|
item->setPriority(newPrio);
|
||||||
// Update folders progress in the tree
|
// Update folders progress in the tree
|
||||||
m_rootItem->recalculateProgress();
|
m_rootItem->recalculateProgress();
|
||||||
m_rootItem->recalculateAvailability();
|
m_rootItem->recalculateAvailability();
|
||||||
emit dataChanged(this->index(0, 0), this->index((rowCount() - 1), (columnCount() - 1)));
|
|
||||||
|
notifyModelUpdate(index);
|
||||||
emit filteredFilesChanged();
|
emit filteredFilesChanged();
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (role == Qt::EditRole)
|
if (role == Qt::EditRole)
|
||||||
{
|
{
|
||||||
Q_ASSERT(index.isValid());
|
auto *item = static_cast<TorrentContentModelItem *>(index.internalPointer());
|
||||||
auto *item = static_cast<TorrentContentModelItem*>(index.internalPointer());
|
|
||||||
switch (index.column())
|
switch (index.column())
|
||||||
{
|
{
|
||||||
case TorrentContentModelItem::COL_NAME:
|
case TorrentContentModelItem::COL_NAME:
|
||||||
item->setName(value.toString());
|
|
||||||
break;
|
|
||||||
case TorrentContentModelItem::COL_PRIO:
|
|
||||||
{
|
{
|
||||||
const BitTorrent::DownloadPriority previousPrio = item->priority();
|
const QString currentName = item->name();
|
||||||
const auto newPrio = static_cast<BitTorrent::DownloadPriority>(value.toInt());
|
const QString newName = value.toString();
|
||||||
item->setPriority(newPrio);
|
if (currentName != newName)
|
||||||
if ((newPrio != previousPrio) && ((newPrio == BitTorrent::DownloadPriority::Ignored)
|
|
||||||
|| (previousPrio == BitTorrent::DownloadPriority::Ignored)))
|
|
||||||
{
|
{
|
||||||
emit filteredFilesChanged();
|
item->setName(newName);
|
||||||
|
emit dataChanged(index, index);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case TorrentContentModelItem::COL_PRIO:
|
||||||
|
{
|
||||||
|
const BitTorrent::DownloadPriority currentPrio = item->priority();
|
||||||
|
const auto newPrio = static_cast<BitTorrent::DownloadPriority>(value.toInt());
|
||||||
|
if (currentPrio != newPrio)
|
||||||
|
{
|
||||||
|
item->setPriority(newPrio);
|
||||||
|
|
||||||
|
notifyModelUpdate(index);
|
||||||
|
if ((newPrio == BitTorrent::DownloadPriority::Ignored)
|
||||||
|
|| (currentPrio == BitTorrent::DownloadPriority::Ignored))
|
||||||
|
{
|
||||||
|
emit filteredFilesChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return false;
|
break;
|
||||||
}
|
}
|
||||||
emit dataChanged(index, index);
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
@ -336,14 +353,14 @@ bool TorrentContentModel::setData(const QModelIndex &index, const QVariant &valu
|
|||||||
|
|
||||||
TorrentContentModelItem::ItemType TorrentContentModel::itemType(const QModelIndex &index) const
|
TorrentContentModelItem::ItemType TorrentContentModel::itemType(const QModelIndex &index) const
|
||||||
{
|
{
|
||||||
return static_cast<const TorrentContentModelItem*>(index.internalPointer())->itemType();
|
return static_cast<const TorrentContentModelItem *>(index.internalPointer())->itemType();
|
||||||
}
|
}
|
||||||
|
|
||||||
int TorrentContentModel::getFileIndex(const QModelIndex &index)
|
int TorrentContentModel::getFileIndex(const QModelIndex &index)
|
||||||
{
|
{
|
||||||
auto *item = static_cast<TorrentContentModelItem*>(index.internalPointer());
|
auto *item = static_cast<TorrentContentModelItem *>(index.internalPointer());
|
||||||
if (item->itemType() == TorrentContentModelItem::FileType)
|
if (item->itemType() == TorrentContentModelItem::FileType)
|
||||||
return static_cast<TorrentContentModelFile*>(item)->fileIndex();
|
return static_cast<TorrentContentModelFile *>(item)->fileIndex();
|
||||||
|
|
||||||
Q_ASSERT(item->itemType() == TorrentContentModelItem::FileType);
|
Q_ASSERT(item->itemType() == TorrentContentModelItem::FileType);
|
||||||
return -1;
|
return -1;
|
||||||
@ -354,7 +371,7 @@ QVariant TorrentContentModel::data(const QModelIndex &index, const int role) con
|
|||||||
if (!index.isValid())
|
if (!index.isValid())
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
auto *item = static_cast<TorrentContentModelItem*>(index.internalPointer());
|
auto *item = static_cast<TorrentContentModelItem *>(index.internalPointer());
|
||||||
|
|
||||||
switch (role)
|
switch (role)
|
||||||
{
|
{
|
||||||
@ -392,8 +409,10 @@ QVariant TorrentContentModel::data(const QModelIndex &index, const int role) con
|
|||||||
return item->underlyingData(index.column());
|
return item->underlyingData(index.column());
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return {};
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
Qt::ItemFlags TorrentContentModel::flags(const QModelIndex &index) const
|
Qt::ItemFlags TorrentContentModel::flags(const QModelIndex &index) const
|
||||||
@ -431,19 +450,14 @@ QVariant TorrentContentModel::headerData(int section, Qt::Orientation orientatio
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QModelIndex TorrentContentModel::index(int row, int column, const QModelIndex &parent) const
|
QModelIndex TorrentContentModel::index(const int row, const int column, const QModelIndex &parent) const
|
||||||
{
|
{
|
||||||
if (parent.isValid() && (parent.column() != 0))
|
if (column >= columnCount())
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
if (column >= TorrentContentModelItem::NB_COL)
|
const TorrentContentModelFolder *parentItem = parent.isValid()
|
||||||
return {};
|
? static_cast<TorrentContentModelFolder *>(parent.internalPointer())
|
||||||
|
: m_rootItem;
|
||||||
TorrentContentModelFolder *parentItem = nullptr;
|
|
||||||
if (!parent.isValid())
|
|
||||||
parentItem = m_rootItem;
|
|
||||||
else
|
|
||||||
parentItem = static_cast<TorrentContentModelFolder*>(parent.internalPointer());
|
|
||||||
Q_ASSERT(parentItem);
|
Q_ASSERT(parentItem);
|
||||||
|
|
||||||
if (row >= parentItem->childCount())
|
if (row >= parentItem->childCount())
|
||||||
@ -452,6 +466,7 @@ QModelIndex TorrentContentModel::index(int row, int column, const QModelIndex &p
|
|||||||
TorrentContentModelItem *childItem = parentItem->child(row);
|
TorrentContentModelItem *childItem = parentItem->child(row);
|
||||||
if (childItem)
|
if (childItem)
|
||||||
return createIndex(row, column, childItem);
|
return createIndex(row, column, childItem);
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -460,28 +475,26 @@ QModelIndex TorrentContentModel::parent(const QModelIndex &index) const
|
|||||||
if (!index.isValid())
|
if (!index.isValid())
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
auto *childItem = static_cast<TorrentContentModelItem*>(index.internalPointer());
|
const auto *item = static_cast<TorrentContentModelItem *>(index.internalPointer());
|
||||||
if (!childItem)
|
if (!item)
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
TorrentContentModelItem *parentItem = childItem->parent();
|
TorrentContentModelItem *parentItem = item->parent();
|
||||||
if (parentItem == m_rootItem)
|
if (parentItem == m_rootItem)
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
|
// From https://doc.qt.io/qt-6/qabstractitemmodel.html#parent:
|
||||||
|
// A common convention used in models that expose tree data structures is that only items
|
||||||
|
// in the first column have children. For that case, when reimplementing this function in
|
||||||
|
// a subclass the column of the returned QModelIndex would be 0.
|
||||||
return createIndex(parentItem->row(), 0, parentItem);
|
return createIndex(parentItem->row(), 0, parentItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
int TorrentContentModel::rowCount(const QModelIndex &parent) const
|
int TorrentContentModel::rowCount(const QModelIndex &parent) const
|
||||||
{
|
{
|
||||||
if (parent.column() > 0)
|
const TorrentContentModelFolder *parentItem = parent.isValid()
|
||||||
return 0;
|
? dynamic_cast<TorrentContentModelFolder *>(static_cast<TorrentContentModelItem *>(parent.internalPointer()))
|
||||||
|
: m_rootItem;
|
||||||
TorrentContentModelFolder *parentItem = nullptr;
|
|
||||||
if (!parent.isValid())
|
|
||||||
parentItem = m_rootItem;
|
|
||||||
else
|
|
||||||
parentItem = dynamic_cast<TorrentContentModelFolder*>(static_cast<TorrentContentModelItem*>(parent.internalPointer()));
|
|
||||||
|
|
||||||
return parentItem ? parentItem->childCount() : 0;
|
return parentItem ? parentItem->childCount() : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -551,20 +564,47 @@ void TorrentContentModel::setupModelData(const BitTorrent::AbstractFileStorage &
|
|||||||
emit layoutChanged();
|
emit layoutChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
void TorrentContentModel::selectAll()
|
void TorrentContentModel::notifyModelUpdate(const QModelIndex &index)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < m_rootItem->childCount(); ++i)
|
Q_ASSERT(index.isValid());
|
||||||
{
|
|
||||||
TorrentContentModelItem* child = m_rootItem->child(i);
|
|
||||||
if (child->priority() == BitTorrent::DownloadPriority::Ignored)
|
|
||||||
child->setPriority(BitTorrent::DownloadPriority::Normal);
|
|
||||||
}
|
|
||||||
emit dataChanged(index(0, 0), index((rowCount() - 1), (columnCount() - 1)));
|
|
||||||
}
|
|
||||||
|
|
||||||
void TorrentContentModel::selectNone()
|
const int lastColumnIndex = columnCount(index) - 1;
|
||||||
{
|
|
||||||
for (int i = 0; i < m_rootItem->childCount(); ++i)
|
// emit itself
|
||||||
m_rootItem->child(i)->setPriority(BitTorrent::DownloadPriority::Ignored);
|
emit dataChanged(index.siblingAtColumn(0), index.siblingAtColumn(lastColumnIndex));
|
||||||
emit dataChanged(index(0, 0), index((rowCount() - 1), (columnCount() - 1)));
|
|
||||||
|
// propagate up the model
|
||||||
|
QModelIndex parentIndex = parent(index);
|
||||||
|
while (parentIndex.isValid())
|
||||||
|
{
|
||||||
|
emit dataChanged(parentIndex.siblingAtColumn(0), parentIndex.siblingAtColumn(lastColumnIndex));
|
||||||
|
parentIndex = parent(parentIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
// propagate down the model
|
||||||
|
QVector<QModelIndex> parentIndexes;
|
||||||
|
|
||||||
|
if (hasChildren(index))
|
||||||
|
parentIndexes.push_back(index);
|
||||||
|
|
||||||
|
while (!parentIndexes.isEmpty())
|
||||||
|
{
|
||||||
|
const QModelIndex parent = parentIndexes.takeLast();
|
||||||
|
|
||||||
|
const int childCount = rowCount(parent);
|
||||||
|
const QModelIndex childTopLeft = this->index(0, 0, parent);
|
||||||
|
const QModelIndex childBottomRight = this->index((childCount - 1), lastColumnIndex, parent);
|
||||||
|
|
||||||
|
// emit this generation
|
||||||
|
emit dataChanged(childTopLeft, childBottomRight);
|
||||||
|
|
||||||
|
// check generations further down
|
||||||
|
parentIndexes.reserve(childCount);
|
||||||
|
for (int i = 0; i < childCount; ++i)
|
||||||
|
{
|
||||||
|
const QModelIndex child = childTopLeft.siblingAtRow(i);
|
||||||
|
if (hasChildren(child))
|
||||||
|
parentIndexes.push_back(child);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -79,11 +79,9 @@ public:
|
|||||||
signals:
|
signals:
|
||||||
void filteredFilesChanged();
|
void filteredFilesChanged();
|
||||||
|
|
||||||
public slots:
|
|
||||||
void selectAll();
|
|
||||||
void selectNone();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void notifyModelUpdate(const QModelIndex &index);
|
||||||
|
|
||||||
TorrentContentModelFolder *m_rootItem = nullptr;
|
TorrentContentModelFolder *m_rootItem = nullptr;
|
||||||
QVector<TorrentContentModelFile *> m_filesIndex;
|
QVector<TorrentContentModelFile *> m_filesIndex;
|
||||||
QFileIconProvider *m_fileIconProvider = nullptr;
|
QFileIconProvider *m_fileIconProvider = nullptr;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user