#! /usr/bin/env python
# -*- coding: utf-8 -*-
#-----------------------------------------------------------------------------
# Name: DetailsPanel.py
# Purpose:
#
# Author: Jeremy Arendt
#
# Created: 2004/01/02
# RCS-ID: $Id: detailspanel.py,v 1.7 2005/11/30 00:57:59 inigo Exp $
# Copyright: (c) 2002
# Licence: See G3.LICENCE.TXT
#-----------------------------------------------------------------------------
import wx
import sys
import urlparse
from wxPython.wx import wxTheClipboard,wxTextDataObject
from btconfig import BTConfig
from p2pgauge import Avail_Gauge
from time import strftime,gmtime
from binascii import b2a_hex
from threading import Thread
if sys.platform == "win32":
win32_flag = True
else:
win32_flag = False
if win32_flag:
from webbrowser import open_new
else:
from leoxv import open_new
class FrozenText(wx.StaticText):
def __init__(self, parent, id, label, pos = wx.DefaultPosition,
size = wx.DefaultSize, style = 0, name = "staticText"):
wx.StaticText.__init__(self, parent, id, label, pos, size, wx.ST_NO_AUTORESIZE | style, name)
wx.EVT_ERASE_BACKGROUND(self, self.AntiFlicker)
def AntiFlicker(self, event):
pass
def TryLabel(self, value):
try:
if value.decode('latin-1') != self.GetLabel():
self.SetLabel(value.decode('latin-1'))
except UnicodeDecodeError:
pass
class TransferPanel(wx.Panel):
def __init__(self, parent, btconfig=None, images=None):
wx.Panel.__init__(self, parent, -1)
self.btconfig = btconfig
sizer = wx.FlexGridSizer(cols=1)
sizer.AddGrowableCol(0)
sizer.AddGrowableRow(1)
box1 = wx.StaticBox(self, -1, _("Transfer"))
xferboxer = wx.StaticBoxSizer(box1, wx.VERTICAL)
sizer.Add(xferboxer, 1, wx.EXPAND|wx.ALL, 2)
# XFER ---------------------------------------------------
xferflexer = wx.FlexGridSizer(cols = 4, hgap = 10, vgap = 2)
xferboxer.Add(xferflexer, 1, wx.EXPAND | wx.ALL, 2)
xlabels = [0] * 20
xlabels[0] = FrozenText(self, -1, _("Status:"))
xlabels[1] = FrozenText(self, -1, "", style = wx.ALIGN_RIGHT)
xlabels[2] = FrozenText(self, -1, _("Time left:"))
xlabels[3] = FrozenText(self, -1, "", style = wx.ALIGN_RIGHT)
xlabels[4] = FrozenText(self, -1, _("Downloaded:"))
xlabels[5] = FrozenText(self, -1, "", style = wx.ALIGN_RIGHT)
xlabels[6] = FrozenText(self, -1, _("Uploaded:"))
xlabels[7] = FrozenText(self, -1, "", style = wx.ALIGN_RIGHT)
xlabels[8] = FrozenText(self, -1, _("Down Rate:"))
xlabels[9] = FrozenText(self, -1, "", style = wx.ALIGN_RIGHT)
xlabels[10] = FrozenText(self, -1, _("Up Rate:"))
xlabels[11] = FrozenText(self, -1, "", style = wx.ALIGN_RIGHT)
xlabels[12] = FrozenText(self, -1, _("Max Up Rate:"))
xlabels[13] = FrozenText(self, -1, "", style = wx.ALIGN_RIGHT)
xlabels[14] = FrozenText(self, -1, _("Share Ratio:"))
xlabels[15] = FrozenText(self, -1, "", style = wx.ALIGN_RIGHT)
xlabels[16] = FrozenText(self, -1, _("Max Uploads:"))
xlabels[17] = FrozenText(self, -1, "", style = wx.ALIGN_RIGHT)
xlabels[18] = FrozenText(self, -1, _("Listening Port:"))
xlabels[19] = FrozenText(self, -1, "", style = wx.ALIGN_RIGHT)
for l in xlabels:
xferflexer.Add(l, 1, wx.EXPAND)
xferflexer.AddGrowableCol(1)
xferflexer.AddGrowableCol(3)
self.SetSizer(sizer)
self.Layout()
class DetailsPanel2(wx.Panel):
def __init__(self, parent, btconfig, images):
wx.Panel.__init__(self, parent, -1)
self.btconfig = btconfig
self.avail_gauge = Avail_Gauge(self, btconfig)
self.avail_gauge.SetSize((-1, 27))
tt = wx.ToolTip(_("The piece frequency graph.\n It displays the distribution of the parts of the file within a group of peers"))
self.avail_gauge.SetToolTip(tt)
tree = wx.TreeCtrl(self, -1, size = (90, -1), style = wx.TR_DEFAULT_STYLE | wx.TR_HIDE_ROOT | wx.TR_HAS_BUTTONS | wx.TR_SINGLE)
self.tree = tree
root = tree.AddRoot("root")
transfer = self.tree.AppendItem(root, "Transfer")
peers = self.tree.AppendItem(root, "Peers")
pieces = self.tree.AppendItem(root, "Pieces")
file = self.tree.AppendItem(root, "File")
tracker = self.tree.AppendItem(root, "Tracker")
tree.Expand(transfer)
tree.Expand(peers)
tree.Expand(file)
tree.SelectItem(tracker)
right_panel = TransferPanel(self)
sizer = wx.FlexGridSizer(cols=1)
sizer.AddGrowableCol(0)
sizer.AddGrowableRow(1)
colsizer = wx.FlexGridSizer(cols = 2, hgap = 2, vgap = 2)
colsizer.AddGrowableCol(1)
colsizer.AddGrowableRow(0)
colsizer.Add(tree, 1, wx.EXPAND)
colsizer.Add(right_panel, 1, wx.EXPAND)
sizer.Add(self.avail_gauge, 1, wx.EXPAND)
sizer.Add(colsizer, 1, wx.EXPAND)
self.SetSizer(sizer)
self.SetAutoLayout(True)
wx.EVT_SIZE(self, self.OnResize)
def OnResize(self, event):
self.SetSize(self.GetClientSize())
self.Layout()
def FmtFileSize(self, bytes):
if bytes > 2**30:
return '%.2f GB' % (bytes/1073741824.0)
elif bytes > 2**20:
return '%.1f MB' % (bytes/1048576.0)
elif bytes > 2**10:
return '%.1f KB' % (bytes/1024.0)
else:
return '%d B' % bytes
class DetailsPanel(wx.Panel):
def __init__(self, parent, btconfig, images):
wx.Panel.__init__(self, parent, -1)
self.btconfig = btconfig
self.hasdata = False
self.staticset = False
if win32_flag:
wx.SystemOptions.SetOptionInt("msw.staticbox.optimized-paint", 0)
self.avail_gauge = Avail_Gauge(self, btconfig)
self.avail_gauge.SetSize((-1, 27))
tt = wx.ToolTip(_("The piece frequency graph.\n It displays the distribution of the parts of the file within a group of peers"))
self.avail_gauge.SetToolTip(tt)
sizer = wx.FlexGridSizer(cols=1)
sizer.AddGrowableCol(0)
sizer.AddGrowableRow(1)
colsizer = wx.FlexGridSizer(cols = 2, hgap = 8, vgap = 2)
box1 = wx.StaticBox(self, -1, _("Transfer"))
xferboxer = wx.StaticBoxSizer(box1, wx.VERTICAL)
box2 = wx.StaticBox(self, -1, _("Peers"))
peerboxer = wx.StaticBoxSizer(box2, wx.VERTICAL)
box3 = wx.StaticBox(self, -1, _("File"))
fileboxer = wx.StaticBoxSizer(box3, wx.VERTICAL)
box4 = wx.StaticBox(self, -1, _("Torrent"))
trackerboxer = wx.StaticBoxSizer(box4, wx.VERTICAL)
# XFER ---------------------------------------------------
xferflexer = wx.FlexGridSizer(cols = 4, hgap = 10, vgap = 2)
xferboxer.Add(xferflexer, 1, wx.EXPAND | wx.ALL, 2)
xlabels = [0] * 20
xlabels[0] = FrozenText(self, -1, _("Status:"))
xlabels[1] = FrozenText(self, -1, "", style = wx.ALIGN_RIGHT)
xlabels[2] = FrozenText(self, -1, _("Time left:"))
xlabels[3] = FrozenText(self, -1, "", style = wx.ALIGN_RIGHT)
xlabels[4] = FrozenText(self, -1, _("Downloaded:"))
xlabels[5] = FrozenText(self, -1, "", style = wx.ALIGN_RIGHT)
xlabels[6] = FrozenText(self, -1, _("Uploaded:"))
xlabels[7] = FrozenText(self, -1, "", style = wx.ALIGN_RIGHT)
xlabels[8] = FrozenText(self, -1, _("Down Rate:"))
xlabels[9] = FrozenText(self, -1, "", style = wx.ALIGN_RIGHT)
xlabels[10] = FrozenText(self, -1, _("Up Rate:"))
xlabels[11] = FrozenText(self, -1, "", style = wx.ALIGN_RIGHT)
xlabels[12] = FrozenText(self, -1, _("Max Up Rate:"))
xlabels[13] = FrozenText(self, -1, "", style = wx.ALIGN_RIGHT)
xlabels[14] = FrozenText(self, -1, _("Share Ratio:"))
xlabels[15] = FrozenText(self, -1, "", style = wx.ALIGN_RIGHT)
xlabels[16] = FrozenText(self, -1, _("Max Uploads:"))
xlabels[17] = FrozenText(self, -1, "", style = wx.ALIGN_RIGHT)
xlabels[18] = FrozenText(self, -1, _("Listening Port:"))
xlabels[19] = FrozenText(self, -1, "", style = wx.ALIGN_RIGHT)
for l in xlabels:
xferflexer.Add(l, 1, wx.EXPAND)
xferflexer.AddGrowableCol(1)
xferflexer.AddGrowableCol(3)
# PEERS ---------------------------------------------------
peerflexer = wx.FlexGridSizer(cols = 4, hgap = 10, vgap = 2)
peerboxer.Add(peerflexer, 1, wx.EXPAND | wx.ALL, 2)
plabels = [0] * 22
plabels[0] = FrozenText(self, -1, _("Connections:"))
plabels[1] = FrozenText(self, -1, "", style = wx.ALIGN_RIGHT)
plabels[2] = FrozenText(self, -1, _("Seeds:"))
plabels[3] = FrozenText(self, -1, "", style = wx.ALIGN_RIGHT)
plabels[4] = FrozenText(self, -1, _("Locally Initiated:"))
plabels[5] = FrozenText(self, -1, "", style = wx.ALIGN_RIGHT)
plabels[6] = FrozenText(self, -1, _("Remotely Initiated:"))
plabels[7] = FrozenText(self, -1, "", style = wx.ALIGN_RIGHT)
plabels[8] = FrozenText(self, -1, _("Avg Up Rate:"))
plabels[9] = FrozenText(self, -1, "", style = wx.ALIGN_RIGHT)
plabels[10] = FrozenText(self, -1, _("Avg Down Rate:"))
plabels[11] = FrozenText(self, -1, "", style = wx.ALIGN_RIGHT)
plabels[12] = FrozenText(self, -1, _("Total Copies Seen:"))
plabels[13] = FrozenText(self, -1, "", style = wx.ALIGN_RIGHT)
plabels[14] = FrozenText(self, -1, _("Avg Progress:"))
plabels[15] = FrozenText(self, -1, "", style = wx.ALIGN_RIGHT)
plabels[16] = FrozenText(self, -1, _("Total Seeds:"))
plabels[17] = FrozenText(self, -1, "", style = wx.ALIGN_RIGHT)
plabels[18] = FrozenText(self, -1, _("Total Downloaded:"))
plabels[19] = FrozenText(self, -1, "", style = wx.ALIGN_RIGHT)
plabels[20] = FrozenText(self, -1, _("Total Incomplete:"))
plabels[21] = FrozenText(self, -1, "", style = wx.ALIGN_RIGHT)
for l in plabels:
peerflexer.Add(l, 1, wx.EXPAND)
peerflexer.AddGrowableCol(1)
peerflexer.AddGrowableCol(3)
# FILE ---------------------------------------------------
fileflexer = wx.FlexGridSizer(cols = 2, hgap = 10, vgap = 2)
fileboxer.Add(fileflexer, 1, wx.EXPAND | wx.ALL, 2)
flabels = [0] * 10
flabels[0] = FrozenText(self, -1, _("Filename:"))
flabels[1] = FrozenText(self, -1, "", style = wx.ALIGN_RIGHT)
flabels[2] = FrozenText(self, -1, _("Filesize:"))
flabels[3] = FrozenText(self, -1, "", style = wx.ALIGN_RIGHT)
flabels[4] = FrozenText(self, -1, _("Info Hash:"))
flabels[5] = FrozenText(self, -1, "", style = wx.ALIGN_RIGHT)
flabels[6] = FrozenText(self, -1, _("Pieces:"))
flabels[7] = FrozenText(self, -1, "", style = wx.ALIGN_RIGHT)
flabels[8] = FrozenText(self, -1, _("Piece Size:"))
flabels[9] = FrozenText(self, -1, "", style = wx.ALIGN_RIGHT)
flabels[5].SetForegroundColour('NAVY')
wx.EVT_LEFT_DOWN(flabels[5], self.OnHashClick)
for l in flabels:
fileflexer.Add(l, 1, wx.EXPAND)
fileflexer.AddGrowableCol(1)
# TRACKER ---------------------------------------------------
trackerflexer = wx.FlexGridSizer(cols = 2, hgap = 10, vgap = 2)
trackerboxer.Add(trackerflexer, 1, wx.EXPAND | wx.ALL, 2)
tlabels = [0] * 8
tlabels[0] = FrozenText(self, -1, _("Tracker URL:"))
tlabels[1] = FrozenText(self, -1, "", style = wx.ALIGN_RIGHT)
tlabels[2] = FrozenText(self, -1, _("Creation Date:"))
tlabels[3] = FrozenText(self, -1, "", style = wx.ALIGN_RIGHT)
tlabels[4] = FrozenText(self, -1, _("Comment:"))
tlabels[5] = FrozenText(self, -1, "", style = wx.ALIGN_RIGHT)
tlabels[6] = FrozenText(self, -1, _("My Peer ID:"))
tlabels[7] = FrozenText(self, -1, "", style = wx.ALIGN_RIGHT)
tlabels[1].SetForegroundColour('Blue')
wx.EVT_LEFT_DOWN(tlabels[1], self.OnUrlClick)
for l in tlabels:
trackerflexer.Add(l, 1, wx.EXPAND)
trackerflexer.AddGrowableCol(1)
# END LABEL HURRICANE-----------------------------------------
self.xlabels = xlabels
self.flabels = flabels
self.plabels = plabels
self.tlabels = tlabels
colsizer.Add(xferboxer, 1, wx.EXPAND)
colsizer.Add(peerboxer, 1, wx.EXPAND)
colsizer.Add(fileboxer, 1, wx.EXPAND)
colsizer.Add(trackerboxer, 1, wx.EXPAND)
colsizer.AddGrowableCol(0)
colsizer.AddGrowableCol(1)
colsizer.AddGrowableRow(0)
colsizer.AddGrowableRow(1)
sizer.Add(self.avail_gauge, 1, wx.EXPAND)
sizer.Add(colsizer, 1, wx.EXPAND | wx.ALL, 2)
self.SetSizer(sizer)
self.SetAutoLayout(True)
def FmtFileSize(self, bytes):
if bytes > 2**30:
return '%.2f GB' % (bytes/1073741824.0)
elif bytes > 2**20:
return '%.1f MB' % (bytes/1048576.0)
elif bytes > 2**10:
return '%.1f KB' % (bytes/1024.0)
else:
return '%d B' % bytes
def Clear(self):
if self.hasdata:
self.avail_gauge.SetValue(0, [])
for i in range(1, len(self.xlabels), 2):
self.xlabels[i].SetLabel("")
for i in range(1, len(self.plabels), 2):
self.plabels[i].SetLabel("")
for i in range(1, len(self.flabels), 2):
self.flabels[i].SetLabel("")
for i in range(1, len(self.tlabels), 2):
self.tlabels[i].SetLabel("")
self.hasdata = False
# d: dynamic session data. s: static session data
def Update(self, btsession):
d = btsession.GetStatusData()
s = btsession.GetStaticData()
if d == None or len(d) == 0 or s == None or len(s) == 0:
return
if not btsession.IsRunning():
if self.hasdata:
self.avail_gauge.SetValue(0, [])
for i in range(1, len(self.xlabels), 2):
self.xlabels[i].SetLabel("")
for i in range(1, len(self.plabels), 2):
self.plabels[i].SetLabel("")
for i in range(1, len(self.flabels), 2):
self.flabels[i].SetLabel("")
for i in range(1, len(self.tlabels), 2):
self.tlabels[i].SetLabel("")
self.hasdata = False
return
announce, creation_date, comment, info_hash = [''] * 4
activity, dtotal, utotal, drate, urate, seeds, peers = [''] * 7
local, remote, avg_urate, avg_drate, filename, filesize = [''] * 6
peer_id , listen_port, piecesize = [''] * 3
# S section
if s['announce'] != None:
announce = s['announce']
if s['creation_date'] != None:
t = gmtime(int(s['creation_date']))
creation_date = strftime("%b %d, %Y", t)
if s['comment'] != None:
comment = str(s['comment'])
if s['info_hash'] != None:
info_hash = b2a_hex(s['info_hash'])
info_hash = info_hash.upper()
if s['nhashes'] != None:
nhashes = str( s['nhashes'] )
if s['filename'] != None:
filename = s['filename']
if s['filesize'] != None:
filesize = "%.1f MB" % (float(s['filesize'] ) / 1048576)
if s['peer_id'] != None:
peer_id = b2a_hex(s['peer_id'])
peer_id = peer_id.upper()
if s['listen_port'] != None:
listen_port = str(s['listen_port'])
if s['piecesize'] != None:
x = s['piecesize']
if x < 1048576:
piecesize = "%s KB" % str(x/1024)
elif x < 1073741824:
piecesize = "%s MB" % str(x/1048576)
else: #gigabyte sized pieces should never happen...
piecesize = "%s GB" % str(x/1073741824)
# D section
if d['timeleft'] == None or d['timeleft'] == -1:
timeleft = ''
else:
if d['timeleft'] < 86400:
t = gmtime(int(d['timeleft']))
timeleft = strftime("%H:%M:%S", t)
else:
timeleft = "%.1f Days" % (float(d['timeleft']) / 86400)
if btsession.IsChecking():
activity = 'Checking'
elif btsession.IsComplete() and btsession.IsPaused():
activity = 'Complete'
elif btsession.IsComplete():
activity = 'Seeding'
elif btsession.IsStopped():
activity = 'Stopped'
elif btsession.IsPaused():
activity = 'Paused'
else:
activity = 'Downloading'
if d['utotal'] != None:
utotal = self.FmtFileSize(d['utotal'])
if d['dtotal'] != None:
dtotal = self.FmtFileSize(d['dtotal'])
if d['fractionDone'] != None:
fractionDone = str(round(d['fractionDone']*100, 2))
if d['urate'] != None:
urate = "%.1f KB/s" % (float(d['urate']) / 1024 )
if d['drate'] != None:
drate = "%.1f KB/s" % (float(d['drate']) / 1024 )
if d['peers'] != None:
peers = str( d['peers'] )
if d['seeds'] != None:
seeds = str( d['seeds'] )
if d['avg_progress']:
avg_progress = "%d%s" % (int(d['avg_progress'] * 100), '%')
else:
avg_progress = "0"
if d['dist_copies']:
dist_copies = "%0.2f" % d['dist_copies']
else:
dist_copies = "0"
try:
if d['utotal'] > 0 and d['dtotal'] > 0:
share_ratio = "%0.2f" % ((float(d['utotal'])+1) / (float(d['dtotal'])+1))
else:
share_ratio = "0"
except ZeroDivisionError:
share_ratio = "0"
spew = d['spew']
nlocal = 0
nremote = 0
navg_urate = 0.0
navg_drate = 0.0
nuploaders = 0
ndownloders = 0
# from cfg
cfg = btsession.GetCfg()
max_urate = "%dKB/s" % cfg.Get('maxupspeed')
max_uploads = "%d" % cfg.Get('maxuploads')
# from scrape
scrape = btsession.GetScrapeData()
scrape_seeds = ""
scrape_incomplete = ""
scrape_downloaded = ""
if scrape:
if scrape.get('complete') != None:
scrape_seeds = "%d" % scrape.get('complete')
if scrape.get('incomplete') != None:
scrape_incomplete = "%d" % scrape.get('incomplete')
if scrape.get('downloaded') != None:
scrape_downloaded = "%d" % scrape.get('downloaded')
# from spew
if spew != None and len(spew) > 0:
for c in spew:
if c['initiation'] == 'Local':
nlocal += 1
else:
nremote += 1
if (float(c['upload'][0]) / 1024) > 0.1:
navg_urate += float(c['upload'][0]) / 1024
nuploaders += 1
if (float(c['download'][0]) / 1024) > 0.1:
navg_drate += float(c['download'][0]) / 1024
ndownloders += 1
try:
if nuploaders > 0:
navg_urate = navg_urate / nuploaders
if ndownloders > 0:
navg_drate = navg_drate / ndownloders
except ZeroDivisionError:
pass
local = str(nlocal)
remote = str(nremote)
avg_urate = "%.1f KB/s" % navg_urate
avg_drate = "%.1f KB/s" % navg_drate
xlabels = self.xlabels
flabels = self.flabels
plabels = self.plabels
tlabels = self.tlabels
# xfer
xlabels[1].TryLabel( activity ) #Status
xlabels[3].TryLabel( timeleft ) #ETL
xlabels[5].TryLabel( dtotal ) #Downloaded
xlabels[7].TryLabel( utotal ) #Uploaded
xlabels[9].TryLabel( drate ) #Download Rate
xlabels[11].TryLabel( urate ) #Upload Rate
xlabels[13].TryLabel( max_urate ) #Max Urate
xlabels[15].TryLabel( share_ratio ) #Share Ratio
xlabels[17].TryLabel( max_uploads ) #Max Uploads
xlabels[19].TryLabel( listen_port ) #Listening Port
# peer
plabels[1].TryLabel( peers ) #Connections
plabels[3].TryLabel( seeds ) #Seeds
plabels[5].TryLabel( local ) #Local
plabels[7].TryLabel( remote ) #Remote
plabels[9].TryLabel( avg_urate ) #Avg urate
plabels[11].TryLabel( avg_drate ) #Avg drate
plabels[13].TryLabel( dist_copies ) #Seen Copies
plabels[15].TryLabel( avg_progress ) #Avg progress
plabels[17].TryLabel( scrape_seeds ) #scrape seeds
plabels[19].TryLabel( scrape_downloaded ) #scrape downloaded
plabels[21].TryLabel( scrape_incomplete ) #scrape incomplete
#Checks to see if the static data has already been drawn
if not self.staticset:
# file
flabels[1].SetLabel( filename ) #Filename
flabels[3].TryLabel( filesize ) #Filesize
flabels[5].TryLabel( info_hash ) #Hash
flabels[7].TryLabel( nhashes ) #Pieces
flabels[9].TryLabel( piecesize ) #Piece size
# tracker
tlabels[1].TryLabel( announce ) #Announce
tlabels[3].TryLabel( creation_date ) #Creation Date
tlabels[5].TryLabel( comment ) #Comment
tlabels[7].TryLabel( peer_id ) #PeerID
self.staticset = True
self.avail_gauge.SetValue(d['avg_progress'], d['availlist'])
self.hasdata = True
def _OpenUrl(self, url):
try:
open_new(url)
except:
pass
def OnUrlClick(self, event):
url = self.tlabels[1].GetLabel()
url = "http://%s/" % (urlparse.urlparse(url)[1])
Thread(target = self._OpenUrl, args = [url]).start()
def OnHashClick(self, event):
clipdata = wxTextDataObject()
clipdata.SetText(self.flabels[5].GetLabel())
wxTheClipboard.Open()
wxTheClipboard.SetData(clipdata)
wxTheClipboard.Close()
if __name__ == "__main__":
_ = lambda x: x # needed for gettext
app = wx.PySimpleApp()
frame = wx.Frame(None, -1, '')
ppp = DetailsPanel(frame, BTConfig(), None)
ppp.Show(True)
frame.Show(True)
app.MainLoop()
|