mirror of
https://git.deluge-torrent.org/deluge
synced 2025-08-25 03:45:31 +00:00
ListView still needs some improvements, but it is working now.
Removed columns.py as this has been merged with listview.py.
This commit is contained in:
parent
e13b42203b
commit
ac29983651
3 changed files with 131 additions and 184 deletions
|
@ -1,153 +0,0 @@
|
||||||
#
|
|
||||||
# columns.py
|
|
||||||
#
|
|
||||||
# Copyright (C) 2006 Zach Tibbitts ('zachtib') <zach@collegegeek.org>
|
|
||||||
# Copyright (C) 2007 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 2 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 pygtk
|
|
||||||
pygtk.require('2.0')
|
|
||||||
import gtk
|
|
||||||
|
|
||||||
import deluge.common
|
|
||||||
|
|
||||||
# Cell data functions to pass to add_func_column()
|
|
||||||
|
|
||||||
def cell_data_speed(column, cell, model, iter, data):
|
|
||||||
speed = int(model.get_value(iter, data))
|
|
||||||
speed_str = deluge.common.fspeed(speed)
|
|
||||||
cell.set_property('text', speed_str)
|
|
||||||
|
|
||||||
def cell_data_size(column, cell, model, iter, data):
|
|
||||||
size = long(model.get_value(iter, data))
|
|
||||||
size_str = deluge.common.fsize(size)
|
|
||||||
cell.set_property('text', size_str)
|
|
||||||
|
|
||||||
def cell_data_peer(column, cell, model, iter, data):
|
|
||||||
c1, c2 = data
|
|
||||||
a = int(model.get_value(iter, c1))
|
|
||||||
b = int(model.get_value(iter, c2))
|
|
||||||
cell.set_property('text', '%d (%d)'%(a, b))
|
|
||||||
|
|
||||||
def cell_data_time(column, cell, model, iter, data):
|
|
||||||
time = int(model.get_value(iter, data))
|
|
||||||
if time < 0 or time == 0:
|
|
||||||
time_str = _("Infinity")
|
|
||||||
else:
|
|
||||||
time_str = deluge.common.ftime(time)
|
|
||||||
cell.set_property('text', time_str)
|
|
||||||
|
|
||||||
def cell_data_ratio(column, cell, model, iter, data):
|
|
||||||
ratio = float(model.get_value(iter, data))
|
|
||||||
if ratio == -1:
|
|
||||||
ratio_str = _("Unknown")
|
|
||||||
else:
|
|
||||||
ratio_str = "%.3f"%ratio
|
|
||||||
cell.set_property('text', ratio_str)
|
|
||||||
|
|
||||||
## Functions to create columns
|
|
||||||
|
|
||||||
def add_func_column(view, header, func, data, sortid=None):
|
|
||||||
column = gtk.TreeViewColumn(header)
|
|
||||||
render = gtk.CellRendererText()
|
|
||||||
column.pack_start(render, True)
|
|
||||||
column.set_cell_data_func(render, func, data)
|
|
||||||
if sortid is not None:
|
|
||||||
column.set_clickable(True)
|
|
||||||
column.set_sort_column_id(sortid)
|
|
||||||
else:
|
|
||||||
try:
|
|
||||||
if len(data) == 1:
|
|
||||||
column.set_clickable(True)
|
|
||||||
column.set_sort_column_id(data[0])
|
|
||||||
except TypeError:
|
|
||||||
column.set_clickable(True)
|
|
||||||
column.set_sort_column_id(data)
|
|
||||||
column.set_resizable(True)
|
|
||||||
column.set_expand(False)
|
|
||||||
column.set_min_width(10)
|
|
||||||
column.set_reorderable(True)
|
|
||||||
view.append_column(column)
|
|
||||||
return column
|
|
||||||
|
|
||||||
|
|
||||||
def add_text_column(view, header, cid):
|
|
||||||
render = gtk.CellRendererText()
|
|
||||||
column = gtk.TreeViewColumn(header, render, text=cid)
|
|
||||||
column.set_clickable(True)
|
|
||||||
column.set_sort_column_id(cid)
|
|
||||||
column.set_resizable(True)
|
|
||||||
column.set_expand(False)
|
|
||||||
column.set_min_width(10)
|
|
||||||
column.set_reorderable(True)
|
|
||||||
view.append_column(column)
|
|
||||||
return column
|
|
||||||
|
|
||||||
def add_progress_column(view, header, pid, mid):
|
|
||||||
render = gtk.CellRendererProgress()
|
|
||||||
column = gtk.TreeViewColumn(header, render, value=pid, text=mid)
|
|
||||||
column.set_clickable(True)
|
|
||||||
column.set_sort_column_id(pid)
|
|
||||||
column.set_resizable(True)
|
|
||||||
column.set_expand(False)
|
|
||||||
column.set_min_width(10)
|
|
||||||
column.set_reorderable(True)
|
|
||||||
view.append_column(column)
|
|
||||||
return column
|
|
||||||
|
|
||||||
def add_toggle_column(view, header, cid, toggled_signal=None):
|
|
||||||
render = gtk.CellRendererToggle()
|
|
||||||
render.set_property('activatable', True)
|
|
||||||
column = gtk.TreeViewColumn(header, render, active=cid)
|
|
||||||
column.set_clickable(True)
|
|
||||||
column.set_resizable(True)
|
|
||||||
column.set_expand(False)
|
|
||||||
column.set_min_width(10)
|
|
||||||
column.set_reorderable(True)
|
|
||||||
view.append_column(column)
|
|
||||||
if toggled_signal is not None:
|
|
||||||
render.connect("toggled", toggled_signal)
|
|
||||||
return column
|
|
||||||
|
|
||||||
def add_texticon_column(view, header, icon_col, text_col):
|
|
||||||
column = gtk.TreeViewColumn(header)
|
|
||||||
column.set_clickable(True)
|
|
||||||
column.set_resizable(True)
|
|
||||||
column.set_expand(False)
|
|
||||||
column.set_min_width(10)
|
|
||||||
column.set_reorderable(True)
|
|
||||||
render = gtk.CellRendererPixbuf()
|
|
||||||
column.pack_start(render, expand=False)
|
|
||||||
column.add_attribute(render, 'pixbuf', icon_col)
|
|
||||||
render = gtk.CellRendererText()
|
|
||||||
column.pack_start(render, expand=True)
|
|
||||||
column.add_attribute(render, 'text', text_col)
|
|
||||||
view.append_column(column)
|
|
||||||
return column
|
|
|
@ -38,6 +38,8 @@ pygtk.require('2.0')
|
||||||
import gtk
|
import gtk
|
||||||
import gettext
|
import gettext
|
||||||
|
|
||||||
|
import deluge.common
|
||||||
|
|
||||||
# Get the logger
|
# Get the logger
|
||||||
log = logging.getLogger("deluge")
|
log = logging.getLogger("deluge")
|
||||||
|
|
||||||
|
@ -49,9 +51,9 @@ def cell_data_speed(column, cell, model, iter, data):
|
||||||
cell.set_property('text', speed_str)
|
cell.set_property('text', speed_str)
|
||||||
|
|
||||||
def cell_data_size(column, cell, model, iter, data):
|
def cell_data_size(column, cell, model, iter, data):
|
||||||
size = long(model.get_value(iter, data))
|
size = long(model.get_value(iter, data))
|
||||||
size_str = deluge.common.fsize(size)
|
size_str = deluge.common.fsize(size)
|
||||||
cell.set_property('text', size_str)
|
cell.set_property('text', size_str)
|
||||||
|
|
||||||
def cell_data_peer(column, cell, model, iter, data):
|
def cell_data_peer(column, cell, model, iter, data):
|
||||||
c1, c2 = data
|
c1, c2 = data
|
||||||
|
@ -79,7 +81,6 @@ class ListView:
|
||||||
class ListViewColumn:
|
class ListViewColumn:
|
||||||
def __init__(self, name, column_indices):
|
def __init__(self, name, column_indices):
|
||||||
self.name = name
|
self.name = name
|
||||||
# self.column_types = column_types
|
|
||||||
self.column_indices = column_indices
|
self.column_indices = column_indices
|
||||||
|
|
||||||
def __init__(self, treeview_widget=None):
|
def __init__(self, treeview_widget=None):
|
||||||
|
@ -101,6 +102,17 @@ class ListView:
|
||||||
self.columns = {}
|
self.columns = {}
|
||||||
self.liststore_columns = []
|
self.liststore_columns = []
|
||||||
|
|
||||||
|
def set_treeview(self, treeview_widget):
|
||||||
|
self.treeview = treeview_widget
|
||||||
|
return
|
||||||
|
|
||||||
|
def get_column_index(self, name):
|
||||||
|
# Only return as list if needed
|
||||||
|
if len(self.columns[name].column_indices) > 1:
|
||||||
|
return self.columns[name].column_indices
|
||||||
|
else:
|
||||||
|
return self.columns[name].column_indices[0]
|
||||||
|
|
||||||
def create_new_liststore(self):
|
def create_new_liststore(self):
|
||||||
# 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.
|
||||||
|
@ -110,8 +122,6 @@ class ListView:
|
||||||
# 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):
|
||||||
new_list, columns = user_data
|
new_list, columns = user_data
|
||||||
# Iterate over the columns except the last one. This one would have
|
|
||||||
# been just added and no need to copy it from the old list.
|
|
||||||
for column in range(model.get_n_columns()):
|
for column in range(model.get_n_columns()):
|
||||||
# Get the current value of the column for this row
|
# Get the current value of the column for this row
|
||||||
value = model.get_value(row, column)
|
value = model.get_value(row, column)
|
||||||
|
@ -171,8 +181,12 @@ class ListView:
|
||||||
column = gtk.TreeViewColumn(header)
|
column = gtk.TreeViewColumn(header)
|
||||||
render = gtk.CellRendererText()
|
render = gtk.CellRendererText()
|
||||||
column.pack_start(render, True)
|
column.pack_start(render, True)
|
||||||
column.set_cell_data_func(render, function,
|
if len(self.columns[header].column_indices) > 1:
|
||||||
|
column.set_cell_data_func(render, function,
|
||||||
tuple(self.columns[header].column_indices))
|
tuple(self.columns[header].column_indices))
|
||||||
|
else:
|
||||||
|
column.set_cell_data_func(render, function,
|
||||||
|
self.columns[header].column_indices[0])
|
||||||
column.set_clickable(True)
|
column.set_clickable(True)
|
||||||
column.set_sort_column_id(column_indices[sortid])
|
column.set_sort_column_id(column_indices[sortid])
|
||||||
column.set_resizable(True)
|
column.set_resizable(True)
|
||||||
|
|
|
@ -45,61 +45,147 @@ import listview
|
||||||
# Get the logger
|
# Get the logger
|
||||||
log = logging.getLogger("deluge")
|
log = logging.getLogger("deluge")
|
||||||
|
|
||||||
class TorrentView:
|
class TorrentView(listview.ListView):
|
||||||
def __init__(self, window):
|
def __init__(self, window):
|
||||||
|
# Call the ListView constructor
|
||||||
|
listview.ListView.__init__(self)
|
||||||
log.debug("TorrentView Init..")
|
log.debug("TorrentView Init..")
|
||||||
self.window = window
|
self.window = window
|
||||||
self.core = functions.get_core()
|
self.core = functions.get_core()
|
||||||
# Create a ListView object using the torrent_view from the mainwindow
|
# Set the treeview used in listview with the one from our glade file
|
||||||
self.torrent_view = listview.ListView(
|
self.set_treeview(self.window.main_glade.get_widget("torrent_view"))
|
||||||
self.window.main_glade.get_widget("torrent_view"))
|
|
||||||
|
|
||||||
self.torrent_view.add_text_column("torrent_id", visible=False)
|
self.add_text_column("torrent_id", visible=False)
|
||||||
self.torrent_view.add_texticon_column("Name")
|
self.add_texticon_column("Name")
|
||||||
self.torrent_view.add_func_column("Size",
|
self.add_func_column("Size",
|
||||||
listview.cell_data_size,
|
listview.cell_data_size,
|
||||||
[long])
|
[long])
|
||||||
self.torrent_view.add_progress_column("Progress")
|
self.add_progress_column("Progress")
|
||||||
self.torrent_view.add_func_column("Seeders",
|
self.add_func_column("Seeders",
|
||||||
listview.cell_data_peer,
|
listview.cell_data_peer,
|
||||||
[int, int])
|
[int, int])
|
||||||
self.torrent_view.add_func_column("Peers",
|
self.add_func_column("Peers",
|
||||||
listview.cell_data_peer,
|
listview.cell_data_peer,
|
||||||
[int, int])
|
[int, int])
|
||||||
self.torrent_view.add_func_column("Down Speed",
|
self.add_func_column("Down Speed",
|
||||||
listview.cell_data_speed,
|
listview.cell_data_speed,
|
||||||
[int])
|
[float])
|
||||||
self.torrent_view.add_func_column("Up Speed",
|
self.add_func_column("Up Speed",
|
||||||
listview.cell_data_speed,
|
listview.cell_data_speed,
|
||||||
[int])
|
[float])
|
||||||
self.torrent_view.add_func_column("ETA",
|
self.add_func_column("ETA",
|
||||||
listview.cell_data_time,
|
listview.cell_data_time,
|
||||||
[int])
|
[int])
|
||||||
self.torrent_view.add_func_column("Ratio",
|
self.add_func_column("Ratio",
|
||||||
listview.cell_data_ratio,
|
listview.cell_data_ratio,
|
||||||
[float])
|
[float])
|
||||||
|
|
||||||
### Connect Signals ###
|
### Connect Signals ###
|
||||||
# Connect to the 'button-press-event' to know when to bring up the
|
# Connect to the 'button-press-event' to know when to bring up the
|
||||||
# torrent menu popup.
|
# torrent menu popup.
|
||||||
self.torrent_view.treeview.connect("button-press-event",
|
self.treeview.connect("button-press-event",
|
||||||
self.on_button_press_event)
|
self.on_button_press_event)
|
||||||
# Connect to the 'changed' event of TreeViewSelection to get selection
|
# Connect to the 'changed' event of TreeViewSelection to get selection
|
||||||
# changes.
|
# changes.
|
||||||
self.torrent_view.treeview.get_selection().connect("changed",
|
self.treeview.get_selection().connect("changed",
|
||||||
self.on_selection_changed)
|
self.on_selection_changed)
|
||||||
|
|
||||||
def update(self):
|
def update(self):
|
||||||
pass
|
"""Update the view, this is likely called by a timer"""
|
||||||
|
# This function is used for the foreach method of the treemodel
|
||||||
|
def update_row(model, path, row, user_data):
|
||||||
|
torrent_id = self.liststore.get_value(row, 0)
|
||||||
|
status_keys = ["progress", "state", "num_seeds",
|
||||||
|
"num_peers", "download_payload_rate", "upload_payload_rate",
|
||||||
|
"eta"]
|
||||||
|
status = functions.get_torrent_status(self.core, torrent_id,
|
||||||
|
status_keys)
|
||||||
|
|
||||||
|
# Set values for each column in the row
|
||||||
|
|
||||||
|
self.liststore.set_value(row,
|
||||||
|
self.get_column_index("Progress")[0],
|
||||||
|
status["progress"]*100)
|
||||||
|
self.liststore.set_value(row,
|
||||||
|
self.get_column_index("Progress")[1],
|
||||||
|
status["state"])
|
||||||
|
self.liststore.set_value(row,
|
||||||
|
self.get_column_index("Seeders")[0],
|
||||||
|
status["num_seeds"])
|
||||||
|
self.liststore.set_value(row,
|
||||||
|
self.get_column_index("Seeders")[1],
|
||||||
|
status["num_seeds"])
|
||||||
|
self.liststore.set_value(row,
|
||||||
|
self.get_column_index("Peers")[0],
|
||||||
|
status["num_peers"])
|
||||||
|
self.liststore.set_value(row,
|
||||||
|
self.get_column_index("Peers")[1],
|
||||||
|
status["num_peers"])
|
||||||
|
self.liststore.set_value(row,
|
||||||
|
self.get_column_index("Down Speed"),
|
||||||
|
status["download_payload_rate"])
|
||||||
|
self.liststore.set_value(row,
|
||||||
|
self.get_column_index("Up Speed"),
|
||||||
|
status["upload_payload_rate"])
|
||||||
|
self.liststore.set_value(row,
|
||||||
|
self.get_column_index("ETA"),
|
||||||
|
status["eta"])
|
||||||
|
|
||||||
|
# Iterates through every row and updates them accordingly
|
||||||
|
if self.liststore is not None:
|
||||||
|
self.liststore.foreach(update_row, None)
|
||||||
|
|
||||||
def add_row(self, torrent_id):
|
def add_row(self, torrent_id):
|
||||||
pass
|
"""Adds a new torrent row to the treeview"""
|
||||||
|
# Get the status and info dictionaries
|
||||||
|
status_keys = ["name", "total_size", "progress", "state",
|
||||||
|
"num_seeds", "num_peers", "download_payload_rate",
|
||||||
|
"upload_payload_rate", "eta"]
|
||||||
|
status = functions.get_torrent_status(self.core, torrent_id,
|
||||||
|
status_keys)
|
||||||
|
# Insert the row with info provided from core
|
||||||
|
self.liststore.append([
|
||||||
|
torrent_id,
|
||||||
|
None,
|
||||||
|
status["name"],
|
||||||
|
status["total_size"],
|
||||||
|
status["progress"]*100,
|
||||||
|
status["state"],
|
||||||
|
status["num_seeds"],
|
||||||
|
status["num_seeds"],
|
||||||
|
status["num_peers"],
|
||||||
|
status["num_peers"],
|
||||||
|
status["download_payload_rate"],
|
||||||
|
status["upload_payload_rate"],
|
||||||
|
status["eta"],
|
||||||
|
0.0
|
||||||
|
])
|
||||||
|
|
||||||
def remove_row(self, torrent_id):
|
def remove_row(self, torrent_id):
|
||||||
pass
|
"""Removes a row with torrent_id"""
|
||||||
|
row = self.liststore.get_iter_first()
|
||||||
|
while row is not None:
|
||||||
|
# Check if this row is the row we want to remove
|
||||||
|
if self.liststore.get_value(row, 0) == torrent_id:
|
||||||
|
self.liststore.remove(row)
|
||||||
|
# Force an update of the torrentview
|
||||||
|
self.update()
|
||||||
|
break
|
||||||
|
row = self.liststore.iter_next(row)
|
||||||
|
|
||||||
def get_selected_torrents(self):
|
def get_selected_torrents(self):
|
||||||
pass
|
"""Returns a list of selected torrents or None"""
|
||||||
|
torrent_ids = []
|
||||||
|
paths = self.treeview.get_selection().get_selected_rows()[1]
|
||||||
|
|
||||||
|
try:
|
||||||
|
for path in paths:
|
||||||
|
torrent_ids.append(
|
||||||
|
self.liststore.get_value(
|
||||||
|
self.liststore.get_iter(path), 0))
|
||||||
|
return torrent_ids
|
||||||
|
except ValueError:
|
||||||
|
return None
|
||||||
|
|
||||||
### Callbacks ###
|
### Callbacks ###
|
||||||
def on_button_press_event(self, widget, event):
|
def on_button_press_event(self, widget, event):
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue