mirror of
https://github.com/transmission/transmission
synced 2024-12-25 01:03:01 +00:00
be74cb6356
* Bump minimum Qt version to 5.6 * Switch from QRegExp to QRegularExpression While still available, QRegExp has been moved to Qt6::Core5Compat module and is not part of Qt6::Core. * Use qIsEffectiveTLD instead of QUrl::topLevelDomain The latter is not part of Qt6::Core. The former is a private utility in Qt6::Network; using it for now, until (and if) we switch to something non-Qt-specific. * Use QStyle::State_Horizontal state when drawing progress bars Although available for a long time, this state either didn't apply to progress bars before Qt 6, or was deduced based on bar size. With Qt 6, failing to specify it results in bad rendering. * Don't use QStringRef (and associated methods) While still available, QStringRef has been moved to Qt6::Core5Compat module and is not part of Qt6::Core. Related method (e.g. QString::midRef) have been removed in Qt 6. * Use Qt::ItemIsAutoTristate instead of Qt::ItemIsTristate The latter was deprecated and replaced with the former in Qt 5.6. * Don't use QApplication::globalStrut This property has been deprecated in Qt 5.15 and removed in Qt 6. * Use QImage::fromHICON instead of QtWin::fromHICON WinExtras module (providind the latter helper) has been removed in Qt 6. * Use QStringDecoder instead of QTextCodec While still available, QTextCodec has been moved to Qt6::Core5Compat module and is not part of Qt6::Core. * Don't forward-declare QStringList Instead of being a standalone class, its definition has changed to QList<QString> template specialization in Qt 6. * Use explicit (since Qt 6) QFileInfo constructor * Use QDateTime's {to,from}SecsSinceEpoch instead of {to,from}Time_t The latter was deprecated in Qt 5.8 and removed in Qt 6. * Don't use QFuture<>'s operator== It has been removed in Qt 6. Since the original issue this code was solving was caused by future reuse, just don't reuse futures and create new finished ones when necessary. * Use std::vector<> instead of QVector<> The latter has been changed to a typedef for QList<>, which might not be what one wants, and which also changed behavior a bit leading to compilation errors. * Don't use + for flags, cast to int explicitly Operator+ for enum values has been deleted in Qt 6, so using operator| instead. Then, there's no conversion from QFlags<> to QVariant, so need to cast to int. * Support Qt 6 in CMake and for MSI packaging * Remove extra (empty) CMake variable use when constructing Qt target names * Simplify logic in tr_qt_add_translation CMake helper Co-authored-by: Charles Kerr <charles@charleskerr.com>
689 lines
13 KiB
C++
689 lines
13 KiB
C++
/*
|
|
* This file Copyright (C) 2009-2015 Mnemosyne LLC
|
|
*
|
|
* It may be used under the GNU GPL versions 2 or 3
|
|
* or any future license endorsed by Mnemosyne LLC.
|
|
*
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include <array>
|
|
#include <bitset>
|
|
#include <ctime> // time_t
|
|
#include <vector>
|
|
|
|
#include <QIcon>
|
|
#include <QMetaType>
|
|
#include <QObject>
|
|
#include <QString>
|
|
|
|
#include <libtransmission/transmission.h>
|
|
#include <libtransmission/crypto-utils.h>
|
|
#include <libtransmission/quark.h>
|
|
|
|
#include "FaviconCache.h"
|
|
#include "IconCache.h"
|
|
#include "Macros.h"
|
|
#include "Speed.h"
|
|
|
|
#ifdef ERROR
|
|
#undef ERROR
|
|
#endif
|
|
|
|
class QPixmap;
|
|
|
|
class Prefs;
|
|
|
|
extern "C"
|
|
{
|
|
struct tr_variant;
|
|
}
|
|
|
|
struct Peer
|
|
{
|
|
bool client_is_choked;
|
|
bool client_is_interested;
|
|
bool is_downloading_from;
|
|
bool is_encrypted;
|
|
bool is_incoming;
|
|
bool is_uploading_to;
|
|
bool peer_is_choked;
|
|
bool peer_is_interested;
|
|
QString address;
|
|
QString client_name;
|
|
QString flags;
|
|
int port;
|
|
Speed rate_to_client;
|
|
Speed rate_to_peer;
|
|
double progress;
|
|
};
|
|
|
|
using PeerList = std::vector<Peer>;
|
|
|
|
struct TrackerStat
|
|
{
|
|
QPixmap getFavicon() const;
|
|
|
|
bool has_announced;
|
|
bool has_scraped;
|
|
bool is_backup;
|
|
bool last_announce_succeeded;
|
|
bool last_announce_timed_out;
|
|
bool last_scrape_succeeded;
|
|
bool last_scrape_timed_out;
|
|
int announce_state;
|
|
int download_count;
|
|
int id;
|
|
int last_announce_peer_count;
|
|
int last_announce_start_time;
|
|
int last_announce_time;
|
|
int last_scrape_start_time;
|
|
int last_scrape_time;
|
|
int leecher_count;
|
|
int next_announce_time;
|
|
int next_scrape_time;
|
|
int scrape_state;
|
|
int seeder_count;
|
|
int tier;
|
|
FaviconCache::Key favicon_key;
|
|
QString announce;
|
|
QString last_announce_result;
|
|
QString last_scrape_result;
|
|
};
|
|
|
|
using TrackerStatsList = std::vector<TrackerStat>;
|
|
|
|
struct TorrentFile
|
|
{
|
|
bool wanted = true;
|
|
int index = -1;
|
|
int priority = 0;
|
|
QString filename;
|
|
uint64_t size = 0;
|
|
uint64_t have = 0;
|
|
};
|
|
|
|
using FileList = std::vector<TorrentFile>;
|
|
|
|
class TorrentHash
|
|
{
|
|
private:
|
|
std::array<uint8_t, SHA_DIGEST_LENGTH> data_ = {};
|
|
|
|
public:
|
|
TorrentHash()
|
|
{
|
|
}
|
|
|
|
explicit TorrentHash(char const* str)
|
|
{
|
|
tr_hex_to_sha1(data_.data(), str);
|
|
}
|
|
|
|
explicit TorrentHash(QString const& str)
|
|
{
|
|
tr_hex_to_sha1(data_.data(), str.toUtf8().constData());
|
|
}
|
|
|
|
bool operator==(TorrentHash const& that) const
|
|
{
|
|
return data_ == that.data_;
|
|
}
|
|
|
|
bool operator!=(TorrentHash const& that) const
|
|
{
|
|
return data_ != that.data_;
|
|
}
|
|
|
|
bool operator<(TorrentHash const& that) const
|
|
{
|
|
return data_ < that.data_;
|
|
}
|
|
|
|
QString toString() const
|
|
{
|
|
char str[SHA_DIGEST_LENGTH * 2 + 1];
|
|
tr_sha1_to_hex(str, data_.data());
|
|
return QString::fromUtf8(str, SHA_DIGEST_LENGTH * 2);
|
|
}
|
|
};
|
|
|
|
class Torrent : public QObject
|
|
{
|
|
Q_OBJECT
|
|
TR_DISABLE_COPY_MOVE(Torrent)
|
|
|
|
public:
|
|
Torrent(Prefs const&, int id);
|
|
|
|
int getBandwidthPriority() const
|
|
{
|
|
return bandwidth_priority_;
|
|
}
|
|
|
|
int id() const
|
|
{
|
|
return id_;
|
|
}
|
|
|
|
QString const& name() const
|
|
{
|
|
return name_;
|
|
}
|
|
|
|
bool hasName() const
|
|
{
|
|
return !name_.isEmpty();
|
|
}
|
|
|
|
QString const& creator() const
|
|
{
|
|
return creator_;
|
|
}
|
|
|
|
QString const& comment() const
|
|
{
|
|
return comment_;
|
|
}
|
|
|
|
QString const& getPath() const
|
|
{
|
|
return download_dir_;
|
|
}
|
|
|
|
QString getError() const;
|
|
|
|
TorrentHash const& hash() const
|
|
{
|
|
return hash_;
|
|
}
|
|
|
|
bool hasError() const
|
|
{
|
|
return error_ != TR_STAT_OK;
|
|
}
|
|
|
|
bool isDone() const
|
|
{
|
|
return leftUntilDone() == 0;
|
|
}
|
|
|
|
bool isSeed() const
|
|
{
|
|
return haveVerified() >= totalSize();
|
|
}
|
|
|
|
bool isPrivate() const
|
|
{
|
|
return is_private_;
|
|
}
|
|
|
|
bool getSeedRatio(double& setmeRatio) const;
|
|
|
|
uint64_t haveVerified() const
|
|
{
|
|
return have_verified_;
|
|
}
|
|
|
|
uint64_t haveUnverified() const
|
|
{
|
|
return have_unchecked_;
|
|
}
|
|
|
|
uint64_t desiredAvailable() const
|
|
{
|
|
return desired_available_;
|
|
}
|
|
|
|
uint64_t haveTotal() const
|
|
{
|
|
return haveVerified() + haveUnverified();
|
|
}
|
|
|
|
uint64_t totalSize() const
|
|
{
|
|
return total_size_;
|
|
}
|
|
|
|
uint64_t sizeWhenDone() const
|
|
{
|
|
return size_when_done_;
|
|
}
|
|
|
|
uint64_t leftUntilDone() const
|
|
{
|
|
return left_until_done_;
|
|
}
|
|
|
|
uint64_t pieceSize() const
|
|
{
|
|
return piece_size_;
|
|
}
|
|
|
|
bool hasMetadata() const
|
|
{
|
|
return metadataPercentDone() >= 1.0;
|
|
}
|
|
|
|
int pieceCount() const
|
|
{
|
|
return piece_count_;
|
|
}
|
|
|
|
double ratio() const
|
|
{
|
|
auto const u = uploadedEver();
|
|
auto const d = downloadedEver();
|
|
auto const t = totalSize();
|
|
return double(u) / (d ? d : t);
|
|
}
|
|
|
|
double percentComplete() const
|
|
{
|
|
return totalSize() != 0 ? haveTotal() / static_cast<double>(totalSize()) : 0;
|
|
}
|
|
|
|
double percentDone() const
|
|
{
|
|
auto const l = leftUntilDone();
|
|
auto const s = sizeWhenDone();
|
|
return s ? static_cast<double>(s - l) / static_cast<double>(s) : 0.0;
|
|
}
|
|
|
|
double metadataPercentDone() const
|
|
{
|
|
return metadata_percent_complete_;
|
|
}
|
|
|
|
uint64_t downloadedEver() const
|
|
{
|
|
return downloaded_ever_;
|
|
}
|
|
|
|
uint64_t uploadedEver() const
|
|
{
|
|
return uploaded_ever_;
|
|
}
|
|
|
|
uint64_t failedEver() const
|
|
{
|
|
return failed_ever_;
|
|
}
|
|
|
|
int compareSeedRatio(Torrent const&) const;
|
|
int compareRatio(Torrent const&) const;
|
|
int compareETA(Torrent const&) const;
|
|
|
|
bool hasETA() const
|
|
{
|
|
return getETA() >= 0;
|
|
}
|
|
|
|
int getETA() const
|
|
{
|
|
return eta_;
|
|
}
|
|
|
|
time_t lastActivity() const
|
|
{
|
|
return activity_date_;
|
|
}
|
|
|
|
time_t lastStarted() const
|
|
{
|
|
return start_date_;
|
|
}
|
|
|
|
time_t dateAdded() const
|
|
{
|
|
return added_date_;
|
|
}
|
|
|
|
time_t dateCreated() const
|
|
{
|
|
return date_created_;
|
|
}
|
|
|
|
time_t dateEdited() const
|
|
{
|
|
return edit_date_;
|
|
}
|
|
|
|
time_t manualAnnounceTime() const
|
|
{
|
|
return manual_announce_time_;
|
|
}
|
|
|
|
bool canManualAnnounceAt(time_t t) const
|
|
{
|
|
return isReadyToTransfer() && (manualAnnounceTime() <= t);
|
|
}
|
|
|
|
int peersWeAreDownloadingFrom() const
|
|
{
|
|
return peers_sending_to_us_;
|
|
}
|
|
|
|
int webseedsWeAreDownloadingFrom() const
|
|
{
|
|
return webseeds_sending_to_us_;
|
|
}
|
|
|
|
int peersWeAreUploadingTo() const
|
|
{
|
|
return peers_getting_from_us_;
|
|
}
|
|
|
|
bool isUploading() const
|
|
{
|
|
return peersWeAreUploadingTo() > 0;
|
|
}
|
|
|
|
int connectedPeers() const
|
|
{
|
|
return peers_connected_;
|
|
}
|
|
|
|
int connectedPeersAndWebseeds() const
|
|
{
|
|
return connectedPeers() + webseedsWeAreDownloadingFrom();
|
|
}
|
|
|
|
Speed const& downloadSpeed() const
|
|
{
|
|
return download_speed_;
|
|
}
|
|
|
|
Speed const& uploadSpeed() const
|
|
{
|
|
return upload_speed_;
|
|
}
|
|
|
|
double getVerifyProgress() const
|
|
{
|
|
return recheck_progress_;
|
|
}
|
|
|
|
bool includesTracker(FaviconCache::Key const& key) const;
|
|
|
|
FaviconCache::Keys const& trackerKeys() const
|
|
{
|
|
return tracker_keys_;
|
|
}
|
|
|
|
Speed uploadLimit() const
|
|
{
|
|
return Speed::fromKBps(upload_limit_);
|
|
}
|
|
|
|
Speed downloadLimit() const
|
|
{
|
|
return Speed::fromKBps(download_limit_);
|
|
}
|
|
|
|
bool uploadIsLimited() const
|
|
{
|
|
return upload_limited_;
|
|
}
|
|
|
|
bool downloadIsLimited() const
|
|
{
|
|
return download_limited_;
|
|
}
|
|
|
|
bool honorsSessionLimits() const
|
|
{
|
|
return honors_session_limits_;
|
|
}
|
|
|
|
int peerLimit() const
|
|
{
|
|
return peer_limit_;
|
|
}
|
|
|
|
double seedRatioLimit() const
|
|
{
|
|
return seed_ratio_limit_;
|
|
}
|
|
|
|
tr_ratiolimit seedRatioMode() const
|
|
{
|
|
return static_cast<tr_ratiolimit>(seed_ratio_mode_);
|
|
}
|
|
|
|
int seedIdleLimit() const
|
|
{
|
|
return seed_idle_limit_;
|
|
}
|
|
|
|
tr_idlelimit seedIdleMode() const
|
|
{
|
|
return static_cast<tr_idlelimit>(seed_idle_mode_);
|
|
}
|
|
|
|
TrackerStatsList const& trackerStats() const
|
|
{
|
|
return tracker_stats_;
|
|
}
|
|
|
|
PeerList const& peers() const
|
|
{
|
|
return peers_;
|
|
}
|
|
|
|
FileList const& files() const
|
|
{
|
|
return files_;
|
|
}
|
|
|
|
int queuePosition() const
|
|
{
|
|
return queue_position_;
|
|
}
|
|
|
|
bool isStalled() const
|
|
{
|
|
return is_stalled_;
|
|
}
|
|
|
|
QString activityString() const;
|
|
|
|
tr_torrent_activity getActivity() const
|
|
{
|
|
return static_cast<tr_torrent_activity>(status_);
|
|
}
|
|
|
|
bool isFinished() const
|
|
{
|
|
return is_finished_;
|
|
}
|
|
|
|
bool isPaused() const
|
|
{
|
|
return getActivity() == TR_STATUS_STOPPED;
|
|
}
|
|
|
|
bool isWaitingToVerify() const
|
|
{
|
|
return getActivity() == TR_STATUS_CHECK_WAIT;
|
|
}
|
|
|
|
bool isVerifying() const
|
|
{
|
|
return getActivity() == TR_STATUS_CHECK;
|
|
}
|
|
|
|
bool isDownloading() const
|
|
{
|
|
return getActivity() == TR_STATUS_DOWNLOAD;
|
|
}
|
|
|
|
bool isWaitingToDownload() const
|
|
{
|
|
return getActivity() == TR_STATUS_DOWNLOAD_WAIT;
|
|
}
|
|
|
|
bool isSeeding() const
|
|
{
|
|
return getActivity() == TR_STATUS_SEED;
|
|
}
|
|
|
|
bool isWaitingToSeed() const
|
|
{
|
|
return getActivity() == TR_STATUS_SEED_WAIT;
|
|
}
|
|
|
|
bool isReadyToTransfer() const
|
|
{
|
|
return getActivity() == TR_STATUS_DOWNLOAD || getActivity() == TR_STATUS_SEED;
|
|
}
|
|
|
|
bool isQueued() const
|
|
{
|
|
return isWaitingToDownload() || isWaitingToSeed();
|
|
}
|
|
|
|
QIcon getMimeTypeIcon() const;
|
|
|
|
enum Field
|
|
{
|
|
ACTIVITY_DATE,
|
|
ADDED_DATE,
|
|
BANDWIDTH_PRIORITY,
|
|
COMMENT,
|
|
CREATOR,
|
|
DATE_CREATED,
|
|
DESIRED_AVAILABLE,
|
|
DOWNLOADED_EVER,
|
|
DOWNLOAD_DIR,
|
|
DOWNLOAD_LIMIT,
|
|
DOWNLOAD_LIMITED,
|
|
DOWNLOAD_SPEED,
|
|
EDIT_DATE,
|
|
ERROR,
|
|
ERROR_STRING,
|
|
ETA,
|
|
FAILED_EVER,
|
|
FILE_COUNT,
|
|
FILES,
|
|
HASH,
|
|
HAVE_UNCHECKED,
|
|
HAVE_VERIFIED,
|
|
HONORS_SESSION_LIMITS,
|
|
ICON,
|
|
IS_FINISHED,
|
|
IS_PRIVATE,
|
|
IS_STALLED,
|
|
LEFT_UNTIL_DONE,
|
|
MANUAL_ANNOUNCE_TIME,
|
|
METADATA_PERCENT_COMPLETE,
|
|
NAME,
|
|
PEERS,
|
|
PEERS_CONNECTED,
|
|
PEERS_GETTING_FROM_US,
|
|
PEERS_SENDING_TO_US,
|
|
PEER_LIMIT,
|
|
PERCENT_DONE,
|
|
PIECE_COUNT,
|
|
PIECE_SIZE,
|
|
PRIMARY_MIME_TYPE,
|
|
QUEUE_POSITION,
|
|
RECHECK_PROGRESS,
|
|
SEED_IDLE_LIMIT,
|
|
SEED_IDLE_MODE,
|
|
SEED_RATIO_LIMIT,
|
|
SEED_RATIO_MODE,
|
|
SIZE_WHEN_DONE,
|
|
START_DATE,
|
|
STATUS,
|
|
TOTAL_SIZE,
|
|
TRACKER_STATS,
|
|
UPLOADED_EVER,
|
|
UPLOAD_LIMIT,
|
|
UPLOAD_LIMITED,
|
|
UPLOAD_SPEED,
|
|
WEBSEEDS_SENDING_TO_US,
|
|
|
|
N_FIELDS
|
|
};
|
|
using fields_t = std::bitset<N_FIELDS>;
|
|
|
|
fields_t update(tr_quark const* keys, tr_variant const* const* values, size_t n);
|
|
|
|
private:
|
|
int const id_;
|
|
|
|
bool download_limited_ = {};
|
|
bool honors_session_limits_ = {};
|
|
bool is_finished_ = {};
|
|
bool is_private_ = {};
|
|
bool is_stalled_ = {};
|
|
bool upload_limited_ = {};
|
|
|
|
time_t activity_date_ = {};
|
|
time_t added_date_ = {};
|
|
time_t date_created_ = {};
|
|
time_t edit_date_ = {};
|
|
time_t manual_announce_time_ = {};
|
|
time_t start_date_ = {};
|
|
|
|
int bandwidth_priority_ = {};
|
|
int download_limit_ = {};
|
|
int error_ = {};
|
|
int eta_ = {};
|
|
int peer_limit_ = {};
|
|
int peers_connected_ = {};
|
|
int peers_getting_from_us_ = {};
|
|
int peers_sending_to_us_ = {};
|
|
int piece_count_ = {};
|
|
int queue_position_ = {};
|
|
int seed_idle_limit_ = {};
|
|
int seed_idle_mode_ = {};
|
|
int seed_ratio_mode_ = {};
|
|
int status_ = {};
|
|
int upload_limit_ = {};
|
|
int webseeds_sending_to_us_ = {};
|
|
|
|
uint64_t desired_available_ = {};
|
|
uint64_t downloaded_ever_ = {};
|
|
uint64_t failed_ever_ = {};
|
|
uint64_t file_count_ = {};
|
|
uint64_t have_unchecked_ = {};
|
|
uint64_t have_verified_ = {};
|
|
uint64_t left_until_done_ = {};
|
|
uint64_t piece_size_ = {};
|
|
uint64_t size_when_done_ = {};
|
|
uint64_t total_size_ = {};
|
|
uint64_t uploaded_ever_ = {};
|
|
|
|
double metadata_percent_complete_ = {};
|
|
double percent_done_ = {};
|
|
double recheck_progress_ = {};
|
|
double seed_ratio_limit_ = {};
|
|
|
|
QString primary_mime_type_;
|
|
QString comment_;
|
|
QString creator_;
|
|
QString download_dir_;
|
|
QString error_string_;
|
|
QString name_;
|
|
|
|
// mutable because it's a lazy lookup
|
|
mutable QIcon icon_ = IconCache::get().fileIcon();
|
|
|
|
PeerList peers_;
|
|
FileList files_;
|
|
|
|
FaviconCache::Keys tracker_keys_;
|
|
TrackerStatsList tracker_stats_;
|
|
|
|
Speed upload_speed_;
|
|
Speed download_speed_;
|
|
|
|
Prefs const& prefs_;
|
|
|
|
TorrentHash hash_;
|
|
};
|
|
|
|
Q_DECLARE_METATYPE(Torrent const*)
|