Merge branch 'toff-master'

This commit is contained in:
rakshasa
2019-07-08 21:40:02 +02:00
10 changed files with 141 additions and 17 deletions
+3
View File
@@ -99,6 +99,9 @@ Delete the file the torrent is tied to, and clear the association.
.TP .TP
\fBI\fR \fBI\fR
Toggle whether torrent ignores ratio settings. Toggle whether torrent ignores ratio settings.
.TP
\fBF\fR
Add a temporary name based regex filter to the current view.
.SS "DOWNLOAD VIEW KEYS" .SS "DOWNLOAD VIEW KEYS"
.TP .TP
\fB->\fR \fB->\fR
+7
View File
@@ -225,6 +225,13 @@ Toggle whether torrent ignores ratio settings.
</para></listitem> </para></listitem>
</varlistentry> </varlistentry>
<varlistentry>
<term>F</term>
<listitem><para>
Add a temporary name based regex filter to the current view.
</para></listitem>
</varlistentry>
</variablelist> </variablelist>
</refsect2> </refsect2>
+55 -2
View File
@@ -39,6 +39,8 @@
#include <sys/types.h> #include <sys/types.h>
#include <ctime> #include <ctime>
#include <regex>
#include <rak/algorithm.h> #include <rak/algorithm.h>
#include <rak/functional.h> #include <rak/functional.h>
#include <rak/functional_fun.h> #include <rak/functional_fun.h>
@@ -369,6 +371,53 @@ apply_compare(rpc::target_type target, const torrent::Object::list_type& args) {
return (int64_t) (target.second < target.third); return (int64_t) (target.second < target.third);
} }
// Regexp based 'match' function.
// arg1: the text to match.
// arg2: the regexp pattern.
// eg: match{d.name=,.*linux.*iso}
torrent::Object apply_match(rpc::target_type target, const torrent::Object::list_type& args) {
if (args.size() != 2)
throw torrent::input_error("Wrong argument count for 'match': 2 arguments needed.");
// 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;
rpc::target_type target1 = rpc::is_target_pair(target) ? rpc::get_target_left(target) : target;
rpc::target_type target2 = rpc::is_target_pair(target) ? rpc::get_target_right(target) : target;
if (args.front().is_dict_key())
result1 = rpc::commands.call_command(args.front().as_dict_key().c_str(), args.front().as_dict_obj(), target1);
else
result1 = rpc::parse_command_single(target1, args.front().as_string());
if (args.back().is_dict_key())
result2 = rpc::commands.call_command(args.back().as_dict_key().c_str(), args.back().as_dict_obj(), target2);
else
result2 = args.back().as_string();
if (result1.type() != result2.type())
throw torrent::input_error("Type mismatch for 'match' arguments.");
std::string text = result1.as_string();
std::string pattern = result2.as_string();
std::transform(text.begin(), text.end(), text.begin(), ::tolower);
std::transform(pattern.begin(), pattern.end(), pattern.begin(), ::tolower);
bool isAMatch = false;
try {
std::regex re(pattern);
isAMatch = std::regex_match(text, re);
} catch (const std::regex_error& exc) {
control->core()->push_log_std("regex_error: " + std::string(exc.what()));
}
return isAMatch ? (int64_t)true : (int64_t)false;
}
torrent::Object torrent::Object
apply_to_time(const torrent::Object& rawArgs, int flags) { apply_to_time(const torrent::Object& rawArgs, int flags) {
std::tm *u; std::tm *u;
@@ -737,8 +786,11 @@ initialize_command_ui() {
CMD2_ANY_L ("view.list", std::bind(&apply_view_list)); CMD2_ANY_L ("view.list", std::bind(&apply_view_list));
CMD2_ANY_LIST("view.set", std::bind(&apply_view_set, std::placeholders::_2)); CMD2_ANY_LIST("view.set", std::bind(&apply_view_set, std::placeholders::_2));
CMD2_ANY_LIST("view.filter", std::bind(&apply_view_event, &core::ViewManager::set_filter, std::placeholders::_2)); CMD2_ANY_LIST ("view.filter", std::bind(&apply_view_event, &core::ViewManager::set_filter, std::placeholders::_2));
CMD2_ANY_LIST("view.filter_on", std::bind(&apply_view_filter_on, std::placeholders::_2)); CMD2_ANY_LIST ("view.filter_on", std::bind(&apply_view_filter_on, std::placeholders::_2));
CMD2_ANY_LIST ("view.filter.temp", std::bind(&apply_view_event, &core::ViewManager::set_filter_temp, std::placeholders::_2));
CMD2_VAR_STRING("view.filter.temp.excluded", "default,started,stopped");
CMD2_VAR_BOOL ("view.filter.temp.log", 0);
CMD2_ANY_LIST("view.sort", std::bind(&apply_view_sort, std::placeholders::_2)); CMD2_ANY_LIST("view.sort", std::bind(&apply_view_sort, std::placeholders::_2));
CMD2_ANY_LIST("view.sort_new", std::bind(&apply_view_event, &core::ViewManager::set_sort_new, std::placeholders::_2)); CMD2_ANY_LIST("view.sort_new", std::bind(&apply_view_event, &core::ViewManager::set_sort_new, std::placeholders::_2));
@@ -794,6 +846,7 @@ initialize_command_ui() {
CMD2_ANY_LIST("greater", &apply_greater); CMD2_ANY_LIST("greater", &apply_greater);
CMD2_ANY_LIST("equal", &apply_equal); CMD2_ANY_LIST("equal", &apply_equal);
CMD2_ANY_LIST("compare", &apply_compare); CMD2_ANY_LIST("compare", &apply_compare);
CMD2_ANY_LIST("match", &apply_match);
CMD2_ANY_VALUE("convert.gm_time", std::bind(&apply_to_time, std::placeholders::_2, 0)); CMD2_ANY_VALUE("convert.gm_time", std::bind(&apply_to_time, std::placeholders::_2, 0));
CMD2_ANY_VALUE("convert.gm_date", std::bind(&apply_to_time, std::placeholders::_2, 0x2)); CMD2_ANY_VALUE("convert.gm_date", std::bind(&apply_to_time, std::placeholders::_2, 0x2));
+17 -13
View File
@@ -89,17 +89,21 @@ struct view_downloads_compare : std::binary_function<Download*, Download*, bool>
}; };
struct view_downloads_filter : std::unary_function<Download*, bool> { struct view_downloads_filter : std::unary_function<Download*, bool> {
view_downloads_filter(const torrent::Object& cmd) : m_command(cmd) {} view_downloads_filter(const torrent::Object& cmd, const torrent::Object& cmd2) : m_command(cmd), m_command2(cmd2) {}
bool operator () (Download* d1) const { bool operator () (Download* d1) const {
if (m_command.is_empty()) return this->evalCmd(m_command, d1) && this->evalCmd(m_command2, d1);
}
bool evalCmd(const torrent::Object& cmd, Download* d1) const {
if (cmd.is_empty())
return true; return true;
try { try {
torrent::Object result; torrent::Object result;
if (m_command.is_dict_key()) { if (cmd.is_dict_key()) {
// torrent::Object tmp_command = m_command; // torrent::Object tmp_command = cmd;
// uint32_t flags = tmp_command.flags() & torrent::Object::mask_function; // uint32_t flags = tmp_command.flags() & torrent::Object::mask_function;
// tmp_command.unset_flags(torrent::Object::mask_function); // tmp_command.unset_flags(torrent::Object::mask_function);
@@ -109,10 +113,10 @@ struct view_downloads_filter : std::unary_function<Download*, bool> {
// result = rpc::commands.call_command(tmp_command.as_dict_key().c_str(), tmp_command.as_dict_obj(), // result = rpc::commands.call_command(tmp_command.as_dict_key().c_str(), tmp_command.as_dict_obj(),
// rpc::make_target(d1)); // rpc::make_target(d1));
result = rpc::commands.call_command(m_command.as_dict_key().c_str(), m_command.as_dict_obj(), rpc::make_target(d1)); result = rpc::commands.call_command(cmd.as_dict_key().c_str(), cmd.as_dict_obj(), rpc::make_target(d1));
} else { } else {
result = rpc::parse_command_single(rpc::make_target(d1), m_command.as_string()); result = rpc::parse_command_single(rpc::make_target(d1), cmd.as_string());
} }
switch (result.type()) { switch (result.type()) {
@@ -136,6 +140,7 @@ struct view_downloads_filter : std::unary_function<Download*, bool> {
} }
const torrent::Object& m_command; const torrent::Object& m_command;
const torrent::Object& m_command2;
}; };
void void
@@ -262,8 +267,8 @@ View::filter() {
return; return;
// Parition the list in two steps so we know which elements changed. // Parition the list in two steps so we know which elements changed.
iterator splitVisible = std::stable_partition(begin_visible(), end_visible(), view_downloads_filter(m_filter)); iterator splitVisible = std::stable_partition(begin_visible(), end_visible(), view_downloads_filter(m_filter, m_temp_filter));
iterator splitFiltered = std::stable_partition(begin_filtered(), end_filtered(), view_downloads_filter(m_filter)); iterator splitFiltered = std::stable_partition(begin_filtered(), end_filtered(), view_downloads_filter(m_filter, m_temp_filter));
base_type changed(splitVisible, splitFiltered); base_type changed(splitVisible, splitFiltered);
iterator splitChanged = changed.begin() + std::distance(splitVisible, end_visible()); iterator splitChanged = changed.begin() + std::distance(splitVisible, end_visible());
@@ -296,10 +301,10 @@ View::filter() {
} }
void void
View::filter_by(const torrent::Object& condition, View::base_type& result) View::filter_by(const torrent::Object& condition, View::base_type& result) {
{
// std::copy_if(begin_visible(), end_visible(), result.begin(), view_downloads_filter(condition)); // std::copy_if(begin_visible(), end_visible(), result.begin(), view_downloads_filter(condition));
view_downloads_filter matches = view_downloads_filter(condition); view_downloads_filter matches = view_downloads_filter(condition, m_temp_filter);
for (iterator itr = begin_visible(); itr != end_visible(); ++itr) for (iterator itr = begin_visible(); itr != end_visible(); ++itr)
if (matches(*itr)) if (matches(*itr))
result.push_back(*itr); result.push_back(*itr);
@@ -312,8 +317,7 @@ View::filter_download(core::Download* download) {
if (itr == base_type::end()) if (itr == base_type::end())
throw torrent::internal_error("View::filter_download(...) could not find download."); throw torrent::internal_error("View::filter_download(...) could not find download.");
if (view_downloads_filter(m_filter)(download)) { if (view_downloads_filter(m_filter, m_temp_filter)(download)) {
if (itr >= end_visible()) { if (itr >= end_visible()) {
erase_internal(itr); erase_internal(itr);
insert_visible(download); insert_visible(download);
+4 -1
View File
@@ -124,7 +124,9 @@ public:
void filter_download(core::Download* download); void filter_download(core::Download* download);
const torrent::Object& get_filter() const { return m_filter; } const torrent::Object& get_filter() const { return m_filter; }
void set_filter(const torrent::Object& s) { m_filter = s; } void set_filter(const torrent::Object& s) { m_filter = s; }
const torrent::Object& get_filter_temp() const { return m_temp_filter; }
void set_filter_temp(const torrent::Object& s) { m_temp_filter = s; }
void set_filter_on_event(const std::string& event); void set_filter_on_event(const std::string& event);
void clear_filter_on(); void clear_filter_on();
@@ -173,6 +175,7 @@ private:
torrent::Object m_sortCurrent; torrent::Object m_sortCurrent;
torrent::Object m_filter; torrent::Object m_filter;
torrent::Object m_temp_filter; // Temporary view filter (eg: name based filter)
torrent::Object m_event_added; torrent::Object m_event_added;
torrent::Object m_event_removed; torrent::Object m_event_removed;
+8
View File
@@ -109,6 +109,14 @@ ViewManager::set_filter(const std::string& name, const torrent::Object& cmd) {
(*viewItr)->filter(); (*viewItr)->filter();
} }
void
ViewManager::set_filter_temp(const std::string& name, const torrent::Object& cmd) {
iterator viewItr = find_throw(name);
(*viewItr)->set_filter_temp(cmd);
(*viewItr)->filter();
}
void void
ViewManager::set_filter_on(const std::string& name, const filter_args& args) { ViewManager::set_filter_on(const std::string& name, const filter_args& args) {
iterator viewItr = find_throw(name); iterator viewItr = find_throw(name);
+1
View File
@@ -93,6 +93,7 @@ public:
void set_sort_current(const std::string& name, const torrent::Object& cmd) { (*find_throw(name))->set_sort_current(cmd); } void set_sort_current(const std::string& name, const torrent::Object& cmd) { (*find_throw(name))->set_sort_current(cmd); }
void set_filter(const std::string& name, const torrent::Object& cmd); void set_filter(const std::string& name, const torrent::Object& cmd);
void set_filter_temp(const std::string& name, const torrent::Object& cmd);
void set_filter_on(const std::string& name, const filter_args& args); void set_filter_on(const std::string& name, const filter_args& args);
void set_event_added(const std::string& name, const torrent::Object& cmd) { (*find_throw(name))->set_event_added(cmd); } void set_event_added(const std::string& name, const torrent::Object& cmd) { (*find_throw(name))->set_event_added(cmd); }
+1 -1
View File
@@ -81,7 +81,7 @@ WindowDownloadList::redraw() {
if (m_view == NULL) if (m_view == NULL)
return; return;
m_canvas->print(0, 0, "%s", ("[View: " + m_view->name() + "]").c_str()); m_canvas->print(0, 0, "%s", ("[View: " + m_view->name() + (m_view->get_filter_temp().is_empty() ? "" : " (filtered)") + "]").c_str());
if (m_view->empty_visible() || m_canvas->width() < 5 || m_canvas->height() < 2) if (m_view->empty_visible() || m_canvas->width() < 5 || m_canvas->height() < 2)
return; return;
+44
View File
@@ -36,6 +36,8 @@
#include "config.h" #include "config.h"
#include <sstream>
#include <rak/functional.h> #include <rak/functional.h>
#include <rak/string_manip.h> #include <rak/string_manip.h>
#include <torrent/exceptions.h> #include <torrent/exceptions.h>
@@ -259,6 +261,25 @@ DownloadList::receive_view_input(Input type) {
title = "command"; title = "command";
break; break;
case INPUT_FILTER:
{
// Do not allow to subfilter the defined excluded views
const std::string excluded_views = rpc::call_command_string("view.filter.temp.excluded");
std::stringstream ss(excluded_views);
std::string view_name_var;
while(ss.good()) {
std::getline(ss, view_name_var, ',');
if (current_view()->name() == rak::trim(view_name_var)) {
control->core()->push_log_std("View '" + current_view()->name() + "' can't be filtered.");
return;
}
}
title = "filter";
}
break;
default: default:
throw torrent::internal_error("DownloadList::receive_view_input(...) Invalid input type."); throw torrent::internal_error("DownloadList::receive_view_input(...) Invalid input type.");
} }
@@ -332,6 +353,28 @@ DownloadList::receive_exit_input(Input type) {
input->str()); input->str());
break; break;
case INPUT_FILTER:
if (input->str().empty()) {
if (rpc::call_command_value("view.filter.temp.log"))
control->core()->push_log_std("Clear temporary filter on '" + current_view()->name() + "' view.");
current_view()->set_filter_temp(torrent::Object());
current_view()->filter();
current_view()->sort();
} else {
std::string pattern = input->str();
if (pattern.back() != '$')
pattern = pattern + ".*";
if (pattern.front() != '^')
pattern = ".*" + pattern;
std::transform(pattern.begin(), pattern.end(), pattern.begin(), ::tolower);
std::string temp_filter = "match={d.name=," + pattern + "}";
if (rpc::call_command_value("view.filter.temp.log"))
control->core()->push_log_std("Temporary filter on '" + current_view()->name() + "' view: " + pattern);
current_view()->set_filter_temp(temp_filter);
current_view()->filter();
}
break;
default: default:
throw torrent::internal_error("DownloadList::receive_exit_input(...) Invalid input type."); throw torrent::internal_error("DownloadList::receive_exit_input(...) Invalid input type.");
} }
@@ -353,6 +396,7 @@ DownloadList::setup_keys() {
m_bindings[KEY_ENTER] = std::bind(&DownloadList::receive_view_input, this, INPUT_LOAD_MODIFIED); m_bindings[KEY_ENTER] = std::bind(&DownloadList::receive_view_input, this, INPUT_LOAD_MODIFIED);
m_bindings['\x0F'] = std::bind(&DownloadList::receive_view_input, this, INPUT_CHANGE_DIRECTORY); m_bindings['\x0F'] = std::bind(&DownloadList::receive_view_input, this, INPUT_CHANGE_DIRECTORY);
m_bindings['X' - '@'] = std::bind(&DownloadList::receive_view_input, this, INPUT_COMMAND); m_bindings['X' - '@'] = std::bind(&DownloadList::receive_view_input, this, INPUT_COMMAND);
m_bindings['F'] = std::bind(&DownloadList::receive_view_input, this, INPUT_FILTER);
m_uiArray[DISPLAY_LOG]->bindings()[KEY_LEFT] = m_uiArray[DISPLAY_LOG]->bindings()[KEY_LEFT] =
m_uiArray[DISPLAY_LOG]->bindings()['B' - '@'] = m_uiArray[DISPLAY_LOG]->bindings()['B' - '@'] =
+1
View File
@@ -87,6 +87,7 @@ public:
INPUT_LOAD_MODIFIED, INPUT_LOAD_MODIFIED,
INPUT_CHANGE_DIRECTORY, INPUT_CHANGE_DIRECTORY,
INPUT_COMMAND, INPUT_COMMAND,
INPUT_FILTER,
INPUT_EOI INPUT_EOI
} Input; } Input;