Have torrent.get_ratio return -1 when downloaded bytes is 0.

Have torrentview and statistics_tab display an infinity character when 
ratio is -1
This commit is contained in:
Andrew Resch 2008-10-26 21:10:03 +00:00
parent 97fb9f8aee
commit feaee5f344
3 changed files with 106 additions and 112 deletions

View file

@ -314,19 +314,11 @@ class Torrent:
else:
status = self.status
up = status.all_time_upload
down = status.all_time_download
# Return -1.0 if the downloaded bytes is 0, this is to represent infinity
if status.all_time_download == 0:
return -1.0
# Convert 'up' and 'down' to floats for proper calculation
up = float(up)
down = float(down)
try:
ratio = up / down
except ZeroDivisionError:
return 0.0
return ratio
return float(status.all_time_upload) / float(status.all_time_download)
def get_files(self):
"""Returns a list of files this torrent contains"""

View file

@ -2,19 +2,19 @@
# listview.py
#
# Copyright (C) 2007, 2008 Andrew Resch ('andar') <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.,
@ -50,7 +50,7 @@ def cell_data_speed(column, cell, model, 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):
@ -67,7 +67,7 @@ def cell_data_peer(column, cell, model, row, data):
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)
@ -76,15 +76,15 @@ def cell_data_time(column, cell, model, row, data):
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 == -1:
ratio_str = _("Unknown")
if ratio < 0:
ratio_str = ""
else:
ratio_str = "%.3f" % ratio
cell.set_property('text', ratio_str)
class ListViewColumnState:
@ -96,7 +96,7 @@ class ListViewColumnState:
self.visible = visible
self.sort = sort
self.sort_order = sort_order
class ListView:
"""ListView is used to make custom GtkTreeViews. It supports the adding
and removing of columns, creating a menu for a column toggle list and
@ -108,8 +108,8 @@ class ListView:
def __init__(self, name, column_indices):
# Name is how a column is identified and is also the header
self.name = name
# Column_indices holds the indexes to the liststore_columns that
# this column utilizes. It is stored as a list.
# Column_indices holds the indexes to the liststore_columns that
# this column utilizes. It is stored as a list.
self.column_indices = column_indices
# Column is a reference to the GtkTreeViewColumn object
self.column = None
@ -119,18 +119,18 @@ class ListView:
# If column is 'hidden' then it will not be visible and will not
# show up in any menu listing; it cannot be shown ever.
self.hidden = False
def __init__(self, treeview_widget=None):
log.debug("ListView initialized..")
if treeview_widget is not None:
# User supplied a treeview widget
self.treeview = treeview_widget
else:
self.treeview = gtk.TreeView()
self.liststore = None
self.treeview.set_model(self.liststore)
self.treeview.set_rules_hint(True)
self.treeview.set_reorderable(True)
@ -149,13 +149,13 @@ class ListView:
# A list of menus that self.menu will be a submenu of everytime it is
# created.
self.checklist_menus = []
def save_state(self, filename):
"""Saves the listview state (column positions and visibility) to
filename."""
# A list of ListViewColumnStates
state = []
# Get the list of TreeViewColumns from the TreeView
treeview_columns = self.treeview.get_columns()
counter = 0
@ -166,12 +166,12 @@ class ListView:
if self.get_column_name(id) == column.get_title():
sort = id
# Append a new column state to the state list
state.append(ListViewColumnState(column.get_title(), counter,
column.get_width(), column.get_visible(),
state.append(ListViewColumnState(column.get_title(), counter,
column.get_width(), column.get_visible(),
sort, int(column.get_sort_order())))
# Increase the counter because this is how we determine position
counter += 1
# Get the config location for saving the state file
config_location = ConfigManager("gtkui.conf")["config_location"]
@ -182,13 +182,13 @@ class ListView:
state_file.close()
except IOError, e:
log.warning("Unable to save state file: %s", e)
def load_state(self, filename):
"""Load the listview state from filename."""
# Get the config location for loading the state file
config_location = ConfigManager("gtkui.conf")["config_location"]
state = None
try:
log.debug("Loading ListView state file: %s", filename)
state_file = open(os.path.join(config_location, filename), "rb")
@ -196,16 +196,16 @@ class ListView:
state_file.close()
except (EOFError, IOError), e:
log.warning("Unable to load state file: %s", e)
# Keep the state in self.state so we can access it as we add new columns
self.state = state
def set_treeview(self, treeview_widget):
"""Set the treeview widget that this listview uses."""
self.treeview = treeview_widget
self.treeview.set_model(self.liststore)
return
def get_column_index(self, name):
"""Get the liststore column indices belonging to this column.
Will return a list if greater than 1 column.
@ -221,33 +221,33 @@ class ListView:
for key, value in self.columns.items():
if index in value.column_indices:
return key
def get_state_field_column(self, field):
"""Returns the column number for the state field"""
for column in self.columns.keys():
if self.columns[column].status_field == None:
continue
for f in self.columns[column].status_field:
if field == f:
return self.columns[column].column_indices[
self.columns[column].status_field.index(f)]
def on_menuitem_toggled(self, widget):
"""Callback for the generated column menuitems."""
# Get the column name from the widget
name = widget.get_child().get_text()
# Set the column's visibility based on the widgets active state
self.columns[name].column.set_visible(widget.get_active())
return
def register_checklist_menu(self, menu):
"""Register a checklist menu with the listview. It will automatically
attach any new checklist menu it makes to this menu.
"""
self.checklist_menus.append(menu)
def create_checklist_menu(self):
"""Creates a menu used for toggling the display of columns."""
menu = gtk.Menu()
@ -267,20 +267,20 @@ class ListView:
menuitem.connect("toggled", self.on_menuitem_toggled)
# Add the new checkmenuitem to the menu
menu.append(menuitem)
# Attach this new menu to all the checklist_menus
for _menu in self.checklist_menus:
_menu.set_submenu(menu)
_menu.show_all()
return menu
def create_new_liststore(self):
"""Creates a new GtkListStore based on the liststore_columns list"""
# Create a new liststore with added column and move the data from the
# Create a new liststore with added column and move the data from the
# old one to the new one.
new_list = gtk.ListStore(*tuple(self.liststore_columns))
# This function is used in the liststore.foreach method with user_data
# being the new liststore and the columns list
def copy_row(model, path, row, user_data):
@ -291,11 +291,11 @@ class ListView:
value = model.get_value(row, column)
# Set the value of this row and column in the new liststore
new_list.set_value(new_row, column, value)
# Do the actual row copy
if self.liststore is not None:
self.liststore.foreach(copy_row, (new_list, self.columns))
sort_column = None
if self.treeview.get_model():
# Save the liststore filter column
@ -303,11 +303,11 @@ class ListView:
self.liststore = new_list
self.treeview.set_model(self.liststore)
if sort_column and sort_column != (None, None):
self.treeview.get_model().set_sort_column_id(*sort_column)
return
def remove_column(self, header):
"""Removes the column with the name 'header' from the listview"""
# Start by removing this column from the treeview
@ -324,20 +324,20 @@ class ListView:
# We need to shift this column_indices
for index in column.column_indices:
index = index - len(column_indices)
# Remove from the liststore columns list
for index in column_indices:
del self.liststore_columns[index]
# Create a new liststore
self.create_new_liststore()
# Re-create the menu
self.create_checklist_menu()
return
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,
column_type=None):
"""Adds a column to the ListView"""
@ -350,21 +350,21 @@ class ListView:
else:
self.liststore_columns.append(col_types)
column_indices.append(len(self.liststore_columns) - 1)
# Add to the index list so we know the order of the visible columns.
if position is not None:
self.column_index.insert(position, header)
else:
self.column_index.append(header)
# Create a new column object and add it to the list
self.columns[header] = self.ListViewColumn(header, column_indices)
self.columns[header].status_field = status_field
# Create a new list with the added column
self.create_new_liststore()
column = gtk.TreeViewColumn(header)
if column_type == "text":
column.pack_start(render)
@ -377,11 +377,11 @@ class ListView:
elif column_type == "func":
column.pack_start(render, True)
if len(self.columns[header].column_indices) > 1:
column.set_cell_data_func(render, function,
column.set_cell_data_func(render, function,
tuple(self.columns[header].column_indices))
else:
column.set_cell_data_func(render, function,
self.columns[header].column_indices[0])
self.columns[header].column_indices[0])
elif column_type == "progress":
column.pack_start(render)
if function is None:
@ -390,7 +390,7 @@ class ListView:
column.add_attribute(render, "value",
self.columns[header].column_indices[value])
else:
column.set_cell_data_func(render, function,
column.set_cell_data_func(render, function,
tuple(self.columns[header].column_indices))
elif column_type == "texticon":
column.pack_start(render[pixbuf], False)
@ -419,7 +419,7 @@ class ListView:
if column_state.width > 0:
column.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED)
column.set_fixed_width(column_state.width)
if column_state.sort is not None and column_state.sort > -1:
self.treeview.get_model().set_sort_column_id(column_state.sort, column_state.sort_order)
column.set_visible(column_state.visible)
@ -437,8 +437,8 @@ class ListView:
self.create_checklist_menu()
return True
def add_text_column(self, header, col_type=str, hidden=False,
def add_text_column(self, header, col_type=str, hidden=False,
position=None,
status_field=None,
sortid=0,
@ -448,63 +448,63 @@ class ListView:
render = gtk.CellRendererText()
self.add_column(header, render, col_type, hidden, position,
status_field, sortid, column_type=column_type)
return True
def add_bool_column(self, header, col_type=bool, hidden=False,
position=None,
status_field=None,
sortid=0,
column_type="bool"):
"""Add a bool column to the listview"""
render = gtk.CellRendererToggle()
self.add_column(header, render, col_type, hidden, position,
status_field, sortid, column_type=column_type)
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,
column_type="func"):
"""Add a function column to the listview. Need a header name, the
function and the column types."""
render = gtk.CellRendererText()
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)
return True
def add_progress_column(self, header, col_types=[float, str],
sortid=0,
hidden=False,
position=None,
def add_progress_column(self, header, col_types=[float, str],
sortid=0,
hidden=False,
position=None,
status_field=None,
function=None,
column_type="progress"):
"""Add a progress column to the listview."""
render = gtk.CellRendererProgress()
self.add_column(header, render, col_types, hidden, position,
status_field, sortid, function=function,
column_type=column_type,
column_type=column_type,
value=0, text=1)
return True
def add_texticon_column(self, header, col_types=[str, str],
sortid=1,
hidden=False,
position=None,
hidden=False,
position=None,
status_field=None,
column_type="texticon",
function=None):
"""Adds a texticon column to the listview."""
render1 = gtk.CellRendererPixbuf()
render2 = gtk.CellRendererText()
render2 = gtk.CellRendererText()
self.add_column(header, (render1, render2), col_types, hidden,
position, status_field, sortid,
position, status_field, sortid,
column_type=column_type, function=function,
pixbuf=0, text=1)

View file

@ -2,19 +2,19 @@
# statistics_tab.py
#
# Copyright (C) 2008 Andrew Resch ('andar') <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.,
@ -46,28 +46,30 @@ def fpeer_size_second(first, second):
return "%s (%s)" % (first, deluge.common.fsize(second))
def fratio(value):
if value < 0:
return ""
return "%.3f" % value
def fpcnt(value):
return "%.2f%%" % value
def fspeed(value, max_value=-1):
if max_value > -1:
return "%s [%s KiB/s]" % (deluge.common.fspeed(value), max_value)
else:
return deluge.common.fspeed(value)
class StatisticsTab(Tab):
def __init__(self):
Tab.__init__(self)
# Get the labels we need to update.
# widgetname, modifier function, status keys
glade = component.get("MainWindow").main_glade
self._name = "Statistics"
self._child_widget = glade.get_widget("statistics_tab")
self._tab_label = glade.get_widget("statistics_tab_label")
self.label_widgets = [
(glade.get_widget("summary_pieces"), fpeer_size_second, ("num_pieces", "piece_length")),
(glade.get_widget("summary_availability"), fratio, ("distributed_copies",)),
@ -87,37 +89,37 @@ class StatisticsTab(Tab):
(glade.get_widget("summary_auto_managed"), str, ("is_auto_managed",)),
(glade.get_widget("progressbar"), fpcnt, ("progress",))
]
def update(self):
# Get the first selected torrent
selected = component.get("TorrentView").get_selected_torrents()
# Only use the first torrent in the list or return if None selected
if len(selected) != 0:
selected = selected[0]
else:
# No torrent is selected in the torrentview
return
# Get the torrent status
status_keys = ["progress", "num_pieces", "piece_length",
"distributed_copies", "total_done", "total_payload_download",
"total_uploaded", "total_payload_upload", "download_payload_rate",
status_keys = ["progress", "num_pieces", "piece_length",
"distributed_copies", "total_done", "total_payload_download",
"total_uploaded", "total_payload_upload", "download_payload_rate",
"upload_payload_rate", "num_peers", "num_seeds", "total_peers",
"total_seeds", "eta", "ratio", "next_announce",
"tracker_status", "max_connections", "max_upload_slots",
"max_upload_speed", "max_download_speed", "active_time",
"tracker_status", "max_connections", "max_upload_slots",
"max_upload_speed", "max_download_speed", "active_time",
"seeding_time", "seed_rank", "is_auto_managed"]
client.get_torrent_status(
self._on_get_torrent_status, selected, status_keys)
def _on_get_torrent_status(self, status):
# Check to see if we got valid data from the core
if status is None:
return
# Update all the label widgets
# Update all the label widgets
for widget in self.label_widgets:
if widget[1] != None:
args = []
@ -127,22 +129,22 @@ class StatisticsTab(Tab):
except Exception, e:
log.debug("Unable to get status value: %s", e)
continue
txt = widget[1](*args)
else:
txt = status[widget[2][0]]
if widget[0].get_text() != txt:
widget[0].set_text(txt)
# Do the progress bar because it's a special case (not a label)
w = component.get("MainWindow").main_glade.get_widget("progressbar")
fraction = status["progress"] / 100
if w.get_fraction() != fraction:
w.set_fraction(fraction)
def clear(self):
for widget in self.label_widgets:
widget[0].set_text("")
component.get("MainWindow").main_glade.get_widget("progressbar").set_fraction(0.0)