diff --git a/TODO b/TODO index e16cd55e..ae7d0c7f 100644 --- a/TODO +++ b/TODO @@ -11,4 +11,6 @@ Consider basing WindowPeer* on a common base class. Some kind of indication that a tracker request was tried, but won't be allowed since the tracker set a min interval. -Make accumulate return the value, no refs please... \ No newline at end of file +Make accumulate return the value, no refs please... + +!!! Clean up logs at regular intervals. \ No newline at end of file diff --git a/src/core/log.cc b/src/core/log.cc index 5f74f1ed..4d787a8d 100644 --- a/src/core/log.cc +++ b/src/core/log.cc @@ -11,6 +11,9 @@ void Log::push_front(const std::string& msg) { Base::push_front(Type(utils::Timer::cache(), msg)); + if (size() > 50) + Base::pop_back(); + m_signalUpdate.emit(); } diff --git a/src/core/manager.cc b/src/core/manager.cc index 4ebfbf39..9e54aec3 100644 --- a/src/core/manager.cc +++ b/src/core/manager.cc @@ -27,10 +27,15 @@ Manager::initialize() { torrent::initialize(); torrent::listen_open(m_portFirst, m_portLast); + + // Register log signals. } void Manager::cleanup() { + // Need to disconnect log signals? Not really since we won't receive + // any more. + torrent::cleanup(); core::CurlStack::cleanup(); } @@ -101,13 +106,15 @@ Manager::receive_http_done(CurlGet* http) { } catch (torrent::local_error& e) { // What to do? Keep in list for now. - m_log.push_front(e.what()); + m_logImportant.push_front(e.what()); + m_logComplete.push_front(e.what()); } } void Manager::receive_http_failed(std::string msg) { - m_log.push_front("Http download error: \"" + msg + "\""); + m_logImportant.push_front("Http download error: \"" + msg + "\""); + m_logComplete.push_front("Http download error: \"" + msg + "\""); } void @@ -119,7 +126,8 @@ Manager::create_file(const std::string& uri) { } catch (torrent::local_error& e) { // What to do? Keep in list for now. - m_log.push_front(e.what()); + m_logImportant.push_front(e.what()); + m_logComplete.push_front(e.what()); } } @@ -143,6 +151,9 @@ Manager::create_final(std::istream* s) { if (m_debugTracker >= 0) (*itr)->get_download().signal_tracker_dump(sigc::mem_fun(*this, &Manager::receive_debug_tracker)); + // If we want to monitor network stuff. + (*itr)->get_download().signal_network_log(sigc::mem_fun(m_logComplete, &Log::push_front)); + return itr; } diff --git a/src/core/manager.h b/src/core/manager.h index 0e172450..e7d1da05 100644 --- a/src/core/manager.h +++ b/src/core/manager.h @@ -28,7 +28,8 @@ public: HttpQueue& get_http_queue() { return m_httpQueue; } Poll& get_poll() { return m_poll; } - Log& get_log() { return m_log; } + Log& get_log_important() { return m_logImportant; } + Log& get_log_complete() { return m_logComplete; } void initialize(); void cleanup(); @@ -63,7 +64,8 @@ private: HttpQueue m_httpQueue; Poll m_poll; - Log m_log; + Log m_logImportant; + Log m_logComplete; std::string m_dns; int m_portFirst; diff --git a/src/display/Makefile.am b/src/display/Makefile.am index 008c09ec..d69a5276 100644 --- a/src/display/Makefile.am +++ b/src/display/Makefile.am @@ -21,6 +21,8 @@ libsub_display_a_SOURCES = \ window_input.h \ window_log.cc \ window_log.h \ + window_log_complete.cc \ + window_log_complete.h \ window_peer_info.cc \ window_peer_info.h \ window_peer_list.cc \ diff --git a/src/display/manager.cc b/src/display/manager.cc index 64a8587f..000cbd5d 100644 --- a/src/display/manager.cc +++ b/src/display/manager.cc @@ -21,6 +21,11 @@ Manager::erase(Window* w) { return Base::erase(itr); } +Manager::iterator +Manager::find(Window* w) { + return std::find(begin(), end(), w); +} + void Manager::adjust_layout() { int countDynamic = 0; diff --git a/src/display/manager.h b/src/display/manager.h index b3ba1234..0915889e 100644 --- a/src/display/manager.h +++ b/src/display/manager.h @@ -28,6 +28,8 @@ public: iterator erase(Window* w); + iterator find(Window* w); + void adjust_layout(); void do_update(); diff --git a/src/display/window_log.cc b/src/display/window_log.cc index 6c571504..78e9d2c8 100644 --- a/src/display/window_log.cc +++ b/src/display/window_log.cc @@ -1,5 +1,7 @@ #include "config.h" +#include + #include "canvas.h" #include "window_log.h" @@ -12,7 +14,7 @@ WindowLog::WindowLog(core::Log* l) : set_active(false); // We're trying out scheduled tasks instead. - //m_connUpdate = l->signal_update().connect(sigc::mem_fun(*this, &WindowLog::receive_update)); + m_connUpdate = l->signal_update().connect(sigc::mem_fun(*this, &WindowLog::receive_update)); } WindowLog::~WindowLog() { @@ -35,14 +37,23 @@ WindowLog::redraw() { //m_canvas->print(std::max(0, (int)m_canvas->get_width() / 2 - 5), pos++, "*** Log ***"); m_canvas->print(0, 0, "___"); - for (core::Log::iterator itr = m_log->begin(), end = find_older(); itr != end && pos < m_minHeight; ++itr) - m_canvas->print(0, pos++, ": %s", itr->second.c_str()); + for (core::Log::iterator itr = m_log->begin(), end = find_older(); itr != end && pos < m_canvas->get_height(); ++itr) { + std::tm *t = std::localtime(&itr->first.tval().tv_sec); + + if (t == NULL) + m_canvas->print(0, pos++, "(time error) %s", + itr->second.c_str()); + else + m_canvas->print(0, pos++, "(%02i:%02i:%02i) %s", + t->tm_hour, t->tm_min, t->tm_sec, + itr->second.c_str()); + } } void WindowLog::receive_update() { iterator itr = find_older(); - int h = std::distance(m_log->begin(), itr); + int h = std::min(std::distance(m_log->begin(), itr), 10); if (h != m_minHeight) { set_active(h != 0); diff --git a/src/display/window_log_complete.cc b/src/display/window_log_complete.cc new file mode 100644 index 00000000..727ae64e --- /dev/null +++ b/src/display/window_log_complete.cc @@ -0,0 +1,55 @@ +#include "config.h" + +#include + +#include "canvas.h" +#include "window_log_complete.h" + +namespace display { + +WindowLogComplete::WindowLogComplete(core::Log* l) : + Window(new Canvas, true), + m_log(l) { + + // We're trying out scheduled tasks instead. + m_connUpdate = l->signal_update().connect(sigc::mem_fun(*this, &WindowLogComplete::receive_update)); +} + +WindowLogComplete::~WindowLogComplete() { + m_connUpdate.disconnect(); +} + +WindowLogComplete::iterator +WindowLogComplete::find_older() { + return m_log->find_older(utils::Timer::cache() - 60*1000000); +} + +void +WindowLogComplete::redraw() { + m_nextDraw = utils::Timer::max(); + + m_canvas->erase(); + + int pos = 0; + + m_canvas->print(std::max(0, (int)m_canvas->get_width() / 2 - 5), pos++, "*** Log ***"); + + for (core::Log::iterator itr = m_log->begin(), e = m_log->end(); itr != e && pos < m_canvas->get_height(); ++itr) { + std::tm *t = std::localtime(&itr->first.tval().tv_sec); + + if (t == NULL) + m_canvas->print(0, pos++, "(time error) %s", + itr->second.c_str()); + else + m_canvas->print(0, pos++, "(%02i:%02i:%02i) %s", + t->tm_hour, t->tm_min, t->tm_sec, + itr->second.c_str()); + } +} + +void +WindowLogComplete::receive_update() { + mark_dirty(); +} + +} diff --git a/src/display/window_log_complete.h b/src/display/window_log_complete.h new file mode 100644 index 00000000..3c68e96f --- /dev/null +++ b/src/display/window_log_complete.h @@ -0,0 +1,32 @@ +#ifndef RTORRENT_DISPLAY_WINDOW_LOG_COMPLETE_H +#define RTORRENT_DISPLAY_WINDOW_LOG_COMPLETE_H + +#include + +#include "core/log.h" + +#include "window.h" + +namespace display { + +class WindowLogComplete : public Window { +public: + typedef core::Log::iterator iterator; + + WindowLogComplete(core::Log* l); + ~WindowLogComplete(); + + virtual void redraw(); + + void receive_update(); + +private: + inline iterator find_older(); + + core::Log* m_log; + sigc::connection m_connUpdate; +}; + +} + +#endif diff --git a/src/display/window_tracker_list.cc b/src/display/window_tracker_list.cc index 5bd20b52..64af29b0 100644 --- a/src/display/window_tracker_list.cc +++ b/src/display/window_tracker_list.cc @@ -4,6 +4,7 @@ #include "core/download.h" #include "rak/algorithm.h" +#include "utils/parse.h" #include "window_tracker_list.h" @@ -38,18 +39,21 @@ WindowTrackerList::redraw() { Range range = rak::advance_bidirectional(0, *m_focus, m_download->get_download().get_tracker_size(), - m_canvas->get_height()); + (m_canvas->get_height() + 1) / 2); while (range.first != range.second) { torrent::Tracker t = m_download->get_download().get_tracker(range.first); - m_canvas->print(0, pos, "%c %2i %s", + m_canvas->print(0, pos++, "%c %s", range.first == *m_focus ? '*' : ' ', - t.get_group(), t.get_url().c_str()); + m_canvas->print(0, pos++, "%c Group: %2i Id: %s", + range.first == *m_focus ? '*' : ' ', + t.get_group(), + utils::escape_string(t.get_tracker_id()).c_str()); + ++range.first; - ++pos; } } diff --git a/src/ui/download_list.cc b/src/ui/download_list.cc index 0b48fc7d..7d97b2f5 100644 --- a/src/ui/download_list.cc +++ b/src/ui/download_list.cc @@ -13,6 +13,7 @@ #include "display/window_http_queue.h" #include "display/window_input.h" #include "display/window_log.h" +#include "display/window_log_complete.h" #include "display/window_statusbar.h" #include "display/window_title.h" @@ -23,34 +24,35 @@ namespace ui { DownloadList::DownloadList(Control* c) : - m_title(new WTitle("rtorrent " VERSION " - " + torrent::get(torrent::LIBRARY_NAME))), - m_status(new WStatus(&c->get_core())), - m_textInput(new WInput(new input::TextInput)), + m_windowTitle(new WTitle("rtorrent " VERSION " - " + torrent::get(torrent::LIBRARY_NAME))), + m_windowStatus(new WStatus(&c->get_core())), + m_windowTextInput(new WInput(new input::TextInput)), m_windowHttpQueue(new WHttp(&c->get_core().get_http_queue())), m_taskUpdate(sigc::mem_fun(*this, &DownloadList::task_update)), - m_download(NULL), + m_uiDownload(NULL), m_focus(c->get_core().get_download_list().end()), m_control(c), m_bindings(new input::Bindings) { - m_window = new WList(&m_control->get_core().get_download_list(), &m_focus); - m_windowLog = new WLog(&m_control->get_core().get_log()); + m_windowDownloadList = new WList(&m_control->get_core().get_download_list(), &m_focus); + m_windowLog = new WLog(&m_control->get_core().get_log_important()); + m_windowLogComplete = NULL; bind_keys(m_bindings); - m_textInput->get_input()->slot_dirty(sigc::mem_fun(*m_textInput, &WInput::mark_dirty)); + m_windowTextInput->get_input()->slot_dirty(sigc::mem_fun(*m_windowTextInput, &WInput::mark_dirty)); } DownloadList::~DownloadList() { - delete m_window; - delete m_title; - delete m_status; + delete m_windowDownloadList; + delete m_windowTitle; + delete m_windowStatus; delete m_bindings; delete m_windowLog; - delete m_textInput->get_input(); - delete m_textInput; + delete m_windowTextInput->get_input(); + delete m_windowTextInput; delete m_windowHttpQueue; } @@ -58,33 +60,36 @@ void DownloadList::activate() { m_taskUpdate.insert(utils::Timer::cache() + 1000000); - m_textInput->set_active(false); + m_windowTextInput->set_active(false); m_control->get_input().push_front(m_bindings); m_control->get_display().push_back(m_windowLog); 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); - m_control->get_display().push_front(m_title); + m_control->get_display().push_back(m_windowTextInput); + m_control->get_display().push_back(m_windowStatus); + m_control->get_display().push_front(m_windowDownloadList); + m_control->get_display().push_front(m_windowTitle); } void DownloadList::disable() { m_taskUpdate.remove(); - if (m_textInput->is_active()) { - m_textInput->get_input()->clear(); + if (m_windowTextInput->is_active()) { + m_windowTextInput->get_input()->clear(); receive_exit_input(); } + if (m_windowLogComplete != NULL) + receive_toggle_log(); + m_control->get_input().erase(m_bindings); - m_control->get_display().erase(m_title); - 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_windowTitle); + m_control->get_display().erase(m_windowDownloadList); + m_control->get_display().erase(m_windowStatus); + m_control->get_display().erase(m_windowTextInput); m_control->get_display().erase(m_windowLog); m_control->get_display().erase(m_windowHttpQueue); } @@ -111,7 +116,7 @@ DownloadList::receive_prev() { void DownloadList::receive_throttle(int t) { - m_status->mark_dirty(); + m_windowStatus->mark_dirty(); torrent::set(torrent::THROTTLE_ROOT_CONST_RATE, torrent::get(torrent::THROTTLE_ROOT_CONST_RATE) + t * 1024); } @@ -140,25 +145,25 @@ DownloadList::receive_view_download() { if (m_focus == m_control->get_core().get_download_list().end()) return; - if (m_download != NULL) - throw std::logic_error("DownloadList::receive_view_download() called but m_download != NULL"); + if (m_uiDownload != NULL) + throw std::logic_error("DownloadList::receive_view_download() called but m_uiDownload != NULL"); disable(); - m_download = new Download(*m_focus, m_control); + m_uiDownload = new Download(*m_focus, m_control); - m_download->activate(); - m_download->get_bindings()[KEY_LEFT] = sigc::mem_fun(*this, &DownloadList::receive_exit_download); + m_uiDownload->activate(); + m_uiDownload->get_bindings()[KEY_LEFT] = sigc::mem_fun(*this, &DownloadList::receive_exit_download); } void DownloadList::receive_exit_download() { - if (m_download == NULL) - throw std::logic_error("DownloadList::receive_exit_download() called but m_download == NULL"); + if (m_uiDownload == NULL) + throw std::logic_error("DownloadList::receive_exit_download() called but m_uiDownload == NULL"); - m_download->disable(); - delete m_download; - m_download = NULL; + m_uiDownload->disable(); + delete m_uiDownload; + m_uiDownload = NULL; activate(); @@ -167,13 +172,13 @@ DownloadList::receive_exit_download() { void DownloadList::receive_view_input() { - m_status->set_active(false); - m_textInput->set_active(true); + m_windowStatus->set_active(false); + m_windowTextInput->set_active(true); m_control->get_display().adjust_layout(); - m_control->get_input().set_text_input(m_textInput->get_input()); + m_control->get_input().set_text_input(m_windowTextInput->get_input()); - m_textInput->set_focus(true); + m_windowTextInput->set_focus(true); (*m_bindings)['\n'] = sigc::mem_fun(*this, &DownloadList::receive_exit_input); (*m_bindings)[KEY_ENTER] = sigc::mem_fun(*this, &DownloadList::receive_exit_input); @@ -181,21 +186,46 @@ DownloadList::receive_view_input() { void DownloadList::receive_exit_input() { - m_status->set_active(true); - m_textInput->set_active(false); + m_windowStatus->set_active(true); + m_windowTextInput->set_active(false); m_control->get_display().adjust_layout(); m_control->get_input().set_text_input(); - m_slotOpenUri(m_textInput->get_input()->str()); + m_slotOpenUri(m_windowTextInput->get_input()->str()); - m_textInput->get_input()->clear(); - m_textInput->set_focus(false); + m_windowTextInput->get_input()->clear(); + m_windowTextInput->set_focus(false); m_bindings->erase('\n'); m_bindings->erase(KEY_ENTER); } +void +DownloadList::receive_toggle_log() { + if (m_windowLogComplete == NULL) { + display::Manager::iterator itr = m_control->get_display().find(m_windowDownloadList); + + if (itr == m_control->get_display().end()) + throw std::logic_error("ui::DownloadList::receive_toggle_log() could not find download list"); + + *itr = m_windowLogComplete = new WLogComplete(&m_control->get_core().get_log_complete()); + + } else { + display::Manager::iterator itr = m_control->get_display().find(m_windowLogComplete); + + if (itr == m_control->get_display().end()) + throw std::logic_error("ui::DownloadList::receive_toggle_log() could not find download list"); + + *itr = m_windowDownloadList; + + delete m_windowLogComplete; + m_windowLogComplete = NULL; + } + + m_control->get_display().adjust_layout(); +} + void DownloadList::task_update() { m_windowLog->receive_update(); @@ -218,6 +248,7 @@ DownloadList::bind_keys(input::Bindings* b) { (*b)[KEY_UP] = sigc::mem_fun(*this, &DownloadList::receive_prev); (*b)[KEY_DOWN] = sigc::mem_fun(*this, &DownloadList::receive_next); (*b)[KEY_RIGHT] = sigc::mem_fun(*this, &DownloadList::receive_view_download); + (*b)['l'] = sigc::mem_fun(*this, &DownloadList::receive_toggle_log); (*b)['\x7f'] = sigc::mem_fun(*this, &DownloadList::receive_view_input); (*b)[KEY_BACKSPACE] = sigc::mem_fun(*this, &DownloadList::receive_view_input); @@ -225,7 +256,7 @@ DownloadList::bind_keys(input::Bindings* b) { void DownloadList::mark_dirty() { - m_window->mark_dirty(); + m_windowDownloadList->mark_dirty(); } } diff --git a/src/ui/download_list.h b/src/ui/download_list.h index b89f0006..74fb4933 100644 --- a/src/ui/download_list.h +++ b/src/ui/download_list.h @@ -15,6 +15,7 @@ namespace display { class WindowHttpQueue; class WindowInput; class WindowLog; + class WindowLogComplete; class WindowStatusbar; class WindowTitle; } @@ -30,6 +31,7 @@ public: typedef display::WindowHttpQueue WHttp; typedef display::WindowInput WInput; typedef display::WindowLog WLog; + typedef display::WindowLogComplete WLogComplete; typedef display::WindowStatusbar WStatus; typedef display::WindowTitle WTitle; @@ -41,7 +43,7 @@ public: DownloadList(Control* c); ~DownloadList(); - WList& get_window() { return *m_window; } + WList& get_window_download_list() { return *m_windowDownloadList; } input::Bindings& get_bindings() { return *m_bindings; } void activate(); @@ -67,22 +69,26 @@ private: void receive_view_input(); void receive_exit_input(); + void receive_toggle_log(); + void task_update(); void bind_keys(input::Bindings* b); void mark_dirty(); - WList* m_window; - WTitle* m_title; - WStatus* m_status; + WList* m_windowDownloadList; + WTitle* m_windowTitle; + WStatus* m_windowStatus; WLog* m_windowLog; - WInput* m_textInput; + WInput* m_windowTextInput; WHttp* m_windowHttpQueue; + WLogComplete* m_windowLogComplete; + utils::Task m_taskUpdate; - Download* m_download; + Download* m_uiDownload; DList* m_list; DList::iterator m_focus;