Browse Source

Merge pull request #3187 from glassez/model

Improve TorrentModel class (Issue #2433).
adaptive-webui-19844
sledgehammer999 10 years ago
parent
commit
bc97208516
  1. 1
      src/core/bittorrent/private/sessionprivate.h
  2. 5
      src/core/bittorrent/session.cpp
  3. 2
      src/core/bittorrent/session.h
  4. 10
      src/core/bittorrent/torrenthandle.cpp
  5. 1
      src/core/bittorrent/torrenthandle.h
  6. 2
      src/gui/mainwindow.cpp
  7. 2
      src/gui/properties/propertieswidget.h
  8. 644
      src/gui/torrentmodel.cpp
  9. 99
      src/gui/torrentmodel.h
  10. 48
      src/gui/transferlistdelegate.cpp
  11. 52
      src/gui/transferlistfilterswidget.cpp
  12. 19
      src/gui/transferlistfilterswidget.h
  13. 34
      src/gui/transferlistsortmodel.cpp
  14. 318
      src/gui/transferlistwidget.cpp
  15. 4
      src/gui/transferlistwidget.h

1
src/core/bittorrent/private/sessionprivate.h

@ -59,6 +59,7 @@ struct SessionPrivate
virtual void handleTorrentRatioLimitChanged(BitTorrent::TorrentHandle *const torrent) = 0; virtual void handleTorrentRatioLimitChanged(BitTorrent::TorrentHandle *const torrent) = 0;
virtual void handleTorrentSavePathChanged(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 handleTorrentMetadataReceived(BitTorrent::TorrentHandle *const torrent) = 0;
virtual void handleTorrentPaused(BitTorrent::TorrentHandle *const torrent) = 0; virtual void handleTorrentPaused(BitTorrent::TorrentHandle *const torrent) = 0;
virtual void handleTorrentResumed(BitTorrent::TorrentHandle *const torrent) = 0; virtual void handleTorrentResumed(BitTorrent::TorrentHandle *const torrent) = 0;

5
src/core/bittorrent/session.cpp

@ -1631,6 +1631,11 @@ void Session::handleTorrentSavePathChanged(TorrentHandle *const torrent)
emit torrentSavePathChanged(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<TrackerEntry> &newTrackers) void Session::handleTorrentTrackersAdded(TorrentHandle *const torrent, const QList<TrackerEntry> &newTrackers)
{ {
foreach (const TrackerEntry &newTracker, newTrackers) foreach (const TrackerEntry &newTracker, newTrackers)

2
src/core/bittorrent/session.h

@ -195,6 +195,7 @@ namespace BitTorrent
void torrentFinished(BitTorrent::TorrentHandle *const torrent); void torrentFinished(BitTorrent::TorrentHandle *const torrent);
void torrentFinishedChecking(BitTorrent::TorrentHandle *const torrent); void torrentFinishedChecking(BitTorrent::TorrentHandle *const torrent);
void torrentSavePathChanged(BitTorrent::TorrentHandle *const torrent); void torrentSavePathChanged(BitTorrent::TorrentHandle *const torrent);
void torrentLabelChanged(BitTorrent::TorrentHandle *const torrent, const QString &oldLabel);
void allTorrentsFinished(); void allTorrentsFinished();
void metadataLoaded(const BitTorrent::TorrentInfo &info); void metadataLoaded(const BitTorrent::TorrentInfo &info);
void torrentMetadataLoaded(BitTorrent::TorrentHandle *const torrent); void torrentMetadataLoaded(BitTorrent::TorrentHandle *const torrent);
@ -289,6 +290,7 @@ namespace BitTorrent
QString tempPath() const; QString tempPath() const;
void handleTorrentRatioLimitChanged(TorrentHandle *const torrent); void handleTorrentRatioLimitChanged(TorrentHandle *const torrent);
void handleTorrentSavePathChanged(TorrentHandle *const torrent); void handleTorrentSavePathChanged(TorrentHandle *const torrent);
void handleTorrentLabelChanged(TorrentHandle *const torrent, const QString &oldLabel);
void handleTorrentMetadataReceived(TorrentHandle *const torrent); void handleTorrentMetadataReceived(TorrentHandle *const torrent);
void handleTorrentPaused(TorrentHandle *const torrent); void handleTorrentPaused(TorrentHandle *const torrent);
void handleTorrentResumed(TorrentHandle *const torrent); void handleTorrentResumed(TorrentHandle *const torrent);

10
src/core/bittorrent/torrenthandle.cpp

@ -969,6 +969,14 @@ int TorrentHandle::timeSinceDownload() const
return m_nativeStatus.time_since_download; 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 int TorrentHandle::downloadLimit() const
{ {
SAFE_RETURN(int, download_limit, -1) SAFE_RETURN(int, download_limit, -1)
@ -1117,9 +1125,11 @@ void TorrentHandle::setName(const QString &name)
void TorrentHandle::setLabel(const QString &label) void TorrentHandle::setLabel(const QString &label)
{ {
if (m_label != label) { if (m_label != label) {
QString oldLabel = m_label;
m_label = label; m_label = label;
m_needSaveResumeData = true; m_needSaveResumeData = true;
adjustSavePath(); adjustSavePath();
m_session->handleTorrentLabelChanged(this, oldLabel);
} }
} }

1
src/core/bittorrent/torrenthandle.h

@ -241,6 +241,7 @@ namespace BitTorrent
QDateTime completedTime() const; QDateTime completedTime() const;
int timeSinceUpload() const; int timeSinceUpload() const;
int timeSinceDownload() const; int timeSinceDownload() const;
int timeSinceActivity() const;
int downloadLimit() const; int downloadLimit() const;
int uploadLimit() const; int uploadLimit() const;
bool superSeeding() const; bool superSeeding() const;

2
src/gui/mainwindow.cpp

@ -332,8 +332,6 @@ MainWindow::MainWindow(QWidget *parent)
connect(executable_watcher, SIGNAL(fileChanged(QString)), this, SLOT(notifyOfUpdate(QString))); connect(executable_watcher, SIGNAL(fileChanged(QString)), this, SLOT(notifyOfUpdate(QString)));
executable_watcher->addPath(qApp->applicationFilePath()); executable_watcher->addPath(qApp->applicationFilePath());
// Populate the transfer list
transferList->getSourceModel()->populate();
transferList->setFocus(); transferList->setFocus();
// Update the number of torrents (tab) // Update the number of torrents (tab)

2
src/gui/properties/propertieswidget.h

@ -97,7 +97,6 @@ public slots:
void saveSettings(); void saveSettings();
void reloadPreferences(); void reloadPreferences();
void openDoubleClickedFile(const QModelIndex &); void openDoubleClickedFile(const QModelIndex &);
void updateSavePath(BitTorrent::TorrentHandle *const torrent);
void loadTrackers(BitTorrent::TorrentHandle *const torrent); void loadTrackers(BitTorrent::TorrentHandle *const torrent);
private: private:
@ -126,6 +125,7 @@ private:
private slots: private slots:
void filterText(const QString& filter); void filterText(const QString& filter);
void updateSavePath(BitTorrent::TorrentHandle *const torrent);
}; };
#endif // PROPERTIESWIDGET_H #endif // PROPERTIESWIDGET_H

644
src/gui/torrentmodel.cpp

@ -1,6 +1,7 @@
/* /*
* Bittorrent Client using Qt4 and libtorrent. * Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2010 Christophe Dumez * Copyright (C) 2015 Vladimir Golovnev <glassez@yandex.ru>
* Copyright (C) 2010 Christophe Dumez <chris@qbittorrent.org>
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
@ -34,483 +35,416 @@
#include <QIcon> #include <QIcon>
#include "core/bittorrent/session.h" #include "core/bittorrent/session.h"
#include "core/bittorrent/torrenthandle.h"
#include "core/torrentfilter.h" #include "core/torrentfilter.h"
#include "core/utils/fs.h" #include "core/utils/fs.h"
#include "torrentmodel.h" #include "torrentmodel.h"
namespace { static QIcon getIconByState(BitTorrent::TorrentState state);
QIcon get_paused_icon() { static QColor getColorByState(BitTorrent::TorrentState state);
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;
}
QIcon get_stalled_downloading_icon() { static QIcon getPausedIcon();
static QIcon cached = QIcon(":/icons/skin/stalledDL.png"); static QIcon getQueuedIcon();
return cached; 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 bool isDarkTheme();
static QIcon cached = QIcon(":/icons/skin/uploading.png");
return cached;
}
QIcon get_stalled_uploading_icon() { // TorrentModel
static QIcon cached = QIcon(":/icons/skin/stalledUP.png");
return cached;
}
QIcon get_completed_icon() { TorrentModel::TorrentModel(QObject *parent)
static QIcon cached = QIcon(":/icons/skin/completed.png"); : QAbstractListModel(parent)
return cached; {
} // Load the torrents
foreach (BitTorrent::TorrentHandle *const torrent, BitTorrent::Session::instance()->torrents())
QIcon get_checking_icon() { addTorrent(torrent);
static QIcon cached = QIcon(":/icons/skin/checking.png");
return cached;
}
QIcon get_error_icon() { // Listen for torrent changes
static QIcon cached = QIcon(":/icons/skin/error.png"); connect(BitTorrent::Session::instance(), SIGNAL(torrentAdded(BitTorrent::TorrentHandle *const)), SLOT(addTorrent(BitTorrent::TorrentHandle *const)));
return cached; 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() 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)));
QPalette pal = QApplication::palette(); connect(BitTorrent::Session::instance(), SIGNAL(torrentResumed(BitTorrent::TorrentHandle *const)), SLOT(handleTorrentStatusUpdated(BitTorrent::TorrentHandle *const)));
// QPalette::Base is used for the background of the Treeview connect(BitTorrent::Session::instance(), SIGNAL(torrentPaused(BitTorrent::TorrentHandle *const)), SLOT(handleTorrentStatusUpdated(BitTorrent::TorrentHandle *const)));
QColor color = pal.color(QPalette::Active, QPalette::Base); connect(BitTorrent::Session::instance(), SIGNAL(torrentFinishedChecking(BitTorrent::TorrentHandle *const)), SLOT(handleTorrentStatusUpdated(BitTorrent::TorrentHandle *const)));
return (color.lightness() < 127);
}
} }
TorrentModelItem::TorrentModelItem(BitTorrent::TorrentHandle *torrent) int TorrentModel::rowCount(const QModelIndex &index) const
: m_torrent(torrent)
{ {
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) { if (orientation == Qt::Horizontal) {
case BitTorrent::TorrentState::Downloading: if (role == Qt::DisplayRole) {
case BitTorrent::TorrentState::ForcedDownloading: switch(section) {
case BitTorrent::TorrentState::DownloadingMetadata: case TR_PRIORITY: return "#";
return get_downloading_icon(); case TR_NAME: return tr("Name", "i.e: torrent name");
case BitTorrent::TorrentState::Allocating: case TR_SIZE: return tr("Size", "i.e: torrent size");
case BitTorrent::TorrentState::StalledDownloading: case TR_PROGRESS: return tr("Done", "% Done");
return get_stalled_downloading_icon(); case TR_STATUS: return tr("Status", "Torrent status (e.g. downloading, seeding, paused)");
case BitTorrent::TorrentState::StalledUploading: case TR_SEEDS: return tr("Seeds", "i.e. full sources (often untranslated)");
return get_stalled_uploading_icon(); case TR_PEERS: return tr("Peers", "i.e. partial sources (often untranslated)");
case BitTorrent::TorrentState::Uploading: case TR_DLSPEED: return tr("Down Speed", "i.e: Download speed");
case BitTorrent::TorrentState::ForcedUploading: case TR_UPSPEED: return tr("Up Speed", "i.e: Upload speed");
return get_uploading_icon(); case TR_RATIO: return tr("Ratio", "Share ratio");
case BitTorrent::TorrentState::PausedDownloading: case TR_ETA: return tr("ETA", "i.e: Estimated Time of Arrival / Time left");
return get_paused_icon(); case TR_LABEL: return tr("Label");
case BitTorrent::TorrentState::PausedUploading: case TR_ADD_DATE: return tr("Added On", "Torrent was added to transfer list on 01/01/2010 08:00");
return get_completed_icon(); case TR_SEED_DATE: return tr("Completed On", "Torrent was completed on 01/01/2010 08:00");
case BitTorrent::TorrentState::QueuedDownloading: case TR_TRACKER: return tr("Tracker");
case BitTorrent::TorrentState::QueuedUploading: case TR_DLLIMIT: return tr("Down Limit", "i.e: Download limit");
return get_queued_icon(); case TR_UPLIMIT: return tr("Up Limit", "i.e: Upload limit");
case BitTorrent::TorrentState::CheckingDownloading: case TR_AMOUNT_DOWNLOADED: return tr("Downloaded", "Amount of data downloaded (e.g. in MB)");
case BitTorrent::TorrentState::CheckingUploading: case TR_AMOUNT_UPLOADED: return tr("Uploaded", "Amount of data uploaded (e.g. in MB)");
return get_checking_icon(); case TR_AMOUNT_DOWNLOADED_SESSION: return tr("Session Download", "Amount of data downloaded since program open (e.g. in MB)");
case BitTorrent::TorrentState::Unknown: case TR_AMOUNT_UPLOADED_SESSION: return tr("Session Upload", "Amount of data uploaded since program open (e.g. in MB)");
case BitTorrent::TorrentState::Error: case TR_AMOUNT_LEFT: return tr("Remaining", "Amount of data left to download (e.g. in MB)");
return get_error_icon(); case TR_TIME_ELAPSED: return tr("Time Active", "Time (duration) the torrent is active (not paused)");
default: case TR_SAVE_PATH: return tr("Save path", "Torrent save path");
Q_ASSERT(false); case TR_COMPLETED: return tr("Completed", "Amount of data completed (e.g. in MB)");
return get_error_icon(); 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) return QVariant();
{
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
}
} }
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 (!index.isValid()) return QVariant();
if (role != Qt::DisplayRole) return false;
// Label, seed date and Name columns can be edited BitTorrent::TorrentHandle *const torrent = m_torrents.value(index.row());
switch(column) { if (!torrent) return QVariant();
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;
}
QVariant TorrentModelItem::data(int column, int role) const if ((role == Qt::DecorationRole) && (index.column() == TR_NAME))
{ return getIconByState(torrent->state());
if ((role == Qt::DecorationRole) && (column == TR_NAME))
return getIconByState(state());
if (role == Qt::ForegroundRole) if (role == Qt::ForegroundRole)
return getColorByState(state()); return getColorByState(torrent->state());
if ((role != Qt::DisplayRole) && (role != Qt::UserRole)) if ((role != Qt::DisplayRole) && (role != Qt::UserRole))
return QVariant(); return QVariant();
switch(column) { switch(index.column()) {
case TR_NAME: case TR_NAME:
return m_torrent->name(); return torrent->name();
case TR_PRIORITY: case TR_PRIORITY:
return m_torrent->queuePosition(); return torrent->queuePosition();
case TR_SIZE: case TR_SIZE:
return m_torrent->hasMetadata() ? m_torrent->wantedSize() : -1; return torrent->wantedSize();
case TR_PROGRESS: case TR_PROGRESS:
return m_torrent->progress(); return torrent->progress();
case TR_STATUS: case TR_STATUS:
return static_cast<int>(m_torrent->state()); return static_cast<int>(torrent->state());
case TR_SEEDS: case TR_SEEDS:
return (role == Qt::DisplayRole) ? m_torrent->seedsCount() : m_torrent->completeCount(); return (role == Qt::DisplayRole) ? torrent->seedsCount() : torrent->completeCount();
case TR_PEERS: 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: case TR_DLSPEED:
return m_torrent->downloadPayloadRate(); return torrent->downloadPayloadRate();
case TR_UPSPEED: case TR_UPSPEED:
return m_torrent->uploadPayloadRate(); return torrent->uploadPayloadRate();
case TR_ETA: case TR_ETA:
return m_torrent->eta(); return torrent->eta();
case TR_RATIO: case TR_RATIO:
return m_torrent->realRatio(); return torrent->realRatio();
case TR_LABEL: case TR_LABEL:
return m_torrent->label(); return torrent->label();
case TR_ADD_DATE: case TR_ADD_DATE:
return m_torrent->addedTime(); return torrent->addedTime();
case TR_SEED_DATE: case TR_SEED_DATE:
return m_torrent->completedTime(); return torrent->completedTime();
case TR_TRACKER: case TR_TRACKER:
return m_torrent->currentTracker(); return torrent->currentTracker();
case TR_DLLIMIT: case TR_DLLIMIT:
return m_torrent->downloadLimit(); return torrent->downloadLimit();
case TR_UPLIMIT: case TR_UPLIMIT:
return m_torrent->uploadLimit(); return torrent->uploadLimit();
case TR_AMOUNT_DOWNLOADED: case TR_AMOUNT_DOWNLOADED:
return m_torrent->totalDownload(); return torrent->totalDownload();
case TR_AMOUNT_UPLOADED: case TR_AMOUNT_UPLOADED:
return m_torrent->totalUpload(); return torrent->totalUpload();
case TR_AMOUNT_DOWNLOADED_SESSION: case TR_AMOUNT_DOWNLOADED_SESSION:
return m_torrent->totalPayloadDownload(); return torrent->totalPayloadDownload();
case TR_AMOUNT_UPLOADED_SESSION: case TR_AMOUNT_UPLOADED_SESSION:
return m_torrent->totalPayloadUpload(); return torrent->totalPayloadUpload();
case TR_AMOUNT_LEFT: case TR_AMOUNT_LEFT:
return m_torrent->incompletedSize(); return torrent->incompletedSize();
case TR_TIME_ELAPSED: 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: case TR_SAVE_PATH:
return m_torrent->savePathParsed(); return torrent->savePathParsed();
case TR_COMPLETED: case TR_COMPLETED:
return m_torrent->completedSize(); return torrent->completedSize();
case TR_RATIO_LIMIT: case TR_RATIO_LIMIT:
return m_torrent->maxRatio(); return torrent->maxRatio();
case TR_SEEN_COMPLETE_DATE: case TR_SEEN_COMPLETE_DATE:
return m_torrent->lastSeenComplete(); return torrent->lastSeenComplete();
case TR_LAST_ACTIVITY: case TR_LAST_ACTIVITY:
if (m_torrent->isPaused() || m_torrent->isChecking()) if (torrent->isPaused() || torrent->isChecking())
return -1; return -1;
if (m_torrent->timeSinceUpload() < m_torrent->timeSinceDownload()) return torrent->timeSinceActivity();
return m_torrent->timeSinceUpload();
else
return m_torrent->timeSinceDownload();
case TR_TOTAL_SIZE: case TR_TOTAL_SIZE:
return m_torrent->hasMetadata() ? m_torrent->totalSize() : -1; return torrent->totalSize();
default: default:
return QVariant(); return QVariant();
} }
}
BitTorrent::TorrentHandle *TorrentModelItem::torrentHandle() const return QVariant();
{
return m_torrent;
} }
// TORRENT MODEL bool TorrentModel::setData(const QModelIndex &index, const QVariant &value, int role)
TorrentModel::TorrentModel(QObject *parent)
: QAbstractListModel(parent)
{ {
} qDebug() << Q_FUNC_INFO << value;
if (!index.isValid() || (role != Qt::DisplayRole)) return false;
void TorrentModel::populate() qDebug("Index is valid and role is DisplayRole");
{ BitTorrent::TorrentHandle *const torrent = m_torrents.value(index.row());
// Load the torrents if (!torrent) return false;
foreach (BitTorrent::TorrentHandle *const torrent, BitTorrent::Session::instance()->torrents())
addTorrent(torrent);
// Listen for torrent changes // Label, seed date and Name columns can be edited
connect(BitTorrent::Session::instance(), SIGNAL(torrentAdded(BitTorrent::TorrentHandle *const)), SLOT(addTorrent(BitTorrent::TorrentHandle *const))); switch(index.column()) {
connect(BitTorrent::Session::instance(), SIGNAL(torrentAboutToBeRemoved(BitTorrent::TorrentHandle *const)), SLOT(handleTorrentAboutToBeRemoved(BitTorrent::TorrentHandle *const))); case TR_NAME:
connect(BitTorrent::Session::instance(), SIGNAL(torrentStatusUpdated(BitTorrent::TorrentHandle *const)), this, SLOT(handleTorrentStatusUpdated(BitTorrent::TorrentHandle *const))); 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))); return true;
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)));
} }
TorrentModel::~TorrentModel() { void TorrentModel::addTorrent(BitTorrent::TorrentHandle *const torrent)
qDebug() << Q_FUNC_INFO << "ENTER"; {
qDeleteAll(m_items); if (m_torrents.indexOf(torrent) == -1) {
m_items.clear(); const int row = m_torrents.size();
qDebug() << Q_FUNC_INFO << "EXIT"; beginInsertRows(QModelIndex(), row, row);
m_torrents << torrent;
endInsertRows();
}
} }
QVariant TorrentModel::headerData(int section, Qt::Orientation orientation, Qt::ItemFlags TorrentModel::flags(const QModelIndex &index) const
int role) const
{ {
if (orientation == Qt::Horizontal) { if (!index.isValid()) return 0;
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);
}
}
}
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_torrents.value(index.row());
return m_items[index.row()]->data(index.column(), role);
return QVariant();
} }
bool TorrentModel::setData(const QModelIndex &index, const QVariant &value, int role) void TorrentModel::handleTorrentAboutToBeRemoved(BitTorrent::TorrentHandle *const torrent)
{ {
qDebug() << Q_FUNC_INFO << value; const int row = m_torrents.indexOf(torrent);
if (!index.isValid() || (role != Qt::DisplayRole)) return false; if (row >= 0) {
beginRemoveRows(QModelIndex(), row, row);
qDebug("Index is valid and role is DisplayRole"); m_torrents.removeAt(row);
if ((index.row() >= 0) && (index.row() < rowCount()) && (index.column() >= 0) && (index.column() < columnCount())) { endRemoveRows();
bool change = m_items[index.row()]->setData(index.column(), value, role);
if (change)
notifyTorrentChanged(index.row());
return change;
} }
return false;
} }
int TorrentModel::torrentRow(const BitTorrent::InfoHash &hash) const void TorrentModel::handleTorrentStatusUpdated(BitTorrent::TorrentHandle *const torrent)
{ {
int row = 0; const int row = m_torrents.indexOf(torrent);
if (row >= 0)
foreach (TorrentModelItem *const item, m_items) { emit dataChanged(index(row, 0), index(row, columnCount() - 1));
if (item->hash() == hash) return row;
++row;
}
return -1;
} }
void TorrentModel::addTorrent(BitTorrent::TorrentHandle *const torrent) // Static functions
QIcon getIconByState(BitTorrent::TorrentState state)
{ {
if (torrentRow(torrent->hash()) < 0) { switch (state) {
beginInsertTorrent(m_items.size()); case BitTorrent::TorrentState::Downloading:
TorrentModelItem *item = new TorrentModelItem(torrent); case BitTorrent::TorrentState::ForcedDownloading:
connect(item, SIGNAL(labelChanged(QString, QString)), SLOT(handleTorrentLabelChange(QString, QString))); case BitTorrent::TorrentState::DownloadingMetadata:
m_items << item; return getDownloadingIcon();
emit torrentAdded(item); case BitTorrent::TorrentState::Allocating:
endInsertTorrent(); 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()) static QIcon cached = QIcon(":/icons/skin/uploading.png");
return 0; return cached;
// Explicitly mark as editable
return QAbstractListModel::flags(index) | Qt::ItemIsEditable;
} }
void TorrentModel::handleTorrentLabelChange(QString previous, QString current) QIcon getStalledUploadingIcon()
{ {
emit torrentChangedLabel(static_cast<TorrentModelItem*>(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()) static QIcon cached = QIcon(":/icons/skin/completed.png");
return m_items.at(row)->hash(); return cached;
return QString();
} }
BitTorrent::TorrentHandle *TorrentModel::torrentHandle(const QModelIndex &index) const QIcon getCheckingIcon()
{ {
if (index.isValid() && (index.row() >= 0) && (index.row() < rowCount())) static QIcon cached = QIcon(":/icons/skin/checking.png");
return m_items[index.row()]->torrentHandle(); return cached;
return 0;
} }
void TorrentModel::handleTorrentAboutToBeRemoved(BitTorrent::TorrentHandle *const torrent) QIcon getErrorIcon()
{ {
const int row = torrentRow(torrent->hash()); static QIcon cached = QIcon(":/icons/skin/error.png");
qDebug() << Q_FUNC_INFO << row; return cached;
if (row >= 0) {
emit torrentAboutToBeRemoved(m_items.at(row));
beginRemoveTorrent(row);
delete m_items.takeAt(row);
endRemoveTorrent();
}
} }
void TorrentModel::handleTorrentStatusUpdated(BitTorrent::TorrentHandle *const torrent) bool isDarkTheme()
{ {
const int row = torrentRow(torrent->hash()); QPalette pal = QApplication::palette();
if (row >= 0) // QPalette::Base is used for the background of the Treeview
notifyTorrentChanged(row); QColor color = pal.color(QPalette::Active, QPalette::Base);
return (color.lightness() < 127);
} }

99
src/gui/torrentmodel.h

@ -1,6 +1,7 @@
/* /*
* Bittorrent Client using Qt4 and libtorrent. * Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2010 Christophe Dumez * Copyright (C) 2015 Vladimir Golovnev <glassez@yandex.ru>
* Copyright (C) 2010 Christophe Dumez <chris@qbittorrent.org>
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
@ -34,35 +35,11 @@
#include <QAbstractListModel> #include <QAbstractListModel>
#include <QList> #include <QList>
#include "core/bittorrent/torrenthandle.h" namespace BitTorrent
{
class QIcon; class InfoHash;
class TorrentHandle;
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;
};
class TorrentModel : public QAbstractListModel class TorrentModel : public QAbstractListModel
{ {
@ -70,39 +47,59 @@ class TorrentModel : public QAbstractListModel
Q_DISABLE_COPY(TorrentModel) Q_DISABLE_COPY(TorrentModel)
public: 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); explicit TorrentModel(QObject *parent = 0);
~TorrentModel();
inline int rowCount(const QModelIndex& index = QModelIndex()) const { Q_UNUSED(index); return m_items.size(); } int rowCount(const QModelIndex& index = QModelIndex()) const;
int columnCount(const QModelIndex &parent=QModelIndex()) const { Q_UNUSED(parent); return TorrentModelItem::NB_COLUMNS; } int columnCount(const QModelIndex &parent=QModelIndex()) const;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::DisplayRole); bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::DisplayRole);
QVariant headerData(int section, Qt::Orientation orientation, int role) const; 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; Qt::ItemFlags flags(const QModelIndex &index) const;
void populate();
signals: BitTorrent::TorrentHandle *torrentHandle(const QModelIndex &index) const;
void torrentAdded(TorrentModelItem *torrentItem);
void torrentAboutToBeRemoved(TorrentModelItem *torrentItem);
void torrentChangedLabel(TorrentModelItem *torrentItem, QString previous, QString current);
private slots: private slots:
void addTorrent(BitTorrent::TorrentHandle *const torrent); void addTorrent(BitTorrent::TorrentHandle *const torrent);
void notifyTorrentChanged(int row);
void handleTorrentLabelChange(QString previous, QString current);
void handleTorrentAboutToBeRemoved(BitTorrent::TorrentHandle *const torrent); void handleTorrentAboutToBeRemoved(BitTorrent::TorrentHandle *const torrent);
void handleTorrentStatusUpdated(BitTorrent::TorrentHandle *const torrent); void handleTorrentStatusUpdated(BitTorrent::TorrentHandle *const torrent);
private: private:
void beginInsertTorrent(int row); QList<BitTorrent::TorrentHandle *> m_torrents;
void endInsertTorrent();
void beginRemoveTorrent(int row);
void endRemoveTorrent();
private:
QList<TorrentModelItem*> m_items;
}; };
#endif // TORRENTMODEL_H #endif // TORRENTMODEL_H

48
src/gui/transferlistdelegate.cpp

@ -56,27 +56,27 @@ void TransferListDelegate::paint(QPainter * painter, const QStyleOptionViewItem
QStyleOptionViewItemV2 opt = QItemDelegate::setOptions(index, option); QStyleOptionViewItemV2 opt = QItemDelegate::setOptions(index, option);
painter->save(); painter->save();
switch(index.column()) { switch(index.column()) {
case TorrentModelItem::TR_AMOUNT_DOWNLOADED: case TorrentModel::TR_AMOUNT_DOWNLOADED:
case TorrentModelItem::TR_AMOUNT_UPLOADED: case TorrentModel::TR_AMOUNT_UPLOADED:
case TorrentModelItem::TR_AMOUNT_DOWNLOADED_SESSION: case TorrentModel::TR_AMOUNT_DOWNLOADED_SESSION:
case TorrentModelItem::TR_AMOUNT_UPLOADED_SESSION: case TorrentModel::TR_AMOUNT_UPLOADED_SESSION:
case TorrentModelItem::TR_AMOUNT_LEFT: case TorrentModel::TR_AMOUNT_LEFT:
case TorrentModelItem::TR_COMPLETED: case TorrentModel::TR_COMPLETED:
case TorrentModelItem::TR_SIZE: case TorrentModel::TR_SIZE:
case TorrentModelItem::TR_TOTAL_SIZE: { case TorrentModel::TR_TOTAL_SIZE: {
QItemDelegate::drawBackground(painter, opt, index); QItemDelegate::drawBackground(painter, opt, index);
opt.displayAlignment = Qt::AlignRight | Qt::AlignVCenter; opt.displayAlignment = Qt::AlignRight | Qt::AlignVCenter;
QItemDelegate::drawDisplay(painter, opt, option.rect, Utils::Misc::friendlyUnit(index.data().toLongLong())); QItemDelegate::drawDisplay(painter, opt, option.rect, Utils::Misc::friendlyUnit(index.data().toLongLong()));
break; break;
} }
case TorrentModelItem::TR_ETA: { case TorrentModel::TR_ETA: {
QItemDelegate::drawBackground(painter, opt, index); QItemDelegate::drawBackground(painter, opt, index);
opt.displayAlignment = Qt::AlignRight | Qt::AlignVCenter; opt.displayAlignment = Qt::AlignRight | Qt::AlignVCenter;
QItemDelegate::drawDisplay(painter, opt, option.rect, Utils::Misc::userFriendlyDuration(index.data().toLongLong())); QItemDelegate::drawDisplay(painter, opt, option.rect, Utils::Misc::userFriendlyDuration(index.data().toLongLong()));
break; break;
} }
case TorrentModelItem::TR_SEEDS: case TorrentModel::TR_SEEDS:
case TorrentModelItem::TR_PEERS: { case TorrentModel::TR_PEERS: {
QString display = QString::number(index.data().toLongLong()); QString display = QString::number(index.data().toLongLong());
qlonglong total = index.data(Qt::UserRole).toLongLong(); qlonglong total = index.data(Qt::UserRole).toLongLong();
if (total > 0) { if (total > 0) {
@ -88,7 +88,7 @@ void TransferListDelegate::paint(QPainter * painter, const QStyleOptionViewItem
QItemDelegate::drawDisplay(painter, opt, opt.rect, display); QItemDelegate::drawDisplay(painter, opt, opt.rect, display);
break; break;
} }
case TorrentModelItem::TR_STATUS: { case TorrentModel::TR_STATUS: {
const int state = index.data().toInt(); const int state = index.data().toInt();
QString display; QString display;
switch(state) { switch(state) {
@ -138,23 +138,23 @@ void TransferListDelegate::paint(QPainter * painter, const QStyleOptionViewItem
QItemDelegate::drawDisplay(painter, opt, opt.rect, display); QItemDelegate::drawDisplay(painter, opt, opt.rect, display);
break; break;
} }
case TorrentModelItem::TR_UPSPEED: case TorrentModel::TR_UPSPEED:
case TorrentModelItem::TR_DLSPEED: { case TorrentModel::TR_DLSPEED: {
QItemDelegate::drawBackground(painter, opt, index); QItemDelegate::drawBackground(painter, opt, index);
const qulonglong speed = index.data().toULongLong(); const qulonglong speed = index.data().toULongLong();
opt.displayAlignment = Qt::AlignRight | Qt::AlignVCenter; opt.displayAlignment = Qt::AlignRight | Qt::AlignVCenter;
QItemDelegate::drawDisplay(painter, opt, opt.rect, Utils::Misc::friendlyUnit(speed)+tr("/s", "/second (.i.e per second)")); QItemDelegate::drawDisplay(painter, opt, opt.rect, Utils::Misc::friendlyUnit(speed)+tr("/s", "/second (.i.e per second)"));
break; break;
} }
case TorrentModelItem::TR_UPLIMIT: case TorrentModel::TR_UPLIMIT:
case TorrentModelItem::TR_DLLIMIT: { case TorrentModel::TR_DLLIMIT: {
QItemDelegate::drawBackground(painter, opt, index); QItemDelegate::drawBackground(painter, opt, index);
const qlonglong limit = index.data().toLongLong(); const qlonglong limit = index.data().toLongLong();
opt.displayAlignment = Qt::AlignRight | Qt::AlignVCenter; 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("")); 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; break;
} }
case TorrentModelItem::TR_TIME_ELAPSED: { case TorrentModel::TR_TIME_ELAPSED: {
QItemDelegate::drawBackground(painter, opt, index); QItemDelegate::drawBackground(painter, opt, index);
QString txt = Utils::Misc::userFriendlyDuration(index.data().toLongLong()); QString txt = Utils::Misc::userFriendlyDuration(index.data().toLongLong());
qlonglong seeding_time = index.data(Qt::UserRole).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); QItemDelegate::drawDisplay(painter, opt, opt.rect, txt);
break; break;
} }
case TorrentModelItem::TR_ADD_DATE: case TorrentModel::TR_ADD_DATE:
case TorrentModelItem::TR_SEED_DATE: case TorrentModel::TR_SEED_DATE:
QItemDelegate::drawBackground(painter, opt, index); QItemDelegate::drawBackground(painter, opt, index);
QItemDelegate::drawDisplay(painter, opt, opt.rect, index.data().toDateTime().toLocalTime().toString(Qt::DefaultLocaleShortDate)); QItemDelegate::drawDisplay(painter, opt, opt.rect, index.data().toDateTime().toLocalTime().toString(Qt::DefaultLocaleShortDate));
break; break;
case TorrentModelItem::TR_RATIO_LIMIT: case TorrentModel::TR_RATIO_LIMIT:
case TorrentModelItem::TR_RATIO: { case TorrentModel::TR_RATIO: {
QItemDelegate::drawBackground(painter, opt, index); QItemDelegate::drawBackground(painter, opt, index);
opt.displayAlignment = Qt::AlignRight | Qt::AlignVCenter; opt.displayAlignment = Qt::AlignRight | Qt::AlignVCenter;
const qreal ratio = index.data().toDouble(); 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)); ((ratio == -1) || (ratio > BitTorrent::TorrentHandle::MAX_RATIO)) ? QString::fromUtf8("") : Utils::String::fromDouble(ratio, 2));
break; break;
} }
case TorrentModelItem::TR_PRIORITY: { case TorrentModel::TR_PRIORITY: {
const int priority = index.data().toInt(); const int priority = index.data().toInt();
opt.displayAlignment = Qt::AlignRight | Qt::AlignVCenter; opt.displayAlignment = Qt::AlignRight | Qt::AlignVCenter;
if (priority > 0) if (priority > 0)
@ -188,7 +188,7 @@ void TransferListDelegate::paint(QPainter * painter, const QStyleOptionViewItem
} }
break; break;
} }
case TorrentModelItem::TR_PROGRESS: { case TorrentModel::TR_PROGRESS: {
QStyleOptionProgressBarV2 newopt; QStyleOptionProgressBarV2 newopt;
qreal progress = index.data().toDouble()*100.; qreal progress = index.data().toDouble()*100.;
newopt.rect = opt.rect; newopt.rect = opt.rect;
@ -211,7 +211,7 @@ void TransferListDelegate::paint(QPainter * painter, const QStyleOptionViewItem
#endif #endif
break; break;
} }
case TorrentModelItem::TR_LAST_ACTIVITY: { case TorrentModel::TR_LAST_ACTIVITY: {
QString elapsedString; QString elapsedString;
long long elapsed = index.data().toLongLong(); long long elapsed = index.data().toLongLong();
QItemDelegate::drawBackground(painter, opt, index); QItemDelegate::drawBackground(painter, opt, index);

52
src/gui/transferlistfilterswidget.cpp

@ -50,6 +50,7 @@
#include "core/torrentfilter.h" #include "core/torrentfilter.h"
#include "core/bittorrent/trackerentry.h" #include "core/bittorrent/trackerentry.h"
#include "core/bittorrent/session.h" #include "core/bittorrent/session.h"
#include "core/bittorrent/torrenthandle.h"
#include "core/net/downloadmanager.h" #include "core/net/downloadmanager.h"
#include "core/net/downloadhandler.h" #include "core/net/downloadhandler.h"
#include "core/utils/misc.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(customContextMenuRequested(QPoint)), SLOT(showMenu(QPoint)));
connect(this, SIGNAL(currentRowChanged(int)), SLOT(applyFilter(int))); 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 QSize FiltersBase::sizeHint() const
@ -165,9 +167,9 @@ void StatusFiltersWidget::applyFilter(int row)
transferList->applyStatusFilter(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) LabelFiltersList::LabelFiltersList(QWidget *parent, TransferListWidget *transferList)
: FiltersBase(parent, transferList) : FiltersBase(parent, transferList)
@ -175,7 +177,8 @@ LabelFiltersList::LabelFiltersList(QWidget *parent, TransferListWidget *transfer
, m_totalLabeled(0) , m_totalLabeled(0)
{ {
setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); 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 // Add Label filters
QListWidgetItem *allLabels = new QListWidgetItem(this); QListWidgetItem *allLabels = new QListWidgetItem(this);
@ -309,12 +312,12 @@ void LabelFiltersList::removeUnusedLabels()
updateGeometry(); 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(oldLabel), qPrintable(torrent->label()));
qDebug("Torrent label changed from %s to %s", qPrintable(old_label), qPrintable(new_label)); removeItem(oldLabel);
removeItem(old_label); QString newLabel = torrent->label();
addItem(new_label, true); addItem(newLabel, true);
} }
void LabelFiltersList::showMenu(QPoint) 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; ++m_totalTorrents;
QString label = torrentItem->data(TorrentModelItem::TR_LABEL).toString(); QString label = torrent->label();
addItem(label, true); addItem(label, true);
// FIXME: Drop this confusion.
// labelFilters->addItem() may have changed the label, update the model accordingly. // 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; --m_totalTorrents;
Q_ASSERT(torrentItem); removeItem(torrent->label());
QString label = torrentItem->data(TorrentModelItem::TR_LABEL).toString();
removeItem(label);
} }
QString LabelFiltersList::labelFromRow(int row) const QString LabelFiltersList::labelFromRow(int row) const
@ -681,11 +685,10 @@ void TrackerFiltersList::applyFilter(int row)
transferList->applyTrackerFilter(getHashes(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 = torrent->hash();
QString hash = handle->hash(); QList<BitTorrent::TrackerEntry> trackers = torrent->trackers();
QList<BitTorrent::TrackerEntry> trackers = handle->trackers();
foreach (const BitTorrent::TrackerEntry &tracker, trackers) foreach (const BitTorrent::TrackerEntry &tracker, trackers)
addItem(tracker.url(), hash); 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)); 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 = torrent->hash();
QString hash = handle->hash(); QList<BitTorrent::TrackerEntry> trackers = torrent->trackers();
QList<BitTorrent::TrackerEntry> trackers = handle->trackers();
foreach (const BitTorrent::TrackerEntry &tracker, trackers) foreach (const BitTorrent::TrackerEntry &tracker, trackers)
removeItem(tracker.url(), hash); removeItem(tracker.url(), hash);

19
src/gui/transferlistfilterswidget.h

@ -40,7 +40,6 @@ class QCheckBox;
QT_END_NAMESPACE QT_END_NAMESPACE
class TransferListWidget; class TransferListWidget;
class TorrentModelItem;
namespace BitTorrent namespace BitTorrent
{ {
@ -68,8 +67,8 @@ protected:
private slots: private slots:
virtual void showMenu(QPoint) = 0; virtual void showMenu(QPoint) = 0;
virtual void applyFilter(int row) = 0; virtual void applyFilter(int row) = 0;
virtual void handleNewTorrent(TorrentModelItem* torrentItem) = 0; virtual void handleNewTorrent(BitTorrent::TorrentHandle *const) = 0;
virtual void torrentAboutToBeDeleted(TorrentModelItem* torrentItem) = 0; virtual void torrentAboutToBeDeleted(BitTorrent::TorrentHandle *const) = 0;
}; };
class StatusFiltersWidget: public FiltersBase class StatusFiltersWidget: public FiltersBase
@ -88,8 +87,8 @@ private:
// No need to redeclare them here as slots. // No need to redeclare them here as slots.
virtual void showMenu(QPoint); virtual void showMenu(QPoint);
virtual void applyFilter(int row); virtual void applyFilter(int row);
virtual void handleNewTorrent(TorrentModelItem*); virtual void handleNewTorrent(BitTorrent::TorrentHandle *const);
virtual void torrentAboutToBeDeleted(TorrentModelItem*); virtual void torrentAboutToBeDeleted(BitTorrent::TorrentHandle *const);
}; };
class LabelFiltersList: public FiltersBase class LabelFiltersList: public FiltersBase
@ -106,7 +105,7 @@ private slots:
void removeItem(const QString &label); void removeItem(const QString &label);
void removeSelectedLabel(); void removeSelectedLabel();
void removeUnusedLabels(); void removeUnusedLabels();
void torrentChangedLabel(TorrentModelItem *torrentItem, QString old_label, QString new_label); void torrentChangedLabel(BitTorrent::TorrentHandle *const torrent, const QString &oldLabel);
private: private:
@ -114,8 +113,8 @@ private:
// No need to redeclare them here as slots. // No need to redeclare them here as slots.
virtual void showMenu(QPoint); virtual void showMenu(QPoint);
virtual void applyFilter(int row); virtual void applyFilter(int row);
virtual void handleNewTorrent(TorrentModelItem* torrentItem); virtual void handleNewTorrent(BitTorrent::TorrentHandle *const torrent);
virtual void torrentAboutToBeDeleted(TorrentModelItem* torrentItem); virtual void torrentAboutToBeDeleted(BitTorrent::TorrentHandle *const torrent);
QString labelFromRow(int row) const; QString labelFromRow(int row) const;
int rowFromLabel(const QString &label) const; int rowFromLabel(const QString &label) const;
@ -152,8 +151,8 @@ private:
// No need to redeclare them here as slots. // No need to redeclare them here as slots.
virtual void showMenu(QPoint); virtual void showMenu(QPoint);
virtual void applyFilter(int row); virtual void applyFilter(int row);
virtual void handleNewTorrent(TorrentModelItem* torrentItem); virtual void handleNewTorrent(BitTorrent::TorrentHandle *const torrent);
virtual void torrentAboutToBeDeleted(TorrentModelItem* torrentItem); virtual void torrentAboutToBeDeleted(BitTorrent::TorrentHandle *const torrent);
QString trackerFromRow(int row) const; QString trackerFromRow(int row) const;
int rowFromTracker(const QString &tracker) const; int rowFromTracker(const QString &tracker) const;
QString getHost(const QString &trakcer) const; QString getHost(const QString &trakcer) const;

34
src/gui/transferlistsortmodel.cpp

@ -75,7 +75,7 @@ bool TransferListSortModel::lessThan(const QModelIndex &left, const QModelIndex
{ {
const int column = sortColumn(); const int column = sortColumn();
if (column == TorrentModelItem::TR_NAME) { if (column == TorrentModel::TR_NAME) {
QVariant vL = left.data(); QVariant vL = left.data();
QVariant vR = right.data(); QVariant vR = right.data();
if (!vL.isValid() || !vR.isValid() || (vL == vR)) if (!vL.isValid() || !vR.isValid() || (vL == vR))
@ -87,7 +87,7 @@ bool TransferListSortModel::lessThan(const QModelIndex &left, const QModelIndex
return QSortFilterProxyModel::lessThan(left, right); 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 vL = left.data().toDateTime();
QDateTime vR = right.data().toDateTime(); QDateTime vR = right.data().toDateTime();
@ -97,10 +97,10 @@ bool TransferListSortModel::lessThan(const QModelIndex &left, const QModelIndex
return vL < vR; return vL < vR;
} }
else if (column == TorrentModelItem::TR_PRIORITY) { else if (column == TorrentModel::TR_PRIORITY) {
return lowerPositionThan(left, right); 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_active = left.data().toInt();
int left_total = left.data(Qt::UserRole).toInt(); int left_total = left.data(Qt::UserRole).toInt();
int right_active = right.data().toInt(); int right_active = right.data().toInt();
@ -116,10 +116,10 @@ bool TransferListSortModel::lessThan(const QModelIndex &left, const QModelIndex
return (left_active < right_active); return (left_active < right_active);
} }
} }
else if (column == TorrentModelItem::TR_ETA) { else if (column == TorrentModel::TR_ETA) {
TorrentModel *model = qobject_cast<TorrentModel *>(sourceModel()); TorrentModel *model = qobject_cast<TorrentModel *>(sourceModel());
const int prioL = model->data(model->index(left.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(), TorrentModelItem::TR_PRIORITY)).toInt(); const int prioR = model->data(model->index(right.row(), TorrentModel::TR_PRIORITY)).toInt();
const qlonglong etaL = left.data().toLongLong(); const qlonglong etaL = left.data().toLongLong();
const qlonglong etaR = right.data().toLongLong(); const qlonglong etaR = right.data().toLongLong();
const bool ascend = (sortOrder() == Qt::AscendingOrder); const bool ascend = (sortOrder() == Qt::AscendingOrder);
@ -144,8 +144,8 @@ bool TransferListSortModel::lessThan(const QModelIndex &left, const QModelIndex
if (invalidL && invalidR) { if (invalidL && invalidR) {
if (seedingL) { //Both seeding if (seedingL) { //Both seeding
QDateTime dateL = model->data(model->index(left.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(), TorrentModelItem::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. //not valid dates should be sorted at the bottom.
if (!dateL.isValid()) return false; if (!dateL.isValid()) return false;
@ -164,7 +164,7 @@ bool TransferListSortModel::lessThan(const QModelIndex &left, const QModelIndex
return !invalidL; return !invalidL;
} }
} }
else if (column == TorrentModelItem::TR_LAST_ACTIVITY) { else if (column == TorrentModel::TR_LAST_ACTIVITY) {
const qlonglong vL = left.data().toLongLong(); const qlonglong vL = left.data().toLongLong();
const qlonglong vR = right.data().toLongLong(); const qlonglong vR = right.data().toLongLong();
@ -173,7 +173,7 @@ bool TransferListSortModel::lessThan(const QModelIndex &left, const QModelIndex
return vL < vR; 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 vL = left.data().toDouble();
const qreal vR = right.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<TorrentModel*>(sourceModel()); const TorrentModel *model = dynamic_cast<TorrentModel*>(sourceModel());
// Sort according to TR_PRIORITY // Sort according to TR_PRIORITY
const int queueL = model->data(model->index(left.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(), TorrentModelItem::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)) {
if ((queueL > 0) && (queueR > 0)) if ((queueL > 0) && (queueR > 0))
return queueL < queueR; return queueL < queueR;
@ -204,8 +204,8 @@ bool TransferListSortModel::lowerPositionThan(const QModelIndex &left, const QMo
} }
// Sort according to TR_SEED_DATE // Sort according to TR_SEED_DATE
const QDateTime dateL = model->data(model->index(left.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(), TorrentModelItem::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.isValid() && dateR.isValid()) {
if (dateL != dateR) if (dateL != dateR)
return dateL < dateR; return dateL < dateR;
@ -216,8 +216,8 @@ bool TransferListSortModel::lowerPositionThan(const QModelIndex &left, const QMo
return true; return true;
// Finally, sort by hash // Finally, sort by hash
const QString hashL(model->torrentHash(left.row())); const QString hashL(model->torrentHandle(model->index(left.row()))->hash());
const QString hashR(model->torrentHash(right.row())); const QString hashR(model->torrentHandle(model->index(right.row()))->hash());
return hashL < hashR; return hashL < hashR;
} }

318
src/gui/transferlistwidget.cpp

@ -61,6 +61,8 @@
#include "autoexpandabledialog.h" #include "autoexpandabledialog.h"
#include "transferlistsortmodel.h" #include "transferlistsortmodel.h"
static QStringList extractHashes(const QList<BitTorrent::TorrentHandle *> &torrents);
TransferListWidget::TransferListWidget(QWidget *parent, MainWindow *main_window) TransferListWidget::TransferListWidget(QWidget *parent, MainWindow *main_window)
: QTreeView(parent) : QTreeView(parent)
, main_window(main_window) , main_window(main_window)
@ -80,7 +82,7 @@ TransferListWidget::TransferListWidget(QWidget *parent, MainWindow *main_window)
nameFilterModel = new TransferListSortModel(); nameFilterModel = new TransferListSortModel();
nameFilterModel->setDynamicSortFilter(true); nameFilterModel->setDynamicSortFilter(true);
nameFilterModel->setSourceModel(listModel); nameFilterModel->setSourceModel(listModel);
nameFilterModel->setFilterKeyColumn(TorrentModelItem::TR_NAME); nameFilterModel->setFilterKeyColumn(TorrentModel::TR_NAME);
nameFilterModel->setFilterRole(Qt::DisplayRole); nameFilterModel->setFilterRole(Qt::DisplayRole);
nameFilterModel->setSortCaseSensitivity(Qt::CaseInsensitive); nameFilterModel->setSortCaseSensitivity(Qt::CaseInsensitive);
@ -101,40 +103,40 @@ TransferListWidget::TransferListWidget(QWidget *parent, MainWindow *main_window)
// Default hidden columns // Default hidden columns
if (!column_loaded) { if (!column_loaded) {
setColumnHidden(TorrentModelItem::TR_ADD_DATE, true); setColumnHidden(TorrentModel::TR_ADD_DATE, true);
setColumnHidden(TorrentModelItem::TR_SEED_DATE, true); setColumnHidden(TorrentModel::TR_SEED_DATE, true);
setColumnHidden(TorrentModelItem::TR_UPLIMIT, true); setColumnHidden(TorrentModel::TR_UPLIMIT, true);
setColumnHidden(TorrentModelItem::TR_DLLIMIT, true); setColumnHidden(TorrentModel::TR_DLLIMIT, true);
setColumnHidden(TorrentModelItem::TR_TRACKER, true); setColumnHidden(TorrentModel::TR_TRACKER, true);
setColumnHidden(TorrentModelItem::TR_AMOUNT_DOWNLOADED, true); setColumnHidden(TorrentModel::TR_AMOUNT_DOWNLOADED, true);
setColumnHidden(TorrentModelItem::TR_AMOUNT_UPLOADED, true); setColumnHidden(TorrentModel::TR_AMOUNT_UPLOADED, true);
setColumnHidden(TorrentModelItem::TR_AMOUNT_DOWNLOADED_SESSION, true); setColumnHidden(TorrentModel::TR_AMOUNT_DOWNLOADED_SESSION, true);
setColumnHidden(TorrentModelItem::TR_AMOUNT_UPLOADED_SESSION, true); setColumnHidden(TorrentModel::TR_AMOUNT_UPLOADED_SESSION, true);
setColumnHidden(TorrentModelItem::TR_AMOUNT_LEFT, true); setColumnHidden(TorrentModel::TR_AMOUNT_LEFT, true);
setColumnHidden(TorrentModelItem::TR_TIME_ELAPSED, true); setColumnHidden(TorrentModel::TR_TIME_ELAPSED, true);
setColumnHidden(TorrentModelItem::TR_SAVE_PATH, true); setColumnHidden(TorrentModel::TR_SAVE_PATH, true);
setColumnHidden(TorrentModelItem::TR_COMPLETED, true); setColumnHidden(TorrentModel::TR_COMPLETED, true);
setColumnHidden(TorrentModelItem::TR_RATIO_LIMIT, true); setColumnHidden(TorrentModel::TR_RATIO_LIMIT, true);
setColumnHidden(TorrentModelItem::TR_SEEN_COMPLETE_DATE, true); setColumnHidden(TorrentModel::TR_SEEN_COMPLETE_DATE, true);
setColumnHidden(TorrentModelItem::TR_LAST_ACTIVITY, true); setColumnHidden(TorrentModel::TR_LAST_ACTIVITY, true);
setColumnHidden(TorrentModelItem::TR_TOTAL_SIZE, true); setColumnHidden(TorrentModel::TR_TOTAL_SIZE, true);
} }
//Ensure that at least one column is visible at all times //Ensure that at least one column is visible at all times
bool atLeastOne = false; bool atLeastOne = false;
for (unsigned int i = 0; i<TorrentModelItem::NB_COLUMNS; i++) { for (unsigned int i = 0; i<TorrentModel::NB_COLUMNS; i++) {
if (!isColumnHidden(i)) { if (!isColumnHidden(i)) {
atLeastOne = true; atLeastOne = true;
break; break;
} }
} }
if (!atLeastOne) if (!atLeastOne)
setColumnHidden(TorrentModelItem::TR_NAME, false); setColumnHidden(TorrentModel::TR_NAME, false);
//When adding/removing columns between versions some may //When adding/removing columns between versions some may
//end up being size 0 when the new version is launched with //end up being size 0 when the new version is launched with
//a conf file from the previous version. //a conf file from the previous version.
for (unsigned int i = 0; i<TorrentModelItem::NB_COLUMNS; i++) for (unsigned int i = 0; i<TorrentModel::NB_COLUMNS; i++)
if (!columnWidth(i)) if (!columnWidth(i))
resizeColumnToContents(i); resizeColumnToContents(i);
@ -177,16 +179,6 @@ void TransferListWidget::previewFile(QString filePath)
openUrl(filePath); openUrl(filePath);
} }
int TransferListWidget::getRowFromHash(QString hash) const
{
return listModel->torrentRow(hash);
}
inline QString TransferListWidget::getHashFromRow(int row) const
{
return listModel->torrentHash(row);
}
inline QModelIndex TransferListWidget::mapToSource(const QModelIndex &index) const inline QModelIndex TransferListWidget::mapToSource(const QModelIndex &index) const
{ {
Q_ASSERT(index.isValid()); Q_ASSERT(index.isValid());
@ -204,9 +196,7 @@ inline QModelIndex TransferListWidget::mapFromSource(const QModelIndex &index) c
void TransferListWidget::torrentDoubleClicked(const QModelIndex& index) void TransferListWidget::torrentDoubleClicked(const QModelIndex& index)
{ {
const int row = mapToSource(index).row(); BitTorrent::TorrentHandle *const torrent = listModel->torrentHandle(mapToSource(index));
const QString hash = getHashFromRow(row);
BitTorrent::TorrentHandle *const torrent = BitTorrent::Session::instance()->findTorrent(hash);
if (!torrent) return; if (!torrent) return;
int action; int action;
@ -227,37 +217,30 @@ void TransferListWidget::torrentDoubleClicked(const QModelIndex& index)
} }
} }
QStringList TransferListWidget::getSelectedTorrentsHashes() const QList<BitTorrent::TorrentHandle *> TransferListWidget::getSelectedTorrents() const
{ {
QStringList hashes; QList<BitTorrent::TorrentHandle *> torrents;
const QModelIndexList selectedIndexes = selectionModel()->selectedRows(); foreach (const QModelIndex &index, selectionModel()->selectedRows())
foreach (const QModelIndex &index, selectedIndexes) torrents << listModel->torrentHandle(mapToSource(index));
hashes << getHashFromRow(mapToSource(index).row());
return hashes; return torrents;
} }
void TransferListWidget::setSelectedTorrentsLocation() void TransferListWidget::setSelectedTorrentsLocation()
{ {
const QStringList hashes = getSelectedTorrentsHashes(); const QList<BitTorrent::TorrentHandle *> torrents = getSelectedTorrents();
if (hashes.isEmpty()) return; if (torrents.isEmpty()) return;
BitTorrent::TorrentHandle *const firstTorrent = BitTorrent::Session::instance()->findTorrent(hashes.first());
if (!firstTorrent) return;
QString dir; QString dir;
const QDir saveDir(firstTorrent->savePath()); const QDir saveDir(torrents[0]->savePath());
qDebug("Old save path is %s", qPrintable(saveDir.absolutePath())); qDebug("Old save path is %s", qPrintable(saveDir.absolutePath()));
dir = QFileDialog::getExistingDirectory(this, tr("Choose save path"), saveDir.absolutePath(), dir = QFileDialog::getExistingDirectory(this, tr("Choose save path"), saveDir.absolutePath(),
QFileDialog::DontConfirmOverwrite | QFileDialog::ShowDirsOnly | QFileDialog::HideNameFilterDetails); QFileDialog::DontConfirmOverwrite | QFileDialog::ShowDirsOnly | QFileDialog::HideNameFilterDetails);
if (!dir.isNull()) { if (!dir.isNull()) {
qDebug("New path is %s", qPrintable(dir)); qDebug("New path is %s", qPrintable(dir));
foreach (const QString &hash, hashes) { foreach (BitTorrent::TorrentHandle *const torrent, torrents) {
// Actually move storage // Actually move storage
BitTorrent::TorrentHandle *const torrent = BitTorrent::Session::instance()->findTorrent(hash);
if (!torrent) continue;
torrent->move(Utils::Fs::expandPathAbs(dir)); torrent->move(Utils::Fs::expandPathAbs(dir));
main_window->getProperties()->updateSavePath(torrent);
} }
} }
} }
@ -276,27 +259,20 @@ void TransferListWidget::resumeAllTorrents()
void TransferListWidget::startSelectedTorrents() void TransferListWidget::startSelectedTorrents()
{ {
foreach (const QString &hash, getSelectedTorrentsHashes()) { foreach (BitTorrent::TorrentHandle *const torrent, getSelectedTorrents())
BitTorrent::TorrentHandle *const torrent = BitTorrent::Session::instance()->findTorrent(hash); torrent->resume();
if (torrent)
torrent->resume();
}
} }
void TransferListWidget::forceStartSelectedTorrents() void TransferListWidget::forceStartSelectedTorrents()
{ {
foreach (const QString &hash, getSelectedTorrentsHashes()) { foreach (BitTorrent::TorrentHandle *const torrent, getSelectedTorrents())
BitTorrent::TorrentHandle *const torrent = BitTorrent::Session::instance()->findTorrent(hash); torrent->resume(true);
if (torrent)
torrent->resume(true);
}
} }
void TransferListWidget::startVisibleTorrents() void TransferListWidget::startVisibleTorrents()
{ {
for (int i = 0; i < nameFilterModel->rowCount(); ++i) { for (int i = 0; i < nameFilterModel->rowCount(); ++i) {
const int row = mapToSource(nameFilterModel->index(i, 0)).row(); BitTorrent::TorrentHandle *const torrent = listModel->torrentHandle(mapToSource(nameFilterModel->index(i, 0)));
BitTorrent::TorrentHandle *const torrent = BitTorrent::Session::instance()->findTorrent(getHashFromRow(row));
if (torrent) if (torrent)
torrent->resume(); torrent->resume();
} }
@ -304,18 +280,14 @@ void TransferListWidget::startVisibleTorrents()
void TransferListWidget::pauseSelectedTorrents() void TransferListWidget::pauseSelectedTorrents()
{ {
foreach (const QString &hash, getSelectedTorrentsHashes()) { foreach (BitTorrent::TorrentHandle *const torrent, getSelectedTorrents())
BitTorrent::TorrentHandle *const torrent = BitTorrent::Session::instance()->findTorrent(hash); torrent->pause();
if (torrent)
torrent->pause();
}
} }
void TransferListWidget::pauseVisibleTorrents() void TransferListWidget::pauseVisibleTorrents()
{ {
for (int i = 0; i < nameFilterModel->rowCount(); ++i) { for (int i = 0; i < nameFilterModel->rowCount(); ++i) {
const int row = mapToSource(nameFilterModel->index(i, 0)).row(); BitTorrent::TorrentHandle *const torrent = listModel->torrentHandle(mapToSource(nameFilterModel->index(i, 0)));
BitTorrent::TorrentHandle *const torrent = BitTorrent::Session::instance()->findTorrent(getHashFromRow(row));
if (torrent) if (torrent)
torrent->pause(); torrent->pause();
} }
@ -324,117 +296,103 @@ void TransferListWidget::pauseVisibleTorrents()
void TransferListWidget::deleteSelectedTorrents() void TransferListWidget::deleteSelectedTorrents()
{ {
if (main_window->getCurrentTabWidget() != this) return; 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<BitTorrent::TorrentHandle *> torrents = getSelectedTorrents();
if (torrents.empty()) return;
bool delete_local_files = false; bool delete_local_files = false;
if (Preferences::instance()->confirmTorrentDeletion() && if (Preferences::instance()->confirmTorrentDeletion() &&
!DeletionConfirmationDlg::askForDeletionConfirmation(delete_local_files, hashes.size(), torrent->name())) !DeletionConfirmationDlg::askForDeletionConfirmation(delete_local_files, torrents.size(), torrents[0]->name()))
return; return;
foreach (const QString &hash, hashes) foreach (BitTorrent::TorrentHandle *const torrent, torrents)
BitTorrent::Session::instance()->deleteTorrent(hash, delete_local_files); BitTorrent::Session::instance()->deleteTorrent(torrent->hash(), delete_local_files);
} }
void TransferListWidget::deleteVisibleTorrents() void TransferListWidget::deleteVisibleTorrents()
{ {
if (nameFilterModel->rowCount() <= 0) return; if (nameFilterModel->rowCount() <= 0) return;
QStringList hashes;
for (int i = 0; i<nameFilterModel->rowCount(); ++i) {
const int row = mapToSource(nameFilterModel->index(i, 0)).row();
hashes << getHashFromRow(row);
}
BitTorrent::TorrentHandle *const torrent = BitTorrent::Session::instance()->findTorrent(hashes[0]); QList<BitTorrent::TorrentHandle *> torrents;
for (int i = 0; i < nameFilterModel->rowCount(); ++i)
torrents << listModel->torrentHandle(mapToSource(nameFilterModel->index(i, 0)));
bool delete_local_files = false; bool delete_local_files = false;
if (Preferences::instance()->confirmTorrentDeletion() && if (Preferences::instance()->confirmTorrentDeletion() &&
!DeletionConfirmationDlg::askForDeletionConfirmation(delete_local_files, hashes.size(), torrent->name())) !DeletionConfirmationDlg::askForDeletionConfirmation(delete_local_files, torrents.size(), torrents[0]->name()))
return; return;
foreach (const QString &hash, hashes) foreach (BitTorrent::TorrentHandle *const torrent, torrents)
BitTorrent::Session::instance()->deleteTorrent(hash, delete_local_files); BitTorrent::Session::instance()->deleteTorrent(torrent->hash(), delete_local_files);
} }
void TransferListWidget::increasePrioSelectedTorrents() void TransferListWidget::increasePrioSelectedTorrents()
{ {
qDebug() << Q_FUNC_INFO; qDebug() << Q_FUNC_INFO;
if (main_window->getCurrentTabWidget() == this) if (main_window->getCurrentTabWidget() == this)
BitTorrent::Session::instance()->increaseTorrentsPriority(getSelectedTorrentsHashes()); BitTorrent::Session::instance()->increaseTorrentsPriority(extractHashes(getSelectedTorrents()));
} }
void TransferListWidget::decreasePrioSelectedTorrents() void TransferListWidget::decreasePrioSelectedTorrents()
{ {
qDebug() << Q_FUNC_INFO; qDebug() << Q_FUNC_INFO;
if (main_window->getCurrentTabWidget() == this) if (main_window->getCurrentTabWidget() == this)
BitTorrent::Session::instance()->decreaseTorrentsPriority(getSelectedTorrentsHashes()); BitTorrent::Session::instance()->decreaseTorrentsPriority(extractHashes(getSelectedTorrents()));
} }
void TransferListWidget::topPrioSelectedTorrents() void TransferListWidget::topPrioSelectedTorrents()
{ {
if (main_window->getCurrentTabWidget() == this) if (main_window->getCurrentTabWidget() == this)
BitTorrent::Session::instance()->topTorrentsPriority(getSelectedTorrentsHashes()); BitTorrent::Session::instance()->topTorrentsPriority(extractHashes(getSelectedTorrents()));
} }
void TransferListWidget::bottomPrioSelectedTorrents() void TransferListWidget::bottomPrioSelectedTorrents()
{ {
if (main_window->getCurrentTabWidget() == this) if (main_window->getCurrentTabWidget() == this)
BitTorrent::Session::instance()->bottomTorrentsPriority(getSelectedTorrentsHashes()); BitTorrent::Session::instance()->bottomTorrentsPriority(extractHashes(getSelectedTorrents()));
} }
void TransferListWidget::copySelectedMagnetURIs() const void TransferListWidget::copySelectedMagnetURIs() const
{ {
QStringList magnet_uris; QStringList magnet_uris;
const QStringList hashes = getSelectedTorrentsHashes(); foreach (BitTorrent::TorrentHandle *const torrent, getSelectedTorrents())
foreach (const QString &hash, hashes) { magnet_uris << torrent->toMagnetUri();
BitTorrent::TorrentHandle *const torrent = BitTorrent::Session::instance()->findTorrent(hash);
if (torrent)
magnet_uris << torrent->toMagnetUri();
}
qApp->clipboard()->setText(magnet_uris.join("\n")); qApp->clipboard()->setText(magnet_uris.join("\n"));
} }
void TransferListWidget::copySelectedNames() const void TransferListWidget::copySelectedNames() const
{ {
QStringList torrent_names; QStringList torrent_names;
const QStringList hashes = getSelectedTorrentsHashes(); foreach (BitTorrent::TorrentHandle *const torrent, getSelectedTorrents())
foreach (const QString &hash, hashes) { torrent_names << torrent->name();
BitTorrent::TorrentHandle *const torrent = BitTorrent::Session::instance()->findTorrent(hash);
if (torrent)
torrent_names << torrent->name();
}
qApp->clipboard()->setText(torrent_names.join("\n")); qApp->clipboard()->setText(torrent_names.join("\n"));
} }
void TransferListWidget::hidePriorityColumn(bool hide) void TransferListWidget::hidePriorityColumn(bool hide)
{ {
qDebug("hidePriorityColumn(%d)", hide); qDebug("hidePriorityColumn(%d)", hide);
setColumnHidden(TorrentModelItem::TR_PRIORITY, hide); setColumnHidden(TorrentModel::TR_PRIORITY, hide);
if (!hide && !columnWidth(TorrentModelItem::TR_PRIORITY)) if (!hide && !columnWidth(TorrentModel::TR_PRIORITY))
resizeColumnToContents(TorrentModelItem::TR_PRIORITY); resizeColumnToContents(TorrentModel::TR_PRIORITY);
} }
void TransferListWidget::openSelectedTorrentsFolder() const void TransferListWidget::openSelectedTorrentsFolder() const
{ {
QSet<QString> pathsList; QSet<QString> pathsList;
const QStringList hashes = getSelectedTorrentsHashes(); foreach (BitTorrent::TorrentHandle *const torrent, getSelectedTorrents()) {
foreach (const QString &hash, hashes) { QString rootFolder = torrent->rootPath();
BitTorrent::TorrentHandle *const torrent = BitTorrent::Session::instance()->findTorrent(hash); qDebug("Opening path at %s", qPrintable(rootFolder));
if (torrent) { if (!pathsList.contains(rootFolder)) {
QString rootFolder = torrent->rootPath(); pathsList.insert(rootFolder);
qDebug("Opening path at %s", qPrintable(rootFolder)); openUrl(rootFolder);
if (!pathsList.contains(rootFolder)) {
pathsList.insert(rootFolder);
openUrl(rootFolder);
}
} }
} }
} }
void TransferListWidget::previewSelectedTorrents() void TransferListWidget::previewSelectedTorrents()
{ {
const QStringList hashes = getSelectedTorrentsHashes(); foreach (BitTorrent::TorrentHandle *const torrent, getSelectedTorrents()) {
foreach (const QString &hash, hashes) { if (torrent->hasMetadata())
BitTorrent::TorrentHandle *const torrent = BitTorrent::Session::instance()->findTorrent(hash);
if (torrent && torrent->hasMetadata())
new PreviewSelect(this, torrent); new PreviewSelect(this, torrent);
} }
} }
@ -444,19 +402,17 @@ void TransferListWidget::setDlLimitSelectedTorrents()
QList<BitTorrent::TorrentHandle *> selected_torrents; QList<BitTorrent::TorrentHandle *> selected_torrents;
bool first = true; bool first = true;
bool all_same_limit = true; bool all_same_limit = true;
const QStringList hashes = getSelectedTorrentsHashes(); foreach (BitTorrent::TorrentHandle *const torrent, getSelectedTorrents()) {
foreach (const QString &hash, hashes) { if (!torrent->isSeed()) {
BitTorrent::TorrentHandle *const torrent = BitTorrent::Session::instance()->findTorrent(hash);
if (torrent && !torrent->isSeed()) {
selected_torrents << torrent; selected_torrents << torrent;
// Determine current limit for selected torrents // Determine current limit for selected torrents
if (first) if (first)
first = false; first = false;
else else if (all_same_limit && (torrent->downloadLimit() != selected_torrents.first()->downloadLimit()))
if (all_same_limit && (torrent->downloadLimit() != selected_torrents.first()->downloadLimit())) all_same_limit = false;
all_same_limit = false;
} }
} }
if (selected_torrents.empty()) return; if (selected_torrents.empty()) return;
bool ok = false; bool ok = false;
@ -477,19 +433,15 @@ void TransferListWidget::setUpLimitSelectedTorrents()
QList<BitTorrent::TorrentHandle *> selected_torrents; QList<BitTorrent::TorrentHandle *> selected_torrents;
bool first = true; bool first = true;
bool all_same_limit = true; bool all_same_limit = true;
const QStringList hashes = getSelectedTorrentsHashes(); foreach (BitTorrent::TorrentHandle *const torrent, getSelectedTorrents()) {
foreach (const QString &hash, hashes) { selected_torrents << torrent;
BitTorrent::TorrentHandle *const torrent = BitTorrent::Session::instance()->findTorrent(hash); // Determine current limit for selected torrents
if (torrent) { if (first)
selected_torrents << torrent; first = false;
// Determine current limit for selected torrents else if (all_same_limit && (torrent->uploadLimit() != selected_torrents.first()->uploadLimit()))
if (first) all_same_limit = false;
first = false;
else
if (all_same_limit && (torrent->uploadLimit() != selected_torrents.first()->uploadLimit()))
all_same_limit = false;
}
} }
if (selected_torrents.empty()) return; if (selected_torrents.empty()) return;
bool ok = false; bool ok = false;
@ -507,26 +459,20 @@ void TransferListWidget::setUpLimitSelectedTorrents()
void TransferListWidget::setMaxRatioSelectedTorrents() void TransferListWidget::setMaxRatioSelectedTorrents()
{ {
const QStringList hashes = getSelectedTorrentsHashes(); const QList<BitTorrent::TorrentHandle *> torrents = getSelectedTorrents();
if (hashes.isEmpty()) if (torrents.isEmpty()) return;
return;
bool useGlobalValue = true; bool useGlobalValue = true;
qreal currentMaxRatio = BitTorrent::Session::instance()->globalMaxRatio();; qreal currentMaxRatio = BitTorrent::Session::instance()->globalMaxRatio();;
if (hashes.count() == 1) { if (torrents.count() == 1)
BitTorrent::TorrentHandle *const torrent = BitTorrent::Session::instance()->findTorrent(hashes.first()); currentMaxRatio = torrents[0]->maxRatio(&useGlobalValue);
if (torrent)
currentMaxRatio = torrent->maxRatio(&useGlobalValue);
}
UpDownRatioDlg dlg(useGlobalValue, currentMaxRatio, BitTorrent::TorrentHandle::MAX_RATIO, this); UpDownRatioDlg dlg(useGlobalValue, currentMaxRatio, BitTorrent::TorrentHandle::MAX_RATIO, this);
if (dlg.exec() != QDialog::Accepted) return; if (dlg.exec() != QDialog::Accepted) return;
foreach (const QString &hash, hashes) { foreach (BitTorrent::TorrentHandle *const torrent, torrents) {
BitTorrent::TorrentHandle *const torrent = BitTorrent::Session::instance()->findTorrent(hash); qreal ratio = (dlg.useDefault() ? BitTorrent::TorrentHandle::USE_GLOBAL_RATIO : dlg.ratio());
if (torrent) { torrent->setRatioLimit(ratio);
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); 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; if (ret != QMessageBox::Yes) return;
const QStringList hashes = getSelectedTorrentsHashes(); foreach (BitTorrent::TorrentHandle *const torrent, getSelectedTorrents())
foreach (const QString &hash, hashes) { torrent->forceRecheck();
BitTorrent::TorrentHandle *const torrent = BitTorrent::Session::instance()->findTorrent(hash);
if (torrent)
torrent->forceRecheck();
}
} }
// hide/show columns menu // hide/show columns menu
@ -550,7 +492,7 @@ void TransferListWidget::displayDLHoSMenu(const QPoint&)
hideshowColumn.setTitle(tr("Column visibility")); hideshowColumn.setTitle(tr("Column visibility"));
QList<QAction*> actions; QList<QAction*> actions;
for (int i = 0; i < listModel->columnCount(); ++i) { 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); actions.append(0);
continue; continue;
} }
@ -560,7 +502,7 @@ void TransferListWidget::displayDLHoSMenu(const QPoint&)
actions.append(myAct); actions.append(myAct);
} }
int visibleCols = 0; int visibleCols = 0;
for (unsigned int i = 0; i<TorrentModelItem::NB_COLUMNS; i++) { for (unsigned int i = 0; i<TorrentModel::NB_COLUMNS; i++) {
if (!isColumnHidden(i)) if (!isColumnHidden(i))
visibleCols++; visibleCols++;
@ -586,32 +528,22 @@ void TransferListWidget::displayDLHoSMenu(const QPoint&)
void TransferListWidget::toggleSelectedTorrentsSuperSeeding() const void TransferListWidget::toggleSelectedTorrentsSuperSeeding() const
{ {
const QStringList hashes = getSelectedTorrentsHashes(); foreach (BitTorrent::TorrentHandle *const torrent, getSelectedTorrents()) {
foreach (const QString &hash, hashes) { if (torrent->hasMetadata())
BitTorrent::TorrentHandle *const torrent = BitTorrent::Session::instance()->findTorrent(hash);
if (torrent && torrent->hasMetadata())
torrent->setSuperSeeding(!torrent->superSeeding()); torrent->setSuperSeeding(!torrent->superSeeding());
} }
} }
void TransferListWidget::toggleSelectedTorrentsSequentialDownload() const void TransferListWidget::toggleSelectedTorrentsSequentialDownload() const
{ {
const QStringList hashes = getSelectedTorrentsHashes(); foreach (BitTorrent::TorrentHandle *const torrent, getSelectedTorrents())
foreach (const QString &hash, hashes) { torrent->toggleSequentialDownload();
BitTorrent::TorrentHandle *const torrent = BitTorrent::Session::instance()->findTorrent(hash);
if (torrent)
torrent->toggleSequentialDownload();
}
} }
void TransferListWidget::toggleSelectedFirstLastPiecePrio() const void TransferListWidget::toggleSelectedFirstLastPiecePrio() const
{ {
QStringList hashes = getSelectedTorrentsHashes(); foreach (BitTorrent::TorrentHandle *const torrent, getSelectedTorrents())
foreach (const QString &hash, hashes) { torrent->setFirstLastPiecePriority(!torrent->hasFirstLastPiecePriority());
BitTorrent::TorrentHandle *const torrent = BitTorrent::Session::instance()->findTorrent(hash);
if (torrent)
torrent->setFirstLastPiecePriority(!torrent->hasFirstLastPiecePriority());
}
} }
void TransferListWidget::askNewLabelForSelection() void TransferListWidget::askNewLabelForSelection()
@ -649,9 +581,9 @@ void TransferListWidget::renameSelectedTorrent()
const QModelIndexList selectedIndexes = selectionModel()->selectedRows(); const QModelIndexList selectedIndexes = selectionModel()->selectedRows();
if (selectedIndexes.size() != 1) return; if (selectedIndexes.size() != 1) return;
if (!selectedIndexes.first().isValid()) return; if (!selectedIndexes.first().isValid()) return;
QModelIndex mi = listModel->index(mapToSource(selectedIndexes.first()).row(), TorrentModelItem::TR_NAME);
const QString hash = getHashFromRow(mi.row()); const QModelIndex mi = listModel->index(mapToSource(selectedIndexes.first()).row(), TorrentModel::TR_NAME);
BitTorrent::TorrentHandle *const torrent = BitTorrent::Session::instance()->findTorrent(hash); BitTorrent::TorrentHandle *const torrent = listModel->torrentHandle(mi);
if (!torrent) return; if (!torrent) return;
// Ask for a new Name // Ask for a new Name
@ -666,19 +598,15 @@ void TransferListWidget::renameSelectedTorrent()
void TransferListWidget::setSelectionLabel(QString label) void TransferListWidget::setSelectionLabel(QString label)
{ {
const QStringList& hashes = getSelectedTorrentsHashes(); foreach (const QModelIndex &index, selectionModel()->selectedRows())
foreach (const QString &hash, hashes) { listModel->setData(listModel->index(mapToSource(index).row(), TorrentModel::TR_LABEL), label, Qt::DisplayRole);
Q_ASSERT(!hash.isEmpty());
const int row = getRowFromHash(hash);
listModel->setData(listModel->index(row, TorrentModelItem::TR_LABEL), QVariant(label), Qt::DisplayRole);
}
} }
void TransferListWidget::removeLabelFromRows(QString label) void TransferListWidget::removeLabelFromRows(QString label)
{ {
for (int i = 0; i < listModel->rowCount(); ++i) { for (int i = 0; i < listModel->rowCount(); ++i) {
if (listModel->data(listModel->index(i, TorrentModelItem::TR_LABEL)) == label) { if (listModel->data(listModel->index(i, TorrentModel::TR_LABEL)) == label) {
listModel->setData(listModel->index(i, TorrentModelItem::TR_LABEL), "", Qt::DisplayRole); listModel->setData(listModel->index(i, TorrentModel::TR_LABEL), "", Qt::DisplayRole);
} }
} }
} }
@ -750,9 +678,8 @@ void TransferListWidget::displayListMenu(const QPoint&)
qDebug("Displaying menu"); qDebug("Displaying menu");
foreach (const QModelIndex &index, selectedIndexes) { foreach (const QModelIndex &index, selectedIndexes) {
// Get the file name // Get the file name
QString hash = getHashFromRow(mapToSource(index).row());
// Get handle and pause the torrent // Get handle and pause the torrent
torrent = BitTorrent::Session::instance()->findTorrent(hash); torrent = listModel->torrentHandle(mapToSource(index));
if (!torrent) continue; if (!torrent) continue;
if (torrent->hasMetadata()) if (torrent->hasMetadata())
@ -907,8 +834,7 @@ void TransferListWidget::currentChanged(const QModelIndex& current, const QModel
qDebug("CURRENT CHANGED"); qDebug("CURRENT CHANGED");
BitTorrent::TorrentHandle *torrent = 0; BitTorrent::TorrentHandle *torrent = 0;
if (current.isValid()) { if (current.isValid()) {
const int row = mapToSource(current).row(); torrent = listModel->torrentHandle(mapToSource(current));
torrent = BitTorrent::Session::instance()->findTorrent(getHashFromRow(row));
// Scroll Fix // Scroll Fix
scrollTo(current); scrollTo(current);
} }
@ -946,8 +872,8 @@ void TransferListWidget::applyStatusFilter(int f)
nameFilterModel->setStatusFilter(static_cast<TorrentFilter::Type>(f)); nameFilterModel->setStatusFilter(static_cast<TorrentFilter::Type>(f));
// Select first item if nothing is selected // Select first item if nothing is selected
if (selectionModel()->selectedRows(0).empty() && nameFilterModel->rowCount() > 0) { 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())); qDebug("Nothing is selected, selecting first row: %s", qPrintable(nameFilterModel->index(0, TorrentModel::TR_NAME).data().toString()));
selectionModel()->setCurrentIndex(nameFilterModel->index(0, TorrentModelItem::TR_NAME), QItemSelectionModel::SelectCurrent | QItemSelectionModel::Rows); selectionModel()->setCurrentIndex(nameFilterModel->index(0, TorrentModel::TR_NAME), QItemSelectionModel::SelectCurrent | QItemSelectionModel::Rows);
} }
} }
@ -964,3 +890,11 @@ bool TransferListWidget::loadSettings()
return ok; return ok;
} }
QStringList extractHashes(const QList<BitTorrent::TorrentHandle *> &torrents)
{
QStringList hashes;
foreach (BitTorrent::TorrentHandle *const torrent, torrents)
hashes << torrent->hash();
return hashes;
}

4
src/gui/transferlistwidget.h

@ -95,12 +95,10 @@ public slots:
void renameSelectedTorrent(); void renameSelectedTorrent();
protected: protected:
int getRowFromHash(QString hash) const;
QString getHashFromRow(int row) const;
QModelIndex mapToSource(const QModelIndex &index) const; QModelIndex mapToSource(const QModelIndex &index) const;
QModelIndex mapFromSource(const QModelIndex &index) const; QModelIndex mapFromSource(const QModelIndex &index) const;
bool loadSettings(); bool loadSettings();
QStringList getSelectedTorrentsHashes() const; QList<BitTorrent::TorrentHandle *> getSelectedTorrents() const;
protected slots: protected slots:
void torrentDoubleClicked(const QModelIndex& index); void torrentDoubleClicked(const QModelIndex& index);

Loading…
Cancel
Save