diff --git a/configure.ac b/configure.ac index 846a01ad..c7329ac8 100644 --- a/configure.ac +++ b/configure.ac @@ -1,4 +1,4 @@ -AC_INIT(rtorrent, 0.7.1, jaris@ifi.uio.no) +AC_INIT(rtorrent, 0.7.2, jaris@ifi.uio.no) AM_INIT_AUTOMAKE AM_CONFIG_HEADER(config.h) @@ -23,7 +23,7 @@ TORRENT_WITHOUT_NCURSESW() TORRENT_WITHOUT_STATVFS() TORRENT_WITHOUT_STATFS() -PKG_CHECK_MODULES(STUFF, sigc++-2.0 libtorrent >= 0.11.1, +PKG_CHECK_MODULES(STUFF, sigc++-2.0 libtorrent >= 0.11.2, CXXFLAGS="$CXXFLAGS $STUFF_CFLAGS $CURL_CFLAGS"; LIBS="$LIBS $STUFF_LIBS $CURL_LIBS") diff --git a/doc/rtorrent.1.xml b/doc/rtorrent.1.xml index 671fa138..6be07fa7 100644 --- a/doc/rtorrent.1.xml +++ b/doc/rtorrent.1.xml @@ -221,7 +221,8 @@ Toggle whether torrent ignores ratio settings. -> View torrent file list. Use the space-bar to change the file priority -and * to change the priority of all files. +and * to change the priority of all +files. Use / to collapse the directories. OUTDATED diff --git a/src/core/download_list.cc b/src/core/download_list.cc index 4574e340..13346d0b 100644 --- a/src/core/download_list.cc +++ b/src/core/download_list.cc @@ -315,7 +315,8 @@ DownloadList::resume(Download* download) { return; } - open_throw(download); + // This will never actually do anything due to the above hash check. + // open_throw(download); download->variable()->set("state_changed", cachedTime.seconds()); diff --git a/src/core/manager.cc b/src/core/manager.cc index c08e9ffe..2d7d81e0 100644 --- a/src/core/manager.cc +++ b/src/core/manager.cc @@ -491,65 +491,58 @@ Manager::receive_hashing_changed() { // Try quick hashing all those with hashing == initial, set them to // something else when failed. - for (View::iterator itr = m_hashingView->begin_visible(), last = m_hashingView->end_visible(); itr != last; ++itr) - try { - - if ((*itr)->is_hash_checking()) { - foundHashing = true; - continue; - } - - if ((*itr)->is_hash_checked()) - throw torrent::internal_error("core::Manager::receive_hashing_changed() hash already checked or checking."); + for (View::iterator itr = m_hashingView->begin_visible(), last = m_hashingView->end_visible(); itr != last; ++itr) { + if ((*itr)->is_hash_checked()) + throw torrent::internal_error("core::Manager::receive_hashing_changed() hash already checked or checking."); - if ((*itr)->is_hash_failed() || - (*itr)->variable()->get_value("hashing") != Download::variable_hashing_initial || - (*itr)->download()->chunks_hashed() != 0) - continue; + if ((*itr)->is_hash_checking()) { + foundHashing = true; + continue; + } + if ((*itr)->is_hash_failed()) + continue; + + bool tryQuick = + (*itr)->variable()->get_value("hashing") == Download::variable_hashing_initial && + (*itr)->download()->file_list()->bitfield()->empty(); + + if (!tryQuick && foundHashing) + continue; + + try { m_downloadList->open_throw(*itr); - torrent::resume_load_progress(*(*itr)->download(), (*itr)->download()->bencode()->get_key("libtorrent_resume")); - if ((*itr)->download()->hash_check(true)) { - // Set this to exit the function so that the delayed hash done - // signal gets triggered before we try any real hashing. - foundHashing = true; + // Since the bitfield is allocated on loading of resume load or + // hash start, and unallocated on close, we know that if it it + // not empty then we have loaded any existing resume data. + if ((*itr)->download()->file_list()->bitfield()->empty()) + torrent::resume_load_progress(*(*itr)->download(), (*itr)->download()->bencode()->get_key("libtorrent_resume")); + + // Need to clean up the below. + if (tryQuick) { + if (!(*itr)->download()->hash_check(true)) + // Temporary hack. + (*itr)->download()->hash_stop(); + + // Make sure we don't repeat the quick hashing. + (*itr)->variable()->set_value("hashing", Download::variable_hashing_rehash); } else { - // Temporary hack. - (*itr)->download()->hash_stop(); + (*itr)->download()->hash_check(false); } - (*itr)->variable()->set_value("hashing", Download::variable_hashing_rehash); - } catch (torrent::local_error& e) { - (*itr)->set_hash_failed(true); - push_log(e.what()); - } - - if (foundHashing) - return; - - for (View::iterator itr = m_hashingView->begin_visible(), last = m_hashingView->end_visible(); itr != last; ++itr) - try { - - if ((*itr)->is_hash_checked() || (*itr)->is_hash_checking()) - throw torrent::internal_error("core::Manager::receive_hashing_changed() hash already checked or checking."); - - if ((*itr)->is_hash_failed()) - continue; - - m_downloadList->open_throw(*itr); - torrent::resume_load_progress(*(*itr)->download(), (*itr)->download()->bencode()->get_key("libtorrent_resume")); - - (*itr)->download()->hash_check(false); - - return; - - } catch (torrent::local_error& e) { - (*itr)->set_hash_failed(true); - push_log(e.what()); + if (tryQuick) { + // Make sure we don't repeat the quick hashing. + (*itr)->variable()->set_value("hashing", Download::variable_hashing_rehash); + + } else { + (*itr)->set_hash_failed(true); + push_log(e.what()); + } } + } } } diff --git a/src/display/window_file_list.cc b/src/display/window_file_list.cc index ac4ca897..5cd1c0b1 100644 --- a/src/display/window_file_list.cc +++ b/src/display/window_file_list.cc @@ -36,23 +36,24 @@ #include "config.h" -#include -#include #include #include #include #include #include "core/download.h" +#include "ui/element_file_list.h" #include "window_file_list.h" namespace display { -WindowFileList::WindowFileList(core::Download* d, iterator* selected) : +// Don't really like the direction of the element dependency, but +// don't really feel like making a seperate class for containing the +// necessary information. +WindowFileList::WindowFileList(const ui::ElementFileList* element) : Window(new Canvas, 0, 0, 0, extent_full, extent_full), - m_download(d), - m_selected(selected) { + m_element(element) { } /* @@ -77,17 +78,50 @@ WindowFileList::redraw() { m_slotSchedule(this, (cachedTime + rak::timer::from_seconds(10)).round_seconds()); m_canvas->erase(); - torrent::FileList* fl = m_download->download()->file_list(); + torrent::FileList* fl = m_element->download()->download()->file_list(); if (fl->size_files() == 0 || m_canvas->height() < 2) return; - unsigned int pos = 0; - iterator itr = rak::advance_bidirectional(iterator(fl->begin()), *m_selected, iterator(fl->end()), m_canvas->height() - 1).first; + iterator entries[m_canvas->height() - 1]; + unsigned int last = 0; + + for (iterator itr = m_element->selected(); last != m_canvas->height() - 1; ) { + if (m_element->is_collapsed()) + itr.forward_current_depth(); + else + ++itr; + + entries[last++] = itr; + + if (itr == iterator(fl->end())) + break; + } + + unsigned int first = m_canvas->height() - 1; + + for (iterator itr = m_element->selected(); first >= last || first > (m_canvas->height() - 1) / 2; ) { + entries[--first] = itr; + + if (itr == iterator(fl->begin())) + break; + + if (m_element->is_collapsed()) + itr.backward_current_depth(); + else + --itr; + } + + unsigned int pos = 0; m_canvas->print(0, pos++, "Cmp Pri Size Filename"); - while (pos != m_canvas->height() && itr != iterator(fl->end())) { + while (pos != m_canvas->height()) { + iterator itr = entries[first]; + + if (itr == iterator(fl->end())) + break; + if (itr.is_empty()) { m_canvas->print(16, pos, "EMPTY"); @@ -136,11 +170,11 @@ WindowFileList::redraw() { m_canvas->print(0, pos, "BORK BORK"); } - if (itr == *m_selected) + if (itr == m_element->selected()) m_canvas->set_attr(0, pos, m_canvas->width(), is_focused() ? A_REVERSE : A_BOLD, COLOR_PAIR(0)); - ++itr; - ++pos; + pos++; + first = (first + 1) % (m_canvas->height() - 1); } } diff --git a/src/display/window_file_list.h b/src/display/window_file_list.h index ab11c371..8f4c4f08 100644 --- a/src/display/window_file_list.h +++ b/src/display/window_file_list.h @@ -37,34 +37,33 @@ #ifndef RTORRENT_DISPLAY_FILE_LIST_H #define RTORRENT_DISPLAY_FILE_LIST_H -#include - #include "window.h" +namespace ui { + class ElementFileList; +} + namespace torrent { class File; class FileListIterator; -} - -namespace core { - class Download; + class file_list_collapsed_iterator; } namespace display { class WindowFileList : public Window { public: - typedef torrent::FileListIterator iterator; + typedef torrent::FileListIterator iterator; + typedef torrent::file_list_collapsed_iterator collapsed_iterator; - WindowFileList(core::Download* d, iterator* selected); + WindowFileList(const ui::ElementFileList* element); virtual void redraw(); private: int done_percentage(torrent::File* e); - core::Download* m_download; - iterator* m_selected; + const ui::ElementFileList* m_element; }; } diff --git a/src/ui/element_file_list.cc b/src/ui/element_file_list.cc index 0e8cfc23..9ce88be7 100644 --- a/src/ui/element_file_list.cc +++ b/src/ui/element_file_list.cc @@ -62,13 +62,15 @@ ElementFileList::ElementFileList(core::Download* d) : m_window(NULL), m_elementInfo(NULL), - m_selected(iterator(d->download()->file_list()->begin())) { + m_selected(iterator(d->download()->file_list()->begin())), + m_collapsed(false) { m_bindings[KEY_LEFT] = m_bindings['B' - '@'] = sigc::mem_fun(&m_slotExit, &slot_type::operator()); - m_bindings[KEY_RIGHT] = m_bindings['F' - '@'] = sigc::bind(sigc::mem_fun(this, &ElementFileList::activate_display), DISPLAY_INFO); + m_bindings[KEY_RIGHT] = m_bindings['F' - '@'] = sigc::mem_fun(*this, &ElementFileList::receive_select); m_bindings[' '] = sigc::mem_fun(*this, &ElementFileList::receive_priority); m_bindings['*'] = sigc::mem_fun(*this, &ElementFileList::receive_change_all); + m_bindings['/'] = sigc::mem_fun(*this, &ElementFileList::receive_collapse); m_bindings[KEY_NPAGE] = sigc::mem_fun(*this, &ElementFileList::receive_pagenext); m_bindings[KEY_PPAGE] = sigc::mem_fun(*this, &ElementFileList::receive_pageprev); @@ -119,7 +121,7 @@ ElementFileList::activate(display::Frame* frame, bool focus) { if (focus) control->input()->push_back(&m_bindings); - m_window = new WFileList(m_download, &m_selected); + m_window = new WFileList(this); m_window->set_active(true); m_window->set_focused(focus); @@ -193,7 +195,12 @@ void ElementFileList::receive_next() { torrent::FileList* fl = m_download->download()->file_list(); - if (m_selected == iterator(fl->end()) || ++m_selected == iterator(fl->end())) + if (is_collapsed()) + m_selected.forward_current_depth(); + else + m_selected++; + + if (m_selected == iterator(fl->end())) m_selected = iterator(fl->begin()); update_itr(); @@ -206,7 +213,11 @@ ElementFileList::receive_prev() { if (m_selected == iterator(fl->begin())) m_selected = iterator(fl->end()); - m_selected--; + if (is_collapsed()) + m_selected.backward_current_depth(); + else + m_selected--; + update_itr(); } @@ -230,7 +241,7 @@ ElementFileList::receive_pagenext() { void ElementFileList::receive_pageprev() { if (m_window == NULL) - throw torrent::internal_error("ui::ElementFileList::receive_pageprev(...) called on a disabled object"); + return; torrent::FileList* fl = m_download->download()->file_list(); @@ -242,33 +253,29 @@ ElementFileList::receive_pageprev() { update_itr(); } -// Take a range as input and return the next entry at the same -// directory depth as first. If the returned iterator equals 'last' or -// is_leaving() == true then the search failed. UHM... wrong... +void +ElementFileList::receive_select() { + if (m_window == NULL || m_state != DISPLAY_LIST) + return; -torrent::FileListIterator -next_current_depth(torrent::FileListIterator first, torrent::FileListIterator last) { - if (first == last) - return first; - - uint32_t depth = (first++).depth(); - - while (first != last && (first.depth() > depth || first.is_leaving())) - ++first; - - return first; + if (is_collapsed() && !m_selected.is_file()) { + m_selected++; + m_window->mark_dirty(); + } else { + activate_display(DISPLAY_INFO); + } } void ElementFileList::receive_priority() { if (m_window == NULL) - throw torrent::internal_error("ui::ElementFileList::receive_prev(...) called on a disabled object"); + return; - torrent::FileList* fl = m_download->download()->file_list(); torrent::priority_t priority = torrent::priority_t((m_selected.file()->priority() + 2) % 3); iterator first = m_selected; - iterator last = next_current_depth(m_selected, iterator(fl->end())); + iterator last = m_selected; + last.forward_current_depth(); while (first != last) { if (first.is_file()) @@ -284,7 +291,7 @@ ElementFileList::receive_priority() { void ElementFileList::receive_change_all() { if (m_window == NULL) - throw torrent::internal_error("ui::ElementFileList::receive_prev(...) called on a disabled object"); + return; torrent::FileList* fl = m_download->download()->file_list(); torrent::priority_t priority = torrent::priority_t((m_selected.file()->priority() + 2) % 3); @@ -296,6 +303,15 @@ ElementFileList::receive_change_all() { update_itr(); } +void +ElementFileList::receive_collapse() { + if (m_window == NULL) + return; + + set_collapsed(!is_collapsed()); + m_window->mark_dirty(); +} + void ElementFileList::update_itr() { m_window->mark_dirty(); diff --git a/src/ui/element_file_list.h b/src/ui/element_file_list.h index cae5c1b7..e71cb14d 100644 --- a/src/ui/element_file_list.h +++ b/src/ui/element_file_list.h @@ -44,8 +44,6 @@ #include "element_base.h" -class Control; - namespace display { class WindowFileList; } @@ -72,14 +70,23 @@ public: void activate_display(Display display); + bool is_collapsed() const { return m_collapsed; } + void set_collapsed(bool s) { m_collapsed = s; } + + iterator selected() const { return m_selected; } + core::Download* download() const { return m_download; } + private: void receive_next(); void receive_prev(); void receive_pagenext(); void receive_pageprev(); + void receive_select(); + void receive_priority(); void receive_change_all(); + void receive_collapse(); void update_itr(); @@ -91,6 +98,7 @@ private: // Change to unsigned, please. iterator m_selected; + bool m_collapsed; }; }