refactor: use fmt to build the GTK client's user-visible strings (#2788)
Co-authored-by: Mike Gelfand <mikedld@mikedld.com>
This commit is contained in:
parent
44e30bf092
commit
fcc1510ecb
|
@ -107,7 +107,7 @@ static auto constexpr Options = std::array<tr_option, 45>{
|
||||||
{ { 'a', "allowed", "Allowed IP addresses. (Default: " TR_DEFAULT_RPC_WHITELIST ")", "a", true, "<list>" },
|
{ { 'a', "allowed", "Allowed IP addresses. (Default: " TR_DEFAULT_RPC_WHITELIST ")", "a", true, "<list>" },
|
||||||
{ 'b', "blocklist", "Enable peer blocklists", "b", false, nullptr },
|
{ 'b', "blocklist", "Enable peer blocklists", "b", false, nullptr },
|
||||||
{ 'B', "no-blocklist", "Disable peer blocklists", "B", false, nullptr },
|
{ 'B', "no-blocklist", "Disable peer blocklists", "B", false, nullptr },
|
||||||
{ 'c', "watch-dir", "Where to watch for new .torrent files", "c", true, "<directory>" },
|
{ 'c', "watch-dir", "Where to watch for new torrent files", "c", true, "<directory>" },
|
||||||
{ 'C', "no-watch-dir", "Disable the watch-dir", "C", false, nullptr },
|
{ 'C', "no-watch-dir", "Disable the watch-dir", "C", false, nullptr },
|
||||||
{ 941, "incomplete-dir", "Where to store new torrents until they're complete", nullptr, true, "<directory>" },
|
{ 941, "incomplete-dir", "Where to store new torrents until they're complete", nullptr, true, "<directory>" },
|
||||||
{ 942, "no-incomplete-dir", "Don't store incomplete torrents in a different location", nullptr, false, nullptr },
|
{ 942, "no-incomplete-dir", "Don't store incomplete torrents in a different location", nullptr, false, nullptr },
|
||||||
|
@ -243,7 +243,7 @@ static auto onFileAdded(tr_watchdir_t dir, char const* name, void* vsession)
|
||||||
|
|
||||||
if (tr_torrentNew(ctor, nullptr) == nullptr)
|
if (tr_torrentNew(ctor, nullptr) == nullptr)
|
||||||
{
|
{
|
||||||
tr_logAddError(fmt::format(_("Couldn't add .torrent file '{path}'"), fmt::arg("path", name)));
|
tr_logAddError(fmt::format(_("Couldn't add torrent file '{path}'"), fmt::arg("path", name)));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -254,7 +254,7 @@ static auto onFileAdded(tr_watchdir_t dir, char const* name, void* vsession)
|
||||||
{
|
{
|
||||||
tr_error* error = nullptr;
|
tr_error* error = nullptr;
|
||||||
|
|
||||||
tr_logAddInfo(fmt::format(_("Removing .torrent file '{path}'"), fmt::arg("path", name)));
|
tr_logAddInfo(fmt::format(_("Removing torrent file '{path}'"), fmt::arg("path", name)));
|
||||||
|
|
||||||
if (!tr_sys_path_remove(filename.c_str(), &error))
|
if (!tr_sys_path_remove(filename.c_str(), &error))
|
||||||
{
|
{
|
||||||
|
@ -761,7 +761,7 @@ static int daemon_start(void* varg, [[maybe_unused]] bool foreground)
|
||||||
(void)tr_variantDictFindStrView(settings, TR_KEY_watch_dir, &dir);
|
(void)tr_variantDictFindStrView(settings, TR_KEY_watch_dir, &dir);
|
||||||
if (!std::empty(dir))
|
if (!std::empty(dir))
|
||||||
{
|
{
|
||||||
tr_logAddInfo(fmt::format(_("Watching '{path}' for new .torrent files"), fmt::arg("path", dir)));
|
tr_logAddInfo(fmt::format(_("Watching '{path}' for new torrent files"), fmt::arg("path", dir)));
|
||||||
|
|
||||||
watchdir = tr_watchdir_new(dir, &onFileAdded, mySession, ev_base, force_generic);
|
watchdir = tr_watchdir_new(dir, &onFileAdded, mySession, ev_base, force_generic);
|
||||||
if (watchdir == nullptr)
|
if (watchdir == nullptr)
|
||||||
|
|
|
@ -351,7 +351,7 @@ void register_magnet_link_handler()
|
||||||
auto const msg = fmt::format(
|
auto const msg = fmt::format(
|
||||||
_("Couldn't register Transmission as a {content_type} handler: {error} ({error_code})"),
|
_("Couldn't register Transmission as a {content_type} handler: {error} ({error_code})"),
|
||||||
fmt::arg("content_type", content_type),
|
fmt::arg("content_type", content_type),
|
||||||
fmt::arg("error", e.what().raw()),
|
fmt::arg("error", e.what()),
|
||||||
fmt::arg("error_code", e.code()));
|
fmt::arg("error_code", e.code()));
|
||||||
g_warning("%s", msg.c_str());
|
g_warning("%s", msg.c_str());
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,10 @@
|
||||||
|
|
||||||
#include <glibmm/i18n.h>
|
#include <glibmm/i18n.h>
|
||||||
|
|
||||||
|
#include <fmt/core.h>
|
||||||
|
#include <fmt/chrono.h>
|
||||||
|
#include <fmt/format.h>
|
||||||
|
|
||||||
#include <libtransmission/transmission.h>
|
#include <libtransmission/transmission.h>
|
||||||
#include <libtransmission/utils.h> /* tr_free */
|
#include <libtransmission/utils.h> /* tr_free */
|
||||||
#include <libtransmission/web-utils.h>
|
#include <libtransmission/web-utils.h>
|
||||||
|
@ -464,7 +468,7 @@ Gtk::Widget* DetailsDialog::Impl::options_page_new()
|
||||||
[this]() { torrent_set_bool(TR_KEY_honorsSessionLimits, honor_limits_check_->get_active()); });
|
[this]() { torrent_set_bool(TR_KEY_honorsSessionLimits, honor_limits_check_->get_active()); });
|
||||||
|
|
||||||
down_limited_check_ = Gtk::make_managed<Gtk::CheckButton>(
|
down_limited_check_ = Gtk::make_managed<Gtk::CheckButton>(
|
||||||
gtr_sprintf(_("Limit _download speed (%s):"), _(speed_K_str)),
|
fmt::format(_("Limit _download speed ({speed_units}):"), fmt::arg("speed_units", speed_K_str)),
|
||||||
true);
|
true);
|
||||||
down_limited_check_->set_active(false);
|
down_limited_check_->set_active(false);
|
||||||
down_limited_check_tag_ = down_limited_check_->signal_toggled().connect(
|
down_limited_check_tag_ = down_limited_check_->signal_toggled().connect(
|
||||||
|
@ -475,7 +479,9 @@ Gtk::Widget* DetailsDialog::Impl::options_page_new()
|
||||||
[this]() { torrent_set_int(TR_KEY_downloadLimit, down_limit_spin_->get_value_as_int()); });
|
[this]() { torrent_set_int(TR_KEY_downloadLimit, down_limit_spin_->get_value_as_int()); });
|
||||||
t->add_row_w(row, *down_limited_check_, *down_limit_spin_);
|
t->add_row_w(row, *down_limited_check_, *down_limit_spin_);
|
||||||
|
|
||||||
up_limited_check_ = Gtk::make_managed<Gtk::CheckButton>(gtr_sprintf(_("Limit _upload speed (%s):"), _(speed_K_str)), true);
|
up_limited_check_ = Gtk::make_managed<Gtk::CheckButton>(
|
||||||
|
fmt::format(_("Limit _upload speed ({speed_units}):"), fmt::arg("speed_units", speed_K_str)),
|
||||||
|
true);
|
||||||
up_limited_check_tag_ = up_limited_check_->signal_toggled().connect(
|
up_limited_check_tag_ = up_limited_check_->signal_toggled().connect(
|
||||||
[this]() { torrent_set_bool(TR_KEY_uploadLimited, up_limited_check_->get_active()); });
|
[this]() { torrent_set_bool(TR_KEY_uploadLimited, up_limited_check_->get_active()); });
|
||||||
|
|
||||||
|
@ -593,19 +599,16 @@ void gtr_text_buffer_set_text(Glib::RefPtr<Gtk::TextBuffer> const& b, Glib::ustr
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Glib::ustring get_short_date_string(time_t t)
|
std::string get_date_string(time_t t)
|
||||||
{
|
{
|
||||||
char buf[64];
|
|
||||||
struct tm tm;
|
|
||||||
|
|
||||||
if (t == 0)
|
if (t == 0)
|
||||||
{
|
{
|
||||||
return _("N/A");
|
return _("N/A");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct tm tm;
|
||||||
tr_localtime_r(&t, &tm);
|
tr_localtime_r(&t, &tm);
|
||||||
strftime(buf, sizeof(buf), "%d %b %Y", &tm);
|
return fmt::format("{:%x}", tm);
|
||||||
return Glib::locale_to_utf8(buf);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
@ -660,9 +663,9 @@ void DetailsDialog::Impl::refreshInfo(std::vector<tr_torrent*> const& torrents)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
auto const creator = Glib::ustring(infos.front().creator != nullptr ? infos.front().creator : "");
|
auto const creator = tr_strvStrip(infos.front().creator != nullptr ? infos.front().creator : "");
|
||||||
auto const date = infos.front().date_created;
|
auto const date = infos.front().date_created;
|
||||||
auto const datestr = get_short_date_string(date);
|
auto const datestr = get_date_string(date);
|
||||||
bool const mixed_creator = std::any_of(
|
bool const mixed_creator = std::any_of(
|
||||||
infos.begin(),
|
infos.begin(),
|
||||||
infos.end(),
|
infos.end(),
|
||||||
|
@ -672,31 +675,28 @@ void DetailsDialog::Impl::refreshInfo(std::vector<tr_torrent*> const& torrents)
|
||||||
infos.end(),
|
infos.end(),
|
||||||
[date](auto const& info) { return date != info.date_created; });
|
[date](auto const& info) { return date != info.date_created; });
|
||||||
|
|
||||||
bool const empty_creator = creator.empty();
|
bool const empty_creator = std::empty(creator);
|
||||||
bool const empty_date = date == 0;
|
bool const empty_date = date == 0;
|
||||||
|
|
||||||
if (mixed_date || mixed_creator)
|
if (mixed_creator || mixed_date)
|
||||||
{
|
{
|
||||||
str = mixed;
|
str = mixed;
|
||||||
}
|
}
|
||||||
else if (empty_date && empty_creator)
|
else if (!empty_creator && !empty_date)
|
||||||
{
|
{
|
||||||
str = _("N/A");
|
str = fmt::format(_("Created by {creator} on {date}"), fmt::arg("creator", creator), fmt::arg("date", datestr));
|
||||||
|
}
|
||||||
|
else if (!empty_creator)
|
||||||
|
{
|
||||||
|
str = fmt::format(_("Created by {creator}"), fmt::arg("creator", creator));
|
||||||
|
}
|
||||||
|
else if (!empty_date)
|
||||||
|
{
|
||||||
|
str = fmt::format(_("Created on {date}"), fmt::arg("date", datestr));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (empty_date && !empty_creator)
|
str = _("N/A");
|
||||||
{
|
|
||||||
str = gtr_sprintf(_("Created by %1$s"), creator);
|
|
||||||
}
|
|
||||||
else if (empty_creator && !empty_date)
|
|
||||||
{
|
|
||||||
str = gtr_sprintf(_("Created on %1$s"), datestr);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
str = gtr_sprintf(_("Created by %1$s on %2$s"), creator, datestr);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -845,15 +845,21 @@ void DetailsDialog::Impl::refreshInfo(std::vector<tr_torrent*> const& torrents)
|
||||||
}
|
}
|
||||||
else if (pieceSize >= 0)
|
else if (pieceSize >= 0)
|
||||||
{
|
{
|
||||||
str = gtr_sprintf(
|
str = fmt::format(
|
||||||
ngettext("%1$s (%2$'d piece @ %3$s)", "%1$s (%2$'d pieces @ %3$s)", pieces),
|
ngettext(
|
||||||
sizebuf,
|
"{file_size} ({piece_count} piece @ {piece_size})",
|
||||||
pieces,
|
"{file_size} ({piece_count} pieces @ {piece_size})",
|
||||||
tr_formatter_mem_B(pieceSize));
|
pieces),
|
||||||
|
fmt::arg("file_size", sizebuf),
|
||||||
|
fmt::arg("piece_count", pieces),
|
||||||
|
fmt::arg("piece_size", tr_formatter_mem_B(pieceSize)));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
str = gtr_sprintf(ngettext("%1$s (%2$'d piece)", "%1$s (%2$'d pieces)", pieces), sizebuf, pieces);
|
str = fmt::format(
|
||||||
|
ngettext("{file_size} ({piece_count} piece)", "{file_size} ({piece_count} pieces)", pieces),
|
||||||
|
fmt::arg("file_size", sizebuf),
|
||||||
|
fmt::arg("piece_count", pieces));
|
||||||
}
|
}
|
||||||
|
|
||||||
size_lb_->set_text(str);
|
size_lb_->set_text(str);
|
||||||
|
@ -891,47 +897,62 @@ void DetailsDialog::Impl::refreshInfo(std::vector<tr_torrent*> const& torrents)
|
||||||
|
|
||||||
if (haveUnchecked == 0 && leftUntilDone == 0)
|
if (haveUnchecked == 0 && leftUntilDone == 0)
|
||||||
{
|
{
|
||||||
str = gtr_sprintf(_("%1$s (%2$s%%)"), total, buf2);
|
str = fmt::format(
|
||||||
|
_("{current_size} ({percent_done}%)"),
|
||||||
|
fmt::arg("current_size", total),
|
||||||
|
fmt::arg("percent_done", buf2));
|
||||||
}
|
}
|
||||||
else if (haveUnchecked == 0)
|
else if (haveUnchecked == 0)
|
||||||
{
|
{
|
||||||
str = gtr_sprintf(_("%1$s (%2$s%% of %3$s%% Available)"), total, buf2, avail);
|
str = fmt::format(
|
||||||
|
_("{current_size} ({percent_done}% of {percent_available}% available"),
|
||||||
|
fmt::arg("current_size", total),
|
||||||
|
fmt::arg("percent_done", buf2),
|
||||||
|
fmt::arg("percent_available", avail));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
str = gtr_sprintf(_("%1$s (%2$s%% of %3$s%% Available); %4$s Unverified"), total, buf2, avail, unver);
|
str = fmt::format(
|
||||||
|
_("{current_size} ({percent_done}% of {percent_available}% available; {unverified_size} unverified)"),
|
||||||
|
fmt::arg("current_size", total),
|
||||||
|
fmt::arg("percent_done", buf2),
|
||||||
|
fmt::arg("percent_available", avail),
|
||||||
|
fmt::arg("unverified_size", unver));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
have_lb_->set_text(str);
|
have_lb_->set_text(str);
|
||||||
|
|
||||||
/* dl_lb */
|
// dl_lb
|
||||||
if (stats.empty())
|
if (stats.empty())
|
||||||
{
|
{
|
||||||
str = no_torrent;
|
str = no_torrent;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
uint64_t d = 0;
|
auto const downloaded_str = tr_strlsize(std::accumulate(
|
||||||
uint64_t f = 0;
|
std::begin(stats),
|
||||||
|
std::end(stats),
|
||||||
|
uint64_t{ 0 },
|
||||||
|
[](auto sum, auto const* st) { return sum + st->downloadedEver; }));
|
||||||
|
|
||||||
for (auto const* const st : stats)
|
auto const failed = std::accumulate(
|
||||||
|
std::begin(stats),
|
||||||
|
std::end(stats),
|
||||||
|
uint64_t{ 0 },
|
||||||
|
[](auto sum, auto const* st) { return sum + st->corruptEver; });
|
||||||
|
|
||||||
|
if (failed != 0)
|
||||||
{
|
{
|
||||||
d += st->downloadedEver;
|
str = fmt::format(
|
||||||
f += st->corruptEver;
|
_("{downloaded_size} (+{discarded_size} discarded after failed checksum)"),
|
||||||
}
|
fmt::arg("downloaded_size", downloaded_str),
|
||||||
|
fmt::arg("discarded_size", tr_strlsize(failed)));
|
||||||
auto const dbuf = tr_strlsize(d);
|
|
||||||
auto const fbuf = tr_strlsize(f);
|
|
||||||
|
|
||||||
if (f != 0)
|
|
||||||
{
|
|
||||||
str = gtr_sprintf(_("%1$s (+%2$s discarded after failed checksum)"), dbuf, fbuf);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
str = dbuf;
|
str = downloaded_str;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -954,7 +975,10 @@ void DetailsDialog::Impl::refreshInfo(std::vector<tr_torrent*> const& torrents)
|
||||||
std::end(stats),
|
std::end(stats),
|
||||||
uint64_t{},
|
uint64_t{},
|
||||||
[](auto sum, auto const* st) { return sum + st->sizeWhenDone; });
|
[](auto sum, auto const* st) { return sum + st->sizeWhenDone; });
|
||||||
str = gtr_sprintf(_("%s (Ratio: %s)"), tr_strlsize(uploaded), tr_strlratio(tr_getRatio(uploaded, denominator)));
|
str = fmt::format(
|
||||||
|
_("{uploaded_size} (Ratio: {ratio})"),
|
||||||
|
fmt::arg("uploaded_size", tr_strlsize(uploaded)),
|
||||||
|
fmt::arg("ratio", tr_strlratio(tr_getRatio(uploaded, denominator))));
|
||||||
}
|
}
|
||||||
|
|
||||||
ul_lb_->set_text(str);
|
ul_lb_->set_text(str);
|
||||||
|
@ -1025,7 +1049,8 @@ void DetailsDialog::Impl::refreshInfo(std::vector<tr_torrent*> const& torrents)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
str = gtr_sprintf(_("%1$s ago"), tr_strltime(period));
|
// e.g. 5 minutes ago
|
||||||
|
str = fmt::format(_("{time_span} ago"), fmt::arg("time_span", tr_strltime(period)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1355,6 +1380,11 @@ void DetailsDialog::Impl::refreshPeerList(std::vector<tr_torrent*> const& torren
|
||||||
row[peer_cols.was_updated] = false;
|
row[peer_cols.was_updated] = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto make_key = [](tr_torrent const* tor, tr_peer_stat const* ps)
|
||||||
|
{
|
||||||
|
return fmt::format("{}.{}", tr_torrentId(tor), ps->addr);
|
||||||
|
};
|
||||||
|
|
||||||
/* step 3: add any new peers */
|
/* step 3: add any new peers */
|
||||||
for (size_t i = 0; i < torrents.size(); ++i)
|
for (size_t i = 0; i < torrents.size(); ++i)
|
||||||
{
|
{
|
||||||
|
@ -1363,7 +1393,7 @@ void DetailsDialog::Impl::refreshPeerList(std::vector<tr_torrent*> const& torren
|
||||||
for (int j = 0; j < peerCount[i]; ++j)
|
for (int j = 0; j < peerCount[i]; ++j)
|
||||||
{
|
{
|
||||||
auto const* s = &peers.at(i)[j];
|
auto const* s = &peers.at(i)[j];
|
||||||
auto const key = gtr_sprintf("%d.%s", tr_torrentId(tor), s->addr);
|
auto const key = make_key(tor, s);
|
||||||
|
|
||||||
if (hash.find(key) == hash.end())
|
if (hash.find(key) == hash.end())
|
||||||
{
|
{
|
||||||
|
@ -1382,7 +1412,7 @@ void DetailsDialog::Impl::refreshPeerList(std::vector<tr_torrent*> const& torren
|
||||||
for (int j = 0; j < peerCount[i]; ++j)
|
for (int j = 0; j < peerCount[i]; ++j)
|
||||||
{
|
{
|
||||||
auto const* s = &peers.at(i)[j];
|
auto const* s = &peers.at(i)[j];
|
||||||
auto const key = gtr_sprintf("%d.%s", tr_torrentId(tor), s->addr);
|
auto const key = make_key(tor, s);
|
||||||
refreshPeerRow(store->get_iter(hash.at(key).get_path()), s);
|
refreshPeerRow(store->get_iter(hash.at(key).get_path()), s);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1418,6 +1448,11 @@ void DetailsDialog::Impl::refreshWebseedList(std::vector<tr_torrent*> const& tor
|
||||||
auto& hash = webseed_hash_;
|
auto& hash = webseed_hash_;
|
||||||
auto& store = webseed_store_;
|
auto& store = webseed_store_;
|
||||||
|
|
||||||
|
auto make_key = [](tr_torrent const* tor, char const* url)
|
||||||
|
{
|
||||||
|
return fmt::format("{}.{}", tr_torrentId(tor), url);
|
||||||
|
};
|
||||||
|
|
||||||
/* step 1: mark all webseeds as not-updated */
|
/* step 1: mark all webseeds as not-updated */
|
||||||
for (auto const& row : store->children())
|
for (auto const& row : store->children())
|
||||||
{
|
{
|
||||||
|
@ -1432,7 +1467,7 @@ void DetailsDialog::Impl::refreshWebseedList(std::vector<tr_torrent*> const& tor
|
||||||
has_any_webseeds = true;
|
has_any_webseeds = true;
|
||||||
|
|
||||||
auto const* const url = tr_torrentWebseed(tor, j).url;
|
auto const* const url = tr_torrentWebseed(tor, j).url;
|
||||||
auto const key = gtr_sprintf("%d.%s", tr_torrentId(tor), url);
|
auto const key = make_key(tor, url);
|
||||||
|
|
||||||
if (hash.find(key) == hash.end())
|
if (hash.find(key) == hash.end())
|
||||||
{
|
{
|
||||||
|
@ -1450,7 +1485,7 @@ void DetailsDialog::Impl::refreshWebseedList(std::vector<tr_torrent*> const& tor
|
||||||
for (size_t j = 0, n = tr_torrentWebseedCount(tor); j < n; ++j)
|
for (size_t j = 0, n = tr_torrentWebseedCount(tor); j < n; ++j)
|
||||||
{
|
{
|
||||||
auto const webseed = tr_torrentWebseed(tor, j);
|
auto const webseed = tr_torrentWebseed(tor, j);
|
||||||
auto const key = gtr_sprintf("%d.%s", tr_torrentId(tor), webseed.url);
|
auto const key = make_key(tor, webseed.url);
|
||||||
auto const iter = store->get_iter(hash.at(key).get_path());
|
auto const iter = store->get_iter(hash.at(key).get_path());
|
||||||
|
|
||||||
auto const KBps = double(webseed.download_bytes_per_second) / speed_K;
|
auto const KBps = double(webseed.download_bytes_per_second) / speed_K;
|
||||||
|
@ -1649,6 +1684,7 @@ void setPeerViewColumns(Gtk::TreeView* peer_view)
|
||||||
else if (*col == peer_cols.progress)
|
else if (*col == peer_cols.progress)
|
||||||
{
|
{
|
||||||
auto* r = Gtk::make_managed<Gtk::CellRendererProgress>();
|
auto* r = Gtk::make_managed<Gtk::CellRendererProgress>();
|
||||||
|
// % is percent done
|
||||||
c = Gtk::make_managed<Gtk::TreeViewColumn>(_("%"), *r);
|
c = Gtk::make_managed<Gtk::TreeViewColumn>(_("%"), *r);
|
||||||
c->add_attribute(r->property_text(), *col);
|
c->add_attribute(r->property_text(), *col);
|
||||||
}
|
}
|
||||||
|
@ -1837,12 +1873,12 @@ Gtk::Widget* DetailsDialog::Impl::peer_page_new()
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
|
|
||||||
char const err_markup_begin[] = "<span color=\"red\">";
|
auto constexpr ErrMarkupBegin = "<span color=\"red\">"sv;
|
||||||
char const err_markup_end[] = "</span>";
|
auto constexpr ErrMarkupEnd = "</span>"sv;
|
||||||
char const timeout_markup_begin[] = "<span color=\"#246\">";
|
auto constexpr TimeoutMarkupBegin = "<span color=\"#246\">"sv;
|
||||||
char const timeout_markup_end[] = "</span>";
|
auto constexpr TimeoutMarkupEnd = "</span>"sv;
|
||||||
char const success_markup_begin[] = "<span color=\"#080\">";
|
auto constexpr SuccessMarkupBegin = "<span color=\"#080\">"sv;
|
||||||
char const success_markup_end[] = "</span>";
|
auto constexpr SuccessMarkupEnd = "</span>"sv;
|
||||||
|
|
||||||
std::array<std::string_view, 3> const text_dir_mark = { ""sv, "\u200E"sv, "\u200F"sv };
|
std::array<std::string_view, 3> const text_dir_mark = { ""sv, "\u200E"sv, "\u200F"sv };
|
||||||
|
|
||||||
|
@ -1867,29 +1903,35 @@ void appendAnnounceInfo(tr_tracker_view const& tracker, time_t const now, Gtk::T
|
||||||
|
|
||||||
if (tracker.lastAnnounceSucceeded)
|
if (tracker.lastAnnounceSucceeded)
|
||||||
{
|
{
|
||||||
gstr << gtr_sprintf(
|
gstr << fmt::format(
|
||||||
_("Got a list of %1$s%2$'d peers%3$s %4$s ago"),
|
// {markup_begin} and {markup_end} should surround the peer text
|
||||||
success_markup_begin,
|
ngettext(
|
||||||
tracker.lastAnnouncePeerCount,
|
"Got a list of {markup_begin}{peer_count} peer{markup_end} {time_span} ago",
|
||||||
success_markup_end,
|
"Got a list of {markup_begin}{peer_count} peers{markup_end} {time_span} ago",
|
||||||
timebuf);
|
tracker.lastAnnouncePeerCount),
|
||||||
|
fmt::arg("markup_begin", SuccessMarkupBegin),
|
||||||
|
fmt::arg("peer_count", tracker.lastAnnouncePeerCount),
|
||||||
|
fmt::arg("markup_end", SuccessMarkupEnd),
|
||||||
|
fmt::arg("time_span", timebuf));
|
||||||
}
|
}
|
||||||
else if (tracker.lastAnnounceTimedOut)
|
else if (tracker.lastAnnounceTimedOut)
|
||||||
{
|
{
|
||||||
gstr << gtr_sprintf(
|
gstr << fmt::format(
|
||||||
_("Peer list request %1$stimed out%2$s %3$s ago; will retry"),
|
// {markup_begin} and {markup_end} should surround the time_span
|
||||||
timeout_markup_begin,
|
_("Peer list request {markup_begin}timed out {time_span} ago{markup_end}; will retry"),
|
||||||
timeout_markup_end,
|
fmt::arg("markup_begin", TimeoutMarkupBegin),
|
||||||
timebuf);
|
fmt::arg("time_span", timebuf),
|
||||||
|
fmt::arg("markup_end", TimeoutMarkupEnd));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
gstr << gtr_sprintf(
|
gstr << fmt::format(
|
||||||
_("Got an error %1$s\"%2$s\"%3$s %4$s ago"),
|
// {markup_begin} and {markup_end} should surround the error
|
||||||
err_markup_begin,
|
_("Got an error '{markup_begin}{error}{markup_end}' {time_span} ago"),
|
||||||
tracker.lastAnnounceResult,
|
fmt::arg("markup_begin", ErrMarkupBegin),
|
||||||
err_markup_end,
|
fmt::arg("error", Glib::Markup::escape_text(tracker.lastAnnounceResult)),
|
||||||
timebuf);
|
fmt::arg("markup_end", ErrMarkupEnd),
|
||||||
|
fmt::arg("time_span", timebuf));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1904,7 +1946,9 @@ void appendAnnounceInfo(tr_tracker_view const& tracker, time_t const now, Gtk::T
|
||||||
case TR_TRACKER_WAITING:
|
case TR_TRACKER_WAITING:
|
||||||
gstr << '\n';
|
gstr << '\n';
|
||||||
gstr << text_dir_mark[direction];
|
gstr << text_dir_mark[direction];
|
||||||
gstr << gtr_sprintf(_("Asking for more peers in %s"), tr_strltime_rounded(tracker.nextAnnounceTime - now));
|
gstr << fmt::format(
|
||||||
|
_("Asking for more peers in {time_span}"),
|
||||||
|
fmt::arg("time_span", tr_strltime_rounded(tracker.nextAnnounceTime - now)));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TR_TRACKER_QUEUED:
|
case TR_TRACKER_QUEUED:
|
||||||
|
@ -1916,9 +1960,12 @@ void appendAnnounceInfo(tr_tracker_view const& tracker, time_t const now, Gtk::T
|
||||||
case TR_TRACKER_ACTIVE:
|
case TR_TRACKER_ACTIVE:
|
||||||
gstr << '\n';
|
gstr << '\n';
|
||||||
gstr << text_dir_mark[direction];
|
gstr << text_dir_mark[direction];
|
||||||
gstr << gtr_sprintf(
|
gstr << fmt::format(
|
||||||
_("Asking for more peers now… <small>%s</small>"),
|
// {markup_begin} and {markup_end} should surround the time_span
|
||||||
tr_strltime_rounded(now - tracker.lastAnnounceStartTime));
|
_("Asking for more peers now… {markup_begin}{time_span}{markup_end}"),
|
||||||
|
fmt::arg("markup_begin", "<small>"),
|
||||||
|
fmt::arg("time_span", tr_strltime_rounded(now - tracker.lastAnnounceStartTime)),
|
||||||
|
fmt::arg("markup_end", "</small>"));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -1936,22 +1983,26 @@ void appendScrapeInfo(tr_tracker_view const& tracker, time_t const now, Gtk::Tex
|
||||||
|
|
||||||
if (tracker.lastScrapeSucceeded)
|
if (tracker.lastScrapeSucceeded)
|
||||||
{
|
{
|
||||||
gstr << gtr_sprintf(
|
gstr << fmt::format(
|
||||||
_("Tracker had %s%'d seeders and %'d leechers%s %s ago"),
|
// {markup_begin} and {markup_end} should surround the seeder/leecher text
|
||||||
success_markup_begin,
|
_("Tracker had {markup_begin}{seeder_count} {seeder_or_seeders} and {leecher_count} {leecher_or_leechers}{markup_end} {time_span} ago"),
|
||||||
tracker.seederCount,
|
fmt::arg("seeder_count", tracker.seederCount),
|
||||||
tracker.leecherCount,
|
fmt::arg("seeder_or_seeders", ngettext("seeder", "seeders", tracker.seederCount)),
|
||||||
success_markup_end,
|
fmt::arg("leecher_count", tracker.leecherCount),
|
||||||
timebuf);
|
fmt::arg("leecher_or_leechers", ngettext("leecher", "leechers", tracker.leecherCount)),
|
||||||
|
fmt::arg("time_span", timebuf),
|
||||||
|
fmt::arg("markup_begin", SuccessMarkupBegin),
|
||||||
|
fmt::arg("markup_end", SuccessMarkupEnd));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
gstr << gtr_sprintf(
|
gstr << fmt::format(
|
||||||
_("Got a scrape error \"%s%s%s\" %s ago"),
|
// {markup_begin} and {markup_end} should surround the error text
|
||||||
err_markup_begin,
|
_("Got a scrape error '{markup_begin}{error}{markup_end}' {time_span} ago"),
|
||||||
tracker.lastScrapeResult,
|
fmt::arg("error", Glib::Markup::escape_text(tracker.lastScrapeResult)),
|
||||||
err_markup_end,
|
fmt::arg("time_span", timebuf),
|
||||||
timebuf);
|
fmt::arg("markup_begin", ErrMarkupBegin),
|
||||||
|
fmt::arg("markup_end", ErrMarkupEnd));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1963,7 +2014,9 @@ void appendScrapeInfo(tr_tracker_view const& tracker, time_t const now, Gtk::Tex
|
||||||
case TR_TRACKER_WAITING:
|
case TR_TRACKER_WAITING:
|
||||||
gstr << '\n';
|
gstr << '\n';
|
||||||
gstr << text_dir_mark[direction];
|
gstr << text_dir_mark[direction];
|
||||||
gstr << gtr_sprintf(_("Asking for peer counts in %s"), tr_strltime_rounded(tracker.nextScrapeTime - now));
|
gstr << fmt::format(
|
||||||
|
_("Asking for peer counts in {time_span}"),
|
||||||
|
fmt::arg("time_span", tr_strltime_rounded(tracker.nextScrapeTime - now)));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TR_TRACKER_QUEUED:
|
case TR_TRACKER_QUEUED:
|
||||||
|
@ -1975,9 +2028,11 @@ void appendScrapeInfo(tr_tracker_view const& tracker, time_t const now, Gtk::Tex
|
||||||
case TR_TRACKER_ACTIVE:
|
case TR_TRACKER_ACTIVE:
|
||||||
gstr << '\n';
|
gstr << '\n';
|
||||||
gstr << text_dir_mark[direction];
|
gstr << text_dir_mark[direction];
|
||||||
gstr << gtr_sprintf(
|
gstr << fmt::format(
|
||||||
_("Asking for peer counts now… <small>%s</small>"),
|
_("Asking for peer counts now… {markup_begin}{time_span}{markup_end}"),
|
||||||
tr_strltime_rounded(now - tracker.lastScrapeStartTime));
|
fmt::arg("markup_begin", "<small>"),
|
||||||
|
fmt::arg("time_span", tr_strltime_rounded(now - tracker.lastScrapeStartTime)),
|
||||||
|
fmt::arg("markup_end", "</small>"));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -1995,7 +2050,7 @@ void buildTrackerSummary(
|
||||||
// hostname
|
// hostname
|
||||||
gstr << text_dir_mark[direction];
|
gstr << text_dir_mark[direction];
|
||||||
gstr << (tracker.isBackup ? "<i>" : "<b>");
|
gstr << (tracker.isBackup ? "<i>" : "<b>");
|
||||||
gstr << Glib::Markup::escape_text(!key.empty() ? gtr_sprintf("%s - %s", tracker.host, key) : tracker.host);
|
gstr << Glib::Markup::escape_text(!key.empty() ? fmt::format("{} - {}", tracker.host, key) : tracker.host);
|
||||||
gstr << (tracker.isBackup ? "</i>" : "</b>");
|
gstr << (tracker.isBackup ? "</i>" : "</b>");
|
||||||
|
|
||||||
if (!tracker.isBackup)
|
if (!tracker.isBackup)
|
||||||
|
@ -2261,7 +2316,7 @@ void DetailsDialog::Impl::on_edit_trackers()
|
||||||
int const torrent_id = tr_torrentId(tor);
|
int const torrent_id = tr_torrentId(tor);
|
||||||
|
|
||||||
auto d = std::make_shared<Gtk::Dialog>(
|
auto d = std::make_shared<Gtk::Dialog>(
|
||||||
gtr_sprintf(_("%s - Edit Trackers"), tr_torrentName(tor)),
|
fmt::format(_("{torrent_name} - Edit Trackers"), fmt::arg("torrent_name", tr_torrentName(tor))),
|
||||||
dialog_,
|
dialog_,
|
||||||
Gtk::DIALOG_MODAL | Gtk::DIALOG_DESTROY_WITH_PARENT);
|
Gtk::DIALOG_MODAL | Gtk::DIALOG_DESTROY_WITH_PARENT);
|
||||||
d->add_button(_("_Cancel"), Gtk::RESPONSE_CANCEL);
|
d->add_button(_("_Cancel"), Gtk::RESPONSE_CANCEL);
|
||||||
|
@ -2371,7 +2426,7 @@ void DetailsDialog::Impl::on_tracker_list_add_button_clicked()
|
||||||
guint row;
|
guint row;
|
||||||
|
|
||||||
auto w = std::make_shared<Gtk::Dialog>(
|
auto w = std::make_shared<Gtk::Dialog>(
|
||||||
gtr_sprintf(_("%s - Add Tracker"), tr_torrentName(tor)),
|
fmt::format(_("{torrent_name} - Add Tracker"), fmt::arg("torrent_name", tr_torrentName(tor))),
|
||||||
dialog_,
|
dialog_,
|
||||||
Gtk::DIALOG_DESTROY_WITH_PARENT);
|
Gtk::DIALOG_DESTROY_WITH_PARENT);
|
||||||
w->add_button(_("_Cancel"), Gtk::RESPONSE_CANCEL);
|
w->add_button(_("_Cancel"), Gtk::RESPONSE_CANCEL);
|
||||||
|
@ -2611,7 +2666,7 @@ void DetailsDialog::Impl::set_torrents(std::vector<int> const& ids)
|
||||||
{
|
{
|
||||||
int const id = ids.front();
|
int const id = ids.front();
|
||||||
auto const* tor = core_->find_torrent(id);
|
auto const* tor = core_->find_torrent(id);
|
||||||
title = gtr_sprintf(_("%s Properties"), tr_torrentName(tor));
|
title = fmt::format(_("{torrent_name} Properties"), fmt::arg("torrent_name", tr_torrentName(tor)));
|
||||||
|
|
||||||
file_list_->set_torrent(id);
|
file_list_->set_torrent(id);
|
||||||
file_list_->show();
|
file_list_->show();
|
||||||
|
@ -2619,10 +2674,13 @@ void DetailsDialog::Impl::set_torrents(std::vector<int> const& ids)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
title = fmt::format(
|
||||||
|
ngettext("Properties - {count} Torrent", "Properties - {count} Torrents", len),
|
||||||
|
fmt::arg("count", len));
|
||||||
|
|
||||||
file_list_->clear();
|
file_list_->clear();
|
||||||
file_list_->hide();
|
file_list_->hide();
|
||||||
file_label_->show();
|
file_label_->show();
|
||||||
title = gtr_sprintf(_("%'d Torrent Properties"), len);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dialog_.set_title(title);
|
dialog_.set_title(title);
|
||||||
|
|
|
@ -745,8 +745,8 @@ bool FileList::Impl::on_rename_done_idle(Glib::ustring const& path_string, Glib:
|
||||||
*static_cast<Gtk::Window*>(widget_.get_toplevel()),
|
*static_cast<Gtk::Window*>(widget_.get_toplevel()),
|
||||||
fmt::format(
|
fmt::format(
|
||||||
_("Couldn't rename '{old_path}' as '{path}': {error} ({error_code})"),
|
_("Couldn't rename '{old_path}' as '{path}': {error} ({error_code})"),
|
||||||
fmt::arg("old_path", path_string.raw()),
|
fmt::arg("old_path", path_string),
|
||||||
fmt::arg("path", newname.raw()),
|
fmt::arg("path", newname),
|
||||||
fmt::arg("error", tr_strerror(error)),
|
fmt::arg("error", tr_strerror(error)),
|
||||||
fmt::arg("error_code", error)),
|
fmt::arg("error_code", error)),
|
||||||
false,
|
false,
|
||||||
|
|
|
@ -711,7 +711,9 @@ bool FilterBar::Impl::update_count_label()
|
||||||
|
|
||||||
/* set the text */
|
/* set the text */
|
||||||
show_lb_->set_markup_with_mnemonic(
|
show_lb_->set_markup_with_mnemonic(
|
||||||
visibleCount == std::min(activityCount, trackerCount) ? _("_Show:") : gtr_sprintf(_("_Show %'d of:"), visibleCount));
|
visibleCount == std::min(activityCount, trackerCount) ?
|
||||||
|
_("_Show:") :
|
||||||
|
fmt::format(_("_Show {count:L} of:"), fmt::arg("count", visibleCount)));
|
||||||
|
|
||||||
show_lb_->steal_data(DIRTY_KEY);
|
show_lb_->steal_data(DIRTY_KEY);
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -8,6 +8,8 @@
|
||||||
|
|
||||||
#include <glibmm/i18n.h>
|
#include <glibmm/i18n.h>
|
||||||
|
|
||||||
|
#include <fmt/core.h>
|
||||||
|
|
||||||
#include <libtransmission/utils.h>
|
#include <libtransmission/utils.h>
|
||||||
|
|
||||||
#include "FreeSpaceLabel.h"
|
#include "FreeSpaceLabel.h"
|
||||||
|
@ -47,9 +49,8 @@ bool FreeSpaceLabel::Impl::on_freespace_timer()
|
||||||
}
|
}
|
||||||
|
|
||||||
auto const bytes = tr_dirSpace(dir_).free;
|
auto const bytes = tr_dirSpace(dir_).free;
|
||||||
auto const text = bytes < 0 ? _("Error") : gtr_sprintf(_("%s free"), tr_strlsize(bytes));
|
auto const text = bytes < 0 ? _("Error") : fmt::format(_("{disk_space} free"), fmt::arg("disk_space", tr_strlsize(bytes)));
|
||||||
auto const markup = gtr_sprintf("<i>%s</i>", text);
|
label_.set_markup(fmt::format("<i>{}</i>", text));
|
||||||
label_.set_markup(markup);
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -220,17 +220,15 @@ void MainWindow::Impl::syncAltSpeedButton()
|
||||||
bool const b = gtr_pref_flag_get(TR_KEY_alt_speed_enabled);
|
bool const b = gtr_pref_flag_get(TR_KEY_alt_speed_enabled);
|
||||||
char const* const stock = b ? "alt-speed-on" : "alt-speed-off";
|
char const* const stock = b ? "alt-speed-on" : "alt-speed-off";
|
||||||
|
|
||||||
auto const u = tr_formatter_speed_KBps(gtr_pref_int_get(TR_KEY_alt_speed_up));
|
|
||||||
auto const d = tr_formatter_speed_KBps(gtr_pref_int_get(TR_KEY_alt_speed_down));
|
|
||||||
|
|
||||||
auto const str = b ? gtr_sprintf(_("Click to disable Alternative Speed Limits\n (%1$s down, %2$s up)"), d, u) :
|
|
||||||
gtr_sprintf(_("Click to enable Alternative Speed Limits\n (%1$s down, %2$s up)"), d, u);
|
|
||||||
|
|
||||||
alt_speed_button_->set_active(b);
|
alt_speed_button_->set_active(b);
|
||||||
alt_speed_image_->set_from_icon_name(stock, Gtk::BuiltinIconSize::ICON_SIZE_MENU);
|
alt_speed_image_->set_from_icon_name(stock, Gtk::BuiltinIconSize::ICON_SIZE_MENU);
|
||||||
alt_speed_button_->set_halign(Gtk::ALIGN_CENTER);
|
alt_speed_button_->set_halign(Gtk::ALIGN_CENTER);
|
||||||
alt_speed_button_->set_valign(Gtk::ALIGN_CENTER);
|
alt_speed_button_->set_valign(Gtk::ALIGN_CENTER);
|
||||||
alt_speed_button_->set_tooltip_text(str);
|
alt_speed_button_->set_tooltip_text(fmt::format(
|
||||||
|
b ? _("Click to disable Alternative Speed Limits\n ({download_speed} down, {upload_speed} up)") :
|
||||||
|
_("Click to enable Alternative Speed Limits\n ({download_speed} down, {upload_speed} up)"),
|
||||||
|
fmt::arg("download_speed", tr_formatter_speed_KBps(gtr_pref_int_get(TR_KEY_alt_speed_down))),
|
||||||
|
fmt::arg("upload_speed", tr_formatter_speed_KBps(gtr_pref_int_get(TR_KEY_alt_speed_up)))));
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::Impl::alt_speed_toggled_cb()
|
void MainWindow::Impl::alt_speed_toggled_cb()
|
||||||
|
@ -381,7 +379,7 @@ void MainWindow::Impl::onOptionsClicked(Gtk::Button* button)
|
||||||
|
|
||||||
gtr_label_set_text(
|
gtr_label_set_text(
|
||||||
*static_cast<Gtk::Label*>(ratio_on_item_->get_child()),
|
*static_cast<Gtk::Label*>(ratio_on_item_->get_child()),
|
||||||
gtr_sprintf(_("Stop at Ratio (%s)"), tr_strlratio(gtr_pref_double_get(TR_KEY_ratio_limit))));
|
fmt::format(_("Stop at Ratio ({ratio})"), fmt::arg("ratio", tr_strlratio(gtr_pref_double_get(TR_KEY_ratio_limit)))));
|
||||||
|
|
||||||
(gtr_pref_flag_get(TR_KEY_ratio_limit_enabled) ? ratio_on_item_ : ratio_off_item_)->set_active(true);
|
(gtr_pref_flag_get(TR_KEY_ratio_limit_enabled) ? ratio_on_item_ : ratio_off_item_)->set_active(true);
|
||||||
|
|
||||||
|
@ -589,31 +587,28 @@ void MainWindow::Impl::updateStats()
|
||||||
if (auto const pch = gtr_pref_string_get(TR_KEY_statusbar_stats); pch == "session-ratio")
|
if (auto const pch = gtr_pref_string_get(TR_KEY_statusbar_stats); pch == "session-ratio")
|
||||||
{
|
{
|
||||||
tr_sessionGetStats(session, &stats);
|
tr_sessionGetStats(session, &stats);
|
||||||
buf = gtr_sprintf(_("Ratio: %s"), tr_strlratio(stats.ratio));
|
buf = fmt::format(_("Ratio: {ratio}"), tr_strlratio(stats.ratio));
|
||||||
}
|
}
|
||||||
else if (pch == "session-transfer")
|
else if (pch == "session-transfer")
|
||||||
{
|
{
|
||||||
tr_sessionGetStats(session, &stats);
|
tr_sessionGetStats(session, &stats);
|
||||||
/* Translators: "size|" is here for disambiguation. Please remove it from your translation.
|
buf = fmt::format(
|
||||||
%1$s is the size of the data we've downloaded
|
C_("current session totals", "Down: {downloaded_size}, Up: {uploaded_size}"),
|
||||||
%2$s is the size of the data we've uploaded */
|
fmt::arg("downloaded_size", tr_strlsize(stats.downloadedBytes)),
|
||||||
buf = gtr_sprintf(Q_("Down: %1$s, Up: %2$s"), tr_strlsize(stats.downloadedBytes), tr_strlsize(stats.uploadedBytes));
|
fmt::arg("uploaded_size", tr_strlsize(stats.uploadedBytes)));
|
||||||
}
|
}
|
||||||
else if (pch == "total-transfer")
|
else if (pch == "total-transfer")
|
||||||
{
|
{
|
||||||
tr_sessionGetCumulativeStats(session, &stats);
|
tr_sessionGetCumulativeStats(session, &stats);
|
||||||
/* Translators: "size|" is here for disambiguation. Please remove it from your translation.
|
buf = fmt::format(
|
||||||
%1$s is the size of the data we've downloaded
|
C_("all-time totals", "Down: {downloaded_size}, Up: {uploaded_size}"),
|
||||||
%2$s is the size of the data we've uploaded */
|
fmt::arg("downloaded_size", tr_strlsize(stats.downloadedBytes)),
|
||||||
buf = gtr_sprintf(
|
fmt::arg("uploaded_size", tr_strlsize(stats.uploadedBytes)));
|
||||||
Q_("size|Down: %1$s, Up: %2$s"),
|
|
||||||
tr_strlsize(stats.downloadedBytes),
|
|
||||||
tr_strlsize(stats.uploadedBytes));
|
|
||||||
}
|
}
|
||||||
else /* default is total-ratio */
|
else /* default is total-ratio */
|
||||||
{
|
{
|
||||||
tr_sessionGetCumulativeStats(session, &stats);
|
tr_sessionGetCumulativeStats(session, &stats);
|
||||||
buf = gtr_sprintf(_("Ratio: %s"), tr_strlratio(stats.ratio));
|
buf = fmt::format(_("Ratio: {ratio}"), fmt::arg("ratio", tr_strlratio(stats.ratio)));
|
||||||
}
|
}
|
||||||
|
|
||||||
stats_lb_->set_text(buf);
|
stats_lb_->set_text(buf);
|
||||||
|
@ -625,25 +620,25 @@ void MainWindow::Impl::updateSpeeds()
|
||||||
|
|
||||||
if (session != nullptr)
|
if (session != nullptr)
|
||||||
{
|
{
|
||||||
double upSpeed = 0;
|
auto dn_count = int{};
|
||||||
double downSpeed = 0;
|
auto dn_speed = double{};
|
||||||
int upCount = 0;
|
auto up_count = int{};
|
||||||
int downCount = 0;
|
auto up_speed = double{};
|
||||||
auto const model = core_->get_model();
|
|
||||||
|
|
||||||
|
auto const model = core_->get_model();
|
||||||
for (auto const& row : model->children())
|
for (auto const& row : model->children())
|
||||||
{
|
{
|
||||||
upSpeed += row.get_value(torrent_cols.speed_up);
|
dn_count += row.get_value(torrent_cols.active_peers_down);
|
||||||
upCount += row.get_value(torrent_cols.active_peers_up);
|
dn_speed += row.get_value(torrent_cols.speed_down);
|
||||||
downSpeed += row.get_value(torrent_cols.speed_down);
|
up_count += row.get_value(torrent_cols.active_peers_up);
|
||||||
downCount += row.get_value(torrent_cols.active_peers_down);
|
up_speed += row.get_value(torrent_cols.speed_up);
|
||||||
}
|
}
|
||||||
|
|
||||||
dl_lb_->set_text(gtr_sprintf("%s %s", tr_formatter_speed_KBps(downSpeed), gtr_get_unicode_string(GtrUnicode::Down)));
|
dl_lb_->set_text(fmt::format(_("{download_speed} ▼"), fmt::arg("download_speed", dn_speed)));
|
||||||
dl_lb_->set_visible(downCount > 0);
|
dl_lb_->set_visible(dn_count > 0);
|
||||||
|
|
||||||
ul_lb_->set_text(gtr_sprintf("%s %s", tr_formatter_speed_KBps(upSpeed), gtr_get_unicode_string(GtrUnicode::Up)));
|
ul_lb_->set_text(fmt::format(_("{upload_speed} ▲"), fmt::arg("upload_speed", up_speed)));
|
||||||
ul_lb_->set_visible(downCount > 0 || upCount > 0);
|
ul_lb_->set_visible(dn_count > 0 || up_count > 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -111,11 +111,11 @@ bool MakeProgressDialog::onProgressDialogRefresh()
|
||||||
/* progress label */
|
/* progress label */
|
||||||
if (!builder_.isDone)
|
if (!builder_.isDone)
|
||||||
{
|
{
|
||||||
str = gtr_sprintf(_("Creating \"%s\""), base);
|
str = fmt::format(_("Creating '{path}'"), fmt::arg("path", base));
|
||||||
}
|
}
|
||||||
else if (builder_.result == TrMakemetaResult::OK)
|
else if (builder_.result == TrMakemetaResult::OK)
|
||||||
{
|
{
|
||||||
str = gtr_sprintf(_("Created \"%s\"!"), base);
|
str = fmt::format(_("Created '{path}'"), fmt::arg("path", base));
|
||||||
}
|
}
|
||||||
else if (builder_.result == TrMakemetaResult::CANCELLED)
|
else if (builder_.result == TrMakemetaResult::CANCELLED)
|
||||||
{
|
{
|
||||||
|
@ -130,7 +130,7 @@ bool MakeProgressDialog::onProgressDialogRefresh()
|
||||||
str = fmt::format(
|
str = fmt::format(
|
||||||
_("Couldn't read '{path}': {error} ({error_code})"),
|
_("Couldn't read '{path}': {error} ({error_code})"),
|
||||||
fmt::arg("path", builder_.errfile),
|
fmt::arg("path", builder_.errfile),
|
||||||
fmt::arg("error", Glib::strerror(builder_.my_errno).raw()),
|
fmt::arg("error", Glib::strerror(builder_.my_errno)),
|
||||||
fmt::arg("error_code", builder_.my_errno));
|
fmt::arg("error_code", builder_.my_errno));
|
||||||
}
|
}
|
||||||
else if (builder_.result == TrMakemetaResult::ERR_IO_WRITE)
|
else if (builder_.result == TrMakemetaResult::ERR_IO_WRITE)
|
||||||
|
@ -138,7 +138,7 @@ bool MakeProgressDialog::onProgressDialogRefresh()
|
||||||
str = fmt::format(
|
str = fmt::format(
|
||||||
_("Couldn't save '{path}': {error} ({error_code})"),
|
_("Couldn't save '{path}': {error} ({error_code})"),
|
||||||
fmt::arg("path", builder_.errfile),
|
fmt::arg("path", builder_.errfile),
|
||||||
fmt::arg("error", Glib::strerror(builder_.my_errno).raw()),
|
fmt::arg("error", Glib::strerror(builder_.my_errno)),
|
||||||
fmt::arg("error_code", builder_.my_errno));
|
fmt::arg("error_code", builder_.my_errno));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -158,7 +158,7 @@ bool MakeProgressDialog::onProgressDialogRefresh()
|
||||||
/* how much data we've scanned through to generate checksums */
|
/* how much data we've scanned through to generate checksums */
|
||||||
str = fmt::format(
|
str = fmt::format(
|
||||||
_("Scanned {file_size}"),
|
_("Scanned {file_size}"),
|
||||||
fmt::arg("file_size", tr_strlsize((uint64_t)builder_.pieceIndex * (uint64_t)builder_.pieceSize).raw()));
|
fmt::arg("file_size", tr_strlsize((uint64_t)builder_.pieceIndex * (uint64_t)builder_.pieceSize)));
|
||||||
}
|
}
|
||||||
|
|
||||||
progress_bar_->set_fraction(fraction);
|
progress_bar_->set_fraction(fraction);
|
||||||
|
@ -276,7 +276,7 @@ void MakeDialog::Impl::onResponse(int response)
|
||||||
/* destination file */
|
/* destination file */
|
||||||
auto const dir = destination_chooser_->get_filename();
|
auto const dir = destination_chooser_->get_filename();
|
||||||
auto const base = Glib::path_get_basename(builder_->top);
|
auto const base = Glib::path_get_basename(builder_->top);
|
||||||
auto const target = gtr_sprintf("%s/%s.torrent", dir, base).raw();
|
auto const target = gtr_sprintf("%s/%s.torrent", dir, base);
|
||||||
|
|
||||||
/* build the array of trackers */
|
/* build the array of trackers */
|
||||||
auto const tracker_text = announce_text_buffer_->get_text(false);
|
auto const tracker_text = announce_text_buffer_->get_text(false);
|
||||||
|
@ -498,9 +498,8 @@ MakeDialog::Impl::Impl(MakeDialog& dialog, Glib::RefPtr<Session> const& core)
|
||||||
fr->add(*sw);
|
fr->add(*sw);
|
||||||
v->pack_start(*fr, true, true, 0);
|
v->pack_start(*fr, true, true, 0);
|
||||||
auto* l = Gtk::make_managed<Gtk::Label>();
|
auto* l = Gtk::make_managed<Gtk::Label>();
|
||||||
l->set_markup(
|
l->set_markup(_(
|
||||||
_("To add a backup URL, add it on the line after the primary URL.\n"
|
"To add a backup URL, add it on the next line after a primary URL.\nTo add a new primary URL, add it after a blank line."));
|
||||||
"To add another primary URL, add it after a blank line."));
|
|
||||||
l->set_justify(Gtk::JUSTIFY_LEFT);
|
l->set_justify(Gtk::JUSTIFY_LEFT);
|
||||||
l->set_halign(Gtk::ALIGN_START);
|
l->set_halign(Gtk::ALIGN_START);
|
||||||
l->set_valign(Gtk::ALIGN_CENTER);
|
l->set_valign(Gtk::ALIGN_CENTER);
|
||||||
|
|
|
@ -188,7 +188,7 @@ void MessageLogWindow::Impl::doSave(Gtk::Window& parent, Glib::ustring const& fi
|
||||||
parent,
|
parent,
|
||||||
fmt::format(
|
fmt::format(
|
||||||
_("Couldn't save '{path}': {error} ({error_code})"),
|
_("Couldn't save '{path}': {error} ({error_code})"),
|
||||||
fmt::arg("path", filename.raw()),
|
fmt::arg("path", filename),
|
||||||
fmt::arg("error", g_strerror(errcode)),
|
fmt::arg("error", g_strerror(errcode)),
|
||||||
fmt::arg("error_code", errcode)),
|
fmt::arg("error_code", errcode)),
|
||||||
false,
|
false,
|
||||||
|
|
|
@ -171,7 +171,7 @@ void OptionsDialog::Impl::updateTorrent()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* When the source .torrent file is deleted
|
* When the source torrent file is deleted
|
||||||
* (such as, if it was a temp file that a web browser passed to us),
|
* (such as, if it was a temp file that a web browser passed to us),
|
||||||
* gtk invokes this callback and `filename' will be nullptr.
|
* gtk invokes this callback and `filename' will be nullptr.
|
||||||
* The `filename' tests here are to prevent us from losing the current
|
* The `filename' tests here are to prevent us from losing the current
|
||||||
|
@ -292,7 +292,7 @@ OptionsDialog::Impl::Impl(
|
||||||
filename_ = tr_ctorGetSourceFile(ctor_.get()) != nullptr ? tr_ctorGetSourceFile(ctor_.get()) : "";
|
filename_ = tr_ctorGetSourceFile(ctor_.get()) != nullptr ? tr_ctorGetSourceFile(ctor_.get()) : "";
|
||||||
downloadDir_ = str;
|
downloadDir_ = str;
|
||||||
file_list_ = Gtk::make_managed<FileList>(core_, 0);
|
file_list_ = Gtk::make_managed<FileList>(core_, 0);
|
||||||
trash_check_ = Gtk::make_managed<Gtk::CheckButton>(_("Mo_ve .torrent file to the trash"), true);
|
trash_check_ = Gtk::make_managed<Gtk::CheckButton>(_("Mo_ve torrent file to the trash"), true);
|
||||||
run_check_ = Gtk::make_managed<Gtk::CheckButton>(_("_Start when added"), true);
|
run_check_ = Gtk::make_managed<Gtk::CheckButton>(_("_Start when added"), true);
|
||||||
|
|
||||||
priority_combo_ = gtr_priority_combo_new();
|
priority_combo_ = gtr_priority_combo_new();
|
||||||
|
@ -376,7 +376,7 @@ OptionsDialog::Impl::Impl(
|
||||||
run_check_->set_active(!flag);
|
run_check_->set_active(!flag);
|
||||||
grid->attach(*run_check_, 0, row, 2, 1);
|
grid->attach(*run_check_, 0, row, 2, 1);
|
||||||
|
|
||||||
/* "trash .torrent file" row */
|
/* "trash torrent file" row */
|
||||||
row++;
|
row++;
|
||||||
|
|
||||||
if (!tr_ctorGetDeleteSource(ctor_.get(), &flag))
|
if (!tr_ctorGetDeleteSource(ctor_.get(), &flag))
|
||||||
|
|
|
@ -254,7 +254,7 @@ Gtk::Widget* PrefsDialog::Impl::downloadingPage()
|
||||||
t->add_section_title(row, C_("Gerund", "Adding"));
|
t->add_section_title(row, C_("Gerund", "Adding"));
|
||||||
|
|
||||||
{
|
{
|
||||||
auto* l = new_check_button(_("Automatically add .torrent files _from:"), TR_KEY_watch_dir_enabled, core_);
|
auto* l = new_check_button(_("Automatically add torrent files _from:"), TR_KEY_watch_dir_enabled, core_);
|
||||||
auto* w = new_path_chooser_button(TR_KEY_watch_dir, core_);
|
auto* w = new_path_chooser_button(TR_KEY_watch_dir, core_);
|
||||||
w->set_sensitive(gtr_pref_flag_get(TR_KEY_watch_dir_enabled));
|
w->set_sensitive(gtr_pref_flag_get(TR_KEY_watch_dir_enabled));
|
||||||
l->signal_toggled().connect([l, w]() { target_cb(l, w); });
|
l->signal_toggled().connect([l, w]() { target_cb(l, w); });
|
||||||
|
@ -267,7 +267,7 @@ Gtk::Widget* PrefsDialog::Impl::downloadingPage()
|
||||||
|
|
||||||
t->add_wide_control(
|
t->add_wide_control(
|
||||||
row,
|
row,
|
||||||
*new_check_button(_("Mo_ve .torrent file to the trash"), TR_KEY_trash_original_torrent_files, core_));
|
*new_check_button(_("Mo_ve torrent file to the trash"), TR_KEY_trash_original_torrent_files, core_));
|
||||||
|
|
||||||
t->add_row(row, _("Save to _Location:"), *new_path_chooser_button(TR_KEY_download_dir, core_));
|
t->add_row(row, _("Save to _Location:"), *new_path_chooser_button(TR_KEY_download_dir, core_));
|
||||||
|
|
||||||
|
@ -415,7 +415,7 @@ void updateBlocklistText(Gtk::Label* w, Glib::RefPtr<Session> const& core)
|
||||||
auto const msg = fmt::format(
|
auto const msg = fmt::format(
|
||||||
ngettext("Blocklist has {count} entry", "Blocklist has {count} entries", n),
|
ngettext("Blocklist has {count} entry", "Blocklist has {count} entries", n),
|
||||||
fmt::arg("count", n));
|
fmt::arg("count", n));
|
||||||
w->set_markup(gtr_sprintf("<i>%s</i>", msg.c_str()));
|
w->set_markup(fmt::format("<i>{}</i>", msg));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* prefs dialog is being destroyed, so stop listening to blocklist updates */
|
/* prefs dialog is being destroyed, so stop listening to blocklist updates */
|
||||||
|
@ -887,7 +887,11 @@ Gtk::Widget* PrefsDialog::Impl::speedPage()
|
||||||
t->add_section_title(row, _("Speed Limits"));
|
t->add_section_title(row, _("Speed Limits"));
|
||||||
|
|
||||||
{
|
{
|
||||||
auto* w = new_check_button(gtr_sprintf(_("_Upload (%s):"), _(speed_K_str)), TR_KEY_speed_limit_up_enabled, core_);
|
auto* w = new_check_button(
|
||||||
|
// checkbox to limit upload speed
|
||||||
|
fmt::format(_("_Upload ({speed_units}):"), fmt::arg("speed_units", speed_K_str)),
|
||||||
|
TR_KEY_speed_limit_up_enabled,
|
||||||
|
core_);
|
||||||
auto* w2 = new_spin_button(TR_KEY_speed_limit_up, core_, 0, INT_MAX, 5);
|
auto* w2 = new_spin_button(TR_KEY_speed_limit_up, core_, 0, INT_MAX, 5);
|
||||||
w2->set_sensitive(gtr_pref_flag_get(TR_KEY_speed_limit_up_enabled));
|
w2->set_sensitive(gtr_pref_flag_get(TR_KEY_speed_limit_up_enabled));
|
||||||
w->signal_toggled().connect([w, w2]() { target_cb(w, w2); });
|
w->signal_toggled().connect([w, w2]() { target_cb(w, w2); });
|
||||||
|
@ -895,7 +899,11 @@ Gtk::Widget* PrefsDialog::Impl::speedPage()
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
auto* w = new_check_button(gtr_sprintf(_("_Download (%s):"), _(speed_K_str)), TR_KEY_speed_limit_down_enabled, core_);
|
auto* w = new_check_button(
|
||||||
|
// checkbox to limit download speed
|
||||||
|
fmt::format(_("_Download ({speed_units}):"), fmt::arg("speed_units", speed_K_str)),
|
||||||
|
TR_KEY_speed_limit_down_enabled,
|
||||||
|
core_);
|
||||||
auto* w2 = new_spin_button(TR_KEY_speed_limit_down, core_, 0, INT_MAX, 5);
|
auto* w2 = new_spin_button(TR_KEY_speed_limit_down, core_, 0, INT_MAX, 5);
|
||||||
w2->set_sensitive(gtr_pref_flag_get(TR_KEY_speed_limit_down_enabled));
|
w2->set_sensitive(gtr_pref_flag_get(TR_KEY_speed_limit_down_enabled));
|
||||||
w->signal_toggled().connect([w, w2]() { target_cb(w, w2); });
|
w->signal_toggled().connect([w, w2]() { target_cb(w, w2); });
|
||||||
|
@ -906,7 +914,7 @@ Gtk::Widget* PrefsDialog::Impl::speedPage()
|
||||||
|
|
||||||
{
|
{
|
||||||
auto* h = Gtk::make_managed<Gtk::Box>(Gtk::ORIENTATION_HORIZONTAL, GUI_PAD);
|
auto* h = Gtk::make_managed<Gtk::Box>(Gtk::ORIENTATION_HORIZONTAL, GUI_PAD);
|
||||||
auto* w = Gtk::make_managed<Gtk::Label>(gtr_sprintf("<b>%s</b>", _("Alternative Speed Limits")));
|
auto* w = Gtk::make_managed<Gtk::Label>(fmt::format("<b>{}</b>", _("Alternative Speed Limits")));
|
||||||
w->set_halign(Gtk::ALIGN_START);
|
w->set_halign(Gtk::ALIGN_START);
|
||||||
w->set_valign(Gtk::ALIGN_CENTER);
|
w->set_valign(Gtk::ALIGN_CENTER);
|
||||||
w->set_use_markup(true);
|
w->set_use_markup(true);
|
||||||
|
@ -917,7 +925,7 @@ Gtk::Widget* PrefsDialog::Impl::speedPage()
|
||||||
|
|
||||||
{
|
{
|
||||||
auto* w = Gtk::make_managed<Gtk::Label>(
|
auto* w = Gtk::make_managed<Gtk::Label>(
|
||||||
gtr_sprintf("<small>%s</small>", _("Override normal speed limits manually or at scheduled times")));
|
fmt::format("<small>{}</small>", _("Override normal speed limits manually or at scheduled times")));
|
||||||
w->set_use_markup(true);
|
w->set_use_markup(true);
|
||||||
w->set_halign(Gtk::ALIGN_START);
|
w->set_halign(Gtk::ALIGN_START);
|
||||||
w->set_valign(Gtk::ALIGN_CENTER);
|
w->set_valign(Gtk::ALIGN_CENTER);
|
||||||
|
@ -926,12 +934,14 @@ Gtk::Widget* PrefsDialog::Impl::speedPage()
|
||||||
|
|
||||||
t->add_row(
|
t->add_row(
|
||||||
row,
|
row,
|
||||||
gtr_sprintf(_("U_pload (%s):"), _(speed_K_str)),
|
// labels a spinbutton for alternate upload speed limits
|
||||||
|
fmt::format(_("U_pload ({speed_units}):"), fmt::arg("speed_units", speed_K_str)),
|
||||||
*new_spin_button(TR_KEY_alt_speed_up, core_, 0, INT_MAX, 5));
|
*new_spin_button(TR_KEY_alt_speed_up, core_, 0, INT_MAX, 5));
|
||||||
|
|
||||||
t->add_row(
|
t->add_row(
|
||||||
row,
|
row,
|
||||||
gtr_sprintf(_("Do_wnload (%s):"), _(speed_K_str)),
|
// labels a spinbutton for alternate download speed limits
|
||||||
|
fmt::format(_("Do_wnload ({speed_units}):"), fmt::arg("speed_units", speed_K_str)),
|
||||||
*new_spin_button(TR_KEY_alt_speed_down, core_, 0, INT_MAX, 5));
|
*new_spin_button(TR_KEY_alt_speed_down, core_, 0, INT_MAX, 5));
|
||||||
|
|
||||||
{
|
{
|
||||||
|
@ -939,6 +949,7 @@ Gtk::Widget* PrefsDialog::Impl::speedPage()
|
||||||
auto* start_combo = new_time_combo(core_, TR_KEY_alt_speed_time_begin);
|
auto* start_combo = new_time_combo(core_, TR_KEY_alt_speed_time_begin);
|
||||||
page->sched_widgets.push_back(start_combo);
|
page->sched_widgets.push_back(start_combo);
|
||||||
h->pack_start(*start_combo, true, true, 0);
|
h->pack_start(*start_combo, true, true, 0);
|
||||||
|
// label goes between two time selectors, e.g. "limit speeds from [time] to [time]"
|
||||||
auto* to_label = Gtk::make_managed<Gtk::Label>(_(" _to "), true);
|
auto* to_label = Gtk::make_managed<Gtk::Label>(_(" _to "), true);
|
||||||
page->sched_widgets.push_back(to_label);
|
page->sched_widgets.push_back(to_label);
|
||||||
h->pack_start(*to_label, false, false, 0);
|
h->pack_start(*to_label, false, false, 0);
|
||||||
|
@ -1006,7 +1017,10 @@ network_page_data::~network_page_data()
|
||||||
|
|
||||||
void onPortTested(bool isOpen, network_page_data* data)
|
void onPortTested(bool isOpen, network_page_data* data)
|
||||||
{
|
{
|
||||||
data->portLabel->set_markup(isOpen ? _("Port is <b>open</b>") : _("Port is <b>closed</b>"));
|
data->portLabel->set_markup(fmt::format(
|
||||||
|
isOpen ? _("Port is {markup_begin}open{markup_end}") : _("Port is {markup_begin}closed{markup_end}"),
|
||||||
|
fmt::arg("markup_begin", "<b>"),
|
||||||
|
fmt::arg("markup_end", "</b>")));
|
||||||
data->portButton->set_sensitive(true);
|
data->portButton->set_sensitive(true);
|
||||||
data->portSpin->set_sensitive(true);
|
data->portSpin->set_sensitive(true);
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,8 @@
|
||||||
#include <glibmm.h>
|
#include <glibmm.h>
|
||||||
#include <glibmm/i18n.h>
|
#include <glibmm/i18n.h>
|
||||||
|
|
||||||
|
#include <fmt/core.h>
|
||||||
|
|
||||||
#include <libtransmission/transmission.h>
|
#include <libtransmission/transmission.h>
|
||||||
|
|
||||||
#include "HigWorkarea.h"
|
#include "HigWorkarea.h"
|
||||||
|
@ -72,7 +74,9 @@ void RelocateDialog::Impl::startMovingNextTorrent()
|
||||||
|
|
||||||
torrent_ids_.pop_back();
|
torrent_ids_.pop_back();
|
||||||
|
|
||||||
message_dialog_->set_message(gtr_sprintf(_("Moving \"%s\""), tr_torrentName(tor)), true);
|
message_dialog_->set_message(
|
||||||
|
fmt::format(_("Moving '{torrent_name}'"), fmt::arg("torrent_name", tr_torrentName(tor))),
|
||||||
|
true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* every once in awhile, check to see if the move is done.
|
/* every once in awhile, check to see if the move is done.
|
||||||
|
|
|
@ -3,9 +3,10 @@
|
||||||
// A copy of this license can be found in licenses/ .
|
// A copy of this license can be found in licenses/ .
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cmath> /* pow() */
|
#include <cmath> // pow()
|
||||||
#include <cstring> // strstr
|
#include <cstring> // strstr
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
#include <iostream>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
@ -617,9 +618,9 @@ void rename_torrent(Glib::RefPtr<Gio::File> const& file)
|
||||||
{
|
{
|
||||||
auto const errmsg = fmt::format(
|
auto const errmsg = fmt::format(
|
||||||
_("Couldn't rename '{old_path}' as '{path}': {error} ({error_code})"),
|
_("Couldn't rename '{old_path}' as '{path}': {error} ({error_code})"),
|
||||||
fmt::arg("old_path", old_name.raw()),
|
fmt::arg("old_path", old_name),
|
||||||
fmt::arg("path", new_name.raw()),
|
fmt::arg("path", new_name),
|
||||||
fmt::arg("error", e.what().raw()),
|
fmt::arg("error", e.what()),
|
||||||
fmt::arg("error_code", e.code()));
|
fmt::arg("error_code", e.code()));
|
||||||
g_message("%s", errmsg.c_str());
|
g_message("%s", errmsg.c_str());
|
||||||
}
|
}
|
||||||
|
@ -1037,7 +1038,7 @@ int Session::Impl::add_ctor(tr_ctor* ctor, bool do_prompt, bool do_notify)
|
||||||
|
|
||||||
if (tr_torrentFindFromMetainfo(get_session(), metainfo) != nullptr)
|
if (tr_torrentFindFromMetainfo(get_session(), metainfo) != nullptr)
|
||||||
{
|
{
|
||||||
/* don't complain about .torrent files in the watch directory
|
/* don't complain about torrent files in the watch directory
|
||||||
* that have already been added... that gets annoying and we
|
* that have already been added... that gets annoying and we
|
||||||
* don't want to be nagging users to clean up their watch dirs */
|
* don't want to be nagging users to clean up their watch dirs */
|
||||||
if (tr_ctorGetSourceFile(ctor) == nullptr || !adding_from_watch_dir_)
|
if (tr_ctorGetSourceFile(ctor) == nullptr || !adding_from_watch_dir_)
|
||||||
|
@ -1115,7 +1116,7 @@ void Session::Impl::add_file_async_callback(
|
||||||
{
|
{
|
||||||
if (!file->load_contents_finish(result, contents, length))
|
if (!file->load_contents_finish(result, contents, length))
|
||||||
{
|
{
|
||||||
auto const errmsg = fmt::format(_("Couldn't read '{path}'"), fmt::arg("path", file->get_parse_name().raw()));
|
auto const errmsg = fmt::format(_("Couldn't read '{path}'"), fmt::arg("path", file->get_parse_name()));
|
||||||
g_message("%s", errmsg.c_str());
|
g_message("%s", errmsg.c_str());
|
||||||
}
|
}
|
||||||
else if (tr_ctorSetMetainfo(ctor, contents, length, nullptr))
|
else if (tr_ctorSetMetainfo(ctor, contents, length, nullptr))
|
||||||
|
@ -1131,8 +1132,8 @@ void Session::Impl::add_file_async_callback(
|
||||||
{
|
{
|
||||||
auto const errmsg = fmt::format(
|
auto const errmsg = fmt::format(
|
||||||
_("Couldn't read '{path}': {error} ({error_code})"),
|
_("Couldn't read '{path}': {error} ({error_code})"),
|
||||||
fmt::arg("path", file->get_parse_name().raw()),
|
fmt::arg("path", file->get_parse_name()),
|
||||||
fmt::arg("error", e.what().raw()),
|
fmt::arg("error", e.what()),
|
||||||
fmt::arg("error_code", e.code()));
|
fmt::arg("error_code", e.code()));
|
||||||
g_message("%s", errmsg.c_str());
|
g_message("%s", errmsg.c_str());
|
||||||
}
|
}
|
||||||
|
@ -1182,7 +1183,8 @@ bool Session::Impl::add_file(Glib::RefPtr<Gio::File> const& file, bool do_start,
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
tr_ctorFree(ctor);
|
tr_ctorFree(ctor);
|
||||||
g_message(_("Skipping unknown torrent \"%s\""), file->get_parse_name().c_str());
|
std::cerr << fmt::format(_("Couldn't add torrent file '{path}'"), fmt::arg("path", file->get_parse_name()))
|
||||||
|
<< std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
return handled;
|
return handled;
|
||||||
|
@ -1457,7 +1459,7 @@ bool gtr_inhibit_hibernation(guint32& cookie)
|
||||||
}
|
}
|
||||||
catch (Glib::Error const& e)
|
catch (Glib::Error const& e)
|
||||||
{
|
{
|
||||||
tr_logAddError(fmt::format(_("Couldn't inhibit desktop hibernation: {error}"), fmt::arg("error", e.what().raw())));
|
tr_logAddError(fmt::format(_("Couldn't inhibit desktop hibernation: {error}"), fmt::arg("error", e.what())));
|
||||||
}
|
}
|
||||||
|
|
||||||
return success;
|
return success;
|
||||||
|
@ -1482,7 +1484,7 @@ void gtr_uninhibit_hibernation(guint inhibit_cookie)
|
||||||
}
|
}
|
||||||
catch (Glib::Error const& e)
|
catch (Glib::Error const& e)
|
||||||
{
|
{
|
||||||
tr_logAddError(fmt::format(_("Couldn't inhibit desktop hibernation: {error}"), fmt::arg("error", e.what().raw())));
|
tr_logAddError(fmt::format(_("Couldn't inhibit desktop hibernation: {error}"), fmt::arg("error", e.what())));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,8 @@
|
||||||
#include <glibmm.h>
|
#include <glibmm.h>
|
||||||
#include <glibmm/i18n.h>
|
#include <glibmm/i18n.h>
|
||||||
|
|
||||||
|
#include <fmt/core.h>
|
||||||
|
|
||||||
#include "HigWorkarea.h"
|
#include "HigWorkarea.h"
|
||||||
#include "PrefsDialog.h"
|
#include "PrefsDialog.h"
|
||||||
#include "Session.h"
|
#include "Session.h"
|
||||||
|
@ -60,6 +62,11 @@ void setLabelFromRatio(Gtk::Label* l, double d)
|
||||||
setLabel(l, tr_strlratio(d));
|
setLabel(l, tr_strlratio(d));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto startedTimesText(uint64_t n)
|
||||||
|
{
|
||||||
|
return fmt::format(ngettext("Started {count:L} time", "Started {count:L} times", n), fmt::arg("count", n));
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
bool StatsDialog::Impl::updateStats()
|
bool StatsDialog::Impl::updateStats()
|
||||||
|
@ -75,10 +82,7 @@ bool StatsDialog::Impl::updateStats()
|
||||||
setLabel(one_time_lb_, tr_strltime(one.secondsActive));
|
setLabel(one_time_lb_, tr_strltime(one.secondsActive));
|
||||||
setLabelFromRatio(one_ratio_lb_, one.ratio);
|
setLabelFromRatio(one_ratio_lb_, one.ratio);
|
||||||
|
|
||||||
setLabel(
|
setLabel(all_sessions_lb_, startedTimesText(all.sessionCount));
|
||||||
all_sessions_lb_,
|
|
||||||
gtr_sprintf(ngettext("Started %'d time", "Started %'d times", (int)all.sessionCount), (int)all.sessionCount));
|
|
||||||
|
|
||||||
setLabel(all_up_lb_, tr_strlsize(all.uploadedBytes));
|
setLabel(all_up_lb_, tr_strlsize(all.uploadedBytes));
|
||||||
setLabel(all_down_lb_, tr_strlsize(all.downloadedBytes));
|
setLabel(all_down_lb_, tr_strlsize(all.downloadedBytes));
|
||||||
setLabel(all_time_lb_, tr_strltime(all.secondsActive));
|
setLabel(all_time_lb_, tr_strltime(all.secondsActive));
|
||||||
|
@ -158,7 +162,7 @@ StatsDialog::Impl::Impl(StatsDialog& dialog, Glib::RefPtr<Session> const& core)
|
||||||
t->add_section_divider(row);
|
t->add_section_divider(row);
|
||||||
t->add_section_title(row, _("Total"));
|
t->add_section_title(row, _("Total"));
|
||||||
|
|
||||||
all_sessions_lb_ = Gtk::make_managed<Gtk::Label>(_("Started %'d time"));
|
all_sessions_lb_ = Gtk::make_managed<Gtk::Label>(startedTimesText(1));
|
||||||
all_sessions_lb_->set_single_line_mode(true);
|
all_sessions_lb_->set_single_line_mode(true);
|
||||||
t->add_label_w(row, *all_sessions_lb_);
|
t->add_label_w(row, *all_sessions_lb_);
|
||||||
++row;
|
++row;
|
||||||
|
|
|
@ -6,10 +6,13 @@
|
||||||
#include <climits> /* INT_MAX */
|
#include <climits> /* INT_MAX */
|
||||||
#include <cstring> // strchr()
|
#include <cstring> // strchr()
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
#include <glibmm.h>
|
#include <glibmm.h>
|
||||||
#include <glibmm/i18n.h>
|
#include <glibmm/i18n.h>
|
||||||
|
|
||||||
|
#include <fmt/core.h>
|
||||||
|
|
||||||
#include <libtransmission/transmission.h>
|
#include <libtransmission/transmission.h>
|
||||||
#include <libtransmission/utils.h> /* tr_truncd() */
|
#include <libtransmission/utils.h> /* tr_truncd() */
|
||||||
|
|
||||||
|
@ -33,7 +36,7 @@ auto const SmallScale = 0.9;
|
||||||
auto const CompactIconSize = Gtk::ICON_SIZE_MENU;
|
auto const CompactIconSize = Gtk::ICON_SIZE_MENU;
|
||||||
auto const FullIconSize = Gtk::ICON_SIZE_DND;
|
auto const FullIconSize = Gtk::ICON_SIZE_DND;
|
||||||
|
|
||||||
Glib::ustring getProgressString(tr_torrent const* tor, uint64_t total_size, tr_stat const* st)
|
auto getProgressString(tr_torrent const* tor, uint64_t total_size, tr_stat const* st)
|
||||||
{
|
{
|
||||||
Glib::ustring gstr;
|
Glib::ustring gstr;
|
||||||
|
|
||||||
|
@ -43,81 +46,56 @@ Glib::ustring getProgressString(tr_torrent const* tor, uint64_t total_size, tr_s
|
||||||
double seedRatio;
|
double seedRatio;
|
||||||
bool const hasSeedRatio = tr_torrentGetSeedRatio(tor, &seedRatio);
|
bool const hasSeedRatio = tr_torrentGetSeedRatio(tor, &seedRatio);
|
||||||
|
|
||||||
if (!isDone) /* downloading */
|
if (!isDone) // downloading
|
||||||
{
|
{
|
||||||
gstr += gtr_sprintf(
|
// 50 MB of 200 MB (25%)
|
||||||
/* %1$s is how much we've got,
|
gstr += fmt::format(
|
||||||
%2$s is how much we'll have when done,
|
_("{current_size} of {complete_size} ({percent_done}%)"),
|
||||||
%3$s%% is a percentage of the two */
|
fmt::arg("current_size", tr_strlsize(haveTotal)),
|
||||||
_("%1$s of %2$s (%3$s%%)"),
|
fmt::arg("complete_size", tr_strlsize(st->sizeWhenDone)),
|
||||||
tr_strlsize(haveTotal),
|
fmt::arg("percent_done", tr_strlpercent(st->percentDone * 100.0)));
|
||||||
tr_strlsize(st->sizeWhenDone),
|
|
||||||
tr_strlpercent(st->percentDone * 100.0));
|
|
||||||
}
|
}
|
||||||
else if (!isSeed) /* partial seeds */
|
else if (!isSeed && hasSeedRatio) // partial seed, seed ratio
|
||||||
{
|
{
|
||||||
if (hasSeedRatio)
|
// 50 MB of 200 MB (25%), uploaded 30 MB (Ratio: X%, Goal: Y%)
|
||||||
{
|
gstr += fmt::format(
|
||||||
gstr += gtr_sprintf(
|
_("{current_size} of {complete_size} ({percent_complete}%), uploaded {uploaded_size} (Ratio: {ratio}, Goal: {seed_ratio})"),
|
||||||
/* %1$s is how much we've got,
|
fmt::arg("current_size", tr_strlsize(haveTotal)),
|
||||||
%2$s is the torrent's total size,
|
fmt::arg("complete_size", tr_strlsize(total_size)),
|
||||||
%3$s%% is a percentage of the two,
|
fmt::arg("percent_done", tr_strlpercent(st->percentComplete * 100.0)),
|
||||||
%4$s is how much we've uploaded,
|
fmt::arg("uploaded_size", tr_strlsize(st->uploadedEver)),
|
||||||
%5$s is our upload-to-download ratio,
|
fmt::arg("ratio", tr_strlratio(st->ratio)),
|
||||||
%6$s is the ratio we want to reach before we stop uploading */
|
fmt::arg("seed_ratio", tr_strlratio(seedRatio)));
|
||||||
_("%1$s of %2$s (%3$s%%), uploaded %4$s (Ratio: %5$s Goal: %6$s)"),
|
|
||||||
tr_strlsize(haveTotal),
|
|
||||||
tr_strlsize(total_size),
|
|
||||||
tr_strlpercent(st->percentComplete * 100.0),
|
|
||||||
tr_strlsize(st->uploadedEver),
|
|
||||||
tr_strlratio(st->ratio),
|
|
||||||
tr_strlratio(seedRatio));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
gstr += gtr_sprintf(
|
|
||||||
/* %1$s is how much we've got,
|
|
||||||
%2$s is the torrent's total size,
|
|
||||||
%3$s%% is a percentage of the two,
|
|
||||||
%4$s is how much we've uploaded,
|
|
||||||
%5$s is our upload-to-download ratio */
|
|
||||||
_("%1$s of %2$s (%3$s%%), uploaded %4$s (Ratio: %5$s)"),
|
|
||||||
tr_strlsize(haveTotal),
|
|
||||||
tr_strlsize(total_size),
|
|
||||||
tr_strlpercent(st->percentComplete * 100.0),
|
|
||||||
tr_strlsize(st->uploadedEver),
|
|
||||||
tr_strlratio(st->ratio));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else /* seeding */
|
else if (!isSeed) // partial seed, no seed ratio
|
||||||
{
|
{
|
||||||
if (hasSeedRatio)
|
gstr += fmt::format(
|
||||||
{
|
_("{current_size} of {complete_size} ({percent_complete}%), uploaded {uploaded_size} (Ratio: {ratio})"),
|
||||||
gstr += gtr_sprintf(
|
fmt::arg("current_size", tr_strlsize(haveTotal)),
|
||||||
/* %1$s is the torrent's total size,
|
fmt::arg("complete_size", tr_strlsize(total_size)),
|
||||||
%2$s is how much we've uploaded,
|
fmt::arg("percent_complete", tr_strlpercent(st->percentComplete * 100.0)),
|
||||||
%3$s is our upload-to-download ratio,
|
fmt::arg("uploaded_size", tr_strlsize(st->uploadedEver)),
|
||||||
%4$s is the ratio we want to reach before we stop uploading */
|
fmt::arg("ratio", tr_strlratio(st->ratio)));
|
||||||
_("%1$s, uploaded %2$s (Ratio: %3$s Goal: %4$s)"),
|
}
|
||||||
tr_strlsize(total_size),
|
else if (hasSeedRatio) // seed, seed ratio
|
||||||
tr_strlsize(st->uploadedEver),
|
{
|
||||||
tr_strlratio(st->ratio),
|
gstr += fmt::format(
|
||||||
tr_strlratio(seedRatio));
|
_("{complete_size}, uploaded {uploaded_size} (Ratio: {ratio}, Goal: {seed_ratio})"),
|
||||||
}
|
fmt::arg("complete_size", tr_strlsize(total_size)),
|
||||||
else /* seeding w/o a ratio */
|
fmt::arg("uploaded_size", tr_strlsize(st->uploadedEver)),
|
||||||
{
|
fmt::arg("ratio", tr_strlratio(st->ratio)),
|
||||||
gstr += gtr_sprintf(
|
fmt::arg("seed_ratio", tr_strlratio(seedRatio)));
|
||||||
/* %1$s is the torrent's total size,
|
}
|
||||||
%2$s is how much we've uploaded,
|
else // seed, no seed ratio
|
||||||
%3$s is our upload-to-download ratio */
|
{
|
||||||
_("%1$s, uploaded %2$s (Ratio: %3$s)"),
|
gstr += fmt::format(
|
||||||
tr_strlsize(total_size),
|
_("{complete_size}, uploaded {uploaded_size} (Ratio: {ratio})"),
|
||||||
tr_strlsize(st->uploadedEver),
|
fmt::arg("complete_size", tr_strlsize(total_size)),
|
||||||
tr_strlratio(st->ratio));
|
fmt::arg("uploaded_size", tr_strlsize(st->uploadedEver)),
|
||||||
}
|
fmt::arg("ratio", tr_strlratio(st->ratio)));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* add time when downloading */
|
// add time remaining when applicable
|
||||||
if (st->activity == TR_STATUS_DOWNLOAD || (hasSeedRatio && st->activity == TR_STATUS_SEED))
|
if (st->activity == TR_STATUS_DOWNLOAD || (hasSeedRatio && st->activity == TR_STATUS_SEED))
|
||||||
{
|
{
|
||||||
int const eta = st->eta;
|
int const eta = st->eta;
|
||||||
|
@ -129,37 +107,32 @@ Glib::ustring getProgressString(tr_torrent const* tor, uint64_t total_size, tr_s
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* time remaining */
|
gstr += fmt::format(_("{time_span} remaining"), fmt::arg("time_span", tr_strltime(eta)));
|
||||||
gstr += gtr_sprintf(_("%s remaining"), tr_strltime(eta));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return gstr;
|
return gstr;
|
||||||
}
|
}
|
||||||
|
|
||||||
Glib::ustring getShortTransferString(
|
std::string getShortTransferString(
|
||||||
tr_torrent const* tor,
|
tr_torrent const* const tor,
|
||||||
tr_stat const* st,
|
tr_stat const* const st,
|
||||||
double uploadSpeed_KBps,
|
double uploadSpeed_KBps,
|
||||||
double downloadSpeed_KBps)
|
double downloadSpeed_KBps)
|
||||||
{
|
{
|
||||||
bool const haveMeta = tr_torrentHasMetadata(tor);
|
bool const have_meta = tr_torrentHasMetadata(tor);
|
||||||
|
|
||||||
if (bool const haveDown = haveMeta && (st->peersSendingToUs > 0 || st->webseedsSendingToUs > 0); haveDown)
|
if (bool const have_down = have_meta && (st->peersSendingToUs > 0 || st->webseedsSendingToUs > 0); have_down)
|
||||||
{
|
{
|
||||||
/* down speed, down symbol, up speed, up symbol */
|
return fmt::format(
|
||||||
return gtr_sprintf(
|
_("{upload_speed} ▲ {download_speed} ▼"),
|
||||||
_("%1$s %2$s %3$s %4$s"),
|
|
||||||
tr_formatter_speed_KBps(downloadSpeed_KBps),
|
tr_formatter_speed_KBps(downloadSpeed_KBps),
|
||||||
gtr_get_unicode_string(GtrUnicode::Down),
|
tr_formatter_speed_KBps(uploadSpeed_KBps));
|
||||||
tr_formatter_speed_KBps(uploadSpeed_KBps),
|
|
||||||
gtr_get_unicode_string(GtrUnicode::Up));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bool const haveUp = haveMeta && st->peersGettingFromUs > 0; haveUp)
|
if (bool const have_up = have_meta && st->peersGettingFromUs > 0; have_up)
|
||||||
{
|
{
|
||||||
/* up speed, up symbol */
|
return fmt::format(_("{upload_speed} ▲"), tr_formatter_speed_KBps(downloadSpeed_KBps));
|
||||||
return gtr_sprintf(_("%1$s %2$s"), tr_formatter_speed_KBps(uploadSpeed_KBps), gtr_get_unicode_string(GtrUnicode::Up));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (st->isStalled)
|
if (st->isStalled)
|
||||||
|
@ -170,151 +143,161 @@ Glib::ustring getShortTransferString(
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
Glib::ustring getShortStatusString(tr_torrent const* tor, tr_stat const* st, double uploadSpeed_KBps, double downloadSpeed_KBps)
|
std::string getShortStatusString(
|
||||||
|
tr_torrent const* const tor,
|
||||||
|
tr_stat const* const st,
|
||||||
|
double uploadSpeed_KBps,
|
||||||
|
double downloadSpeed_KBps)
|
||||||
{
|
{
|
||||||
Glib::ustring gstr;
|
|
||||||
|
|
||||||
switch (st->activity)
|
switch (st->activity)
|
||||||
{
|
{
|
||||||
case TR_STATUS_STOPPED:
|
case TR_STATUS_STOPPED:
|
||||||
gstr += st->finished ? _("Finished") : _("Paused");
|
return st->finished ? _("Finished") : _("Paused");
|
||||||
break;
|
|
||||||
|
|
||||||
case TR_STATUS_CHECK_WAIT:
|
case TR_STATUS_CHECK_WAIT:
|
||||||
gstr += _("Queued for verification");
|
return _("Queued for verification");
|
||||||
break;
|
|
||||||
|
|
||||||
case TR_STATUS_DOWNLOAD_WAIT:
|
case TR_STATUS_DOWNLOAD_WAIT:
|
||||||
gstr += _("Queued for download");
|
return _("Queued for download");
|
||||||
break;
|
|
||||||
|
|
||||||
case TR_STATUS_SEED_WAIT:
|
case TR_STATUS_SEED_WAIT:
|
||||||
gstr += _("Queued for seeding");
|
return _("Queued for seeding");
|
||||||
break;
|
|
||||||
|
|
||||||
case TR_STATUS_CHECK:
|
case TR_STATUS_CHECK:
|
||||||
gstr += gtr_sprintf(_("Verifying local data (%.1f%% tested)"), tr_truncd(st->recheckProgress * 100.0, 1));
|
return fmt::format(
|
||||||
break;
|
_("Verifying local data ({percent_done:.1}% tested)"),
|
||||||
|
fmt::arg("percent_done", tr_truncd(st->recheckProgress * 100.0, 1)));
|
||||||
|
|
||||||
case TR_STATUS_DOWNLOAD:
|
case TR_STATUS_DOWNLOAD:
|
||||||
case TR_STATUS_SEED:
|
case TR_STATUS_SEED:
|
||||||
{
|
return fmt::format(
|
||||||
/* download/upload speed, ratio */
|
"{} {}",
|
||||||
gstr += gtr_sprintf("%s ", getShortTransferString(tor, st, uploadSpeed_KBps, downloadSpeed_KBps));
|
getShortTransferString(tor, st, uploadSpeed_KBps, downloadSpeed_KBps),
|
||||||
gstr += gtr_sprintf(_("Ratio: %s"), tr_strlratio(st->ratio));
|
fmt::format(_("Ratio: {ratio}"), fmt::arg("ratio", tr_strlratio(st->ratio))));
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break;
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
return gstr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Glib::ustring getStatusString(
|
static std::optional<std::string> getErrorString(tr_stat const* st)
|
||||||
|
{
|
||||||
|
switch (st->error)
|
||||||
|
{
|
||||||
|
case TR_STAT_TRACKER_WARNING:
|
||||||
|
return fmt::format(_("Tracker warning: '{warning}'"), fmt::arg("warning", st->errorString));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TR_STAT_TRACKER_ERROR:
|
||||||
|
return fmt::format(_("Tracker Error: '{error}'"), fmt::arg("error", st->errorString));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TR_STAT_LOCAL_ERROR:
|
||||||
|
return fmt::format(_("Local error: '{error}'"), fmt::arg("error", st->errorString));
|
||||||
|
|
||||||
|
default:
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static auto getActivityString(
|
||||||
|
tr_torrent const* const tor,
|
||||||
|
tr_stat const* const st,
|
||||||
|
double const uploadSpeed_KBps,
|
||||||
|
double const downloadSpeed_KBps)
|
||||||
|
{
|
||||||
|
switch (st->activity)
|
||||||
|
{
|
||||||
|
case TR_STATUS_STOPPED:
|
||||||
|
case TR_STATUS_CHECK_WAIT:
|
||||||
|
case TR_STATUS_CHECK:
|
||||||
|
case TR_STATUS_DOWNLOAD_WAIT:
|
||||||
|
case TR_STATUS_SEED_WAIT:
|
||||||
|
return getShortStatusString(tor, st, uploadSpeed_KBps, downloadSpeed_KBps);
|
||||||
|
|
||||||
|
case TR_STATUS_DOWNLOAD:
|
||||||
|
if (!tr_torrentHasMetadata(tor))
|
||||||
|
{
|
||||||
|
return fmt::format(
|
||||||
|
ngettext(
|
||||||
|
"Downloading metadata from {active_count} connected peer ({percent_done:d}% done)",
|
||||||
|
"Downloading metadata from {active_count} connected peers ({percent_done:d}% done)",
|
||||||
|
st->peersConnected),
|
||||||
|
fmt::arg("active_count", st->peersConnected),
|
||||||
|
fmt::arg("percent_done", 100.0 * st->metadataPercentComplete));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (st->peersSendingToUs != 0 && st->webseedsSendingToUs != 0)
|
||||||
|
{
|
||||||
|
return fmt::format(
|
||||||
|
ngettext(
|
||||||
|
"Downloading from {active_count} of {connected_count} connected peer and webseed",
|
||||||
|
"Downloading from {active_count} of {connected_count} connected peers and webseeds",
|
||||||
|
st->peersConnected + st->webseedsSendingToUs),
|
||||||
|
fmt::arg("active_count", st->peersSendingToUs + st->webseedsSendingToUs),
|
||||||
|
fmt::arg("connected_count", st->peersConnected + st->webseedsSendingToUs));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (st->webseedsSendingToUs != 0)
|
||||||
|
{
|
||||||
|
return fmt::format(
|
||||||
|
ngettext(
|
||||||
|
"Downloading from {active_count} webseed",
|
||||||
|
"Downloading from {active_count} webseeds",
|
||||||
|
st->webseedsSendingToUs),
|
||||||
|
fmt::arg("active_count", st->webseedsSendingToUs));
|
||||||
|
}
|
||||||
|
|
||||||
|
return fmt::format(
|
||||||
|
ngettext(
|
||||||
|
"Downloading from {active_count} of {connected_count} connected peer",
|
||||||
|
"Downloading from {active_count} of {connected_count} connected peers",
|
||||||
|
st->peersConnected),
|
||||||
|
fmt::arg("active_count", st->peersSendingToUs),
|
||||||
|
fmt::arg("connected_count", st->peersConnected));
|
||||||
|
|
||||||
|
case TR_STATUS_SEED:
|
||||||
|
return fmt::format(
|
||||||
|
ngettext(
|
||||||
|
"Seeding to {active_count} of {connected_count} connected peer",
|
||||||
|
"Seeding to {active_count} of {connected_count} connected peers",
|
||||||
|
st->peersConnected),
|
||||||
|
fmt::arg("active_count", st->peersGettingFromUs),
|
||||||
|
fmt::arg("connected_count", st->peersConnected));
|
||||||
|
|
||||||
|
default:
|
||||||
|
g_assert_not_reached();
|
||||||
|
return std::string{};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string getStatusString(
|
||||||
tr_torrent const* tor,
|
tr_torrent const* tor,
|
||||||
tr_stat const* st,
|
tr_stat const* st,
|
||||||
double const uploadSpeed_KBps,
|
double const uploadSpeed_KBps,
|
||||||
double const downloadSpeed_KBps)
|
double const downloadSpeed_KBps)
|
||||||
{
|
{
|
||||||
Glib::ustring gstr;
|
auto status_str = std::string{};
|
||||||
|
|
||||||
if (st->error != 0)
|
if (auto error_string = getErrorString(st); error_string)
|
||||||
{
|
{
|
||||||
char const* fmt[] = {
|
status_str = *error_string;
|
||||||
nullptr,
|
|
||||||
N_("Tracker gave a warning: \"%s\""),
|
|
||||||
N_("Tracker gave an error: \"%s\""),
|
|
||||||
N_("Error: %s"),
|
|
||||||
};
|
|
||||||
|
|
||||||
gstr += gtr_sprintf(_(fmt[st->error]), st->errorString);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
switch (st->activity)
|
status_str = getActivityString(tor, st, uploadSpeed_KBps, downloadSpeed_KBps);
|
||||||
{
|
|
||||||
case TR_STATUS_STOPPED:
|
|
||||||
case TR_STATUS_CHECK_WAIT:
|
|
||||||
case TR_STATUS_CHECK:
|
|
||||||
case TR_STATUS_DOWNLOAD_WAIT:
|
|
||||||
case TR_STATUS_SEED_WAIT:
|
|
||||||
{
|
|
||||||
gstr += getShortStatusString(tor, st, uploadSpeed_KBps, downloadSpeed_KBps);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case TR_STATUS_DOWNLOAD:
|
|
||||||
{
|
|
||||||
if (!tr_torrentHasMetadata(tor))
|
|
||||||
{
|
|
||||||
/* Downloading metadata from 2 peer (s)(50% done) */
|
|
||||||
gstr += gtr_sprintf(
|
|
||||||
_("Downloading metadata from %1$'d %2$s (%3$d%% done)"),
|
|
||||||
st->peersConnected,
|
|
||||||
ngettext("peer", "peers", st->peersConnected),
|
|
||||||
(int)(100.0 * st->metadataPercentComplete));
|
|
||||||
}
|
|
||||||
else if (st->peersSendingToUs != 0 && st->webseedsSendingToUs != 0)
|
|
||||||
{
|
|
||||||
/* Downloading from 2 of 3 peer (s) and 2 webseed (s) */
|
|
||||||
gstr += gtr_sprintf(
|
|
||||||
_("Downloading from %1$'d of %2$'d %3$s and %4$'d %5$s"),
|
|
||||||
st->peersSendingToUs,
|
|
||||||
st->peersConnected,
|
|
||||||
ngettext("peer", "peers", st->peersConnected),
|
|
||||||
st->webseedsSendingToUs,
|
|
||||||
ngettext("web seed", "web seeds", st->webseedsSendingToUs));
|
|
||||||
}
|
|
||||||
else if (st->webseedsSendingToUs != 0)
|
|
||||||
{
|
|
||||||
/* Downloading from 3 web seed (s) */
|
|
||||||
gstr += gtr_sprintf(
|
|
||||||
_("Downloading from %1$'d %2$s"),
|
|
||||||
st->webseedsSendingToUs,
|
|
||||||
ngettext("web seed", "web seeds", st->webseedsSendingToUs));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* Downloading from 2 of 3 peer (s) */
|
|
||||||
gstr += gtr_sprintf(
|
|
||||||
_("Downloading from %1$'d of %2$'d %3$s"),
|
|
||||||
st->peersSendingToUs,
|
|
||||||
st->peersConnected,
|
|
||||||
ngettext("peer", "peers", st->peersConnected));
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case TR_STATUS_SEED:
|
|
||||||
gstr += gtr_sprintf(
|
|
||||||
ngettext(
|
|
||||||
"Seeding to %1$'d of %2$'d connected peer",
|
|
||||||
"Seeding to %1$'d of %2$'d connected peers",
|
|
||||||
st->peersConnected),
|
|
||||||
st->peersGettingFromUs,
|
|
||||||
st->peersConnected);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
g_assert_not_reached();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (st->activity != TR_STATUS_CHECK_WAIT && st->activity != TR_STATUS_CHECK && st->activity != TR_STATUS_DOWNLOAD_WAIT &&
|
if (st->activity != TR_STATUS_CHECK_WAIT && st->activity != TR_STATUS_CHECK && st->activity != TR_STATUS_DOWNLOAD_WAIT &&
|
||||||
st->activity != TR_STATUS_SEED_WAIT && st->activity != TR_STATUS_STOPPED)
|
st->activity != TR_STATUS_SEED_WAIT && st->activity != TR_STATUS_STOPPED)
|
||||||
{
|
{
|
||||||
auto const buf = getShortTransferString(tor, st, uploadSpeed_KBps, downloadSpeed_KBps);
|
if (auto const buf = getShortTransferString(tor, st, uploadSpeed_KBps, downloadSpeed_KBps); !std::empty(buf))
|
||||||
|
|
||||||
if (!buf.empty())
|
|
||||||
{
|
{
|
||||||
gstr += gtr_sprintf(" - %s", buf);
|
status_str += fmt::format(" - {}", buf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return gstr;
|
return status_str;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
46
gtk/Utils.cc
46
gtk/Utils.cc
|
@ -100,31 +100,29 @@ Glib::ustring tr_strltime(time_t seconds)
|
||||||
}
|
}
|
||||||
|
|
||||||
auto const days = (int)(seconds / 86400);
|
auto const days = (int)(seconds / 86400);
|
||||||
|
auto const d = fmt::format(ngettext("{days} day", "{days} days", days), fmt::arg("days", days));
|
||||||
int const hours = (seconds % 86400) / 3600;
|
int const hours = (seconds % 86400) / 3600;
|
||||||
int const minutes = (seconds % 3600) / 60;
|
auto const h = fmt::format(ngettext("{hours} hour", "{hours} hours", hours), fmt::arg("hours", hours));
|
||||||
seconds = (seconds % 3600) % 60;
|
|
||||||
|
|
||||||
auto const d = gtr_sprintf(ngettext("%'d day", "%'d days", days), days);
|
|
||||||
auto const h = gtr_sprintf(ngettext("%'d hour", "%'d hours", hours), hours);
|
|
||||||
auto const m = gtr_sprintf(ngettext("%'d minute", "%'d minutes", minutes), minutes);
|
|
||||||
auto const s = gtr_sprintf(ngettext("%'d second", "%'d seconds", (int)seconds), (int)seconds);
|
|
||||||
|
|
||||||
if (days != 0)
|
if (days != 0)
|
||||||
{
|
{
|
||||||
return (days >= 4 || hours == 0) ? d : gtr_sprintf("%s, %s", d, h);
|
return (days >= 4 || hours == 0) ? d : fmt::format("{}, {}", d, h);
|
||||||
}
|
}
|
||||||
else if (hours != 0)
|
|
||||||
|
int const minutes = (seconds % 3600) / 60;
|
||||||
|
auto const m = fmt::format(ngettext("{minutes} minute", "{minutes} minutes", minutes), fmt::arg("minutes", minutes));
|
||||||
|
if (hours != 0)
|
||||||
{
|
{
|
||||||
return (hours >= 4 || minutes == 0) ? h : gtr_sprintf("%s, %s", h, m);
|
return (hours >= 4 || minutes == 0) ? h : fmt::format("{}, {}", h, m);
|
||||||
}
|
}
|
||||||
else if (minutes != 0)
|
|
||||||
|
seconds = (seconds % 3600) % 60;
|
||||||
|
auto const s = fmt::format(ngettext("{seconds} second", "{seconds} seconds", seconds), fmt::arg("seconds", seconds));
|
||||||
|
if (minutes != 0)
|
||||||
{
|
{
|
||||||
return (minutes >= 4 || seconds == 0) ? m : gtr_sprintf("%s, %s", m, s);
|
return (minutes >= 4 || seconds == 0) ? m : fmt::format("{}, {}", m, s);
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return s;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
|
@ -154,14 +152,14 @@ void gtr_add_torrent_error_dialog(Gtk::Widget& child, tr_torrent* duplicate_torr
|
||||||
|
|
||||||
if (duplicate_torrent != nullptr)
|
if (duplicate_torrent != nullptr)
|
||||||
{
|
{
|
||||||
secondary = gtr_sprintf(
|
secondary = fmt::format(
|
||||||
_("The torrent file \"%s\" is already in use by \"%s.\""),
|
_("The torrent file '{path}' is already in use by '{torrent_name}'."),
|
||||||
filename,
|
fmt::arg("path", filename),
|
||||||
tr_torrentName(duplicate_torrent));
|
fmt::arg("torrent_name", tr_torrentName(duplicate_torrent)));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
secondary = gtr_sprintf(_("Unable to add torrent file \"%s\"."), filename);
|
secondary = fmt::format(_("Couldn't add torrent file '{path}'"), fmt::arg("path", filename));
|
||||||
}
|
}
|
||||||
|
|
||||||
auto w = std::make_shared<Gtk::MessageDialog>(
|
auto w = std::make_shared<Gtk::MessageDialog>(
|
||||||
|
@ -452,13 +450,13 @@ void gtr_unrecognized_url_dialog(Gtk::Widget& parent, Glib::ustring const& url)
|
||||||
|
|
||||||
auto w = std::make_shared<Gtk::MessageDialog>(
|
auto w = std::make_shared<Gtk::MessageDialog>(
|
||||||
*window,
|
*window,
|
||||||
fmt::format(_("Unsupported URL: '{url}'"), fmt::arg("url", url.raw())),
|
fmt::format(_("Unsupported URL: '{url}'"), fmt::arg("url", url)),
|
||||||
false /*use markup*/,
|
false /*use markup*/,
|
||||||
Gtk::MESSAGE_ERROR,
|
Gtk::MESSAGE_ERROR,
|
||||||
Gtk::BUTTONS_CLOSE,
|
Gtk::BUTTONS_CLOSE,
|
||||||
true /*modal*/);
|
true /*modal*/);
|
||||||
|
|
||||||
gstr += gtr_sprintf(_("Transmission doesn't know how to use \"%s\""), url);
|
gstr += fmt::format(_("Transmission doesn't know how to use '{url}'"), fmt::arg("url", url));
|
||||||
|
|
||||||
if (tr_magnet_metainfo{}.parseMagnet(url.raw()))
|
if (tr_magnet_metainfo{}.parseMagnet(url.raw()))
|
||||||
{
|
{
|
||||||
|
|
13
gtk/Utils.h
13
gtk/Utils.h
|
@ -14,6 +14,9 @@
|
||||||
#include <glibmm.h>
|
#include <glibmm.h>
|
||||||
#include <gtkmm.h>
|
#include <gtkmm.h>
|
||||||
|
|
||||||
|
#include <fmt/core.h>
|
||||||
|
#include <fmt/format.h>
|
||||||
|
|
||||||
#include <libtransmission/transmission.h>
|
#include <libtransmission/transmission.h>
|
||||||
#include <libtransmission/tr-macros.h>
|
#include <libtransmission/tr-macros.h>
|
||||||
|
|
||||||
|
@ -204,6 +207,16 @@ struct std::hash<Glib::ustring>
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct fmt::formatter<Glib::ustring> : formatter<std::string>
|
||||||
|
{
|
||||||
|
template<typename FormatContext>
|
||||||
|
auto format(Glib::ustring const& ustr, FormatContext& ctx) const
|
||||||
|
{
|
||||||
|
return formatter<std::string>::format(ustr.raw(), ctx);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
namespace Glib
|
namespace Glib
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
|
@ -225,7 +225,7 @@ bool tr_announce_list::canAdd(tr_url_parsed_t const& announce)
|
||||||
|
|
||||||
bool tr_announce_list::save(std::string const& torrent_file, tr_error** error) const
|
bool tr_announce_list::save(std::string const& torrent_file, tr_error** error) const
|
||||||
{
|
{
|
||||||
// load the .torrent file
|
// load the torrent file
|
||||||
auto metainfo = tr_variant{};
|
auto metainfo = tr_variant{};
|
||||||
if (!tr_variantFromFile(&metainfo, TR_VARIANT_PARSE_BENC, std::string{ torrent_file }, error))
|
if (!tr_variantFromFile(&metainfo, TR_VARIANT_PARSE_BENC, std::string{ torrent_file }, error))
|
||||||
{
|
{
|
||||||
|
|
|
@ -101,7 +101,7 @@ bool tr_metaInfoBuilderSetPieceSize(tr_metainfo_builder* builder, uint32_t bytes
|
||||||
void tr_metaInfoBuilderFree(tr_metainfo_builder*);
|
void tr_metaInfoBuilderFree(tr_metainfo_builder*);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief create a new .torrent file
|
* @brief create a new torrent file
|
||||||
*
|
*
|
||||||
* This is actually done in a worker thread, not the main thread!
|
* This is actually done in a worker thread, not the main thread!
|
||||||
* Otherwise the client's interface would lock up while this runs.
|
* Otherwise the client's interface would lock up while this runs.
|
||||||
|
|
|
@ -27,7 +27,7 @@ struct tr_session;
|
||||||
*/
|
*/
|
||||||
void tr_setConfigDir(tr_session* session, std::string_view config_dir);
|
void tr_setConfigDir(tr_session* session, std::string_view config_dir);
|
||||||
|
|
||||||
/** @brief return the directory where .torrent files are stored */
|
/** @brief return the directory where torrent files are stored */
|
||||||
char const* tr_getTorrentDir(tr_session const*);
|
char const* tr_getTorrentDir(tr_session const*);
|
||||||
|
|
||||||
/** @brief return the directory where the Web Client's web ui files are kept */
|
/** @brief return the directory where the Web Client's web ui files are kept */
|
||||||
|
|
|
@ -257,7 +257,7 @@ static bool useNewMetainfo(tr_torrent* tor, tr_incomplete_metadata const* m, tr_
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// yay we have an info dict. Let's make a .torrent file
|
// yay we have an info dict. Let's make a torrent file
|
||||||
auto top_v = tr_variant{};
|
auto top_v = tr_variant{};
|
||||||
tr_buildMetainfoExceptInfoDict(tor->metainfo_, &top_v);
|
tr_buildMetainfoExceptInfoDict(tor->metainfo_, &top_v);
|
||||||
tr_variantMergeDicts(tr_variantDictAddDict(&top_v, TR_KEY_info, 0), &info_dict_v);
|
tr_variantMergeDicts(tr_variantDictAddDict(&top_v, TR_KEY_info, 0), &info_dict_v);
|
||||||
|
@ -265,7 +265,7 @@ static bool useNewMetainfo(tr_torrent* tor, tr_incomplete_metadata const* m, tr_
|
||||||
tr_variantFree(&top_v);
|
tr_variantFree(&top_v);
|
||||||
tr_variantFree(&info_dict_v);
|
tr_variantFree(&info_dict_v);
|
||||||
|
|
||||||
// does this synthetic .torrent file parse?
|
// does this synthetic torrent file parse?
|
||||||
auto metainfo = tr_torrent_metainfo{};
|
auto metainfo = tr_torrent_metainfo{};
|
||||||
if (!metainfo.parseBenc(benc))
|
if (!metainfo.parseBenc(benc))
|
||||||
{
|
{
|
||||||
|
|
|
@ -234,7 +234,7 @@ void tr_sessionClose(tr_session*);
|
||||||
/**
|
/**
|
||||||
* @brief Return the session's configuration directory.
|
* @brief Return the session's configuration directory.
|
||||||
*
|
*
|
||||||
* This is where transmission stores its .torrent files, .resume files,
|
* This is where transmission stores its torrent files, .resume files,
|
||||||
* blocklists, etc. It's set in tr_transmissionInit() and is immutable
|
* blocklists, etc. It's set in tr_transmissionInit() and is immutable
|
||||||
* during the session.
|
* during the session.
|
||||||
*/
|
*/
|
||||||
|
@ -780,7 +780,7 @@ char const* tr_blocklistGetURL(tr_session const*);
|
||||||
/** @} */
|
/** @} */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Instantiating tr_torrents and wrangling .torrent file metadata
|
* Instantiating tr_torrents and wrangling torrent file metadata
|
||||||
*
|
*
|
||||||
* 1. Torrent metadata is handled in the tr_torrent_metadata class.
|
* 1. Torrent metadata is handled in the tr_torrent_metadata class.
|
||||||
*
|
*
|
||||||
|
@ -803,7 +803,7 @@ tr_ctor* tr_ctorNew(tr_session const* session);
|
||||||
/** @brief Free a torrent constructor object */
|
/** @brief Free a torrent constructor object */
|
||||||
void tr_ctorFree(tr_ctor* ctor);
|
void tr_ctorFree(tr_ctor* ctor);
|
||||||
|
|
||||||
/** @brief Set whether or not to delete the source .torrent file
|
/** @brief Set whether or not to delete the source torrent file
|
||||||
when the torrent is added. (Default: False) */
|
when the torrent is added. (Default: False) */
|
||||||
void tr_ctorSetDeleteSource(tr_ctor* ctor, bool doDelete);
|
void tr_ctorSetDeleteSource(tr_ctor* ctor, bool doDelete);
|
||||||
|
|
||||||
|
@ -813,7 +813,7 @@ bool tr_ctorSetMetainfoFromMagnetLink(tr_ctor* ctor, char const* magnet, tr_erro
|
||||||
/** @brief Set the constructor's metainfo from a raw benc already in memory */
|
/** @brief Set the constructor's metainfo from a raw benc already in memory */
|
||||||
bool tr_ctorSetMetainfo(tr_ctor* ctor, char const* metainfo, size_t len, tr_error** error);
|
bool tr_ctorSetMetainfo(tr_ctor* ctor, char const* metainfo, size_t len, tr_error** error);
|
||||||
|
|
||||||
/** @brief Set the constructor's metainfo from a local .torrent file */
|
/** @brief Set the constructor's metainfo from a local torrent file */
|
||||||
bool tr_ctorSetMetainfoFromFile(tr_ctor* ctor, char const* filename, tr_error** error);
|
bool tr_ctorSetMetainfoFromFile(tr_ctor* ctor, char const* filename, tr_error** error);
|
||||||
|
|
||||||
tr_torrent_metainfo const* tr_ctorGetMetainfo(tr_ctor const* ctor);
|
tr_torrent_metainfo const* tr_ctorGetMetainfo(tr_ctor const* ctor);
|
||||||
|
@ -859,10 +859,10 @@ bool tr_ctorGetPaused(tr_ctor const* ctor, tr_ctorMode mode, bool* setmeIsPaused
|
||||||
/** @brief Get the download path from this peer constructor */
|
/** @brief Get the download path from this peer constructor */
|
||||||
bool tr_ctorGetDownloadDir(tr_ctor const* ctor, tr_ctorMode mode, char const** setmeDownloadDir);
|
bool tr_ctorGetDownloadDir(tr_ctor const* ctor, tr_ctorMode mode, char const** setmeDownloadDir);
|
||||||
|
|
||||||
/** @brief Get the "delete .torrent file" flag from this peer constructor */
|
/** @brief Get the "delete torrent file" flag from this peer constructor */
|
||||||
bool tr_ctorGetDeleteSource(tr_ctor const* ctor, bool* setmeDoDelete);
|
bool tr_ctorGetDeleteSource(tr_ctor const* ctor, bool* setmeDoDelete);
|
||||||
|
|
||||||
/** @brief Get the .torrent file that this ctor's metainfo came from,
|
/** @brief Get the torrent file that this ctor's metainfo came from,
|
||||||
or nullptr if tr_ctorSetMetainfoFromFile() wasn't used */
|
or nullptr if tr_ctorSetMetainfoFromFile() wasn't used */
|
||||||
char const* tr_ctorGetSourceFile(tr_ctor const* ctor);
|
char const* tr_ctorGetSourceFile(tr_ctor const* ctor);
|
||||||
|
|
||||||
|
@ -897,7 +897,7 @@ tr_torrent* tr_torrentNew(tr_ctor* ctor, tr_torrent** setme_duplicate_of);
|
||||||
|
|
||||||
using tr_fileFunc = bool (*)(char const* filename, struct tr_error** error);
|
using tr_fileFunc = bool (*)(char const* filename, struct tr_error** error);
|
||||||
|
|
||||||
/** @brief Removes our .torrent and .resume files for this torrent */
|
/** @brief Removes our torrent and .resume files for this torrent */
|
||||||
void tr_torrentRemove(tr_torrent* torrent, bool removeLocalData, tr_fileFunc removeFunc);
|
void tr_torrentRemove(tr_torrent* torrent, bool removeLocalData, tr_fileFunc removeFunc);
|
||||||
|
|
||||||
/** @brief Start a torrent */
|
/** @brief Start a torrent */
|
||||||
|
@ -1443,7 +1443,7 @@ struct tr_torrent_view
|
||||||
struct tr_torrent_view tr_torrentView(tr_torrent const* tor);
|
struct tr_torrent_view tr_torrentView(tr_torrent const* tor);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Get the filename of Transmission's internal copy of the .torrent file.
|
* Get the filename of Transmission's internal copy of the torrent file.
|
||||||
* This is a duplicate that must be freed with tr_free() when done.
|
* This is a duplicate that must be freed with tr_free() when done.
|
||||||
*/
|
*/
|
||||||
char* tr_torrentFilename(tr_torrent const* tor);
|
char* tr_torrentFilename(tr_torrent const* tor);
|
||||||
|
@ -1538,7 +1538,7 @@ struct tr_stat
|
||||||
float percentComplete;
|
float percentComplete;
|
||||||
|
|
||||||
/** How much of the metadata the torrent has.
|
/** How much of the metadata the torrent has.
|
||||||
For torrents added from a .torrent this will always be 1.
|
For torrents added from a torrent this will always be 1.
|
||||||
For magnet links, this number will from from 0 to 1 as the metadata is downloaded.
|
For magnet links, this number will from from 0 to 1 as the metadata is downloaded.
|
||||||
Range is [0..1] */
|
Range is [0..1] */
|
||||||
float metadataPercentComplete;
|
float metadataPercentComplete;
|
||||||
|
|
|
@ -158,7 +158,7 @@ static void tr_watchdir_on_retry_timer(evutil_socket_t /*fd*/, short /*type*/, v
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
tr_logAddWarn(fmt::format(_("Couldn't add .torrent file '{path}'"), fmt::arg("path", retry->name)));
|
tr_logAddWarn(fmt::format(_("Couldn't add torrent file '{path}'"), fmt::arg("path", retry->name)));
|
||||||
}
|
}
|
||||||
|
|
||||||
tr_watchdir_retries_remove(&handle->active_retries, retry);
|
tr_watchdir_retries_remove(&handle->active_retries, retry);
|
||||||
|
|
|
@ -69,7 +69,7 @@ void WatchDir::setPath(QString const& path, bool is_enabled)
|
||||||
{
|
{
|
||||||
watcher_ = std::make_unique<QFileSystemWatcher>(QStringList{ path });
|
watcher_ = std::make_unique<QFileSystemWatcher>(QStringList{ path });
|
||||||
connect(watcher_.get(), &QFileSystemWatcher::directoryChanged, this, &WatchDir::watcherActivated);
|
connect(watcher_.get(), &QFileSystemWatcher::directoryChanged, this, &WatchDir::watcherActivated);
|
||||||
// trigger the watchdir for .torrent files in there already
|
// trigger the watchdir for torrent files in there already
|
||||||
QTimer::singleShot(0, this, SLOT(rescanAllWatchedDirectories()));
|
QTimer::singleShot(0, this, SLOT(rescanAllWatchedDirectories()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -86,7 +86,7 @@ void WatchDir::watcherActivated(QString const& path)
|
||||||
files.insert(str);
|
files.insert(str);
|
||||||
}
|
}
|
||||||
|
|
||||||
// try to add any new files which end in .torrent
|
// try to add any new files which end in torrent
|
||||||
auto const new_files = files - watch_dir_files_;
|
auto const new_files = files - watch_dir_files_;
|
||||||
auto const torrent_suffix = QStringLiteral(".torrent");
|
auto const torrent_suffix = QStringLiteral(".torrent");
|
||||||
|
|
||||||
|
@ -107,7 +107,7 @@ void WatchDir::watcherActivated(QString const& path)
|
||||||
|
|
||||||
case ERROR:
|
case ERROR:
|
||||||
{
|
{
|
||||||
// give the .torrent a few seconds to finish downloading
|
// give the torrent a few seconds to finish downloading
|
||||||
auto* t = new QTimer(this);
|
auto* t = new QTimer(this);
|
||||||
t->setObjectName(dir.absoluteFilePath(name));
|
t->setObjectName(dir.absoluteFilePath(name));
|
||||||
t->setSingleShot(true);
|
t->setSingleShot(true);
|
||||||
|
|
|
@ -338,7 +338,7 @@ TEST_F(AnnounceListTest, save)
|
||||||
};
|
};
|
||||||
auto constexpr Tiers = std::array<tr_tracker_tier_t, 3>{ 0, 1, 2 };
|
auto constexpr Tiers = std::array<tr_tracker_tier_t, 3>{ 0, 1, 2 };
|
||||||
|
|
||||||
// first, set up a scratch .torrent
|
// first, set up a scratch torrent
|
||||||
auto constexpr* const OriginalFile = LIBTRANSMISSION_TEST_ASSETS_DIR "/Android-x86 8.1 r6 iso.torrent";
|
auto constexpr* const OriginalFile = LIBTRANSMISSION_TEST_ASSETS_DIR "/Android-x86 8.1 r6 iso.torrent";
|
||||||
auto original_content = std::vector<char>{};
|
auto original_content = std::vector<char>{};
|
||||||
auto const test_file = tr_strvJoin(::testing::TempDir(), "transmission-announce-list-test.torrent"sv);
|
auto const test_file = tr_strvJoin(::testing::TempDir(), "transmission-announce-list-test.torrent"sv);
|
||||||
|
@ -354,13 +354,13 @@ TEST_F(AnnounceListTest, save)
|
||||||
EXPECT_TRUE(announce_list.add(Urls[1], Tiers[1]));
|
EXPECT_TRUE(announce_list.add(Urls[1], Tiers[1]));
|
||||||
EXPECT_TRUE(announce_list.add(Urls[2], Tiers[2]));
|
EXPECT_TRUE(announce_list.add(Urls[2], Tiers[2]));
|
||||||
|
|
||||||
// try saving to a nonexistent .torrent file
|
// try saving to a nonexistent torrent file
|
||||||
EXPECT_FALSE(announce_list.save("/this/path/does/not/exist", &error));
|
EXPECT_FALSE(announce_list.save("/this/path/does/not/exist", &error));
|
||||||
EXPECT_NE(nullptr, error);
|
EXPECT_NE(nullptr, error);
|
||||||
EXPECT_NE(0, error->code);
|
EXPECT_NE(0, error->code);
|
||||||
tr_error_clear(&error);
|
tr_error_clear(&error);
|
||||||
|
|
||||||
// now save to a real .torrent fi le
|
// now save to a real torrent file
|
||||||
EXPECT_TRUE(announce_list.save(test_file, &error));
|
EXPECT_TRUE(announce_list.save(test_file, &error));
|
||||||
EXPECT_EQ(nullptr, error);
|
EXPECT_EQ(nullptr, error);
|
||||||
|
|
||||||
|
|
|
@ -56,8 +56,8 @@ protected:
|
||||||
EXPECT_FALSE(builder->isFolder);
|
EXPECT_FALSE(builder->isFolder);
|
||||||
EXPECT_FALSE(builder->abortFlag);
|
EXPECT_FALSE(builder->abortFlag);
|
||||||
|
|
||||||
// have tr_makeMetaInfo() build the .torrent file
|
// have tr_makeMetaInfo() build the torrent file
|
||||||
auto const torrent_file = tr_strvJoin(input_file, ".torrent");
|
auto const torrent_file = tr_strvJoin(input_file, ".torrent"sv);
|
||||||
tr_makeMetaInfo(
|
tr_makeMetaInfo(
|
||||||
builder,
|
builder,
|
||||||
torrent_file.c_str(),
|
torrent_file.c_str(),
|
||||||
|
@ -80,7 +80,7 @@ protected:
|
||||||
}
|
}
|
||||||
sync();
|
sync();
|
||||||
|
|
||||||
// now let's check our work: parse the .torrent file
|
// now let's check our work: parse the torrent file
|
||||||
EXPECT_TRUE(metainfo.parseTorrentFile(torrent_file));
|
EXPECT_TRUE(metainfo.parseTorrentFile(torrent_file));
|
||||||
|
|
||||||
// quick check of some of the parsed metainfo
|
// quick check of some of the parsed metainfo
|
||||||
|
@ -147,7 +147,7 @@ protected:
|
||||||
EXPECT_EQ(payload_sizes[i], builder->files[i].size);
|
EXPECT_EQ(payload_sizes[i], builder->files[i].size);
|
||||||
}
|
}
|
||||||
|
|
||||||
// build the .torrent file
|
// build the torrent file
|
||||||
auto torrent_file = tr_strvJoin(top, ".torrent"sv);
|
auto torrent_file = tr_strvJoin(top, ".torrent"sv);
|
||||||
tr_makeMetaInfo(
|
tr_makeMetaInfo(
|
||||||
builder,
|
builder,
|
||||||
|
@ -171,7 +171,7 @@ protected:
|
||||||
EXPECT_TRUE(waitFor(test, 5000));
|
EXPECT_TRUE(waitFor(test, 5000));
|
||||||
sync();
|
sync();
|
||||||
|
|
||||||
// now let's check our work: parse the .torrent file
|
// now let's check our work: parse the torrent file
|
||||||
auto metainfo = tr_torrent_metainfo{};
|
auto metainfo = tr_torrent_metainfo{};
|
||||||
EXPECT_TRUE(metainfo.parseTorrentFile(torrent_file));
|
EXPECT_TRUE(metainfo.parseTorrentFile(torrent_file));
|
||||||
|
|
||||||
|
|
|
@ -38,6 +38,8 @@ protected:
|
||||||
|
|
||||||
SessionTest::SetUp();
|
SessionTest::SetUp();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static auto constexpr MaxWaitMsec = 3000;
|
||||||
};
|
};
|
||||||
|
|
||||||
TEST_P(IncompleteDirTest, incompleteDir)
|
TEST_P(IncompleteDirTest, incompleteDir)
|
||||||
|
@ -110,7 +112,7 @@ TEST_P(IncompleteDirTest, incompleteDir)
|
||||||
{
|
{
|
||||||
return data.done;
|
return data.done;
|
||||||
};
|
};
|
||||||
EXPECT_TRUE(waitFor(test, 1000));
|
EXPECT_TRUE(waitFor(test, MaxWaitMsec));
|
||||||
}
|
}
|
||||||
|
|
||||||
evbuffer_free(data.buf);
|
evbuffer_free(data.buf);
|
||||||
|
|
|
@ -199,7 +199,7 @@ TEST_F(RenameTest, singleFilenameTorrent)
|
||||||
EXPECT_STREQ("foobar", tr_torrentName(tor)); // confirm the torrent's name is now 'foobar'
|
EXPECT_STREQ("foobar", tr_torrentName(tor)); // confirm the torrent's name is now 'foobar'
|
||||||
EXPECT_STREQ("foobar", tr_torrentFile(tor, 0).name); // confirm the file's name is now 'foobar'
|
EXPECT_STREQ("foobar", tr_torrentFile(tor, 0).name); // confirm the file's name is now 'foobar'
|
||||||
char* const torrent_filename = tr_torrentFilename(tor);
|
char* const torrent_filename = tr_torrentFilename(tor);
|
||||||
EXPECT_STREQ(nullptr, strstr(torrent_filename, "foobar")); // confirm .torrent file hasn't changed
|
EXPECT_STREQ(nullptr, strstr(torrent_filename, "foobar")); // confirm torrent file hasn't changed
|
||||||
tr_free(torrent_filename);
|
tr_free(torrent_filename);
|
||||||
tmpstr = tr_strvPath(tor->currentDir().sv(), "foobar");
|
tmpstr = tr_strvPath(tor->currentDir().sv(), "foobar");
|
||||||
EXPECT_TRUE(tr_sys_path_exists(tmpstr.c_str(), nullptr)); // confirm the file's name is now 'foobar' on the disk
|
EXPECT_TRUE(tr_sys_path_exists(tmpstr.c_str(), nullptr)); // confirm the file's name is now 'foobar' on the disk
|
||||||
|
|
|
@ -36,7 +36,7 @@ namespace
|
||||||
auto constexpr TimeoutSecs = long{ 30 };
|
auto constexpr TimeoutSecs = long{ 30 };
|
||||||
|
|
||||||
char constexpr MyName[] = "transmission-show";
|
char constexpr MyName[] = "transmission-show";
|
||||||
char constexpr Usage[] = "Usage: transmission-show [options] <.torrent file>";
|
char constexpr Usage[] = "Usage: transmission-show [options] <torrent-file>";
|
||||||
char constexpr UserAgent[] = "transmission-show/" LONG_VERSION_STRING;
|
char constexpr UserAgent[] = "transmission-show/" LONG_VERSION_STRING;
|
||||||
|
|
||||||
auto options = std::array<tr_option, 5>{
|
auto options = std::array<tr_option, 5>{
|
||||||
|
@ -328,13 +328,13 @@ int tr_main(int argc, char* argv[])
|
||||||
/* make sure the user specified a filename */
|
/* make sure the user specified a filename */
|
||||||
if (std::empty(opts.filename))
|
if (std::empty(opts.filename))
|
||||||
{
|
{
|
||||||
fprintf(stderr, "ERROR: No .torrent file specified.\n");
|
fprintf(stderr, "ERROR: No torrent file specified.\n");
|
||||||
tr_getopt_usage(MyName, Usage, std::data(options));
|
tr_getopt_usage(MyName, Usage, std::data(options));
|
||||||
fprintf(stderr, "\n");
|
fprintf(stderr, "\n");
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* try to parse the .torrent file */
|
/* try to parse the torrent file */
|
||||||
auto metainfo = tr_torrent_metainfo{};
|
auto metainfo = tr_torrent_metainfo{};
|
||||||
tr_error* error = nullptr;
|
tr_error* error = nullptr;
|
||||||
auto const parsed = metainfo.parseTorrentFile(opts.filename, nullptr, &error);
|
auto const parsed = metainfo.parseTorrentFile(opts.filename, nullptr, &error);
|
||||||
|
@ -342,7 +342,7 @@ int tr_main(int argc, char* argv[])
|
||||||
{
|
{
|
||||||
fprintf(
|
fprintf(
|
||||||
stderr,
|
stderr,
|
||||||
"Error parsing .torrent file \"%" TR_PRIsv "\": %s (%d)\n",
|
"Error parsing torrent file \"%" TR_PRIsv "\": %s (%d)\n",
|
||||||
TR_PRIsv_ARG(opts.filename),
|
TR_PRIsv_ARG(opts.filename),
|
||||||
error->message,
|
error->message,
|
||||||
error->code);
|
error->code);
|
||||||
|
|
Loading…
Reference in New Issue