1 theshadow 1.1 #!/usr/bin/env python
2
3 # Written by Bram Cohen and Myers Carpenter
|
4 theshadow 1.2 # Modifications by various people
|
5 theshadow 1.1 # see LICENSE.txt for license information
6
|
7 theshadow 1.41 from BitTorrent import PSYCO
|
8 theshadow 1.20 if PSYCO.psyco:
9 try:
10 import psyco
11 assert psyco.__version__ >= 0x010100f0
12 psyco.full()
13 except:
14 pass
15
|
16 theshadow 1.1 from sys import argv, version
17 assert version >= '2', "Install Python 2.0 or greater"
18
|
19 theshadow 1.32 from BitTorrent.download import Download
|
20 theshadow 1.2 from BitTorrent.ConnChoice import *
|
21 theshadow 1.35 from BitTorrent.ConfigReader import configReader
|
22 theshadow 1.36 from BitTorrent.bencode import bencode
|
23 theshadow 1.46 from threading import Event, Thread
|
24 theshadow 1.2 from os.path import *
|
25 theshadow 1.1 from os import getcwd
26 from wxPython.wx import *
|
27 theshadow 1.15 from time import strftime, time, localtime
|
28 theshadow 1.1 from webbrowser import open_new
|
29 theshadow 1.15 from traceback import print_exc
30 from StringIO import StringIO
|
31 theshadow 1.36 from sha import sha
|
32 theshadow 1.2 import re
|
33 theshadow 1.4 import sys, os
|
34 theshadow 1.6 from BitTorrent import version
|
35 theshadow 1.13
|
36 theshadow 1.2 true = 1
37 false = 0
|
38 theshadow 1.1
|
39 theshadow 1.11 PROFILER = false
40
|
41 theshadow 1.4 basepath=os.path.abspath(os.path.dirname(sys.argv[0]))
42
|
43 theshadow 1.1 def hours(n):
44 if n == -1:
45 return '<unknown>'
46 if n == 0:
47 return 'complete!'
48 n = int(n)
49 h, r = divmod(n, 60 * 60)
50 m, sec = divmod(r, 60)
51 if h > 1000000:
52 return '<unknown>'
53 if h > 0:
|
54 theshadow 1.3 return '%d hour(s) %02d min %02d sec' % (h, m, sec)
|
55 theshadow 1.1 else:
56 return '%d min %02d sec' % (m, sec)
57
|
58 theshadow 1.9 def size_format(s):
59 if (s < 1024):
60 r = str(s) + 'B'
61 elif (s < 1048576):
62 r = str(int(s/1024)) + 'KiB'
63 elif (s < 1073741824L):
64 r = str(int(s/1048576)) + 'MiB'
65 elif (s < 1099511627776L):
66 r = str(int((s/1073741824.0)*100.0)/100.0) + 'GiB'
67 else:
68 r = str(int((s/1099511627776.0)*100.0)/100.0) + 'TiB'
69 return(r)
70
71 def comma_format(s):
72 r = str(s)
73 for i in range(len(r)-3, 0, -3):
74 r = r[:i]+','+r[i:]
75 return(r)
76
|
77 theshadow 1.1 wxEVT_INVOKE = wxNewEventType()
78
79 def EVT_INVOKE(win, func):
80 win.Connect(-1, -1, wxEVT_INVOKE, func)
81
82 class InvokeEvent(wxPyEvent):
|
83 theshadow 1.46 def __init__(self, func = None, args = None, kwargs = None):
|
84 theshadow 1.1 wxPyEvent.__init__(self)
85 self.SetEventType(wxEVT_INVOKE)
|
86 theshadow 1.46 self.func = func
87 self.args = args
88 self.kwargs = kwargs
|
89 theshadow 1.1
|
90 theshadow 1.2 def pr(event):
91 print 'augh!'
92
|
93 theshadow 1.4
|
94 theshadow 1.1 class DownloadInfoFrame:
|
95 theshadow 1.13 def __init__(self, flag, configfile):
|
96 theshadow 1.16 try:
|
97 theshadow 1.13 self.FONT = configfile.configfileargs['gui_font']
|
98 theshadow 1.14 self.default_font = wxFont(self.FONT, wxDEFAULT, wxNORMAL, wxNORMAL, false)
|
99 theshadow 1.2 frame = wxFrame(None, -1, 'BitTorrent ' + version + ' download')
|
100 theshadow 1.3 self.aaa = 0
|
101 theshadow 1.1 self.flag = flag
|
102 theshadow 1.6 self.uiflag = Event()
|
103 theshadow 1.1 self.fin = false
|
104 theshadow 1.2 self.aboutBox = None
105 self.detailBox = None
|
106 theshadow 1.3 self.advBox = None
|
107 theshadow 1.2 self.creditsBox = None
|
108 theshadow 1.4 self.statusIconHelpBox = None
|
109 theshadow 1.3 self.reannouncelast = 0
|
110 theshadow 1.2 self.spinlock = 0
|
111 theshadow 1.4 self.scrollock = 0
|
112 theshadow 1.3 self.lastError = 0
|
113 theshadow 1.6 self.spewwait = time()
|
114 theshadow 1.3 self.config = None
|
115 theshadow 1.4 self.updateSpinnerFlag = 0
116 self.updateSliderFlag = 0
117 self.statusIconValue = ' '
118 self.iconized = 0
|
119 theshadow 1.5 self.checking = None
|
120 theshadow 1.6 self.activity = 'Starting up...'
121 self.firstupdate = true
122 self.shuttingdown = false
|
123 theshadow 1.7 self.ispaused = false
|
124 theshadow 1.9 self.bgalloc_periods = 0
125 self.gui_lastupdate = time()
|
126 theshadow 1.11 self.gui_fractiondone = None
127 self.fileList = None
|
128 theshadow 1.13 self.lastexternalannounce = ''
|
129 theshadow 1.15 self.refresh_details = false
130 self._errorwindow = None
|
131 theshadow 1.16 self.lastuploadsettings = 0
|
132 theshadow 1.21 self.filename = None
|
133 theshadow 1.46 if sys.platform == 'win32':
134 self.invokeLaterEvent = InvokeEvent()
135 self.invokeLaterList = []
|
136 theshadow 1.11
137 wxInitAllImageHandlers()
138 self.statusIcons={
139 'startup':wxIcon(os.path.join(basepath,'white.ico'), wxBITMAP_TYPE_ICO),
140 'disconnected':wxIcon(os.path.join(basepath,'black.ico'), wxBITMAP_TYPE_ICO),
141 'noconnections':wxIcon(os.path.join(basepath,'red.ico'), wxBITMAP_TYPE_ICO),
142 'nocompletes':wxIcon(os.path.join(basepath,'blue.ico'), wxBITMAP_TYPE_ICO),
143 'noincoming':wxIcon(os.path.join(basepath,'yellow.ico'), wxBITMAP_TYPE_ICO),
144 'allgood':wxIcon(os.path.join(basepath,'green.ico'), wxBITMAP_TYPE_ICO)
145 }
146
147 self.filestatusIcons = wxImageList(16, 16)
148 self.filestatusIcons.Add(wxBitmap(os.path.join(basepath,'black1.ico'),wxBITMAP_TYPE_ICO))
149 self.filestatusIcons.Add(wxBitmap(os.path.join(basepath,'yellow1.ico'), wxBITMAP_TYPE_ICO))
150 self.filestatusIcons.Add(wxBitmap(os.path.join(basepath,'green1.ico'), wxBITMAP_TYPE_ICO))
151
152 self.allocbuttonBitmap = wxBitmap(os.path.join(basepath,'alloc.gif'), wxBITMAP_TYPE_GIF)
|
153 theshadow 1.3
|
154 theshadow 1.2 if (sys.platform == 'win32'):
|
155 theshadow 1.4 self.icon = wxIcon(os.path.join(basepath,'icon_bt.ico'), wxBITMAP_TYPE_ICO)
|
156 theshadow 1.2 self.starttime = time ()
157
158 self.frame = frame
159 if (sys.platform == 'win32'):
160 self.frame.SetIcon(self.icon)
|
161 theshadow 1.1
162 panel = wxPanel(frame, -1)
|
163 theshadow 1.11
|
164 theshadow 1.13 def StaticText(text, font = self.FONT, underline = false, color = None, panel = panel):
|
165 theshadow 1.11 x = wxStaticText(panel, -1, text, style = wxALIGN_LEFT)
166 x.SetFont(wxFont(font, wxDEFAULT, wxNORMAL, wxNORMAL, underline))
167 if color is not None:
168 x.SetForegroundColour(color)
169 return x
170
|
171 theshadow 1.1 colSizer = wxFlexGridSizer(cols = 1, vgap = 3)
|
172 theshadow 1.4
|
173 theshadow 1.2 border = wxBoxSizer(wxHORIZONTAL)
174 border.Add(colSizer, 1, wxEXPAND | wxALL, 4)
175 panel.SetSizer(border)
176 panel.SetAutoLayout(true)
|
177 theshadow 1.1
|
178 theshadow 1.4 topboxsizer = wxFlexGridSizer(cols = 3, vgap = 0)
179 topboxsizer.AddGrowableCol (0)
180
181 fnsizer = wxFlexGridSizer(cols = 1, vgap = 0)
|
182 theshadow 1.3 fnsizer.AddGrowableCol (0)
|
183 theshadow 1.4 fnsizer.AddGrowableRow (1)
184
|
185 theshadow 1.13 fileNameText = StaticText('', self.FONT+4)
|
186 theshadow 1.2 fnsizer.Add(fileNameText, 1, wxALIGN_BOTTOM|wxEXPAND)
|
187 theshadow 1.4 self.fileNameText = fileNameText
188
189 fnsizer2 = wxFlexGridSizer(cols = 8, vgap = 0)
190 fnsizer2.AddGrowableCol (0)
191
|
192 theshadow 1.11 fileSizeText = StaticText('')
|
193 theshadow 1.4 fnsizer2.Add(fileSizeText, 1, wxALIGN_BOTTOM|wxEXPAND)
194 self.fileSizeText = fileSizeText
|
195 theshadow 1.2
|
196 theshadow 1.13 fileDetails = StaticText('Details', self.FONT, true, 'Blue')
|
197 theshadow 1.4 fnsizer2.Add(fileDetails, 0, wxALIGN_BOTTOM)
|
198 theshadow 1.2
|
199 theshadow 1.31 fnsizer2.Add(StaticText(' '))
|
200 theshadow 1.4
|
201 theshadow 1.13 advText = StaticText('Advanced', self.FONT, true, 'Blue')
|
202 theshadow 1.4 fnsizer2.Add(advText, 0, wxALIGN_BOTTOM)
|
203 theshadow 1.31 fnsizer2.Add(StaticText(' '))
|
204 theshadow 1.4
|
205 theshadow 1.13 prefsText = StaticText('Prefs', self.FONT, true, 'Blue')
|
206 theshadow 1.4 fnsizer2.Add(prefsText, 0, wxALIGN_BOTTOM)
|
207 theshadow 1.31 fnsizer2.Add(StaticText(' '))
|
208 theshadow 1.2
|
209 theshadow 1.13 aboutText = StaticText('About', self.FONT, true, 'Blue')
|
210 theshadow 1.4 fnsizer2.Add(aboutText, 0, wxALIGN_BOTTOM)
211
|
212 theshadow 1.31 fnsizer2.Add(StaticText(' '))
|
213 theshadow 1.4 fnsizer.Add(fnsizer2,0,wxEXPAND)
214 topboxsizer.Add(fnsizer,0,wxEXPAND)
|
215 theshadow 1.11 topboxsizer.Add(StaticText(' '))
|
216 theshadow 1.4
217 self.statusIcon = wxEmptyBitmap(32,32)
218 statidata = wxMemoryDC()
219 statidata.SelectObject(self.statusIcon)
220 statidata.SetPen(wxTRANSPARENT_PEN)
221 statidata.SetBrush(wxBrush(wx.wxSystemSettings_GetColour(wxSYS_COLOUR_MENU),wxSOLID))
222 statidata.DrawRectangle(0,0,32,32)
223 self.statusIconPtr = wxStaticBitmap(panel, -1, self.statusIcon)
224 topboxsizer.Add(self.statusIconPtr)
225
|
226 theshadow 1.2 self.fnsizer = fnsizer
|
227 theshadow 1.4 self.fnsizer2 = fnsizer2
228 self.topboxsizer = topboxsizer
229 colSizer.Add(topboxsizer, 0, wxEXPAND)
|
230 theshadow 1.1
231 self.gauge = wxGauge(panel, -1, range = 1000, style = wxGA_SMOOTH)
232 colSizer.Add(self.gauge, 0, wxEXPAND)
|
233 theshadow 1.4 # self.gauge.SetForegroundColour(wx.wxSystemSettings_GetColour(wxSYS_COLOUR_3DSHADOW))
|
234 theshadow 1.1
|
235 theshadow 1.2 timeSizer = wxFlexGridSizer(cols = 2)
|
236 theshadow 1.11 timeSizer.Add(StaticText('Time elapsed / estimated : '))
237 self.timeText = StaticText(self.activity+' ')
|
238 theshadow 1.2 timeSizer.Add(self.timeText)
239 timeSizer.AddGrowableCol(1)
240 colSizer.Add(timeSizer)
|
241 theshadow 1.1
|
242 theshadow 1.2 destSizer = wxFlexGridSizer(cols = 2, hgap = 8)
|
243 theshadow 1.11 self.fileDestLabel = StaticText('Download to:')
|
244 theshadow 1.4 destSizer.Add(self.fileDestLabel)
|
245 theshadow 1.11 self.fileDestText = StaticText('')
|
246 theshadow 1.2 destSizer.Add(self.fileDestText, flag = wxEXPAND)
247 destSizer.AddGrowableCol(1)
248 colSizer.Add(destSizer, flag = wxEXPAND)
|
249 theshadow 1.4 self.destSizer = destSizer
|
250 theshadow 1.2
251 statSizer = wxFlexGridSizer(cols = 3, hgap = 8)
252
253 self.ratesSizer = wxFlexGridSizer(cols = 2)
254 self.infoSizer = wxFlexGridSizer(cols = 2)
255
|
256 theshadow 1.11 self.ratesSizer.Add(StaticText(' Download rate: '))
|
257 theshadow 1.13 self.downRateText = StaticText('0 kB/s ')
|
258 theshadow 1.2 self.ratesSizer.Add(self.downRateText, flag = wxEXPAND)
259
|
260 theshadow 1.11 self.downTextLabel = StaticText('Downloaded: ')
|
261 theshadow 1.4 self.infoSizer.Add(self.downTextLabel)
|
262 theshadow 1.13 self.downText = StaticText('0.00 MiB ')
|
263 theshadow 1.2 self.infoSizer.Add(self.downText, flag = wxEXPAND)
264
|
265 theshadow 1.11 self.ratesSizer.Add(StaticText(' Upload rate: '))
|
266 theshadow 1.13 self.upRateText = StaticText('0 kB/s ')
|
267 theshadow 1.2 self.ratesSizer.Add(self.upRateText, flag = wxEXPAND)
268
|
269 theshadow 1.11 self.upTextLabel = StaticText('Uploaded: ')
|
270 theshadow 1.4 self.infoSizer.Add(self.upTextLabel)
|
271 theshadow 1.13 self.upText = StaticText('0.00 MiB ')
|
272 theshadow 1.2 self.infoSizer.Add(self.upText, flag = wxEXPAND)
273
274 shareSizer = wxFlexGridSizer(cols = 2, hgap = 8)
|
275 theshadow 1.11 shareSizer.Add(StaticText('Share rating:'))
276 self.shareRatingText = StaticText('')
|
277 theshadow 1.2 shareSizer.AddGrowableCol(1)
278 shareSizer.Add(self.shareRatingText, flag = wxEXPAND)
279
280 statSizer.Add(self.ratesSizer)
281 statSizer.Add(self.infoSizer)
282 statSizer.Add(shareSizer, flag = wxALIGN_CENTER_VERTICAL)
283 colSizer.Add (statSizer)
284
285 torrentSizer = wxFlexGridSizer(cols = 1)
|
286 theshadow 1.11 self.peerStatusText = StaticText('')
|
287 theshadow 1.2 torrentSizer.Add(self.peerStatusText, 0, wxEXPAND)
|
288 theshadow 1.11 self.seedStatusText = StaticText('')
|
289 theshadow 1.2 torrentSizer.Add(self.seedStatusText, 0, wxEXPAND)
290 torrentSizer.AddGrowableCol(0)
291 colSizer.Add(torrentSizer, 0, wxEXPAND)
|
292 theshadow 1.4 self.torrentSizer = torrentSizer
|
293 theshadow 1.1
|
294 theshadow 1.4 self.errorTextSizer = wxFlexGridSizer(cols = 1)
|
295 theshadow 1.13 self.errorText = StaticText('', self.FONT, false, 'Red')
|
296 theshadow 1.4 self.errorTextSizer.Add(self.errorText, 0, wxEXPAND)
297 colSizer.Add(self.errorTextSizer, 0, wxEXPAND)
|
298 theshadow 1.3
|
299 theshadow 1.7 cancelSizer=wxGridSizer(cols = 2, hgap = 40)
300 self.pauseButton = wxButton(panel, -1, 'Pause')
|
301 theshadow 1.15 # self.pauseButton.SetFont(self.default_font)
|
302 theshadow 1.7 cancelSizer.Add(self.pauseButton, 0, wxALIGN_CENTER)
303
|
304 theshadow 1.1 self.cancelButton = wxButton(panel, -1, 'Cancel')
|
305 theshadow 1.15 # self.cancelButton.SetFont(self.default_font)
|
306 theshadow 1.7 cancelSizer.Add(self.cancelButton, 0, wxALIGN_CENTER)
307 colSizer.Add(cancelSizer, 0, wxALIGN_CENTER)
|
308 theshadow 1.2
309 # Setting options
310
|
311 theshadow 1.3 slideSizer = wxFlexGridSizer(cols = 7, hgap = 0, vgap = 5)
|
312 theshadow 1.2
313 # dropdown
314
|
315 theshadow 1.11 self.connChoiceLabel = StaticText('Settings for ')
|
316 theshadow 1.9 slideSizer.Add (self.connChoiceLabel, 0, wxALIGN_LEFT|wxALIGN_CENTER_VERTICAL)
|
317 theshadow 1.15 self.connChoice = wxChoice (panel, -1, (-1, -1), (self.FONT*11, -1),
318 choices = connChoiceList)
|
319 theshadow 1.14 self.connChoice.SetFont(self.default_font)
|
320 theshadow 1.2 self.connChoice.SetSelection(0)
321 slideSizer.Add (self.connChoice, 0, wxALIGN_CENTER)
|
322 theshadow 1.11 self.rateSpinnerLabel = StaticText(' Upload rate (kB/s) ')
|
323 theshadow 1.9 slideSizer.Add (self.rateSpinnerLabel, 0, wxALIGN_RIGHT|wxALIGN_CENTER_VERTICAL)
|
324 theshadow 1.2
325 # max upload rate
326
327 self.rateSpinner = wxSpinCtrl (panel, -1, "", (-1,-1), (50, -1))
|
328 theshadow 1.14 self.rateSpinner.SetFont(self.default_font)
|
329 theshadow 1.2 self.rateSpinner.SetRange(0,5000)
330 self.rateSpinner.SetValue(0)
|
331 theshadow 1.9 slideSizer.Add (self.rateSpinner, 0, wxALIGN_CENTER|wxALIGN_CENTER_VERTICAL)
|
332 theshadow 1.2
|
333 theshadow 1.11 self.rateLowerText = StaticText(' %5d' % (0))
334 self.rateUpperText = StaticText('%5d' % (5000))
|
335 theshadow 1.4 self.rateslider = wxSlider(panel, -1, 0, 0, 5000, (-1, -1), (80, -1))
|
336 theshadow 1.2
|
337 theshadow 1.9 slideSizer.Add(self.rateLowerText, 0, wxALIGN_RIGHT|wxALIGN_CENTER_VERTICAL)
338 slideSizer.Add(self.rateslider, 0, wxALIGN_CENTER|wxALIGN_CENTER_VERTICAL)
339 slideSizer.Add(self.rateUpperText, 0, wxALIGN_LEFT|wxALIGN_CENTER_VERTICAL)
|
340 theshadow 1.2
|
341 theshadow 1.11 slideSizer.Add(StaticText(''), 0, wxALIGN_LEFT)
|
342 theshadow 1.2
|
343 theshadow 1.13 self.bgallocText = StaticText('', self.FONT+2, false, 'Red')
|
344 theshadow 1.9 slideSizer.Add(self.bgallocText, 0, wxALIGN_LEFT)
|
345 theshadow 1.2
346 # max uploads
347
|
348 theshadow 1.11 self.connSpinnerLabel = StaticText(' Max uploads ')
|
349 theshadow 1.9 slideSizer.Add (self.connSpinnerLabel, 0, wxALIGN_RIGHT|wxALIGN_CENTER_VERTICAL)
|
350 theshadow 1.2 self.connSpinner = wxSpinCtrl (panel, -1, "", (-1,-1), (50, -1))
|
351 theshadow 1.14 self.connSpinner.SetFont(self.default_font)
|
352 theshadow 1.2 self.connSpinner.SetRange(4,100)
353 self.connSpinner.SetValue(4)
|
354 theshadow 1.9 slideSizer.Add (self.connSpinner, 0, wxALIGN_CENTER|wxALIGN_CENTER_VERTICAL)
|
355 theshadow 1.2
|
356 theshadow 1.11 self.connLowerText = StaticText(' %5d' % (4))
357 self.connUpperText = StaticText('%5d' % (100))
|
358 theshadow 1.2 self.connslider = wxSlider(panel, -1, 4, 4, 100, (-1, -1), (80, -1))
359
|
360 theshadow 1.9 slideSizer.Add(self.connLowerText, 0, wxALIGN_RIGHT|wxALIGN_CENTER_VERTICAL)
361 slideSizer.Add(self.connslider, 0, wxALIGN_CENTER|wxALIGN_CENTER_VERTICAL)
362 slideSizer.Add(self.connUpperText, 0, wxALIGN_LEFT|wxALIGN_CENTER_VERTICAL)
|
363 theshadow 1.2
364 colSizer.Add(slideSizer, 1, wxALL|wxALIGN_CENTER|wxEXPAND, 0)
365
|
366 theshadow 1.13 self.unlimitedLabel = StaticText('0 kB/s means unlimited. Tip: your download rate is proportional to your upload rate', self.FONT-2)
|
367 theshadow 1.4 colSizer.Add(self.unlimitedLabel, 0, wxALIGN_CENTER)
|
368 theshadow 1.2
369 EVT_LEFT_DOWN(aboutText, self.about)
370 EVT_LEFT_DOWN(fileDetails, self.details)
|
371 theshadow 1.4 EVT_LEFT_DOWN(self.statusIconPtr,self.statusIconHelp)
|
372 theshadow 1.3 EVT_LEFT_DOWN(advText, self.advanced)
|
373 theshadow 1.4 EVT_LEFT_DOWN(prefsText, self.openConfigMenu)
|
374 theshadow 1.2 EVT_CLOSE(frame, self.done)
|
375 theshadow 1.7 EVT_BUTTON(frame, self.pauseButton.GetId(), self.pause)
|
376 theshadow 1.2 EVT_BUTTON(frame, self.cancelButton.GetId(), self.done)
377 EVT_INVOKE(frame, self.onInvoke)
378 EVT_SCROLL(self.rateslider, self.onRateScroll)
379 EVT_SCROLL(self.connslider, self.onConnScroll)
380 EVT_CHOICE(self.connChoice, -1, self.onConnChoice)
381 EVT_SPINCTRL(self.connSpinner, -1, self.onConnSpinner)
382 EVT_SPINCTRL(self.rateSpinner, -1, self.onRateSpinner)
383 if (sys.platform == 'win32'):
|
384 theshadow 1.3 EVT_ICONIZE(self.frame, self.onIconify)
|
385 theshadow 1.2
|
386 theshadow 1.11 colSizer.AddGrowableCol (0)
387 colSizer.AddGrowableRow (6)
|
388 theshadow 1.2 self.frame.Show()
389 border.Fit(panel)
390 self.frame.Fit()
|
391 theshadow 1.3 self.panel = panel
392 self.border = border
|
393 theshadow 1.31 self.addwidth = aboutText.GetBestSize().GetWidth() + fileDetails.GetBestSize().GetWidth() + (self.FONT*14)
|
394 theshadow 1.3 self.fnsizer = fnsizer
395 self.colSizer = colSizer
396 minsize = self.colSizer.GetSize()
397 minsize.SetWidth (minsize.GetWidth())
398 minsize.SetHeight (minsize.GetHeight())
399 self.colSizer.SetMinSize (minsize)
400 self.colSizer.Fit(self.frame)
401 colSizer.Fit(frame)
|
402 theshadow 1.16 except:
403 self.exception()
404
|
405 theshadow 1.46 if sys.platform == 'win32': # windows-only optimization
406 def onInvoke(self, event):
|
407 theshadow 1.45 while self.invokeLaterList:
408 func,args,kwargs = self.invokeLaterList[0]
409 if self.uiflag.isSet():
410 return
411 try:
412 apply(func,args,kwargs)
413 except:
414 self.exception()
415 del self.invokeLaterList[0]
|
416 theshadow 1.16
|
417 theshadow 1.46 def invokeLater(self, func, args = [], kwargs = {}):
|
418 theshadow 1.16 if not self.uiflag.isSet():
|
419 theshadow 1.45 self.invokeLaterList.append((func,args,kwargs))
420 if len(self.invokeLaterList) == 1:
421 wxPostEvent(self.frame, self.invokeLaterEvent)
|
422 theshadow 1.46 else:
423 def onInvoke(self, event):
424 if not self.uiflag.isSet():
425 try:
426 apply(event.func, event.args, event.kwargs)
427 except:
428 self.exception()
429
430 def invokeLater(self, func, args = [], kwargs = {}):
431 if not self.uiflag.isSet():
432 wxPostEvent(self.frame, InvokeEvent(func, args, kwargs))
|
433 theshadow 1.2
|
434 theshadow 1.4
435 def setStatusIcon(self, name):
436 if name != self.statusIconValue:
437 self.statusIconValue = name;
438 statidata = wxMemoryDC()
439 statidata.SelectObject(self.statusIcon)
440 statidata.BeginDrawing()
441 statidata.DrawIcon(self.statusIcons[name],0,0)
442 statidata.EndDrawing()
443 statidata.SelectObject(wxNullBitmap)
444 self.statusIconPtr.Refresh()
445
446
447 def createStatusIcon(self, name):
448 iconbuffer = wxEmptyBitmap(32,32)
449 bbdata = wxMemoryDC()
450 bbdata.SelectObject(iconbuffer)
451 bbdata.SetPen(wxTRANSPARENT_PEN)
452 bbdata.SetBrush(wxBrush(wx.wxSystemSettings_GetColour(wxSYS_COLOUR_MENU),wxSOLID))
453 bbdata.DrawRectangle(0,0,32,32)
454 bbdata.DrawIcon(self.statusIcons[name],0,0)
455 theshadow 1.4 return iconbuffer
456
457
|
458 theshadow 1.2 def onIconify(self, evt):
|
459 theshadow 1.17 try:
|
460 theshadow 1.4 if self.configfile.configfileargs['win32_taskbar_icon']:
461 if not hasattr(self.frame, "tbicon"):
462 self.frame.tbicon = wxTaskBarIcon()
463 self.frame.tbicon.SetIcon(self.icon, "BitTorrent")
464 # setup a taskbar icon, and catch some events from it
465 EVT_TASKBAR_LEFT_DCLICK(self.frame.tbicon, self.onTaskBarActivate)
466 EVT_TASKBAR_RIGHT_UP(self.frame.tbicon, self.onTaskBarMenu)
467 EVT_MENU(self.frame.tbicon, self.TBMENU_RESTORE, self.onTaskBarActivate)
468 EVT_MENU(self.frame.tbicon, self.TBMENU_CLOSE, self.done)
469 self.frame.Hide()
|
470 theshadow 1.3 else:
|
471 theshadow 1.4 EVT_ICONIZE(self.frame, self.onIconifyDummy)
472 if self.iconized:
473 self.frame.Iconize(false)
474 self.iconized = false
475 else:
476 self.frame.Iconize(true)
477 self.iconized = true
478 EVT_ICONIZE(self.frame, self.onIconify)
479 # rant here -- why in god's name can't a function called by an event
480 # trigger the event without calling itself?
481 # self.frame.Iconize(not self.frame.IsIconized()) should do this job...
|
482 theshadow 1.17 except:
483 self.exception()
|
484 theshadow 1.4
485 def onIconifyDummy(self, evt):
486 return
|
487 theshadow 1.2
488 def onTaskBarActivate(self, evt):
|
489 theshadow 1.17 try:
|
490 theshadow 1.2 if self.frame.IsIconized():
491 self.frame.Iconize(false)
492 if not self.frame.IsShown():
493 self.frame.Show(true)
|
494 theshadow 1.4 self.frame.Raise()
|
495 theshadow 1.2 if hasattr(self.frame, "tbicon"):
496 del self.frame.tbicon
|
497 theshadow 1.17 except:
498 self.exception()
|
499 theshadow 1.2
500 TBMENU_RESTORE = 1000
501 TBMENU_CLOSE = 1001
502
503 def onTaskBarMenu(self, evt):
504 menu = wxMenu()
505 menu.Append(self.TBMENU_RESTORE, "Restore BitTorrent")
506 menu.Append(self.TBMENU_CLOSE, "Close")
507 self.frame.tbicon.PopupMenu(menu)
508 menu.Destroy()
509
|
510 theshadow 1.24
511 def _try_get_config(self):
512 if self.config is None:
513 self.config = self.dow.getConfig()
514 return self.config != None
515
516
|
517 theshadow 1.2 def onRateScroll(self, event):
|
518 theshadow 1.17 try:
|
519 theshadow 1.4 if (self.scrollock == 0):
520 self.scrollock = 1
|
521 theshadow 1.24 if not self._try_get_config():
522 return
|
523 theshadow 1.26 self.updateSpinnerFlag = 1
524 self.dow.setUploadRate(self.rateslider.GetValue() * 1000
|
525 theshadow 1.7 * connChoices[self.connChoice.GetSelection()]['rate'].get('div',1))
|
526 theshadow 1.4 self.scrollock = 0
|
527 theshadow 1.17 except:
528 self.exception()
|
529 theshadow 1.2
530 def onConnScroll(self, event):
|
531 theshadow 1.17 try:
|
532 theshadow 1.24 if not self._try_get_config():
533 return
|
534 theshadow 1.2 self.connSpinner.SetValue (self.connslider.GetValue ())
|
535 theshadow 1.26 self.dow.setConns(self.connslider.GetValue())
|
536 theshadow 1.17 except:
537 self.exception()
|
538 theshadow 1.2
539 def onRateSpinner(self, event):
|
540 theshadow 1.17 try:
|
541 theshadow 1.24 if not self._try_get_config():
542 return
|
543 theshadow 1.2 if (self.spinlock == 0):
544 self.spinlock = 1
|
545 theshadow 1.7 spinnerValue = self.rateSpinner.GetValue()
546 div = connChoices[self.connChoice.GetSelection()]['rate'].get('div',1)
547 if div > 1:
548 if spinnerValue > (self.config['max_upload_rate']/1000):
549 round_up = div - 1
550 else:
551 round_up = 0
552 newValue = int((spinnerValue + round_up) / div) * div
553 if newValue != spinnerValue:
554 self.rateSpinner.SetValue(newValue)
|
555 theshadow 1.2 else:
|
556 theshadow 1.8 newValue = spinnerValue
|
557 theshadow 1.26 self.dow.setUploadRate(newValue * 1000)
|
558 theshadow 1.7 self.updateSliderFlag = 1
|
559 theshadow 1.2 self.spinlock = 0
|
560 theshadow 1.17 except:
561 self.exception()
|
562 theshadow 1.2
563 def onConnSpinner(self, event):
|
564 theshadow 1.17 try:
|
565 theshadow 1.24 if not self._try_get_config():
566 return
|
567 theshadow 1.2 self.connslider.SetValue (self.connSpinner.GetValue())
|
568 theshadow 1.26 self.dow.setConns(self.connslider.GetValue())
|
569 theshadow 1.17 except:
570 self.exception()
|
571 theshadow 1.2
572 def onConnChoice(self, event):
|
573 theshadow 1.17 try:
|
574 theshadow 1.24 if not self._try_get_config():
575 return
|
576 theshadow 1.2 num = self.connChoice.GetSelection()
|
577 theshadow 1.16 if connChoices[num].has_key('super-seed'): # selecting super-seed is now a toggle
578 self.dow.set_super_seed() # one way change, don't go back
579 num = self.lastuploadsettings
580 self.connChoice.SetSelection(num)
581 return
582 self.lastuploadsettings = num
|
583 theshadow 1.2 self.rateSpinner.SetRange (connChoices[num]['rate']['min'],
584 connChoices[num]['rate']['max'])
|
585 theshadow 1.4 self.rateSpinner.SetValue (connChoices[num]['rate']['def'])
|
586 theshadow 1.2 self.rateslider.SetRange (
587 connChoices[num]['rate']['min']/connChoices[num]['rate'].get('div',1),
588 connChoices[num]['rate']['max']/connChoices[num]['rate'].get('div',1))
589 self.rateslider.SetValue (
590 connChoices[num]['rate']['def']/connChoices[num]['rate'].get('div',1))
591 self.rateLowerText.SetLabel (' %d' % (connChoices[num]['rate']['min']))
592 self.rateUpperText.SetLabel ('%d' % (connChoices[num]['rate']['max']))
593 self.connSpinner.SetRange (connChoices[num]['conn']['min'],
594 connChoices[num]['conn']['max'])
|
595 theshadow 1.4 self.connSpinner.SetValue (connChoices[num]['conn']['def'])
|
596 theshadow 1.2 self.connslider.SetRange (connChoices[num]['conn']['min'],
597 connChoices[num]['conn']['max'])
598 self.connslider.SetValue (connChoices[num]['conn']['def'])
599 self.connLowerText.SetLabel (' %d' % (connChoices[num]['conn']['min']))
600 self.connUpperText.SetLabel ('%d' % (connChoices[num]['conn']['max']))
601 self.onConnScroll (0)
602 self.onRateScroll (0)
|
603 theshadow 1.26 self.dow.setInitiate(connChoices[num].get('initiate', 40))
|
604 theshadow 1.17 except:
605 self.exception()
|
606 theshadow 1.2
|
607 theshadow 1.4
|
608 theshadow 1.2 def about(self, event):
|
609 theshadow 1.17 try:
|
610 theshadow 1.2 if (self.aboutBox is not None):
611 try:
612 self.aboutBox.Close ()
613 except wxPyDeadObjectError, e:
614 self.aboutBox = None
615
616 self.aboutBox = wxFrame(None, -1, 'About BitTorrent', size = (1,1))
|
617 theshadow 1.3 if (sys.platform == 'win32'):
618 self.aboutBox.SetIcon(self.icon)
|
619 theshadow 1.2
620 panel = wxPanel(self.aboutBox, -1)
|
621 theshadow 1.11
|
622 theshadow 1.13 def StaticText(text, font = self.FONT, underline = false, color = None, panel = panel):
|
623 theshadow 1.11 x = wxStaticText(panel, -1, text, style = wxALIGN_LEFT)
624 x.SetFont(wxFont(font, wxDEFAULT, wxNORMAL, wxNORMAL, underline))
625 if color is not None:
626 x.SetForegroundColour(color)
627 return x
628
|
629 theshadow 1.2 colSizer = wxFlexGridSizer(cols = 1, vgap = 3)
630
631 titleSizer = wxBoxSizer(wxHORIZONTAL)
|
632 theshadow 1.13 aboutTitle = StaticText('BitTorrent ' + version + ' ', self.FONT+4)
|
633 theshadow 1.2 titleSizer.Add (aboutTitle)
|
634 theshadow 1.13 linkDonate = StaticText('Donate to Bram', self.FONT, true, 'Blue')
|
635 theshadow 1.2 titleSizer.Add (linkDonate, 1, wxALIGN_BOTTOM&wxEXPAND)
636 colSizer.Add(titleSizer, 0, wxEXPAND)
637
|
638 theshadow 1.11 colSizer.Add(StaticText('created by Bram Cohen, Copyright 2001-2003,'))
639 colSizer.Add(StaticText('experimental version maintained by John Hoffman 2003'))
640 colSizer.Add(StaticText('modified from experimental version by Eike Frost 2003'))
|
641 theshadow 1.13 credits = StaticText('full credits\n', self.FONT, true, 'Blue')
|
642 theshadow 1.2 colSizer.Add(credits);
643
|
644 theshadow 1.20 si = ( 'exact Version String: ' + version + '\n' +
645 'Python version: ' + sys.version + '\n' +
646 'wxWindows version: ' + wxVERSION_STRING + '\n' )
647 try:
648 si += 'Psyco version: ' + hex(psyco.__version__)[2:] + '\n'
649 except:
650 pass
651 colSizer.Add(StaticText(si))
|
652 theshadow 1.2
|
653 theshadow 1.11 babble1 = StaticText(
|
654 theshadow 1.2 'This is an experimental, unofficial build of BitTorrent.\n' +
655 'It is Free Software under an MIT-Style license.')
|
656 theshadow 1.13 babble2 = StaticText('BitTorrent Homepage (link)', self.FONT, true, 'Blue')
657 babble3 = StaticText("TheSHAD0W's Client Homepage (link)", self.FONT, true, 'Blue')
658 babble4 = StaticText("Eike Frost's Client Homepage (link)", self.FONT, true, 'Blue')
659 babble6 = StaticText('License Terms (link)', self.FONT, true, 'Blue')
|
660 theshadow 1.2 colSizer.Add (babble1)
661 colSizer.Add (babble2)
|
662 theshadow 1.6 colSizer.Add (babble3)
|
663 theshadow 1.2 colSizer.Add (babble4)
664 colSizer.Add (babble6)
665
666 okButton = wxButton(panel, -1, 'Ok')
|
667 theshadow 1.15 # okButton.SetFont(self.default_font)
|
668 theshadow 1.2 colSizer.Add(okButton, 0, wxALIGN_RIGHT)
|
669 theshadow 1.1 colSizer.AddGrowableCol(0)
670
671 border = wxBoxSizer(wxHORIZONTAL)
672 border.Add(colSizer, 1, wxEXPAND | wxALL, 4)
673 panel.SetSizer(border)
674 panel.SetAutoLayout(true)
|
675 theshadow 1.2
|
676 theshadow 1.3 def donatelink(self):
677 Thread(target = open_new('https://www.paypal.com/cgi-bin/webscr?cmd=_xclick&business=bram@bitconjurer.org&item_name=BitTorrent&amount=5.00&submit=donate')).start()
678 EVT_LEFT_DOWN(linkDonate, donatelink)
679 def aboutlink(self):
680 Thread(target = open_new('http://bitconjurer.org/BitTorrent/')).start()
681 EVT_LEFT_DOWN(babble2, aboutlink)
|
682 theshadow 1.6 def shadlink(self):
|
683 theshadow 1.9 Thread(target = open_new('http://bt.degreez.net/')).start()
|
684 theshadow 1.6 EVT_LEFT_DOWN(babble3, shadlink)
|
685 theshadow 1.3 def explink(self):
686 Thread(target = open_new('http://ei.kefro.st/projects/btclient/')).start()
687 EVT_LEFT_DOWN(babble4, explink)
688 def licenselink(self):
689 Thread(target = open_new('http://ei.kefro.st/projects/btclient/LICENSE.TXT')).start()
690 EVT_LEFT_DOWN(babble6, licenselink)
|
691 theshadow 1.2 EVT_LEFT_DOWN(credits, self.credits)
692
|
693 theshadow 1.3 def closeAbout(self, frame = self):
694 frame.aboutBox.Close ()
695 EVT_BUTTON(self.aboutBox, okButton.GetId(), closeAbout)
|
696 theshadow 1.11 def kill(self, frame = self):
697 frame.aboutBox.Destroy()
698 frame.aboutBox = None
699 EVT_CLOSE(self.aboutBox, kill)
|
700 theshadow 1.2
701 self.aboutBox.Show ()
702 border.Fit(panel)
703 self.aboutBox.Fit()
|
704 theshadow 1.17 except:
705 self.exception()
|
706 theshadow 1.2
|
707 theshadow 1.4
|
708 theshadow 1.2 def details(self, event):
|
709 theshadow 1.17 try:
|
710 theshadow 1.2 metainfo = self.dow.getResponse()
|
711 theshadow 1.18 if metainfo is None:
712 return
|
713 theshadow 1.11 if metainfo.has_key('announce'):
714 announce = metainfo['announce']
715 else:
716 announce = None
717 if metainfo.has_key('announce-list'):
718 announce_list = metainfo['announce-list']
719 else:
720 announce_list = None
|
721 theshadow 1.2 info = metainfo['info']
722 info_hash = sha(bencode(info))
723 piece_length = info['piece length']
724
725 if (self.detailBox is not None):
726 try:
727 self.detailBox.Close ()
728 except wxPyDeadObjectError, e:
729 self.detailBox = None
730
731 self.detailBox = wxFrame(None, -1, 'Torrent Details ', size = wxSize(405,230))
|
732 theshadow 1.3 if (sys.platform == 'win32'):
733 self.detailBox.SetIcon(self.icon)
|
734 theshadow 1.2
735 panel = wxPanel(self.detailBox, -1, size = wxSize (400,220))
|
736 theshadow 1.11
|
737 theshadow 1.13 def StaticText(text, font = self.FONT, underline = false, color = None, panel = panel):
|
738 theshadow 1.11 x = wxStaticText(panel, -1, text, style = wxALIGN_CENTER_VERTICAL)
739 x.SetFont(wxFont(font, wxDEFAULT, wxNORMAL, wxNORMAL, underline))
740 if color is not None:
741 x.SetForegroundColour(color)
742 return x
743
|
744 theshadow 1.2 colSizer = wxFlexGridSizer(cols = 1, vgap = 3)
|
745 theshadow 1.9 colSizer.AddGrowableCol(0)
|
746 theshadow 1.2
747 titleSizer = wxBoxSizer(wxHORIZONTAL)
|
748 theshadow 1.13 aboutTitle = StaticText('Details about ' + self.filename, self.FONT+4)
|
749 theshadow 1.6
|
750 theshadow 1.2 titleSizer.Add (aboutTitle)
751 colSizer.Add (titleSizer)
752
|
753 theshadow 1.9 detailSizer = wxFlexGridSizer(cols = 2, vgap = 6)
|
754 theshadow 1.2
755 if info.has_key('length'):
|
756 theshadow 1.11 detailSizer.Add(StaticText('file name :'))
757 detailSizer.Add(StaticText(info['name']))
758 if info.has_key('md5sum'):
759 detailSizer.Add(StaticText('MD5 hash :'))
760 detailSizer.Add(StaticText(info['md5sum']))
|
761 theshadow 1.2 file_length = info['length']
|
762 theshadow 1.6 name = "file size"
|
763 theshadow 1.2 else:
|
764 theshadow 1.9 detail1Sizer = wxFlexGridSizer(cols = 1, vgap = 6)
|
765 theshadow 1.11 detail1Sizer.Add(StaticText('directory name : ' + info['name']))
766 colSizer.Add (detail1Sizer)
767 bgallocButton = wxBitmapButton(panel, -1, self.allocbuttonBitmap, size = (52,20))
768 def bgalloc(self, frame = self):
769 if frame.dow.storagewrapper is not None:
770 frame.dow.storagewrapper.bgalloc()
771 EVT_BUTTON(self.detailBox, bgallocButton.GetId(), bgalloc)
772
773 bgallocbuttonSizer = wxFlexGridSizer(cols = 3, hgap = 4, vgap = 0)
774 bgallocbuttonSizer.Add(StaticText('(finish allocation)'), -1, wxALIGN_CENTER_VERTICAL)
775 bgallocbuttonSizer.Add(bgallocButton, -1, wxALIGN_CENTER)
776 colSizer.Add(bgallocbuttonSizer, -1, wxALIGN_RIGHT)
777
|
778 theshadow 1.6 file_length = 0
779
780 fileList = wxListCtrl(panel, -1, wxPoint(-1,-1), (325,100), wxLC_REPORT)
|
781 theshadow 1.11 self.fileList = fileList
782 fileList.SetImageList(self.filestatusIcons, wxIMAGE_LIST_SMALL)
783
|
784 theshadow 1.6 fileList.SetAutoLayout (true)
|
785 theshadow 1.11 fileList.InsertColumn(0, "file")
786 fileList.InsertColumn(1, "", format=wxLIST_FORMAT_RIGHT, width=55)
787 fileList.InsertColumn(2, "")
788
789 for i in range(len(info['files'])):
790 x = wxListItem()
|
791 theshadow 1.15 # x.SetFont(self.default_font)
|
792 theshadow 1.11 fileList.InsertItem(x)
|
793 theshadow 1.6
794 x = 0
|
795 theshadow 1.2 for file in info['files']:
|
796 theshadow 1.11 path = ' '
|
797 theshadow 1.2 for item in file['path']:
798 if (path != ''):
799 path = path + "/"
800 path = path + item
|
801 theshadow 1.11 path += ' (' + str(file['length']) + ')'
802 fileList.SetStringItem(x, 0, path)
803 if file.has_key('md5sum'):
804 fileList.SetStringItem(x, 2, ' [' + str(file['md5sum']) + ']')
|
805 theshadow 1.6 x += 1
|
806 theshadow 1.2 file_length += file['length']
|
807 theshadow 1.9 fileList.SetColumnWidth(0,wxLIST_AUTOSIZE)
|
808 theshadow 1.11 fileList.SetColumnWidth(2,wxLIST_AUTOSIZE)
|
809 theshadow 1.6
|
810 theshadow 1.2 name = 'archive size'
|
811 theshadow 1.11 colSizer.Add(fileList, 1, wxEXPAND)
812 colSizer.AddGrowableRow(3)
|
813 theshadow 1.2
|
814 theshadow 1.11 detailSizer.Add(StaticText('info_hash :'),0,wxALIGN_CENTER_VERTICAL)
|
815 theshadow 1.6 detailSizer.Add(wxTextCtrl(panel, -1, info_hash.hexdigest(), size = (325, -1), style = wxTE_READONLY))
|
816 theshadow 1.10 num_pieces = int((file_length+piece_length-1)/piece_length)
|
817 theshadow 1.11 detailSizer.Add(StaticText(name + ' : '))
818 detailSizer.Add(StaticText('%s (%s bytes)' % (size_format(file_length), comma_format(file_length))))
819 detailSizer.Add(StaticText('pieces : '))
820 if num_pieces > 1:
821 detailSizer.Add(StaticText('%i (%s bytes each)' % (num_pieces, comma_format(piece_length))))
822 else:
823 detailSizer.Add(StaticText('1'))
824
825 if announce_list is None:
826 detailSizer.Add(StaticText('announce url : '),0,wxALIGN_CENTER_VERTICAL)
827 detailSizer.Add(wxTextCtrl(panel, -1, announce, size = (325, -1), style = wxTE_READONLY))
828 else:
829 detailSizer.Add(StaticText(''))
830 trackerList = wxListCtrl(panel, -1, wxPoint(-1,-1), (325,75), wxLC_REPORT)
831 trackerList.SetAutoLayout (true)
832 trackerList.InsertColumn(0, "")
833 trackerList.InsertColumn(1, "announce urls")
834
835 for tier in range(len(announce_list)):
836 for t in range(len(announce_list[tier])):
837 i = wxListItem()
|
838 theshadow 1.15 # i.SetFont(self.default_font)
|
839 theshadow 1.11 trackerList.InsertItem(i)
840 if announce is not None:
841 for l in [1,2]:
842 i = wxListItem()
|
843 theshadow 1.15 # i.SetFont(self.default_font)
|
844 theshadow 1.11 trackerList.InsertItem(i)
845
846 x = 0
847 for tier in range(len(announce_list)):
848 for t in range(len(announce_list[tier])):
849 if t == 0:
850 trackerList.SetStringItem(x, 0, 'tier '+str(tier)+':')
851 trackerList.SetStringItem(x, 1, announce_list[tier][t])
852 x += 1
853 if announce is not None:
854 trackerList.SetStringItem(x+1, 0, 'single:')
855 trackerList.SetStringItem(x+1, 1, announce)
856 trackerList.SetColumnWidth(0,wxLIST_AUTOSIZE)
857 trackerList.SetColumnWidth(1,wxLIST_AUTOSIZE)
858 detailSizer.Add(trackerList)
859
860 if announce is None and announce_list is not None:
861 announce = announce_list[0][0]
862 if announce is not None:
863 detailSizer.Add(StaticText('likely tracker :'))
864 p = re.compile( '(.*/)[^/]+')
865 theshadow 1.11 turl = p.sub (r'\1', announce)
|
866 theshadow 1.14 trackerUrl = StaticText(turl, self.FONT, true, 'Blue')
|
867 theshadow 1.11 detailSizer.Add(trackerUrl)
|
868 theshadow 1.15 if metainfo.has_key('comment'):
|
869 theshadow 1.11 detailSizer.Add(StaticText('comment :'))
|
870 theshadow 1.15 detailSizer.Add(StaticText(metainfo['comment']))
871 if metainfo.has_key('creation date'):
|
872 theshadow 1.11 detailSizer.Add(StaticText('creation date :'))
|
873 theshadow 1.17 try:
874 detailSizer.Add(StaticText(
875 strftime('%x %X',localtime(metainfo['creation date']))))
876 except:
877 try:
878 detailSizer.Add(StaticText(metainfo['creation date']))
879 except:
880 detailSizer.Add(StaticText('<cannot read date>'))
|
881 theshadow 1.2
|
882 theshadow 1.9 detailSizer.AddGrowableCol(1)
883 colSizer.Add (detailSizer, 1, wxEXPAND)
884
|
885 theshadow 1.2 okButton = wxButton(panel, -1, 'Ok')
|
886 theshadow 1.15 # okButton.SetFont(self.default_font)
|
887 theshadow 1.2 colSizer.Add(okButton, 0, wxALIGN_RIGHT)
888 colSizer.AddGrowableCol(0)
889
|
890 theshadow 1.6 if not self.configfile.configfileargs['gui_stretchwindow']:
891 aboutTitle.SetSize((400,-1))
892 else:
893 panel.SetAutoLayout(true)
894
|
895 theshadow 1.2 border = wxBoxSizer(wxHORIZONTAL)
896 border.Add(colSizer, 1, wxEXPAND | wxALL, 4)
897 panel.SetSizer(border)
898 panel.SetAutoLayout(true)
899
|
900 theshadow 1.3 def closeDetail(self, frame = self):
901 frame.detailBox.Close ()
902 EVT_BUTTON(self.detailBox, okButton.GetId(), closeDetail)
|
903 theshadow 1.11 def kill(self, frame = self):
904 frame.detailBox.Destroy()
905 frame.detailBox = None
906 frame.fileList = None
|
907 theshadow 1.25 frame.dow.filedatflag.clear()
|
908 theshadow 1.11 EVT_CLOSE(self.detailBox, kill)
|
909 theshadow 1.2
|
910 theshadow 1.3 def trackerurl(self, turl = turl):
|
911 theshadow 1.2 Thread(target = open_new(turl)).start()
912
913 EVT_LEFT_DOWN(trackerUrl, trackerurl)
914
915 self.detailBox.Show ()
916 border.Fit(panel)
917 self.detailBox.Fit()
918
|
919 theshadow 1.17 self.refresh_details = true
|
920 theshadow 1.25 self.dow.filedatflag.set()
|
921 theshadow 1.17 except:
922 self.exception()
|
923 theshadow 1.15
924
|
925 theshadow 1.2 def credits(self, event):
|
926 theshadow 1.17 try:
|
927 theshadow 1.2 if (self.creditsBox is not None):
928 try:
929 self.creditsBox.Close ()
930 except wxPyDeadObjectError, e:
931 self.creditsBox = None
932
933 self.creditsBox = wxFrame(None, -1, 'Credits', size = (1,1))
|
934 theshadow 1.3 if (sys.platform == 'win32'):
935 self.creditsBox.SetIcon(self.icon)
|
936 theshadow 1.2
|
937 theshadow 1.4 panel = wxPanel(self.creditsBox, -1)
|
938 theshadow 1.11
|
939 theshadow 1.13 def StaticText(text, font = self.FONT, underline = false, color = None, panel = panel):
|
940 theshadow 1.11 x = wxStaticText(panel, -1, text, style = wxALIGN_LEFT)
941 x.SetFont(wxFont(font, wxDEFAULT, wxNORMAL, wxNORMAL, underline))
942 if color is not None:
943 x.SetForegroundColour(color)
944 return x
945
|
946 theshadow 1.2 colSizer = wxFlexGridSizer(cols = 1, vgap = 3)
947
948 titleSizer = wxBoxSizer(wxHORIZONTAL)
|
949 theshadow 1.13 aboutTitle = StaticText('Credits', self.FONT+4)
|
950 theshadow 1.2 titleSizer.Add (aboutTitle)
951 colSizer.Add (titleSizer)
|
952 theshadow 1.11 colSizer.Add (StaticText(
|
953 theshadow 1.2 'The following people have all helped with this\n' +
954 'version of BitTorrent in some way (in no particular order) -\n'));
955 creditSizer = wxFlexGridSizer(cols = 3)
|
956 theshadow 1.11 creditSizer.Add(StaticText(
|
957 theshadow 1.2 'Bill Bumgarner\n' +
958 'David Creswick\n' +
959 'Andrew Loewenstern\n' +
960 'Ross Cohen\n' +
961 'Jeremy Avnet\n' +
962 'Greg Broiles\n' +
963 'Barry Cohen\n' +
964 'Bram Cohen\n' +
965 'sayke\n' +
966 'Steve Jenson\n' +
967 'Myers Carpenter\n' +
968 'Francis Crick\n' +
969 'Petru Paler\n' +
970 'Jeff Darcy\n' +
|
971 theshadow 1.22 'John Gilmore\n' +
|
972 theshadow 1.34 'Xavier Bassery\n' +
973 'Pav Lucistnik'))
|
974 theshadow 1.11 creditSizer.Add(StaticText(' '))
975 creditSizer.Add(StaticText(
|
976 theshadow 1.2 'Yann Vernier\n' +
977 'Pat Mahoney\n' +
978 'Boris Zbarsky\n' +
979 'Eric Tiedemann\n' +
980 'Henry "Pi" James\n' +
981 'Loring Holden\n' +
982 'Robert Stone\n' +
983 'Michael Janssen\n' +
984 'Eike Frost\n' +
985 'Andrew Todd\n' +
986 'otaku\n' +
|
987 theshadow 1.3 'Edward Keyes\n' +
|
988 theshadow 1.14 'John Hoffman\n' +
989 'Uoti Urpala\n' +
|
990 theshadow 1.28 'Jon Wolf\n' +
991 'Christoph Hohmann'))
|
992 theshadow 1.2 colSizer.Add (creditSizer, flag = wxALIGN_CENTER_HORIZONTAL)
993 okButton = wxButton(panel, -1, 'Ok')
|
994 theshadow 1.15 # okButton.SetFont(self.default_font)
|
995 theshadow 1.2 colSizer.Add(okButton, 0, wxALIGN_RIGHT)
996 colSizer.AddGrowableCol(0)
997
998 border = wxBoxSizer(wxHORIZONTAL)
999 border.Add(colSizer, 1, wxEXPAND | wxALL, 4)
1000 panel.SetSizer(border)
1001 panel.SetAutoLayout(true)
1002
|
1003 theshadow 1.3 def closeCredits(self, frame = self):
1004 frame.creditsBox.Close ()
1005 EVT_BUTTON(self.creditsBox, okButton.GetId(), closeCredits)
|
1006 theshadow 1.11 def kill(self, frame = self):
1007 frame.creditsBox.Destroy()
1008 frame.creditsBox = None
1009 EVT_CLOSE(self.creditsBox, kill)
|
1010 theshadow 1.2
|
1011 theshadow 1.22 self.creditsBox.Show()
|
1012 theshadow 1.2 border.Fit(panel)
1013 self.creditsBox.Fit()
|
1014 theshadow 1.22 except:
1015 self.exception()
|
1016 theshadow 1.2
|
1017 theshadow 1.4
1018 def statusIconHelp(self, event):
|
1019 theshadow 1.17 try:
|
1020 theshadow 1.4 if (self.statusIconHelpBox is not None):
1021 try:
1022 self.statusIconHelpBox.Close ()
1023 except wxPyDeadObjectError, e:
1024 self.statusIconHelpBox = None
1025
|
1026 theshadow 1.6 self.statusIconHelpBox = wxFrame(None, -1, 'Help with the BitTorrent Status Light', size = (1,1))
|
1027 theshadow 1.4 if (sys.platform == 'win32'):
1028 self.statusIconHelpBox.SetIcon(self.icon)
1029
1030 panel = wxPanel(self.statusIconHelpBox, -1)
|
1031 theshadow 1.11
|
1032 theshadow 1.13 def StaticText(text, font = self.FONT, underline = false, color = None, panel = panel):
|
1033 theshadow 1.11 x = wxStaticText(panel, -1, text, style = wxALIGN_LEFT)
1034 x.SetFont(wxFont(font, wxDEFAULT, wxNORMAL, wxNORMAL, underline))
1035 if color is not None:
1036 x.SetForegroundColour(color)
1037 return x
1038
|
1039 theshadow 1.6 fullsizer = wxFlexGridSizer(cols = 1, vgap = 13)
1040 colsizer = wxFlexGridSizer(cols = 2, hgap = 13, vgap = 13)
|
1041 theshadow 1.4
1042 disconnectedicon=self.createStatusIcon('disconnected')
1043 colsizer.Add(wxStaticBitmap(panel, -1, disconnectedicon))
|
1044 theshadow 1.11 colsizer.Add(StaticText(
|
1045 theshadow 1.4 'Waiting to connect to the tracker.\n' +
|
1046 theshadow 1.6 'If the status light stays black for a long time the tracker\n' +
|
1047 theshadow 1.4 'you are trying to connect to may not be working. Unless you\n' +
1048 'are receiving a message telling you otherwise, please wait,\n' +
1049 'and BitTorrent will automatically try to reconnect for you.'), 1, wxALIGN_CENTER_VERTICAL)
1050
1051 noconnectionsicon=self.createStatusIcon('noconnections')
1052 colsizer.Add(wxStaticBitmap(panel, -1, noconnectionsicon))
|
1053 theshadow 1.11 colsizer.Add(StaticText(
|
1054 theshadow 1.4 'You have no connections with other clients.\n' +
1055 'Please be patient. If after several minutes the status\n' +
|
1056 theshadow 1.6 'light remains red, this torrent may be old and abandoned.'), 1, wxALIGN_CENTER_VERTICAL)
|
1057 theshadow 1.4
1058 noincomingicon=self.createStatusIcon('noincoming')
1059 colsizer.Add(wxStaticBitmap(panel, -1, noincomingicon))
|
1060 theshadow 1.11 colsizer.Add(StaticText(
|
1061 theshadow 1.6 'You have not received any incoming connections from others.\n' +
|
1062 theshadow 1.4 'It may only be because no one has tried. If you never see\n' +
|
1063 theshadow 1.6 'the status light turn green, it may indicate your system\n' +
|
1064 theshadow 1.4 'is behind a firewall or proxy server. Please look into\n' +
1065 'routing BitTorrent through your firewall in order to receive\n' +
1066 'the best possible download rate.'), 1, wxALIGN_CENTER_VERTICAL)
1067
|
1068 theshadow 1.15 nocompletesicon=self.createStatusIcon('nocompletes')
1069 colsizer.Add(wxStaticBitmap(panel, -1, nocompletesicon))
1070 colsizer.Add(StaticText(
1071 'There are no complete copies among the clients you are\n' +
1072 'connected to. Don\'t panic, other clients in the torrent\n' +
1073 "you can't see may have the missing data.\n" +
1074 'If the status light remains blue, you may have problems\n' +
1075 'completing your download.'), 1, wxALIGN_CENTER_VERTICAL)
1076
|
1077 theshadow 1.4 allgoodicon=self.createStatusIcon('allgood')
1078 colsizer.Add(wxStaticBitmap(panel, -1, allgoodicon))
|
1079 theshadow 1.11 colsizer.Add(StaticText(
|
1080 theshadow 1.4 'The torrent is operating properly.'), 1, wxALIGN_CENTER_VERTICAL)
|
1081 theshadow 1.6
1082 fullsizer.Add(colsizer, 0, wxALIGN_CENTER)
1083 colsizer2 = wxFlexGridSizer(cols = 1, hgap = 13)
1084
|
1085 theshadow 1.11 colsizer2.Add(StaticText(
|
1086 theshadow 1.6 'Please note that the status light is not omniscient, and that it may\n' +
1087 'be wrong in many instances. A torrent with a blue light may complete\n' +
1088 "normally, and an occasional yellow light doesn't mean your computer\n" +
1089 'has suddenly become firewalled.'), 1, wxALIGN_CENTER_VERTICAL)
1090
|
1091 theshadow 1.11 colspacer = StaticText(' ')
|
1092 theshadow 1.6 colsizer2.Add(colspacer)
|
1093 theshadow 1.4
1094 okButton = wxButton(panel, -1, 'Ok')
|
1095 theshadow 1.15 # okButton.SetFont(self.default_font)
|
1096 theshadow 1.6 colsizer2.Add(okButton, 0, wxALIGN_CENTER)
1097 fullsizer.Add(colsizer2, 0, wxALIGN_CENTER)
|
1098 theshadow 1.4
1099 border = wxBoxSizer(wxHORIZONTAL)
|
1100 theshadow 1.6 border.Add(fullsizer, 1, wxEXPAND | wxALL, 4)
|
1101 theshadow 1.4
1102 panel.SetSizer(border)
1103 panel.SetAutoLayout(true)
1104
1105
1106 def closeHelp(self, frame = self):
1107 frame.statusIconHelpBox.Close ()
1108 EVT_BUTTON(self.statusIconHelpBox, okButton.GetId(), closeHelp)
1109
1110 self.statusIconHelpBox.Show ()
1111 border.Fit(panel)
1112 self.statusIconHelpBox.Fit()
|
1113 theshadow 1.17 except:
1114 self.exception()
|
1115 theshadow 1.4
1116
1117 def openConfigMenu(self, event):
|
1118 theshadow 1.17 try:
1119 self.configfile.configMenu(self)
1120 except:
1121 self.exception()
|
1122 theshadow 1.4
1123
|
1124 theshadow 1.3 def advanced(self, event):
|
1125 theshadow 1.17 try:
|
1126 theshadow 1.21 if self.filename is None:
1127 return
|
1128 theshadow 1.3 if (self.advBox is not None):
1129 try:
1130 self.advBox.Close ()
1131 except wxPyDeadObjectError, e:
1132 self.advBox = None
1133
|
1134 theshadow 1.9 self.advBox = wxFrame(None, -1, 'BitTorrent Advanced', size = wxSize(200,200))
|
1135 theshadow 1.3 if (sys.platform == 'win32'):
1136 self.advBox.SetIcon(self.icon)
1137
1138 panel = wxPanel(self.advBox, -1, size = wxSize (200,200))
|
1139 theshadow 1.2
|
1140 theshadow 1.13 def StaticText(text, font = self.FONT, underline = false, color = None, panel = panel):
|
1141 theshadow 1.11 x = wxStaticText(panel, -1, text, style = wxALIGN_LEFT)
1142 x.SetFont(wxFont(font, wxDEFAULT, wxNORMAL, wxNORMAL, underline))
1143 if color is not None:
1144 x.SetForegroundColour(color)
1145 return x
1146
1147 colSizer = wxFlexGridSizer (cols = 1, vgap = 1)
|
1148 theshadow 1.13 colSizer.Add (StaticText('Advanced Info for ' + self.filename, self.FONT+4))
|
1149 theshadow 1.15
1150 try: # get system font width
1151 fw = wxSystemSettings_GetFont(wxSYS_DEFAULT_GUI_FONT).GetPointSize()+1
1152 except:
1153 fw = wxSystemSettings_GetFont(wxSYS_SYSTEM_FONT).GetPointSize()+1
1154
|
1155 theshadow 1.19 spewList = wxListCtrl(panel, -1, wxPoint(-1,-1), (fw*66,350), wxLC_REPORT|wxLC_HRULES|wxLC_VRULES)
|
1156 theshadow 1.15 self.spewList = spewList
|
1157 theshadow 1.3 spewList.SetAutoLayout (true)
|
1158 theshadow 1.1
|
1159 theshadow 1.3 colSizer.Add(spewList, -1, wxEXPAND)
|
1160 theshadow 1.1
|
1161 theshadow 1.11 colSizer.Add(StaticText(''))
1162 self.storagestats1 = StaticText('')
1163 self.storagestats2 = StaticText('')
1164 colSizer.Add(self.storagestats1, -1, wxEXPAND)
1165 colSizer.Add(self.storagestats2, -1, wxEXPAND)
1166 colSizer.Add(StaticText(''))
1167
1168 buttonSizer = wxFlexGridSizer (cols = 5, hgap = 20)
|
1169 theshadow 1.3
|
1170 theshadow 1.11 reannounceButton = wxButton(panel, -1, 'Manual Announce')
|
1171 theshadow 1.15 # reannounceButton.SetFont(self.default_font)
|
1172 theshadow 1.3 buttonSizer.Add (reannounceButton)
1173
|
1174 theshadow 1.11 extannounceButton = wxButton(panel, -1, 'External Announce')
|
1175 theshadow 1.15 # extannounceButton.SetFont(self.default_font)
|
1176 theshadow 1.11 buttonSizer.Add (extannounceButton)
1177
|
1178 theshadow 1.9 bgallocButton = wxButton(panel, -1, 'Finish Allocation')
|
1179 theshadow 1.15 # bgallocButton.SetFont(self.default_font)
|
1180 theshadow 1.9 buttonSizer.Add (bgallocButton)
1181
|
1182 theshadow 1.11 buttonSizer.Add(StaticText(''))
1183
|
1184 theshadow 1.3 okButton = wxButton(panel, -1, 'Ok')
|
1185 theshadow 1.15 # okButton.SetFont(self.default_font)
|
1186 theshadow 1.11 buttonSizer.Add (okButton)
|
1187 theshadow 1.3
|
1188 theshadow 1.11 colSizer.Add (buttonSizer, 0, wxALIGN_CENTER)
1189 # colSizer.SetMinSize ((578,350))
1190 colSizer.AddGrowableCol(0)
1191 colSizer.AddGrowableRow(1)
|
1192 theshadow 1.3
1193 panel.SetSizer(colSizer)
1194 panel.SetAutoLayout(true)
1195
|
1196 theshadow 1.15 spewList.InsertColumn(0, "Optimistic Unchoke", format=wxLIST_FORMAT_CENTER, width=fw*2)
1197 spewList.InsertColumn(1, "IP", width=fw*11)
1198 spewList.InsertColumn(2, "Local/Remote", format=wxLIST_FORMAT_CENTER, width=fw*3)
1199 spewList.InsertColumn(3, "Up", format=wxLIST_FORMAT_RIGHT, width=fw*6)
1200 spewList.InsertColumn(4, "Interested", format=wxLIST_FORMAT_CENTER, width=fw*2)
1201 spewList.InsertColumn(5, "Choking", format=wxLIST_FORMAT_CENTER, width=fw*2)
|
1202 theshadow 1.19 spewList.InsertColumn(6, "Down", format=wxLIST_FORMAT_RIGHT, width=fw*6)
1203 spewList.InsertColumn(7, "Interesting", format=wxLIST_FORMAT_CENTER, width=fw*2)
1204 spewList.InsertColumn(8, "Choked", format=wxLIST_FORMAT_CENTER, width=fw*2)
1205 spewList.InsertColumn(9, "Snubbed", format=wxLIST_FORMAT_CENTER, width=fw*2)
1206 spewList.InsertColumn(10, "Downloaded", format=wxLIST_FORMAT_RIGHT, width=fw*7)
1207 spewList.InsertColumn(11, "Uploaded", format=wxLIST_FORMAT_RIGHT, width=fw*7)
1208 spewList.InsertColumn(12, "Completed", format=wxLIST_FORMAT_RIGHT, width=fw*6)
1209 spewList.InsertColumn(13, "Peer Download Speed", format=wxLIST_FORMAT_RIGHT, width=fw*6)
|
1210 theshadow 1.3
1211 def reannounce(self, frame = self):
1212 if (time () - frame.reannouncelast > 60):
1213 frame.reannouncelast = time ()
1214 frame.dow.reannounce()
1215 EVT_BUTTON(self.advBox, reannounceButton.GetId(), reannounce)
1216
|
1217 theshadow 1.11 self.advextannouncebox = None
1218 def reannounce_external(self, frame = self):
1219 if (frame.advextannouncebox is not None):
1220 try:
1221 frame.advextannouncebox.Close ()
1222 except wxPyDeadObjectError, e:
1223 frame.advextannouncebox = None
1224
1225 frame.advextannouncebox = wxFrame(None, -1, 'External Announce', size = (1,1))
1226 if (sys.platform == 'win32'):
1227 frame.advextannouncebox.SetIcon(frame.icon)
1228
1229 panel = wxPanel(frame.advextannouncebox, -1)
1230
1231 fullsizer = wxFlexGridSizer(cols = 1, vgap = 13)
|
1232 theshadow 1.14 msg = wxStaticText(panel, -1, "Enter tracker anounce URL:")
1233 msg.SetFont(frame.default_font)
1234 fullsizer.Add(msg)
|
1235 theshadow 1.11
1236 frame.advexturl = wxTextCtrl(parent = panel, id = -1, value = '',
1237 size = (255, 20), style = wxTE_PROCESS_TAB)
|
1238 theshadow 1.14 frame.advexturl.SetFont(frame.default_font)
|
1239 theshadow 1.13 frame.advexturl.SetValue(frame.lastexternalannounce)
|
1240 theshadow 1.11 fullsizer.Add(frame.advexturl)
1241
1242 buttonSizer = wxFlexGridSizer (cols = 2, hgap = 10)
1243
1244 okButton = wxButton(panel, -1, 'OK')
|
1245 theshadow 1.15 # okButton.SetFont(frame.default_font)
|
1246 theshadow 1.11 buttonSizer.Add (okButton)
1247
1248 cancelButton = wxButton(panel, -1, 'Cancel')
|
1249 theshadow 1.15 # cancelButton.SetFont(frame.default_font)
|
1250 theshadow 1.11 buttonSizer.Add (cancelButton)
1251
1252 fullsizer.Add (buttonSizer, 0, wxALIGN_CENTER)
1253
1254 border = wxBoxSizer(wxHORIZONTAL)
1255 border.Add(fullsizer, 1, wxEXPAND | wxALL, 4)
1256
1257 panel.SetSizer(border)
1258 panel.SetAutoLayout(true)
1259
1260 def ok(self, frame = frame):
|
1261 theshadow 1.13 special = frame.advexturl.GetValue()
1262 if special:
1263 frame.lastexternalannounce = special
1264 if (time () - frame.reannouncelast > 60):
1265 frame.reannouncelast = time ()
|
1266 theshadow 1.11 frame.dow.reannounce(special)
1267 frame.advextannouncebox.Close()
1268 EVT_BUTTON(frame.advextannouncebox, okButton.GetId(), ok)
1269
1270 def cancel(self, frame = frame):
1271 frame.advextannouncebox.Close()
|
1272 theshadow 1.13 EVT_BUTTON(frame.advextannouncebox, cancelButton.GetId(), cancel)
|
1273 theshadow 1.11
1274 def kill(self, frame = frame):
1275 frame.advextannouncebox.Destroy()
1276 frame.advextannouncebox = None
1277 EVT_CLOSE(frame.advextannouncebox, kill)
1278
1279 frame.advextannouncebox.Show ()
1280 fullsizer.Fit(panel)
1281 frame.advextannouncebox.Fit()
|
1282 theshadow 1.42
|
1283 theshadow 1.11 EVT_BUTTON(self.advBox, extannounceButton.GetId(), reannounce_external)
1284
|
1285 theshadow 1.9 def bgalloc(self, frame = self):
1286 if frame.dow.storagewrapper is not None:
1287 frame.dow.storagewrapper.bgalloc()
1288 EVT_BUTTON(self.advBox, bgallocButton.GetId(), bgalloc)
1289
|
1290 theshadow 1.11 def closeAdv(self, frame = self):
1291 frame.advBox.Close ()
1292 def killAdv(self, frame = self):
|
1293 theshadow 1.42 frame.dow.spewflag.clear()
|
1294 theshadow 1.11 frame.advBox.Destroy()
1295 frame.advBox = None
1296 if (frame.advextannouncebox is not None):
1297 try:
1298 frame.advextannouncebox.Close ()
1299 except wxPyDeadObjectError, e:
1300 pass
1301 frame.advextannouncebox = None
1302 EVT_BUTTON(self.advBox, okButton.GetId(), closeAdv)
1303 EVT_CLOSE(self.advBox, killAdv)
1304
|
1305 theshadow 1.3 self.advBox.Show ()
1306 colSizer.Fit(panel)
1307 self.advBox.Fit()
|
1308 theshadow 1.25 self.dow.spewflag.set()
|
1309 theshadow 1.17 except:
1310 self.exception()
|
1311 theshadow 1.1
|
1312 theshadow 1.6
1313 def displayUsage(self, text):
|
1314 theshadow 1.17 try:
|
1315 theshadow 1.6 start = self.dow.getUsageText()
|
1316 theshadow 1.9 if text[:len(start)] != start:
|
1317 theshadow 1.6 return false
1318
|
1319 theshadow 1.9 self.done(None)
|
1320 theshadow 1.6 self.usageBox = wxFrame(None, -1, 'Usage', size = (480,400))
1321 if (sys.platform == 'win32'):
1322 self.usageBox.SetIcon(self.icon)
1323
1324 panel = wxScrolledWindow(self.usageBox, -1)
1325 colSizer = wxFlexGridSizer(cols = 1)
1326
1327 colSizer.Add (wxStaticText(panel, -1, text))
1328 okButton = wxButton(panel, -1, 'Ok')
|
1329 theshadow 1.15 # okButton.SetFont(self.default_font)
|
1330 theshadow 1.6 colSizer.Add(okButton, 0, wxALIGN_RIGHT)
1331 colSizer.AddGrowableCol(0)
1332
1333
1334 def closeUsage(self, frame = self):
1335 frame.usageBox.Close()
1336 EVT_BUTTON(self.usageBox, okButton.GetId(), closeUsage)
|
1337 theshadow 1.11 def kill(self, frame = self):
1338 frame.usageBox.Destroy()
1339 frame.usageBox = None
1340 EVT_CLOSE(self.usageBox, kill)
|
1341 theshadow 1.6
1342 self.usageBox.Show ()
1343 panel.FitInside()
1344 panel.SetSizer(colSizer)
1345 panel.SetAutoLayout(true)
1346 panel.SetScrollRate(0,1)
1347 self.usageBox.Fit()
1348
1349 return true
|
1350 theshadow 1.17 except:
1351 self.exception()
|
1352 theshadow 1.6
|
1353 theshadow 1.1
1354 def updateStatus(self, fractionDone = None,
1355 timeEst = None, downRate = None, upRate = None,
|
1356 theshadow 1.3 activity = None, statistics = None, spew = None, sizeDone = None,
1357 **kws):
|
1358 theshadow 1.9 if activity is not None:
1359 self.activity = activity
|
1360 theshadow 1.11 if fractionDone is not None:
1361 self.gui_fractiondone = fractionDone
|
1362 theshadow 1.25 if self.gui_lastupdate + 0.05 > time(): # refreshing too fast, skip it
1363 return
|
1364 theshadow 1.9 if not self.ispaused:
1365 self.invokeLater(self.onUpdateStatus,
|
1366 theshadow 1.11 [timeEst, downRate, upRate, statistics, spew, sizeDone])
|
1367 theshadow 1.9
|
1368 theshadow 1.11 def onUpdateStatus(self, timeEst, downRate, upRate, statistics, spew, sizeDone):
|
1369 theshadow 1.23 if self.gui_lastupdate + 0.05 > time(): # refreshing too fast, skip it
|
1370 theshadow 1.9 return
|
1371 theshadow 1.1
|
1372 theshadow 1.6 if self.firstupdate:
1373 self.connChoice.SetStringSelection(self.configfile.configfileargs['gui_ratesettingsdefault'])
1374 self.onConnChoice(0) # force config selection for default value
1375 self.gauge.SetForegroundColour(self.configfile.checkingcolor)
1376 self.firstupdate = false
|
1377 theshadow 1.9
|
1378 theshadow 1.4 if statistics is None:
1379 self.setStatusIcon('startup')
1380 elif statistics.numPeers + statistics.numSeeds + statistics.numOldSeeds == 0:
1381 if statistics.last_failed:
1382 self.setStatusIcon('disconnected')
1383 else:
1384 self.setStatusIcon('noconnections')
|
1385 theshadow 1.14 elif ( not statistics.external_connection_made
1386 and not self.configfile.configfileargs['gui_forcegreenonfirewall'] ):
1387 self.setStatusIcon('noincoming')
1388 elif ( (statistics.numSeeds + statistics.numOldSeeds == 0)
1389 and ( (self.fin and statistics.numCopies < 1)
1390 or (not self.fin and statistics.numCopies2 < 1) ) ):
1391 self.setStatusIcon('nocompletes')
1392 else:
|
1393 theshadow 1.4 self.setStatusIcon('allgood')
1394
1395 if self.updateSliderFlag == 1:
1396 self.updateSliderFlag = 0
|
1397 theshadow 1.7 newValue = (self.rateSpinner.GetValue()
1398 / connChoices[self.connChoice.GetSelection()]['rate'].get('div',1))
1399 if self.rateslider.GetValue() != newValue:
1400 self.rateslider.SetValue(newValue)
1401
|
1402 theshadow 1.4 if self.updateSpinnerFlag == 1:
1403 self.updateSpinnerFlag = 0
|
1404 theshadow 1.40 cc = connChoices[self.connChoice.GetSelection()]
|
1405 theshadow 1.39 if cc.has_key('rate'):
1406 newValue = (self.rateslider.GetValue() * cc['rate'].get('div',1))
1407 if self.rateSpinner.GetValue() != newValue:
1408 self.rateSpinner.SetValue(newValue)
|
1409 theshadow 1.2 if self.fin:
1410 if statistics is not None:
1411 if statistics.numOldSeeds > 0 or statistics.numCopies > 1:
1412 self.gauge.SetValue(1000)
1413 else:
1414 self.gauge.SetValue(int(1000*statistics.numCopies))
|
1415 theshadow 1.11 elif self.gui_fractiondone is not None:
1416 gaugelevel = int(self.gui_fractiondone * 1000)
|
1417 theshadow 1.2 self.gauge.SetValue(gaugelevel)
|
1418 theshadow 1.3 if statistics is not None and statistics.downTotal is not None:
|
1419 theshadow 1.4 if self.configfile.configfileargs['gui_displaymiscstats']:
1420 self.frame.SetTitle('%.1f%% (%.2f MiB) %s - BitTorrent %s' % (float(gaugelevel)/10, float(sizeDone) / (1<<20), self.filename, version))
1421 else:
1422 self.frame.SetTitle('%.1f%% %s - BitTorrent %s' % (float(gaugelevel)/10, self.filename, version))
1423 self.gauge.SetForegroundColour(self.configfile.downloadcolor)
|
1424 theshadow 1.2 else:
1425 self.frame.SetTitle('%.0f%% %s - BitTorrent %s' % (float(gaugelevel)/10, self.filename, version))
|
1426 theshadow 1.1 if timeEst is not None:
|
1427 theshadow 1.2 self.timeText.SetLabel(hours(time () - self.starttime) + ' / ' + hours(timeEst))
|
1428 theshadow 1.6 else:
1429 if self.fin:
1430 self.timeText.SetLabel(self.activity)
1431 else:
1432 self.timeText.SetLabel(hours(time () - self.starttime) + ' / ' + self.activity)
|
1433 theshadow 1.1 if downRate is not None:
|
1434 theshadow 1.3 self.downRateText.SetLabel('%.0f kB/s' % (float(downRate) / 1000))
|
1435 theshadow 1.1 if upRate is not None:
|
1436 theshadow 1.3 self.upRateText.SetLabel('%.0f kB/s' % (float(upRate) / 1000))
|
1437 theshadow 1.2 if hasattr(self.frame, "tbicon"):
|
1438 theshadow 1.3 icontext='BitTorrent '
|
1439 theshadow 1.11 if self.gui_fractiondone is not None and not self.fin:
1440 if statistics is not None and statistics.downTotal is not None:
1441 icontext=icontext+' %.1f%% (%.2f MiB)' % (self.gui_fractiondone*100, float(sizeDone) / (1<<20))
1442 else:
1443 icontext=icontext+' %.0f%%' % (self.gui_fractiondone*100)
|
1444 theshadow 1.2 if upRate is not None:
|
1445 theshadow 1.3 icontext=icontext+' u:%.0f kB/s' % (float(upRate) / 1000)
|
1446 theshadow 1.2 if downRate is not None:
|
1447 theshadow 1.3 icontext=icontext+' d:%.0f kB/s' % (float(downRate) / 1000)
1448 icontext+=' %s' % self.filename
|
1449 theshadow 1.2 self.frame.tbicon.SetIcon(self.icon,icontext)
1450 if statistics is not None:
|
1451 theshadow 1.4 if self.configfile.configfileargs['gui_displaymiscstats']:
1452 self.downText.SetLabel('%.2f MiB' % (float(statistics.downTotal) / (1 << 20)))
1453 self.upText.SetLabel('%.2f MiB' % (float(statistics.upTotal) / (1 << 20)))
|
1454 theshadow 1.3 if (statistics.shareRating < 0) or (statistics.shareRating > 1000):
1455 self.shareRatingText.SetLabel('oo :-D')
1456 self.shareRatingText.SetForegroundColour('Forest Green')
1457 else:
1458 shareSmiley = ''
1459 color = 'Black'
1460 if ((statistics.shareRating >= 0) and (statistics.shareRating < 0.5)):
1461 shareSmiley = ':-('
1462 color = 'Red'
1463 else:
1464 if ((statistics.shareRating >= 0.5) and (statistics.shareRating < 1.0)):
1465 shareSmiley = ':-|'
1466 color = 'Orange'
1467 else:
1468 if (statistics.shareRating >= 1.0):
1469 shareSmiley = ':-)'
1470 color = 'Forest Green'
1471 self.shareRatingText.SetLabel('%.3f %s' % (statistics.shareRating, shareSmiley))
1472 self.shareRatingText.SetForegroundColour(color)
1473
|
1474 theshadow 1.4 if self.configfile.configfileargs['gui_displaystats']:
1475 if not self.fin:
|
1476 theshadow 1.14 self.seedStatusText.SetLabel('connected to %d seeds; also seeing %.3f distributed copies' % (statistics.numSeeds,0.001*int(1000*statistics.numCopies2)))
|
1477 theshadow 1.4 else:
1478 self.seedStatusText.SetLabel('%d seeds seen recently; also seeing %.3f distributed copies' % (statistics.numOldSeeds,0.001*int(1000*statistics.numCopies)))
1479 self.peerStatusText.SetLabel('connected to %d peers with an average of %.1f%% completed (total speed %.0f kB/s)' % (statistics.numPeers,statistics.percentDone,float(statistics.torrentRate) / (1000)))
|
1480 theshadow 1.3 if ((time () - self.lastError) > 300):
1481 self.errorText.SetLabel('')
|
1482 theshadow 1.9
1483 if ( self.configfile.configfileargs['gui_displaymiscstats']
|
1484 theshadow 1.25 and statistics is not None and statistics.backgroundallocating ):
|
1485 theshadow 1.9 self.bgalloc_periods += 1
1486 if self.bgalloc_periods > 3:
1487 self.bgalloc_periods = 0
|
1488 theshadow 1.11 self.bgallocText.SetLabel('ALLOCATING'+(' .'*self.bgalloc_periods))
|
1489 theshadow 1.27 elif self.dow.superseedflag.isSet():
|
1490 theshadow 1.15 self.bgallocText.SetLabel('SUPER-SEED')
|
1491 theshadow 1.9 else:
1492 self.bgallocText.SetLabel('')
1493
|
1494 theshadow 1.4
|
1495 theshadow 1.3 if spew is not None and (time()-self.spewwait>1):
1496 if (self.advBox is not None):
1497 self.spewwait = time()
1498 spewList = self.spewList
|
1499 theshadow 1.29 spewlen = len(spew)+2
1500 if statistics is not None:
1501 kickbanlen = len(statistics.peers_kicked)+len(statistics.peers_banned)
1502 if kickbanlen:
1503 spewlen += kickbanlen+1
1504 else:
1505 kickbanlen = 0
1506 for x in range(spewlen-spewList.GetItemCount()):
|
1507 theshadow 1.11 i = wxListItem()
|
1508 theshadow 1.15 # i.SetFont(self.default_font)
|
1509 theshadow 1.11 spewList.InsertItem(i)
|
1510 theshadow 1.29 for x in range(spewlen,spewList.GetItemCount()):
|
1511 theshadow 1.13 spewList.DeleteItem(len(spew)+1)
|
1512 theshadow 1.3
|
1513 theshadow 1.9 tot_uprate = 0.0
1514 tot_downrate = 0.0
|
1515 theshadow 1.3 for x in range(len(spew)):
1516 if (spew[x]['optimistic'] == 1):
1517 a = '*'
1518 else:
1519 a = ' '
1520 spewList.SetStringItem(x, 0, a)
1521 spewList.SetStringItem(x, 1, spew[x]['ip'])
1522 spewList.SetStringItem(x, 2, spew[x]['direction'])
1523 if spew[x]['uprate'] > 100:
1524 spewList.SetStringItem(x, 3, '%.0f kB/s' % (float(spew[x]['uprate']) / 1000))
1525 else:
|
1526 theshadow 1.4 spewList.SetStringItem(x, 3, ' ')
|
1527 theshadow 1.9 tot_uprate += spew[x]['uprate']
|
1528 theshadow 1.3 if (spew[x]['uinterested'] == 1):
1529 a = '*'
1530 else:
1531 a = ' '
1532 spewList.SetStringItem(x, 4, a)
1533 if (spew[x]['uchoked'] == 1):
1534 a = '*'
1535 else:
1536 a = ' '
1537 spewList.SetStringItem(x, 5, a)
|
1538 theshadow 1.4
|
1539 theshadow 1.3 if spew[x]['downrate'] > 100:
|
1540 theshadow 1.19 spewList.SetStringItem(x, 6, '%.0f kB/s' % (float(spew[x]['downrate']) / 1000))
|
1541 theshadow 1.3 else:
|
1542 theshadow 1.19 spewList.SetStringItem(x, 6, ' ')
|
1543 theshadow 1.9 tot_downrate += spew[x]['downrate']
|
1544 theshadow 1.4
|
1545 theshadow 1.3 if (spew[x]['dinterested'] == 1):
1546 a = '*'
1547 else:
1548 a = ' '
|
1549 theshadow 1.19 spewList.SetStringItem(x, 7, a)
|
1550 theshadow 1.3 if (spew[x]['dchoked'] == 1):
1551 a = '*'
1552 else:
1553 a = ' '
|
1554 theshadow 1.19 spewList.SetStringItem(x, 8, a)
|
1555 theshadow 1.3 if (spew[x]['snubbed'] == 1):
1556 a = '*'
1557 else:
1558 a = ' '
|
1559 theshadow 1.19 spewList.SetStringItem(x, 9, a)
1560 spewList.SetStringItem(x, 10, '%.2f MiB' % (float(spew[x]['dtotal']) / (1 << 20)))
|
1561 theshadow 1.25 if spew[x]['utotal'] is not None:
1562 a = '%.2f MiB' % (float(spew[x]['utotal']) / (1 << 20))
1563 else:
1564 a = ''
1565 spewList.SetStringItem(x, 11, a)
|
1566 theshadow 1.19 spewList.SetStringItem(x, 12, '%.1f%%' % (float(int(spew[x]['completed']*1000))/10))
|
1567 theshadow 1.25 if spew[x]['speed'] is not None:
1568 a = '%.0f kB/s' % (float(spew[x]['speed']) / 1000)
1569 else:
1570 a = ''
1571 spewList.SetStringItem(x, 13, a)
|
1572 theshadow 1.9
|
1573 theshadow 1.29 x = len(spew)
1574 for i in range(14):
1575 spewList.SetStringItem(x, i, '')
|
1576 theshadow 1.9
|
1577 theshadow 1.29 x += 1
|
1578 theshadow 1.9 spewList.SetStringItem(x, 1, ' TOTALS:')
1579 spewList.SetStringItem(x, 3, '%.0f kB/s' % (float(tot_uprate) / 1000))
|
1580 theshadow 1.19 spewList.SetStringItem(x, 6, '%.0f kB/s' % (float(tot_downrate) / 1000))
|
1581 theshadow 1.9 if statistics is not None:
|
1582 theshadow 1.19 spewList.SetStringItem(x, 10, '%.2f MiB' % (float(statistics.downTotal) / (1 << 20)))
1583 spewList.SetStringItem(x, 11, '%.2f MiB' % (float(statistics.upTotal) / (1 << 20)))
|
1584 theshadow 1.9 else:
|
1585 theshadow 1.19 spewList.SetStringItem(x, 10, '')
|
1586 theshadow 1.9 spewList.SetStringItem(x, 11, '')
|
1587 theshadow 1.29 for i in [0,2,4,5,7,8,9,12,13]:
1588 spewList.SetStringItem(x, i, '')
1589
1590 if kickbanlen:
1591 x += 1
1592 for i in range(14):
1593 spewList.SetStringItem(x, i, '')
1594
1595 for ip in statistics.peers_kicked:
1596 x += 1
1597 spewList.SetStringItem(x, 1, ip)
1598 spewList.SetStringItem(x, 3, 'KICKED')
1599 for i in [0,2,4,5,6,7,8,9,10,11,12,13]:
1600 spewList.SetStringItem(x, i, '')
1601
1602 for ip in statistics.peers_banned:
1603 x += 1
1604 spewList.SetStringItem(x, 1, ip)
1605 spewList.SetStringItem(x, 3, 'BANNED')
1606 for i in [0,2,4,5,6,7,8,9,10,11,12,13]:
1607 spewList.SetStringItem(x, i, '')
|
1608 theshadow 1.9
|
1609 theshadow 1.25 if statistics is not None:
|
1610 theshadow 1.11 self.storagestats1.SetLabel(
|
1611 theshadow 1.22 ' currently downloading %d pieces (%d just started), %d pieces partially retrieved'
|
1612 theshadow 1.25 % ( statistics.storage_active,
1613 statistics.storage_new,
1614 statistics.storage_dirty ) )
|
1615 theshadow 1.11 self.storagestats2.SetLabel(
1616 ' %d of %d pieces complete (%d just downloaded), %d failed hash check'
|
1617 theshadow 1.25 % ( statistics.storage_numcomplete,
1618 statistics.storage_totalpieces,
1619 statistics.storage_justdownloaded,
1620 statistics.storage_numflunked ) )
|
1621 theshadow 1.11
|
1622 theshadow 1.15 if ( self.fileList is not None and statistics is not None
1623 and (statistics.filelistupdated or self.refresh_details) ):
1624 self.refresh_details = false
|
1625 theshadow 1.11 statistics.filelistupdated = false
1626 for i in range(len(statistics.filecomplete)):
1627 if statistics.fileinplace[i]:
1628 self.fileList.SetItemImage(i,2,2)
1629 self.fileList.SetStringItem(i,1,"done")
1630 elif statistics.filecomplete[i]:
1631 self.fileList.SetItemImage(i,1,1)
1632 self.fileList.SetStringItem(i,1,"100%")
1633 else:
1634 frac = int((len(statistics.filepieces2[i])-len(statistics.filepieces[i]))*100
1635 /len(statistics.filepieces2[i]))
1636 if frac > 0:
1637 self.fileList.SetStringItem(i,1,'%d%%' % (frac))
|
1638 theshadow 1.9
|
1639 theshadow 1.4 if self.configfile.configReset: # whoopee! Set everything invisible! :-)
1640 self.configfile.configReset = false
|
1641 theshadow 1.14
1642 self.dow.config['security'] = self.configfile.configfileargs['security']
|
1643 theshadow 1.4
1644 statsdisplayflag = self.configfile.configfileargs['gui_displaymiscstats']
1645 self.downTextLabel.Show(statsdisplayflag)
1646 self.upTextLabel.Show(statsdisplayflag)
1647 self.fileDestLabel.Show(statsdisplayflag)
1648 self.fileDestText.Show(statsdisplayflag)
1649 self.colSizer.Layout()
1650
1651 self.downText.SetLabel('') # blank these to flush them
1652 self.upText.SetLabel('')
1653 self.seedStatusText.SetLabel('')
1654 self.peerStatusText.SetLabel('')
1655
1656 ratesettingsmode = self.configfile.configfileargs['gui_ratesettingsmode']
1657 ratesettingsflag1 = true #\ settings
1658 ratesettingsflag2 = false #/ for 'basic'
1659 if ratesettingsmode == 'none':
1660 ratesettingsflag1 = false
1661 elif ratesettingsmode == 'full':
1662 ratesettingsflag2 = true
1663 self.connChoiceLabel.Show(ratesettingsflag1)
1664 theshadow 1.4 self.connChoice.Show(ratesettingsflag1)
1665 self.rateSpinnerLabel.Show(ratesettingsflag2)
1666 self.rateSpinner.Show(ratesettingsflag2)
1667 self.rateLowerText.Show(ratesettingsflag2)
1668 self.rateUpperText.Show(ratesettingsflag2)
1669 self.rateslider.Show(ratesettingsflag2)
1670 self.connSpinnerLabel.Show(ratesettingsflag2)
1671 self.connSpinner.Show(ratesettingsflag2)
1672 self.connLowerText.Show(ratesettingsflag2)
1673 self.connUpperText.Show(ratesettingsflag2)
1674 self.connslider.Show(ratesettingsflag2)
1675 self.unlimitedLabel.Show(ratesettingsflag2)
1676
1677 if statistics is None or statistics.downTotal is None:
1678 self.gauge.SetForegroundColour(self.configfile.checkingcolor)
1679 self.gauge.SetBackgroundColour(wx.wxSystemSettings_GetColour(wxSYS_COLOUR_MENU))
1680 elif self.fin:
1681 self.gauge.SetForegroundColour(self.configfile.seedingcolor)
1682 self.gauge.SetBackgroundColour(self.configfile.downloadcolor)
1683 else:
1684 self.gauge.SetForegroundColour(self.configfile.downloadcolor)
1685 theshadow 1.4 self.gauge.SetBackgroundColour(wx.wxSystemSettings_GetColour(wxSYS_COLOUR_MENU))
|
1686 theshadow 1.5
|
1687 theshadow 1.44 self.frame.Layout()
1688 self.frame.Refresh()
|
1689 theshadow 1.9
1690 self.gui_lastupdate = time()
|
1691 theshadow 1.11 self.gui_fractiondone = None
|
1692 theshadow 1.4
1693
|
1694 theshadow 1.1 def finished(self):
1695 self.fin = true
1696 self.invokeLater(self.onFinishEvent)
1697
1698 def failed(self):
1699 self.fin = true
1700 self.invokeLater(self.onFailEvent)
1701
1702 def error(self, errormsg):
1703 self.invokeLater(self.onErrorEvent, [errormsg])
1704
1705 def onFinishEvent(self):
|
1706 theshadow 1.6 self.activity = hours(time () - self.starttime) + ' / ' +'Download Succeeded!'
|
1707 theshadow 1.1 self.cancelButton.SetLabel('Finish')
|
1708 theshadow 1.4 self.gauge.SetBackgroundColour(self.configfile.downloadcolor)
|
1709 theshadow 1.2 self.gauge.SetValue(0)
|
1710 theshadow 1.4 self.gauge.SetForegroundColour(self.configfile.seedingcolor)
|
1711 theshadow 1.1 self.frame.SetTitle('%s - Upload - BitTorrent %s' % (self.filename, version))
|
1712 theshadow 1.2 if (sys.platform == 'win32'):
|
1713 theshadow 1.4 self.icon = wxIcon(os.path.join(basepath,'icon_done.ico'), wxBITMAP_TYPE_ICO)
|
1714 theshadow 1.2 self.frame.SetIcon(self.icon)
1715 if hasattr(self.frame, "tbicon"):
1716 self.frame.tbicon.SetIcon(self.icon, "BitTorrent - Finished")
|
1717 theshadow 1.1 self.downRateText.SetLabel('')
1718
1719 def onFailEvent(self):
|
1720 theshadow 1.6 if not self.shuttingdown:
1721 self.timeText.SetLabel(hours(time () - self.starttime) + ' / ' +'Failed!')
1722 self.activity = 'Failed!'
1723 self.cancelButton.SetLabel('Close')
1724 self.gauge.SetValue(0)
1725 self.downRateText.SetLabel('')
|
1726 theshadow 1.30 self.setStatusIcon('startup')
|
1727 theshadow 1.1
1728 def onErrorEvent(self, errormsg):
|
1729 theshadow 1.6 if not self.displayUsage(errormsg):
|
1730 theshadow 1.14 if errormsg[:2] == ' ': # indent at least 2 spaces means a warning message
1731 self.errorText.SetLabel(errormsg)
1732 self.lastError = time ()
1733 else:
1734 self.errorText.SetLabel(strftime('ERROR (%I:%M %p) -\n') + errormsg)
1735 self.lastError = time ()
|
1736 theshadow 1.6
|
1737 theshadow 1.1
1738 def chooseFile(self, default, size, saveas, dir):
1739 f = Event()
1740 bucket = [None]
|
1741 theshadow 1.3 self.invokeLater(self.onChooseFile, [default, bucket, f, size, dir, saveas])
|
1742 theshadow 1.1 f.wait()
1743 return bucket[0]
1744
|
1745 theshadow 1.3 def onChooseFile(self, default, bucket, f, size, dir, saveas):
|
1746 theshadow 1.9 if saveas == '':
1747 if self.configfile.configfileargs['gui_default_savedir'] != '':
1748 start_dir = self.configfile.configfileargs['gui_default_savedir']
1749 else:
1750 start_dir = self.configfile.configfileargs['last_saved']
1751 if not isdir(start_dir): # if it's not set properly
1752 start_dir = '/' # yes, this hack does work in Windows
|
1753 theshadow 1.3 if dir:
|
1754 theshadow 1.9 if isdir(join(start_dir,default)):
1755 start_dir = join(start_dir,default)
1756 dl = wxDirDialog(self.frame,
1757 'Choose a directory to save to, pick a partial download to resume',
1758 defaultPath = start_dir, style = wxDD_DEFAULT_STYLE | wxDD_NEW_DIR_BUTTON)
|
1759 theshadow 1.3 else:
|
1760 theshadow 1.9 dl = wxFileDialog(self.frame,
1761 'Choose file to save as, pick a partial download to resume',
|
1762 theshadow 1.38 defaultDir = start_dir, defaultFile = default, wildcard = '*',
|
1763 theshadow 1.9 style = wxSAVE)
1764
1765 if dl.ShowModal() != wxID_OK:
1766 f.set()
1767 self.done(None)
1768 return
1769
1770 d = dl.GetPath()
1771 bucket[0] = d
1772 d1,d2 = split(d)
1773 if d2 == default:
1774 d = d1
1775 self.configfile.WriteLastSaved(d)
1776
1777 else:
1778 bucket[0] = saveas
1779 default = basename(saveas)
|
1780 theshadow 1.3
|
1781 theshadow 1.9 self.fileNameText.SetLabel('%s' % (default))
1782 self.fileSizeText.SetLabel('(%.2f MiB)' % (float(size) / (1 << 20)))
1783 self.timeText.SetLabel(hours(time () - self.starttime) + ' / ' + self.activity)
1784 self.fileDestText.SetLabel(bucket[0])
1785 self.filename = default
1786 self.frame.SetTitle(default + '- BitTorrent ' + version)
1787
1788 minsize = self.fileNameText.GetBestSize()
1789 if (not self.configfile.configfileargs['gui_stretchwindow'] or
1790 minsize.GetWidth() < self.addwidth):
1791 minsize.SetWidth(self.addwidth)
1792 self.fnsizer.SetMinSize (minsize)
1793 minsize.SetHeight(self.fileSizeText.GetBestSize().GetHeight())
1794 self.fnsizer2.SetMinSize (minsize)
|
1795 theshadow 1.31 minsize.SetWidth(minsize.GetWidth()+(self.FONT*8))
|
1796 theshadow 1.9 minsize.SetHeight(self.fileNameText.GetBestSize().GetHeight()+self.fileSizeText.GetBestSize().GetHeight())
1797 minsize.SetHeight(2*self.errorText.GetBestSize().GetHeight())
1798 self.errorTextSizer.SetMinSize(minsize)
1799 self.topboxsizer.SetMinSize(minsize)
1800
1801 # Kludge to make details and about catch the event
1802 self.frame.SetSize ((self.frame.GetSizeTuple()[0]+1, self.frame.GetSizeTuple()[1]+1))
1803 self.frame.SetSize ((self.frame.GetSizeTuple()[0]-1, self.frame.GetSizeTuple()[1]-1))
1804 self.colSizer.Fit(self.frame)
|
1805 theshadow 1.44 self.frame.Layout()
1806 self.frame.Refresh()
1807 f.set()
|
1808 theshadow 1.1
1809 def newpath(self, path):
1810 self.fileDestText.SetLabel(path)
1811
|
1812 theshadow 1.7 def pause(self, event):
1813 self.invokeLater(self.onPause)
1814
1815 def onPause(self):
1816 if self.ispaused:
1817 self.ispaused = false
1818 self.pauseButton.SetLabel('Pause')
1819 self.dow.Unpause()
1820 else:
|
1821 theshadow 1.17 if self.dow.Pause():
1822 self.ispaused = true
1823 self.pauseButton.SetLabel('Resume')
1824 self.downRateText.SetLabel(' ')
1825 self.upRateText.SetLabel(' ')
1826 self.seedStatusText.SetLabel(' ')
1827 self.peerStatusText.SetLabel(' ')
1828 self.setStatusIcon('startup')
|
1829 theshadow 1.7
|
1830 theshadow 1.1 def done(self, event):
|
1831 theshadow 1.6 self.uiflag.set()
|
1832 theshadow 1.43 self.flag.set()
|
1833 theshadow 1.6 self.shuttingdown = true
|
1834 theshadow 1.2 if hasattr(self.frame, "tbicon"):
1835 self.frame.tbicon.Destroy()
1836 del self.frame.tbicon
|
1837 theshadow 1.7 if self.ispaused:
1838 self.dow.Unpause()
|
1839 theshadow 1.2 if (self.detailBox is not None):
1840 try:
1841 self.detailBox.Close ()
1842 except wxPyDeadObjectError, e:
1843 self.detailBox = None
1844 if (self.aboutBox is not None):
1845 try:
1846 self.aboutBox.Close ()
1847 except wxPyDeadObjectError, e:
1848 self.aboutBox = None
1849 if (self.creditsBox is not None):
1850 try:
1851 self.creditsBox.Close ()
1852 except wxPyDeadObjectError, e:
1853 self.creditsBox = None
|
1854 theshadow 1.3 if (self.advBox is not None):
1855 try:
1856 self.advBox.Close ()
1857 except wxPyDeadObjectError, e:
1858 self.advBox = None
|
1859 theshadow 1.6
1860 if (self.statusIconHelpBox is not None):
1861 try:
1862 self.statusIconHelpBox.Close ()
1863 except wxPyDeadObjectError, e:
1864 self.statusIconHelpBox = None
1865 self.configfile.Close()
|
1866 theshadow 1.1 self.frame.Destroy()
1867
|
1868 theshadow 1.16 def exception(self):
1869 data = StringIO()
1870 print_exc(file = data)
1871 print data.getvalue() # report exception here too
1872 self.on_errorwindow(data.getvalue())
1873
|
1874 theshadow 1.15 def errorwindow(self, err):
1875 self.invokeLater(self.on_errorwindow,[err])
1876
1877 def on_errorwindow(self, err):
1878 if self._errorwindow is None:
1879 w = wxFrame(None, -1, 'BITTORRENT ERROR', size = (1,1))
1880 panel = wxPanel(w, -1)
1881 sizer = wxFlexGridSizer(cols = 1)
1882
|
1883 theshadow 1.20 t = ( 'BitTorrent ' + version + '\n' +
1884 'OS: ' + sys.platform + '\n' +
1885 'Python version: ' + sys.version + '\n' +
1886 'wxWindows version: ' + wxVERSION_STRING + '\n' )
1887
1888 try:
1889 t += 'Psyco version: ' + hex(psyco.__version__)[2:] + '\n'
1890 except:
1891 pass
|
1892 theshadow 1.37 try:
1893 t += 'Allocation method: ' + self.config['alloc_type']
1894 if self.dow.storagewrapper.bgalloc_active:
1895 t += '*'
1896 t += '\n'
1897 except:
1898 pass
|
1899 theshadow 1.20
1900 sizer.Add(wxTextCtrl(panel, -1, t + '\n' + err,
|
1901 theshadow 1.17 size = (500,300), style = wxTE_READONLY|wxTE_MULTILINE))
|
1902 theshadow 1.15
|
1903 theshadow 1.16 sizer.Add(wxStaticText(panel, -1,
1904 '\nHelp us iron out the bugs in the engine!' +
1905 '\nPlease report this error to info@degreez.net'))
|
1906 theshadow 1.15
1907 border = wxBoxSizer(wxHORIZONTAL)
1908 border.Add(sizer, 1, wxEXPAND | wxALL, 4)
1909
1910 panel.SetSizer(border)
1911 panel.SetAutoLayout(true)
1912
1913 w.Show()
1914 border.Fit(panel)
1915 w.Fit()
1916 self._errorwindow = w
1917
|
1918 theshadow 1.2
|
1919 theshadow 1.1 class btWxApp(wxApp):
1920 def __init__(self, x, params):
1921 self.params = params
|
1922 theshadow 1.13 self.configfile = configReader()
|
1923 theshadow 1.1 wxApp.__init__(self, x)
1924
1925 def OnInit(self):
1926 doneflag = Event()
|
1927 theshadow 1.13 d = DownloadInfoFrame(doneflag, self.configfile)
|
1928 theshadow 1.1 self.SetTopWindow(d.frame)
|
1929 theshadow 1.3 if len(self.params) == 0:
|
1930 theshadow 1.9 b = wxFileDialog (d.frame, 'Choose .torrent file to use',
1931 defaultDir = '', defaultFile = '', wildcard = '*.torrent',
1932 style = wxOPEN)
|
1933 theshadow 1.11
|
1934 theshadow 1.6 if b.ShowModal() == wxID_OK:
|
1935 theshadow 1.3 self.params.append (b.GetPath())
1936
|
1937 theshadow 1.13 thread = Thread(target = next, args = [self.params, d, doneflag, self.configfile])
|
1938 theshadow 1.1 thread.setDaemon(false)
1939 thread.start()
1940 return 1
1941
1942 def run(params):
1943 app = btWxApp(0, params)
1944 app.MainLoop()
1945
|
1946 theshadow 1.13 def next(params, d, doneflag, configfile):
|
1947 theshadow 1.11 if PROFILER:
1948 import profile, pstats
1949 p = profile.Profile()
|
1950 theshadow 1.13 p.runcall(_next, params, d, doneflag, configfile)
|
1951 theshadow 1.11 log = open('profile_data.'+strftime('%y%m%d%H%M%S')+'.txt','a')
1952 normalstdout = sys.stdout
1953 sys.stdout = log
|
1954 theshadow 1.45 # pstats.Stats(p).strip_dirs().sort_stats('cumulative').print_stats()
1955 pstats.Stats(p).strip_dirs().sort_stats('time').print_stats()
|
1956 theshadow 1.11 sys.stdout = normalstdout
1957 else:
|
1958 theshadow 1.13 _next(params, d, doneflag, configfile)
|
1959 theshadow 1.11
|
1960 theshadow 1.13 def _next(params, d, doneflag, configfile):
|
1961 theshadow 1.15 dow = Download()
|
1962 theshadow 1.2 d.dow = dow
|
1963 theshadow 1.13 configfile.setDownloadDefaults(dow.getDefaults())
|
1964 theshadow 1.4 d.configfile = configfile
1965 d.configfileargs = d.configfile.configfileargs
|
1966 theshadow 1.15 try:
1967 dow.download(params, d.chooseFile, d.updateStatus, d.finished, d.error, doneflag, 100,
1968 d.newpath, d.configfileargs, d.errorwindow)
1969 except:
1970 data = StringIO()
|
1971 theshadow 1.16 print_exc(file = data)
|
1972 theshadow 1.15 print data.getvalue() # report exception here too
1973 d.errorwindow(data.getvalue())
|
1974 theshadow 1.1 if not d.fin:
1975 d.failed()
|
1976 theshadow 1.11
|
1977 theshadow 1.1
1978 if __name__ == '__main__':
|
1979 theshadow 1.48 if argv[1:] == ['--version']:
1980 print version
1981 sys.exit(0)
|
1982 theshadow 1.1 run(argv[1:])
|