From d76877b1a23910547e81ef77622d7f539339fe69 Mon Sep 17 00:00:00 2001 From: Christophe Dumez Date: Sun, 14 Nov 2010 15:28:22 +0000 Subject: [PATCH] Brand new torrent model for the transfer list --- src/advancedsettings.h | 3 +- src/mainwindow.cpp | 18 +- src/mainwindow.h | 2 +- src/qtlibtorrent/qbtsession.h | 2 +- src/qtlibtorrent/qtlibtorrent.pri | 5 + src/qtlibtorrent/torrentmodel.cpp | 413 ++++++++++++++++++++++ src/qtlibtorrent/torrentmodel.h | 92 +++++ src/scannedfoldersmodel.cpp | 2 +- src/transferlistdelegate.h | 51 ++- src/transferlistfilterswidget.h | 40 +-- src/transferlistwidget.cpp | 559 ++---------------------------- src/transferlistwidget.h | 24 +- 12 files changed, 609 insertions(+), 602 deletions(-) create mode 100644 src/qtlibtorrent/torrentmodel.cpp create mode 100644 src/qtlibtorrent/torrentmodel.h diff --git a/src/advancedsettings.h b/src/advancedsettings.h index 0b24bebf1..5f97e2a4e 100644 --- a/src/advancedsettings.h +++ b/src/advancedsettings.h @@ -11,8 +11,7 @@ #include "preferences.h" enum AdvSettingsCols {PROPERTY, VALUE}; -enum AdvSettingsRows {DISK_CACHE, OUTGOING_PORT_MIN, OUTGOING_PORT_MAX, IGNORE_LIMIT_LAN, COUNT_OVERHEAD, RECHECK_COMPLETED, LIST_REFRESH, RESOLVE_COUNTRIES, RESOLVE_HOSTS, MAX_HALF_OPEN, SUPER_SEEDING, NETWORK_IFACE, PROGRAM_NOTIFICATIONS, TRACKER_STATUS, TRACKER_PORT }; -#define ROW_COUNT 15 +enum AdvSettingsRows {DISK_CACHE, OUTGOING_PORT_MIN, OUTGOING_PORT_MAX, IGNORE_LIMIT_LAN, COUNT_OVERHEAD, RECHECK_COMPLETED, LIST_REFRESH, RESOLVE_COUNTRIES, RESOLVE_HOSTS, MAX_HALF_OPEN, SUPER_SEEDING, NETWORK_IFACE, PROGRAM_NOTIFICATIONS, TRACKER_STATUS, TRACKER_PORT, ROW_COUNT }; class AdvancedSettings: public QTableWidget { Q_OBJECT diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 95ec95033..644fbfab1 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -69,6 +69,7 @@ #include "qinisettings.h" #include "torrentimportdlg.h" #include "rsssettings.h" +#include "torrentmodel.h" #ifdef Q_WS_MAC #include "qmacapplication.h" void qt_mac_set_dock_menu(QMenu *menu); @@ -162,7 +163,9 @@ MainWindow::MainWindow(QWidget *parent, QStringList torrentCmdLine) : QMainWindo vSplitter->setCollapsible(0, true); vSplitter->setCollapsible(1, false); tabs->addTab(vSplitter, QIcon(QString::fromUtf8(":/Icons/oxygen/folder-remote.png")), tr("Transfers")); - connect(transferList, SIGNAL(torrentStatusUpdate(uint,uint,uint,uint,uint)), this, SLOT(updateNbTorrents(uint,uint,uint,uint,uint))); + connect(transferList->getSourceModel(), SIGNAL(rowsInserted(QModelIndex, int, int)), this, SLOT(updateNbTorrents())); + connect(transferList->getSourceModel(), SIGNAL(rowsRemoved(QModelIndex, int, int)), this, SLOT(updateNbTorrents())); + vboxLayout->addWidget(tabs); // Name filter @@ -236,6 +239,9 @@ MainWindow::MainWindow(QWidget *parent, QStringList torrentCmdLine) : QMainWindo // Add torrent given on command line processParams(torrentCmdLine); + // Populate the transfer list + transferList->getSourceModel()->populate(); + qDebug("GUI Built"); #ifdef Q_WS_WIN if(!Preferences::neverCheckFileAssoc() && !Preferences::isFileAssocOk()) { @@ -395,11 +401,8 @@ void MainWindow::displaySearchTab(bool enable) { } } -void MainWindow::updateNbTorrents(unsigned int nb_downloading, unsigned int nb_seeding, unsigned int nb_active, unsigned int nb_inactive, unsigned int nb_paused) { - Q_UNUSED(nb_downloading); - Q_UNUSED(nb_seeding); - Q_UNUSED(nb_paused); - tabs->setTabText(0, tr("Transfers (%1)").arg(QString::number(nb_inactive+nb_active))); +void MainWindow::updateNbTorrents() { + tabs->setTabText(0, tr("Transfers (%1)").arg(transferList->getSourceModel()->rowCount())); } void MainWindow::on_actionWebsite_triggered() const { @@ -420,7 +423,6 @@ void MainWindow::tab_changed(int new_tab) { // because the tab order is undetermined now if(tabs->currentWidget() == vSplitter) { qDebug("Changed tab to transfer list, refreshing the list"); - transferList->refreshList(); properties->loadDynamicData(); return; } @@ -665,8 +667,6 @@ void MainWindow::on_actionAbout_triggered() { void MainWindow::showEvent(QShowEvent *e) { qDebug("** Show Event **"); if(getCurrentTabWidget() == transferList) { - qDebug("-> Refreshing transfer list"); - transferList->refreshList(); properties->loadDynamicData(); } e->accept(); diff --git a/src/mainwindow.h b/src/mainwindow.h index 1303e730a..ced89b0c4 100644 --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -79,7 +79,7 @@ public slots: void showNotificationBaloon(QString title, QString msg) const; void downloadFromURLList(const QStringList& urls); void updateAltSpeedsBtn(bool alternative); - void updateNbTorrents(unsigned int nb_downloading, unsigned int nb_seeding, unsigned int nb_active, unsigned int nb_inactive, unsigned int nb_paused); + void updateNbTorrents(); void deleteBTSession(); protected slots: diff --git a/src/qtlibtorrent/qbtsession.h b/src/qtlibtorrent/qbtsession.h index 76f3161d2..880755a43 100644 --- a/src/qtlibtorrent/qbtsession.h +++ b/src/qtlibtorrent/qbtsession.h @@ -190,7 +190,7 @@ protected slots: #endif signals: - void addedTorrent(QTorrentHandle& h); + void addedTorrent(const QTorrentHandle& h); void deletedTorrent(QString hash); void pausedTorrent(QTorrentHandle& h); void resumedTorrent(QTorrentHandle& h); diff --git a/src/qtlibtorrent/qtlibtorrent.pri b/src/qtlibtorrent/qtlibtorrent.pri index dcb6e17b8..7bc0035d4 100644 --- a/src/qtlibtorrent/qtlibtorrent.pri +++ b/src/qtlibtorrent/qtlibtorrent.pri @@ -7,3 +7,8 @@ HEADERS += $$PWD/qbtsession.h \ SOURCES += $$PWD/qbtsession.cpp \ $$PWD/qtorrenthandle.cpp + +!contains(DEFINES, DISABLE_GUI) { + HEADERS += $$PWD/torrentmodel.h + SOURCES += $$PWD/torrentmodel.cpp +} diff --git a/src/qtlibtorrent/torrentmodel.cpp b/src/qtlibtorrent/torrentmodel.cpp new file mode 100644 index 000000000..e1d698ce9 --- /dev/null +++ b/src/qtlibtorrent/torrentmodel.cpp @@ -0,0 +1,413 @@ +#include + +#include "torrentmodel.h" +#include "torrentpersistentdata.h" +#include "qbtsession.h" + +using namespace libtorrent; + +TorrentModelItem::TorrentModelItem(const QTorrentHandle &h) +{ + m_torrent = h; + m_name = TorrentPersistentData::getName(h.hash()); + if(m_name.isEmpty()) m_name = h.name(); + m_addedTime = TorrentPersistentData::getAddedDate(h.hash()); + m_seedTime = TorrentPersistentData::getSeedDate(h.hash()); + m_label = TorrentPersistentData::getLabel(h.hash()); +} + +TorrentModelItem::State TorrentModelItem::state() const +{ + try { + // Pause or Queued + if(m_torrent.is_paused()) { + m_icon = QIcon(":/Icons/skin/paused.png"); + m_fgColor = QColor("red"); + return m_torrent.is_seed() ? STATE_PAUSED_UP : STATE_PAUSED_DL; + } + if(m_torrent.is_queued()) { + m_icon = QIcon(":/Icons/skin/queued.png"); + m_fgColor = QColor("grey"); + return m_torrent.is_seed() ? STATE_QUEUED_UP : STATE_QUEUED_DL; + } + // Other states + switch(m_torrent.state()) { + case torrent_status::allocating: + case torrent_status::downloading_metadata: + case torrent_status::downloading: { + if(m_torrent.download_payload_rate() > 0) { + m_icon = QIcon(":/Icons/skin/downloading.png"); + m_fgColor = QColor("green"); + return STATE_DOWNLOADING; + } else { + m_icon = QIcon(":/Icons/skin/stalledDL.png"); + m_fgColor = QColor("grey"); + return STATE_STALLED_DL; + } + } + case torrent_status::finished: + case torrent_status::seeding: + if(m_torrent.upload_payload_rate() > 0) { + m_icon = QIcon(":/Icons/skin/uploading.png"); + m_fgColor = QColor("orange"); + return STATE_SEEDING; + } else { + m_icon = QIcon(":/Icons/skin/stalledUP.png"); + m_fgColor = QColor("grey"); + return STATE_STALLED_UP; + } + case torrent_status::queued_for_checking: + case torrent_status::checking_resume_data: + case torrent_status::checking_files: + m_icon = QIcon(":/Icons/skin/checking.png"); + m_fgColor = QColor("grey"); + return m_torrent.is_seed() ? STATE_CHECKING_UP : STATE_CHECKING_DL; + default: + m_icon = QIcon(":/Icons/skin/error.png"); + m_fgColor = QColor("red"); + return STATE_INVALID; + } + } catch(invalid_handle&) { + m_icon = QIcon(":/Icons/skin/error.png"); + m_fgColor = QColor("red"); + return STATE_INVALID; + } +} + +bool TorrentModelItem::setData(int column, const QVariant &value, int role) +{ + if(role != Qt::DisplayRole) return false; + // Label and Name columns can be edited + switch(column) { + case TR_NAME: + m_name = value.toString(); + TorrentPersistentData::saveName(m_torrent.hash(), m_name); + return true; + case TR_LABEL: { + QString new_label = value.toString(); + if(m_label != new_label) { + QString old_label = m_label; + m_label = new_label; + TorrentPersistentData::saveLabel(m_torrent.hash(), new_label); + emit labelChanged(old_label, new_label); + } + return true; + } + default: + break; + } + return false; +} + +QVariant TorrentModelItem::data(int column, int role) const +{ + if(role == Qt::DecorationRole && column == TR_NAME) { + return m_icon; + } + if(role == Qt::ForegroundRole) { + return m_fgColor; + } + if(role != Qt::DisplayRole) return QVariant(); + switch(column) { + case TR_NAME: + return m_name; + case TR_PRIORITY: + return m_torrent.queue_position(); + case TR_SIZE: + return static_cast(m_torrent.actual_size()); + case TR_PROGRESS: + return m_torrent.progress(); + case TR_STATUS: + return state(); + case TR_SEEDS: { + // XXX: Probably a better way to do this + qulonglong seeds = m_torrent.num_seeds()*1000000; + if(m_torrent.num_complete() >= m_torrent.num_seeds()) + seeds += m_torrent.num_complete()*10; + else + seeds += 1; + return seeds; + } + case TR_PEERS: { + qulonglong peers = (m_torrent.num_peers()-m_torrent.num_seeds())*1000000; + if(m_torrent.num_incomplete() >= (m_torrent.num_peers()-m_torrent.num_seeds())) + peers += m_torrent.num_incomplete()*10; + else + peers += 1; + return peers; + } + case TR_DLSPEED: + return m_torrent.download_payload_rate(); + case TR_UPSPEED: + return m_torrent.upload_payload_rate(); + case TR_ETA: { + // XXX: Is this correct? + if(m_torrent.is_seed() || m_torrent.is_paused() || m_torrent.is_queued()) return MAX_ETA; + return QBtSession::instance()->getETA(m_torrent.hash()); + } + case TR_RATIO: + return QBtSession::instance()->getRealRatio(m_torrent.hash()); + case TR_LABEL: + return m_label; + case TR_ADD_DATE: + return m_addedTime; + case TR_SEED_DATE: + return m_seedTime; + case TR_TRACKER: + return m_torrent.current_tracker(); + case TR_DLLIMIT: + return m_torrent.download_limit(); + case TR_UPLIMIT: + return m_torrent.upload_limit(); + default: + return QVariant(); + } +} + +// TORRENT MODEL + +TorrentModel::TorrentModel(QObject *parent) : + QAbstractListModel(parent), m_refreshInterval(2000) +{ +} + +void TorrentModel::populate() { + // Load the torrents + std::vector torrents = QBtSession::instance()->getSession()->get_torrents(); + std::vector::const_iterator it; + for(it = torrents.begin(); it != torrents.end(); it++) { + addTorrent(QTorrentHandle(*it)); + } + // Refresh timer + connect(&m_refreshTimer, SIGNAL(timeout()), SLOT(forceModelRefresh())); + m_refreshTimer.start(m_refreshInterval); + // Listen for torrent changes + connect(QBtSession::instance(), SIGNAL(addedTorrent(QTorrentHandle)), SLOT(addTorrent(QTorrentHandle))); + connect(QBtSession::instance(), SIGNAL(deletedTorrent(QString)), SLOT(removeTorrent(QString))); + connect(QBtSession::instance(), SIGNAL(finishedTorrent(QTorrentHandle&)), SLOT(handleTorrentUpdate(QTorrentHandle&))); + connect(QBtSession::instance(), SIGNAL(metadataReceived(QTorrentHandle&)), SLOT(handleTorrentUpdate(QTorrentHandle&))); + connect(QBtSession::instance(), SIGNAL(resumedTorrent(QTorrentHandle&)), SLOT(handleTorrentUpdate(QTorrentHandle&))); + connect(QBtSession::instance(), SIGNAL(pausedTorrent(QTorrentHandle&)), SLOT(handleTorrentUpdate(QTorrentHandle&))); + connect(QBtSession::instance(), SIGNAL(torrentFinishedChecking(QTorrentHandle&)), SLOT(handleTorrentUpdate(QTorrentHandle&))); +} + +TorrentModel::~TorrentModel() { + qDeleteAll(m_torrents); + m_torrents.clear(); +} + +QVariant TorrentModel::headerData(int section, Qt::Orientation orientation, + int role) const +{ + if (orientation == Qt::Horizontal) { + if(role == Qt::DisplayRole) { + switch(section) { + case TorrentModelItem::TR_NAME: return tr("Name", "i.e: torrent name"); + case TorrentModelItem::TR_PRIORITY: return "#"; + case TorrentModelItem::TR_SIZE: return tr("Size", "i.e: torrent size"); + case TorrentModelItem::TR_PROGRESS: return tr("Done", "% Done"); + case TorrentModelItem::TR_STATUS: return tr("Status", "Torrent status (e.g. downloading, seeding, paused)"); + case TorrentModelItem::TR_SEEDS: return tr("Seeds", "i.e. full sources (often untranslated)"); + case TorrentModelItem::TR_PEERS: return tr("Peers", "i.e. partial sources (often untranslated)"); + case TorrentModelItem::TR_DLSPEED: return tr("Down Speed", "i.e: Download speed"); + case TorrentModelItem::TR_UPSPEED: return tr("Up Speed", "i.e: Upload speed"); + case TorrentModelItem::TR_RATIO: return tr("Ratio", "Share ratio"); + case TorrentModelItem::TR_ETA: return tr("ETA", "i.e: Estimated Time of Arrival / Time left"); + case TorrentModelItem::TR_LABEL: return tr("Label"); + case TorrentModelItem::TR_ADD_DATE: return tr("Added On", "Torrent was added to transfer list on 01/01/2010 08:00"); + case TorrentModelItem::TR_SEED_DATE: return tr("Completed On", "Torrent was completed on 01/01/2010 08:00"); + case TorrentModelItem::TR_TRACKER: return tr("Tracker"); + case TorrentModelItem::TR_DLLIMIT: return tr("Down Limit", "i.e: Download limit"); + case TorrentModelItem::TR_UPLIMIT: return tr("Up Limit", "i.e: Upload limit"); + default: + return QVariant(); + } + } + if(role == Qt::TextAlignmentRole) { + switch(section) { + case TorrentModelItem::TR_PRIORITY: + case TorrentModelItem::TR_SIZE: + case TorrentModelItem::TR_SEEDS: + case TorrentModelItem::TR_PEERS: + case TorrentModelItem::TR_DLSPEED: + case TorrentModelItem::TR_UPSPEED: + case TorrentModelItem::TR_RATIO: + case TorrentModelItem::TR_DLLIMIT: + case TorrentModelItem::TR_UPLIMIT: + return Qt::AlignRight; + case TorrentModelItem::TR_PROGRESS: + return Qt::AlignHCenter; + default: + return Qt::AlignLeft; + } + } + } + + return QVariant(); +} + +QVariant TorrentModel::data(const QModelIndex &index, int role) const +{ + if(!index.isValid()) return QVariant(); + try { + if(index.row() >= 0 && index.row() < rowCount() && index.column() >= 0 && index.column() < columnCount()) + return m_torrents[index.row()]->data(index.column(), role); + } catch(invalid_handle&) {} + return QVariant(); +} + +bool TorrentModel::setData(const QModelIndex &index, const QVariant &value, int role) +{ + if(!index.isValid() || role != Qt::DisplayRole) return false; + try { + if(index.row() >= 0 && index.row() < rowCount() && index.column() >= 0 && index.column() < columnCount()) { + bool change = m_torrents[index.row()]->setData(index.column(), value, role); + if(change) + notifyTorrentChanged(index.row()); + return change; + } + } catch(invalid_handle&) {} + return false; +} + +int TorrentModel::torrentRow(const QString &hash) const +{ + QList::const_iterator it; + int row; + for(it = m_torrents.constBegin(); it != m_torrents.constEnd(); it++) { + try { + if((*it)->hash() == hash) return row; + }catch(invalid_handle&) {} + ++row; + } + return -1; +} + +void TorrentModel::addTorrent(const QTorrentHandle &h) +{ + if(torrentRow(h.hash()) < 0) { + beginInsertTorrent(m_torrents.size()); + TorrentModelItem *item = new TorrentModelItem(h); + connect(item, SIGNAL(labelChanged(QString,QString)), SLOT(handleTorrentLabelChange(QString,QString))); + m_torrents << item; + emit torrentAdded(item); + endInsertTorrent(); + } +} + +void TorrentModel::removeTorrent(const QString &hash) +{ + const int row = torrentRow(hash); + if(row > 0) { + emit torrentAboutToBeRemoved(m_torrents.at(row)); + beginRemoveTorrent(row); + m_torrents.removeAt(row); + endRemoveTorrent(); + } +} + +void TorrentModel::beginInsertTorrent(int row) +{ + beginInsertRows(QModelIndex(), row, row); +} + +void TorrentModel::endInsertTorrent() +{ + endInsertRows(); +} + +void TorrentModel::beginRemoveTorrent(int row) +{ + beginRemoveRows(QModelIndex(), row, row); +} + +void TorrentModel::endRemoveTorrent() +{ + endRemoveRows(); +} + +void TorrentModel::handleTorrentUpdate(QTorrentHandle &h) +{ + const int row = torrentRow(h.hash()); + if(row >= 0) { + notifyTorrentChanged(row); + } +} + +void TorrentModel::notifyTorrentChanged(int row) +{ + emit dataChanged(index(row, 0), index(row, columnCount()-1)); +} + +void TorrentModel::setRefreshInterval(int refreshInterval) +{ + if(m_refreshInterval != refreshInterval) { + m_refreshInterval = refreshInterval; + m_refreshTimer.stop(); + m_refreshTimer.start(m_refreshInterval); + } +} + +void TorrentModel::forceModelRefresh() +{ + emit dataChanged(index(0, 0), index(rowCount()-1, columnCount()-1)); +} + +TorrentStatusReport TorrentModel::getTorrentStatusReport() const +{ + TorrentStatusReport report; + QList::const_iterator it; + for(it = m_torrents.constBegin(); it != m_torrents.constEnd(); it++) { + switch((*it)->data(TorrentModelItem::TR_STATUS).toInt()) { + case TorrentModelItem::STATE_DOWNLOADING: + ++report.nb_active; + ++report.nb_downloading; + break; + case TorrentModelItem::STATE_PAUSED_DL: + ++report.nb_paused; + case TorrentModelItem::STATE_STALLED_DL: + case TorrentModelItem::STATE_CHECKING_DL: + case TorrentModelItem::STATE_QUEUED_DL: { + ++report.nb_inactive; + ++report.nb_downloading; + break; + } + case TorrentModelItem::STATE_SEEDING: + ++report.nb_active; + ++report.nb_seeding; + break; + case TorrentModelItem::STATE_PAUSED_UP: + ++report.nb_paused; + case TorrentModelItem::STATE_STALLED_UP: + case TorrentModelItem::STATE_CHECKING_UP: + case TorrentModelItem::STATE_QUEUED_UP: { + ++report.nb_seeding; + ++report.nb_inactive; + break; + } + default: + break; + } + } + return report; +} + +Qt::ItemFlags TorrentModel::flags(const QModelIndex &index) const +{ + if (!index.isValid()) + return 0; + // Explicitely mark as editable + return QAbstractListModel::flags(index) | Qt::ItemIsEditable; +} + +void TorrentModel::handleTorrentLabelChange(QString previous, QString current) +{ + emit torrentChangedLabel(static_cast(sender()), previous, current); +} + +QString TorrentModel::torrentHash(int row) const +{ + if(row >= 0 && row < rowCount()) + return m_torrents.at(row)->hash(); + return QString(); +} diff --git a/src/qtlibtorrent/torrentmodel.h b/src/qtlibtorrent/torrentmodel.h new file mode 100644 index 000000000..b0d092b2f --- /dev/null +++ b/src/qtlibtorrent/torrentmodel.h @@ -0,0 +1,92 @@ +#ifndef TORRENTMODEL_H +#define TORRENTMODEL_H + +#include +#include +#include +#include +#include + +#include "qtorrenthandle.h" + +struct TorrentStatusReport { + TorrentStatusReport(): nb_downloading(0), nb_seeding(0), nb_active(0), nb_inactive(0), nb_paused(0) {} + uint nb_downloading; uint nb_seeding; uint nb_active; uint nb_inactive; uint nb_paused; +}; + +class TorrentModelItem : public QObject { +Q_OBJECT + +public: + enum State {STATE_DOWNLOADING, STATE_STALLED_DL, STATE_STALLED_UP, STATE_SEEDING, STATE_PAUSED_DL, STATE_PAUSED_UP, STATE_QUEUED_DL, STATE_QUEUED_UP, STATE_CHECKING_UP, STATE_CHECKING_DL, STATE_INVALID}; + enum Column {TR_NAME, TR_PRIORITY, TR_SIZE, TR_PROGRESS, TR_STATUS, TR_SEEDS, TR_PEERS, TR_DLSPEED, TR_UPSPEED, TR_ETA, TR_RATIO, TR_LABEL, TR_ADD_DATE, TR_SEED_DATE, TR_TRACKER, TR_DLLIMIT, TR_UPLIMIT, NB_COLUMNS}; + +public: + TorrentModelItem(const QTorrentHandle& h); + inline int columnCount() const { return NB_COLUMNS; } + QVariant data(int column, int role = Qt::DisplayRole) const; + bool setData(int column, const QVariant &value, int role = Qt::DisplayRole); + inline QString hash() const { return m_torrent.hash(); } + +signals: + void labelChanged(QString previous, QString current); + +private: + State state() const; + +private: + QTorrentHandle m_torrent; + QDateTime m_addedTime; + QDateTime m_seedTime; + QString m_label; + QString m_name; + mutable QIcon m_icon; + mutable QColor m_fgColor; +}; + +class TorrentModel : public QAbstractListModel +{ + Q_OBJECT + Q_DISABLE_COPY(TorrentModel) + +public: + explicit TorrentModel(QObject *parent = 0); + ~TorrentModel(); + inline int rowCount(const QModelIndex& index = QModelIndex()) const { Q_UNUSED(index); return m_torrents.size(); } + int columnCount(const QModelIndex &parent=QModelIndex()) const { Q_UNUSED(parent); return TorrentModelItem::NB_COLUMNS; } + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; + bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole); + QVariant headerData(int section, Qt::Orientation orientation, int role) const; + int torrentRow(const QString &hash) const; + QString torrentHash(int row) const; + void setRefreshInterval(int refreshInterval); + TorrentStatusReport getTorrentStatusReport() const; + Qt::ItemFlags flags(const QModelIndex &index) const; + void populate(); + +signals: + void torrentAdded(TorrentModelItem *torrentItem); + void torrentAboutToBeRemoved(TorrentModelItem *torrentItem); + void torrentChangedLabel(TorrentModelItem *torrentItem, QString previous, QString current); + +private slots: + void addTorrent(const QTorrentHandle& h); + void removeTorrent(const QString &hash); + void handleTorrentUpdate(QTorrentHandle &h); + void notifyTorrentChanged(int row); + void forceModelRefresh(); + void handleTorrentLabelChange(QString previous, QString current); + +private: + void beginInsertTorrent(int row); + void endInsertTorrent(); + void beginRemoveTorrent(int row); + void endRemoveTorrent(); + +private: + QList m_torrents; + int m_refreshInterval; + QTimer m_refreshTimer; +}; + +#endif // TORRENTMODEL_H diff --git a/src/scannedfoldersmodel.cpp b/src/scannedfoldersmodel.cpp index 5eced0aa8..466d28957 100644 --- a/src/scannedfoldersmodel.cpp +++ b/src/scannedfoldersmodel.cpp @@ -53,7 +53,7 @@ public: }; ScanFoldersModel *ScanFoldersModel::instance(QObject *parent) { - Q_ASSERT(!parent != !m_instance); + //Q_ASSERT(!parent != !m_instance); if (!m_instance) m_instance = new ScanFoldersModel(parent); return m_instance; diff --git a/src/transferlistdelegate.h b/src/transferlistdelegate.h index 7fac185ad..3e9200854 100644 --- a/src/transferlistdelegate.h +++ b/src/transferlistdelegate.h @@ -40,14 +40,13 @@ #include #include #include "misc.h" +#include "torrentmodel.h" #ifdef Q_WS_WIN #include #endif // Defines for download list list columns -enum TorrentState {STATE_DOWNLOADING, STATE_STALLED_DL, STATE_STALLED_UP, STATE_SEEDING, STATE_PAUSED_DL, STATE_PAUSED_UP, STATE_QUEUED_DL, STATE_QUEUED_UP, STATE_CHECKING_UP, STATE_CHECKING_DL, STATE_INVALID}; -enum Column {TR_NAME, TR_PRIORITY, TR_SIZE, TR_PROGRESS, TR_STATUS, TR_SEEDS, TR_PEERS, TR_DLSPEED, TR_UPSPEED, TR_ETA, TR_RATIO, TR_LABEL, TR_ADD_DATE, TR_SEED_DATE, TR_TRACKER, TR_DLLIMIT, TR_UPLIMIT, TR_HASH}; class TransferListDelegate: public QItemDelegate { Q_OBJECT @@ -61,19 +60,19 @@ public: QStyleOptionViewItemV2 opt = QItemDelegate::setOptions(index, option); painter->save(); switch(index.column()){ - case TR_SIZE:{ + case TorrentModelItem::TR_SIZE:{ QItemDelegate::drawBackground(painter, opt, index); opt.displayAlignment = Qt::AlignRight; QItemDelegate::drawDisplay(painter, opt, option.rect, misc::friendlyUnit(index.data().toLongLong())); break; } - case TR_ETA:{ + case TorrentModelItem::TR_ETA:{ QItemDelegate::drawBackground(painter, opt, index); QItemDelegate::drawDisplay(painter, opt, option.rect, misc::userFriendlyDuration(index.data().toLongLong())); break; } - case TR_SEEDS: - case TR_PEERS: { + case TorrentModelItem::TR_SEEDS: + case TorrentModelItem::TR_PEERS: { const qulonglong tot_val = index.data().toULongLong(); QString display = QString::number((qulonglong)tot_val/1000000); if(tot_val%2 == 0) { @@ -85,30 +84,30 @@ public: QItemDelegate::drawDisplay(painter, opt, opt.rect, display); break; } - case TR_STATUS: { + case TorrentModelItem::TR_STATUS: { const int state = index.data().toInt(); QString display; switch(state) { - case STATE_DOWNLOADING: + case TorrentModelItem::STATE_DOWNLOADING: display = tr("Downloading"); break; - case STATE_PAUSED_DL: - case STATE_PAUSED_UP: + case TorrentModelItem::STATE_PAUSED_DL: + case TorrentModelItem::STATE_PAUSED_UP: display = tr("Paused"); break; - case STATE_QUEUED_DL: - case STATE_QUEUED_UP: + case TorrentModelItem::STATE_QUEUED_DL: + case TorrentModelItem::STATE_QUEUED_UP: display = tr("Queued", "i.e. torrent is queued"); break; - case STATE_SEEDING: - case STATE_STALLED_UP: + case TorrentModelItem::STATE_SEEDING: + case TorrentModelItem::STATE_STALLED_UP: display = tr("Seeding", "Torrent is complete and in upload-only mode"); break; - case STATE_STALLED_DL: + case TorrentModelItem::STATE_STALLED_DL: display = tr("Stalled", "Torrent is waiting for download to begin"); break; - case STATE_CHECKING_DL: - case STATE_CHECKING_UP: + case TorrentModelItem::STATE_CHECKING_DL: + case TorrentModelItem::STATE_CHECKING_UP: display = tr("Checking", "Torrent local data is being checked"); break; default: @@ -118,16 +117,16 @@ public: QItemDelegate::drawDisplay(painter, opt, opt.rect, display); break; } - case TR_UPSPEED: - case TR_DLSPEED:{ + case TorrentModelItem::TR_UPSPEED: + case TorrentModelItem::TR_DLSPEED:{ QItemDelegate::drawBackground(painter, opt, index); const qulonglong speed = index.data().toULongLong(); opt.displayAlignment = Qt::AlignRight; QItemDelegate::drawDisplay(painter, opt, opt.rect, misc::friendlyUnit(speed)+tr("/s", "/second (.i.e per second)")); break; } - case TR_UPLIMIT: - case TR_DLLIMIT:{ + case TorrentModelItem::TR_UPLIMIT: + case TorrentModelItem::TR_DLLIMIT:{ QItemDelegate::drawBackground(painter, opt, index); const qlonglong limit = index.data().toLongLong(); opt.displayAlignment = Qt::AlignRight; @@ -137,12 +136,12 @@ public: QItemDelegate::drawDisplay(painter, opt, opt.rect, QString::fromUtf8("∞")); break; } - case TR_ADD_DATE: - case TR_SEED_DATE: + case TorrentModelItem::TR_ADD_DATE: + case TorrentModelItem::TR_SEED_DATE: QItemDelegate::drawBackground(painter, opt, index); QItemDelegate::drawDisplay(painter, opt, opt.rect, index.data().toDateTime().toLocalTime().toString(Qt::DefaultLocaleShortDate)); break; - case TR_RATIO:{ + case TorrentModelItem::TR_RATIO:{ QItemDelegate::drawBackground(painter, opt, index); opt.displayAlignment = Qt::AlignRight; const double ratio = index.data().toDouble(); @@ -152,7 +151,7 @@ public: QItemDelegate::drawDisplay(painter, opt, opt.rect, QString::number(ratio, 'f', 2)); break; } - case TR_PRIORITY: { + case TorrentModelItem::TR_PRIORITY: { const int priority = index.data().toInt(); if(priority >= 0) { opt.displayAlignment = Qt::AlignRight; @@ -164,7 +163,7 @@ public: } break; } - case TR_PROGRESS:{ + case TorrentModelItem::TR_PROGRESS:{ QStyleOptionProgressBarV2 newopt; qreal progress = index.data().toDouble()*100.; // We don't want to display 100% unless diff --git a/src/transferlistfilterswidget.h b/src/transferlistfilterswidget.h index edde85112..de2db1d8e 100644 --- a/src/transferlistfilterswidget.h +++ b/src/transferlistfilterswidget.h @@ -47,6 +47,7 @@ #include "transferlistwidget.h" #include "preferences.h" #include "qinisettings.h" +#include "torrentmodel.h" class LabelFiltersList: public QListWidget { Q_OBJECT @@ -236,12 +237,12 @@ public: // SIGNAL/SLOT connect(statusFilters, SIGNAL(currentRowChanged(int)), transferList, SLOT(applyStatusFilter(int))); - connect(transferList, SIGNAL(torrentStatusUpdate(uint,uint,uint,uint,uint)), this, SLOT(updateTorrentNumbers(uint, uint, uint, uint, uint))); + connect(transferList->getSourceModel(), SIGNAL(dataChanged(QModelIndex,QModelIndex)), SLOT(updateTorrentNumbers())); + connect(transferList->getSourceModel(), SIGNAL(torrentAdded(TorrentModelItem*)), SLOT(handleNewTorrent(TorrentModelItem*))); connect(labelFilters, SIGNAL(currentRowChanged(int)), this, SLOT(applyLabelFilter(int))); connect(labelFilters, SIGNAL(torrentDropped(int)), this, SLOT(torrentDropped(int))); - connect(transferList, SIGNAL(torrentAdded(QModelIndex)), this, SLOT(torrentAdded(QModelIndex))); - connect(transferList, SIGNAL(torrentAboutToBeRemoved(QModelIndex)), this, SLOT(torrentAboutToBeDeleted(QModelIndex))); - connect(transferList, SIGNAL(torrentChangedLabel(QString,QString)), this, SLOT(torrentChangedLabel(QString, QString))); + connect(transferList->getSourceModel(), SIGNAL(torrentAboutToBeRemoved(TorrentModelItem*)), SLOT(torrentAboutToBeDeleted(TorrentModelItem*))); + connect(transferList->getSourceModel(), SIGNAL(torrentChangedLabel(TorrentModelItem*,QString,QString)), SLOT(torrentChangedLabel(TorrentModelItem*, QString, QString))); // Add Label filters QListWidgetItem *allLabels = new QListWidgetItem(labelFilters); @@ -296,13 +297,14 @@ public: } protected slots: - void updateTorrentNumbers(uint nb_downloading, uint nb_seeding, uint nb_active, uint nb_inactive, uint nb_paused) { - statusFilters->item(FILTER_ALL)->setData(Qt::DisplayRole, QVariant(tr("All")+" ("+QString::number(nb_active+nb_inactive)+")")); - statusFilters->item(FILTER_DOWNLOADING)->setData(Qt::DisplayRole, QVariant(tr("Downloading")+" ("+QString::number(nb_downloading)+")")); - statusFilters->item(FILTER_COMPLETED)->setData(Qt::DisplayRole, QVariant(tr("Completed")+" ("+QString::number(nb_seeding)+")")); - statusFilters->item(FILTER_PAUSED)->setData(Qt::DisplayRole, QVariant(tr("Paused")+" ("+QString::number(nb_paused)+")")); - statusFilters->item(FILTER_ACTIVE)->setData(Qt::DisplayRole, QVariant(tr("Active")+" ("+QString::number(nb_active)+")")); - statusFilters->item(FILTER_INACTIVE)->setData(Qt::DisplayRole, QVariant(tr("Inactive")+" ("+QString::number(nb_inactive)+")")); + void updateTorrentNumbers() { + const TorrentStatusReport report = transferList->getSourceModel()->getTorrentStatusReport(); + statusFilters->item(FILTER_ALL)->setData(Qt::DisplayRole, QVariant(tr("All")+" ("+QString::number(report.nb_active+report.nb_inactive)+")")); + statusFilters->item(FILTER_DOWNLOADING)->setData(Qt::DisplayRole, QVariant(tr("Downloading")+" ("+QString::number(report.nb_downloading)+")")); + statusFilters->item(FILTER_COMPLETED)->setData(Qt::DisplayRole, QVariant(tr("Completed")+" ("+QString::number(report.nb_seeding)+")")); + statusFilters->item(FILTER_PAUSED)->setData(Qt::DisplayRole, QVariant(tr("Paused")+" ("+QString::number(report.nb_paused)+")")); + statusFilters->item(FILTER_ACTIVE)->setData(Qt::DisplayRole, QVariant(tr("Active")+" ("+QString::number(report.nb_active)+")")); + statusFilters->item(FILTER_INACTIVE)->setData(Qt::DisplayRole, QVariant(tr("Inactive")+" ("+QString::number(report.nb_inactive)+")")); } void torrentDropped(int row) { @@ -405,7 +407,8 @@ protected slots: } } - void torrentChangedLabel(QString old_label, QString new_label) { + void torrentChangedLabel(TorrentModelItem *torrentItem, QString old_label, QString new_label) { + Q_UNUSED(torrentItem); qDebug("Torrent label changed from %s to %s", qPrintable(old_label), qPrintable(new_label)); if(!old_label.isEmpty()) { if(customLabels.contains(old_label)) { @@ -432,10 +435,8 @@ protected slots: updateStickyLabelCounters(); } - void torrentAdded(QModelIndex index) { - Q_ASSERT(index.isValid()); - if(!index.isValid()) return; - const QString &label = transferList->getSourceModel()->index(index.row(), TR_LABEL).data(Qt::DisplayRole).toString().trimmed(); + void handleNewTorrent(TorrentModelItem* torrentItem) { + QString label = torrentItem->data(TorrentModelItem::TR_LABEL).toString(); qDebug("New torrent was added with label: %s", qPrintable(label)); if(!label.isEmpty()) { if(!customLabels.contains(label)) { @@ -459,10 +460,9 @@ protected slots: updateStickyLabelCounters(); } - void torrentAboutToBeDeleted(QModelIndex index) { - Q_ASSERT(index.isValid()); - if(!index.isValid()) return; - QString label = transferList->getSourceModel()->index(index.row(), TR_LABEL).data(Qt::DisplayRole).toString().trimmed(); + void torrentAboutToBeDeleted(TorrentModelItem* torrentItem) { + Q_ASSERT(torrentItem); + QString label = torrentItem->data(TorrentModelItem::TR_LABEL).toString(); if(!label.isEmpty()) { // Update label counter const int new_count = customLabels.value(label, 0) - 1; diff --git a/src/transferlistwidget.cpp b/src/transferlistwidget.cpp index c5105d6f9..1e2735ebb 100644 --- a/src/transferlistwidget.cpp +++ b/src/transferlistwidget.cpp @@ -37,6 +37,7 @@ #include "options_imp.h" #include "mainwindow.h" #include "preferences.h" +#include "torrentmodel.h" #include "deletionconfirmationdlg.h" #include "propertieswidget.h" #include @@ -63,54 +64,27 @@ TransferListWidget::TransferListWidget(QWidget *parent, MainWindow *main_window, setItemDelegate(listDelegate); // Create transfer list model - listModel = new QStandardItemModel(0,18); - listModel->setHeaderData(TR_NAME, Qt::Horizontal, tr("Name", "i.e: torrent name")); - listModel->setHeaderData(TR_PRIORITY, Qt::Horizontal, "#"); - listModel->horizontalHeaderItem(TR_PRIORITY)->setTextAlignment(Qt::AlignRight); - listModel->setHeaderData(TR_SIZE, Qt::Horizontal, tr("Size", "i.e: torrent size")); - listModel->horizontalHeaderItem(TR_SIZE)->setTextAlignment(Qt::AlignRight); - listModel->setHeaderData(TR_PROGRESS, Qt::Horizontal, tr("Done", "% Done")); - listModel->horizontalHeaderItem(TR_PROGRESS)->setTextAlignment(Qt::AlignHCenter); - listModel->setHeaderData(TR_STATUS, Qt::Horizontal, tr("Status", "Torrent status (e.g. downloading, seeding, paused)")); - listModel->setHeaderData(TR_SEEDS, Qt::Horizontal, tr("Seeds", "i.e. full sources (often untranslated)")); - listModel->horizontalHeaderItem(TR_SEEDS)->setTextAlignment(Qt::AlignRight); - listModel->setHeaderData(TR_PEERS, Qt::Horizontal, tr("Peers", "i.e. partial sources (often untranslated)")); - listModel->horizontalHeaderItem(TR_PEERS)->setTextAlignment(Qt::AlignRight); - listModel->setHeaderData(TR_DLSPEED, Qt::Horizontal, tr("Down Speed", "i.e: Download speed")); - listModel->horizontalHeaderItem(TR_DLSPEED)->setTextAlignment(Qt::AlignRight); - listModel->setHeaderData(TR_UPSPEED, Qt::Horizontal, tr("Up Speed", "i.e: Upload speed"));; - listModel->horizontalHeaderItem(TR_UPSPEED)->setTextAlignment(Qt::AlignRight); - listModel->setHeaderData(TR_RATIO, Qt::Horizontal, tr("Ratio", "Share ratio")); - listModel->horizontalHeaderItem(TR_RATIO)->setTextAlignment(Qt::AlignRight); - listModel->setHeaderData(TR_ETA, Qt::Horizontal, tr("ETA", "i.e: Estimated Time of Arrival / Time left")); - listModel->setHeaderData(TR_LABEL, Qt::Horizontal, tr("Label")); - listModel->setHeaderData(TR_ADD_DATE, Qt::Horizontal, tr("Added On", "Torrent was added to transfer list on 01/01/2010 08:00")); - listModel->setHeaderData(TR_SEED_DATE, Qt::Horizontal, tr("Completed On", "Torrent was completed on 01/01/2010 08:00")); - listModel->setHeaderData(TR_TRACKER, Qt::Horizontal, tr("Tracker")); - listModel->setHeaderData(TR_DLLIMIT, Qt::Horizontal, tr("Down Limit", "i.e: Download limit")); - listModel->horizontalHeaderItem(TR_DLLIMIT)->setTextAlignment(Qt::AlignRight); - listModel->setHeaderData(TR_UPLIMIT, Qt::Horizontal, tr("Up Limit", "i.e: Upload limit"));; - listModel->horizontalHeaderItem(TR_UPLIMIT)->setTextAlignment(Qt::AlignRight); - + listModel = new TorrentModel(this); // Set Sort/Filter proxy labelFilterModel = new QSortFilterProxyModel(); labelFilterModel->setDynamicSortFilter(true); labelFilterModel->setSourceModel(listModel); - labelFilterModel->setFilterKeyColumn(TR_LABEL); + labelFilterModel->setFilterKeyColumn(TorrentModelItem::TR_LABEL); labelFilterModel->setFilterRole(Qt::DisplayRole); statusFilterModel = new QSortFilterProxyModel(); statusFilterModel->setDynamicSortFilter(true); statusFilterModel->setSourceModel(labelFilterModel); - statusFilterModel->setFilterKeyColumn(TR_STATUS); + statusFilterModel->setFilterKeyColumn(TorrentModelItem::TR_STATUS); statusFilterModel->setFilterRole(Qt::DisplayRole); nameFilterModel = new QSortFilterProxyModel(); nameFilterModel->setDynamicSortFilter(true); nameFilterModel->setSourceModel(statusFilterModel); - nameFilterModel->setFilterKeyColumn(TR_NAME); + nameFilterModel->setFilterKeyColumn(TorrentModelItem::TR_NAME); nameFilterModel->setFilterRole(Qt::DisplayRole); + setModel(nameFilterModel); @@ -123,9 +97,7 @@ TransferListWidget::TransferListWidget(QWidget *parent, MainWindow *main_window, setAutoScroll(true); setDragDropMode(QAbstractItemView::DragOnly); - hideColumn(TR_PRIORITY); - //hideColumn(TR_LABEL); - hideColumn(TR_HASH); + hideColumn(TorrentModelItem::TR_PRIORITY); loadHiddenColumns(); // Load last columns width for transfer list if(!loadColWidthList()) { @@ -134,25 +106,12 @@ TransferListWidget::TransferListWidget(QWidget *parent, MainWindow *main_window, loadLastSortedColumn(); setContextMenuPolicy(Qt::CustomContextMenu); - // Listen for BTSession events - connect(BTSession, SIGNAL(addedTorrent(QTorrentHandle&)), this, SLOT(addTorrent(QTorrentHandle&))); - connect(BTSession, SIGNAL(finishedTorrent(QTorrentHandle&)), this, SLOT(setFinished(QTorrentHandle&))); - connect(BTSession, SIGNAL(metadataReceived(QTorrentHandle&)), this, SLOT(updateMetadata(QTorrentHandle&))); - connect(BTSession, SIGNAL(pausedTorrent(QTorrentHandle&)), this, SLOT(pauseTorrent(QTorrentHandle&))); - connect(BTSession, SIGNAL(resumedTorrent(QTorrentHandle&)), this, SLOT(resumeTorrent(QTorrentHandle&))); - connect(BTSession, SIGNAL(torrentFinishedChecking(QTorrentHandle&)), this, SLOT(updateMetadata(QTorrentHandle&))); - connect(BTSession, SIGNAL(deletedTorrent(QString)), SLOT(deleteTorrent(QString))); // Listen for list events connect(this, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(torrentDoubleClicked(QModelIndex))); connect(this, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(displayListMenu(const QPoint&))); header()->setContextMenuPolicy(Qt::CustomContextMenu); connect(header(), SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(displayDLHoSMenu(const QPoint&))); - - // Refresh timer - refreshTimer = new QTimer(); - refreshTimer->start(settings.value("Preferences/General/RefreshInterval", 1500).toInt()); - connect(refreshTimer, SIGNAL(timeout()), this, SLOT(refreshList())); } TransferListWidget::~TransferListWidget() { @@ -161,7 +120,6 @@ TransferListWidget::~TransferListWidget() { saveColWidthList(); saveHiddenColumns(); // Clean up - delete refreshTimer; delete labelFilterModel; delete statusFilterModel; delete nameFilterModel; @@ -169,169 +127,14 @@ TransferListWidget::~TransferListWidget() { delete listDelegate; } -void TransferListWidget::addTorrent(QTorrentHandle& h) { - if(!h.is_valid()) return; - // Check that the torrent is not already there - if(getRowFromHash(h.hash()) >= 0) return; - // Actuall add the torrent - const int row = listModel->rowCount(); - try { - // Adding torrent to transfer list - listModel->insertRow(row); - listModel->setData(listModel->index(row, TR_NAME), QVariant(h.name())); - listModel->setData(listModel->index(row, TR_SIZE), QVariant((qlonglong)h.actual_size())); - listModel->setData(listModel->index(row, TR_ETA), QVariant((qlonglong)MAX_ETA)); - listModel->setData(listModel->index(row, TR_SEEDS), QVariant((double)0.0)); - listModel->setData(listModel->index(row, TR_PEERS), QVariant((double)0.0)); - listModel->setData(listModel->index(row, TR_ADD_DATE), QVariant(TorrentPersistentData::getAddedDate(h.hash()))); - listModel->setData(listModel->index(row, TR_SEED_DATE), QVariant(TorrentPersistentData::getSeedDate(h.hash()))); - listModel->setData(listModel->index(row, TR_UPLIMIT), QVariant(h.upload_limit())); - listModel->setData(listModel->index(row, TR_DLLIMIT), QVariant(h.download_limit())); - listModel->setData(listModel->index(row, TR_RATIO), QVariant(BTSession->getRealRatio(h.hash()))); - const QString label = TorrentPersistentData::getLabel(h.hash()); - listModel->setData(listModel->index(row, TR_LABEL), QVariant(label)); - if(BTSession->isQueueingEnabled()) - listModel->setData(listModel->index(row, TR_PRIORITY), QVariant((int)h.queue_position())); - listModel->setData(listModel->index(row, TR_HASH), QVariant(h.hash())); - // Pause torrent if it is - if(h.is_paused()) { - if(h.is_seed()) { - listModel->setData(listModel->index(row, TR_STATUS), STATE_PAUSED_UP); - listModel->setData(listModel->index(row, TR_ETA), QVariant((qlonglong)0)); - } else { - listModel->setData(listModel->index(row, TR_STATUS), STATE_PAUSED_DL); - } - if(TorrentPersistentData::hasError(h.hash())) - listModel->setData(listModel->index(row, TR_NAME), QVariant(QIcon(QString::fromUtf8(":/Icons/skin/error.png"))), Qt::DecorationRole); - else - listModel->setData(listModel->index(row, TR_NAME), QVariant(QIcon(QString::fromUtf8(":/Icons/skin/paused.png"))), Qt::DecorationRole); - setRowColor(row, QString::fromUtf8("red")); - }else{ - if(h.is_seed()) { - listModel->setData(listModel->index(row, TR_NAME), QVariant(QIcon(QString::fromUtf8(":/Icons/skin/stalledUP.png"))), Qt::DecorationRole); - listModel->setData(listModel->index(row, TR_STATUS), STATE_STALLED_UP); - listModel->setData(listModel->index(row, TR_ETA), QVariant((qlonglong)0)); - } else { - listModel->setData(listModel->index(row, TR_NAME), QVariant(QIcon(QString::fromUtf8(":/Icons/skin/stalledDL.png"))), Qt::DecorationRole); - listModel->setData(listModel->index(row, TR_STATUS), STATE_STALLED_DL); - } - setRowColor(row, QApplication::palette().color(QPalette::WindowText)); - } - // Select first torrent to be added - if(listModel->rowCount() == 1) - selectionModel()->setCurrentIndex(nameFilterModel->index(row, TR_NAME), QItemSelectionModel::SelectCurrent|QItemSelectionModel::Rows); - // Emit signal - emit torrentAdded(listModel->index(row, 0)); - // Refresh the list - refreshList(true); - } catch(invalid_handle e) { - // Remove added torrent - listModel->removeRow(row); - } -} - -QStandardItemModel* TransferListWidget::getSourceModel() const { +TorrentModel* TransferListWidget::getSourceModel() const { return listModel; } -void TransferListWidget::setRowColor(int row, QColor color) { - const unsigned int nbColumns = listModel->columnCount()-1; - for(unsigned int i=0; isetData(listModel->index(row, i), QVariant(color), Qt::ForegroundRole); - } -} - -void TransferListWidget::deleteTorrent(int row, bool refresh_list) { - Q_ASSERT(row >= 0); - const QModelIndex index = listModel->index(row, 0); - Q_ASSERT(index.isValid()); - if(!index.isValid()) return; - emit torrentAboutToBeRemoved(index); - listModel->removeRow(row); - if(refresh_list) - refreshList(true); -} - -// Wrapper slot for bittorrent signal -void TransferListWidget::pauseTorrent(QTorrentHandle &h) { - pauseTorrent(getRowFromHash(h.hash())); -} - -void TransferListWidget::deleteTorrent(QString hash) { - const int row = getRowFromHash(hash); - if(row >= 0) { - deleteTorrent(row, true); - } -} - -void TransferListWidget::pauseTorrent(int row, bool refresh_list) { - const QTorrentHandle h = BTSession->getTorrentHandle(getHashFromRow(row)); - listModel->setData(listModel->index(row, TR_DLSPEED), QVariant((double)0.0)); - listModel->setData(listModel->index(row, TR_UPSPEED), QVariant((double)0.0)); - listModel->setData(listModel->index(row, TR_PROGRESS), h.progress()); - if(h.is_seed()) { - listModel->setData(listModel->index(row, TR_STATUS), STATE_PAUSED_UP); - if(h.has_error() || TorrentPersistentData::hasError(h.hash())) { - listModel->setData(listModel->index(row, TR_NAME), h.error(), Qt::ToolTipRole); - listModel->setData(listModel->index(row, TR_NAME), QIcon(QString::fromUtf8(":/Icons/skin/error.png")), Qt::DecorationRole); - } else { - listModel->setData(listModel->index(row, TR_NAME), QIcon(QString::fromUtf8(":/Icons/skin/paused.png")), Qt::DecorationRole); - } - } else { - listModel->setData(listModel->index(row, TR_STATUS), STATE_PAUSED_DL); - if(h.has_error() || TorrentPersistentData::hasError(h.hash())) { - listModel->setData(listModel->index(row, TR_NAME), h.error(), Qt::ToolTipRole); - listModel->setData(listModel->index(row, TR_NAME), QIcon(QString::fromUtf8(":/Icons/skin/error.png")), Qt::DecorationRole); - } else { - listModel->setData(listModel->index(row, TR_NAME), QIcon(QString::fromUtf8(":/Icons/skin/paused.png")), Qt::DecorationRole); - } - listModel->setData(listModel->index(row, TR_ETA), QVariant((qlonglong)MAX_ETA)); - } - listModel->setData(listModel->index(row, TR_SEEDS), QVariant(0.0)); - listModel->setData(listModel->index(row, TR_PEERS), QVariant(0.0)); - setRowColor(row, QString::fromUtf8("red")); - if(refresh_list) - refreshList(); -} - - int TransferListWidget::getNbTorrents() const { return listModel->rowCount(); } -// Wrapper slot for bittorrent signal -void TransferListWidget::resumeTorrent(QTorrentHandle &h) { - resumeTorrent(getRowFromHash(h.hash())); -} - -void TransferListWidget::resumeTorrent(int row, bool refresh_list) { - const QTorrentHandle h = BTSession->getTorrentHandle(getHashFromRow(row)); - if(!h.is_valid()) return; - if(h.is_seed()) { - listModel->setData(listModel->index(row, TR_NAME), QVariant(QIcon(":/Icons/skin/stalledUP.png")), Qt::DecorationRole); - listModel->setData(listModel->index(row, TR_STATUS), STATE_STALLED_UP); - } else { - listModel->setData(listModel->index(row, TR_NAME), QVariant(QIcon(":/Icons/skin/stalledDL.png")), Qt::DecorationRole); - listModel->setData(listModel->index(row, TR_STATUS), STATE_STALLED_DL); - } - listModel->setData(listModel->index(row, TR_NAME), "", Qt::ToolTipRole); - setRowColor(row, QApplication::palette().color(QPalette::WindowText)); - if(refresh_list) - refreshList(); -} - -void TransferListWidget::updateMetadata(QTorrentHandle &h) { - if(!h.is_valid()) return; - const QString hash = h.hash(); - const int row = getRowFromHash(hash); - if(row != -1) { - qDebug("Updating torrent metadata in download list"); - listModel->setData(listModel->index(row, TR_NAME), QVariant(h.name())); - listModel->setData(listModel->index(row, TR_SIZE), QVariant((qlonglong)h.actual_size())); - listModel->setData(listModel->index(row, TR_PROGRESS), QVariant((double)h.progress())); - } -} - void TransferListWidget::previewFile(QString filePath) { #ifdef Q_WS_WIN QDesktopServices::openUrl(QUrl(QString("file:///")+filePath)); @@ -340,262 +143,17 @@ void TransferListWidget::previewFile(QString filePath) { #endif } -int TransferListWidget::updateTorrent(int row) { - TorrentState s = STATE_INVALID; - const QString hash = getHashFromRow(row); - const QTorrentHandle h = BTSession->getTorrentHandle(hash); - if(!h.is_valid()) { - // Torrent will be deleted from list by caller - return s; - } - try { - if(!isColumnHidden(TR_SEEDS)) { - // Connected_seeds*100000+total_seeds*10 (if total_seeds is available) - // Connected_seeds*100000+1 (if total_seeds is unavailable) - qulonglong seeds = h.num_seeds()*1000000; - if(h.num_complete() >= h.num_seeds()) - seeds += h.num_complete()*10; - else - seeds += 1; - listModel->setData(listModel->index(row, TR_SEEDS), QVariant(seeds)); - } - if(!isColumnHidden(TR_PEERS)) { - qulonglong peers = (h.num_peers()-h.num_seeds())*1000000; - if(h.num_incomplete() >= (h.num_peers()-h.num_seeds())) - peers += h.num_incomplete()*10; - else - peers += 1; - listModel->setData(listModel->index(row, TR_PEERS), QVariant(peers)); - } - if(!isColumnHidden(TR_TRACKER)) { - listModel->setData(listModel->index(row, TR_TRACKER), QVariant(h.current_tracker())); - } - // Update torrent size. It changes when files are filtered from torrent properties - // or Web UI - listModel->setData(listModel->index(row, TR_SIZE), QVariant((qlonglong)h.actual_size())); - // Update Up/Dl limits - if(!isColumnHidden(TR_UPLIMIT)) - listModel->setData(listModel->index(row, TR_UPLIMIT), QVariant((qlonglong)h.upload_limit())); - if(!isColumnHidden(TR_DLLIMIT)) - listModel->setData(listModel->index(row, TR_DLLIMIT), QVariant((qlonglong)h.download_limit())); - // Queueing code - if(BTSession->isQueueingEnabled()) { - if(h.is_seed()) - listModel->setData(listModel->index(row, TR_PRIORITY), -1); - else - listModel->setData(listModel->index(row, TR_PRIORITY), QVariant((int)h.queue_position())); - if(h.is_queued()) { - if(h.state() == torrent_status::checking_files || h.state() == torrent_status::queued_for_checking) { - listModel->setData(listModel->index(row, TR_PROGRESS), QVariant((double)h.progress())); - if(h.is_seed()) { - s = STATE_CHECKING_UP; - } else { - s = STATE_CHECKING_DL; - } - listModel->setData(listModel->index(row, TR_NAME), QVariant(QIcon(QString::fromUtf8(":/Icons/skin/checking.png"))), Qt::DecorationRole); - listModel->setData(listModel->index(row, TR_STATUS), s); - } else { - listModel->setData(listModel->index(row, TR_ETA), QVariant((qlonglong)MAX_ETA)); - if(h.is_seed()) { - s = STATE_QUEUED_UP; - } else { - s = STATE_QUEUED_DL; - } - listModel->setData(listModel->index(row, TR_NAME), QVariant(QIcon(QString::fromUtf8(":/Icons/skin/queued.png"))), Qt::DecorationRole); - listModel->setData(listModel->index(row, TR_STATUS), s); - } - // Reset speeds and seeds/leech - listModel->setData(listModel->index(row, TR_DLSPEED), QVariant((double)0.)); - listModel->setData(listModel->index(row, TR_UPSPEED), QVariant((double)0.)); - if(!isColumnHidden(TR_SEEDS)) - listModel->setData(listModel->index(row, TR_SEEDS), QVariant(0.0)); - if(!isColumnHidden(TR_PEERS)) - listModel->setData(listModel->index(row, TR_PEERS), QVariant(0.0)); - setRowColor(row, "grey"); - return s; - } - } - - if(h.is_paused()) { - // XXX: Force progress update because of bug #621381 - listModel->setData(listModel->index(row, TR_PROGRESS), QVariant((double)h.progress())); - if(h.is_seed()) - return STATE_PAUSED_UP; - return STATE_PAUSED_DL; - } - - // Parse download state - switch(h.state()) { - case torrent_status::allocating: - case torrent_status::checking_files: - case torrent_status::queued_for_checking: - case torrent_status::checking_resume_data: - if(h.is_seed()) { - s = STATE_CHECKING_UP; - } else { - s = STATE_CHECKING_DL; - } - listModel->setData(listModel->index(row, TR_NAME), QVariant(QIcon(QString::fromUtf8(":/Icons/skin/checking.png"))), Qt::DecorationRole); - listModel->setData(listModel->index(row, TR_PROGRESS), QVariant((double)h.progress())); - if(!isColumnHidden(TR_ETA)) - listModel->setData(listModel->index(row, TR_ETA), QVariant((qlonglong)MAX_ETA)); - setRowColor(row, QString::fromUtf8("grey")); - break; - case torrent_status::downloading: - case torrent_status::downloading_metadata: - if(h.download_payload_rate() > 0) { - listModel->setData(listModel->index(row, TR_NAME), QVariant(QIcon(QString::fromUtf8(":/Icons/skin/downloading.png"))), Qt::DecorationRole); - if(!isColumnHidden(TR_ETA)) - listModel->setData(listModel->index(row, TR_ETA), QVariant((qlonglong)BTSession->getETA(hash))); - s = STATE_DOWNLOADING; - setRowColor(row, QString::fromUtf8("green")); - }else{ - listModel->setData(listModel->index(row, TR_NAME), QVariant(QIcon(QString::fromUtf8(":/Icons/skin/stalledDL.png"))), Qt::DecorationRole); - if(!isColumnHidden(TR_ETA)) - listModel->setData(listModel->index(row, TR_ETA), QVariant((qlonglong)MAX_ETA)); - s = STATE_STALLED_DL; - setRowColor(row, QApplication::palette().color(QPalette::WindowText)); - } - listModel->setData(listModel->index(row, TR_DLSPEED), QVariant((double)h.download_payload_rate())); - listModel->setData(listModel->index(row, TR_PROGRESS), QVariant((double)h.progress())); - break; - case torrent_status::finished: - case torrent_status::seeding: - if(h.upload_payload_rate() > 0) { - s = STATE_SEEDING; - listModel->setData(listModel->index(row, TR_NAME), QVariant(QIcon(QString::fromUtf8(":/Icons/skin/uploading.png"))), Qt::DecorationRole); - setRowColor(row, "orange"); - } else { - s = STATE_STALLED_UP; - listModel->setData(listModel->index(row, TR_NAME), QVariant(QIcon(QString::fromUtf8(":/Icons/skin/stalledUP.png"))), Qt::DecorationRole); - setRowColor(row, QApplication::palette().color(QPalette::WindowText)); - } - listModel->setData(listModel->index(row, TR_PROGRESS), QVariant((double)1.)); - } - // Common to both downloads and uploads - listModel->setData(listModel->index(row, TR_STATUS), s); - listModel->setData(listModel->index(row, TR_UPSPEED), QVariant((double)h.upload_payload_rate())); - // Share ratio - if(!isColumnHidden(TR_RATIO)) - listModel->setData(listModel->index(row, TR_RATIO), QVariant(BTSession->getRealRatio(hash))); - }catch(invalid_handle) { - // Torrent will be deleted by caller - s = STATE_INVALID; - } - return s; -} - -void TransferListWidget::setFinished(QTorrentHandle &h) { - const int row = getRowFromHash(h.hash()); - try { - if(row >= 0) { - if(h.is_paused()) { - listModel->setData(listModel->index(row, TR_NAME), QIcon(":/Icons/skin/paused.png"), Qt::DecorationRole); - listModel->setData(listModel->index(row, TR_STATUS), STATE_PAUSED_UP); - setRowColor(row, "red"); - }else{ - listModel->setData(listModel->index(row, TR_NAME), QVariant(QIcon(":/Icons/skin/stalledUP.png")), Qt::DecorationRole); - listModel->setData(listModel->index(row, TR_STATUS), STATE_STALLED_UP); - setRowColor(row, QApplication::palette().color(QPalette::WindowText)); - } - listModel->setData(listModel->index(row, TR_ETA), QVariant((qlonglong)0)); - listModel->setData(listModel->index(row, TR_DLSPEED), QVariant((double)0.)); - listModel->setData(listModel->index(row, TR_PROGRESS), QVariant((double)1.)); - listModel->setData(listModel->index(row, TR_PRIORITY), QVariant((int)-1)); - listModel->setData(listModel->index(row, TR_SEED_DATE), QVariant(TorrentPersistentData::getSeedDate(h.hash()))); - } - } catch(invalid_handle) { - if(row >= 0) { - deleteTorrent(row); - } - } -} - void TransferListWidget::setRefreshInterval(int t) { qDebug("Settings transfer list refresh interval to %dms", t); - refreshTimer->start(t); -} - -void TransferListWidget::refreshList(bool force) { - // Stop updating the display - setUpdatesEnabled(false); - // Refresh only if displayed - if(!force && main_window->getCurrentTabWidget() != this) return; - unsigned int nb_downloading = 0, nb_seeding=0, nb_active=0, nb_inactive = 0, nb_paused = 0; - if(BTSession->getSession()->get_torrents().size() != (uint)listModel->rowCount()) { - // Oups, we have torrents that are not displayed, fix this - std::vector torrents = BTSession->getSession()->get_torrents(); - std::vector::iterator itr; - for(itr = torrents.begin(); itr != torrents.end(); itr++) { - QTorrentHandle h(*itr); - if(h.is_valid() && getRowFromHash(h.hash()) < 0) { - addTorrent(h); - } - } - - } - QStringList bad_hashes; - for(int i=0; irowCount(); ++i) { - const int s = updateTorrent(i); - switch(s) { - case STATE_DOWNLOADING: - ++nb_active; - ++nb_downloading; - break; - case STATE_STALLED_DL: - case STATE_CHECKING_DL: - case STATE_PAUSED_DL: - case STATE_QUEUED_DL: { - if(s == STATE_PAUSED_DL) { - ++nb_paused; - } - ++nb_inactive; - ++nb_downloading; - break; - } - case STATE_SEEDING: - ++nb_active; - ++nb_seeding; - break; - case STATE_STALLED_UP: - case STATE_CHECKING_UP: - case STATE_PAUSED_UP: - case STATE_QUEUED_UP: { - if(s == STATE_PAUSED_UP) { - ++nb_paused; - } - ++nb_seeding; - ++nb_inactive; - break; - } - case STATE_INVALID: - bad_hashes << getHashFromRow(i); - break; - default: - break; - } - } - // Remove bad torrents from list - foreach(const QString &hash, bad_hashes) { - const int row = getRowFromHash(hash); - if(row >= 0) - deleteTorrent(row, false); - } - // Update status filters counters - emit torrentStatusUpdate(nb_downloading, nb_seeding, nb_active, nb_inactive, nb_paused); - // Start updating the display - setUpdatesEnabled(true); + listModel->setRefreshInterval(t); } int TransferListWidget::getRowFromHash(QString hash) const{ - const QList items = listModel->findItems(hash, Qt::MatchExactly, TR_HASH); - if(items.empty()) return -1; - Q_ASSERT(items.size() == 1); - return items.first()->row(); + return listModel->torrentRow(hash); } inline QString TransferListWidget::getHashFromRow(int row) const { - return listModel->data(listModel->index(row, TR_HASH)).toString(); + return listModel->torrentHash(row); } inline QModelIndex TransferListWidget::mapToSource(const QModelIndex &index) const { @@ -635,10 +193,8 @@ void TransferListWidget::torrentDoubleClicked(const QModelIndex& index) { case TOGGLE_PAUSE: if(h.is_paused()) { h.resume(); - resumeTorrent(row); } else { h.pause(); - pauseTorrent(row); } break; case OPEN_DEST: @@ -700,11 +256,8 @@ void TransferListWidget::startSelectedTorrents() { QTorrentHandle h = BTSession->getTorrentHandle(hash); if(h.is_valid() && h.is_paused()) { h.resume(); - resumeTorrent(getRowFromHash(hash), false); } } - if(!hashes.empty()) - refreshList(); } void TransferListWidget::startAllTorrents() { @@ -712,10 +265,8 @@ void TransferListWidget::startAllTorrents() { QTorrentHandle h = BTSession->getTorrentHandle(getHashFromRow(i)); if(h.is_valid() && h.is_paused()) { h.resume(); - resumeTorrent(i, false); } } - refreshList(); } void TransferListWidget::startVisibleTorrents() { @@ -728,10 +279,8 @@ void TransferListWidget::startVisibleTorrents() { QTorrentHandle h = BTSession->getTorrentHandle(hash); if(h.is_valid() && h.is_paused()) { h.resume(); - resumeTorrent(getRowFromHash(hash), false); } } - refreshList(); } void TransferListWidget::pauseSelectedTorrents() { @@ -740,11 +289,8 @@ void TransferListWidget::pauseSelectedTorrents() { QTorrentHandle h = BTSession->getTorrentHandle(hash); if(h.is_valid() && !h.is_paused()) { h.pause(); - pauseTorrent(getRowFromHash(hash), false); } } - if(!hashes.empty()) - refreshList(); } void TransferListWidget::pauseAllTorrents() { @@ -752,10 +298,8 @@ void TransferListWidget::pauseAllTorrents() { QTorrentHandle h = BTSession->getTorrentHandle(getHashFromRow(i)); if(h.is_valid() && !h.is_paused()) { h.pause(); - pauseTorrent(i, false); } } - refreshList(); } void TransferListWidget::pauseVisibleTorrents() { @@ -768,10 +312,8 @@ void TransferListWidget::pauseVisibleTorrents() { QTorrentHandle h = BTSession->getTorrentHandle(hash); if(h.is_valid() && !h.is_paused()) { h.pause(); - pauseTorrent(getRowFromHash(hash), false); } } - refreshList(); } void TransferListWidget::deleteSelectedTorrents() { @@ -781,11 +323,8 @@ void TransferListWidget::deleteSelectedTorrents() { bool delete_local_files = false; if(DeletionConfirmationDlg::askForDeletionConfirmation(&delete_local_files)) { foreach(const QString &hash, hashes) { - const int row = getRowFromHash(hash); - deleteTorrent(row, false); BTSession->deleteTorrent(hash, delete_local_files); } - refreshList(); } } } @@ -800,11 +339,8 @@ void TransferListWidget::deleteVisibleTorrents() { hashes << getHashFromRow(row); } foreach(const QString &hash, hashes) { - const int row = getRowFromHash(hash); - deleteTorrent(row, false); BTSession->deleteTorrent(hash, delete_local_files); } - refreshList(); } } @@ -817,7 +353,6 @@ void TransferListWidget::increasePrioSelectedTorrents() { h.queue_position_up(); } } - refreshList(); } void TransferListWidget::decreasePrioSelectedTorrents() { @@ -829,7 +364,6 @@ void TransferListWidget::decreasePrioSelectedTorrents() { h.queue_position_down(); } } - refreshList(); } void TransferListWidget::topPrioSelectedTorrents() { @@ -841,7 +375,6 @@ void TransferListWidget::topPrioSelectedTorrents() { h.queue_position_top(); } } - refreshList(); } void TransferListWidget::bottomPrioSelectedTorrents() { @@ -853,16 +386,6 @@ void TransferListWidget::bottomPrioSelectedTorrents() { h.queue_position_bottom(); } } - refreshList(); -} - -void TransferListWidget::buySelectedTorrents() const { - const QStringList hashes = getSelectedTorrentsHashes(); - foreach(const QString &hash, hashes) { - const QTorrentHandle h = BTSession->getTorrentHandle(hash); - if(h.is_valid()) - QDesktopServices::openUrl(QUrl("http://match.sharemonkey.com/?info_hash="+h.hash()+"&n="+h.name()+"&cid=33")); - } } void TransferListWidget::copySelectedMagnetURIs() const { @@ -878,7 +401,7 @@ void TransferListWidget::copySelectedMagnetURIs() const { void TransferListWidget::hidePriorityColumn(bool hide) { qDebug("hidePriorityColumn(%d)", hide); - setColumnHidden(TR_PRIORITY, hide); + setColumnHidden(TorrentModelItem::TR_PRIORITY, hide); } void TransferListWidget::openSelectedTorrentsFolder() const { @@ -992,7 +515,7 @@ void TransferListWidget::saveHiddenColumns() const { for(short i=0; iheaderData(i, Qt::Horizontal).toString())); + //qDebug("Column named %s is hidden.", qPrintable(listModel->headerData(i, Qt::Horizontal).toString())); ishidden_list << "0"; } else { ishidden_list << "1"; @@ -1018,11 +541,11 @@ bool TransferListWidget::loadHiddenColumns() { } // As a default, hide less useful columns if(!loaded) { - setColumnHidden(TR_ADD_DATE, true); - setColumnHidden(TR_SEED_DATE, true); - setColumnHidden(TR_UPLIMIT, true); - setColumnHidden(TR_DLLIMIT, true); - setColumnHidden(TR_TRACKER, true); + setColumnHidden(TorrentModelItem::TR_ADD_DATE, true); + setColumnHidden(TorrentModelItem::TR_SEED_DATE, true); + setColumnHidden(TorrentModelItem::TR_UPLIMIT, true); + setColumnHidden(TorrentModelItem::TR_DLLIMIT, true); + setColumnHidden(TorrentModelItem::TR_TRACKER, true); } return loaded; } @@ -1032,12 +555,12 @@ void TransferListWidget::displayDLHoSMenu(const QPoint&){ QMenu hideshowColumn(this); hideshowColumn.setTitle(tr("Column visibility")); QList actions; - for(int i=0; i < TR_HASH; ++i) { - if(!BTSession->isQueueingEnabled() && i == TR_PRIORITY) { + for(int i=0; i < listModel->rowCount(); ++i) { + if(!BTSession->isQueueingEnabled() && i == TorrentModelItem::TR_PRIORITY) { actions.append(0); continue; } - QAction *myAct = hideshowColumn.addAction(listModel->headerData(i, Qt::Horizontal).toString()); + QAction *myAct = hideshowColumn.addAction(listModel->headerData(i, Qt::Horizontal, Qt::DisplayRole).toString()); myAct->setCheckable(true); myAct->setChecked(!isColumnHidden(i)); actions.append(myAct); @@ -1115,10 +638,8 @@ void TransferListWidget::renameSelectedTorrent() { bool ok; const QString name = QInputDialog::getText(this, tr("Rename"), tr("New name:"), QLineEdit::Normal, h.name(), &ok); if (ok && !name.isEmpty()) { - // Remember the name - TorrentPersistentData::saveName(hash, name); - // Visually change the name - nameFilterModel->setData(selectedIndexes.first(), name); + // Rename the torrent + nameFilterModel->setData(selectedIndexes.first(), name, Qt::DisplayRole); } } @@ -1127,10 +648,8 @@ void TransferListWidget::setSelectionLabel(QString label) { foreach(const QString &hash, hashes) { Q_ASSERT(!hash.isEmpty()); const int row = getRowFromHash(hash); - const QString old_label = listModel->data(listModel->index(row, TR_LABEL)).toString(); - listModel->setData(listModel->index(row, TR_LABEL), QVariant(label)); - TorrentPersistentData::saveLabel(hash, label); - emit torrentChangedLabel(old_label, label); + const QString old_label = listModel->data(listModel->index(row, TorrentModelItem::TR_LABEL)).toString(); + listModel->setData(listModel->index(row, TorrentModelItem::TR_LABEL), QVariant(label)); // Update save path if necessary QTorrentHandle h = BTSession->getTorrentHandle(hash); BTSession->changeLabelInTorrentSavePath(h, old_label, label); @@ -1139,11 +658,9 @@ void TransferListWidget::setSelectionLabel(QString label) { void TransferListWidget::removeLabelFromRows(QString label) { for(int i=0; irowCount(); ++i) { - if(listModel->data(listModel->index(i, TR_LABEL)) == label) { + if(listModel->data(listModel->index(i, TorrentModelItem::TR_LABEL)) == label) { const QString hash = getHashFromRow(i); - listModel->setData(listModel->index(i, TR_LABEL), "", Qt::DisplayRole); - TorrentPersistentData::saveLabel(hash, ""); - emit torrentChangedLabel(label, ""); + listModel->setData(listModel->index(i, TorrentModelItem::TR_LABEL), "", Qt::DisplayRole); // Update save path if necessary QTorrentHandle h = BTSession->getTorrentHandle(hash); BTSession->changeLabelInTorrentSavePath(h, label, ""); @@ -1482,31 +999,31 @@ void TransferListWidget::applyNameFilter(QString name) { void TransferListWidget::applyStatusFilter(int f) { switch(f) { case FILTER_DOWNLOADING: - statusFilterModel->setFilterRegExp(QRegExp(QString::number(STATE_DOWNLOADING)+"|"+QString::number(STATE_STALLED_DL)+"|"+ - QString::number(STATE_PAUSED_DL)+"|"+QString::number(STATE_CHECKING_DL)+"|"+ - QString::number(STATE_QUEUED_DL), Qt::CaseSensitive)); + statusFilterModel->setFilterRegExp(QRegExp(QString::number(TorrentModelItem::STATE_DOWNLOADING)+"|"+QString::number(TorrentModelItem::STATE_STALLED_DL)+"|"+ + QString::number(TorrentModelItem::STATE_PAUSED_DL)+"|"+QString::number(TorrentModelItem::STATE_CHECKING_DL)+"|"+ + QString::number(TorrentModelItem::STATE_QUEUED_DL), Qt::CaseSensitive)); break; case FILTER_COMPLETED: - statusFilterModel->setFilterRegExp(QRegExp(QString::number(STATE_SEEDING)+"|"+QString::number(STATE_STALLED_UP)+"|"+ - QString::number(STATE_PAUSED_UP)+"|"+QString::number(STATE_CHECKING_UP)+"|"+ - QString::number(STATE_QUEUED_UP), Qt::CaseSensitive)); + statusFilterModel->setFilterRegExp(QRegExp(QString::number(TorrentModelItem::STATE_SEEDING)+"|"+QString::number(TorrentModelItem::STATE_STALLED_UP)+"|"+ + QString::number(TorrentModelItem::STATE_PAUSED_UP)+"|"+QString::number(TorrentModelItem::STATE_CHECKING_UP)+"|"+ + QString::number(TorrentModelItem::STATE_QUEUED_UP), Qt::CaseSensitive)); break; case FILTER_ACTIVE: - statusFilterModel->setFilterRegExp(QRegExp(QString::number(STATE_DOWNLOADING)+"|"+QString::number(STATE_SEEDING), Qt::CaseSensitive)); + statusFilterModel->setFilterRegExp(QRegExp(QString::number(TorrentModelItem::STATE_DOWNLOADING)+"|"+QString::number(TorrentModelItem::STATE_SEEDING), Qt::CaseSensitive)); break; case FILTER_INACTIVE: - statusFilterModel->setFilterRegExp(QRegExp("[^"+QString::number(STATE_DOWNLOADING)+QString::number(STATE_SEEDING)+"]", Qt::CaseSensitive)); + statusFilterModel->setFilterRegExp(QRegExp("[^"+QString::number(TorrentModelItem::STATE_DOWNLOADING)+QString::number(TorrentModelItem::STATE_SEEDING)+"]", Qt::CaseSensitive)); break; case FILTER_PAUSED: - statusFilterModel->setFilterRegExp(QRegExp(QString::number(STATE_PAUSED_UP)+"|"+QString::number(STATE_PAUSED_DL))); + statusFilterModel->setFilterRegExp(QRegExp(QString::number(TorrentModelItem::STATE_PAUSED_UP)+"|"+QString::number(TorrentModelItem::STATE_PAUSED_DL))); break; default: statusFilterModel->setFilterRegExp(QRegExp()); } // Select first item if nothing is selected if(selectionModel()->selectedRows(0).empty() && nameFilterModel->rowCount() > 0) { - qDebug("Nothing is selected, selecting first row: %s", qPrintable(nameFilterModel->index(0, TR_NAME).data().toString())); - selectionModel()->setCurrentIndex(nameFilterModel->index(0, TR_NAME), QItemSelectionModel::SelectCurrent|QItemSelectionModel::Rows); + qDebug("Nothing is selected, selecting first row: %s", qPrintable(nameFilterModel->index(0, TorrentModelItem::TR_NAME).data().toString())); + selectionModel()->setCurrentIndex(nameFilterModel->index(0, TorrentModelItem::TR_NAME), QItemSelectionModel::SelectCurrent|QItemSelectionModel::Rows); } } diff --git a/src/transferlistwidget.h b/src/transferlistwidget.h index a0b947467..122c053d3 100644 --- a/src/transferlistwidget.h +++ b/src/transferlistwidget.h @@ -38,9 +38,9 @@ class QStandardItemModel; class QSortFilterProxyModel; class QBtSession; -class QTimer; class TransferListDelegate; class MainWindow; +class TorrentModel; enum TorrentFilter {FILTER_ALL, FILTER_DOWNLOADING, FILTER_COMPLETED, FILTER_PAUSED, FILTER_ACTIVE, FILTER_INACTIVE}; @@ -51,13 +51,9 @@ public: TransferListWidget(QWidget *parent, MainWindow *main_window, QBtSession* BTSession); ~TransferListWidget(); int getNbTorrents() const; - QStandardItemModel* getSourceModel() const; + TorrentModel* getSourceModel() const; public slots: - void refreshList(bool force=false); - void addTorrent(QTorrentHandle& h); - void pauseTorrent(QTorrentHandle &h); - void setFinished(QTorrentHandle &h); void setSelectionLabel(QString label); void setRefreshInterval(int t); void setSelectedTorrentsLocation(); @@ -73,7 +69,6 @@ public slots: void decreasePrioSelectedTorrents(); void topPrioSelectedTorrents(); void bottomPrioSelectedTorrents(); - void buySelectedTorrents() const; void copySelectedMagnetURIs() const; void openSelectedTorrentsFolder() const; void recheckSelectedTorrents(); @@ -102,41 +97,28 @@ protected: QStringList getSelectedTorrentsHashes() const; protected slots: - int updateTorrent(int row); - void deleteTorrent(QString hash); - void deleteTorrent(int row, bool refresh_list=true); - void pauseTorrent(int row, bool refresh_list=true); - void resumeTorrent(int row, bool refresh_list=true); void torrentDoubleClicked(const QModelIndex& index); bool loadHiddenColumns(); void saveHiddenColumns() const; void displayListMenu(const QPoint&); - void updateMetadata(QTorrentHandle &h); void currentChanged(const QModelIndex& current, const QModelIndex&); - void resumeTorrent(QTorrentHandle &h); #if LIBTORRENT_VERSION_MINOR > 14 void toggleSelectedTorrentsSuperSeeding() const; #endif void toggleSelectedTorrentsSequentialDownload() const; void toggleSelectedFirstLastPiecePrio() const; void askNewLabelForSelection(); - void setRowColor(int row, QColor color); signals: void currentTorrentChanged(QTorrentHandle &h); - void torrentStatusUpdate(uint nb_downloading, uint nb_seeding, uint nb_active, uint nb_inactive, uint nb_paused); - void torrentAdded(QModelIndex index); - void torrentAboutToBeRemoved(QModelIndex index); - void torrentChangedLabel(QString old_label, QString new_label); private: TransferListDelegate *listDelegate; - QStandardItemModel *listModel; + TorrentModel *listModel; QSortFilterProxyModel *nameFilterModel; QSortFilterProxyModel *statusFilterModel; QSortFilterProxyModel *labelFilterModel; QBtSession* BTSession; - QTimer *refreshTimer; MainWindow *main_window; };