mirror of
https://git.deluge-torrent.org/deluge
synced 2025-08-09 18:08:39 +00:00
[GTKUI] Reorganise layout of tab items and add Tracker tab
* Changed layout of Status, Details and Options tabs. * Moved the Tracker translations to ui.common. * Created a new Trackers tab. * Added State to progressbar. * Translate State in piecesbar.
This commit is contained in:
parent
14776d86f5
commit
6496383e82
8 changed files with 1462 additions and 1424 deletions
|
@ -39,10 +39,7 @@ all the interfaces.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import sys
|
|
||||||
import logging
|
import logging
|
||||||
import urlparse
|
|
||||||
import locale
|
|
||||||
from hashlib import sha1 as sha
|
from hashlib import sha1 as sha
|
||||||
|
|
||||||
from deluge import bencode
|
from deluge import bencode
|
||||||
|
@ -51,10 +48,12 @@ import deluge.configmanager
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
# Dummy tranlation dict so Torrent states text is available for Translators
|
# Dummy tranlation dict so Torrent states text is available for Translators
|
||||||
# All entries in deluge.common.TORRENT_STATE should be here. It does not need importing
|
# All entries in deluge.common.TORRENT_STATE should be here. It does not need importing
|
||||||
# as the string matches the translation text so using the _() function is enough.
|
# as the string matches the translation text so using the _() function is enough.
|
||||||
def _(message): return message
|
def _(message):
|
||||||
|
return message
|
||||||
STATE_TRANSLATION = {
|
STATE_TRANSLATION = {
|
||||||
"All": _("All"),
|
"All": _("All"),
|
||||||
"Active": _("Active"),
|
"Active": _("Active"),
|
||||||
|
@ -67,8 +66,16 @@ STATE_TRANSLATION = {
|
||||||
"Queued": _("Queued"),
|
"Queued": _("Queued"),
|
||||||
"Error": _("Error"),
|
"Error": _("Error"),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TRACKER_STATUS_TRANSLATION = {
|
||||||
|
"Error": _("Error"),
|
||||||
|
"Warning": _("Warning"),
|
||||||
|
"Announce OK": _("Announce OK"),
|
||||||
|
"Announce Sent": _("Announce Sent")
|
||||||
|
}
|
||||||
del _
|
del _
|
||||||
|
|
||||||
|
|
||||||
class TorrentInfo(object):
|
class TorrentInfo(object):
|
||||||
"""
|
"""
|
||||||
Collects information about a torrent file.
|
Collects information about a torrent file.
|
||||||
|
|
|
@ -21,11 +21,11 @@ def fpeer_size_second(first, second):
|
||||||
|
|
||||||
|
|
||||||
def fdate_blank(value):
|
def fdate_blank(value):
|
||||||
"""Display value as date, eg 05/05/08 or blank"""
|
"""Display value as date, eg 05/05/08 or dash"""
|
||||||
if value > 0.0:
|
if value > 0.0:
|
||||||
return fdate(value)
|
return fdate(value)
|
||||||
else:
|
else:
|
||||||
return ""
|
return "-"
|
||||||
|
|
||||||
|
|
||||||
def str_yes_no(value):
|
def str_yes_no(value):
|
||||||
|
@ -59,25 +59,22 @@ class DetailsTab(Tab):
|
||||||
(builder.get_object("summary_pieces"), fpeer_size_second, ("num_pieces", "piece_length")),
|
(builder.get_object("summary_pieces"), fpeer_size_second, ("num_pieces", "piece_length")),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
self.status_keys = [status for widget in self.label_widgets for status in widget[2]]
|
||||||
|
|
||||||
def update(self):
|
def update(self):
|
||||||
# Get the first selected torrent
|
# Get the first selected torrent
|
||||||
selected = component.get("TorrentView").get_selected_torrents()
|
selected = component.get("TorrentView").get_selected_torrents()
|
||||||
|
|
||||||
# Only use the first torrent in the list or return if None selected
|
# Only use the first torrent in the list or return if None selected
|
||||||
if len(selected) != 0:
|
if selected:
|
||||||
selected = selected[0]
|
selected = selected[0]
|
||||||
else:
|
else:
|
||||||
# No torrent is selected in the torrentview
|
# No torrent is selected in the torrentview
|
||||||
self.clear()
|
self.clear()
|
||||||
return
|
return
|
||||||
|
|
||||||
# Get the torrent status
|
|
||||||
status_keys = ["name", "total_size", "num_files", "time_added", "completed_time",
|
|
||||||
"download_location", "hash", "comment", "owner", "num_pieces", "piece_length",
|
|
||||||
"shared", "private"]
|
|
||||||
|
|
||||||
session = component.get("SessionProxy")
|
session = component.get("SessionProxy")
|
||||||
session.get_torrent_status(selected, status_keys).addCallback(self._on_get_torrent_status)
|
session.get_torrent_status(selected, self.status_keys).addCallback(self._on_get_torrent_status)
|
||||||
|
|
||||||
def _on_get_torrent_status(self, status):
|
def _on_get_torrent_status(self, status):
|
||||||
# Check to see if we got valid data from the core
|
# Check to see if we got valid data from the core
|
||||||
|
@ -87,14 +84,11 @@ class DetailsTab(Tab):
|
||||||
# Update all the label widgets
|
# Update all the label widgets
|
||||||
for widget in self.label_widgets:
|
for widget in self.label_widgets:
|
||||||
if widget[1] is not None:
|
if widget[1] is not None:
|
||||||
args = []
|
|
||||||
try:
|
try:
|
||||||
for key in widget[2]:
|
args = [status[key] for key in widget[2]]
|
||||||
args.append(status[key])
|
except KeyError, ex:
|
||||||
except Exception, e:
|
log.debug("Unable to get status value: %s", ex)
|
||||||
log.debug("Unable to get status value: %s", e)
|
|
||||||
continue
|
continue
|
||||||
|
|
||||||
txt = widget[1](*args)
|
txt = widget[1](*args)
|
||||||
else:
|
else:
|
||||||
txt = status[widget[2][0]]
|
txt = status[widget[2][0]]
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -77,7 +77,6 @@ class OptionsTab(Tab):
|
||||||
|
|
||||||
component.get("MainWindow").connect_signals({
|
component.get("MainWindow").connect_signals({
|
||||||
"on_button_apply_clicked": self._on_button_apply_clicked,
|
"on_button_apply_clicked": self._on_button_apply_clicked,
|
||||||
"on_button_edit_trackers_clicked": self._on_button_edit_trackers_clicked,
|
|
||||||
"on_chk_move_completed_toggled": self._on_chk_move_completed_toggled,
|
"on_chk_move_completed_toggled": self._on_chk_move_completed_toggled,
|
||||||
"on_chk_stop_at_ratio_toggled": self._on_chk_stop_at_ratio_toggled,
|
"on_chk_stop_at_ratio_toggled": self._on_chk_stop_at_ratio_toggled,
|
||||||
"on_chk_toggled": self._on_chk_toggled,
|
"on_chk_toggled": self._on_chk_toggled,
|
||||||
|
@ -102,7 +101,7 @@ class OptionsTab(Tab):
|
||||||
torrent_id = component.get("TorrentView").get_selected_torrents()
|
torrent_id = component.get("TorrentView").get_selected_torrents()
|
||||||
|
|
||||||
# Only use the first torrent in the list or return if None selected
|
# Only use the first torrent in the list or return if None selected
|
||||||
if len(torrent_id) != 0:
|
if torrent_id:
|
||||||
torrent_id = torrent_id[0]
|
torrent_id = torrent_id[0]
|
||||||
self._child_widget.set_sensitive(True)
|
self._child_widget.set_sensitive(True)
|
||||||
else:
|
else:
|
||||||
|
@ -250,17 +249,6 @@ class OptionsTab(Tab):
|
||||||
)
|
)
|
||||||
self.button_apply.set_sensitive(False)
|
self.button_apply.set_sensitive(False)
|
||||||
|
|
||||||
def _on_button_edit_trackers_clicked(self, button):
|
|
||||||
from edittrackersdialog import EditTrackersDialog
|
|
||||||
dialog = EditTrackersDialog(
|
|
||||||
self.prev_torrent_id,
|
|
||||||
component.get("MainWindow").window)
|
|
||||||
|
|
||||||
def on_response(result):
|
|
||||||
if result:
|
|
||||||
self.button_apply.set_sensitive(True)
|
|
||||||
dialog.run().addCallback(on_response)
|
|
||||||
|
|
||||||
def _on_chk_move_completed_toggled(self, widget):
|
def _on_chk_move_completed_toggled(self, widget):
|
||||||
value = self.chk_move_completed.get_active()
|
value = self.chk_move_completed.get_active()
|
||||||
self.move_completed_path_chooser.set_sensitive(value)
|
self.move_completed_path_chooser.set_sensitive(value)
|
||||||
|
|
|
@ -52,6 +52,7 @@ COLOR_STATES = {
|
||||||
3: "completed"
|
3: "completed"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class PiecesBar(gtk.DrawingArea):
|
class PiecesBar(gtk.DrawingArea):
|
||||||
# Draw in response to an expose-event
|
# Draw in response to an expose-event
|
||||||
__gsignals__ = {"expose-event": "override"}
|
__gsignals__ = {"expose-event": "override"}
|
||||||
|
@ -141,7 +142,7 @@ class PiecesBar(gtk.DrawingArea):
|
||||||
|
|
||||||
def __draw_pieces(self):
|
def __draw_pieces(self):
|
||||||
if (self.__resized() or self.__pieces != self.__old_pieces or
|
if (self.__resized() or self.__pieces != self.__old_pieces or
|
||||||
self.__pieces_overlay == None):
|
self.__pieces_overlay is None):
|
||||||
# Need to recreate the cache drawing
|
# Need to recreate the cache drawing
|
||||||
self.__pieces_overlay = cairo.ImageSurface(
|
self.__pieces_overlay = cairo.ImageSurface(
|
||||||
cairo.FORMAT_ARGB32, self.__width, self.__height
|
cairo.FORMAT_ARGB32, self.__width, self.__height
|
||||||
|
@ -194,8 +195,7 @@ class PiecesBar(gtk.DrawingArea):
|
||||||
if not self.__state:
|
if not self.__state:
|
||||||
# Nothing useful to draw, return now!
|
# Nothing useful to draw, return now!
|
||||||
return
|
return
|
||||||
if (self.__resized() or self.__fraction != self.__old_fraction) or \
|
if (self.__resized() or self.__fraction != self.__old_fraction) or self.__progress_overlay is None:
|
||||||
self.__progress_overlay is None:
|
|
||||||
# Need to recreate the cache drawing
|
# Need to recreate the cache drawing
|
||||||
self.__progress_overlay = cairo.ImageSurface(
|
self.__progress_overlay = cairo.ImageSurface(
|
||||||
cairo.FORMAT_ARGB32, self.__width, self.__height
|
cairo.FORMAT_ARGB32, self.__width, self.__height
|
||||||
|
@ -230,7 +230,7 @@ class PiecesBar(gtk.DrawingArea):
|
||||||
text += self.__text
|
text += self.__text
|
||||||
else:
|
else:
|
||||||
if self.__state:
|
if self.__state:
|
||||||
text += self.__state + " "
|
text += _(self.__state) + " "
|
||||||
if self.__fraction == 1.0:
|
if self.__fraction == 1.0:
|
||||||
format = "%d%%"
|
format = "%d%%"
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -55,8 +55,10 @@ def fratio(value):
|
||||||
return "%.3f" % value
|
return "%.3f" % value
|
||||||
|
|
||||||
|
|
||||||
def fpcnt(value):
|
def fpcnt(value, state):
|
||||||
return "%.2f%%" % value
|
if state:
|
||||||
|
state = _(state) + " "
|
||||||
|
return "%s%.2f%%" % (state, value)
|
||||||
|
|
||||||
|
|
||||||
def fspeed(value, max_value=-1):
|
def fspeed(value, max_value=-1):
|
||||||
|
@ -102,40 +104,32 @@ class StatusTab(Tab):
|
||||||
(builder.get_object("summary_peers"), deluge.common.fpeer, ("num_peers", "total_peers")),
|
(builder.get_object("summary_peers"), deluge.common.fpeer, ("num_peers", "total_peers")),
|
||||||
(builder.get_object("summary_eta"), deluge.common.ftime, ("eta",)),
|
(builder.get_object("summary_eta"), deluge.common.ftime, ("eta",)),
|
||||||
(builder.get_object("summary_share_ratio"), fratio, ("ratio",)),
|
(builder.get_object("summary_share_ratio"), fratio, ("ratio",)),
|
||||||
(builder.get_object("summary_tracker_status"), None, ("tracker_status",)),
|
|
||||||
(builder.get_object("summary_next_announce"), deluge.common.ftime, ("next_announce",)),
|
|
||||||
(builder.get_object("summary_active_time"), deluge.common.ftime, ("active_time",)),
|
(builder.get_object("summary_active_time"), deluge.common.ftime, ("active_time",)),
|
||||||
(builder.get_object("summary_seed_time"), deluge.common.ftime, ("seeding_time",)),
|
(builder.get_object("summary_seed_time"), deluge.common.ftime, ("seeding_time",)),
|
||||||
(builder.get_object("summary_seed_rank"), str, ("seed_rank",)),
|
(builder.get_object("summary_seed_rank"), str, ("seed_rank",)),
|
||||||
(builder.get_object("summary_auto_managed"), str, ("is_auto_managed",)),
|
(builder.get_object("progressbar"), fpcnt, ("progress", "state")),
|
||||||
(builder.get_object("progressbar"), fpcnt, ("progress",)),
|
|
||||||
(builder.get_object("summary_last_seen_complete"), fdate_or_never, ("last_seen_complete",)),
|
(builder.get_object("summary_last_seen_complete"), fdate_or_never, ("last_seen_complete",)),
|
||||||
(builder.get_object("summary_torrent_status"), str, ("message",)),
|
(builder.get_object("summary_torrent_status"), str, ("message",)),
|
||||||
(builder.get_object("summary_tracker"), None, ("tracker_host",)),
|
|
||||||
]
|
]
|
||||||
|
|
||||||
|
self.status_keys = [status for widget in self.label_widgets for status in widget[2]]
|
||||||
|
|
||||||
def update(self):
|
def update(self):
|
||||||
# Get the first selected torrent
|
# Get the first selected torrent
|
||||||
selected = component.get("TorrentView").get_selected_torrents()
|
selected = component.get("TorrentView").get_selected_torrents()
|
||||||
|
|
||||||
# Only use the first torrent in the list or return if None selected
|
# Only use the first torrent in the list or return if None selected
|
||||||
if len(selected) != 0:
|
if selected:
|
||||||
selected = selected[0]
|
selected = selected[0]
|
||||||
else:
|
else:
|
||||||
# No torrent is selected in the torrentview
|
# No torrent is selected in the torrentview
|
||||||
|
self.clear()
|
||||||
return
|
return
|
||||||
|
|
||||||
# Get the torrent status
|
# Get the torrent status
|
||||||
status_keys = [
|
status_keys = self.status_keys
|
||||||
"distributed_copies", "all_time_download", "total_payload_download",
|
|
||||||
"total_uploaded", "total_payload_upload", "download_payload_rate", "max_download_speed",
|
|
||||||
"upload_payload_rate", "max_upload_speed", "num_peers", "num_seeds", "total_peers",
|
|
||||||
"total_seeds", "eta", "ratio", "tracker_status", "next_announce", "active_time",
|
|
||||||
"seeding_time", "seed_rank", "is_auto_managed", "progress", "last_seen_complete",
|
|
||||||
"message", "tracker_host"
|
|
||||||
]
|
|
||||||
if self.config['show_piecesbar']:
|
if self.config['show_piecesbar']:
|
||||||
status_keys.extend(["pieces", "state", "num_pieces"])
|
status_keys = self.status_keys + ["pieces", "num_pieces"]
|
||||||
|
|
||||||
component.get("SessionProxy").get_torrent_status(
|
component.get("SessionProxy").get_torrent_status(
|
||||||
selected, status_keys).addCallback(self._on_get_torrent_status)
|
selected, status_keys).addCallback(self._on_get_torrent_status)
|
||||||
|
@ -145,33 +139,14 @@ class StatusTab(Tab):
|
||||||
if status is None:
|
if status is None:
|
||||||
return
|
return
|
||||||
|
|
||||||
if status["is_auto_managed"]:
|
|
||||||
status["is_auto_managed"] = _("On")
|
|
||||||
else:
|
|
||||||
status["is_auto_managed"] = _("Off")
|
|
||||||
|
|
||||||
translate_tracker_status = {
|
|
||||||
"Error": _("Error"),
|
|
||||||
"Warning": _("Warning"),
|
|
||||||
"Announce OK": _("Announce OK"),
|
|
||||||
"Announce Sent": _("Announce Sent")
|
|
||||||
}
|
|
||||||
for key, value in translate_tracker_status.iteritems():
|
|
||||||
if key in status["tracker_status"]:
|
|
||||||
status["tracker_status"] = status["tracker_status"].replace(key, value, 1)
|
|
||||||
break
|
|
||||||
|
|
||||||
# Update all the label widgets
|
# Update all the label widgets
|
||||||
for widget in self.label_widgets:
|
for widget in self.label_widgets:
|
||||||
if widget[1] is not None:
|
if widget[1] is not None:
|
||||||
args = []
|
|
||||||
try:
|
try:
|
||||||
for key in widget[2]:
|
args = [status[key] for key in widget[2]]
|
||||||
args.append(status[key])
|
except KeyError, ex:
|
||||||
except Exception, e:
|
log.debug("Unable to get status value: %s", ex)
|
||||||
log.debug("Unable to get status value: %s", e)
|
|
||||||
continue
|
continue
|
||||||
|
|
||||||
txt = widget[1](*args)
|
txt = widget[1](*args)
|
||||||
else:
|
else:
|
||||||
txt = status[widget[2][0]]
|
txt = status[widget[2][0]]
|
||||||
|
@ -202,7 +177,7 @@ class StatusTab(Tab):
|
||||||
if show:
|
if show:
|
||||||
self.piecesbar = PiecesBar()
|
self.piecesbar = PiecesBar()
|
||||||
self.builder.get_object("status_progress_vbox").pack_start(
|
self.builder.get_object("status_progress_vbox").pack_start(
|
||||||
self.piecesbar, False, False, 5
|
self.piecesbar, False, False, 0
|
||||||
)
|
)
|
||||||
self.progressbar.hide()
|
self.progressbar.hide()
|
||||||
|
|
||||||
|
|
|
@ -1,36 +1,10 @@
|
||||||
#
|
# -*- coding: utf-8 -*-
|
||||||
# torrentdetails.py
|
|
||||||
#
|
#
|
||||||
# Copyright (C) 2007 Andrew Resch <andrewresch@gmail.com>
|
# Copyright (C) 2007 Andrew Resch <andrewresch@gmail.com>
|
||||||
#
|
#
|
||||||
# Deluge is free software.
|
# This file is part of Deluge and is licensed under GNU General Public License 3.0, or later, with
|
||||||
#
|
# the additional special exception to link portions of this program with the OpenSSL library.
|
||||||
# You may redistribute it and/or modify it under the terms of the
|
# See LICENSE for more details.
|
||||||
# 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.
|
|
||||||
#
|
|
||||||
#
|
#
|
||||||
|
|
||||||
|
|
||||||
|
@ -45,6 +19,7 @@ from deluge.ui.gtkui.common import save_pickled_state_file, load_pickled_state_f
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class Tab:
|
class Tab:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.is_visible = True
|
self.is_visible = True
|
||||||
|
@ -69,6 +44,7 @@ class Tab:
|
||||||
|
|
||||||
return self._tab_label
|
return self._tab_label
|
||||||
|
|
||||||
|
|
||||||
class TorrentDetails(component.Component):
|
class TorrentDetails(component.Component):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
component.Component.__init__(self, "TorrentDetails", interval=2)
|
component.Component.__init__(self, "TorrentDetails", interval=2)
|
||||||
|
@ -91,13 +67,15 @@ class TorrentDetails(component.Component):
|
||||||
from files_tab import FilesTab
|
from files_tab import FilesTab
|
||||||
from peers_tab import PeersTab
|
from peers_tab import PeersTab
|
||||||
from options_tab import OptionsTab
|
from options_tab import OptionsTab
|
||||||
|
from trackers_tab import TrackersTab
|
||||||
|
|
||||||
default_tabs = {
|
default_tabs = {
|
||||||
"Status": StatusTab,
|
"Status": StatusTab,
|
||||||
"Details": DetailsTab,
|
"Details": DetailsTab,
|
||||||
"Files": FilesTab,
|
"Files": FilesTab,
|
||||||
"Peers": PeersTab,
|
"Peers": PeersTab,
|
||||||
"Options": OptionsTab
|
"Options": OptionsTab,
|
||||||
|
"Trackers": TrackersTab
|
||||||
}
|
}
|
||||||
|
|
||||||
# tab_name, visible
|
# tab_name, visible
|
||||||
|
@ -106,7 +84,8 @@ class TorrentDetails(component.Component):
|
||||||
("Details", True),
|
("Details", True),
|
||||||
("Files", True),
|
("Files", True),
|
||||||
("Peers", True),
|
("Peers", True),
|
||||||
("Options", True)
|
("Options", True),
|
||||||
|
("Trackers", True)
|
||||||
]
|
]
|
||||||
|
|
||||||
self.translate_tabs = {
|
self.translate_tabs = {
|
||||||
|
@ -115,7 +94,8 @@ class TorrentDetails(component.Component):
|
||||||
"Details": _("_Details"),
|
"Details": _("_Details"),
|
||||||
"Files": _("_Files"),
|
"Files": _("_Files"),
|
||||||
"Peers": _("_Peers"),
|
"Peers": _("_Peers"),
|
||||||
"Options" : _("_Options")
|
"Options": _("_Options"),
|
||||||
|
"Trackers": _("_Trackers")
|
||||||
}
|
}
|
||||||
|
|
||||||
# Get the state from saved file
|
# Get the state from saved file
|
||||||
|
@ -129,13 +109,12 @@ class TorrentDetails(component.Component):
|
||||||
break
|
break
|
||||||
|
|
||||||
# The state is a list of tab_names in the order they should appear
|
# The state is a list of tab_names in the order they should appear
|
||||||
if state == None:
|
if state is None:
|
||||||
# Set the default order
|
# Set the default order
|
||||||
state = default_order
|
state = default_order
|
||||||
|
|
||||||
# We need to rename the tab in the state for backwards compat
|
# We need to rename the tab in the state for backwards compat
|
||||||
self.state = [(tab_name.replace("Statistics", "Status"), visible) for
|
self.state = [(tab_name.replace("Statistics", "Status"), visible) for tab_name, visible in state]
|
||||||
tab_name, visible in state]
|
|
||||||
|
|
||||||
for tab in default_tabs.itervalues():
|
for tab in default_tabs.itervalues():
|
||||||
self.add_tab(tab(), generate_menu=False)
|
self.add_tab(tab(), generate_menu=False)
|
||||||
|
@ -162,7 +141,6 @@ class TorrentDetails(component.Component):
|
||||||
break
|
break
|
||||||
return position
|
return position
|
||||||
|
|
||||||
|
|
||||||
def add_tab(self, tab, generate_menu=True, visible=None):
|
def add_tab(self, tab, generate_menu=True, visible=None):
|
||||||
name = tab.get_name()
|
name = tab.get_name()
|
||||||
|
|
||||||
|
@ -208,10 +186,8 @@ class TorrentDetails(component.Component):
|
||||||
if generate_menu:
|
if generate_menu:
|
||||||
self.generate_menu()
|
self.generate_menu()
|
||||||
|
|
||||||
|
|
||||||
def regenerate_positions(self):
|
def regenerate_positions(self):
|
||||||
"""This will sync up the positions in the tab, with the position stored
|
"""Sync the positions in the tab, with the position stored in the tab object"""
|
||||||
in the tab object"""
|
|
||||||
for tab in self.tabs:
|
for tab in self.tabs:
|
||||||
page_num = self.notebook.page_num(self.tabs[tab]._child_widget)
|
page_num = self.notebook.page_num(self.tabs[tab]._child_widget)
|
||||||
if page_num > -1:
|
if page_num > -1:
|
||||||
|
@ -262,8 +238,7 @@ class TorrentDetails(component.Component):
|
||||||
|
|
||||||
def show_tab(self, tab_name, generate_menu=True):
|
def show_tab(self, tab_name, generate_menu=True):
|
||||||
log.debug("%s\n%s\n%s", self.tabs[tab_name].get_child_widget(),
|
log.debug("%s\n%s\n%s", self.tabs[tab_name].get_child_widget(),
|
||||||
self.tabs[tab_name].get_tab_label(),
|
self.tabs[tab_name].get_tab_label(), self.tabs[tab_name].position)
|
||||||
self.tabs[tab_name].position)
|
|
||||||
|
|
||||||
position = self.tab_insert_position(self.tabs[tab_name].weight)
|
position = self.tab_insert_position(self.tabs[tab_name].weight)
|
||||||
|
|
||||||
|
@ -344,7 +319,6 @@ class TorrentDetails(component.Component):
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
def shutdown(self):
|
def shutdown(self):
|
||||||
# Save the state of the tabs
|
# Save the state of the tabs
|
||||||
for tab in self.tabs:
|
for tab in self.tabs:
|
||||||
|
@ -362,7 +336,7 @@ class TorrentDetails(component.Component):
|
||||||
self.clear()
|
self.clear()
|
||||||
|
|
||||||
if self.notebook.get_property("visible"):
|
if self.notebook.get_property("visible"):
|
||||||
if page_num == None:
|
if page_num is None:
|
||||||
page_num = self.notebook.get_current_page()
|
page_num = self.notebook.get_current_page()
|
||||||
try:
|
try:
|
||||||
# Get the tab name
|
# Get the tab name
|
||||||
|
|
96
deluge/ui/gtkui/trackers_tab.py
Normal file
96
deluge/ui/gtkui/trackers_tab.py
Normal file
|
@ -0,0 +1,96 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
# Copyright (C) 2008 Andrew Resch <andrewresch@gmail.com>
|
||||||
|
#
|
||||||
|
# This file is part of Deluge and is licensed under GNU General Public License 3.0, or later, with
|
||||||
|
# the additional special exception to link portions of this program with the OpenSSL library.
|
||||||
|
# See LICENSE for more details.
|
||||||
|
#
|
||||||
|
|
||||||
|
import logging
|
||||||
|
|
||||||
|
import deluge.component as component
|
||||||
|
from deluge.common import ftime
|
||||||
|
from deluge.ui.gtkui.torrentdetails import Tab
|
||||||
|
|
||||||
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
def fcount(value):
|
||||||
|
return "%s" % len(value)
|
||||||
|
|
||||||
|
|
||||||
|
def ftranslate(text):
|
||||||
|
if text:
|
||||||
|
text = _(text)
|
||||||
|
return text
|
||||||
|
|
||||||
|
|
||||||
|
class TrackersTab(Tab):
|
||||||
|
def __init__(self):
|
||||||
|
Tab.__init__(self)
|
||||||
|
# Get the labels we need to update.
|
||||||
|
# widget name, modifier function, status keys
|
||||||
|
builder = component.get("MainWindow").get_builder()
|
||||||
|
|
||||||
|
self._name = "Trackers"
|
||||||
|
self._child_widget = builder.get_object("trackers_tab")
|
||||||
|
self._tab_label = builder.get_object("trackers_tab_label")
|
||||||
|
|
||||||
|
self.label_widgets = [
|
||||||
|
(builder.get_object("summary_next_announce"), ftime, ("next_announce",)),
|
||||||
|
(builder.get_object("summary_tracker"), None, ("tracker_host",)),
|
||||||
|
(builder.get_object("summary_tracker_status"), ftranslate, ("tracker_status",)),
|
||||||
|
(builder.get_object("summary_tracker_total"), fcount, ("trackers",)),
|
||||||
|
]
|
||||||
|
|
||||||
|
self.status_keys = [status for widget in self.label_widgets for status in widget[2]]
|
||||||
|
|
||||||
|
component.get("MainWindow").connect_signals({
|
||||||
|
"on_button_edit_trackers_clicked": self._on_button_edit_trackers_clicked,
|
||||||
|
})
|
||||||
|
|
||||||
|
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 selected:
|
||||||
|
selected = selected[0]
|
||||||
|
else:
|
||||||
|
self.clear()
|
||||||
|
return
|
||||||
|
|
||||||
|
session = component.get("SessionProxy")
|
||||||
|
session.get_torrent_status(selected, self.status_keys).addCallback(self._on_get_torrent_status)
|
||||||
|
|
||||||
|
def _on_get_torrent_status(self, status):
|
||||||
|
# Check to see if we got valid data from the core
|
||||||
|
if not status:
|
||||||
|
return
|
||||||
|
|
||||||
|
# Update all the label widgets
|
||||||
|
for widget in self.label_widgets:
|
||||||
|
if widget[1] is None:
|
||||||
|
txt = status[widget[2][0]]
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
args = [status[key] for key in widget[2]]
|
||||||
|
except KeyError, ex:
|
||||||
|
log.debug("Unable to get status value: %s", ex)
|
||||||
|
continue
|
||||||
|
txt = widget[1](*args)
|
||||||
|
|
||||||
|
if widget[0].get_text() != txt:
|
||||||
|
widget[0].set_text(txt)
|
||||||
|
|
||||||
|
def clear(self):
|
||||||
|
for widget in self.label_widgets:
|
||||||
|
widget[0].set_text("")
|
||||||
|
|
||||||
|
def _on_button_edit_trackers_clicked(self, button):
|
||||||
|
torrent_id = component.get("TorrentView").get_selected_torrent()
|
||||||
|
if torrent_id:
|
||||||
|
from edittrackersdialog import EditTrackersDialog
|
||||||
|
dialog = EditTrackersDialog(torrent_id, component.get("MainWindow").window)
|
||||||
|
dialog.run()
|
Loading…
Add table
Add a link
Reference in a new issue