2010-11-14 22:32:29 +03:00
|
|
|
/*
|
|
|
|
* Bittorrent Client using Qt4 and libtorrent.
|
|
|
|
* Copyright (C) 2010 Christophe Dumez
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU General Public License
|
|
|
|
* as published by the Free Software Foundation; either version 2
|
|
|
|
* of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
|
|
*
|
|
|
|
* In addition, as a special exception, the copyright holders give permission to
|
|
|
|
* link this program with the OpenSSL project's "OpenSSL" library (or with
|
|
|
|
* modified versions of it that use the same license as the "OpenSSL" library),
|
|
|
|
* and distribute the linked executables. You must obey the GNU General Public
|
|
|
|
* License in all respects for all of the code used other than "OpenSSL". If you
|
|
|
|
* modify file(s), you may extend this exception to your version of the file(s),
|
|
|
|
* but you are not obligated to do so. If you do not wish to do so, delete this
|
|
|
|
* exception statement from your version.
|
|
|
|
*
|
|
|
|
* Contact : chris@qbittorrent.org
|
|
|
|
*/
|
|
|
|
|
2010-11-14 18:28:22 +03:00
|
|
|
#include <QDebug>
|
|
|
|
|
|
|
|
#include "torrentmodel.h"
|
|
|
|
#include "torrentpersistentdata.h"
|
|
|
|
#include "qbtsession.h"
|
2013-11-10 23:25:16 +04:00
|
|
|
#include "fs_utils.h"
|
2010-11-14 18:28:22 +03:00
|
|
|
|
2014-10-18 03:42:36 +04:00
|
|
|
#include <libtorrent/session.hpp>
|
|
|
|
|
2010-11-14 18:28:22 +03:00
|
|
|
using namespace libtorrent;
|
|
|
|
|
2014-06-03 21:35:50 +04:00
|
|
|
namespace {
|
|
|
|
QIcon get_paused_icon() {
|
2014-05-11 15:29:06 +04:00
|
|
|
static QIcon cached = QIcon(":/Icons/skin/paused.png");
|
|
|
|
return cached;
|
|
|
|
}
|
|
|
|
|
2014-06-03 21:35:50 +04:00
|
|
|
QIcon get_queued_icon() {
|
2014-05-11 15:29:06 +04:00
|
|
|
static QIcon cached = QIcon(":/Icons/skin/queued.png");
|
|
|
|
return cached;
|
|
|
|
}
|
|
|
|
|
2014-06-03 21:35:50 +04:00
|
|
|
QIcon get_downloading_icon() {
|
2014-05-11 15:29:06 +04:00
|
|
|
static QIcon cached = QIcon(":/Icons/skin/downloading.png");
|
|
|
|
return cached;
|
|
|
|
}
|
|
|
|
|
2014-06-03 21:35:50 +04:00
|
|
|
QIcon get_stalled_downloading_icon() {
|
2014-05-11 15:29:06 +04:00
|
|
|
static QIcon cached = QIcon(":/Icons/skin/stalledDL.png");
|
|
|
|
return cached;
|
|
|
|
}
|
|
|
|
|
2014-06-03 21:35:50 +04:00
|
|
|
QIcon get_uploading_icon() {
|
2014-05-11 15:29:06 +04:00
|
|
|
static QIcon cached = QIcon(":/Icons/skin/uploading.png");
|
|
|
|
return cached;
|
|
|
|
}
|
|
|
|
|
2014-06-03 21:35:50 +04:00
|
|
|
QIcon get_stalled_uploading_icon() {
|
2014-05-11 15:29:06 +04:00
|
|
|
static QIcon cached = QIcon(":/Icons/skin/stalledUP.png");
|
|
|
|
return cached;
|
|
|
|
}
|
|
|
|
|
2014-06-03 21:35:50 +04:00
|
|
|
QIcon get_checking_icon() {
|
2014-05-11 15:29:06 +04:00
|
|
|
static QIcon cached = QIcon(":/Icons/skin/checking.png");
|
|
|
|
return cached;
|
|
|
|
}
|
|
|
|
|
2014-06-03 21:35:50 +04:00
|
|
|
QIcon get_error_icon() {
|
2014-05-11 15:29:06 +04:00
|
|
|
static QIcon cached = QIcon(":/Icons/skin/error.png");
|
|
|
|
return cached;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-11-14 18:28:22 +03:00
|
|
|
TorrentModelItem::TorrentModelItem(const QTorrentHandle &h)
|
2012-08-25 17:34:00 +04:00
|
|
|
: m_torrent(h)
|
2014-05-14 02:09:45 +04:00
|
|
|
, m_lastStatus(h.status(torrent_handle::query_accurate_download_counters))
|
2012-08-25 17:34:00 +04:00
|
|
|
, m_addedTime(TorrentPersistentData::getAddedDate(h.hash()))
|
|
|
|
, m_label(TorrentPersistentData::getLabel(h.hash()))
|
|
|
|
, m_name(TorrentPersistentData::getName(h.hash()))
|
|
|
|
, m_hash(h.hash())
|
2010-11-14 18:28:22 +03:00
|
|
|
{
|
2012-08-25 17:34:00 +04:00
|
|
|
if (m_name.isEmpty())
|
|
|
|
m_name = h.name();
|
2010-11-14 18:28:22 +03:00
|
|
|
}
|
|
|
|
|
2014-06-03 21:35:50 +04:00
|
|
|
void TorrentModelItem::refreshStatus(libtorrent::torrent_status const& status) {
|
2014-05-18 12:07:49 +04:00
|
|
|
m_lastStatus = status;
|
2014-05-14 02:09:45 +04:00
|
|
|
}
|
|
|
|
|
2014-06-03 21:35:50 +04:00
|
|
|
TorrentModelItem::State TorrentModelItem::state() const {
|
2010-11-14 18:28:22 +03:00
|
|
|
try {
|
|
|
|
// Pause or Queued
|
2014-10-25 14:12:05 +04:00
|
|
|
if (m_torrent.is_paused(m_lastStatus))
|
2014-05-14 02:09:45 +04:00
|
|
|
return m_torrent.is_seed(m_lastStatus) ? STATE_PAUSED_UP : STATE_PAUSED_DL;
|
2014-10-25 14:12:05 +04:00
|
|
|
|
|
|
|
if (m_torrent.is_queued(m_lastStatus)
|
|
|
|
&& m_lastStatus.state != torrent_status::queued_for_checking
|
|
|
|
&& m_lastStatus.state != torrent_status::checking_resume_data
|
|
|
|
&& m_lastStatus.state != torrent_status::checking_files)
|
|
|
|
return m_torrent.is_seed(m_lastStatus) ? STATE_QUEUED_UP : STATE_QUEUED_DL;
|
|
|
|
|
2010-11-14 18:28:22 +03:00
|
|
|
// Other states
|
2014-05-14 02:09:45 +04:00
|
|
|
switch(m_lastStatus.state) {
|
2010-11-14 18:28:22 +03:00
|
|
|
case torrent_status::allocating:
|
2013-10-22 22:34:27 +04:00
|
|
|
return STATE_ALLOCATING;
|
2010-11-14 18:28:22 +03:00
|
|
|
case torrent_status::downloading_metadata:
|
2013-10-22 22:34:27 +04:00
|
|
|
return STATE_DOWNLOADING_META;
|
2014-10-25 14:12:05 +04:00
|
|
|
case torrent_status::downloading:
|
|
|
|
return m_lastStatus.download_payload_rate > 0 ? STATE_DOWNLOADING : STATE_STALLED_DL;
|
2010-11-14 18:28:22 +03:00
|
|
|
case torrent_status::finished:
|
|
|
|
case torrent_status::seeding:
|
2014-10-25 14:12:05 +04:00
|
|
|
return m_lastStatus.upload_payload_rate > 0 ? STATE_SEEDING : STATE_STALLED_UP;
|
2010-11-14 18:28:22 +03:00
|
|
|
case torrent_status::queued_for_checking:
|
2013-10-22 22:34:27 +04:00
|
|
|
return STATE_QUEUED_CHECK;
|
2010-11-14 18:28:22 +03:00
|
|
|
case torrent_status::checking_resume_data:
|
2013-10-22 22:34:27 +04:00
|
|
|
return STATE_QUEUED_FASTCHECK;
|
2010-11-14 18:28:22 +03:00
|
|
|
case torrent_status::checking_files:
|
2014-05-14 02:09:45 +04:00
|
|
|
return m_torrent.is_seed(m_lastStatus) ? STATE_CHECKING_UP : STATE_CHECKING_DL;
|
2010-11-14 18:28:22 +03:00
|
|
|
default:
|
|
|
|
return STATE_INVALID;
|
|
|
|
}
|
|
|
|
} catch(invalid_handle&) {
|
|
|
|
return STATE_INVALID;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-10-25 14:12:05 +04:00
|
|
|
QIcon TorrentModelItem::getIconByState(State state) {
|
|
|
|
switch (state) {
|
|
|
|
case STATE_DOWNLOADING:
|
|
|
|
case STATE_DOWNLOADING_META:
|
|
|
|
return get_downloading_icon();
|
|
|
|
case STATE_ALLOCATING:
|
|
|
|
case STATE_STALLED_DL:
|
|
|
|
return get_stalled_downloading_icon();
|
|
|
|
case STATE_STALLED_UP:
|
|
|
|
return get_stalled_uploading_icon();
|
|
|
|
case STATE_SEEDING:
|
|
|
|
return get_uploading_icon();
|
|
|
|
case STATE_PAUSED_DL:
|
|
|
|
case STATE_PAUSED_UP:
|
|
|
|
return get_paused_icon();
|
|
|
|
case STATE_QUEUED_DL:
|
|
|
|
case STATE_QUEUED_UP:
|
|
|
|
return get_queued_icon();
|
|
|
|
case STATE_CHECKING_UP:
|
|
|
|
case STATE_CHECKING_DL:
|
|
|
|
case STATE_QUEUED_CHECK:
|
|
|
|
case STATE_QUEUED_FASTCHECK:
|
|
|
|
return get_checking_icon();
|
|
|
|
case STATE_INVALID:
|
|
|
|
return get_error_icon();
|
|
|
|
default:
|
|
|
|
Q_ASSERT(false);
|
|
|
|
return get_error_icon();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
QColor TorrentModelItem::getColorByState(State state) {
|
|
|
|
switch (state) {
|
|
|
|
case STATE_DOWNLOADING:
|
|
|
|
case STATE_DOWNLOADING_META:
|
|
|
|
return QColor(Qt::green);
|
|
|
|
case STATE_ALLOCATING:
|
|
|
|
case STATE_STALLED_DL:
|
|
|
|
case STATE_STALLED_UP:
|
|
|
|
return QColor(Qt::gray);
|
|
|
|
case STATE_SEEDING:
|
|
|
|
return QColor(255, 165, 0);
|
|
|
|
case STATE_PAUSED_DL:
|
|
|
|
case STATE_PAUSED_UP:
|
|
|
|
return QColor(Qt::red);
|
|
|
|
case STATE_QUEUED_DL:
|
|
|
|
case STATE_QUEUED_UP:
|
|
|
|
case STATE_CHECKING_UP:
|
|
|
|
case STATE_CHECKING_DL:
|
|
|
|
case STATE_QUEUED_CHECK:
|
|
|
|
case STATE_QUEUED_FASTCHECK:
|
|
|
|
return QColor(Qt::gray);
|
|
|
|
case STATE_INVALID:
|
|
|
|
return QColor(Qt::red);
|
|
|
|
default:
|
|
|
|
Q_ASSERT(false);
|
|
|
|
return QColor(Qt::red);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-11-14 18:28:22 +03:00
|
|
|
bool TorrentModelItem::setData(int column, const QVariant &value, int role)
|
|
|
|
{
|
2010-11-14 21:46:16 +03:00
|
|
|
qDebug() << Q_FUNC_INFO << column << value;
|
2012-02-20 21:30:53 +04:00
|
|
|
if (role != Qt::DisplayRole) return false;
|
2012-09-10 22:09:22 +04:00
|
|
|
// Label, seed date and Name columns can be edited
|
2010-11-14 18:28:22 +03:00
|
|
|
switch(column) {
|
|
|
|
case TR_NAME:
|
|
|
|
m_name = value.toString();
|
|
|
|
TorrentPersistentData::saveName(m_torrent.hash(), m_name);
|
|
|
|
return true;
|
|
|
|
case TR_LABEL: {
|
|
|
|
QString new_label = value.toString();
|
2012-02-20 21:30:53 +04:00
|
|
|
if (m_label != new_label) {
|
2010-11-14 18:28:22 +03:00
|
|
|
QString old_label = m_label;
|
|
|
|
m_label = new_label;
|
|
|
|
TorrentPersistentData::saveLabel(m_torrent.hash(), new_label);
|
|
|
|
emit labelChanged(old_label, new_label);
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
QVariant TorrentModelItem::data(int column, int role) const
|
|
|
|
{
|
2012-02-20 21:30:53 +04:00
|
|
|
if (role == Qt::DecorationRole && column == TR_NAME) {
|
2014-10-25 14:12:05 +04:00
|
|
|
return getIconByState(state());
|
2010-11-14 18:28:22 +03:00
|
|
|
}
|
2012-02-20 21:30:53 +04:00
|
|
|
if (role == Qt::ForegroundRole) {
|
2014-10-25 14:12:05 +04:00
|
|
|
return getColorByState(state());
|
2010-11-14 18:28:22 +03:00
|
|
|
}
|
2012-02-20 21:30:53 +04:00
|
|
|
if (role != Qt::DisplayRole && role != Qt::UserRole) return QVariant();
|
2010-11-14 18:28:22 +03:00
|
|
|
switch(column) {
|
|
|
|
case TR_NAME:
|
2013-09-18 01:44:18 +04:00
|
|
|
return m_name.isEmpty() ? m_torrent.name() : m_name;
|
|
|
|
case TR_PRIORITY: {
|
2014-10-20 21:39:13 +04:00
|
|
|
int pos = m_torrent.queue_position(m_lastStatus);
|
2013-09-18 01:44:18 +04:00
|
|
|
if (pos > -1)
|
|
|
|
return pos - HiddenData::getSize();
|
|
|
|
else
|
|
|
|
return pos;
|
|
|
|
}
|
2010-11-14 18:28:22 +03:00
|
|
|
case TR_SIZE:
|
2014-05-14 02:09:45 +04:00
|
|
|
return m_lastStatus.has_metadata ? static_cast<qlonglong>(m_lastStatus.total_wanted) : -1;
|
2010-11-14 18:28:22 +03:00
|
|
|
case TR_PROGRESS:
|
2014-05-14 02:09:45 +04:00
|
|
|
return m_torrent.progress(m_lastStatus);
|
2010-11-14 18:28:22 +03:00
|
|
|
case TR_STATUS:
|
|
|
|
return state();
|
|
|
|
case TR_SEEDS: {
|
2014-05-14 02:09:45 +04:00
|
|
|
return (role == Qt::DisplayRole) ? m_lastStatus.num_seeds : m_lastStatus.num_complete;
|
2010-11-14 18:28:22 +03:00
|
|
|
}
|
|
|
|
case TR_PEERS: {
|
2014-05-14 02:09:45 +04:00
|
|
|
return (role == Qt::DisplayRole) ? (m_lastStatus.num_peers-m_lastStatus.num_seeds) : m_lastStatus.num_incomplete;
|
2010-11-14 18:28:22 +03:00
|
|
|
}
|
|
|
|
case TR_DLSPEED:
|
2014-05-14 02:09:45 +04:00
|
|
|
return m_lastStatus.download_payload_rate;
|
2010-11-14 18:28:22 +03:00
|
|
|
case TR_UPSPEED:
|
2014-05-14 02:09:45 +04:00
|
|
|
return m_lastStatus.upload_payload_rate;
|
2010-11-14 18:28:22 +03:00
|
|
|
case TR_ETA: {
|
|
|
|
// XXX: Is this correct?
|
2014-05-14 02:09:45 +04:00
|
|
|
if (m_torrent.is_paused(m_lastStatus) || m_torrent.is_queued(m_lastStatus)) return MAX_ETA;
|
|
|
|
return QBtSession::instance()->getETA(m_hash, m_lastStatus);
|
2010-11-14 18:28:22 +03:00
|
|
|
}
|
|
|
|
case TR_RATIO:
|
2014-05-14 02:09:45 +04:00
|
|
|
return QBtSession::instance()->getRealRatio(m_lastStatus);
|
2010-11-14 18:28:22 +03:00
|
|
|
case TR_LABEL:
|
|
|
|
return m_label;
|
|
|
|
case TR_ADD_DATE:
|
|
|
|
return m_addedTime;
|
|
|
|
case TR_SEED_DATE:
|
2014-06-07 15:44:08 +04:00
|
|
|
return m_lastStatus.completed_time ? QDateTime::fromTime_t(m_lastStatus.completed_time) : QDateTime();
|
2010-11-14 18:28:22 +03:00
|
|
|
case TR_TRACKER:
|
2014-05-14 02:09:45 +04:00
|
|
|
return misc::toQString(m_lastStatus.current_tracker);
|
2010-11-14 18:28:22 +03:00
|
|
|
case TR_DLLIMIT:
|
|
|
|
return m_torrent.download_limit();
|
|
|
|
case TR_UPLIMIT:
|
|
|
|
return m_torrent.upload_limit();
|
2010-11-16 20:43:54 +03:00
|
|
|
case TR_AMOUNT_DOWNLOADED:
|
2014-05-14 02:09:45 +04:00
|
|
|
return static_cast<qlonglong>(m_lastStatus.all_time_download);
|
2012-12-27 17:55:40 +04:00
|
|
|
case TR_AMOUNT_UPLOADED:
|
2014-05-14 02:09:45 +04:00
|
|
|
return static_cast<qlonglong>(m_lastStatus.all_time_upload);
|
2010-11-16 20:43:54 +03:00
|
|
|
case TR_AMOUNT_LEFT:
|
2014-05-14 02:09:45 +04:00
|
|
|
return static_cast<qlonglong>(m_lastStatus.total_wanted - m_lastStatus.total_wanted_done);
|
2010-12-21 21:25:44 +03:00
|
|
|
case TR_TIME_ELAPSED:
|
2014-05-14 02:09:45 +04:00
|
|
|
return (role == Qt::DisplayRole) ? m_lastStatus.active_time : m_lastStatus.seeding_time;
|
2013-05-01 09:52:06 +04:00
|
|
|
case TR_SAVE_PATH:
|
2013-11-10 23:25:16 +04:00
|
|
|
return fsutils::toNativePath(m_torrent.save_path_parsed());
|
2014-08-14 21:19:35 +04:00
|
|
|
case TR_COMPLETED:
|
|
|
|
return static_cast<qlonglong>(m_lastStatus.total_wanted_done);
|
2014-08-14 21:46:55 +04:00
|
|
|
case TR_RATIO_LIMIT: {
|
|
|
|
QString hash = misc::toQString(m_lastStatus.info_hash);
|
|
|
|
return QBtSession::instance()->getMaxRatioPerTorrent(hash, NULL);
|
|
|
|
}
|
2014-10-24 23:41:03 +04:00
|
|
|
case TR_SEEN_COMPLETE_DATE:
|
|
|
|
return m_lastStatus.last_seen_complete ? QDateTime::fromTime_t(m_lastStatus.last_seen_complete) : QDateTime();
|
2010-11-14 18:28:22 +03:00
|
|
|
default:
|
|
|
|
return QVariant();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// TORRENT MODEL
|
|
|
|
|
|
|
|
TorrentModel::TorrentModel(QObject *parent) :
|
|
|
|
QAbstractListModel(parent), m_refreshInterval(2000)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void TorrentModel::populate() {
|
|
|
|
// Load the torrents
|
|
|
|
std::vector<torrent_handle> torrents = QBtSession::instance()->getSession()->get_torrents();
|
2012-07-14 02:28:23 +04:00
|
|
|
|
|
|
|
std::vector<torrent_handle>::const_iterator it = torrents.begin();
|
|
|
|
std::vector<torrent_handle>::const_iterator itend = torrents.end();
|
|
|
|
for ( ; it != itend; ++it) {
|
2014-08-09 23:07:32 +04:00
|
|
|
const QTorrentHandle h(*it);
|
|
|
|
if (HiddenData::hasData(h.hash()))
|
|
|
|
continue;
|
|
|
|
addTorrent(h);
|
2010-11-14 18:28:22 +03:00
|
|
|
}
|
|
|
|
// Refresh timer
|
|
|
|
connect(&m_refreshTimer, SIGNAL(timeout()), SLOT(forceModelRefresh()));
|
|
|
|
m_refreshTimer.start(m_refreshInterval);
|
|
|
|
// Listen for torrent changes
|
|
|
|
connect(QBtSession::instance(), SIGNAL(addedTorrent(QTorrentHandle)), SLOT(addTorrent(QTorrentHandle)));
|
2010-11-14 21:46:16 +03:00
|
|
|
connect(QBtSession::instance(), SIGNAL(torrentAboutToBeRemoved(QTorrentHandle)), SLOT(handleTorrentAboutToBeRemoved(QTorrentHandle)));
|
2010-11-14 18:28:22 +03:00
|
|
|
connect(QBtSession::instance(), SIGNAL(deletedTorrent(QString)), SLOT(removeTorrent(QString)));
|
2012-09-10 22:09:22 +04:00
|
|
|
connect(QBtSession::instance(), SIGNAL(finishedTorrent(QTorrentHandle)), SLOT(handleFinishedTorrent(QTorrentHandle)));
|
2010-11-24 23:31:14 +03:00
|
|
|
connect(QBtSession::instance(), SIGNAL(metadataReceived(QTorrentHandle)), SLOT(handleTorrentUpdate(QTorrentHandle)));
|
|
|
|
connect(QBtSession::instance(), SIGNAL(resumedTorrent(QTorrentHandle)), SLOT(handleTorrentUpdate(QTorrentHandle)));
|
|
|
|
connect(QBtSession::instance(), SIGNAL(pausedTorrent(QTorrentHandle)), SLOT(handleTorrentUpdate(QTorrentHandle)));
|
|
|
|
connect(QBtSession::instance(), SIGNAL(torrentFinishedChecking(QTorrentHandle)), SLOT(handleTorrentUpdate(QTorrentHandle)));
|
2014-05-18 12:07:49 +04:00
|
|
|
connect(QBtSession::instance(), SIGNAL(stateUpdate(std::vector<libtorrent::torrent_status>)), SLOT(stateUpdated(std::vector<libtorrent::torrent_status>)));
|
2010-11-14 18:28:22 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
TorrentModel::~TorrentModel() {
|
2011-03-14 22:18:52 +03:00
|
|
|
qDebug() << Q_FUNC_INFO << "ENTER";
|
2010-11-14 18:28:22 +03:00
|
|
|
qDeleteAll(m_torrents);
|
|
|
|
m_torrents.clear();
|
2011-03-14 22:18:52 +03:00
|
|
|
qDebug() << Q_FUNC_INFO << "EXIT";
|
2010-11-14 18:28:22 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
QVariant TorrentModel::headerData(int section, Qt::Orientation orientation,
|
|
|
|
int role) const
|
|
|
|
{
|
|
|
|
if (orientation == Qt::Horizontal) {
|
2012-02-20 21:30:53 +04:00
|
|
|
if (role == Qt::DisplayRole) {
|
2010-11-14 18:28:22 +03:00
|
|
|
switch(section) {
|
|
|
|
case TorrentModelItem::TR_NAME: return tr("Name", "i.e: torrent name");
|
|
|
|
case TorrentModelItem::TR_PRIORITY: return "#";
|
|
|
|
case TorrentModelItem::TR_SIZE: return tr("Size", "i.e: torrent size");
|
|
|
|
case TorrentModelItem::TR_PROGRESS: return tr("Done", "% Done");
|
|
|
|
case TorrentModelItem::TR_STATUS: return tr("Status", "Torrent status (e.g. downloading, seeding, paused)");
|
|
|
|
case TorrentModelItem::TR_SEEDS: return tr("Seeds", "i.e. full sources (often untranslated)");
|
|
|
|
case TorrentModelItem::TR_PEERS: return tr("Peers", "i.e. partial sources (often untranslated)");
|
|
|
|
case TorrentModelItem::TR_DLSPEED: return tr("Down Speed", "i.e: Download speed");
|
|
|
|
case TorrentModelItem::TR_UPSPEED: return tr("Up Speed", "i.e: Upload speed");
|
|
|
|
case TorrentModelItem::TR_RATIO: return tr("Ratio", "Share ratio");
|
|
|
|
case TorrentModelItem::TR_ETA: return tr("ETA", "i.e: Estimated Time of Arrival / Time left");
|
|
|
|
case TorrentModelItem::TR_LABEL: return tr("Label");
|
|
|
|
case TorrentModelItem::TR_ADD_DATE: return tr("Added On", "Torrent was added to transfer list on 01/01/2010 08:00");
|
|
|
|
case TorrentModelItem::TR_SEED_DATE: return tr("Completed On", "Torrent was completed on 01/01/2010 08:00");
|
|
|
|
case TorrentModelItem::TR_TRACKER: return tr("Tracker");
|
|
|
|
case TorrentModelItem::TR_DLLIMIT: return tr("Down Limit", "i.e: Download limit");
|
|
|
|
case TorrentModelItem::TR_UPLIMIT: return tr("Up Limit", "i.e: Upload limit");
|
2014-01-25 23:28:34 +04:00
|
|
|
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_LEFT: return tr("Remaining", "Amount of data left to download (e.g. in MB)");
|
2010-12-21 21:25:44 +03:00
|
|
|
case TorrentModelItem::TR_TIME_ELAPSED: return tr("Time Active", "Time (duration) the torrent is active (not paused)");
|
2013-05-01 09:52:06 +04:00
|
|
|
case TorrentModelItem::TR_SAVE_PATH: return tr("Save path", "Torrent save path");
|
2014-08-14 21:19:35 +04:00
|
|
|
case TorrentModelItem::TR_COMPLETED: return tr("Completed", "Amount of data completed (e.g. in MB)");
|
2014-08-14 21:46:55 +04:00
|
|
|
case TorrentModelItem::TR_RATIO_LIMIT: return tr("Ratio Limit", "Upload share ratio limit");
|
2014-10-24 23:41:03 +04:00
|
|
|
case TorrentModelItem::TR_SEEN_COMPLETE_DATE: return tr("Last Seen Complete", "Torrent was seen complete on 01/01/2010 08:00");
|
2010-11-14 18:28:22 +03:00
|
|
|
default:
|
|
|
|
return QVariant();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return QVariant();
|
|
|
|
}
|
|
|
|
|
|
|
|
QVariant TorrentModel::data(const QModelIndex &index, int role) const
|
|
|
|
{
|
2012-02-20 21:30:53 +04:00
|
|
|
if (!index.isValid()) return QVariant();
|
2010-11-14 18:28:22 +03:00
|
|
|
try {
|
2012-02-20 21:30:53 +04:00
|
|
|
if (index.row() >= 0 && index.row() < rowCount() && index.column() >= 0 && index.column() < columnCount())
|
2010-11-14 18:28:22 +03:00
|
|
|
return m_torrents[index.row()]->data(index.column(), role);
|
|
|
|
} catch(invalid_handle&) {}
|
|
|
|
return QVariant();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool TorrentModel::setData(const QModelIndex &index, const QVariant &value, int role)
|
|
|
|
{
|
2010-11-14 21:46:16 +03:00
|
|
|
qDebug() << Q_FUNC_INFO << value;
|
2012-02-20 21:30:53 +04:00
|
|
|
if (!index.isValid() || role != Qt::DisplayRole) return false;
|
2010-11-14 21:46:16 +03:00
|
|
|
qDebug("Index is valid and role is DisplayRole");
|
2010-11-14 18:28:22 +03:00
|
|
|
try {
|
2012-02-20 21:30:53 +04:00
|
|
|
if (index.row() >= 0 && index.row() < rowCount() && index.column() >= 0 && index.column() < columnCount()) {
|
2010-11-14 18:28:22 +03:00
|
|
|
bool change = m_torrents[index.row()]->setData(index.column(), value, role);
|
2012-02-20 21:30:53 +04:00
|
|
|
if (change)
|
2010-11-14 18:28:22 +03:00
|
|
|
notifyTorrentChanged(index.row());
|
|
|
|
return change;
|
|
|
|
}
|
|
|
|
} catch(invalid_handle&) {}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
int TorrentModel::torrentRow(const QString &hash) const
|
|
|
|
{
|
2010-11-14 21:50:32 +03:00
|
|
|
int row = 0;
|
2012-07-14 02:28:23 +04:00
|
|
|
|
|
|
|
QList<TorrentModelItem*>::const_iterator it = m_torrents.constBegin();
|
|
|
|
QList<TorrentModelItem*>::const_iterator itend = m_torrents.constEnd();
|
|
|
|
for ( ; it != itend; ++it) {
|
2012-02-20 21:30:53 +04:00
|
|
|
if ((*it)->hash() == hash) return row;
|
2010-11-14 18:28:22 +03:00
|
|
|
++row;
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
void TorrentModel::addTorrent(const QTorrentHandle &h)
|
|
|
|
{
|
2012-02-20 21:30:53 +04:00
|
|
|
if (torrentRow(h.hash()) < 0) {
|
2010-11-14 18:28:22 +03:00
|
|
|
beginInsertTorrent(m_torrents.size());
|
|
|
|
TorrentModelItem *item = new TorrentModelItem(h);
|
|
|
|
connect(item, SIGNAL(labelChanged(QString,QString)), SLOT(handleTorrentLabelChange(QString,QString)));
|
|
|
|
m_torrents << item;
|
|
|
|
emit torrentAdded(item);
|
|
|
|
endInsertTorrent();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void TorrentModel::removeTorrent(const QString &hash)
|
|
|
|
{
|
|
|
|
const int row = torrentRow(hash);
|
2010-11-14 21:46:16 +03:00
|
|
|
qDebug() << Q_FUNC_INFO << hash << row;
|
2012-02-20 21:30:53 +04:00
|
|
|
if (row >= 0) {
|
2010-11-14 18:28:22 +03:00
|
|
|
beginRemoveTorrent(row);
|
2014-11-02 14:54:10 +03:00
|
|
|
delete m_torrents[row];
|
2010-11-14 18:28:22 +03:00
|
|
|
m_torrents.removeAt(row);
|
|
|
|
endRemoveTorrent();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void TorrentModel::beginInsertTorrent(int row)
|
|
|
|
{
|
|
|
|
beginInsertRows(QModelIndex(), row, row);
|
|
|
|
}
|
|
|
|
|
|
|
|
void TorrentModel::endInsertTorrent()
|
|
|
|
{
|
|
|
|
endInsertRows();
|
|
|
|
}
|
|
|
|
|
|
|
|
void TorrentModel::beginRemoveTorrent(int row)
|
|
|
|
{
|
|
|
|
beginRemoveRows(QModelIndex(), row, row);
|
|
|
|
}
|
|
|
|
|
|
|
|
void TorrentModel::endRemoveTorrent()
|
|
|
|
{
|
|
|
|
endRemoveRows();
|
|
|
|
}
|
|
|
|
|
2010-11-24 23:31:14 +03:00
|
|
|
void TorrentModel::handleTorrentUpdate(const QTorrentHandle &h)
|
2010-11-14 18:28:22 +03:00
|
|
|
{
|
|
|
|
const int row = torrentRow(h.hash());
|
2012-02-20 21:30:53 +04:00
|
|
|
if (row >= 0) {
|
2014-05-18 12:07:49 +04:00
|
|
|
m_torrents[row]->refreshStatus(h.status(torrent_handle::query_accurate_download_counters));
|
2010-11-14 18:28:22 +03:00
|
|
|
notifyTorrentChanged(row);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-09-10 22:09:22 +04:00
|
|
|
void TorrentModel::handleFinishedTorrent(const QTorrentHandle& h)
|
|
|
|
{
|
|
|
|
const int row = torrentRow(h.hash());
|
|
|
|
if (row < 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
// Update completion date
|
2014-05-18 12:07:49 +04:00
|
|
|
m_torrents[row]->refreshStatus(h.status(torrent_handle::query_accurate_download_counters));
|
2012-09-10 22:09:22 +04:00
|
|
|
notifyTorrentChanged(row);
|
|
|
|
}
|
|
|
|
|
2010-11-14 18:28:22 +03:00
|
|
|
void TorrentModel::notifyTorrentChanged(int row)
|
|
|
|
{
|
|
|
|
emit dataChanged(index(row, 0), index(row, columnCount()-1));
|
|
|
|
}
|
|
|
|
|
|
|
|
void TorrentModel::setRefreshInterval(int refreshInterval)
|
|
|
|
{
|
2012-02-20 21:30:53 +04:00
|
|
|
if (m_refreshInterval != refreshInterval) {
|
2010-11-14 18:28:22 +03:00
|
|
|
m_refreshInterval = refreshInterval;
|
|
|
|
m_refreshTimer.stop();
|
|
|
|
m_refreshTimer.start(m_refreshInterval);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void TorrentModel::forceModelRefresh()
|
|
|
|
{
|
|
|
|
emit dataChanged(index(0, 0), index(rowCount()-1, columnCount()-1));
|
2014-05-18 12:07:49 +04:00
|
|
|
QBtSession::instance()->postTorrentUpdate();
|
2010-11-14 18:28:22 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
TorrentStatusReport TorrentModel::getTorrentStatusReport() const
|
|
|
|
{
|
|
|
|
TorrentStatusReport report;
|
2012-07-14 02:28:23 +04:00
|
|
|
|
|
|
|
QList<TorrentModelItem*>::const_iterator it = m_torrents.constBegin();
|
|
|
|
QList<TorrentModelItem*>::const_iterator itend = m_torrents.constEnd();
|
|
|
|
for ( ; it != itend; ++it) {
|
2014-10-25 14:13:09 +04:00
|
|
|
switch((*it)->state()) {
|
2010-11-14 18:28:22 +03:00
|
|
|
case TorrentModelItem::STATE_DOWNLOADING:
|
|
|
|
++report.nb_active;
|
|
|
|
++report.nb_downloading;
|
|
|
|
break;
|
2014-05-15 22:59:39 +04:00
|
|
|
case TorrentModelItem::STATE_DOWNLOADING_META:
|
|
|
|
++report.nb_downloading;
|
|
|
|
break;
|
2010-11-14 18:28:22 +03:00
|
|
|
case TorrentModelItem::STATE_PAUSED_DL:
|
|
|
|
++report.nb_paused;
|
|
|
|
case TorrentModelItem::STATE_STALLED_DL:
|
|
|
|
case TorrentModelItem::STATE_CHECKING_DL:
|
|
|
|
case TorrentModelItem::STATE_QUEUED_DL: {
|
|
|
|
++report.nb_inactive;
|
|
|
|
++report.nb_downloading;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case TorrentModelItem::STATE_SEEDING:
|
|
|
|
++report.nb_active;
|
|
|
|
++report.nb_seeding;
|
|
|
|
break;
|
|
|
|
case TorrentModelItem::STATE_PAUSED_UP:
|
|
|
|
++report.nb_paused;
|
|
|
|
case TorrentModelItem::STATE_STALLED_UP:
|
|
|
|
case TorrentModelItem::STATE_CHECKING_UP:
|
|
|
|
case TorrentModelItem::STATE_QUEUED_UP: {
|
|
|
|
++report.nb_seeding;
|
|
|
|
++report.nb_inactive;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return report;
|
|
|
|
}
|
|
|
|
|
|
|
|
Qt::ItemFlags TorrentModel::flags(const QModelIndex &index) const
|
|
|
|
{
|
|
|
|
if (!index.isValid())
|
|
|
|
return 0;
|
|
|
|
// Explicitely mark as editable
|
|
|
|
return QAbstractListModel::flags(index) | Qt::ItemIsEditable;
|
|
|
|
}
|
|
|
|
|
|
|
|
void TorrentModel::handleTorrentLabelChange(QString previous, QString current)
|
|
|
|
{
|
|
|
|
emit torrentChangedLabel(static_cast<TorrentModelItem*>(sender()), previous, current);
|
|
|
|
}
|
|
|
|
|
|
|
|
QString TorrentModel::torrentHash(int row) const
|
|
|
|
{
|
2012-02-20 21:30:53 +04:00
|
|
|
if (row >= 0 && row < rowCount())
|
2010-11-14 18:28:22 +03:00
|
|
|
return m_torrents.at(row)->hash();
|
|
|
|
return QString();
|
|
|
|
}
|
2010-11-14 21:46:16 +03:00
|
|
|
|
|
|
|
void TorrentModel::handleTorrentAboutToBeRemoved(const QTorrentHandle &h)
|
|
|
|
{
|
|
|
|
const int row = torrentRow(h.hash());
|
2012-02-20 21:30:53 +04:00
|
|
|
if (row >= 0) {
|
2010-11-14 21:46:16 +03:00
|
|
|
emit torrentAboutToBeRemoved(m_torrents.at(row));
|
|
|
|
}
|
|
|
|
}
|
2013-11-16 21:29:50 +04:00
|
|
|
|
2014-06-03 21:35:50 +04:00
|
|
|
void TorrentModel::stateUpdated(const std::vector<libtorrent::torrent_status> &statuses) {
|
2014-05-18 12:07:49 +04:00
|
|
|
typedef std::vector<libtorrent::torrent_status> statuses_t;
|
|
|
|
|
2014-06-03 21:35:50 +04:00
|
|
|
for (statuses_t::const_iterator i = statuses.begin(), end = statuses.end(); i != end; ++i) {
|
2014-05-18 12:07:49 +04:00
|
|
|
libtorrent::torrent_status const& status = *i;
|
|
|
|
|
2014-10-11 02:37:25 +04:00
|
|
|
const int row = torrentRow(misc::toQString(status.info_hash));
|
2014-05-18 12:07:49 +04:00
|
|
|
if (row >= 0)
|
|
|
|
m_torrents[row]->refreshStatus(status);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-11-16 21:29:50 +04:00
|
|
|
bool TorrentModel::inhibitSystem()
|
|
|
|
{
|
|
|
|
QList<TorrentModelItem*>::const_iterator it = m_torrents.constBegin();
|
|
|
|
QList<TorrentModelItem*>::const_iterator itend = m_torrents.constEnd();
|
|
|
|
for ( ; it != itend; ++it) {
|
|
|
|
switch((*it)->data(TorrentModelItem::TR_STATUS).toInt()) {
|
|
|
|
case TorrentModelItem::STATE_DOWNLOADING:
|
2014-05-15 22:59:39 +04:00
|
|
|
case TorrentModelItem::STATE_DOWNLOADING_META:
|
2013-11-16 21:29:50 +04:00
|
|
|
case TorrentModelItem::STATE_STALLED_DL:
|
|
|
|
case TorrentModelItem::STATE_SEEDING:
|
|
|
|
case TorrentModelItem::STATE_STALLED_UP:
|
|
|
|
return true;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|