mirror of
https://github.com/d47081/qBittorrent.git
synced 2025-01-24 05:25:37 +00:00
Merge pull request #4994 from evsh/availability-column
Add availability column to torrent contents
This commit is contained in:
commit
92a7479e2d
@ -1953,3 +1953,24 @@ void TorrentHandle::prioritizeFiles(const QVector<int> &priorities)
|
|||||||
|
|
||||||
updateStatus();
|
updateStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QVector<qreal> TorrentHandle::availableFileFractions() const
|
||||||
|
{
|
||||||
|
QVector<int> piecesAvailability = pieceAvailability();
|
||||||
|
const auto filesCount = this->filesCount();
|
||||||
|
// libtorrent returns empty array for seeding only torrents
|
||||||
|
if (piecesAvailability.empty()) return QVector<qreal>(filesCount, -1.);
|
||||||
|
|
||||||
|
QVector<qreal> res;
|
||||||
|
res.reserve(filesCount);
|
||||||
|
TorrentInfo info = this->info();
|
||||||
|
for (int file = 0; file < filesCount; ++file) {
|
||||||
|
TorrentInfo::PieceRange filePieces = info.filePieces(file);
|
||||||
|
int availablePieces = 0;
|
||||||
|
for (int piece = filePieces.first(); piece <= filePieces.last(); ++piece) {
|
||||||
|
availablePieces += piecesAvailability[piece] > 0 ? 1 : 0;
|
||||||
|
}
|
||||||
|
res.push_back(static_cast<qreal>(availablePieces) / filePieces.size());
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
@ -361,6 +361,14 @@ namespace BitTorrent
|
|||||||
void handleAppendExtensionToggled();
|
void handleAppendExtensionToggled();
|
||||||
void saveResumeData(bool updateStatus = false);
|
void saveResumeData(bool updateStatus = false);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief fraction of file pieces that are available at least from one peer
|
||||||
|
*
|
||||||
|
* This is not the same as torrrent availability, it is just a fraction of pieces
|
||||||
|
* that can be downloaded right now. It varies between 0 to 1.
|
||||||
|
*/
|
||||||
|
QVector<qreal> availableFileFractions() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
typedef boost::function<void ()> EventTrigger;
|
typedef boost::function<void ()> EventTrigger;
|
||||||
|
|
||||||
|
@ -39,6 +39,7 @@ const char C_NON_BREAKING_SPACE[] = " ";
|
|||||||
const char C_UP[] = "▲";
|
const char C_UP[] = "▲";
|
||||||
const char C_DOWN[] = "▼";
|
const char C_DOWN[] = "▼";
|
||||||
const char C_COPYRIGHT[] = "©";
|
const char C_COPYRIGHT[] = "©";
|
||||||
|
const char C_THIN_SPACE[] = " ";
|
||||||
const char C_UTP[] = "μTP";
|
const char C_UTP[] = "μTP";
|
||||||
const char C_LOCALE_ENGLISH[] = "English";
|
const char C_LOCALE_ENGLISH[] = "English";
|
||||||
const char C_LOCALE_ENGLISH_AUSTRALIA[] = "English(Australia)";
|
const char C_LOCALE_ENGLISH_AUSTRALIA[] = "English(Australia)";
|
||||||
|
@ -737,6 +737,7 @@ void AddNewTorrentDialog::setupTreeview()
|
|||||||
// Hide useless columns after loading the header state
|
// Hide useless columns after loading the header state
|
||||||
ui->contentTreeView->hideColumn(PROGRESS);
|
ui->contentTreeView->hideColumn(PROGRESS);
|
||||||
ui->contentTreeView->hideColumn(REMAINING);
|
ui->contentTreeView->hideColumn(REMAINING);
|
||||||
|
ui->contentTreeView->hideColumn(AVAILABILITY);
|
||||||
|
|
||||||
// Expand root folder
|
// Expand root folder
|
||||||
ui->contentTreeView->setExpanded(m_contentModel->index(0, 0), true);
|
ui->contentTreeView->setExpanded(m_contentModel->index(0, 0), true);
|
||||||
|
@ -493,6 +493,7 @@ void PropertiesWidget::loadDynamicData()
|
|||||||
qDebug("Updating priorities in files tab");
|
qDebug("Updating priorities in files tab");
|
||||||
m_ui->filesList->setUpdatesEnabled(false);
|
m_ui->filesList->setUpdatesEnabled(false);
|
||||||
PropListModel->model()->updateFilesProgress(m_torrent->filesProgress());
|
PropListModel->model()->updateFilesProgress(m_torrent->filesProgress());
|
||||||
|
PropListModel->model()->updateFilesAvailability(m_torrent->availableFileFractions());
|
||||||
// XXX: We don't update file priorities regularly for performance
|
// XXX: We don't update file priorities regularly for performance
|
||||||
// reasons. This means that priorities will not be updated if
|
// reasons. This means that priorities will not be updated if
|
||||||
// set from the Web UI.
|
// set from the Web UI.
|
||||||
|
@ -42,6 +42,7 @@
|
|||||||
#include <QProxyStyle>
|
#include <QProxyStyle>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include "base/unicodestrings.h"
|
||||||
#include "base/utils/misc.h"
|
#include "base/utils/misc.h"
|
||||||
#include "base/utils/string.h"
|
#include "base/utils/string.h"
|
||||||
#include "propertieswidget.h"
|
#include "propertieswidget.h"
|
||||||
@ -131,6 +132,19 @@ void PropListDelegate::paint(QPainter *painter, const QStyleOptionViewItem &opti
|
|||||||
QItemDelegate::drawDisplay(painter, opt, option.rect, text);
|
QItemDelegate::drawDisplay(painter, opt, option.rect, text);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case AVAILABILITY: {
|
||||||
|
const qreal availability = index.data().toDouble();
|
||||||
|
if (availability < 0) {
|
||||||
|
QItemDelegate::drawDisplay(painter, opt, option.rect, tr("N/A"));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
const QString value = (availability >= 1.0)
|
||||||
|
? QLatin1String("100")
|
||||||
|
: Utils::String::fromDouble(availability * 100., 1);
|
||||||
|
QItemDelegate::drawDisplay(painter, opt, option.rect, value + C_THIN_SPACE + QLatin1Char('%'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
QItemDelegate::paint(painter, option, index);
|
QItemDelegate::paint(painter, option, index);
|
||||||
break;
|
break;
|
||||||
|
@ -46,7 +46,8 @@ enum PropColumn
|
|||||||
PCSIZE,
|
PCSIZE,
|
||||||
PROGRESS,
|
PROGRESS,
|
||||||
PRIORITY,
|
PRIORITY,
|
||||||
REMAINING
|
REMAINING,
|
||||||
|
AVAILABILITY
|
||||||
};
|
};
|
||||||
|
|
||||||
class PropListDelegate: public QItemDelegate
|
class PropListDelegate: public QItemDelegate
|
||||||
@ -72,3 +73,4 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -56,7 +56,7 @@ namespace
|
|||||||
|
|
||||||
TorrentContentModel::TorrentContentModel(QObject *parent)
|
TorrentContentModel::TorrentContentModel(QObject *parent)
|
||||||
: QAbstractItemModel(parent)
|
: QAbstractItemModel(parent)
|
||||||
, m_rootItem(new TorrentContentModelFolder(QList<QVariant>({ tr("Name"), tr("Size"), tr("Progress"), tr("Download Priority"), tr("Remaining") })))
|
, m_rootItem(new TorrentContentModelFolder(QList<QVariant>({ tr("Name"), tr("Size"), tr("Progress"), tr("Download Priority"), tr("Remaining"), tr("Availability") })))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -76,6 +76,7 @@ void TorrentContentModel::updateFilesProgress(const QVector<qreal> &fp)
|
|||||||
m_filesIndex[i]->setProgress(fp[i]);
|
m_filesIndex[i]->setProgress(fp[i]);
|
||||||
// Update folders progress in the tree
|
// Update folders progress in the tree
|
||||||
m_rootItem->recalculateProgress();
|
m_rootItem->recalculateProgress();
|
||||||
|
m_rootItem->recalculateAvailability();
|
||||||
emit dataChanged(index(0, 0), index(rowCount(), columnCount()));
|
emit dataChanged(index(0, 0), index(rowCount(), columnCount()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -92,6 +93,20 @@ void TorrentContentModel::updateFilesPriorities(const QVector<int> &fprio)
|
|||||||
emit dataChanged(index(0, 0), index(rowCount(), columnCount()));
|
emit dataChanged(index(0, 0), index(rowCount(), columnCount()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TorrentContentModel::updateFilesAvailability(const QVector<qreal> &fa)
|
||||||
|
{
|
||||||
|
Q_ASSERT(m_filesIndex.size() == fa.size());
|
||||||
|
// XXX: Why is this necessary?
|
||||||
|
if (m_filesIndex.size() != fa.size()) return;
|
||||||
|
|
||||||
|
emit layoutAboutToBeChanged();
|
||||||
|
for (int i = 0; i < fa.size(); ++i)
|
||||||
|
m_filesIndex[i]->setAvailability(fa[i]);
|
||||||
|
// Update folders progress in the tree
|
||||||
|
m_rootItem->recalculateProgress();
|
||||||
|
emit dataChanged(index(0, 0), index(rowCount(), columnCount()));
|
||||||
|
}
|
||||||
|
|
||||||
QVector<int> TorrentContentModel::getFilePriorities() const
|
QVector<int> TorrentContentModel::getFilePriorities() const
|
||||||
{
|
{
|
||||||
QVector<int> prio;
|
QVector<int> prio;
|
||||||
@ -134,6 +149,7 @@ bool TorrentContentModel::setData(const QModelIndex& index, const QVariant& valu
|
|||||||
item->setPriority(prio::NORMAL);
|
item->setPriority(prio::NORMAL);
|
||||||
// Update folders progress in the tree
|
// Update folders progress in the tree
|
||||||
m_rootItem->recalculateProgress();
|
m_rootItem->recalculateProgress();
|
||||||
|
m_rootItem->recalculateAvailability();
|
||||||
emit dataChanged(this->index(0, 0), this->index(rowCount() - 1, columnCount() - 1));
|
emit dataChanged(this->index(0, 0), this->index(rowCount() - 1, columnCount() - 1));
|
||||||
emit filteredFilesChanged();
|
emit filteredFilesChanged();
|
||||||
}
|
}
|
||||||
|
@ -41,40 +41,42 @@
|
|||||||
|
|
||||||
class TorrentContentModelFile;
|
class TorrentContentModelFile;
|
||||||
|
|
||||||
class TorrentContentModel: public QAbstractItemModel {
|
class TorrentContentModel: public QAbstractItemModel
|
||||||
Q_OBJECT
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
TorrentContentModel(QObject *parent = 0);
|
TorrentContentModel(QObject *parent = 0);
|
||||||
~TorrentContentModel();
|
~TorrentContentModel();
|
||||||
|
|
||||||
void updateFilesProgress(const QVector<qreal> &fp);
|
void updateFilesProgress(const QVector<qreal> &fp);
|
||||||
void updateFilesPriorities(const QVector<int> &fprio);
|
void updateFilesPriorities(const QVector<int> &fprio);
|
||||||
QVector<int> getFilePriorities() const;
|
void updateFilesAvailability(const QVector<qreal> &fa);
|
||||||
bool allFiltered() const;
|
QVector<int> getFilePriorities() const;
|
||||||
virtual int columnCount(const QModelIndex &parent=QModelIndex()) const;
|
bool allFiltered() const;
|
||||||
virtual bool setData(const QModelIndex& index, const QVariant& value, int role = Qt::EditRole);
|
virtual int columnCount(const QModelIndex &parent = QModelIndex()) const;
|
||||||
TorrentContentModelItem::ItemType itemType(const QModelIndex& index) const;
|
virtual bool setData(const QModelIndex& index, const QVariant& value, int role = Qt::EditRole);
|
||||||
int getFileIndex(const QModelIndex& index);
|
TorrentContentModelItem::ItemType itemType(const QModelIndex& index) const;
|
||||||
virtual QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const;
|
int getFileIndex(const QModelIndex& index);
|
||||||
virtual Qt::ItemFlags flags(const QModelIndex& index) const;
|
virtual QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const;
|
||||||
virtual QVariant headerData(int section, Qt::Orientation orientation, int role) const;
|
virtual Qt::ItemFlags flags(const QModelIndex& index) const;
|
||||||
virtual QModelIndex index(int row, int column, const QModelIndex& parent = QModelIndex()) const;
|
virtual QVariant headerData(int section, Qt::Orientation orientation, int role) const;
|
||||||
virtual QModelIndex parent(const QModelIndex& index) const;
|
virtual QModelIndex index(int row, int column, const QModelIndex& parent = QModelIndex()) const;
|
||||||
virtual int rowCount(const QModelIndex& parent = QModelIndex()) const;
|
virtual QModelIndex parent(const QModelIndex& index) const;
|
||||||
void clear();
|
virtual int rowCount(const QModelIndex& parent = QModelIndex()) const;
|
||||||
void setupModelData(const BitTorrent::TorrentInfo &info);
|
void clear();
|
||||||
|
void setupModelData(const BitTorrent::TorrentInfo &info);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void filteredFilesChanged();
|
void filteredFilesChanged();
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void selectAll();
|
void selectAll();
|
||||||
void selectNone();
|
void selectNone();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
TorrentContentModelFolder* m_rootItem;
|
TorrentContentModelFolder *m_rootItem;
|
||||||
QVector<TorrentContentModelFile*> m_filesIndex;
|
QVector<TorrentContentModelFile *> m_filesIndex;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // TORRENTCONTENTMODEL_H
|
#endif // TORRENTCONTENTMODEL_H
|
||||||
|
@ -32,43 +32,54 @@
|
|||||||
#include "torrentcontentmodelfolder.h"
|
#include "torrentcontentmodelfolder.h"
|
||||||
|
|
||||||
TorrentContentModelFile::TorrentContentModelFile(const QString &fileName, qulonglong fileSize,
|
TorrentContentModelFile::TorrentContentModelFile(const QString &fileName, qulonglong fileSize,
|
||||||
TorrentContentModelFolder* parent, int file_index)
|
TorrentContentModelFolder *parent, int fileIndex)
|
||||||
: TorrentContentModelItem(parent)
|
: TorrentContentModelItem(parent)
|
||||||
, m_fileIndex(file_index)
|
, m_fileIndex(fileIndex)
|
||||||
{
|
{
|
||||||
Q_ASSERT(parent);
|
Q_ASSERT(parent);
|
||||||
|
|
||||||
m_name = fileName;
|
m_name = fileName;
|
||||||
|
|
||||||
// Do not display incomplete extensions
|
// Do not display incomplete extensions
|
||||||
if (m_name.endsWith(".!qB"))
|
if (m_name.endsWith(".!qB"))
|
||||||
m_name.chop(4);
|
m_name.chop(4);
|
||||||
|
|
||||||
m_size = fileSize;
|
m_size = fileSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
int TorrentContentModelFile::fileIndex() const
|
int TorrentContentModelFile::fileIndex() const
|
||||||
{
|
{
|
||||||
return m_fileIndex;
|
return m_fileIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TorrentContentModelFile::setPriority(int new_prio, bool update_parent)
|
void TorrentContentModelFile::setPriority(int newPriority, bool updateParent)
|
||||||
{
|
{
|
||||||
Q_ASSERT(new_prio != prio::MIXED);
|
Q_ASSERT(newPriority != prio::MIXED);
|
||||||
|
|
||||||
if (m_priority == new_prio)
|
if (m_priority == newPriority)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
m_priority = new_prio;
|
m_priority = newPriority;
|
||||||
|
|
||||||
// Update parent
|
// Update parent
|
||||||
if (update_parent)
|
if (updateParent)
|
||||||
m_parentItem->updatePriority();
|
m_parentItem->updatePriority();
|
||||||
}
|
}
|
||||||
|
|
||||||
void TorrentContentModelFile::setProgress(qreal progress)
|
void TorrentContentModelFile::setProgress(qreal progress)
|
||||||
{
|
{
|
||||||
m_progress = progress;
|
m_progress = progress;
|
||||||
m_remaining = (qulonglong)(m_size * (1.0 - m_progress));
|
m_remaining = static_cast<qulonglong>(m_size * (1.0 - m_progress));
|
||||||
Q_ASSERT(m_progress <= 1.);
|
Q_ASSERT(m_progress <= 1.);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TorrentContentModelFile::setAvailability(qreal availability)
|
||||||
|
{
|
||||||
|
m_availability = availability;
|
||||||
|
Q_ASSERT(m_availability <= 1.);
|
||||||
|
}
|
||||||
|
|
||||||
|
TorrentContentModelItem::ItemType TorrentContentModelFile::itemType() const
|
||||||
|
{
|
||||||
|
return FileType;
|
||||||
}
|
}
|
||||||
|
@ -33,19 +33,20 @@
|
|||||||
|
|
||||||
#include "torrentcontentmodelitem.h"
|
#include "torrentcontentmodelitem.h"
|
||||||
|
|
||||||
class TorrentContentModelFile : public TorrentContentModelItem
|
class TorrentContentModelFile: public TorrentContentModelItem
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
TorrentContentModelFile(const QString &fileName, qulonglong fileSize,
|
TorrentContentModelFile(const QString &fileName, qulonglong fileSize,
|
||||||
TorrentContentModelFolder* parent, int file_index);
|
TorrentContentModelFolder *parent, int fileIndex);
|
||||||
|
|
||||||
int fileIndex() const;
|
int fileIndex() const;
|
||||||
void setPriority(int new_prio, bool update_parent = true);
|
void setPriority(int newPriority, bool updateParent = true) override;
|
||||||
void setProgress(qreal progress);
|
void setProgress(qreal progress);
|
||||||
ItemType itemType() const { return FileType; }
|
void setAvailability(qreal availability);
|
||||||
|
ItemType itemType() const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int m_fileIndex;
|
int m_fileIndex;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // TORRENTCONTENTMODELFILE_H
|
#endif // TORRENTCONTENTMODELFILE_H
|
||||||
|
@ -31,136 +31,167 @@
|
|||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include "torrentcontentmodelfolder.h"
|
#include "torrentcontentmodelfolder.h"
|
||||||
|
|
||||||
TorrentContentModelFolder::TorrentContentModelFolder(const QString& name, TorrentContentModelFolder* parent)
|
TorrentContentModelFolder::TorrentContentModelFolder(const QString &name, TorrentContentModelFolder *parent)
|
||||||
: TorrentContentModelItem(parent)
|
: TorrentContentModelItem(parent)
|
||||||
{
|
{
|
||||||
Q_ASSERT(parent);
|
Q_ASSERT(parent);
|
||||||
m_name = name;
|
m_name = name;
|
||||||
// Do not display incomplete extensions
|
// Do not display incomplete extensions
|
||||||
if (m_name.endsWith(".!qB"))
|
if (m_name.endsWith(".!qB"))
|
||||||
m_name.chop(4);
|
m_name.chop(4);
|
||||||
}
|
}
|
||||||
|
|
||||||
TorrentContentModelFolder::TorrentContentModelFolder(const QList<QVariant>& data)
|
TorrentContentModelFolder::TorrentContentModelFolder(const QList<QVariant> &data)
|
||||||
: TorrentContentModelItem(0)
|
: TorrentContentModelItem(0)
|
||||||
{
|
{
|
||||||
Q_ASSERT(data.size() == NB_COL);
|
Q_ASSERT(data.size() == NB_COL);
|
||||||
m_itemData = data;
|
m_itemData = data;
|
||||||
}
|
}
|
||||||
|
|
||||||
TorrentContentModelFolder::~TorrentContentModelFolder()
|
TorrentContentModelFolder::~TorrentContentModelFolder()
|
||||||
{
|
{
|
||||||
qDeleteAll(m_childItems);
|
qDeleteAll(m_childItems);
|
||||||
|
}
|
||||||
|
|
||||||
|
TorrentContentModelItem::ItemType TorrentContentModelFolder::itemType() const
|
||||||
|
{
|
||||||
|
return FolderType;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TorrentContentModelFolder::deleteAllChildren()
|
void TorrentContentModelFolder::deleteAllChildren()
|
||||||
{
|
{
|
||||||
Q_ASSERT(isRootItem());
|
Q_ASSERT(isRootItem());
|
||||||
qDeleteAll(m_childItems);
|
qDeleteAll(m_childItems);
|
||||||
m_childItems.clear();
|
m_childItems.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
const QList<TorrentContentModelItem*>& TorrentContentModelFolder::children() const
|
const QList<TorrentContentModelItem *> &TorrentContentModelFolder::children() const
|
||||||
{
|
{
|
||||||
return m_childItems;
|
return m_childItems;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TorrentContentModelFolder::appendChild(TorrentContentModelItem* item)
|
void TorrentContentModelFolder::appendChild(TorrentContentModelItem *item)
|
||||||
{
|
{
|
||||||
Q_ASSERT(item);
|
Q_ASSERT(item);
|
||||||
m_childItems.append(item);
|
m_childItems.append(item);
|
||||||
// Update own size
|
// Update own size
|
||||||
if (item->itemType() == FileType)
|
if (item->itemType() == FileType)
|
||||||
increaseSize(item->size());
|
increaseSize(item->size());
|
||||||
}
|
}
|
||||||
|
|
||||||
TorrentContentModelItem* TorrentContentModelFolder::child(int row) const
|
TorrentContentModelItem *TorrentContentModelFolder::child(int row) const
|
||||||
{
|
{
|
||||||
return m_childItems.value(row, 0);
|
return m_childItems.value(row, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
TorrentContentModelFolder* TorrentContentModelFolder::childFolderWithName(const QString& name) const
|
TorrentContentModelFolder *TorrentContentModelFolder::childFolderWithName(const QString &name) const
|
||||||
{
|
{
|
||||||
foreach (TorrentContentModelItem* child, m_childItems) {
|
foreach (TorrentContentModelItem *child, m_childItems)
|
||||||
if (child->itemType() == FolderType && child->name() == name)
|
if ((child->itemType() == FolderType) && (child->name() == name))
|
||||||
return static_cast<TorrentContentModelFolder*>(child);
|
return static_cast<TorrentContentModelFolder *>(child);
|
||||||
}
|
return 0;
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int TorrentContentModelFolder::childCount() const
|
int TorrentContentModelFolder::childCount() const
|
||||||
{
|
{
|
||||||
return m_childItems.count();
|
return m_childItems.count();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only non-root folders use this function
|
// Only non-root folders use this function
|
||||||
void TorrentContentModelFolder::updatePriority()
|
void TorrentContentModelFolder::updatePriority()
|
||||||
{
|
{
|
||||||
if (isRootItem())
|
if (isRootItem())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Q_ASSERT(!m_childItems.isEmpty());
|
Q_ASSERT(!m_childItems.isEmpty());
|
||||||
|
|
||||||
// If all children have the same priority
|
// If all children have the same priority
|
||||||
// then the folder should have the same
|
// then the folder should have the same
|
||||||
// priority
|
// priority
|
||||||
const int prio = m_childItems.first()->priority();
|
const int prio = m_childItems.first()->priority();
|
||||||
for (int i=1; i<m_childItems.size(); ++i) {
|
for (int i = 1; i < m_childItems.size(); ++i) {
|
||||||
if (m_childItems.at(i)->priority() != prio) {
|
if (m_childItems.at(i)->priority() != prio) {
|
||||||
setPriority(prio::MIXED);
|
setPriority(prio::MIXED);
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
// All child items have the same priority
|
||||||
// All child items have the same priority
|
// Update own if necessary
|
||||||
// Update own if necessary
|
setPriority(prio);
|
||||||
setPriority(prio);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TorrentContentModelFolder::setPriority(int new_prio, bool update_parent)
|
void TorrentContentModelFolder::setPriority(int newPriority, bool updateParent)
|
||||||
{
|
{
|
||||||
if (m_priority == new_prio)
|
if (m_priority == newPriority)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
m_priority = new_prio;
|
m_priority = newPriority;
|
||||||
|
|
||||||
// Update parent priority
|
// Update parent priority
|
||||||
if (update_parent)
|
if (updateParent)
|
||||||
m_parentItem->updatePriority();
|
m_parentItem->updatePriority();
|
||||||
|
|
||||||
// Update children
|
// Update children
|
||||||
if (m_priority != prio::MIXED) {
|
if (m_priority != prio::MIXED)
|
||||||
foreach (TorrentContentModelItem* child, m_childItems)
|
foreach (TorrentContentModelItem *child, m_childItems)
|
||||||
child->setPriority(m_priority, false);
|
child->setPriority(m_priority, false);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TorrentContentModelFolder::recalculateProgress()
|
void TorrentContentModelFolder::recalculateProgress()
|
||||||
{
|
{
|
||||||
qreal tProgress = 0;
|
qreal tProgress = 0;
|
||||||
qulonglong tSize = 0;
|
qulonglong tSize = 0;
|
||||||
qulonglong tRemaining = 0;
|
qulonglong tRemaining = 0;
|
||||||
foreach (TorrentContentModelItem* child, m_childItems) {
|
foreach (TorrentContentModelItem *child, m_childItems) {
|
||||||
if (child->priority() != prio::IGNORED) {
|
if (child->priority() != prio::IGNORED) {
|
||||||
if (child->itemType() == FolderType)
|
if (child->itemType() == FolderType)
|
||||||
static_cast<TorrentContentModelFolder*>(child)->recalculateProgress();
|
static_cast<TorrentContentModelFolder *>(child)->recalculateProgress();
|
||||||
tProgress += child->progress() * child->size();
|
tProgress += child->progress() * child->size();
|
||||||
tSize += child->size();
|
tSize += child->size();
|
||||||
tRemaining += child->remaining();
|
tRemaining += child->remaining();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (!isRootItem() && tSize > 0) {
|
if (!isRootItem() && (tSize > 0)) {
|
||||||
m_progress = tProgress / tSize;
|
m_progress = tProgress / tSize;
|
||||||
m_remaining = tRemaining;
|
m_remaining = tRemaining;
|
||||||
Q_ASSERT(m_progress <= 1.);
|
Q_ASSERT(m_progress <= 1.);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TorrentContentModelFolder::recalculateAvailability()
|
||||||
|
{
|
||||||
|
qreal tAvailability = 0;
|
||||||
|
qulonglong tSize = 0;
|
||||||
|
bool foundAnyData = false;
|
||||||
|
foreach (TorrentContentModelItem* child, m_childItems) {
|
||||||
|
if (child->priority() == prio::IGNORED)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (child->itemType() == FolderType)
|
||||||
|
static_cast<TorrentContentModelFolder*>(child)->recalculateAvailability();
|
||||||
|
const qreal childAvailability = child->availability();
|
||||||
|
if (childAvailability >= 0) { // -1 means "no data"
|
||||||
|
tAvailability += childAvailability * child->size();
|
||||||
|
foundAnyData = true;
|
||||||
|
}
|
||||||
|
tSize += child->size();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isRootItem() && (tSize > 0) && foundAnyData) {
|
||||||
|
m_availability = tAvailability / tSize;
|
||||||
|
Q_ASSERT(m_availability <= 1.);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
m_availability = -1.;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void TorrentContentModelFolder::increaseSize(qulonglong delta)
|
void TorrentContentModelFolder::increaseSize(qulonglong delta)
|
||||||
{
|
{
|
||||||
if (isRootItem())
|
if (isRootItem())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
m_size += delta;
|
m_size += delta;
|
||||||
m_parentItem->increaseSize(delta);
|
m_parentItem->increaseSize(delta);
|
||||||
}
|
}
|
||||||
|
@ -33,34 +33,35 @@
|
|||||||
|
|
||||||
#include "torrentcontentmodelitem.h"
|
#include "torrentcontentmodelitem.h"
|
||||||
|
|
||||||
class TorrentContentModelFolder : public TorrentContentModelItem
|
class TorrentContentModelFolder: public TorrentContentModelItem
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
// Folder constructor
|
// Folder constructor
|
||||||
TorrentContentModelFolder(const QString& name, TorrentContentModelFolder* parent);
|
TorrentContentModelFolder(const QString& name, TorrentContentModelFolder* parent);
|
||||||
|
|
||||||
// Invisible root item constructor
|
// Invisible root item constructor
|
||||||
TorrentContentModelFolder(const QList<QVariant>& data);
|
TorrentContentModelFolder(const QList<QVariant>& data);
|
||||||
|
|
||||||
~TorrentContentModelFolder();
|
~TorrentContentModelFolder();
|
||||||
|
|
||||||
ItemType itemType() const { return FolderType; }
|
ItemType itemType() const override;
|
||||||
|
|
||||||
void increaseSize(qulonglong delta);
|
void increaseSize(qulonglong delta);
|
||||||
void recalculateProgress();
|
void recalculateProgress();
|
||||||
void updatePriority();
|
void recalculateAvailability();
|
||||||
|
void updatePriority();
|
||||||
|
|
||||||
void setPriority(int new_prio, bool update_parent = true);
|
void setPriority(int newPriority, bool updateParent = true) override;
|
||||||
|
|
||||||
void deleteAllChildren();
|
void deleteAllChildren();
|
||||||
const QList<TorrentContentModelItem*>& children() const;
|
const QList<TorrentContentModelItem*>& children() const;
|
||||||
void appendChild(TorrentContentModelItem* item);
|
void appendChild(TorrentContentModelItem* item);
|
||||||
TorrentContentModelItem* child(int row) const;
|
TorrentContentModelItem* child(int row) const;
|
||||||
TorrentContentModelFolder* childFolderWithName(const QString& name) const;
|
TorrentContentModelFolder* childFolderWithName(const QString& name) const;
|
||||||
int childCount() const;
|
int childCount() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QList<TorrentContentModelItem*> m_childItems;
|
QList<TorrentContentModelItem*> m_childItems;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // TORRENTCONTENTMODELFOLDER_H
|
#endif // TORRENTCONTENTMODELFOLDER_H
|
||||||
|
@ -34,36 +34,40 @@
|
|||||||
#include "torrentcontentmodelfolder.h"
|
#include "torrentcontentmodelfolder.h"
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
|
|
||||||
TorrentContentModelItem::TorrentContentModelItem(TorrentContentModelFolder* parent)
|
TorrentContentModelItem::TorrentContentModelItem(TorrentContentModelFolder *parent)
|
||||||
: m_parentItem(parent)
|
: m_parentItem(parent)
|
||||||
, m_size(0)
|
, m_size(0)
|
||||||
, m_remaining(0)
|
, m_remaining(0)
|
||||||
, m_priority(prio::NORMAL)
|
, m_priority(prio::NORMAL)
|
||||||
, m_progress(0)
|
, m_progress(0)
|
||||||
|
, m_availability(-1.)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
TorrentContentModelItem::~TorrentContentModelItem()
|
TorrentContentModelItem::~TorrentContentModelItem() = default;
|
||||||
|
|
||||||
|
bool TorrentContentModelItem::isRootItem() const
|
||||||
{
|
{
|
||||||
|
return !m_parentItem;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString TorrentContentModelItem::name() const
|
QString TorrentContentModelItem::name() const
|
||||||
{
|
{
|
||||||
Q_ASSERT(!isRootItem());
|
Q_ASSERT(!isRootItem());
|
||||||
return m_name;
|
return m_name;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TorrentContentModelItem::setName(const QString& name)
|
void TorrentContentModelItem::setName(const QString &name)
|
||||||
{
|
{
|
||||||
Q_ASSERT(!isRootItem());
|
Q_ASSERT(!isRootItem());
|
||||||
m_name = name;
|
m_name = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
qulonglong TorrentContentModelItem::size() const
|
qulonglong TorrentContentModelItem::size() const
|
||||||
{
|
{
|
||||||
Q_ASSERT(!isRootItem());
|
Q_ASSERT(!isRootItem());
|
||||||
|
|
||||||
return m_size;
|
return m_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
qreal TorrentContentModelItem::progress() const
|
qreal TorrentContentModelItem::progress() const
|
||||||
@ -81,47 +85,57 @@ qulonglong TorrentContentModelItem::remaining() const
|
|||||||
return m_remaining;
|
return m_remaining;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
qreal TorrentContentModelItem::availability() const
|
||||||
|
{
|
||||||
|
Q_ASSERT(!isRootItem());
|
||||||
|
|
||||||
|
return m_size > 0 ? m_availability : 0.;
|
||||||
|
}
|
||||||
|
|
||||||
int TorrentContentModelItem::priority() const
|
int TorrentContentModelItem::priority() const
|
||||||
{
|
{
|
||||||
Q_ASSERT(!isRootItem());
|
Q_ASSERT(!isRootItem());
|
||||||
return m_priority;
|
return m_priority;
|
||||||
}
|
}
|
||||||
|
|
||||||
int TorrentContentModelItem::columnCount() const
|
int TorrentContentModelItem::columnCount() const
|
||||||
{
|
{
|
||||||
return NB_COL;
|
return NB_COL;
|
||||||
}
|
}
|
||||||
|
|
||||||
QVariant TorrentContentModelItem::data(int column) const
|
QVariant TorrentContentModelItem::data(int column) const
|
||||||
{
|
{
|
||||||
if (isRootItem())
|
if (isRootItem())
|
||||||
return m_itemData.value(column);
|
return m_itemData.value(column);
|
||||||
|
|
||||||
switch(column) {
|
switch (column) {
|
||||||
case COL_NAME:
|
case COL_NAME:
|
||||||
return m_name;
|
return m_name;
|
||||||
case COL_PRIO:
|
case COL_PRIO:
|
||||||
return m_priority;
|
return m_priority;
|
||||||
case COL_PROGRESS:
|
case COL_PROGRESS:
|
||||||
return progress();
|
return progress();
|
||||||
case COL_SIZE:
|
case COL_SIZE:
|
||||||
return m_size;
|
return m_size;
|
||||||
case COL_REMAINING:
|
case COL_REMAINING:
|
||||||
return remaining();
|
return remaining();
|
||||||
default:
|
case COL_AVAILABILITY:
|
||||||
Q_ASSERT(false);
|
return availability();
|
||||||
return QVariant();
|
default:
|
||||||
}
|
Q_ASSERT(false);
|
||||||
|
return QVariant();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int TorrentContentModelItem::row() const
|
int TorrentContentModelItem::row() const
|
||||||
{
|
{
|
||||||
if (m_parentItem)
|
if (m_parentItem)
|
||||||
return m_parentItem->children().indexOf(const_cast<TorrentContentModelItem*>(this));
|
return m_parentItem->children().indexOf(const_cast<TorrentContentModelItem *>(this));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
TorrentContentModelFolder* TorrentContentModelItem::parent() const
|
TorrentContentModelFolder *TorrentContentModelItem::parent() const
|
||||||
{
|
{
|
||||||
return m_parentItem;
|
return m_parentItem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,48 +34,74 @@
|
|||||||
#include <QList>
|
#include <QList>
|
||||||
#include <QVariant>
|
#include <QVariant>
|
||||||
|
|
||||||
namespace prio {
|
namespace prio
|
||||||
enum FilePriority {IGNORED=0, NORMAL=1, HIGH=6, MAXIMUM=7, MIXED=-1};
|
{
|
||||||
|
enum FilePriority
|
||||||
|
{
|
||||||
|
IGNORED=0,
|
||||||
|
NORMAL=1,
|
||||||
|
HIGH=6,
|
||||||
|
MAXIMUM=7,
|
||||||
|
MIXED=-1
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
class TorrentContentModelFolder;
|
class TorrentContentModelFolder;
|
||||||
|
|
||||||
class TorrentContentModelItem {
|
class TorrentContentModelItem
|
||||||
|
{
|
||||||
public:
|
public:
|
||||||
enum TreeItemColumns {COL_NAME, COL_SIZE, COL_PROGRESS, COL_PRIO, COL_REMAINING, NB_COL};
|
enum TreeItemColumns
|
||||||
enum ItemType { FileType, FolderType };
|
{
|
||||||
|
COL_NAME,
|
||||||
|
COL_SIZE,
|
||||||
|
COL_PROGRESS,
|
||||||
|
COL_PRIO,
|
||||||
|
COL_REMAINING,
|
||||||
|
COL_AVAILABILITY,
|
||||||
|
NB_COL
|
||||||
|
};
|
||||||
|
|
||||||
TorrentContentModelItem(TorrentContentModelFolder* parent);
|
enum ItemType
|
||||||
virtual ~TorrentContentModelItem();
|
{
|
||||||
|
FileType,
|
||||||
|
FolderType
|
||||||
|
};
|
||||||
|
|
||||||
inline bool isRootItem() const { return !m_parentItem; }
|
TorrentContentModelItem(TorrentContentModelFolder *parent);
|
||||||
TorrentContentModelFolder* parent() const;
|
virtual ~TorrentContentModelItem();
|
||||||
virtual ItemType itemType() const = 0;
|
|
||||||
|
|
||||||
QString name() const;
|
bool isRootItem() const;
|
||||||
void setName(const QString& name);
|
TorrentContentModelFolder *parent() const;
|
||||||
|
virtual ItemType itemType() const = 0;
|
||||||
|
|
||||||
qulonglong size() const;
|
QString name() const;
|
||||||
qreal progress() const;
|
void setName(const QString &name);
|
||||||
qulonglong remaining() const;
|
|
||||||
|
|
||||||
int priority() const;
|
qulonglong size() const;
|
||||||
virtual void setPriority(int new_prio, bool update_parent = true) = 0;
|
qreal progress() const;
|
||||||
|
qulonglong remaining() const;
|
||||||
|
|
||||||
int columnCount() const;
|
qreal availability() const;
|
||||||
QVariant data(int column) const;
|
|
||||||
int row() const;
|
int priority() const;
|
||||||
|
virtual void setPriority(int newPriority, bool updateParent = true) = 0;
|
||||||
|
|
||||||
|
int columnCount() const;
|
||||||
|
QVariant data(int column) const;
|
||||||
|
int row() const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
TorrentContentModelFolder* m_parentItem;
|
TorrentContentModelFolder *m_parentItem;
|
||||||
// Root item members
|
// Root item members
|
||||||
QList<QVariant> m_itemData;
|
QList<QVariant> m_itemData;
|
||||||
// Non-root item members
|
// Non-root item members
|
||||||
QString m_name;
|
QString m_name;
|
||||||
qulonglong m_size;
|
qulonglong m_size;
|
||||||
qulonglong m_remaining;
|
qulonglong m_remaining;
|
||||||
int m_priority;
|
int m_priority;
|
||||||
qreal m_progress;
|
qreal m_progress;
|
||||||
|
qreal m_availability;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // TORRENTCONTENTMODELITEM_H
|
#endif // TORRENTCONTENTMODELITEM_H
|
||||||
|
Loading…
x
Reference in New Issue
Block a user