From 64c8f61bb187e5d7cef4966b62aa30d5908780b6 Mon Sep 17 00:00:00 2001 From: "Vladimir Golovnev (Glassez)" Date: Sun, 7 Jun 2015 15:03:30 +0300 Subject: [PATCH] Improve TorrentModel class. --- src/core/bittorrent/private/sessionprivate.h | 1 + src/core/bittorrent/session.cpp | 5 + src/core/bittorrent/session.h | 2 + src/core/bittorrent/torrenthandle.cpp | 10 + src/core/bittorrent/torrenthandle.h | 1 + src/gui/mainwindow.cpp | 2 - src/gui/properties/propertieswidget.h | 2 +- src/gui/torrentmodel.cpp | 644 +++++++++---------- src/gui/torrentmodel.h | 99 ++- src/gui/transferlistdelegate.cpp | 48 +- src/gui/transferlistfilterswidget.cpp | 52 +- src/gui/transferlistfilterswidget.h | 19 +- src/gui/transferlistsortmodel.cpp | 34 +- src/gui/transferlistwidget.cpp | 318 ++++----- src/gui/transferlistwidget.h | 4 +- 15 files changed, 561 insertions(+), 680 deletions(-) diff --git a/src/core/bittorrent/private/sessionprivate.h b/src/core/bittorrent/private/sessionprivate.h index 38733c983..be009e87b 100644 --- a/src/core/bittorrent/private/sessionprivate.h +++ b/src/core/bittorrent/private/sessionprivate.h @@ -59,6 +59,7 @@ struct SessionPrivate virtual void handleTorrentRatioLimitChanged(BitTorrent::TorrentHandle *const torrent) = 0; virtual void handleTorrentSavePathChanged(BitTorrent::TorrentHandle *const torrent) = 0; + virtual void handleTorrentLabelChanged(BitTorrent::TorrentHandle *const torrent, const QString &oldLabel) = 0; virtual void handleTorrentMetadataReceived(BitTorrent::TorrentHandle *const torrent) = 0; virtual void handleTorrentPaused(BitTorrent::TorrentHandle *const torrent) = 0; virtual void handleTorrentResumed(BitTorrent::TorrentHandle *const torrent) = 0; diff --git a/src/core/bittorrent/session.cpp b/src/core/bittorrent/session.cpp index 12470e2dd..efa28fc7b 100644 --- a/src/core/bittorrent/session.cpp +++ b/src/core/bittorrent/session.cpp @@ -1631,6 +1631,11 @@ void Session::handleTorrentSavePathChanged(TorrentHandle *const torrent) emit torrentSavePathChanged(torrent); } +void Session::handleTorrentLabelChanged(TorrentHandle *const torrent, const QString &oldLabel) +{ + emit torrentLabelChanged(torrent, oldLabel); +} + void Session::handleTorrentTrackersAdded(TorrentHandle *const torrent, const QList &newTrackers) { foreach (const TrackerEntry &newTracker, newTrackers) diff --git a/src/core/bittorrent/session.h b/src/core/bittorrent/session.h index 2e7284767..f8108a2ec 100644 --- a/src/core/bittorrent/session.h +++ b/src/core/bittorrent/session.h @@ -195,6 +195,7 @@ namespace BitTorrent void torrentFinished(BitTorrent::TorrentHandle *const torrent); void torrentFinishedChecking(BitTorrent::TorrentHandle *const torrent); void torrentSavePathChanged(BitTorrent::TorrentHandle *const torrent); + void torrentLabelChanged(BitTorrent::TorrentHandle *const torrent, const QString &oldLabel); void allTorrentsFinished(); void metadataLoaded(const BitTorrent::TorrentInfo &info); void torrentMetadataLoaded(BitTorrent::TorrentHandle *const torrent); @@ -289,6 +290,7 @@ namespace BitTorrent QString tempPath() const; void handleTorrentRatioLimitChanged(TorrentHandle *const torrent); void handleTorrentSavePathChanged(TorrentHandle *const torrent); + void handleTorrentLabelChanged(TorrentHandle *const torrent, const QString &oldLabel); void handleTorrentMetadataReceived(TorrentHandle *const torrent); void handleTorrentPaused(TorrentHandle *const torrent); void handleTorrentResumed(TorrentHandle *const torrent); diff --git a/src/core/bittorrent/torrenthandle.cpp b/src/core/bittorrent/torrenthandle.cpp index cc8f4b18d..5d4064328 100644 --- a/src/core/bittorrent/torrenthandle.cpp +++ b/src/core/bittorrent/torrenthandle.cpp @@ -969,6 +969,14 @@ int TorrentHandle::timeSinceDownload() const return m_nativeStatus.time_since_download; } +int TorrentHandle::timeSinceActivity() const +{ + if (m_nativeStatus.time_since_upload < m_nativeStatus.time_since_download) + return m_nativeStatus.time_since_upload; + else + return m_nativeStatus.time_since_download; +} + int TorrentHandle::downloadLimit() const { SAFE_RETURN(int, download_limit, -1) @@ -1117,9 +1125,11 @@ void TorrentHandle::setName(const QString &name) void TorrentHandle::setLabel(const QString &label) { if (m_label != label) { + QString oldLabel = m_label; m_label = label; m_needSaveResumeData = true; adjustSavePath(); + m_session->handleTorrentLabelChanged(this, oldLabel); } } diff --git a/src/core/bittorrent/torrenthandle.h b/src/core/bittorrent/torrenthandle.h index 1b4663d15..84bff8416 100644 --- a/src/core/bittorrent/torrenthandle.h +++ b/src/core/bittorrent/torrenthandle.h @@ -241,6 +241,7 @@ namespace BitTorrent QDateTime completedTime() const; int timeSinceUpload() const; int timeSinceDownload() const; + int timeSinceActivity() const; int downloadLimit() const; int uploadLimit() const; bool superSeeding() const; diff --git a/src/gui/mainwindow.cpp b/src/gui/mainwindow.cpp index 0ace0512c..95dbf7f27 100644 --- a/src/gui/mainwindow.cpp +++ b/src/gui/mainwindow.cpp @@ -332,8 +332,6 @@ MainWindow::MainWindow(QWidget *parent) connect(executable_watcher, SIGNAL(fileChanged(QString)), this, SLOT(notifyOfUpdate(QString))); executable_watcher->addPath(qApp->applicationFilePath()); - // Populate the transfer list - transferList->getSourceModel()->populate(); transferList->setFocus(); // Update the number of torrents (tab) diff --git a/src/gui/properties/propertieswidget.h b/src/gui/properties/propertieswidget.h index d4fe43bd8..0f56b071e 100644 --- a/src/gui/properties/propertieswidget.h +++ b/src/gui/properties/propertieswidget.h @@ -97,7 +97,6 @@ public slots: void saveSettings(); void reloadPreferences(); void openDoubleClickedFile(const QModelIndex &); - void updateSavePath(BitTorrent::TorrentHandle *const torrent); void loadTrackers(BitTorrent::TorrentHandle *const torrent); private: @@ -126,6 +125,7 @@ private: private slots: void filterText(const QString& filter); + void updateSavePath(BitTorrent::TorrentHandle *const torrent); }; #endif // PROPERTIESWIDGET_H diff --git a/src/gui/torrentmodel.cpp b/src/gui/torrentmodel.cpp index a9d18c652..154905111 100644 --- a/src/gui/torrentmodel.cpp +++ b/src/gui/torrentmodel.cpp @@ -1,6 +1,7 @@ /* - * Bittorrent Client using Qt4 and libtorrent. - * Copyright (C) 2010 Christophe Dumez + * Bittorrent Client using Qt and libtorrent. + * Copyright (C) 2015 Vladimir Golovnev + * Copyright (C) 2010 Christophe Dumez * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -34,483 +35,416 @@ #include #include "core/bittorrent/session.h" +#include "core/bittorrent/torrenthandle.h" #include "core/torrentfilter.h" #include "core/utils/fs.h" #include "torrentmodel.h" -namespace { -QIcon get_paused_icon() { - static QIcon cached = QIcon(":/icons/skin/paused.png"); - return cached; -} - -QIcon get_queued_icon() { - static QIcon cached = QIcon(":/icons/skin/queued.png"); - return cached; -} - -QIcon get_downloading_icon() { - static QIcon cached = QIcon(":/icons/skin/downloading.png"); - return cached; -} +static QIcon getIconByState(BitTorrent::TorrentState state); +static QColor getColorByState(BitTorrent::TorrentState state); -QIcon get_stalled_downloading_icon() { - static QIcon cached = QIcon(":/icons/skin/stalledDL.png"); - return cached; -} +static QIcon getPausedIcon(); +static QIcon getQueuedIcon(); +static QIcon getDownloadingIcon(); +static QIcon getStalledDownloadingIcon(); +static QIcon getUploadingIcon(); +static QIcon getStalledUploadingIcon(); +static QIcon getCompletedIcon(); +static QIcon getCheckingIcon(); +static QIcon getErrorIcon(); -QIcon get_uploading_icon() { - static QIcon cached = QIcon(":/icons/skin/uploading.png"); - return cached; -} +static bool isDarkTheme(); -QIcon get_stalled_uploading_icon() { - static QIcon cached = QIcon(":/icons/skin/stalledUP.png"); - return cached; -} +// TorrentModel -QIcon get_completed_icon() { - static QIcon cached = QIcon(":/icons/skin/completed.png"); - return cached; -} - -QIcon get_checking_icon() { - static QIcon cached = QIcon(":/icons/skin/checking.png"); - return cached; -} +TorrentModel::TorrentModel(QObject *parent) + : QAbstractListModel(parent) +{ + // Load the torrents + foreach (BitTorrent::TorrentHandle *const torrent, BitTorrent::Session::instance()->torrents()) + addTorrent(torrent); -QIcon get_error_icon() { - static QIcon cached = QIcon(":/icons/skin/error.png"); - return cached; -} + // Listen for torrent changes + connect(BitTorrent::Session::instance(), SIGNAL(torrentAdded(BitTorrent::TorrentHandle *const)), SLOT(addTorrent(BitTorrent::TorrentHandle *const))); + connect(BitTorrent::Session::instance(), SIGNAL(torrentAboutToBeRemoved(BitTorrent::TorrentHandle *const)), SLOT(handleTorrentAboutToBeRemoved(BitTorrent::TorrentHandle *const))); + connect(BitTorrent::Session::instance(), SIGNAL(torrentStatusUpdated(BitTorrent::TorrentHandle *const)), this, SLOT(handleTorrentStatusUpdated(BitTorrent::TorrentHandle *const))); -bool isDarkTheme() -{ - QPalette pal = QApplication::palette(); - // QPalette::Base is used for the background of the Treeview - QColor color = pal.color(QPalette::Active, QPalette::Base); - return (color.lightness() < 127); -} + connect(BitTorrent::Session::instance(), SIGNAL(torrentFinished(BitTorrent::TorrentHandle *const)), SLOT(handleTorrentStatusUpdated(BitTorrent::TorrentHandle *const))); + connect(BitTorrent::Session::instance(), SIGNAL(torrentMetadataLoaded(BitTorrent::TorrentHandle *const)), SLOT(handleTorrentStatusUpdated(BitTorrent::TorrentHandle *const))); + connect(BitTorrent::Session::instance(), SIGNAL(torrentResumed(BitTorrent::TorrentHandle *const)), SLOT(handleTorrentStatusUpdated(BitTorrent::TorrentHandle *const))); + connect(BitTorrent::Session::instance(), SIGNAL(torrentPaused(BitTorrent::TorrentHandle *const)), SLOT(handleTorrentStatusUpdated(BitTorrent::TorrentHandle *const))); + connect(BitTorrent::Session::instance(), SIGNAL(torrentFinishedChecking(BitTorrent::TorrentHandle *const)), SLOT(handleTorrentStatusUpdated(BitTorrent::TorrentHandle *const))); } -TorrentModelItem::TorrentModelItem(BitTorrent::TorrentHandle *torrent) - : m_torrent(torrent) +int TorrentModel::rowCount(const QModelIndex &index) const { + Q_UNUSED(index); + return m_torrents.size(); } -BitTorrent::TorrentState TorrentModelItem::state() const +int TorrentModel::columnCount(const QModelIndex &parent) const { - return m_torrent->state(); + Q_UNUSED(parent); + return NB_COLUMNS; } -QIcon TorrentModelItem::getIconByState(BitTorrent::TorrentState state) +QVariant TorrentModel::headerData(int section, Qt::Orientation orientation, int role) const { - switch (state) { - case BitTorrent::TorrentState::Downloading: - case BitTorrent::TorrentState::ForcedDownloading: - case BitTorrent::TorrentState::DownloadingMetadata: - return get_downloading_icon(); - case BitTorrent::TorrentState::Allocating: - case BitTorrent::TorrentState::StalledDownloading: - return get_stalled_downloading_icon(); - case BitTorrent::TorrentState::StalledUploading: - return get_stalled_uploading_icon(); - case BitTorrent::TorrentState::Uploading: - case BitTorrent::TorrentState::ForcedUploading: - return get_uploading_icon(); - case BitTorrent::TorrentState::PausedDownloading: - return get_paused_icon(); - case BitTorrent::TorrentState::PausedUploading: - return get_completed_icon(); - case BitTorrent::TorrentState::QueuedDownloading: - case BitTorrent::TorrentState::QueuedUploading: - return get_queued_icon(); - case BitTorrent::TorrentState::CheckingDownloading: - case BitTorrent::TorrentState::CheckingUploading: - return get_checking_icon(); - case BitTorrent::TorrentState::Unknown: - case BitTorrent::TorrentState::Error: - return get_error_icon(); - default: - Q_ASSERT(false); - return get_error_icon(); + if (orientation == Qt::Horizontal) { + if (role == Qt::DisplayRole) { + switch(section) { + case TR_PRIORITY: return "#"; + case TR_NAME: return tr("Name", "i.e: torrent name"); + case TR_SIZE: return tr("Size", "i.e: torrent size"); + case TR_PROGRESS: return tr("Done", "% Done"); + case TR_STATUS: return tr("Status", "Torrent status (e.g. downloading, seeding, paused)"); + case TR_SEEDS: return tr("Seeds", "i.e. full sources (often untranslated)"); + case TR_PEERS: return tr("Peers", "i.e. partial sources (often untranslated)"); + case TR_DLSPEED: return tr("Down Speed", "i.e: Download speed"); + case TR_UPSPEED: return tr("Up Speed", "i.e: Upload speed"); + case TR_RATIO: return tr("Ratio", "Share ratio"); + case TR_ETA: return tr("ETA", "i.e: Estimated Time of Arrival / Time left"); + case TR_LABEL: return tr("Label"); + case TR_ADD_DATE: return tr("Added On", "Torrent was added to transfer list on 01/01/2010 08:00"); + case TR_SEED_DATE: return tr("Completed On", "Torrent was completed on 01/01/2010 08:00"); + case TR_TRACKER: return tr("Tracker"); + case TR_DLLIMIT: return tr("Down Limit", "i.e: Download limit"); + case TR_UPLIMIT: return tr("Up Limit", "i.e: Upload limit"); + case TR_AMOUNT_DOWNLOADED: return tr("Downloaded", "Amount of data downloaded (e.g. in MB)"); + case TR_AMOUNT_UPLOADED: return tr("Uploaded", "Amount of data uploaded (e.g. in MB)"); + case TR_AMOUNT_DOWNLOADED_SESSION: return tr("Session Download", "Amount of data downloaded since program open (e.g. in MB)"); + case TR_AMOUNT_UPLOADED_SESSION: return tr("Session Upload", "Amount of data uploaded since program open (e.g. in MB)"); + case TR_AMOUNT_LEFT: return tr("Remaining", "Amount of data left to download (e.g. in MB)"); + case TR_TIME_ELAPSED: return tr("Time Active", "Time (duration) the torrent is active (not paused)"); + case TR_SAVE_PATH: return tr("Save path", "Torrent save path"); + case TR_COMPLETED: return tr("Completed", "Amount of data completed (e.g. in MB)"); + case TR_RATIO_LIMIT: return tr("Ratio Limit", "Upload share ratio limit"); + case TR_SEEN_COMPLETE_DATE: return tr("Last Seen Complete", "Indicates the time when the torrent was last seen complete/whole"); + case TR_LAST_ACTIVITY: return tr("Last Activity", "Time passed since a chunk was downloaded/uploaded"); + case TR_TOTAL_SIZE: return tr("Total Size", "i.e. Size including unwanted data"); + default: + return QVariant(); + } + } + else if (role == Qt::TextAlignmentRole) { + switch(section) { + case TR_AMOUNT_DOWNLOADED: + case TR_AMOUNT_UPLOADED: + case TR_AMOUNT_DOWNLOADED_SESSION: + case TR_AMOUNT_UPLOADED_SESSION: + case TR_AMOUNT_LEFT: + case TR_COMPLETED: + case TR_SIZE: + case TR_TOTAL_SIZE: + case TR_ETA: + case TR_SEEDS: + case TR_PEERS: + case TR_UPSPEED: + case TR_DLSPEED: + case TR_UPLIMIT: + case TR_DLLIMIT: + case TR_RATIO_LIMIT: + case TR_RATIO: + case TR_PRIORITY: + case TR_LAST_ACTIVITY: + return QVariant(Qt::AlignRight | Qt::AlignVCenter); + default: + return QAbstractListModel::headerData(section, orientation, role); + } + } } -} -QColor TorrentModelItem::getColorByState(BitTorrent::TorrentState state) -{ - bool dark = isDarkTheme(); - - switch (state) { - case BitTorrent::TorrentState::Downloading: - case BitTorrent::TorrentState::ForcedDownloading: - case BitTorrent::TorrentState::DownloadingMetadata: - return QColor(34, 139, 34); // Forest Green - case BitTorrent::TorrentState::Allocating: - case BitTorrent::TorrentState::StalledDownloading: - case BitTorrent::TorrentState::StalledUploading: - if (!dark) - return QColor(0, 0, 0); // Black - else - return QColor(255, 255, 255); // White - case BitTorrent::TorrentState::Uploading: - case BitTorrent::TorrentState::ForcedUploading: - if (!dark) - return QColor(65, 105, 225); // Royal Blue - else - return QColor(100, 149, 237); // Cornflower Blue - case BitTorrent::TorrentState::PausedDownloading: - return QColor(250, 128, 114); // Salmon - case BitTorrent::TorrentState::PausedUploading: - if (!dark) - return QColor(0, 0, 139); // Dark Blue - else - return QColor(65, 105, 225); // Royal Blue - case BitTorrent::TorrentState::Error: - return QColor(255, 0, 0); // red - case BitTorrent::TorrentState::QueuedDownloading: - case BitTorrent::TorrentState::QueuedUploading: - case BitTorrent::TorrentState::CheckingDownloading: - case BitTorrent::TorrentState::CheckingUploading: - return QColor(0, 128, 128); // Teal - case BitTorrent::TorrentState::Unknown: - return QColor(255, 0, 0); // red - default: - Q_ASSERT(false); - return QColor(255, 0, 0); // red - } + return QVariant(); } -bool TorrentModelItem::setData(int column, const QVariant &value, int role) +QVariant TorrentModel::data(const QModelIndex &index, int role) const { - qDebug() << Q_FUNC_INFO << column << value; - if (role != Qt::DisplayRole) return false; + if (!index.isValid()) return QVariant(); - // Label, seed date and Name columns can be edited - switch(column) { - case TR_NAME: - m_torrent->setName(value.toString()); - return true; - case TR_LABEL: { - QString new_label = value.toString(); - if (m_torrent->label() != new_label) { - QString old_label = m_torrent->label(); - m_torrent->setLabel(new_label); - emit labelChanged(old_label, new_label); - } - return true; - } - default: - break; - } - return false; -} + BitTorrent::TorrentHandle *const torrent = m_torrents.value(index.row()); + if (!torrent) return QVariant(); -QVariant TorrentModelItem::data(int column, int role) const -{ - if ((role == Qt::DecorationRole) && (column == TR_NAME)) - return getIconByState(state()); + if ((role == Qt::DecorationRole) && (index.column() == TR_NAME)) + return getIconByState(torrent->state()); if (role == Qt::ForegroundRole) - return getColorByState(state()); + return getColorByState(torrent->state()); if ((role != Qt::DisplayRole) && (role != Qt::UserRole)) return QVariant(); - switch(column) { + switch(index.column()) { case TR_NAME: - return m_torrent->name(); + return torrent->name(); case TR_PRIORITY: - return m_torrent->queuePosition(); + return torrent->queuePosition(); case TR_SIZE: - return m_torrent->hasMetadata() ? m_torrent->wantedSize() : -1; + return torrent->wantedSize(); case TR_PROGRESS: - return m_torrent->progress(); + return torrent->progress(); case TR_STATUS: - return static_cast(m_torrent->state()); + return static_cast(torrent->state()); case TR_SEEDS: - return (role == Qt::DisplayRole) ? m_torrent->seedsCount() : m_torrent->completeCount(); + return (role == Qt::DisplayRole) ? torrent->seedsCount() : torrent->completeCount(); case TR_PEERS: - return (role == Qt::DisplayRole) ? (m_torrent->peersCount() - m_torrent->seedsCount()) : m_torrent->incompleteCount(); + return (role == Qt::DisplayRole) ? (torrent->peersCount() - torrent->seedsCount()) : torrent->incompleteCount(); case TR_DLSPEED: - return m_torrent->downloadPayloadRate(); + return torrent->downloadPayloadRate(); case TR_UPSPEED: - return m_torrent->uploadPayloadRate(); + return torrent->uploadPayloadRate(); case TR_ETA: - return m_torrent->eta(); + return torrent->eta(); case TR_RATIO: - return m_torrent->realRatio(); + return torrent->realRatio(); case TR_LABEL: - return m_torrent->label(); + return torrent->label(); case TR_ADD_DATE: - return m_torrent->addedTime(); + return torrent->addedTime(); case TR_SEED_DATE: - return m_torrent->completedTime(); + return torrent->completedTime(); case TR_TRACKER: - return m_torrent->currentTracker(); + return torrent->currentTracker(); case TR_DLLIMIT: - return m_torrent->downloadLimit(); + return torrent->downloadLimit(); case TR_UPLIMIT: - return m_torrent->uploadLimit(); + return torrent->uploadLimit(); case TR_AMOUNT_DOWNLOADED: - return m_torrent->totalDownload(); + return torrent->totalDownload(); case TR_AMOUNT_UPLOADED: - return m_torrent->totalUpload(); + return torrent->totalUpload(); case TR_AMOUNT_DOWNLOADED_SESSION: - return m_torrent->totalPayloadDownload(); + return torrent->totalPayloadDownload(); case TR_AMOUNT_UPLOADED_SESSION: - return m_torrent->totalPayloadUpload(); + return torrent->totalPayloadUpload(); case TR_AMOUNT_LEFT: - return m_torrent->incompletedSize(); + return torrent->incompletedSize(); case TR_TIME_ELAPSED: - return (role == Qt::DisplayRole) ? m_torrent->activeTime() : m_torrent->seedingTime(); + return (role == Qt::DisplayRole) ? torrent->activeTime() : torrent->seedingTime(); case TR_SAVE_PATH: - return m_torrent->savePathParsed(); + return torrent->savePathParsed(); case TR_COMPLETED: - return m_torrent->completedSize(); + return torrent->completedSize(); case TR_RATIO_LIMIT: - return m_torrent->maxRatio(); + return torrent->maxRatio(); case TR_SEEN_COMPLETE_DATE: - return m_torrent->lastSeenComplete(); + return torrent->lastSeenComplete(); case TR_LAST_ACTIVITY: - if (m_torrent->isPaused() || m_torrent->isChecking()) + if (torrent->isPaused() || torrent->isChecking()) return -1; - if (m_torrent->timeSinceUpload() < m_torrent->timeSinceDownload()) - return m_torrent->timeSinceUpload(); - else - return m_torrent->timeSinceDownload(); + return torrent->timeSinceActivity(); case TR_TOTAL_SIZE: - return m_torrent->hasMetadata() ? m_torrent->totalSize() : -1; + return torrent->totalSize(); default: return QVariant(); } -} -BitTorrent::TorrentHandle *TorrentModelItem::torrentHandle() const -{ - return m_torrent; + return QVariant(); } -// TORRENT MODEL - -TorrentModel::TorrentModel(QObject *parent) - : QAbstractListModel(parent) +bool TorrentModel::setData(const QModelIndex &index, const QVariant &value, int role) { -} + qDebug() << Q_FUNC_INFO << value; + if (!index.isValid() || (role != Qt::DisplayRole)) return false; -void TorrentModel::populate() -{ - // Load the torrents - foreach (BitTorrent::TorrentHandle *const torrent, BitTorrent::Session::instance()->torrents()) - addTorrent(torrent); + qDebug("Index is valid and role is DisplayRole"); + BitTorrent::TorrentHandle *const torrent = m_torrents.value(index.row()); + if (!torrent) return false; - // Listen for torrent changes - connect(BitTorrent::Session::instance(), SIGNAL(torrentAdded(BitTorrent::TorrentHandle *const)), SLOT(addTorrent(BitTorrent::TorrentHandle *const))); - connect(BitTorrent::Session::instance(), SIGNAL(torrentAboutToBeRemoved(BitTorrent::TorrentHandle *const)), SLOT(handleTorrentAboutToBeRemoved(BitTorrent::TorrentHandle *const))); - connect(BitTorrent::Session::instance(), SIGNAL(torrentStatusUpdated(BitTorrent::TorrentHandle *const)), this, SLOT(handleTorrentStatusUpdated(BitTorrent::TorrentHandle *const))); + // Label, seed date and Name columns can be edited + switch(index.column()) { + case TR_NAME: + torrent->setName(value.toString()); + break; + case TR_LABEL: + torrent->setLabel(value.toString()); + break; + default: + return false; + } - connect(BitTorrent::Session::instance(), SIGNAL(torrentFinished(BitTorrent::TorrentHandle *const)), SLOT(handleTorrentStatusUpdated(BitTorrent::TorrentHandle *const))); - connect(BitTorrent::Session::instance(), SIGNAL(torrentMetadataLoaded(BitTorrent::TorrentHandle *const)), SLOT(handleTorrentStatusUpdated(BitTorrent::TorrentHandle *const))); - connect(BitTorrent::Session::instance(), SIGNAL(torrentResumed(BitTorrent::TorrentHandle *const)), SLOT(handleTorrentStatusUpdated(BitTorrent::TorrentHandle *const))); - connect(BitTorrent::Session::instance(), SIGNAL(torrentPaused(BitTorrent::TorrentHandle *const)), SLOT(handleTorrentStatusUpdated(BitTorrent::TorrentHandle *const))); - connect(BitTorrent::Session::instance(), SIGNAL(torrentFinishedChecking(BitTorrent::TorrentHandle *const)), SLOT(handleTorrentStatusUpdated(BitTorrent::TorrentHandle *const))); + return true; } -TorrentModel::~TorrentModel() { - qDebug() << Q_FUNC_INFO << "ENTER"; - qDeleteAll(m_items); - m_items.clear(); - qDebug() << Q_FUNC_INFO << "EXIT"; +void TorrentModel::addTorrent(BitTorrent::TorrentHandle *const torrent) +{ + if (m_torrents.indexOf(torrent) == -1) { + const int row = m_torrents.size(); + beginInsertRows(QModelIndex(), row, row); + m_torrents << torrent; + endInsertRows(); + } } -QVariant TorrentModel::headerData(int section, Qt::Orientation orientation, - int role) const +Qt::ItemFlags TorrentModel::flags(const QModelIndex &index) const { - if (orientation == Qt::Horizontal) { - if (role == Qt::DisplayRole) { - switch(section) { - case TorrentModelItem::TR_PRIORITY: return "#"; - case TorrentModelItem::TR_NAME: return tr("Name", "i.e: torrent name"); - 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"); - case TorrentModelItem::TR_AMOUNT_DOWNLOADED: return tr("Downloaded", "Amount of data downloaded (e.g. in MB)"); - case TorrentModelItem::TR_AMOUNT_UPLOADED: return tr("Uploaded", "Amount of data uploaded (e.g. in MB)"); - case TorrentModelItem::TR_AMOUNT_DOWNLOADED_SESSION: return tr("Session Download", "Amount of data downloaded since program open (e.g. in MB)"); - case TorrentModelItem::TR_AMOUNT_UPLOADED_SESSION: return tr("Session Upload", "Amount of data uploaded since program open (e.g. in MB)"); - case TorrentModelItem::TR_AMOUNT_LEFT: return tr("Remaining", "Amount of data left to download (e.g. in MB)"); - case TorrentModelItem::TR_TIME_ELAPSED: return tr("Time Active", "Time (duration) the torrent is active (not paused)"); - case TorrentModelItem::TR_SAVE_PATH: return tr("Save path", "Torrent save path"); - case TorrentModelItem::TR_COMPLETED: return tr("Completed", "Amount of data completed (e.g. in MB)"); - case TorrentModelItem::TR_RATIO_LIMIT: return tr("Ratio Limit", "Upload share ratio limit"); - case TorrentModelItem::TR_SEEN_COMPLETE_DATE: return tr("Last Seen Complete", "Indicates the time when the torrent was last seen complete/whole"); - case TorrentModelItem::TR_LAST_ACTIVITY: return tr("Last Activity", "Time passed since a chunk was downloaded/uploaded"); - case TorrentModelItem::TR_TOTAL_SIZE: return tr("Total Size", "i.e. Size including unwanted data"); - default: - return QVariant(); - } - } - else if (role == Qt::TextAlignmentRole) { - switch(section) { - case TorrentModelItem::TR_AMOUNT_DOWNLOADED: - case TorrentModelItem::TR_AMOUNT_UPLOADED: - case TorrentModelItem::TR_AMOUNT_DOWNLOADED_SESSION: - case TorrentModelItem::TR_AMOUNT_UPLOADED_SESSION: - case TorrentModelItem::TR_AMOUNT_LEFT: - case TorrentModelItem::TR_COMPLETED: - case TorrentModelItem::TR_SIZE: - case TorrentModelItem::TR_TOTAL_SIZE: - case TorrentModelItem::TR_ETA: - case TorrentModelItem::TR_SEEDS: - case TorrentModelItem::TR_PEERS: - case TorrentModelItem::TR_UPSPEED: - case TorrentModelItem::TR_DLSPEED: - case TorrentModelItem::TR_UPLIMIT: - case TorrentModelItem::TR_DLLIMIT: - case TorrentModelItem::TR_RATIO_LIMIT: - case TorrentModelItem::TR_RATIO: - case TorrentModelItem::TR_PRIORITY: - case TorrentModelItem::TR_LAST_ACTIVITY: - return QVariant(Qt::AlignRight | Qt::AlignVCenter); - default: - return QAbstractListModel::headerData(section, orientation, role); - } - } - } + if (!index.isValid()) return 0; - return QVariant(); + // Explicitly mark as editable + return QAbstractListModel::flags(index) | Qt::ItemIsEditable; } -QVariant TorrentModel::data(const QModelIndex &index, int role) const +BitTorrent::TorrentHandle *TorrentModel::torrentHandle(const QModelIndex &index) const { - if (!index.isValid()) return QVariant(); + if (!index.isValid()) return 0; - if (index.row() >= 0 && index.row() < rowCount() && index.column() >= 0 && index.column() < columnCount()) - return m_items[index.row()]->data(index.column(), role); - - return QVariant(); + return m_torrents.value(index.row()); } -bool TorrentModel::setData(const QModelIndex &index, const QVariant &value, int role) +void TorrentModel::handleTorrentAboutToBeRemoved(BitTorrent::TorrentHandle *const torrent) { - qDebug() << Q_FUNC_INFO << value; - if (!index.isValid() || (role != Qt::DisplayRole)) return false; - - qDebug("Index is valid and role is DisplayRole"); - if ((index.row() >= 0) && (index.row() < rowCount()) && (index.column() >= 0) && (index.column() < columnCount())) { - bool change = m_items[index.row()]->setData(index.column(), value, role); - if (change) - notifyTorrentChanged(index.row()); - return change; + const int row = m_torrents.indexOf(torrent); + if (row >= 0) { + beginRemoveRows(QModelIndex(), row, row); + m_torrents.removeAt(row); + endRemoveRows(); } - - return false; } -int TorrentModel::torrentRow(const BitTorrent::InfoHash &hash) const +void TorrentModel::handleTorrentStatusUpdated(BitTorrent::TorrentHandle *const torrent) { - int row = 0; - - foreach (TorrentModelItem *const item, m_items) { - if (item->hash() == hash) return row; - ++row; - } - return -1; + const int row = m_torrents.indexOf(torrent); + if (row >= 0) + emit dataChanged(index(row, 0), index(row, columnCount() - 1)); } -void TorrentModel::addTorrent(BitTorrent::TorrentHandle *const torrent) +// Static functions + +QIcon getIconByState(BitTorrent::TorrentState state) { - if (torrentRow(torrent->hash()) < 0) { - beginInsertTorrent(m_items.size()); - TorrentModelItem *item = new TorrentModelItem(torrent); - connect(item, SIGNAL(labelChanged(QString, QString)), SLOT(handleTorrentLabelChange(QString, QString))); - m_items << item; - emit torrentAdded(item); - endInsertTorrent(); + switch (state) { + case BitTorrent::TorrentState::Downloading: + case BitTorrent::TorrentState::ForcedDownloading: + case BitTorrent::TorrentState::DownloadingMetadata: + return getDownloadingIcon(); + case BitTorrent::TorrentState::Allocating: + case BitTorrent::TorrentState::StalledDownloading: + return getStalledDownloadingIcon(); + case BitTorrent::TorrentState::StalledUploading: + return getStalledUploadingIcon(); + case BitTorrent::TorrentState::Uploading: + case BitTorrent::TorrentState::ForcedUploading: + return getUploadingIcon(); + case BitTorrent::TorrentState::PausedDownloading: + return getPausedIcon(); + case BitTorrent::TorrentState::PausedUploading: + return getCompletedIcon(); + case BitTorrent::TorrentState::QueuedDownloading: + case BitTorrent::TorrentState::QueuedUploading: + return getQueuedIcon(); + case BitTorrent::TorrentState::CheckingDownloading: + case BitTorrent::TorrentState::CheckingUploading: + return getCheckingIcon(); + case BitTorrent::TorrentState::Unknown: + case BitTorrent::TorrentState::Error: + return getErrorIcon(); + default: + Q_ASSERT(false); + return getErrorIcon(); } } -void TorrentModel::beginInsertTorrent(int row) +QColor getColorByState(BitTorrent::TorrentState state) { - beginInsertRows(QModelIndex(), row, row); + bool dark = isDarkTheme(); + + switch (state) { + case BitTorrent::TorrentState::Downloading: + case BitTorrent::TorrentState::ForcedDownloading: + case BitTorrent::TorrentState::DownloadingMetadata: + return QColor(34, 139, 34); // Forest Green + case BitTorrent::TorrentState::Allocating: + case BitTorrent::TorrentState::StalledDownloading: + case BitTorrent::TorrentState::StalledUploading: + if (!dark) + return QColor(0, 0, 0); // Black + else + return QColor(255, 255, 255); // White + case BitTorrent::TorrentState::Uploading: + case BitTorrent::TorrentState::ForcedUploading: + if (!dark) + return QColor(65, 105, 225); // Royal Blue + else + return QColor(100, 149, 237); // Cornflower Blue + case BitTorrent::TorrentState::PausedDownloading: + return QColor(250, 128, 114); // Salmon + case BitTorrent::TorrentState::PausedUploading: + if (!dark) + return QColor(0, 0, 139); // Dark Blue + else + return QColor(65, 105, 225); // Royal Blue + case BitTorrent::TorrentState::Error: + return QColor(255, 0, 0); // red + case BitTorrent::TorrentState::QueuedDownloading: + case BitTorrent::TorrentState::QueuedUploading: + case BitTorrent::TorrentState::CheckingDownloading: + case BitTorrent::TorrentState::CheckingUploading: + return QColor(0, 128, 128); // Teal + case BitTorrent::TorrentState::Unknown: + return QColor(255, 0, 0); // red + default: + Q_ASSERT(false); + return QColor(255, 0, 0); // red + } } -void TorrentModel::endInsertTorrent() +QIcon getPausedIcon() { - endInsertRows(); + static QIcon cached = QIcon(":/icons/skin/paused.png"); + return cached; } -void TorrentModel::beginRemoveTorrent(int row) +QIcon getQueuedIcon() { - beginRemoveRows(QModelIndex(), row, row); + static QIcon cached = QIcon(":/icons/skin/queued.png"); + return cached; } -void TorrentModel::endRemoveTorrent() +QIcon getDownloadingIcon() { - endRemoveRows(); + static QIcon cached = QIcon(":/icons/skin/downloading.png"); + return cached; } -void TorrentModel::notifyTorrentChanged(int row) +QIcon getStalledDownloadingIcon() { - emit dataChanged(index(row, 0), index(row, columnCount() - 1)); + static QIcon cached = QIcon(":/icons/skin/stalledDL.png"); + return cached; } -Qt::ItemFlags TorrentModel::flags(const QModelIndex &index) const +QIcon getUploadingIcon() { - if (!index.isValid()) - return 0; - // Explicitly mark as editable - return QAbstractListModel::flags(index) | Qt::ItemIsEditable; + static QIcon cached = QIcon(":/icons/skin/uploading.png"); + return cached; } -void TorrentModel::handleTorrentLabelChange(QString previous, QString current) +QIcon getStalledUploadingIcon() { - emit torrentChangedLabel(static_cast(sender()), previous, current); + static QIcon cached = QIcon(":/icons/skin/stalledUP.png"); + return cached; } -QString TorrentModel::torrentHash(int row) const +QIcon getCompletedIcon() { - if (row >= 0 && row < rowCount()) - return m_items.at(row)->hash(); - return QString(); + static QIcon cached = QIcon(":/icons/skin/completed.png"); + return cached; } -BitTorrent::TorrentHandle *TorrentModel::torrentHandle(const QModelIndex &index) const +QIcon getCheckingIcon() { - if (index.isValid() && (index.row() >= 0) && (index.row() < rowCount())) - return m_items[index.row()]->torrentHandle(); - - return 0; + static QIcon cached = QIcon(":/icons/skin/checking.png"); + return cached; } -void TorrentModel::handleTorrentAboutToBeRemoved(BitTorrent::TorrentHandle *const torrent) +QIcon getErrorIcon() { - const int row = torrentRow(torrent->hash()); - qDebug() << Q_FUNC_INFO << row; - if (row >= 0) { - emit torrentAboutToBeRemoved(m_items.at(row)); - - beginRemoveTorrent(row); - delete m_items.takeAt(row); - endRemoveTorrent(); - } + static QIcon cached = QIcon(":/icons/skin/error.png"); + return cached; } -void TorrentModel::handleTorrentStatusUpdated(BitTorrent::TorrentHandle *const torrent) +bool isDarkTheme() { - const int row = torrentRow(torrent->hash()); - if (row >= 0) - notifyTorrentChanged(row); + QPalette pal = QApplication::palette(); + // QPalette::Base is used for the background of the Treeview + QColor color = pal.color(QPalette::Active, QPalette::Base); + return (color.lightness() < 127); } diff --git a/src/gui/torrentmodel.h b/src/gui/torrentmodel.h index 931de042c..e4abc97d4 100644 --- a/src/gui/torrentmodel.h +++ b/src/gui/torrentmodel.h @@ -1,6 +1,7 @@ /* - * Bittorrent Client using Qt4 and libtorrent. - * Copyright (C) 2010 Christophe Dumez + * Bittorrent Client using Qt and libtorrent. + * Copyright (C) 2015 Vladimir Golovnev + * Copyright (C) 2010 Christophe Dumez * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -34,35 +35,11 @@ #include #include -#include "core/bittorrent/torrenthandle.h" - -class QIcon; - -class TorrentModelItem : public QObject { - Q_OBJECT - -public: - enum Column {TR_PRIORITY, TR_NAME, TR_SIZE, TR_TOTAL_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_AMOUNT_DOWNLOADED, TR_AMOUNT_UPLOADED, TR_AMOUNT_DOWNLOADED_SESSION, TR_AMOUNT_UPLOADED_SESSION, TR_AMOUNT_LEFT, TR_TIME_ELAPSED, TR_SAVE_PATH, TR_COMPLETED, TR_RATIO_LIMIT, TR_SEEN_COMPLETE_DATE, TR_LAST_ACTIVITY, NB_COLUMNS}; - -public: - TorrentModelItem(BitTorrent::TorrentHandle *torrent); - 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 BitTorrent::InfoHash hash() const { return m_torrent->hash(); } - BitTorrent::TorrentState state() const; - BitTorrent::TorrentHandle *torrentHandle() const; - -signals: - void labelChanged(QString previous, QString current); - -private: - static QIcon getIconByState(BitTorrent::TorrentState state); - static QColor getColorByState(BitTorrent::TorrentState state); - -private: - BitTorrent::TorrentHandle *m_torrent; -}; +namespace BitTorrent +{ + class InfoHash; + class TorrentHandle; +} class TorrentModel : public QAbstractListModel { @@ -70,39 +47,59 @@ class TorrentModel : public QAbstractListModel Q_DISABLE_COPY(TorrentModel) public: + enum Column + { + TR_PRIORITY, + TR_NAME, + TR_SIZE, + TR_TOTAL_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_AMOUNT_DOWNLOADED, + TR_AMOUNT_UPLOADED, + TR_AMOUNT_DOWNLOADED_SESSION, + TR_AMOUNT_UPLOADED_SESSION, + TR_AMOUNT_LEFT, + TR_TIME_ELAPSED, + TR_SAVE_PATH, + TR_COMPLETED, + TR_RATIO_LIMIT, + TR_SEEN_COMPLETE_DATE, + TR_LAST_ACTIVITY, + + NB_COLUMNS + }; + explicit TorrentModel(QObject *parent = 0); - ~TorrentModel(); - inline int rowCount(const QModelIndex& index = QModelIndex()) const { Q_UNUSED(index); return m_items.size(); } - int columnCount(const QModelIndex &parent=QModelIndex()) const { Q_UNUSED(parent); return TorrentModelItem::NB_COLUMNS; } + + int rowCount(const QModelIndex& index = QModelIndex()) const; + int columnCount(const QModelIndex &parent=QModelIndex()) const; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::DisplayRole); QVariant headerData(int section, Qt::Orientation orientation, int role) const; - int torrentRow(const BitTorrent::InfoHash &hash) const; - QString torrentHash(int row) const; - BitTorrent::TorrentHandle *torrentHandle(const QModelIndex &index) 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); + BitTorrent::TorrentHandle *torrentHandle(const QModelIndex &index) const; private slots: void addTorrent(BitTorrent::TorrentHandle *const torrent); - void notifyTorrentChanged(int row); - void handleTorrentLabelChange(QString previous, QString current); void handleTorrentAboutToBeRemoved(BitTorrent::TorrentHandle *const torrent); void handleTorrentStatusUpdated(BitTorrent::TorrentHandle *const torrent); private: - void beginInsertTorrent(int row); - void endInsertTorrent(); - void beginRemoveTorrent(int row); - void endRemoveTorrent(); - -private: - QList m_items; + QList m_torrents; }; #endif // TORRENTMODEL_H diff --git a/src/gui/transferlistdelegate.cpp b/src/gui/transferlistdelegate.cpp index f73a0a9a6..05af68de1 100644 --- a/src/gui/transferlistdelegate.cpp +++ b/src/gui/transferlistdelegate.cpp @@ -56,27 +56,27 @@ void TransferListDelegate::paint(QPainter * painter, const QStyleOptionViewItem QStyleOptionViewItemV2 opt = QItemDelegate::setOptions(index, option); painter->save(); switch(index.column()) { - case TorrentModelItem::TR_AMOUNT_DOWNLOADED: - case TorrentModelItem::TR_AMOUNT_UPLOADED: - case TorrentModelItem::TR_AMOUNT_DOWNLOADED_SESSION: - case TorrentModelItem::TR_AMOUNT_UPLOADED_SESSION: - case TorrentModelItem::TR_AMOUNT_LEFT: - case TorrentModelItem::TR_COMPLETED: - case TorrentModelItem::TR_SIZE: - case TorrentModelItem::TR_TOTAL_SIZE: { + case TorrentModel::TR_AMOUNT_DOWNLOADED: + case TorrentModel::TR_AMOUNT_UPLOADED: + case TorrentModel::TR_AMOUNT_DOWNLOADED_SESSION: + case TorrentModel::TR_AMOUNT_UPLOADED_SESSION: + case TorrentModel::TR_AMOUNT_LEFT: + case TorrentModel::TR_COMPLETED: + case TorrentModel::TR_SIZE: + case TorrentModel::TR_TOTAL_SIZE: { QItemDelegate::drawBackground(painter, opt, index); opt.displayAlignment = Qt::AlignRight | Qt::AlignVCenter; QItemDelegate::drawDisplay(painter, opt, option.rect, Utils::Misc::friendlyUnit(index.data().toLongLong())); break; } - case TorrentModelItem::TR_ETA: { + case TorrentModel::TR_ETA: { QItemDelegate::drawBackground(painter, opt, index); opt.displayAlignment = Qt::AlignRight | Qt::AlignVCenter; QItemDelegate::drawDisplay(painter, opt, option.rect, Utils::Misc::userFriendlyDuration(index.data().toLongLong())); break; } - case TorrentModelItem::TR_SEEDS: - case TorrentModelItem::TR_PEERS: { + case TorrentModel::TR_SEEDS: + case TorrentModel::TR_PEERS: { QString display = QString::number(index.data().toLongLong()); qlonglong total = index.data(Qt::UserRole).toLongLong(); if (total > 0) { @@ -88,7 +88,7 @@ void TransferListDelegate::paint(QPainter * painter, const QStyleOptionViewItem QItemDelegate::drawDisplay(painter, opt, opt.rect, display); break; } - case TorrentModelItem::TR_STATUS: { + case TorrentModel::TR_STATUS: { const int state = index.data().toInt(); QString display; switch(state) { @@ -138,23 +138,23 @@ void TransferListDelegate::paint(QPainter * painter, const QStyleOptionViewItem QItemDelegate::drawDisplay(painter, opt, opt.rect, display); break; } - case TorrentModelItem::TR_UPSPEED: - case TorrentModelItem::TR_DLSPEED: { + case TorrentModel::TR_UPSPEED: + case TorrentModel::TR_DLSPEED: { QItemDelegate::drawBackground(painter, opt, index); const qulonglong speed = index.data().toULongLong(); opt.displayAlignment = Qt::AlignRight | Qt::AlignVCenter; QItemDelegate::drawDisplay(painter, opt, opt.rect, Utils::Misc::friendlyUnit(speed)+tr("/s", "/second (.i.e per second)")); break; } - case TorrentModelItem::TR_UPLIMIT: - case TorrentModelItem::TR_DLLIMIT: { + case TorrentModel::TR_UPLIMIT: + case TorrentModel::TR_DLLIMIT: { QItemDelegate::drawBackground(painter, opt, index); const qlonglong limit = index.data().toLongLong(); opt.displayAlignment = Qt::AlignRight | Qt::AlignVCenter; QItemDelegate::drawDisplay(painter, opt, opt.rect, limit > 0 ? Utils::String::fromDouble(limit/1024., 1) + " " + tr("KiB/s", "KiB/second (.i.e per second)") : QString::fromUtf8("∞")); break; } - case TorrentModelItem::TR_TIME_ELAPSED: { + case TorrentModel::TR_TIME_ELAPSED: { QItemDelegate::drawBackground(painter, opt, index); QString txt = Utils::Misc::userFriendlyDuration(index.data().toLongLong()); qlonglong seeding_time = index.data(Qt::UserRole).toLongLong(); @@ -163,13 +163,13 @@ void TransferListDelegate::paint(QPainter * painter, const QStyleOptionViewItem QItemDelegate::drawDisplay(painter, opt, opt.rect, txt); break; } - case TorrentModelItem::TR_ADD_DATE: - case TorrentModelItem::TR_SEED_DATE: + case TorrentModel::TR_ADD_DATE: + case TorrentModel::TR_SEED_DATE: QItemDelegate::drawBackground(painter, opt, index); QItemDelegate::drawDisplay(painter, opt, opt.rect, index.data().toDateTime().toLocalTime().toString(Qt::DefaultLocaleShortDate)); break; - case TorrentModelItem::TR_RATIO_LIMIT: - case TorrentModelItem::TR_RATIO: { + case TorrentModel::TR_RATIO_LIMIT: + case TorrentModel::TR_RATIO: { QItemDelegate::drawBackground(painter, opt, index); opt.displayAlignment = Qt::AlignRight | Qt::AlignVCenter; const qreal ratio = index.data().toDouble(); @@ -177,7 +177,7 @@ void TransferListDelegate::paint(QPainter * painter, const QStyleOptionViewItem ((ratio == -1) || (ratio > BitTorrent::TorrentHandle::MAX_RATIO)) ? QString::fromUtf8("∞") : Utils::String::fromDouble(ratio, 2)); break; } - case TorrentModelItem::TR_PRIORITY: { + case TorrentModel::TR_PRIORITY: { const int priority = index.data().toInt(); opt.displayAlignment = Qt::AlignRight | Qt::AlignVCenter; if (priority > 0) @@ -188,7 +188,7 @@ void TransferListDelegate::paint(QPainter * painter, const QStyleOptionViewItem } break; } - case TorrentModelItem::TR_PROGRESS: { + case TorrentModel::TR_PROGRESS: { QStyleOptionProgressBarV2 newopt; qreal progress = index.data().toDouble()*100.; newopt.rect = opt.rect; @@ -211,7 +211,7 @@ void TransferListDelegate::paint(QPainter * painter, const QStyleOptionViewItem #endif break; } - case TorrentModelItem::TR_LAST_ACTIVITY: { + case TorrentModel::TR_LAST_ACTIVITY: { QString elapsedString; long long elapsed = index.data().toLongLong(); QItemDelegate::drawBackground(painter, opt, index); diff --git a/src/gui/transferlistfilterswidget.cpp b/src/gui/transferlistfilterswidget.cpp index 7e4716986..c25163a77 100644 --- a/src/gui/transferlistfilterswidget.cpp +++ b/src/gui/transferlistfilterswidget.cpp @@ -50,6 +50,7 @@ #include "core/torrentfilter.h" #include "core/bittorrent/trackerentry.h" #include "core/bittorrent/session.h" +#include "core/bittorrent/torrenthandle.h" #include "core/net/downloadmanager.h" #include "core/net/downloadhandler.h" #include "core/utils/misc.h" @@ -70,8 +71,9 @@ FiltersBase::FiltersBase(QWidget *parent, TransferListWidget *transferList) connect(this, SIGNAL(customContextMenuRequested(QPoint)), SLOT(showMenu(QPoint))); connect(this, SIGNAL(currentRowChanged(int)), SLOT(applyFilter(int))); - connect(transferList->getSourceModel(), SIGNAL(torrentAdded(TorrentModelItem*)), SLOT(handleNewTorrent(TorrentModelItem*))); - connect(transferList->getSourceModel(), SIGNAL(torrentAboutToBeRemoved(TorrentModelItem*)), SLOT(torrentAboutToBeDeleted(TorrentModelItem*))); + + connect(BitTorrent::Session::instance(), SIGNAL(torrentAdded(BitTorrent::TorrentHandle *const)), SLOT(handleNewTorrent(BitTorrent::TorrentHandle *const))); + connect(BitTorrent::Session::instance(), SIGNAL(torrentAboutToBeRemoved(BitTorrent::TorrentHandle *const)), SLOT(torrentAboutToBeDeleted(BitTorrent::TorrentHandle *const))); } QSize FiltersBase::sizeHint() const @@ -165,9 +167,9 @@ void StatusFiltersWidget::applyFilter(int row) transferList->applyStatusFilter(row); } -void StatusFiltersWidget::handleNewTorrent(TorrentModelItem*) {} +void StatusFiltersWidget::handleNewTorrent(BitTorrent::TorrentHandle *const) {} -void StatusFiltersWidget::torrentAboutToBeDeleted(TorrentModelItem*) {} +void StatusFiltersWidget::torrentAboutToBeDeleted(BitTorrent::TorrentHandle *const) {} LabelFiltersList::LabelFiltersList(QWidget *parent, TransferListWidget *transferList) : FiltersBase(parent, transferList) @@ -175,7 +177,8 @@ LabelFiltersList::LabelFiltersList(QWidget *parent, TransferListWidget *transfer , m_totalLabeled(0) { setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); - connect(transferList->getSourceModel(), SIGNAL(torrentChangedLabel(TorrentModelItem*,QString,QString)), SLOT(torrentChangedLabel(TorrentModelItem*, QString, QString))); + + connect(BitTorrent::Session::instance(), SIGNAL(torrentLabelChanged(BitTorrent::TorrentHandle *const, QString)), SLOT(torrentChangedLabel(BitTorrent::TorrentHandle *const, QString))); // Add Label filters QListWidgetItem *allLabels = new QListWidgetItem(this); @@ -309,12 +312,12 @@ void LabelFiltersList::removeUnusedLabels() updateGeometry(); } -void LabelFiltersList::torrentChangedLabel(TorrentModelItem *torrentItem, QString old_label, QString new_label) +void LabelFiltersList::torrentChangedLabel(BitTorrent::TorrentHandle *const torrent, const QString &oldLabel) { - Q_UNUSED(torrentItem); - qDebug("Torrent label changed from %s to %s", qPrintable(old_label), qPrintable(new_label)); - removeItem(old_label); - addItem(new_label, true); + qDebug("Torrent label changed from %s to %s", qPrintable(oldLabel), qPrintable(torrent->label())); + removeItem(oldLabel); + QString newLabel = torrent->label(); + addItem(newLabel, true); } void LabelFiltersList::showMenu(QPoint) @@ -384,21 +387,22 @@ void LabelFiltersList::applyFilter(int row) } } -void LabelFiltersList::handleNewTorrent(TorrentModelItem* torrentItem) +void LabelFiltersList::handleNewTorrent(BitTorrent::TorrentHandle *const torrent) { + Q_ASSERT(torrent); ++m_totalTorrents; - QString label = torrentItem->data(TorrentModelItem::TR_LABEL).toString(); + QString label = torrent->label(); addItem(label, true); + // FIXME: Drop this confusion. // labelFilters->addItem() may have changed the label, update the model accordingly. - torrentItem->setData(TorrentModelItem::TR_LABEL, label); + torrent->setLabel(label); } -void LabelFiltersList::torrentAboutToBeDeleted(TorrentModelItem* torrentItem) +void LabelFiltersList::torrentAboutToBeDeleted(BitTorrent::TorrentHandle *const torrent) { + Q_ASSERT(torrent); --m_totalTorrents; - Q_ASSERT(torrentItem); - QString label = torrentItem->data(TorrentModelItem::TR_LABEL).toString(); - removeItem(label); + removeItem(torrent->label()); } QString LabelFiltersList::labelFromRow(int row) const @@ -681,11 +685,10 @@ void TrackerFiltersList::applyFilter(int row) transferList->applyTrackerFilter(getHashes(row)); } -void TrackerFiltersList::handleNewTorrent(TorrentModelItem* torrentItem) +void TrackerFiltersList::handleNewTorrent(BitTorrent::TorrentHandle *const torrent) { - BitTorrent::TorrentHandle *const handle = torrentItem->torrentHandle(); - QString hash = handle->hash(); - QList trackers = handle->trackers(); + QString hash = torrent->hash(); + QList trackers = torrent->trackers(); foreach (const BitTorrent::TrackerEntry &tracker, trackers) addItem(tracker.url(), hash); @@ -696,11 +699,10 @@ void TrackerFiltersList::handleNewTorrent(TorrentModelItem* torrentItem) item(0)->setText(tr("All (%1)", "this is for the tracker filter").arg(++m_totalTorrents)); } -void TrackerFiltersList::torrentAboutToBeDeleted(TorrentModelItem* torrentItem) +void TrackerFiltersList::torrentAboutToBeDeleted(BitTorrent::TorrentHandle *const torrent) { - BitTorrent::TorrentHandle *const handle = torrentItem->torrentHandle(); - QString hash = handle->hash(); - QList trackers = handle->trackers(); + QString hash = torrent->hash(); + QList trackers = torrent->trackers(); foreach (const BitTorrent::TrackerEntry &tracker, trackers) removeItem(tracker.url(), hash); diff --git a/src/gui/transferlistfilterswidget.h b/src/gui/transferlistfilterswidget.h index 4e670b2fc..63babc89e 100644 --- a/src/gui/transferlistfilterswidget.h +++ b/src/gui/transferlistfilterswidget.h @@ -40,7 +40,6 @@ class QCheckBox; QT_END_NAMESPACE class TransferListWidget; -class TorrentModelItem; namespace BitTorrent { @@ -68,8 +67,8 @@ protected: private slots: virtual void showMenu(QPoint) = 0; virtual void applyFilter(int row) = 0; - virtual void handleNewTorrent(TorrentModelItem* torrentItem) = 0; - virtual void torrentAboutToBeDeleted(TorrentModelItem* torrentItem) = 0; + virtual void handleNewTorrent(BitTorrent::TorrentHandle *const) = 0; + virtual void torrentAboutToBeDeleted(BitTorrent::TorrentHandle *const) = 0; }; class StatusFiltersWidget: public FiltersBase @@ -88,8 +87,8 @@ private: // No need to redeclare them here as slots. virtual void showMenu(QPoint); virtual void applyFilter(int row); - virtual void handleNewTorrent(TorrentModelItem*); - virtual void torrentAboutToBeDeleted(TorrentModelItem*); + virtual void handleNewTorrent(BitTorrent::TorrentHandle *const); + virtual void torrentAboutToBeDeleted(BitTorrent::TorrentHandle *const); }; class LabelFiltersList: public FiltersBase @@ -106,7 +105,7 @@ private slots: void removeItem(const QString &label); void removeSelectedLabel(); void removeUnusedLabels(); - void torrentChangedLabel(TorrentModelItem *torrentItem, QString old_label, QString new_label); + void torrentChangedLabel(BitTorrent::TorrentHandle *const torrent, const QString &oldLabel); private: @@ -114,8 +113,8 @@ private: // No need to redeclare them here as slots. virtual void showMenu(QPoint); virtual void applyFilter(int row); - virtual void handleNewTorrent(TorrentModelItem* torrentItem); - virtual void torrentAboutToBeDeleted(TorrentModelItem* torrentItem); + virtual void handleNewTorrent(BitTorrent::TorrentHandle *const torrent); + virtual void torrentAboutToBeDeleted(BitTorrent::TorrentHandle *const torrent); QString labelFromRow(int row) const; int rowFromLabel(const QString &label) const; @@ -152,8 +151,8 @@ private: // No need to redeclare them here as slots. virtual void showMenu(QPoint); virtual void applyFilter(int row); - virtual void handleNewTorrent(TorrentModelItem* torrentItem); - virtual void torrentAboutToBeDeleted(TorrentModelItem* torrentItem); + virtual void handleNewTorrent(BitTorrent::TorrentHandle *const torrent); + virtual void torrentAboutToBeDeleted(BitTorrent::TorrentHandle *const torrent); QString trackerFromRow(int row) const; int rowFromTracker(const QString &tracker) const; QString getHost(const QString &trakcer) const; diff --git a/src/gui/transferlistsortmodel.cpp b/src/gui/transferlistsortmodel.cpp index 50652f7a9..efbce598b 100644 --- a/src/gui/transferlistsortmodel.cpp +++ b/src/gui/transferlistsortmodel.cpp @@ -75,7 +75,7 @@ bool TransferListSortModel::lessThan(const QModelIndex &left, const QModelIndex { const int column = sortColumn(); - if (column == TorrentModelItem::TR_NAME) { + if (column == TorrentModel::TR_NAME) { QVariant vL = left.data(); QVariant vR = right.data(); if (!vL.isValid() || !vR.isValid() || (vL == vR)) @@ -87,7 +87,7 @@ bool TransferListSortModel::lessThan(const QModelIndex &left, const QModelIndex return QSortFilterProxyModel::lessThan(left, right); } - else if (column == TorrentModelItem::TR_ADD_DATE || column == TorrentModelItem::TR_SEED_DATE || column == TorrentModelItem::TR_SEEN_COMPLETE_DATE) { + else if (column == TorrentModel::TR_ADD_DATE || column == TorrentModel::TR_SEED_DATE || column == TorrentModel::TR_SEEN_COMPLETE_DATE) { QDateTime vL = left.data().toDateTime(); QDateTime vR = right.data().toDateTime(); @@ -97,10 +97,10 @@ bool TransferListSortModel::lessThan(const QModelIndex &left, const QModelIndex return vL < vR; } - else if (column == TorrentModelItem::TR_PRIORITY) { + else if (column == TorrentModel::TR_PRIORITY) { return lowerPositionThan(left, right); } - else if (column == TorrentModelItem::TR_PEERS || column == TorrentModelItem::TR_SEEDS) { + else if (column == TorrentModel::TR_PEERS || column == TorrentModel::TR_SEEDS) { int left_active = left.data().toInt(); int left_total = left.data(Qt::UserRole).toInt(); int right_active = right.data().toInt(); @@ -116,10 +116,10 @@ bool TransferListSortModel::lessThan(const QModelIndex &left, const QModelIndex return (left_active < right_active); } } - else if (column == TorrentModelItem::TR_ETA) { + else if (column == TorrentModel::TR_ETA) { TorrentModel *model = qobject_cast(sourceModel()); - const int prioL = model->data(model->index(left.row(), TorrentModelItem::TR_PRIORITY)).toInt(); - const int prioR = model->data(model->index(right.row(), TorrentModelItem::TR_PRIORITY)).toInt(); + const int prioL = model->data(model->index(left.row(), TorrentModel::TR_PRIORITY)).toInt(); + const int prioR = model->data(model->index(right.row(), TorrentModel::TR_PRIORITY)).toInt(); const qlonglong etaL = left.data().toLongLong(); const qlonglong etaR = right.data().toLongLong(); const bool ascend = (sortOrder() == Qt::AscendingOrder); @@ -144,8 +144,8 @@ bool TransferListSortModel::lessThan(const QModelIndex &left, const QModelIndex if (invalidL && invalidR) { if (seedingL) { //Both seeding - QDateTime dateL = model->data(model->index(left.row(), TorrentModelItem::TR_SEED_DATE)).toDateTime(); - QDateTime dateR = model->data(model->index(right.row(), TorrentModelItem::TR_SEED_DATE)).toDateTime(); + QDateTime dateL = model->data(model->index(left.row(), TorrentModel::TR_SEED_DATE)).toDateTime(); + QDateTime dateR = model->data(model->index(right.row(), TorrentModel::TR_SEED_DATE)).toDateTime(); //not valid dates should be sorted at the bottom. if (!dateL.isValid()) return false; @@ -164,7 +164,7 @@ bool TransferListSortModel::lessThan(const QModelIndex &left, const QModelIndex return !invalidL; } } - else if (column == TorrentModelItem::TR_LAST_ACTIVITY) { + else if (column == TorrentModel::TR_LAST_ACTIVITY) { const qlonglong vL = left.data().toLongLong(); const qlonglong vR = right.data().toLongLong(); @@ -173,7 +173,7 @@ bool TransferListSortModel::lessThan(const QModelIndex &left, const QModelIndex return vL < vR; } - else if (column == TorrentModelItem::TR_RATIO_LIMIT) { + else if (column == TorrentModel::TR_RATIO_LIMIT) { const qreal vL = left.data().toDouble(); const qreal vR = right.data().toDouble(); @@ -194,8 +194,8 @@ bool TransferListSortModel::lowerPositionThan(const QModelIndex &left, const QMo const TorrentModel *model = dynamic_cast(sourceModel()); // Sort according to TR_PRIORITY - const int queueL = model->data(model->index(left.row(), TorrentModelItem::TR_PRIORITY)).toInt(); - const int queueR = model->data(model->index(right.row(), TorrentModelItem::TR_PRIORITY)).toInt(); + const int queueL = model->data(model->index(left.row(), TorrentModel::TR_PRIORITY)).toInt(); + const int queueR = model->data(model->index(right.row(), TorrentModel::TR_PRIORITY)).toInt(); if ((queueL > 0) || (queueR > 0)) { if ((queueL > 0) && (queueR > 0)) return queueL < queueR; @@ -204,8 +204,8 @@ bool TransferListSortModel::lowerPositionThan(const QModelIndex &left, const QMo } // Sort according to TR_SEED_DATE - const QDateTime dateL = model->data(model->index(left.row(), TorrentModelItem::TR_SEED_DATE)).toDateTime(); - const QDateTime dateR = model->data(model->index(right.row(), TorrentModelItem::TR_SEED_DATE)).toDateTime(); + const QDateTime dateL = model->data(model->index(left.row(), TorrentModel::TR_SEED_DATE)).toDateTime(); + const QDateTime dateR = model->data(model->index(right.row(), TorrentModel::TR_SEED_DATE)).toDateTime(); if (dateL.isValid() && dateR.isValid()) { if (dateL != dateR) return dateL < dateR; @@ -216,8 +216,8 @@ bool TransferListSortModel::lowerPositionThan(const QModelIndex &left, const QMo return true; // Finally, sort by hash - const QString hashL(model->torrentHash(left.row())); - const QString hashR(model->torrentHash(right.row())); + const QString hashL(model->torrentHandle(model->index(left.row()))->hash()); + const QString hashR(model->torrentHandle(model->index(right.row()))->hash()); return hashL < hashR; } diff --git a/src/gui/transferlistwidget.cpp b/src/gui/transferlistwidget.cpp index a7511d762..f8644bc99 100644 --- a/src/gui/transferlistwidget.cpp +++ b/src/gui/transferlistwidget.cpp @@ -61,6 +61,8 @@ #include "autoexpandabledialog.h" #include "transferlistsortmodel.h" +static QStringList extractHashes(const QList &torrents); + TransferListWidget::TransferListWidget(QWidget *parent, MainWindow *main_window) : QTreeView(parent) , main_window(main_window) @@ -80,7 +82,7 @@ TransferListWidget::TransferListWidget(QWidget *parent, MainWindow *main_window) nameFilterModel = new TransferListSortModel(); nameFilterModel->setDynamicSortFilter(true); nameFilterModel->setSourceModel(listModel); - nameFilterModel->setFilterKeyColumn(TorrentModelItem::TR_NAME); + nameFilterModel->setFilterKeyColumn(TorrentModel::TR_NAME); nameFilterModel->setFilterRole(Qt::DisplayRole); nameFilterModel->setSortCaseSensitivity(Qt::CaseInsensitive); @@ -101,40 +103,40 @@ TransferListWidget::TransferListWidget(QWidget *parent, MainWindow *main_window) // Default hidden columns if (!column_loaded) { - 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); - setColumnHidden(TorrentModelItem::TR_AMOUNT_DOWNLOADED, true); - setColumnHidden(TorrentModelItem::TR_AMOUNT_UPLOADED, true); - setColumnHidden(TorrentModelItem::TR_AMOUNT_DOWNLOADED_SESSION, true); - setColumnHidden(TorrentModelItem::TR_AMOUNT_UPLOADED_SESSION, true); - setColumnHidden(TorrentModelItem::TR_AMOUNT_LEFT, true); - setColumnHidden(TorrentModelItem::TR_TIME_ELAPSED, true); - setColumnHidden(TorrentModelItem::TR_SAVE_PATH, true); - setColumnHidden(TorrentModelItem::TR_COMPLETED, true); - setColumnHidden(TorrentModelItem::TR_RATIO_LIMIT, true); - setColumnHidden(TorrentModelItem::TR_SEEN_COMPLETE_DATE, true); - setColumnHidden(TorrentModelItem::TR_LAST_ACTIVITY, true); - setColumnHidden(TorrentModelItem::TR_TOTAL_SIZE, true); + setColumnHidden(TorrentModel::TR_ADD_DATE, true); + setColumnHidden(TorrentModel::TR_SEED_DATE, true); + setColumnHidden(TorrentModel::TR_UPLIMIT, true); + setColumnHidden(TorrentModel::TR_DLLIMIT, true); + setColumnHidden(TorrentModel::TR_TRACKER, true); + setColumnHidden(TorrentModel::TR_AMOUNT_DOWNLOADED, true); + setColumnHidden(TorrentModel::TR_AMOUNT_UPLOADED, true); + setColumnHidden(TorrentModel::TR_AMOUNT_DOWNLOADED_SESSION, true); + setColumnHidden(TorrentModel::TR_AMOUNT_UPLOADED_SESSION, true); + setColumnHidden(TorrentModel::TR_AMOUNT_LEFT, true); + setColumnHidden(TorrentModel::TR_TIME_ELAPSED, true); + setColumnHidden(TorrentModel::TR_SAVE_PATH, true); + setColumnHidden(TorrentModel::TR_COMPLETED, true); + setColumnHidden(TorrentModel::TR_RATIO_LIMIT, true); + setColumnHidden(TorrentModel::TR_SEEN_COMPLETE_DATE, true); + setColumnHidden(TorrentModel::TR_LAST_ACTIVITY, true); + setColumnHidden(TorrentModel::TR_TOTAL_SIZE, true); } //Ensure that at least one column is visible at all times bool atLeastOne = false; - for (unsigned int i = 0; itorrentRow(hash); -} - -inline QString TransferListWidget::getHashFromRow(int row) const -{ - return listModel->torrentHash(row); -} - inline QModelIndex TransferListWidget::mapToSource(const QModelIndex &index) const { Q_ASSERT(index.isValid()); @@ -204,9 +196,7 @@ inline QModelIndex TransferListWidget::mapFromSource(const QModelIndex &index) c void TransferListWidget::torrentDoubleClicked(const QModelIndex& index) { - const int row = mapToSource(index).row(); - const QString hash = getHashFromRow(row); - BitTorrent::TorrentHandle *const torrent = BitTorrent::Session::instance()->findTorrent(hash); + BitTorrent::TorrentHandle *const torrent = listModel->torrentHandle(mapToSource(index)); if (!torrent) return; int action; @@ -227,37 +217,30 @@ void TransferListWidget::torrentDoubleClicked(const QModelIndex& index) } } -QStringList TransferListWidget::getSelectedTorrentsHashes() const +QList TransferListWidget::getSelectedTorrents() const { - QStringList hashes; - const QModelIndexList selectedIndexes = selectionModel()->selectedRows(); - foreach (const QModelIndex &index, selectedIndexes) - hashes << getHashFromRow(mapToSource(index).row()); - return hashes; + QList torrents; + foreach (const QModelIndex &index, selectionModel()->selectedRows()) + torrents << listModel->torrentHandle(mapToSource(index)); + + return torrents; } void TransferListWidget::setSelectedTorrentsLocation() { - const QStringList hashes = getSelectedTorrentsHashes(); - if (hashes.isEmpty()) return; - - BitTorrent::TorrentHandle *const firstTorrent = BitTorrent::Session::instance()->findTorrent(hashes.first()); - if (!firstTorrent) return; + const QList torrents = getSelectedTorrents(); + if (torrents.isEmpty()) return; QString dir; - const QDir saveDir(firstTorrent->savePath()); + const QDir saveDir(torrents[0]->savePath()); qDebug("Old save path is %s", qPrintable(saveDir.absolutePath())); dir = QFileDialog::getExistingDirectory(this, tr("Choose save path"), saveDir.absolutePath(), QFileDialog::DontConfirmOverwrite | QFileDialog::ShowDirsOnly | QFileDialog::HideNameFilterDetails); if (!dir.isNull()) { qDebug("New path is %s", qPrintable(dir)); - foreach (const QString &hash, hashes) { + foreach (BitTorrent::TorrentHandle *const torrent, torrents) { // Actually move storage - BitTorrent::TorrentHandle *const torrent = BitTorrent::Session::instance()->findTorrent(hash); - if (!torrent) continue; - torrent->move(Utils::Fs::expandPathAbs(dir)); - main_window->getProperties()->updateSavePath(torrent); } } } @@ -276,27 +259,20 @@ void TransferListWidget::resumeAllTorrents() void TransferListWidget::startSelectedTorrents() { - foreach (const QString &hash, getSelectedTorrentsHashes()) { - BitTorrent::TorrentHandle *const torrent = BitTorrent::Session::instance()->findTorrent(hash); - if (torrent) - torrent->resume(); - } + foreach (BitTorrent::TorrentHandle *const torrent, getSelectedTorrents()) + torrent->resume(); } void TransferListWidget::forceStartSelectedTorrents() { - foreach (const QString &hash, getSelectedTorrentsHashes()) { - BitTorrent::TorrentHandle *const torrent = BitTorrent::Session::instance()->findTorrent(hash); - if (torrent) - torrent->resume(true); - } + foreach (BitTorrent::TorrentHandle *const torrent, getSelectedTorrents()) + torrent->resume(true); } void TransferListWidget::startVisibleTorrents() { for (int i = 0; i < nameFilterModel->rowCount(); ++i) { - const int row = mapToSource(nameFilterModel->index(i, 0)).row(); - BitTorrent::TorrentHandle *const torrent = BitTorrent::Session::instance()->findTorrent(getHashFromRow(row)); + BitTorrent::TorrentHandle *const torrent = listModel->torrentHandle(mapToSource(nameFilterModel->index(i, 0))); if (torrent) torrent->resume(); } @@ -304,18 +280,14 @@ void TransferListWidget::startVisibleTorrents() void TransferListWidget::pauseSelectedTorrents() { - foreach (const QString &hash, getSelectedTorrentsHashes()) { - BitTorrent::TorrentHandle *const torrent = BitTorrent::Session::instance()->findTorrent(hash); - if (torrent) - torrent->pause(); - } + foreach (BitTorrent::TorrentHandle *const torrent, getSelectedTorrents()) + torrent->pause(); } void TransferListWidget::pauseVisibleTorrents() { for (int i = 0; i < nameFilterModel->rowCount(); ++i) { - const int row = mapToSource(nameFilterModel->index(i, 0)).row(); - BitTorrent::TorrentHandle *const torrent = BitTorrent::Session::instance()->findTorrent(getHashFromRow(row)); + BitTorrent::TorrentHandle *const torrent = listModel->torrentHandle(mapToSource(nameFilterModel->index(i, 0))); if (torrent) torrent->pause(); } @@ -324,117 +296,103 @@ void TransferListWidget::pauseVisibleTorrents() void TransferListWidget::deleteSelectedTorrents() { if (main_window->getCurrentTabWidget() != this) return; - const QStringList& hashes = getSelectedTorrentsHashes(); - if (hashes.empty()) return; - BitTorrent::TorrentHandle *const torrent = BitTorrent::Session::instance()->findTorrent(hashes[0]); + const QList torrents = getSelectedTorrents(); + if (torrents.empty()) return; + bool delete_local_files = false; if (Preferences::instance()->confirmTorrentDeletion() && - !DeletionConfirmationDlg::askForDeletionConfirmation(delete_local_files, hashes.size(), torrent->name())) + !DeletionConfirmationDlg::askForDeletionConfirmation(delete_local_files, torrents.size(), torrents[0]->name())) return; - foreach (const QString &hash, hashes) - BitTorrent::Session::instance()->deleteTorrent(hash, delete_local_files); + foreach (BitTorrent::TorrentHandle *const torrent, torrents) + BitTorrent::Session::instance()->deleteTorrent(torrent->hash(), delete_local_files); } void TransferListWidget::deleteVisibleTorrents() { if (nameFilterModel->rowCount() <= 0) return; - QStringList hashes; - for (int i = 0; irowCount(); ++i) { - const int row = mapToSource(nameFilterModel->index(i, 0)).row(); - hashes << getHashFromRow(row); - } - BitTorrent::TorrentHandle *const torrent = BitTorrent::Session::instance()->findTorrent(hashes[0]); + QList torrents; + for (int i = 0; i < nameFilterModel->rowCount(); ++i) + torrents << listModel->torrentHandle(mapToSource(nameFilterModel->index(i, 0))); + bool delete_local_files = false; if (Preferences::instance()->confirmTorrentDeletion() && - !DeletionConfirmationDlg::askForDeletionConfirmation(delete_local_files, hashes.size(), torrent->name())) + !DeletionConfirmationDlg::askForDeletionConfirmation(delete_local_files, torrents.size(), torrents[0]->name())) return; - foreach (const QString &hash, hashes) - BitTorrent::Session::instance()->deleteTorrent(hash, delete_local_files); + foreach (BitTorrent::TorrentHandle *const torrent, torrents) + BitTorrent::Session::instance()->deleteTorrent(torrent->hash(), delete_local_files); } void TransferListWidget::increasePrioSelectedTorrents() { qDebug() << Q_FUNC_INFO; if (main_window->getCurrentTabWidget() == this) - BitTorrent::Session::instance()->increaseTorrentsPriority(getSelectedTorrentsHashes()); + BitTorrent::Session::instance()->increaseTorrentsPriority(extractHashes(getSelectedTorrents())); } void TransferListWidget::decreasePrioSelectedTorrents() { qDebug() << Q_FUNC_INFO; if (main_window->getCurrentTabWidget() == this) - BitTorrent::Session::instance()->decreaseTorrentsPriority(getSelectedTorrentsHashes()); + BitTorrent::Session::instance()->decreaseTorrentsPriority(extractHashes(getSelectedTorrents())); } void TransferListWidget::topPrioSelectedTorrents() { if (main_window->getCurrentTabWidget() == this) - BitTorrent::Session::instance()->topTorrentsPriority(getSelectedTorrentsHashes()); + BitTorrent::Session::instance()->topTorrentsPriority(extractHashes(getSelectedTorrents())); } void TransferListWidget::bottomPrioSelectedTorrents() { if (main_window->getCurrentTabWidget() == this) - BitTorrent::Session::instance()->bottomTorrentsPriority(getSelectedTorrentsHashes()); + BitTorrent::Session::instance()->bottomTorrentsPriority(extractHashes(getSelectedTorrents())); } void TransferListWidget::copySelectedMagnetURIs() const { QStringList magnet_uris; - const QStringList hashes = getSelectedTorrentsHashes(); - foreach (const QString &hash, hashes) { - BitTorrent::TorrentHandle *const torrent = BitTorrent::Session::instance()->findTorrent(hash); - if (torrent) - magnet_uris << torrent->toMagnetUri(); - } + foreach (BitTorrent::TorrentHandle *const torrent, getSelectedTorrents()) + magnet_uris << torrent->toMagnetUri(); + qApp->clipboard()->setText(magnet_uris.join("\n")); } void TransferListWidget::copySelectedNames() const { QStringList torrent_names; - const QStringList hashes = getSelectedTorrentsHashes(); - foreach (const QString &hash, hashes) { - BitTorrent::TorrentHandle *const torrent = BitTorrent::Session::instance()->findTorrent(hash); - if (torrent) - torrent_names << torrent->name(); - } + foreach (BitTorrent::TorrentHandle *const torrent, getSelectedTorrents()) + torrent_names << torrent->name(); + qApp->clipboard()->setText(torrent_names.join("\n")); } void TransferListWidget::hidePriorityColumn(bool hide) { qDebug("hidePriorityColumn(%d)", hide); - setColumnHidden(TorrentModelItem::TR_PRIORITY, hide); - if (!hide && !columnWidth(TorrentModelItem::TR_PRIORITY)) - resizeColumnToContents(TorrentModelItem::TR_PRIORITY); + setColumnHidden(TorrentModel::TR_PRIORITY, hide); + if (!hide && !columnWidth(TorrentModel::TR_PRIORITY)) + resizeColumnToContents(TorrentModel::TR_PRIORITY); } void TransferListWidget::openSelectedTorrentsFolder() const { QSet pathsList; - const QStringList hashes = getSelectedTorrentsHashes(); - foreach (const QString &hash, hashes) { - BitTorrent::TorrentHandle *const torrent = BitTorrent::Session::instance()->findTorrent(hash); - if (torrent) { - QString rootFolder = torrent->rootPath(); - qDebug("Opening path at %s", qPrintable(rootFolder)); - if (!pathsList.contains(rootFolder)) { - pathsList.insert(rootFolder); - openUrl(rootFolder); - } + foreach (BitTorrent::TorrentHandle *const torrent, getSelectedTorrents()) { + QString rootFolder = torrent->rootPath(); + qDebug("Opening path at %s", qPrintable(rootFolder)); + if (!pathsList.contains(rootFolder)) { + pathsList.insert(rootFolder); + openUrl(rootFolder); } } } void TransferListWidget::previewSelectedTorrents() { - const QStringList hashes = getSelectedTorrentsHashes(); - foreach (const QString &hash, hashes) { - BitTorrent::TorrentHandle *const torrent = BitTorrent::Session::instance()->findTorrent(hash); - if (torrent && torrent->hasMetadata()) + foreach (BitTorrent::TorrentHandle *const torrent, getSelectedTorrents()) { + if (torrent->hasMetadata()) new PreviewSelect(this, torrent); } } @@ -444,19 +402,17 @@ void TransferListWidget::setDlLimitSelectedTorrents() QList selected_torrents; bool first = true; bool all_same_limit = true; - const QStringList hashes = getSelectedTorrentsHashes(); - foreach (const QString &hash, hashes) { - BitTorrent::TorrentHandle *const torrent = BitTorrent::Session::instance()->findTorrent(hash); - if (torrent && !torrent->isSeed()) { + foreach (BitTorrent::TorrentHandle *const torrent, getSelectedTorrents()) { + if (!torrent->isSeed()) { selected_torrents << torrent; // Determine current limit for selected torrents if (first) first = false; - else - if (all_same_limit && (torrent->downloadLimit() != selected_torrents.first()->downloadLimit())) - all_same_limit = false; + else if (all_same_limit && (torrent->downloadLimit() != selected_torrents.first()->downloadLimit())) + all_same_limit = false; } } + if (selected_torrents.empty()) return; bool ok = false; @@ -477,19 +433,15 @@ void TransferListWidget::setUpLimitSelectedTorrents() QList selected_torrents; bool first = true; bool all_same_limit = true; - const QStringList hashes = getSelectedTorrentsHashes(); - foreach (const QString &hash, hashes) { - BitTorrent::TorrentHandle *const torrent = BitTorrent::Session::instance()->findTorrent(hash); - if (torrent) { - selected_torrents << torrent; - // Determine current limit for selected torrents - if (first) - first = false; - else - if (all_same_limit && (torrent->uploadLimit() != selected_torrents.first()->uploadLimit())) - all_same_limit = false; - } + foreach (BitTorrent::TorrentHandle *const torrent, getSelectedTorrents()) { + selected_torrents << torrent; + // Determine current limit for selected torrents + if (first) + first = false; + else if (all_same_limit && (torrent->uploadLimit() != selected_torrents.first()->uploadLimit())) + all_same_limit = false; } + if (selected_torrents.empty()) return; bool ok = false; @@ -507,26 +459,20 @@ void TransferListWidget::setUpLimitSelectedTorrents() void TransferListWidget::setMaxRatioSelectedTorrents() { - const QStringList hashes = getSelectedTorrentsHashes(); - if (hashes.isEmpty()) - return; + const QList torrents = getSelectedTorrents(); + if (torrents.isEmpty()) return; + bool useGlobalValue = true; qreal currentMaxRatio = BitTorrent::Session::instance()->globalMaxRatio();; - if (hashes.count() == 1) { - BitTorrent::TorrentHandle *const torrent = BitTorrent::Session::instance()->findTorrent(hashes.first()); - if (torrent) - currentMaxRatio = torrent->maxRatio(&useGlobalValue); - } + if (torrents.count() == 1) + currentMaxRatio = torrents[0]->maxRatio(&useGlobalValue); UpDownRatioDlg dlg(useGlobalValue, currentMaxRatio, BitTorrent::TorrentHandle::MAX_RATIO, this); if (dlg.exec() != QDialog::Accepted) return; - foreach (const QString &hash, hashes) { - BitTorrent::TorrentHandle *const torrent = BitTorrent::Session::instance()->findTorrent(hash); - if (torrent) { - qreal ratio = (dlg.useDefault() ? BitTorrent::TorrentHandle::USE_GLOBAL_RATIO : dlg.ratio()); - torrent->setRatioLimit(ratio); - } + foreach (BitTorrent::TorrentHandle *const torrent, torrents) { + qreal ratio = (dlg.useDefault() ? BitTorrent::TorrentHandle::USE_GLOBAL_RATIO : dlg.ratio()); + torrent->setRatioLimit(ratio); } } @@ -535,12 +481,8 @@ void TransferListWidget::recheckSelectedTorrents() QMessageBox::StandardButton ret = QMessageBox::question(this, tr("Recheck confirmation"), tr("Are you sure you want to recheck the selected torrent(s)?"), QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes); if (ret != QMessageBox::Yes) return; - const QStringList hashes = getSelectedTorrentsHashes(); - foreach (const QString &hash, hashes) { - BitTorrent::TorrentHandle *const torrent = BitTorrent::Session::instance()->findTorrent(hash); - if (torrent) - torrent->forceRecheck(); - } + foreach (BitTorrent::TorrentHandle *const torrent, getSelectedTorrents()) + torrent->forceRecheck(); } // hide/show columns menu @@ -550,7 +492,7 @@ void TransferListWidget::displayDLHoSMenu(const QPoint&) hideshowColumn.setTitle(tr("Column visibility")); QList actions; for (int i = 0; i < listModel->columnCount(); ++i) { - if (!BitTorrent::Session::instance()->isQueueingEnabled() && i == TorrentModelItem::TR_PRIORITY) { + if (!BitTorrent::Session::instance()->isQueueingEnabled() && i == TorrentModel::TR_PRIORITY) { actions.append(0); continue; } @@ -560,7 +502,7 @@ void TransferListWidget::displayDLHoSMenu(const QPoint&) actions.append(myAct); } int visibleCols = 0; - for (unsigned int i = 0; ifindTorrent(hash); - if (torrent && torrent->hasMetadata()) + foreach (BitTorrent::TorrentHandle *const torrent, getSelectedTorrents()) { + if (torrent->hasMetadata()) torrent->setSuperSeeding(!torrent->superSeeding()); } } void TransferListWidget::toggleSelectedTorrentsSequentialDownload() const { - const QStringList hashes = getSelectedTorrentsHashes(); - foreach (const QString &hash, hashes) { - BitTorrent::TorrentHandle *const torrent = BitTorrent::Session::instance()->findTorrent(hash); - if (torrent) - torrent->toggleSequentialDownload(); - } + foreach (BitTorrent::TorrentHandle *const torrent, getSelectedTorrents()) + torrent->toggleSequentialDownload(); } void TransferListWidget::toggleSelectedFirstLastPiecePrio() const { - QStringList hashes = getSelectedTorrentsHashes(); - foreach (const QString &hash, hashes) { - BitTorrent::TorrentHandle *const torrent = BitTorrent::Session::instance()->findTorrent(hash); - if (torrent) - torrent->setFirstLastPiecePriority(!torrent->hasFirstLastPiecePriority()); - } + foreach (BitTorrent::TorrentHandle *const torrent, getSelectedTorrents()) + torrent->setFirstLastPiecePriority(!torrent->hasFirstLastPiecePriority()); } void TransferListWidget::askNewLabelForSelection() @@ -649,9 +581,9 @@ void TransferListWidget::renameSelectedTorrent() const QModelIndexList selectedIndexes = selectionModel()->selectedRows(); if (selectedIndexes.size() != 1) return; if (!selectedIndexes.first().isValid()) return; - QModelIndex mi = listModel->index(mapToSource(selectedIndexes.first()).row(), TorrentModelItem::TR_NAME); - const QString hash = getHashFromRow(mi.row()); - BitTorrent::TorrentHandle *const torrent = BitTorrent::Session::instance()->findTorrent(hash); + + const QModelIndex mi = listModel->index(mapToSource(selectedIndexes.first()).row(), TorrentModel::TR_NAME); + BitTorrent::TorrentHandle *const torrent = listModel->torrentHandle(mi); if (!torrent) return; // Ask for a new Name @@ -666,19 +598,15 @@ void TransferListWidget::renameSelectedTorrent() void TransferListWidget::setSelectionLabel(QString label) { - const QStringList& hashes = getSelectedTorrentsHashes(); - foreach (const QString &hash, hashes) { - Q_ASSERT(!hash.isEmpty()); - const int row = getRowFromHash(hash); - listModel->setData(listModel->index(row, TorrentModelItem::TR_LABEL), QVariant(label), Qt::DisplayRole); - } + foreach (const QModelIndex &index, selectionModel()->selectedRows()) + listModel->setData(listModel->index(mapToSource(index).row(), TorrentModel::TR_LABEL), label, Qt::DisplayRole); } void TransferListWidget::removeLabelFromRows(QString label) { for (int i = 0; i < listModel->rowCount(); ++i) { - if (listModel->data(listModel->index(i, TorrentModelItem::TR_LABEL)) == label) { - listModel->setData(listModel->index(i, TorrentModelItem::TR_LABEL), "", Qt::DisplayRole); + if (listModel->data(listModel->index(i, TorrentModel::TR_LABEL)) == label) { + listModel->setData(listModel->index(i, TorrentModel::TR_LABEL), "", Qt::DisplayRole); } } } @@ -750,9 +678,8 @@ void TransferListWidget::displayListMenu(const QPoint&) qDebug("Displaying menu"); foreach (const QModelIndex &index, selectedIndexes) { // Get the file name - QString hash = getHashFromRow(mapToSource(index).row()); // Get handle and pause the torrent - torrent = BitTorrent::Session::instance()->findTorrent(hash); + torrent = listModel->torrentHandle(mapToSource(index)); if (!torrent) continue; if (torrent->hasMetadata()) @@ -907,8 +834,7 @@ void TransferListWidget::currentChanged(const QModelIndex& current, const QModel qDebug("CURRENT CHANGED"); BitTorrent::TorrentHandle *torrent = 0; if (current.isValid()) { - const int row = mapToSource(current).row(); - torrent = BitTorrent::Session::instance()->findTorrent(getHashFromRow(row)); + torrent = listModel->torrentHandle(mapToSource(current)); // Scroll Fix scrollTo(current); } @@ -946,8 +872,8 @@ void TransferListWidget::applyStatusFilter(int f) nameFilterModel->setStatusFilter(static_cast(f)); // 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, TorrentModelItem::TR_NAME).data().toString())); - selectionModel()->setCurrentIndex(nameFilterModel->index(0, TorrentModelItem::TR_NAME), QItemSelectionModel::SelectCurrent | QItemSelectionModel::Rows); + qDebug("Nothing is selected, selecting first row: %s", qPrintable(nameFilterModel->index(0, TorrentModel::TR_NAME).data().toString())); + selectionModel()->setCurrentIndex(nameFilterModel->index(0, TorrentModel::TR_NAME), QItemSelectionModel::SelectCurrent | QItemSelectionModel::Rows); } } @@ -964,3 +890,11 @@ bool TransferListWidget::loadSettings() return ok; } +QStringList extractHashes(const QList &torrents) +{ + QStringList hashes; + foreach (BitTorrent::TorrentHandle *const torrent, torrents) + hashes << torrent->hash(); + + return hashes; +} diff --git a/src/gui/transferlistwidget.h b/src/gui/transferlistwidget.h index da1469702..67261dd63 100644 --- a/src/gui/transferlistwidget.h +++ b/src/gui/transferlistwidget.h @@ -95,12 +95,10 @@ public slots: void renameSelectedTorrent(); protected: - int getRowFromHash(QString hash) const; - QString getHashFromRow(int row) const; QModelIndex mapToSource(const QModelIndex &index) const; QModelIndex mapFromSource(const QModelIndex &index) const; bool loadSettings(); - QStringList getSelectedTorrentsHashes() const; + QList getSelectedTorrents() const; protected slots: void torrentDoubleClicked(const QModelIndex& index);