diff --git a/src/command_download.cc b/src/command_download.cc index d55be354..668b1676 100644 --- a/src/command_download.cc +++ b/src/command_download.cc @@ -431,6 +431,8 @@ initialize_command_download() { ADD_CD_F_VOID("start", rak::make_mem_fun(control->core()->download_list(), &core::DownloadList::start_normal)); ADD_CD_F_VOID("stop", rak::make_mem_fun(control->core()->download_list(), &core::DownloadList::stop_normal)); + ADD_CD_F_VOID("resume", rak::make_mem_fun(control->core()->download_list(), &core::DownloadList::resume_default)); + ADD_CD_F_VOID("pause", rak::make_mem_fun(control->core()->download_list(), &core::DownloadList::pause_default)); ADD_CD_F_VOID("open", rak::make_mem_fun(control->core()->download_list(), &core::DownloadList::open_throw)); ADD_CD_F_VOID("close", rak::make_mem_fun(control->core()->download_list(), &core::DownloadList::close_throw)); ADD_CD_F_VOID("erase", rak::make_mem_fun(control->core()->download_list(), &core::DownloadList::erase_ptr)); diff --git a/src/command_events.cc b/src/command_events.cc index 836600f3..e4c0e9d3 100644 --- a/src/command_events.cc +++ b/src/command_events.cc @@ -73,7 +73,7 @@ apply_on_state_change(core::DownloadList::slot_map* slotMap, const torrent::Obje if (args.size() == 1) slotMap->erase(key); else - (*slotMap)[key] = sigc::bind(sigc::ptr_fun(&rpc::parse_command_d_multiple_std), args.back().as_string()); + (*slotMap)[key] = args.back().as_string(); return torrent::Object(); } diff --git a/src/command_helpers.h b/src/command_helpers.h index b659d641..e22c4875 100644 --- a/src/command_helpers.h +++ b/src/command_helpers.h @@ -179,9 +179,12 @@ add_variable(key, NULL, NULL, &rpc::CommandVariable::get_string, NULL, std::stri commandDownloadSlotsItr->set_slot(slot); \ rpc::commands.insert_type(key, commandDownloadSlotsItr++, &rpc::CommandSlot::function, rpc::CommandMap::flag_dont_delete | rpc::CommandMap::flag_public_xmlrpc, parm, doc); -#define CMD_D_ANY_NONE(key, slot) \ +#define CMD_D_ANY(key, slot) \ CMD_D_SLOT(key, call_unknown, slot, "i:", "") +#define CMD_D_STRING(key, slot) \ + CMD_D_SLOT(key, call_string, slot, "i:", "") + #define CMD_D_VOID(key, slot) \ CMD_D_SLOT(key, call_unknown, rpc::object_fn(slot), "i:", "") diff --git a/src/command_ui.cc b/src/command_ui.cc index 5a45f388..7db7f2c3 100644 --- a/src/command_ui.cc +++ b/src/command_ui.cc @@ -385,6 +385,13 @@ cmd_ui_unfocus_download(core::Download* download, const torrent::Object& rawArgs return torrent::Object(); } +torrent::Object +cmd_view_filter_download(core::Download* download, const torrent::Object& rawArgs) { + (*control->view_manager()->find_throw(rawArgs.as_string()))->filter_download(download); + + return torrent::Object(); +} + void initialize_command_ui() { ADD_VARIABLE_STRING("key_layout", "qwerty"); @@ -403,10 +410,14 @@ initialize_command_ui() { ADD_COMMAND_LIST("view_event_added", rak::bind_ptr_fn(&apply_view_cfilter, &core::ViewManager::set_event_added)); ADD_COMMAND_LIST("view_event_removed", rak::bind_ptr_fn(&apply_view_cfilter, &core::ViewManager::set_event_removed)); + // Cleanup and add . to view. + + CMD_D_STRING("view.filter_download", rak::ptr_fn(&cmd_view_filter_download)); + // Commands that affect the default rtorrent UI. // ADD_ANY_NONE("ui.focus", rak::ptr_fn(&cmd_ui_focus)); - CMD_D_ANY_NONE("ui.unfocus_download", rak::ptr_fn(&cmd_ui_unfocus_download)); + CMD_D_ANY("ui.unfocus_download", rak::ptr_fn(&cmd_ui_unfocus_download)); // Move. diff --git a/src/core/download_list.cc b/src/core/download_list.cc index fb1cb753..fca9cbe2 100644 --- a/src/core/download_list.cc +++ b/src/core/download_list.cc @@ -77,7 +77,7 @@ struct download_list_call { void operator () (const DownloadList::slot_map::value_type& s) { try { - s.second(m_download); + rpc::parse_command_d_multiple_std(m_download, s.second); } catch (torrent::input_error& e) { control->core()->push_log((std::string("Download event action failed: ") + e.what()).c_str()); } @@ -166,6 +166,11 @@ DownloadList::insert(Download* download) { (*itr)->download()->signal_download_done(sigc::bind(sigc::mem_fun(*this, &DownloadList::received_finished), download)); (*itr)->download()->signal_hash_done(sigc::bind(sigc::mem_fun(*this, &DownloadList::hash_done), download)); + // This needs to be separated into two different calls to ensure + // the download remains in the view. + std::for_each(control->view_manager()->begin(), control->view_manager()->end(), std::bind2nd(std::mem_fun(&View::insert), download)); + std::for_each(control->view_manager()->begin(), control->view_manager()->end(), std::bind2nd(std::mem_fun(&View::filter_download), download)); + std::for_each(slot_map_insert().begin(), slot_map_insert().end(), download_list_call(*itr)); } catch (torrent::local_error& e) { @@ -195,6 +200,7 @@ DownloadList::erase(iterator itr) { control->core()->download_store()->remove(*itr); std::for_each(slot_map_erase().begin(), slot_map_erase().end(), download_list_call(*itr)); + std::for_each(control->view_manager()->begin(), control->view_manager()->end(), std::bind2nd(std::mem_fun(&View::erase), *itr)); torrent::download_remove(*(*itr)->download()); delete *itr; @@ -246,6 +252,10 @@ DownloadList::close_try(Download* download) { return false; rpc::call_command("d.set_state", (int64_t)0, rpc::make_target(download)); + + (*control->view_manager()->find_throw("started"))->set_not_visible(download); + (*control->view_manager()->find_throw("stopped"))->set_visible(download); + close_throw(download); return true; @@ -319,8 +329,6 @@ DownloadList::start_normal(Download* download) { (*control->view_manager()->find_throw("stopped"))->set_not_visible(download); (*control->view_manager()->find_throw("started"))->set_visible(download); - - resume(download); } bool @@ -340,7 +348,6 @@ DownloadList::start_try(Download* download) { (*control->view_manager()->find_throw("stopped"))->set_not_visible(download); (*control->view_manager()->find_throw("started"))->set_visible(download); - resume(download); return true; } @@ -352,8 +359,6 @@ DownloadList::stop_normal(Download* download) { (*control->view_manager()->find_throw("started"))->set_not_visible(download); (*control->view_manager()->find_throw("stopped"))->set_visible(download); - - pause(download); } bool @@ -368,7 +373,6 @@ DownloadList::stop_try(Download* download) { (*control->view_manager()->find_throw("started"))->set_not_visible(download); (*control->view_manager()->find_throw("stopped"))->set_visible(download); - pause(download); return true; } diff --git a/src/core/download_list.h b/src/core/download_list.h index ee0855ff..87585204 100644 --- a/src/core/download_list.h +++ b/src/core/download_list.h @@ -59,9 +59,8 @@ class Download; class DownloadList : private std::list { public: - typedef std::list base_type; - typedef sigc::slot1 slot_type; - typedef std::map slot_map; + typedef std::list base_type; + typedef std::map slot_map; using base_type::iterator; using base_type::const_iterator; @@ -117,6 +116,7 @@ public: void resume(Download* d, int flags = 0); void pause(Download* d, int flags = 0); + void resume_default(Download* d) { resume(d); } void pause_default(Download* d) { pause(d); } void check_hash(Download* d); diff --git a/src/core/manager.cc b/src/core/manager.cc index 3a61d97a..399d7d8b 100644 --- a/src/core/manager.cc +++ b/src/core/manager.cc @@ -212,8 +212,8 @@ Manager::initialize_second() { // Register slots to be called when a download is inserted/erased, // opened or closed. - m_downloadList->slot_map_insert()["1_connect_logs"] = sigc::bind(&rpc::parse_command_d_single_std, "d.initialize_logs="); - m_downloadList->slot_map_erase()["9_delete_tied"] = sigc::bind(&rpc::parse_command_d_single_std, "d.delete_tied="); + m_downloadList->slot_map_insert()["1_connect_logs"] = "d.initialize_logs="; + m_downloadList->slot_map_erase()["9_delete_tied"] = "d.delete_tied="; torrent::connection_manager()->set_signal_handshake_log(sigc::mem_fun(this, &Manager::handshake_log)); } diff --git a/src/core/view.cc b/src/core/view.cc index 9f2d1c24..785c3bcf 100644 --- a/src/core/view.cc +++ b/src/core/view.cc @@ -51,92 +51,6 @@ namespace core { -View::~View() { - if (m_name.empty()) - return; - - std::for_each(m_list->slot_map_begin(), m_list->slot_map_end(), rak::bind2nd(std::ptr_fun(&DownloadList::erase_key), "0_view_" + m_name)); -} - -void -View::initialize(const std::string& name, core::DownloadList* dlist) { - if (!m_name.empty()) - throw torrent::internal_error("View::initialize(...) called on an already initialized view."); - - if (name.empty()) - throw torrent::internal_error("View::initialize(...) called with an empty name."); - - std::string key = "0_view_" + name; - - if (dlist->has_slot_insert(key) || dlist->has_slot_erase(key)) - throw torrent::internal_error("View::initialize(...) duplicate key name found in DownloadList."); - - m_name = name; - m_list = dlist; - - // Urgh, wrong. No filtering being done. - std::for_each(m_list->begin(), m_list->end(), rak::bind1st(std::mem_fun(&View::push_back), this)); - - m_size = base_type::size(); - m_focus = 0; - - m_list->slot_map_insert()[key] = sigc::bind(sigc::mem_fun(this, &View::received), (int)DownloadList::SLOTS_INSERT); - m_list->slot_map_erase()[key] = sigc::bind(sigc::mem_fun(this, &View::received), (int)DownloadList::SLOTS_ERASE); - - set_last_changed(rak::timer()); -} - -void -View::set_visible(Download* download) { - iterator itr = std::find(begin_filtered(), end_filtered(), download); - - if (itr == end_filtered()) - return; - - // Don't optimize erase since we want to keep the order of the - // non-visible elements. - base_type::erase(itr); - insert_visible(download); - - rpc::parse_command_multiple_d_nothrow(download, m_eventAdded); -} - -void -View::set_not_visible(Download* download) { - iterator itr = std::find(begin_visible(), end_visible(), download); - - if (itr == end_visible()) - return; - - // Don't optimize erase since we want to keep the order of the - // non-visible elements. - base_type::erase(itr); - base_type::push_back(download); - - rpc::parse_command_multiple_d_nothrow(download, m_eventRemoved); -} - -void -View::next_focus() { - if (empty()) - return; - - m_focus = (m_focus + 1) % (size() + 1); - m_signalChanged.emit(); -} - -void -View::prev_focus() { - if (empty()) - return; - - m_focus = (m_focus - 1 + size() + 1) % (size() + 1); - m_signalChanged.emit(); -} - -// Need to use wrapper-functors so it will properly call the virtual -// functions. - // Also add focus thingie here? struct view_downloads_compare : std::binary_function { view_downloads_compare(const std::string& cmd) : m_command(cmd) {} @@ -188,6 +102,117 @@ struct view_downloads_filter : std::unary_function { const std::string& m_command; }; +View::~View() { + if (m_name.empty()) + return; + + std::for_each(m_list->slot_map_begin(), m_list->slot_map_end(), rak::bind2nd(std::ptr_fun(&DownloadList::erase_key), "0_view_" + m_name)); +} + +void +View::initialize(const std::string& name, core::DownloadList* dlist) { + if (!m_name.empty()) + throw torrent::internal_error("View::initialize(...) called on an already initialized view."); + + if (name.empty()) + throw torrent::internal_error("View::initialize(...) called with an empty name."); + + std::string key = "0_view_" + name; + + if (dlist->has_slot_insert(key) || dlist->has_slot_erase(key)) + throw torrent::internal_error("View::initialize(...) duplicate key name found in DownloadList."); + + m_name = name; + m_list = dlist; + + // Urgh, wrong. No filtering being done. + std::for_each(m_list->begin(), m_list->end(), rak::bind1st(std::mem_fun(&View::push_back), this)); + + m_size = base_type::size(); + m_focus = 0; + + set_last_changed(rak::timer()); +} + +void +View::insert(Download* download) { +// if (view_downloads_filter(m_filter)(download)) { +// insert_visible(download); +// rpc::parse_command_multiple_d_nothrow(download, m_eventAdded); + +// } else { +// base_type::insert(end_filtered(), download); +// } + + // We can't make the download visible until after it has been added + // to every single View, as it might trigger a command too early. + base_type::insert(base_type::end(), download); +} + +void +View::erase(Download* download) { + iterator itr = std::find(base_type::begin(), base_type::end(), download); + + if (itr >= end_visible()) { + erase_internal(itr); + + } else { + erase_internal(itr); + rpc::parse_command_multiple_d_nothrow(download, m_eventRemoved); + } +} + +void +View::set_visible(Download* download) { + iterator itr = std::find(begin_filtered(), end_filtered(), download); + + if (itr == end_filtered()) + return; + + // Don't optimize erase since we want to keep the order of the + // non-visible elements. + base_type::erase(itr); + insert_visible(download); + + rpc::parse_command_multiple_d_nothrow(download, m_eventAdded); +} + +void +View::set_not_visible(Download* download) { + iterator itr = std::find(begin_visible(), end_visible(), download); + + if (itr == end_visible()) + return; + + m_size--; + m_focus -= (m_focus > position(itr)); + + // Don't optimize erase since we want to keep the order of the + // non-visible elements. + base_type::erase(itr); + base_type::push_back(download); + + rpc::parse_command_multiple_d_nothrow(download, m_eventRemoved); +} + +void +View::next_focus() { + if (empty()) + return; + + m_focus = (m_focus + 1) % (size() + 1); + m_signalChanged.emit(); +} + +void +View::prev_focus() { + if (empty()) + return; + + m_focus = (m_focus - 1 + size() + 1) % (size() + 1); + m_signalChanged.emit(); +} + void View::sort() { Download* curFocus = focus() != end_visible() ? *focus() : NULL; @@ -231,12 +256,49 @@ View::filter() { std::for_each(splitChanged, changed.end(), rak::bind2nd(std::ptr_fun(&rpc::parse_command_multiple_d_nothrow), m_eventAdded)); } +void +View::filter_download(core::Download* download) { + iterator itr = std::find(base_type::begin(), base_type::end(), download); + + if (itr == base_type::end()) + throw torrent::internal_error("View::filter_download(...) could not find download."); + + if (view_downloads_filter(m_filter)(download)) { + + if (itr >= end_visible()) { + erase_internal(itr); + insert_visible(download); + + rpc::parse_command_multiple_d_nothrow(download, m_eventAdded); + + } else { + // This makes sure the download is sorted even if it is + // already visible. + // + // Consider removing this. + erase_internal(itr); + insert_visible(download); + } + + } else { + if (itr >= end_visible()) + return; + + erase_internal(itr); + base_type::push_back(download); + + rpc::parse_command_multiple_d_nothrow(download, m_eventRemoved); + } + + m_signalChanged.emit(); +} + void View::set_filter_on(int event) { if (event == DownloadList::SLOTS_INSERT || event == DownloadList::SLOTS_ERASE || event >= DownloadList::SLOTS_MAX_SIZE) throw torrent::internal_error("View::filter_on(...) invalid event."); - m_list->slots(event)["0_view_" + m_name] = sigc::bind(sigc::mem_fun(this, &View::received), event); + m_list->slots(event)["0_view_" + m_name] = "view.filter_download=" + m_name; } void @@ -257,7 +319,7 @@ View::insert_visible(Download* d) { } inline void -View::erase(iterator itr) { +View::erase_internal(iterator itr) { if (itr == end_filtered()) throw torrent::internal_error("View::erase_visible(...) iterator out of range."); @@ -267,74 +329,4 @@ View::erase(iterator itr) { base_type::erase(itr); } -void -View::received(core::Download* download, int event) { - iterator itr = std::find(base_type::begin(), base_type::end(), download); - - switch (event) { - case DownloadList::SLOTS_INSERT: - - if (itr != base_type::end()) - throw torrent::internal_error("View::received(..., SLOTS_INSERT) already inserted."); - - if (view_downloads_filter(m_filter)(download)) { - insert_visible(download); - rpc::parse_command_multiple_d_nothrow(download, m_eventAdded); - - } else { - base_type::insert(end_filtered(), download); - return; - } - - if (m_focus > m_size) - throw torrent::internal_error("View::received(...) m_focus > m_size."); - - break; - - case DownloadList::SLOTS_ERASE: - if (itr >= end_visible()) { - erase(itr); - return; - } - - erase(itr); - rpc::parse_command_multiple_d_nothrow(download, m_eventRemoved); - - break; - - default: - if (itr == end_filtered()) - throw torrent::internal_error("View::received(..., SLOTS_*) could not find download."); - - if (view_downloads_filter(m_filter)(download)) { - - if (itr >= end_visible()) { - erase(itr); - insert_visible(download); - - rpc::parse_command_multiple_d_nothrow(download, m_eventAdded); - - } else { - // This makes sure the download is sorted even if it is - // already visible. - erase(itr); - insert_visible(download); - } - - } else { - if (itr >= end_visible()) - return; - - erase(itr); - base_type::push_back(download); - - rpc::parse_command_multiple_d_nothrow(download, m_eventRemoved); - } - - break; - } - - m_signalChanged.emit(); -} - } diff --git a/src/core/view.h b/src/core/view.h index b24503fb..d6bfe629 100644 --- a/src/core/view.h +++ b/src/core/view.h @@ -102,6 +102,9 @@ public: const_iterator focus() const { return begin() + m_focus; } void set_focus(iterator itr) { m_focus = position(itr); m_signalChanged.emit(); } + void insert(Download* download); + void erase(Download* download); + void set_visible(Download* download); void set_not_visible(Download* download); @@ -115,6 +118,7 @@ public: // Need to explicity trigger filtering. void filter(); + void filter_download(core::Download* download); void set_filter(const std::string& s) { m_filter = s; } void set_filter_on(int event); @@ -144,9 +148,7 @@ private: void push_back(Download* d) { base_type::push_back(d); } inline void insert_visible(Download* d); - inline void erase(iterator itr); - - void received(Download* d, int event); + inline void erase_internal(iterator itr); size_type position(const_iterator itr) const { return itr - begin(); } diff --git a/src/main.cc b/src/main.cc index b1b5d2da..deb166bf 100644 --- a/src/main.cc +++ b/src/main.cc @@ -185,15 +185,11 @@ main(int argc, char** argv) { "view_add = started\n" "view_filter = started,d.get_state=\n" -// "view_filter_on = started,start,stop\n" -// "view_sort_new = started,less=d.get_name=\n" -// "view_sort_current = started,less=d.get_name=\n" + "view_event_added = started,d.resume=\n" + "view_event_removed = started,d.pause=\n" "view_add = stopped\n" "view_filter = stopped,not=$d.get_state=\n" -// "view_filter_on = stopped,start,stop\n" -// "view_sort_new = stopped,less=d.get_name=\n" -// "view_sort_current = stopped,less=d.get_name=\n" "view_add = complete\n" "view_filter = complete,d.get_complete=\n" diff --git a/src/ui/download_list.cc b/src/ui/download_list.cc index 94918e33..29140e92 100644 --- a/src/ui/download_list.cc +++ b/src/ui/download_list.cc @@ -98,7 +98,7 @@ DownloadList::activate(display::Frame* frame, bool focus) { m_frame = frame; control->input()->push_back(&m_bindings); - control->core()->download_list()->slot_map_erase()["0_download_list"] = sigc::bind(&rpc::parse_command_d_single_std, "ui.unfocus_download="); + control->core()->download_list()->slot_map_erase()["0_download_list"] = "ui.unfocus_download="; activate_display(DISPLAY_DOWNLOAD_LIST); }