Merge branch 'master' into pieces-progress-bar

This commit is contained in:
Pedro Algarvio 2011-05-28 10:54:03 +01:00
commit ef98d19ed4
22 changed files with 216 additions and 131 deletions

1
create_potfiles_in.py Normal file → Executable file
View file

@ -1,3 +1,4 @@
#!/usr/bin/env python
import os import os
# Paths to exclude # Paths to exclude

View file

@ -166,6 +166,18 @@ def get_default_download_dir():
if windows_check(): if windows_check():
return os.path.expanduser("~") return os.path.expanduser("~")
else: else:
from xdg.BaseDirectory import xdg_config_home
userdir_file = os.path.join(xdg_config_home, 'user-dirs.dirs')
try:
for line in open(userdir_file, 'r'):
if not line.startswith('#') and 'XDG_DOWNLOAD_DIR' in line:
download_dir = os.path.expandvars(\
line.partition("=")[2].rstrip().strip('"'))
if os.path.isdir(download_dir):
return download_dir
except IOError:
pass
return os.environ.get("HOME") return os.environ.get("HOME")
def windows_check(): def windows_check():

View file

@ -88,7 +88,9 @@ class Core(component.Component):
# Set the user agent # Set the user agent
self.settings = lt.session_settings() self.settings = lt.session_settings()
self.settings.user_agent = "Deluge %s" % deluge.common.get_version() self.settings.user_agent = "Deluge/%(deluge_version)s Libtorrent/%(lt_version)s" % \
{ 'deluge_version': deluge.common.get_version(),
'lt_version': self.get_libtorrent_version().rpartition(".")[0] }
# Set session settings # Set session settings
self.settings.send_redundant_have = True self.settings.send_redundant_have = True

View file

@ -620,6 +620,13 @@ class Torrent(object):
if distributed_copies < 0: if distributed_copies < 0:
distributed_copies = 0.0 distributed_copies = 0.0
# Calculate the seeds:peers ratio
if self.status.num_incomplete == 0:
# Use -1.0 to signify infinity
seeds_peers_ratio = -1.0
else:
seeds_peers_ratio = self.status.num_complete / float(self.status.num_incomplete)
full_status = { full_status = {
"active_time": self.status.active_time, "active_time": self.status.active_time,
"all_time_download": self.status.all_time_download, "all_time_download": self.status.all_time_download,
@ -651,6 +658,7 @@ class Torrent(object):
"remove_at_ratio": self.options["remove_at_ratio"], "remove_at_ratio": self.options["remove_at_ratio"],
"save_path": self.options["download_location"], "save_path": self.options["download_location"],
"seeding_time": self.status.seeding_time, "seeding_time": self.status.seeding_time,
"seeds_peers_ratio": seeds_peers_ratio,
"seed_rank": self.status.seed_rank, "seed_rank": self.status.seed_rank,
"state": self.state, "state": self.state,
"stop_at_ratio": self.options["stop_at_ratio"], "stop_at_ratio": self.options["stop_at_ratio"],

View file

@ -384,7 +384,7 @@ class GtkUI(GtkPluginBase):
def create_columns(self, treeView): def create_columns(self, treeView):
rendererToggle = gtk.CellRendererToggle() rendererToggle = gtk.CellRendererToggle()
column = gtk.TreeViewColumn( column = gtk.TreeViewColumn(
_("Active"), rendererToggle, activatable=True, active=1 _("Active"), rendererToggle, activatable=1, active=1
) )
column.set_sort_column_id(1) column.set_sort_column_id(1)
treeView.append_column(column) treeView.append_column(column)

View file

@ -44,7 +44,7 @@ __plugin_name__ = "AutoAdd"
__author__ = "Chase Sterling, Pedro Algarvio" __author__ = "Chase Sterling, Pedro Algarvio"
__author_email__ = "chase.sterling@gmail.com, pedro@algarvio.me" __author_email__ = "chase.sterling@gmail.com, pedro@algarvio.me"
__version__ = "1.02" __version__ = "1.02"
__url__ = "http://forum.deluge-torrent.org/viewtopic.php?f=9&t=26775" __url__ = "http://dev.deluge-torrent.org/wiki/Plugins/AutoAdd"
__license__ = "GPLv3" __license__ = "GPLv3"
__description__ = "Monitors folders for .torrent files." __description__ = "Monitors folders for .torrent files."
__long_description__ = """""" __long_description__ = """"""

View file

@ -39,15 +39,11 @@ __author_email__ = "mvoncken@gmail.com"
__version__ = "0.1" __version__ = "0.1"
__url__ = "http://deluge-torrent.org" __url__ = "http://deluge-torrent.org"
__license__ = "GPLv3" __license__ = "GPLv3"
__description__ = "Label plugin." __description__ = "Allows labels to be assigned to torrents"
__long_description__ = """ __long_description__ = """
Label plugin. Allows labels to be assigned to torrents
Offers filters on state,tracker and keyword.
adds a tracker column.
future: Real labels.
Also offers filters on state, tracker and keywords
""" """
__pkg_data__ = {__plugin_name__.lower(): ["template/*", "data/*"]} __pkg_data__ = {__plugin_name__.lower(): ["template/*", "data/*"]}

View file

@ -46,10 +46,13 @@ __version__ = "0.1"
__url__ = "http://dev.deluge-torrent.org/" __url__ = "http://dev.deluge-torrent.org/"
__license__ = "GPLv3" __license__ = "GPLv3"
__description__ = "Plugin which provides notifications to Deluge." __description__ = "Plugin which provides notifications to Deluge."
__long_description__ = __description__ + """\ __long_description__ = """
Email, Popup, Blink and Sound notifications are supported. Plugin which provides notifications to Deluge
The plugin also allows other plugins to make use of itself for their own custom
notifications. Email, Popup, Blink and Sound notifications
The plugin also allows other plugins to make
use of itself for their own custom notifications
""" """
__pkg_data__ = {__plugin_name__.lower(): ["template/*", "data/*"]} __pkg_data__ = {__plugin_name__.lower(): ["template/*", "data/*"]}

View file

@ -182,6 +182,13 @@ class DelugeRPCProtocol(Protocol):
exception_cls = getattr(error, request[2]) exception_cls = getattr(error, request[2])
exception = exception_cls(*request[3], **request[4]) exception = exception_cls(*request[3], **request[4])
# Ideally we would chain the deferreds instead of instance
# checking just to log them. But, that would mean that any
# errback on the fist deferred should returns it's failure
# so it could pass back to the 2nd deferred on the chain. But,
# that does not always happen.
# So, just do some instance checking and just log rpc error at
# diferent levels.
r = self.__rpc_requests[request_id] r = self.__rpc_requests[request_id]
msg = "RPCError Message Received!" msg = "RPCError Message Received!"
msg += "\n" + "-" * 80 msg += "\n" + "-" * 80

View file

@ -56,11 +56,11 @@ class AboutDialog:
version = deluge.common.get_version() version = deluge.common.get_version()
self.about.set_copyright(u'Copyright \u00A9 2007-2009 Deluge Team') self.about.set_copyright(u'Copyright \u00A9 2007-2011 Deluge Team')
self.about.set_comments( self.about.set_comments(
"A peer-to-peer file sharing program\nutilizing the Bittorrent " "A peer-to-peer file sharing program\nutilizing the BitTorrent "
"protocol.\n\nCore Version: %coreversion%\nlibtorrent version: " "protocol\n\n"
"%ltversion%") "Client Version: %s\n" % version)
self.about.set_version(version) self.about.set_version(version)
self.about.set_authors([ self.about.set_authors([
"Current Developers:", "Andrew Resch", "Damien Churchill", "Current Developers:", "Andrew Resch", "Damien Churchill",
@ -253,17 +253,21 @@ class AboutDialog:
"This program is free software; you can redistribute it and/or " "This program is free software; you can redistribute it and/or "
"modify it under the terms of the GNU General Public License as " "modify it under the terms of the GNU General Public License as "
"published by the Free Software Foundation; either version 3 of " "published by the Free Software Foundation; either version 3 of "
"the License, or (at your option) any later version. This program " "the License, or (at your option) any later version. \n\n"
"This program "
"is distributed in the hope that it will be useful, but WITHOUT " "is distributed in the hope that it will be useful, but WITHOUT "
"ANY WARRANTY; without even the implied warranty of " "ANY WARRANTY; without even the implied warranty of "
"MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU " "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU "
"General Public License for more details. You should have received " "General Public License for more details. \n\n"
"You should have received "
"a copy of the GNU General Public License along with this program; " "a copy of the GNU General Public License along with this program; "
"if not, see <http://www.gnu.org/licenses>. In addition, as a " "if not, see <http://www.gnu.org/licenses>. \n\n"
"In addition, as a "
"special exception, the copyright holders give permission to link " "special exception, the copyright holders give permission to link "
"the code of portions of this program with the OpenSSL library. " "the code of portions of this program with the OpenSSL library. "
"You must obey the GNU General Public License in all respects for " "You must obey the GNU General Public License in all respects for "
"all of the code used other than OpenSSL. If you modify file(s) " "all of the code used other than OpenSSL. \n\n"
"If you modify file(s) "
"with this exception, you may extend this exception to your " "with this exception, you may extend this exception to your "
"version of the file(s), but you are not obligated to do so. If " "version of the file(s), but you are not obligated to do so. If "
"you do not wish to do so, delete this exception statement from " "you do not wish to do so, delete this exception statement from "
@ -271,7 +275,7 @@ class AboutDialog:
"source files in the program, then also delete it here." "source files in the program, then also delete it here."
)) ))
self.about.set_website("http://deluge-torrent.org") self.about.set_website("http://deluge-torrent.org")
self.about.set_website_label("http://deluge-torrent.org") self.about.set_website_label("www.deluge-torrent.org")
self.about.set_icon(common.get_deluge_icon()) self.about.set_icon(common.get_deluge_icon())
self.about.set_logo(gtk.gdk.pixbuf_new_from_file( self.about.set_logo(gtk.gdk.pixbuf_new_from_file(
@ -279,6 +283,13 @@ class AboutDialog:
)) ))
if client.connected(): if client.connected():
if not client.is_classicmode():
self.about.set_comments(
self.about.get_comments() + "Server Version: %coreversion%\n")
self.about.set_comments(
self.about.get_comments() + "Libtorrent Version: %ltversion%\n")
def on_lt_version(result): def on_lt_version(result):
c = self.about.get_comments() c = self.about.get_comments()
c = c.replace("%ltversion%", result) c = c.replace("%ltversion%", result)
@ -290,7 +301,10 @@ class AboutDialog:
self.about.set_comments(c) self.about.set_comments(c)
client.core.get_libtorrent_version().addCallback(on_lt_version) client.core.get_libtorrent_version().addCallback(on_lt_version)
if not client.is_classicmode():
client.daemon.info().addCallback(on_info) client.daemon.info().addCallback(on_info)
else:
client.core.get_libtorrent_version().addCallback(on_lt_version)
def run(self): def run(self):
self.about.show_all() self.about.show_all()

View file

@ -74,8 +74,6 @@ class EditTrackersDialog:
"on_button_edit_ok_clicked": self.on_button_edit_ok_clicked, "on_button_edit_ok_clicked": self.on_button_edit_ok_clicked,
"on_button_remove_clicked": self.on_button_remove_clicked, "on_button_remove_clicked": self.on_button_remove_clicked,
"on_button_down_clicked": self.on_button_down_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_add_ok_clicked": self.on_button_add_ok_clicked, "on_button_add_ok_clicked": self.on_button_add_ok_clicked,
"on_button_add_cancel_clicked": self.on_button_add_cancel_clicked "on_button_add_cancel_clicked": self.on_button_add_cancel_clicked
}) })
@ -94,7 +92,6 @@ class EditTrackersDialog:
self.dialog.connect("delete-event", self._on_delete_event) self.dialog.connect("delete-event", self._on_delete_event)
self.dialog.connect("response", self._on_response) self.dialog.connect("response", self._on_response)
self.changed = False
def run(self): def run(self):
# Make sure we have a torrent_id.. if not just return # Make sure we have a torrent_id.. if not just return
@ -103,7 +100,9 @@ class EditTrackersDialog:
# Get the trackers for this torrent # Get the trackers for this torrent
session = component.get("SessionProxy") session = component.get("SessionProxy")
session.get_torrent_status(self.torrent_id, ["trackers"]).addCallback(self._on_get_torrent_status) session.get_torrent_status(
self.torrent_id, ["trackers"]
).addCallback(self._on_get_torrent_status)
client.force_call() client.force_call()
self.deferred = defer.Deferred() self.deferred = defer.Deferred()
@ -115,49 +114,50 @@ class EditTrackersDialog:
self.dialog.destroy() self.dialog.destroy()
def _on_response(self, widget, response): def _on_response(self, widget, response):
self.deferred.callback(response) if response == 1:
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)
if self.old_trackers != self.trackers:
# Set the torrens trackers
client.core.set_torrent_trackers(self.torrent_id, self.trackers)
self.deferred.callback(gtk.RESPONSE_OK)
else:
self.deferred.callback(gtk.RESPONSE_CANCEL)
else:
self.deferred.callback(gtk.RESPONSE_CANCEL)
self.dialog.destroy() self.dialog.destroy()
def _on_get_torrent_status(self, status): def _on_get_torrent_status(self, status):
"""Display trackers dialog""" """Display trackers dialog"""
for tracker in status["trackers"]: self.old_trackers = list(status["trackers"])
for tracker in self.old_trackers:
self.add_tracker(tracker["tier"], tracker["url"]) self.add_tracker(tracker["tier"], tracker["url"])
self.dialog.show() self.dialog.show()
def add_tracker(self, tier, url): def add_tracker(self, tier, url):
"""Adds a tracker to the list""" """Adds a tracker to the list"""
self.liststore.append([tier, url]) self.liststore.append([tier, url])
self.changed = True
def get_selected(self): def get_selected(self):
"""Returns the selected tracker""" """Returns the selected tracker"""
return self.treeview.get_selection().get_selected()[1] 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
# Now change the tier for this tracker
self.liststore.set_value(selected, 0, new_tier)
self.changed = True
def on_button_add_clicked(self, widget): def on_button_add_clicked(self, widget):
log.debug("on_button_add_clicked") log.debug("on_button_add_clicked")
# Show the add tracker dialog # Show the add tracker dialog
self.add_tracker_dialog.show() self.add_tracker_dialog.show()
self.glade.get_widget("textview_trackers").grab_focus() self.glade.get_widget("textview_trackers").grab_focus()
self.changed = True
def on_button_remove_clicked(self, widget): def on_button_remove_clicked(self, widget):
log.debug("on_button_remove_clicked") log.debug("on_button_remove_clicked")
selected = self.get_selected() selected = self.get_selected()
if selected != None: if selected != None:
self.liststore.remove(selected) self.liststore.remove(selected)
self.changed = True
def on_button_edit_clicked(self, widget): def on_button_edit_clicked(self, widget):
"""edits an existing tracker""" """edits an existing tracker"""
@ -179,10 +179,9 @@ class EditTrackersDialog:
tracker = self.glade.get_widget("entry_edit_tracker").get_text() tracker = self.glade.get_widget("entry_edit_tracker").get_text()
self.liststore.set_value(selected, 1, tracker) self.liststore.set_value(selected, 1, tracker)
self.edit_tracker_entry.hide() self.edit_tracker_entry.hide()
self.changed = True
def on_button_down_clicked(self, widget): def on_button_up_clicked(self, widget):
log.debug("on_button_down_clicked") log.debug("on_button_up_clicked")
selected = self.get_selected() selected = self.get_selected()
num_rows = self.liststore.iter_n_children(None) num_rows = self.liststore.iter_n_children(None)
if selected != None and num_rows > 1: if selected != None and num_rows > 1:
@ -192,27 +191,16 @@ class EditTrackersDialog:
new_tier = tier - 1 new_tier = tier - 1
# Now change the tier for this tracker # Now change the tier for this tracker
self.liststore.set_value(selected, 0, new_tier) self.liststore.set_value(selected, 0, new_tier)
self.changed = True
def on_button_ok_clicked(self, widget): def on_button_down_clicked(self, widget):
log.debug("on_button_ok_clicked") log.debug("on_button_down_clicked")
self.trackers = [] selected = self.get_selected()
def each(model, path, iter, data): num_rows = self.liststore.iter_n_children(None)
tracker = {} if selected != None and num_rows > 1:
tracker["tier"] = model.get_value(iter, 0) tier = self.liststore.get_value(selected, 0)
tracker["url"] = model.get_value(iter, 1) new_tier = tier + 1
self.trackers.append(tracker) # Now change the tier for this tracker
self.liststore.foreach(each, None) self.liststore.set_value(selected, 0, new_tier)
# Set the torrens trackers
client.core.set_torrent_trackers(self.torrent_id, self.trackers)
if self.changed:
self.dialog.response(gtk.RESPONSE_OK)
else:
self.dialog.response(gtk.RESPONSE_CANCEL)
def on_button_cancel_clicked(self, widget):
log.debug("on_button_cancel_clicked")
self.dialog.response(gtk.RESPONSE_CANCEL)
def on_button_add_ok_clicked(self, widget): def on_button_add_ok_clicked(self, widget):
log.debug("on_button_add_ok_clicked") log.debug("on_button_add_ok_clicked")

View file

@ -122,7 +122,8 @@ class FilesTab(Tab):
self._editing_index = None self._editing_index = None
# Filename column # Filename column
column = gtk.TreeViewColumn(_("Filename")) self.filename_column_name = _("Filename")
column = gtk.TreeViewColumn(self.filename_column_name)
render = gtk.CellRendererPixbuf() render = gtk.CellRendererPixbuf()
column.pack_start(render, False) column.pack_start(render, False)
column.add_attribute(render, "stock-id", 6) column.add_attribute(render, "stock-id", 6)
@ -440,9 +441,8 @@ class FilesTab(Tab):
""" """
Go through the tree and update the folder complete percentages. Go through the tree and update the folder complete percentages.
""" """
root = self.treestore.get_iter_root() root = self.treestore.get_iter_root()
if self.treestore[root][5] != -1: if root is None or self.treestore[root][5] != -1:
return return
def get_completed_bytes(row): def get_completed_bytes(row):
@ -485,7 +485,10 @@ class FilesTab(Tab):
if self._editing_index == row[5]: if self._editing_index == row[5]:
continue continue
try:
progress_string = "%.2f%%" % (status["file_progress"][index] * 100) progress_string = "%.2f%%" % (status["file_progress"][index] * 100)
except IndexError:
continue
if row[2] != progress_string: if row[2] != progress_string:
row[2] = progress_string row[2] = progress_string
progress_value = status["file_progress"][index] * 100 progress_value = status["file_progress"][index] * 100
@ -504,17 +507,15 @@ class FilesTab(Tab):
# We only care about right-clicks # We only care about right-clicks
if event.button == 3: if event.button == 3:
x, y = event.get_coords() x, y = event.get_coords()
path = self.listview.get_path_at_pos(int(x), int(y)) cursor_path = self.listview.get_path_at_pos(int(x), int(y))
if not path: if not cursor_path:
return return
row = self.treestore.get_iter(path[0])
if self.get_selected_files(): paths = self.listview.get_selection().get_selected_rows()[1]
if self.treestore.get_value(row, 5) not in self.get_selected_files(): if cursor_path[0] not in paths:
row = self.treestore.get_iter(cursor_path[0])
self.listview.get_selection().unselect_all() self.listview.get_selection().unselect_all()
self.listview.get_selection().select_iter(row) self.listview.get_selection().select_iter(row)
else:
self.listview.get_selection().select_iter(row)
for widget in self.file_menu_priority_items: for widget in self.file_menu_priority_items:
widget.set_sensitive(not self.__compact) widget.set_sensitive(not self.__compact)
@ -523,16 +524,25 @@ class FilesTab(Tab):
return True return True
def _on_key_press_event(self, widget, event): def _on_key_press_event(self, widget, event):
# Menu key keyname = gtk.gdk.keyval_name(event.keyval)
if gtk.gdk.keyval_name(event.keyval) != "Menu": func = getattr(self, 'keypress_' + keyname, None)
return selected_rows = self.listview.get_selection().get_selected_rows()[1]
if func and selected_rows:
if not self.get_selected_files(): return func(event)
else:
return return
def keypress_Menu(self, event):
self.file_menu.popup(None, None, None, 3, event.time) self.file_menu.popup(None, None, None, 3, event.time)
return True return True
def keypress_F2(self, event):
path, col = self.listview.get_cursor()
for column in self.listview.get_columns():
if column.get_title() == self.filename_column_name:
self.listview.set_cursor(path, column, True)
return True
def _on_menuitem_open_file_activate(self, menuitem): def _on_menuitem_open_file_activate(self, menuitem):
self._on_row_activated(None, None, None) self._on_row_activated(None, None, None)

View file

@ -40,6 +40,7 @@ import gtk.glade
import logging import logging
import pkg_resources import pkg_resources
import glib import glib
import warnings
import deluge.component as component import deluge.component as component
import deluge.common import deluge.common
@ -259,6 +260,10 @@ class FilterTreeView(component.Component):
value = model.get_value(row, 1) value = model.get_value(row, 1)
label = model.get_value(row, 2) label = model.get_value(row, 2)
count = model.get_value(row, 3) count = model.get_value(row, 3)
#Supress Warning: g_object_set_qdata: assertion `G_IS_OBJECT (object)' failed
with warnings.catch_warnings():
warnings.simplefilter("ignore")
pix = model.get_value(row, 4) pix = model.get_value(row, 4)
if pix: if pix:

View file

@ -37,6 +37,7 @@
<property name="use_underline">True</property> <property name="use_underline">True</property>
<property name="use_stock">False</property> <property name="use_stock">False</property>
<signal name="activate" handler="on_menuitem_addtorrent_activate"/> <signal name="activate" handler="on_menuitem_addtorrent_activate"/>
<accelerator key="O" modifiers="GDK_CONTROL_MASK" signal="activate"/>
<child internal-child="image"> <child internal-child="image">
<widget class="GtkImage" id="image1"> <widget class="GtkImage" id="image1">
<property name="visible">True</property> <property name="visible">True</property>
@ -56,6 +57,7 @@
<property name="use_underline">True</property> <property name="use_underline">True</property>
<property name="use_stock">False</property> <property name="use_stock">False</property>
<signal name="activate" handler="on_menuitem_createtorrent_activate"/> <signal name="activate" handler="on_menuitem_createtorrent_activate"/>
<accelerator key="N" modifiers="GDK_CONTROL_MASK" signal="activate"/>
<child internal-child="image"> <child internal-child="image">
<widget class="GtkImage" id="image2"> <widget class="GtkImage" id="image2">
<property name="visible">True</property> <property name="visible">True</property>
@ -80,6 +82,7 @@
<property name="use_underline">True</property> <property name="use_underline">True</property>
<property name="use_stock">False</property> <property name="use_stock">False</property>
<signal name="activate" handler="on_menuitem_quitdaemon_activate"/> <signal name="activate" handler="on_menuitem_quitdaemon_activate"/>
<accelerator key="Q" modifiers="GDK_SHIFT_MASK|GDK_CONTROL_MASK" signal="activate"/>
<child internal-child="image"> <child internal-child="image">
<widget class="GtkImage" id="image3"> <widget class="GtkImage" id="image3">
<property name="visible">True</property> <property name="visible">True</property>
@ -131,6 +134,7 @@
<property name="use_underline">True</property> <property name="use_underline">True</property>
<property name="use_stock">True</property> <property name="use_stock">True</property>
<signal name="activate" handler="on_menuitem_preferences_activate"/> <signal name="activate" handler="on_menuitem_preferences_activate"/>
<accelerator key="P" modifiers="GDK_CONTROL_MASK" signal="activate"/>
</widget> </widget>
</child> </child>
<child> <child>
@ -143,6 +147,7 @@
<property name="use_underline">True</property> <property name="use_underline">True</property>
<property name="use_stock">False</property> <property name="use_stock">False</property>
<signal name="activate" handler="on_menuitem_connectionmanager_activate"/> <signal name="activate" handler="on_menuitem_connectionmanager_activate"/>
<accelerator key="M" modifiers="GDK_CONTROL_MASK" signal="activate"/>
<child internal-child="image"> <child internal-child="image">
<widget class="GtkImage" id="image4"> <widget class="GtkImage" id="image4">
<property name="visible">True</property> <property name="visible">True</property>
@ -318,6 +323,7 @@
<property name="use_underline">True</property> <property name="use_underline">True</property>
<property name="use_stock">False</property> <property name="use_stock">False</property>
<signal name="activate" handler="on_menuitem_faq_activate"/> <signal name="activate" handler="on_menuitem_faq_activate"/>
<accelerator key="F1" signal="activate"/>
<child internal-child="image"> <child internal-child="image">
<widget class="GtkImage" id="image6"> <widget class="GtkImage" id="image6">
<property name="visible">True</property> <property name="visible">True</property>

View file

@ -274,6 +274,13 @@
<property name="use_underline">True</property> <property name="use_underline">True</property>
</widget> </widget>
</child> </child>
<child>
<widget class="GtkMenuItem" id="menuitem_change_owner">
<property name="visible">False</property>
<property name="label" translatable="yes">_Change Ownership</property>
<property name="use_underline">True</property>
</widget>
</child>
</widget> </widget>
<widget class="GtkMenu" id="queue_torrent_menu"> <widget class="GtkMenu" id="queue_torrent_menu">
<property name="visible">True</property> <property name="visible">True</property>

View file

@ -33,11 +33,13 @@
# #
# #
import gobject
gobject.set_prgname("deluge")
# Install the twisted reactor # Install the twisted reactor
from twisted.internet import gtk2reactor from twisted.internet import gtk2reactor
reactor = gtk2reactor.install() reactor = gtk2reactor.install()
import gobject
import gettext import gettext
import locale import locale
import pkg_resources import pkg_resources
@ -114,7 +116,7 @@ DEFAULT_PREFS = {
"interactive_add": True, "interactive_add": True,
"focus_add_dialog": True, "focus_add_dialog": True,
"enable_system_tray": True, "enable_system_tray": True,
"close_to_tray": True, "close_to_tray": False,
"start_in_tray": False, "start_in_tray": False,
"enable_appindicator": False, "enable_appindicator": False,
"lock_tray": False, "lock_tray": False,

View file

@ -111,6 +111,15 @@ def cell_data_date_or_never(column, cell, model, row, data):
else: else:
cell.set_property('text', _("Never")) cell.set_property('text', _("Never"))
def cell_data_speed_limit(column, cell, model, row, data):
"""Display value as a speed, eg. 2 KiB/s"""
speed = model.get_value(row, data)
speed_str = ""
if speed > 0:
speed_str = deluge.common.fspeed(speed * 1024)
cell.set_property('text', speed_str)
class ListViewColumnState: class ListViewColumnState:
"""Used for saving/loading column state""" """Used for saving/loading column state"""
def __init__(self, name, position, width, visible, sort, sort_order): def __init__(self, name, position, width, visible, sort, sort_order):
@ -435,7 +444,7 @@ class ListView:
def add_column(self, header, render, col_types, hidden, position, def add_column(self, header, render, col_types, hidden, position,
status_field, sortid, text=0, value=0, pixbuf=0, function=None, status_field, sortid, text=0, value=0, pixbuf=0, function=None,
column_type=None, sort_func=None, tooltip=None): column_type=None, sort_func=None, tooltip=None, default=True):
"""Adds a column to the ListView""" """Adds a column to the ListView"""
# Add the column types to liststore_columns # Add the column types to liststore_columns
column_indices = [] column_indices = []
@ -516,10 +525,12 @@ class ListView:
column.get_widget().set_tooltip_markup(tooltip) column.get_widget().set_tooltip_markup(tooltip)
# Check for loaded state and apply # Check for loaded state and apply
column_in_state = False
if self.state != None: if self.state != None:
for column_state in self.state: for column_state in self.state:
if header == column_state.name: if header == column_state.name:
# We found a loaded state # We found a loaded state
column_in_state = True
if column_state.width > 0: if column_state.width > 0:
column.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED) column.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED)
column.set_fixed_width(column_state.width) column.set_fixed_width(column_state.width)
@ -530,6 +541,12 @@ class ListView:
) )
column.set_visible(column_state.visible) column.set_visible(column_state.visible)
position = column_state.position position = column_state.position
break
# Set this column to not visible if its not in the state and
# its not supposed to be shown by default
if not column_in_state and not default and not hidden:
column.set_visible(False)
if position is not None: if position is not None:
self.treeview.insert_column(column, position) self.treeview.insert_column(column, position)
@ -546,64 +563,64 @@ class ListView:
def add_text_column(self, header, col_type=str, hidden=False, position=None, def add_text_column(self, header, col_type=str, hidden=False, position=None,
status_field=None, sortid=0, column_type="text", status_field=None, sortid=0, column_type="text",
sort_func=None, tooltip=None): sort_func=None, tooltip=None, default=True):
"""Add a text column to the listview. Only the header name is required. """Add a text column to the listview. Only the header name is required.
""" """
render = gtk.CellRendererText() render = gtk.CellRendererText()
self.add_column(header, render, col_type, hidden, position, self.add_column(header, render, col_type, hidden, position,
status_field, sortid, column_type=column_type, status_field, sortid, column_type=column_type,
sort_func=sort_func, tooltip=tooltip) sort_func=sort_func, tooltip=tooltip, default=default)
return True return True
def add_bool_column(self, header, col_type=bool, hidden=False, def add_bool_column(self, header, col_type=bool, hidden=False,
position=None, status_field=None, sortid=0, position=None, status_field=None, sortid=0,
column_type="bool", tooltip=None): column_type="bool", tooltip=None, default=True):
"""Add a bool column to the listview""" """Add a bool column to the listview"""
render = gtk.CellRendererToggle() render = gtk.CellRendererToggle()
self.add_column(header, render, col_type, hidden, position, self.add_column(header, render, col_type, hidden, position,
status_field, sortid, column_type=column_type, status_field, sortid, column_type=column_type,
tooltip=tooltip) tooltip=tooltip, default=default)
def add_func_column(self, header, function, col_types, sortid=0, def add_func_column(self, header, function, col_types, sortid=0,
hidden=False, position=None, status_field=None, hidden=False, position=None, status_field=None,
column_type="func", sort_func=None, tooltip=None): column_type="func", sort_func=None, tooltip=None, default=True):
"""Add a function column to the listview. Need a header name, the """Add a function column to the listview. Need a header name, the
function and the column types.""" function and the column types."""
render = gtk.CellRendererText() render = gtk.CellRendererText()
self.add_column(header, render, col_types, hidden, position, self.add_column(header, render, col_types, hidden, position,
status_field, sortid, column_type=column_type, status_field, sortid, column_type=column_type,
function=function, sort_func=sort_func, tooltip=tooltip) function=function, sort_func=sort_func, tooltip=tooltip, default=default)
return True return True
def add_progress_column(self, header, col_types=[float, str], sortid=0, def add_progress_column(self, header, col_types=[float, str], sortid=0,
hidden=False, position=None, status_field=None, hidden=False, position=None, status_field=None,
function=None, column_type="progress", function=None, column_type="progress",
tooltip=None): tooltip=None, default=True):
"""Add a progress column to the listview.""" """Add a progress column to the listview."""
render = gtk.CellRendererProgress() render = gtk.CellRendererProgress()
self.add_column(header, render, col_types, hidden, position, self.add_column(header, render, col_types, hidden, position,
status_field, sortid, function=function, status_field, sortid, function=function,
column_type=column_type, value=0, text=1, column_type=column_type, value=0, text=1,
tooltip=tooltip) tooltip=tooltip, default=default)
return True return True
def add_texticon_column(self, header, col_types=[str, str], sortid=1, def add_texticon_column(self, header, col_types=[str, str], sortid=1,
hidden=False, position=None, status_field=None, hidden=False, position=None, status_field=None,
column_type="texticon", function=None, column_type="texticon", function=None,
tooltip=None): tooltip=None, default=True):
"""Adds a texticon column to the listview.""" """Adds a texticon column to the listview."""
render1 = gtk.CellRendererPixbuf() render1 = gtk.CellRendererPixbuf()
render2 = gtk.CellRendererText() render2 = gtk.CellRendererText()
self.add_column(header, (render1, render2), col_types, hidden, position, self.add_column(header, (render1, render2), col_types, hidden, position,
status_field, sortid, column_type=column_type, status_field, sortid, column_type=column_type,
function=function, pixbuf=0, text=1, tooltip=tooltip) function=function, pixbuf=0, text=1, tooltip=tooltip, default=default)
return True return True

View file

@ -102,10 +102,6 @@ class MenuBar(component.Component):
self.torrentmenu = self.torrentmenu_glade.get_widget("torrent_menu") self.torrentmenu = self.torrentmenu_glade.get_widget("torrent_menu")
self.menu_torrent = self.window.main_glade.get_widget("menu_torrent") self.menu_torrent = self.window.main_glade.get_widget("menu_torrent")
self.menuitem_change_owner = gtk.MenuItem(_("Change Ownership"))
self.torrentmenu_glade.get_widget("options_torrent_menu").append(self.menuitem_change_owner)
# Attach the torrent_menu to the Torrent file menu # Attach the torrent_menu to the Torrent file menu
self.menu_torrent.set_submenu(self.torrentmenu) self.menu_torrent.set_submenu(self.torrentmenu)
@ -209,12 +205,8 @@ class MenuBar(component.Component):
# Show the Torrent menu because we're connected to a host # Show the Torrent menu because we're connected to a host
self.menu_torrent.show() self.menu_torrent.show()
# Hide the change owner submenu until we get the accounts back from the
# demon.
self.menuitem_change_owner.set_visible(False)
if client.get_auth_level() == deluge.common.AUTH_LEVEL_ADMIN: if client.get_auth_level() == deluge.common.AUTH_LEVEL_ADMIN:
# Get Known accounts to allow chaning ownership # Get known accounts to allow changing ownership
client.core.get_known_accounts().addCallback( client.core.get_known_accounts().addCallback(
self._on_known_accounts).addErrback(self._on_known_accounts_fail self._on_known_accounts).addErrback(self._on_known_accounts_fail
) )
@ -234,7 +226,6 @@ class MenuBar(component.Component):
self.window.main_glade.get_widget("separatormenuitem").hide() self.window.main_glade.get_widget("separatormenuitem").hide()
self.window.main_glade.get_widget("menuitem_quitdaemon").hide() self.window.main_glade.get_widget("menuitem_quitdaemon").hide()
def update_menu(self): def update_menu(self):
selected = component.get('TorrentView').get_selected_torrents() selected = component.get('TorrentView').get_selected_torrents()
if not selected or len(selected) == 0: if not selected or len(selected) == 0:
@ -531,7 +522,7 @@ class MenuBar(component.Component):
if len(known_accounts) <= 1: if len(known_accounts) <= 1:
return return
self.menuitem_change_owner.set_visible(True) self.torrentmenu_glade.get_widget("menuitem_change_owner").set_visible(True)
self.change_owner_submenu = gtk.Menu() self.change_owner_submenu = gtk.Menu()
self.change_owner_submenu_items = {} self.change_owner_submenu_items = {}
@ -549,13 +540,13 @@ class MenuBar(component.Component):
self.change_owner_submenu.show_all() self.change_owner_submenu.show_all()
self.change_owner_submenu_items[None].set_active(True) self.change_owner_submenu_items[None].set_active(True)
self.change_owner_submenu_items[None].hide() self.change_owner_submenu_items[None].hide()
self.menuitem_change_owner.connect( self.torrentmenu_glade.get_widget("menuitem_change_owner").connect(
"activate", self._on_change_owner_submenu_active "activate", self._on_change_owner_submenu_active
) )
self.menuitem_change_owner.set_submenu(self.change_owner_submenu) self.torrentmenu_glade.get_widget("menuitem_change_owner").set_submenu(self.change_owner_submenu)
def _on_known_accounts_fail(self, reason): def _on_known_accounts_fail(self, reason):
self.menuitem_change_owner.set_visible(False) self.torrentmenu_glade.get_widget("menuitem_change_owner").set_visible(False)
def _on_change_owner_submenu_active(self, widget): def _on_change_owner_submenu_active(self, widget):
log.debug("_on_change_owner_submenu_active") log.debug("_on_change_owner_submenu_active")

View file

@ -43,6 +43,7 @@ import gtk.glade
import gettext import gettext
import gobject import gobject
import logging import logging
import warnings
from urlparse import urlparse from urlparse import urlparse
import deluge.common import deluge.common
@ -77,13 +78,17 @@ ICON_STATE = {
"Seeding": icon_seeding, "Seeding": icon_seeding,
"Paused": icon_inactive, "Paused": icon_inactive,
"Error": icon_alert, "Error": icon_alert,
"Queued": icon_queued "Queued": icon_queued,
"Checking Resume Data": icon_checking
} }
def cell_data_statusicon(column, cell, model, row, data): def cell_data_statusicon(column, cell, model, row, data):
"""Display text with an icon""" """Display text with an icon"""
try: try:
icon = ICON_STATE[model.get_value(row, data)] icon = ICON_STATE[model.get_value(row, data)]
#Supress Warning: g_object_set_qdata: assertion `G_IS_OBJECT (object)' failed
with warnings.catch_warnings():
warnings.simplefilter("ignore")
if cell.get_property("pixbuf") != icon: if cell.get_property("pixbuf") != icon:
cell.set_property("pixbuf", icon) cell.set_property("pixbuf", icon)
except KeyError: except KeyError:
@ -104,6 +109,9 @@ def cell_data_trackericon(column, cell, model, row, data):
else: else:
icon = create_blank_icon() icon = create_blank_icon()
#Supress Warning: g_object_set_qdata: assertion `G_IS_OBJECT (object)' failed
with warnings.catch_warnings():
warnings.simplefilter("ignore")
if cell.get_property("pixbuf") != icon: if cell.get_property("pixbuf") != icon:
cell.set_property("pixbuf", icon) cell.set_property("pixbuf", icon)
@ -214,45 +222,51 @@ class TorrentView(listview.ListView, component.Component):
status_field=["total_wanted"]) status_field=["total_wanted"])
self.add_func_column(_("Downloaded"), listview.cell_data_size, self.add_func_column(_("Downloaded"), listview.cell_data_size,
[gobject.TYPE_UINT64], [gobject.TYPE_UINT64],
status_field=["all_time_download"]) status_field=["all_time_download"], default=False)
self.add_func_column(_("Uploaded"), listview.cell_data_size, self.add_func_column(_("Uploaded"), listview.cell_data_size,
[gobject.TYPE_UINT64], [gobject.TYPE_UINT64],
status_field=["total_uploaded"]) status_field=["total_uploaded"], default=False)
self.add_progress_column(_("Progress"), self.add_progress_column(_("Progress"),
status_field=["progress", "state"], status_field=["progress", "state"],
col_types=[float, str], col_types=[float, str],
function=cell_data_progress) function=cell_data_progress)
self.add_func_column(_("Seeders"), listview.cell_data_peer, [int, int], self.add_func_column(_("Seeders"), listview.cell_data_peer, [int, int],
status_field=["num_seeds", "total_seeds"], status_field=["num_seeds", "total_seeds"],
sort_func=seed_peer_column_sort) sort_func=seed_peer_column_sort, default=False)
self.add_func_column(_("Peers"), listview.cell_data_peer, [int, int], self.add_func_column(_("Peers"), listview.cell_data_peer, [int, int],
status_field=["num_peers", "total_peers"], status_field=["num_peers", "total_peers"],
sort_func=seed_peer_column_sort) sort_func=seed_peer_column_sort, default=False)
self.add_func_column(_("Seeders") + "/" + _("Peers"), listview.cell_data_ratio, [float],
status_field=["seeds_peers_ratio"], default=False)
self.add_func_column(_("Down Speed"), listview.cell_data_speed, [float], self.add_func_column(_("Down Speed"), listview.cell_data_speed, [float],
status_field=["download_payload_rate"]) status_field=["download_payload_rate"])
self.add_func_column(_("Up Speed"), listview.cell_data_speed, [float], self.add_func_column(_("Up Speed"), listview.cell_data_speed, [float],
status_field=["upload_payload_rate"]) status_field=["upload_payload_rate"])
self.add_func_column(_("Down Limit"), listview.cell_data_speed_limit, [float],
status_field=["max_download_speed"], default=False)
self.add_func_column(_("Up Limit"), listview.cell_data_speed_limit, [float],
status_field=["max_upload_speed"], default=False)
self.add_func_column(_("ETA"), listview.cell_data_time, [int], self.add_func_column(_("ETA"), listview.cell_data_time, [int],
status_field=["eta"], sort_func=eta_column_sort) status_field=["eta"], sort_func=eta_column_sort)
self.add_func_column(_("Ratio"), listview.cell_data_ratio, [float], self.add_func_column(_("Ratio"), listview.cell_data_ratio, [float],
status_field=["ratio"]) status_field=["ratio"], default=False)
self.add_func_column(_("Avail"), listview.cell_data_ratio, [float], self.add_func_column(_("Avail"), listview.cell_data_ratio, [float],
status_field=["distributed_copies"]) status_field=["distributed_copies"], default=False)
self.add_func_column(_("Added"), listview.cell_data_date, [float], self.add_func_column(_("Added"), listview.cell_data_date, [float],
status_field=["time_added"]) status_field=["time_added"], default=False)
self.add_func_column(_("Last Seen Complete"), self.add_func_column(_("Last Seen Complete"),
listview.cell_data_date_or_never, [float], listview.cell_data_date_or_never, [float],
status_field=["last_seen_complete"]) status_field=["last_seen_complete"], default=False)
self.add_texticon_column(_("Tracker"), self.add_texticon_column(_("Tracker"),
status_field=["tracker_host", "tracker_host"], status_field=["tracker_host", "tracker_host"],
function=cell_data_trackericon) function=cell_data_trackericon, default=False)
self.add_text_column(_("Save Path"), status_field=["save_path"]) self.add_text_column(_("Save Path"), status_field=["save_path"], default=False)
self.add_text_column(_("Owner"), status_field=["owner"]) self.add_text_column(_("Owner"), status_field=["owner"], default=False)
self.add_bool_column(_("Public"), status_field=["public"]) self.add_bool_column(_("Public"), status_field=["public"], default=False)
self.restore_columns_order_from_state() self.restore_columns_order_from_state()
self.add_bool_column(_("Shared"), status_field=["shared"], self.add_bool_column(_("Shared"), status_field=["shared"],
tooltip=_("Torrent is shared between other Deluge " tooltip=_("Torrent is shared between other Deluge "
"users or not.")) "users or not."), default=False)
# Set filter to None for now # Set filter to None for now
self.filter = None self.filter = None

0
gettextize.sh Normal file → Executable file
View file

1
msgfmt.py Normal file → Executable file
View file

@ -1,3 +1,4 @@
#!/usr/bin/env python
# -*- coding: iso-8859-1 -*- # -*- coding: iso-8859-1 -*-
# Written by Martin v. Lwis <loewis@informatik.hu-berlin.de> # Written by Martin v. Lwis <loewis@informatik.hu-berlin.de>
# Plural forms support added by alexander smishlajev <alex@tycobka.lv> # Plural forms support added by alexander smishlajev <alex@tycobka.lv>

View file

@ -1,3 +1,4 @@
#!/usr/bin/env python
# #
# setup.py # setup.py
# #