mirror of
https://github.com/transmission/transmission.git
synced 2026-02-15 07:26:49 +00:00
* fix: hicpp-use-auto,modernize-use-auto * refactor: make Prefs::getKey() a static method refactor: make Prefs::isCore() a static method refactor: make Prefs::type() a static method * refactor: Application takes a Prefs& arg, not a std::unique_ptr<Prefs> arg * fix: bugprone-exception-escape save settings by calling prefs.save() from main() * refactor: load settings by calling prefs.load() from main() * refactor: use preferred declaration order in Prefs * fixup! fix: bugprone-exception-escape * refactor: add Prefs::current_values() * refactor: clean up namespace use in Prefs.cc * feat: add QString, QDateTime serializers * test: add scaffolding for testing Qt code test: add tests for Prefs * refactor: remove unused #includes * build: add clang-tidy rules to tests/qt/ * refactor: clean up the new test code a little * chore: add missing copyright statement * ci: ensure Qt6Test is installed build: check for QTest when ENABLE_TESTS + ENABLE_QT are ON * fixup! feat: add QString, QDateTime serializers * fix: Wswitch warning * build: do not disable tests in release/windows/build-qt5.psl, build-qt6.psl * ci: set QT_QPA_PLATFORM for running new Qt tests * test: build cleanly in Qt 5.15 * fixup! fixup! feat: add QString, QDateTime serializers fix QDateTime serializer on macOS * fixup! ci: set QT_QPA_PLATFORM for running new Qt tests install xcb-util-cursor on alpine
312 lines
7.5 KiB
C++
312 lines
7.5 KiB
C++
// This file Copyright © Mnemosyne LLC.
|
|
// It may be used under GPLv2 (SPDX: GPL-2.0-only), GPLv3 (SPDX: GPL-3.0-only),
|
|
// or any future license endorsed by Mnemosyne LLC.
|
|
// License text can be found in the licenses/ folder.
|
|
|
|
#include "VariantHelpers.h"
|
|
|
|
#include <cmath>
|
|
#include <cstdint>
|
|
#include <limits>
|
|
#include <mutex>
|
|
#include <string_view>
|
|
|
|
#include <QDateTime>
|
|
#include <QUrl>
|
|
|
|
#include <libtransmission/serializer.h>
|
|
|
|
#include "Application.h" // qApp
|
|
#include "Speed.h"
|
|
#include "Torrent.h"
|
|
|
|
namespace ser = libtransmission::serializer;
|
|
|
|
namespace trqt::variant_helpers
|
|
{
|
|
|
|
bool change(double& setme, double const& value)
|
|
{
|
|
bool const changed = std::fabs(setme - value) > std::numeric_limits<double>::epsilon();
|
|
|
|
if (changed)
|
|
{
|
|
setme = value;
|
|
}
|
|
|
|
return changed;
|
|
}
|
|
|
|
bool change(Speed& setme, tr_variant const* value)
|
|
{
|
|
auto const byps = getValue<int>(value);
|
|
return byps && change(setme, Speed{ *byps, Speed::Units::Byps });
|
|
}
|
|
|
|
bool change(TorrentHash& setme, tr_variant const* value)
|
|
{
|
|
auto const hash_string = getValue<std::string_view>(value);
|
|
return hash_string && change(setme, TorrentHash{ *hash_string });
|
|
}
|
|
|
|
bool change(Peer& setme, tr_variant const* value)
|
|
{
|
|
auto changed = false;
|
|
|
|
auto pos = size_t{ 0 };
|
|
auto key = tr_quark{};
|
|
tr_variant* child = nullptr;
|
|
while (tr_variantDictChild(const_cast<tr_variant*>(value), pos++, &key, &child))
|
|
{
|
|
switch (key)
|
|
{
|
|
#define HANDLE_KEY(key, field) \
|
|
case TR_KEY_##key: \
|
|
changed = change(setme.field, child) || changed; \
|
|
break;
|
|
|
|
HANDLE_KEY(address, address)
|
|
HANDLE_KEY(client_is_choked, client_is_choked)
|
|
HANDLE_KEY(client_is_interested, client_is_interested)
|
|
HANDLE_KEY(client_name, client_name)
|
|
HANDLE_KEY(flag_str, flags)
|
|
HANDLE_KEY(is_downloading_from, is_downloading_from)
|
|
HANDLE_KEY(is_encrypted, is_encrypted)
|
|
HANDLE_KEY(is_incoming, is_incoming)
|
|
HANDLE_KEY(is_uploading_to, is_uploading_to)
|
|
HANDLE_KEY(peer_is_choked, peer_is_choked)
|
|
HANDLE_KEY(peer_is_interested, peer_is_interested)
|
|
HANDLE_KEY(port, port)
|
|
HANDLE_KEY(progress, progress)
|
|
HANDLE_KEY(rate_to_client, rate_to_client)
|
|
HANDLE_KEY(rate_to_peer, rate_to_peer)
|
|
#undef HANDLE_KEY
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
return changed;
|
|
}
|
|
|
|
bool change(TorrentFile& setme, tr_variant const* value)
|
|
{
|
|
auto changed = false;
|
|
|
|
auto pos = size_t{ 0 };
|
|
auto key = tr_quark{};
|
|
tr_variant* child = nullptr;
|
|
while (tr_variantDictChild(const_cast<tr_variant*>(value), pos++, &key, &child))
|
|
{
|
|
switch (key)
|
|
{
|
|
#define HANDLE_KEY(key) \
|
|
case TR_KEY_##key: \
|
|
changed = change(setme.key, child) || changed; \
|
|
break;
|
|
|
|
HANDLE_KEY(priority)
|
|
HANDLE_KEY(wanted)
|
|
#undef HANDLE_KEY
|
|
#define HANDLE_KEY(key, field) \
|
|
case TR_KEY_##key: \
|
|
changed = change(setme.field, child) || changed; \
|
|
break;
|
|
|
|
HANDLE_KEY(bytes_completed, have)
|
|
HANDLE_KEY(length, size)
|
|
HANDLE_KEY(name, filename)
|
|
#undef HANDLE_KEY
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
return changed;
|
|
}
|
|
|
|
bool change(TrackerStat& setme, tr_variant const* value)
|
|
{
|
|
bool changed = false;
|
|
bool site_changed = false;
|
|
|
|
auto pos = size_t{ 0 };
|
|
auto key = tr_quark{};
|
|
tr_variant* child = nullptr;
|
|
while (tr_variantDictChild(const_cast<tr_variant*>(value), pos++, &key, &child))
|
|
{
|
|
bool field_changed = false;
|
|
|
|
switch (key)
|
|
{
|
|
#define HANDLE_KEY(key) \
|
|
case TR_KEY_##key: \
|
|
field_changed = change(setme.key, child); \
|
|
break;
|
|
HANDLE_KEY(announce)
|
|
HANDLE_KEY(announce_state)
|
|
HANDLE_KEY(download_count)
|
|
HANDLE_KEY(has_announced)
|
|
HANDLE_KEY(has_scraped)
|
|
HANDLE_KEY(id)
|
|
HANDLE_KEY(is_backup)
|
|
HANDLE_KEY(last_announce_peer_count)
|
|
HANDLE_KEY(last_announce_result)
|
|
HANDLE_KEY(last_announce_start_time)
|
|
HANDLE_KEY(last_announce_succeeded)
|
|
HANDLE_KEY(last_announce_time)
|
|
HANDLE_KEY(last_announce_timed_out)
|
|
HANDLE_KEY(last_scrape_result)
|
|
HANDLE_KEY(last_scrape_start_time)
|
|
HANDLE_KEY(last_scrape_succeeded)
|
|
HANDLE_KEY(last_scrape_time)
|
|
HANDLE_KEY(last_scrape_timed_out)
|
|
HANDLE_KEY(leecher_count)
|
|
HANDLE_KEY(next_announce_time)
|
|
HANDLE_KEY(next_scrape_time)
|
|
HANDLE_KEY(scrape_state)
|
|
HANDLE_KEY(seeder_count)
|
|
HANDLE_KEY(sitename)
|
|
HANDLE_KEY(tier)
|
|
|
|
#undef HANDLE_KEY
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (field_changed)
|
|
{
|
|
site_changed |= key == TR_KEY_announce || key == TR_KEY_sitename;
|
|
}
|
|
|
|
changed = true;
|
|
}
|
|
|
|
if (site_changed && !setme.announce.isEmpty() && trApp != nullptr)
|
|
{
|
|
if (setme.sitename.isEmpty())
|
|
{
|
|
QStringList const separated_host = QUrl{ setme.announce }.host().split(QStringLiteral("."));
|
|
setme.sitename = separated_host.at(separated_host.size() - 2);
|
|
}
|
|
|
|
setme.announce = trApp->intern(setme.announce);
|
|
trApp->load_favicon(setme.announce);
|
|
}
|
|
|
|
return changed;
|
|
}
|
|
|
|
///
|
|
|
|
void variantInit(tr_variant* init_me, bool value)
|
|
{
|
|
*init_me = value;
|
|
}
|
|
|
|
void variantInit(tr_variant* init_me, int64_t value)
|
|
{
|
|
*init_me = value;
|
|
}
|
|
|
|
void variantInit(tr_variant* init_me, int value)
|
|
{
|
|
*init_me = value;
|
|
}
|
|
|
|
void variantInit(tr_variant* init_me, double value)
|
|
{
|
|
*init_me = value;
|
|
}
|
|
|
|
void variantInit(tr_variant* init_me, QByteArray const& value)
|
|
{
|
|
*init_me = std::string_view{ value.constData(), static_cast<size_t>(value.size()) };
|
|
}
|
|
|
|
void variantInit(tr_variant* init_me, QString const& value)
|
|
{
|
|
*init_me = value.toStdString();
|
|
}
|
|
|
|
void variantInit(tr_variant* init_me, std::string_view value)
|
|
{
|
|
*init_me = value;
|
|
}
|
|
|
|
namespace
|
|
{
|
|
bool toInt(tr_variant const& src, int* tgt)
|
|
{
|
|
if (auto const val = src.value_if<int64_t>())
|
|
{
|
|
if (*val < std::numeric_limits<int>::min() || *val > std::numeric_limits<int>::max())
|
|
{
|
|
return false;
|
|
}
|
|
|
|
*tgt = static_cast<int>(*val);
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
tr_variant fromInt(int const& val)
|
|
{
|
|
return static_cast<int64_t>(val);
|
|
}
|
|
|
|
// ---
|
|
|
|
bool toQDateTime(tr_variant const& src, QDateTime* tgt)
|
|
{
|
|
if (auto const val = ser::to_value<int64_t>(src))
|
|
{
|
|
*tgt = QDateTime::fromSecsSinceEpoch(*val);
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
tr_variant fromQDateTime(QDateTime const& src)
|
|
{
|
|
return ser::to_variant(int64_t{ src.toSecsSinceEpoch() });
|
|
}
|
|
|
|
// ---
|
|
|
|
bool toQString(tr_variant const& src, QString* tgt)
|
|
{
|
|
if (auto const val = src.value_if<std::string_view>())
|
|
{
|
|
*tgt = QString::fromUtf8(std::data(*val), std::size(*val));
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
tr_variant fromQString(QString const& val)
|
|
{
|
|
return val.toStdString();
|
|
}
|
|
} // namespace
|
|
|
|
void register_qt_converters()
|
|
{
|
|
static auto once = std::once_flag{};
|
|
std::call_once(
|
|
once,
|
|
[]
|
|
{
|
|
using namespace libtransmission::serializer;
|
|
Converters::add(toInt, fromInt);
|
|
Converters::add(toQDateTime, fromQDateTime);
|
|
Converters::add(toQString, fromQString);
|
|
});
|
|
}
|
|
|
|
} // namespace trqt::variant_helpers
|