From 9e0db66b58ecd1d0653c82febbe28bbdb74b15fc Mon Sep 17 00:00:00 2001 From: rakshasa Date: Fri, 4 Mar 2005 22:00:39 +0000 Subject: [PATCH] Added file view. git-svn-id: svn://rakshasa.no/libtorrent/trunk/rtorrent@322 e378c898-3ddf-0310-93e7-cc216c733640 --- src/display/Makefile.am | 2 + src/display/canvas.h | 18 ++++--- src/display/window_file_list.cc | 83 +++++++++++++++++++++++++++++++++ src/display/window_file_list.h | 34 ++++++++++++++ src/display/window_peer_info.cc | 12 +++-- src/display/window_peer_info.h | 6 --- src/display/window_peer_list.cc | 11 +++-- src/display/window_peer_list.h | 14 +++--- src/main.cc | 15 ++++-- src/ui/Makefile.am | 2 + src/ui/download.cc | 38 +++++++++++---- src/ui/download.h | 8 +++- src/ui/file_list.cc | 65 ++++++++++++++++++++++++++ src/ui/file_list.h | 42 +++++++++++++++++ 14 files changed, 305 insertions(+), 45 deletions(-) create mode 100644 src/display/window_file_list.cc create mode 100644 src/display/window_file_list.h create mode 100644 src/ui/file_list.cc create mode 100644 src/ui/file_list.h diff --git a/src/display/Makefile.am b/src/display/Makefile.am index f093d8df..68eca0b3 100644 --- a/src/display/Makefile.am +++ b/src/display/Makefile.am @@ -13,6 +13,8 @@ libsub_display_a_SOURCES = \ window_download_list.h \ window_download_statusbar.cc \ window_download_statusbar.h \ + window_file_list.cc \ + window_file_list.h \ window_http_queue.cc \ window_http_queue.h \ window_input.cc \ diff --git a/src/display/canvas.h b/src/display/canvas.h index b93392d5..41cc0914 100644 --- a/src/display/canvas.h +++ b/src/display/canvas.h @@ -34,28 +34,32 @@ public: chtype tl, chtype tr, chtype bl, chtype br) { wborder(m_window, ls, rs, ts, bs, tl, tr, bl, br); } - void print(int x, int y, const char* str) { mvwprintw(m_window, y, x, str); } + // The format string is non-const, but that will not be a problem + // since the string shall always be a C string choosen at + // compiletime. Might cause extra copying of the string? + + void print(int x, int y, char* str) { mvwprintw(m_window, y, x, str); } template - void print(int x, int y, const char* str, A1 a1) { mvwprintw(m_window, y, x, str, a1); } + void print(int x, int y, char* str, A1 a1) { mvwprintw(m_window, y, x, str, a1); } template - void print(int x, int y, const char* str, A1 a1, A2 a2) { mvwprintw(m_window, y, x, str, a1, a2); } + void print(int x, int y, char* str, A1 a1, A2 a2) { mvwprintw(m_window, y, x, str, a1, a2); } template - void print(int x, int y, const char* str, + void print(int x, int y, char* str, A1 a1, A2 a2, A3 a3) { mvwprintw(m_window, y, x, str, a1, a2, a3); } template - void print(int x, int y, const char* str, + void print(int x, int y, char* str, A1 a1, A2 a2, A3 a3, A4 a4) { mvwprintw(m_window, y, x, str, a1, a2, a3, a4); } template - void print(int x, int y, const char* str, + void print(int x, int y, char* str, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5) { mvwprintw(m_window, y, x, str, a1, a2, a3, a4, a5); } template - void print(int x, int y, const char* str, + void print(int x, int y, char* str, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6) { mvwprintw(m_window, y, x, str, a1, a2, a3, a4, a5, a6); } void set_attr(int x, int y, int n, int attr, int color) { mvwchgat(m_window, y, x, n, attr, color, NULL); } diff --git a/src/display/window_file_list.cc b/src/display/window_file_list.cc new file mode 100644 index 00000000..e4738fd1 --- /dev/null +++ b/src/display/window_file_list.cc @@ -0,0 +1,83 @@ +#include "config.h" + +#include "core/download.h" + +#include "window_file_list.h" + +namespace display { + +WindowFileList::WindowFileList(core::Download* d, int* focus) : + Window(new Canvas, true), + m_download(d), + m_focus(focus) { +} + +void +WindowFileList::redraw() { + m_nextDraw = utils::Timer::cache().round_seconds() + 10 * 1000000; + m_canvas->erase(); + + int y1 = 0; + int y2 = m_canvas->get_height(); + + m_canvas->print( 2, y1, "File"); + m_canvas->print(55, y1, "Size"); + m_canvas->print(62, y1, "Pri"); + m_canvas->print(67, y1, "Cmpl"); + + ++y1; + + int files = m_download->get_download().get_entry_size(); + int index = std::min(std::max(*m_focus - (y2 - y1) / 2, 0), files - (y2 - y1)); + + while (index < files && y1 < y2) { + torrent::Entry e = m_download->get_download().get_entry(index); + + std::string path = e.get_path(); + + if (path.length() <= 50) + path = path + std::string(50 - path.length(), ' '); + else + path = path.substr(0, 50); + + std::string priority; + + switch (e.get_priority()) { + case torrent::Entry::STOPPED: + priority = "off"; + break; + + case torrent::Entry::NORMAL: + priority = " "; + break; + + case torrent::Entry::HIGH: + priority = "hig"; + break; + + default: + priority = "BUG"; + break; + }; + + m_canvas->print(0, y1, "%c %s %5.1f %s %3d", + index == *m_focus ? '*' : ' ', + path.c_str(), + (double)e.get_size() / (double)(1 << 20), + priority.c_str(), + done_percentage(e)); + + ++index; + ++y1; + } + +} + +int +WindowFileList::done_percentage(torrent::Entry& e) { + int chunks = e.get_chunk_end() - e.get_chunk_begin(); + + return chunks ? (e.get_completed() * 100) / chunks : 100; +} + +} diff --git a/src/display/window_file_list.h b/src/display/window_file_list.h new file mode 100644 index 00000000..30e71578 --- /dev/null +++ b/src/display/window_file_list.h @@ -0,0 +1,34 @@ +#ifndef RTORRENT_DISPLAY_FILE_LIST_H +#define RTORRENT_DISPLAY_FILE_LIST_H + +#include + +#include "window.h" + +namespace torrent { + class Entry; +} + +namespace core { + class Download; +} + +namespace display { + +class WindowFileList : public Window { +public: + WindowFileList(core::Download* d, int* focus); + + virtual void redraw(); + +private: + int done_percentage(torrent::Entry& e); + + core::Download* m_download; + + int* m_focus; +}; + +} + +#endif diff --git a/src/display/window_peer_info.cc b/src/display/window_peer_info.cc index e5520d01..7994b6f4 100644 --- a/src/display/window_peer_info.cc +++ b/src/display/window_peer_info.cc @@ -23,12 +23,13 @@ WindowPeerInfo::redraw() { m_canvas->erase(); int y = 0; + torrent::Download d = m_download->get_download(); - m_canvas->print(0, y++, "Hash: %s", utils::string_to_hex(m_download->get_download().get_hash()).c_str()); + m_canvas->print(0, y++, "Hash: %s", utils::string_to_hex(d.get_hash()).c_str()); m_canvas->print(0, y++, "Chunks: %u / %u * %u", - m_download->get_download().get_chunks_done(), - m_download->get_download().get_chunks_total(), - m_download->get_download().get_chunks_size()); + d.get_chunks_done(), + d.get_chunks_total(), + d.get_chunks_size()); y++; @@ -41,7 +42,8 @@ WindowPeerInfo::redraw() { m_canvas->print(0, y++, "DNS: %s:%hu", (*m_focus)->get_dns().c_str(), (*m_focus)->get_port()); m_canvas->print(0, y++, "Id: %s" , utils::escape_string((*m_focus)->get_id()).c_str()); m_canvas->print(0, y++, "Snubbed: %s", (*m_focus)->get_snubbed() ? "Yes" : "No"); - m_canvas->print(0, y++, "Done: %i%", (*m_focus)->get_chunks_done()); + + m_canvas->print(0, y++, "Done: %i%", d.get_chunks_total() ? (*m_focus)->get_chunks_done() / d.get_chunks_total() : 0); m_canvas->print(0, y++, "Rate: %5.1f/%5.1f KB Total: %.1f/%.1f MB", (double)(*m_focus)->get_rate_up() / (double)(1 << 10), diff --git a/src/display/window_peer_info.h b/src/display/window_peer_info.h index 2695ecc9..27020be4 100644 --- a/src/display/window_peer_info.h +++ b/src/display/window_peer_info.h @@ -2,7 +2,6 @@ #define RTORRENT_DISPLAY_PEER_INFO_H #include -#include #include #include "window.h" @@ -16,12 +15,9 @@ namespace display { class WindowPeerInfo : public Window { public: typedef std::list PList; - typedef sigc::slot0 SlotChunksTotal; WindowPeerInfo(core::Download* d, PList* l, PList::iterator* f); - void slot_chunks_total(SlotChunksTotal s) { m_slotChunksTotal = s; } - virtual void redraw(); private: @@ -29,8 +25,6 @@ private: PList* m_list; PList::iterator* m_focus; - - SlotChunksTotal m_slotChunksTotal; }; } diff --git a/src/display/window_peer_list.cc b/src/display/window_peer_list.cc index aaad5a56..4830626d 100644 --- a/src/display/window_peer_list.cc +++ b/src/display/window_peer_list.cc @@ -2,13 +2,16 @@ #include +#include "core/download.h" + #include "canvas.h" #include "window_peer_list.h" namespace display { -WindowPeerList::WindowPeerList(PList* l, PList::iterator* f) : +WindowPeerList::WindowPeerList(core::Download* d, PList* l, PList::iterator* f) : Window(new Canvas, true), + m_download(d), m_list(l), m_focus(f) { } @@ -59,9 +62,7 @@ WindowPeerList::redraw() { last = m_list->end(); } - uint32_t chunksTotal = m_slotChunksTotal(); - - if (chunksTotal <= 0) + if (m_download->get_download().get_chunks_total() <= 0) throw std::logic_error("WindowPeerList::redraw() m_slotChunksTotal() returned invalid value"); while (itr != m_list->end() && y < m_canvas->get_height()) { @@ -97,7 +98,7 @@ WindowPeerList::redraw() { itr->get_incoming_queue_size()); x += 6; - m_canvas->print(x, y, "%3i", (itr->get_chunks_done() * 100) / chunksTotal); + m_canvas->print(x, y, "%3i", (itr->get_chunks_done() * 100) / m_download->get_download().get_chunks_total()); x += 6; if (itr->get_incoming_queue_size()) diff --git a/src/display/window_peer_list.h b/src/display/window_peer_list.h index 2dc4f738..d32d3742 100644 --- a/src/display/window_peer_list.h +++ b/src/display/window_peer_list.h @@ -2,29 +2,29 @@ #define RTORRENT_DISPLAY_PEER_LIST_H #include -#include #include #include "window.h" +namespace core { + class Download; +} + namespace display { class WindowPeerList : public Window { public: typedef std::list PList; - typedef sigc::slot0 SlotChunksTotal; - WindowPeerList(PList* l, PList::iterator* f); - - void slot_chunks_total(SlotChunksTotal s) { m_slotChunksTotal = s; } + WindowPeerList(core::Download* d, PList* l, PList::iterator* f); virtual void redraw(); private: + core::Download* m_download; + PList* m_list; PList::iterator* m_focus; - - SlotChunksTotal m_slotChunksTotal; }; } diff --git a/src/main.cc b/src/main.cc index e72cbe60..26843fad 100644 --- a/src/main.cc +++ b/src/main.cc @@ -92,6 +92,12 @@ load_arg_torrents(ui::Control* c, char** begin, char** end) { std::for_each(begin, end, std::bind1st(std::mem_fun(&core::Manager::insert), &c->get_core())); } +void +initialize_display(ui::Control* c) { + display::Canvas::init(); + display::Window::slot_adjust(sigc::mem_fun(c->get_display(), &display::Manager::adjust_layout)); +} + void initialize_core(ui::Control* c) { c->get_core().get_poll().slot_read_stdin(sigc::mem_fun(c->get_input(), &input::Manager::pressed)); @@ -115,19 +121,18 @@ main(int argc, char** argv) { int firstArg = parse_options(&uiControl, argc, argv); - display::Canvas::init(); - display::Window::slot_adjust(sigc::mem_fun(uiControl.get_display(), &display::Manager::adjust_layout)); + initialize_display(&uiControl); + initialize_core(&uiControl); uiRoot.init(); - initialize_core(&uiControl); - load_session_torrents(&uiControl); load_arg_torrents(&uiControl, argv + firstArg, argv + argc); uiControl.get_display().adjust_layout(); while (!is_shutting_down || !torrent::get(torrent::SHUTDOWN_DONE)) { + if (uiRoot.get_shutdown_received()) { do_shutdown(&uiControl); uiRoot.set_shutdown_received(false); @@ -188,6 +193,8 @@ void print_help() { std::cout << "Rakshasa's Torrent client. " << std::endl; std::cout << std::endl; + std::cout << "All value pairs (f.ex rate and queue size) will be in the UP/DOWN order." << std::endl; + std::cout << std::endl; std::cout << "Usage: rtorrent [OPTIONS]... [FILE]... [URL]..." << std::endl; std::cout << " -h Display this very helpful text" << std::endl; std::cout << " -i Set the IP address that is sent to the tracker" << std::endl; diff --git a/src/ui/Makefile.am b/src/ui/Makefile.am index 526b8e05..3b2bc95d 100644 --- a/src/ui/Makefile.am +++ b/src/ui/Makefile.am @@ -6,6 +6,8 @@ libsub_ui_a_SOURCES = \ download.h \ download_list.cc \ download_list.h \ + file_list.cc \ + file_list.h \ root.cc \ root.h diff --git a/src/ui/download.cc b/src/ui/download.cc index 14988472..b688eeeb 100644 --- a/src/ui/download.cc +++ b/src/ui/download.cc @@ -14,6 +14,7 @@ #include "control.h" #include "download.h" +#include "file_list.h" namespace ui { @@ -21,6 +22,8 @@ Download::Download(DPtr d, Control* c) : m_download(d), m_state(DISPLAY_NONE), + m_uiFileList(NULL), + m_title(c->get_display().end()), m_window(c->get_display().end()), m_downloadStatus(c->get_display().end()), @@ -57,6 +60,8 @@ Download::activate() { m_downloadStatus = m_control->get_display().insert(m_control->get_display().end(), new WDownloadStatus(m_download)); m_mainStatus = m_control->get_display().insert(m_control->get_display().end(), new WMainStatus(&m_control->get_core())); + m_uiFileList = new FileList(m_control, m_download); + m_control->get_input().push_front(m_bindings); activate_display(DISPLAY_MAIN); @@ -69,15 +74,19 @@ Download::disable() { disable_display(); - delete *m_title; - delete *m_downloadStatus; - delete *m_mainStatus; - m_control->get_display().erase(m_window); m_control->get_display().erase(m_title); m_control->get_display().erase(m_downloadStatus); m_control->get_display().erase(m_mainStatus); + delete *m_title; + delete *m_downloadStatus; + delete *m_mainStatus; + + delete m_uiFileList; + + m_uiFileList = NULL; + m_window = m_title = m_downloadStatus = m_mainStatus = m_control->get_display().end(); m_control->get_input().erase(m_bindings); @@ -93,21 +102,24 @@ Download::activate_display(Display d) { switch (d) { case DISPLAY_MAIN: - *m_window = wpl = new WPeerList(&m_peers, &m_focus); - - wpl->slot_chunks_total(sigc::mem_fun(m_download->get_download(), &torrent::Download::get_chunks_total)); + *m_window = wpl = new WPeerList(m_download, &m_peers, &m_focus); (*m_bindings)[KEY_RIGHT] = sigc::bind(sigc::mem_fun(*this, &Download::receive_change), DISPLAY_PEER); + (*m_bindings)['p'] = sigc::bind(sigc::mem_fun(*this, &Download::receive_change), DISPLAY_FILE_LIST); break; case DISPLAY_PEER: *m_window = wpi = new WPeerInfo(m_download, &m_peers, &m_focus); - wpi->slot_chunks_total(sigc::mem_fun(m_download->get_download(), &torrent::Download::get_chunks_total)); - (*m_bindings)[' '] = sigc::bind(sigc::mem_fun(*this, &Download::receive_change), DISPLAY_MAIN); break; + case DISPLAY_FILE_LIST: + m_uiFileList->activate(m_window); + + (*m_bindings)[' '] = sigc::bind(sigc::mem_fun(*this, &Download::receive_change), DISPLAY_MAIN); + break; + default: throw std::logic_error("ui::Download::activate_display(...) got wrong state"); } @@ -131,10 +143,18 @@ Download::disable_display() { break; + case DISPLAY_FILE_LIST: + m_uiFileList->disable(); + m_bindings->erase(' '); + *m_window = NULL; + + return; + default: break; } + // urgh, get ui's for the rest too. delete *m_window; *m_window = NULL; diff --git a/src/ui/download.h b/src/ui/download.h index 6df324f0..625c67b3 100644 --- a/src/ui/download.h +++ b/src/ui/download.h @@ -8,8 +8,8 @@ namespace display { class WindowTitle; class WindowPeerInfo; - class WindowPeerList; class WindowStatusbar; + class WindowPeerList; class WindowDownloadStatusbar; } @@ -20,6 +20,7 @@ namespace core { namespace ui { class Control; +class FileList; class Download { public: @@ -37,7 +38,8 @@ public: typedef enum { DISPLAY_NONE, DISPLAY_MAIN, - DISPLAY_PEER + DISPLAY_PEER, + DISPLAY_FILE_LIST } Display; // We own 'window'. @@ -79,6 +81,8 @@ private: Display m_state; + FileList* m_uiFileList; + MItr m_title; MItr m_window; MItr m_downloadStatus; diff --git a/src/ui/file_list.cc b/src/ui/file_list.cc new file mode 100644 index 00000000..c0837a32 --- /dev/null +++ b/src/ui/file_list.cc @@ -0,0 +1,65 @@ +#include "config.h" + +#include + +#include "display/window_file_list.h" + +#include "control.h" +#include "file_list.h" + +namespace ui { + +FileList::FileList(Control* c, core::Download* d) : + m_download(d), + m_window(NULL), + m_control(c), + m_focus(0) { + + m_bindings[KEY_DOWN] = sigc::mem_fun(*this, &FileList::receive_next); + m_bindings[KEY_UP] = sigc::mem_fun(*this, &FileList::receive_prev); +} + +void +FileList::activate(MItr mItr) { + if (m_window != NULL) + throw std::logic_error("ui::FileList::activate(...) called on an object in the wrong state"); + + m_control->get_input().push_front(&m_bindings); + + *mItr = m_window = new WFileList(m_download, &m_focus); +} + +void +FileList::disable() { + if (m_window == NULL) + throw std::logic_error("ui::FileList::disable(...) called on an object in the wrong state"); + + m_control->get_input().erase(&m_bindings); + + delete m_window; + m_window = NULL; +} + +void +FileList::receive_next() { + if (m_window == NULL) + throw std::logic_error("ui::FileList::receive_next(...) called on a disabled object"); + + if (++m_focus >= (int)m_download->get_download().get_entry_size()) + m_focus = 0; + + m_window->mark_dirty(); +} + +void +FileList::receive_prev() { + if (m_window == NULL) + throw std::logic_error("ui::FileList::receive_prev(...) called on a disabled object"); + + if (--m_focus < 0) + m_focus = std::max(0, (int)m_download->get_download().get_entry_size() - 1); + + m_window->mark_dirty(); +} + +} diff --git a/src/ui/file_list.h b/src/ui/file_list.h new file mode 100644 index 00000000..d4decfe5 --- /dev/null +++ b/src/ui/file_list.h @@ -0,0 +1,42 @@ +#ifndef RTORRENT_UI_FILE_LIST_H +#define RTORRENT_UI_FILE_LIST_H + +#include "core/download.h" +#include "display/manager.h" +#include "input/bindings.h" + +namespace display { + class WindowFileList; +} + +namespace ui { + +class Control; + +class FileList { +public: + typedef display::WindowFileList WFileList; + typedef display::Manager::iterator MItr; + + FileList(Control* c, core::Download* d); + + void activate(MItr mItr); + void disable(); + +private: + void receive_next(); + void receive_prev(); + + core::Download* m_download; + WFileList* m_window; + + Control* m_control; + input::Bindings m_bindings; + + // Change to unsigned, please. + int m_focus; +}; + +} + +#endif