diff --git a/doc/rtorrent.1.xml b/doc/rtorrent.1.xml index 56888087..611a263b 100644 --- a/doc/rtorrent.1.xml +++ b/doc/rtorrent.1.xml @@ -572,6 +572,7 @@ torrent::input_error exception on bad input. + ADVANCED SETTINGS diff --git a/src/core/download_list.cc b/src/core/download_list.cc index 2b1bd5a2..87de839b 100644 --- a/src/core/download_list.cc +++ b/src/core/download_list.cc @@ -67,6 +67,7 @@ struct download_list_call { DownloadList::iterator DownloadList::insert(std::istream* str, bool printLog) { torrent::Object* object = new torrent::Object; + torrent::Download download; try { @@ -76,14 +77,7 @@ DownloadList::insert(std::istream* str, bool printLog) { if (str->fail()) throw torrent::input_error("Could not create download, the input is not a valid torrent."); - torrent::Download d = torrent::download_add(object); - - iterator itr = Base::insert(end(), new Download(d)); - - (*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)); - - return itr; + download = torrent::download_add(object); } catch (torrent::local_error& e) { delete object; @@ -93,6 +87,18 @@ DownloadList::insert(std::istream* str, bool printLog) { return end(); } + + iterator itr = Base::insert(end(), new Download(download)); + + 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) { + throw torrent::internal_error("Caught during DownloadList::insert part 2: " + std::string(e.what())); + } + + return itr; } void diff --git a/src/core/view_downloads.cc b/src/core/view_downloads.cc index 685cda90..eef8a581 100644 --- a/src/core/view_downloads.cc +++ b/src/core/view_downloads.cc @@ -101,22 +101,31 @@ ViewDownloads::prev_focus() { m_signalChanged.emit(); } -// Also add focus thingie here. +// Also add focus thingie here? struct view_downloads_compare : std::binary_function { - view_downloads_compare(const ViewSort* s) : m_sort(s) {} + view_downloads_compare(const ViewDownloads::sort_list& s) : m_sort(s) {} bool operator () (Download* d1, Download* d2) const { - return m_sort->compare(d1, d2); + for (ViewDownloads::sort_list::const_iterator itr = m_sort.begin(), last = m_sort.end(); itr != last; ++itr) + if ((*itr)->less(d1, d2)) + return true; + else if ((*itr)->less(d2, d1)) + return false; + + // Since we're testing equivalence, return false if we're + // equal. This is a requirement for the stl sorting algorithms. + return false; } - const ViewSort* m_sort; + const ViewDownloads::sort_list& m_sort; }; void -ViewDownloads::sort(const ViewSort* s) { +ViewDownloads::sort() { Download* curFocus = focus() != end() ? *focus() : NULL; - std::sort(begin(), end(), view_downloads_compare(s)); + // Don't go randomly switching around equivalent elements. + std::stable_sort(begin(), end(), view_downloads_compare(m_sortCurrent)); m_focus = position(std::find(begin(), end(), curFocus)); m_signalChanged.emit(); diff --git a/src/core/view_downloads.h b/src/core/view_downloads.h index d26b394c..15ddbb84 100644 --- a/src/core/view_downloads.h +++ b/src/core/view_downloads.h @@ -49,6 +49,7 @@ #include #include #include +//#include #include namespace core { @@ -61,6 +62,7 @@ class ViewDownloads : public 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; @@ -77,7 +79,7 @@ public: using base_type::empty; using base_type::size; - ViewDownloads() : m_sortNew(NULL) {} + ViewDownloads() {} ~ViewDownloads(); void initialize(const std::string& name, core::DownloadList* list); @@ -91,11 +93,10 @@ public: void next_focus(); void prev_focus(); - void sort(const ViewSort* s); + void sort(); - // This is set to ViewNone by default by ViewManager before - // initialize is called. - void set_sort_new(const ViewSort* s) { m_sortNew = s; } + void set_sort_new(const sort_list& s) { m_sortNew = s; } + void set_sort_current(const sort_list& s) { m_sortCurrent = s; } // Don't connect any slots until after initialize else it get's // triggered when adding the Download's in DownloadList. @@ -117,7 +118,8 @@ private: core::DownloadList* m_list; size_type m_focus; - const ViewSort* m_sortNew; + sort_list m_sortNew; + sort_list m_sortCurrent; // Timer, last changed. @@ -132,8 +134,9 @@ public: // normal etc. // How to take focus into account? + //virtual bool filter(Download* d1) const { return true; } - virtual bool compare(Download* d1, Download* d2) const = 0; + virtual bool less(Download* d1, Download* d2) const = 0; }; } diff --git a/src/core/view_manager.cc b/src/core/view_manager.cc index 9dc0b56f..c31c48d3 100644 --- a/src/core/view_manager.cc +++ b/src/core/view_manager.cc @@ -46,16 +46,9 @@ namespace core { -class ViewSortFirst : public ViewSort { -public: - virtual bool compare(Download* d1, Download* d2) const { - return true; - } -}; - class ViewSortName : public ViewSort { public: - virtual bool compare(Download* d1, Download* d2) const { + virtual bool less(Download* d1, Download* d2) const { return d1->download()->name() < d2->download()->name(); } }; @@ -65,9 +58,9 @@ public: ViewSortVariable(const std::string& name, const std::string& value) : m_name(name), m_value(value) {} - virtual bool compare(Download* d1, Download* d2) const { + virtual bool less(Download* d1, Download* d2) const { return - d1->variable()->get_string(m_name) == m_value || + d1->variable()->get_string(m_name) == m_value && d2->variable()->get_string(m_name) != m_value; } @@ -81,42 +74,24 @@ public: ViewSortReverse(ViewSort* s) : m_sort(s) {} ~ViewSortReverse() { delete m_sort; } - virtual bool compare(Download* d1, Download* d2) const { - return m_sort->compare(d2, d1); + virtual bool less(Download* d1, Download* d2) const { + return m_sort->less(d2, d1); } private: ViewSort* m_sort; }; -// Hmm, use a list in ViewDownloads instead? -class ViewSortAnd : public ViewSort { -public: - ViewSortAnd(ViewSort* s1, ViewSort* s2) : m_sort1(s1), m_sort2(s2) {} - ~ViewSortAnd() { delete m_sort1; delete m_sort2; } - - virtual bool compare(Download* d1, Download* d2) const { - return m_sort1->compare(d1, d2) && m_sort2->compare(d1, d2); - } - -private: - ViewSort* m_sort1; - ViewSort* m_sort2; -}; - ViewManager::ViewManager(DownloadList* dl) : m_list(dl) { - m_sort["first"] = new ViewSortFirst(); - m_sort["last"] = new ViewSortReverse(new ViewSortFirst()); +// m_sort["first"] = new ViewSortNot(new ViewSort()); +// m_sort["last"] = new ViewSort(); m_sort["name"] = new ViewSortName(); m_sort["name_reverse"] = new ViewSortReverse(new ViewSortName()); m_sort["started"] = new ViewSortVariable("state", "started"); - m_sort["started_name"] = new ViewSortAnd(new ViewSortVariable("state", "started"), new ViewSortName()); - m_sort["stopped"] = new ViewSortVariable("state", "stopped"); - m_sort["stopped_name"] = new ViewSortAnd(new ViewSortVariable("state", "stopped"), new ViewSortName()); } void @@ -133,8 +108,6 @@ ViewManager::insert(const std::string& name) { throw torrent::internal_error("ViewManager::insert(...) name already inserted."); ViewDownloads* view = new ViewDownloads(); - - view->set_sort_new(m_sort["last"]); view->initialize(name, m_list); return base_type::insert(end(), view); @@ -155,28 +128,42 @@ ViewManager::find_throw(const std::string& name) { return itr; } -void -ViewManager::sort(const std::string& name, const std::string& sort) { - iterator viewItr = find_throw(name); +inline ViewManager::sort_list +ViewManager::build_list(const sort_args& args) { + ViewDownloads::sort_list sortList; + sortList.reserve(args.size()); - sort_map::const_iterator sortItr = m_sort.find(sort); + for (sort_args::const_iterator itr = args.begin(), last = args.end(); itr != last; ++itr) { + sort_map::const_iterator sortItr = m_sort.find(*itr); - if (sortItr == m_sort.end()) - throw torrent::input_error("Invalid sorting identifier."); + if (sortItr == m_sort.end()) + throw torrent::input_error("Invalid sorting identifier."); - (*viewItr)->sort(sortItr->second); + sortList.push_back(sortItr->second); + } + + return sortList; } void -ViewManager::set_sort_new(const std::string& name, const std::string& sort) { +ViewManager::sort(const std::string& name) { iterator viewItr = find_throw(name); - sort_map::const_iterator sortItr = m_sort.find(sort); + (*viewItr)->sort(); +} - if (sortItr == m_sort.end()) - throw torrent::input_error("Invalid sorting identifier."); +void +ViewManager::set_sort_new(const std::string& name, const sort_args& sort) { + iterator viewItr = find_throw(name); - (*viewItr)->set_sort_new(sortItr->second); + (*viewItr)->set_sort_new(build_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)); } } diff --git a/src/core/view_manager.h b/src/core/view_manager.h index bc961259..c7c04aab 100644 --- a/src/core/view_manager.h +++ b/src/core/view_manager.h @@ -41,6 +41,8 @@ #include #include +#include "view_downloads.h" + namespace core { class ViewDownloads; @@ -50,6 +52,8 @@ class ViewManager : public rak::unordered_vector { public: typedef rak::unordered_vector base_type; typedef std::map sort_map; + typedef ViewDownloads::sort_list sort_list; + typedef std::list sort_args; using base_type::iterator; using base_type::const_iterator; @@ -75,6 +79,7 @@ public: void clear(); iterator insert(const std::string& name); + void insert_throw(const std::string& name) { insert(name); } // When erasing, just 'disable' the view so that the users won't // suddenly find their pointer dangling? @@ -82,13 +87,14 @@ public: iterator find(const std::string& name); iterator find_throw(const std::string& name); - void sort(const std::string& name, const std::string& sort); + void sort(const std::string& name); - // For now, just take the sort type as a string. Later might move - // this lookup outside. - void set_sort_new(const std::string& name, const std::string& sort); + void set_sort_new(const std::string& name, const sort_args& sort); + void set_sort_current(const std::string& name, const sort_args& sort); private: + inline sort_list build_list(const sort_args& args); + DownloadList* m_list; sort_map m_sort; diff --git a/src/main.cc b/src/main.cc index 7b9fe60c..a9c7a829 100644 --- a/src/main.cc +++ b/src/main.cc @@ -164,10 +164,14 @@ main(int argc, char** argv) { control->variable()->process_command("view_add = main"); control->variable()->process_command("view_sort_new = main,name"); + control->variable()->process_command("view_sort_current = main,name"); // Move env and go through "try_import". - if (!control->variable()->process_file("~/.rtorrent.rc")) - control->core()->get_log_important().push_front("Could not load \"~/.rtorrent.rc\"."); +// if (!control->variable()->process_file("~/.rtorrent.rc")) +// control->core()->get_log_important().push_front("Could not load \"~/.rtorrent.rc\"."); + + // Complain. + control->variable()->process_command("try_import = ~/.rtorrent.rc"); int firstArg = parse_options(control, argc, argv); diff --git a/src/option_handler_rules.cc b/src/option_handler_rules.cc index f370f4f0..2f5cedca 100644 --- a/src/option_handler_rules.cc +++ b/src/option_handler_rules.cc @@ -183,26 +183,24 @@ apply_tos(const std::string& arg) { } void -apply_view_add(Control* control, const std::string& arg) { - // Restrict the range of characters. - - control->view_manager()->insert(rak::trim(arg)); -} - -void -apply_view_sort(Control* control, const std::string& arg) { +apply_view_sort_current(Control* control, const std::string& arg) { rak::split_iterator_t itr = rak::split_iterator(arg, ','); std::string name = rak::trim(*itr); - ++itr; - std::string sort = rak::trim(*itr); - ++itr; + if (name.empty()) + throw torrent::input_error("First argument must be a string."); - if (name.empty() || sort.empty() || itr != rak::split_iterator(arg)) - throw torrent::input_error("Invalid number of arguments."); + core::ViewManager::sort_args sortArgs; - control->view_manager()->sort(name, sort); + while (++itr != rak::split_iterator(arg)) { + sortArgs.push_back(rak::trim(*itr)); + + if (sortArgs.back().empty()) + throw torrent::input_error("One of the arguments is empty."); + } + + control->view_manager()->set_sort_current(name, sortArgs); } void @@ -210,15 +208,20 @@ apply_view_sort_new(Control* control, const std::string& arg) { rak::split_iterator_t itr = rak::split_iterator(arg, ','); std::string name = rak::trim(*itr); - ++itr; - std::string sort = rak::trim(*itr); - ++itr; + if (name.empty()) + throw torrent::input_error("First argument must be a string."); - if (name.empty() || sort.empty() || itr != rak::split_iterator(arg)) - throw torrent::input_error("Invalid number of arguments."); + core::ViewManager::sort_args sortArgs; - control->view_manager()->set_sort_new(name, sort); + while (++itr != rak::split_iterator(arg)) { + sortArgs.push_back(rak::trim(*itr)); + + if (sortArgs.back().empty()) + throw torrent::input_error("One of the arguments is empty."); + } + + control->view_manager()->set_sort_new(name, sortArgs); } void @@ -271,9 +274,10 @@ initialize_option_handler(Control* c) { variables->insert("try_import", new utils::VariableStringSlot(rak::value_fn(std::string()), rak::mem_fn(control->variable(), &utils::VariableMap::process_file_nothrow))); - variables->insert("view_add", new utils::VariableStringSlot(rak::value_fn(std::string()), rak::bind_ptr_fn(&apply_view_add, c))); - variables->insert("view_sort", new utils::VariableStringSlot(rak::value_fn(std::string()), rak::bind_ptr_fn(&apply_view_sort, c))); + variables->insert("view_add", new utils::VariableStringSlot(rak::value_fn(std::string()), rak::mem_fn(c->view_manager(), &core::ViewManager::insert_throw))); + variables->insert("view_sort", new utils::VariableStringSlot(rak::value_fn(std::string()), rak::mem_fn(c->view_manager(), &core::ViewManager::sort))); 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("schedule", new utils::VariableStringSlot(rak::value_fn(std::string()), rak::mem_fn(c->command_scheduler(), &CommandScheduler::parse)));