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
commit 6aae2acbe5
4 changed files with 91 additions and 97 deletions

View file

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

View file

@ -2,19 +2,19 @@
# listview.py # listview.py
# #
# Copyright (C) 2007, 2008 Andrew Resch ('andar') <andrewresch@gmail.com> # Copyright (C) 2007, 2008 Andrew Resch ('andar') <andrewresch@gmail.com>
# #
# Deluge is free software. # Deluge is free software.
# #
# You may redistribute it and/or modify it under the terms of the # You may redistribute it and/or modify it under the terms of the
# GNU General Public License, as published by the Free Software # GNU General Public License, as published by the Free Software
# Foundation; either version 3 of the License, or (at your option) # Foundation; either version 3 of the License, or (at your option)
# any later version. # any later version.
# #
# deluge is distributed in the hope that it will be useful, # deluge is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of # but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the GNU General Public License for more details. # See the GNU General Public License for more details.
# #
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with deluge. If not, write to: # along with deluge. If not, write to:
# The Free Software Foundation, Inc., # The Free Software Foundation, Inc.,
@ -50,7 +50,7 @@ def cell_data_speed(column, cell, model, row, data):
speed_str = "" speed_str = ""
if speed > 0: if speed > 0:
speed_str = deluge.common.fspeed(speed) speed_str = deluge.common.fspeed(speed)
cell.set_property('text', speed_str) cell.set_property('text', speed_str)
def cell_data_size(column, cell, model, row, data): 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)) cell.set_property('text', '%d (%d)' % (first, second))
else: else:
cell.set_property('text', '%d' % first) cell.set_property('text', '%d' % first)
def cell_data_time(column, cell, model, row, data): def cell_data_time(column, cell, model, row, data):
"""Display value as time, eg 1m10s""" """Display value as time, eg 1m10s"""
time = model.get_value(row, data) time = model.get_value(row, data)
@ -76,15 +76,15 @@ def cell_data_time(column, cell, model, row, data):
else: else:
time_str = deluge.common.ftime(time) time_str = deluge.common.ftime(time)
cell.set_property('text', time_str) cell.set_property('text', time_str)
def cell_data_ratio(column, cell, model, row, data): def cell_data_ratio(column, cell, model, row, data):
"""Display value as a ratio with a precision of 3.""" """Display value as a ratio with a precision of 3."""
ratio = model.get_value(row, data) ratio = model.get_value(row, data)
if ratio == -1: if ratio < 0:
ratio_str = _("Unknown") ratio_str = ""
else: else:
ratio_str = "%.3f" % ratio ratio_str = "%.3f" % ratio
cell.set_property('text', ratio_str) cell.set_property('text', ratio_str)
class ListViewColumnState: class ListViewColumnState:
@ -96,7 +96,7 @@ class ListViewColumnState:
self.visible = visible self.visible = visible
self.sort = sort self.sort = sort
self.sort_order = sort_order self.sort_order = sort_order
class ListView: class ListView:
"""ListView is used to make custom GtkTreeViews. It supports the adding """ListView is used to make custom GtkTreeViews. It supports the adding
and removing of columns, creating a menu for a column toggle list and 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): def __init__(self, name, column_indices):
# Name is how a column is identified and is also the header # Name is how a column is identified and is also the header
self.name = name self.name = name
# Column_indices holds the indexes to the liststore_columns that # Column_indices holds the indexes to the liststore_columns that
# this column utilizes. It is stored as a list. # this column utilizes. It is stored as a list.
self.column_indices = column_indices self.column_indices = column_indices
# Column is a reference to the GtkTreeViewColumn object # Column is a reference to the GtkTreeViewColumn object
self.column = None self.column = None
@ -122,19 +122,19 @@ class ListView:
# If this is set, it is used to sort the model # If this is set, it is used to sort the model
self.sort_func = None self.sort_func = None
self.sort_id = None self.sort_id = None
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..")
if treeview_widget is not None: if treeview_widget is not None:
# User supplied a treeview widget # User supplied a treeview widget
self.treeview = treeview_widget self.treeview = treeview_widget
else: else:
self.treeview = gtk.TreeView() self.treeview = gtk.TreeView()
if state_file: if state_file:
self.load_state(state_file) self.load_state(state_file)
self.liststore = None self.liststore = None
self.model_filter = None self.model_filter = None
@ -155,13 +155,13 @@ class ListView:
# A list of menus that self.menu will be a submenu of everytime it is # A list of menus that self.menu will be a submenu of everytime it is
# created. # created.
self.checklist_menus = [] self.checklist_menus = []
# Create the model filter and column # Create the model filter and column
self.add_bool_column("filter", hidden=True) self.add_bool_column("filter", hidden=True)
def create_model_filter(self): def create_model_filter(self):
"""create new filter-model """create new filter-model
must be called after listview.create_new_liststore must be called after listview.create_new_liststore
""" """
sort_column = None sort_column = None
if self.model_filter: if self.model_filter:
@ -171,7 +171,7 @@ class ListView:
model_filter.set_visible_column( model_filter.set_visible_column(
self.columns["filter"].column_indices[0]) self.columns["filter"].column_indices[0])
self.model_filter = gtk.TreeModelSort(model_filter) self.model_filter = gtk.TreeModelSort(model_filter)
self.set_sort_functions() self.set_sort_functions()
self.treeview.set_model(self.model_filter) self.treeview.set_model(self.model_filter)
if sort_column and sort_column != (None, None): if sort_column and sort_column != (None, None):
self.model_filter.set_sort_column_id(*sort_column) self.model_filter.set_sort_column_id(*sort_column)
@ -184,13 +184,13 @@ class ListView:
column.sort_id, column.sort_id,
column.sort_func, column.sort_func,
column.sort_id) column.sort_id)
def save_state(self, filename): def save_state(self, filename):
"""Saves the listview state (column positions and visibility) to """Saves the listview state (column positions and visibility) to
filename.""" filename."""
# A list of ListViewColumnStates # A list of ListViewColumnStates
state = [] state = []
# Get the list of TreeViewColumns from the TreeView # Get the list of TreeViewColumns from the TreeView
treeview_columns = self.treeview.get_columns() treeview_columns = self.treeview.get_columns()
counter = 0 counter = 0
@ -200,12 +200,12 @@ class ListView:
if self.get_column_name(id) == column.get_title(): if self.get_column_name(id) == column.get_title():
sort = id sort = id
# Append a new column state to the state list # Append a new column state to the state list
state.append(ListViewColumnState(column.get_title(), counter, state.append(ListViewColumnState(column.get_title(), counter,
column.get_width(), column.get_visible(), column.get_width(), column.get_visible(),
sort, int(column.get_sort_order()))) sort, int(column.get_sort_order())))
# Increase the counter because this is how we determine position # Increase the counter because this is how we determine position
counter += 1 counter += 1
# Get the config location for saving the state file # Get the config location for saving the state file
config_location = ConfigManager("gtkui.conf")["config_location"] config_location = ConfigManager("gtkui.conf")["config_location"]
@ -216,13 +216,13 @@ class ListView:
state_file.close() state_file.close()
except IOError, e: except IOError, e:
log.warning("Unable to save state file: %s", e) log.warning("Unable to save state file: %s", e)
def load_state(self, filename): def load_state(self, filename):
"""Load the listview state from filename.""" """Load the listview state from filename."""
# Get the config location for loading the state file # Get the config location for loading the state file
config_location = ConfigManager("gtkui.conf")["config_location"] config_location = ConfigManager("gtkui.conf")["config_location"]
state = None state = None
try: try:
log.debug("Loading ListView state file: %s", filename) log.debug("Loading ListView state file: %s", filename)
state_file = open(os.path.join(config_location, filename), "rb") state_file = open(os.path.join(config_location, filename), "rb")
@ -230,16 +230,16 @@ class ListView:
state_file.close() state_file.close()
except (EOFError, IOError), e: except (EOFError, IOError), e:
log.warning("Unable to load state file: %s", 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 # Keep the state in self.state so we can access it as we add new columns
self.state = state self.state = state
def set_treeview(self, treeview_widget): def set_treeview(self, treeview_widget):
"""Set the treeview widget that this listview uses.""" """Set the treeview widget that this listview uses."""
self.treeview = treeview_widget self.treeview = treeview_widget
self.treeview.set_model(self.liststore) self.treeview.set_model(self.liststore)
return return
def get_column_index(self, name): def get_column_index(self, name):
"""Get the liststore column indices belonging to this column. """Get the liststore column indices belonging to this column.
Will return a list. Will return a list.
@ -251,33 +251,33 @@ class ListView:
for key, value in self.columns.items(): for key, value in self.columns.items():
if index in value.column_indices: if index in value.column_indices:
return key return key
def get_state_field_column(self, field): def get_state_field_column(self, field):
"""Returns the column number for the state field""" """Returns the column number for the state field"""
for column in self.columns.keys(): for column in self.columns.keys():
if self.columns[column].status_field == None: if self.columns[column].status_field == None:
continue continue
for f in self.columns[column].status_field: for f in self.columns[column].status_field:
if field == f: if field == f:
return self.columns[column].column_indices[ return self.columns[column].column_indices[
self.columns[column].status_field.index(f)] self.columns[column].status_field.index(f)]
def on_menuitem_toggled(self, widget): def on_menuitem_toggled(self, widget):
"""Callback for the generated column menuitems.""" """Callback for the generated column menuitems."""
# Get the column name from the widget # Get the column name from the widget
name = widget.get_child().get_text() name = widget.get_child().get_text()
# Set the column's visibility based on the widgets active state # Set the column's visibility based on the widgets active state
self.columns[name].column.set_visible(widget.get_active()) self.columns[name].column.set_visible(widget.get_active())
return return
def register_checklist_menu(self, menu): def register_checklist_menu(self, menu):
"""Register a checklist menu with the listview. It will automatically """Register a checklist menu with the listview. It will automatically
attach any new checklist menu it makes to this menu. attach any new checklist menu it makes to this menu.
""" """
self.checklist_menus.append(menu) self.checklist_menus.append(menu)
def create_checklist_menu(self): def create_checklist_menu(self):
"""Creates a menu used for toggling the display of columns.""" """Creates a menu used for toggling the display of columns."""
menu = gtk.Menu() menu = gtk.Menu()
@ -297,20 +297,20 @@ class ListView:
menuitem.connect("toggled", self.on_menuitem_toggled) menuitem.connect("toggled", self.on_menuitem_toggled)
# Add the new checkmenuitem to the menu # Add the new checkmenuitem to the menu
menu.append(menuitem) menu.append(menuitem)
# Attach this new menu to all the checklist_menus # Attach this new menu to all the checklist_menus
for _menu in self.checklist_menus: for _menu in self.checklist_menus:
_menu.set_submenu(menu) _menu.set_submenu(menu)
_menu.show_all() _menu.show_all()
return menu return menu
def create_new_liststore(self): def create_new_liststore(self):
"""Creates a new GtkListStore based on the liststore_columns list""" """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. # old one to the new one.
new_list = gtk.ListStore(*tuple(self.liststore_columns)) new_list = gtk.ListStore(*tuple(self.liststore_columns))
# This function is used in the liststore.foreach method with user_data # This function is used in the liststore.foreach method with user_data
# being the new liststore and the columns list # being the new liststore and the columns list
def copy_row(model, path, row, user_data): def copy_row(model, path, row, user_data):
@ -321,17 +321,17 @@ class ListView:
value = model.get_value(row, column) value = model.get_value(row, column)
# Set the value of this row and column in the new liststore # Set the value of this row and column in the new liststore
new_list.set_value(new_row, column, value) new_list.set_value(new_row, column, value)
# Do the actual row copy # Do the actual row copy
if self.liststore is not None: if self.liststore is not None:
self.liststore.foreach(copy_row, (new_list, self.columns)) self.liststore.foreach(copy_row, (new_list, self.columns))
self.liststore = new_list self.liststore = new_list
# Create the model # Create the model
self.create_model_filter() self.create_model_filter()
return return
def remove_column(self, header): def remove_column(self, header):
"""Removes the column with the name 'header' from the listview""" """Removes the column with the name 'header' from the listview"""
# Start by removing this column from the treeview # Start by removing this column from the treeview
@ -348,11 +348,11 @@ class ListView:
# We need to shift this column_indices # We need to shift this column_indices
for index in column.column_indices: for index in column.column_indices:
index = index - len(column_indices) index = index - len(column_indices)
# Remove from the liststore columns list # Remove from the liststore columns list
for index in column_indices: for index in column_indices:
del self.liststore_columns[index] del self.liststore_columns[index]
# Create a new liststore # Create a new liststore
self.create_new_liststore() self.create_new_liststore()
@ -360,8 +360,8 @@ class ListView:
self.create_checklist_menu() self.create_checklist_menu()
return 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, status_field, sortid, text=0, value=0, pixbuf=0, function=None,
column_type=None, sort_func=None): column_type=None, sort_func=None):
"""Adds a column to the ListView""" """Adds a column to the ListView"""
@ -374,23 +374,23 @@ class ListView:
else: else:
self.liststore_columns.append(col_types) self.liststore_columns.append(col_types)
column_indices.append(len(self.liststore_columns) - 1) column_indices.append(len(self.liststore_columns) - 1)
# Add to the index list so we know the order of the visible columns. # Add to the index list so we know the order of the visible columns.
if position is not None: if position is not None:
self.column_index.insert(position, header) self.column_index.insert(position, header)
else: else:
self.column_index.append(header) self.column_index.append(header)
# Create a new column object and add it to the list # Create a new column object and add it to the list
self.columns[header] = self.ListViewColumn(header, column_indices) self.columns[header] = self.ListViewColumn(header, column_indices)
self.columns[header].status_field = status_field self.columns[header].status_field = status_field
self.columns[header].sort_func = sort_func self.columns[header].sort_func = sort_func
self.columns[header].sort_id = column_indices[sortid] self.columns[header].sort_id = column_indices[sortid]
# Create a new list with the added column # Create a new list with the added column
self.create_new_liststore() self.create_new_liststore()
column = gtk.TreeViewColumn(header) column = gtk.TreeViewColumn(header)
if column_type == "text": if column_type == "text":
column.pack_start(render) column.pack_start(render)
@ -403,11 +403,11 @@ 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(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(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)
if function is None: if function is None:
@ -416,7 +416,7 @@ 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(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)
@ -445,7 +445,7 @@ class ListView:
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)
if column_state.sort is not None and column_state.sort > -1: if column_state.sort is not None and column_state.sort > -1:
self.model_filter.set_sort_column_id(column_state.sort, column_state.sort_order) self.model_filter.set_sort_column_id(column_state.sort, column_state.sort_order)
column.set_visible(column_state.visible) column.set_visible(column_state.visible)
@ -461,10 +461,10 @@ class ListView:
self.columns[header].column = column self.columns[header].column = column
# Re-create the menu item because of the new column # Re-create the menu item because of the new column
self.create_checklist_menu() self.create_checklist_menu()
return True 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, position=None,
status_field=None, status_field=None,
sortid=0, sortid=0,
@ -475,63 +475,63 @@ class ListView:
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, sort_func=sort_func) status_field, sortid, column_type=column_type, sort_func=sort_func)
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, position=None,
status_field=None, status_field=None,
sortid=0, sortid=0,
column_type="bool"): column_type="bool"):
"""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)
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): column_type="func", sort_func=None):
"""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) function=function, sort_func=sort_func)
return True return True
def add_progress_column(self, header, col_types=[float, str], def add_progress_column(self, header, col_types=[float, str],
sortid=0, sortid=0,
hidden=False, hidden=False,
position=None, position=None,
status_field=None, status_field=None,
function=None, function=None,
column_type="progress"): column_type="progress"):
"""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, column_type=column_type,
value=0, text=1) value=0, text=1)
return True return True
def add_texticon_column(self, header, col_types=[str, str], def add_texticon_column(self, header, col_types=[str, str],
sortid=1, sortid=1,
hidden=False, hidden=False,
position=None, position=None,
status_field=None, status_field=None,
column_type="texticon", column_type="texticon",
function=None): function=None):
"""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, self.add_column(header, (render1, render2), col_types, hidden,
position, status_field, sortid, position, status_field, sortid,
column_type=column_type, function=function, column_type=column_type, function=function,
pixbuf=0, text=1) pixbuf=0, text=1)

View file

@ -46,6 +46,8 @@ def fpeer_size_second(first, second):
return "%s (%s)" % (first, deluge.common.fsize(second)) return "%s (%s)" % (first, deluge.common.fsize(second))
def fratio(value): def fratio(value):
if value < 0:
return ""
return "%.3f" % value return "%.3f" % value
def fpcnt(value): def fpcnt(value):

View file

@ -113,7 +113,7 @@ def queue_column_sort(model, iter1, iter2, data):
return 1 return 1
if v2 > v1: if v2 > v1:
return -1 return -1
class TorrentView(listview.ListView, component.Component): class TorrentView(listview.ListView, component.Component):
"""TorrentView handles the listing of torrents.""" """TorrentView handles the listing of torrents."""
def __init__(self): def __init__(self):
@ -130,7 +130,7 @@ class TorrentView(listview.ListView, component.Component):
# We keep a copy of the previous status to compare for changes # We keep a copy of the previous status to compare for changes
self.prev_status = {} self.prev_status = {}
# Register the columns menu with the listview so it gets updated # Register the columns menu with the listview so it gets updated
# accordingly. # accordingly.
self.register_checklist_menu( self.register_checklist_menu(
@ -196,7 +196,7 @@ class TorrentView(listview.ListView, component.Component):
self.on_selection_changed) self.on_selection_changed)
self.treeview.connect("drag-drop", self.on_drag_drop) self.treeview.connect("drag-drop", self.on_drag_drop)
def start(self): def start(self):
"""Start the torrentview""" """Start the torrentview"""
# We need to get the core session state to know which torrents are in # We need to get the core session state to know which torrents are in
@ -297,12 +297,12 @@ class TorrentView(listview.ListView, component.Component):
if row[column_index[i]] != row_value: if row[column_index[i]] != row_value:
row[column_index[i]] = row_value row[column_index[i]] = row_value
except Exception, e: except Exception, e:
log.debug("%s", e) log.debug("%s", e)
# Update the toolbar buttons just in case some state has changed # Update the toolbar buttons just in case some state has changed
component.get("ToolBar").update_buttons() component.get("ToolBar").update_buttons()
component.get("MenuBar").update_menu() component.get("MenuBar").update_menu()
self.prev_status = status self.prev_status = status
def _on_get_torrents_status(self, status): def _on_get_torrents_status(self, status):