From d5314e2c443eda6a1d2b2c2c4c2b7ab30a0a5d46 Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Mon, 22 Dec 2025 20:05:57 -0600 Subject: [PATCH] refactor: add `libtransmission-app` (#7978) * refactor: add libtransmission-app * refactor: add libtransmission-app/display-modes.h * refactor: use app::SortMode, app:ShowMode in Qt client * feat: add to_variant(), to_value() in serializer * refactor: use app::SortMode in GTK client * refactor: use app::ShowMode in GTK client * refactor: make naming consistent with libtransmission-app --- CMakeLists.txt | 1 + gtk/.clang-format | 6 +- gtk/CMakeLists.txt | 1 + gtk/FaviconCache.cc | 2 +- gtk/FilterBar.cc | 149 +++++++++--------- gtk/Prefs.cc | 12 +- gtk/Prefs.h | 13 ++ gtk/Session.cc | 5 +- gtk/Session.h | 3 +- gtk/TorrentFilter.cc | 70 ++++---- gtk/TorrentFilter.h | 24 +-- gtk/TorrentSorter.cc | 41 +++-- gtk/TorrentSorter.h | 6 +- gtk/main.cc | 6 +- gtk/transmission-ui.xml | 36 ++--- gtk/ui/gtk3/FilterBar.ui | 4 +- gtk/ui/gtk4/FilterBar.ui | 4 +- libtransmission-app/.clang-tidy | 55 +++++++ libtransmission-app/CMakeLists.txt | 25 +++ libtransmission-app/app.cc | 19 +++ libtransmission-app/app.h | 14 ++ libtransmission-app/converters.cc | 140 ++++++++++++++++ libtransmission-app/converters.h | 13 ++ libtransmission-app/display-modes.h | 40 +++++ .../favicon-cache.h | 0 libtransmission/CMakeLists.txt | 2 - libtransmission/serializer.h | 18 +++ qt/Application.h | 2 +- qt/CMakeLists.txt | 1 + qt/CustomVariantType.h | 2 +- qt/FaviconCache.cc | 2 +- qt/FilterBar.cc | 42 +++-- qt/Filters.cc | 31 ++-- qt/Filters.h | 91 ++--------- qt/MainWindow.cc | 34 ++-- qt/Prefs.cc | 96 +++-------- qt/Prefs.h | 4 +- qt/Session.cc | 23 ++- qt/TorrentFilter.cc | 32 ++-- qt/TorrentFilter.h | 3 +- qt/TrackerDelegate.cc | 3 +- qt/VariantHelpers.h | 7 - qt/main.cc | 5 +- 43 files changed, 674 insertions(+), 413 deletions(-) create mode 100644 libtransmission-app/.clang-tidy create mode 100644 libtransmission-app/CMakeLists.txt create mode 100644 libtransmission-app/app.cc create mode 100644 libtransmission-app/app.h create mode 100644 libtransmission-app/converters.cc create mode 100644 libtransmission-app/converters.h create mode 100644 libtransmission-app/display-modes.h rename {libtransmission => libtransmission-app}/favicon-cache.h (100%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7e1ca311c..b6774fd7e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -827,6 +827,7 @@ function(tr_install_web DST_DIR) endfunction() add_subdirectory(libtransmission) +add_subdirectory(libtransmission-app) set(MAC_PROJECT_DIR macosx) diff --git a/gtk/.clang-format b/gtk/.clang-format index d5b141488..6ff534ac7 100644 --- a/gtk/.clang-format +++ b/gtk/.clang-format @@ -3,11 +3,13 @@ BasedOnStyle: InheritParentConfig IncludeBlocks: Regroup IncludeCategories: - - Regex: '^' + - Regex: '^' + Priority: 4 SortPriority: 3 - Regex: '^ +#include #include #include diff --git a/gtk/FilterBar.cc b/gtk/FilterBar.cc index aee0bbae0..610fc0ba9 100644 --- a/gtk/FilterBar.cc +++ b/gtk/FilterBar.cc @@ -13,6 +13,8 @@ #include "TorrentFilter.h" #include "Utils.h" +#include + #include #include @@ -45,12 +47,13 @@ #include #include +using namespace transmission::app; + namespace { -using ActivityType = TorrentFilter::Activity; using TrackerType = TorrentFilter::Tracker; -constexpr auto ActivitySeparator = static_cast(-1); +constexpr auto ShowModeSeparator = static_cast(-1); constexpr auto TrackerSeparator = static_cast(-1); } // namespace @@ -72,18 +75,20 @@ private: template T* get_template_child(char const* name) const; - void activity_combo_box_init(Gtk::ComboBox& combo); - static void render_activity_pixbuf_func(Gtk::CellRendererPixbuf& cell_renderer, Gtk::TreeModel::const_iterator const& iter); + void show_mode_combo_box_init(Gtk::ComboBox& combo); + static void render_show_mode_pixbuf_func( + Gtk::CellRendererPixbuf& cell_renderer, + Gtk::TreeModel::const_iterator const& iter); void tracker_combo_box_init(Gtk::ComboBox& combo); static void render_pixbuf_func(Gtk::CellRendererPixbuf& cell_renderer, Gtk::TreeModel::const_iterator const& iter); static void render_number_func(Gtk::CellRendererText& cell_renderer, Gtk::TreeModel::const_iterator const& iter); - void update_filter_activity(); + void update_filter_show_mode(); void update_filter_tracker(); void update_filter_text(); - bool activity_filter_model_update(); + bool show_mode_filter_model_update(); bool tracker_filter_model_update(); void favicon_ready_cb(Glib::RefPtr const* pixbuf, Gtk::TreeModel::Path const& path); @@ -94,9 +99,9 @@ private: void update_count_label_idle(); bool update_count_label(); - static Glib::RefPtr activity_filter_model_new(); + static Glib::RefPtr show_mode_filter_model_new(); static void status_model_update_count(Gtk::TreeModel::iterator const& iter, int n); - static bool activity_is_it_a_separator(Gtk::TreeModel::const_iterator const& iter); + static bool show_mode_is_it_a_separator(Gtk::TreeModel::const_iterator const& iter); static Glib::RefPtr tracker_filter_model_new(); static void tracker_model_update_count(Gtk::TreeModel::iterator const& iter, int n); @@ -110,10 +115,10 @@ private: FilterBar& widget_; Glib::RefPtr const core_; - Glib::RefPtr const activity_model_; + Glib::RefPtr const show_mode_model_; Glib::RefPtr const tracker_model_; - Gtk::ComboBox* activity_ = nullptr; + Gtk::ComboBox* show_mode_ = nullptr; Gtk::ComboBox* tracker_ = nullptr; Gtk::Entry* entry_ = nullptr; Gtk::Label* show_lb_ = nullptr; @@ -390,54 +395,50 @@ void FilterBar::Impl::tracker_combo_box_init(Gtk::ComboBox& combo) namespace { -/*** -**** -**** ACTIVITY -**** -***/ +// --- Show Mode -class ActivityFilterModelColumns : public Gtk::TreeModelColumnRecord +class ShowModeFilterModelColumns : public Gtk::TreeModelColumnRecord { public: - ActivityFilterModelColumns() noexcept + ShowModeFilterModelColumns() noexcept { add(name); add(count); - add(type); + add(show_mode); add(icon_name); } Gtk::TreeModelColumn name; Gtk::TreeModelColumn count; - Gtk::TreeModelColumn type; + Gtk::TreeModelColumn show_mode; Gtk::TreeModelColumn icon_name; }; -ActivityFilterModelColumns const activity_filter_cols; +ShowModeFilterModelColumns const show_mode_filter_cols; } // namespace -bool FilterBar::Impl::activity_is_it_a_separator(Gtk::TreeModel::const_iterator const& iter) +bool FilterBar::Impl::show_mode_is_it_a_separator(Gtk::TreeModel::const_iterator const& iter) { - return iter->get_value(activity_filter_cols.type) == ActivitySeparator; + return iter->get_value(show_mode_filter_cols.show_mode) == ShowModeSeparator; } void FilterBar::Impl::status_model_update_count(Gtk::TreeModel::iterator const& iter, int n) { - if (n != iter->get_value(activity_filter_cols.count)) + if (n != iter->get_value(show_mode_filter_cols.count)) { - iter->set_value(activity_filter_cols.count, n); + iter->set_value(show_mode_filter_cols.count, n); } } -bool FilterBar::Impl::activity_filter_model_update() +bool FilterBar::Impl::show_mode_filter_model_update() { auto const torrents_model = core_->get_model(); - for (auto& row : activity_model_->children()) + for (auto& row : show_mode_model_->children()) { - auto const type = row.get_value(activity_filter_cols.type); - if (type == ActivitySeparator) + auto const type = row.get_value(show_mode_filter_cols.show_mode); + if (type == ShowModeSeparator) { continue; } @@ -447,7 +448,7 @@ bool FilterBar::Impl::activity_filter_model_update() for (auto i = 0U, count = torrents_model->get_n_items(); i < count; ++i) { auto const torrent = gtr_ptr_dynamic_cast(torrents_model->get_object(i)); - if (torrent != nullptr && TorrentFilter::match_activity(*torrent, static_cast(type))) + if (torrent != nullptr && TorrentFilter::match_mode(*torrent, static_cast(type))) { ++hits; } @@ -459,29 +460,29 @@ bool FilterBar::Impl::activity_filter_model_update() return false; } -Glib::RefPtr FilterBar::Impl::activity_filter_model_new() +Glib::RefPtr FilterBar::Impl::show_mode_filter_model_new() { struct FilterTypeInfo { - ActivityType type; + ShowMode show_mode; char const* context; char const* name; char const* icon_name; }; static auto constexpr types = std::array({ { - { ActivityType::ALL, nullptr, N_("All"), nullptr }, - { ActivityType{ -1 }, nullptr, nullptr, nullptr }, - { ActivityType::ACTIVE, nullptr, N_("Active"), "system-run" }, - { ActivityType::DOWNLOADING, "Verb", NC_("Verb", "Downloading"), "network-receive" }, - { ActivityType::SEEDING, "Verb", NC_("Verb", "Seeding"), "network-transmit" }, - { ActivityType::PAUSED, nullptr, N_("Paused"), "media-playback-pause" }, - { ActivityType::FINISHED, nullptr, N_("Finished"), "media-playback-stop" }, - { ActivityType::VERIFYING, "Verb", NC_("Verb", "Verifying"), "view-refresh" }, - { ActivityType::ERROR, nullptr, N_("Error"), "dialog-error" }, + { ShowMode::ShowAll, nullptr, N_("All"), nullptr }, + { ShowMode{ -1 }, nullptr, nullptr, nullptr }, + { ShowMode::ShowActive, nullptr, N_("Active"), "system-run" }, + { ShowMode::ShowDownloading, "Verb", NC_("Verb", "Downloading"), "network-receive" }, + { ShowMode::ShowSeeding, "Verb", NC_("Verb", "Seeding"), "network-transmit" }, + { ShowMode::ShowPaused, nullptr, N_("Paused"), "media-playback-pause" }, + { ShowMode::ShowFinished, nullptr, N_("Finished"), "media-playback-stop" }, + { ShowMode::ShowVerifying, "Verb", NC_("Verb", "Verifying"), "view-refresh" }, + { ShowMode::ShowError, nullptr, N_("Error"), "dialog-error" }, } }); - auto store = Gtk::ListStore::create(activity_filter_cols); + auto store = Gtk::ListStore::create(show_mode_filter_cols); for (auto const& type : types) { @@ -489,40 +490,40 @@ Glib::RefPtr FilterBar::Impl::activity_filter_model_new() Glib::ustring(type.context != nullptr ? g_dpgettext2(nullptr, type.context, type.name) : _(type.name)) : Glib::ustring(); auto const iter = store->append(); - iter->set_value(activity_filter_cols.name, name); - iter->set_value(activity_filter_cols.type, type.type); - iter->set_value(activity_filter_cols.icon_name, Glib::ustring(type.icon_name != nullptr ? type.icon_name : "")); + iter->set_value(show_mode_filter_cols.name, name); + iter->set_value(show_mode_filter_cols.show_mode, type.show_mode); + iter->set_value(show_mode_filter_cols.icon_name, Glib::ustring(type.icon_name != nullptr ? type.icon_name : "")); } return store; } -void FilterBar::Impl::render_activity_pixbuf_func( +void FilterBar::Impl::render_show_mode_pixbuf_func( Gtk::CellRendererPixbuf& cell_renderer, Gtk::TreeModel::const_iterator const& iter) { - auto const type = ActivityType{ iter->get_value(activity_filter_cols.type) }; - cell_renderer.property_width() = type == ActivityType::ALL ? 0 : 20; - cell_renderer.property_ypad() = type == ActivityType::ALL ? 0 : 2; + auto const type = ShowMode{ iter->get_value(show_mode_filter_cols.show_mode) }; + cell_renderer.property_width() = type == ShowMode::ShowAll ? 0 : 20; + cell_renderer.property_ypad() = type == ShowMode::ShowAll ? 0 : 2; } -void FilterBar::Impl::activity_combo_box_init(Gtk::ComboBox& combo) +void FilterBar::Impl::show_mode_combo_box_init(Gtk::ComboBox& combo) { - combo.set_model(activity_model_); - combo.set_row_separator_func(sigc::hide<0>(&Impl::activity_is_it_a_separator)); + combo.set_model(show_mode_model_); + combo.set_row_separator_func(sigc::hide<0>(&Impl::show_mode_is_it_a_separator)); combo.set_active(0); { auto* r = Gtk::make_managed(); combo.pack_start(*r, false); - combo.add_attribute(r->property_icon_name(), activity_filter_cols.icon_name); - combo.set_cell_data_func(*r, [r](auto const& iter) { render_activity_pixbuf_func(*r, iter); }); + combo.add_attribute(r->property_icon_name(), show_mode_filter_cols.icon_name); + combo.set_cell_data_func(*r, [r](auto const& iter) { render_show_mode_pixbuf_func(*r, iter); }); } { auto* r = Gtk::make_managed(); combo.pack_start(*r, true); - combo.add_attribute(r->property_text(), activity_filter_cols.name); + combo.add_attribute(r->property_text(), show_mode_filter_cols.name); } { @@ -537,16 +538,16 @@ void FilterBar::Impl::update_filter_text() filter_->set_text(entry_->get_text()); } -void FilterBar::Impl::update_filter_activity() +void FilterBar::Impl::update_filter_show_mode() { - /* set active_activity_type_ from the activity combobox */ - if (auto const iter = activity_->get_active(); iter) + /* set active_show_mode_type_ from the show_mode combobox */ + if (auto const iter = show_mode_->get_active(); iter) { - filter_->set_activity(ActivityType{ iter->get_value(activity_filter_cols.type) }); + filter_->set_mode(ShowMode{ iter->get_value(show_mode_filter_cols.show_mode) }); } else { - filter_->set_activity(ActivityType::ALL); + filter_->set_mode(ShowMode::ShowAll); } } @@ -577,15 +578,15 @@ bool FilterBar::Impl::update_count_label() trackerCount = iter->get_value(tracker_filter_cols.count); } - /* get the activity count */ - int activityCount = 0; - if (auto const iter = activity_->get_active(); iter) + /* get the mode count */ + int modeCount = 0; + if (auto const iter = show_mode_->get_active(); iter) { - activityCount = iter->get_value(activity_filter_cols.count); + modeCount = iter->get_value(show_mode_filter_cols.count); } /* set the text */ - if (auto const new_markup = visibleCount == std::min(activityCount, trackerCount) ? + if (auto const new_markup = visibleCount == std::min(modeCount, trackerCount) ? _("_Show:") : fmt::format(fmt::runtime(_("_Show {count:L} of:")), fmt::arg("count", visibleCount)); new_markup != show_lb_->get_label().raw()) @@ -606,14 +607,14 @@ void FilterBar::Impl::update_count_label_idle() void FilterBar::Impl::update_filter_models(Torrent::ChangeFlags changes) { - static auto TR_CONSTEXPR23 activity_flags = Torrent::ChangeFlag::ACTIVE_PEERS_DOWN | Torrent::ChangeFlag::ACTIVE_PEERS_UP | + static auto TR_CONSTEXPR23 show_mode_flags = Torrent::ChangeFlag::ACTIVE_PEERS_DOWN | Torrent::ChangeFlag::ACTIVE_PEERS_UP | Torrent::ChangeFlag::ACTIVE | Torrent::ChangeFlag::ACTIVITY | Torrent::ChangeFlag::ERROR_CODE | Torrent::ChangeFlag::FINISHED; static auto constexpr tracker_flags = Torrent::ChangeFlag::TRACKERS; - if (changes.test(activity_flags)) + if (changes.test(show_mode_flags)) { - activity_filter_model_update(); + show_mode_filter_model_update(); } if (changes.test(tracker_flags)) @@ -623,7 +624,7 @@ void FilterBar::Impl::update_filter_models(Torrent::ChangeFlags changes) filter_->update(changes); - if (changes.test(activity_flags | tracker_flags)) + if (changes.test(show_mode_flags | tracker_flags)) { update_count_label_idle(); } @@ -657,7 +658,7 @@ void FilterBarExtraInit::class_init(void* klass, void* /*user_data*/) gtk_widget_class_set_template_from_resource(widget_klass, gtr_get_full_resource_path("FilterBar.ui").c_str()); - gtk_widget_class_bind_template_child_full(widget_klass, "activity_combo", FALSE, 0); + gtk_widget_class_bind_template_child_full(widget_klass, "show_mode_combo", FALSE, 0); gtk_widget_class_bind_template_child_full(widget_klass, "tracker_combo", FALSE, 0); gtk_widget_class_bind_template_child_full(widget_klass, "text_entry", FALSE, 0); gtk_widget_class_bind_template_child_full(widget_klass, "show_label", FALSE, 0); @@ -692,9 +693,9 @@ FilterBar::~FilterBar() = default; FilterBar::Impl::Impl(FilterBar& widget, Glib::RefPtr const& core) : widget_(widget) , core_(core) - , activity_model_(activity_filter_model_new()) + , show_mode_model_(show_mode_filter_model_new()) , tracker_model_(tracker_filter_model_new()) - , activity_(get_template_child("activity_combo")) + , show_mode_(get_template_child("show_mode_combo")) , tracker_(get_template_child("tracker_combo")) , entry_(get_template_child("text_entry")) , show_lb_(get_template_child("show_label")) @@ -704,10 +705,10 @@ FilterBar::Impl::Impl(FilterBar& widget, Glib::RefPtr const& core) update_filter_models_on_change_tag_ = core_->signal_torrents_changed().connect( sigc::hide<0>(sigc::mem_fun(*this, &Impl::update_filter_models_idle))); - activity_filter_model_update(); + show_mode_filter_model_update(); tracker_filter_model_update(); - activity_combo_box_init(*activity_); + show_mode_combo_box_init(*show_mode_); tracker_combo_box_init(*tracker_); filter_->signal_changed().connect([this](auto /*changes*/) { update_count_label_idle(); }); @@ -715,7 +716,7 @@ FilterBar::Impl::Impl(FilterBar& widget, Glib::RefPtr const& core) filter_model_ = FilterListModel::create(core_->get_sorted_model(), filter_); tracker_->signal_changed().connect(sigc::mem_fun(*this, &Impl::update_filter_tracker)); - activity_->signal_changed().connect(sigc::mem_fun(*this, &Impl::update_filter_activity)); + show_mode_->signal_changed().connect(sigc::mem_fun(*this, &Impl::update_filter_show_mode)); #if GTKMM_CHECK_VERSION(4, 0, 0) entry_->signal_icon_release().connect([this](auto /*icon_position*/) { entry_->set_text({}); }); diff --git a/gtk/Prefs.cc b/gtk/Prefs.cc index a1803c0f1..afcb59056 100644 --- a/gtk/Prefs.cc +++ b/gtk/Prefs.cc @@ -7,7 +7,10 @@ #include "GtkCompat.h" #include "PrefsDialog.h" +#include + #include +#include #include #include @@ -17,6 +20,8 @@ #include using namespace std::literals; +using namespace transmission::app; +using libtransmission::serializer::to_variant; std::string gl_confdir; @@ -71,7 +76,7 @@ namespace map.try_emplace(TR_KEY_show_statusbar, true); map.try_emplace(TR_KEY_show_toolbar, true); map.try_emplace(TR_KEY_show_tracker_scrapes, false); - map.try_emplace(TR_KEY_sort_mode, "sort-by-name"sv); + 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_torrent_added_notification_enabled, true); @@ -121,6 +126,11 @@ tr_variant& gtr_pref_get_all() return getPrefs(); } +tr_variant::Map& gtr_pref_get_map() +{ + return *getPrefs().get_if(); +} + int64_t gtr_pref_int_get(tr_quark const key) { int64_t i = 0; diff --git a/gtk/Prefs.h b/gtk/Prefs.h index 25ab23c69..cdcbf3fad 100644 --- a/gtk/Prefs.h +++ b/gtk/Prefs.h @@ -6,12 +6,25 @@ #include /* tr_variant, tr_session */ #include +#include +#include #include // int64_t #include #include #include +[[nodiscard]] tr_variant::Map& gtr_pref_get_map(); + +template +[[nodiscard]] std::optional gtr_pref_get(tr_quark const key) +{ + using namespace libtransmission::serializer; + auto const& map = gtr_pref_get_map(); + auto const iter = map.find(key); + return iter != std::end(map) ? to_value(iter->second) : std::nullopt; +} + void gtr_pref_init(std::string_view config_dir); int64_t gtr_pref_int_get(tr_quark key); diff --git a/gtk/Session.cc b/gtk/Session.cc index b64f20fcc..afa29a10e 100644 --- a/gtk/Session.cc +++ b/gtk/Session.cc @@ -478,7 +478,10 @@ void Session::Impl::on_pref_changed(tr_quark const key) switch (key) { case TR_KEY_sort_mode: - sorter_->set_mode(gtr_pref_string_get(TR_KEY_sort_mode)); + if (auto const sort_mode = gtr_pref_get(TR_KEY_sort_mode)) + { + sorter_->set_mode(*sort_mode); + } break; case TR_KEY_sort_reversed: diff --git a/gtk/Session.h b/gtk/Session.h index 77fc3bd36..df1b11d20 100644 --- a/gtk/Session.h +++ b/gtk/Session.h @@ -7,8 +7,9 @@ #include "GtkCompat.h" #include "Torrent.h" +#include + #include -#include #include #include diff --git a/gtk/TorrentFilter.cc b/gtk/TorrentFilter.cc index a17078cfb..ee329f877 100644 --- a/gtk/TorrentFilter.cc +++ b/gtk/TorrentFilter.cc @@ -19,24 +19,25 @@ TorrentFilter::TorrentFilter() { } -void TorrentFilter::set_activity(Activity type) +void TorrentFilter::set_mode(ShowMode const mode) { - if (activity_type_ == type) + if (show_mode_ == mode) { return; } auto change = Change::DIFFERENT; - if (activity_type_ == Activity::ALL) + + if (show_mode_ == ShowMode::ShowAll) { change = Change::MORE_STRICT; } - else if (type == Activity::ALL) + else if (mode == ShowMode::ShowAll) { change = Change::LESS_STRICT; } - activity_type_ = type; + show_mode_ = mode; changed(change); } @@ -98,9 +99,9 @@ void TorrentFilter::set_text(Glib::ustring const& text) changed(change); } -bool TorrentFilter::match_activity(Torrent const& torrent) const +bool TorrentFilter::match_mode(Torrent const& torrent) const { - return match_activity(torrent, activity_type_); + return match_mode(torrent, show_mode_); } bool TorrentFilter::match_tracker(Torrent const& torrent) const @@ -115,12 +116,12 @@ bool TorrentFilter::match_text(Torrent const& torrent) const bool TorrentFilter::match(Torrent const& torrent) const { - return match_activity(torrent) && match_tracker(torrent) && match_text(torrent); + return match_mode(torrent) && match_tracker(torrent) && match_text(torrent); } bool TorrentFilter::matches_all() const { - return activity_type_ == Activity::ALL && tracker_type_ == Tracker::ALL && text_.empty(); + return show_mode_ == ShowMode::ShowAll && tracker_type_ == Tracker::ALL && text_.empty(); } void TorrentFilter::update(Torrent::ChangeFlags changes) @@ -129,23 +130,23 @@ void TorrentFilter::update(Torrent::ChangeFlags changes) bool refilter_needed = false; - if (activity_type_ != Activity::ALL) + if (show_mode_ != ShowMode::ShowAll) { - static auto TR_CONSTEXPR23 ActivityFlags = std::array, 7U>{ { - { Activity::DOWNLOADING, Flag::ACTIVITY }, - { Activity::SEEDING, Flag::ACTIVITY }, - { Activity::ACTIVE, Flag::ACTIVE_PEER_COUNT | Flag::ACTIVITY }, - { Activity::PAUSED, Flag::ACTIVITY }, - { Activity::FINISHED, Flag::FINISHED }, - { Activity::VERIFYING, Flag::ACTIVITY }, - { Activity::ERROR, Flag::ERROR_CODE }, + static auto TR_CONSTEXPR23 ShowModeFlags = std::array, 7U>{ { + { ShowMode::ShowActive, Flag::ACTIVE_PEER_COUNT | Flag::ACTIVITY }, + { ShowMode::ShowDownloading, Flag::ACTIVITY }, + { ShowMode::ShowError, Flag::ERROR_CODE }, + { ShowMode::ShowFinished, Flag::FINISHED }, + { ShowMode::ShowPaused, Flag::ACTIVITY }, + { ShowMode::ShowSeeding, Flag::ACTIVITY }, + { ShowMode::ShowVerifying, Flag::ACTIVITY }, } }; auto const iter = std::find_if( - std::begin(ActivityFlags), - std::end(ActivityFlags), - [key = activity_type_](auto const& row) { return row.first == key; }); - refilter_needed = iter != std::end(ActivityFlags) && changes.test(iter->second); + std::begin(ShowModeFlags), + std::end(ShowModeFlags), + [key = show_mode_](auto const& row) { return row.first == key; }); + refilter_needed = iter != std::end(ShowModeFlags) && changes.test(iter->second); } if (!refilter_needed) @@ -170,43 +171,42 @@ Glib::RefPtr TorrentFilter::create() return Glib::make_refptr_for_instance(new TorrentFilter()); } -bool TorrentFilter::match_activity(Torrent const& torrent, Activity type) +bool TorrentFilter::match_mode(Torrent const& torrent, ShowMode const type) { auto activity = tr_torrent_activity(); switch (type) { - case Activity::ALL: + case ShowMode::ShowAll: return true; - case Activity::DOWNLOADING: + case ShowMode::ShowDownloading: activity = torrent.get_activity(); return activity == TR_STATUS_DOWNLOAD || activity == TR_STATUS_DOWNLOAD_WAIT; - case Activity::SEEDING: + case ShowMode::ShowSeeding: activity = torrent.get_activity(); return activity == TR_STATUS_SEED || activity == TR_STATUS_SEED_WAIT; - case Activity::ACTIVE: + case ShowMode::ShowActive: return torrent.get_active_peer_count() > 0 || torrent.get_activity() == TR_STATUS_CHECK; - case Activity::PAUSED: + case ShowMode::ShowPaused: return torrent.get_activity() == TR_STATUS_STOPPED; - case Activity::FINISHED: + case ShowMode::ShowFinished: return torrent.get_finished(); - case Activity::VERIFYING: + case ShowMode::ShowVerifying: activity = torrent.get_activity(); return activity == TR_STATUS_CHECK || activity == TR_STATUS_CHECK_WAIT; - case Activity::ERROR: + case ShowMode::ShowError: return torrent.get_error_code() != 0; - - default: - g_assert_not_reached(); - return true; } + + g_assert_not_reached(); + return true; } bool TorrentFilter::match_tracker(Torrent const& torrent, Tracker type, Glib::ustring const& host) diff --git a/gtk/TorrentFilter.h b/gtk/TorrentFilter.h index 6f36e07b4..5679b75c7 100644 --- a/gtk/TorrentFilter.h +++ b/gtk/TorrentFilter.h @@ -8,6 +8,8 @@ #include "FilterBase.h" #include "Torrent.h" +#include + #include #include @@ -16,17 +18,7 @@ class TorrentFilter : public FilterBase { public: - enum class Activity : int8_t - { - ALL, - DOWNLOADING, - SEEDING, - ACTIVE, - PAUSED, - FINISHED, - VERIFYING, - ERROR, - }; + using ShowMode = transmission::app::ShowMode; enum class Tracker : int8_t { @@ -35,13 +27,13 @@ public: }; public: - void set_activity(Activity type); + void set_mode(ShowMode mode); void set_tracker(Tracker type, Glib::ustring const& host); void set_text(Glib::ustring const& text); - bool match_activity(Torrent const& torrent) const; - bool match_tracker(Torrent const& torrent) const; + bool match_mode(Torrent const& torrent) const; bool match_text(Torrent const& torrent) const; + bool match_tracker(Torrent const& torrent) const; // FilterBase bool match(Torrent const& torrent) const override; @@ -51,7 +43,7 @@ public: static Glib::RefPtr create(); - static bool match_activity(Torrent const& torrent, Activity type); + static bool match_mode(Torrent const& torrent, ShowMode mode); static bool match_tracker(Torrent const& torrent, Tracker type, Glib::ustring const& host); static bool match_text(Torrent const& torrent, Glib::ustring const& text); @@ -59,7 +51,7 @@ private: TorrentFilter(); private: - Activity activity_type_ = Activity::ALL; + ShowMode show_mode_ = transmission::app::DefaultShowMode; Tracker tracker_type_ = Tracker::ALL; Glib::ustring tracker_host_; Glib::ustring text_; diff --git a/gtk/TorrentSorter.cc b/gtk/TorrentSorter.cc index 2bce1f6ae..cea087eb9 100644 --- a/gtk/TorrentSorter.cc +++ b/gtk/TorrentSorter.cc @@ -9,18 +9,24 @@ #include "SorterBase.hh" #include "Utils.h" +#include + #include #include #include +#include + #include #include #include using namespace std::string_view_literals; +using namespace transmission::app; namespace { +using CompareFunc = int (*)(Torrent const&, Torrent const&); constexpr bool is_valid_eta(time_t value) { @@ -150,6 +156,12 @@ int compare_by_progress(Torrent const& lhs, Torrent const& rhs) return compare_by_ratio(lhs, rhs); } +// NOLINTNEXTLINE(bugprone-easily-swappable-parameters) +int compare_by_id(Torrent const& lhs, Torrent const& rhs) +{ + return -tr_compare_3way(lhs.get_id(), rhs.get_id()); +} + // NOLINTNEXTLINE(bugprone-easily-swappable-parameters) int compare_by_eta(Torrent const& lhs, Torrent const& rhs) { @@ -171,7 +183,6 @@ int compare_by_state(Torrent const& lhs, Torrent const& rhs) return compare_by_queue(lhs, rhs); } - } // namespace TorrentSorter::TorrentSorter() @@ -179,25 +190,23 @@ TorrentSorter::TorrentSorter() { } -void TorrentSorter::set_mode(std::string_view mode) +void TorrentSorter::set_mode(SortMode const mode) { static auto constexpr DefaultCompareFunc = &compare_by_name; - static auto constexpr CompareFuncs = std::array, 9U>{ { - { "sort-by-activity"sv, &compare_by_activity }, - { "sort-by-age"sv, &compare_by_age }, - { "sort-by-name"sv, &compare_by_name }, - { "sort-by-progress"sv, &compare_by_progress }, - { "sort-by-queue"sv, &compare_by_queue }, - { "sort-by-ratio"sv, &compare_by_ratio }, - { "sort-by-size"sv, &compare_by_size }, - { "sort-by-state"sv, &compare_by_state }, - { "sort-by-time-left"sv, &compare_by_eta }, + static auto const CompareFuncs = small::max_size_map{ { + { SortMode::SortByActivity, &compare_by_activity }, + { SortMode::SortByAge, &compare_by_age }, + { SortMode::SortByEta, &compare_by_eta }, + { SortMode::SortById, &compare_by_id }, + { SortMode::SortByName, &compare_by_name }, + { SortMode::SortByProgress, &compare_by_progress }, + { SortMode::SortByQueue, &compare_by_queue }, + { SortMode::SortByRatio, &compare_by_ratio }, + { SortMode::SortBySize, &compare_by_size }, + { SortMode::SortByState, &compare_by_state }, } }; - auto const iter = std::find_if( - std::begin(CompareFuncs), - std::end(CompareFuncs), - [key = mode](auto const& row) { return row.first == key; }); + auto const iter = CompareFuncs.find(mode); auto const compare_func = iter != std::end(CompareFuncs) ? iter->second : DefaultCompareFunc; if (compare_func_ == compare_func) { diff --git a/gtk/TorrentSorter.h b/gtk/TorrentSorter.h index bfe9000ef..68e9c5f64 100644 --- a/gtk/TorrentSorter.h +++ b/gtk/TorrentSorter.h @@ -8,14 +8,18 @@ #include "SorterBase.h" #include "Torrent.h" +#include + #include +using SortMode = transmission::app::SortMode; + class TorrentSorter : public SorterBase { using CompareFunc = int (*)(Torrent const&, Torrent const&); public: - void set_mode(std::string_view mode); + void set_mode(SortMode mode); void set_reversed(bool is_reversed); // SorterBase diff --git a/gtk/main.cc b/gtk/main.cc index 154eb90d3..29409f073 100644 --- a/gtk/main.cc +++ b/gtk/main.cc @@ -8,6 +8,8 @@ #include "Prefs.h" #include "Utils.h" +#include + #include #include #include @@ -48,11 +50,9 @@ Glib::OptionEntry create_option_entry(Glib::ustring const& long_name, gchar shor int main(int argc, char** argv) { - /* init libtransmission */ - tr_lib_init(); + transmission::app::init(); /* init i18n */ - tr_locale_set_global(""); bindtextdomain(AppTranslationDomainName, TRANSMISSIONLOCALEDIR); bind_textdomain_codeset(AppTranslationDomainName, "UTF-8"); textdomain(AppTranslationDomainName); diff --git a/gtk/transmission-ui.xml b/gtk/transmission-ui.xml index 39b4de618..d7d8ed69d 100644 --- a/gtk/transmission-ui.xml +++ b/gtk/transmission-ui.xml @@ -201,47 +201,47 @@ win.sort-torrents Sort by _Activity - sort-by-activity + sort_by_activity win.sort-torrents Sort by A_ge - sort-by-age + sort_by_age win.sort-torrents Sort by _Name - sort-by-name + sort_by_name win.sort-torrents Sort by _Progress - sort-by-progress + sort_by_progress win.sort-torrents Sort by _Queue - sort-by-queue + sort_by_queue win.sort-torrents Sort by Rati_o - sort-by-ratio + sort_by_ratio win.sort-torrents Sort by Si_ze - sort-by-size + sort_by_size win.sort-torrents Sort by Stat_e - sort-by-state + sort_by_state win.sort-torrents Sort by Time _Left - sort-by-time-left + sort_by_time_left
@@ -308,47 +308,47 @@ win.sort-torrents Sort by _Activity - sort-by-activity + sort_by_activity win.sort-torrents Sort by A_ge - sort-by-age + sort_by_age win.sort-torrents Sort by _Name - sort-by-name + sort_by_name win.sort-torrents Sort by _Progress - sort-by-progress + sort_by_progress win.sort-torrents Sort by _Queue - sort-by-queue + sort_by_queue win.sort-torrents Sort by Rati_o - sort-by-ratio + sort_by_ratio win.sort-torrents Sort by Si_ze - sort-by-size + sort_by_size win.sort-torrents Sort by Stat_e - sort-by-state + sort_by_state win.sort-torrents Sort by Time _Left - sort-by-time-left + sort_by_time_left
diff --git a/gtk/ui/gtk3/FilterBar.ui b/gtk/ui/gtk3/FilterBar.ui index 132673430..e743e7ebb 100644 --- a/gtk/ui/gtk3/FilterBar.ui +++ b/gtk/ui/gtk3/FilterBar.ui @@ -12,7 +12,7 @@ False _Show: True - activity_combo + show_mode_combo False @@ -21,7 +21,7 @@ - + True False 6 diff --git a/gtk/ui/gtk4/FilterBar.ui b/gtk/ui/gtk4/FilterBar.ui index 9af6f9499..ff09de225 100644 --- a/gtk/ui/gtk4/FilterBar.ui +++ b/gtk/ui/gtk4/FilterBar.ui @@ -7,11 +7,11 @@ _Show: 1 - activity_combo + show_mode_combo - + 1 6 diff --git a/libtransmission-app/.clang-tidy b/libtransmission-app/.clang-tidy new file mode 100644 index 000000000..e36096bce --- /dev/null +++ b/libtransmission-app/.clang-tidy @@ -0,0 +1,55 @@ +--- +HeaderFilterRegex: .*/libtransmission/.* + +# TODO: Enable `portability-template-virtual-member-function` after https://github.com/llvm/llvm-project/issues/139031 is fixed +# PRs welcome to fix & re-enable any of these explicitly-disabled checks +Checks: > + bugprone-*, + -bugprone-branch-clone, + -bugprone-easily-swappable-parameters, + -bugprone-implicit-widening-of-multiplication-result, + -bugprone-narrowing-conversions, + cert-*, + -cert-err58-cpp, + -cert-int09-c, + clang-analyzer-*, + -clang-analyzer-optin.core.EnumCastOutOfRange, + cppcoreguidelines-avoid-do-while, + cppcoreguidelines-avoid-goto, + cppcoreguidelines-avoid-reference-coroutine-parameters, + cppcoreguidelines-init-variables, + cppcoreguidelines-interfaces-global-init, + cppcoreguidelines-no-malloc, + cppcoreguidelines-prefer-member-initializer, + cppcoreguidelines-pro-type-cstyle-cast, + cppcoreguidelines-pro-type-member-init, + cppcoreguidelines-slicing, + cppcoreguidelines-special-member-functions, + cppcoreguidelines-virtual-class-destructor, + google-explicit-constructor, + misc-*, + -misc-include-cleaner, + -misc-no-recursion, + -misc-non-private-member-variables-in-classes, + modernize-*, + -modernize-use-trailing-return-type, + performance-*, + -performance-move-const-arg, + portability-*, + -portability-template-virtual-member-function, + readability-*, + -readability-enum-initial-value, + -readability-function-cognitive-complexity, + -readability-identifier-length, + -readability-magic-numbers, + -readability-qualified-auto, + +CheckOptions: + - { key: cppcoreguidelines-avoid-do-while.IgnoreMacros, value: true } + - { key: cppcoreguidelines-special-member-functions.AllowSoleDefaultDtor, value: true } + - { key: readability-identifier-naming.ConstexprVariableCase, value: CamelCase } + - { key: readability-identifier-naming.ParameterCase, value: lower_case } + - { key: readability-identifier-naming.PrivateMemberSuffix, value: _ } + - { key: readability-identifier-naming.ProtectedMemberSuffix, value: _ } + - { key: readability-identifier-naming.VariableCase, value: lower_case } + - { key: readability-implicit-bool-conversion.UseUpperCaseLiteralSuffix, value: true } diff --git a/libtransmission-app/CMakeLists.txt b/libtransmission-app/CMakeLists.txt new file mode 100644 index 000000000..9e0d59916 --- /dev/null +++ b/libtransmission-app/CMakeLists.txt @@ -0,0 +1,25 @@ +include(CheckLibraryExists) +include(CheckSymbolExists) + +set(LIBNAME ${TR_NAME}-app) + +add_library(${LIBNAME} STATIC) +add_library(transmission::app ALIAS ${LIBNAME}) + +target_sources(${LIBNAME} + PRIVATE + app.cc + app.h + converters.cc + converters.h + display-modes.h + favicon-cache.h) + +target_include_directories(${LIBNAME} + PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR}/.. + ${CMAKE_CURRENT_BINARY_DIR}/..) + +target_link_libraries(${LIBNAME} + PUBLIC + fmt::fmt-header-only) diff --git a/libtransmission-app/app.cc b/libtransmission-app/app.cc new file mode 100644 index 000000000..e358afae8 --- /dev/null +++ b/libtransmission-app/app.cc @@ -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. + +#include // tr_lib_init() + +#include "libtransmission-app/app.h" +#include "libtransmission-app/converters.h" + +namespace transmission::app +{ +void init() +{ + tr_lib_init(); + tr_locale_set_global(""); + detail::register_app_converters(); +} +} // namespace transmission::app diff --git a/libtransmission-app/app.h b/libtransmission-app/app.h new file mode 100644 index 000000000..3d1a5c867 --- /dev/null +++ b/libtransmission-app/app.h @@ -0,0 +1,14 @@ +// 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 + +namespace transmission::app +{ + +// should be called once when starting the app +void init(); + +} // namespace transmission::app diff --git a/libtransmission-app/converters.cc b/libtransmission-app/converters.cc new file mode 100644 index 000000000..75a957065 --- /dev/null +++ b/libtransmission-app/converters.cc @@ -0,0 +1,140 @@ +// 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 +#include +#include +#include + +#include "libtransmission/serializer.h" +#include "libtransmission/variant.h" + +#include "libtransmission-app/display-modes.h" +#include "libtransmission-app/converters.h" + +namespace transmission::app::detail +{ +namespace +{ +template +using Lookup = std::array, N>; + +// --- + +auto constexpr ShowKeys = std::array, ShowModeCount>{ { + { TR_KEY_show_active, ShowMode::ShowActive }, + { TR_KEY_show_all, ShowMode::ShowAll }, + { TR_KEY_show_downloading, ShowMode::ShowDownloading }, + { TR_KEY_show_error, ShowMode::ShowError }, + { TR_KEY_show_finished, ShowMode::ShowFinished }, + { TR_KEY_show_paused, ShowMode::ShowPaused }, + { TR_KEY_show_seeding, ShowMode::ShowSeeding }, + { TR_KEY_show_verifying, ShowMode::ShowVerifying }, +} }; + +bool to_show_mode(tr_variant const& src, ShowMode* tgt) +{ + static constexpr auto& Keys = ShowKeys; + + if (auto const str = src.value_if()) + { + if (auto const needle = tr_quark_lookup(*str)) + { + for (auto const& [key, val] : Keys) + { + if (needle == key) + { + *tgt = val; + return true; + } + } + } + } + + return false; +} + +tr_variant from_show_mode(ShowMode const& src) +{ + static constexpr auto& Keys = ShowKeys; + + for (auto const& [key, val] : Keys) + { + if (src == val) + { + return tr_variant::unmanaged_string(key); + } + } + + return tr_variant::unmanaged_string(TR_KEY_show_all); +} + +// --- + +auto constexpr SortKeys = std::array, SortModeCount>{ { + { TR_KEY_sort_by_activity, SortMode::SortByActivity }, + { TR_KEY_sort_by_age, SortMode::SortByAge }, + { TR_KEY_sort_by_eta, SortMode::SortByEta }, + { TR_KEY_sort_by_id, SortMode::SortById }, + { TR_KEY_sort_by_name, SortMode::SortByName }, + { TR_KEY_sort_by_progress, SortMode::SortByProgress }, + { TR_KEY_sort_by_queue, SortMode::SortByQueue }, + { TR_KEY_sort_by_ratio, SortMode::SortByRatio }, + { TR_KEY_sort_by_size, SortMode::SortBySize }, + { TR_KEY_sort_by_state, SortMode::SortByState }, +} }; + +bool to_sort_mode(tr_variant const& src, SortMode* tgt) +{ + static constexpr auto& Keys = SortKeys; + + if (auto const str = src.value_if()) + { + if (auto const needle = tr_quark_lookup(*str)) + { + for (auto const& [key, val] : Keys) + { + if (needle == key) + { + *tgt = val; + return true; + } + } + } + } + + return false; +} + +tr_variant from_sort_mode(SortMode const& src) +{ + static constexpr auto& Keys = SortKeys; + + for (auto const& [key, val] : Keys) + { + if (src == val) + { + return tr_variant::unmanaged_string(key); + } + } + + return tr_variant::unmanaged_string(TR_KEY_sort_by_name); +} +} // unnamed namespace + +void register_app_converters() +{ + static auto once = std::once_flag{}; + std::call_once( + once, + [] + { + using Converters = libtransmission::serializer::Converters; + Converters::add(to_show_mode, from_show_mode); + Converters::add(to_sort_mode, from_sort_mode); + }); +} + +} // namespace transmission::app::detail diff --git a/libtransmission-app/converters.h b/libtransmission-app/converters.h new file mode 100644 index 000000000..a3e39c463 --- /dev/null +++ b/libtransmission-app/converters.h @@ -0,0 +1,13 @@ +// 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 + +namespace transmission::app::detail +{ + +void register_app_converters(); + +} // namespace transmission::app::detail diff --git a/libtransmission-app/display-modes.h b/libtransmission-app/display-modes.h new file mode 100644 index 000000000..2f539e2ab --- /dev/null +++ b/libtransmission-app/display-modes.h @@ -0,0 +1,40 @@ +// 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 + +namespace transmission::app +{ +enum class ShowMode +{ + ShowAll, + ShowActive, + ShowDownloading, + ShowSeeding, + ShowPaused, + ShowFinished, + ShowVerifying, + ShowError, +}; +inline auto constexpr ShowModeCount = 8U; +inline auto constexpr DefaultShowMode = ShowMode::ShowAll; + +enum class SortMode +{ + SortByActivity, + SortByAge, + SortByEta, + SortByName, + SortByProgress, + SortByQueue, + SortByRatio, + SortBySize, + SortByState, + SortById, +}; +inline auto constexpr SortModeCount = 10U; +inline auto constexpr DefaultSortMode = SortMode::SortByName; + +} // namespace transmission::app diff --git a/libtransmission/favicon-cache.h b/libtransmission-app/favicon-cache.h similarity index 100% rename from libtransmission/favicon-cache.h rename to libtransmission-app/favicon-cache.h diff --git a/libtransmission/CMakeLists.txt b/libtransmission/CMakeLists.txt index cec4f8bbb..daa84c6e1 100644 --- a/libtransmission/CMakeLists.txt +++ b/libtransmission/CMakeLists.txt @@ -55,7 +55,6 @@ target_sources(${TR_NAME} error-types.h error.cc error.h - favicon-cache.h file-capacity.cc file-piece-map.cc file-piece-map.h @@ -307,7 +306,6 @@ if(INSTALL_LIB) FILES error-types.h error.h - favicon-cache.h file.h log.h makemeta.h diff --git a/libtransmission/serializer.h b/libtransmission/serializer.h index eaa391876..f30285c24 100644 --- a/libtransmission/serializer.h +++ b/libtransmission/serializer.h @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -213,6 +214,23 @@ private: static inline ConverterStorage converter_storage; }; +template +[[nodiscard]] std::optional to_value(tr_variant const& var) +{ + if (auto ret = T{}; Converters::deserialize(var, &ret)) + { + return ret; + } + + return {}; +} + +template +[[nodiscard]] tr_variant to_variant(T const& val) +{ + return Converters::serialize(val); +} + // --- /** diff --git a/qt/Application.h b/qt/Application.h index 0cff3e6b3..73ad19e71 100644 --- a/qt/Application.h +++ b/qt/Application.h @@ -17,7 +17,7 @@ #include #include -#include +#include #include "AddData.h" #include "Typedefs.h" diff --git a/qt/CMakeLists.txt b/qt/CMakeLists.txt index 7a77e6191..1a6f81ef2 100644 --- a/qt/CMakeLists.txt +++ b/qt/CMakeLists.txt @@ -211,6 +211,7 @@ target_include_directories(${TR_NAME}-qt target_link_libraries(${TR_NAME}-qt PRIVATE + ${TR_NAME}-app ${TR_NAME} transmission::qt_impl) diff --git a/qt/CustomVariantType.h b/qt/CustomVariantType.h index a900a143d..4d0055ede 100644 --- a/qt/CustomVariantType.h +++ b/qt/CustomVariantType.h @@ -15,7 +15,7 @@ public: TrackerStatsList = QMetaType::User, PeerList, FileList, - FilterModeType, + ShowModeType, SortModeType }; }; diff --git a/qt/FaviconCache.cc b/qt/FaviconCache.cc index cae19d263..ba942a6f0 100644 --- a/qt/FaviconCache.cc +++ b/qt/FaviconCache.cc @@ -4,7 +4,7 @@ // or any future license endorsed by Mnemosyne LLC. // License text can be found in the licenses/ folder. -#include +#include #include #include diff --git a/qt/FilterBar.cc b/qt/FilterBar.cc index c5f64ccfd..86021c327 100644 --- a/qt/FilterBar.cc +++ b/qt/FilterBar.cc @@ -45,25 +45,25 @@ FilterBarComboBox* FilterBar::createActivityCombo() auto* model = new QStandardItemModel{ this }; auto* row = new QStandardItem{ tr("All") }; - row->setData(FilterMode::SHOW_ALL, ACTIVITY_ROLE); + row->setData(QVariant::fromValue(ShowMode::ShowAll), ACTIVITY_ROLE); model->appendRow(row); model->appendRow(new QStandardItem{}); // separator FilterBarComboBoxDelegate::setSeparator(model, model->index(1, 0)); - auto add_row = [model](auto const filter_mode, QString label, std::optional const type) + auto add_row = [model](auto const show_mode, QString label, std::optional const type) { - auto* row = type ? new QStandardItem{ icons::icon(*type), label } : new QStandardItem{ label }; - row->setData(filter_mode, ACTIVITY_ROLE); - model->appendRow(row); + auto* new_row = type ? new QStandardItem{ icons::icon(*type), label } : new QStandardItem{ label }; + new_row->setData(QVariant::fromValue(show_mode), ACTIVITY_ROLE); + model->appendRow(new_row); }; - add_row(FilterMode::SHOW_ACTIVE, tr("Active"), icons::Type::TorrentStateActive); - add_row(FilterMode::SHOW_SEEDING, tr("Seeding"), icons::Type::TorrentStateSeeding); - add_row(FilterMode::SHOW_DOWNLOADING, tr("Downloading"), icons::Type::TorrentStateDownloading); - add_row(FilterMode::SHOW_PAUSED, tr("Paused"), icons::Type::TorrentStatePaused); - add_row(FilterMode::SHOW_FINISHED, tr("Finished"), {}); - add_row(FilterMode::SHOW_VERIFYING, tr("Verifying"), icons::Type::TorrentStateVerifying); - add_row(FilterMode::SHOW_ERROR, tr("Error"), icons::Type::TorrentStateError); + add_row(ShowMode::ShowActive, tr("Active"), icons::Type::TorrentStateActive); + add_row(ShowMode::ShowSeeding, tr("Seeding"), icons::Type::TorrentStateSeeding); + add_row(ShowMode::ShowDownloading, tr("Downloading"), icons::Type::TorrentStateDownloading); + add_row(ShowMode::ShowPaused, tr("Paused"), icons::Type::TorrentStatePaused); + add_row(ShowMode::ShowFinished, tr("Finished"), {}); + add_row(ShowMode::ShowVerifying, tr("Verifying"), icons::Type::TorrentStateVerifying); + add_row(ShowMode::ShowError, tr("Error"), icons::Type::TorrentStateError); c->setModel(model); return c; @@ -97,8 +97,6 @@ Torrent::fields_t constexpr TrackerFields = { return name; } -auto constexpr ActivityFields = FilterMode::TorrentFields; - } // namespace void FilterBar::refreshTrackers() @@ -266,9 +264,9 @@ void FilterBar::refreshPref(int key) { case Prefs::FILTER_MODE: { - auto const m = prefs_.get(key); + auto const show_mode = prefs_.get(key); QAbstractItemModel const* const model = activity_combo_->model(); - QModelIndexList indices = model->match(model->index(0, 0), ACTIVITY_ROLE, m.mode()); + QModelIndexList indices = model->match(model->index(0, 0), ACTIVITY_ROLE, QVariant::fromValue(show_mode)); activity_combo_->setCurrentIndex(indices.isEmpty() ? 0 : indices.first().row()); break; } @@ -308,7 +306,7 @@ void FilterBar::onTorrentsChanged(torrent_ids_t const& ids, Torrent::fields_t co recountTrackersSoon(); } - if ((changed_fields & ActivityFields).any()) + if ((changed_fields & ShowModeFields).any()) { recountActivitySoon(); } @@ -335,8 +333,8 @@ void FilterBar::onActivityIndexChanged(int i) { if (!is_bootstrapping_) { - auto const mode = FilterMode(activity_combo_->itemData(i, ACTIVITY_ROLE).toInt()); - prefs_.set(Prefs::FILTER_MODE, mode); + auto const show_mode = activity_combo_->itemData(i, ACTIVITY_ROLE).value(); + prefs_.set(Prefs::FILTER_MODE, show_mode); } } @@ -369,10 +367,10 @@ void FilterBar::recount() for (int row = 0, n = model->rowCount(); row < n; ++row) { auto const index = model->index(row, 0); - auto const mode = index.data(ACTIVITY_ROLE).toInt(); - auto const count = torrents_per_mode[mode]; + auto const show_mode = index.data(ACTIVITY_ROLE).value(); + auto const count = torrents_per_mode[static_cast(show_mode)]; model->setData(index, count, FilterBarComboBox::CountRole); - model->setData(index, getCountString(static_cast(count)), FilterBarComboBox::CountStringRole); + model->setData(index, getCountString(count), FilterBarComboBox::CountStringRole); } } diff --git a/qt/Filters.cc b/qt/Filters.cc index 828029a53..eaf846a32 100644 --- a/qt/Filters.cc +++ b/qt/Filters.cc @@ -5,33 +5,46 @@ #include "Filters.h" -// NB: if you change this function, update TorrentFields too -bool FilterMode::test(Torrent const& tor, int mode) +// NOTE: `ShowModeFields` is the set of all Torrent properties +// needed to correctly run these tests. If you change these tests, +// then update `ShowModeFields` accordingly. +bool should_show_torrent(Torrent const& tor, ShowMode const mode) { switch (mode) { - case SHOW_ACTIVE: + case ShowMode::ShowActive: return tor.peersWeAreUploadingTo() > 0 || tor.peersWeAreDownloadingFrom() > 0 || tor.isVerifying(); - case SHOW_DOWNLOADING: + case ShowMode::ShowDownloading: return tor.isDownloading() || tor.isWaitingToDownload(); - case SHOW_ERROR: + case ShowMode::ShowError: return tor.hasError(); - case SHOW_FINISHED: + case ShowMode::ShowFinished: return tor.isFinished(); - case SHOW_PAUSED: + case ShowMode::ShowPaused: return tor.isPaused(); - case SHOW_SEEDING: + case ShowMode::ShowSeeding: return tor.isSeeding() || tor.isWaitingToSeed(); - case SHOW_VERIFYING: + case ShowMode::ShowVerifying: return tor.isVerifying() || tor.isWaitingToVerify(); default: // SHOW_ALL return true; } } + +// The Torrent properties that can affect ShowMode filtering. +// When one of these changes, it's time to refilter. +// Update this as needed when ShowModeTests changes. +Torrent::fields_t const ShowModeFields{ + (uint64_t{ 1 } << Torrent::TORRENT_ERROR) | // + (uint64_t{ 1 } << Torrent::IS_FINISHED) | // + (uint64_t{ 1 } << Torrent::PEERS_GETTING_FROM_US) | // + (uint64_t{ 1 } << Torrent::PEERS_SENDING_TO_US) | // + (uint64_t{ 1 } << Torrent::STATUS) // +}; diff --git a/qt/Filters.h b/qt/Filters.h index cdb250819..7be3ee79d 100644 --- a/qt/Filters.h +++ b/qt/Filters.h @@ -5,89 +5,20 @@ #pragma once -#include // uint64_t +#include #include "Torrent.h" -class FilterMode -{ -public: - enum - { - SHOW_ALL, - SHOW_ACTIVE, - SHOW_DOWNLOADING, - SHOW_SEEDING, - SHOW_PAUSED, - SHOW_FINISHED, - SHOW_VERIFYING, - SHOW_ERROR, - NUM_MODES - }; +// The Torrent properties that can affect ShowMode filtering. +// When one of these changes, it's time to refilter. +extern Torrent::fields_t const ShowModeFields; - explicit FilterMode(int mode = SHOW_ALL) - : mode_{ mode } - { - } - - [[nodiscard]] int mode() const - { - return mode_; - } - - /* The Torrent properties that can affect this filter. - When one of these changes, it's time to refilter. */ - static constexpr auto TorrentFields = Torrent::fields_t{ - (uint64_t{ 1 } << Torrent::TORRENT_ERROR) | // - (uint64_t{ 1 } << Torrent::IS_FINISHED) | // - (uint64_t{ 1 } << Torrent::PEERS_GETTING_FROM_US) | // - (uint64_t{ 1 } << Torrent::PEERS_SENDING_TO_US) | // - (uint64_t{ 1 } << Torrent::STATUS) // - }; - - static bool test(Torrent const& tor, int mode); - - [[nodiscard]] bool test(Torrent const& tor) const - { - return test(tor, mode()); - } - -private: - int mode_; -}; - -Q_DECLARE_METATYPE(FilterMode) - -class SortMode -{ -public: - enum - { - SORT_BY_ACTIVITY, - SORT_BY_AGE, - SORT_BY_ETA, - SORT_BY_NAME, - SORT_BY_PROGRESS, - SORT_BY_QUEUE, - SORT_BY_RATIO, - SORT_BY_SIZE, - SORT_BY_STATE, - SORT_BY_ID, - NUM_MODES - }; - - explicit SortMode(int mode = SORT_BY_ID) noexcept - : mode_{ mode } - { - } - - [[nodiscard]] constexpr auto mode() const noexcept - { - return mode_; - } - -private: - int mode_ = SORT_BY_ID; -}; +using ShowMode = transmission::app::ShowMode; +Q_DECLARE_METATYPE(ShowMode) +inline auto constexpr DefaultShowMode = transmission::app::DefaultShowMode; +inline auto constexpr ShowModeCount = transmission::app::ShowModeCount; +bool should_show_torrent(Torrent const& torrent, ShowMode); +using SortMode = transmission::app::SortMode; Q_DECLARE_METATYPE(SortMode) +inline auto constexpr DefaultSortMode = transmission::app::DefaultSortMode; diff --git a/qt/MainWindow.cc b/qt/MainWindow.cc index 059d44950..231aeb5a2 100644 --- a/qt/MainWindow.cc +++ b/qt/MainWindow.cc @@ -156,16 +156,16 @@ MainWindow::MainWindow(Session& session, Prefs& prefs, TorrentModel& model, bool ui_.listView->setModel(&filter_model_); connect(ui_.listView->selectionModel(), &QItemSelectionModel::selectionChanged, refresh_action_sensitivity_soon); - std::array, 9> const sort_modes = { { - { ui_.action_SortByActivity, SortMode::SORT_BY_ACTIVITY }, - { ui_.action_SortByAge, SortMode::SORT_BY_AGE }, - { ui_.action_SortByETA, SortMode::SORT_BY_ETA }, - { ui_.action_SortByName, SortMode::SORT_BY_NAME }, - { ui_.action_SortByProgress, SortMode::SORT_BY_PROGRESS }, - { ui_.action_SortByQueue, SortMode::SORT_BY_QUEUE }, - { ui_.action_SortByRatio, SortMode::SORT_BY_RATIO }, - { ui_.action_SortBySize, SortMode::SORT_BY_SIZE }, - { ui_.action_SortByState, SortMode::SORT_BY_STATE }, + auto const sort_modes = std::array, 9U>{ { + { ui_.action_SortByActivity, SortMode::SortByActivity }, + { ui_.action_SortByAge, SortMode::SortByAge }, + { ui_.action_SortByETA, SortMode::SortByEta }, + { ui_.action_SortByName, SortMode::SortByName }, + { ui_.action_SortByProgress, SortMode::SortByProgress }, + { ui_.action_SortByQueue, SortMode::SortByQueue }, + { ui_.action_SortByRatio, SortMode::SortByRatio }, + { ui_.action_SortBySize, SortMode::SortBySize }, + { ui_.action_SortByState, SortMode::SortByState }, } }; // NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks) @@ -173,7 +173,7 @@ MainWindow::MainWindow(Session& session, Prefs& prefs, TorrentModel& model, bool for (auto const& [action, mode] : sort_modes) { - action->setProperty(SortModeKey, mode); + action->setProperty(SortModeKey, QVariant::fromValue(mode)); action_group->addAction(action); } @@ -437,7 +437,7 @@ QMenu* MainWindow::createStatsModeMenu() void MainWindow::onSortModeChanged(QAction const* action) { - prefs_.set(Prefs::SORT_MODE, SortMode(action->property(SortModeKey).toInt())); + prefs_.set(Prefs::SORT_MODE, action->property(SortModeKey)); } void MainWindow::setSortAscendingPref(bool b) @@ -1109,7 +1109,6 @@ void MainWindow::trayActivated(QSystemTrayIcon::ActivationReason reason) void MainWindow::refreshPref(int key) { auto b = bool{}; - auto i = int{}; auto str = QString{}; switch (key) @@ -1130,11 +1129,12 @@ void MainWindow::refreshPref(int key) break; case Prefs::SORT_MODE: - i = prefs_.get(key).mode(); - - for (auto* action : ui_.action_SortByActivity->actionGroup()->actions()) { - action->setChecked(i == action->property(SortModeKey).toInt()); + auto const sort_mode = prefs_.get(key); + for (auto* action : ui_.action_SortByActivity->actionGroup()->actions()) + { + action->setChecked(sort_mode == action->property(SortModeKey).value()); + } } break; diff --git a/qt/Prefs.cc b/qt/Prefs.cc index 432a06fb7..879cc8a5b 100644 --- a/qt/Prefs.cc +++ b/qt/Prefs.cc @@ -21,6 +21,7 @@ #include #include +#include #include #include "CustomVariantType.h" @@ -29,6 +30,8 @@ #include "VariantHelpers.h" namespace api_compat = libtransmission::api_compat; +using libtransmission::serializer::to_value; +using libtransmission::serializer::to_variant; using ::trqt::variant_helpers::dictAdd; using ::trqt::variant_helpers::getValue; using namespace std::string_view_literals; @@ -90,7 +93,7 @@ std::array const Prefs::Items{ { MAIN_WINDOW_WIDTH, TR_KEY_main_window_width, QMetaType::Int }, { MAIN_WINDOW_X, TR_KEY_main_window_x, QMetaType::Int }, { MAIN_WINDOW_Y, TR_KEY_main_window_y, QMetaType::Int }, - { FILTER_MODE, TR_KEY_filter_mode, CustomVariantType::FilterModeType }, + { FILTER_MODE, TR_KEY_filter_mode, CustomVariantType::ShowModeType }, { FILTER_TRACKERS, TR_KEY_filter_trackers, QMetaType::QString }, { FILTER_TEXT, TR_KEY_filter_text, QMetaType::QString }, { SESSION_IS_REMOTE, TR_KEY_remote_session_enabled, QMetaType::Bool }, @@ -164,31 +167,6 @@ std::array const Prefs::Items{ namespace { - -auto constexpr FilterModes = std::array, FilterMode::NUM_MODES>{ { - { FilterMode::SHOW_ALL, "show-all" }, - { FilterMode::SHOW_ACTIVE, "show-active" }, - { FilterMode::SHOW_DOWNLOADING, "show-downloading" }, - { FilterMode::SHOW_SEEDING, "show-seeding" }, - { FilterMode::SHOW_PAUSED, "show-paused" }, - { FilterMode::SHOW_FINISHED, "show-finished" }, - { FilterMode::SHOW_VERIFYING, "show-verifying" }, - { FilterMode::SHOW_ERROR, "show-error" }, -} }; - -auto constexpr SortModes = std::array, SortMode::NUM_MODES>{ { - { SortMode::SORT_BY_NAME, "sort-by-name" }, - { SortMode::SORT_BY_ACTIVITY, "sort-by-activity" }, - { SortMode::SORT_BY_AGE, "sort-by-age" }, - { SortMode::SORT_BY_ETA, "sort-by-eta" }, - { SortMode::SORT_BY_PROGRESS, "sort-by-progress" }, - { SortMode::SORT_BY_QUEUE, "sort-by-queue" }, - { SortMode::SORT_BY_RATIO, "sort-by-ratio" }, - { SortMode::SORT_BY_SIZE, "sort-by-size" }, - { SortMode::SORT_BY_STATE, "sort-by-state" }, - { SortMode::SORT_BY_ID, "sort-by-id" }, -} }; - bool isValidUtf8(QByteArray const& byteArray) { #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) @@ -257,30 +235,16 @@ Prefs::Prefs(QString config_dir) break; case CustomVariantType::SortModeType: - if (auto const value = getValue(b); value) + if (auto const val = to_value(*b)) { - auto const test = [&value](auto const& item) - { - return item.second == *value; - }; - // NOLINTNEXTLINE(readability-qualified-auto) - auto const it = std::find_if(std::cbegin(SortModes), std::cend(SortModes), test); - auto const& [mode, mode_str] = it == std::end(SortModes) ? SortModes.front() : *it; - values_[i] = QVariant::fromValue(SortMode{ mode }); + values_[i] = QVariant::fromValue(*val); } break; - case CustomVariantType::FilterModeType: - if (auto const value = getValue(b); value) + case CustomVariantType::ShowModeType: + if (auto const val = to_value(*b)) { - auto const test = [&value](auto const& item) - { - return item.second == *value; - }; - // NOLINTNEXTLINE(readability-qualified-auto) - auto const it = std::find_if(std::cbegin(FilterModes), std::cend(FilterModes), test); - auto const& [mode, mode_str] = it == std::end(FilterModes) ? FilterModes.front() : *it; - values_[i] = QVariant::fromValue(FilterMode{ mode }); + values_[i] = QVariant::fromValue(*val); } break; @@ -349,32 +313,12 @@ Prefs::~Prefs() break; case CustomVariantType::SortModeType: - { - auto const mode = val.value().mode(); - auto const test = [&mode](auto const& item) - { - return item.first == mode; - }; - // NOLINTNEXTLINE(readability-qualified-auto) - auto const it = std::find_if(std::cbegin(SortModes), std::cend(SortModes), test); - auto const& [mode_val, mode_str] = it == std::end(SortModes) ? SortModes.front() : *it; - dictAdd(¤t_settings, key, mode_str); - break; - } + *tr_variantDictAdd(¤t_settings, key) = to_variant(val.value()); + break; - case CustomVariantType::FilterModeType: - { - auto const mode = val.value().mode(); - auto const test = [&mode](auto const& item) - { - return item.first == mode; - }; - // NOLINTNEXTLINE(readability-qualified-auto) - auto const it = std::find_if(std::cbegin(FilterModes), std::cend(FilterModes), test); - auto const& [mode_val, mode_str] = it == std::end(FilterModes) ? FilterModes.front() : *it; - dictAdd(¤t_settings, key, mode_str); - break; - } + case CustomVariantType::ShowModeType: + *tr_variantDictAdd(¤t_settings, key) = to_variant(val.value()); + break; case QMetaType::QString: dictAdd(¤t_settings, key, val.toString()); @@ -430,11 +374,11 @@ tr_variant Prefs::get_default_app_settings() settings.try_emplace(TR_KEY_blocklist_updates_enabled, true); settings.try_emplace(TR_KEY_compact_view, false); settings.try_emplace(TR_KEY_download_dir, download_dir); - settings.try_emplace(TR_KEY_filter_mode, tr_variant::unmanaged_string("all"sv)); + settings.try_emplace(TR_KEY_filter_mode, to_variant(DefaultShowMode)); settings.try_emplace(TR_KEY_inhibit_desktop_hibernation, false); settings.try_emplace(TR_KEY_main_window_height, 500); settings.try_emplace(TR_KEY_main_window_layout_order, tr_variant::unmanaged_string("menu,toolbar,filter,list,statusbar"sv)); - settings.try_emplace(TR_KEY_main_window_width, 300); + settings.try_emplace(TR_KEY_main_window_width, 600); settings.try_emplace(TR_KEY_main_window_x, 50); settings.try_emplace(TR_KEY_main_window_y, 50); settings.try_emplace(TR_KEY_open_dialog_dir, QDir::home().absolutePath().toStdString()); @@ -443,11 +387,11 @@ tr_variant Prefs::get_default_app_settings() settings.try_emplace(TR_KEY_remote_session_enabled, false); settings.try_emplace(TR_KEY_remote_session_host, tr_variant::unmanaged_string("localhost"sv)); settings.try_emplace(TR_KEY_remote_session_https, false); - settings.try_emplace(TR_KEY_remote_session_password, tr_variant::unmanaged_string("")); + settings.try_emplace(TR_KEY_remote_session_password, tr_variant::unmanaged_string(""sv)); settings.try_emplace(TR_KEY_remote_session_port, TrDefaultRpcPort); settings.try_emplace(TR_KEY_remote_session_requires_authentication, false); - settings.try_emplace(TR_KEY_remote_session_rpc_url_path, TR_DEFAULT_RPC_URL_STR "rpc"); - settings.try_emplace(TR_KEY_remote_session_username, tr_variant::unmanaged_string("")); + settings.try_emplace(TR_KEY_remote_session_rpc_url_path, tr_variant::unmanaged_string(TR_DEFAULT_RPC_URL_STR "rpc")); + settings.try_emplace(TR_KEY_remote_session_username, tr_variant::unmanaged_string(""sv)); settings.try_emplace(TR_KEY_show_backup_trackers, false); settings.try_emplace(TR_KEY_show_filterbar, true); settings.try_emplace(TR_KEY_show_notification_area_icon, false); @@ -455,7 +399,7 @@ tr_variant Prefs::get_default_app_settings() settings.try_emplace(TR_KEY_show_statusbar, true); settings.try_emplace(TR_KEY_show_toolbar, true); settings.try_emplace(TR_KEY_show_tracker_scrapes, false); - settings.try_emplace(TR_KEY_sort_mode, tr_variant::unmanaged_string("sort-by-name"sv)); + settings.try_emplace(TR_KEY_sort_mode, to_variant(DefaultSortMode)); settings.try_emplace(TR_KEY_sort_reversed, false); settings.try_emplace(TR_KEY_start_minimized, false); settings.try_emplace(TR_KEY_statusbar_stats, tr_variant::unmanaged_string("total-ratio")); diff --git a/qt/Prefs.h b/qt/Prefs.h index 5bcca3221..6a1c9d9ef 100644 --- a/qt/Prefs.h +++ b/qt/Prefs.h @@ -13,6 +13,8 @@ #include +#include + class QDateTime; extern "C" @@ -168,7 +170,7 @@ public: QDateTime getDateTime(int key) const; template - T get(int key) const + [[nodiscard]] T get(int const key) const { return values_[key].value(); } diff --git a/qt/Session.cc b/qt/Session.cc index cba0b5887..7a10ede58 100644 --- a/qt/Session.cc +++ b/qt/Session.cc @@ -27,6 +27,7 @@ #include #include +#include #include #include #include @@ -35,6 +36,7 @@ #include "AddData.h" #include "CustomVariantType.h" +#include "Filters.h" #include "Prefs.h" #include "RpcQueue.h" #include "SessionDialog.h" @@ -43,10 +45,11 @@ using namespace std::literals; +using ::libtransmission::serializer::to_value; +using ::libtransmission::serializer::to_variant; using ::trqt::variant_helpers::dictAdd; using ::trqt::variant_helpers::dictFind; using ::trqt::variant_helpers::getValue; -using ::trqt::variant_helpers::to_variant; /*** **** @@ -675,6 +678,8 @@ using TorrentProperties = Session::TorrentProperties; }; } // clang-format on + + return {}; } } // namespace @@ -952,8 +957,22 @@ void Session::updateInfo(tr_variant* args_dict) break; - case CustomVariantType::FilterModeType: + case CustomVariantType::ShowModeType: + if (auto const val = to_value(*b)) + { + prefs_.set(i, *val); + } + + break; + case CustomVariantType::SortModeType: + if (auto const val = to_value(*b)) + { + prefs_.set(i, *val); + } + + break; + case QMetaType::QString: if (auto const value = getValue(b); value) { diff --git a/qt/TorrentFilter.cc b/qt/TorrentFilter.cc index 39966c2f5..105b52078 100644 --- a/qt/TorrentFilter.cc +++ b/qt/TorrentFilter.cc @@ -81,9 +81,9 @@ bool TorrentFilter::lessThan(QModelIndex const& left, QModelIndex const& right) auto const* a = sourceModel()->data(left, TorrentModel::TorrentRole).value(); auto const* b = sourceModel()->data(right, TorrentModel::TorrentRole).value(); - switch (prefs_.get(Prefs::SORT_MODE).mode()) + switch (prefs_.get(Prefs::SORT_MODE)) { - case SortMode::SORT_BY_QUEUE: + case SortMode::SortByQueue: if (val == 0) { val = -tr_compare_3way(a->queuePosition(), b->queuePosition()); @@ -91,7 +91,7 @@ bool TorrentFilter::lessThan(QModelIndex const& left, QModelIndex const& right) break; - case SortMode::SORT_BY_SIZE: + case SortMode::SortBySize: if (val == 0) { val = tr_compare_3way(a->sizeWhenDone(), b->sizeWhenDone()); @@ -99,7 +99,7 @@ bool TorrentFilter::lessThan(QModelIndex const& left, QModelIndex const& right) break; - case SortMode::SORT_BY_AGE: + case SortMode::SortByAge: if (val == 0) { val = tr_compare_3way(a->dateAdded(), b->dateAdded()); @@ -107,7 +107,7 @@ bool TorrentFilter::lessThan(QModelIndex const& left, QModelIndex const& right) break; - case SortMode::SORT_BY_ID: + case SortMode::SortById: if (val == 0) { val = tr_compare_3way(a->id(), b->id()); @@ -115,7 +115,7 @@ bool TorrentFilter::lessThan(QModelIndex const& left, QModelIndex const& right) break; - case SortMode::SORT_BY_ACTIVITY: + case SortMode::SortByActivity: if (val == 0) { val = tr_compare_3way(a->downloadSpeed() + a->uploadSpeed(), b->downloadSpeed() + b->uploadSpeed()); @@ -130,7 +130,7 @@ bool TorrentFilter::lessThan(QModelIndex const& left, QModelIndex const& right) [[fallthrough]]; - case SortMode::SORT_BY_STATE: + case SortMode::SortByState: if (val == 0) { val = -tr_compare_3way(a->isPaused(), b->isPaused()); @@ -153,7 +153,7 @@ bool TorrentFilter::lessThan(QModelIndex const& left, QModelIndex const& right) [[fallthrough]]; - case SortMode::SORT_BY_PROGRESS: + case SortMode::SortByProgress: if (val == 0) { val = tr_compare_3way(a->metadataPercentDone(), b->metadataPercentDone()); @@ -176,7 +176,7 @@ bool TorrentFilter::lessThan(QModelIndex const& left, QModelIndex const& right) [[fallthrough]]; - case SortMode::SORT_BY_RATIO: + case SortMode::SortByRatio: if (val == 0) { val = a->compareRatio(*b); @@ -184,7 +184,7 @@ bool TorrentFilter::lessThan(QModelIndex const& left, QModelIndex const& right) break; - case SortMode::SORT_BY_ETA: + case SortMode::SortByEta: if (val == 0) { val = a->compareETA(*b); @@ -221,8 +221,8 @@ bool TorrentFilter::filterAcceptsRow(int source_row, QModelIndex const& source_p if (accepts) { - auto const m = prefs_.get(Prefs::FILTER_MODE); - accepts = m.test(tor); + auto const show_mode = prefs_.get(Prefs::FILTER_MODE); + accepts = should_show_torrent(tor, show_mode); } if (accepts) @@ -241,7 +241,7 @@ bool TorrentFilter::filterAcceptsRow(int source_row, QModelIndex const& source_p return accepts; } -std::array TorrentFilter::countTorrentsPerMode() const +std::array TorrentFilter::countTorrentsPerMode() const { auto* const torrent_model = dynamic_cast(sourceModel()); if (torrent_model == nullptr) @@ -249,13 +249,13 @@ std::array TorrentFilter::countTorrentsPerMode() con return {}; } - auto torrent_counts = std::array{}; + auto torrent_counts = std::array{}; for (auto const& tor : torrent_model->torrents()) { - for (int mode = 0; mode < FilterMode::NUM_MODES; ++mode) + for (unsigned int mode = 0; mode < ShowModeCount; ++mode) { - if (FilterMode::test(*tor, mode)) + if (should_show_torrent(*tor, static_cast(mode))) { ++torrent_counts[mode]; } diff --git a/qt/TorrentFilter.h b/qt/TorrentFilter.h index 41df2b614..0cd628cad 100644 --- a/qt/TorrentFilter.h +++ b/qt/TorrentFilter.h @@ -14,7 +14,6 @@ class QString; -class FilterMode; class Prefs; class Torrent; @@ -36,7 +35,7 @@ public: TorrentFilter& operator=(TorrentFilter&&) = delete; TorrentFilter& operator=(TorrentFilter const&) = delete; - [[nodiscard]] std::array countTorrentsPerMode() const; + [[nodiscard]] std::array countTorrentsPerMode() const; protected: // QSortFilterProxyModel diff --git a/qt/TrackerDelegate.cc b/qt/TrackerDelegate.cc index b8862786d..edf0e6093 100644 --- a/qt/TrackerDelegate.cc +++ b/qt/TrackerDelegate.cc @@ -10,7 +10,8 @@ #include #include -#include + +#include #include "Formatter.h" #include "Torrent.h" diff --git a/qt/VariantHelpers.h b/qt/VariantHelpers.h index 932916499..9ce8c16fe 100644 --- a/qt/VariantHelpers.h +++ b/qt/VariantHelpers.h @@ -14,7 +14,6 @@ #include -#include #include class QByteArray; @@ -29,12 +28,6 @@ namespace trqt::variant_helpers { void register_qt_converters(); -template -[[nodiscard]] tr_variant to_variant(T const& val) -{ - return libtransmission::serializer::Converters::serialize(val); -} - template>* = nullptr> auto getValue(tr_variant const* variant) { diff --git a/qt/main.cc b/qt/main.cc index 413193485..d799a645b 100644 --- a/qt/main.cc +++ b/qt/main.cc @@ -15,6 +15,8 @@ #include #include +#include + #include "Application.h" #include "InteropHelper.h" #include "Prefs.h" @@ -99,8 +101,7 @@ bool tryDelegate(QStringList const& filenames) int tr_main(int argc, char** argv) { - tr_lib_init(); - tr_locale_set_global(""); + transmission::app::init(); trqt::variant_helpers::register_qt_converters(); // parse the command-line arguments