diff --git a/src/command_ui.cc b/src/command_ui.cc index 506391c8..2f44adc7 100644 --- a/src/command_ui.cc +++ b/src/command_ui.cc @@ -53,6 +53,7 @@ #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) { @@ -76,6 +77,23 @@ apply_view_filter(view_filter_slot viewFilterSlot, const torrent::Object& rawArg return torrent::Object(); } +torrent::Object +apply_view_cfilter(view_cfilter_slot viewFilterSlot, const torrent::Object& rawArgs) { + const torrent::Object::list_type& args = rawArgs.as_list(); + + if (args.size() != 2) + throw torrent::input_error("Too few arguments."); + + const std::string& name = args.front().as_string(); + + if (name.empty()) + throw torrent::input_error("First argument must be a string."); + + (control->view_manager()->*viewFilterSlot)(name, args.back().as_string()); + + return torrent::Object(); +} + torrent::Object apply_view_sort(const torrent::Object& rawArgs) { const torrent::Object::list_type& args = rawArgs.as_list(); @@ -144,6 +162,46 @@ apply_cat(rpc::target_type target, const torrent::Object& rawArgs) { return result; } +bool +as_boolean(const torrent::Object& rawArgs) { + switch (rawArgs.type()) { + case torrent::Object::TYPE_VALUE: return rawArgs.as_value(); + case torrent::Object::TYPE_STRING: return !rawArgs.as_string().empty(); + case torrent::Object::TYPE_LIST: return !rawArgs.as_list().empty(); + case torrent::Object::TYPE_MAP: return !rawArgs.as_map().empty(); + default: return false; + } +} + +torrent::Object +apply_not(rpc::target_type target, const torrent::Object& rawArgs) { + return (int64_t)as_boolean(rawArgs); +} + +torrent::Object +apply_and(rpc::target_type target, const torrent::Object& rawArgs) { + if (rawArgs.type() != torrent::Object::TYPE_LIST) + return as_boolean(rawArgs); + + for (torrent::Object::list_const_iterator itr = rawArgs.as_list().begin(), last = rawArgs.as_list().end(); itr != last; itr++) + if (!as_boolean(rpc::parse_command_single(target, itr->as_string()))) + return (int64_t)false; + + return (int64_t)true; +} + +torrent::Object +apply_or(rpc::target_type target, const torrent::Object& rawArgs) { + if (rawArgs.type() != torrent::Object::TYPE_LIST) + return as_boolean(rawArgs); + + for (torrent::Object::list_const_iterator itr = rawArgs.as_list().begin(), last = rawArgs.as_list().end(); itr != last; itr++) + if (as_boolean(rpc::parse_command_single(target, itr->as_string()))) + return (int64_t)true; + + return (int64_t)false; +} + torrent::Object apply_to_time(int flags, const torrent::Object& rawArgs) { std::tm *u; @@ -287,7 +345,7 @@ initialize_command_ui() { ADD_COMMAND_NONE_L("view_list", rak::ptr_fn(&apply_view_list)); ADD_COMMAND_NONE_L("view_set", rak::ptr_fn(&apply_view_set)); - ADD_COMMAND_LIST("view_filter", rak::bind_ptr_fn(&apply_view_filter, &core::ViewManager::set_filter)); + 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_sort", rak::ptr_fn(&apply_view_sort)); @@ -301,6 +359,9 @@ initialize_command_ui() { ADD_ANY_NONE("print", rak::ptr_fn(&apply_print)); ADD_ANY_NONE("cat", rak::ptr_fn(&apply_cat)); ADD_ANY_NONE("if", rak::bind_ptr_fn(&apply_if, 0)); + ADD_ANY_NONE("not", rak::ptr_fn(&apply_not)); + ADD_ANY_NONE("and", rak::ptr_fn(&apply_and)); + ADD_ANY_NONE("or", rak::ptr_fn(&apply_or)); // A temporary command for handling stuff until we get proper // support for seperation of commands and literals. diff --git a/src/core/view.cc b/src/core/view.cc index 4eec2bba..ab6814d5 100644 --- a/src/core/view.cc +++ b/src/core/view.cc @@ -39,6 +39,7 @@ #include #include #include +#include #include #include #include @@ -128,19 +129,30 @@ struct view_downloads_compare : std::binary_function }; struct view_downloads_filter : std::unary_function { - view_downloads_filter(const View::filter_list& s) : m_filter(s) {} + view_downloads_filter(const std::string& cmd) : m_command(cmd) {} bool operator () (Download* d1) const { - for (View::filter_list::const_iterator itr = m_filter.begin(), last = m_filter.end(); itr != last; ++itr) - if (!(**itr)(d1)) - return false; + try { + torrent::Object result = rpc::parse_command_single(rpc::make_target(d1), m_command); - // The default filter action is to return true, to not filter the - // download out. - return true; + switch (result.type()) { + case torrent::Object::TYPE_NONE: return false; + case torrent::Object::TYPE_VALUE: return result.as_value(); + case torrent::Object::TYPE_STRING: return !result.as_string().empty(); + case torrent::Object::TYPE_LIST: return !result.as_list().empty(); + case torrent::Object::TYPE_MAP: return !result.as_map().empty(); + } + + // The default filter action is to return true, to not filter + // the download out. + return true; + + } catch (torrent::input_error& e) { + return false; + } } - const View::filter_list& m_filter; + const std::string& m_command; }; void @@ -232,6 +244,8 @@ View::received(core::Download* download, int event) { // Erase even if it is in visible so that the download is // re-sorted. + // + // Do we really want to do this? erase(itr); insert_visible(download); diff --git a/src/core/view.h b/src/core/view.h index fc6ee500..f541673f 100644 --- a/src/core/view.h +++ b/src/core/view.h @@ -62,14 +62,12 @@ namespace core { class Download; class DownloadList; class ViewSort; -class ViewFilter; class View : private std::vector { public: typedef std::vector base_type; typedef sigc::signal0 signal_type; typedef std::vector sort_list; - typedef std::vector filter_list; using base_type::iterator; using base_type::const_iterator; @@ -117,10 +115,9 @@ public: // Need to explicity trigger filtering. void filter(); - void set_filter(const filter_list& s) { m_filter = s; } + void set_filter(const std::string& s) { m_filter = s; } void set_filter_on(int event); - void set_cfilter(const std::string& s) { m_cfilter = s; } void clear_filter_on(); @@ -162,9 +159,8 @@ private: sort_list m_sortNew; sort_list m_sortCurrent; - filter_list m_filter; - - std::string m_cfilter; + // This should be replaced by a faster non-string command type. + std::string m_filter; rak::timer m_lastChanged; signal_type m_signalChanged; @@ -177,13 +173,6 @@ public: virtual bool operator () (Download* d1, Download* d2) const = 0; }; -class ViewFilter { -public: - virtual ~ViewFilter() {} - - virtual bool operator () (Download* d1) const = 0; -}; - } #endif diff --git a/src/core/view_manager.cc b/src/core/view_manager.cc index ea911ea6..340036e7 100644 --- a/src/core/view_manager.cc +++ b/src/core/view_manager.cc @@ -111,21 +111,6 @@ private: ViewSort* m_sort; }; -class ViewFilterVariableValue : public ViewFilter { -public: - ViewFilterVariableValue(const char* name, torrent::Object::value_type v, bool inverse = false) : - m_name(name), m_value(v), m_inverse(inverse) {} - - virtual bool operator () (Download* d1) const { - return (rpc::call_command_value(m_name, rpc::make_target(d1)) == m_value) != m_inverse; - } - -private: - const char* m_name; - torrent::Object::value_type m_value; - bool m_inverse; -}; - // Really need to implement a factory and allow options in the sort // statements. ViewManager::ViewManager(DownloadList* dl) : @@ -143,19 +128,12 @@ ViewManager::ViewManager(DownloadList* dl) : m_sort["state_changed"] = new ViewSortVariableValue("d.get_state_changed"); m_sort["state_changed_reverse"] = new ViewSortVariableValue("d.get_state_changed", true); - - m_filter["started"] = new ViewFilterVariableValue("d.get_state", 1); - m_filter["stopped"] = new ViewFilterVariableValue("d.get_state", 0); - m_filter["complete"] = new ViewFilterVariableValue("d.get_complete", 0, true); - m_filter["incomplete"] = new ViewFilterVariableValue("d.get_complete", 0); - m_filter["hashing"] = new ViewFilterVariableValue("d.get_hashing", 0, 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())); - std::for_each(m_filter.begin(), m_filter.end(), rak::on(rak::mem_ref(&filter_map::value_type::second), rak::call_delete())); base_type::clear(); } @@ -230,28 +208,11 @@ ViewManager::set_sort_current(const std::string& name, const sort_args& sort) { (*viewItr)->set_sort_current(build_sort_list(sort)); } -inline ViewManager::filter_list -ViewManager::build_filter_list(const filter_args& args) { - View::filter_list filterList; - filterList.reserve(args.size()); - - for (filter_args::const_iterator itr = args.begin(), last = args.end(); itr != last; ++itr) { - filter_map::const_iterator filterItr = m_filter.find(itr->c_str()); - - if (filterItr == m_filter.end()) - throw torrent::input_error("Invalid filtering identifier."); - - filterList.push_back(filterItr->second); - } - - return filterList; -} - void -ViewManager::set_filter(const std::string& name, const filter_args& args) { +ViewManager::set_filter(const std::string& name, const std::string& cmd) { iterator viewItr = find_throw(name); - (*viewItr)->set_filter(build_filter_list(args)); + (*viewItr)->set_filter(cmd); (*viewItr)->filter(); } diff --git a/src/core/view_manager.h b/src/core/view_manager.h index 45bf1336..17bdbed4 100644 --- a/src/core/view_manager.h +++ b/src/core/view_manager.h @@ -60,8 +60,6 @@ public: typedef View::sort_list sort_list; typedef std::list sort_args; - typedef std::map filter_map; - typedef View::filter_list filter_list; typedef std::list filter_args; using base_type::iterator; @@ -105,17 +103,15 @@ public: 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_filter(const std::string& name, const filter_args& args); + 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); - inline filter_list build_filter_list(const sort_args& args); DownloadList* m_list; sort_map m_sort; - filter_map m_filter; }; } diff --git a/src/main.cc b/src/main.cc index db60207a..4c113bef 100644 --- a/src/main.cc +++ b/src/main.cc @@ -184,38 +184,38 @@ main(int argc, char** argv) { "view_sort_current = name,name\n" "view_add = started\n" - "view_filter = started,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_add = stopped\n" - "view_filter = stopped,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_add = complete\n" - "view_filter = complete,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_add = incomplete\n" - "view_filter = incomplete,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" // The hashing view does not include stopped torrents. "view_add = hashing\n" - "view_filter = hashing,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_add = seeding\n" - "view_filter = seeding,started,complete\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" diff --git a/src/rpc/command.h b/src/rpc/command.h index 37988791..a5f609ea 100644 --- a/src/rpc/command.h +++ b/src/rpc/command.h @@ -102,6 +102,8 @@ public: typedef const torrent::Object (*peer_slot) (Command*, torrent::Peer*, const torrent::Object&); typedef const torrent::Object (*tracker_slot) (Command*, torrent::Tracker*, const torrent::Object&); + typedef const torrent::Object (*download_pair_slot) (Command*, core::Download*, core::Download*, const torrent::Object&); + static const int target_generic = 0; static const int target_any = 1; static const int target_download = 2; @@ -110,6 +112,8 @@ public: static const int target_file = 5; static const int target_file_itr = 6; + static const int target_download_pair = 7; + Command() {} virtual ~Command() {} @@ -118,18 +122,30 @@ protected: void operator = (const Command&); }; -template +template struct target_type_id { // Nothing here, so we cause an error. }; -template <> struct target_type_id { static const int value = Command::target_generic; }; -template <> struct target_type_id { static const int value = Command::target_any; }; -template <> struct target_type_id { static const int value = Command::target_download; }; -template <> struct target_type_id { static const int value = Command::target_peer; }; -template <> struct target_type_id { static const int value = Command::target_tracker; }; -template <> struct target_type_id { static const int value = Command::target_file; }; -template <> struct target_type_id { static const int value = Command::target_file_itr; }; +template <> struct target_type_id { static const int value = Command::target_generic; }; +template <> struct target_type_id { static const int value = Command::target_any; }; +template <> struct target_type_id { static const int value = Command::target_download; }; +template <> struct target_type_id { static const int value = Command::target_peer; }; +template <> struct target_type_id { static const int value = Command::target_tracker; }; +template <> struct target_type_id { static const int value = Command::target_file; }; +template <> struct target_type_id { static const int value = Command::target_file_itr; }; + +template <> struct target_type_id { static const int value = Command::target_download_pair; }; + +template <> struct target_type_id<> { static const int value = Command::target_generic; }; +template <> struct target_type_id { static const int value = Command::target_any; }; +template <> struct target_type_id { static const int value = Command::target_download; }; +template <> struct target_type_id { static const int value = Command::target_peer; }; +template <> struct target_type_id { static const int value = Command::target_tracker; }; +template <> struct target_type_id { static const int value = Command::target_file; }; +template <> struct target_type_id { static const int value = Command::target_file_itr; }; + +template <> struct target_type_id { static const int value = Command::target_download_pair; }; } diff --git a/src/rpc/command_map.h b/src/rpc/command_map.h index 35de3f9d..23d54ec1 100644 --- a/src/rpc/command_map.h +++ b/src/rpc/command_map.h @@ -72,6 +72,8 @@ struct command_map_data_type { Command::file_itr_slot m_fileItrSlot; Command::peer_slot m_peerSlot; Command::tracker_slot m_trackerSlot; + + Command::download_slot m_downloadPairSlot; }; int m_flags; @@ -108,6 +110,7 @@ public: iterator insert(key_type key, Command* variable, int flags, const char* parm, const char* doc); + // Make this a wrapper call to insert without extra fluff. template void insert_type(key_type key, Command* variable, T targetSlot, int flags, const char* parm, const char* doc) { iterator itr = insert(key, variable, flags, parm, doc); @@ -132,12 +135,13 @@ private: }; inline target_type make_target() { return target_type((int)Command::target_generic, NULL); } -inline target_type make_target(core::Download* target) { return target_type((int)Command::target_download, target); } -inline target_type make_target(torrent::Peer* target) { return target_type((int)Command::target_peer, target); } -inline target_type make_target(torrent::Tracker* target) { return target_type((int)Command::target_tracker, target); } -inline target_type make_target(torrent::File* target) { return target_type((int)Command::target_file, target); } -inline target_type make_target(torrent::FileListIterator* target) { return target_type((int)Command::target_file_itr, target); } inline target_type make_target(int type, void* target) { return target_type(type, target); } +inline target_type make_target(int type, void* target1, void* target2) { return target_type(type, target1, target2); } + +template +inline target_type make_target(T target) { + return target_type((int)target_type_id::value, target); +} } diff --git a/src/rpc/parse_commands.h b/src/rpc/parse_commands.h index 9dc90810..b1758c80 100644 --- a/src/rpc/parse_commands.h +++ b/src/rpc/parse_commands.h @@ -71,6 +71,11 @@ inline void parse_command_multiple(target_type target, const char* fi bool parse_command_file(const std::string& path); const char* parse_command_name(const char* first, const char* last, std::string* dest); +inline torrent::Object +parse_command_single(target_type target, const std::string& cmd) { + return parse_command(target, cmd.c_str(), cmd.c_str() + cmd.size()).first; +} + inline void parse_command_single_std(const std::string& cmd) { parse_command(make_target(), cmd.c_str(), cmd.c_str() + cmd.size());