diff --git a/ChangeLog b/ChangeLog index 5ee24f192..fa49e73d1 100644 --- a/ChangeLog +++ b/ChangeLog @@ -2,6 +2,7 @@ Deluge 1.1.0 - "" (In Development) Core: * Implement #79 ability to change outgoing port range * Implement #296 ability to change peer TOS byte + * Add per-torrent move on completed settings GtkUI: * Add peer progress to the peers tab diff --git a/deluge/core/core.py b/deluge/core/core.py index 424608cdc..88c0b99f5 100644 --- a/deluge/core/core.py +++ b/deluge/core/core.py @@ -626,6 +626,14 @@ class Core( def export_set_torrent_remove_at_ratio(self, torrent_id, value): """Sets the torrent to be removed at 'stop_ratio'""" return self.torrents[torrent_id].set_remove_at_ratio(value) + + def export_set_torrent_move_on_completed(self, torrent_id, value): + """Sets the torrent to be moved when completed""" + return self.torrents[torrent_id].set_move_on_completed(value) + + def export_set_torrent_move_on_completed_path(self, torrent_id, value): + """Sets the path for the torrent to be moved when completed""" + return self.torrents[torrent_id].set_move_on_completed_path(value) def export_block_ip_range(self, range): """Block an ip range""" diff --git a/deluge/core/torrent.py b/deluge/core/torrent.py index 4dbf8ef06..2f5698c8f 100644 --- a/deluge/core/torrent.py +++ b/deluge/core/torrent.py @@ -88,7 +88,10 @@ class Torrent: self.stop_at_ratio = False self.stop_ratio = 2.00 self.remove_at_ratio = False - + + self.move_on_completed = False + self.move_on_completed_path = deluge.common.get_default_download_dir() + # Load values from state if we have it if state is not None: # This is for saving the total uploaded between sessions @@ -240,6 +243,12 @@ class Torrent: # Force a reannounce if there is at least 1 tracker self.force_reannounce() + def set_move_on_completed(self, value): + self.move_on_completed = value + + def set_move_on_completed_path(self, value): + self.move_on_completed_path = value + def update_state(self): """Updates the state based on what libtorrent's state for the torrent is""" # Set the initial state based on the lt state @@ -459,7 +468,9 @@ class Torrent: "is_auto_managed": self.auto_managed, "stop_ratio": self.stop_ratio, "stop_at_ratio": self.stop_at_ratio, - "remove_at_ratio": self.remove_at_ratio + "remove_at_ratio": self.remove_at_ratio, + "move_on_completed": self.move_on_completed, + "move_on_completed_path": self.move_on_completed_path } fns = { diff --git a/deluge/core/torrentmanager.py b/deluge/core/torrentmanager.py index 04bd7c58f..8571c4573 100644 --- a/deluge/core/torrentmanager.py +++ b/deluge/core/torrentmanager.py @@ -621,9 +621,15 @@ class TorrentManager(component.Component): torrent = self.torrents[torrent_id] log.debug("%s is finished..", torrent_id) # Move completed download to completed folder if needed - if self.config["move_completed"] and not torrent.is_finished: - if torrent.save_path != self.config["move_completed_path"]: - torrent.move_storage(self.config["move_completed_path"]) + if not torrent.is_finished: + move_path = None + if torrent.move_on_completed: + move_path = torrent.move_on_completed_path + elif self.config["move_completed"]: + move_path = self.config["move_completed_path"] + if move_path: + if torrent.save_path != move_path: + torrent.move_storage(move_path) torrent.is_finished = True torrent.update_state() diff --git a/deluge/ui/client.py b/deluge/ui/client.py index a693cd749..deae82df4 100644 --- a/deluge/ui/client.py +++ b/deluge/ui/client.py @@ -168,7 +168,8 @@ class BaseClient(object): "deregister_client", "register_client", "add_torrent_file", "set_torrent_prioritize_first_last", "set_torrent_auto_managed", "set_torrent_stop_ratio", "set_torrent_stop_at_ratio", - "set_torrent_remove_at_ratio"] + "set_torrent_remove_at_ratio", "set_torrent_move_on_completed", + "set_torrent_move_on_completed_path"] def __init__(self): self.core = _core diff --git a/deluge/ui/gtkui/glade/main_window.glade b/deluge/ui/gtkui/glade/main_window.glade index 9c9762e23..8b39328aa 100644 --- a/deluge/ui/gtkui/glade/main_window.glade +++ b/deluge/ui/gtkui/glade/main_window.glade @@ -664,191 +664,274 @@ - + True - 0 - - - 1 - 2 - GTK_FILL - - - - - True - 0 - - - 3 - 4 - GTK_FILL - - - - - True - 0 - - - 1 - 2 - 1 - 2 - GTK_FILL - - - - - True - 0 - - - 3 - 4 - 1 - 2 - GTK_FILL - - - - - True - 5 - - - True - 0 - <b>Downloaded:</b> - True - - - - - GTK_FILL - - - - - True - 5 - - - True - 0 - <b>Uploaded:</b> - True - - - - - 1 - 2 - GTK_FILL - - - - - True - 5 - - - True - 0 - <b>Share Ratio:</b> - True - - - - - 2 - 3 - GTK_FILL - - - - - True - 5 - - - True - 0 - <b>Next Announce:</b> - True - - + 5 + 6 3 4 GTK_FILL - + True - 15 - 5 - - - True - 0 - <b>Speed:</b> - True - - + 0 + <b>Auto Managed:</b> + True - 2 - 3 + 4 + 5 + 3 + 4 GTK_FILL - + True - 15 - 5 - - - True - 0 - <b>Speed:</b> - True - - - 2 - 3 + 7 + 8 + 2 + 3 + GTK_FILL + + + + + True + + + 7 + 8 1 2 GTK_FILL - + True - 15 - 5 - - - True - 0 - <b>ETA:</b> - True - - + 0 + <b>Seed Rank:</b> + True - 2 - 3 + 6 + 7 2 3 GTK_FILL + + + True + 0 + <b>Seeding Time:</b> + True + + + 6 + 7 + 1 + 2 + GTK_FILL + + + + + True + + + 7 + 8 + GTK_FILL + + + + + True + 0 + <b>Active Time:</b> + True + + + 6 + 7 + GTK_FILL + + + + + True + 0 + True + + + 1 + 2 + 3 + 4 + GTK_FILL + + + + + True + 0 + + + 3 + 4 + 3 + 4 + GTK_FILL + + + + + True + 0 + PANGO_WRAP_CHAR + + + 1 + 6 + 4 + 5 + GTK_FILL + + + + + True + 0 + <b>Tracker Status:</b> + True + + + 4 + 5 + GTK_FILL + + + + + + True + 0 + True + PANGO_WRAP_WORD_CHAR + + + 5 + 6 + 2 + 3 + GTK_FILL + + + + + + True + 0 + 1 + <b>Availability:</b> + True + + + 4 + 5 + 2 + 3 + GTK_FILL + + + + + True + 0 + + + 3 + 4 + 2 + 3 + GTK_FILL + + + + + True + 0 + + + 1 + 2 + 2 + 3 + GTK_FILL + + + + + True + 0 + + + 5 + 6 + 1 + 2 + GTK_FILL + + + + + True + 0 + <b>Peers:</b> + True + + + 4 + 5 + 1 + 2 + GTK_FILL + + + + + True + 0 + + + 5 + 6 + GTK_FILL + + + + + True + 0 + <b>Seeders:</b> + True + + + 4 + 5 + GTK_FILL + + True @@ -872,271 +955,188 @@ - + True - 0 - <b>Seeders:</b> - True + 15 + 5 + + + True + 0 + <b>ETA:</b> + True + + - 4 - 5 - GTK_FILL - - - - - True - 0 - - - 5 - 6 - GTK_FILL - - - - - True - 0 - <b>Peers:</b> - True - - - 4 - 5 - 1 - 2 - GTK_FILL - - - - - True - 0 - - - 5 - 6 - 1 - 2 - GTK_FILL - - - - - True - 0 - - - 1 - 2 + 2 + 3 2 3 GTK_FILL - + + True + 15 + 5 + + + True + 0 + <b>Speed:</b> + True + + + + + 2 + 3 + 1 + 2 + GTK_FILL + + + + + True + 15 + 5 + + + True + 0 + <b>Speed:</b> + True + + + + + 2 + 3 + GTK_FILL + + + + + True + 5 + + + True + 0 + <b>Next Announce:</b> + True + + + + + 3 + 4 + GTK_FILL + + + + + True + 5 + + + True + 0 + <b>Share Ratio:</b> + True + + + + + 2 + 3 + GTK_FILL + + + + + True + 5 + + + True + 0 + <b>Uploaded:</b> + True + + + + + 1 + 2 + GTK_FILL + + + + + True + 5 + + + True + 0 + <b>Downloaded:</b> + True + + + + + GTK_FILL + + + + True 0 3 4 - 2 - 3 + 1 + 2 GTK_FILL - + True 0 - 1 - <b>Availability:</b> - True - - - 4 - 5 - 2 - 3 - GTK_FILL - - - - - True - 0 - True - PANGO_WRAP_WORD_CHAR - - - 5 - 6 - 2 - 3 - GTK_FILL - - - - - - True - 0 - <b>Tracker Status:</b> - True - - - 4 - 5 - GTK_FILL - - - - - - True - 0 - PANGO_WRAP_CHAR 1 - 6 - 4 - 5 + 2 + 1 + 2 GTK_FILL - + True 0 3 4 - 3 - 4 GTK_FILL - + True 0 - True 1 2 - 3 - 4 - GTK_FILL - - - - - True - 0 - <b>Active Time:</b> - True - - - 6 - 7 - GTK_FILL - - - - - True - - - 7 - 8 - GTK_FILL - - - - - True - 0 - <b>Seeding Time:</b> - True - - - 6 - 7 - 1 - 2 - GTK_FILL - - - - - True - 0 - <b>Seed Rank:</b> - True - - - 6 - 7 - 2 - 3 - GTK_FILL - - - - - True - - - 7 - 8 - 1 - 2 - GTK_FILL - - - - - True - - - 7 - 8 - 2 - 3 - GTK_FILL - - - - - True - 0 - <b>Auto Managed:</b> - True - - - 4 - 5 - 3 - 4 - GTK_FILL - - - - - True - - - 5 - 6 - 3 - 4 GTK_FILL @@ -1223,7 +1223,7 @@ - + True 0 True @@ -1231,43 +1231,28 @@ 1 2 - 3 - 4 + 4 + 5 - - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 0 - True - - - 1 - 4 - 5 - 6 - - - - - + True 0 1 - <b>Status:</b> + <b># of files:</b> True - 5 - 6 + 4 + 5 GTK_FILL - + True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK 0 @@ -1278,66 +1263,53 @@ 1 4 - 2 - 3 + 1 + 2 - + True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 5 - - - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 0 - <b>Path:</b> - True - - - - - 2 - 3 - GTK_FILL - - - - - - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 5 - - - True - 0 - 0 - 1 - <b>Name:</b> - True - - - - - GTK_FILL - - - - - - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_STRUCTURE_MASK 0 - True + <b>Hash:</b> + True + + + 1 + 2 + GTK_FILL + + + + + + True + 0 PANGO_WRAP_CHAR True 1 4 + 6 + 7 + + + + + + True + 0 + 1 + <b>Tracker:</b> + True + + + 6 + 7 + GTK_FILL @@ -1364,52 +1336,65 @@ - - True - 0 - 1 - <b>Tracker:</b> - True - - - 6 - 7 - GTK_FILL - - - - - + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_STRUCTURE_MASK 0 + True PANGO_WRAP_CHAR True 1 4 - 6 - 7 - + True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 0 - <b>Hash:</b> - True + 5 + + + True + 0 + 0 + 1 + <b>Name:</b> + True + + - 1 - 2 GTK_FILL - + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 5 + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 0 + <b>Path:</b> + True + + + + + 2 + 3 + GTK_FILL + + + + + True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK 0 @@ -1420,28 +1405,43 @@ 1 4 - 1 - 2 + 2 + 3 - + True 0 1 - <b># of files:</b> + <b>Status:</b> True - 4 - 5 + 5 + 6 GTK_FILL - + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 0 + True + + + 1 + 4 + 5 + 6 + + + + + True 0 True @@ -1449,8 +1449,8 @@ 1 2 - 4 - 5 + 3 + 4 @@ -1633,7 +1633,7 @@ - + True True 6 @@ -1643,100 +1643,8 @@ 1 2 - 3 - 4 - - - - - - - True - 0 - Max Upload Slots: - - - 3 - 4 - GTK_FILL - - - - - - True - KiB/s - - - 2 - 3 - 1 - 2 - - - - - - - True - KiB/s - - - 2 - 3 - - - - - - - True - 0 - Max Download Speed: - - - GTK_FILL - - - - - - True - 0 - Max Upload Speed: - - - 1 - 2 - GTK_FILL - - - - - - True - 0 - Max Connections: - - 2 3 - GTK_FILL - - - - - - True - True - 6 - 1 - -1 -1 999999 1 10 10 - 1 - - - 1 - 2 @@ -1760,7 +1668,99 @@ - + + True + True + 6 + 1 + -1 -1 999999 1 10 10 + 1 + + + 1 + 2 + + + + + + + True + 0 + Max Connections: + + + 2 + 3 + GTK_FILL + + + + + + True + 0 + Max Upload Speed: + + + 1 + 2 + GTK_FILL + + + + + + True + 0 + Max Download Speed: + + + GTK_FILL + + + + + + True + KiB/s + + + 2 + 3 + + + + + + + True + KiB/s + + + 2 + 3 + 1 + 2 + + + + + + + True + 0 + Max Upload Slots: + + + 3 + 4 + GTK_FILL + + + + + True True 6 @@ -1770,8 +1770,8 @@ 1 2 - 2 - 3 + 3 + 4 @@ -1883,6 +1883,55 @@ 1 + + + True + True + Move completed: + 0 + True + + + + False + False + 2 + + + + + True + + + True + False + GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER + False + Select A Folder + + + False + False + + + + + False + True + + + False + False + 1 + + + + + False + False + 3 + + 1 @@ -1920,6 +1969,8 @@ True + 0 + 0 5 12 @@ -1958,6 +2009,8 @@ True True True + 0 + 0 0 @@ -2023,6 +2076,8 @@ True + 0 + 0 12 @@ -2354,23 +2409,14 @@ 10 2 - - True - 0 - <i>Current Version:</i> - True - - - GTK_FILL - - - - + True 1 2 + 1 + 2 @@ -2388,17 +2434,26 @@ - + True 1 2 - 1 - 2 + + + True + 0 + <i>Current Version:</i> + True + + + GTK_FILL + + diff --git a/deluge/ui/gtkui/options_tab.py b/deluge/ui/gtkui/options_tab.py index e27e47640..2db117987 100644 --- a/deluge/ui/gtkui/options_tab.py +++ b/deluge/ui/gtkui/options_tab.py @@ -56,14 +56,29 @@ class OptionsTab(Tab): self.chk_stop_at_ratio = glade.get_widget("chk_stop_at_ratio") self.chk_remove_at_ratio = glade.get_widget("chk_remove_at_ratio") self.spin_stop_ratio = glade.get_widget("spin_stop_ratio") + self.chk_move_completed = glade.get_widget("chk_move_completed") + self.filechooser_move_completed = glade.get_widget("filechooser_move_completed") + self.entry_move_completed = glade.get_widget("entry_move_completed") self.prev_torrent_id = None self.prev_status = None glade.signal_autoconnect({ "on_button_apply_clicked": self._on_button_apply_clicked, - "on_button_edit_trackers_clicked": self._on_button_edit_trackers_clicked + "on_button_edit_trackers_clicked": self._on_button_edit_trackers_clicked, + "on_chk_move_completed_toggled": self._on_chk_move_completed_toggled }) + + def start(self): + if client.is_localhost(): + self.filechooser_move_completed.show() + self.entry_move_completed.hide() + else: + self.filechooser_move_completed.hide() + self.entry_move_completed.show() + + def stop(self): + pass def on_button_press_event(self, widget, event): from deluge.ui.gtkui.notification import Notification @@ -95,7 +110,9 @@ class OptionsTab(Tab): "is_auto_managed", "stop_at_ratio", "stop_ratio", - "remove_at_ratio"]) + "remove_at_ratio", + "move_on_completed", + "move_on_completed_path"]) self.prev_torrent_id = torrent_id def clear(self): @@ -129,6 +146,13 @@ class OptionsTab(Tab): self.spin_stop_ratio.set_value(status["stop_ratio"]) if status["remove_at_ratio"] != self.prev_status["remove_at_ratio"]: self.chk_remove_at_ratio.set_active(status["remove_at_ratio"]) + if status["move_on_completed"] != self.prev_status["move_on_completed"]: + self.chk_move_completed.set_active(status["move_on_completed"]) + if status["move_on_completed_path"] != self.prev_status["move_on_completed_path"]: + if client.is_localhost(): + self.filechooser_move_completed.set_current_folder(status["move_on_completed_path"]) + else: + self.entry_move_completed.set_text(status["move_on_completed_path"]) self.prev_status = status @@ -151,6 +175,14 @@ class OptionsTab(Tab): client.set_torrent_stop_ratio(self.prev_torrent_id, self.spin_stop_ratio.get_value()) if self.chk_remove_at_ratio.get_active() != self.prev_status["remove_at_ratio"]: client.set_torrent_remove_at_ratio(self.prev_torrent_id, self.chk_remove_at_ratio.get_active()) + if self.chk_move_completed.get_active() != self.prev_status["move_on_completed"]: + client.set_torrent_move_on_completed(self.prev_torrent_id, self.chk_move_completed.get_active()) + if self.chk_move_completed.get_active(): + if client.is_localhost(): + path = self.filechooser_move_completed.get_current_folder() + else: + path = self.entry_move_completed.get_text() + client.set_torrent_move_on_completed_path(self.prev_torrent_id, path) def _on_button_edit_trackers_clicked(self, button): @@ -159,3 +191,12 @@ class OptionsTab(Tab): self.prev_torrent_id, component.get("MainWindow").window) dialog.run() + + def _on_chk_move_completed_toggled(self, widget): + value = self.chk_move_completed.get_active() + if client.is_localhost(): + widget = self.filechooser_move_completed + else: + widget = self.entry_move_completed + + widget.set_sensitive(value) diff --git a/deluge/ui/gtkui/torrentdetails.py b/deluge/ui/gtkui/torrentdetails.py index e2d8b2b8d..bd37f3bbc 100644 --- a/deluge/ui/gtkui/torrentdetails.py +++ b/deluge/ui/gtkui/torrentdetails.py @@ -284,9 +284,22 @@ class TorrentDetails(component.Component): self.show_tab(tab_name) elif not visible and self.tabs[tab_name].is_visible: self.hide_tab(tab_name) - + + def start(self): + for tab in self.tabs.values(): + try: + tab.start() + except AttributeError: + pass + def stop(self): self.clear() + for tab in self.tabs.values(): + try: + tab.stop() + except AttributeError: + pass + def shutdown(self): # Save the state of the tabs