From a5452d04ae1c89871e5575947aefbd0dc1cbca10 Mon Sep 17 00:00:00 2001 From: Christophe Dumez Date: Tue, 21 Feb 2012 21:54:24 +0200 Subject: [PATCH] Clean up and refactor torrent content model code --- src/properties/propertieswidget.cpp | 9 +- src/properties/propertieswidget.h | 4 +- src/src.pro | 7 +- src/torrentadditiondlg.cpp | 7 +- src/torrentadditiondlg.h | 4 +- src/torrentcontentfiltermodel.cpp | 98 ++++ src/torrentcontentfiltermodel.h | 65 +++ src/torrentcontentmodel.cpp | 325 +++++++++++++ src/torrentcontentmodel.h | 76 ++++ src/torrentcontentmodelitem.cpp | 320 +++++++++++++ src/torrentcontentmodelitem.h | 102 +++++ src/torrentfilesmodel.h | 684 ---------------------------- 12 files changed, 1005 insertions(+), 696 deletions(-) create mode 100644 src/torrentcontentfiltermodel.cpp create mode 100644 src/torrentcontentfiltermodel.h create mode 100644 src/torrentcontentmodel.cpp create mode 100644 src/torrentcontentmodel.h create mode 100644 src/torrentcontentmodelitem.cpp create mode 100644 src/torrentcontentmodelitem.h delete mode 100644 src/torrentfilesmodel.h diff --git a/src/properties/propertieswidget.cpp b/src/properties/propertieswidget.cpp index 9f389beec..c35c250a1 100644 --- a/src/properties/propertieswidget.cpp +++ b/src/properties/propertieswidget.cpp @@ -46,7 +46,8 @@ #include "torrentpersistentdata.h" #include "qbtsession.h" #include "proplistdelegate.h" -#include "torrentfilesmodel.h" +#include "torrentcontentfiltermodel.h" +#include "torrentcontentmodel.h" #include "peerlistwidget.h" #include "trackerlist.h" #include "mainwindow.h" @@ -73,7 +74,7 @@ PropertiesWidget::PropertiesWidget(QWidget *parent, MainWindow* main_window, Tra setEnabled(false); // Set Properties list model - PropListModel = new TorrentFilesFilterModel(); + PropListModel = new TorrentContentFilterModel(); filesList->setModel(PropListModel); PropDelegate = new PropListDelegate(this); filesList->setItemDelegate(PropDelegate); @@ -414,7 +415,7 @@ void PropertiesWidget::loadUrlSeeds() { void PropertiesWidget::openDoubleClickedFile(QModelIndex index) { if (!index.isValid()) return; if (!h.is_valid() || !h.has_metadata()) return; - if (PropListModel->getType(index) == TorrentFileItem::TFILE) { + if (PropListModel->getType(index) == TorrentContentModelItem::TFILE) { int i = PropListModel->getFileIndex(index); const QDir saveDir(h.save_path()); const QString filename = h.filepath_at(i); @@ -516,7 +517,7 @@ void PropertiesWidget::renameSelectedFile() { QMessageBox::Ok); return; } - if (PropListModel->getType(index) == TorrentFileItem::TFILE) { + if (PropListModel->getType(index) == TorrentContentModelItem::TFILE) { // File renaming const int file_index = PropListModel->getFileIndex(index); if (!h.is_valid() || !h.has_metadata()) return; diff --git a/src/properties/propertieswidget.h b/src/properties/propertieswidget.h index 9e656fbd3..cb098557f 100644 --- a/src/properties/propertieswidget.h +++ b/src/properties/propertieswidget.h @@ -37,7 +37,7 @@ class TransferListWidget; -class TorrentFilesFilterModel; +class TorrentContentFilterModel; class PropListDelegate; class torrent_file; class PeerListWidget; @@ -101,7 +101,7 @@ private: QTorrentHandle h; QTimer *refreshTimer; SlideState state; - TorrentFilesFilterModel *PropListModel; + TorrentContentFilterModel *PropListModel; PropListDelegate *PropDelegate; PeerListWidget *peersList; TrackerList *trackerList; diff --git a/src/src.pro b/src/src.pro index afb6038a1..872987160 100644 --- a/src/src.pro +++ b/src/src.pro @@ -119,7 +119,9 @@ nox { transferlistwidget.h \ transferlistdelegate.h \ transferlistfilterswidget.h \ - torrentfilesmodel.h \ + torrentcontentmodel.h \ + torrentcontentmodelitem.h \ + torrentcontentfiltermodel.h \ deletionconfirmationdlg.h \ statusbar.h \ reverseresolution.h \ @@ -142,6 +144,9 @@ nox { SOURCES += mainwindow.cpp \ ico.cpp \ transferlistwidget.cpp \ + torrentcontentmodel.cpp \ + torrentcontentmodelitem.cpp \ + torrentcontentfiltermodel.cpp \ torrentadditiondlg.cpp \ sessionapplication.cpp \ torrentimportdlg.cpp \ diff --git a/src/torrentadditiondlg.cpp b/src/torrentadditiondlg.cpp index 58de2b425..97ae051e8 100644 --- a/src/torrentadditiondlg.cpp +++ b/src/torrentadditiondlg.cpp @@ -45,7 +45,8 @@ #include #include "qbtsession.h" -#include "torrentfilesmodel.h" +#include "torrentcontentfiltermodel.h" +#include "torrentcontentmodel.h" #include "preferences.h" #include "transferlistwidget.h" #include "qinisettings.h" @@ -67,7 +68,7 @@ torrentAdditionDialog::torrentAdditionDialog(QWidget *parent) : CancelButton->setIcon(IconProvider::instance()->getIcon("dialog-cancel")); OkButton->setIcon(IconProvider::instance()->getIcon("list-add")); // Set Properties list model - PropListModel = new TorrentFilesFilterModel(this); + PropListModel = new TorrentContentFilterModel(this); connect(PropListModel, SIGNAL(filteredFilesChanged()), SLOT(updateDiskSpaceLabels())); torrentContentList->setModel(PropListModel); torrentContentList->hideColumn(PROGRESS); @@ -407,7 +408,7 @@ void torrentAdditionDialog::renameSelectedFile() { QMessageBox::Ok); return; } - if (PropListModel->getType(index) == TorrentFileItem::TFILE) { + if (PropListModel->getType(index) == TorrentContentModelItem::TFILE) { // File renaming const uint file_index = PropListModel->getFileIndex(index); QString old_name = files_path.at(file_index); diff --git a/src/torrentadditiondlg.h b/src/torrentadditiondlg.h index 27ee67a81..7051ef2ef 100644 --- a/src/torrentadditiondlg.h +++ b/src/torrentadditiondlg.h @@ -37,7 +37,7 @@ #include -class TorrentFilesFilterModel; +class TorrentContentFilterModel; class PropListDelegate; class torrentAdditionDialog : public QDialog, private Ui_addTorrentDialog{ @@ -83,7 +83,7 @@ private: QString defaultSavePath; QString old_label; bool appendLabelToSavePath; - TorrentFilesFilterModel *PropListModel; + TorrentContentFilterModel *PropListModel; PropListDelegate *PropDelegate; unsigned int nbFiles; boost::intrusive_ptr t; diff --git a/src/torrentcontentfiltermodel.cpp b/src/torrentcontentfiltermodel.cpp new file mode 100644 index 000000000..aafb160fc --- /dev/null +++ b/src/torrentcontentfiltermodel.cpp @@ -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 +#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 diff --git a/src/torrentcontentmodel.cpp b/src/torrentcontentmodel.cpp new file mode 100644 index 000000000..7224fab8d --- /dev/null +++ b/src/torrentcontentmodel.cpp @@ -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 + +TorrentContentModel::TorrentContentModel(QObject *parent): + QAbstractItemModel(parent), files_index(0) +{ + QList 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& fp) +{ + emit layoutAboutToBeChanged(); + for (unsigned int i=0; i= 0); + files_index[i]->setProgress(fp[i]); + } + emit dataChanged(index(0,0), index(rowCount(), columnCount())); +} + +void TorrentContentModel::updateFilesPriorities(const std::vector &fprio) +{ + emit layoutAboutToBeChanged(); + for (unsigned int i=0; isetPriority(fprio[i]); + } + emit dataChanged(index(0,0), index(rowCount(), columnCount())); +} + +std::vector TorrentContentModel::getFilesPriorities(unsigned int nbFiles) const +{ + std::vector prio; + for (unsigned int i=0; igetPriority()); + prio.push_back(files_index[i]->getPriority()); + } + return prio; +} + +bool TorrentContentModel::allFiltered() const +{ + for (int i=0; ichildCount(); ++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(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(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(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(index.internalPointer()); + return item->getType(); +} + +int TorrentContentModel::getFileIndex(const QModelIndex& index) +{ + TorrentContentModelItem *item = static_cast(index.internalPointer()); + return item->getFileIndex(); +} + +QVariant TorrentContentModel::data(const QModelIndex &index, int role) const +{ + if (!index.isValid()) + return QVariant(); + + TorrentContentModelItem *item = static_cast(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(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(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(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= 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; ichildCount(); ++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; ichildCount(); ++i) { + rootItem->child(i)->setPriority(prio::IGNORED); + } + emit dataChanged(index(0,0), index(rowCount(), columnCount())); +} diff --git a/src/torrentcontentmodel.h b/src/torrentcontentmodel.h new file mode 100644 index 000000000..425e58d0b --- /dev/null +++ b/src/torrentcontentmodel.h @@ -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 +#include +#include +#include +#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& fp); + void updateFilesPriorities(const std::vector &fprio); + std::vector 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 diff --git a/src/torrentcontentmodelitem.cpp b/src/torrentcontentmodelitem.cpp new file mode 100644 index 000000000..1b88f6867 --- /dev/null +++ b/src/torrentcontentmodelitem.cpp @@ -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 + +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& 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::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; igetPriority() != 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; igetName(); + 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(this)); + return 0; +} + +TorrentContentModelItem* TorrentContentModelItem::parent() +{ + return m_parentItem; +} diff --git a/src/torrentcontentmodelitem.h b/src/torrentcontentmodelitem.h new file mode 100644 index 000000000..fdb490d84 --- /dev/null +++ b/src/torrentcontentmodelitem.h @@ -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 +#include +#include + +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& 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& children() const; + +private: + TorrentContentModelItem *m_parentItem; + FileType m_type; + QList m_childItems; + QList m_itemData; + int m_fileIndex; + qulonglong m_totalDone; +}; + +#endif // TORRENTCONTENTMODELITEM_H diff --git a/src/torrentfilesmodel.h b/src/torrentfilesmodel.h deleted file mode 100644 index 51584da4a..000000000 --- a/src/torrentfilesmodel.h +++ /dev/null @@ -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 -#include -#include -#include -#include -#include -#include -#include -#include -#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 childItems; - QList 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& 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 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; igetPriority() != 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; igetName(); - 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(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 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 fp) { - emit layoutAboutToBeChanged(); - for (unsigned int i=0; i= 0); - files_index[i]->setProgress(fp[i]); - } - emit dataChanged(index(0,0), index(rowCount(), columnCount())); - } - - void updateFilesPriorities(const std::vector &fprio) { - emit layoutAboutToBeChanged(); - for (unsigned int i=0; isetPriority(fprio[i]); - } - emit dataChanged(index(0,0), index(rowCount(), columnCount())); - } - - std::vector getFilesPriorities(unsigned int nbFiles) const { - std::vector prio; - for (unsigned int i=0; igetPriority()); - prio.push_back(files_index[i]->getPriority()); - } - return prio; - } - - bool allFiltered() const { - for (int i=0; ichildCount(); ++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(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(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(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(index.internalPointer()); - return item->getType(); - } - - int getFileIndex(const QModelIndex &index) { - TorrentFileItem *item = static_cast(index.internalPointer()); - return item->getFileIndex(); - } - - QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const { - if (!index.isValid()) - return QVariant(); - TorrentFileItem *item = static_cast(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(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(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(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= 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; ichildCount(); ++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; ichildCount(); ++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