Browse Source

Fix torrent content checkboxes not updated properly

And reduce emitting redundant 'data updated' signals.

Closes #17144, #17764.
adaptive-webui-19844
Chocobo1 2 years ago
parent
commit
9a20aa51de
No known key found for this signature in database
GPG Key ID: 210D9C873253A68C
  1. 8
      src/gui/torrentcontentfiltermodel.cpp
  2. 156
      src/gui/torrentcontentmodel.cpp
  3. 2
      src/gui/torrentcontentmodel.h

8
src/gui/torrentcontentfiltermodel.cpp

@ -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

156
src/gui/torrentcontentmodel.cpp

@ -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,13 +269,11 @@ 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;
@ -283,52 +281,71 @@ bool TorrentContentModel::setData(const QModelIndex &index, const QVariant &valu
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()); {
const QString currentName = item->name();
const QString newName = value.toString();
if (currentName != newName)
{
item->setName(newName);
emit dataChanged(index, index);
return true;
}
}
break; break;
case TorrentContentModelItem::COL_PRIO: case TorrentContentModelItem::COL_PRIO:
{ {
const BitTorrent::DownloadPriority previousPrio = item->priority(); const BitTorrent::DownloadPriority currentPrio = item->priority();
const auto newPrio = static_cast<BitTorrent::DownloadPriority>(value.toInt()); const auto newPrio = static_cast<BitTorrent::DownloadPriority>(value.toInt());
if (currentPrio != newPrio)
{
item->setPriority(newPrio); item->setPriority(newPrio);
if ((newPrio != previousPrio) && ((newPrio == BitTorrent::DownloadPriority::Ignored)
|| (previousPrio == BitTorrent::DownloadPriority::Ignored))) notifyModelUpdate(index);
if ((newPrio == BitTorrent::DownloadPriority::Ignored)
|| (currentPrio == BitTorrent::DownloadPriority::Ignored))
{ {
emit filteredFilesChanged(); emit filteredFilesChanged();
} }
return true;
}
} }
break; break;
default: default:
return false; break;
} }
emit dataChanged(index, index);
return true;
} }
return false; return false;
@ -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 {};
if (column >= TorrentContentModelItem::NB_COL)
return {}; return {};
TorrentContentModelFolder *parentItem = nullptr; const TorrentContentModelFolder *parentItem = parent.isValid()
if (!parent.isValid()) ? static_cast<TorrentContentModelFolder *>(parent.internalPointer())
parentItem = m_rootItem; : 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;
} }
@ -550,3 +563,48 @@ void TorrentContentModel::setupModelData(const BitTorrent::AbstractFileStorage &
} }
emit layoutChanged(); emit layoutChanged();
} }
void TorrentContentModel::notifyModelUpdate(const QModelIndex &index)
{
Q_ASSERT(index.isValid());
const int lastColumnIndex = columnCount(index) - 1;
// emit itself
emit dataChanged(index.siblingAtColumn(0), index.siblingAtColumn(lastColumnIndex));
// 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);
}
}
}

2
src/gui/torrentcontentmodel.h

@ -80,6 +80,8 @@ signals:
void filteredFilesChanged(); void filteredFilesChanged();
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…
Cancel
Save