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