Start work of new torrent info tabs.

This commit is contained in:
Andrew Resch 2008-03-17 09:36:43 +00:00
parent 86d8ea3f5b
commit 1a5ebf73ee
9 changed files with 1302 additions and 775 deletions

View file

@ -0,0 +1,98 @@
#
# details_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 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 gtk, gtk.glade
from deluge.ui.client import aclient as client
import deluge.component as component
import deluge.common
class DetailsTab:
def __init__(self):
# Get the labels we need to update.
# widgetname, modifier function, status keys
glade = component.get("MainWindow").main_glade
self.label_widgets = [
(glade.get_widget("summary_name"), None, ("name",)),
(glade.get_widget("summary_total_size"), deluge.common.fsize, ("total_size",)),
(glade.get_widget("summary_num_files"), str, ("num_files",)),
(glade.get_widget("summary_tracker"), None, ("tracker",)),
(glade.get_widget("summary_torrent_path"), None, ("save_path",))
]
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 = ["name", "total_size", "num_files",
"tracker", "save_path", "private"]
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
for widget in self.label_widgets:
if widget[1] != None:
args = []
try:
for key in widget[2]:
args.append(status[key])
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)
def clear(self):
for widget in self.label_widgets:
widget[0].set_text("")

View file

@ -0,0 +1,144 @@
#
# files_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 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 gtk, gtk.glade
import gobject
import gettext
import os.path
from deluge.ui.client import aclient as client
import deluge.component as component
import deluge.common
import deluge.ui.gtkui.listview
from deluge.log import LOG as log
class FilesTab:
def __init__(self):
glade = component.get("MainWindow").get_glade()
self.listview = glade.get_widget("files_listview")
# country, filename, size, priority
self.liststore = gtk.ListStore(str, gobject.TYPE_UINT64, str, int, str)
# Filename column
column = gtk.TreeViewColumn(_("Filename"))
render = gtk.CellRendererText()
column.pack_start(render, False)
column.add_attribute(render, "text", 0)
self.listview.append_column(column)
# Size column
column = gtk.TreeViewColumn(_("Size"))
render = gtk.CellRendererText()
column.pack_start(render, False)
column.set_cell_data_func(render, deluge.ui.gtkui.listview.cell_data_size, 1)
self.listview.append_column(column)
# Progress column
column = gtk.TreeViewColumn(_("Progress"))
render = gtk.CellRendererProgress()
column.pack_start(render, False)
column.add_attribute(render, "text", 2)
column.add_attribute(render, "value", 3)
self.listview.append_column(column)
# Priority column
column = gtk.TreeViewColumn(_("Priority"))
render = gtk.CellRendererText()
column.pack_start(render, False)
column.add_attribute(render, "text", 4)
self.listview.append_column(column)
self.listview.set_model(self.liststore)
# torrent_id: (filepath, size)
self.files_list = {}
self.torrent_id = None
def update(self):
# Get the first selected torrent
torrent_id = component.get("TorrentView").get_selected_torrents()
# Only use the first torrent in the list or return if None selected
if len(torrent_id) != 0:
torrent_id = torrent_id[0]
else:
# No torrent is selected in the torrentview
self.liststore.clear()
return
if torrent_id != self.torrent_id:
# We only want to do this if the torrent_id has changed
self.liststore.clear()
self.torrent_id = torrent_id
if self.torrent_id not in self.files_list.keys():
# We need to get the files list
log.debug("Getting file list from core..")
client.get_torrent_status(
self._on_get_torrent_files,
self.torrent_id,
["files", "file_progress", "file_priorities"])
client.force_call(block=True)
else:
self.update_files()
client.get_torrent_status(self._on_get_torrent_status, self.torrent_id, ["file_progress", "file_priorities"])
client.force_call(True)
else:
client.get_torrent_status(self._on_get_torrent_status, self.torrent_id, ["file_progress", "file_priorities"])
client.force_call(True)
def update_files(self):
# Updates the filename and size columns based on info in self.files_list
# This assumes the list is currently empty.
for file in self.files_list[self.torrent_id]:
row = self.liststore.append()
# Store the torrent id
self.liststore.set_value(row, 0,
os.path.split(file["path"])[1])
self.liststore.set_value(row, 1, file["size"])
def _on_get_torrent_files(self, status):
self.files_list[self.torrent_id] = status["files"]
self.update_files()
self._on_get_torrent_status(status)
def _on_get_torrent_status(self, status):
for index, row in enumerate(self.liststore):
row[2] = "%.2f%%" % (status["file_progress"][index] * 100)
row[3] = status["file_progress"][index] * 100
row[4] = status["file_priorities"][index]
def clear(self):
self.liststore.clear()

File diff suppressed because it is too large Load diff

View file

@ -102,7 +102,11 @@ class MainWindow(component.Component):
def visible(self):
"""Returns True if window is visible, False if not."""
return self.window.get_property("visible")
def get_glade(self):
"""Returns a reference to the main window glade object."""
return self.main_glade
def quit(self):
del self.config
gtk.main_quit()

View file

@ -0,0 +1,99 @@
#
# peers_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 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 gtk, gtk.glade
from deluge.ui.client import aclient as client
import deluge.component as component
import deluge.common
def cell_data_country(column, cell, model, row, data):
pass
class PeersTab:
def __init__(self):
glade = component.get("MainWindow").get_glade()
self.listview = glade.get_widget("peers_listview")
# country, filename, size, priority
self.liststore = gtk.ListStore(str, str, str, str, int, int, int)
# Country column
column = gtk.TreeViewColumn()
render = gtk.CellRendererPixbuf()
column.pack_start(render, False)
column.set_cell_data_func(render, cell_data_country, 0)
self.listview.append_column(column)
# Address column
column = gtk.TreeViewColumn(_("Address"))
render = gtk.CellRendererText()
column.pack_start(render, False)
column.add_attribute(render, "text", 1)
self.listview.append_column(column)
# Client column
column = gtk.TreeViewColumn(_("Client"))
render = gtk.CellRendererText()
column.pack_start(render, False)
column.add_attribute(render, "text", 2)
self.listview.append_column(column)
# Progress column
column = gtk.TreeViewColumn(_("Progress"))
render = gtk.CellRendererProgress()
column.pack_start(render, False)
column.add_attribute(render, "text", 3)
column.add_attribute(render, "value", 4)
self.listview.append_column(column)
# Down Speed column
column = gtk.TreeViewColumn(_("Down Speed"))
render = gtk.CellRendererText()
column.pack_start(render, False)
column.set_cell_data_func(render, deluge.common.fspeed, 5)
self.listview.append_column(column)
# Up Speed column
column = gtk.TreeViewColumn(_("Up Speed"))
render = gtk.CellRendererText()
column.pack_start(render, False)
column.set_cell_data_func(render, deluge.common.fspeed, 6)
self.listview.append_column(column)
self.listview.set_model(self.liststore)
def update(self):
pass
def clear(self):
pass

View file

@ -40,7 +40,7 @@ from deluge.log import LOG as log
class PluginManager(deluge.pluginmanagerbase.PluginManagerBase,
component.Component):
def __init__(self):
component.Component.__init__(self, "PluginManager")
component.Component.__init__(self, "PluginManager", depend=["Signals"])
self.config = ConfigManager("gtkui.conf")
deluge.pluginmanagerbase.PluginManagerBase.__init__(
self, "gtkui.conf", "deluge.plugin.gtkui")

View file

@ -0,0 +1,136 @@
#
# 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 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 gtk, gtk.glade
from deluge.ui.client import aclient as client
import deluge.component as component
import deluge.common
def fpeer_sized(first, second):
return "%s (%s)" % (deluge.common.fsize(first), deluge.common.fsize(second))
def fpeer_size_second(first, second):
return "%s (%s)" % (first, deluge.common.fsize(second))
def fratio(value):
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:
def __init__(self):
# Get the labels we need to update.
# widgetname, modifier function, status keys
glade = component.get("MainWindow").main_glade
self.label_widgets = [
(glade.get_widget("summary_pieces"), fpeer_size_second, ("num_pieces", "piece_length")),
(glade.get_widget("summary_availability"), fratio, ("distributed_copies",)),
(glade.get_widget("summary_total_downloaded"), fpeer_sized, ("total_done", "total_payload_download")),
(glade.get_widget("summary_total_uploaded"), fpeer_sized, ("total_uploaded", "total_payload_upload")),
(glade.get_widget("summary_download_speed"), fspeed, ("download_payload_rate", "max_download_speed")),
(glade.get_widget("summary_upload_speed"), fspeed, ("upload_payload_rate", "max_upload_speed")),
(glade.get_widget("summary_seeders"), deluge.common.fpeer, ("num_seeds", "total_seeds")),
(glade.get_widget("summary_peers"), deluge.common.fpeer, ("num_peers", "total_peers")),
(glade.get_widget("summary_eta"), deluge.common.ftime, ("eta",)),
(glade.get_widget("summary_share_ratio"), fratio, ("ratio",)),
(glade.get_widget("summary_tracker_status"), None, ("tracker_status",)),
(glade.get_widget("summary_next_announce"), deluge.common.ftime, ("next_announce",)),
(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",
"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"]
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
for widget in self.label_widgets:
if widget[1] != None:
args = []
try:
for key in widget[2]:
args.append(status[key])
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)

View file

@ -64,7 +64,9 @@ class ToolBar(component.Component):
"toolbutton_add",
"toolbutton_remove",
"toolbutton_pause",
"toolbutton_resume"
"toolbutton_resume",
"toolbutton_queue_up",
"toolbutton_queue_down"
]
# Set the Remove Torrent toolbuttons drop-down menu

View file

@ -33,34 +33,17 @@
"""The torrent details component shows info about the selected torrent."""
import pygtk
pygtk.require('2.0')
import gtk, gtk.glade
import gettext
import deluge.component as component
from deluge.ui.client import aclient as client
import deluge.common
from statistics_tab import StatisticsTab
from details_tab import DetailsTab
from files_tab import FilesTab
from peers_tab import PeersTab
from deluge.log import LOG as log
def fpeer_sized(first, second):
return "%s (%s)" % (deluge.common.fsize(first), deluge.common.fsize(second))
def fpeer_size_second(first, second):
return "%s (%s)" % (first, deluge.common.fsize(second))
def fratio(value):
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 TorrentDetails(component.Component):
def __init__(self):
component.Component.__init__(self, "TorrentDetails", interval=2000)
@ -69,37 +52,19 @@ class TorrentDetails(component.Component):
self.notebook = glade.get_widget("torrent_info")
self.details_tab = glade.get_widget("torrentdetails_tab")
# Don't show tabs if there is only 1
if self.notebook.get_n_pages() < 2:
self.notebook.set_show_tabs(False)
else:
self.notebook.set_show_tabs(True)
self.is_visible = True
# Get the labels we need to update.
# widgetname, modifier function, status keys
self.label_widgets = [
(glade.get_widget("summary_name"), None, ("name",)),
(glade.get_widget("summary_total_size"), deluge.common.fsize, ("total_size",)),
(glade.get_widget("summary_num_files"), str, ("num_files",)),
(glade.get_widget("summary_pieces"), fpeer_size_second, ("num_pieces", "piece_length")),
(glade.get_widget("summary_availability"), fratio, ("distributed_copies",)),
(glade.get_widget("summary_total_downloaded"), fpeer_sized, ("total_done", "total_payload_download")),
(glade.get_widget("summary_total_uploaded"), fpeer_sized, ("total_uploaded", "total_payload_upload")),
(glade.get_widget("summary_download_speed"), fspeed, ("download_payload_rate", "max_download_speed")),
(glade.get_widget("summary_upload_speed"), fspeed, ("upload_payload_rate", "max_upload_speed")),
(glade.get_widget("summary_seeders"), deluge.common.fpeer, ("num_seeds", "total_seeds")),
(glade.get_widget("summary_peers"), deluge.common.fpeer, ("num_peers", "total_peers")),
(glade.get_widget("summary_eta"), deluge.common.ftime, ("eta",)),
(glade.get_widget("summary_share_ratio"), fratio, ("ratio",)),
(glade.get_widget("summary_tracker"), None, ("tracker",)),
(glade.get_widget("summary_tracker_status"), None, ("tracker_status",)),
(glade.get_widget("summary_next_announce"), deluge.common.ftime, ("next_announce",)),
(glade.get_widget("summary_torrent_path"), None, ("save_path",)),
(glade.get_widget("progressbar"), fpcnt, ("progress",))
]
self.notebook.connect("switch-page", self._on_switch_page)
statistics_tab = StatisticsTab()
details_tab = DetailsTab()
files_tab = FilesTab()
peers_tab = PeersTab()
self.tabs = []
self.tabs.insert(0, statistics_tab)
self.tabs.insert(1, details_tab)
self.tabs.insert(2, files_tab)
self.tabs.insert(3, peers_tab)
def visible(self, visible):
if visible:
@ -108,78 +73,18 @@ class TorrentDetails(component.Component):
self.notebook.hide()
self.window.vpaned.set_position(-1)
self.is_visible = visible
def stop(self):
self.clear()
def update(self):
# Show tabs if more than 1 page
if self.notebook.get_n_pages() > 1:
self.notebook.set_show_tabs(True)
# Only update if this page is showing
if self.notebook.page_num(self.details_tab) is \
self.notebook.get_current_page() and \
self.notebook.get_property("visible"):
# 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", "name", "total_size", "num_files",
"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", "tracker", "next_announce",
"tracker_status", "save_path", "max_connections",
"max_upload_slots", "max_upload_speed", "max_download_speed",
"private"]
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
for widget in self.label_widgets:
if widget[1] != None:
args = []
try:
for key in widget[2]:
args.append(status[key])
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 = self.window.main_glade.get_widget("progressbar")
fraction = status["progress"] / 100
if w.get_fraction() != fraction:
w.set_fraction(fraction)
if self.notebook.get_property("visible"):
# Update the tab that is in view
self.tabs[self.notebook.get_current_page()].update()
def clear(self):
# Only update if this page is showing
if self.notebook.page_num(self.details_tab) is \
self.notebook.get_current_page():
self.tabs[self.notebook.get_current_page()].clear()
def _on_switch_page(self, notebook, page, page_num):
self.tabs[page_num].update()
client.force_call(False)
for widget in self.label_widgets:
widget[0].set_text("")
self.window.main_glade.get_widget("progressbar").set_fraction(0.0)