Fixup recent Qt client changes (#1107)

* Add EDIT_DATE torrent property declaration (Qt client)

Switch to static assertion to help avoid similar issues in the future.

* Only declare std::hash<QString> for Qt < 5.14

* Pass main window as context when connecting lambdas to torrents model signals (Qt client)

This helps to automatically disconnect from signals on main window
destruction. If not done, use after free is possible since main window is
destroyed before torrents model.

Fixes: #1106
This commit is contained in:
Mike Gelfand 2020-01-14 23:28:34 +02:00 committed by GitHub
parent 34b02bfe34
commit 20119f006c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 104 additions and 92 deletions

View File

@ -243,16 +243,16 @@ MainWindow::MainWindow(Session& session, Prefs& prefs, TorrentModel& model, bool
connect(ui.action_Quit, SIGNAL(triggered()), qApp, SLOT(quit()));
auto refreshActionSensitivitySoon = [this]() { refreshSoon(REFRESH_ACTION_SENSITIVITY); };
connect(&myFilterModel, &TorrentFilter::rowsInserted, refreshActionSensitivitySoon);
connect(&myFilterModel, &TorrentFilter::rowsRemoved, refreshActionSensitivitySoon);
connect(&myFilterModel, &TorrentFilter::rowsInserted, this, refreshActionSensitivitySoon);
connect(&myFilterModel, &TorrentFilter::rowsRemoved, this, refreshActionSensitivitySoon);
// torrent view
myFilterModel.setSourceModel(&myModel);
auto refreshSoonAdapter = [this]() { refreshSoon(); };
connect(&myModel, &TorrentModel::modelReset, refreshSoonAdapter);
connect(&myModel, &TorrentModel::rowsRemoved, refreshSoonAdapter);
connect(&myModel, &TorrentModel::rowsInserted, refreshSoonAdapter);
connect(&myModel, &TorrentModel::dataChanged, refreshSoonAdapter);
connect(&myModel, &TorrentModel::modelReset, this, refreshSoonAdapter);
connect(&myModel, &TorrentModel::rowsRemoved, this, refreshSoonAdapter);
connect(&myModel, &TorrentModel::rowsInserted, this, refreshSoonAdapter);
connect(&myModel, &TorrentModel::dataChanged, this, refreshSoonAdapter);
ui.listView->setModel(&myFilterModel);
connect(ui.listView->selectionModel(), &QItemSelectionModel::selectionChanged, refreshActionSensitivitySoon);
@ -313,10 +313,10 @@ MainWindow::MainWindow(Session& session, Prefs& prefs, TorrentModel& model, bool
ui.verticalLayout->insertWidget(0, myFilterBar = new FilterBar(myPrefs, myModel, myFilterModel));
auto refreshHeaderSoon = [this]() { refreshSoon(REFRESH_TORRENT_VIEW_HEADER); };
connect(&myModel, &TorrentModel::rowsInserted, refreshHeaderSoon);
connect(&myModel, &TorrentModel::rowsRemoved, refreshHeaderSoon);
connect(&myFilterModel, &TorrentFilter::rowsInserted, refreshHeaderSoon);
connect(&myFilterModel, &TorrentFilter::rowsRemoved, refreshHeaderSoon);
connect(&myModel, &TorrentModel::rowsInserted, this, refreshHeaderSoon);
connect(&myModel, &TorrentModel::rowsRemoved, this, refreshHeaderSoon);
connect(&myFilterModel, &TorrentFilter::rowsInserted, this, refreshHeaderSoon);
connect(&myFilterModel, &TorrentFilter::rowsRemoved, this, refreshHeaderSoon);
connect(ui.listView, SIGNAL(headerDoubleClicked()), myFilterBar, SLOT(clear()));
QList<int> initKeys;
@ -332,7 +332,7 @@ MainWindow::MainWindow(Session& session, Prefs& prefs, TorrentModel& model, bool
auto refreshStatusSoon = [this]() { refreshSoon(REFRESH_STATUS_BAR); };
connect(&mySession, SIGNAL(sourceChanged()), this, SLOT(onSessionSourceChanged()));
connect(&mySession, &Session::statsUpdated, refreshStatusSoon);
connect(&mySession, &Session::statsUpdated, this, refreshStatusSoon);
connect(&mySession, SIGNAL(dataReadProgress()), this, SLOT(dataReadProgress()));
connect(&mySession, SIGNAL(dataSendProgress()), this, SLOT(dataSendProgress()));
connect(&mySession, SIGNAL(httpAuthenticationRequired()), this, SLOT(wrongAuthentication()));

View File

@ -23,80 +23,68 @@
#include "Torrent.h"
#include "Utils.h"
Torrent::Torrent(Prefs const& prefs, int id) :
myId(id),
myPrefs(prefs)
struct Property
{
#ifndef NDEBUG
int id;
tr_quark key;
int type;
};
for (int i = 0; i < PROPERTY_COUNT; ++i)
{
assert(myProperties[i].id == i);
}
#endif
setIcon(MIME_ICON, Utils::getFileIcon());
}
/***
****
***/
Torrent::Property Torrent::myProperties[] =
Property constexpr myProperties[] =
{
{ UPLOAD_SPEED, TR_KEY_rateUpload, QVariant::ULongLong } /* Bps */,
{ DOWNLOAD_SPEED, TR_KEY_rateDownload, QVariant::ULongLong }, /* Bps */
{ DOWNLOAD_DIR, TR_KEY_downloadDir, QVariant::String },
{ ACTIVITY, TR_KEY_status, QVariant::Int },
{ NAME, TR_KEY_name, QVariant::String },
{ ERROR, TR_KEY_error, QVariant::Int },
{ ERROR_STRING, TR_KEY_errorString, QVariant::String },
{ SIZE_WHEN_DONE, TR_KEY_sizeWhenDone, QVariant::ULongLong },
{ LEFT_UNTIL_DONE, TR_KEY_leftUntilDone, QVariant::ULongLong },
{ HAVE_UNCHECKED, TR_KEY_haveUnchecked, QVariant::ULongLong },
{ HAVE_VERIFIED, TR_KEY_haveValid, QVariant::ULongLong },
{ DESIRED_AVAILABLE, TR_KEY_desiredAvailable, QVariant::ULongLong },
{ TOTAL_SIZE, TR_KEY_totalSize, QVariant::ULongLong },
{ PIECE_SIZE, TR_KEY_pieceSize, QVariant::ULongLong },
{ PIECE_COUNT, TR_KEY_pieceCount, QVariant::Int },
{ PEERS_GETTING_FROM_US, TR_KEY_peersGettingFromUs, QVariant::Int },
{ PEERS_SENDING_TO_US, TR_KEY_peersSendingToUs, QVariant::Int },
{ WEBSEEDS_SENDING_TO_US, TR_KEY_webseedsSendingToUs, QVariant::Int },
{ PERCENT_DONE, TR_KEY_percentDone, QVariant::Double },
{ METADATA_PERCENT_DONE, TR_KEY_metadataPercentComplete, QVariant::Double },
{ PERCENT_VERIFIED, TR_KEY_recheckProgress, QVariant::Double },
{ DATE_ACTIVITY, TR_KEY_activityDate, QVariant::DateTime },
{ DATE_ADDED, TR_KEY_addedDate, QVariant::DateTime },
{ DATE_STARTED, TR_KEY_startDate, QVariant::DateTime },
{ DATE_CREATED, TR_KEY_dateCreated, QVariant::DateTime },
{ PEERS_CONNECTED, TR_KEY_peersConnected, QVariant::Int },
{ ETA, TR_KEY_eta, QVariant::Int },
{ DOWNLOADED_EVER, TR_KEY_downloadedEver, QVariant::ULongLong },
{ UPLOADED_EVER, TR_KEY_uploadedEver, QVariant::ULongLong },
{ FAILED_EVER, TR_KEY_corruptEver, QVariant::ULongLong },
{ TRACKERSTATS, TR_KEY_trackerStats, CustomVariantType::TrackerStatsList },
{ MIME_ICON, TR_KEY_NONE, QVariant::Icon },
{ SEED_RATIO_LIMIT, TR_KEY_seedRatioLimit, QVariant::Double },
{ SEED_RATIO_MODE, TR_KEY_seedRatioMode, QVariant::Int },
{ SEED_IDLE_LIMIT, TR_KEY_seedIdleLimit, QVariant::Int },
{ SEED_IDLE_MODE, TR_KEY_seedIdleMode, QVariant::Int },
{ DOWN_LIMIT, TR_KEY_downloadLimit, QVariant::Int }, /* KB/s */
{ DOWN_LIMITED, TR_KEY_downloadLimited, QVariant::Bool },
{ UP_LIMIT, TR_KEY_uploadLimit, QVariant::Int }, /* KB/s */
{ UP_LIMITED, TR_KEY_uploadLimited, QVariant::Bool },
{ HONORS_SESSION_LIMITS, TR_KEY_honorsSessionLimits, QVariant::Bool },
{ PEER_LIMIT, TR_KEY_peer_limit, QVariant::Int },
{ HASH_STRING, TR_KEY_hashString, QVariant::String },
{ IS_FINISHED, TR_KEY_isFinished, QVariant::Bool },
{ IS_PRIVATE, TR_KEY_isPrivate, QVariant::Bool },
{ IS_STALLED, TR_KEY_isStalled, QVariant::Bool },
{ COMMENT, TR_KEY_comment, QVariant::String },
{ CREATOR, TR_KEY_creator, QVariant::String },
{ MANUAL_ANNOUNCE_TIME, TR_KEY_manualAnnounceTime, QVariant::DateTime },
{ PEERS, TR_KEY_peers, CustomVariantType::PeerList },
{ BANDWIDTH_PRIORITY, TR_KEY_bandwidthPriority, QVariant::Int },
{ QUEUE_POSITION, TR_KEY_queuePosition, QVariant::Int },
{ Torrent::UPLOAD_SPEED, TR_KEY_rateUpload, QVariant::ULongLong } /* Bps */,
{ Torrent::DOWNLOAD_SPEED, TR_KEY_rateDownload, QVariant::ULongLong }, /* Bps */
{ Torrent::DOWNLOAD_DIR, TR_KEY_downloadDir, QVariant::String },
{ Torrent::ACTIVITY, TR_KEY_status, QVariant::Int },
{ Torrent::NAME, TR_KEY_name, QVariant::String },
{ Torrent::ERROR, TR_KEY_error, QVariant::Int },
{ Torrent::ERROR_STRING, TR_KEY_errorString, QVariant::String },
{ Torrent::SIZE_WHEN_DONE, TR_KEY_sizeWhenDone, QVariant::ULongLong },
{ Torrent::LEFT_UNTIL_DONE, TR_KEY_leftUntilDone, QVariant::ULongLong },
{ Torrent::HAVE_UNCHECKED, TR_KEY_haveUnchecked, QVariant::ULongLong },
{ Torrent::HAVE_VERIFIED, TR_KEY_haveValid, QVariant::ULongLong },
{ Torrent::DESIRED_AVAILABLE, TR_KEY_desiredAvailable, QVariant::ULongLong },
{ Torrent::TOTAL_SIZE, TR_KEY_totalSize, QVariant::ULongLong },
{ Torrent::PIECE_SIZE, TR_KEY_pieceSize, QVariant::ULongLong },
{ Torrent::PIECE_COUNT, TR_KEY_pieceCount, QVariant::Int },
{ Torrent::PEERS_GETTING_FROM_US, TR_KEY_peersGettingFromUs, QVariant::Int },
{ Torrent::PEERS_SENDING_TO_US, TR_KEY_peersSendingToUs, QVariant::Int },
{ Torrent::WEBSEEDS_SENDING_TO_US, TR_KEY_webseedsSendingToUs, QVariant::Int },
{ Torrent::PERCENT_DONE, TR_KEY_percentDone, QVariant::Double },
{ Torrent::METADATA_PERCENT_DONE, TR_KEY_metadataPercentComplete, QVariant::Double },
{ Torrent::PERCENT_VERIFIED, TR_KEY_recheckProgress, QVariant::Double },
{ Torrent::DATE_ACTIVITY, TR_KEY_activityDate, QVariant::DateTime },
{ Torrent::DATE_ADDED, TR_KEY_addedDate, QVariant::DateTime },
{ Torrent::DATE_STARTED, TR_KEY_startDate, QVariant::DateTime },
{ Torrent::DATE_CREATED, TR_KEY_dateCreated, QVariant::DateTime },
{ Torrent::PEERS_CONNECTED, TR_KEY_peersConnected, QVariant::Int },
{ Torrent::ETA, TR_KEY_eta, QVariant::Int },
{ Torrent::DOWNLOADED_EVER, TR_KEY_downloadedEver, QVariant::ULongLong },
{ Torrent::UPLOADED_EVER, TR_KEY_uploadedEver, QVariant::ULongLong },
{ Torrent::FAILED_EVER, TR_KEY_corruptEver, QVariant::ULongLong },
{ Torrent::TRACKERSTATS, TR_KEY_trackerStats, CustomVariantType::TrackerStatsList },
{ Torrent::MIME_ICON, TR_KEY_NONE, QVariant::Icon },
{ Torrent::SEED_RATIO_LIMIT, TR_KEY_seedRatioLimit, QVariant::Double },
{ Torrent::SEED_RATIO_MODE, TR_KEY_seedRatioMode, QVariant::Int },
{ Torrent::SEED_IDLE_LIMIT, TR_KEY_seedIdleLimit, QVariant::Int },
{ Torrent::SEED_IDLE_MODE, TR_KEY_seedIdleMode, QVariant::Int },
{ Torrent::DOWN_LIMIT, TR_KEY_downloadLimit, QVariant::Int }, /* KB/s */
{ Torrent::DOWN_LIMITED, TR_KEY_downloadLimited, QVariant::Bool },
{ Torrent::UP_LIMIT, TR_KEY_uploadLimit, QVariant::Int }, /* KB/s */
{ Torrent::UP_LIMITED, TR_KEY_uploadLimited, QVariant::Bool },
{ Torrent::HONORS_SESSION_LIMITS, TR_KEY_honorsSessionLimits, QVariant::Bool },
{ Torrent::PEER_LIMIT, TR_KEY_peer_limit, QVariant::Int },
{ Torrent::HASH_STRING, TR_KEY_hashString, QVariant::String },
{ Torrent::IS_FINISHED, TR_KEY_isFinished, QVariant::Bool },
{ Torrent::IS_PRIVATE, TR_KEY_isPrivate, QVariant::Bool },
{ Torrent::IS_STALLED, TR_KEY_isStalled, QVariant::Bool },
{ Torrent::COMMENT, TR_KEY_comment, QVariant::String },
{ Torrent::CREATOR, TR_KEY_creator, QVariant::String },
{ Torrent::MANUAL_ANNOUNCE_TIME, TR_KEY_manualAnnounceTime, QVariant::DateTime },
{ Torrent::PEERS, TR_KEY_peers, CustomVariantType::PeerList },
{ Torrent::BANDWIDTH_PRIORITY, TR_KEY_bandwidthPriority, QVariant::Int },
{ Torrent::QUEUE_POSITION, TR_KEY_queuePosition, QVariant::Int },
{ Torrent::EDIT_DATE, TR_KEY_editDate, QVariant::Int },
};
/***
@ -184,6 +172,36 @@ Torrent::KeyList const Torrent::detailStatKeys{
****
***/
Torrent::Torrent(Prefs const& prefs, int id) :
myId(id),
myPrefs(prefs)
{
static_assert(TR_N_ELEMENTS(myProperties) == PROPERTY_COUNT);
static_assert(([] () constexpr
{
int i = 0;
for (auto const& property : myProperties)
{
if (property.id != i)
{
return false;
}
++i;
}
return true;
})());
setIcon(MIME_ICON, Utils::getFileIcon());
}
/***
****
***/
bool Torrent::setInt(int i, int value)
{
bool changed = false;

View File

@ -591,14 +591,6 @@ public:
static KeyList const mainInfoKeys;
static KeyList const mainStatKeys;
private:
struct Property
{
int id;
tr_quark key;
int type;
};
private:
int getInt(int key) const;
bool getBool(int key) const;
@ -627,8 +619,6 @@ private:
Prefs const& myPrefs;
QVariant myValues[PROPERTY_COUNT];
FileList myFiles;
static Property myProperties[];
};
Q_DECLARE_METATYPE(Torrent const*)

View File

@ -99,6 +99,8 @@ public:
}
};
#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
namespace std
{
@ -112,3 +114,5 @@ struct hash<QString>
};
} // namespace std
#endif