Fix for #1885 and add simple caching to the data funcs for the torrentview
* Fix for #1885 (Wrong tracker icon in torrent list) * Moved the data functions from torrentview/listview into torrentview_data_funcs.py * Added caching the current value of the cell renderer for the data functions * Reordered if-tests in deluge.common.fsize * Disable data funcs when column is hidden
This commit is contained in:
parent
feaeee0379
commit
8ecc0e11a7
|
@ -258,6 +258,17 @@ def open_url_in_browser(url):
|
||||||
|
|
||||||
## Formatting text functions
|
## Formatting text functions
|
||||||
|
|
||||||
|
byte_txt = "Bytes"
|
||||||
|
kib_txt = "KiB"
|
||||||
|
mib_txt = "MiB"
|
||||||
|
gib_txt = "GiB"
|
||||||
|
|
||||||
|
def translate_strings():
|
||||||
|
byte_txt = _("Bytes")
|
||||||
|
kib_txt = _("KiB")
|
||||||
|
mib_txt = _("MiB")
|
||||||
|
gib_txt = _("GiB")
|
||||||
|
|
||||||
def fsize(fsize_b):
|
def fsize(fsize_b):
|
||||||
"""
|
"""
|
||||||
Formats the bytes value into a string with KiB, MiB or GiB units
|
Formats the bytes value into a string with KiB, MiB or GiB units
|
||||||
|
@ -273,14 +284,17 @@ def fsize(fsize_b):
|
||||||
'109.6 KiB'
|
'109.6 KiB'
|
||||||
|
|
||||||
"""
|
"""
|
||||||
fsize_kb = fsize_b / 1024.0
|
# Bigger than 1 GiB
|
||||||
if fsize_kb < 1024:
|
if (fsize_b >= 1073741824):
|
||||||
return "%.1f %s" % (fsize_kb, _("KiB"))
|
return "%.1f %s" % (fsize_b / 1073741824.0, gib_txt)
|
||||||
fsize_mb = fsize_kb / 1024.0
|
# Bigger than 1 MiB
|
||||||
if fsize_mb < 1024:
|
elif (fsize_b >= 1048576):
|
||||||
return "%.1f %s" % (fsize_mb, _("MiB"))
|
return "%.1f %s" % (fsize_b / 1048576.0, mib_txt)
|
||||||
fsize_gb = fsize_mb / 1024.0
|
# Bigger than 1 KiB
|
||||||
return "%.1f %s" % (fsize_gb, _("GiB"))
|
elif (fsize_b >= 1024):
|
||||||
|
return "%.1f %s" % (fsize_b / 1024.0, kib_txt)
|
||||||
|
else:
|
||||||
|
return "%d %s" % (fsize_b, byte_txt)
|
||||||
|
|
||||||
def fsize_short(fsize_b):
|
def fsize_short(fsize_b):
|
||||||
"""
|
"""
|
||||||
|
@ -797,6 +811,7 @@ def setup_translations(setup_pygtk=False):
|
||||||
import gtk.glade
|
import gtk.glade
|
||||||
gtk.glade.bindtextdomain("deluge", translations_path)
|
gtk.glade.bindtextdomain("deluge", translations_path)
|
||||||
gtk.glade.textdomain("deluge")
|
gtk.glade.textdomain("deluge")
|
||||||
|
translate_strings()
|
||||||
except Exception, e:
|
except Exception, e:
|
||||||
log.error("Unable to initialize gettext/locale!")
|
log.error("Unable to initialize gettext/locale!")
|
||||||
log.exception(e)
|
log.exception(e)
|
||||||
|
|
|
@ -12,7 +12,15 @@ class CommonTestCase(unittest.TestCase):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def test_fsize(self):
|
def test_fsize(self):
|
||||||
self.failUnless(fsize(112245) == "109.6 KiB")
|
self.assertEquals(fsize(100), "100 Bytes")
|
||||||
|
self.assertEquals(fsize(1023), "1023 Bytes")
|
||||||
|
self.assertEquals(fsize(1024), "1.0 KiB")
|
||||||
|
self.assertEquals(fsize(1048575), "1024.0 KiB")
|
||||||
|
self.assertEquals(fsize(1048576), "1.0 MiB")
|
||||||
|
self.assertEquals(fsize(1073741823), "1024.0 MiB")
|
||||||
|
self.assertEquals(fsize(1073741824), "1.0 GiB")
|
||||||
|
self.assertEquals(fsize(112245), "109.6 KiB")
|
||||||
|
self.assertEquals(fsize(110723441824), "103.1 GiB")
|
||||||
|
|
||||||
def test_fpcnt(self):
|
def test_fpcnt(self):
|
||||||
self.failUnless(fpcnt(0.9311) == "93.11%")
|
self.failUnless(fpcnt(0.9311) == "93.11%")
|
||||||
|
|
|
@ -17,7 +17,7 @@ class TrackerIconsTestCase(unittest.TestCase):
|
||||||
def test_get_deluge_png(self):
|
def test_get_deluge_png(self):
|
||||||
# Deluge has a png favicon link
|
# Deluge has a png favicon link
|
||||||
icon = TrackerIcon(os.path.join(dirname, "deluge.png"))
|
icon = TrackerIcon(os.path.join(dirname, "deluge.png"))
|
||||||
d = icons.get("deluge-torrent.org")
|
d = icons.fetch("deluge-torrent.org")
|
||||||
d.addCallback(self.assertNotIdentical, None)
|
d.addCallback(self.assertNotIdentical, None)
|
||||||
d.addCallback(self.assertEquals, icon)
|
d.addCallback(self.assertEquals, icon)
|
||||||
return d
|
return d
|
||||||
|
@ -26,7 +26,7 @@ class TrackerIconsTestCase(unittest.TestCase):
|
||||||
# Google doesn't have any icon links
|
# Google doesn't have any icon links
|
||||||
# So instead we'll grab its favicon.ico
|
# So instead we'll grab its favicon.ico
|
||||||
icon = TrackerIcon(os.path.join(dirname, "google.ico"))
|
icon = TrackerIcon(os.path.join(dirname, "google.ico"))
|
||||||
d = icons.get("www.google.com")
|
d = icons.fetch("www.google.com")
|
||||||
d.addCallback(self.assertNotIdentical, None)
|
d.addCallback(self.assertNotIdentical, None)
|
||||||
d.addCallback(self.assertEquals, icon)
|
d.addCallback(self.assertEquals, icon)
|
||||||
return d
|
return d
|
||||||
|
@ -34,7 +34,7 @@ class TrackerIconsTestCase(unittest.TestCase):
|
||||||
def test_get_google_ico_with_redirect(self):
|
def test_get_google_ico_with_redirect(self):
|
||||||
# google.com redirects to www.google.com
|
# google.com redirects to www.google.com
|
||||||
icon = TrackerIcon(os.path.join(dirname, "google.ico"))
|
icon = TrackerIcon(os.path.join(dirname, "google.ico"))
|
||||||
d = icons.get("google.com")
|
d = icons.fetch("google.com")
|
||||||
d.addCallback(self.assertNotIdentical, None)
|
d.addCallback(self.assertNotIdentical, None)
|
||||||
d.addCallback(self.assertEquals, icon)
|
d.addCallback(self.assertEquals, icon)
|
||||||
return d
|
return d
|
||||||
|
@ -42,7 +42,7 @@ class TrackerIconsTestCase(unittest.TestCase):
|
||||||
def test_get_ubuntu_ico(self):
|
def test_get_ubuntu_ico(self):
|
||||||
# ubuntu.com has inline css which causes HTMLParser issues
|
# ubuntu.com has inline css which causes HTMLParser issues
|
||||||
icon = TrackerIcon(os.path.join(dirname, "ubuntu.ico"))
|
icon = TrackerIcon(os.path.join(dirname, "ubuntu.ico"))
|
||||||
d = icons.get("www.ubuntu.com")
|
d = icons.fetch("www.ubuntu.com")
|
||||||
d.addCallback(self.assertNotIdentical, None)
|
d.addCallback(self.assertNotIdentical, None)
|
||||||
d.addCallback(self.assertEquals, icon)
|
d.addCallback(self.assertEquals, icon)
|
||||||
return d
|
return d
|
||||||
|
@ -50,19 +50,19 @@ class TrackerIconsTestCase(unittest.TestCase):
|
||||||
def test_get_openbt_png(self):
|
def test_get_openbt_png(self):
|
||||||
# openbittorrent.com has an incorrect type (image/gif)
|
# openbittorrent.com has an incorrect type (image/gif)
|
||||||
icon = TrackerIcon(os.path.join(dirname, "openbt.png"))
|
icon = TrackerIcon(os.path.join(dirname, "openbt.png"))
|
||||||
d = icons.get("openbittorrent.com")
|
d = icons.fetch("openbittorrent.com")
|
||||||
d.addCallback(self.assertNotIdentical, None)
|
d.addCallback(self.assertNotIdentical, None)
|
||||||
d.addCallback(self.assertEquals, icon)
|
d.addCallback(self.assertEquals, icon)
|
||||||
return d
|
return d
|
||||||
|
|
||||||
def test_get_publicbt_ico(self):
|
def test_get_publicbt_ico(self):
|
||||||
icon = TrackerIcon(os.path.join(dirname, "publicbt.ico"))
|
icon = TrackerIcon(os.path.join(dirname, "publicbt.ico"))
|
||||||
d = icons.get("publicbt.org")
|
d = icons.fetch("publicbt.org")
|
||||||
d.addCallback(self.assertNotIdentical, None)
|
d.addCallback(self.assertNotIdentical, None)
|
||||||
d.addCallback(self.assertEquals, icon)
|
d.addCallback(self.assertEquals, icon)
|
||||||
return d
|
return d
|
||||||
|
|
||||||
def test_get_empty_string_tracker(self):
|
def test_get_empty_string_tracker(self):
|
||||||
d = icons.get("")
|
d = icons.fetch("")
|
||||||
d.addCallback(self.assertIdentical, None)
|
d.addCallback(self.assertIdentical, None)
|
||||||
return d
|
return d
|
||||||
|
|
|
@ -48,7 +48,7 @@ import twisted.web.error
|
||||||
from deluge.ui.client import client
|
from deluge.ui.client import client
|
||||||
from deluge.httpdownloader import download_file
|
from deluge.httpdownloader import download_file
|
||||||
import deluge.component as component
|
import deluge.component as component
|
||||||
import listview
|
from torrentview_data_funcs import cell_data_size
|
||||||
from deluge.configmanager import ConfigManager
|
from deluge.configmanager import ConfigManager
|
||||||
import deluge.common
|
import deluge.common
|
||||||
import deluge.ui.common
|
import deluge.ui.common
|
||||||
|
@ -136,7 +136,7 @@ class AddTorrentDialog(component.Component):
|
||||||
render = gtk.CellRendererText()
|
render = gtk.CellRendererText()
|
||||||
column = gtk.TreeViewColumn(_("Size"))
|
column = gtk.TreeViewColumn(_("Size"))
|
||||||
column.pack_start(render)
|
column.pack_start(render)
|
||||||
column.set_cell_data_func(render, listview.cell_data_size, 2)
|
column.set_cell_data_func(render, cell_data_size, 2)
|
||||||
self.listview_files.append_column(column)
|
self.listview_files.append_column(column)
|
||||||
|
|
||||||
self.listview_torrents.set_model(self.torrent_liststore)
|
self.listview_torrents.set_model(self.torrent_liststore)
|
||||||
|
|
|
@ -142,7 +142,7 @@ class FilesTab(Tab):
|
||||||
column = gtk.TreeViewColumn(_("Size"))
|
column = gtk.TreeViewColumn(_("Size"))
|
||||||
render = gtk.CellRendererText()
|
render = gtk.CellRendererText()
|
||||||
column.pack_start(render, False)
|
column.pack_start(render, False)
|
||||||
column.set_cell_data_func(render, deluge.ui.gtkui.listview.cell_data_size, 1)
|
column.set_cell_data_func(render, deluge.ui.gtkui.torrentview_data_funcs.cell_data_size, 1)
|
||||||
column.set_sort_column_id(1)
|
column.set_sort_column_id(1)
|
||||||
column.set_clickable(True)
|
column.set_clickable(True)
|
||||||
column.set_resizable(True)
|
column.set_resizable(True)
|
||||||
|
|
|
@ -228,7 +228,7 @@ class FilterTreeView(component.Component):
|
||||||
self.filters[(cat, value)] = row
|
self.filters[(cat, value)] = row
|
||||||
|
|
||||||
if cat == "tracker_host" and value not in ("All", "Error") and value:
|
if cat == "tracker_host" and value not in ("All", "Error") and value:
|
||||||
d = self.tracker_icons.get(value)
|
d = self.tracker_icons.fetch(value)
|
||||||
d.addCallback(on_get_icon)
|
d.addCallback(on_get_icon)
|
||||||
|
|
||||||
self.treestore.set_value(row, FILTER_COLUMN, True)
|
self.treestore.set_value(row, FILTER_COLUMN, True)
|
||||||
|
|
|
@ -49,71 +49,6 @@ signal_new('button-press-event', gtk.TreeViewColumn,
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
# Cell data functions to pass to add_func_column()
|
|
||||||
def cell_data_speed(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)
|
|
||||||
|
|
||||||
cell.set_property('text', speed_str)
|
|
||||||
|
|
||||||
def cell_data_size(column, cell, model, row, data):
|
|
||||||
"""Display value in terms of size, eg. 2 MB"""
|
|
||||||
size = model.get_value(row, data)
|
|
||||||
size_str = deluge.common.fsize(size)
|
|
||||||
cell.set_property('text', size_str)
|
|
||||||
|
|
||||||
def cell_data_peer(column, cell, model, row, data):
|
|
||||||
"""Display values as 'value1 (value2)'"""
|
|
||||||
(first, second) = model.get(row, *data)
|
|
||||||
# Only display a (total) if second is greater than -1
|
|
||||||
if second > -1:
|
|
||||||
cell.set_property('text', '%d (%d)' % (first, second))
|
|
||||||
else:
|
|
||||||
cell.set_property('text', '%d' % first)
|
|
||||||
|
|
||||||
def cell_data_time(column, cell, model, row, data):
|
|
||||||
"""Display value as time, eg 1m10s"""
|
|
||||||
time = model.get_value(row, data)
|
|
||||||
if time <= 0:
|
|
||||||
time_str = ""
|
|
||||||
else:
|
|
||||||
time_str = deluge.common.ftime(time)
|
|
||||||
cell.set_property('text', time_str)
|
|
||||||
|
|
||||||
def cell_data_ratio(column, cell, model, row, data):
|
|
||||||
"""Display value as a ratio with a precision of 3."""
|
|
||||||
ratio = model.get_value(row, data)
|
|
||||||
if ratio < 0:
|
|
||||||
ratio_str = "∞"
|
|
||||||
else:
|
|
||||||
ratio_str = "%.3f" % ratio
|
|
||||||
|
|
||||||
cell.set_property('text', ratio_str)
|
|
||||||
|
|
||||||
def cell_data_date(column, cell, model, row, data):
|
|
||||||
"""Display value as date, eg 05/05/08"""
|
|
||||||
cell.set_property('text', deluge.common.fdate(model.get_value(row, data)))
|
|
||||||
|
|
||||||
def cell_data_date_or_never(column, cell, model, row, data):
|
|
||||||
"""Display value as date, eg 05/05/08 or Never"""
|
|
||||||
value = model.get_value(row, data)
|
|
||||||
if value > 0.0:
|
|
||||||
cell.set_property('text', deluge.common.fdate(value))
|
|
||||||
else:
|
|
||||||
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):
|
||||||
|
@ -150,7 +85,7 @@ class ListView:
|
||||||
self.sort_func = None
|
self.sort_func = None
|
||||||
self.sort_id = None
|
self.sort_id = None
|
||||||
|
|
||||||
class TreeviewColumn(gtk.TreeViewColumn):
|
class TreeviewColumn(gtk.TreeViewColumn, object):
|
||||||
"""
|
"""
|
||||||
TreeViewColumn does not signal right-click events, and we need them
|
TreeViewColumn does not signal right-click events, and we need them
|
||||||
This subclass is equivalent to TreeViewColumn, but it signals these events
|
This subclass is equivalent to TreeViewColumn, but it signals these events
|
||||||
|
@ -165,6 +100,10 @@ class ListView:
|
||||||
self.set_widget(label)
|
self.set_widget(label)
|
||||||
label.show()
|
label.show()
|
||||||
label.__realize = label.connect('realize', self.onRealize)
|
label.__realize = label.connect('realize', self.onRealize)
|
||||||
|
self.title = title
|
||||||
|
self.data_func = None
|
||||||
|
self.data_func_data = None
|
||||||
|
self.cell_renderer = None
|
||||||
|
|
||||||
def onRealize(self, widget):
|
def onRealize(self, widget):
|
||||||
widget.disconnect(widget.__realize)
|
widget.disconnect(widget.__realize)
|
||||||
|
@ -176,6 +115,21 @@ class ListView:
|
||||||
def onButtonPressed(self, widget, event):
|
def onButtonPressed(self, widget, event):
|
||||||
self.emit('button-press-event', event)
|
self.emit('button-press-event', event)
|
||||||
|
|
||||||
|
def set_cell_data_func_attributes(self, cell_renderer, func, func_data=None):
|
||||||
|
"""Store the values to be set by set_cell_data_func"""
|
||||||
|
self.data_func = func
|
||||||
|
self.data_func_data = func_data
|
||||||
|
self.cell_renderer = cell_renderer
|
||||||
|
|
||||||
|
def set_visible(self, visible):
|
||||||
|
gtk.TreeViewColumn.set_visible(self, visible)
|
||||||
|
if self.data_func:
|
||||||
|
if not visible:
|
||||||
|
# Set data function to None to prevent unecessary calls when column is hidden
|
||||||
|
self.set_cell_data_func(self.cell_renderer, None, func_data=None)
|
||||||
|
else:
|
||||||
|
self.set_cell_data_func(self.cell_renderer, self.data_func, self.data_func_data)
|
||||||
|
|
||||||
def __init__(self, treeview_widget=None, state_file=None):
|
def __init__(self, treeview_widget=None, state_file=None):
|
||||||
log.debug("ListView initialized..")
|
log.debug("ListView initialized..")
|
||||||
|
|
||||||
|
@ -521,10 +475,10 @@ class ListView:
|
||||||
elif column_type == "func":
|
elif column_type == "func":
|
||||||
column.pack_start(render, True)
|
column.pack_start(render, True)
|
||||||
if len(self.columns[header].column_indices) > 1:
|
if len(self.columns[header].column_indices) > 1:
|
||||||
column.set_cell_data_func(render, function,
|
column.set_cell_data_func_attributes(render, function,
|
||||||
tuple(self.columns[header].column_indices))
|
tuple(self.columns[header].column_indices))
|
||||||
else:
|
else:
|
||||||
column.set_cell_data_func(render, function,
|
column.set_cell_data_func_attributes(render, function,
|
||||||
self.columns[header].column_indices[0])
|
self.columns[header].column_indices[0])
|
||||||
elif column_type == "progress":
|
elif column_type == "progress":
|
||||||
column.pack_start(render)
|
column.pack_start(render)
|
||||||
|
@ -534,12 +488,12 @@ class ListView:
|
||||||
column.add_attribute(render, "value",
|
column.add_attribute(render, "value",
|
||||||
self.columns[header].column_indices[value])
|
self.columns[header].column_indices[value])
|
||||||
else:
|
else:
|
||||||
column.set_cell_data_func(render, function,
|
column.set_cell_data_func_attributes(render, function,
|
||||||
tuple(self.columns[header].column_indices))
|
tuple(self.columns[header].column_indices))
|
||||||
elif column_type == "texticon":
|
elif column_type == "texticon":
|
||||||
column.pack_start(render[pixbuf], False)
|
column.pack_start(render[pixbuf], False)
|
||||||
if function is not None:
|
if function is not None:
|
||||||
column.set_cell_data_func(render[pixbuf], function,
|
column.set_cell_data_func_attributes(render[pixbuf], function,
|
||||||
self.columns[header].column_indices[pixbuf])
|
self.columns[header].column_indices[pixbuf])
|
||||||
column.pack_start(render[text], True)
|
column.pack_start(render[text], True)
|
||||||
column.add_attribute(render[text], "text",
|
column.add_attribute(render[text], "text",
|
||||||
|
|
|
@ -41,7 +41,7 @@ from itertools import izip
|
||||||
from deluge.ui.client import client
|
from deluge.ui.client import client
|
||||||
import deluge.component as component
|
import deluge.component as component
|
||||||
import deluge.common
|
import deluge.common
|
||||||
from deluge.ui.gtkui.listview import cell_data_speed as cell_data_speed
|
from deluge.ui.gtkui.torrentview_data_funcs import cell_data_speed_down, cell_data_speed_up
|
||||||
from deluge.ui.gtkui.torrentdetails import Tab
|
from deluge.ui.gtkui.torrentdetails import Tab
|
||||||
from deluge.ui.countries import COUNTRIES
|
from deluge.ui.countries import COUNTRIES
|
||||||
from deluge.ui.gtkui.common import save_pickled_state_file, load_pickled_state_file
|
from deluge.ui.gtkui.common import save_pickled_state_file, load_pickled_state_file
|
||||||
|
@ -139,7 +139,7 @@ class PeersTab(Tab):
|
||||||
column = gtk.TreeViewColumn(_("Down Speed"))
|
column = gtk.TreeViewColumn(_("Down Speed"))
|
||||||
render = gtk.CellRendererText()
|
render = gtk.CellRendererText()
|
||||||
column.pack_start(render, False)
|
column.pack_start(render, False)
|
||||||
column.set_cell_data_func(render, cell_data_speed, 3)
|
column.set_cell_data_func(render, cell_data_speed_down, 3)
|
||||||
column.set_sort_column_id(3)
|
column.set_sort_column_id(3)
|
||||||
column.set_clickable(True)
|
column.set_clickable(True)
|
||||||
column.set_resizable(True)
|
column.set_resizable(True)
|
||||||
|
@ -152,7 +152,7 @@ class PeersTab(Tab):
|
||||||
column = gtk.TreeViewColumn(_("Up Speed"))
|
column = gtk.TreeViewColumn(_("Up Speed"))
|
||||||
render = gtk.CellRendererText()
|
render = gtk.CellRendererText()
|
||||||
column.pack_start(render, False)
|
column.pack_start(render, False)
|
||||||
column.set_cell_data_func(render, cell_data_speed, 4)
|
column.set_cell_data_func(render, cell_data_speed_up, 4)
|
||||||
column.set_sort_column_id(4)
|
column.set_sort_column_id(4)
|
||||||
column.set_clickable(True)
|
column.set_clickable(True)
|
||||||
column.set_resizable(True)
|
column.set_resizable(True)
|
||||||
|
|
|
@ -50,101 +50,10 @@ import deluge.common
|
||||||
import deluge.component as component
|
import deluge.component as component
|
||||||
from deluge.ui.client import client
|
from deluge.ui.client import client
|
||||||
from removetorrentdialog import RemoveTorrentDialog
|
from removetorrentdialog import RemoveTorrentDialog
|
||||||
|
import torrentview_data_funcs as funcs
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
# Status icons.. Create them from file only once to avoid constantly
|
|
||||||
# re-creating them.
|
|
||||||
icon_downloading = gtk.gdk.pixbuf_new_from_file(deluge.common.get_pixmap("downloading16.png"))
|
|
||||||
icon_seeding = gtk.gdk.pixbuf_new_from_file(deluge.common.get_pixmap("seeding16.png"))
|
|
||||||
icon_inactive = gtk.gdk.pixbuf_new_from_file(deluge.common.get_pixmap("inactive16.png"))
|
|
||||||
icon_alert = gtk.gdk.pixbuf_new_from_file(deluge.common.get_pixmap("alert16.png"))
|
|
||||||
icon_queued = gtk.gdk.pixbuf_new_from_file(deluge.common.get_pixmap("queued16.png"))
|
|
||||||
icon_checking = gtk.gdk.pixbuf_new_from_file(deluge.common.get_pixmap("checking16.png"))
|
|
||||||
|
|
||||||
# Holds the info for which status icon to display based on state
|
|
||||||
ICON_STATE = {
|
|
||||||
"Allocating": icon_checking,
|
|
||||||
"Checking": icon_checking,
|
|
||||||
"Downloading": icon_downloading,
|
|
||||||
"Seeding": icon_seeding,
|
|
||||||
"Paused": icon_inactive,
|
|
||||||
"Error": icon_alert,
|
|
||||||
"Queued": icon_queued,
|
|
||||||
"Checking Resume Data": icon_checking
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
def cell_data_statusicon(column, cell, model, row, data):
|
|
||||||
"""Display text with an icon"""
|
|
||||||
try:
|
|
||||||
icon = ICON_STATE[model.get_value(row, data)]
|
|
||||||
|
|
||||||
#Supress Warning: g_object_set_qdata: assertion `G_IS_OBJECT (object)' failed
|
|
||||||
original_filters = warnings.filters[:]
|
|
||||||
warnings.simplefilter("ignore")
|
|
||||||
try:
|
|
||||||
if cell.get_property("pixbuf") != icon:
|
|
||||||
cell.set_property("pixbuf", icon)
|
|
||||||
finally:
|
|
||||||
warnings.filters = original_filters
|
|
||||||
|
|
||||||
except KeyError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
def cell_data_trackericon(column, cell, model, row, data):
|
|
||||||
def on_get_icon(icon):
|
|
||||||
def create_blank_pixbuf():
|
|
||||||
i = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB, True, 8, 16, 16)
|
|
||||||
i.fill(0x00000000)
|
|
||||||
return i
|
|
||||||
|
|
||||||
if icon:
|
|
||||||
pixbuf = icon.get_cached_icon()
|
|
||||||
if not pixbuf:
|
|
||||||
try:
|
|
||||||
pixbuf = gtk.gdk.pixbuf_new_from_file_at_size(icon.get_filename(), 16, 16)
|
|
||||||
except gobject.GError, e:
|
|
||||||
# Failed to load the pixbuf (Bad image file), so set a blank pixbuf
|
|
||||||
pixbuf = create_blank_pixbuf()
|
|
||||||
finally:
|
|
||||||
icon.set_cached_icon(pixbuf)
|
|
||||||
else:
|
|
||||||
pixbuf = create_blank_pixbuf()
|
|
||||||
|
|
||||||
#Suppress Warning: g_object_set_qdata: assertion `G_IS_OBJECT (object)' failed
|
|
||||||
with warnings.catch_warnings():
|
|
||||||
warnings.simplefilter("ignore")
|
|
||||||
if cell.get_property("pixbuf") != pixbuf:
|
|
||||||
cell.set_property("pixbuf", pixbuf)
|
|
||||||
|
|
||||||
host = model[row][data]
|
|
||||||
if host:
|
|
||||||
d = component.get("TrackerIcons").get(host)
|
|
||||||
d.addCallback(on_get_icon)
|
|
||||||
else:
|
|
||||||
on_get_icon(None)
|
|
||||||
|
|
||||||
def cell_data_progress(column, cell, model, row, data):
|
|
||||||
"""Display progress bar with text"""
|
|
||||||
(value, state_str) = model.get(row, *data)
|
|
||||||
if cell.get_property("value") != value:
|
|
||||||
cell.set_property("value", value)
|
|
||||||
|
|
||||||
# Marked for translate states text are in filtertreeview
|
|
||||||
textstr = _(state_str)
|
|
||||||
if state_str != "Seeding" and value < 100:
|
|
||||||
textstr = "%s %.2f%%" % (textstr, value)
|
|
||||||
if cell.get_property("text") != textstr:
|
|
||||||
cell.set_property("text", textstr)
|
|
||||||
|
|
||||||
def cell_data_queue(column, cell, model, row, data):
|
|
||||||
value = model.get_value(row, data)
|
|
||||||
if value < 0:
|
|
||||||
cell.set_property("text", "")
|
|
||||||
else:
|
|
||||||
cell.set_property("text", str(value + 1))
|
|
||||||
|
|
||||||
def queue_peer_seed_sort_function(v1, v2):
|
def queue_peer_seed_sort_function(v1, v2):
|
||||||
if v1 == v2:
|
if v1 == v2:
|
||||||
return 0
|
return 0
|
||||||
|
@ -339,58 +248,58 @@ class TorrentView(listview.ListView, component.Component):
|
||||||
# Add the columns to the listview
|
# Add the columns to the listview
|
||||||
self.add_text_column("torrent_id", hidden=True, unique=True)
|
self.add_text_column("torrent_id", hidden=True, unique=True)
|
||||||
self.add_bool_column("dirty", hidden=True)
|
self.add_bool_column("dirty", hidden=True)
|
||||||
self.add_func_column("#", cell_data_queue, [int],
|
self.add_func_column("#", funcs.cell_data_queue, [int],
|
||||||
status_field=["queue"],
|
status_field=["queue"],
|
||||||
sort_func=queue_column_sort)
|
sort_func=queue_column_sort)
|
||||||
self.add_texticon_column(_("Name"),
|
self.add_texticon_column(_("Name"),
|
||||||
status_field=["state", "name"],
|
status_field=["state", "name"],
|
||||||
function=cell_data_statusicon,
|
function=funcs.cell_data_statusicon,
|
||||||
default_sort=True)
|
default_sort=True)
|
||||||
self.add_func_column(_("Size"), listview.cell_data_size,
|
self.add_func_column(_("Size"), funcs.cell_data_size,
|
||||||
[gobject.TYPE_UINT64],
|
[gobject.TYPE_UINT64],
|
||||||
status_field=["total_wanted"])
|
status_field=["total_wanted"])
|
||||||
self.add_func_column(_("Downloaded"), listview.cell_data_size,
|
self.add_func_column(_("Downloaded"), funcs.cell_data_size,
|
||||||
[gobject.TYPE_UINT64],
|
[gobject.TYPE_UINT64],
|
||||||
status_field=["all_time_download"], default=False)
|
status_field=["all_time_download"], default=False)
|
||||||
self.add_func_column(_("Uploaded"), listview.cell_data_size,
|
self.add_func_column(_("Uploaded"), funcs.cell_data_size,
|
||||||
[gobject.TYPE_UINT64],
|
[gobject.TYPE_UINT64],
|
||||||
status_field=["total_uploaded"], default=False)
|
status_field=["total_uploaded"], default=False)
|
||||||
self.add_func_column(_("Remaining"), listview.cell_data_size, [gobject.TYPE_UINT64],
|
self.add_func_column(_("Remaining"), funcs.cell_data_size, [gobject.TYPE_UINT64],
|
||||||
status_field=["total_remaining"], default=False)
|
status_field=["total_remaining"], 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=funcs.cell_data_progress)
|
||||||
self.add_func_column(_("Seeders"), listview.cell_data_peer, [int, int],
|
self.add_func_column(_("Seeders"), funcs.cell_data_peer, [int, int],
|
||||||
status_field=["num_seeds", "total_seeds"],
|
status_field=["num_seeds", "total_seeds"],
|
||||||
sort_func=seed_peer_column_sort, default=False)
|
sort_func=seed_peer_column_sort, default=False)
|
||||||
self.add_func_column(_("Peers"), listview.cell_data_peer, [int, int],
|
self.add_func_column(_("Peers"), funcs.cell_data_peer, [int, int],
|
||||||
status_field=["num_peers", "total_peers"],
|
status_field=["num_peers", "total_peers"],
|
||||||
sort_func=seed_peer_column_sort, default=False)
|
sort_func=seed_peer_column_sort, default=False)
|
||||||
self.add_func_column(_("Seeders") + "/" + _("Peers"), listview.cell_data_ratio, [float],
|
self.add_func_column(_("Seeders") + "/" + _("Peers"), funcs.cell_data_ratio_seeders, [float],
|
||||||
status_field=["seeds_peers_ratio"], default=False)
|
status_field=["seeds_peers_ratio"], default=False)
|
||||||
self.add_func_column(_("Down Speed"), listview.cell_data_speed, [float],
|
self.add_func_column(_("Down Speed"), funcs.cell_data_speed_down, [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"), funcs.cell_data_speed_up, [float],
|
||||||
status_field=["upload_payload_rate"])
|
status_field=["upload_payload_rate"])
|
||||||
self.add_func_column(_("Down Limit"), listview.cell_data_speed_limit, [float],
|
self.add_func_column(_("Down Limit"), funcs.cell_data_speed_limit_down, [float],
|
||||||
status_field=["max_download_speed"], default=False)
|
status_field=["max_download_speed"], default=False)
|
||||||
self.add_func_column(_("Up Limit"), listview.cell_data_speed_limit, [float],
|
self.add_func_column(_("Up Limit"), funcs.cell_data_speed_limit_up, [float],
|
||||||
status_field=["max_upload_speed"], default=False)
|
status_field=["max_upload_speed"], default=False)
|
||||||
self.add_func_column(_("ETA"), listview.cell_data_time, [int],
|
self.add_func_column(_("ETA"), funcs.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"), funcs.cell_data_ratio_ratio, [float],
|
||||||
status_field=["ratio"], default=False)
|
status_field=["ratio"], default=False)
|
||||||
self.add_func_column(_("Avail"), listview.cell_data_ratio, [float],
|
self.add_func_column(_("Avail"), funcs.cell_data_ratio_avail, [float],
|
||||||
status_field=["distributed_copies"], default=False)
|
status_field=["distributed_copies"], default=False)
|
||||||
self.add_func_column(_("Added"), listview.cell_data_date, [float],
|
self.add_func_column(_("Added"), funcs.cell_data_date, [float],
|
||||||
status_field=["time_added"], default=False)
|
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],
|
funcs.cell_data_date_or_never, [float],
|
||||||
status_field=["last_seen_complete"], default=False)
|
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, default=False)
|
function=funcs.cell_data_trackericon, default=False)
|
||||||
self.add_text_column(_("Save Path"), status_field=["save_path"], default=False)
|
self.add_text_column(_("Save Path"), status_field=["save_path"], default=False)
|
||||||
self.add_text_column(_("Owner"), status_field=["owner"], default=False)
|
self.add_text_column(_("Owner"), status_field=["owner"], default=False)
|
||||||
self.add_bool_column(_("Public"), status_field=["public"], default=False)
|
self.add_bool_column(_("Public"), status_field=["public"], default=False)
|
||||||
|
|
|
@ -0,0 +1,302 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# torrentview_data_funcs.py
|
||||||
|
#
|
||||||
|
# Copyright (C) 2007, 2008 Andrew Resch <andrewresch@gmail.com>
|
||||||
|
#
|
||||||
|
# Deluge is free software.
|
||||||
|
#
|
||||||
|
# You may redistribute it and/or modify it under the terms of the
|
||||||
|
# GNU General Public License, as published by the Free Software
|
||||||
|
# Foundation; either version 3 of the License, or (at your option)
|
||||||
|
# any later version.
|
||||||
|
#
|
||||||
|
# deluge is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
# See the GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with deluge. If not, write to:
|
||||||
|
# The Free Software Foundation, Inc.,
|
||||||
|
# 51 Franklin Street, Fifth Floor
|
||||||
|
# Boston, MA 02110-1301, USA.
|
||||||
|
#
|
||||||
|
# In addition, as a special exception, the copyright holders give
|
||||||
|
# permission to link the code of portions of this program with the OpenSSL
|
||||||
|
# library.
|
||||||
|
# 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) with this
|
||||||
|
# exception, you may extend this exception to your 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 your version. If you delete this exception
|
||||||
|
# statement from all source files in the program, then also delete it here.
|
||||||
|
#
|
||||||
|
#
|
||||||
|
|
||||||
|
import deluge.common as common
|
||||||
|
import gtk
|
||||||
|
import warnings
|
||||||
|
import gobject
|
||||||
|
import deluge.component as component
|
||||||
|
|
||||||
|
# Status icons.. Create them from file only once to avoid constantly
|
||||||
|
# re-creating them.
|
||||||
|
icon_downloading = gtk.gdk.pixbuf_new_from_file(common.get_pixmap("downloading16.png"))
|
||||||
|
icon_seeding = gtk.gdk.pixbuf_new_from_file(common.get_pixmap("seeding16.png"))
|
||||||
|
icon_inactive = gtk.gdk.pixbuf_new_from_file(common.get_pixmap("inactive16.png"))
|
||||||
|
icon_alert = gtk.gdk.pixbuf_new_from_file(common.get_pixmap("alert16.png"))
|
||||||
|
icon_queued = gtk.gdk.pixbuf_new_from_file(common.get_pixmap("queued16.png"))
|
||||||
|
icon_checking = gtk.gdk.pixbuf_new_from_file(common.get_pixmap("checking16.png"))
|
||||||
|
|
||||||
|
# Holds the info for which status icon to display based on state
|
||||||
|
ICON_STATE = {
|
||||||
|
"Allocating": icon_checking,
|
||||||
|
"Checking": icon_checking,
|
||||||
|
"Downloading": icon_downloading,
|
||||||
|
"Seeding": icon_seeding,
|
||||||
|
"Paused": icon_inactive,
|
||||||
|
"Error": icon_alert,
|
||||||
|
"Queued": icon_queued,
|
||||||
|
"Checking Resume Data": icon_checking
|
||||||
|
}
|
||||||
|
|
||||||
|
def _(message): return message
|
||||||
|
|
||||||
|
TRANSLATE = {
|
||||||
|
"Downloading": _("Downloading"),
|
||||||
|
"Seeding": _("Seeding"),
|
||||||
|
"Paused": _("Paused"),
|
||||||
|
"Checking": _("Checking"),
|
||||||
|
"Queued": _("Queued"),
|
||||||
|
"Error": _("Error"),
|
||||||
|
}
|
||||||
|
|
||||||
|
del _
|
||||||
|
|
||||||
|
def _t(text):
|
||||||
|
if text in TRANSLATE:
|
||||||
|
text = TRANSLATE[text]
|
||||||
|
return _(text)
|
||||||
|
|
||||||
|
# Cache the key used to calculate the current value set for the specific cell
|
||||||
|
# renderer. This is much cheaper than fetch the current value and test if
|
||||||
|
# it's equal.
|
||||||
|
func_last_value = {"cell_data_speed_down": None,
|
||||||
|
"cell_data_speed_up": None,
|
||||||
|
"cell_data_time": None,
|
||||||
|
"cell_data_ratio_seeders": None,
|
||||||
|
"cell_data_ratio_ratio": None,
|
||||||
|
"cell_data_ratio_avail": None,
|
||||||
|
"cell_data_date": None,
|
||||||
|
"cell_data_date_or_never": None,
|
||||||
|
"cell_data_speed_limit_down": None,
|
||||||
|
"cell_data_speed_limit_up": None,
|
||||||
|
"cell_data_trackericon": None,
|
||||||
|
"cell_data_statusicon": None,
|
||||||
|
"cell_data_queue": None,
|
||||||
|
"cell_data_progress": [None, None],
|
||||||
|
}
|
||||||
|
|
||||||
|
def cell_data_statusicon(column, cell, model, row, data):
|
||||||
|
"""Display text with an icon"""
|
||||||
|
try:
|
||||||
|
state = model.get_value(row, data)
|
||||||
|
|
||||||
|
if func_last_value["cell_data_statusicon"] == state:
|
||||||
|
return
|
||||||
|
func_last_value["cell_data_statusicon"] = state
|
||||||
|
|
||||||
|
icon = ICON_STATE[state]
|
||||||
|
|
||||||
|
#Supress Warning: g_object_set_qdata: assertion `G_IS_OBJECT (object)' failed
|
||||||
|
original_filters = warnings.filters[:]
|
||||||
|
warnings.simplefilter("ignore")
|
||||||
|
try:
|
||||||
|
cell.set_property("pixbuf", icon)
|
||||||
|
finally:
|
||||||
|
warnings.filters = original_filters
|
||||||
|
|
||||||
|
except KeyError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def create_blank_pixbuf():
|
||||||
|
i = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB, True, 8, 16, 16)
|
||||||
|
i.fill(0x00000000)
|
||||||
|
return i
|
||||||
|
|
||||||
|
def set_icon(icon, cell):
|
||||||
|
if icon:
|
||||||
|
pixbuf = icon.get_cached_icon()
|
||||||
|
if pixbuf is None:
|
||||||
|
try:
|
||||||
|
pixbuf = gtk.gdk.pixbuf_new_from_file_at_size(icon.get_filename(), 16, 16)
|
||||||
|
except gobject.GError, e:
|
||||||
|
# Failed to load the pixbuf (Bad image file), so set a blank pixbuf
|
||||||
|
pixbuf = create_blank_pixbuf()
|
||||||
|
finally:
|
||||||
|
icon.set_cached_icon(pixbuf)
|
||||||
|
else:
|
||||||
|
pixbuf = create_blank_pixbuf()
|
||||||
|
|
||||||
|
#Suppress Warning: g_object_set_qdata: assertion `G_IS_OBJECT (object)' failed
|
||||||
|
with warnings.catch_warnings():
|
||||||
|
warnings.simplefilter("ignore")
|
||||||
|
cell.set_property("pixbuf", pixbuf)
|
||||||
|
|
||||||
|
def cell_data_trackericon(column, cell, model, row, data):
|
||||||
|
host = model[row][data]
|
||||||
|
|
||||||
|
if func_last_value["cell_data_trackericon"] == host:
|
||||||
|
return
|
||||||
|
if host:
|
||||||
|
if not component.get("TrackerIcons").has(host):
|
||||||
|
# Set blank icon while waiting for the icon to be loaded
|
||||||
|
set_icon(None, cell)
|
||||||
|
component.get("TrackerIcons").fetch(host)
|
||||||
|
func_last_value["cell_data_trackericon"] = None
|
||||||
|
else:
|
||||||
|
set_icon(component.get("TrackerIcons").get(host), cell)
|
||||||
|
# Only set the last value when we have found the icon
|
||||||
|
func_last_value["cell_data_trackericon"] = host
|
||||||
|
else:
|
||||||
|
set_icon(None, cell)
|
||||||
|
func_last_value["cell_data_trackericon"] = None
|
||||||
|
|
||||||
|
def cell_data_progress(column, cell, model, row, data):
|
||||||
|
"""Display progress bar with text"""
|
||||||
|
(value, state_str) = model.get(row, *data)
|
||||||
|
if func_last_value["cell_data_progress"][0] != value:
|
||||||
|
func_last_value["cell_data_progress"][0] = value
|
||||||
|
cell.set_property("value", value)
|
||||||
|
|
||||||
|
textstr = _t(state_str)
|
||||||
|
if state_str != "Seeding" and value < 100:
|
||||||
|
textstr = textstr + " %.2f%%" % value
|
||||||
|
|
||||||
|
if func_last_value["cell_data_progress"][1] != textstr:
|
||||||
|
func_last_value["cell_data_progress"][1] = textstr
|
||||||
|
cell.set_property("text", textstr)
|
||||||
|
|
||||||
|
def cell_data_queue(column, cell, model, row, data):
|
||||||
|
value = model.get_value(row, data)
|
||||||
|
|
||||||
|
if func_last_value["cell_data_queue"] == value:
|
||||||
|
return
|
||||||
|
func_last_value["cell_data_queue"] = value
|
||||||
|
|
||||||
|
if value < 0:
|
||||||
|
cell.set_property("text", "")
|
||||||
|
else:
|
||||||
|
cell.set_property("text", str(value + 1))
|
||||||
|
|
||||||
|
def cell_data_speed(cell, model, row, data, cache_key):
|
||||||
|
"""Display value as a speed, eg. 2 KiB/s"""
|
||||||
|
try:
|
||||||
|
speed = model.get_value(row, data)
|
||||||
|
except AttributeError, e:
|
||||||
|
print "AttributeError"
|
||||||
|
import traceback
|
||||||
|
traceback.print_exc()
|
||||||
|
if func_last_value[cache_key] == speed:
|
||||||
|
return
|
||||||
|
func_last_value[cache_key] = speed
|
||||||
|
|
||||||
|
speed_str = ""
|
||||||
|
if speed > 0:
|
||||||
|
speed_str = common.fspeed(speed)
|
||||||
|
cell.set_property('text', speed_str)
|
||||||
|
|
||||||
|
def cell_data_speed_down(column, cell, model, row, data):
|
||||||
|
"""Display value as a speed, eg. 2 KiB/s"""
|
||||||
|
cell_data_speed(cell, model, row, data, "cell_data_speed_down")
|
||||||
|
|
||||||
|
def cell_data_speed_up(column, cell, model, row, data):
|
||||||
|
"""Display value as a speed, eg. 2 KiB/s"""
|
||||||
|
cell_data_speed(cell, model, row, data, "cell_data_speed_up")
|
||||||
|
|
||||||
|
def cell_data_speed_limit(cell, model, row, data, cache_key):
|
||||||
|
"""Display value as a speed, eg. 2 KiB/s"""
|
||||||
|
speed = model.get_value(row, data)
|
||||||
|
|
||||||
|
if func_last_value[cache_key] == speed:
|
||||||
|
return
|
||||||
|
func_last_value[cache_key] = speed
|
||||||
|
|
||||||
|
speed_str = ""
|
||||||
|
if speed > 0:
|
||||||
|
speed_str = common.fspeed(speed * 1024)
|
||||||
|
cell.set_property('text', speed_str)
|
||||||
|
|
||||||
|
def cell_data_speed_limit_down(column, cell, model, row, data):
|
||||||
|
cell_data_speed_limit(cell, model, row, data, "cell_data_speed_limit_down")
|
||||||
|
|
||||||
|
def cell_data_speed_limit_up(column, cell, model, row, data):
|
||||||
|
cell_data_speed_limit(cell, model, row, data, "cell_data_speed_limit_up")
|
||||||
|
|
||||||
|
def cell_data_size(column, cell, model, row, data):
|
||||||
|
"""Display value in terms of size, eg. 2 MB"""
|
||||||
|
size = model.get_value(row, data)
|
||||||
|
cell.set_property('text', common.fsize(size))
|
||||||
|
|
||||||
|
def cell_data_peer(column, cell, model, row, data):
|
||||||
|
"""Display values as 'value1 (value2)'"""
|
||||||
|
(first, second) = model.get(row, *data)
|
||||||
|
# Only display a (total) if second is greater than -1
|
||||||
|
if second > -1:
|
||||||
|
cell.set_property('text', '%d (%d)' % (first, second))
|
||||||
|
else:
|
||||||
|
cell.set_property('text', '%d' % first)
|
||||||
|
|
||||||
|
def cell_data_time(column, cell, model, row, data):
|
||||||
|
"""Display value as time, eg 1m10s"""
|
||||||
|
time = model.get_value(row, data)
|
||||||
|
if func_last_value["cell_data_time"] == time:
|
||||||
|
return
|
||||||
|
func_last_value["cell_data_time"] = time
|
||||||
|
|
||||||
|
if time <= 0:
|
||||||
|
time_str = ""
|
||||||
|
else:
|
||||||
|
time_str = common.ftime(time)
|
||||||
|
cell.set_property('text', time_str)
|
||||||
|
|
||||||
|
def cell_data_ratio(cell, model, row, data, cache_key):
|
||||||
|
"""Display value as a ratio with a precision of 3."""
|
||||||
|
ratio = model.get_value(row, data)
|
||||||
|
# Previous value in cell is the same as for this value, so ignore
|
||||||
|
if func_last_value[cache_key] == ratio:
|
||||||
|
return
|
||||||
|
func_last_value[cache_key] = ratio
|
||||||
|
cell.set_property('text', "∞" if ratio < 0 else "%.3f" % ratio)
|
||||||
|
|
||||||
|
def cell_data_ratio_seeders(column, cell, model, row, data):
|
||||||
|
cell_data_ratio(cell, model, row, data, "cell_data_ratio_seeders")
|
||||||
|
|
||||||
|
def cell_data_ratio_ratio(column, cell, model, row, data):
|
||||||
|
cell_data_ratio(cell, model, row, data, "cell_data_ratio_ratio")
|
||||||
|
|
||||||
|
def cell_data_ratio_avail(column, cell, model, row, data):
|
||||||
|
cell_data_ratio(cell, model, row, data, "cell_data_ratio_avail")
|
||||||
|
|
||||||
|
def cell_data_date(column, cell, model, row, data):
|
||||||
|
"""Display value as date, eg 05/05/08"""
|
||||||
|
date = model.get_value(row, data)
|
||||||
|
|
||||||
|
if func_last_value["cell_data_date"] == date:
|
||||||
|
return
|
||||||
|
func_last_value["cell_data_date"] = date
|
||||||
|
|
||||||
|
date_str = common.fdate(date)
|
||||||
|
cell.set_property('text', date_str)
|
||||||
|
|
||||||
|
def cell_data_date_or_never(column, cell, model, row, data):
|
||||||
|
"""Display value as date, eg 05/05/08 or Never"""
|
||||||
|
value = model.get_value(row, data)
|
||||||
|
|
||||||
|
if func_last_value["cell_data_date_or_never"] == value:
|
||||||
|
return
|
||||||
|
func_last_value["cell_data_date_or_never"] = value
|
||||||
|
|
||||||
|
date_str = common.fdate(value) if value > 0.0 else _("Never")
|
||||||
|
cell.set_property('text', date_str)
|
||||||
|
|
|
@ -178,9 +178,38 @@ class TrackerIcons(Component):
|
||||||
self.pending = {}
|
self.pending = {}
|
||||||
self.redirects = {}
|
self.redirects = {}
|
||||||
|
|
||||||
|
def has(self, host):
|
||||||
|
"""
|
||||||
|
Returns True or False if the tracker icon for the given host exists or not.
|
||||||
|
|
||||||
|
:param host: the host for the TrackerIcon
|
||||||
|
:type host: string
|
||||||
|
:returns: True or False
|
||||||
|
:rtype: bool
|
||||||
|
"""
|
||||||
|
return host.lower() in self.icons
|
||||||
|
|
||||||
def get(self, host):
|
def get(self, host):
|
||||||
"""
|
"""
|
||||||
Returns a TrackerIcon for the given tracker's host
|
Returns a TrackerIcon for the given tracker's host
|
||||||
|
from the icon cache.
|
||||||
|
|
||||||
|
:param host: the host for the TrackerIcon
|
||||||
|
:type host: string
|
||||||
|
:returns: the TrackerIcon for the host
|
||||||
|
:rtype: TrackerIcon
|
||||||
|
"""
|
||||||
|
host = host.lower()
|
||||||
|
if host in self.icons:
|
||||||
|
return self.icons[host]
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
def fetch(self, host):
|
||||||
|
"""
|
||||||
|
Fetches (downloads) the icon for the given host.
|
||||||
|
When the icon is downloaded a callback is fired
|
||||||
|
on the the queue of callers to this function.
|
||||||
|
|
||||||
:param host: the host to obtain the TrackerIcon for
|
:param host: the host to obtain the TrackerIcon for
|
||||||
:type host: string
|
:type host: string
|
||||||
|
|
Loading…
Reference in New Issue