* Change :rtorrent:state to an integer.

* Split up DownloadList::insert to get proper ordering of slot map
calls and variable initialization.

* Added filtering to ViewDownloads.


git-svn-id: svn://rakshasa.no/libtorrent/trunk/rtorrent@675 e378c898-3ddf-0310-93e7-cc216c733640
This commit is contained in:
rakshasa
2006-04-26 21:23:37 +00:00
parent c5c9a1ddae
commit 8ae5e51a0f
11 changed files with 224 additions and 64 deletions
+1 -1
View File
@@ -70,7 +70,7 @@ Download::Download(download_type d) :
m_variables.insert("connection_leech", new utils::VariableAny(connection_type_to_string(download_type::CONNECTION_LEECH)));
m_variables.insert("connection_seed", new utils::VariableAny(connection_type_to_string(download_type::CONNECTION_SEED)));
m_variables.insert("state", new utils::VariableObject(bencode(), "rtorrent", "state", torrent::Object::TYPE_STRING));
m_variables.insert("state", new utils::VariableObject(bencode(), "rtorrent", "state", torrent::Object::TYPE_VALUE));
m_variables.insert("tied_to_file", new utils::VariableObject(bencode(), "rtorrent", "tied_to_file", torrent::Object::TYPE_STRING));
// The "state_changed" variable is required to be a valid unix time
+29 -21
View File
@@ -141,16 +141,16 @@ DownloadFactory::receive_success() {
if (m_stream == NULL)
throw torrent::client_error("DownloadFactory::receive_success() called on an object with m_stream == NULL");
DownloadList::iterator itr = m_manager->download_list().insert(m_stream, m_printLog);
Download* download = m_manager->download_list().create(m_stream, m_printLog);
if (itr == m_manager->download_list().end()) {
if (download == NULL) {
// core::Manager should already have added the error message to
// the log.
m_slotFinished();
return;
}
torrent::Object* root = (*itr)->bencode();
torrent::Object* root = download->bencode();
if (!m_session) {
// We only allow session torrents to keep their
@@ -164,37 +164,46 @@ DownloadFactory::receive_success() {
torrent::Object* rtorrent = &root->get_key("rtorrent");
initialize_rtorrent(*itr, rtorrent);
initialize_rtorrent(download, rtorrent);
if (m_manager->download_list().insert(download) == m_manager->download_list().end()) {
// ATM doesn't really ever get here.
delete download;
m_slotFinished();
return;
}
// Move to 'rtorrent'.
(*itr)->variable()->set("connection_leech", m_variables.get("connection_leech"));
(*itr)->variable()->set("connection_seed", m_variables.get("connection_seed"));
(*itr)->variable()->set("min_peers", control->variable()->get("min_peers"));
(*itr)->variable()->set("max_peers", control->variable()->get("max_peers"));
(*itr)->variable()->set("max_uploads", control->variable()->get("max_uploads"));
download->variable()->set("connection_leech", m_variables.get("connection_leech"));
download->variable()->set("connection_seed", m_variables.get("connection_seed"));
download->variable()->set("min_peers", control->variable()->get("min_peers"));
download->variable()->set("max_peers", control->variable()->get("max_peers"));
download->variable()->set("max_uploads", control->variable()->get("max_uploads"));
if (!control->variable()->get_value("use_udp_trackers"))
(*itr)->enable_udp_trackers(false);
download->enable_udp_trackers(false);
if (m_session) {
if (!rtorrent->has_key_string("directory"))
(*itr)->variable()->set("directory", m_variables.get("directory"));
download->variable()->set("directory", m_variables.get("directory"));
else
(*itr)->variable()->set("directory", rtorrent->get_key("directory"));
download->variable()->set("directory", rtorrent->get_key("directory"));
if ((*itr)->variable()->get_string("state") == "started")
m_manager->download_list().resume(*itr);
if (download->variable()->get_value("state") == 1)
m_manager->download_list().resume(download);
} else {
(*itr)->variable()->set("directory", m_variables.get("directory"));
download->variable()->set("directory", m_variables.get("directory"));
if (m_variables.get("tied_to_file").as_value())
(*itr)->variable()->set("tied_to_file", m_uri);
download->variable()->set("tied_to_file", m_uri);
// Use the state thingie here, move below.
if (m_start)
m_manager->download_list().start(*itr);
m_manager->download_list().start(download);
m_manager->download_store().save(*itr);
m_manager->download_store().save(download);
}
m_slotFinished();
@@ -216,9 +225,8 @@ DownloadFactory::receive_failed(const std::string& msg) {
void
DownloadFactory::initialize_rtorrent(Download* download, torrent::Object* rtorrent) {
if (!rtorrent->has_key_string("state") ||
(rtorrent->get_key("state").as_string() != "stopped" && rtorrent->get_key("state").as_string() != "started")) {
rtorrent->insert_key("state", "stopped");
if (!rtorrent->has_key_value("state") || rtorrent->get_key("state").as_value() > 1) {
rtorrent->insert_key("state", (int64_t)m_start);
rtorrent->insert_key("state_changed", cachedTime.seconds());
} else if (!rtorrent->has_key_value("state_changed") ||
+15 -7
View File
@@ -64,13 +64,12 @@ struct download_list_call {
Download* m_download;
};
DownloadList::iterator
DownloadList::insert(std::istream* str, bool printLog) {
Download*
DownloadList::create(std::istream* str, bool printLog) {
torrent::Object* object = new torrent::Object;
torrent::Download download;
try {
*str >> *object;
// Catch, delete.
@@ -85,16 +84,25 @@ DownloadList::insert(std::istream* str, bool printLog) {
if (printLog)
control->core()->push_log(e.what());
return end();
return NULL;
}
iterator itr = Base::insert(end(), new Download(download));
// There's no non-critical exceptions that should be throwable by
// the ctor, so don't catch.
return new Download(download);
}
DownloadList::iterator
DownloadList::insert(Download* d) {
iterator itr = Base::insert(end(), d);
try {
(*itr)->download()->signal_download_done(sigc::bind(sigc::mem_fun(*this, &DownloadList::finished), *itr));
std::for_each(m_slotMapInsert.begin(), m_slotMapInsert.end(), download_list_call(*itr));
} catch (torrent::local_error& e) {
// Should perhaps relax this, just print an error and remove the
// downloads?
throw torrent::internal_error("Caught during DownloadList::insert part 2: " + std::string(e.what()));
}
@@ -152,14 +160,14 @@ DownloadList::close(Download* d) {
void
DownloadList::start(Download* d) {
d->variable()->set("state", "started");
d->variable()->set("state", (int64_t)1);
resume(d);
}
void
DownloadList::stop(Download* d) {
d->variable()->set("state", "stopped");
d->variable()->set("state", (int64_t)0);
pause(d);
}
+4 -1
View File
@@ -73,7 +73,10 @@ public:
~DownloadList() { clear(); }
iterator insert(std::istream* str, bool printLog);
// Might move this to DownloadFactory.
Download* create(std::istream* str, bool printLog);
iterator insert(Download* d);
void erase(Download* d);
iterator erase(iterator itr);
+49 -8
View File
@@ -73,6 +73,7 @@ ViewDownloads::initialize(const std::string& name, core::DownloadList* list) {
m_name = name;
m_list = list;
m_size = 0;
m_focus = 0;
std::for_each(m_list->begin(), m_list->end(), std::bind1st(std::mem_fun(&ViewDownloads::received_insert), this));
@@ -101,6 +102,9 @@ ViewDownloads::prev_focus() {
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<Download*, Download*, bool> {
view_downloads_compare(const ViewDownloads::sort_list& s) : m_sort(s) {}
@@ -120,6 +124,22 @@ struct view_downloads_compare : std::binary_function<Download*, Download*, bool>
const ViewDownloads::sort_list& m_sort;
};
struct view_downloads_filter : std::unary_function<Download*, bool> {
view_downloads_filter(const ViewDownloads::filter_list& s) : m_filter(s) {}
bool operator () (Download* d1) const {
for (ViewDownloads::filter_list::const_iterator itr = m_filter.begin(), last = m_filter.end(); itr != last; ++itr)
if (!(**itr)(d1))
return false;
// The default filter action is to return true, to not filter the
// download out.
return true;
}
const ViewDownloads::filter_list& m_filter;
};
void
ViewDownloads::sort() {
Download* curFocus = focus() != end() ? *focus() : NULL;
@@ -132,11 +152,32 @@ ViewDownloads::sort() {
}
void
ViewDownloads::received_insert(core::Download* d) {
iterator itr = std::find_if(begin(), end(), std::bind1st(view_downloads_compare(m_sortNew), d));
ViewDownloads::filter() {
iterator split = std::stable_partition(base_type::begin(), base_type::end(), view_downloads_filter(m_filter));
if (m_focus >= position(itr))
m_focus++;
m_size = position(split);
// Fix focus
m_focus = std::min(m_focus, m_size);
}
void
ViewDownloads::received_insert(core::Download* d) {
// Chagne according to filtered/not.
iterator itr;
if (view_downloads_filter(m_filter)(d)) {
itr = std::find_if(begin(), end(), std::bind1st(view_downloads_compare(m_sortNew), d));
m_size++;
m_focus += (m_focus >= position(itr));
} else {
itr = end_filtered();
}
if (m_focus > m_size)
throw torrent::internal_error("ViewDownloads::received_insert(...) m_focus > m_size.");
base_type::insert(itr, d);
m_signalChanged.emit();
@@ -144,13 +185,13 @@ ViewDownloads::received_insert(core::Download* d) {
void
ViewDownloads::received_erase(core::Download* d) {
iterator itr = std::find(begin(), end(), d);
iterator itr = std::find(begin(), end_filtered(), d);
if (itr == end())
if (itr == end_filtered())
return;
if (m_focus > position(itr))
m_focus--;
m_size -= (itr < end());
m_focus -= (m_focus > position(itr));
base_type::erase(itr);
m_signalChanged.emit();
+38 -15
View File
@@ -42,6 +42,11 @@
//
// Do we want to be able to modify the underlying DownloadList from
// here?
//
// ViewDownloads::m_size indicates the number of Download's that
// remain visible, e.g. has not been filtered out. The Download's that
// were filtered are still in the underlying vector, but cannot be
// accessed through the normal stl container functions.
#ifndef RTORRENT_CORE_VIEW_DOWNLOADS_H
#define RTORRENT_CORE_VIEW_DOWNLOADS_H
@@ -57,12 +62,14 @@ namespace core {
class Download;
class DownloadList;
class ViewSort;
class ViewFilter;
class ViewDownloads : public std::vector<core::Download*> {
public:
typedef std::vector<core::Download*> base_type;
typedef sigc::signal0<void> signal_type;
typedef std::vector<const ViewSort*> sort_list;
typedef std::vector<core::Download*> base_type;
typedef sigc::signal0<void> signal_type;
typedef std::vector<const ViewSort*> sort_list;
typedef std::vector<const ViewFilter*> filter_list;
using base_type::iterator;
using base_type::const_iterator;
@@ -72,12 +79,7 @@ public:
using base_type::size_type;
using base_type::begin;
using base_type::end;
using base_type::rbegin;
using base_type::rend;
using base_type::empty;
using base_type::size;
ViewDownloads() {}
~ViewDownloads();
@@ -86,6 +88,18 @@ public:
const std::string& name() const { return m_name; }
bool empty() const { return m_size == 0; }
size_type size() const { return m_size; }
// Perhaps this should be renamed?
iterator end() { return begin() + m_size; }
const_iterator end() const { return begin() + m_size; }
// using base_type::rend;
iterator end_filtered() { return base_type::end(); }
const_iterator end_filtered() const { return base_type::end(); }
iterator focus() { return begin() + m_focus; }
const_iterator focus() const { return begin() + m_focus; }
void set_focus(iterator itr) { m_focus = position(itr); m_signalChanged.emit(); }
@@ -98,6 +112,10 @@ public:
void set_sort_new(const sort_list& s) { m_sortNew = s; }
void set_sort_current(const sort_list& s) { m_sortCurrent = s; }
// Need to explicity trigger filtering.
void filter();
void set_filter(const filter_list& s) { m_filter = s; }
// Don't connect any slots until after initialize else it get's
// triggered when adding the Download's in DownloadList.
signal_type& signal_changed() { return m_signalChanged; }
@@ -109,18 +127,22 @@ private:
void received_insert(core::Download* d);
void received_erase(core::Download* d);
size_type position(const_iterator itr) const { return (size_type)(itr - begin()); }
size_type position(const_iterator itr) const { return itr - begin(); }
// An received thing for changed status so we can sort and filter.
std::string m_name;
core::DownloadList* m_list;
size_type m_size;
size_type m_focus;
sort_list m_sortNew;
sort_list m_sortCurrent;
filter_list m_filter;
// Timer, last changed.
signal_type m_signalChanged;
@@ -130,15 +152,16 @@ class ViewSort {
public:
virtual ~ViewSort() {}
// Add various extra stuff here, like bool flags for can sort new,
// normal etc.
// How to take focus into account?
//virtual bool filter(Download* d1) const { return true; }
virtual bool less(Download* d1, Download* d2) const = 0;
};
class ViewFilter {
public:
virtual ~ViewFilter() {}
virtual bool operator () (Download* d1) const = 0;
};
}
#endif
+50 -5
View File
@@ -95,6 +95,22 @@ private:
ViewSort* m_sort;
};
class ViewFilterVariableValue : public ViewFilter {
public:
ViewFilterVariableValue(const std::string& name, torrent::Object::value_type v) :
m_name(name), m_value(v) {}
virtual bool operator () (Download* d1) const {
return d1->variable()->get_value(m_name) == m_value;
}
private:
std::string m_name;
torrent::Object::value_type m_value;
};
// Really need to implement a factory and allow options in the sort
// statements.
ViewManager::ViewManager(DownloadList* dl) :
m_list(dl) {
@@ -103,11 +119,13 @@ ViewManager::ViewManager(DownloadList* dl) :
m_sort["name"] = new ViewSortName();
m_sort["name_reverse"] = new ViewSortReverse(new ViewSortName());
m_sort["started"] = new ViewSortVariable("state", "started");
m_sort["stopped"] = new ViewSortVariable("state", "stopped");
m_sort["stopped"] = new ViewSortVariableValue("state");
m_sort["started"] = new ViewSortReverse(new ViewSortVariableValue("state"));
m_sort["state_changed"] = new ViewSortVariableValue("state_changed");
m_sort["state_changed_reverse"] = new ViewSortReverse(new ViewSortVariableValue("state_changed"));
m_filter["started"] = new ViewFilterVariableValue("state", 1);
}
void
@@ -145,7 +163,7 @@ ViewManager::find_throw(const std::string& name) {
}
inline ViewManager::sort_list
ViewManager::build_list(const sort_args& args) {
ViewManager::build_sort_list(const sort_args& args) {
ViewDownloads::sort_list sortList;
sortList.reserve(args.size());
@@ -165,6 +183,9 @@ void
ViewManager::sort(const std::string& name) {
iterator viewItr = find_throw(name);
// Should we rename sort, or add a seperate function?
(*viewItr)->filter();
(*viewItr)->sort();
}
@@ -172,14 +193,38 @@ void
ViewManager::set_sort_new(const std::string& name, const sort_args& sort) {
iterator viewItr = find_throw(name);
(*viewItr)->set_sort_new(build_list(sort));
(*viewItr)->set_sort_new(build_sort_list(sort));
}
void
ViewManager::set_sort_current(const std::string& name, const sort_args& sort) {
iterator viewItr = find_throw(name);
(*viewItr)->set_sort_current(build_list(sort));
(*viewItr)->set_sort_current(build_sort_list(sort));
}
inline ViewManager::filter_list
ViewManager::build_filter_list(const filter_args& args) {
ViewDownloads::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);
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) {
iterator viewItr = find_throw(name);
(*viewItr)->set_filter(build_filter_list(args));
}
}
+10 -1
View File
@@ -51,10 +51,15 @@ class ViewSort;
class ViewManager : public rak::unordered_vector<ViewDownloads*> {
public:
typedef rak::unordered_vector<ViewDownloads*> base_type;
typedef std::map<std::string, ViewSort*> sort_map;
typedef ViewDownloads::sort_list sort_list;
typedef std::list<std::string> sort_args;
typedef std::map<std::string, ViewFilter*> filter_map;
typedef ViewDownloads::filter_list filter_list;
typedef std::list<std::string> filter_args;
using base_type::iterator;
using base_type::const_iterator;
using base_type::reverse_iterator;
@@ -92,12 +97,16 @@ 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);
private:
inline sort_list build_list(const sort_args& args);
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;
};
}
+3 -2
View File
@@ -163,6 +163,7 @@ main(int argc, char** argv) {
initialize_option_handler(control);
control->variable()->process_command("view_add = main");
control->variable()->process_command("view_filter = main,started");
control->variable()->process_command("view_sort_new = main,name");
control->variable()->process_command("view_sort_current = main,name");
@@ -170,8 +171,8 @@ main(int argc, char** argv) {
control->variable()->process_command("view_add = scheduler");
control->variable()->process_command("view_sort_new = scheduler,state_changed"); // add started?
control->variable()->process_command("view_sort_current = scheduler,state_changed");
// control->variable()->process_command("schedule = scheduler,10,10,download_scheduler=");
// control->variable()->process_command("schedule = scheduler,10,10,download_scheduler=");
// Move env and go through "try_import".
// if (!control->variable()->process_file("~/.rtorrent.rc"))
+23
View File
@@ -225,6 +225,27 @@ apply_view_sort_new(Control* control, const std::string& arg) {
control->view_manager()->set_sort_new(name, sortArgs);
}
void
apply_view_filter(Control* control, const std::string& arg) {
rak::split_iterator_t<std::string> itr = rak::split_iterator(arg, ',');
std::string name = rak::trim(*itr);
if (name.empty())
throw torrent::input_error("First argument must be a string.");
core::ViewManager::filter_args filterArgs;
while (++itr != rak::split_iterator(arg)) {
filterArgs.push_back(rak::trim(*itr));
if (filterArgs.back().empty())
throw torrent::input_error("One of the arguments is empty.");
}
control->view_manager()->set_filter(name, filterArgs);
}
void
apply_download_scheduler(core::Scheduler* scheduler, __UNUSED const std::string& arg) {
scheduler->update();
@@ -285,6 +306,8 @@ initialize_option_handler(Control* c) {
variables->insert("view_sort_new", new utils::VariableStringSlot(rak::value_fn(std::string()), rak::bind_ptr_fn(&apply_view_sort_new, c)));
variables->insert("view_sort_current", new utils::VariableStringSlot(rak::value_fn(std::string()), rak::bind_ptr_fn(&apply_view_sort_current, c)));
variables->insert("view_filter", new utils::VariableStringSlot(rak::value_fn(std::string()), rak::bind_ptr_fn(&apply_view_filter, c)));
variables->insert("schedule", new utils::VariableStringSlot(rak::value_fn(std::string()),
rak::mem_fn<const std::string&>(c->command_scheduler(), &CommandScheduler::parse)));
variables->insert("schedule_remove", new utils::VariableStringSlot(rak::value_fn(std::string()),
+2 -3
View File
@@ -108,9 +108,8 @@ Root::setup_keys() {
m_bindings['D'] = sigc::bind(sigc::mem_fun(*this, &Root::adjust_down_throttle), 50);
m_bindings['C'] = sigc::bind(sigc::mem_fun(*this, &Root::adjust_down_throttle), -50);
//m_bindings[KEY_RESIZE] = sigc::mem_fun(*m_control->display(), &display::Manager::adjust_layout);
m_bindings['\x0C'] = sigc::mem_fun(m_control->display(), &display::Manager::force_redraw);
m_bindings['\x11'] = sigc::mem_fun(m_control, &Control::receive_normal_shutdown);
m_bindings['\x0C'] = sigc::mem_fun(m_control->display(), &display::Manager::force_redraw); // ^L
m_bindings['\x11'] = sigc::mem_fun(m_control, &Control::receive_normal_shutdown); // ^Q
}
void