forked from premiere/premiere-libtorrent
overhauled client_test. refactored and simplified. still in progress
This commit is contained in:
parent
a6f345181f
commit
a63370f650
|
@ -16,7 +16,7 @@ project client_test
|
|||
<link>static
|
||||
;
|
||||
|
||||
exe client_test : client_test.cpp ;
|
||||
exe client_test : client_test.cpp print.cpp torrent_view.cpp ;
|
||||
|
||||
exe simple_client : simple_client.cpp ;
|
||||
exe stats_counters : stats_counters.cpp ;
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,298 @@
|
|||
#ifdef _WIN32
|
||||
|
||||
#include <windows.h>
|
||||
#include <conio.h>
|
||||
|
||||
#else
|
||||
|
||||
#include <unistd.h> // for close()
|
||||
#include <fcntl.h> // for open()
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#endif
|
||||
|
||||
#include "print.hpp"
|
||||
|
||||
#include <cmath>
|
||||
|
||||
char const* esc(char const* code)
|
||||
{
|
||||
// this is a silly optimization
|
||||
// to avoid copying of strings
|
||||
enum { num_strings = 200 };
|
||||
static char buf[num_strings][20];
|
||||
static int round_robin = 0;
|
||||
char* ret = buf[round_robin];
|
||||
++round_robin;
|
||||
if (round_robin >= num_strings) round_robin = 0;
|
||||
ret[0] = '\033';
|
||||
ret[1] = '[';
|
||||
int i = 2;
|
||||
int j = 0;
|
||||
while (code[j]) ret[i++] = code[j++];
|
||||
ret[i++] = 'm';
|
||||
ret[i++] = 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::string to_string(int v, int width)
|
||||
{
|
||||
char buf[100];
|
||||
snprintf(buf, sizeof(buf), "%*d", width, v);
|
||||
return buf;
|
||||
}
|
||||
|
||||
std::string add_suffix(float val, char const* suffix)
|
||||
{
|
||||
std::string ret;
|
||||
if (val == 0)
|
||||
{
|
||||
ret.resize(4 + 2, ' ');
|
||||
if (suffix) ret.resize(4 + 2 + strlen(suffix), ' ');
|
||||
return ret;
|
||||
}
|
||||
|
||||
const char* prefix[] = {"kB", "MB", "GB", "TB"};
|
||||
const int num_prefix = sizeof(prefix) / sizeof(const char*);
|
||||
for (int i = 0; i < num_prefix; ++i)
|
||||
{
|
||||
val /= 1000.f;
|
||||
if (std::fabs(val) < 1000.f)
|
||||
{
|
||||
ret = to_string(val, 4);
|
||||
ret += prefix[i];
|
||||
if (suffix) ret += suffix;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
ret = to_string(val, 4);
|
||||
ret += "PB";
|
||||
if (suffix) ret += suffix;
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::string color(std::string const& s, color_code c)
|
||||
{
|
||||
if (c == col_none) return s;
|
||||
|
||||
char buf[1024];
|
||||
snprintf(buf, sizeof(buf), "\x1b[3%dm%s\x1b[39m", c, s.c_str());
|
||||
return buf;
|
||||
}
|
||||
|
||||
std::string const& progress_bar(int progress, int width, color_code c
|
||||
, char fill, char bg, std::string caption)
|
||||
{
|
||||
static std::string bar;
|
||||
bar.clear();
|
||||
bar.reserve(width + 10);
|
||||
|
||||
int progress_chars = (progress * width + 500) / 1000;
|
||||
|
||||
if (caption.empty())
|
||||
{
|
||||
char code[10];
|
||||
snprintf(code, sizeof(code), "\x1b[3%dm", c);
|
||||
bar = code;
|
||||
std::fill_n(std::back_inserter(bar), progress_chars, fill);
|
||||
std::fill_n(std::back_inserter(bar), width - progress_chars, bg);
|
||||
bar += esc("39");
|
||||
}
|
||||
else
|
||||
{
|
||||
// foreground color (depends a bit on background color)
|
||||
color_code tc = col_black;
|
||||
if (c == col_black || c == col_blue)
|
||||
tc = col_white;
|
||||
|
||||
caption.resize(width, ' ');
|
||||
|
||||
char str[256];
|
||||
snprintf(str, sizeof(str), "\x1b[4%d;3%dm%s\x1b[48;5;238m\x1b[37m%s\x1b[49;39m"
|
||||
, c, tc, caption.substr(0, progress_chars).c_str(), caption.substr(progress_chars).c_str());
|
||||
bar = str;
|
||||
}
|
||||
return bar;
|
||||
}
|
||||
|
||||
void set_cursor_pos(int x, int y)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
HANDLE out = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
COORD c = {x, y};
|
||||
SetConsoleCursorPosition(out, c);
|
||||
#else
|
||||
printf("\033[%d;%dH", y + 1, x + 1);
|
||||
#endif
|
||||
}
|
||||
|
||||
void clear_screen()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
HANDLE out = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
|
||||
COORD c = {0, 0};
|
||||
CONSOLE_SCREEN_BUFFER_INFO si;
|
||||
GetConsoleScreenBufferInfo(out, &si);
|
||||
DWORD n;
|
||||
FillConsoleOutputCharacter(out, ' ', si.dwSize.X * si.dwSize.Y, c, &n);
|
||||
FillConsoleOutputAttribute(out, 0x7, si.dwSize.X * si.dwSize.Y, c, &n);
|
||||
#else
|
||||
printf("\033[2J");
|
||||
#endif
|
||||
}
|
||||
|
||||
void clear_below(int y)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
HANDLE out = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
|
||||
COORD c = {0, y};
|
||||
SetConsoleCursorPosition(out, c);
|
||||
CONSOLE_SCREEN_BUFFER_INFO si;
|
||||
GetConsoleScreenBufferInfo(out, &si);
|
||||
DWORD n;
|
||||
FillConsoleOutputCharacter(out, ' ', si.dwSize.X * (si.dwSize.Y - y), c, &n);
|
||||
FillConsoleOutputAttribute(out, 0x7, si.dwSize.X * (si.dwSize.Y - y), c, &n);
|
||||
#else
|
||||
printf("\033[%d;1H\033[J", y + 1);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
void terminal_size(int* terminal_width, int* terminal_height)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
HANDLE out = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
CONSOLE_SCREEN_BUFFER_INFO coninfo;
|
||||
if (GetConsoleScreenBufferInfo(out, &coninfo))
|
||||
{
|
||||
*terminal_width = coninfo.dwSize.X;
|
||||
*terminal_height = coninfo.srWindow.Bottom - coninfo.srWindow.Top;
|
||||
#else
|
||||
int tty = open("/dev/tty", O_RDONLY);
|
||||
winsize size;
|
||||
int ret = ioctl(tty, TIOCGWINSZ, (char*)&size);
|
||||
close(tty);
|
||||
if (ret == 0)
|
||||
{
|
||||
*terminal_width = size.ws_col;
|
||||
*terminal_height = size.ws_row;
|
||||
#endif
|
||||
|
||||
if (*terminal_width < 64)
|
||||
*terminal_width = 64;
|
||||
if (*terminal_height < 25)
|
||||
*terminal_height = 25;
|
||||
}
|
||||
else
|
||||
{
|
||||
*terminal_width = 190;
|
||||
*terminal_height = 100;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
void apply_ansi_code(int* attributes, bool* reverse, int code)
|
||||
{
|
||||
const static int color_table[8] =
|
||||
{
|
||||
0, // black
|
||||
FOREGROUND_RED, // red
|
||||
FOREGROUND_GREEN, // green
|
||||
FOREGROUND_RED | FOREGROUND_GREEN, // yellow
|
||||
FOREGROUND_BLUE, // blue
|
||||
FOREGROUND_RED | FOREGROUND_BLUE, // magenta
|
||||
FOREGROUND_BLUE | FOREGROUND_GREEN, // cyan
|
||||
FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE // white
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
foreground_mask = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE,
|
||||
background_mask = BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE
|
||||
};
|
||||
|
||||
const static int fg_mask[2] = {foreground_mask, background_mask};
|
||||
const static int bg_mask[2] = {background_mask, foreground_mask};
|
||||
const static int fg_shift[2] = { 0, 4};
|
||||
const static int bg_shift[2] = { 4, 0};
|
||||
|
||||
if (code == 0)
|
||||
{
|
||||
// reset
|
||||
*attributes = color_table[7];
|
||||
*reverse = false;
|
||||
}
|
||||
else if (code == 7)
|
||||
{
|
||||
if (*reverse) return;
|
||||
*reverse = true;
|
||||
int fg_col = *attributes & foreground_mask;
|
||||
int bg_col = (*attributes & background_mask) >> 4;
|
||||
*attributes &= ~(foreground_mask + background_mask);
|
||||
*attributes |= fg_col << 4;
|
||||
*attributes |= bg_col;
|
||||
}
|
||||
else if (code >= 30 && code <= 37)
|
||||
{
|
||||
// foreground color
|
||||
*attributes &= ~fg_mask[*reverse];
|
||||
*attributes |= color_table[code - 30] << fg_shift[*reverse];
|
||||
}
|
||||
else if (code >= 40 && code <= 47)
|
||||
{
|
||||
// foreground color
|
||||
*attributes &= ~bg_mask[*reverse];
|
||||
*attributes |= color_table[code - 40] << bg_shift[*reverse];
|
||||
}
|
||||
}
|
||||
#endif
|
||||
void print(char const* str)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
HANDLE out = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
|
||||
char* buf = (char*)str;
|
||||
|
||||
int current_attributes = 7;
|
||||
bool reverse = false;
|
||||
SetConsoleTextAttribute(out, current_attributes);
|
||||
|
||||
char* start = buf;
|
||||
DWORD written;
|
||||
while (*buf != 0)
|
||||
{
|
||||
if (*buf == '\033' && buf[1] == '[')
|
||||
{
|
||||
*buf = 0;
|
||||
WriteFile(out, start, buf - start, &written, NULL);
|
||||
buf += 2; // skip escape and '['
|
||||
start = buf;
|
||||
one_more:
|
||||
while (*buf != 'm' && *buf != ';' && *buf != 0) ++buf;
|
||||
if (*buf == 0) break;
|
||||
int code = atoi(start);
|
||||
apply_ansi_code(¤t_attributes, &reverse, code);
|
||||
if (*buf == ';')
|
||||
{
|
||||
++buf;
|
||||
start = buf;
|
||||
goto one_more;
|
||||
}
|
||||
SetConsoleTextAttribute(out, current_attributes);
|
||||
++buf; // skip 'm'
|
||||
start = buf;
|
||||
}
|
||||
else
|
||||
{
|
||||
++buf;
|
||||
}
|
||||
}
|
||||
WriteFile(out, start, buf - start, &written, NULL);
|
||||
|
||||
#else
|
||||
puts(str);
|
||||
#endif
|
||||
}
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
#ifndef PRINT_HPP_
|
||||
#define PRINT_HPP_
|
||||
|
||||
#include <string>
|
||||
|
||||
enum color_code
|
||||
{
|
||||
col_none = -1,
|
||||
col_black = 0,
|
||||
col_red = 1,
|
||||
col_green = 2,
|
||||
col_yellow = 3,
|
||||
col_blue = 4,
|
||||
col_magenta = 5,
|
||||
col_cyan = 6,
|
||||
col_white = 7,
|
||||
};
|
||||
|
||||
char const* esc(char const* code);
|
||||
|
||||
std::string to_string(int v, int width);
|
||||
|
||||
std::string add_suffix(float val, char const* suffix = 0);
|
||||
|
||||
std::string color(std::string const& s, color_code c);
|
||||
|
||||
std::string const& progress_bar(int progress, int width, color_code c = col_green
|
||||
, char fill = '#', char bg = '-', std::string caption = "");
|
||||
|
||||
void set_cursor_pos(int x, int y);
|
||||
|
||||
void clear_screen();
|
||||
|
||||
void clear_below(int y);
|
||||
|
||||
void terminal_size(int* terminal_width, int* terminal_height);
|
||||
|
||||
void print(char const* str);
|
||||
|
||||
#endif // PRINT_HPP_
|
||||
|
|
@ -0,0 +1,386 @@
|
|||
#include "torrent_view.hpp"
|
||||
#include "print.hpp"
|
||||
|
||||
const int header_size = 2;
|
||||
|
||||
std::string torrent_state(lt::torrent_status const& s)
|
||||
{
|
||||
static char const* state_str[] =
|
||||
{"checking (q)", "checking", "dl metadata"
|
||||
, "downloading", "finished", "seeding", "allocating", "checking (r)"};
|
||||
|
||||
if (!s.error.empty()) return s.error;
|
||||
std::string ret;
|
||||
if (s.paused && !s.auto_managed) ret += "paused";
|
||||
else if (s.paused && s.auto_managed) ret += "queued";
|
||||
else if (s.upload_mode) ret += "upload mode";
|
||||
else ret += state_str[s.state];
|
||||
if (!s.paused && !s.auto_managed) ret += " [F]";
|
||||
char buf[10];
|
||||
snprintf(buf, sizeof(buf), " (%.1f%%)", s.progress_ppm / 10000.f);
|
||||
ret += buf;
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool compare_torrent(lt::torrent_status const* lhs, lt::torrent_status const* rhs)
|
||||
{
|
||||
if (lhs->queue_position != -1 && rhs->queue_position != -1)
|
||||
{
|
||||
// both are downloading, sort by queue pos
|
||||
return lhs->queue_position < rhs->queue_position;
|
||||
}
|
||||
else if (lhs->queue_position == -1 && rhs->queue_position == -1)
|
||||
{
|
||||
// both are seeding, sort by seed-rank
|
||||
if (lhs->seed_rank != rhs->seed_rank)
|
||||
return lhs->seed_rank > rhs->seed_rank;
|
||||
|
||||
return lhs->info_hash < rhs->info_hash;
|
||||
}
|
||||
|
||||
return (lhs->queue_position == -1) < (rhs->queue_position == -1);
|
||||
}
|
||||
|
||||
torrent_view::torrent_view()
|
||||
: m_active_torrent(0)
|
||||
, m_scroll_position(0)
|
||||
, m_torrent_filter(0)
|
||||
, m_max_lines(30)
|
||||
{}
|
||||
|
||||
void torrent_view::set_max_size(int height)
|
||||
{
|
||||
m_max_lines = height;
|
||||
}
|
||||
|
||||
int torrent_view::filter() const
|
||||
{
|
||||
return m_torrent_filter;
|
||||
}
|
||||
|
||||
void torrent_view::set_filter(int filter)
|
||||
{
|
||||
if (filter == m_torrent_filter) return;
|
||||
m_torrent_filter = filter;
|
||||
|
||||
update_filtered_torrents();
|
||||
render();
|
||||
}
|
||||
|
||||
// returns the lt::torrent_status of the currently selected torrent.
|
||||
lt::torrent_status const& torrent_view::get_active_torrent() const
|
||||
{
|
||||
if (m_active_torrent >= int(m_filtered_handles.size()))
|
||||
m_active_torrent = int(m_filtered_handles.size()) - 1;
|
||||
if (m_active_torrent < 0) m_active_torrent = 0;
|
||||
TORRENT_ASSERT(m_active_torrent >= 0);
|
||||
|
||||
return *m_filtered_handles[m_active_torrent];
|
||||
}
|
||||
|
||||
lt::torrent_handle torrent_view::get_active_handle() const
|
||||
{
|
||||
if (m_active_torrent >= int(m_filtered_handles.size()))
|
||||
m_active_torrent = int(m_filtered_handles.size()) - 1;
|
||||
if (m_active_torrent < 0) m_active_torrent = 0;
|
||||
TORRENT_ASSERT(m_active_torrent >= 0);
|
||||
|
||||
if (m_filtered_handles.empty()) return lt::torrent_handle();
|
||||
|
||||
return m_filtered_handles[m_active_torrent]->handle;
|
||||
}
|
||||
|
||||
void torrent_view::update_torrents(std::vector<lt::torrent_status> const& st)
|
||||
{
|
||||
std::set<lt::torrent_handle> updates;
|
||||
bool need_filter_update = false;
|
||||
for (std::vector<lt::torrent_status>::const_iterator i = st.begin();
|
||||
i != st.end(); ++i)
|
||||
{
|
||||
boost::unordered_set<lt::torrent_status>::iterator j = m_all_handles.find(*i);
|
||||
// add new entries here
|
||||
if (j == m_all_handles.end())
|
||||
{
|
||||
j = m_all_handles.insert(*i).first;
|
||||
if (show_torrent(*j))
|
||||
{
|
||||
m_filtered_handles.push_back(&*j);
|
||||
need_filter_update = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
bool prev_show = show_torrent(*j);
|
||||
((lt::torrent_status&)*j) = *i;
|
||||
if (prev_show != show_torrent(*j))
|
||||
need_filter_update = true;
|
||||
else
|
||||
updates.insert(i->handle);
|
||||
}
|
||||
}
|
||||
if (need_filter_update)
|
||||
{
|
||||
update_filtered_torrents();
|
||||
render();
|
||||
}
|
||||
else
|
||||
{
|
||||
int torrent_index = 0;
|
||||
int lines_printed = header_size;
|
||||
for (std::vector<lt::torrent_status const*>::iterator i
|
||||
= m_filtered_handles.begin();
|
||||
i != m_filtered_handles.end(); ++torrent_index)
|
||||
{
|
||||
if (torrent_index < m_scroll_position)
|
||||
{
|
||||
++i;
|
||||
continue;
|
||||
}
|
||||
if (lines_printed >= m_max_lines)
|
||||
break;
|
||||
|
||||
lt::torrent_status const& s = **i;
|
||||
if (!s.handle.is_valid())
|
||||
continue;
|
||||
++i;
|
||||
|
||||
if (updates.count(s.handle) == 0)
|
||||
continue;
|
||||
|
||||
set_cursor_pos(0, torrent_index + header_size);
|
||||
print_torrent(s, torrent_index == m_active_torrent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int torrent_view::height() const
|
||||
{
|
||||
return int(m_filtered_handles.size() + header_size);
|
||||
}
|
||||
|
||||
void torrent_view::arrow_up()
|
||||
{
|
||||
if (m_filtered_handles.empty()) return;
|
||||
if (m_active_torrent <= 0) return;
|
||||
|
||||
set_cursor_pos(0, header_size + m_active_torrent - m_scroll_position);
|
||||
print_torrent(*m_filtered_handles[m_active_torrent], false);
|
||||
--m_active_torrent;
|
||||
TORRENT_ASSERT(m_active_torrent >= 0);
|
||||
|
||||
set_cursor_pos(0, header_size + m_active_torrent - m_scroll_position);
|
||||
print_torrent(*m_filtered_handles[m_active_torrent], true);
|
||||
}
|
||||
|
||||
void torrent_view::arrow_down()
|
||||
{
|
||||
if (m_filtered_handles.empty()) return;
|
||||
if (m_active_torrent >= int(m_filtered_handles.size()) - 1) return;
|
||||
|
||||
set_cursor_pos(0, header_size + m_active_torrent - m_scroll_position);
|
||||
print_torrent(*m_filtered_handles[m_active_torrent], false);
|
||||
|
||||
++m_active_torrent;
|
||||
TORRENT_ASSERT(m_active_torrent >= 0);
|
||||
|
||||
set_cursor_pos(0, header_size + m_active_torrent - m_scroll_position);
|
||||
print_torrent(*m_filtered_handles[m_active_torrent], true);
|
||||
}
|
||||
|
||||
void torrent_view::render()
|
||||
{
|
||||
print_tabs();
|
||||
print_headers();
|
||||
|
||||
int lines_printed = header_size;
|
||||
|
||||
// handle scrolling down when moving the cursor
|
||||
// below the fold
|
||||
TORRENT_ASSERT(m_scroll_position >= 0);
|
||||
if (m_active_torrent >= m_max_lines - m_scroll_position)
|
||||
m_scroll_position = m_active_torrent - m_max_lines + 1;
|
||||
TORRENT_ASSERT(m_scroll_position >= 0);
|
||||
if (m_active_torrent < m_scroll_position)
|
||||
m_scroll_position = m_active_torrent;
|
||||
TORRENT_ASSERT(m_scroll_position >= 0);
|
||||
|
||||
int torrent_index = 0;
|
||||
|
||||
for (std::vector<lt::torrent_status const*>::iterator i = m_filtered_handles.begin();
|
||||
i != m_filtered_handles.end(); ++torrent_index)
|
||||
{
|
||||
if (torrent_index < m_scroll_position)
|
||||
{
|
||||
++i;
|
||||
continue;
|
||||
}
|
||||
if (lines_printed >= m_max_lines)
|
||||
{
|
||||
print("...\n");
|
||||
++lines_printed;
|
||||
break;
|
||||
}
|
||||
|
||||
lt::torrent_status const& s = **i;
|
||||
if (!s.handle.is_valid())
|
||||
{
|
||||
i = m_filtered_handles.erase(i);
|
||||
continue;
|
||||
}
|
||||
++i;
|
||||
|
||||
set_cursor_pos(0, torrent_index + header_size);
|
||||
print_torrent(s, torrent_index == m_active_torrent);
|
||||
++lines_printed;
|
||||
}
|
||||
|
||||
clear_below(torrent_index + header_size);
|
||||
}
|
||||
|
||||
void torrent_view::print_tabs()
|
||||
{
|
||||
set_cursor_pos(0, 0);
|
||||
|
||||
char str[400];
|
||||
int pos = 0;
|
||||
char const* filter_names[] = { "all", "downloading", "non-paused"
|
||||
, "seeding", "queued", "stopped", "checking", "loaded"};
|
||||
for (int i = 0; i < int(sizeof(filter_names)/sizeof(filter_names[0])); ++i)
|
||||
{
|
||||
pos += snprintf(str+ pos, sizeof(str) - pos, "%s[%s]%s"
|
||||
, m_torrent_filter == i?esc("7"):""
|
||||
, filter_names[i], m_torrent_filter == i?esc("0"):"");
|
||||
}
|
||||
pos += snprintf(str + pos, sizeof(str) - pos, "\x1b[K");
|
||||
|
||||
print(str);
|
||||
}
|
||||
|
||||
void torrent_view::print_headers()
|
||||
{
|
||||
set_cursor_pos(0, 1);
|
||||
|
||||
char str[400];
|
||||
int pos = 0;
|
||||
|
||||
// print title bar for torrent list
|
||||
pos = snprintf(str, sizeof(str)
|
||||
, " %-3s %-50s %-35s %-17s %-17s %-11s %-6s %-6s %-4s\x1bK"
|
||||
, "#", "Name", "Progress", "Download", "Upload", "Peers (D:S)"
|
||||
, "Down", "Up", "Flags");
|
||||
|
||||
print(str);
|
||||
}
|
||||
|
||||
void torrent_view::print_torrent(lt::torrent_status const& s, bool selected)
|
||||
{
|
||||
int pos = 0;
|
||||
char str[512];
|
||||
|
||||
// the active torrent is highligted in the list
|
||||
// this inverses the forground and background colors
|
||||
char const* selection = "";
|
||||
if (selected)
|
||||
selection = "\x1b[1m\x1b[44m";
|
||||
|
||||
char queue_pos[16] = {0};
|
||||
if (s.queue_position == -1)
|
||||
snprintf(queue_pos, sizeof(queue_pos), "-");
|
||||
else
|
||||
snprintf(queue_pos, sizeof(queue_pos), "%d", s.queue_position);
|
||||
|
||||
std::string name = s.name;
|
||||
if (name.size() > 50) name.resize(50);
|
||||
|
||||
color_code progress_bar_color = col_yellow;
|
||||
if (!s.error.empty()) progress_bar_color = col_red;
|
||||
else if (s.paused) progress_bar_color = col_blue;
|
||||
else if (s.state == lt::torrent_status::downloading_metadata)
|
||||
progress_bar_color = col_magenta;
|
||||
else if (s.current_tracker.empty())
|
||||
progress_bar_color = col_green;
|
||||
|
||||
pos += snprintf(str + pos, sizeof(str) - pos, "%s%c%-3s %-50s %s%s %s (%s) "
|
||||
"%s (%s) %5d:%-5d %s %s %c%s"
|
||||
, selection
|
||||
, s.is_loaded ? 'L' : ' '
|
||||
, queue_pos
|
||||
, name.c_str()
|
||||
, progress_bar(s.progress_ppm / 1000, 35, progress_bar_color, '-', '#', torrent_state(s)).c_str()
|
||||
, selection
|
||||
, color(add_suffix(s.download_rate, "/s"), col_green).c_str()
|
||||
, color(add_suffix(s.total_download), col_green).c_str()
|
||||
, color(add_suffix(s.upload_rate, "/s"), col_red).c_str()
|
||||
, color(add_suffix(s.total_upload), col_red).c_str()
|
||||
, s.num_peers - s.num_seeds, s.num_seeds
|
||||
, color(add_suffix(s.all_time_download), col_green).c_str()
|
||||
, color(add_suffix(s.all_time_upload), col_red).c_str()
|
||||
, s.need_save_resume?'S':' ', esc("0"));
|
||||
|
||||
// if this is the selected torrent, restore the background color
|
||||
if (selected)
|
||||
pos += snprintf(str + pos, sizeof(str) - pos, "%s", esc("0"));
|
||||
|
||||
pos += snprintf(str + pos, sizeof(str) - pos, "\x1b[K");
|
||||
/*
|
||||
// don't print the piece bar if we don't have any piece, or if we have all
|
||||
if (print_piece_bar && s.num_pieces != 0 && s.progress_ppm != 1000000)
|
||||
{
|
||||
out += " ";
|
||||
out += piece_bar(s.pieces, terminal_width - 7);
|
||||
out += "\n";
|
||||
++lines_printed;
|
||||
if (s.seed_mode)
|
||||
{
|
||||
out += " ";
|
||||
out += piece_bar(s.verified_pieces, terminal_width - 7);
|
||||
out += "\n";
|
||||
++lines_printed;
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
print(str);
|
||||
}
|
||||
|
||||
bool torrent_view::show_torrent(lt::torrent_status const& st)
|
||||
{
|
||||
switch (m_torrent_filter)
|
||||
{
|
||||
case torrents_all: return true;
|
||||
case torrents_downloading:
|
||||
return !st.paused
|
||||
&& st.state != lt::torrent_status::seeding
|
||||
&& st.state != lt::torrent_status::finished;
|
||||
case torrents_not_paused: return !st.paused;
|
||||
case torrents_seeding:
|
||||
return !st.paused
|
||||
&& (st.state == lt::torrent_status::seeding
|
||||
|| st.state == lt::torrent_status::finished);
|
||||
case torrents_queued: return st.paused && st.auto_managed;
|
||||
case torrents_stopped: return st.paused && !st.auto_managed;
|
||||
case torrents_checking: return st.state == lt::torrent_status::checking_files;
|
||||
case torrents_loaded: return st.is_loaded;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// refresh all pointers in m_filtered_handles. This must be done when
|
||||
// inserting or removing elements from m_all_handles, since pointers may
|
||||
// be invalidated or when a torrent changes status to either become
|
||||
// visible or filtered
|
||||
void torrent_view::update_filtered_torrents()
|
||||
{
|
||||
m_filtered_handles.clear();
|
||||
for (boost::unordered_set<lt::torrent_status>::iterator i = m_all_handles.begin()
|
||||
, end(m_all_handles.end()); i != end; ++i)
|
||||
{
|
||||
if (!show_torrent(*i)) continue;
|
||||
m_filtered_handles.push_back(&*i);
|
||||
}
|
||||
if (m_active_torrent >= int(m_filtered_handles.size())) m_active_torrent = m_filtered_handles.size() - 1;
|
||||
if (m_active_torrent < 0) m_active_torrent = 0;
|
||||
TORRENT_ASSERT(m_active_torrent >= 0);
|
||||
std::sort(m_filtered_handles.begin(), m_filtered_handles.end(), &compare_torrent);
|
||||
}
|
||||
|
Loading…
Reference in New Issue