From 0fdacf4d547675e5518f7835242f76257038fe96 Mon Sep 17 00:00:00 2001 From: Christophe Dumez Date: Sun, 26 Aug 2012 18:10:32 +0300 Subject: [PATCH] Use polymorphism to distinguish folder / file items in torrent content model Step to address issue #24. --- src/addnewtorrentdialog.cpp | 2 +- src/properties/propertieswidget.cpp | 4 +- src/src.pro | 4 + src/torrentcontentfiltermodel.cpp | 6 +- src/torrentcontentfiltermodel.h | 4 +- src/torrentcontentmodel.cpp | 50 ++--- src/torrentcontentmodel.h | 4 +- src/torrentcontentmodelfile.cpp | 86 +++++++++ src/torrentcontentmodelfile.h | 52 ++++++ src/torrentcontentmodelfolder.cpp | 185 ++++++++++++++++++ src/torrentcontentmodelfolder.h | 66 +++++++ src/torrentcontentmodelitem.cpp | 280 ++++++---------------------- src/torrentcontentmodelitem.h | 61 +++--- 13 files changed, 507 insertions(+), 297 deletions(-) create mode 100644 src/torrentcontentmodelfile.cpp create mode 100644 src/torrentcontentmodelfile.h create mode 100644 src/torrentcontentmodelfolder.cpp create mode 100644 src/torrentcontentmodelfolder.h diff --git a/src/addnewtorrentdialog.cpp b/src/addnewtorrentdialog.cpp index a93ce4875..18aa0fc09 100644 --- a/src/addnewtorrentdialog.cpp +++ b/src/addnewtorrentdialog.cpp @@ -402,7 +402,7 @@ void AddNewTorrentDialog::renameSelectedFile() QMessageBox::Ok); return; } - if (m_contentModel->getType(index) == TorrentContentModelItem::TFILE) { + if (m_contentModel->itemType(index) == TorrentContentModelItem::FileType) { // File renaming const int file_index = m_contentModel->getFileIndex(index); QString old_name = m_filesPath.at(file_index); diff --git a/src/properties/propertieswidget.cpp b/src/properties/propertieswidget.cpp index 7c311cb92..e203396c5 100644 --- a/src/properties/propertieswidget.cpp +++ b/src/properties/propertieswidget.cpp @@ -412,7 +412,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) == TorrentContentModelItem::TFILE) { + if (PropListModel->itemType(index) == TorrentContentModelItem::FileType) { int i = PropListModel->getFileIndex(index); const QDir saveDir(h.save_path()); const QString filename = h.filepath_at(i); @@ -514,7 +514,7 @@ void PropertiesWidget::renameSelectedFile() { QMessageBox::Ok); return; } - if (PropListModel->getType(index) == TorrentContentModelItem::TFILE) { + if (PropListModel->itemType(index) == TorrentContentModelItem::FileType) { // File renaming const int file_index = PropListModel->getFileIndex(index); if (!h.is_valid() || !h.has_metadata()) return; diff --git a/src/src.pro b/src/src.pro index 879f3841d..9d98e5d68 100644 --- a/src/src.pro +++ b/src/src.pro @@ -123,6 +123,8 @@ nox { transferlistfilterswidget.h \ torrentcontentmodel.h \ torrentcontentmodelitem.h \ + torrentcontentmodelfolder.h \ + torrentcontentmodelfile.h \ torrentcontentfiltermodel.h \ deletionconfirmationdlg.h \ statusbar.h \ @@ -148,6 +150,8 @@ nox { transferlistwidget.cpp \ torrentcontentmodel.cpp \ torrentcontentmodelitem.cpp \ + torrentcontentmodelfolder.cpp \ + torrentcontentmodelfile.cpp \ torrentcontentfiltermodel.cpp \ sessionapplication.cpp \ torrentimportdlg.cpp \ diff --git a/src/torrentcontentfiltermodel.cpp b/src/torrentcontentfiltermodel.cpp index aafb160fc..6e2627e08 100644 --- a/src/torrentcontentfiltermodel.cpp +++ b/src/torrentcontentfiltermodel.cpp @@ -54,9 +54,9 @@ TorrentContentModel* TorrentContentFilterModel::model() const return m_model; } -TorrentContentModelItem::FileType TorrentContentFilterModel::getType(const QModelIndex& index) const +TorrentContentModelItem::ItemType TorrentContentFilterModel::itemType(const QModelIndex& index) const { - return m_model->getType(mapToSource(index)); + return m_model->itemType(mapToSource(index)); } int TorrentContentFilterModel::getFileIndex(const QModelIndex& index) const @@ -74,7 +74,7 @@ QModelIndex TorrentContentFilterModel::parent(const QModelIndex& child) const 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) { + if (m_model->itemType(m_model->index(source_row, 0, source_parent)) == TorrentContentModelItem::FolderType) { // always accept folders, since we want to filter their children return true; } diff --git a/src/torrentcontentfiltermodel.h b/src/torrentcontentfiltermodel.h index cd6b515a9..b6c88ac3c 100644 --- a/src/torrentcontentfiltermodel.h +++ b/src/torrentcontentfiltermodel.h @@ -44,7 +44,7 @@ public: virtual ~TorrentContentFilterModel(); TorrentContentModel* model() const; - TorrentContentModelItem::FileType getType(const QModelIndex& index) const; + TorrentContentModelItem::ItemType itemType(const QModelIndex& index) const; int getFileIndex(const QModelIndex& index) const; virtual QModelIndex parent(const QModelIndex& child) const; @@ -59,7 +59,7 @@ public slots: void selectNone(); private: - TorrentContentModel *m_model; + TorrentContentModel* m_model; }; #endif // TORRENTCONTENTFILTERMODEL_H diff --git a/src/torrentcontentmodel.cpp b/src/torrentcontentmodel.cpp index 65768c3da..112314c73 100644 --- a/src/torrentcontentmodel.cpp +++ b/src/torrentcontentmodel.cpp @@ -32,11 +32,13 @@ #include "misc.h" #include "torrentcontentmodel.h" #include "torrentcontentmodelitem.h" +#include "torrentcontentmodelFolder.h" +#include "torrentcontentmodelFile.h" #include TorrentContentModel::TorrentContentModel(QObject *parent): QAbstractItemModel(parent), - m_rootItem(new TorrentContentModelItem(QList() << tr("Name") << tr("Size") + m_rootItem(new TorrentContentModelFolder(QList() << tr("Name") << tr("Size") << tr("Progress") << tr("Priority"))) { } @@ -73,7 +75,7 @@ std::vector TorrentContentModel::getFilesPriorities() const std::vector prio; prio.reserve(m_filesIndex.size()); foreach (const TorrentContentModelItem* file, m_filesIndex) { - prio.push_back(file->getPriority()); + prio.push_back(file->priority()); } return prio; } @@ -81,7 +83,7 @@ std::vector TorrentContentModel::getFilesPriorities() const bool TorrentContentModel::allFiltered() const { for (int i=0; ichildCount(); ++i) { - if (m_rootItem->child(i)->getPriority() != prio::IGNORED) + if (m_rootItem->child(i)->priority() != prio::IGNORED) return false; } return true; @@ -102,8 +104,8 @@ bool TorrentContentModel::setData(const QModelIndex& index, const QVariant& valu 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()) { + qDebug("setData(%s, %d", qPrintable(item->name()), value.toInt()); + if (item->priority() != value.toInt()) { if (value.toInt() == Qt::PartiallyChecked) item->setPriority(prio::PARTIAL); else if (value.toInt() == Qt::Unchecked) @@ -140,16 +142,17 @@ bool TorrentContentModel::setData(const QModelIndex& index, const QVariant& valu return false; } -TorrentContentModelItem::FileType TorrentContentModel::getType(const QModelIndex& index) const +TorrentContentModelItem::ItemType TorrentContentModel::itemType(const QModelIndex& index) const { const TorrentContentModelItem *item = static_cast(index.internalPointer()); - return item->getType(); + return item->itemType(); } int TorrentContentModel::getFileIndex(const QModelIndex& index) { - TorrentContentModelItem* item = static_cast(index.internalPointer()); - return item->getFileIndex(); + TorrentContentModelFile* item = dynamic_cast(static_cast(index.internalPointer())); + Q_ASSERT(item); + return item->fileIndex(); } QVariant TorrentContentModel::data(const QModelIndex &index, int role) const @@ -159,7 +162,7 @@ QVariant TorrentContentModel::data(const QModelIndex &index, int role) const TorrentContentModelItem *item = static_cast(index.internalPointer()); if (index.column() == 0 && role == Qt::DecorationRole) { - if (item->isFolder()) + if (item->itemType() == TorrentContentModelItem::FolderType) return IconProvider::instance()->getIcon("inode-directory"); else return IconProvider::instance()->getIcon("text-plain"); @@ -182,7 +185,7 @@ Qt::ItemFlags TorrentContentModel::flags(const QModelIndex& index) const if (!index.isValid()) return 0; - if (getType(index) == TorrentContentModelItem::FOLDER) + if (itemType(index) == TorrentContentModelItem::FolderType) return Qt::ItemIsEditable | Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable | Qt::ItemIsTristate; return Qt::ItemIsEditable | Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable; } @@ -203,12 +206,12 @@ QModelIndex TorrentContentModel::index(int row, int column, const QModelIndex& p if (column >= TorrentContentModelItem::NB_COL) return QModelIndex(); - TorrentContentModelItem *parentItem; + TorrentContentModelFolder *parentItem; if (!parent.isValid()) parentItem = m_rootItem; else - parentItem = static_cast(parent.internalPointer()); + parentItem = static_cast(parent.internalPointer()); Q_ASSERT(parentItem); if (row >= parentItem->childCount()) return QModelIndex(); @@ -239,17 +242,16 @@ QModelIndex TorrentContentModel::parent(const QModelIndex& index) const int TorrentContentModel::rowCount(const QModelIndex& parent) const { - TorrentContentModelItem* parentItem; - if (parent.column() > 0) return 0; + TorrentContentModelFolder* parentItem ; if (!parent.isValid()) parentItem = m_rootItem; else - parentItem = static_cast(parent.internalPointer()); + parentItem = dynamic_cast(static_cast(parent.internalPointer())); - return parentItem->childCount(); + return parentItem ? parentItem->childCount() : 0; } void TorrentContentModel::clear() @@ -272,9 +274,9 @@ void TorrentContentModel::setupModelData(const libtorrent::torrent_info& t) qDebug("Torrent contains %d files", t.num_files()); m_filesIndex.reserve(t.num_files()); - TorrentContentModelItem* parent = m_rootItem; - TorrentContentModelItem* root_folder = parent; - TorrentContentModelItem* current_parent; + TorrentContentModelFolder* parent = m_rootItem; + TorrentContentModelFolder* root_folder = parent; + TorrentContentModelFolder* current_parent; // Iterate over files for (int i=0; ichildWithName(pathPart); + TorrentContentModelFolder* new_parent = current_parent->childFolderWithName(pathPart); if (!new_parent) - new_parent = new TorrentContentModelItem(pathPart, current_parent); + new_parent = new TorrentContentModelFolder(pathPart, current_parent); current_parent = new_parent; } // Actually create the file - m_filesIndex.push_back(new TorrentContentModelItem(t, fentry, current_parent, i)); + m_filesIndex.push_back(new TorrentContentModelFile(t, fentry, current_parent, i)); } emit layoutChanged(); } @@ -306,7 +308,7 @@ void TorrentContentModel::selectAll() { for (int i=0; ichildCount(); ++i) { TorrentContentModelItem* child = m_rootItem->child(i); - if (child->getPriority() == prio::IGNORED) + if (child->priority() == prio::IGNORED) child->setPriority(prio::NORMAL); } emit dataChanged(index(0,0), index(rowCount(), columnCount())); diff --git a/src/torrentcontentmodel.h b/src/torrentcontentmodel.h index 72773abec..ff9199679 100644 --- a/src/torrentcontentmodel.h +++ b/src/torrentcontentmodel.h @@ -51,7 +51,7 @@ public: 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; + TorrentContentModelItem::ItemType itemType(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; @@ -70,7 +70,7 @@ public slots: void selectNone(); private: - TorrentContentModelItem* m_rootItem; + TorrentContentModelFolder* m_rootItem; QVector m_filesIndex; }; diff --git a/src/torrentcontentmodelfile.cpp b/src/torrentcontentmodelfile.cpp new file mode 100644 index 000000000..e11d81e12 --- /dev/null +++ b/src/torrentcontentmodelfile.cpp @@ -0,0 +1,86 @@ +/* + * 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 "torrentcontentmodelfile.h" +#include "torrentcontentmodelfolder.h" +#include "fs_utils.h" +#include "misc.h" + +TorrentContentModelFile::TorrentContentModelFile(const libtorrent::torrent_info& t, + const libtorrent::file_entry& f, + TorrentContentModelFolder* parent, + int file_index) + : TorrentContentModelItem(parent) + , m_fileIndex(file_index) +{ + Q_ASSERT(parent); + +#if LIBTORRENT_VERSION_MINOR >= 16 + m_name = fsutils::fileName(misc::toQStringU(t.files().file_path(f))); +#else + m_name = misc::toQStringU(f.path.filename()); +#endif + + // Do not display incomplete extensions + if (m_name.endsWith(".!qB")) + m_name.chop(4); + + m_size = (qulonglong)f.size; + + // Update parent + m_parentItem->appendChild(this); + m_parentItem->updateSize(); +} + +int TorrentContentModelFile::fileIndex() const +{ + return m_fileIndex; +} + +void TorrentContentModelFile::setPriority(int new_prio, bool update_parent) +{ + Q_ASSERT(new_prio != prio::PARTIAL); + + if (m_priority == new_prio) + return; + + m_priority = new_prio; + + // Reset progress if priority is 0 + if (m_priority == 0) + setProgress(0); + + // Update parent + if (update_parent) { + m_parentItem->updateSize(); + m_parentItem->updateProgress(); + m_parentItem->updatePriority(); + } +} diff --git a/src/torrentcontentmodelfile.h b/src/torrentcontentmodelfile.h new file mode 100644 index 000000000..5ad77b55c --- /dev/null +++ b/src/torrentcontentmodelfile.h @@ -0,0 +1,52 @@ +/* + * 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 TORRENTCONTENTMODELFILE_H +#define TORRENTCONTENTMODELFILE_H + +#include "torrentcontentmodelitem.h" + +class TorrentContentModelFile : public TorrentContentModelItem +{ +public: + TorrentContentModelFile(const libtorrent::torrent_info& t, + const libtorrent::file_entry& f, + TorrentContentModelFolder* parent, + int file_index); + + int fileIndex() const; + void setPriority(int new_prio, bool update_parent = true); + ItemType itemType() const { return FileType; } + +private: + int m_fileIndex; +}; + +#endif // TORRENTCONTENTMODELFILE_H diff --git a/src/torrentcontentmodelfolder.cpp b/src/torrentcontentmodelfolder.cpp new file mode 100644 index 000000000..5721437f0 --- /dev/null +++ b/src/torrentcontentmodelfolder.cpp @@ -0,0 +1,185 @@ +/* + * 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 "torrentcontentmodelfolder.h" + +TorrentContentModelFolder::TorrentContentModelFolder(const QString& name, TorrentContentModelFolder* parent) + : TorrentContentModelItem(parent) +{ + Q_ASSERT(parent); + m_name = name; + // Do not display incomplete extensions + if (m_name.endsWith(".!qB")) + m_name.chop(4); + + // Update parent + m_parentItem->appendChild(this); +} + +TorrentContentModelFolder::TorrentContentModelFolder(const QList& data) + : TorrentContentModelItem(0) +{ + Q_ASSERT(data.size() == NB_COL); + m_itemData = data; +} + +TorrentContentModelFolder::~TorrentContentModelFolder() +{ + qDeleteAll(m_childItems); +} + +void TorrentContentModelFolder::deleteAllChildren() +{ + Q_ASSERT(isRootItem()); + qDeleteAll(m_childItems); + m_childItems.clear(); +} + +const QList& TorrentContentModelFolder::children() const +{ + return m_childItems; +} + +void TorrentContentModelFolder::appendChild(TorrentContentModelItem* item) +{ + Q_ASSERT(item); + + int i=0; + for ( ; i < m_childItems.size(); ++i) { + QString newchild_name = item->name(); + if (QString::localeAwareCompare(newchild_name, m_childItems.at(i)->name()) < 0) + break; + } + m_childItems.insert(i, item); +} + +TorrentContentModelItem* TorrentContentModelFolder::child(int row) const +{ + return m_childItems.value(row, 0); +} + +TorrentContentModelFolder* TorrentContentModelFolder::childFolderWithName(const QString& name) const +{ + foreach (TorrentContentModelItem* child, m_childItems) { + if (child->itemType() == FolderType && child->name() == name) + return static_cast(child); + } + return 0; +} + +int TorrentContentModelFolder::childCount() const +{ + return m_childItems.count(); +} + +// Only non-root folders use this function +void TorrentContentModelFolder::updatePriority() +{ + if (isRootItem()) + return; + + 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()->priority(); + for (int i=1; ipriority() != prio) { + setPriority(prio::PARTIAL); + return; + } + } + // All child items have the same priority + // Update own if necessary + if (prio != priority()) + setPriority(prio); +} + +void TorrentContentModelFolder::setPriority(int new_prio, bool update_parent) +{ + if (m_priority == new_prio) + return; + + m_priority = new_prio; + + // Reset progress if priority is IGNORED + if (m_priority == prio::IGNORED) + setProgress(0); + + // Update parent + if (update_parent) { + m_parentItem->updateSize(); + m_parentItem->updateProgress(); + m_parentItem->updatePriority(); + } + + // Update children + if (m_priority != prio::PARTIAL) { + qDebug("Updating children items"); + foreach (TorrentContentModelItem* child, m_childItems) { + // Do not update the parent since + // the parent is causing the update + child->setPriority(m_priority, false); + } + } + + updateSize(); + updateProgress(); +} + +void TorrentContentModelFolder::updateProgress() +{ + if (isRootItem()) + return; + + m_totalDone = 0; + foreach (TorrentContentModelItem* child, m_childItems) { + if (child->priority() > 0) + m_totalDone += child->totalDone(); + } + //qDebug("Folder: total_done: %llu/%llu", total_done, getSize()); + Q_ASSERT(m_totalDone <= size()); + setProgress(m_totalDone); +} + +void TorrentContentModelFolder::updateSize() +{ + if (isRootItem()) + return; + + qulonglong size = 0; + foreach (TorrentContentModelItem* child, m_childItems) { + if (child->priority() != prio::IGNORED) + size += child->size(); + } + setSize(size); +} diff --git a/src/torrentcontentmodelfolder.h b/src/torrentcontentmodelfolder.h new file mode 100644 index 000000000..1f520b2a1 --- /dev/null +++ b/src/torrentcontentmodelfolder.h @@ -0,0 +1,66 @@ +/* + * 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 TORRENTCONTENTMODELFOLDER_H +#define TORRENTCONTENTMODELFOLDER_H + +#include "torrentcontentmodelitem.h" + +class TorrentContentModelFolder : public TorrentContentModelItem +{ +public: + // Folder constructor + TorrentContentModelFolder(const QString& name, TorrentContentModelFolder* parent); + + // Invisible root item constructor + TorrentContentModelFolder(const QList& data); + + ~TorrentContentModelFolder(); + + ItemType itemType() const { return FolderType; } + + void updateSize(); + void updateProgress(); + void updatePriority(); + + void setPriority(int new_prio, bool update_parent = true); + + void deleteAllChildren(); + const QList& children() const; + void appendChild(TorrentContentModelItem* item); + TorrentContentModelItem* child(int row) const; + TorrentContentModelFolder* childFolderWithName(const QString& name) const; + int childCount() const; + +private: + QList m_childItems; +}; + +#endif // TORRENTCONTENTMODELFOLDER_H diff --git a/src/torrentcontentmodelitem.cpp b/src/torrentcontentmodelitem.cpp index 05a0de560..2d107fbc7 100644 --- a/src/torrentcontentmodelitem.cpp +++ b/src/torrentcontentmodelitem.cpp @@ -31,281 +31,113 @@ #include "misc.h" #include "fs_utils.h" #include "torrentcontentmodelitem.h" +#include "torrentcontentmodelfolder.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) +TorrentContentModelItem::TorrentContentModelItem(TorrentContentModelFolder* parent) + : m_parentItem(parent) + , m_progress(0) + , m_priority(prio::NORMAL) + , m_totalDone(0) { - Q_ASSERT(parent); - -#if LIBTORRENT_VERSION_MINOR >= 16 - QString name = fsutils::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 +QString TorrentContentModelItem::name() 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(); + Q_ASSERT(!isRootItem()); + return m_name; } void TorrentContentModelItem::setName(const QString& name) { - Q_ASSERT(m_type != ROOT); - m_itemData.replace(COL_NAME, name); + Q_ASSERT(!isRootItem()); + m_name = name; } -qulonglong TorrentContentModelItem::getSize() const +qulonglong TorrentContentModelItem::size() const { - return m_itemData.value(COL_SIZE).toULongLong(); + Q_ASSERT(!isRootItem()); + return m_size; } void TorrentContentModelItem::setSize(qulonglong size) { - Q_ASSERT (m_type != ROOT); - if (getSize() == size) + Q_ASSERT(!isRootItem()); + if (m_size == 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); + m_size = size; + m_parentItem->updateSize(); } void TorrentContentModelItem::setProgress(qulonglong done) { - Q_ASSERT (m_type != ROOT); - if (getPriority() == 0) return; + Q_ASSERT(!isRootItem()); + if (m_priority == prio::IGNORED) + return; + m_totalDone = done; - qulonglong size = getSize(); - Q_ASSERT(m_totalDone <= size); + Q_ASSERT(m_totalDone <= m_size); qreal progress; - if (size > 0) - progress = m_totalDone/(float)size; + if (m_size > 0) + progress = m_totalDone / (double) m_size; else progress = 1.; Q_ASSERT(progress >= 0. && progress <= 1.); - m_itemData.replace(COL_PROGRESS, progress); + m_progress = progress; m_parentItem->updateProgress(); } -qulonglong TorrentContentModelItem::getTotalDone() const +qulonglong TorrentContentModelItem::totalDone() const { + Q_ASSERT(!isRootItem()); return m_totalDone; } -float TorrentContentModelItem::getProgress() const +float TorrentContentModelItem::progress() const { - Q_ASSERT (m_type != ROOT); - if (getPriority() == 0) + Q_ASSERT(!isRootItem()); + if (m_priority == prio::IGNORED) return -1; - qulonglong size = getSize(); - if (size > 0) - return m_totalDone / (float) getSize(); - return 1.; + + if (m_size > 0) + return m_totalDone / (double) m_size; + return 1; } -void TorrentContentModelItem::updateProgress() +int TorrentContentModelItem::priority() const { - 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 priority - // Update own 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) const -{ - //Q_ASSERT(row >= 0 && row < childItems.size()); - return m_childItems.value(row, 0); -} - -int TorrentContentModelItem::childCount() const -{ - return m_childItems.count(); + Q_ASSERT(!isRootItem()); + return m_priority; } int TorrentContentModelItem::columnCount() const { - return m_itemData.count(); + return NB_COL; } QVariant TorrentContentModelItem::data(int column) const { - if (column == COL_PROGRESS && m_type != ROOT) - return getProgress(); - return m_itemData.value(column); + if (isRootItem()) + return m_itemData.value(column); + + switch(column) { + case COL_NAME: + return m_name; + case COL_PRIO: + return m_priority; + case COL_PROGRESS: + return progress(); // XXX: m_progress ? + case COL_SIZE: + return m_size; + default: + Q_ASSERT(false); + return QVariant(); + } } int TorrentContentModelItem::row() const @@ -315,7 +147,7 @@ int TorrentContentModelItem::row() const return 0; } -TorrentContentModelItem* TorrentContentModelItem::parent() const +TorrentContentModelFolder* TorrentContentModelItem::parent() const { return m_parentItem; } diff --git a/src/torrentcontentmodelitem.h b/src/torrentcontentmodelitem.h index c0a57da8f..38afa564a 100644 --- a/src/torrentcontentmodelitem.h +++ b/src/torrentcontentmodelitem.h @@ -39,63 +39,46 @@ namespace prio { enum FilePriority {IGNORED=0, NORMAL=1, HIGH=2, MAXIMUM=7, PARTIAL=-1}; } +class TorrentContentModelFolder; + class TorrentContentModelItem { public: enum TreeItemColumns {COL_NAME, COL_SIZE, COL_PROGRESS, COL_PRIO, NB_COL}; - enum FileType {TFILE, FOLDER, ROOT}; + enum ItemType { FileType, FolderType }; - // 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(TorrentContentModelFolder* parent); + virtual ~TorrentContentModelItem(); - ~TorrentContentModelItem(); + inline bool isRootItem() const { return !m_parentItem; } + TorrentContentModelFolder* parent() const; + virtual ItemType itemType() const = 0; - FileType getType() const; - - int getFileIndex() const; - - QString getName() const; + QString name() const; void setName(const QString& name); - qulonglong getSize() const; + qulonglong size() const; void setSize(qulonglong size); - void updateSize(); - qulonglong getTotalDone() const; + qulonglong totalDone() const; void setProgress(qulonglong done); - float getProgress() const; - void updateProgress(); + float progress() const; - int getPriority() const; - void setPriority(int new_prio, bool update_parent=true); - void updatePriority(); + int priority() const; + virtual void setPriority(int new_prio, bool update_parent = true) = 0; - TorrentContentModelItem* childWithName(const QString& name) const; - bool isFolder() const; - - void appendChild(TorrentContentModelItem *item); - TorrentContentModelItem* child(int row) const; - int childCount() const; int columnCount() const; QVariant data(int column) const; int row() const; - TorrentContentModelItem* parent() const; - void deleteAllChildren(); - const QList& children() const; - -private: - TorrentContentModelItem* m_parentItem; - FileType m_type; - QList m_childItems; +protected: + TorrentContentModelFolder* m_parentItem; + // Root item members QList m_itemData; - int m_fileIndex; + // Non-root item members + QString m_name; + qulonglong m_size; + float m_progress; + int m_priority; qulonglong m_totalDone; };