Browse Source

Use polymorphism to distinguish folder / file items in torrent content model

Step to address issue #24.
adaptive-webui-19844
Christophe Dumez 12 years ago
parent
commit
0fdacf4d54
  1. 2
      src/addnewtorrentdialog.cpp
  2. 4
      src/properties/propertieswidget.cpp
  3. 4
      src/src.pro
  4. 6
      src/torrentcontentfiltermodel.cpp
  5. 4
      src/torrentcontentfiltermodel.h
  6. 50
      src/torrentcontentmodel.cpp
  7. 4
      src/torrentcontentmodel.h
  8. 86
      src/torrentcontentmodelfile.cpp
  9. 52
      src/torrentcontentmodelfile.h
  10. 185
      src/torrentcontentmodelfolder.cpp
  11. 66
      src/torrentcontentmodelfolder.h
  12. 274
      src/torrentcontentmodelitem.cpp
  13. 61
      src/torrentcontentmodelitem.h

2
src/addnewtorrentdialog.cpp

@ -402,7 +402,7 @@ void AddNewTorrentDialog::renameSelectedFile()
QMessageBox::Ok); QMessageBox::Ok);
return; return;
} }
if (m_contentModel->getType(index) == TorrentContentModelItem::TFILE) { if (m_contentModel->itemType(index) == TorrentContentModelItem::FileType) {
// File renaming // File renaming
const int file_index = m_contentModel->getFileIndex(index); const int file_index = m_contentModel->getFileIndex(index);
QString old_name = m_filesPath.at(file_index); QString old_name = m_filesPath.at(file_index);

4
src/properties/propertieswidget.cpp

@ -412,7 +412,7 @@ void PropertiesWidget::loadUrlSeeds() {
void PropertiesWidget::openDoubleClickedFile(QModelIndex index) { void PropertiesWidget::openDoubleClickedFile(QModelIndex index) {
if (!index.isValid()) return; if (!index.isValid()) return;
if (!h.is_valid() || !h.has_metadata()) 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); int i = PropListModel->getFileIndex(index);
const QDir saveDir(h.save_path()); const QDir saveDir(h.save_path());
const QString filename = h.filepath_at(i); const QString filename = h.filepath_at(i);
@ -514,7 +514,7 @@ void PropertiesWidget::renameSelectedFile() {
QMessageBox::Ok); QMessageBox::Ok);
return; return;
} }
if (PropListModel->getType(index) == TorrentContentModelItem::TFILE) { if (PropListModel->itemType(index) == TorrentContentModelItem::FileType) {
// File renaming // File renaming
const int file_index = PropListModel->getFileIndex(index); const int file_index = PropListModel->getFileIndex(index);
if (!h.is_valid() || !h.has_metadata()) return; if (!h.is_valid() || !h.has_metadata()) return;

4
src/src.pro

@ -123,6 +123,8 @@ nox {
transferlistfilterswidget.h \ transferlistfilterswidget.h \
torrentcontentmodel.h \ torrentcontentmodel.h \
torrentcontentmodelitem.h \ torrentcontentmodelitem.h \
torrentcontentmodelfolder.h \
torrentcontentmodelfile.h \
torrentcontentfiltermodel.h \ torrentcontentfiltermodel.h \
deletionconfirmationdlg.h \ deletionconfirmationdlg.h \
statusbar.h \ statusbar.h \
@ -148,6 +150,8 @@ nox {
transferlistwidget.cpp \ transferlistwidget.cpp \
torrentcontentmodel.cpp \ torrentcontentmodel.cpp \
torrentcontentmodelitem.cpp \ torrentcontentmodelitem.cpp \
torrentcontentmodelfolder.cpp \
torrentcontentmodelfile.cpp \
torrentcontentfiltermodel.cpp \ torrentcontentfiltermodel.cpp \
sessionapplication.cpp \ sessionapplication.cpp \
torrentimportdlg.cpp \ torrentimportdlg.cpp \

6
src/torrentcontentfiltermodel.cpp

@ -54,9 +54,9 @@ TorrentContentModel* TorrentContentFilterModel::model() const
return m_model; 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 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 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 // always accept folders, since we want to filter their children
return true; return true;
} }

4
src/torrentcontentfiltermodel.h

@ -44,7 +44,7 @@ public:
virtual ~TorrentContentFilterModel(); virtual ~TorrentContentFilterModel();
TorrentContentModel* model() const; TorrentContentModel* model() const;
TorrentContentModelItem::FileType getType(const QModelIndex& index) const; TorrentContentModelItem::ItemType itemType(const QModelIndex& index) const;
int getFileIndex(const QModelIndex& index) const; int getFileIndex(const QModelIndex& index) const;
virtual QModelIndex parent(const QModelIndex& child) const; virtual QModelIndex parent(const QModelIndex& child) const;
@ -59,7 +59,7 @@ public slots:
void selectNone(); void selectNone();
private: private:
TorrentContentModel *m_model; TorrentContentModel* m_model;
}; };
#endif // TORRENTCONTENTFILTERMODEL_H #endif // TORRENTCONTENTFILTERMODEL_H

50
src/torrentcontentmodel.cpp

@ -32,11 +32,13 @@
#include "misc.h" #include "misc.h"
#include "torrentcontentmodel.h" #include "torrentcontentmodel.h"
#include "torrentcontentmodelitem.h" #include "torrentcontentmodelitem.h"
#include "torrentcontentmodelFolder.h"
#include "torrentcontentmodelFile.h"
#include <QDir> #include <QDir>
TorrentContentModel::TorrentContentModel(QObject *parent): TorrentContentModel::TorrentContentModel(QObject *parent):
QAbstractItemModel(parent), QAbstractItemModel(parent),
m_rootItem(new TorrentContentModelItem(QList<QVariant>() << tr("Name") << tr("Size") m_rootItem(new TorrentContentModelFolder(QList<QVariant>() << tr("Name") << tr("Size")
<< tr("Progress") << tr("Priority"))) << tr("Progress") << tr("Priority")))
{ {
} }
@ -73,7 +75,7 @@ std::vector<int> TorrentContentModel::getFilesPriorities() const
std::vector<int> prio; std::vector<int> prio;
prio.reserve(m_filesIndex.size()); prio.reserve(m_filesIndex.size());
foreach (const TorrentContentModelItem* file, m_filesIndex) { foreach (const TorrentContentModelItem* file, m_filesIndex) {
prio.push_back(file->getPriority()); prio.push_back(file->priority());
} }
return prio; return prio;
} }
@ -81,7 +83,7 @@ std::vector<int> TorrentContentModel::getFilesPriorities() const
bool TorrentContentModel::allFiltered() const bool TorrentContentModel::allFiltered() const
{ {
for (int i=0; i<m_rootItem->childCount(); ++i) { for (int i=0; i<m_rootItem->childCount(); ++i) {
if (m_rootItem->child(i)->getPriority() != prio::IGNORED) if (m_rootItem->child(i)->priority() != prio::IGNORED)
return false; return false;
} }
return true; return true;
@ -102,8 +104,8 @@ bool TorrentContentModel::setData(const QModelIndex& index, const QVariant& valu
if (index.column() == 0 && role == Qt::CheckStateRole) { if (index.column() == 0 && role == Qt::CheckStateRole) {
TorrentContentModelItem *item = static_cast<TorrentContentModelItem*>(index.internalPointer()); TorrentContentModelItem *item = static_cast<TorrentContentModelItem*>(index.internalPointer());
qDebug("setData(%s, %d", qPrintable(item->getName()), value.toInt()); qDebug("setData(%s, %d", qPrintable(item->name()), value.toInt());
if (item->getPriority() != value.toInt()) { if (item->priority() != value.toInt()) {
if (value.toInt() == Qt::PartiallyChecked) if (value.toInt() == Qt::PartiallyChecked)
item->setPriority(prio::PARTIAL); item->setPriority(prio::PARTIAL);
else if (value.toInt() == Qt::Unchecked) else if (value.toInt() == Qt::Unchecked)
@ -140,16 +142,17 @@ bool TorrentContentModel::setData(const QModelIndex& index, const QVariant& valu
return false; return false;
} }
TorrentContentModelItem::FileType TorrentContentModel::getType(const QModelIndex& index) const TorrentContentModelItem::ItemType TorrentContentModel::itemType(const QModelIndex& index) const
{ {
const TorrentContentModelItem *item = static_cast<const TorrentContentModelItem*>(index.internalPointer()); const TorrentContentModelItem *item = static_cast<const TorrentContentModelItem*>(index.internalPointer());
return item->getType(); return item->itemType();
} }
int TorrentContentModel::getFileIndex(const QModelIndex& index) int TorrentContentModel::getFileIndex(const QModelIndex& index)
{ {
TorrentContentModelItem* item = static_cast<TorrentContentModelItem*>(index.internalPointer()); TorrentContentModelFile* item = dynamic_cast<TorrentContentModelFile*>(static_cast<TorrentContentModelItem*>(index.internalPointer()));
return item->getFileIndex(); Q_ASSERT(item);
return item->fileIndex();
} }
QVariant TorrentContentModel::data(const QModelIndex &index, int role) const 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<TorrentContentModelItem*>(index.internalPointer()); TorrentContentModelItem *item = static_cast<TorrentContentModelItem*>(index.internalPointer());
if (index.column() == 0 && role == Qt::DecorationRole) { if (index.column() == 0 && role == Qt::DecorationRole) {
if (item->isFolder()) if (item->itemType() == TorrentContentModelItem::FolderType)
return IconProvider::instance()->getIcon("inode-directory"); return IconProvider::instance()->getIcon("inode-directory");
else else
return IconProvider::instance()->getIcon("text-plain"); return IconProvider::instance()->getIcon("text-plain");
@ -182,7 +185,7 @@ Qt::ItemFlags TorrentContentModel::flags(const QModelIndex& index) const
if (!index.isValid()) if (!index.isValid())
return 0; 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 | Qt::ItemIsTristate;
return Qt::ItemIsEditable | Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable; 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) if (column >= TorrentContentModelItem::NB_COL)
return QModelIndex(); return QModelIndex();
TorrentContentModelItem *parentItem; TorrentContentModelFolder *parentItem;
if (!parent.isValid()) if (!parent.isValid())
parentItem = m_rootItem; parentItem = m_rootItem;
else else
parentItem = static_cast<TorrentContentModelItem*>(parent.internalPointer()); parentItem = static_cast<TorrentContentModelFolder*>(parent.internalPointer());
Q_ASSERT(parentItem); Q_ASSERT(parentItem);
if (row >= parentItem->childCount()) if (row >= parentItem->childCount())
return QModelIndex(); return QModelIndex();
@ -239,17 +242,16 @@ QModelIndex TorrentContentModel::parent(const QModelIndex& index) const
int TorrentContentModel::rowCount(const QModelIndex& parent) const int TorrentContentModel::rowCount(const QModelIndex& parent) const
{ {
TorrentContentModelItem* parentItem;
if (parent.column() > 0) if (parent.column() > 0)
return 0; return 0;
TorrentContentModelFolder* parentItem ;
if (!parent.isValid()) if (!parent.isValid())
parentItem = m_rootItem; parentItem = m_rootItem;
else else
parentItem = static_cast<TorrentContentModelItem*>(parent.internalPointer()); parentItem = dynamic_cast<TorrentContentModelFolder*>(static_cast<TorrentContentModelItem*>(parent.internalPointer()));
return parentItem->childCount(); return parentItem ? parentItem->childCount() : 0;
} }
void TorrentContentModel::clear() void TorrentContentModel::clear()
@ -272,9 +274,9 @@ void TorrentContentModel::setupModelData(const libtorrent::torrent_info& t)
qDebug("Torrent contains %d files", t.num_files()); qDebug("Torrent contains %d files", t.num_files());
m_filesIndex.reserve(t.num_files()); m_filesIndex.reserve(t.num_files());
TorrentContentModelItem* parent = m_rootItem; TorrentContentModelFolder* parent = m_rootItem;
TorrentContentModelItem* root_folder = parent; TorrentContentModelFolder* root_folder = parent;
TorrentContentModelItem* current_parent; TorrentContentModelFolder* current_parent;
// Iterate over files // Iterate over files
for (int i=0; i<t.num_files(); ++i) { for (int i=0; i<t.num_files(); ++i) {
@ -291,13 +293,13 @@ void TorrentContentModel::setupModelData(const libtorrent::torrent_info& t)
foreach (const QString& pathPart, pathFolders) { foreach (const QString& pathPart, pathFolders) {
if (pathPart == ".unwanted") if (pathPart == ".unwanted")
continue; continue;
TorrentContentModelItem* new_parent = current_parent->childWithName(pathPart); TorrentContentModelFolder* new_parent = current_parent->childFolderWithName(pathPart);
if (!new_parent) if (!new_parent)
new_parent = new TorrentContentModelItem(pathPart, current_parent); new_parent = new TorrentContentModelFolder(pathPart, current_parent);
current_parent = new_parent; current_parent = new_parent;
} }
// Actually create the file // 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(); emit layoutChanged();
} }
@ -306,7 +308,7 @@ void TorrentContentModel::selectAll()
{ {
for (int i=0; i<m_rootItem->childCount(); ++i) { for (int i=0; i<m_rootItem->childCount(); ++i) {
TorrentContentModelItem* child = m_rootItem->child(i); TorrentContentModelItem* child = m_rootItem->child(i);
if (child->getPriority() == prio::IGNORED) if (child->priority() == prio::IGNORED)
child->setPriority(prio::NORMAL); child->setPriority(prio::NORMAL);
} }
emit dataChanged(index(0,0), index(rowCount(), columnCount())); emit dataChanged(index(0,0), index(rowCount(), columnCount()));

4
src/torrentcontentmodel.h

@ -51,7 +51,7 @@ public:
bool allFiltered() const; bool allFiltered() const;
virtual int columnCount(const QModelIndex &parent=QModelIndex()) const; virtual int columnCount(const QModelIndex &parent=QModelIndex()) const;
virtual bool setData(const QModelIndex& index, const QVariant& value, int role = Qt::EditRole); 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); int getFileIndex(const QModelIndex& index);
virtual QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const; virtual QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const;
virtual Qt::ItemFlags flags(const QModelIndex& index) const; virtual Qt::ItemFlags flags(const QModelIndex& index) const;
@ -70,7 +70,7 @@ public slots:
void selectNone(); void selectNone();
private: private:
TorrentContentModelItem* m_rootItem; TorrentContentModelFolder* m_rootItem;
QVector<TorrentContentModelItem*> m_filesIndex; QVector<TorrentContentModelItem*> m_filesIndex;
}; };

86
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();
}
}

52
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

185
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<QVariant>& 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<TorrentContentModelItem*>& 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<TorrentContentModelFolder*>(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; i<m_childItems.size(); ++i) {
if (m_childItems.at(i)->priority() != 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);
}

66
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<QVariant>& 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<TorrentContentModelItem*>& children() const;
void appendChild(TorrentContentModelItem* item);
TorrentContentModelItem* child(int row) const;
TorrentContentModelFolder* childFolderWithName(const QString& name) const;
int childCount() const;
private:
QList<TorrentContentModelItem*> m_childItems;
};
#endif // TORRENTCONTENTMODELFOLDER_H

274
src/torrentcontentmodelitem.cpp

@ -31,281 +31,113 @@
#include "misc.h" #include "misc.h"
#include "fs_utils.h" #include "fs_utils.h"
#include "torrentcontentmodelitem.h" #include "torrentcontentmodelitem.h"
#include "torrentcontentmodelfolder.h"
#include <QDebug> #include <QDebug>
TorrentContentModelItem::TorrentContentModelItem(const libtorrent::torrent_info &t, TorrentContentModelItem::TorrentContentModelItem(TorrentContentModelFolder* parent)
const libtorrent::file_entry &f, : m_parentItem(parent)
TorrentContentModelItem *parent, , m_progress(0)
int file_index): , m_priority(prio::NORMAL)
m_parentItem(parent), m_type(TFILE), m_fileIndex(file_index), m_totalDone(0) , 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<QVariant>& data):
m_parentItem(0), m_type(ROOT), m_itemData(data), m_totalDone(0)
{
Q_ASSERT(data.size() == 4);
} }
TorrentContentModelItem::~TorrentContentModelItem() 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 QString TorrentContentModelItem::name() const
{ {
return m_itemData.at(COL_NAME).toString(); Q_ASSERT(!isRootItem());
return m_name;
} }
void TorrentContentModelItem::setName(const QString& name) void TorrentContentModelItem::setName(const QString& name)
{ {
Q_ASSERT(m_type != ROOT); Q_ASSERT(!isRootItem());
m_itemData.replace(COL_NAME, name); 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) void TorrentContentModelItem::setSize(qulonglong size)
{ {
Q_ASSERT (m_type != ROOT); Q_ASSERT(!isRootItem());
if (getSize() == size) if (m_size == size)
return; return;
m_itemData.replace(COL_SIZE, (qulonglong)size);
m_size = size;
m_parentItem->updateSize(); m_parentItem->updateSize();
} }
void TorrentContentModelItem::updateSize() void TorrentContentModelItem::setProgress(qulonglong done)
{ {
if (m_type == ROOT) Q_ASSERT(!isRootItem());
if (m_priority == prio::IGNORED)
return; 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; m_totalDone = done;
qulonglong size = getSize(); Q_ASSERT(m_totalDone <= m_size);
Q_ASSERT(m_totalDone <= size);
qreal progress; qreal progress;
if (size > 0) if (m_size > 0)
progress = m_totalDone/(float)size; progress = m_totalDone / (double) m_size;
else else
progress = 1.; progress = 1.;
Q_ASSERT(progress >= 0. && progress <= 1.); Q_ASSERT(progress >= 0. && progress <= 1.);
m_itemData.replace(COL_PROGRESS, progress); m_progress = progress;
m_parentItem->updateProgress(); m_parentItem->updateProgress();
} }
qulonglong TorrentContentModelItem::getTotalDone() const qulonglong TorrentContentModelItem::totalDone() const
{ {
Q_ASSERT(!isRootItem());
return m_totalDone; return m_totalDone;
} }
float TorrentContentModelItem::getProgress() const float TorrentContentModelItem::progress() const
{ {
Q_ASSERT (m_type != ROOT); Q_ASSERT(!isRootItem());
if (getPriority() == 0) if (m_priority == prio::IGNORED)
return -1; return -1;
qulonglong size = getSize();
if (size > 0)
return m_totalDone / (float) getSize();
return 1.;
}
void TorrentContentModelItem::updateProgress() if (m_size > 0)
{ return m_totalDone / (double) m_size;
if (m_type == ROOT) return; return 1;
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 int TorrentContentModelItem::priority() const
{ {
return m_itemData.value(COL_PRIO).toInt(); Q_ASSERT(!isRootItem());
} return m_priority;
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 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; 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) const
{
//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 int TorrentContentModelItem::columnCount() const
{ {
return m_itemData.count(); return NB_COL;
} }
QVariant TorrentContentModelItem::data(int column) const QVariant TorrentContentModelItem::data(int column) const
{ {
if (column == COL_PROGRESS && m_type != ROOT) if (isRootItem())
return getProgress();
return m_itemData.value(column); 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 int TorrentContentModelItem::row() const
@ -315,7 +147,7 @@ int TorrentContentModelItem::row() const
return 0; return 0;
} }
TorrentContentModelItem* TorrentContentModelItem::parent() const TorrentContentModelFolder* TorrentContentModelItem::parent() const
{ {
return m_parentItem; return m_parentItem;
} }

61
src/torrentcontentmodelitem.h

@ -39,63 +39,46 @@ namespace prio {
enum FilePriority {IGNORED=0, NORMAL=1, HIGH=2, MAXIMUM=7, PARTIAL=-1}; enum FilePriority {IGNORED=0, NORMAL=1, HIGH=2, MAXIMUM=7, PARTIAL=-1};
} }
class TorrentContentModelFolder;
class TorrentContentModelItem { class TorrentContentModelItem {
public: public:
enum TreeItemColumns {COL_NAME, COL_SIZE, COL_PROGRESS, COL_PRIO, NB_COL}; 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<QVariant>& data);
~TorrentContentModelItem();
FileType getType() const; TorrentContentModelItem(TorrentContentModelFolder* parent);
virtual ~TorrentContentModelItem();
int getFileIndex() const; inline bool isRootItem() const { return !m_parentItem; }
TorrentContentModelFolder* parent() const;
virtual ItemType itemType() const = 0;
QString getName() const; QString name() const;
void setName(const QString& name); void setName(const QString& name);
qulonglong getSize() const; qulonglong size() const;
void setSize(qulonglong size); void setSize(qulonglong size);
void updateSize(); qulonglong totalDone() const;
qulonglong getTotalDone() const;
void setProgress(qulonglong done); void setProgress(qulonglong done);
float getProgress() const; float progress() const;
void updateProgress();
int getPriority() const; int priority() const;
void setPriority(int new_prio, bool update_parent=true); virtual void setPriority(int new_prio, bool update_parent = true) = 0;
void updatePriority();
TorrentContentModelItem* childWithName(const QString& name) const;
bool isFolder() const;
void appendChild(TorrentContentModelItem *item);
TorrentContentModelItem* child(int row) const;
int childCount() const;
int columnCount() const; int columnCount() const;
QVariant data(int column) const; QVariant data(int column) const;
int row() const; int row() const;
TorrentContentModelItem* parent() const; protected:
void deleteAllChildren(); TorrentContentModelFolder* m_parentItem;
const QList<TorrentContentModelItem*>& children() const; // Root item members
private:
TorrentContentModelItem* m_parentItem;
FileType m_type;
QList<TorrentContentModelItem*> m_childItems;
QList<QVariant> m_itemData; QList<QVariant> m_itemData;
int m_fileIndex; // Non-root item members
QString m_name;
qulonglong m_size;
float m_progress;
int m_priority;
qulonglong m_totalDone; qulonglong m_totalDone;
}; };

Loading…
Cancel
Save