From 7062935724663f2458da25757ef87b7a720cd689 Mon Sep 17 00:00:00 2001 From: rakshasa Date: Tue, 18 Mar 2008 09:11:59 +0000 Subject: [PATCH] * Replaced View sort code with commands. git-svn-id: svn://rakshasa.no/libtorrent/trunk/rtorrent@1044 e378c898-3ddf-0310-93e7-cc216c733640 --- src/command_helpers.h | 9 ++-- src/command_ui.cc | 58 ++++++++++++++++++++---- src/core/view.cc | 22 ++++----- src/core/view.h | 20 ++------ src/core/view_manager.cc | 98 ++-------------------------------------- src/core/view_manager.h | 23 ++-------- src/main.cc | 32 ++++++------- src/rpc/command.h | 6 +++ src/rpc/command_map.cc | 22 ++++----- src/rpc/command_map.h | 7 ++- src/rpc/parse_commands.h | 2 +- 11 files changed, 117 insertions(+), 182 deletions(-) diff --git a/src/command_helpers.h b/src/command_helpers.h index dff0b556..ae9bcffa 100644 --- a/src/command_helpers.h +++ b/src/command_helpers.h @@ -144,9 +144,6 @@ add_variable(key, NULL, NULL, &rpc::CommandVariable::get_string, NULL, std::stri #define ADD_COMMAND_VALUE(key, slot) \ ADD_COMMAND_SLOT(key, call_value, slot, "i:i", "") -#define ADD_ANY_VALUE(key, slot) \ - ADD_ANY_SLOT(key, call_value, slot, "i:i", "") - #define ADD_COMMAND_VALUE_UN(key, slot) \ ADD_COMMAND_SLOT(key, call_value, rpc::object_value_fn(slot), "i:i", "") @@ -165,6 +162,12 @@ add_variable(key, NULL, NULL, &rpc::CommandVariable::get_string, NULL, std::stri #define ADD_ANY_NONE(key, slot) \ ADD_ANY_SLOT(key, call_unknown, slot, "i:", "") +#define ADD_ANY_VALUE(key, slot) \ + ADD_ANY_SLOT(key, call_value, slot, "i:i", "") + +#define ADD_ANY_LIST(key, slot) \ + ADD_ANY_SLOT(key, call_list, slot, "i:i", "") + #define ADD_COMMAND_NONE_L(key, slot) \ ADD_COMMAND_SLOT(key, call_unknown, slot, "A:", "") diff --git a/src/command_ui.cc b/src/command_ui.cc index eff77382..805d37dc 100644 --- a/src/command_ui.cc +++ b/src/command_ui.cc @@ -52,11 +52,10 @@ #include "control.h" #include "command_helpers.h" -typedef void (core::ViewManager::*view_filter_slot)(const std::string&, const core::ViewManager::sort_args&); typedef void (core::ViewManager::*view_cfilter_slot)(const std::string&, const std::string&); torrent::Object -apply_view_filter(view_filter_slot viewFilterSlot, const torrent::Object& rawArgs) { +apply_view_filter_on(const torrent::Object& rawArgs) { const torrent::Object::list_type& args = rawArgs.as_list(); if (args.size() < 1) @@ -72,7 +71,7 @@ apply_view_filter(view_filter_slot viewFilterSlot, const torrent::Object& rawArg for (torrent::Object::list_const_iterator itr = ++args.begin(), last = args.end(); itr != last; itr++) filterArgs.push_back(itr->as_string()); - (control->view_manager()->*viewFilterSlot)(name, filterArgs); + control->view_manager()->set_filter_on(name, filterArgs); return torrent::Object(); } @@ -162,6 +161,8 @@ apply_cat(rpc::target_type target, const torrent::Object& rawArgs) { return result; } +// Move these boolean operators to a new file. + bool as_boolean(const torrent::Object& rawArgs) { switch (rawArgs.type()) { @@ -202,6 +203,46 @@ apply_or(rpc::target_type target, const torrent::Object& rawArgs) { return (int64_t)false; } +torrent::Object +apply_less(rpc::target_type target, const torrent::Object& rawArgs) { + const torrent::Object::list_type& args = rawArgs.as_list(); + + // We only need to check if empty() since if size() == 1 it calls + // the same command for both, or if size() == 2 then each side of + // the comparison has different commands. + if (args.empty()) + throw torrent::input_error("Wrong argument count."); + + // This really should be converted to using args flagged as + // commands, so that we can compare commands and statics values. + + torrent::Object result1; + torrent::Object result2; + + if (rpc::is_target_pair(target)) { + result1 = rpc::parse_command_single(rpc::get_target_left(target), args.front().as_string()); + result2 = rpc::parse_command_single(rpc::get_target_right(target), args.back().as_string()); + } else { + result1 = rpc::parse_command_single(target, args.front().as_string()); + result2 = rpc::parse_command_single(target, args.back().as_string()); + } + + if (result1.type() != result2.type()) + throw torrent::input_error("Type mismatch."); + + switch (result1.type()) { + case torrent::Object::TYPE_VALUE: return result1.as_value() < result2.as_value(); + case torrent::Object::TYPE_STRING: return result1.as_string() < result2.as_string(); + default: return (int64_t)false; + } +} + +// Fixme. +torrent::Object +apply_greater(rpc::target_type target, const torrent::Object& rawArgs) { + return (int64_t)!apply_less(target, rawArgs).as_value(); +} + torrent::Object apply_to_time(int flags, const torrent::Object& rawArgs) { std::tm *u; @@ -346,13 +387,11 @@ initialize_command_ui() { ADD_COMMAND_NONE_L("view_set", rak::ptr_fn(&apply_view_set)); ADD_COMMAND_LIST("view_filter", rak::bind_ptr_fn(&apply_view_cfilter, &core::ViewManager::set_filter)); - ADD_COMMAND_LIST("view_filter_on", rak::bind_ptr_fn(&apply_view_filter, &core::ViewManager::set_filter_on)); + ADD_COMMAND_LIST("view_filter_on", rak::ptr_fn(&apply_view_filter_on)); ADD_COMMAND_LIST("view_sort", rak::ptr_fn(&apply_view_sort)); - ADD_COMMAND_LIST("view_sort_new", rak::bind_ptr_fn(&apply_view_filter, &core::ViewManager::set_sort_new)); - ADD_COMMAND_LIST("view_sort_current", rak::bind_ptr_fn(&apply_view_filter, &core::ViewManager::set_sort_current)); - -// ADD_COMMAND_LIST("view_sort_current", rak::bind_ptr_fn(&apply_view_filter, &core::ViewManager::set_sort_current)); + ADD_COMMAND_LIST("view_sort_new", rak::bind_ptr_fn(&apply_view_cfilter, &core::ViewManager::set_sort_new)); + ADD_COMMAND_LIST("view_sort_current", rak::bind_ptr_fn(&apply_view_cfilter, &core::ViewManager::set_sort_current)); // Move. @@ -363,6 +402,9 @@ initialize_command_ui() { ADD_ANY_NONE("and", rak::ptr_fn(&apply_and)); ADD_ANY_NONE("or", rak::ptr_fn(&apply_or)); + ADD_ANY_LIST("less", rak::ptr_fn(&apply_less)); + ADD_ANY_LIST("greater", rak::ptr_fn(&apply_greater)); + // A temporary command for handling stuff until we get proper // support for seperation of commands and literals. ADD_ANY_NONE("branch", rak::bind_ptr_fn(&apply_if, 1)); diff --git a/src/core/view.cc b/src/core/view.cc index 0f4ca030..52fe1686 100644 --- a/src/core/view.cc +++ b/src/core/view.cc @@ -92,7 +92,6 @@ View::next_focus() { return; m_focus = (m_focus + 1) % (size() + 1); - m_signalChanged.emit(); } @@ -102,7 +101,6 @@ View::prev_focus() { return; m_focus = (m_focus - 1 + size() + 1) % (size() + 1); - m_signalChanged.emit(); } @@ -111,21 +109,23 @@ View::prev_focus() { // Also add focus thingie here? struct view_downloads_compare : std::binary_function { - view_downloads_compare(const View::sort_list& s) : m_sort(s) {} + view_downloads_compare(const std::string& cmd) : m_command(cmd) {} bool operator () (Download* d1, Download* d2) const { - for (View::sort_list::const_iterator itr = m_sort.begin(), last = m_sort.end(); itr != last; ++itr) - if ((**itr)(d1, d2)) - return true; - else if ((**itr)(d2, d1)) + try { + if (m_command.empty()) return false; - // Since we're testing equivalence, return false if we're - // equal. This is a requirement for the stl sorting algorithms. - return false; + return rpc::parse_command_single(rpc::make_target_pair(d1, d2), m_command).as_value(); + + } catch (torrent::input_error& e) { +// control->core()->push_log(e.what()); + + return false; + } } - const View::sort_list& m_sort; + const std::string& m_command; }; struct view_downloads_filter : std::unary_function { diff --git a/src/core/view.h b/src/core/view.h index f541673f..f36b3f26 100644 --- a/src/core/view.h +++ b/src/core/view.h @@ -61,13 +61,11 @@ namespace core { class Download; class DownloadList; -class ViewSort; class View : private std::vector { public: typedef std::vector base_type; typedef sigc::signal0 signal_type; - typedef std::vector sort_list; using base_type::iterator; using base_type::const_iterator; @@ -109,8 +107,8 @@ public: void sort(); - void set_sort_new(const sort_list& s) { m_sortNew = s; } - void set_sort_current(const sort_list& s) { m_sortCurrent = s; } + void set_sort_new(const std::string& s) { m_sortNew = s; } + void set_sort_current(const std::string& s) { m_sortCurrent = s; } // Need to explicity trigger filtering. void filter(); @@ -118,7 +116,6 @@ public: void set_filter(const std::string& s) { m_filter = s; } void set_filter_on(int event); - void clear_filter_on(); // The time of the last change to the view, semantics of this is @@ -156,23 +153,16 @@ private: size_type m_size; size_type m_focus; - sort_list m_sortNew; - sort_list m_sortCurrent; + // These should be replaced by a faster non-string command type. + std::string m_sortNew; + std::string m_sortCurrent; - // This should be replaced by a faster non-string command type. std::string m_filter; rak::timer m_lastChanged; signal_type m_signalChanged; }; -class ViewSort { -public: - virtual ~ViewSort() {} - - virtual bool operator () (Download* d1, Download* d2) const = 0; -}; - } #endif diff --git a/src/core/view_manager.cc b/src/core/view_manager.cc index 340036e7..34eaf8e4 100644 --- a/src/core/view_manager.cc +++ b/src/core/view_manager.cc @@ -53,87 +53,15 @@ namespace core { -class ViewSortFalse : public ViewSort { -public: - virtual bool operator () (Download* d1, Download* d2) const { - return false; - } -}; - -class ViewSortName : public ViewSort { -public: - virtual bool operator () (Download* d1, Download* d2) const { - return d1->download()->name() < d2->download()->name(); - } -}; - -class ViewSortVariable : public ViewSort { -public: - ViewSortVariable(const char* name, const char* value) : m_name(name), m_value(value) {} - - virtual bool operator () (Download* d1, Download* d2) const { - return - rpc::call_command_string(m_name, rpc::make_target(d1)) == m_value && - rpc::call_command_string(m_name, rpc::make_target(d2)) != m_value; - } - -private: - const char* m_name; - const char* m_value; -}; - -class ViewSortVariableValue : public ViewSort { -public: - ViewSortVariableValue(const char* name, bool reverse = false) : m_name(name), m_reverse(reverse) {} - - virtual bool operator () (Download* d1, Download* d2) const { - if (m_reverse) - return rpc::call_command_value(m_name, rpc::make_target(d2)) < rpc::call_command_value(m_name, rpc::make_target(d1)); - else - return rpc::call_command_value(m_name, rpc::make_target(d1)) < rpc::call_command_value(m_name, rpc::make_target(d2)); - } - -private: - const char* m_name; - bool m_reverse; -}; - -class ViewSortReverse : public ViewSort { -public: - ViewSortReverse(ViewSort* s) : m_sort(s) {} - ~ViewSortReverse() { delete m_sort; } - - virtual bool operator () (Download* d1, Download* d2) const { - return (*m_sort)(d2, d1); - } - -private: - ViewSort* m_sort; -}; - // Really need to implement a factory and allow options in the sort // statements. ViewManager::ViewManager(DownloadList* dl) : m_list(dl) { - -// m_sort["first"] = new ViewSortNot(new ViewSort()); - m_sort["last"] = new ViewSortFalse(); - m_sort["name"] = new ViewSortName(); - m_sort["name_reverse"] = new ViewSortReverse(new ViewSortName()); - - m_sort["stopped"] = new ViewSortVariableValue("d.get_state"); - m_sort["started"] = new ViewSortVariableValue("d.get_state", true); - m_sort["complete"] = new ViewSortVariableValue("d.get_complete"); - m_sort["incomplete"] = new ViewSortVariableValue("d.get_complete", true); - - m_sort["state_changed"] = new ViewSortVariableValue("d.get_state_changed"); - m_sort["state_changed_reverse"] = new ViewSortVariableValue("d.get_state_changed", true); } void ViewManager::clear() { std::for_each(begin(), end(), rak::call_delete()); - std::for_each(m_sort.begin(), m_sort.end(), rak::on(rak::mem_ref(&sort_map::value_type::second), rak::call_delete())); base_type::clear(); } @@ -164,23 +92,6 @@ ViewManager::find_throw(const std::string& name) { return itr; } -inline ViewManager::sort_list -ViewManager::build_sort_list(const sort_args& args) { - View::sort_list sortList; - sortList.reserve(args.size()); - - for (sort_args::const_iterator itr = args.begin(), last = args.end(); itr != last; ++itr) { - sort_map::const_iterator sortItr = m_sort.find(itr->c_str()); - - if (sortItr == m_sort.end()) - throw torrent::input_error("Invalid sorting identifier."); - - sortList.push_back(sortItr->second); - } - - return sortList; -} - void ViewManager::sort(const std::string& name, uint32_t timeout) { iterator viewItr = find_throw(name); @@ -190,22 +101,21 @@ ViewManager::sort(const std::string& name, uint32_t timeout) { // Should we rename sort, or add a seperate function? (*viewItr)->filter(); - (*viewItr)->sort(); } void -ViewManager::set_sort_new(const std::string& name, const sort_args& sort) { +ViewManager::set_sort_new(const std::string& name, const std::string& cmd) { iterator viewItr = find_throw(name); - (*viewItr)->set_sort_new(build_sort_list(sort)); + (*viewItr)->set_sort_new(cmd); } void -ViewManager::set_sort_current(const std::string& name, const sort_args& sort) { +ViewManager::set_sort_current(const std::string& name, const std::string& cmd) { iterator viewItr = find_throw(name); - (*viewItr)->set_sort_current(build_sort_list(sort)); + (*viewItr)->set_sort_current(cmd); } void diff --git a/src/core/view_manager.h b/src/core/view_manager.h index 17bdbed4..cff38233 100644 --- a/src/core/view_manager.h +++ b/src/core/view_manager.h @@ -37,8 +37,6 @@ #ifndef RTORRENT_CORE_VIEW_MANAGER_H #define RTORRENT_CORE_VIEW_MANAGER_H -#include -#include #include #include @@ -46,21 +44,10 @@ namespace core { -struct view_manager_comp : public std::binary_function { - bool operator () (const char* arg1, const char* arg2) const { return std::strcmp(arg1, arg2) < 0; } -}; - -class ViewSort; - class ViewManager : public rak::unordered_vector { public: typedef rak::unordered_vector base_type; - - typedef std::map sort_map; - typedef View::sort_list sort_list; - typedef std::list sort_args; - - typedef std::list filter_args; + typedef std::list filter_args; using base_type::iterator; using base_type::const_iterator; @@ -100,18 +87,14 @@ public: // Find a better name for 'timeout'. void sort(const std::string& name, uint32_t timeout = 0); - void set_sort_new(const std::string& name, const sort_args& sort); - void set_sort_current(const std::string& name, const sort_args& sort); + void set_sort_new(const std::string& name, const std::string& cmd); + void set_sort_current(const std::string& name, const std::string& cmd); void set_filter(const std::string& name, const std::string& cmd); void set_filter_on(const std::string& name, const filter_args& args); private: - inline sort_list build_sort_list(const sort_args& args); - DownloadList* m_list; - - sort_map m_sort; }; } diff --git a/src/main.cc b/src/main.cc index 4c113bef..415292fa 100644 --- a/src/main.cc +++ b/src/main.cc @@ -180,50 +180,50 @@ main(int argc, char** argv) { "view_add = default\n" "view_add = name\n" - "view_sort_new = name,name\n" - "view_sort_current = name,name\n" + "view_sort_new = name,less=d.get_name=\n" + "view_sort_current = name,less=d.get_name=\n" "view_add = started\n" "view_filter = started,d.get_state=\n" "view_filter_on = started,start,stop\n" - "view_sort_new = started,name\n" - "view_sort_current = started,name\n" + "view_sort_new = started,less=d.get_name=\n" + "view_sort_current = started,less=d.get_name=\n" "view_add = stopped\n" "view_filter = stopped,not=$d.get_state=\n" "view_filter_on = stopped,start,stop\n" - "view_sort_new = stopped,name\n" - "view_sort_current = stopped,name\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" "view_filter_on = complete,hash_done,finished\n" - "view_sort_new = complete,state_changed\n" - "view_sort_current = complete,state_changed_reverse\n" + "view_sort_new = complete,less=d.get_state_changed=\n" + "view_sort_current = complete,less=d.get_state_changed=\n" "view_add = incomplete\n" "view_filter = incomplete,not=$d.get_complete=\n" "view_filter_on = incomplete,hash_done,finished\n" - "view_sort_new = incomplete,state_changed\n" - "view_sort_current = incomplete,state_changed_reverse\n" + "view_sort_new = incomplete,less=d.get_state_changed=\n" + "view_sort_current = incomplete,less=d.get_state_changed=\n" // The hashing view does not include stopped torrents. "view_add = hashing\n" "view_filter = hashing,d.get_hashing=\n" "view_filter_on = hashing,hash_queued,hash_removed,hash_done\n" - "view_sort_new = hashing,state_changed\n" - "view_sort_current = hashing,state_changed\n" +// "view_sort_new = hashing,less=d.get_state_changed=\n" +// "view_sort_current = hashing,less=d.get_state_changed=\n" "view_add = seeding\n" "view_filter = seeding,\"and=d.get_state=,d.get_complete=\"\n" "view_filter_on = seeding,start,stop\n" - "view_sort_new = seeding,state_changed\n" - "view_sort_current = seeding,state_changed_reverse\n" + "view_sort_new = seeding,less=d.get_state_changed=\n" + "view_sort_current = seeding,less=d.get_state_changed=\n" // Changing these will bork the (non-existant) scheduler. "view_add = scheduler\n" - "view_sort_new = scheduler,state_changed\n" // add started? - "view_sort_current = scheduler,state_changed\n" +// "view_sort_new = scheduler,less=d.get_state_changed=\n" +// "view_sort_current = scheduler,less=d.get_state_changed=\n" // "schedule = scheduler,10,10,download_scheduler=\n" diff --git a/src/rpc/command.h b/src/rpc/command.h index a5f609ea..cec93db7 100644 --- a/src/rpc/command.h +++ b/src/rpc/command.h @@ -147,6 +147,12 @@ template <> struct target_type_id { static const in template <> struct target_type_id { static const int value = Command::target_download_pair; }; +// Splitting pairs into separate targets. +inline bool is_target_pair(const target_type& target) { return target.first >= Command::target_download_pair; } + +inline target_type get_target_left(const target_type& target) { return target_type(target.first - 5, target.second); } +inline target_type get_target_right(const target_type& target) { return target_type(target.first - 5, target.third); } + } #endif diff --git a/src/rpc/command_map.cc b/src/rpc/command_map.cc index aedba386..dcc2b0e2 100644 --- a/src/rpc/command_map.cc +++ b/src/rpc/command_map.cc @@ -70,19 +70,9 @@ CommandMap::insert(key_type key, const command_map_data_type src) { itr = base_type::insert(itr, value_type(key, command_map_data_type(src.m_variable, src.m_flags | flag_dont_delete, src.m_parm, src.m_doc))); - itr->second.m_target = src.m_target; - - // This _should_ be optimized int just one assignment. - switch (itr->second.m_target) { - case Command::target_generic: itr->second.m_genericSlot = src.m_genericSlot; break; - case Command::target_any: itr->second.m_anySlot = src.m_anySlot; break; - case Command::target_download: itr->second.m_downloadSlot = src.m_downloadSlot; break; - case Command::target_file: itr->second.m_fileSlot = src.m_fileSlot; break; - case Command::target_file_itr: itr->second.m_fileItrSlot = src.m_fileItrSlot; break; - case Command::target_peer: itr->second.m_peerSlot = src.m_peerSlot; break; - case Command::target_tracker: itr->second.m_trackerSlot = src.m_trackerSlot; break; - default: throw torrent::internal_error("CommandMap::insert(...) Invalid target."); - } + // We can assume all the slots are the same size. + itr->second.m_target = src.m_target; + itr->second.m_genericSlot = src.m_genericSlot; } const CommandMap::mapped_type @@ -119,6 +109,9 @@ CommandMap::call_command(key_type key, const mapped_type& arg, target_type targe case Command::target_tracker: return itr->second.m_trackerSlot (itr->second.m_variable, (torrent::Tracker*)target.second, arg); case Command::target_file: return itr->second.m_fileSlot (itr->second.m_variable, (torrent::File*)target.second, arg); case Command::target_file_itr: return itr->second.m_fileItrSlot (itr->second.m_variable, (torrent::FileListIterator*)target.second, arg); + + case Command::target_download_pair: return itr->second.m_downloadPairSlot(itr->second.m_variable, (core::Download*)target.second, (core::Download*)target.third, arg); + default: throw torrent::internal_error("CommandMap::call_command(...) Invalid target."); } } @@ -146,6 +139,9 @@ CommandMap::call_command(const_iterator itr, const mapped_type& arg, target_type case Command::target_tracker: return itr->second.m_trackerSlot (itr->second.m_variable, (torrent::Tracker*)target.second, arg); case Command::target_file: return itr->second.m_fileSlot (itr->second.m_variable, (torrent::File*)target.second, arg); case Command::target_file_itr: return itr->second.m_fileItrSlot (itr->second.m_variable, (torrent::FileListIterator*)target.second, arg); + + case Command::target_download_pair: return itr->second.m_downloadPairSlot(itr->second.m_variable, (core::Download*)target.second, (core::Download*)target.third, arg); + default: throw torrent::internal_error("CommandMap::call_command(...) Invalid target."); } } diff --git a/src/rpc/command_map.h b/src/rpc/command_map.h index 23d54ec1..7a041b67 100644 --- a/src/rpc/command_map.h +++ b/src/rpc/command_map.h @@ -73,7 +73,7 @@ struct command_map_data_type { Command::peer_slot m_peerSlot; Command::tracker_slot m_trackerSlot; - Command::download_slot m_downloadPairSlot; + Command::download_pair_slot m_downloadPairSlot; }; int m_flags; @@ -143,6 +143,11 @@ inline target_type make_target(T target) { return target_type((int)target_type_id::value, target); } +template +inline target_type make_target_pair(T target1, T target2) { + return target_type((int)target_type_id::value, target1, target2); +} + } #endif diff --git a/src/rpc/parse_commands.h b/src/rpc/parse_commands.h index b1758c80..6a6565e0 100644 --- a/src/rpc/parse_commands.h +++ b/src/rpc/parse_commands.h @@ -65,7 +65,7 @@ void parse_command_multiple(target_type target, const char* fi // Make this take care of lists too. parse_command_type parse_command_object(target_type target, const torrent::Object& object); -inline void parse_command_single(target_type target, const char* first) { parse_command(target, first, first + std::strlen(first)); } +inline torrent::Object parse_command_single(target_type target, const char* first) { return parse_command(target, first, first + std::strlen(first)).first; } inline void parse_command_multiple(target_type target, const char* first) { parse_command_multiple(target, first, first + std::strlen(first)); } bool parse_command_file(const std::string& path);