Christophe Dumez
13 years ago
12 changed files with 1005 additions and 696 deletions
@ -0,0 +1,98 @@ |
|||||||
|
/*
|
||||||
|
* Bittorrent Client using Qt4 and libtorrent. |
||||||
|
* Copyright (C) 2006-2012 Christophe Dumez |
||||||
|
* |
||||||
|
* This program is free software; you can redistribute it and/or |
||||||
|
* modify it under the terms of the GNU General Public License |
||||||
|
* as published by the Free Software Foundation; either version 2 |
||||||
|
* of the License, or (at your option) any later version. |
||||||
|
* |
||||||
|
* This program is distributed in the hope that it will be useful, |
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||||
|
* GNU General Public License for more details. |
||||||
|
* |
||||||
|
* You should have received a copy of the GNU General Public License |
||||||
|
* along with this program; if not, write to the Free Software |
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
||||||
|
* |
||||||
|
* In addition, as a special exception, the copyright holders give permission to |
||||||
|
* link this program with the OpenSSL project's "OpenSSL" library (or with |
||||||
|
* modified versions of it that use the same license as the "OpenSSL" library), |
||||||
|
* and distribute the linked executables. You must obey the GNU General Public |
||||||
|
* License in all respects for all of the code used other than "OpenSSL". If you |
||||||
|
* modify file(s), you may extend this exception to your version of the file(s), |
||||||
|
* but you are not obligated to do so. If you do not wish to do so, delete this |
||||||
|
* exception statement from your version. |
||||||
|
* |
||||||
|
* Contact : chris@qbittorrent.org |
||||||
|
*/ |
||||||
|
|
||||||
|
#include "torrentcontentfiltermodel.h" |
||||||
|
#include "torrentcontentmodel.h" |
||||||
|
|
||||||
|
TorrentContentFilterModel::TorrentContentFilterModel(QObject *parent): |
||||||
|
QSortFilterProxyModel(parent), m_model(new TorrentContentModel(this)) |
||||||
|
{ |
||||||
|
connect(m_model, SIGNAL(filteredFilesChanged()), this, SIGNAL(filteredFilesChanged())); |
||||||
|
setSourceModel(m_model); |
||||||
|
// Filter settings
|
||||||
|
setFilterCaseSensitivity(Qt::CaseInsensitive); |
||||||
|
setFilterKeyColumn(TorrentContentModelItem::COL_NAME); |
||||||
|
setFilterRole(Qt::DisplayRole); |
||||||
|
setDynamicSortFilter(true); |
||||||
|
setSortCaseSensitivity(Qt::CaseInsensitive); |
||||||
|
} |
||||||
|
|
||||||
|
TorrentContentFilterModel::~TorrentContentFilterModel() |
||||||
|
{ |
||||||
|
delete m_model; |
||||||
|
} |
||||||
|
|
||||||
|
TorrentContentModel* TorrentContentFilterModel::model() const |
||||||
|
{ |
||||||
|
return m_model; |
||||||
|
} |
||||||
|
|
||||||
|
TorrentContentModelItem::FileType TorrentContentFilterModel::getType(const QModelIndex& index) const |
||||||
|
{ |
||||||
|
return m_model->getType(mapToSource(index)); |
||||||
|
} |
||||||
|
|
||||||
|
int TorrentContentFilterModel::getFileIndex(const QModelIndex& index) const |
||||||
|
{ |
||||||
|
return m_model->getFileIndex(mapToSource(index)); |
||||||
|
} |
||||||
|
|
||||||
|
QModelIndex TorrentContentFilterModel::parent(const QModelIndex& child) const |
||||||
|
{ |
||||||
|
if (!child.isValid()) return QModelIndex(); |
||||||
|
QModelIndex sourceParent = m_model->parent(mapToSource(child)); |
||||||
|
if (!sourceParent.isValid()) return QModelIndex(); |
||||||
|
return mapFromSource(sourceParent); |
||||||
|
} |
||||||
|
|
||||||
|
bool TorrentContentFilterModel::filterAcceptsRow(int source_row, const QModelIndex& source_parent) const |
||||||
|
{ |
||||||
|
if (m_model->getType(m_model->index(source_row, 0, source_parent)) == TorrentContentModelItem::FOLDER) { |
||||||
|
// always accept folders, since we want to filter their children
|
||||||
|
return true; |
||||||
|
} |
||||||
|
return QSortFilterProxyModel::filterAcceptsRow(source_row, source_parent); |
||||||
|
} |
||||||
|
|
||||||
|
void TorrentContentFilterModel::selectAll() |
||||||
|
{ |
||||||
|
for (int i=0; i<rowCount(); ++i) { |
||||||
|
setData(index(i, 0), Qt::Checked, Qt::CheckStateRole); |
||||||
|
} |
||||||
|
emit dataChanged(index(0,0), index(rowCount(), columnCount())); |
||||||
|
} |
||||||
|
|
||||||
|
void TorrentContentFilterModel::selectNone() |
||||||
|
{ |
||||||
|
for (int i=0; i<rowCount(); ++i) { |
||||||
|
setData(index(i, 0), Qt::Unchecked, Qt::CheckStateRole); |
||||||
|
} |
||||||
|
emit dataChanged(index(0,0), index(rowCount(), columnCount())); |
||||||
|
} |
@ -0,0 +1,65 @@ |
|||||||
|
/*
|
||||||
|
* Bittorrent Client using Qt4 and libtorrent. |
||||||
|
* Copyright (C) 2006-2012 Christophe Dumez |
||||||
|
* |
||||||
|
* This program is free software; you can redistribute it and/or |
||||||
|
* modify it under the terms of the GNU General Public License |
||||||
|
* as published by the Free Software Foundation; either version 2 |
||||||
|
* of the License, or (at your option) any later version. |
||||||
|
* |
||||||
|
* This program is distributed in the hope that it will be useful, |
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||||
|
* GNU General Public License for more details. |
||||||
|
* |
||||||
|
* You should have received a copy of the GNU General Public License |
||||||
|
* along with this program; if not, write to the Free Software |
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
||||||
|
* |
||||||
|
* In addition, as a special exception, the copyright holders give permission to |
||||||
|
* link this program with the OpenSSL project's "OpenSSL" library (or with |
||||||
|
* modified versions of it that use the same license as the "OpenSSL" library), |
||||||
|
* and distribute the linked executables. You must obey the GNU General Public |
||||||
|
* License in all respects for all of the code used other than "OpenSSL". If you |
||||||
|
* modify file(s), you may extend this exception to your version of the file(s), |
||||||
|
* but you are not obligated to do so. If you do not wish to do so, delete this |
||||||
|
* exception statement from your version. |
||||||
|
* |
||||||
|
* Contact : chris@qbittorrent.org |
||||||
|
*/ |
||||||
|
|
||||||
|
#ifndef TORRENTCONTENTFILTERMODEL_H |
||||||
|
#define TORRENTCONTENTFILTERMODEL_H |
||||||
|
|
||||||
|
#include <QSortFilterProxyModel> |
||||||
|
#include "torrentcontentmodelitem.h" |
||||||
|
|
||||||
|
class TorrentContentModel; |
||||||
|
|
||||||
|
class TorrentContentFilterModel: public QSortFilterProxyModel { |
||||||
|
Q_OBJECT |
||||||
|
|
||||||
|
public: |
||||||
|
TorrentContentFilterModel(QObject *parent = 0); |
||||||
|
virtual ~TorrentContentFilterModel(); |
||||||
|
|
||||||
|
TorrentContentModel* model() const; |
||||||
|
TorrentContentModelItem::FileType getType(const QModelIndex& index) const; |
||||||
|
int getFileIndex(const QModelIndex& index) const; |
||||||
|
virtual QModelIndex parent(const QModelIndex& child) const; |
||||||
|
|
||||||
|
signals: |
||||||
|
void filteredFilesChanged(); |
||||||
|
|
||||||
|
protected: |
||||||
|
virtual bool filterAcceptsRow(int source_row, const QModelIndex& source_parent) const; |
||||||
|
|
||||||
|
public slots: |
||||||
|
void selectAll(); |
||||||
|
void selectNone(); |
||||||
|
|
||||||
|
private: |
||||||
|
TorrentContentModel *m_model; |
||||||
|
}; |
||||||
|
|
||||||
|
#endif // TORRENTCONTENTFILTERMODEL_H
|
@ -0,0 +1,325 @@ |
|||||||
|
/*
|
||||||
|
* Bittorrent Client using Qt4 and libtorrent. |
||||||
|
* Copyright (C) 2006-2012 Christophe Dumez |
||||||
|
* |
||||||
|
* This program is free software; you can redistribute it and/or |
||||||
|
* modify it under the terms of the GNU General Public License |
||||||
|
* as published by the Free Software Foundation; either version 2 |
||||||
|
* of the License, or (at your option) any later version. |
||||||
|
* |
||||||
|
* This program is distributed in the hope that it will be useful, |
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||||
|
* GNU General Public License for more details. |
||||||
|
* |
||||||
|
* You should have received a copy of the GNU General Public License |
||||||
|
* along with this program; if not, write to the Free Software |
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
||||||
|
* |
||||||
|
* In addition, as a special exception, the copyright holders give permission to |
||||||
|
* link this program with the OpenSSL project's "OpenSSL" library (or with |
||||||
|
* modified versions of it that use the same license as the "OpenSSL" library), |
||||||
|
* and distribute the linked executables. You must obey the GNU General Public |
||||||
|
* License in all respects for all of the code used other than "OpenSSL". If you |
||||||
|
* modify file(s), you may extend this exception to your version of the file(s), |
||||||
|
* but you are not obligated to do so. If you do not wish to do so, delete this |
||||||
|
* exception statement from your version. |
||||||
|
* |
||||||
|
* Contact : chris@qbittorrent.org |
||||||
|
*/ |
||||||
|
|
||||||
|
#include "iconprovider.h" |
||||||
|
#include "misc.h" |
||||||
|
#include "torrentcontentmodel.h" |
||||||
|
#include "torrentcontentmodelitem.h" |
||||||
|
#include <QDir> |
||||||
|
|
||||||
|
TorrentContentModel::TorrentContentModel(QObject *parent): |
||||||
|
QAbstractItemModel(parent), files_index(0) |
||||||
|
{ |
||||||
|
QList<QVariant> rootData; |
||||||
|
rootData << tr("Name") << tr("Size") << tr("Progress") << tr("Priority"); |
||||||
|
rootItem = new TorrentContentModelItem(rootData); |
||||||
|
} |
||||||
|
|
||||||
|
TorrentContentModel::~TorrentContentModel() |
||||||
|
{ |
||||||
|
if (files_index) |
||||||
|
delete [] files_index; |
||||||
|
delete rootItem; |
||||||
|
} |
||||||
|
|
||||||
|
void TorrentContentModel::updateFilesProgress(const std::vector<libtorrent::size_type>& fp) |
||||||
|
{ |
||||||
|
emit layoutAboutToBeChanged(); |
||||||
|
for (unsigned int i=0; i<fp.size(); ++i) { |
||||||
|
Q_ASSERT(fp[i] >= 0); |
||||||
|
files_index[i]->setProgress(fp[i]); |
||||||
|
} |
||||||
|
emit dataChanged(index(0,0), index(rowCount(), columnCount())); |
||||||
|
} |
||||||
|
|
||||||
|
void TorrentContentModel::updateFilesPriorities(const std::vector<int> &fprio) |
||||||
|
{ |
||||||
|
emit layoutAboutToBeChanged(); |
||||||
|
for (unsigned int i=0; i<fprio.size(); ++i) { |
||||||
|
//qDebug("Called updateFilesPriorities with %d", fprio[i]);
|
||||||
|
files_index[i]->setPriority(fprio[i]); |
||||||
|
} |
||||||
|
emit dataChanged(index(0,0), index(rowCount(), columnCount())); |
||||||
|
} |
||||||
|
|
||||||
|
std::vector<int> TorrentContentModel::getFilesPriorities(unsigned int nbFiles) const |
||||||
|
{ |
||||||
|
std::vector<int> prio; |
||||||
|
for (unsigned int i=0; i<nbFiles; ++i) { |
||||||
|
//qDebug("Called getFilesPriorities: %d", files_index[i]->getPriority());
|
||||||
|
prio.push_back(files_index[i]->getPriority()); |
||||||
|
} |
||||||
|
return prio; |
||||||
|
} |
||||||
|
|
||||||
|
bool TorrentContentModel::allFiltered() const |
||||||
|
{ |
||||||
|
for (int i=0; i<rootItem->childCount(); ++i) { |
||||||
|
if (rootItem->child(i)->getPriority() != prio::IGNORED) |
||||||
|
return false; |
||||||
|
} |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
int TorrentContentModel::columnCount(const QModelIndex& parent) const |
||||||
|
{ |
||||||
|
if (parent.isValid()) |
||||||
|
return static_cast<TorrentContentModelItem*>(parent.internalPointer())->columnCount(); |
||||||
|
else |
||||||
|
return rootItem->columnCount(); |
||||||
|
} |
||||||
|
|
||||||
|
bool TorrentContentModel::setData(const QModelIndex& index, const QVariant& value, int role) |
||||||
|
{ |
||||||
|
if (!index.isValid()) |
||||||
|
return false; |
||||||
|
|
||||||
|
if (index.column() == 0 && role == Qt::CheckStateRole) { |
||||||
|
TorrentContentModelItem *item = static_cast<TorrentContentModelItem*>(index.internalPointer()); |
||||||
|
qDebug("setData(%s, %d", qPrintable(item->getName()), value.toInt()); |
||||||
|
if (item->getPriority() != value.toInt()) { |
||||||
|
if (value.toInt() == Qt::PartiallyChecked) |
||||||
|
item->setPriority(prio::PARTIAL); |
||||||
|
else if (value.toInt() == Qt::Unchecked) |
||||||
|
item->setPriority(prio::IGNORED); |
||||||
|
else |
||||||
|
item->setPriority(prio::NORMAL); |
||||||
|
emit dataChanged(this->index(0,0), this->index(rowCount(), columnCount())); |
||||||
|
emit filteredFilesChanged(); |
||||||
|
} |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
if (role == Qt::EditRole) { |
||||||
|
TorrentContentModelItem *item = static_cast<TorrentContentModelItem*>(index.internalPointer()); |
||||||
|
switch(index.column()) { |
||||||
|
case TorrentContentModelItem::COL_NAME: |
||||||
|
item->setName(value.toString()); |
||||||
|
break; |
||||||
|
case TorrentContentModelItem::COL_SIZE: |
||||||
|
item->setSize(value.toULongLong()); |
||||||
|
break; |
||||||
|
case TorrentContentModelItem::COL_PROGRESS: |
||||||
|
item->setProgress(value.toDouble()); |
||||||
|
break; |
||||||
|
case TorrentContentModelItem::COL_PRIO: |
||||||
|
item->setPriority(value.toInt()); |
||||||
|
break; |
||||||
|
default: |
||||||
|
return false; |
||||||
|
} |
||||||
|
emit dataChanged(index, index); |
||||||
|
return true; |
||||||
|
} |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
TorrentContentModelItem::FileType TorrentContentModel::getType(const QModelIndex& index) const |
||||||
|
{ |
||||||
|
const TorrentContentModelItem *item = static_cast<const TorrentContentModelItem*>(index.internalPointer()); |
||||||
|
return item->getType(); |
||||||
|
} |
||||||
|
|
||||||
|
int TorrentContentModel::getFileIndex(const QModelIndex& index) |
||||||
|
{ |
||||||
|
TorrentContentModelItem *item = static_cast<TorrentContentModelItem*>(index.internalPointer()); |
||||||
|
return item->getFileIndex(); |
||||||
|
} |
||||||
|
|
||||||
|
QVariant TorrentContentModel::data(const QModelIndex &index, int role) const |
||||||
|
{ |
||||||
|
if (!index.isValid()) |
||||||
|
return QVariant(); |
||||||
|
|
||||||
|
TorrentContentModelItem *item = static_cast<TorrentContentModelItem*>(index.internalPointer()); |
||||||
|
if (index.column() == 0 && role == Qt::DecorationRole) { |
||||||
|
if (item->isFolder()) |
||||||
|
return IconProvider::instance()->getIcon("inode-directory"); |
||||||
|
else |
||||||
|
return IconProvider::instance()->getIcon("text-plain"); |
||||||
|
} |
||||||
|
if (index.column() == 0 && role == Qt::CheckStateRole) { |
||||||
|
if (item->data(TorrentContentModelItem::COL_PRIO).toInt() == prio::IGNORED) |
||||||
|
return Qt::Unchecked; |
||||||
|
if (item->data(TorrentContentModelItem::COL_PRIO).toInt() == prio::PARTIAL) |
||||||
|
return Qt::PartiallyChecked; |
||||||
|
return Qt::Checked; |
||||||
|
} |
||||||
|
if (role != Qt::DisplayRole) |
||||||
|
return QVariant(); |
||||||
|
|
||||||
|
return item->data(index.column()); |
||||||
|
} |
||||||
|
|
||||||
|
Qt::ItemFlags TorrentContentModel::flags(const QModelIndex& index) const |
||||||
|
{ |
||||||
|
if (!index.isValid()) |
||||||
|
return 0; |
||||||
|
|
||||||
|
if (getType(index) == TorrentContentModelItem::FOLDER) |
||||||
|
return Qt::ItemIsEditable | Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable | Qt::ItemIsTristate; |
||||||
|
return Qt::ItemIsEditable | Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable; |
||||||
|
} |
||||||
|
|
||||||
|
QVariant TorrentContentModel::headerData(int section, Qt::Orientation orientation, int role) const |
||||||
|
{ |
||||||
|
if (orientation == Qt::Horizontal && role == Qt::DisplayRole) |
||||||
|
return rootItem->data(section); |
||||||
|
|
||||||
|
return QVariant(); |
||||||
|
} |
||||||
|
|
||||||
|
QModelIndex TorrentContentModel::index(int row, int column, const QModelIndex& parent) const |
||||||
|
{ |
||||||
|
if (parent.isValid() && parent.column() != 0) |
||||||
|
return QModelIndex(); |
||||||
|
|
||||||
|
if (column >= TorrentContentModelItem::NB_COL) |
||||||
|
return QModelIndex(); |
||||||
|
|
||||||
|
TorrentContentModelItem *parentItem; |
||||||
|
|
||||||
|
if (!parent.isValid()) |
||||||
|
parentItem = rootItem; |
||||||
|
else |
||||||
|
parentItem = static_cast<TorrentContentModelItem*>(parent.internalPointer()); |
||||||
|
Q_ASSERT(parentItem); |
||||||
|
if (row >= parentItem->childCount()) |
||||||
|
return QModelIndex(); |
||||||
|
|
||||||
|
TorrentContentModelItem *childItem = parentItem->child(row); |
||||||
|
if (childItem) { |
||||||
|
return createIndex(row, column, childItem); |
||||||
|
} else { |
||||||
|
return QModelIndex(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
QModelIndex TorrentContentModel::parent(const QModelIndex& index) const |
||||||
|
{ |
||||||
|
if (!index.isValid()) |
||||||
|
return QModelIndex(); |
||||||
|
|
||||||
|
TorrentContentModelItem *childItem = static_cast<TorrentContentModelItem*>(index.internalPointer()); |
||||||
|
if (!childItem) return QModelIndex(); |
||||||
|
TorrentContentModelItem *parentItem = childItem->parent(); |
||||||
|
|
||||||
|
if (parentItem == rootItem) |
||||||
|
return QModelIndex(); |
||||||
|
|
||||||
|
return createIndex(parentItem->row(), 0, parentItem); |
||||||
|
} |
||||||
|
|
||||||
|
int TorrentContentModel::rowCount(const QModelIndex& parent) const |
||||||
|
{ |
||||||
|
TorrentContentModelItem *parentItem; |
||||||
|
|
||||||
|
if (parent.column() > 0) |
||||||
|
return 0; |
||||||
|
|
||||||
|
if (!parent.isValid()) |
||||||
|
parentItem = rootItem; |
||||||
|
else |
||||||
|
parentItem = static_cast<TorrentContentModelItem*>(parent.internalPointer()); |
||||||
|
|
||||||
|
return parentItem->childCount(); |
||||||
|
} |
||||||
|
|
||||||
|
void TorrentContentModel::clear() |
||||||
|
{ |
||||||
|
qDebug("clear called"); |
||||||
|
beginResetModel(); |
||||||
|
if (files_index) { |
||||||
|
delete [] files_index; |
||||||
|
files_index = 0; |
||||||
|
} |
||||||
|
rootItem->deleteAllChildren(); |
||||||
|
endResetModel(); |
||||||
|
} |
||||||
|
|
||||||
|
void TorrentContentModel::setupModelData(const libtorrent::torrent_info &t) |
||||||
|
{ |
||||||
|
qDebug("setup model data called"); |
||||||
|
if (t.num_files() == 0) |
||||||
|
return; |
||||||
|
|
||||||
|
emit layoutAboutToBeChanged(); |
||||||
|
// Initialize files_index array
|
||||||
|
qDebug("Torrent contains %d files", t.num_files()); |
||||||
|
files_index = new TorrentContentModelItem*[t.num_files()]; |
||||||
|
|
||||||
|
TorrentContentModelItem *parent = this->rootItem; |
||||||
|
TorrentContentModelItem *root_folder = parent; |
||||||
|
TorrentContentModelItem *current_parent; |
||||||
|
|
||||||
|
// Iterate over files
|
||||||
|
for (int i=0; i<t.num_files(); ++i) { |
||||||
|
libtorrent::file_entry fentry = t.file_at(i); |
||||||
|
current_parent = root_folder; |
||||||
|
#if LIBTORRENT_VERSION_MINOR >= 16 |
||||||
|
QString path = QDir::cleanPath(misc::toQStringU(fentry.path)).replace("\\", "/"); |
||||||
|
#else |
||||||
|
QString path = QDir::cleanPath(misc::toQStringU(fentry.path.string())).replace("\\", "/"); |
||||||
|
#endif |
||||||
|
// Iterate of parts of the path to create necessary folders
|
||||||
|
QStringList pathFolders = path.split("/"); |
||||||
|
pathFolders.removeAll(".unwanted"); |
||||||
|
pathFolders.takeLast(); |
||||||
|
foreach (const QString &pathPart, pathFolders) { |
||||||
|
TorrentContentModelItem *new_parent = current_parent->childWithName(pathPart); |
||||||
|
if (!new_parent) { |
||||||
|
new_parent = new TorrentContentModelItem(pathPart, current_parent); |
||||||
|
} |
||||||
|
current_parent = new_parent; |
||||||
|
} |
||||||
|
// Actually create the file
|
||||||
|
TorrentContentModelItem *f = new TorrentContentModelItem(t, fentry, current_parent, i); |
||||||
|
files_index[i] = f; |
||||||
|
} |
||||||
|
emit layoutChanged(); |
||||||
|
} |
||||||
|
|
||||||
|
void TorrentContentModel::selectAll() |
||||||
|
{ |
||||||
|
for (int i=0; i<rootItem->childCount(); ++i) { |
||||||
|
TorrentContentModelItem *child = rootItem->child(i); |
||||||
|
if (child->getPriority() == prio::IGNORED) |
||||||
|
child->setPriority(prio::NORMAL); |
||||||
|
} |
||||||
|
emit dataChanged(index(0,0), index(rowCount(), columnCount())); |
||||||
|
} |
||||||
|
|
||||||
|
void TorrentContentModel::selectNone() |
||||||
|
{ |
||||||
|
for (int i=0; i<rootItem->childCount(); ++i) { |
||||||
|
rootItem->child(i)->setPriority(prio::IGNORED); |
||||||
|
} |
||||||
|
emit dataChanged(index(0,0), index(rowCount(), columnCount())); |
||||||
|
} |
@ -0,0 +1,76 @@ |
|||||||
|
/*
|
||||||
|
* Bittorrent Client using Qt4 and libtorrent. |
||||||
|
* Copyright (C) 2006-2012 Christophe Dumez |
||||||
|
* |
||||||
|
* This program is free software; you can redistribute it and/or |
||||||
|
* modify it under the terms of the GNU General Public License |
||||||
|
* as published by the Free Software Foundation; either version 2 |
||||||
|
* of the License, or (at your option) any later version. |
||||||
|
* |
||||||
|
* This program is distributed in the hope that it will be useful, |
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||||
|
* GNU General Public License for more details. |
||||||
|
* |
||||||
|
* You should have received a copy of the GNU General Public License |
||||||
|
* along with this program; if not, write to the Free Software |
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
||||||
|
* |
||||||
|
* In addition, as a special exception, the copyright holders give permission to |
||||||
|
* link this program with the OpenSSL project's "OpenSSL" library (or with |
||||||
|
* modified versions of it that use the same license as the "OpenSSL" library), |
||||||
|
* and distribute the linked executables. You must obey the GNU General Public |
||||||
|
* License in all respects for all of the code used other than "OpenSSL". If you |
||||||
|
* modify file(s), you may extend this exception to your version of the file(s), |
||||||
|
* but you are not obligated to do so. If you do not wish to do so, delete this |
||||||
|
* exception statement from your version. |
||||||
|
* |
||||||
|
* Contact : chris@qbittorrent.org |
||||||
|
*/ |
||||||
|
|
||||||
|
#ifndef TORRENTCONTENTMODEL_H |
||||||
|
#define TORRENTCONTENTMODEL_H |
||||||
|
|
||||||
|
#include <QAbstractItemModel> |
||||||
|
#include <QModelIndex> |
||||||
|
#include <QVariant> |
||||||
|
#include <libtorrent/torrent_info.hpp> |
||||||
|
#include "torrentcontentmodelitem.h" |
||||||
|
|
||||||
|
class TorrentContentModel: public QAbstractItemModel { |
||||||
|
Q_OBJECT |
||||||
|
|
||||||
|
private: |
||||||
|
TorrentContentModelItem *rootItem; |
||||||
|
TorrentContentModelItem **files_index; |
||||||
|
|
||||||
|
public: |
||||||
|
TorrentContentModel(QObject *parent = 0); |
||||||
|
~TorrentContentModel(); |
||||||
|
|
||||||
|
void updateFilesProgress(const std::vector<libtorrent::size_type>& fp); |
||||||
|
void updateFilesPriorities(const std::vector<int> &fprio); |
||||||
|
std::vector<int> getFilesPriorities(unsigned int nbFiles) const; |
||||||
|
bool allFiltered() const; |
||||||
|
virtual int columnCount(const QModelIndex &parent=QModelIndex()) const; |
||||||
|
virtual bool setData(const QModelIndex& index, const QVariant& value, int role = Qt::EditRole); |
||||||
|
TorrentContentModelItem::FileType getType(const QModelIndex& index) const; |
||||||
|
int getFileIndex(const QModelIndex& index); |
||||||
|
virtual QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const; |
||||||
|
virtual Qt::ItemFlags flags(const QModelIndex& index) const; |
||||||
|
virtual QVariant headerData(int section, Qt::Orientation orientation, int role) const; |
||||||
|
virtual QModelIndex index(int row, int column, const QModelIndex& parent = QModelIndex()) const; |
||||||
|
virtual QModelIndex parent(const QModelIndex& index) const; |
||||||
|
virtual int rowCount(const QModelIndex& parent = QModelIndex()) const; |
||||||
|
void clear(); |
||||||
|
void setupModelData(const libtorrent::torrent_info& t); |
||||||
|
|
||||||
|
signals: |
||||||
|
void filteredFilesChanged(); |
||||||
|
|
||||||
|
public slots: |
||||||
|
void selectAll(); |
||||||
|
void selectNone(); |
||||||
|
}; |
||||||
|
|
||||||
|
#endif // TORRENTCONTENTMODEL_H
|
@ -0,0 +1,320 @@ |
|||||||
|
/*
|
||||||
|
* Bittorrent Client using Qt4 and libtorrent. |
||||||
|
* Copyright (C) 2006-2012 Christophe Dumez |
||||||
|
* |
||||||
|
* This program is free software; you can redistribute it and/or |
||||||
|
* modify it under the terms of the GNU General Public License |
||||||
|
* as published by the Free Software Foundation; either version 2 |
||||||
|
* of the License, or (at your option) any later version. |
||||||
|
* |
||||||
|
* This program is distributed in the hope that it will be useful, |
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||||
|
* GNU General Public License for more details. |
||||||
|
* |
||||||
|
* You should have received a copy of the GNU General Public License |
||||||
|
* along with this program; if not, write to the Free Software |
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
||||||
|
* |
||||||
|
* In addition, as a special exception, the copyright holders give permission to |
||||||
|
* link this program with the OpenSSL project's "OpenSSL" library (or with |
||||||
|
* modified versions of it that use the same license as the "OpenSSL" library), |
||||||
|
* and distribute the linked executables. You must obey the GNU General Public |
||||||
|
* License in all respects for all of the code used other than "OpenSSL". If you |
||||||
|
* modify file(s), you may extend this exception to your version of the file(s), |
||||||
|
* but you are not obligated to do so. If you do not wish to do so, delete this |
||||||
|
* exception statement from your version. |
||||||
|
* |
||||||
|
* Contact : chris@qbittorrent.org |
||||||
|
*/ |
||||||
|
|
||||||
|
#include "misc.h" |
||||||
|
#include "torrentcontentmodelitem.h" |
||||||
|
#include <QDebug> |
||||||
|
|
||||||
|
TorrentContentModelItem::TorrentContentModelItem(const libtorrent::torrent_info &t, |
||||||
|
const libtorrent::file_entry &f, |
||||||
|
TorrentContentModelItem *parent, |
||||||
|
int file_index): |
||||||
|
m_parentItem(parent), m_type(TFILE), m_fileIndex(file_index), m_totalDone(0) |
||||||
|
{ |
||||||
|
Q_ASSERT(parent); |
||||||
|
|
||||||
|
#if LIBTORRENT_VERSION_MINOR >= 16 |
||||||
|
QString name = misc::fileName(misc::toQStringU(t.files().file_path(f))); |
||||||
|
#else |
||||||
|
Q_UNUSED(t); |
||||||
|
QString name = misc::toQStringU(f.path.filename()); |
||||||
|
#endif |
||||||
|
// Do not display incomplete extensions
|
||||||
|
if (name.endsWith(".!qB")) |
||||||
|
name.chop(4); |
||||||
|
|
||||||
|
m_itemData << name |
||||||
|
<< QVariant((qulonglong)f.size) |
||||||
|
<< 0. |
||||||
|
<< prio::NORMAL; |
||||||
|
|
||||||
|
/* Update parent */ |
||||||
|
m_parentItem->appendChild(this); |
||||||
|
m_parentItem->updateSize(); |
||||||
|
} |
||||||
|
|
||||||
|
TorrentContentModelItem::TorrentContentModelItem(QString name, TorrentContentModelItem *parent): |
||||||
|
m_parentItem(parent), m_type(FOLDER), m_totalDone(0) |
||||||
|
{ |
||||||
|
// Do not display incomplete extensions
|
||||||
|
if (name.endsWith(".!qB")) |
||||||
|
name.chop(4); |
||||||
|
m_itemData << name |
||||||
|
<< 0. |
||||||
|
<< 0. |
||||||
|
<< prio::NORMAL; |
||||||
|
|
||||||
|
/* Update parent */ |
||||||
|
m_parentItem->appendChild(this); |
||||||
|
} |
||||||
|
|
||||||
|
TorrentContentModelItem::TorrentContentModelItem(const QList<QVariant>& data): |
||||||
|
m_parentItem(0), m_type(ROOT), m_itemData(data), m_totalDone(0) |
||||||
|
{ |
||||||
|
Q_ASSERT(data.size() == 4); |
||||||
|
} |
||||||
|
|
||||||
|
TorrentContentModelItem::~TorrentContentModelItem() |
||||||
|
{ |
||||||
|
qDeleteAll(m_childItems); |
||||||
|
} |
||||||
|
|
||||||
|
TorrentContentModelItem::FileType TorrentContentModelItem::getType() const |
||||||
|
{ |
||||||
|
return m_type; |
||||||
|
} |
||||||
|
|
||||||
|
int TorrentContentModelItem::getFileIndex() const |
||||||
|
{ |
||||||
|
Q_ASSERT(m_type == TFILE); |
||||||
|
return m_fileIndex; |
||||||
|
} |
||||||
|
|
||||||
|
void TorrentContentModelItem::deleteAllChildren() |
||||||
|
{ |
||||||
|
Q_ASSERT(m_type == ROOT); |
||||||
|
qDeleteAll(m_childItems); |
||||||
|
m_childItems.clear(); |
||||||
|
} |
||||||
|
|
||||||
|
const QList<TorrentContentModelItem*>& TorrentContentModelItem::children() const |
||||||
|
{ |
||||||
|
return m_childItems; |
||||||
|
} |
||||||
|
|
||||||
|
QString TorrentContentModelItem::getName() const |
||||||
|
{ |
||||||
|
return m_itemData.at(COL_NAME).toString(); |
||||||
|
} |
||||||
|
|
||||||
|
void TorrentContentModelItem::setName(const QString& name) |
||||||
|
{ |
||||||
|
Q_ASSERT(m_type != ROOT); |
||||||
|
m_itemData.replace(COL_NAME, name); |
||||||
|
} |
||||||
|
|
||||||
|
qulonglong TorrentContentModelItem::getSize() const |
||||||
|
{ |
||||||
|
return m_itemData.value(COL_SIZE).toULongLong(); |
||||||
|
} |
||||||
|
|
||||||
|
void TorrentContentModelItem::setSize(qulonglong size) |
||||||
|
{ |
||||||
|
Q_ASSERT (m_type != ROOT); |
||||||
|
if (getSize() == size) |
||||||
|
return; |
||||||
|
m_itemData.replace(COL_SIZE, (qulonglong)size); |
||||||
|
m_parentItem->updateSize(); |
||||||
|
} |
||||||
|
|
||||||
|
void TorrentContentModelItem::updateSize() |
||||||
|
{ |
||||||
|
if (m_type == ROOT) |
||||||
|
return; |
||||||
|
Q_ASSERT(m_type == FOLDER); |
||||||
|
qulonglong size = 0; |
||||||
|
foreach (TorrentContentModelItem* child, m_childItems) { |
||||||
|
if (child->getPriority() != prio::IGNORED) |
||||||
|
size += child->getSize(); |
||||||
|
} |
||||||
|
setSize(size); |
||||||
|
} |
||||||
|
|
||||||
|
void TorrentContentModelItem::setProgress(qulonglong done) |
||||||
|
{ |
||||||
|
Q_ASSERT (m_type != ROOT); |
||||||
|
if (getPriority() == 0) return; |
||||||
|
m_totalDone = done; |
||||||
|
qulonglong size = getSize(); |
||||||
|
Q_ASSERT(m_totalDone <= size); |
||||||
|
qreal progress; |
||||||
|
if (size > 0) |
||||||
|
progress = m_totalDone/(float)size; |
||||||
|
else |
||||||
|
progress = 1.; |
||||||
|
Q_ASSERT(progress >= 0. && progress <= 1.); |
||||||
|
m_itemData.replace(COL_PROGRESS, progress); |
||||||
|
m_parentItem->updateProgress(); |
||||||
|
} |
||||||
|
|
||||||
|
qulonglong TorrentContentModelItem::getTotalDone() const |
||||||
|
{ |
||||||
|
return m_totalDone; |
||||||
|
} |
||||||
|
|
||||||
|
float TorrentContentModelItem::getProgress() const |
||||||
|
{ |
||||||
|
Q_ASSERT (m_type != ROOT); |
||||||
|
if (getPriority() == 0) |
||||||
|
return -1; |
||||||
|
qulonglong size = getSize(); |
||||||
|
if (size > 0) |
||||||
|
return m_totalDone / (float) getSize(); |
||||||
|
return 1.; |
||||||
|
} |
||||||
|
|
||||||
|
void TorrentContentModelItem::updateProgress() |
||||||
|
{ |
||||||
|
if (m_type == ROOT) return; |
||||||
|
Q_ASSERT(m_type == FOLDER); |
||||||
|
m_totalDone = 0; |
||||||
|
foreach (TorrentContentModelItem* child, m_childItems) { |
||||||
|
if (child->getPriority() > 0) |
||||||
|
m_totalDone += child->getTotalDone(); |
||||||
|
} |
||||||
|
//qDebug("Folder: total_done: %llu/%llu", total_done, getSize());
|
||||||
|
Q_ASSERT(m_totalDone <= getSize()); |
||||||
|
setProgress(m_totalDone); |
||||||
|
} |
||||||
|
|
||||||
|
int TorrentContentModelItem::getPriority() const |
||||||
|
{ |
||||||
|
return m_itemData.value(COL_PRIO).toInt(); |
||||||
|
} |
||||||
|
|
||||||
|
void TorrentContentModelItem::setPriority(int new_prio, bool update_parent) |
||||||
|
{ |
||||||
|
Q_ASSERT(new_prio != prio::PARTIAL || m_type == FOLDER); // PARTIAL only applies to folders
|
||||||
|
const int old_prio = getPriority(); |
||||||
|
if (old_prio == new_prio) return; |
||||||
|
qDebug("setPriority(%s, %d)", qPrintable(getName()), new_prio); |
||||||
|
// Reset progress if priority is 0
|
||||||
|
if (new_prio == 0) { |
||||||
|
setProgress(0); |
||||||
|
} |
||||||
|
|
||||||
|
m_itemData.replace(COL_PRIO, new_prio); |
||||||
|
|
||||||
|
// Update parent
|
||||||
|
if (update_parent && m_parentItem) { |
||||||
|
qDebug("Updating parent item"); |
||||||
|
m_parentItem->updateSize(); |
||||||
|
m_parentItem->updateProgress(); |
||||||
|
m_parentItem->updatePriority(); |
||||||
|
} |
||||||
|
|
||||||
|
// Update children
|
||||||
|
if (new_prio != prio::PARTIAL && !m_childItems.empty()) { |
||||||
|
qDebug("Updating children items"); |
||||||
|
foreach (TorrentContentModelItem* child, m_childItems) { |
||||||
|
// Do not update the parent since
|
||||||
|
// the parent is causing the update
|
||||||
|
child->setPriority(new_prio, false); |
||||||
|
} |
||||||
|
} |
||||||
|
if (m_type == FOLDER) { |
||||||
|
updateSize(); |
||||||
|
updateProgress(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// Only non-root folders use this function
|
||||||
|
void TorrentContentModelItem::updatePriority() |
||||||
|
{ |
||||||
|
if (m_type == ROOT) return; |
||||||
|
Q_ASSERT(m_type == FOLDER); |
||||||
|
if (m_childItems.isEmpty()) return; |
||||||
|
// If all children have the same priority
|
||||||
|
// then the folder should have the same
|
||||||
|
// priority
|
||||||
|
const int prio = m_childItems.first()->getPriority(); |
||||||
|
for (int i=1; i<m_childItems.size(); ++i) { |
||||||
|
if (m_childItems.at(i)->getPriority() != prio) { |
||||||
|
setPriority(prio::PARTIAL); |
||||||
|
return; |
||||||
|
} |
||||||
|
} |
||||||
|
// All child items have the same priorrity
|
||||||
|
// Update mine if necessary
|
||||||
|
if (prio != getPriority()) |
||||||
|
setPriority(prio); |
||||||
|
} |
||||||
|
|
||||||
|
TorrentContentModelItem* TorrentContentModelItem::childWithName(const QString& name) const |
||||||
|
{ |
||||||
|
foreach (TorrentContentModelItem *child, m_childItems) { |
||||||
|
if (child->getName() == name) |
||||||
|
return child; |
||||||
|
} |
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
bool TorrentContentModelItem::isFolder() const |
||||||
|
{ |
||||||
|
return (m_type==FOLDER); |
||||||
|
} |
||||||
|
|
||||||
|
void TorrentContentModelItem::appendChild(TorrentContentModelItem *item) |
||||||
|
{ |
||||||
|
Q_ASSERT(item); |
||||||
|
Q_ASSERT(m_type != TFILE); |
||||||
|
int i=0; |
||||||
|
for (i=0; i<m_childItems.size(); ++i) { |
||||||
|
QString newchild_name = item->getName(); |
||||||
|
if (QString::localeAwareCompare(newchild_name, m_childItems.at(i)->getName()) < 0) |
||||||
|
break; |
||||||
|
} |
||||||
|
m_childItems.insert(i, item); |
||||||
|
} |
||||||
|
|
||||||
|
TorrentContentModelItem* TorrentContentModelItem::child(int row) |
||||||
|
{ |
||||||
|
//Q_ASSERT(row >= 0 && row < childItems.size());
|
||||||
|
return m_childItems.value(row, 0); |
||||||
|
} |
||||||
|
|
||||||
|
int TorrentContentModelItem::childCount() const |
||||||
|
{ |
||||||
|
return m_childItems.count(); |
||||||
|
} |
||||||
|
|
||||||
|
int TorrentContentModelItem::columnCount() const |
||||||
|
{ |
||||||
|
return m_itemData.count(); |
||||||
|
} |
||||||
|
|
||||||
|
QVariant TorrentContentModelItem::data(int column) const |
||||||
|
{ |
||||||
|
if (column == COL_PROGRESS && m_type != ROOT) |
||||||
|
return getProgress(); |
||||||
|
return m_itemData.value(column); |
||||||
|
} |
||||||
|
|
||||||
|
int TorrentContentModelItem::row() const |
||||||
|
{ |
||||||
|
if (m_parentItem) |
||||||
|
return m_parentItem->children().indexOf(const_cast<TorrentContentModelItem*>(this)); |
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
TorrentContentModelItem* TorrentContentModelItem::parent() |
||||||
|
{ |
||||||
|
return m_parentItem; |
||||||
|
} |
@ -0,0 +1,102 @@ |
|||||||
|
/*
|
||||||
|
* Bittorrent Client using Qt4 and libtorrent. |
||||||
|
* Copyright (C) 2006-2012 Christophe Dumez |
||||||
|
* |
||||||
|
* This program is free software; you can redistribute it and/or |
||||||
|
* modify it under the terms of the GNU General Public License |
||||||
|
* as published by the Free Software Foundation; either version 2 |
||||||
|
* of the License, or (at your option) any later version. |
||||||
|
* |
||||||
|
* This program is distributed in the hope that it will be useful, |
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||||
|
* GNU General Public License for more details. |
||||||
|
* |
||||||
|
* You should have received a copy of the GNU General Public License |
||||||
|
* along with this program; if not, write to the Free Software |
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
||||||
|
* |
||||||
|
* In addition, as a special exception, the copyright holders give permission to |
||||||
|
* link this program with the OpenSSL project's "OpenSSL" library (or with |
||||||
|
* modified versions of it that use the same license as the "OpenSSL" library), |
||||||
|
* and distribute the linked executables. You must obey the GNU General Public |
||||||
|
* License in all respects for all of the code used other than "OpenSSL". If you |
||||||
|
* modify file(s), you may extend this exception to your version of the file(s), |
||||||
|
* but you are not obligated to do so. If you do not wish to do so, delete this |
||||||
|
* exception statement from your version. |
||||||
|
* |
||||||
|
* Contact : chris@qbittorrent.org |
||||||
|
*/ |
||||||
|
|
||||||
|
#ifndef TORRENTCONTENTMODELITEM_H |
||||||
|
#define TORRENTCONTENTMODELITEM_H |
||||||
|
|
||||||
|
#include <QList> |
||||||
|
#include <QVariant> |
||||||
|
#include <libtorrent/torrent_info.hpp> |
||||||
|
|
||||||
|
namespace prio { |
||||||
|
enum FilePriority {IGNORED=0, NORMAL=1, HIGH=2, MAXIMUM=7, PARTIAL=-1}; |
||||||
|
} |
||||||
|
|
||||||
|
class TorrentContentModelItem { |
||||||
|
public: |
||||||
|
enum TreeItemColumns {COL_NAME, COL_SIZE, COL_PROGRESS, COL_PRIO, NB_COL}; |
||||||
|
enum FileType {TFILE, FOLDER, ROOT}; |
||||||
|
|
||||||
|
// File Construction
|
||||||
|
TorrentContentModelItem(const libtorrent::torrent_info &t, |
||||||
|
const libtorrent::file_entry &f, |
||||||
|
TorrentContentModelItem *parent, |
||||||
|
int file_index); |
||||||
|
// Folder constructor
|
||||||
|
TorrentContentModelItem(QString name, TorrentContentModelItem *parent = 0); |
||||||
|
// Invisible root item constructor
|
||||||
|
TorrentContentModelItem(const QList<QVariant>& data); |
||||||
|
|
||||||
|
~TorrentContentModelItem(); |
||||||
|
|
||||||
|
FileType getType() const; |
||||||
|
|
||||||
|
int getFileIndex() const; |
||||||
|
|
||||||
|
QString getName() const; |
||||||
|
void setName(const QString& name); |
||||||
|
|
||||||
|
qulonglong getSize() const; |
||||||
|
void setSize(qulonglong size); |
||||||
|
void updateSize(); |
||||||
|
qulonglong getTotalDone() const; |
||||||
|
|
||||||
|
void setProgress(qulonglong done); |
||||||
|
float getProgress() const; |
||||||
|
void updateProgress(); |
||||||
|
|
||||||
|
int getPriority() const; |
||||||
|
void setPriority(int new_prio, bool update_parent=true); |
||||||
|
void updatePriority(); |
||||||
|
|
||||||
|
TorrentContentModelItem* childWithName(const QString& name) const; |
||||||
|
bool isFolder() const; |
||||||
|
|
||||||
|
void appendChild(TorrentContentModelItem *item); |
||||||
|
TorrentContentModelItem *child(int row); |
||||||
|
int childCount() const; |
||||||
|
int columnCount() const; |
||||||
|
QVariant data(int column) const; |
||||||
|
int row() const; |
||||||
|
|
||||||
|
TorrentContentModelItem *parent(); |
||||||
|
void deleteAllChildren(); |
||||||
|
const QList<TorrentContentModelItem*>& children() const; |
||||||
|
|
||||||
|
private: |
||||||
|
TorrentContentModelItem *m_parentItem; |
||||||
|
FileType m_type; |
||||||
|
QList<TorrentContentModelItem*> m_childItems; |
||||||
|
QList<QVariant> m_itemData; |
||||||
|
int m_fileIndex; |
||||||
|
qulonglong m_totalDone; |
||||||
|
}; |
||||||
|
|
||||||
|
#endif // TORRENTCONTENTMODELITEM_H
|
@ -1,684 +0,0 @@ |
|||||||
/*
|
|
||||||
* Bittorrent Client using Qt4 and libtorrent. |
|
||||||
* Copyright (C) 2006 Christophe Dumez |
|
||||||
* |
|
||||||
* This program is free software; you can redistribute it and/or |
|
||||||
* modify it under the terms of the GNU General Public License |
|
||||||
* as published by the Free Software Foundation; either version 2 |
|
||||||
* of the License, or (at your option) any later version. |
|
||||||
* |
|
||||||
* This program is distributed in the hope that it will be useful, |
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
||||||
* GNU General Public License for more details. |
|
||||||
* |
|
||||||
* You should have received a copy of the GNU General Public License |
|
||||||
* along with this program; if not, write to the Free Software |
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
|
||||||
* |
|
||||||
* In addition, as a special exception, the copyright holders give permission to |
|
||||||
* link this program with the OpenSSL project's "OpenSSL" library (or with |
|
||||||
* modified versions of it that use the same license as the "OpenSSL" library), |
|
||||||
* and distribute the linked executables. You must obey the GNU General Public |
|
||||||
* License in all respects for all of the code used other than "OpenSSL". If you |
|
||||||
* modify file(s), you may extend this exception to your version of the file(s), |
|
||||||
* but you are not obligated to do so. If you do not wish to do so, delete this |
|
||||||
* exception statement from your version. |
|
||||||
* |
|
||||||
* Contact : chris@qbittorrent.org |
|
||||||
*/ |
|
||||||
|
|
||||||
#ifndef TORRENTFILESMODEL_H |
|
||||||
#define TORRENTFILESMODEL_H |
|
||||||
|
|
||||||
#include <QAbstractItemModel> |
|
||||||
#include <QModelIndex> |
|
||||||
#include <QVariant> |
|
||||||
#include <QStringList> |
|
||||||
#include <QString> |
|
||||||
#include <QDir> |
|
||||||
#include <QDebug> |
|
||||||
#include <QSortFilterProxyModel> |
|
||||||
#include <libtorrent/torrent_info.hpp> |
|
||||||
#include "proplistdelegate.h" |
|
||||||
#include "iconprovider.h" |
|
||||||
|
|
||||||
namespace prio { |
|
||||||
enum FilePriority {IGNORED=0, NORMAL=1, HIGH=2, MAXIMUM=7, PARTIAL=-1}; |
|
||||||
} |
|
||||||
|
|
||||||
class TorrentFileItem { |
|
||||||
|
|
||||||
public: |
|
||||||
enum TreeItemColumns {COL_NAME, COL_SIZE, COL_PROGRESS, COL_PRIO, NB_COL}; |
|
||||||
enum FileType {TFILE, FOLDER, ROOT}; |
|
||||||
|
|
||||||
private: |
|
||||||
QList<TorrentFileItem*> childItems; |
|
||||||
QList<QVariant> itemData; |
|
||||||
TorrentFileItem *parentItem; |
|
||||||
FileType m_type; |
|
||||||
qulonglong total_done; |
|
||||||
int file_index; |
|
||||||
|
|
||||||
public: |
|
||||||
// File Construction
|
|
||||||
TorrentFileItem(const libtorrent::torrent_info &t, const libtorrent::file_entry &f, TorrentFileItem *parent, int _file_index) { |
|
||||||
Q_ASSERT(parent); |
|
||||||
parentItem = parent; |
|
||||||
m_type = TFILE; |
|
||||||
file_index = _file_index; |
|
||||||
#if LIBTORRENT_VERSION_MINOR >= 16 |
|
||||||
QString name = misc::fileName(misc::toQStringU(t.files().file_path(f))); |
|
||||||
#else |
|
||||||
Q_UNUSED(t); |
|
||||||
QString name = misc::toQStringU(f.path.filename()); |
|
||||||
#endif |
|
||||||
// Do not display incomplete extensions
|
|
||||||
if (name.endsWith(".!qB")) |
|
||||||
name.chop(4); |
|
||||||
itemData << name; |
|
||||||
//qDebug("Created a TreeItem file with name %s", qPrintable(getName()));
|
|
||||||
//qDebug("parent is %s", qPrintable(parent->getName()));
|
|
||||||
itemData << QVariant((qulonglong)f.size); |
|
||||||
total_done = 0; |
|
||||||
itemData << 0.; // Progress;
|
|
||||||
itemData << prio::NORMAL; // Priority
|
|
||||||
if (parent) { |
|
||||||
parent->appendChild(this); |
|
||||||
parent->updateSize(); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
// Folder constructor
|
|
||||||
TorrentFileItem(QString name, TorrentFileItem *parent=0) { |
|
||||||
parentItem = parent; |
|
||||||
m_type = FOLDER; |
|
||||||
// Do not display incomplete extensions
|
|
||||||
if (name.endsWith(".!qB")) |
|
||||||
name.chop(4); |
|
||||||
itemData << name; |
|
||||||
itemData << 0.; // Size
|
|
||||||
itemData << 0.; // Progress;
|
|
||||||
total_done = 0; |
|
||||||
itemData << prio::NORMAL; // Priority
|
|
||||||
if (parent) { |
|
||||||
parent->appendChild(this); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
TorrentFileItem(const QList<QVariant>& data) { |
|
||||||
parentItem = 0; |
|
||||||
m_type = ROOT; |
|
||||||
Q_ASSERT(data.size() == 4); |
|
||||||
itemData = data; |
|
||||||
total_done = 0; |
|
||||||
} |
|
||||||
|
|
||||||
~TorrentFileItem() { |
|
||||||
qDebug("Deleting item: %s", qPrintable(getName())); |
|
||||||
qDeleteAll(childItems); |
|
||||||
} |
|
||||||
|
|
||||||
FileType getType() const { |
|
||||||
return m_type; |
|
||||||
} |
|
||||||
|
|
||||||
int getFileIndex() const { |
|
||||||
Q_ASSERT(m_type ==TFILE); |
|
||||||
return file_index; |
|
||||||
} |
|
||||||
|
|
||||||
void deleteAllChildren() { |
|
||||||
Q_ASSERT(m_type==ROOT); |
|
||||||
qDeleteAll(childItems); |
|
||||||
childItems.clear(); |
|
||||||
Q_ASSERT(childItems.empty()); |
|
||||||
} |
|
||||||
|
|
||||||
QList<TorrentFileItem*> children() const { |
|
||||||
return childItems; |
|
||||||
} |
|
||||||
|
|
||||||
QString getName() const { |
|
||||||
//Q_ASSERT(type != ROOT);
|
|
||||||
return itemData.at(COL_NAME).toString(); |
|
||||||
} |
|
||||||
|
|
||||||
void setName(QString name) { |
|
||||||
Q_ASSERT(m_type != ROOT); |
|
||||||
itemData.replace(COL_NAME, name); |
|
||||||
} |
|
||||||
|
|
||||||
qulonglong getSize() const { |
|
||||||
return itemData.value(COL_SIZE).toULongLong(); |
|
||||||
} |
|
||||||
|
|
||||||
void setSize(qulonglong size) { |
|
||||||
if (getSize() == size) return; |
|
||||||
itemData.replace(COL_SIZE, (qulonglong)size); |
|
||||||
if (parentItem) |
|
||||||
parentItem->updateSize(); |
|
||||||
} |
|
||||||
|
|
||||||
void updateSize() { |
|
||||||
if (m_type == ROOT) return; |
|
||||||
Q_ASSERT(m_type == FOLDER); |
|
||||||
qulonglong size = 0; |
|
||||||
foreach (TorrentFileItem* child, childItems) { |
|
||||||
if (child->getPriority() != prio::IGNORED) |
|
||||||
size += child->getSize(); |
|
||||||
} |
|
||||||
setSize(size); |
|
||||||
} |
|
||||||
|
|
||||||
void setProgress(qulonglong done) { |
|
||||||
Q_ASSERT (m_type != ROOT); |
|
||||||
if (getPriority() == 0) return; |
|
||||||
total_done = done; |
|
||||||
qulonglong size = getSize(); |
|
||||||
Q_ASSERT(total_done <= size); |
|
||||||
qreal progress; |
|
||||||
if (size > 0) |
|
||||||
progress = total_done/(float)size; |
|
||||||
else |
|
||||||
progress = 1.; |
|
||||||
Q_ASSERT(progress >= 0. && progress <= 1.); |
|
||||||
itemData.replace(COL_PROGRESS, progress); |
|
||||||
parentItem->updateProgress(); |
|
||||||
} |
|
||||||
|
|
||||||
qulonglong getTotalDone() const { |
|
||||||
return total_done; |
|
||||||
} |
|
||||||
|
|
||||||
qreal getProgress() const { |
|
||||||
Q_ASSERT (m_type != ROOT); |
|
||||||
if (getPriority() == 0) |
|
||||||
return -1; |
|
||||||
qulonglong size = getSize(); |
|
||||||
if (size > 0) |
|
||||||
return total_done/(float)getSize(); |
|
||||||
return 1.; |
|
||||||
} |
|
||||||
|
|
||||||
void updateProgress() { |
|
||||||
if (m_type == ROOT) return; |
|
||||||
Q_ASSERT(m_type == FOLDER); |
|
||||||
total_done = 0; |
|
||||||
foreach (TorrentFileItem* child, childItems) { |
|
||||||
if (child->getPriority() > 0) |
|
||||||
total_done += child->getTotalDone(); |
|
||||||
} |
|
||||||
//qDebug("Folder: total_done: %llu/%llu", total_done, getSize());
|
|
||||||
Q_ASSERT(total_done <= getSize()); |
|
||||||
setProgress(total_done); |
|
||||||
} |
|
||||||
|
|
||||||
int getPriority() const { |
|
||||||
return itemData.value(COL_PRIO).toInt(); |
|
||||||
} |
|
||||||
|
|
||||||
void setPriority(int new_prio, bool update_parent=true) { |
|
||||||
Q_ASSERT(new_prio != prio::PARTIAL || m_type == FOLDER); // PARTIAL only applies to folders
|
|
||||||
const int old_prio = getPriority(); |
|
||||||
if (old_prio == new_prio) return; |
|
||||||
qDebug("setPriority(%s, %d)", qPrintable(getName()), new_prio); |
|
||||||
// Reset progress if priority is 0
|
|
||||||
if (new_prio == 0) { |
|
||||||
setProgress(0); |
|
||||||
} |
|
||||||
|
|
||||||
itemData.replace(COL_PRIO, new_prio); |
|
||||||
|
|
||||||
// Update parent
|
|
||||||
if (update_parent && parentItem) { |
|
||||||
qDebug("Updating parent item"); |
|
||||||
parentItem->updateSize(); |
|
||||||
parentItem->updateProgress(); |
|
||||||
parentItem->updatePriority(); |
|
||||||
} |
|
||||||
|
|
||||||
// Update children
|
|
||||||
if (new_prio != prio::PARTIAL && !childItems.empty()) { |
|
||||||
qDebug("Updating children items"); |
|
||||||
foreach (TorrentFileItem* child, childItems) { |
|
||||||
// Do not update the parent since
|
|
||||||
// the parent is causing the update
|
|
||||||
child->setPriority(new_prio, false); |
|
||||||
} |
|
||||||
} |
|
||||||
if (m_type == FOLDER) { |
|
||||||
updateSize(); |
|
||||||
updateProgress(); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
// Only non-root folders use this function
|
|
||||||
void updatePriority() { |
|
||||||
if (m_type == ROOT) return; |
|
||||||
Q_ASSERT(m_type == FOLDER); |
|
||||||
if (childItems.isEmpty()) return; |
|
||||||
// If all children have the same priority
|
|
||||||
// then the folder should have the same
|
|
||||||
// priority
|
|
||||||
const int prio = childItems.first()->getPriority(); |
|
||||||
for (int i=1; i<childItems.size(); ++i) { |
|
||||||
if (childItems.at(i)->getPriority() != prio) { |
|
||||||
setPriority(prio::PARTIAL); |
|
||||||
return; |
|
||||||
} |
|
||||||
} |
|
||||||
// All child items have the same priorrity
|
|
||||||
// Update mine if necessary
|
|
||||||
if (prio != getPriority()) |
|
||||||
setPriority(prio); |
|
||||||
} |
|
||||||
|
|
||||||
TorrentFileItem* childWithName(QString name) const { |
|
||||||
foreach (TorrentFileItem *child, childItems) { |
|
||||||
if (child->getName() == name) return child; |
|
||||||
} |
|
||||||
return 0; |
|
||||||
} |
|
||||||
|
|
||||||
bool isFolder() const { |
|
||||||
return (m_type==FOLDER); |
|
||||||
} |
|
||||||
|
|
||||||
void appendChild(TorrentFileItem *item) { |
|
||||||
Q_ASSERT(item); |
|
||||||
//Q_ASSERT(!childWithName(item->getName()));
|
|
||||||
Q_ASSERT(m_type != TFILE); |
|
||||||
int i=0; |
|
||||||
for (i=0; i<childItems.size(); ++i) { |
|
||||||
QString newchild_name = item->getName(); |
|
||||||
if (QString::localeAwareCompare(newchild_name, childItems.at(i)->getName()) < 0) break; |
|
||||||
} |
|
||||||
childItems.insert(i, item); |
|
||||||
//childItems.append(item);
|
|
||||||
//Q_ASSERT(type != ROOT || childItems.size() == 1);
|
|
||||||
} |
|
||||||
|
|
||||||
TorrentFileItem *child(int row) { |
|
||||||
//Q_ASSERT(row >= 0 && row < childItems.size());
|
|
||||||
return childItems.value(row, 0); |
|
||||||
} |
|
||||||
|
|
||||||
int childCount() const { |
|
||||||
return childItems.count(); |
|
||||||
} |
|
||||||
|
|
||||||
int columnCount() const { |
|
||||||
return itemData.count(); |
|
||||||
} |
|
||||||
|
|
||||||
QVariant data(int column) const { |
|
||||||
if (column == COL_PROGRESS && m_type != ROOT) |
|
||||||
return getProgress(); |
|
||||||
return itemData.value(column); |
|
||||||
} |
|
||||||
|
|
||||||
int row() const { |
|
||||||
if (parentItem) { |
|
||||||
return parentItem->children().indexOf(const_cast<TorrentFileItem*>(this)); |
|
||||||
} |
|
||||||
return 0; |
|
||||||
} |
|
||||||
|
|
||||||
TorrentFileItem *parent() { |
|
||||||
return parentItem; |
|
||||||
} |
|
||||||
}; |
|
||||||
|
|
||||||
|
|
||||||
class TorrentFilesModel: public QAbstractItemModel { |
|
||||||
Q_OBJECT |
|
||||||
|
|
||||||
private: |
|
||||||
TorrentFileItem *rootItem; |
|
||||||
TorrentFileItem **files_index; |
|
||||||
|
|
||||||
public: |
|
||||||
TorrentFilesModel(QObject *parent=0): QAbstractItemModel(parent) { |
|
||||||
files_index = 0; |
|
||||||
QList<QVariant> rootData; |
|
||||||
rootData << tr("Name") << tr("Size") << tr("Progress") << tr("Priority"); |
|
||||||
rootItem = new TorrentFileItem(rootData); |
|
||||||
} |
|
||||||
|
|
||||||
~TorrentFilesModel() { |
|
||||||
qDebug() << Q_FUNC_INFO << "ENTER"; |
|
||||||
delete [] files_index; |
|
||||||
delete rootItem; |
|
||||||
qDebug() << Q_FUNC_INFO << "EXIT"; |
|
||||||
} |
|
||||||
|
|
||||||
void updateFilesProgress(std::vector<libtorrent::size_type> fp) { |
|
||||||
emit layoutAboutToBeChanged(); |
|
||||||
for (unsigned int i=0; i<fp.size(); ++i) { |
|
||||||
Q_ASSERT(fp[i] >= 0); |
|
||||||
files_index[i]->setProgress(fp[i]); |
|
||||||
} |
|
||||||
emit dataChanged(index(0,0), index(rowCount(), columnCount())); |
|
||||||
} |
|
||||||
|
|
||||||
void updateFilesPriorities(const std::vector<int> &fprio) { |
|
||||||
emit layoutAboutToBeChanged(); |
|
||||||
for (unsigned int i=0; i<fprio.size(); ++i) { |
|
||||||
//qDebug("Called updateFilesPriorities with %d", fprio[i]);
|
|
||||||
files_index[i]->setPriority(fprio[i]); |
|
||||||
} |
|
||||||
emit dataChanged(index(0,0), index(rowCount(), columnCount())); |
|
||||||
} |
|
||||||
|
|
||||||
std::vector<int> getFilesPriorities(unsigned int nbFiles) const { |
|
||||||
std::vector<int> prio; |
|
||||||
for (unsigned int i=0; i<nbFiles; ++i) { |
|
||||||
//qDebug("Called getFilesPriorities: %d", files_index[i]->getPriority());
|
|
||||||
prio.push_back(files_index[i]->getPriority()); |
|
||||||
} |
|
||||||
return prio; |
|
||||||
} |
|
||||||
|
|
||||||
bool allFiltered() const { |
|
||||||
for (int i=0; i<rootItem->childCount(); ++i) { |
|
||||||
if (rootItem->child(i)->getPriority() != prio::IGNORED) |
|
||||||
return false; |
|
||||||
} |
|
||||||
return true; |
|
||||||
} |
|
||||||
|
|
||||||
int columnCount(const QModelIndex &parent=QModelIndex()) const { |
|
||||||
if (parent.isValid()) |
|
||||||
return static_cast<TorrentFileItem*>(parent.internalPointer())->columnCount(); |
|
||||||
else |
|
||||||
return rootItem->columnCount(); |
|
||||||
} |
|
||||||
|
|
||||||
bool setData(const QModelIndex & index, const QVariant & value, int role = Qt::EditRole) { |
|
||||||
if (!index.isValid()) return false; |
|
||||||
if (index.column() == 0 && role == Qt::CheckStateRole) { |
|
||||||
TorrentFileItem *item = static_cast<TorrentFileItem*>(index.internalPointer()); |
|
||||||
qDebug("setData(%s, %d", qPrintable(item->getName()), value.toInt()); |
|
||||||
if (item->getPriority() != value.toInt()) { |
|
||||||
if (value.toInt() == Qt::PartiallyChecked) |
|
||||||
item->setPriority(prio::PARTIAL); |
|
||||||
else if (value.toInt() == Qt::Unchecked) |
|
||||||
item->setPriority(prio::IGNORED); |
|
||||||
else |
|
||||||
item->setPriority(prio::NORMAL); |
|
||||||
emit dataChanged(this->index(0,0), this->index(rowCount(), columnCount())); |
|
||||||
emit filteredFilesChanged(); |
|
||||||
} |
|
||||||
return true; |
|
||||||
} |
|
||||||
if (role == Qt::EditRole) { |
|
||||||
TorrentFileItem *item = static_cast<TorrentFileItem*>(index.internalPointer()); |
|
||||||
switch(index.column()) { |
|
||||||
case TorrentFileItem::COL_NAME: |
|
||||||
item->setName(value.toString()); |
|
||||||
break; |
|
||||||
case TorrentFileItem::COL_SIZE: |
|
||||||
item->setSize(value.toULongLong()); |
|
||||||
break; |
|
||||||
case TorrentFileItem::COL_PROGRESS: |
|
||||||
item->setProgress(value.toDouble()); |
|
||||||
break; |
|
||||||
case TorrentFileItem::COL_PRIO: |
|
||||||
item->setPriority(value.toInt()); |
|
||||||
break; |
|
||||||
default: |
|
||||||
return false; |
|
||||||
} |
|
||||||
emit dataChanged(index, index); |
|
||||||
return true; |
|
||||||
} |
|
||||||
return false; |
|
||||||
} |
|
||||||
|
|
||||||
TorrentFileItem::FileType getType(const QModelIndex &index) const { |
|
||||||
const TorrentFileItem *item = static_cast<const TorrentFileItem*>(index.internalPointer()); |
|
||||||
return item->getType(); |
|
||||||
} |
|
||||||
|
|
||||||
int getFileIndex(const QModelIndex &index) { |
|
||||||
TorrentFileItem *item = static_cast<TorrentFileItem*>(index.internalPointer()); |
|
||||||
return item->getFileIndex(); |
|
||||||
} |
|
||||||
|
|
||||||
QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const { |
|
||||||
if (!index.isValid()) |
|
||||||
return QVariant(); |
|
||||||
TorrentFileItem *item = static_cast<TorrentFileItem*>(index.internalPointer()); |
|
||||||
if (index.column() == 0 && role == Qt::DecorationRole) { |
|
||||||
if (item->isFolder()) |
|
||||||
return IconProvider::instance()->getIcon("inode-directory"); |
|
||||||
else |
|
||||||
return IconProvider::instance()->getIcon("text-plain"); |
|
||||||
} |
|
||||||
if (index.column() == 0 && role == Qt::CheckStateRole) { |
|
||||||
if (item->data(TorrentFileItem::COL_PRIO).toInt() == prio::IGNORED) |
|
||||||
return Qt::Unchecked; |
|
||||||
if (item->data(TorrentFileItem::COL_PRIO).toInt() == prio::PARTIAL) |
|
||||||
return Qt::PartiallyChecked; |
|
||||||
return Qt::Checked; |
|
||||||
} |
|
||||||
if (role != Qt::DisplayRole) |
|
||||||
return QVariant(); |
|
||||||
|
|
||||||
return item->data(index.column()); |
|
||||||
} |
|
||||||
|
|
||||||
Qt::ItemFlags flags(const QModelIndex &index) const { |
|
||||||
if (!index.isValid()) |
|
||||||
return 0; |
|
||||||
if (getType(index) == TorrentFileItem::FOLDER) |
|
||||||
return Qt::ItemIsEditable | Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable | Qt::ItemIsTristate; |
|
||||||
return Qt::ItemIsEditable | Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable; |
|
||||||
} |
|
||||||
|
|
||||||
QVariant headerData(int section, Qt::Orientation orientation, int role) const { |
|
||||||
if (orientation == Qt::Horizontal && role == Qt::DisplayRole) |
|
||||||
return rootItem->data(section); |
|
||||||
|
|
||||||
return QVariant(); |
|
||||||
} |
|
||||||
|
|
||||||
QModelIndex index(int row, int column, const QModelIndex &parent=QModelIndex()) const { |
|
||||||
if (parent.isValid() && parent.column() != 0) |
|
||||||
return QModelIndex(); |
|
||||||
if (column >= TorrentFileItem::NB_COL) |
|
||||||
return QModelIndex(); |
|
||||||
|
|
||||||
TorrentFileItem *parentItem; |
|
||||||
|
|
||||||
if (!parent.isValid()) |
|
||||||
parentItem = rootItem; |
|
||||||
else |
|
||||||
parentItem = static_cast<TorrentFileItem*>(parent.internalPointer()); |
|
||||||
Q_ASSERT(parentItem); |
|
||||||
if (row >= parentItem->childCount()) |
|
||||||
return QModelIndex(); |
|
||||||
|
|
||||||
TorrentFileItem *childItem = parentItem->child(row); |
|
||||||
if (childItem) { |
|
||||||
return createIndex(row, column, childItem); |
|
||||||
} else { |
|
||||||
return QModelIndex(); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
QModelIndex parent(const QModelIndex &index) const { |
|
||||||
if (!index.isValid()) |
|
||||||
return QModelIndex(); |
|
||||||
|
|
||||||
TorrentFileItem *childItem = static_cast<TorrentFileItem*>(index.internalPointer()); |
|
||||||
if (!childItem) return QModelIndex(); |
|
||||||
TorrentFileItem *parentItem = childItem->parent(); |
|
||||||
|
|
||||||
if (parentItem == rootItem) |
|
||||||
return QModelIndex(); |
|
||||||
|
|
||||||
return createIndex(parentItem->row(), 0, parentItem); |
|
||||||
} |
|
||||||
|
|
||||||
int rowCount(const QModelIndex &parent=QModelIndex()) const { |
|
||||||
TorrentFileItem *parentItem; |
|
||||||
|
|
||||||
if (parent.column() > 0) |
|
||||||
return 0; |
|
||||||
|
|
||||||
if (!parent.isValid()) |
|
||||||
parentItem = rootItem; |
|
||||||
else |
|
||||||
parentItem = static_cast<TorrentFileItem*>(parent.internalPointer()); |
|
||||||
|
|
||||||
return parentItem->childCount(); |
|
||||||
} |
|
||||||
|
|
||||||
void clear() { |
|
||||||
qDebug("clear called"); |
|
||||||
beginResetModel(); |
|
||||||
if (files_index) { |
|
||||||
delete [] files_index; |
|
||||||
files_index = 0; |
|
||||||
} |
|
||||||
rootItem->deleteAllChildren(); |
|
||||||
endResetModel(); |
|
||||||
} |
|
||||||
|
|
||||||
void setupModelData(const libtorrent::torrent_info &t) { |
|
||||||
qDebug("setup model data called"); |
|
||||||
if (t.num_files() == 0) return; |
|
||||||
emit layoutAboutToBeChanged(); |
|
||||||
// Initialize files_index array
|
|
||||||
qDebug("Torrent contains %d files", t.num_files()); |
|
||||||
files_index = new TorrentFileItem*[t.num_files()]; |
|
||||||
|
|
||||||
TorrentFileItem *parent = this->rootItem; |
|
||||||
TorrentFileItem *root_folder = parent; |
|
||||||
TorrentFileItem *current_parent; |
|
||||||
|
|
||||||
// Iterate over files
|
|
||||||
for (int i=0; i<t.num_files(); ++i) { |
|
||||||
libtorrent::file_entry fentry = t.file_at(i); |
|
||||||
current_parent = root_folder; |
|
||||||
#if LIBTORRENT_VERSION_MINOR >= 16 |
|
||||||
QString path = QDir::cleanPath(misc::toQStringU(fentry.path)).replace("\\", "/"); |
|
||||||
#else |
|
||||||
QString path = QDir::cleanPath(misc::toQStringU(fentry.path.string())).replace("\\", "/"); |
|
||||||
#endif |
|
||||||
// Iterate of parts of the path to create necessary folders
|
|
||||||
QStringList pathFolders = path.split("/"); |
|
||||||
pathFolders.removeAll(".unwanted"); |
|
||||||
pathFolders.takeLast(); |
|
||||||
foreach (const QString &pathPart, pathFolders) { |
|
||||||
TorrentFileItem *new_parent = current_parent->childWithName(pathPart); |
|
||||||
if (!new_parent) { |
|
||||||
new_parent = new TorrentFileItem(pathPart, current_parent); |
|
||||||
} |
|
||||||
current_parent = new_parent; |
|
||||||
} |
|
||||||
// Actually create the file
|
|
||||||
TorrentFileItem *f = new TorrentFileItem(t, fentry, current_parent, i); |
|
||||||
files_index[i] = f; |
|
||||||
} |
|
||||||
emit layoutChanged(); |
|
||||||
} |
|
||||||
|
|
||||||
public slots: |
|
||||||
void selectAll() { |
|
||||||
for (int i=0; i<rootItem->childCount(); ++i) { |
|
||||||
TorrentFileItem *child = rootItem->child(i); |
|
||||||
if (child->getPriority() == prio::IGNORED) |
|
||||||
child->setPriority(prio::NORMAL); |
|
||||||
} |
|
||||||
emit dataChanged(index(0,0), index(rowCount(), columnCount())); |
|
||||||
} |
|
||||||
|
|
||||||
void selectNone() { |
|
||||||
for (int i=0; i<rootItem->childCount(); ++i) { |
|
||||||
rootItem->child(i)->setPriority(prio::IGNORED); |
|
||||||
} |
|
||||||
emit dataChanged(index(0,0), index(rowCount(), columnCount())); |
|
||||||
} |
|
||||||
|
|
||||||
signals: |
|
||||||
void filteredFilesChanged(); |
|
||||||
}; |
|
||||||
|
|
||||||
class TorrentFilesFilterModel: public QSortFilterProxyModel { |
|
||||||
Q_OBJECT |
|
||||||
|
|
||||||
public: |
|
||||||
TorrentFilesFilterModel(QObject *parent = 0): QSortFilterProxyModel(parent) { |
|
||||||
m_model = new TorrentFilesModel(this); |
|
||||||
connect(m_model, SIGNAL(filteredFilesChanged()), this, SIGNAL(filteredFilesChanged())); |
|
||||||
setSourceModel(m_model); |
|
||||||
// Filter settings
|
|
||||||
setFilterCaseSensitivity(Qt::CaseInsensitive); |
|
||||||
setFilterKeyColumn(TorrentFileItem::COL_NAME); |
|
||||||
setFilterRole(Qt::DisplayRole); |
|
||||||
setDynamicSortFilter(true); |
|
||||||
setSortCaseSensitivity(Qt::CaseInsensitive); |
|
||||||
} |
|
||||||
|
|
||||||
~TorrentFilesFilterModel() { |
|
||||||
qDebug() << Q_FUNC_INFO << "ENTER"; |
|
||||||
delete m_model; |
|
||||||
qDebug() << Q_FUNC_INFO << "EXIT"; |
|
||||||
} |
|
||||||
|
|
||||||
TorrentFilesModel* model() const { |
|
||||||
return m_model; |
|
||||||
} |
|
||||||
|
|
||||||
TorrentFileItem::FileType getType(const QModelIndex &index) const { |
|
||||||
return m_model->getType(mapToSource(index)); |
|
||||||
} |
|
||||||
|
|
||||||
int getFileIndex(const QModelIndex &index) { |
|
||||||
return m_model->getFileIndex(mapToSource(index)); |
|
||||||
} |
|
||||||
|
|
||||||
QModelIndex parent(const QModelIndex & child) const { |
|
||||||
if (!child.isValid()) return QModelIndex(); |
|
||||||
QModelIndex sourceParent = m_model->parent(mapToSource(child)); |
|
||||||
if (!sourceParent.isValid()) return QModelIndex(); |
|
||||||
return mapFromSource(sourceParent); |
|
||||||
} |
|
||||||
|
|
||||||
signals: |
|
||||||
void filteredFilesChanged(); |
|
||||||
|
|
||||||
protected: |
|
||||||
bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const { |
|
||||||
if (m_model->getType(m_model->index(source_row, 0, source_parent)) == TorrentFileItem::FOLDER) { |
|
||||||
// always accept folders, since we want to filter their children
|
|
||||||
return true; |
|
||||||
} |
|
||||||
return QSortFilterProxyModel::filterAcceptsRow(source_row, source_parent); |
|
||||||
} |
|
||||||
|
|
||||||
public slots: |
|
||||||
void selectAll() { |
|
||||||
for (int i=0; i<rowCount(); ++i) { |
|
||||||
setData(index(i, 0), Qt::Checked, Qt::CheckStateRole); |
|
||||||
} |
|
||||||
emit dataChanged(index(0,0), index(rowCount(), columnCount())); |
|
||||||
} |
|
||||||
|
|
||||||
void selectNone() { |
|
||||||
for (int i=0; i<rowCount(); ++i) { |
|
||||||
setData(index(i, 0), Qt::Unchecked, Qt::CheckStateRole); |
|
||||||
} |
|
||||||
emit dataChanged(index(0,0), index(rowCount(), columnCount())); |
|
||||||
} |
|
||||||
|
|
||||||
private: |
|
||||||
TorrentFilesModel *m_model; |
|
||||||
}; |
|
||||||
|
|
||||||
|
|
||||||
#endif // TORRENTFILESMODEL_H
|
|
Loading…
Reference in new issue