mirror of
https://github.com/transmission/transmission.git
synced 2026-02-14 23:19:34 +00:00
refactor: move StatsMode to tr::app (#8330)
* refactor: add StatsMode to libtransmission-app * test: add display-mode unit tests * feat: add apicompat for StatsMode * refactor: use StatsMode in Qt client * refactor: add template method for gtr_set_pref() * refactor: use StatsMode in GTK client * ci: use the all-tests alias instead of hardcoding tests * ci: copy runtime DLLS into test output directory for Windows test binaries
This commit is contained in:
4
.github/workflows/actions.yml
vendored
4
.github/workflows/actions.yml
vendored
@@ -170,7 +170,7 @@ jobs:
|
||||
-DUSE_SYSTEM_UTP=OFF `# Not packaged in Ubuntu` \
|
||||
-DUSE_SYSTEM_WIDE_INTEGER=OFF `# Not packaged in Ubuntu`
|
||||
- name: Make
|
||||
run: cmake --build obj --config Debug --target libtransmission-test transmission-show
|
||||
run: cmake --build obj --config Debug --target all-tests
|
||||
- name: Test with sanitizers
|
||||
uses: ./.github/actions/run-tests
|
||||
with:
|
||||
@@ -221,7 +221,7 @@ jobs:
|
||||
-DUSE_SYSTEM_UTP=OFF `# Not packaged in Homebrew` \
|
||||
-DUSE_SYSTEM_WIDE_INTEGER=OFF `# Not packaged in Homebrew`
|
||||
- name: Make
|
||||
run: cmake --build obj --config Debug --target libtransmission-test transmission-show
|
||||
run: cmake --build obj --config Debug --target all-tests
|
||||
- name: Test with sanitizers
|
||||
uses: ./.github/actions/run-tests
|
||||
with:
|
||||
|
||||
@@ -1,6 +1,34 @@
|
||||
include(CheckFunctionExists)
|
||||
include(CheckIncludeFile)
|
||||
|
||||
macro(tr_setup_gtest_target TARGET_NAME TEST_PREFIX)
|
||||
if(WIN32)
|
||||
cmake_policy(PUSH)
|
||||
cmake_minimum_required(VERSION 3.21 FATAL_ERROR)
|
||||
|
||||
add_custom_command(
|
||||
TARGET ${TARGET_NAME} POST_BUILD
|
||||
COMMAND
|
||||
${CMAKE_COMMAND}
|
||||
-E copy_if_different
|
||||
$<TARGET_RUNTIME_DLLS:${TARGET_NAME}>
|
||||
$<TARGET_FILE_DIR:${TARGET_NAME}>
|
||||
COMMAND_EXPAND_LISTS
|
||||
)
|
||||
|
||||
cmake_policy(POP)
|
||||
endif()
|
||||
|
||||
if(NOT CMAKE_CROSSCOMPILING OR CMAKE_CROSSCOMPILING_EMULATOR)
|
||||
gtest_discover_tests(${TARGET_NAME}
|
||||
TEST_PREFIX "${TEST_PREFIX}")
|
||||
else()
|
||||
add_test(
|
||||
NAME ${TARGET_NAME}
|
||||
COMMAND ${TARGET_NAME})
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
macro(tr_auto_option_changed NAME ACC VAL FIL STK)
|
||||
if(NOT ("${VAL}" STREQUAL "AUTO" OR "${VAL}" STREQUAL "ON" OR "${VAL}" STREQUAL "OFF"))
|
||||
if("${VAL}" STREQUAL "0" OR "${VAL}" STREQUAL "NO" OR "${VAL}" STREQUAL "FALSE" OR "${VAL}" STREQUAL "N")
|
||||
|
||||
@@ -18,6 +18,8 @@
|
||||
#include "TorrentCellRenderer.h"
|
||||
#endif
|
||||
|
||||
#include <libtransmission-app/display-modes.h>
|
||||
|
||||
#include <libtransmission/transmission.h>
|
||||
#include <libtransmission/values.h>
|
||||
|
||||
@@ -62,6 +64,7 @@
|
||||
using namespace std::string_literals;
|
||||
using namespace std::string_view_literals;
|
||||
using namespace tr::Values;
|
||||
using namespace tr::app;
|
||||
|
||||
using VariantInt = Glib::Variant<int>;
|
||||
using VariantDouble = Glib::Variant<double>;
|
||||
@@ -132,7 +135,6 @@ private:
|
||||
|
||||
void syncAltSpeedButton();
|
||||
|
||||
void status_menu_toggled_cb(std::string const& action_name, Glib::ustring const& val);
|
||||
void onOptionsClicked();
|
||||
void alt_speed_toggled_cb();
|
||||
void onAltSpeedToggledIdle();
|
||||
@@ -144,7 +146,6 @@ private:
|
||||
sigc::signal<void()> signal_selection_changed_;
|
||||
|
||||
Glib::RefPtr<Gio::ActionGroup> options_actions_;
|
||||
Glib::RefPtr<Gio::ActionGroup> stats_actions_;
|
||||
|
||||
std::array<OptionMenuInfo, 2> speed_menu_info_;
|
||||
OptionMenuInfo ratio_menu_info_;
|
||||
@@ -369,12 +370,6 @@ MainWindow::Impl::~Impl()
|
||||
pref_handler_id_.disconnect();
|
||||
}
|
||||
|
||||
void MainWindow::Impl::status_menu_toggled_cb(std::string const& action_name, Glib::ustring const& val)
|
||||
{
|
||||
stats_actions_->change_action_state(action_name, VariantString::create(val));
|
||||
core_->set_pref(TR_KEY_statusbar_stats, val.raw());
|
||||
}
|
||||
|
||||
void MainWindow::Impl::syncAltSpeedButton()
|
||||
{
|
||||
bool const b = gtr_pref_flag_get(TR_KEY_alt_speed_enabled);
|
||||
@@ -589,38 +584,45 @@ void MainWindow::Impl::onOptionsClicked()
|
||||
|
||||
Glib::RefPtr<Gio::MenuModel> MainWindow::Impl::createStatsMenu()
|
||||
{
|
||||
struct StatsModeInfo
|
||||
using StatsType = gint32;
|
||||
using StatsVariant = Glib::Variant<StatsType>;
|
||||
|
||||
auto const to_var = [](auto const mode)
|
||||
{
|
||||
char const* val;
|
||||
char const* i18n;
|
||||
return StatsVariant::create(static_cast<StatsType>(mode));
|
||||
};
|
||||
|
||||
static auto const stats_modes = std::array<StatsModeInfo, 4>({ {
|
||||
{ "total-ratio", N_("Total Ratio") },
|
||||
{ "session-ratio", N_("Session Ratio") },
|
||||
{ "total-transfer", N_("Total Transfer") },
|
||||
{ "session-transfer", N_("Session Transfer") },
|
||||
} });
|
||||
|
||||
auto top = Gio::Menu::create();
|
||||
auto actions = Gio::SimpleActionGroup::create();
|
||||
|
||||
// build the action group
|
||||
static auto constexpr Key = TR_KEY_statusbar_stats;
|
||||
auto const action_name = "stats-mode"s;
|
||||
auto const full_action_name = fmt::format("{}.{}", StatsMenuActionGroupName, action_name);
|
||||
auto stats_mode_action = actions->add_action_radio_string(
|
||||
auto const current_value = gtr_pref_get<StatsMode>(Key).value_or(DefaultStatsMode);
|
||||
auto actions = Gio::SimpleActionGroup::create();
|
||||
actions->add_action_radio_integer(
|
||||
action_name,
|
||||
[this, action_name](Glib::ustring const& value) { status_menu_toggled_cb(action_name, value); },
|
||||
gtr_pref_string_get(TR_KEY_statusbar_stats));
|
||||
[this, action_name, actions, to_var](gint32 const ival)
|
||||
{
|
||||
actions->change_action_state(action_name, to_var(ival));
|
||||
core_->set_pref(Key, static_cast<StatsMode>(ival));
|
||||
},
|
||||
static_cast<StatsType>(current_value));
|
||||
|
||||
for (auto const& mode : stats_modes)
|
||||
// build the menu
|
||||
auto const full_action_name = fmt::format("{}.{}", StatsMenuActionGroupName, action_name);
|
||||
auto top = Gio::Menu::create();
|
||||
auto const stats_modes = std::array<std::pair<StatsMode, char const*>, StatsModeCount>({ {
|
||||
{ StatsMode::TotalRatio, N_("Total Ratio") },
|
||||
{ StatsMode::SessionRatio, N_("Session Ratio") },
|
||||
{ StatsMode::TotalTransfer, N_("Total Transfer") },
|
||||
{ StatsMode::SessionTransfer, N_("Session Transfer") },
|
||||
} });
|
||||
for (auto const& [mode, display_name] : stats_modes)
|
||||
{
|
||||
auto item = Gio::MenuItem::create(_(mode.i18n), full_action_name);
|
||||
item->set_action_and_target(full_action_name, VariantString::create(mode.val));
|
||||
top->append_item(item);
|
||||
auto item = Gio::MenuItem::create(_(display_name), full_action_name);
|
||||
item->set_action_and_target(full_action_name, to_var(mode));
|
||||
top->append_item(std::move(item));
|
||||
}
|
||||
|
||||
window_.insert_action_group(std::string(StatsMenuActionGroupName), actions);
|
||||
stats_actions_ = actions;
|
||||
|
||||
return top;
|
||||
}
|
||||
@@ -755,40 +757,24 @@ MainWindow::Impl::Impl(
|
||||
#endif
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
} // namespace
|
||||
|
||||
void MainWindow::Impl::updateStats()
|
||||
{
|
||||
Glib::ustring buf;
|
||||
auto const* const session = core_->get_session();
|
||||
|
||||
/* update the stats */
|
||||
if (auto const pch = gtr_pref_string_get(TR_KEY_statusbar_stats); pch == "session-ratio")
|
||||
{
|
||||
auto const stats = tr_sessionGetStats(session);
|
||||
buf = fmt::format(fmt::runtime(_("Ratio: {ratio}")), fmt::arg("ratio", tr_strlratio(stats.ratio)));
|
||||
}
|
||||
else if (pch == "session-transfer")
|
||||
{
|
||||
auto const stats = tr_sessionGetStats(session);
|
||||
buf = fmt::format(
|
||||
fmt::runtime(C_("current session totals", "Down: {downloaded_size}, Up: {uploaded_size}")),
|
||||
fmt::arg("downloaded_size", tr_strlsize(stats.downloadedBytes)),
|
||||
fmt::arg("uploaded_size", tr_strlsize(stats.uploadedBytes)));
|
||||
}
|
||||
else if (pch == "total-transfer")
|
||||
{
|
||||
auto const stats = tr_sessionGetCumulativeStats(session);
|
||||
buf = fmt::format(
|
||||
fmt::runtime(C_("all-time totals", "Down: {downloaded_size}, Up: {uploaded_size}")),
|
||||
fmt::arg("downloaded_size", tr_strlsize(stats.downloadedBytes)),
|
||||
fmt::arg("uploaded_size", tr_strlsize(stats.uploadedBytes)));
|
||||
}
|
||||
else /* default is total-ratio */
|
||||
{
|
||||
auto const stats = tr_sessionGetCumulativeStats(session);
|
||||
buf = fmt::format(fmt::runtime(_("Ratio: {ratio}")), fmt::arg("ratio", tr_strlratio(stats.ratio)));
|
||||
}
|
||||
|
||||
stats_lb_->set_text(buf);
|
||||
static_assert(StatsModeCount == 4U && "StatsMode changed: update this code");
|
||||
auto const mode = gtr_pref_get<StatsMode>(TR_KEY_statusbar_stats).value_or(DefaultStatsMode);
|
||||
auto const use_session_stats = mode == StatsMode::SessionRatio || mode == StatsMode::SessionTransfer;
|
||||
auto const* const ses = core_->get_session();
|
||||
auto const stats = use_session_stats ? tr_sessionGetStats(ses) : tr_sessionGetCumulativeStats(ses);
|
||||
stats_lb_->set_text(
|
||||
mode == StatsMode::SessionTransfer || mode == StatsMode::TotalTransfer ?
|
||||
fmt::format(
|
||||
fmt::runtime(_("Down: {downloaded_size}, Up: {uploaded_size}")),
|
||||
fmt::arg("downloaded_size", tr_strlsize(stats.downloadedBytes)),
|
||||
fmt::arg("uploaded_size", tr_strlsize(stats.uploadedBytes))) :
|
||||
fmt::format(fmt::runtime(_("Ratio: {ratio}")), fmt::arg("ratio", tr_strlratio(stats.ratio))));
|
||||
}
|
||||
|
||||
void MainWindow::Impl::updateSpeeds()
|
||||
|
||||
@@ -73,7 +73,7 @@ std::string gl_confdir;
|
||||
map.try_emplace(TR_KEY_show_tracker_scrapes, false);
|
||||
map.try_emplace(TR_KEY_sort_mode, to_variant(DefaultSortMode));
|
||||
map.try_emplace(TR_KEY_sort_reversed, false);
|
||||
map.try_emplace(TR_KEY_statusbar_stats, "total-ratio"sv);
|
||||
map.try_emplace(TR_KEY_statusbar_stats, to_variant(DefaultStatsMode));
|
||||
map.try_emplace(TR_KEY_torrent_added_notification_enabled, true);
|
||||
map.try_emplace(TR_KEY_torrent_complete_notification_enabled, true);
|
||||
map.try_emplace(TR_KEY_torrent_complete_sound_enabled, true);
|
||||
|
||||
@@ -25,6 +25,14 @@ template<typename T>
|
||||
return iter != std::end(map) ? to_value<T>(iter->second) : std::nullopt;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void gtr_pref_set(tr_quark const key, T const& val)
|
||||
{
|
||||
using namespace tr::serializer;
|
||||
auto& map = gtr_pref_get_map();
|
||||
map.insert_or_assign(key, to_variant(val));
|
||||
}
|
||||
|
||||
void gtr_pref_init(std::string_view config_dir);
|
||||
|
||||
int64_t gtr_pref_int_get(tr_quark key);
|
||||
|
||||
@@ -1140,52 +1140,6 @@ void Session::Impl::maybe_inhibit_hibernation()
|
||||
set_hibernation_allowed(hibernation_allowed);
|
||||
}
|
||||
|
||||
/**
|
||||
*** Prefs
|
||||
**/
|
||||
|
||||
void Session::Impl::commit_prefs_change(tr_quark const key)
|
||||
{
|
||||
signal_prefs_changed_.emit(key);
|
||||
gtr_pref_save(session_);
|
||||
}
|
||||
|
||||
void Session::set_pref(tr_quark const key, std::string const& newval)
|
||||
{
|
||||
if (newval != gtr_pref_string_get(key))
|
||||
{
|
||||
gtr_pref_string_set(key, newval);
|
||||
impl_->commit_prefs_change(key);
|
||||
}
|
||||
}
|
||||
|
||||
void Session::set_pref(tr_quark const key, bool newval)
|
||||
{
|
||||
if (newval != gtr_pref_flag_get(key))
|
||||
{
|
||||
gtr_pref_flag_set(key, newval);
|
||||
impl_->commit_prefs_change(key);
|
||||
}
|
||||
}
|
||||
|
||||
void Session::set_pref(tr_quark const key, int newval)
|
||||
{
|
||||
if (newval != gtr_pref_int_get(key))
|
||||
{
|
||||
gtr_pref_int_set(key, newval);
|
||||
impl_->commit_prefs_change(key);
|
||||
}
|
||||
}
|
||||
|
||||
void Session::set_pref(tr_quark const key, double newval)
|
||||
{
|
||||
if (std::fabs(newval - gtr_pref_double_get(key)) >= 0.0001)
|
||||
{
|
||||
gtr_pref_double_set(key, newval);
|
||||
impl_->commit_prefs_change(key);
|
||||
}
|
||||
}
|
||||
|
||||
/***
|
||||
****
|
||||
**** RPC Interface
|
||||
|
||||
@@ -5,11 +5,13 @@
|
||||
#pragma once
|
||||
|
||||
#include "GtkCompat.h"
|
||||
#include "Prefs.h"
|
||||
#include "Torrent.h"
|
||||
|
||||
#include <libtransmission-app/favicon-cache.h>
|
||||
|
||||
#include <libtransmission/transmission.h>
|
||||
#include <libtransmission/serializer.h>
|
||||
#include <libtransmission/variant.h>
|
||||
|
||||
#include <gdkmm/pixbuf.h>
|
||||
@@ -133,10 +135,16 @@ public:
|
||||
*** Set a preference value, save the prefs file, and emit the "prefs-changed" signal
|
||||
**/
|
||||
|
||||
void set_pref(tr_quark key, std::string const& val);
|
||||
void set_pref(tr_quark key, bool val);
|
||||
void set_pref(tr_quark key, int val);
|
||||
void set_pref(tr_quark key, double val);
|
||||
template<typename T>
|
||||
void set_pref(tr_quark const key, T const& val)
|
||||
{
|
||||
if (gtr_pref_get<T>(key) != val)
|
||||
{
|
||||
gtr_pref_set<T>(key, val);
|
||||
signal_prefs_changed().emit(key);
|
||||
gtr_pref_save(get_session());
|
||||
}
|
||||
}
|
||||
|
||||
// ---
|
||||
|
||||
|
||||
@@ -116,6 +116,49 @@ tr_variant from_sort_mode(SortMode const& src)
|
||||
|
||||
return from_sort_mode(DefaultSortMode);
|
||||
}
|
||||
|
||||
// ---
|
||||
|
||||
auto constexpr StatsKeys = std::array<std::pair<std::string_view, StatsMode>, StatsModeCount>{ {
|
||||
{ "session_ratio", StatsMode::SessionRatio },
|
||||
{ "session_transfer", StatsMode::SessionTransfer },
|
||||
{ "total_ratio", StatsMode::TotalRatio },
|
||||
{ "total_transfer", StatsMode::TotalTransfer },
|
||||
} };
|
||||
|
||||
bool to_stats_mode(tr_variant const& src, StatsMode* tgt)
|
||||
{
|
||||
static constexpr auto& Keys = StatsKeys;
|
||||
|
||||
if (auto const str = src.value_if<std::string_view>())
|
||||
{
|
||||
for (auto const& [key, val] : Keys)
|
||||
{
|
||||
if (str == key)
|
||||
{
|
||||
*tgt = val;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
tr_variant from_stats_mode(StatsMode const& src)
|
||||
{
|
||||
static constexpr auto& Keys = StatsKeys;
|
||||
|
||||
for (auto const& [key, val] : Keys)
|
||||
{
|
||||
if (src == val)
|
||||
{
|
||||
return tr_variant::unmanaged_string(key);
|
||||
}
|
||||
}
|
||||
|
||||
return from_stats_mode(DefaultStatsMode);
|
||||
}
|
||||
} // unnamed namespace
|
||||
|
||||
void register_app_converters()
|
||||
@@ -128,6 +171,7 @@ void register_app_converters()
|
||||
using Converters = tr::serializer::Converters;
|
||||
Converters::add(to_show_mode, from_show_mode);
|
||||
Converters::add(to_sort_mode, from_sort_mode);
|
||||
Converters::add(to_stats_mode, from_stats_mode);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -37,4 +37,14 @@ enum class SortMode
|
||||
inline auto constexpr SortModeCount = 10U;
|
||||
inline auto constexpr DefaultSortMode = SortMode::SortByName;
|
||||
|
||||
enum class StatsMode
|
||||
{
|
||||
TotalRatio,
|
||||
TotalTransfer,
|
||||
SessionRatio,
|
||||
SessionTransfer,
|
||||
};
|
||||
inline auto constexpr StatsModeCount = 4U;
|
||||
inline auto constexpr DefaultStatsMode = StatsMode::TotalRatio;
|
||||
|
||||
} // namespace tr::app
|
||||
|
||||
@@ -639,6 +639,23 @@ struct State
|
||||
}
|
||||
}
|
||||
|
||||
if (state.is_settings && state.current_key_is_any_of({ TR_KEY_statusbar_stats, TR_KEY_statusbar_stats_kebab_APICOMPAT }))
|
||||
{
|
||||
static auto constexpr Strings = std::array<std::pair<std::string_view, std::string_view>, 4U>{ {
|
||||
{ "total_ratio", "total-ratio" },
|
||||
{ "total_transfer", "total-transfer" },
|
||||
{ "session_ratio", "session-ratio" },
|
||||
{ "session_transfer", "session-transfer" },
|
||||
} };
|
||||
for (auto const& [current, legacy] : Strings)
|
||||
{
|
||||
if (src == current || src == legacy)
|
||||
{
|
||||
return state.style == Style::Tr5 ? current : legacy;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(ckerr): replace `new_key == TR_KEY_TORRENTS` here to turn on convert
|
||||
// if it's an array inside an array val whose key was `torrents`.
|
||||
// This is for the edge case of table mode: `torrents : [ [ 'key1', 'key2' ], [ ... ] ]`
|
||||
|
||||
102
qt/MainWindow.cc
102
qt/MainWindow.cc
@@ -410,21 +410,21 @@ QMenu* MainWindow::createOptionsMenu()
|
||||
|
||||
QMenu* MainWindow::createStatsModeMenu()
|
||||
{
|
||||
auto const stats_modes = std::array<std::pair<QAction*, QString>, 4>{ {
|
||||
{ ui_.action_TotalRatio, total_ratio_stats_mode_name_ },
|
||||
{ ui_.action_TotalTransfer, total_transfer_stats_mode_name_ },
|
||||
{ ui_.action_SessionRatio, session_ratio_stats_mode_name_ },
|
||||
{ ui_.action_SessionTransfer, session_transfer_stats_mode_name_ },
|
||||
auto const stats_modes = std::array<std::pair<QAction*, StatsMode>, StatsModeCount>{ {
|
||||
{ ui_.action_TotalRatio, StatsMode::TotalRatio },
|
||||
{ ui_.action_TotalTransfer, StatsMode::TotalTransfer },
|
||||
{ ui_.action_SessionRatio, StatsMode::SessionRatio },
|
||||
{ ui_.action_SessionTransfer, StatsMode::SessionTransfer },
|
||||
} };
|
||||
|
||||
auto* action_group = new QActionGroup{ this };
|
||||
auto* menu = new QMenu{ this };
|
||||
|
||||
for (auto const& mode : stats_modes)
|
||||
for (auto const& [action, mode] : stats_modes)
|
||||
{
|
||||
mode.first->setProperty(StatsModeKey, QString{ mode.second });
|
||||
action_group->addAction(mode.first);
|
||||
menu->addAction(mode.first);
|
||||
action->setProperty(StatsModeKey, QVariant::fromValue(mode));
|
||||
action_group->addAction(action);
|
||||
menu->addAction(action);
|
||||
}
|
||||
|
||||
connect(action_group, &QActionGroup::triggered, this, &MainWindow::onStatsModeChanged);
|
||||
@@ -753,34 +753,16 @@ void MainWindow::refreshStatusBar(TransferStats const& stats)
|
||||
ui_.downloadSpeedLabel->setText(stats.speed_down.to_download_qstring());
|
||||
ui_.downloadSpeedLabel->setVisible(stats.peers_sending);
|
||||
|
||||
auto const mode = prefs_.get<QString>(Prefs::STATUSBAR_STATS);
|
||||
auto str = QString{};
|
||||
|
||||
if (mode == session_ratio_stats_mode_name_)
|
||||
{
|
||||
str = tr("Ratio: %1").arg(Formatter::ratio_to_string(session_.getStats().ratio));
|
||||
}
|
||||
else if (mode == session_transfer_stats_mode_name_)
|
||||
{
|
||||
auto const& st = session_.getStats();
|
||||
str = tr("Down: %1, Up: %2")
|
||||
.arg(Formatter::storage_to_string(st.downloadedBytes))
|
||||
.arg(Formatter::storage_to_string(st.uploadedBytes));
|
||||
}
|
||||
else if (mode == total_transfer_stats_mode_name_)
|
||||
{
|
||||
auto const& st = session_.getCumulativeStats();
|
||||
str = tr("Down: %1, Up: %2")
|
||||
.arg(Formatter::storage_to_string(st.downloadedBytes))
|
||||
.arg(Formatter::storage_to_string(st.uploadedBytes));
|
||||
}
|
||||
else // default is "total-ratio"
|
||||
{
|
||||
assert(mode == total_ratio_stats_mode_name_);
|
||||
str = tr("Ratio: %1").arg(Formatter::ratio_to_string(session_.getCumulativeStats().ratio));
|
||||
}
|
||||
|
||||
ui_.statsLabel->setText(str);
|
||||
static_assert(StatsModeCount == 4U && "StatsMode changed: update this code");
|
||||
auto const mode = prefs_.get<StatsMode>(Prefs::STATUSBAR_STATS);
|
||||
auto const use_session_stats = mode == StatsMode::SessionRatio || mode == StatsMode::SessionTransfer;
|
||||
auto const& st = use_session_stats ? session_.getStats() : session_.getCumulativeStats();
|
||||
ui_.statsLabel->setText(
|
||||
mode == StatsMode::SessionTransfer || mode == StatsMode::TotalTransfer ?
|
||||
tr("Down: %1, Up: %2")
|
||||
.arg(Formatter::storage_to_string(st.downloadedBytes))
|
||||
.arg(Formatter::storage_to_string(st.uploadedBytes)) :
|
||||
tr("Ratio: %1").arg(Formatter::ratio_to_string(st.ratio)));
|
||||
}
|
||||
|
||||
void MainWindow::refreshTorrentViewHeader()
|
||||
@@ -1028,7 +1010,7 @@ void MainWindow::reannounceSelected()
|
||||
|
||||
void MainWindow::onStatsModeChanged(QAction const* action)
|
||||
{
|
||||
prefs_.set(Prefs::STATUSBAR_STATS, action->property(StatsModeKey).toString());
|
||||
prefs_.set(Prefs::STATUSBAR_STATS, action->property(StatsModeKey).value<StatsMode>());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1109,31 +1091,33 @@ void MainWindow::trayActivated(QSystemTrayIcon::ActivationReason reason)
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::refreshPref(int key)
|
||||
void MainWindow::refreshPref(int const idx)
|
||||
{
|
||||
auto b = bool{};
|
||||
auto str = QString{};
|
||||
|
||||
switch (key)
|
||||
switch (idx)
|
||||
{
|
||||
case Prefs::STATUSBAR_STATS:
|
||||
str = prefs_.get<QString>(key);
|
||||
|
||||
for (auto* action : ui_.action_TotalRatio->actionGroup()->actions())
|
||||
{
|
||||
action->setChecked(str == action->property(StatsModeKey).toString());
|
||||
}
|
||||
auto const needle = QVariant::fromValue(prefs_.get<StatsMode>(idx));
|
||||
|
||||
refreshSoon(REFRESH_STATUS_BAR);
|
||||
for (auto* action : ui_.action_TotalRatio->actionGroup()->actions())
|
||||
{
|
||||
action->setChecked(needle == action->property(StatsModeKey));
|
||||
}
|
||||
|
||||
refreshSoon(REFRESH_STATUS_BAR);
|
||||
}
|
||||
break;
|
||||
|
||||
case Prefs::SORT_REVERSED:
|
||||
ui_.action_ReverseSortOrder->setChecked(prefs_.get<bool>(key));
|
||||
ui_.action_ReverseSortOrder->setChecked(prefs_.get<bool>(idx));
|
||||
break;
|
||||
|
||||
case Prefs::SORT_MODE:
|
||||
{
|
||||
auto const sort_mode = prefs_.get<SortMode>(key);
|
||||
auto const sort_mode = prefs_.get<SortMode>(idx);
|
||||
for (auto* action : ui_.action_SortByActivity->actionGroup()->actions())
|
||||
{
|
||||
action->setChecked(sort_mode == action->property(SortModeKey).value<SortMode>());
|
||||
@@ -1143,51 +1127,51 @@ void MainWindow::refreshPref(int key)
|
||||
break;
|
||||
|
||||
case Prefs::DSPEED_ENABLED:
|
||||
(prefs_.get<bool>(key) ? dlimit_on_action_ : dlimit_off_action_)->setChecked(true);
|
||||
(prefs_.get<bool>(idx) ? dlimit_on_action_ : dlimit_off_action_)->setChecked(true);
|
||||
break;
|
||||
|
||||
case Prefs::DSPEED:
|
||||
dlimit_on_action_->setText(
|
||||
tr("Limited at %1").arg(Speed{ prefs_.get<unsigned int>(key), Speed::Units::KByps }.to_qstring()));
|
||||
tr("Limited at %1").arg(Speed{ prefs_.get<unsigned int>(idx), Speed::Units::KByps }.to_qstring()));
|
||||
break;
|
||||
|
||||
case Prefs::USPEED_ENABLED:
|
||||
(prefs_.get<bool>(key) ? ulimit_on_action_ : ulimit_off_action_)->setChecked(true);
|
||||
(prefs_.get<bool>(idx) ? ulimit_on_action_ : ulimit_off_action_)->setChecked(true);
|
||||
break;
|
||||
|
||||
case Prefs::USPEED:
|
||||
ulimit_on_action_->setText(
|
||||
tr("Limited at %1").arg(Speed{ prefs_.get<unsigned int>(key), Speed::Units::KByps }.to_qstring()));
|
||||
tr("Limited at %1").arg(Speed{ prefs_.get<unsigned int>(idx), Speed::Units::KByps }.to_qstring()));
|
||||
break;
|
||||
|
||||
case Prefs::RATIO_ENABLED:
|
||||
(prefs_.get<bool>(key) ? ratio_on_action_ : ratio_off_action_)->setChecked(true);
|
||||
(prefs_.get<bool>(idx) ? ratio_on_action_ : ratio_off_action_)->setChecked(true);
|
||||
break;
|
||||
|
||||
case Prefs::RATIO:
|
||||
ratio_on_action_->setText(tr("Stop at Ratio (%1)").arg(Formatter::ratio_to_string(prefs_.get<double>(key))));
|
||||
ratio_on_action_->setText(tr("Stop at Ratio (%1)").arg(Formatter::ratio_to_string(prefs_.get<double>(idx))));
|
||||
break;
|
||||
|
||||
case Prefs::FILTERBAR:
|
||||
b = prefs_.get<bool>(key);
|
||||
b = prefs_.get<bool>(idx);
|
||||
filter_bar_->setVisible(b);
|
||||
ui_.action_Filterbar->setChecked(b);
|
||||
break;
|
||||
|
||||
case Prefs::STATUSBAR:
|
||||
b = prefs_.get<bool>(key);
|
||||
b = prefs_.get<bool>(idx);
|
||||
ui_.statusBar->setVisible(b);
|
||||
ui_.action_Statusbar->setChecked(b);
|
||||
break;
|
||||
|
||||
case Prefs::TOOLBAR:
|
||||
b = prefs_.get<bool>(key);
|
||||
b = prefs_.get<bool>(idx);
|
||||
ui_.toolBar->setVisible(b);
|
||||
ui_.action_Toolbar->setChecked(b);
|
||||
break;
|
||||
|
||||
case Prefs::SHOW_TRAY_ICON:
|
||||
b = prefs_.get<bool>(key);
|
||||
b = prefs_.get<bool>(idx);
|
||||
ui_.action_TrayIcon->setChecked(b);
|
||||
tray_icon_.setVisible(b);
|
||||
QApplication::setQuitOnLastWindowClosed(!b);
|
||||
@@ -1195,7 +1179,7 @@ void MainWindow::refreshPref(int key)
|
||||
break;
|
||||
|
||||
case Prefs::COMPACT_VIEW:
|
||||
b = prefs_.get<bool>(key);
|
||||
b = prefs_.get<bool>(idx);
|
||||
ui_.action_CompactView->setChecked(b);
|
||||
ui_.listView->setItemDelegate(b ? torrent_delegate_min_ : torrent_delegate_);
|
||||
break;
|
||||
|
||||
@@ -113,7 +113,7 @@ private slots:
|
||||
void openStats();
|
||||
void openTorrent();
|
||||
void openURL();
|
||||
void refreshPref(int key);
|
||||
void refreshPref(int idx);
|
||||
void removeTorrents(bool const delete_files);
|
||||
void setLocation();
|
||||
void setSortAscendingPref(bool);
|
||||
@@ -179,10 +179,6 @@ private:
|
||||
bool auto_add_clipboard_links_ = {};
|
||||
QStringList clipboard_processed_keys_ = {};
|
||||
|
||||
QString const total_ratio_stats_mode_name_ = QStringLiteral("total-ratio");
|
||||
QString const total_transfer_stats_mode_name_ = QStringLiteral("total-transfer");
|
||||
QString const session_ratio_stats_mode_name_ = QStringLiteral("session-ratio");
|
||||
QString const session_transfer_stats_mode_name_ = QStringLiteral("session-transfer");
|
||||
QString const show_options_checkbox_name_ = QStringLiteral("show-options-checkbox");
|
||||
|
||||
struct TransferStats
|
||||
|
||||
@@ -49,6 +49,9 @@ template<typename T>
|
||||
case UserMetaType::SortModeType:
|
||||
return qvarFromOptional(ser::to_value<SortMode>(var));
|
||||
|
||||
case UserMetaType::StatsModeType:
|
||||
return qvarFromOptional(ser::to_value<StatsMode>(var));
|
||||
|
||||
case UserMetaType::ShowModeType:
|
||||
return qvarFromOptional(ser::to_value<ShowMode>(var));
|
||||
|
||||
@@ -89,6 +92,9 @@ template<typename T>
|
||||
case UserMetaType::ShowModeType:
|
||||
return ser::to_variant(var.value<ShowMode>());
|
||||
|
||||
case UserMetaType::StatsModeType:
|
||||
return ser::to_variant(var.value<StatsMode>());
|
||||
|
||||
case QMetaType::QString:
|
||||
return ser::to_variant(var.value<QString>());
|
||||
|
||||
|
||||
@@ -199,7 +199,7 @@ private:
|
||||
{ COMPACT_VIEW, TR_KEY_compact_view, QMetaType::Bool },
|
||||
{ FILTERBAR, TR_KEY_show_filterbar, QMetaType::Bool },
|
||||
{ STATUSBAR, TR_KEY_show_statusbar, QMetaType::Bool },
|
||||
{ STATUSBAR_STATS, TR_KEY_statusbar_stats, QMetaType::QString },
|
||||
{ STATUSBAR_STATS, TR_KEY_statusbar_stats, UserMetaType::StatsModeType },
|
||||
{ SHOW_TRACKER_SCRAPES, TR_KEY_show_tracker_scrapes, QMetaType::Bool },
|
||||
{ SHOW_BACKUP_TRACKERS, TR_KEY_show_backup_trackers, QMetaType::Bool },
|
||||
{ TOOLBAR, TR_KEY_show_toolbar, QMetaType::Bool },
|
||||
|
||||
@@ -18,6 +18,7 @@ public:
|
||||
{
|
||||
ShowModeType = QMetaType::User,
|
||||
SortModeType,
|
||||
StatsModeType,
|
||||
EncryptionModeType,
|
||||
};
|
||||
};
|
||||
@@ -32,3 +33,8 @@ inline auto constexpr ShowModeCount = tr::app::ShowModeCount;
|
||||
using SortMode = tr::app::SortMode;
|
||||
Q_DECLARE_METATYPE(SortMode)
|
||||
inline auto constexpr DefaultSortMode = tr::app::DefaultSortMode;
|
||||
|
||||
using StatsMode = tr::app::StatsMode;
|
||||
Q_DECLARE_METATYPE(StatsMode)
|
||||
inline auto constexpr DefaultStatsMode = tr::app::DefaultStatsMode;
|
||||
inline auto constexpr StatsModeCount = tr::app::StatsModeCount;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
include(TrGTest)
|
||||
|
||||
add_subdirectory(libtransmission)
|
||||
add_subdirectory(libtransmission-app)
|
||||
if(ENABLE_UTILS)
|
||||
add_subdirectory(utils)
|
||||
endif()
|
||||
@@ -19,6 +20,8 @@ if(TARGET libtransmission-test)
|
||||
add_dependencies(all-tests libtransmission-test)
|
||||
endif()
|
||||
|
||||
add_dependencies(all-tests libtransmission-app-test)
|
||||
|
||||
if(TARGET qt-tests)
|
||||
add_dependencies(all-tests qt-tests)
|
||||
endif()
|
||||
|
||||
20
tests/libtransmission-app/CMakeLists.txt
Normal file
20
tests/libtransmission-app/CMakeLists.txt
Normal file
@@ -0,0 +1,20 @@
|
||||
include(GoogleTest)
|
||||
|
||||
add_executable(libtransmission-app-test)
|
||||
|
||||
target_sources(libtransmission-app-test
|
||||
PRIVATE
|
||||
display-mode-tests.cc
|
||||
test-fixtures.h)
|
||||
|
||||
set_property(
|
||||
TARGET libtransmission-app-test
|
||||
PROPERTY FOLDER "tests")
|
||||
|
||||
target_link_libraries(libtransmission-app-test
|
||||
PRIVATE
|
||||
${TR_NAME}-app
|
||||
${TR_NAME}
|
||||
GTest::gtest_main)
|
||||
|
||||
tr_setup_gtest_target(libtransmission-app-test "LTA.")
|
||||
86
tests/libtransmission-app/display-mode-tests.cc
Normal file
86
tests/libtransmission-app/display-mode-tests.cc
Normal file
@@ -0,0 +1,86 @@
|
||||
// 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 <array>
|
||||
#include <string_view>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <libtransmission/serializer.h>
|
||||
#include <libtransmission/variant.h>
|
||||
|
||||
#include "libtransmission-app/display-modes.h"
|
||||
|
||||
#include "test-fixtures.h"
|
||||
|
||||
using DisplayModeTest = TransmissionTest;
|
||||
using namespace std::literals;
|
||||
using tr::serializer::Converters;
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
template<typename T, size_t N>
|
||||
void testModeRoundtrip(std::array<std::pair<std::string_view, T>, N> const& items)
|
||||
{
|
||||
for (auto const& [key, mode] : items)
|
||||
{
|
||||
auto const var = Converters::serialize(mode);
|
||||
EXPECT_TRUE(var.template holds_alternative<std::string_view>());
|
||||
EXPECT_EQ(var.template value_if<std::string_view>().value_or(""sv), key);
|
||||
|
||||
auto out = T{};
|
||||
EXPECT_TRUE(Converters::deserialize(tr_variant{ key }, &out));
|
||||
EXPECT_EQ(out, mode);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST_F(DisplayModeTest, showModeStringsRoundtrip)
|
||||
{
|
||||
auto constexpr Items = std::array<std::pair<std::string_view, tr::app::ShowMode>, tr::app::ShowModeCount>{ {
|
||||
{ "show_active", tr::app::ShowMode::ShowActive },
|
||||
{ "show_all", tr::app::ShowMode::ShowAll },
|
||||
{ "show_downloading", tr::app::ShowMode::ShowDownloading },
|
||||
{ "show_error", tr::app::ShowMode::ShowError },
|
||||
{ "show_finished", tr::app::ShowMode::ShowFinished },
|
||||
{ "show_paused", tr::app::ShowMode::ShowPaused },
|
||||
{ "show_seeding", tr::app::ShowMode::ShowSeeding },
|
||||
{ "show_verifying", tr::app::ShowMode::ShowVerifying },
|
||||
} };
|
||||
|
||||
testModeRoundtrip(Items);
|
||||
}
|
||||
|
||||
TEST_F(DisplayModeTest, sortModeStringsRoundtrip)
|
||||
{
|
||||
auto constexpr Items = std::array<std::pair<std::string_view, tr::app::SortMode>, tr::app::SortModeCount>{ {
|
||||
{ "sort_by_activity", tr::app::SortMode::SortByActivity },
|
||||
{ "sort_by_age", tr::app::SortMode::SortByAge },
|
||||
{ "sort_by_eta", tr::app::SortMode::SortByEta },
|
||||
{ "sort_by_id", tr::app::SortMode::SortById },
|
||||
{ "sort_by_name", tr::app::SortMode::SortByName },
|
||||
{ "sort_by_progress", tr::app::SortMode::SortByProgress },
|
||||
{ "sort_by_queue", tr::app::SortMode::SortByQueue },
|
||||
{ "sort_by_ratio", tr::app::SortMode::SortByRatio },
|
||||
{ "sort_by_size", tr::app::SortMode::SortBySize },
|
||||
{ "sort_by_state", tr::app::SortMode::SortByState },
|
||||
} };
|
||||
|
||||
testModeRoundtrip(Items);
|
||||
}
|
||||
|
||||
TEST_F(DisplayModeTest, statsModeStringsRoundtrip)
|
||||
{
|
||||
auto constexpr Items = std::array<std::pair<std::string_view, tr::app::StatsMode>, tr::app::StatsModeCount>{ {
|
||||
{ "total_ratio", tr::app::StatsMode::TotalRatio },
|
||||
{ "total_transfer", tr::app::StatsMode::TotalTransfer },
|
||||
{ "session_ratio", tr::app::StatsMode::SessionRatio },
|
||||
{ "session_transfer", tr::app::StatsMode::SessionTransfer },
|
||||
} };
|
||||
|
||||
testModeRoundtrip(Items);
|
||||
}
|
||||
19
tests/libtransmission-app/test-fixtures.h
Normal file
19
tests/libtransmission-app/test-fixtures.h
Normal file
@@ -0,0 +1,19 @@
|
||||
// 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "libtransmission-app/app.h"
|
||||
|
||||
class TransmissionTest : public ::testing::Test
|
||||
{
|
||||
protected:
|
||||
static void SetUpTestSuite()
|
||||
{
|
||||
tr::app::init();
|
||||
}
|
||||
};
|
||||
@@ -87,31 +87,7 @@ target_link_libraries(libtransmission-test
|
||||
libevent::event
|
||||
WideInteger::WideInteger)
|
||||
|
||||
if (WIN32)
|
||||
cmake_policy(PUSH)
|
||||
cmake_minimum_required(VERSION 3.21 FATAL_ERROR)
|
||||
|
||||
add_custom_command(
|
||||
TARGET libtransmission-test POST_BUILD
|
||||
COMMAND
|
||||
${CMAKE_COMMAND}
|
||||
-E copy_if_different
|
||||
$<TARGET_RUNTIME_DLLS:libtransmission-test>
|
||||
$<TARGET_FILE_DIR:libtransmission-test>
|
||||
COMMAND_EXPAND_LISTS
|
||||
)
|
||||
|
||||
cmake_policy(POP)
|
||||
endif ()
|
||||
|
||||
if(NOT CMAKE_CROSSCOMPILING OR CMAKE_CROSSCOMPILING_EMULATOR)
|
||||
gtest_discover_tests(libtransmission-test
|
||||
TEST_PREFIX "LT.")
|
||||
else()
|
||||
add_test(
|
||||
NAME libtransmission-test
|
||||
COMMAND libtransmission-test)
|
||||
endif()
|
||||
tr_setup_gtest_target(libtransmission-test "LT.")
|
||||
|
||||
add_custom_command(
|
||||
TARGET libtransmission-test
|
||||
|
||||
@@ -747,7 +747,7 @@ constexpr std::string_view CurrentSettingsJson = R"json({
|
||||
"speed_limit_up_enabled": false,
|
||||
"start_added_torrents": true,
|
||||
"start_minimized": false,
|
||||
"statusbar_stats": "total-ratio",
|
||||
"statusbar_stats": "total_ratio",
|
||||
"torrent_added_notification_enabled": true,
|
||||
"torrent_complete_notification_enabled": true,
|
||||
"torrent_complete_sound_command": [
|
||||
|
||||
Reference in New Issue
Block a user