|
|
@ -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()); |
|
|
|
{ |
|
|
|
|
|
|
|
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()); |
|
|
|
item->setPriority(newPrio); |
|
|
|
if (currentPrio != newPrio) |
|
|
|
if ((newPrio != previousPrio) && ((newPrio == BitTorrent::DownloadPriority::Ignored) |
|
|
|
|
|
|
|
|| (previousPrio == BitTorrent::DownloadPriority::Ignored))) |
|
|
|
|
|
|
|
{ |
|
|
|
{ |
|
|
|
emit filteredFilesChanged(); |
|
|
|
item->setPriority(newPrio); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
notifyModelUpdate(index); |
|
|
|
|
|
|
|
if ((newPrio == BitTorrent::DownloadPriority::Ignored) |
|
|
|
|
|
|
|
|| (currentPrio == BitTorrent::DownloadPriority::Ignored)) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
emit filteredFilesChanged(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return true; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
break; |
|
|
|
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 {}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -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()); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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()) |
|
|
|
{ |
|
|
|
{ |
|
|
|
TorrentContentModelItem* child = m_rootItem->child(i); |
|
|
|
emit dataChanged(parentIndex.siblingAtColumn(0), parentIndex.siblingAtColumn(lastColumnIndex)); |
|
|
|
if (child->priority() == BitTorrent::DownloadPriority::Ignored) |
|
|
|
parentIndex = parent(parentIndex); |
|
|
|
child->setPriority(BitTorrent::DownloadPriority::Normal); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
emit dataChanged(index(0, 0), index((rowCount() - 1), (columnCount() - 1))); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void TorrentContentModel::selectNone() |
|
|
|
// propagate down the model
|
|
|
|
{ |
|
|
|
QVector<QModelIndex> parentIndexes; |
|
|
|
for (int i = 0; i < m_rootItem->childCount(); ++i) |
|
|
|
|
|
|
|
m_rootItem->child(i)->setPriority(BitTorrent::DownloadPriority::Ignored); |
|
|
|
if (hasChildren(index)) |
|
|
|
emit dataChanged(index(0, 0), index((rowCount() - 1), (columnCount() - 1))); |
|
|
|
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); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|