From 78d3d78ef3ae4433b0cc4d4a1be2ecb88b9986f6 Mon Sep 17 00:00:00 2001 From: rakshasa Date: Thu, 17 Feb 2005 21:20:18 +0000 Subject: [PATCH] Improved the http progress display, includes truncated names, download progress and 10 second delay on hiding. git-svn-id: svn://rakshasa.no/libtorrent/trunk/rtorrent@286 e378c898-3ddf-0310-93e7-cc216c733640 --- TODO | 5 ++ src/core/curl_get.cc | 17 +++++ src/core/curl_get.h | 3 + src/core/http_queue.cc | 11 ++- src/core/http_queue.h | 22 +++--- src/core/manager.cc | 4 +- src/core/manager.h | 2 +- src/core/poll.h | 12 ++-- src/display/Makefile.am | 2 + src/display/window_http_queue.cc | 120 +++++++++++++++++++++++++++++++ src/display/window_http_queue.h | 57 +++++++++++++++ src/main.cc | 4 +- src/ui/download_list.cc | 12 +++- src/ui/download_list.h | 12 ++-- 14 files changed, 254 insertions(+), 29 deletions(-) create mode 100644 src/display/window_http_queue.cc create mode 100644 src/display/window_http_queue.h diff --git a/TODO b/TODO index 91617605..90e91232 100644 --- a/TODO +++ b/TODO @@ -3,3 +3,8 @@ up. Polling during last phase of shutdown should be very quick, don't use normal timeout. + +Make clear distinction of upload/download throttle. + +"Caught exception: "Tried to add an existing DownloadMain to DownloadManager"" +Properly handle duplicate torrents. diff --git a/src/core/curl_get.cc b/src/core/curl_get.cc index f67623b4..638989a2 100644 --- a/src/core/curl_get.cc +++ b/src/core/curl_get.cc @@ -58,6 +58,23 @@ CurlGet::close() { m_handle = NULL; } + +double +CurlGet::get_size_done() { + double d = 0.0; + curl_easy_getinfo(m_handle, CURLINFO_SIZE_DOWNLOAD, &d); + + return d; +} + +double +CurlGet::get_size_total() { + double d = 0.0; + curl_easy_getinfo(m_handle, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &d); + + return d; +} + void CurlGet::perform(CURLMsg* msg) { if (msg->msg != CURLMSG_DONE) diff --git a/src/core/curl_get.h b/src/core/curl_get.h index 88afc718..5642a1bb 100644 --- a/src/core/curl_get.h +++ b/src/core/curl_get.h @@ -25,6 +25,9 @@ class CurlGet : public torrent::Http { bool is_busy() { return m_handle; } + double get_size_done(); + double get_size_total(); + protected: CURL* handle() { return m_handle; } diff --git a/src/core/http_queue.cc b/src/core/http_queue.cc index 5cd1adc3..a4fc59ea 100644 --- a/src/core/http_queue.cc +++ b/src/core/http_queue.cc @@ -2,6 +2,7 @@ #include #include +#include #include #include #include @@ -14,7 +15,7 @@ namespace core { HttpQueue::iterator HttpQueue::insert(const std::string& url) { - std::auto_ptr h(m_slotFactory()); + std::auto_ptr h(m_slotFactory()); std::auto_ptr s(new std::stringstream); h->set_url(url); @@ -31,11 +32,15 @@ HttpQueue::insert(const std::string& url) { h.release(); s.release(); + m_signalInsert.emit(*itr); + return itr; } void HttpQueue::erase(iterator itr) { + m_signalErase.emit(*itr); + delete (*itr)->get_stream(); delete *itr; @@ -44,8 +49,8 @@ HttpQueue::erase(iterator itr) { void HttpQueue::clear() { - std::for_each(begin(), end(), func::on(func::call_delete(), std::mem_fun(&CurlGet::get_stream))); - std::for_each(begin(), end(), func::call_delete()); + while (!empty()) + erase(begin()); Base::clear(); } diff --git a/src/core/http_queue.h b/src/core/http_queue.h index 27fe30e5..3e4820b2 100644 --- a/src/core/http_queue.h +++ b/src/core/http_queue.h @@ -3,18 +3,17 @@ #include #include -#include - -namespace torrent { - class Http; -} +#include namespace core { -class HttpQueue : private std::list { +class CurlGet; + +class HttpQueue : private std::list { public: - typedef std::list Base; - typedef sigc::slot0 SlotFactory; + typedef std::list Base; + typedef sigc::signal1 SignalHttp; + typedef sigc::slot0 SlotFactory; using Base::iterator; using Base::const_iterator; @@ -29,7 +28,7 @@ public: using Base::empty; using Base::size; - // Note that any slots connected to the torrent::Http signals must be + // Note that any slots connected to the CurlGet signals must be // pushed in front of the erase slot added by HttpQueue::insert. iterator insert(const std::string& url); void erase(iterator itr); @@ -38,8 +37,13 @@ public: void slot_factory(SlotFactory s) { m_slotFactory = s; } + SignalHttp& signal_insert() { return m_signalInsert; } + SignalHttp& signal_erase() { return m_signalErase; } + private: SlotFactory m_slotFactory; + SignalHttp m_signalInsert; + SignalHttp m_signalErase; }; } diff --git a/src/core/manager.cc b/src/core/manager.cc index 6b495b17..2e0644ba 100644 --- a/src/core/manager.cc +++ b/src/core/manager.cc @@ -6,10 +6,10 @@ #include #include #include -#include #include #include "manager.h" +#include "curl_get.h" namespace core { @@ -95,7 +95,7 @@ Manager::create_http(const std::string& uri) { } void -Manager::receive_http_done(torrent::Http* http) { +Manager::receive_http_done(CurlGet* http) { DownloadList::iterator itr = m_downloadList.end(); try { diff --git a/src/core/manager.h b/src/core/manager.h index 5744117c..4865f335 100644 --- a/src/core/manager.h +++ b/src/core/manager.h @@ -29,7 +29,7 @@ public: void stop(Download* d); private: - void receive_http_done(torrent::Http* http); + void receive_http_done(CurlGet* http); void create_file(const std::string& uri); void create_http(const std::string& uri); diff --git a/src/core/poll.h b/src/core/poll.h index 498bdf36..9301f120 100644 --- a/src/core/poll.h +++ b/src/core/poll.h @@ -6,17 +6,15 @@ #include "curl_stack.h" -namespace torrent { - class Http; -} - namespace core { +class CurlGet; + class Poll { public: - typedef sigc::slot0 Slot; - typedef sigc::slot1 SlotInt; - typedef sigc::slot0 SlotFactory; + typedef sigc::slot0 Slot; + typedef sigc::slot1 SlotInt; + typedef sigc::slot0 SlotFactory; Poll() : m_readSet(new fd_set), m_writeSet(new fd_set), m_exceptSet(new fd_set) {} ~Poll() { delete m_readSet; delete m_writeSet; delete m_exceptSet; } diff --git a/src/display/Makefile.am b/src/display/Makefile.am index 233f8bc4..a7ca100c 100644 --- a/src/display/Makefile.am +++ b/src/display/Makefile.am @@ -13,6 +13,8 @@ libsub_display_a_SOURCES = \ window_download_statusbar.h \ window_download_list.cc \ window_download_list.h \ + window_http_queue.cc \ + window_http_queue.h \ window_input.cc \ window_input.h \ window_peer_info.cc \ diff --git a/src/display/window_http_queue.cc b/src/display/window_http_queue.cc new file mode 100644 index 00000000..177c02ec --- /dev/null +++ b/src/display/window_http_queue.cc @@ -0,0 +1,120 @@ +#include "config.h" + +#include + +#include "core/curl_get.h" +#include "core/http_queue.h" + +#include "canvas.h" +#include "functional.h" +#include "window_http_queue.h" + +namespace display { + +WindowHttpQueue::WindowHttpQueue(core::HttpQueue* q) : + Window(new Canvas, false, 1), + m_queue(q) { + + set_active(false); + m_connInsert = m_queue->signal_insert().connect(sigc::mem_fun(*this, &WindowHttpQueue::receive_insert)); + m_connErase = m_queue->signal_erase().connect(sigc::mem_fun(*this, &WindowHttpQueue::receive_erase)); +} + +void +WindowHttpQueue::redraw() { + if (Timer::cache() - m_lastDraw < 1000000) + return; + + m_lastDraw = Timer::cache(); + + cleanup_list(); + + if (m_container.empty()) { + set_active(false); + m_slotAdjust(); + + return; + } + + m_canvas->erase(); + m_canvas->print(0, 0, "Http [%2i]", m_container.size()); + + int pos = 10; + Container::iterator itr = m_container.begin(); + + while (itr != m_container.end() && pos + 20 < m_canvas->get_width()) { + if (itr->m_http == NULL) + m_canvas->print(pos, 0, "%s done", itr->m_name.c_str()); + + else if (itr->m_http->get_size_total() == 0) + m_canvas->print(pos, 0, "%s ---%%", itr->m_name.c_str()); + + else + m_canvas->print(pos, 0, "%s %3i%%", + itr->m_name.c_str(), + (int)(100.0 * itr->m_http->get_size_done() / itr->m_http->get_size_total())); + + pos += itr->m_name.size() + 6; + ++itr; + } +} + +void +WindowHttpQueue::cleanup_list() { + for (Container::iterator itr = m_container.begin(); itr != m_container.end();) + if (itr->m_http == NULL && itr->m_timer < Timer::cache()) + itr = m_container.erase(itr); + else + ++itr; + + mark_dirty(); +} + +std::string +WindowHttpQueue::create_name(core::CurlGet* h) { + std::string n = h->get_url().substr(h->get_url().rfind('/', h->get_url().size() - std::min((size_t)10, h->get_url().size()))); + + if (n.empty()) + throw std::logic_error("WindowHttpQueue::create_name(...) made a bad string"); + + if (n.size() > 2 && n[0] == '/') + n = n.substr(1); + + if (n.size() > 9 && + (n.substr(n.size() - 8) == ".torrent" || + n.substr(n.size() - 8) == ".TORRENT")) + n = n.substr(0, n.size() - 8); + + if (n.size() > 20) + n = n.substr(0, 20); + + return n; +} + +void +WindowHttpQueue::receive_insert(core::CurlGet* h) { + m_container.push_back(Node(h, create_name(h))); + + if (!is_active()) { + set_active(true); + m_slotAdjust(); + } + + mark_dirty(); +} + +void +WindowHttpQueue::receive_erase(core::CurlGet* h) { + Container::iterator itr = std::find_if(m_container.begin(), m_container.end(), + func::equal(h, std::mem_fun_ref(&Node::get_http))); + + if (itr == m_container.end()) + throw std::logic_error("WindowHttpQueue::receive_erase(...) tried to remove an object we don't have"); + + itr->m_http = NULL; + itr->m_timer = Timer::cache() + 10000000; + + mark_dirty(); +} + +} diff --git a/src/display/window_http_queue.h b/src/display/window_http_queue.h new file mode 100644 index 00000000..ec6da5d7 --- /dev/null +++ b/src/display/window_http_queue.h @@ -0,0 +1,57 @@ +#ifndef RTORRENT_DISPLAY_WINDOW_HTTP_QUEUE_H +#define RTORRENT_DISPLAY_WINDOW_HTTP_QUEUE_H + +#include +#include + +#include "window.h" + +namespace core { + class CurlGet; + class HttpQueue; +} + +namespace display { + +class WindowHttpQueue : public Window { +public: + typedef sigc::slot0 Slot; + + WindowHttpQueue(core::HttpQueue* q); + ~WindowHttpQueue() { m_connInsert.disconnect(); m_connErase.disconnect(); } + + void slot_adjust(Slot s) { m_slotAdjust = s; } + + virtual void redraw(); + +private: + struct Node { + Node(core::CurlGet* h, const std::string& n) : m_http(h), m_name(n) {} + + core::CurlGet* get_http() { return m_http; } + + core::CurlGet* m_http; + std::string m_name; + Timer m_timer; + }; + + typedef std::list Container; + + void cleanup_list(); + + void receive_insert(core::CurlGet* h); + void receive_erase(core::CurlGet* h); + + static std::string create_name(core::CurlGet* h); + + core::HttpQueue* m_queue; + Slot m_slotAdjust; + sigc::connection m_connInsert; + sigc::connection m_connErase; + + Container m_container; +}; + +} + +#endif diff --git a/src/main.cc b/src/main.cc index 955608ee..27e15231 100644 --- a/src/main.cc +++ b/src/main.cc @@ -61,6 +61,8 @@ do_shutdown(ui::Control* c) { std::mem_fun_ref(&core::Download::close)); } + + start_shutdown = false; } void @@ -124,7 +126,7 @@ main(int argc, char** argv) { uiControl.get_display().adjust_layout(); while (!is_shutting_down || !torrent::get(torrent::SHUTDOWN_DONE)) { - if (start_shutdown && !is_shutting_down) + if (start_shutdown) do_shutdown(&uiControl); Timer::update(); diff --git a/src/ui/download_list.cc b/src/ui/download_list.cc index 7bea5180..e2134dc5 100644 --- a/src/ui/download_list.cc +++ b/src/ui/download_list.cc @@ -6,10 +6,12 @@ #include "input/bindings.h" #include "input/text_input.h" -#include "display/window_title.h" + #include "display/window_download_list.h" -#include "display/window_statusbar.h" +#include "display/window_http_queue.h" #include "display/window_input.h" +#include "display/window_statusbar.h" +#include "display/window_title.h" #include "control.h" #include "download.h" @@ -21,6 +23,8 @@ DownloadList::DownloadList(Control* c) : m_title(new WTitle("rtorrent " VERSION " - " + torrent::get(torrent::LIBRARY_NAME))), m_status(new WStatus), m_textInput(new WInput(new input::TextInput)), + m_windowHttpQueue(new WHttp(&c->get_core().get_http_queue())), + m_download(NULL), m_focus(c->get_core().get_download_list().end()), m_control(c), @@ -31,6 +35,7 @@ DownloadList::DownloadList(Control* c) : bind_keys(m_bindings); m_textInput->get_input()->slot_dirty(sigc::mem_fun(*m_textInput, &WInput::mark_dirty)); + m_windowHttpQueue->slot_adjust(sigc::mem_fun(c->get_display(), &display::Manager::adjust_layout)); } DownloadList::~DownloadList() { @@ -41,6 +46,7 @@ DownloadList::~DownloadList() { delete m_textInput->get_input(); delete m_textInput; + delete m_windowHttpQueue; } void @@ -49,6 +55,7 @@ DownloadList::activate() { m_control->get_input().push_front(m_bindings); + m_control->get_display().push_back(m_windowHttpQueue); m_control->get_display().push_back(m_textInput); m_control->get_display().push_back(m_status); m_control->get_display().push_front(m_window); @@ -68,6 +75,7 @@ DownloadList::disable() { m_control->get_display().erase(m_window); m_control->get_display().erase(m_status); m_control->get_display().erase(m_textInput); + m_control->get_display().erase(m_windowHttpQueue); } void diff --git a/src/ui/download_list.h b/src/ui/download_list.h index c26f6e94..e33ee2c9 100644 --- a/src/ui/download_list.h +++ b/src/ui/download_list.h @@ -4,10 +4,11 @@ #include namespace display { - class WindowTitle; class WindowDownloadList; - class WindowStatusbar; + class WindowHttpQueue; class WindowInput; + class WindowStatusbar; + class WindowTitle; } namespace ui { @@ -18,9 +19,11 @@ class Download; class DownloadList { public: typedef display::WindowDownloadList WList; - typedef display::WindowTitle WTitle; - typedef display::WindowStatusbar WStatus; + typedef display::WindowHttpQueue WHttp; typedef display::WindowInput WInput; + typedef display::WindowStatusbar WStatus; + typedef display::WindowTitle WTitle; + typedef core::DownloadList DList; typedef sigc::slot1 SlotOpenUri; @@ -63,6 +66,7 @@ private: WTitle* m_title; WStatus* m_status; WInput* m_textInput; + WHttp* m_windowHttpQueue; Download* m_download;