EditTrackerDialog now works.
Save trackers in torrent state. Load trackers on torrent add from state.
This commit is contained in:
parent
190d6d94ea
commit
6bced0fb8c
12
TODO
12
TODO
|
@ -2,20 +2,22 @@
|
|||
* Queue plugin 'apply_queue' stuff.. Just finishing the queue plugin and it's
|
||||
intended functionality.
|
||||
* Figure out easy way for user-made plugins to add i18n support.
|
||||
* Change the menubar.py gtkui component to menus.py and add support for plugins
|
||||
to add menuitems to the torrentmenu in an easy way.
|
||||
* Restart daemon function
|
||||
* Docstrings!
|
||||
* Implement caching in client.py
|
||||
* Create a new add torrent dialog
|
||||
* Create edit trackers dialog
|
||||
* Implement open folder
|
||||
* Maybe add pop-up menus to the status bar items
|
||||
* Address issue where torrents will redownload if the storage is moved outside
|
||||
of deluge.
|
||||
* Hide open folder if not localhost
|
||||
* Modify sensitivity of torrent/tray menu based on connection state
|
||||
* Add classic/normal mode to preferences
|
||||
* Implement 'Classic' mode
|
||||
* Add remove torrent dialog and ability to remove data
|
||||
|
||||
* Tray tooltip
|
||||
* Add DBUS to gtkui so we can add torrents to existing session
|
||||
* Add LSD
|
||||
* Add torrentfiles location config option
|
||||
* Add autoload folder
|
||||
* Add wizard
|
||||
* Add a health indication to the statusbar
|
||||
|
|
|
@ -387,6 +387,10 @@ class Core(
|
|||
def export_force_recheck(self, torrent_id):
|
||||
"""Forces a data recheck on torrent_id"""
|
||||
return self.torrents.force_recheck(torrent_id)
|
||||
|
||||
def export_set_torrent_trackers(self, torrent_id, trackers):
|
||||
"""Sets a torrents tracker list. trackers will be [{"url", "tier"}]"""
|
||||
return self.torrents.set_trackers(torrent_id, trackers)
|
||||
|
||||
# Signals
|
||||
def torrent_added(self, torrent_id):
|
||||
|
|
|
@ -38,7 +38,8 @@ import deluge.common
|
|||
class Torrent:
|
||||
"""Torrent holds information about torrents added to the libtorrent session.
|
||||
"""
|
||||
def __init__(self, filename, handle, compact, save_path, total_uploaded=0):
|
||||
def __init__(self, filename, handle, compact, save_path, total_uploaded=0,
|
||||
trackers=None):
|
||||
# Set the filename
|
||||
self.filename = filename
|
||||
# Set the libtorrent handle
|
||||
|
@ -53,7 +54,18 @@ class Torrent:
|
|||
self.save_path = save_path
|
||||
# The tracker status
|
||||
self.tracker_status = ""
|
||||
|
||||
# Tracker list
|
||||
if trackers == None:
|
||||
self.trackers = []
|
||||
# Create a list of trackers
|
||||
for value in self.handle.trackers():
|
||||
tracker = {}
|
||||
tracker["url"] = value.url
|
||||
tracker["tier"] = value.tier
|
||||
self.trackers.append(tracker)
|
||||
else:
|
||||
self.trackers = trackers
|
||||
|
||||
def set_tracker_status(self, status):
|
||||
"""Sets the tracker status"""
|
||||
self.tracker_status = status
|
||||
|
@ -62,7 +74,8 @@ class Torrent:
|
|||
"""Returns the state of this torrent for saving to the session state"""
|
||||
status = self.handle.status()
|
||||
return (self.torrent_id, self.filename, self.compact, status.paused,
|
||||
self.save_path, self.total_uploaded + status.total_payload_upload)
|
||||
self.save_path, self.total_uploaded + status.total_payload_upload,
|
||||
self.trackers)
|
||||
|
||||
def get_eta(self):
|
||||
"""Returns the ETA in seconds for this torrent"""
|
||||
|
@ -135,7 +148,7 @@ class Torrent:
|
|||
distributed_copies = status.distributed_copies
|
||||
if distributed_copies < 0:
|
||||
distributed_copies = 0.0
|
||||
|
||||
|
||||
full_status = {
|
||||
"name": self.handle.torrent_info().name(),
|
||||
"total_size": self.handle.torrent_info().total_size(),
|
||||
|
@ -161,6 +174,7 @@ class Torrent:
|
|||
"eta": self.get_eta(),
|
||||
"ratio": self.get_ratio(),
|
||||
"tracker": status.current_tracker,
|
||||
"trackers": self.trackers,
|
||||
"tracker_status": self.tracker_status,
|
||||
"save_path": self.save_path,
|
||||
"files": self.get_files()
|
||||
|
|
|
@ -48,13 +48,14 @@ from deluge.log import LOG as log
|
|||
|
||||
class TorrentState:
|
||||
def __init__(self, torrent_id, filename, compact, paused, save_path,
|
||||
total_uploaded):
|
||||
total_uploaded, trackers):
|
||||
self.torrent_id = torrent_id
|
||||
self.filename = filename
|
||||
self.compact = compact
|
||||
self.paused = paused
|
||||
self.save_path = save_path
|
||||
self.total_uploaded = total_uploaded
|
||||
self.trackers = trackers
|
||||
|
||||
class TorrentManagerState:
|
||||
def __init__(self):
|
||||
|
@ -121,7 +122,7 @@ class TorrentManager:
|
|||
return self.torrents.keys()
|
||||
|
||||
def add(self, filename, filedump=None, compact=None, paused=False,
|
||||
save_path=None, total_uploaded=0):
|
||||
save_path=None, total_uploaded=0, trackers=None):
|
||||
"""Add a torrent to the manager and returns it's torrent_id"""
|
||||
log.info("Adding torrent: %s", filename)
|
||||
|
||||
|
@ -167,14 +168,14 @@ class TorrentManager:
|
|||
storage_mode = lt.storage_mode_t(1)
|
||||
else:
|
||||
storage_mode = lt.storage_mode_t(2)
|
||||
|
||||
|
||||
try:
|
||||
handle = self.session.add_torrent(
|
||||
lt.torrent_info(filedump),
|
||||
str(save_path),
|
||||
resume_data=fastresume,
|
||||
storage_mode=storage_mode,
|
||||
paused=paused)
|
||||
paused=True)
|
||||
except RuntimeError, e:
|
||||
log.warning("Error adding torrent: %s", e)
|
||||
|
||||
|
@ -184,15 +185,23 @@ class TorrentManager:
|
|||
|
||||
# Create a Torrent object
|
||||
torrent = Torrent(filename, handle, compact,
|
||||
save_path, total_uploaded)
|
||||
save_path, total_uploaded, trackers)
|
||||
|
||||
# Add the torrent object to the dictionary
|
||||
self.torrents[torrent.torrent_id] = torrent
|
||||
|
||||
|
||||
# Set the trackers
|
||||
if trackers != None:
|
||||
self.set_trackers(str(handle.info_hash()), trackers)
|
||||
|
||||
# Set per-torrent limits
|
||||
handle.set_max_connections(self.max_connections)
|
||||
handle.set_max_uploads(self.max_uploads)
|
||||
|
||||
# Resume the torrent if needed
|
||||
if paused == False:
|
||||
handle.resume()
|
||||
|
||||
# Save the torrent file
|
||||
self.save_torrent(filename, filedump)
|
||||
|
||||
|
@ -304,7 +313,28 @@ class TorrentManager:
|
|||
log.warning("Unable to resume torrent %s", key)
|
||||
|
||||
return torrent_was_resumed
|
||||
|
||||
|
||||
def set_trackers(self, torrent_id, trackers):
|
||||
"""Sets trackers"""
|
||||
if trackers == [] or trackers == None:
|
||||
return
|
||||
log.debug("Setting trackers for %s", torrent_id)
|
||||
tracker_list = []
|
||||
|
||||
for tracker in trackers:
|
||||
new_entry = lt.announce_entry(tracker["url"])
|
||||
new_entry.tier = tracker["tier"]
|
||||
tracker_list.append(new_entry)
|
||||
|
||||
self.torrents[torrent_id].handle.replace_trackers(tracker_list)
|
||||
# Print out the trackers
|
||||
for t in self.torrents[torrent_id].handle.trackers():
|
||||
log.debug("tier: %s tracker: %s", t.tier, t.url)
|
||||
# Set the tracker list in the torrent object
|
||||
self.torrents[torrent_id].trackers = trackers
|
||||
# Force a reannounce
|
||||
self.force_reannounce(torrent_id)
|
||||
|
||||
def force_reannounce(self, torrent_id):
|
||||
"""Force a tracker reannounce"""
|
||||
try:
|
||||
|
@ -381,7 +411,8 @@ class TorrentManager:
|
|||
for torrent_state in state.torrents:
|
||||
self.add(torrent_state.filename, compact=torrent_state.compact,
|
||||
paused=torrent_state.paused, save_path=torrent_state.save_path,
|
||||
total_uploaded=torrent_state.total_uploaded)
|
||||
total_uploaded=torrent_state.total_uploaded,
|
||||
trackers=torrent_state.trackers)
|
||||
|
||||
def save_state(self):
|
||||
"""Save the state of the TorrentManager to the torrents.state file"""
|
||||
|
|
|
@ -337,6 +337,13 @@ def force_recheck(torrent_ids):
|
|||
except (AttributeError, socket.error):
|
||||
set_core_uri(None)
|
||||
|
||||
def set_torrent_trackers(torrent_id, trackers):
|
||||
"""Sets the torrents trackers"""
|
||||
try:
|
||||
get_core().set_torrent_trackers(torrent_id, trackers)
|
||||
except (AttributeError, socket.error):
|
||||
set_core_uri(None)
|
||||
|
||||
def open_url_in_browser(url):
|
||||
"""Opens link in the desktop's default browser"""
|
||||
def start_browser():
|
||||
|
|
|
@ -41,11 +41,16 @@ from deluge.log import LOG as log
|
|||
|
||||
class EditTrackersDialog:
|
||||
def __init__(self, torrent_id, parent=None):
|
||||
self.torrent_id = torrent_id
|
||||
self.glade = gtk.glade.XML(
|
||||
pkg_resources.resource_filename("deluge.ui.gtkui",
|
||||
"glade/edit_trackers.glade"))
|
||||
|
||||
self.dialog = self.glade.get_widget("edit_trackers_dialog")
|
||||
self.treeview = self.glade.get_widget("tracker_treeview")
|
||||
self.add_tracker_dialog = self.glade.get_widget("add_tracker_dialog")
|
||||
self.add_tracker_dialog.set_transient_for(self.dialog)
|
||||
|
||||
self.dialog.set_icon(deluge.common.get_logo(32))
|
||||
|
||||
if parent != None:
|
||||
|
@ -58,21 +63,148 @@ class EditTrackersDialog:
|
|||
"on_button_remove_clicked": self.on_button_remove_clicked,
|
||||
"on_button_down_clicked": self.on_button_down_clicked,
|
||||
"on_button_ok_clicked": self.on_button_ok_clicked,
|
||||
"on_button_cancel_clicked": self.on_button_cancel_clicked
|
||||
"on_button_cancel_clicked": self.on_button_cancel_clicked,
|
||||
"on_button_add_ok_clicked": self.on_button_add_ok_clicked,
|
||||
"on_button_add_cancel_clicked": self.on_button_add_cancel_clicked
|
||||
})
|
||||
|
||||
# Create a liststore for tier, url
|
||||
self.liststore = gtk.ListStore(int, str)
|
||||
|
||||
# Create the columns
|
||||
self.treeview.append_column(
|
||||
gtk.TreeViewColumn(_("Tier"), gtk.CellRendererText(), text=0))
|
||||
self.treeview.append_column(
|
||||
gtk.TreeViewColumn(_("Tracker"), gtk.CellRendererText(), text=1))
|
||||
|
||||
self.treeview.set_model(self.liststore)
|
||||
self.liststore.set_sort_column_id(0, gtk.SORT_ASCENDING)
|
||||
|
||||
def run(self):
|
||||
# Make sure we have a torrent_id.. if not just return
|
||||
if self.torrent_id == None:
|
||||
return
|
||||
|
||||
# Get the trackers for this torrent
|
||||
trackers = client.get_torrent_status(self.torrent_id, ["trackers"])
|
||||
for tracker in trackers["trackers"]:
|
||||
self.add_tracker(tracker["tier"], tracker["url"])
|
||||
|
||||
self.dialog.show()
|
||||
|
||||
def add_tracker(self, tier, url):
|
||||
"""Adds a tracker to the list"""
|
||||
self.liststore.append([tier, url])
|
||||
|
||||
def get_selected(self):
|
||||
"""Returns the selected tracker"""
|
||||
return self.treeview.get_selection().get_selected()[1]
|
||||
|
||||
def on_button_up_clicked(self, widget):
|
||||
log.debug("on_button_up_clicked")
|
||||
selected = self.get_selected()
|
||||
num_rows = self.liststore.iter_n_children(None)
|
||||
if selected != None and num_rows > 1:
|
||||
tier = self.liststore.get_value(selected, 0)
|
||||
new_tier = tier - 1
|
||||
# Return if the tier is already at the top
|
||||
if tier == 0:
|
||||
return
|
||||
# Change the tier of the tracker we're surplanting
|
||||
def change_tier(model, path, iter, data):
|
||||
t = model.get_value(iter, 0)
|
||||
if t == data:
|
||||
model.set_value(iter, 0, data + 1)
|
||||
self.liststore.foreach(change_tier, new_tier)
|
||||
|
||||
# Now change the tier for this tracker
|
||||
self.liststore.set_value(selected, 0, new_tier)
|
||||
|
||||
def on_button_add_clicked(self, widget):
|
||||
log.debug("on_button_add_clicked")
|
||||
# Show the add tracker dialog
|
||||
self.add_tracker_dialog.show()
|
||||
self.glade.get_widget("entry_tracker").grab_focus()
|
||||
|
||||
def on_button_remove_clicked(self, widget):
|
||||
log.debug("on_button_remove_clicked")
|
||||
selected = self.get_selected()
|
||||
if selected != None:
|
||||
self.liststore.remove(selected)
|
||||
|
||||
def on_button_down_clicked(self, widget):
|
||||
log.debug("on_button_down_clicked")
|
||||
selected = self.get_selected()
|
||||
num_rows = self.liststore.iter_n_children(None)
|
||||
if selected != None and num_rows > 1:
|
||||
tier = self.liststore.get_value(selected, 0)
|
||||
new_tier = tier + 1
|
||||
# This tracker is on the bottom already
|
||||
if new_tier == num_rows:
|
||||
return
|
||||
# Change the tier of the tracker we're surplanting
|
||||
def change_tier(model, path, iter, data):
|
||||
t = model.get_value(iter, 0)
|
||||
if t == data:
|
||||
model.set_value(iter, 0, data - 1)
|
||||
self.liststore.foreach(change_tier, new_tier)
|
||||
# Now change the tier for this tracker
|
||||
self.liststore.set_value(selected, 0, new_tier)
|
||||
|
||||
def on_button_ok_clicked(self, widget):
|
||||
log.debug("on_button_ok_clicked")
|
||||
self.trackers = []
|
||||
def each(model, path, iter, data):
|
||||
tracker = {}
|
||||
tracker["tier"] = model.get_value(iter, 0)
|
||||
tracker["url"] = model.get_value(iter, 1)
|
||||
self.trackers.append(tracker)
|
||||
self.liststore.foreach(each, None)
|
||||
# Set the torrens trackers
|
||||
client.set_torrent_trackers(self.torrent_id, self.trackers)
|
||||
self.dialog.destroy()
|
||||
|
||||
def on_button_cancel_clicked(self, widget):
|
||||
log.debug("on_button_cancel_clicked")
|
||||
self.dialog.destroy()
|
||||
|
||||
def on_button_add_ok_clicked(self, widget):
|
||||
log.debug("on_button_add_ok_clicked")
|
||||
tracker = self.glade.get_widget("entry_tracker").get_text()
|
||||
if tracker[:7] != "http://" or tracker[:8] != "https://":
|
||||
# Bad url.. lets prepend http://
|
||||
tracker = "http://" + tracker
|
||||
|
||||
# Figure out what tier number to use.. it's going to be the highest+1
|
||||
# Also check for duplicates
|
||||
self.highest_tier = 0
|
||||
self.duplicate = False
|
||||
def tier_count(model, path, iter, data):
|
||||
tier = model.get_value(iter, 0)
|
||||
if tier > self.highest_tier:
|
||||
self.highest_tier = tier
|
||||
tracker = model.get_value(iter, 1)
|
||||
if data == tracker:
|
||||
# We already have this tracker in the list
|
||||
self.duplicate = True
|
||||
|
||||
# Check if there are any entries
|
||||
if self.liststore.iter_n_children(None) > 0:
|
||||
self.liststore.foreach(tier_count, tracker)
|
||||
else:
|
||||
self.highest_tier = -1
|
||||
|
||||
# If not a duplicate, then add it to the list
|
||||
if not self.duplicate:
|
||||
# Add the tracker to the list
|
||||
self.add_tracker(self.highest_tier + 1, tracker)
|
||||
|
||||
# Clear the entry widget and hide the dialog
|
||||
self.glade.get_widget("entry_tracker").set_text("")
|
||||
self.add_tracker_dialog.hide()
|
||||
|
||||
def on_button_add_cancel_clicked(self, widget):
|
||||
log.debug("on_button_add_cancel_clicked")
|
||||
# Clear the entry widget and hide the dialog
|
||||
self.glade.get_widget("entry_tracker").set_text("")
|
||||
self.add_tracker_dialog.hide()
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE glade-interface SYSTEM "glade-2.0.dtd">
|
||||
<!--Generated with glade3 3.4.0 on Sat Nov 10 03:18:41 2007 -->
|
||||
<!--Generated with glade3 3.4.0 on Mon Nov 12 03:27:39 2007 -->
|
||||
<glade-interface>
|
||||
<widget class="GtkDialog" id="edit_trackers_dialog">
|
||||
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||
|
@ -70,20 +70,12 @@
|
|||
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||
<property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
|
||||
<property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
|
||||
<property name="shadow_type">GTK_SHADOW_IN</property>
|
||||
<child>
|
||||
<widget class="GtkViewport" id="viewport3">
|
||||
<widget class="GtkTreeView" id="tracker_treeview">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||
<property name="resize_mode">GTK_RESIZE_QUEUE</property>
|
||||
<property name="shadow_type">GTK_SHADOW_NONE</property>
|
||||
<child>
|
||||
<widget class="GtkTreeView" id="tracker_treeview">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||
<property name="headers_clickable">True</property>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
|
@ -93,7 +85,7 @@
|
|||
<property name="visible">True</property>
|
||||
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||
<property name="spacing">1</property>
|
||||
<property name="layout_style">GTK_BUTTONBOX_END</property>
|
||||
<property name="layout_style">GTK_BUTTONBOX_CENTER</property>
|
||||
<child>
|
||||
<widget class="GtkButton" id="button_up">
|
||||
<property name="visible">True</property>
|
||||
|
@ -160,8 +152,6 @@
|
|||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
|
@ -211,4 +201,152 @@
|
|||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
<widget class="GtkDialog" id="add_tracker_dialog">
|
||||
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||
<property name="border_width">5</property>
|
||||
<property name="title" translatable="yes">Add Tracker</property>
|
||||
<property name="window_position">GTK_WIN_POS_CENTER_ON_PARENT</property>
|
||||
<property name="destroy_with_parent">True</property>
|
||||
<property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
|
||||
<property name="decorated">False</property>
|
||||
<property name="has_separator">False</property>
|
||||
<child internal-child="vbox">
|
||||
<widget class="GtkVBox" id="dialog-vbox2">
|
||||
<property name="visible">True</property>
|
||||
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||
<property name="spacing">2</property>
|
||||
<child>
|
||||
<widget class="GtkVBox" id="vbox1">
|
||||
<property name="visible">True</property>
|
||||
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||
<property name="spacing">5</property>
|
||||
<child>
|
||||
<widget class="GtkHBox" id="hbox1">
|
||||
<property name="visible">True</property>
|
||||
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||
<property name="spacing">5</property>
|
||||
<child>
|
||||
<widget class="GtkImage" id="image1">
|
||||
<property name="visible">True</property>
|
||||
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||
<property name="stock">gtk-add</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkLabel" id="label1">
|
||||
<property name="visible">True</property>
|
||||
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||
<property name="label" translatable="yes"><b>Add Tracker</b></property>
|
||||
<property name="use_markup">True</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkHSeparator" id="hseparator1">
|
||||
<property name="visible">True</property>
|
||||
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkHBox" id="hbox2">
|
||||
<property name="visible">True</property>
|
||||
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||
<property name="spacing">5</property>
|
||||
<child>
|
||||
<widget class="GtkLabel" id="label2">
|
||||
<property name="visible">True</property>
|
||||
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||
<property name="label" translatable="yes">Tracker:</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkEntry" id="entry_tracker">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="has_focus">True</property>
|
||||
<property name="is_focus">True</property>
|
||||
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||
<property name="activates_default">True</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="position">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child internal-child="action_area">
|
||||
<widget class="GtkHButtonBox" id="dialog-action_area2">
|
||||
<property name="visible">True</property>
|
||||
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||
<property name="layout_style">GTK_BUTTONBOX_END</property>
|
||||
<child>
|
||||
<widget class="GtkButton" id="button_add_cancel">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||
<property name="label" translatable="yes">gtk-cancel</property>
|
||||
<property name="use_stock">True</property>
|
||||
<property name="response_id">0</property>
|
||||
<signal name="clicked" handler="on_button_add_cancel_clicked"/>
|
||||
</widget>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkButton" id="button_add_ok">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="can_default">True</property>
|
||||
<property name="has_default">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||
<property name="label" translatable="yes">gtk-ok</property>
|
||||
<property name="use_stock">True</property>
|
||||
<property name="response_id">0</property>
|
||||
<signal name="clicked" handler="on_button_add_ok_clicked"/>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="pack_type">GTK_PACK_END</property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
</glade-interface>
|
||||
|
|
|
@ -184,7 +184,9 @@ class MenuBar(component.Component):
|
|||
def on_menuitem_edittrackers_activate(self, data=None):
|
||||
log.debug("on_menuitem_edittrackers_activate")
|
||||
from edittrackersdialog import EditTrackersDialog
|
||||
dialog = EditTrackersDialog(None, component.get("MainWindow").window)
|
||||
dialog = EditTrackersDialog(
|
||||
component.get("TorrentView").get_selected_torrent(),
|
||||
component.get("MainWindow").window)
|
||||
dialog.run()
|
||||
|
||||
def on_menuitem_remove_activate(self, data=None):
|
||||
|
|
|
@ -271,7 +271,15 @@ class TorrentView(listview.ListView, component.Component):
|
|||
self.update()
|
||||
break
|
||||
row = self.liststore.iter_next(row)
|
||||
|
||||
|
||||
def get_selected_torrent(self):
|
||||
"""Returns a torrent_id or None. If multiple torrents are selected,
|
||||
it will return the torrent_id of the first one."""
|
||||
selected = self.get_selected_torrents()
|
||||
if selected == None:
|
||||
return selected
|
||||
return selected[0]
|
||||
|
||||
def get_selected_torrents(self):
|
||||
"""Returns a list of selected torrents or None"""
|
||||
torrent_ids = []
|
||||
|
|
Loading…
Reference in New Issue