~ubuntu-branches/ubuntu/trusty/bittornado/trusty-proposed

« back to all changes in this revision

Viewing changes to .pc/32_use_hashlib_for_sha.patch/btdownloadgui.py

  • Committer: Bazaar Package Importer
  • Author(s): Ronny Cardona (Rcart)
  • Date: 2011-01-24 17:27:47 UTC
  • Revision ID: james.westby@ubuntu.com-20110124172747-j2en9t9kja4cgl06
Tags: 0.3.18-10ubuntu1
* debian/patches/32_use_hashlib_for_sha.patch:
  - Updated use of deprecated sha module to hashlib. (LP: #420387,
  Closes: #593653) 

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#!/usr/bin/env python
 
2
 
 
3
# Written by Bram Cohen and Myers Carpenter
 
4
# Modifications by various people
 
5
# see LICENSE.txt for license information
 
6
 
 
7
from BitTornado import PSYCO
 
8
if PSYCO.psyco:
 
9
    try:
 
10
        import psyco
 
11
        assert psyco.__version__ >= 0x010100f0
 
12
        psyco.full()
 
13
    except:
 
14
        pass
 
15
 
 
16
from sys import argv, version, exit
 
17
assert version >= '2', "Install Python 2.0 or greater"
 
18
 
 
19
try:
 
20
    import wx
 
21
except:
 
22
    print 'wxPython is either not installed or has not been installed properly.'
 
23
    exit(1)
 
24
from BitTornado.download_bt1 import BT1Download, defaults, parse_params, get_usage, get_response
 
25
from BitTornado.RawServer import RawServer, UPnP_ERROR
 
26
from random import seed
 
27
from socket import error as socketerror
 
28
from BitTornado.ConnChoice import *
 
29
from BitTornado.ConfigReader import configReader
 
30
from BitTornado.bencode import bencode, bdecode
 
31
from BitTornado.natpunch import UPnP_test
 
32
from threading import Event, Thread
 
33
from os.path import *
 
34
from os import getcwd
 
35
from time import strftime, time, localtime, sleep
 
36
from BitTornado.clock import clock
 
37
from webbrowser import open_new
 
38
from traceback import print_exc
 
39
from StringIO import StringIO
 
40
from sha import sha
 
41
import re
 
42
import sys, os
 
43
from BitTornado import version, createPeerID, report_email
 
44
 
 
45
try:
 
46
    True
 
47
except:
 
48
    True = 1
 
49
    False = 0
 
50
 
 
51
PROFILER = False
 
52
WXPROFILER = False
 
53
 
 
54
# Note to packagers: edit OLDICONPATH in BitTornado/ConfigDir.py
 
55
 
 
56
def hours(n):
 
57
    if n == 0:
 
58
        return 'download complete'
 
59
    try:
 
60
        n = int(n)
 
61
        assert n >= 0 and n < 5184000  # 60 days
 
62
    except:
 
63
        return '<unknown>'
 
64
    m, s = divmod(n, 60)
 
65
    h, m = divmod(m, 60)
 
66
    if h > 0:
 
67
        return '%d hour(s) %02d min %02d sec' % (h, m, s)
 
68
    else:
 
69
        return '%d min %02d sec' % (m, s)
 
70
 
 
71
def size_format(s):
 
72
    if (s < 1024):
 
73
        r = str(s) + 'B'
 
74
    elif (s < 1048576):
 
75
        r = str(int(s/1024)) + 'KiB'
 
76
    elif (s < 1073741824L):
 
77
        r = str(int(s/1048576)) + 'MiB'
 
78
    elif (s < 1099511627776L):
 
79
        r = str(int((s/1073741824.0)*100.0)/100.0) + 'GiB'
 
80
    else:
 
81
        r = str(int((s/1099511627776.0)*100.0)/100.0) + 'TiB'
 
82
    return(r)
 
83
 
 
84
def comma_format(s):
 
85
    r = str(s)
 
86
    for i in range(len(r)-3, 0, -3):
 
87
        r = r[:i]+','+r[i:]
 
88
    return(r)
 
89
 
 
90
hexchars = '0123456789abcdef'
 
91
hexmap = []
 
92
for i in xrange(256):
 
93
    x = hexchars[(i&0xF0)/16]+hexchars[i&0x0F]
 
94
    hexmap.append(x)
 
95
 
 
96
def tohex(s):
 
97
    r = []
 
98
    for c in s:
 
99
        r.append(hexmap[ord(c)])
 
100
    return ''.join(r)
 
101
 
 
102
wxEVT_INVOKE = wx.NewEventType()
 
103
 
 
104
def EVT_INVOKE(win, func):
 
105
    win.Connect(-1, -1, wxEVT_INVOKE, func)
 
106
 
 
107
class InvokeEvent(wx.PyEvent):
 
108
    def __init__(self, func = None, args = None, kwargs = None):
 
109
        wx.PyEvent.__init__(self)
 
110
        self.SetEventType(wxEVT_INVOKE)
 
111
        self.func = func
 
112
        self.args = args
 
113
        self.kwargs = kwargs
 
114
 
 
115
 
 
116
 
 
117
class DownloadInfoFrame:
 
118
    def __init__(self, flag, configfile):
 
119
        self._errorwindow = None
 
120
        try:
 
121
            self.FONT = configfile.config['gui_font']
 
122
            self.default_font = wx.Font(self.FONT, wx.DEFAULT, wx.NORMAL, wx.NORMAL, False)
 
123
            frame = wx.Frame(None, -1, 'BitTorrent ' + version + ' download',
 
124
                            style = wx.DEFAULT_FRAME_STYLE|wx.FULL_REPAINT_ON_RESIZE)
 
125
            self.flag = flag
 
126
            self.configfile = configfile
 
127
            self.configfileargs = configfile.config
 
128
            self.uiflag = Event()
 
129
            self.fin = False
 
130
            self.aboutBox = None
 
131
            self.detailBox = None
 
132
            self.advBox = None
 
133
            self.creditsBox = None
 
134
            self.statusIconHelpBox = None
 
135
            self.reannouncelast = 0
 
136
            self.spinlock = 0
 
137
            self.scrollock = 0
 
138
            self.lastError = 0
 
139
            self.spewwait = clock()
 
140
            self.config = None
 
141
            self.updateSpinnerFlag = 0
 
142
            self.updateSliderFlag = 0
 
143
            self.statusIconValue = ' '
 
144
            self.iconized = 0
 
145
            self.taskbaricon = False
 
146
            self.checking = None
 
147
            self.activity = 'Starting up...'
 
148
            self.firstupdate = True
 
149
            self.shuttingdown = False
 
150
            self.ispaused = False
 
151
            self.bgalloc_periods = 0
 
152
            self.gui_fractiondone = None
 
153
            self.fileList = None
 
154
            self.lastexternalannounce = ''
 
155
            self.refresh_details = False
 
156
            self.lastuploadsettings = 0
 
157
            self.old_download = 0
 
158
            self.old_upload = 0
 
159
            self.old_ratesettings = None
 
160
            self.current_ratesetting = None
 
161
            self.gaugemode = None
 
162
            self.autorate = False
 
163
            
 
164
            self.filename = None
 
165
            self.dow = None
 
166
            if sys.platform == 'win32':
 
167
                self.invokeLaterEvent = InvokeEvent()
 
168
                self.invokeLaterList = []
 
169
 
 
170
            wx.InitAllImageHandlers()
 
171
            self.basepath = self.configfile.getIconDir()
 
172
            self.icon = wx.Icon(os.path.join(self.basepath,'icon_bt.ico'), wx.BITMAP_TYPE_ICO)
 
173
            self.finicon = wx.Icon(os.path.join(self.basepath,'icon_done.ico'), wx.BITMAP_TYPE_ICO)
 
174
            self.statusIconFiles={
 
175
                'startup':os.path.join(self.basepath,'white.ico'),
 
176
                'disconnected':os.path.join(self.basepath,'black.ico'),
 
177
                'noconnections':os.path.join(self.basepath,'red.ico'),
 
178
                'nocompletes':os.path.join(self.basepath,'blue.ico'),
 
179
                'noincoming':os.path.join(self.basepath,'yellow.ico'),
 
180
                'allgood':os.path.join(self.basepath,'green.ico'),
 
181
                }
 
182
            self.statusIcons={}
 
183
            self.filestatusIcons = wx.ImageList(16, 16)
 
184
            self.filestatusIcons.Add(wx.Bitmap(os.path.join(self.basepath,'black1.ico'),wx.BITMAP_TYPE_ICO))
 
185
            self.filestatusIcons.Add(wx.Bitmap(os.path.join(self.basepath,'yellow1.ico'), wx.BITMAP_TYPE_ICO))
 
186
            self.filestatusIcons.Add(wx.Bitmap(os.path.join(self.basepath,'green1.ico'), wx.BITMAP_TYPE_ICO))
 
187
 
 
188
            self.allocbuttonBitmap = wx.Bitmap(os.path.join(self.basepath,'alloc.gif'), wx.BITMAP_TYPE_GIF)
 
189
 
 
190
            self.starttime = clock()
 
191
 
 
192
            self.frame = frame
 
193
            try:
 
194
                self.frame.SetIcon(self.icon)
 
195
            except:
 
196
                pass
 
197
 
 
198
            panel = wx.Panel(frame, -1)
 
199
            self.bgcolor = panel.GetBackgroundColour()
 
200
 
 
201
            def StaticText(text, font = self.FONT-1, underline = False, color = None, panel = panel):
 
202
                x = wx.StaticText(panel, -1, text, style = wx.ALIGN_LEFT)
 
203
                x.SetFont(wx.Font(font, wx.DEFAULT, wx.NORMAL, wx.NORMAL, underline))
 
204
                if color is not None:
 
205
                    x.SetForegroundColour(color)
 
206
                return x
 
207
 
 
208
            colSizer = wx.FlexGridSizer(cols = 1, vgap = 3)
 
209
 
 
210
            border = wx.BoxSizer(wx.HORIZONTAL)
 
211
            border.Add(colSizer, 1, wx.EXPAND | wx.ALL, 4)
 
212
            panel.SetSizer(border)
 
213
            panel.SetAutoLayout(True)
 
214
 
 
215
            topboxsizer = wx.FlexGridSizer(cols = 3, vgap = 0)
 
216
            topboxsizer.AddGrowableCol (0)
 
217
 
 
218
            fnsizer = wx.FlexGridSizer(cols = 1, vgap = 0)
 
219
            fnsizer.AddGrowableCol (0)
 
220
            fnsizer.AddGrowableRow (1)
 
221
 
 
222
            fileNameText = StaticText('', self.FONT+4)
 
223
            fnsizer.Add(fileNameText, 1, wx.ALIGN_BOTTOM|wx.EXPAND)
 
224
            self.fileNameText = fileNameText
 
225
 
 
226
            fnsizer2 = wx.FlexGridSizer(cols = 8, vgap = 0)
 
227
            fnsizer2.AddGrowableCol (0)
 
228
 
 
229
            fileSizeText = StaticText('')
 
230
            fnsizer2.Add(fileSizeText, 1, wx.ALIGN_BOTTOM|wx.EXPAND)
 
231
            self.fileSizeText = fileSizeText
 
232
 
 
233
            fileDetails = StaticText('Details', self.FONT, True, 'Blue')
 
234
            fnsizer2.Add(fileDetails, 0, wx.ALIGN_BOTTOM)
 
235
 
 
236
            fnsizer2.Add(StaticText('  '))
 
237
 
 
238
            advText = StaticText('Advanced', self.FONT, True, 'Blue')
 
239
            fnsizer2.Add(advText, 0, wx.ALIGN_BOTTOM)
 
240
            fnsizer2.Add(StaticText('  '))
 
241
 
 
242
            prefsText = StaticText('Prefs', self.FONT, True, 'Blue')
 
243
            fnsizer2.Add(prefsText, 0, wx.ALIGN_BOTTOM)
 
244
            fnsizer2.Add(StaticText('  '))
 
245
 
 
246
            aboutText = StaticText('About', self.FONT, True, 'Blue')
 
247
            fnsizer2.Add(aboutText, 0, wx.ALIGN_BOTTOM)
 
248
 
 
249
            fnsizer2.Add(StaticText('  '))
 
250
            fnsizer.Add(fnsizer2,0,wx.EXPAND)
 
251
            topboxsizer.Add(fnsizer,0,wx.EXPAND)
 
252
            topboxsizer.Add(StaticText('  '))
 
253
 
 
254
            self.statusIcon = wx.EmptyBitmap(32,32)
 
255
            statidata = wx.MemoryDC()
 
256
            statidata.SelectObject(self.statusIcon)
 
257
            statidata.SetPen(wx.TRANSPARENT_PEN)
 
258
            statidata.SetBrush(wx.Brush(self.bgcolor,wx.SOLID))
 
259
            statidata.DrawRectangle(0,0,32,32)
 
260
            self.statusIconPtr = wx.StaticBitmap(panel, -1, self.statusIcon)
 
261
            topboxsizer.Add(self.statusIconPtr)
 
262
 
 
263
            self.fnsizer = fnsizer
 
264
            self.fnsizer2 = fnsizer2
 
265
            self.topboxsizer = topboxsizer
 
266
            colSizer.Add(topboxsizer, 0, wx.EXPAND)
 
267
 
 
268
            self.gauge = wx.Gauge(panel, -1, range = 1000, style = wx.GA_SMOOTH)
 
269
            colSizer.Add(self.gauge, 0, wx.EXPAND)
 
270
 
 
271
            timeSizer = wx.FlexGridSizer(cols = 2)
 
272
            timeSizer.Add(StaticText('Time elapsed / estimated : '))
 
273
            self.timeText = StaticText(self.activity+'                    ')
 
274
            timeSizer.Add(self.timeText)
 
275
            timeSizer.AddGrowableCol(1)
 
276
            colSizer.Add(timeSizer)
 
277
 
 
278
            destSizer = wx.FlexGridSizer(cols = 2, hgap = 8)
 
279
            self.fileDestLabel = StaticText('Download to:')
 
280
            destSizer.Add(self.fileDestLabel)
 
281
            self.fileDestText = StaticText('')
 
282
            destSizer.Add(self.fileDestText, flag = wx.EXPAND)
 
283
            destSizer.AddGrowableCol(1)
 
284
            colSizer.Add(destSizer, flag = wx.EXPAND)
 
285
            self.destSizer = destSizer
 
286
 
 
287
            statSizer = wx.FlexGridSizer(cols = 3, hgap = 8)
 
288
 
 
289
            self.ratesSizer = wx.FlexGridSizer(cols = 2)
 
290
            self.infoSizer = wx.FlexGridSizer(cols = 2)
 
291
 
 
292
            self.ratesSizer.Add(StaticText('   Download rate: '))
 
293
            self.downRateText = StaticText('0 kB/s       ')
 
294
            self.ratesSizer.Add(self.downRateText, flag = wx.EXPAND)
 
295
 
 
296
            self.downTextLabel = StaticText('Downloaded: ')
 
297
            self.infoSizer.Add(self.downTextLabel)
 
298
            self.downText = StaticText('0.00 MiB        ')
 
299
            self.infoSizer.Add(self.downText, flag = wx.EXPAND)
 
300
 
 
301
            self.ratesSizer.Add(StaticText('   Upload rate: '))
 
302
            self.upRateText = StaticText('0 kB/s       ')
 
303
            self.ratesSizer.Add(self.upRateText, flag = wx.EXPAND)
 
304
 
 
305
            self.upTextLabel = StaticText('Uploaded: ')
 
306
            self.infoSizer.Add(self.upTextLabel)
 
307
            self.upText = StaticText('0.00 MiB        ')
 
308
            self.infoSizer.Add(self.upText, flag = wx.EXPAND)
 
309
 
 
310
            shareSizer = wx.FlexGridSizer(cols = 2, hgap = 8)
 
311
            shareSizer.Add(StaticText('Share rating:'))
 
312
            self.shareRatingText = StaticText('')
 
313
            shareSizer.AddGrowableCol(1)
 
314
            shareSizer.Add(self.shareRatingText, flag = wx.EXPAND)
 
315
 
 
316
            statSizer.Add(self.ratesSizer)
 
317
            statSizer.Add(self.infoSizer)
 
318
            statSizer.Add(shareSizer, flag = wx.ALIGN_CENTER_VERTICAL)
 
319
            colSizer.Add (statSizer)
 
320
 
 
321
            torrentSizer = wx.FlexGridSizer(cols = 1)
 
322
            self.peerStatusText = StaticText('')
 
323
            torrentSizer.Add(self.peerStatusText, 0, wx.EXPAND)
 
324
            self.seedStatusText = StaticText('')
 
325
            torrentSizer.Add(self.seedStatusText, 0, wx.EXPAND)
 
326
            torrentSizer.AddGrowableCol(0)
 
327
            colSizer.Add(torrentSizer, 0, wx.EXPAND)
 
328
            self.torrentSizer = torrentSizer
 
329
 
 
330
            self.errorTextSizer = wx.FlexGridSizer(cols = 1)
 
331
            self.errorText = StaticText('', self.FONT, False, 'Red')
 
332
            self.errorTextSizer.Add(self.errorText, 0, wx.EXPAND)
 
333
            colSizer.Add(self.errorTextSizer, 0, wx.EXPAND)
 
334
 
 
335
            cancelSizer=wx.GridSizer(cols = 2, hgap = 40)
 
336
            self.pauseButton = wx.Button(panel, -1, 'Pause')
 
337
            cancelSizer.Add(self.pauseButton, 0, wx.ALIGN_CENTER)
 
338
 
 
339
            self.cancelButton = wx.Button(panel, -1, 'Cancel')
 
340
            cancelSizer.Add(self.cancelButton, 0, wx.ALIGN_CENTER)
 
341
            colSizer.Add(cancelSizer, 0, wx.ALIGN_CENTER)
 
342
 
 
343
            # Setting options
 
344
 
 
345
            slideSizer = wx.FlexGridSizer(cols = 7, hgap = 0, vgap = 5)
 
346
 
 
347
            # dropdown
 
348
 
 
349
            self.connChoiceLabel = StaticText('Settings for ')
 
350
            slideSizer.Add (self.connChoiceLabel, 0, wx.ALIGN_LEFT|wx.ALIGN_CENTER_VERTICAL)
 
351
            self.connChoice = wx.Choice (panel, -1, (-1, -1), (self.FONT*12, -1),
 
352
                                        choices = connChoiceList)
 
353
            self.connChoice.SetFont(self.default_font)
 
354
            self.connChoice.SetSelection(0)
 
355
            slideSizer.Add (self.connChoice, 0, wx.ALIGN_CENTER)
 
356
            self.rateSpinnerLabel = StaticText(' Upload rate (kB/s) ')
 
357
            slideSizer.Add (self.rateSpinnerLabel, 0, wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL)
 
358
 
 
359
            # max upload rate
 
360
 
 
361
            self.rateSpinner = wx.SpinCtrl (panel, -1, "", (-1,-1), (50, -1))
 
362
            self.rateSpinner.SetFont(self.default_font)
 
363
            self.rateSpinner.SetRange(0,5000)
 
364
            self.rateSpinner.SetValue(0)
 
365
            slideSizer.Add (self.rateSpinner, 0, wx.ALIGN_CENTER|wx.ALIGN_CENTER_VERTICAL)
 
366
 
 
367
            self.rateLowerText = StaticText('  %5d' % (0))
 
368
            self.rateUpperText = StaticText('%5d' % (5000))
 
369
            self.rateslider = wx.Slider(panel, -1, 0, 0, 5000, (-1, -1), (80, -1))
 
370
 
 
371
            slideSizer.Add(self.rateLowerText, 0, wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL)
 
372
            slideSizer.Add(self.rateslider,    0, wx.ALIGN_CENTER|wx.ALIGN_CENTER_VERTICAL)
 
373
            slideSizer.Add(self.rateUpperText, 0, wx.ALIGN_LEFT|wx.ALIGN_CENTER_VERTICAL)
 
374
 
 
375
            slideSizer.Add(StaticText(''), 0, wx.ALIGN_LEFT)
 
376
 
 
377
            self.bgallocText = StaticText('', self.FONT+2, False, 'Red')
 
378
            slideSizer.Add(self.bgallocText, 0, wx.ALIGN_LEFT)
 
379
 
 
380
            # max uploads
 
381
 
 
382
            self.connSpinnerLabel = StaticText(' Max uploads ')
 
383
            slideSizer.Add (self.connSpinnerLabel, 0, wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL)
 
384
            self.connSpinner = wx.SpinCtrl (panel, -1, "", (-1,-1), (50, -1))
 
385
            self.connSpinner.SetFont(self.default_font)
 
386
            self.connSpinner.SetRange(4,100)
 
387
            self.connSpinner.SetValue(4)
 
388
            slideSizer.Add (self.connSpinner, 0, wx.ALIGN_CENTER|wx.ALIGN_CENTER_VERTICAL)
 
389
 
 
390
            self.connLowerText = StaticText('  %5d' % (4))
 
391
            self.connUpperText = StaticText('%5d' % (100))
 
392
            self.connslider = wx.Slider(panel, -1, 4, 4, 100, (-1, -1), (80, -1))
 
393
 
 
394
            slideSizer.Add(self.connLowerText, 0, wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL)
 
395
            slideSizer.Add(self.connslider,    0, wx.ALIGN_CENTER|wx.ALIGN_CENTER_VERTICAL)
 
396
            slideSizer.Add(self.connUpperText, 0, wx.ALIGN_LEFT|wx.ALIGN_CENTER_VERTICAL)
 
397
 
 
398
            colSizer.Add(slideSizer, 1, wx.ALL|wx.ALIGN_CENTER|wx.EXPAND, 0)
 
399
 
 
400
            self.unlimitedLabel = StaticText('0 kB/s means unlimited. Tip: your download rate is proportional to your upload rate', self.FONT-2)
 
401
            colSizer.Add(self.unlimitedLabel, 0, wx.ALIGN_CENTER)
 
402
 
 
403
            self.priorityIDs = [wx.NewId(),wx.NewId(),wx.NewId(),wx.NewId()]
 
404
            self.prioritycolors = [ wx.Colour(160,160,160),
 
405
                                    wx.Colour(255,64,0),
 
406
                                    wx.Colour(0,0,0),
 
407
                                    wx.Colour(64,64,255) ]
 
408
 
 
409
 
 
410
            wx.EVT_LEFT_DOWN(aboutText, self.about)
 
411
            wx.EVT_LEFT_DOWN(fileDetails, self.details)
 
412
            wx.EVT_LEFT_DOWN(self.statusIconPtr,self.statusIconHelp)
 
413
            wx.EVT_LEFT_DOWN(advText, self.advanced)
 
414
            wx.EVT_LEFT_DOWN(prefsText, self.openConfigMenu)
 
415
            wx.EVT_CLOSE(frame, self.done)
 
416
            wx.EVT_BUTTON(frame, self.pauseButton.GetId(), self.pause)
 
417
            wx.EVT_BUTTON(frame, self.cancelButton.GetId(), self.done)
 
418
            EVT_INVOKE(frame, self.onInvoke)
 
419
            wx.EVT_SCROLL(self.rateslider, self.onRateScroll)
 
420
            wx.EVT_SCROLL(self.connslider, self.onConnScroll)
 
421
            wx.EVT_CHOICE(self.connChoice, -1, self.onConnChoice)
 
422
            wx.EVT_SPINCTRL(self.connSpinner, -1, self.onConnSpinner)
 
423
            wx.EVT_SPINCTRL(self.rateSpinner, -1, self.onRateSpinner)
 
424
            if (sys.platform == 'win32'):
 
425
                self.frame.tbicon = wx.TaskBarIcon()
 
426
                wx.EVT_ICONIZE(self.frame, self.onIconify)
 
427
                wx.EVT_TASKBAR_LEFT_DCLICK(self.frame.tbicon, self.onTaskBarActivate)
 
428
                wx.EVT_TASKBAR_RIGHT_UP(self.frame.tbicon, self.onTaskBarMenu)
 
429
                wx.EVT_MENU(self.frame.tbicon, self.TBMENU_RESTORE, self.onTaskBarActivate)
 
430
                wx.EVT_MENU(self.frame.tbicon, self.TBMENU_CLOSE, self.done)
 
431
            colSizer.AddGrowableCol (0)
 
432
            colSizer.AddGrowableRow (6)
 
433
            self.frame.Show()
 
434
            border.Fit(panel)
 
435
            self.frame.Fit()
 
436
            self.panel = panel
 
437
            self.border = border
 
438
            self.addwidth = aboutText.GetBestSize().GetWidth() + fileDetails.GetBestSize().GetWidth() + (self.FONT*16)
 
439
            self.fnsizer = fnsizer
 
440
            self.colSizer = colSizer
 
441
            minsize = self.colSizer.GetSize()
 
442
            minsize.SetWidth (minsize.GetWidth())
 
443
            minsize.SetHeight (minsize.GetHeight())
 
444
            self.colSizer.SetMinSize (minsize)
 
445
            self.colSizer.Fit(self.frame)
 
446
            colSizer.Fit(frame)
 
447
        except:
 
448
            self.exception()
 
449
 
 
450
    if sys.platform == 'win32':     # windows-only optimization
 
451
        def onInvoke(self, event):
 
452
            while self.invokeLaterList:
 
453
                func,args,kwargs = self.invokeLaterList[0]
 
454
                if self.uiflag.isSet():
 
455
                    return
 
456
                try:
 
457
                    apply(func,args,kwargs)
 
458
                except:
 
459
                    self.exception()
 
460
                del self.invokeLaterList[0]
 
461
 
 
462
        def invokeLater(self, func, args = [], kwargs = {}):
 
463
            if not self.uiflag.isSet():
 
464
                self.invokeLaterList.append((func,args,kwargs))
 
465
                if len(self.invokeLaterList) == 1:
 
466
                    wx.PostEvent(self.frame, self.invokeLaterEvent)
 
467
    else:
 
468
        def onInvoke(self, event):
 
469
            if not self.uiflag.isSet():
 
470
                try:
 
471
                    apply(event.func, event.args, event.kwargs)
 
472
                except:
 
473
                    self.exception()
 
474
 
 
475
        def invokeLater(self, func, args = [], kwargs = {}):
 
476
            if not self.uiflag.isSet():
 
477
                wx.PostEvent(self.frame, InvokeEvent(func, args, kwargs))
 
478
 
 
479
 
 
480
    def getStatusIcon(self, name, bitmap=False):
 
481
        if self.statusIcons.has_key(name):
 
482
            i = self.statusIcons[name]
 
483
            if type(i)  == type(self.icon) and not bitmap:
 
484
                return i
 
485
        if bitmap:
 
486
            i = wx.Bitmap(self.statusIconFiles[name], wx.BITMAP_TYPE_ICO)
 
487
        else:
 
488
            i = wx.Icon(self.statusIconFiles[name], wx.BITMAP_TYPE_ICO)
 
489
        self.statusIcons[name] = i
 
490
        return i
 
491
 
 
492
 
 
493
    def setStatusIcon(self, name):
 
494
        if name == self.statusIconValue:
 
495
            return
 
496
        self.statusIconValue = name
 
497
        statidata = wx.MemoryDC()
 
498
        statidata.SelectObject(self.statusIcon)
 
499
        statidata.BeginDrawing()
 
500
        try:
 
501
            statidata.DrawIcon(self.getStatusIcon(name),0,0)
 
502
        except:
 
503
            statidata.DrawBitmap(self.getStatusIcon(name,True),0,0,True)
 
504
        statidata.EndDrawing()
 
505
        statidata.SelectObject(wx.NullBitmap)
 
506
        self.statusIconPtr.Refresh()
 
507
 
 
508
 
 
509
    def createStatusIcon(self, name):
 
510
        iconbuffer = wx.EmptyBitmap(32,32)
 
511
        bbdata = wx.MemoryDC()
 
512
        bbdata.SelectObject(iconbuffer)
 
513
        bbdata.SetPen(wx.TRANSPARENT_PEN)
 
514
        bbdata.SetBrush(wx.Brush(self.bgcolor,wx.SOLID))
 
515
        bbdata.DrawRectangle(0,0,32,32)
 
516
        try:
 
517
            bbdata.DrawIcon(self.getStatusIcon(name),0,0)
 
518
        except:
 
519
            bbdata.DrawBitmap(self.getStatusIcon(name,True),0,0,True)
 
520
        return iconbuffer
 
521
 
 
522
 
 
523
    def setgaugemode(self, selection):
 
524
        if selection is None:
 
525
            selection = self.gaugemode
 
526
        elif selection == self.gaugemode:
 
527
            return
 
528
        else:
 
529
            self.gaugemode = selection
 
530
        if selection < 0:
 
531
            self.gauge.SetForegroundColour(self.configfile.getcheckingcolor())
 
532
            self.gauge.SetBackgroundColour(wx.SystemSettings_GetColour(wx.SYS_COLOUR_MENU))
 
533
        elif selection == 0:
 
534
            self.gauge.SetForegroundColour(self.configfile.getdownloadcolor())
 
535
            self.gauge.SetBackgroundColour(wx.SystemSettings_GetColour(wx.SYS_COLOUR_MENU))
 
536
        else:
 
537
            self.gauge.SetForegroundColour(self.configfile.getseedingcolor())
 
538
            self.gauge.SetBackgroundColour(self.configfile.getdownloadcolor())
 
539
 
 
540
 
 
541
    def onIconify(self, evt):
 
542
        try:
 
543
            if self.configfileargs['win32_taskbar_icon']:
 
544
                if self.fin:
 
545
                    self.frame.tbicon.SetIcon(self.finicon, "BitTorrent")
 
546
                else:
 
547
                    self.frame.tbicon.SetIcon(self.icon, "BitTorrent")
 
548
                self.frame.Hide()
 
549
                self.taskbaricon = True
 
550
            else:
 
551
                return
 
552
        except:
 
553
            self.exception()
 
554
 
 
555
 
 
556
    def onTaskBarActivate(self, evt):
 
557
        try:
 
558
            if self.frame.IsIconized():
 
559
                self.frame.Iconize(False)
 
560
            if not self.frame.IsShown():
 
561
                self.frame.Show(True)
 
562
                self.frame.Raise()
 
563
            self.frame.tbicon.RemoveIcon()
 
564
            self.taskbaricon = False
 
565
        except wx.PyDeadObjectError:
 
566
            pass
 
567
        except:
 
568
            self.exception()
 
569
 
 
570
    TBMENU_RESTORE = 1000
 
571
    TBMENU_CLOSE   = 1001
 
572
 
 
573
    def onTaskBarMenu(self, evt):
 
574
        menu = wx.Menu()
 
575
        menu.Append(self.TBMENU_RESTORE, "Restore BitTorrent")
 
576
        menu.Append(self.TBMENU_CLOSE,   "Close")
 
577
        self.frame.tbicon.PopupMenu(menu)
 
578
        menu.Destroy()
 
579
 
 
580
 
 
581
    def _try_get_config(self):
 
582
        if self.config is None:
 
583
            try:
 
584
                self.config = self.dow.getConfig()
 
585
            except:
 
586
                pass
 
587
        return self.config != None
 
588
 
 
589
    def onRateScroll(self, event):
 
590
        try:
 
591
            if self.autorate:
 
592
                return
 
593
            if not self._try_get_config():
 
594
                return
 
595
            if (self.scrollock == 0):
 
596
                self.scrollock = 1
 
597
                self.updateSpinnerFlag = 1
 
598
                self.dow.setUploadRate(self.rateslider.GetValue()
 
599
                            * connChoices[self.connChoice.GetSelection()]['rate'].get('div',1))
 
600
                self.scrollock = 0
 
601
        except:
 
602
            self.exception()
 
603
 
 
604
    def onConnScroll(self, event):
 
605
        try:
 
606
            if self.autorate:
 
607
                return
 
608
            if not self._try_get_config():
 
609
                return
 
610
            self.connSpinner.SetValue (self.connslider.GetValue ())
 
611
            self.dow.setConns(self.connslider.GetValue())
 
612
        except:
 
613
            self.exception()
 
614
 
 
615
    def onRateSpinner(self, event = None):
 
616
        try:
 
617
            if self.autorate:
 
618
                return
 
619
            if not self._try_get_config():
 
620
                return
 
621
            if (self.spinlock == 0):
 
622
                self.spinlock = 1
 
623
                spinnerValue = self.rateSpinner.GetValue()
 
624
                div = connChoices[self.connChoice.GetSelection()]['rate'].get('div',1)
 
625
                if div > 1:
 
626
                    if spinnerValue > (self.config['max_upload_rate']):
 
627
                        round_up = div - 1
 
628
                    else:
 
629
                        round_up = 0
 
630
                    newValue = int((spinnerValue + round_up) / div) * div
 
631
                    if newValue != spinnerValue:
 
632
                        self.rateSpinner.SetValue(newValue)
 
633
                else:
 
634
                    newValue = spinnerValue
 
635
                self.dow.setUploadRate(newValue)
 
636
                self.updateSliderFlag = 1
 
637
                self.spinlock = 0
 
638
        except:
 
639
            self.exception()
 
640
 
 
641
    def onDownRateSpinner(self, event=None):
 
642
        try:
 
643
            if not self._try_get_config():
 
644
                return
 
645
            spinnerValue = self.downrateSpinner.GetValue()
 
646
            self.dow.setDownloadRate(self.downrateSpinner.GetValue())
 
647
        except:
 
648
            self.exception()
 
649
 
 
650
    def onConnSpinner(self, event = None):
 
651
        try:
 
652
            if self.autorate:
 
653
                return
 
654
            if not self._try_get_config():
 
655
                return
 
656
            self.connslider.SetValue (self.connSpinner.GetValue())
 
657
            self.dow.setConns(self.connslider.GetValue())
 
658
        except:
 
659
            self.exception()
 
660
 
 
661
    def onConnChoice(self, event, cons=None, rate=None):
 
662
        try:
 
663
            if not self._try_get_config():
 
664
                return
 
665
            num = self.connChoice.GetSelection()
 
666
            choice = connChoices[num]
 
667
            if choice.has_key('super-seed'):  # selecting super-seed is now a toggle
 
668
                self.dow.set_super_seed()     # one way change, don't go back
 
669
                self.connChoice.SetSelection(self.lastuploadsettings)
 
670
                return
 
671
            self.lastuploadsettings = num
 
672
            self.current_ratesetting = self.connChoice.GetStringSelection()
 
673
            if rate is None:
 
674
                rate = choice['rate']['def']
 
675
            self.rateSpinner.SetRange (choice['rate']['min'],
 
676
                                   choice['rate']['max'])
 
677
            self.rateSpinner.SetValue(rate)
 
678
            self.rateslider.SetRange(
 
679
                choice['rate']['min']/choice['rate'].get('div',1),
 
680
                choice['rate']['max']/choice['rate'].get('div',1))
 
681
            self.rateslider.SetValue (rate/choice['rate'].get('div',1))
 
682
            self.rateLowerText.SetLabel ('  %d' % (choice['rate']['min']))
 
683
            self.rateUpperText.SetLabel ('%d' % (choice['rate']['max']))
 
684
            if cons is None:
 
685
                cons = choice['conn']['def']
 
686
            self.connSpinner.SetRange (choice['conn']['min'],
 
687
                                       choice['conn']['max'])
 
688
            self.connSpinner.SetValue (cons)
 
689
            self.connslider.SetRange (choice['conn']['min'],
 
690
                                      choice['conn']['max'])
 
691
            self.connslider.SetValue (cons)
 
692
            self.connLowerText.SetLabel ('  %d' % (choice['conn']['min']))
 
693
            self.connUpperText.SetLabel ('%d' % (choice['conn']['max']))
 
694
            self.onConnScroll (0)
 
695
            self.onRateScroll (0)
 
696
            self.dow.setInitiate(choice.get('initiate', 40))
 
697
            if choice.has_key('automatic'):
 
698
                if not self.autorate:
 
699
                    self.autorate = True
 
700
                    self.rateSpinner.Enable(False)
 
701
                    self.connSpinner.Enable(False)
 
702
                    self.dow.setUploadRate(-1)
 
703
            else:
 
704
                if self.autorate:
 
705
                    self.autorate = False
 
706
                    self.rateSpinner.Enable(True)
 
707
                    self.connSpinner.Enable(True)
 
708
                    self.onRateSpinner()
 
709
                    self.onConnSpinner()
 
710
        except:
 
711
            self.exception()
 
712
 
 
713
 
 
714
    def about(self, event):
 
715
        try:
 
716
            if (self.aboutBox is not None):
 
717
                try:
 
718
                    self.aboutBox.Close ()
 
719
                except wx.PyDeadObjectError, e:
 
720
                    self.aboutBox = None
 
721
 
 
722
            self.aboutBox = wx.Frame(None, -1, 'About BitTorrent', size = (1,1),
 
723
                            style = wx.DEFAULT_FRAME_STYLE|wx.FULL_REPAINT_ON_RESIZE)
 
724
            try:
 
725
                self.aboutBox.SetIcon(self.icon)
 
726
            except:
 
727
                pass
 
728
 
 
729
            panel = wx.Panel(self.aboutBox, -1)
 
730
 
 
731
            def StaticText(text, font = self.FONT, underline = False, color = None, panel = panel):
 
732
                x = wx.StaticText(panel, -1, text, style = wx.ALIGN_LEFT)
 
733
                x.SetFont(wx.Font(font, wx.DEFAULT, wx.NORMAL, wx.NORMAL, underline))
 
734
                if color is not None:
 
735
                    x.SetForegroundColour(color)
 
736
                return x
 
737
 
 
738
            colSizer = wx.FlexGridSizer(cols = 1, vgap = 3)
 
739
 
 
740
            titleSizer = wx.BoxSizer(wx.HORIZONTAL)
 
741
            aboutTitle = StaticText('BitTorrent ' + version + '  ', self.FONT+4)
 
742
            titleSizer.Add (aboutTitle)
 
743
            linkDonate = StaticText('Donate to Bram', self.FONT, True, 'Blue')
 
744
            titleSizer.Add (linkDonate, 1, wx.ALIGN_BOTTOM&wx.EXPAND)
 
745
            colSizer.Add(titleSizer, 0, wx.EXPAND)
 
746
 
 
747
            colSizer.Add(StaticText('created by Bram Cohen, Copyright 2001-2003,'))
 
748
            colSizer.Add(StaticText('experimental version maintained by John Hoffman 2003'))
 
749
            colSizer.Add(StaticText('modified from experimental version by Eike Frost 2003'))
 
750
            credits = StaticText('full credits\n', self.FONT, True, 'Blue')
 
751
            colSizer.Add(credits);
 
752
 
 
753
            si = ( 'exact Version String: ' + version + '\n' +
 
754
                   'Python version: ' + sys.version + '\n' +
 
755
                   'wxPython version: ' + wx.VERSION_STRING + '\n' )
 
756
            try:
 
757
                si += 'Psyco version: ' + hex(psyco.__version__)[2:] + '\n'
 
758
            except:
 
759
                pass
 
760
            colSizer.Add(StaticText(si))
 
761
 
 
762
            babble1 = StaticText(
 
763
             'This is an experimental, unofficial build of BitTorrent.\n' +
 
764
             'It is Free Software under an MIT-Style license.')
 
765
            babble2 = StaticText('BitTorrent Homepage (link)', self.FONT, True, 'Blue')
 
766
            babble3 = StaticText("TheSHAD0W's Client Homepage (link)", self.FONT, True, 'Blue')
 
767
            babble4 = StaticText("Eike Frost's Client Homepage (link)", self.FONT, True, 'Blue')
 
768
            babble6 = StaticText('License Terms (link)', self.FONT, True, 'Blue')
 
769
            colSizer.Add (babble1)
 
770
            colSizer.Add (babble2)
 
771
            colSizer.Add (babble3)
 
772
            colSizer.Add (babble4)
 
773
            colSizer.Add (babble6)
 
774
 
 
775
            okButton = wx.Button(panel, -1, 'Ok')
 
776
            colSizer.Add(okButton, 0, wx.ALIGN_RIGHT)
 
777
            colSizer.AddGrowableCol(0)
 
778
 
 
779
            border = wx.BoxSizer(wx.HORIZONTAL)
 
780
            border.Add(colSizer, 1, wx.EXPAND | wx.ALL, 4)
 
781
            panel.SetSizer(border)
 
782
            panel.SetAutoLayout(True)
 
783
 
 
784
            def donatelink(self):
 
785
                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()
 
786
            wx.EVT_LEFT_DOWN(linkDonate, donatelink)
 
787
            def aboutlink(self):
 
788
                Thread(target = open_new('http://bitconjurer.org/BitTorrent/')).start()
 
789
            wx.EVT_LEFT_DOWN(babble2, aboutlink)
 
790
            def shadlink(self):
 
791
                Thread(target = open_new('http://www.bittornado.com/')).start()
 
792
            wx.EVT_LEFT_DOWN(babble3, shadlink)
 
793
            def explink(self):
 
794
                Thread(target = open_new('http://ei.kefro.st/projects/btclient/')).start()
 
795
            wx.EVT_LEFT_DOWN(babble4, explink)
 
796
            def licenselink(self):
 
797
                Thread(target = open_new('http://ei.kefro.st/projects/btclient/LICENSE.TXT')).start()
 
798
            wx.EVT_LEFT_DOWN(babble6, licenselink)
 
799
            wx.EVT_LEFT_DOWN(credits, self.credits)
 
800
 
 
801
            def closeAbout(e, self = self):
 
802
                if self.aboutBox:
 
803
                    self.aboutBox.Close()
 
804
            wx.EVT_BUTTON(self.aboutBox, okButton.GetId(), closeAbout)
 
805
            def kill(e, self = self):
 
806
                try:
 
807
                    self.aboutBox.RemoveIcon()
 
808
                except:
 
809
                    pass
 
810
                self.aboutBox.Destroy()
 
811
                self.aboutBox = None
 
812
            wx.EVT_CLOSE(self.aboutBox, kill)
 
813
 
 
814
            self.aboutBox.Show()
 
815
            border.Fit(panel)
 
816
            self.aboutBox.Fit()
 
817
        except:
 
818
            self.exception()
 
819
 
 
820
 
 
821
    def details(self, event):
 
822
        try:
 
823
            if not self.dow or not self.filename:
 
824
                return
 
825
            metainfo = self.dow.getResponse()
 
826
            if metainfo is None:
 
827
                return
 
828
            if metainfo.has_key('announce'):
 
829
                announce = metainfo['announce']
 
830
            else:
 
831
                announce = None
 
832
            if metainfo.has_key('announce-list'):
 
833
                announce_list = metainfo['announce-list']
 
834
            else:
 
835
                announce_list = None
 
836
            info = metainfo['info']
 
837
            info_hash = self.dow.infohash
 
838
            piece_length = info['piece length']
 
839
            fileselector = self.dow.fileselector
 
840
 
 
841
            if (self.detailBox is not None):
 
842
                try:
 
843
                    self.detailBox.Close()
 
844
                except wx.PyDeadObjectError, e:
 
845
                    self.detailBox = None
 
846
 
 
847
            self.detailBox = wx.Frame(None, -1, 'Torrent Details ', size = wx.Size(405,230),
 
848
                            style = wx.DEFAULT_FRAME_STYLE|wx.FULL_REPAINT_ON_RESIZE)
 
849
            try:
 
850
                self.detailBox.SetIcon(self.icon)
 
851
            except:
 
852
                pass
 
853
 
 
854
            panel = wx.Panel(self.detailBox, -1, size = wx.Size (400,220))
 
855
 
 
856
            def StaticText(text, font = self.FONT-1, underline = False, color = None, panel = panel):
 
857
                x = wx.StaticText(panel, -1, text, style = wx.ALIGN_CENTER_VERTICAL)
 
858
                x.SetFont(wx.Font(font, wx.DEFAULT, wx.NORMAL, wx.NORMAL, underline))
 
859
                if color is not None:
 
860
                    x.SetForegroundColour(color)
 
861
                return x
 
862
 
 
863
            colSizer = wx.FlexGridSizer(cols = 1, vgap = 3)
 
864
            colSizer.AddGrowableCol(0)
 
865
 
 
866
            titleSizer = wx.BoxSizer(wx.HORIZONTAL)
 
867
            aboutTitle = StaticText('Details about ' + self.filename, self.FONT+4)
 
868
 
 
869
            titleSizer.Add (aboutTitle)
 
870
            colSizer.Add (titleSizer)
 
871
 
 
872
            detailSizer = wx.FlexGridSizer(cols = 2, vgap = 6)
 
873
 
 
874
            if info.has_key('length'):
 
875
                fileListID = None
 
876
                detailSizer.Add(StaticText('file name :'))
 
877
                detailSizer.Add(StaticText(info['name']))
 
878
                if info.has_key('md5sum'):
 
879
                    detailSizer.Add(StaticText('MD5 hash :'))
 
880
                    detailSizer.Add(StaticText(info['md5sum']))
 
881
                file_length = info['length']
 
882
                name = "file size"
 
883
            else:
 
884
                detail1Sizer = wx.FlexGridSizer(cols = 1, vgap = 6)
 
885
                detail1Sizer.Add(StaticText('directory name : ' + info['name']))
 
886
                colSizer.Add (detail1Sizer)
 
887
                bgallocButton = wx.BitmapButton(panel, -1, self.allocbuttonBitmap, size = (52,20))
 
888
                def bgalloc(self, frame = self):
 
889
                    if frame.dow.storagewrapper is not None:
 
890
                        frame.dow.storagewrapper.bgalloc()
 
891
                wx.EVT_BUTTON(self.detailBox, bgallocButton.GetId(), bgalloc)
 
892
 
 
893
                bgallocbuttonSizer = wx.FlexGridSizer(cols = 4, hgap = 4, vgap = 0)
 
894
                bgallocbuttonSizer.Add(StaticText('(right-click to set priority)',self.FONT-1),0,wx.ALIGN_BOTTOM)
 
895
                bgallocbuttonSizer.Add(StaticText('(finish allocation)'), -1, wx.ALIGN_CENTER_VERTICAL)
 
896
                bgallocbuttonSizer.Add(bgallocButton, -1, wx.ALIGN_CENTER)
 
897
                bgallocbuttonSizer.AddGrowableCol(0)
 
898
                colSizer.Add(bgallocbuttonSizer, -1, wx.EXPAND)
 
899
 
 
900
                file_length = 0
 
901
 
 
902
                fileListID = wx.NewId()
 
903
                fileList = wx.ListCtrl(panel, fileListID,
 
904
                                      wx.Point(-1,-1), (325,100), wx.LC_REPORT)
 
905
                self.fileList = fileList
 
906
                fileList.SetImageList(self.filestatusIcons, wx.IMAGE_LIST_SMALL)
 
907
 
 
908
                fileList.SetAutoLayout (True)
 
909
                fileList.InsertColumn(0, "file")
 
910
                fileList.InsertColumn(1, "", format=wx.LIST_FORMAT_RIGHT, width=55)
 
911
                fileList.InsertColumn(2, "")
 
912
 
 
913
                for i in range(len(info['files'])):
 
914
                    x = wx.ListItem()
 
915
                    fileList.InsertItem(x)
 
916
 
 
917
                x = 0
 
918
                for file in info['files']:
 
919
                    path = ' '
 
920
                    for item in file['path']:
 
921
                        if (path != ''):
 
922
                            path = path + "/"
 
923
                        path = path + item
 
924
                    path += ' (' + str(file['length']) + ')'
 
925
                    fileList.SetStringItem(x, 0, path)
 
926
                    if file.has_key('md5sum'):
 
927
                        fileList.SetStringItem(x, 2, '    [' + str(file['md5sum']) + ']')
 
928
                    if fileselector:
 
929
                        p = fileselector[x]
 
930
                        item = self.fileList.GetItem(x)
 
931
                        item.SetTextColour(self.prioritycolors[p+1])
 
932
                        fileList.SetItem(item)
 
933
                    x += 1
 
934
                    file_length += file['length']
 
935
                fileList.SetColumnWidth(0,wx.LIST_AUTOSIZE)
 
936
                fileList.SetColumnWidth(2,wx.LIST_AUTOSIZE)
 
937
 
 
938
                name = 'archive size'
 
939
                colSizer.Add(fileList, 1, wx.EXPAND)
 
940
                colSizer.AddGrowableRow(3)
 
941
 
 
942
            detailSizer.Add(StaticText('info_hash :'),0,wx.ALIGN_CENTER_VERTICAL)
 
943
            detailSizer.Add(wx.TextCtrl(panel, -1, tohex(info_hash), size = (325, -1), style = wx.TE_READONLY))
 
944
            num_pieces = int((file_length+piece_length-1)/piece_length)
 
945
            detailSizer.Add(StaticText(name + ' : '))
 
946
            detailSizer.Add(StaticText('%s (%s bytes)' % (size_format(file_length), comma_format(file_length))))
 
947
            detailSizer.Add(StaticText('pieces : '))
 
948
            if num_pieces > 1:
 
949
                detailSizer.Add(StaticText('%i (%s bytes each)' % (num_pieces, comma_format(piece_length))))
 
950
            else:
 
951
                detailSizer.Add(StaticText('1'))
 
952
 
 
953
            if announce_list is None:
 
954
                detailSizer.Add(StaticText('announce url : '),0,wx.ALIGN_CENTER_VERTICAL)
 
955
                detailSizer.Add(wx.TextCtrl(panel, -1, announce, size = (325, -1), style = wx.TE_READONLY))
 
956
            else:
 
957
                detailSizer.Add(StaticText(''))
 
958
                trackerList = wx.ListCtrl(panel, -1, wx.Point(-1,-1), (325,75), wx.LC_REPORT)
 
959
                trackerList.SetAutoLayout (True)
 
960
                trackerList.InsertColumn(0, "")
 
961
                trackerList.InsertColumn(1, "announce urls")
 
962
 
 
963
                for tier in range(len(announce_list)):
 
964
                    for t in range(len(announce_list[tier])):
 
965
                        i = wx.ListItem()
 
966
                        trackerList.InsertItem(i)
 
967
                if announce is not None:
 
968
                    for l in [1,2]:
 
969
                        i = wx.ListItem()
 
970
                        trackerList.InsertItem(i)
 
971
 
 
972
                x = 0
 
973
                for tier in range(len(announce_list)):
 
974
                    for t in range(len(announce_list[tier])):
 
975
                        if t == 0:
 
976
                            trackerList.SetStringItem(x, 0, 'tier '+str(tier)+':')
 
977
                        trackerList.SetStringItem(x, 1, announce_list[tier][t])
 
978
                        x += 1
 
979
                if announce is not None:
 
980
                    trackerList.SetStringItem(x+1, 0, 'single:')
 
981
                    trackerList.SetStringItem(x+1, 1, announce)
 
982
                trackerList.SetColumnWidth(0,wx.LIST_AUTOSIZE)
 
983
                trackerList.SetColumnWidth(1,wx.LIST_AUTOSIZE)
 
984
                detailSizer.Add(trackerList)
 
985
 
 
986
            if announce is None and announce_list is not None:
 
987
                announce = announce_list[0][0]
 
988
            if announce is not None:
 
989
                detailSizer.Add(StaticText('likely tracker :'))
 
990
                p = re.compile( '(.*/)[^/]+')
 
991
                turl = p.sub (r'\1', announce)
 
992
                trackerUrl = StaticText(turl, self.FONT, True, 'Blue')
 
993
                detailSizer.Add(trackerUrl)
 
994
            if metainfo.has_key('comment'):
 
995
                detailSizer.Add(StaticText('comment :'))
 
996
                detailSizer.Add(StaticText(metainfo['comment']))
 
997
            if metainfo.has_key('creation date'):
 
998
                detailSizer.Add(StaticText('creation date :'))
 
999
                try:
 
1000
                    detailSizer.Add(StaticText(
 
1001
                        strftime('%x %X',localtime(metainfo['creation date']))))
 
1002
                except:
 
1003
                    try:
 
1004
                        detailSizer.Add(StaticText(metainfo['creation date']))
 
1005
                    except:
 
1006
                        detailSizer.Add(StaticText('<cannot read date>'))
 
1007
 
 
1008
            detailSizer.AddGrowableCol(1)
 
1009
            colSizer.Add (detailSizer, 1, wx.EXPAND)
 
1010
 
 
1011
            okButton = wx.Button(panel, -1, 'Ok')
 
1012
            colSizer.Add(okButton, 0, wx.ALIGN_RIGHT)
 
1013
            colSizer.AddGrowableCol(0)
 
1014
 
 
1015
            if not self.configfileargs['gui_stretchwindow']:
 
1016
                aboutTitle.SetSize((400,-1))
 
1017
            else:
 
1018
                panel.SetAutoLayout(True)
 
1019
 
 
1020
            border = wx.BoxSizer(wx.HORIZONTAL)
 
1021
            border.Add(colSizer, 1, wx.EXPAND | wx.ALL, 4)
 
1022
            panel.SetSizer(border)
 
1023
            panel.SetAutoLayout(True)
 
1024
 
 
1025
            if fileselector and fileListID:
 
1026
                def onRightClick(evt, self = self):
 
1027
                    s = []
 
1028
                    i = -1
 
1029
                    while True:
 
1030
                        i = self.fileList.GetNextItem(i,state=wx.LIST_STATE_SELECTED)
 
1031
                        if i == -1:
 
1032
                            break
 
1033
                        s.append(i)
 
1034
                    if not s:   # just in case
 
1035
                        return
 
1036
                    oldstate = self.dow.fileselector[s[0]]
 
1037
                    kind=wx.ITEM_RADIO
 
1038
                    for i in s[1:]:
 
1039
                        if self.dow.fileselector[i] != oldstate:
 
1040
                            oldstate = None
 
1041
                            kind = wx.ITEM_NORMAL
 
1042
                            break
 
1043
                    menu = wx.Menu()
 
1044
                    menu.Append(self.priorityIDs[1], "download first", kind=kind)
 
1045
                    menu.Append(self.priorityIDs[2], "download normally", kind=kind)
 
1046
                    menu.Append(self.priorityIDs[3], "download later", kind=kind)
 
1047
                    menu.Append(self.priorityIDs[0], "download never (deletes)", kind=kind)
 
1048
                    if oldstate is not None:
 
1049
                        menu.Check(self.priorityIDs[oldstate+1], True)
 
1050
 
 
1051
                    def onSelection(evt, self = self, s = s):
 
1052
                        p = evt.GetId()
 
1053
                        priorities = self.dow.fileselector.get_priorities()
 
1054
                        for i in xrange(len(self.priorityIDs)):
 
1055
                            if p == self.priorityIDs[i]:
 
1056
                                for ss in s:
 
1057
                                    priorities[ss] = i-1
 
1058
                                    item = self.fileList.GetItem(ss)
 
1059
                                    item.SetTextColour(self.prioritycolors[i])
 
1060
                                    self.fileList.SetItem(item)
 
1061
                                self.dow.fileselector.set_priorities(priorities)
 
1062
                                self.fileList.Refresh()
 
1063
                                self.refresh_details = True
 
1064
                                break
 
1065
                        
 
1066
                    for id in self.priorityIDs:
 
1067
                        wx.EVT_MENU(self.detailBox, id, onSelection)
 
1068
 
 
1069
                    self.detailBox.PopupMenu(menu, evt.GetPoint())
 
1070
                        
 
1071
                wx.EVT_LIST_ITEM_RIGHT_CLICK(self.detailBox, fileListID, onRightClick)
 
1072
 
 
1073
            def closeDetail(evt, self = self):
 
1074
                if self.detailBox:
 
1075
                    self.detailBox.Close()
 
1076
            wx.EVT_BUTTON(self.detailBox, okButton.GetId(), closeDetail)
 
1077
            def kill(evt, self = self):
 
1078
                try:
 
1079
                    self.detailBox.RemoveIcon()
 
1080
                except:
 
1081
                    pass
 
1082
                self.detailBox.Destroy()
 
1083
                self.detailBox = None
 
1084
                self.fileList = None
 
1085
                self.dow.filedatflag.clear()
 
1086
            wx.EVT_CLOSE(self.detailBox, kill)
 
1087
 
 
1088
            def trackerurl(self, turl = turl):
 
1089
                try:
 
1090
                    Thread(target = open_new(turl)).start()
 
1091
                except:
 
1092
                    pass
 
1093
            wx.EVT_LEFT_DOWN(trackerUrl, trackerurl)
 
1094
 
 
1095
            self.detailBox.Show ()
 
1096
            border.Fit(panel)
 
1097
            self.detailBox.Fit()
 
1098
 
 
1099
            self.refresh_details = True
 
1100
            self.dow.filedatflag.set()
 
1101
        except:
 
1102
            self.exception()
 
1103
 
 
1104
 
 
1105
    def credits(self, event):
 
1106
        try:
 
1107
            if (self.creditsBox is not None):
 
1108
                try:
 
1109
                    self.creditsBox.Close()
 
1110
                except wx.PyDeadObjectError, e:
 
1111
                    self.creditsBox = None
 
1112
 
 
1113
            self.creditsBox = wx.Frame(None, -1, 'Credits', size = (1,1),
 
1114
                            style = wx.DEFAULT_FRAME_STYLE|wx.FULL_REPAINT_ON_RESIZE)
 
1115
            try:
 
1116
                self.creditsBox.SetIcon(self.icon)
 
1117
            except:
 
1118
                pass
 
1119
 
 
1120
            panel = wx.Panel(self.creditsBox, -1)
 
1121
 
 
1122
            def StaticText(text, font = self.FONT, underline = False, color = None, panel = panel):
 
1123
                x = wx.StaticText(panel, -1, text, style = wx.ALIGN_LEFT)
 
1124
                x.SetFont(wx.Font(font, wx.DEFAULT, wx.NORMAL, wx.NORMAL, underline))
 
1125
                if color is not None:
 
1126
                    x.SetForegroundColour(color)
 
1127
                return x
 
1128
 
 
1129
            colSizer = wx.FlexGridSizer(cols = 1, vgap = 3)
 
1130
 
 
1131
            titleSizer = wx.BoxSizer(wx.HORIZONTAL)
 
1132
            aboutTitle = StaticText('Credits', self.FONT+4)
 
1133
            titleSizer.Add (aboutTitle)
 
1134
            colSizer.Add (titleSizer)
 
1135
            colSizer.Add (StaticText(
 
1136
              'The following people have all helped with this\n' +
 
1137
              'version of BitTorrent in some way (in no particular order) -\n'));
 
1138
            creditSizer = wx.FlexGridSizer(cols = 3)
 
1139
            creditSizer.Add(StaticText(
 
1140
              'Bill Bumgarner\n' +
 
1141
              'David Creswick\n' +
 
1142
              'Andrew Loewenstern\n' +
 
1143
              'Ross Cohen\n' +
 
1144
              'Jeremy Avnet\n' +
 
1145
              'Greg Broiles\n' +
 
1146
              'Barry Cohen\n' +
 
1147
              'Bram Cohen\n' +
 
1148
              'sayke\n' +
 
1149
              'Steve Jenson\n' +
 
1150
              'Myers Carpenter\n' +
 
1151
              'Francis Crick\n' +
 
1152
              'Petru Paler\n' +
 
1153
              'Jeff Darcy\n' +
 
1154
              'John Gilmore\n' +
 
1155
              'Xavier Bassery\n' +
 
1156
              'Pav Lucistnik'))
 
1157
            creditSizer.Add(StaticText('  '))
 
1158
            creditSizer.Add(StaticText(
 
1159
              'Yann Vernier\n' +
 
1160
              'Pat Mahoney\n' +
 
1161
              'Boris Zbarsky\n' +
 
1162
              'Eric Tiedemann\n' +
 
1163
              'Henry "Pi" James\n' +
 
1164
              'Loring Holden\n' +
 
1165
              'Robert Stone\n' +
 
1166
              'Michael Janssen\n' +
 
1167
              'Eike Frost\n' +
 
1168
              'Andrew Todd\n' +
 
1169
              'otaku\n' +
 
1170
              'Edward Keyes\n' +
 
1171
              'John Hoffman\n' +
 
1172
              'Uoti Urpala\n' +
 
1173
              'Jon Wolf\n' +
 
1174
              'Christoph Hohmann\n' +
 
1175
              'Micah Anderson'))
 
1176
            colSizer.Add (creditSizer, flag = wx.ALIGN_CENTER_HORIZONTAL)
 
1177
            okButton = wx.Button(panel, -1, 'Ok')
 
1178
            colSizer.Add(okButton, 0, wx.ALIGN_RIGHT)
 
1179
            colSizer.AddGrowableCol(0)
 
1180
 
 
1181
            border = wx.BoxSizer(wx.HORIZONTAL)
 
1182
            border.Add(colSizer, 1, wx.EXPAND | wx.ALL, 4)
 
1183
            panel.SetSizer(border)
 
1184
            panel.SetAutoLayout(True)
 
1185
 
 
1186
            def closeCredits(e, self = self):
 
1187
                if self.creditsBox:
 
1188
                    self.creditsBox.Close()
 
1189
            wx.EVT_BUTTON(self.creditsBox, okButton.GetId(), closeCredits)
 
1190
            def kill(e, self = self):
 
1191
                try:
 
1192
                    self.creditsBox.RemoveIcon()
 
1193
                except:
 
1194
                    pass
 
1195
                self.creditsBox.Destroy()
 
1196
                self.creditsBox = None
 
1197
            wx.EVT_CLOSE(self.creditsBox, kill)
 
1198
 
 
1199
            self.creditsBox.Show()
 
1200
            border.Fit(panel)
 
1201
            self.creditsBox.Fit()
 
1202
        except:
 
1203
            self.exception()
 
1204
 
 
1205
 
 
1206
    def statusIconHelp(self, event):
 
1207
        try:
 
1208
            if (self.statusIconHelpBox is not None):
 
1209
                try:
 
1210
                    self.statusIconHelpBox.Close()
 
1211
                except wx.PyDeadObjectError, e:
 
1212
                    self.statusIconHelpBox = None
 
1213
 
 
1214
            self.statusIconHelpBox = wx.Frame(None, -1, 'Help with the BitTorrent Status Light', size = (1,1),
 
1215
                            style = wx.DEFAULT_FRAME_STYLE|wx.FULL_REPAINT_ON_RESIZE)
 
1216
            try:
 
1217
                self.statusIconHelpBox.SetIcon(self.icon)
 
1218
            except:
 
1219
                pass
 
1220
 
 
1221
            panel = wx.Panel(self.statusIconHelpBox, -1)
 
1222
 
 
1223
            def StaticText(text, font = self.FONT, underline = False, color = None, panel = panel):
 
1224
                x = wx.StaticText(panel, -1, text, style = wx.ALIGN_LEFT)
 
1225
                x.SetFont(wx.Font(font, wx.DEFAULT, wx.NORMAL, wx.NORMAL, underline))
 
1226
                if color is not None:
 
1227
                    x.SetForegroundColour(color)
 
1228
                return x
 
1229
 
 
1230
            fullsizer = wx.FlexGridSizer(cols = 1, vgap = 13)
 
1231
            colsizer = wx.FlexGridSizer(cols = 2, hgap = 13, vgap = 13)
 
1232
 
 
1233
            disconnectedicon=self.createStatusIcon('disconnected')
 
1234
            colsizer.Add(wx.StaticBitmap(panel, -1, disconnectedicon))
 
1235
            colsizer.Add(StaticText(
 
1236
                'Waiting to connect to the tracker.\n' +
 
1237
                'If the status light stays black for a long time the tracker\n' +
 
1238
                'you are trying to connect to may not be working.  Unless you\n' +
 
1239
                'are receiving a message telling you otherwise, please wait,\n' +
 
1240
                'and BitTorrent will automatically try to reconnect for you.'), 1, wx.ALIGN_CENTER_VERTICAL)
 
1241
 
 
1242
            noconnectionsicon=self.createStatusIcon('noconnections')
 
1243
            colsizer.Add(wx.StaticBitmap(panel, -1, noconnectionsicon))
 
1244
            colsizer.Add(StaticText(
 
1245
                'You have no connections with other clients.\n' +
 
1246
                'Please be patient.  If after several minutes the status\n' +
 
1247
                'light remains red, this torrent may be old and abandoned.'), 1, wx.ALIGN_CENTER_VERTICAL)
 
1248
 
 
1249
            noincomingicon=self.createStatusIcon('noincoming')
 
1250
            colsizer.Add(wx.StaticBitmap(panel, -1, noincomingicon))
 
1251
            colsizer.Add(StaticText(
 
1252
                'You have not received any incoming connections from others.\n' +
 
1253
                'It may only be because no one has tried.  If you never see\n' +
 
1254
                'the status light turn green, it may indicate your system\n' +
 
1255
                'is behind a firewall or proxy server.  Please look into\n' +
 
1256
                'routing BitTorrent through your firewall in order to receive\n' +
 
1257
                'the best possible download rate.'), 1, wx.ALIGN_CENTER_VERTICAL)
 
1258
 
 
1259
            nocompletesicon=self.createStatusIcon('nocompletes')
 
1260
            colsizer.Add(wx.StaticBitmap(panel, -1, nocompletesicon))
 
1261
            colsizer.Add(StaticText(
 
1262
                'There are no complete copies among the clients you are\n' +
 
1263
                'connected to.  Don\'t panic, other clients in the torrent\n' +
 
1264
                "you can't see may have the missing data.\n" +
 
1265
                'If the status light remains blue, you may have problems\n' +
 
1266
                'completing your download.'), 1, wx.ALIGN_CENTER_VERTICAL)
 
1267
 
 
1268
            allgoodicon=self.createStatusIcon('allgood')
 
1269
            colsizer.Add(wx.StaticBitmap(panel, -1, allgoodicon))
 
1270
            colsizer.Add(StaticText(
 
1271
                'The torrent is operating properly.'), 1, wx.ALIGN_CENTER_VERTICAL)
 
1272
 
 
1273
            fullsizer.Add(colsizer, 0, wx.ALIGN_CENTER)
 
1274
            colsizer2 = wx.FlexGridSizer(cols = 1, hgap = 13)
 
1275
 
 
1276
            colsizer2.Add(StaticText(
 
1277
                'Please note that the status light is not omniscient, and that it may\n' +
 
1278
                'be wrong in many instances.  A torrent with a blue light may complete\n' +
 
1279
                "normally, and an occasional yellow light doesn't mean your computer\n" +
 
1280
                'has suddenly become firewalled.'), 1, wx.ALIGN_CENTER_VERTICAL)
 
1281
 
 
1282
            colspacer = StaticText('  ')
 
1283
            colsizer2.Add(colspacer)
 
1284
 
 
1285
            okButton = wx.Button(panel, -1, 'Ok')
 
1286
            colsizer2.Add(okButton, 0, wx.ALIGN_CENTER)
 
1287
            fullsizer.Add(colsizer2, 0, wx.ALIGN_CENTER)
 
1288
 
 
1289
            border = wx.BoxSizer(wx.HORIZONTAL)
 
1290
            border.Add(fullsizer, 1, wx.EXPAND | wx.ALL, 4)
 
1291
 
 
1292
            panel.SetSizer(border)
 
1293
            panel.SetAutoLayout(True)
 
1294
 
 
1295
 
 
1296
            def closeHelp(self, frame = self):
 
1297
                frame.statusIconHelpBox.Close()
 
1298
            wx.EVT_BUTTON(self.statusIconHelpBox, okButton.GetId(), closeHelp)
 
1299
 
 
1300
            self.statusIconHelpBox.Show ()
 
1301
            border.Fit(panel)
 
1302
            self.statusIconHelpBox.Fit()
 
1303
        except:
 
1304
            self.exception()
 
1305
 
 
1306
 
 
1307
    def openConfigMenu(self, event):
 
1308
        try:
 
1309
            self.configfile.configMenu(self)
 
1310
        except:
 
1311
            self.exception()
 
1312
 
 
1313
 
 
1314
    def advanced(self, event):
 
1315
        try:
 
1316
            if not self.dow or not self.filename:
 
1317
                return
 
1318
            if (self.advBox is not None):
 
1319
                try:
 
1320
                    self.advBox.Close ()
 
1321
                except wx.PyDeadObjectError, e:
 
1322
                    self.advBox = None
 
1323
 
 
1324
            self.advBox = wx.Frame(None, -1, 'BitTorrent Advanced', size = wx.Size(200,200),
 
1325
                            style = wx.DEFAULT_FRAME_STYLE|wx.FULL_REPAINT_ON_RESIZE)
 
1326
            try:
 
1327
                self.advBox.SetIcon(self.icon)
 
1328
            except:
 
1329
                pass
 
1330
 
 
1331
            panel = wx.Panel(self.advBox, -1, size = wx.Size (200,200))
 
1332
 
 
1333
            def StaticText(text, font = self.FONT-1, underline = False, color = None, panel = panel):
 
1334
                x = wx.StaticText(panel, -1, text, style = wx.ALIGN_LEFT)
 
1335
                x.SetFont(wx.Font(font, wx.DEFAULT, wx.NORMAL, wx.NORMAL, underline))
 
1336
                if color is not None:
 
1337
                    x.SetForegroundColour(color)
 
1338
                return x
 
1339
 
 
1340
            colSizer = wx.FlexGridSizer (cols = 1, vgap = 1)
 
1341
            colSizer.Add (StaticText('Advanced Info for ' + self.filename, self.FONT+4))
 
1342
 
 
1343
            try:    # get system font width
 
1344
                fw = wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT).GetPointSize()+1
 
1345
            except:
 
1346
                fw = wx.SystemSettings_GetFont(wx.SYS_SYSTEM_FONT).GetPointSize()+1
 
1347
 
 
1348
            spewList = wx.ListCtrl(panel, -1, wx.Point(-1,-1), (fw*66,350), wx.LC_REPORT|wx.LC_HRULES|wx.LC_VRULES)
 
1349
            self.spewList = spewList
 
1350
            spewList.SetAutoLayout (True)
 
1351
 
 
1352
            colSizer.Add(spewList, -1, wx.EXPAND)
 
1353
 
 
1354
            colSizer.Add(StaticText(''))
 
1355
            self.storagestats1 = StaticText('')
 
1356
            self.storagestats2 = StaticText('')
 
1357
            colSizer.Add(self.storagestats1, -1, wx.EXPAND)
 
1358
            colSizer.Add(self.storagestats2, -1, wx.EXPAND)
 
1359
            spinnerSizer = wx.FlexGridSizer(cols=4,vgap=0,hgap=0)
 
1360
            cstats = '          Listening on '
 
1361
            if self.connection_stats['interfaces']:
 
1362
                cstats += ', '.join(self.connection_stats['interfaces']) + ' on '
 
1363
            cstats += 'port ' + str(self.connection_stats['port'])
 
1364
            if self.connection_stats['upnp']:
 
1365
                cstats += ', UPnP port forwarded'
 
1366
            spinnerSizer.Add(StaticText(cstats), -1, wx.EXPAND)
 
1367
            spinnerSizer.AddGrowableCol(0)
 
1368
            spinnerSizer.Add(StaticText('Max download rate (kB/s) '),0,wx.ALIGN_CENTER_VERTICAL)
 
1369
            self.downrateSpinner = wx.SpinCtrl (panel, -1, "", (-1,-1), (50, -1))
 
1370
            self.downrateSpinner.SetFont(self.default_font)
 
1371
            self.downrateSpinner.SetRange(0,5000)
 
1372
            self.downrateSpinner.SetValue(self.config['max_download_rate'])
 
1373
            spinnerSizer.Add (self.downrateSpinner, 0)
 
1374
            wx.EVT_SPINCTRL(self.downrateSpinner, -1, self.onDownRateSpinner)
 
1375
            spinnerSizer.Add(StaticText(' (0 = unlimited)  '),0,wx.ALIGN_CENTER_VERTICAL)
 
1376
            colSizer.Add(spinnerSizer,0,wx.EXPAND)
 
1377
 
 
1378
            colSizer.Add(StaticText(''))
 
1379
 
 
1380
            buttonSizer = wx.FlexGridSizer (cols = 5, hgap = 20)
 
1381
 
 
1382
            reannounceButton = wx.Button(panel, -1, 'Manual Announce')
 
1383
            buttonSizer.Add (reannounceButton)
 
1384
 
 
1385
            extannounceButton = wx.Button(panel, -1, 'External Announce')
 
1386
            buttonSizer.Add (extannounceButton)
 
1387
 
 
1388
            bgallocButton = wx.Button(panel, -1, 'Finish Allocation')
 
1389
            buttonSizer.Add (bgallocButton)
 
1390
 
 
1391
            buttonSizer.Add(StaticText(''))
 
1392
 
 
1393
            okButton = wx.Button(panel, -1, 'Ok')
 
1394
            buttonSizer.Add (okButton)
 
1395
 
 
1396
            colSizer.Add (buttonSizer, 0, wx.ALIGN_CENTER)
 
1397
            colSizer.AddGrowableCol(0)
 
1398
            colSizer.AddGrowableRow(1)
 
1399
 
 
1400
            panel.SetSizer(colSizer)
 
1401
            panel.SetAutoLayout(True)
 
1402
 
 
1403
            spewList.InsertColumn(0, "Optimistic Unchoke", format=wx.LIST_FORMAT_CENTER, width=fw*2)
 
1404
            spewList.InsertColumn(1, "Peer ID", width=0)
 
1405
            spewList.InsertColumn(2, "IP", width=fw*11)
 
1406
            spewList.InsertColumn(3, "Local/Remote", format=wx.LIST_FORMAT_CENTER, width=fw*3)
 
1407
            spewList.InsertColumn(4, "Up", format=wx.LIST_FORMAT_RIGHT, width=fw*6)
 
1408
            spewList.InsertColumn(5, "Interested", format=wx.LIST_FORMAT_CENTER, width=fw*2)
 
1409
            spewList.InsertColumn(6, "Choking", format=wx.LIST_FORMAT_CENTER, width=fw*2)
 
1410
            spewList.InsertColumn(7, "Down", format=wx.LIST_FORMAT_RIGHT, width=fw*6)
 
1411
            spewList.InsertColumn(8, "Interesting", format=wx.LIST_FORMAT_CENTER, width=fw*2)
 
1412
            spewList.InsertColumn(9, "Choked", format=wx.LIST_FORMAT_CENTER, width=fw*2)
 
1413
            spewList.InsertColumn(10, "Snubbed", format=wx.LIST_FORMAT_CENTER, width=fw*2)
 
1414
            spewList.InsertColumn(11, "Downloaded", format=wx.LIST_FORMAT_RIGHT, width=fw*7)
 
1415
            spewList.InsertColumn(12, "Uploaded", format=wx.LIST_FORMAT_RIGHT, width=fw*7)
 
1416
            spewList.InsertColumn(13, "Completed", format=wx.LIST_FORMAT_RIGHT, width=fw*6)
 
1417
            spewList.InsertColumn(14, "Peer Download Speed", format=wx.LIST_FORMAT_RIGHT, width=fw*6)
 
1418
 
 
1419
            def reannounce(self, frame = self):
 
1420
                if (clock() - frame.reannouncelast > 60):
 
1421
                    frame.reannouncelast = clock()
 
1422
                    frame.dow.reannounce()
 
1423
            wx.EVT_BUTTON(self.advBox, reannounceButton.GetId(), reannounce)
 
1424
 
 
1425
            self.advextannouncebox = None
 
1426
            def reannounce_external(self, frame = self):
 
1427
                if (frame.advextannouncebox is not None):
 
1428
                    try:
 
1429
                        frame.advextannouncebox.Close ()
 
1430
                    except wx.PyDeadObjectError, e:
 
1431
                        frame.advextannouncebox = None
 
1432
 
 
1433
                frame.advextannouncebox = wx.Frame(None, -1, 'External Announce', size = (1,1),
 
1434
                            style = wx.DEFAULT_FRAME_STYLE|wx.FULL_REPAINT_ON_RESIZE)
 
1435
                try:
 
1436
                    frame.advextannouncebox.SetIcon(frame.icon)
 
1437
                except:
 
1438
                    pass
 
1439
 
 
1440
                panel = wx.Panel(frame.advextannouncebox, -1)
 
1441
 
 
1442
                fullsizer = wx.FlexGridSizer(cols = 1, vgap = 13)
 
1443
                msg = wx.StaticText(panel, -1, "Enter tracker anounce URL:")
 
1444
                msg.SetFont(frame.default_font)
 
1445
                fullsizer.Add(msg)
 
1446
 
 
1447
                frame.advexturl = wx.TextCtrl(parent = panel, id = -1, value = '',
 
1448
                                    size = (255, 20), style = wx.TE_PROCESS_TAB)
 
1449
                frame.advexturl.SetFont(frame.default_font)
 
1450
                frame.advexturl.SetValue(frame.lastexternalannounce)
 
1451
                fullsizer.Add(frame.advexturl)
 
1452
 
 
1453
                buttonSizer = wx.FlexGridSizer (cols = 2, hgap = 10)
 
1454
 
 
1455
                okButton = wx.Button(panel, -1, 'OK')
 
1456
                buttonSizer.Add (okButton)
 
1457
 
 
1458
                cancelButton = wx.Button(panel, -1, 'Cancel')
 
1459
                buttonSizer.Add (cancelButton)
 
1460
 
 
1461
                fullsizer.Add (buttonSizer, 0, wx.ALIGN_CENTER)
 
1462
 
 
1463
                border = wx.BoxSizer(wx.HORIZONTAL)
 
1464
                border.Add(fullsizer, 1, wx.EXPAND | wx.ALL, 4)
 
1465
 
 
1466
                panel.SetSizer(border)
 
1467
                panel.SetAutoLayout(True)
 
1468
 
 
1469
                def ok(self, frame = frame):
 
1470
                    special = frame.advexturl.GetValue()
 
1471
                    if special:
 
1472
                        frame.lastexternalannounce = special
 
1473
                        if (clock() - frame.reannouncelast > 60):
 
1474
                            frame.reannouncelast = clock()
 
1475
                            frame.dow.reannounce(special)
 
1476
                    frame.advextannouncebox.Close()
 
1477
                wx.EVT_BUTTON(frame.advextannouncebox, okButton.GetId(), ok)
 
1478
 
 
1479
                def cancel(self, frame = frame):
 
1480
                    frame.advextannouncebox.Close()
 
1481
                wx.EVT_BUTTON(frame.advextannouncebox, cancelButton.GetId(), cancel)
 
1482
 
 
1483
                frame.advextannouncebox.Show ()
 
1484
                fullsizer.Fit(panel)
 
1485
                frame.advextannouncebox.Fit()
 
1486
 
 
1487
            wx.EVT_BUTTON(self.advBox, extannounceButton.GetId(), reannounce_external)
 
1488
 
 
1489
            def bgalloc(self, frame = self):
 
1490
                if frame.dow.storagewrapper is not None:
 
1491
                    frame.dow.storagewrapper.bgalloc()
 
1492
            wx.EVT_BUTTON(self.advBox, bgallocButton.GetId(), bgalloc)
 
1493
 
 
1494
            def closeAdv(evt, self = self):
 
1495
                self.advBox.Close()
 
1496
            def killAdv(evt, self = self):
 
1497
                try:
 
1498
                    self.advBox.RemoveIcon()
 
1499
                except:
 
1500
                    pass
 
1501
                self.onDownRateSpinner()
 
1502
                self.dow.spewflag.clear()
 
1503
                self.advBox.Destroy()
 
1504
                self.advBox = None
 
1505
                if (self.advextannouncebox is not None):
 
1506
                    try:
 
1507
                        self.advextannouncebox.Close()
 
1508
                    except wx.PyDeadObjectError, e:
 
1509
                        pass
 
1510
                    self.advextannouncebox = None
 
1511
            wx.EVT_BUTTON(self.advBox, okButton.GetId(), closeAdv)
 
1512
            wx.EVT_CLOSE(self.advBox, killAdv)
 
1513
 
 
1514
            self.advBox.Show ()
 
1515
            colSizer.Fit(panel)
 
1516
            self.advBox.Fit()
 
1517
            if self.dow:
 
1518
                self.dow.spewflag.set()
 
1519
        except:
 
1520
            self.exception()
 
1521
 
 
1522
 
 
1523
    def displayUsage(self, text):
 
1524
        self.invokeLater(self.onDisplayUsage, [text])
 
1525
 
 
1526
    def onDisplayUsage(self, text):        
 
1527
        try:
 
1528
            self.done(None)
 
1529
            w = wx.Frame(None, -1, 'BITTORRENT USAGE',
 
1530
                            style = wx.DEFAULT_FRAME_STYLE|wx.FULL_REPAINT_ON_RESIZE)
 
1531
            panel = wx.Panel(w, -1)
 
1532
            sizer = wx.FlexGridSizer(cols = 1)
 
1533
            sizer.Add(wx.TextCtrl(panel, -1, text,
 
1534
                        size = (500,300), style = wx.TE_READONLY|wx.TE_MULTILINE))
 
1535
            okButton = wx.Button(panel, -1, 'Ok')
 
1536
 
 
1537
            def closeUsage(self, frame = self):
 
1538
                frame.usageBox.Close()
 
1539
            wx.EVT_BUTTON(w, okButton.GetId(), closeUsage)
 
1540
            def kill(self, frame = self):
 
1541
                frame.usageBox.Destroy()
 
1542
                frame.usageBox = None
 
1543
            wx.EVT_CLOSE(w, kill)
 
1544
 
 
1545
            sizer.Add(okButton, 0, wx.ALIGN_RIGHT)
 
1546
            border = wx.BoxSizer(wx.HORIZONTAL)
 
1547
            border.Add(sizer, 1, wx.EXPAND | wx.ALL, 4)
 
1548
 
 
1549
            panel.SetSizer(border)
 
1550
            panel.SetAutoLayout(True)
 
1551
 
 
1552
            border.Fit(panel)
 
1553
            w.Fit()
 
1554
            w.Show()
 
1555
            self.usageBox = w
 
1556
        except:
 
1557
            self.exception()
 
1558
 
 
1559
 
 
1560
    def updateStatus(self, dpflag = Event(), fractionDone = None,
 
1561
            timeEst = None, downRate = None, upRate = None,
 
1562
            activity = None, statistics = None, spew = None, sizeDone = None,
 
1563
            **kws):
 
1564
        if activity is not None:
 
1565
            self.activity = activity
 
1566
        self.gui_fractiondone = fractionDone
 
1567
        self.invokeLater(self.onUpdateStatus,
 
1568
                 [dpflag, timeEst, downRate, upRate, statistics, spew, sizeDone])
 
1569
 
 
1570
    def onUpdateStatus(self, dpflag, timeEst, downRate, upRate,
 
1571
                             statistics, spew, sizeDone):
 
1572
        if self.firstupdate:
 
1573
            if not self.old_ratesettings:
 
1574
                self.old_ratesettings = {}
 
1575
            self.connChoice.SetStringSelection(
 
1576
                self.old_ratesettings.get('rate setting',
 
1577
                                  self.configfileargs['gui_ratesettingsdefault']))
 
1578
            self.onConnChoice(0,
 
1579
                              self.old_ratesettings.get('uploads'),
 
1580
                              self.old_ratesettings.get('max upload rate'))
 
1581
            if self.old_ratesettings.has_key('max download rate'):
 
1582
                self.dow.setDownloadRate(self.old_ratesettings['max download rate'])
 
1583
                if self.advBox:
 
1584
                    self.downrateSpinner.SetValue(self.old_ratesettings['max download rate'])
 
1585
            self.firstupdate = False
 
1586
            if self.advBox:
 
1587
                self.dow.spewflag.set()
 
1588
        if self.ispaused or statistics is None:
 
1589
            self.setStatusIcon('startup')
 
1590
        elif statistics.numPeers + statistics.numSeeds + statistics.numOldSeeds == 0:
 
1591
            if statistics.last_failed:
 
1592
                self.setStatusIcon('disconnected')
 
1593
            else:
 
1594
                self.setStatusIcon('noconnections')
 
1595
        elif ( not statistics.external_connection_made
 
1596
            and not self.configfileargs['gui_forcegreenonfirewall'] ):
 
1597
            self.setStatusIcon('noincoming')
 
1598
        elif ( (statistics.numSeeds + statistics.numOldSeeds == 0)
 
1599
               and ( (self.fin and statistics.numCopies < 1)
 
1600
                    or (not self.fin and statistics.numCopies2 < 1) ) ):
 
1601
            self.setStatusIcon('nocompletes')
 
1602
        elif timeEst == 0 and sizeDone < self.torrentsize:
 
1603
            self.setStatusIcon('nocompletes')
 
1604
        else:
 
1605
            self.setStatusIcon('allgood')
 
1606
        if statistics is None:
 
1607
            self.setgaugemode(-1)
 
1608
        elif self.gui_fractiondone == None or self.gui_fractiondone == 1.0:
 
1609
            self.setgaugemode(1)
 
1610
        else:
 
1611
            self.setgaugemode(0)
 
1612
 
 
1613
        if self.updateSliderFlag == 1:
 
1614
            self.updateSliderFlag = 0
 
1615
            newValue = (self.rateSpinner.GetValue()
 
1616
                         / connChoices[self.connChoice.GetSelection()]['rate'].get('div',1))
 
1617
            if self.rateslider.GetValue() != newValue:
 
1618
                self.rateslider.SetValue(newValue)
 
1619
        if self.updateSpinnerFlag == 1:
 
1620
            self.updateSpinnerFlag = 0
 
1621
            cc = connChoices[self.connChoice.GetSelection()]
 
1622
            if cc.has_key('rate'):
 
1623
                newValue = (self.rateslider.GetValue() * cc['rate'].get('div',1))
 
1624
                if self.rateSpinner.GetValue() != newValue:
 
1625
                    self.rateSpinner.SetValue(newValue)
 
1626
 
 
1627
        if self.fin:
 
1628
            if statistics is None or statistics.numOldSeeds > 0 or statistics.numCopies > 1:
 
1629
                self.gauge.SetValue(1000)
 
1630
            else:
 
1631
                self.gauge.SetValue(int(1000*statistics.numCopies))
 
1632
        elif self.gui_fractiondone is not None:
 
1633
            gaugelevel = int(self.gui_fractiondone * 1000)
 
1634
            self.gauge.SetValue(gaugelevel)
 
1635
            if statistics is not None and statistics.downTotal is not None:
 
1636
                if self.configfileargs['gui_displaymiscstats']:
 
1637
                    self.frame.SetTitle('%.1f%% (%.2f MiB) %s - BitTorrent %s' % (float(gaugelevel)/10, float(sizeDone) / (1<<20), self.filename, version))
 
1638
                else:
 
1639
                    self.frame.SetTitle('%.1f%% %s - BitTorrent %s' % (float(gaugelevel)/10, self.filename, version))
 
1640
            else:
 
1641
                self.frame.SetTitle('%.0f%% %s - BitTorrent %s' % (float(gaugelevel)/10, self.filename, version))
 
1642
        if self.ispaused:
 
1643
            self.timeText.SetLabel(hours(clock() - self.starttime) + ' /')
 
1644
        elif timeEst is None:
 
1645
            self.timeText.SetLabel(hours(clock() - self.starttime) + ' / ' + self.activity)
 
1646
        else:
 
1647
            self.timeText.SetLabel(hours(clock() - self.starttime) + ' / ' + hours(timeEst))
 
1648
        if not self.ispaused:
 
1649
            if downRate is not None:
 
1650
                self.downRateText.SetLabel('%.0f kB/s' % (float(downRate) / 1000))
 
1651
            if upRate is not None:
 
1652
                self.upRateText.SetLabel('%.0f kB/s' % (float(upRate) / 1000))
 
1653
        if self.taskbaricon:
 
1654
            icontext='BitTorrent '
 
1655
            if self.gui_fractiondone is not None and not self.fin:
 
1656
                if statistics is not None and statistics.downTotal is not None:
 
1657
                    icontext=icontext+' %.1f%% (%.2f MiB)' % (self.gui_fractiondone*100, float(sizeDone) / (1<<20))
 
1658
                else:
 
1659
                    icontext=icontext+' %.0f%%' % (self.gui_fractiondone*100)
 
1660
            if upRate is not None:
 
1661
                icontext=icontext+' u:%.0f kB/s' % (float(upRate) / 1000)
 
1662
            if downRate is not None:
 
1663
                icontext=icontext+' d:%.0f kB/s' % (float(downRate) / 1000)
 
1664
            icontext+=' %s' % self.filename
 
1665
            try:
 
1666
                if self.gui_fractiondone == None or self.gui_fractiondone == 1.0:
 
1667
                    self.frame.tbicon.SetIcon(self.finicon,icontext)
 
1668
                else:
 
1669
                    self.frame.tbicon.SetIcon(self.icon,icontext)
 
1670
            except:
 
1671
                pass
 
1672
        if statistics is not None:
 
1673
            if self.autorate:
 
1674
                self.rateSpinner.SetValue(statistics.upRate)
 
1675
                self.connSpinner.SetValue(statistics.upSlots)
 
1676
 
 
1677
            downtotal = statistics.downTotal + self.old_download
 
1678
            uptotal = statistics.upTotal + self.old_upload
 
1679
            if self.configfileargs['gui_displaymiscstats']:
 
1680
                self.downText.SetLabel('%.2f MiB' % (float(downtotal) / (1 << 20)))
 
1681
                self.upText.SetLabel('%.2f MiB' % (float(uptotal) / (1 << 20)))
 
1682
            if downtotal > 0:
 
1683
                sharerating = float(uptotal)/downtotal
 
1684
                if sharerating == 0:
 
1685
                    shareSmiley = ''
 
1686
                    color = 'Black'
 
1687
                elif sharerating < 0.5:
 
1688
                    shareSmiley = ':-('
 
1689
                    color = 'Red'
 
1690
                elif sharerating < 1.0:
 
1691
                    shareSmiley = ':-|'
 
1692
                    color = 'Orange'
 
1693
                else:
 
1694
                    shareSmiley = ':-)'
 
1695
                    color = 'Forest Green'
 
1696
            elif uptotal == 0:
 
1697
                sharerating = None
 
1698
                shareSmiley = ''
 
1699
                color = 'Black'
 
1700
            else:
 
1701
                sharerating = None
 
1702
                shareSmiley = '00 :-D'
 
1703
                color = 'Forest Green'
 
1704
            if sharerating is None:
 
1705
                self.shareRatingText.SetLabel(shareSmiley)
 
1706
            else:
 
1707
                self.shareRatingText.SetLabel('%.3f %s' % (sharerating, shareSmiley))
 
1708
            self.shareRatingText.SetForegroundColour(color)
 
1709
 
 
1710
            if self.configfileargs['gui_displaystats']:
 
1711
                if not self.fin:
 
1712
                    self.seedStatusText.SetLabel('connected to %d seeds; also seeing %.3f distributed copies' % (statistics.numSeeds,0.001*int(1000*statistics.numCopies2)))
 
1713
                else:
 
1714
                    self.seedStatusText.SetLabel('%d seeds seen recently; also seeing %.3f distributed copies' % (statistics.numOldSeeds,0.001*int(1000*statistics.numCopies)))
 
1715
                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)))
 
1716
        if ((clock() - self.lastError) > 300):
 
1717
            self.errorText.SetLabel('')
 
1718
 
 
1719
        if ( self.configfileargs['gui_displaymiscstats']
 
1720
            and statistics is not None and statistics.backgroundallocating ):
 
1721
            self.bgalloc_periods += 1
 
1722
            if self.bgalloc_periods > 3:
 
1723
                self.bgalloc_periods = 0
 
1724
            self.bgallocText.SetLabel('ALLOCATING'+(' .'*self.bgalloc_periods))
 
1725
        elif self.dow.superseedflag.isSet():
 
1726
            self.bgallocText.SetLabel('SUPER-SEED')
 
1727
        else:
 
1728
            self.bgallocText.SetLabel('')
 
1729
 
 
1730
 
 
1731
        if spew is not None and (clock()-self.spewwait>1):
 
1732
            if (self.advBox is not None):
 
1733
                self.spewwait = clock()
 
1734
                spewList = self.spewList
 
1735
                spewlen = len(spew)+2
 
1736
                if statistics is not None:
 
1737
                    kickbanlen = len(statistics.peers_kicked)+len(statistics.peers_banned)
 
1738
                    if kickbanlen:
 
1739
                        spewlen += kickbanlen+1
 
1740
                else:
 
1741
                    kickbanlen = 0
 
1742
                for x in range(spewlen-spewList.GetItemCount()):
 
1743
                    i = wx.ListItem()
 
1744
                    spewList.InsertItem(i)
 
1745
                for x in range(spewlen,spewList.GetItemCount()):
 
1746
                    spewList.DeleteItem(len(spew)+1)
 
1747
 
 
1748
                tot_uprate = 0.0
 
1749
                tot_downrate = 0.0
 
1750
                for x in range(len(spew)):
 
1751
                    if (spew[x]['optimistic'] == 1):
 
1752
                        a = '*'
 
1753
                    else:
 
1754
                        a = ' '
 
1755
                    spewList.SetStringItem(x, 0, a)
 
1756
                    spewList.SetStringItem(x, 1, spew[x]['id'])
 
1757
                    spewList.SetStringItem(x, 2, spew[x]['ip'])
 
1758
                    spewList.SetStringItem(x, 3, spew[x]['direction'])
 
1759
                    if spew[x]['uprate'] > 100:
 
1760
                        spewList.SetStringItem(x, 4, '%.0f kB/s' % (float(spew[x]['uprate']) / 1000))
 
1761
                    else:
 
1762
                        spewList.SetStringItem(x, 4, ' ')
 
1763
                    tot_uprate += spew[x]['uprate']
 
1764
                    if (spew[x]['uinterested'] == 1):
 
1765
                        a = '*'
 
1766
                    else:
 
1767
                        a = ' '
 
1768
                    spewList.SetStringItem(x, 5, a)
 
1769
                    if (spew[x]['uchoked'] == 1):
 
1770
                        a = '*'
 
1771
                    else:
 
1772
                        a = ' '
 
1773
                    spewList.SetStringItem(x, 6, a)
 
1774
 
 
1775
                    if spew[x]['downrate'] > 100:
 
1776
                        spewList.SetStringItem(x, 7, '%.0f kB/s' % (float(spew[x]['downrate']) / 1000))
 
1777
                    else:
 
1778
                        spewList.SetStringItem(x, 7, ' ')
 
1779
                    tot_downrate += spew[x]['downrate']
 
1780
 
 
1781
                    if (spew[x]['dinterested'] == 1):
 
1782
                        a = '*'
 
1783
                    else:
 
1784
                        a = ' '
 
1785
                    spewList.SetStringItem(x, 8, a)
 
1786
                    if (spew[x]['dchoked'] == 1):
 
1787
                        a = '*'
 
1788
                    else:
 
1789
                        a = ' '
 
1790
                    spewList.SetStringItem(x, 9, a)
 
1791
                    if (spew[x]['snubbed'] == 1):
 
1792
                        a = '*'
 
1793
                    else:
 
1794
                        a = ' '
 
1795
                    spewList.SetStringItem(x, 10, a)
 
1796
                    spewList.SetStringItem(x, 11, '%.2f MiB' % (float(spew[x]['dtotal']) / (1 << 20)))
 
1797
                    if spew[x]['utotal'] is not None:
 
1798
                        a = '%.2f MiB' % (float(spew[x]['utotal']) / (1 << 20))
 
1799
                    else:
 
1800
                        a = ''
 
1801
                    spewList.SetStringItem(x, 12, a)
 
1802
                    spewList.SetStringItem(x, 13, '%.1f%%' % (float(int(spew[x]['completed']*1000))/10))
 
1803
                    if spew[x]['speed'] is not None:
 
1804
                        a = '%.0f kB/s' % (float(spew[x]['speed']) / 1000)
 
1805
                    else:
 
1806
                        a = ''
 
1807
                    spewList.SetStringItem(x, 14, a)
 
1808
 
 
1809
                x = len(spew)
 
1810
                for i in range(15):
 
1811
                    spewList.SetStringItem(x, i, '')
 
1812
 
 
1813
                x += 1
 
1814
                spewList.SetStringItem(x, 2, '         TOTALS:')
 
1815
                spewList.SetStringItem(x, 4, '%.0f kB/s' % (float(tot_uprate) / 1000))
 
1816
                spewList.SetStringItem(x, 7, '%.0f kB/s' % (float(tot_downrate) / 1000))
 
1817
                if statistics is not None:
 
1818
                    spewList.SetStringItem(x, 11, '%.2f MiB' % (float(statistics.downTotal) / (1 << 20)))
 
1819
                    spewList.SetStringItem(x, 12, '%.2f MiB' % (float(statistics.upTotal) / (1 << 20)))
 
1820
                else:
 
1821
                    spewList.SetStringItem(x, 11, '')
 
1822
                    spewList.SetStringItem(x, 12, '')
 
1823
                for i in [0,1,3,5,6,8,9,10,13,14]:
 
1824
                    spewList.SetStringItem(x, i, '')
 
1825
 
 
1826
                if kickbanlen:
 
1827
                    x += 1
 
1828
                    for i in range(14):
 
1829
                        spewList.SetStringItem(x, i, '')
 
1830
 
 
1831
                    for peer in statistics.peers_kicked:
 
1832
                        x += 1
 
1833
                        spewList.SetStringItem(x, 2, peer[0])
 
1834
                        spewList.SetStringItem(x, 1, peer[1])
 
1835
                        spewList.SetStringItem(x, 4, 'KICKED')
 
1836
                        for i in [0,3,5,6,7,8,9,10,11,12,13,14]:
 
1837
                            spewList.SetStringItem(x, i, '')
 
1838
 
 
1839
                    for peer in statistics.peers_banned:
 
1840
                        x += 1
 
1841
                        spewList.SetStringItem(x, 2, peer[0])
 
1842
                        spewList.SetStringItem(x, 1, peer[1])
 
1843
                        spewList.SetStringItem(x, 4, 'BANNED')
 
1844
                        for i in [0,3,5,6,7,8,9,10,11,12,13,14]:
 
1845
                            spewList.SetStringItem(x, i, '')
 
1846
 
 
1847
                if statistics is not None:
 
1848
                    l1 = (
 
1849
                        '          currently downloading %d pieces (%d just started), %d pieces partially retrieved'
 
1850
                                        % ( statistics.storage_active,
 
1851
                                            statistics.storage_new,
 
1852
                                            statistics.storage_dirty ) )
 
1853
                    if statistics.storage_isendgame:
 
1854
                        l1 += ', endgame mode'
 
1855
                    self.storagestats2.SetLabel(l1)
 
1856
                    self.storagestats1.SetLabel(
 
1857
                        '          %d of %d pieces complete (%d just downloaded), %d failed hash check, %sKiB redundant data discarded'
 
1858
                                        % ( statistics.storage_numcomplete,
 
1859
                                            statistics.storage_totalpieces,
 
1860
                                            statistics.storage_justdownloaded,
 
1861
                                            statistics.storage_numflunked,
 
1862
                                            comma_format(int(statistics.discarded/1024)) ) )
 
1863
 
 
1864
        if ( self.fileList is not None and statistics is not None
 
1865
                and (statistics.filelistupdated.isSet() or self.refresh_details) ):
 
1866
            for i in range(len(statistics.filecomplete)):
 
1867
                if self.dow.fileselector[i] == -1:
 
1868
                    self.fileList.SetItemImage(i,0,0)
 
1869
                    self.fileList.SetStringItem(i,1,'')
 
1870
                elif statistics.fileinplace[i]:
 
1871
                    self.fileList.SetItemImage(i,2,2)
 
1872
                    self.fileList.SetStringItem(i,1,"done")
 
1873
                elif statistics.filecomplete[i]:
 
1874
                    self.fileList.SetItemImage(i,1,1)
 
1875
                    self.fileList.SetStringItem(i,1,"100%")
 
1876
                else:
 
1877
                    self.fileList.SetItemImage(i,0,0)
 
1878
                    frac = statistics.fileamtdone[i]
 
1879
                    if frac:
 
1880
                        self.fileList.SetStringItem(i,1,'%d%%' % (frac*100))
 
1881
                    else:
 
1882
                        self.fileList.SetStringItem(i,1,'')
 
1883
 
 
1884
            statistics.filelistupdated.clear()
 
1885
            self.refresh_details = False
 
1886
 
 
1887
        if self.configfile.configReset():     # whoopee!  Set everything invisible! :-)
 
1888
 
 
1889
            self.dow.config['security'] = self.configfileargs['security']
 
1890
 
 
1891
            statsdisplayflag = self.configfileargs['gui_displaymiscstats']
 
1892
            self.downTextLabel.Show(statsdisplayflag)
 
1893
            self.upTextLabel.Show(statsdisplayflag)
 
1894
            self.fileDestLabel.Show(statsdisplayflag)
 
1895
            self.fileDestText.Show(statsdisplayflag)
 
1896
            self.colSizer.Layout()
 
1897
 
 
1898
            self.downText.SetLabel('')          # blank these to flush them
 
1899
            self.upText.SetLabel('')
 
1900
            self.seedStatusText.SetLabel('')
 
1901
            self.peerStatusText.SetLabel('')
 
1902
 
 
1903
            ratesettingsmode = self.configfileargs['gui_ratesettingsmode']
 
1904
            ratesettingsflag1 = True    #\ settings
 
1905
            ratesettingsflag2 = False   #/ for 'basic'
 
1906
            if ratesettingsmode == 'none':
 
1907
                ratesettingsflag1 = False
 
1908
            elif ratesettingsmode == 'full':
 
1909
                ratesettingsflag2 = True
 
1910
            self.connChoiceLabel.Show(ratesettingsflag1)
 
1911
            self.connChoice.Show(ratesettingsflag1)
 
1912
            self.rateSpinnerLabel.Show(ratesettingsflag2)
 
1913
            self.rateSpinner.Show(ratesettingsflag2)
 
1914
            self.rateLowerText.Show(ratesettingsflag2)
 
1915
            self.rateUpperText.Show(ratesettingsflag2)
 
1916
            self.rateslider.Show(ratesettingsflag2)
 
1917
            self.connSpinnerLabel.Show(ratesettingsflag2)
 
1918
            self.connSpinner.Show(ratesettingsflag2)
 
1919
            self.connLowerText.Show(ratesettingsflag2)
 
1920
            self.connUpperText.Show(ratesettingsflag2)
 
1921
            self.connslider.Show(ratesettingsflag2)
 
1922
            self.unlimitedLabel.Show(ratesettingsflag2)
 
1923
 
 
1924
            self.setgaugemode(None)
 
1925
 
 
1926
        self.frame.Layout()
 
1927
        self.frame.Refresh()
 
1928
 
 
1929
        self.gui_fractiondone = None
 
1930
        dpflag.set()
 
1931
 
 
1932
 
 
1933
    def finished(self):
 
1934
        self.fin = True
 
1935
        self.invokeLater(self.onFinishEvent)
 
1936
 
 
1937
    def failed(self):
 
1938
        self.fin = True
 
1939
        self.invokeLater(self.onFailEvent)
 
1940
 
 
1941
    def error(self, errormsg):
 
1942
        self.invokeLater(self.onErrorEvent, [errormsg])
 
1943
 
 
1944
    def onFinishEvent(self):
 
1945
        self.activity = hours(clock() - self.starttime) + ' / ' +'Download Succeeded!'
 
1946
        self.cancelButton.SetLabel('Finish')
 
1947
        self.gauge.SetValue(0)
 
1948
        self.frame.SetTitle('%s - Upload - BitTorrent %s' % (self.filename, version))
 
1949
        try:
 
1950
            self.frame.SetIcon(self.finicon)
 
1951
        except:
 
1952
            pass
 
1953
        if self.taskbaricon:
 
1954
            self.frame.tbicon.SetIcon(self.finicon, "BitTorrent - Finished")
 
1955
        self.downRateText.SetLabel('')
 
1956
 
 
1957
    def onFailEvent(self):
 
1958
        if not self.shuttingdown:
 
1959
            self.timeText.SetLabel(hours(clock() - self.starttime) + ' / ' +'Failed!')
 
1960
            self.activity = 'Failed!'
 
1961
            self.cancelButton.SetLabel('Close')
 
1962
            self.gauge.SetValue(0)
 
1963
            self.downRateText.SetLabel('')
 
1964
            self.setStatusIcon('startup')
 
1965
 
 
1966
    def onErrorEvent(self, errormsg):
 
1967
        if errormsg[:2] == '  ':    # indent at least 2 spaces means a warning message
 
1968
            self.errorText.SetLabel(errormsg)
 
1969
            self.lastError = clock()
 
1970
        else:
 
1971
            self.errorText.SetLabel(strftime('ERROR (%x %X) -\n') + errormsg)
 
1972
            self.lastError = clock()
 
1973
 
 
1974
 
 
1975
    def chooseFile(self, default, size, saveas, dir):
 
1976
        f = Event()
 
1977
        bucket = [None]
 
1978
        self.invokeLater(self.onChooseFile, [default, bucket, f, size, dir, saveas])
 
1979
        f.wait()
 
1980
        return bucket[0]
 
1981
 
 
1982
    def onChooseFile(self, default, bucket, f, size, dir, saveas):
 
1983
        if saveas == '':
 
1984
            if self.configfileargs['gui_default_savedir'] != '':
 
1985
                start_dir = self.configfileargs['gui_default_savedir']
 
1986
            else:
 
1987
                start_dir = self.configfileargs['last_saved']
 
1988
            if not isdir(start_dir):    # if it's not set properly
 
1989
                start_dir = '/'    # yes, this hack does work in Windows
 
1990
            if dir:
 
1991
                start_dir1 = start_dir
 
1992
                if isdir(join(start_dir,default)):
 
1993
                    start_dir = join(start_dir,default)
 
1994
                dl = wx.DirDialog(self.frame,
 
1995
                        'Choose a directory to save to, pick a partial download to resume',
 
1996
                        defaultPath = start_dir, style = wx.DD_DEFAULT_STYLE | wx.DD_NEW_DIR_BUTTON)
 
1997
            else:
 
1998
                dl = wx.FileDialog(self.frame,
 
1999
                        'Choose file to save as, pick a partial download to resume', 
 
2000
                        defaultDir = start_dir, defaultFile = default, wildcard = '*',
 
2001
                        style = wx.SAVE)
 
2002
 
 
2003
            if dl.ShowModal() != wx.ID_OK:
 
2004
                f.set()
 
2005
                self.done(None)
 
2006
                return
 
2007
 
 
2008
            d = dl.GetPath()
 
2009
            if d == start_dir:
 
2010
                d = start_dir1
 
2011
            bucket[0] = d
 
2012
            d1,d2 = split(d)
 
2013
            if d2 == default:
 
2014
                d = d1
 
2015
            self.configfile.WriteLastSaved(d)
 
2016
 
 
2017
        else:
 
2018
            bucket[0] = saveas
 
2019
            default = basename(saveas)
 
2020
 
 
2021
        self.onChooseFileDone(default, size)
 
2022
        f.set()
 
2023
 
 
2024
    def ChooseFileDone(self, name, size):
 
2025
        self.invokeLater(self.onChooseFileDone, [name, size])
 
2026
 
 
2027
    def onChooseFileDone(self, name, size):
 
2028
        self.torrentsize = size
 
2029
        lname = basename(name)
 
2030
        self.filename = lname
 
2031
        self.fileNameText.SetLabel('%s' % (lname))
 
2032
        self.fileSizeText.SetLabel('(%.2f MiB)' % (float(size) / (1 << 20)))
 
2033
        self.timeText.SetLabel(hours(clock() - self.starttime) + ' / ' + self.activity)
 
2034
        self.fileDestText.SetLabel(name)
 
2035
        self.frame.SetTitle(lname + '- BitTorrent ' + version)
 
2036
 
 
2037
        minsize = self.fileNameText.GetBestSize()
 
2038
        if (not self.configfileargs['gui_stretchwindow'] or
 
2039
                            minsize.GetWidth() < self.addwidth):
 
2040
            minsize.SetWidth(self.addwidth)
 
2041
        self.fnsizer.SetMinSize (minsize)
 
2042
        minsize.SetHeight(self.fileSizeText.GetBestSize().GetHeight())
 
2043
        self.fnsizer2.SetMinSize (minsize)
 
2044
        minsize.SetWidth(minsize.GetWidth()+(self.FONT*8))
 
2045
        minsize.SetHeight(self.fileNameText.GetBestSize().GetHeight()+self.fileSizeText.GetBestSize().GetHeight())
 
2046
        minsize.SetHeight(2*self.errorText.GetBestSize().GetHeight())
 
2047
        self.errorTextSizer.SetMinSize(minsize)
 
2048
        self.topboxsizer.SetMinSize(minsize)
 
2049
 
 
2050
        # Kludge to make details and about catch the event
 
2051
        self.frame.SetSize ((self.frame.GetSizeTuple()[0]+1, self.frame.GetSizeTuple()[1]+1))
 
2052
        self.frame.SetSize ((self.frame.GetSizeTuple()[0]-1, self.frame.GetSizeTuple()[1]-1))
 
2053
        self.colSizer.Fit(self.frame)
 
2054
        self.frame.Layout()
 
2055
        self.frame.Refresh()
 
2056
 
 
2057
    def newpath(self, path):
 
2058
        self.invokeLater(self.onNewpath, [path])
 
2059
 
 
2060
    def onNewpath(self, path):
 
2061
        self.fileDestText.SetLabel(path)
 
2062
 
 
2063
    def pause(self, event):
 
2064
        self.invokeLater(self.onPause)
 
2065
 
 
2066
    def onPause(self):
 
2067
        if not self.dow:
 
2068
            return
 
2069
        if self.ispaused:
 
2070
            self.ispaused = False
 
2071
            self.pauseButton.SetLabel('Pause')
 
2072
            self.dow.Unpause()
 
2073
        else:
 
2074
            if self.dow.Pause():
 
2075
                self.ispaused = True
 
2076
                self.pauseButton.SetLabel('Resume')
 
2077
                self.downRateText.SetLabel(' ')
 
2078
                self.upRateText.SetLabel(' ')
 
2079
                self.setStatusIcon('startup')
 
2080
 
 
2081
    def done(self, event):
 
2082
        self.uiflag.set()
 
2083
        self.flag.set()
 
2084
        self.shuttingdown = True
 
2085
 
 
2086
        try:
 
2087
            self.frame.tbicon.RemoveIcon()
 
2088
        except:
 
2089
            pass
 
2090
        try:
 
2091
            self.frame.tbicon.Destroy()
 
2092
        except:
 
2093
            pass
 
2094
        try:
 
2095
            self.detailBox.Close()
 
2096
        except:
 
2097
            self.detailBox = None
 
2098
        try:
 
2099
            self.aboutBox.Close()
 
2100
        except:
 
2101
            self.aboutBox = None
 
2102
        try:
 
2103
            self.creditsBox.Close()
 
2104
        except:
 
2105
            self.creditsBox = None
 
2106
        try:
 
2107
            self.advBox.Close()
 
2108
        except:
 
2109
            self.advBox = None
 
2110
        try:
 
2111
            self.statusIconHelpBox.Close()
 
2112
        except:
 
2113
            self.statusIconHelpBox = None
 
2114
        try:
 
2115
            self.frame.RemoveIcon()
 
2116
        except:
 
2117
            pass
 
2118
 
 
2119
        self.frame.Destroy()
 
2120
 
 
2121
 
 
2122
    def exception(self):
 
2123
        data = StringIO()
 
2124
        print_exc(file = data)
 
2125
        print data.getvalue()   # report exception here too
 
2126
        self.on_errorwindow(data.getvalue())
 
2127
 
 
2128
    def errorwindow(self, err):
 
2129
        self.invokeLater(self.on_errorwindow,[err])
 
2130
 
 
2131
    def on_errorwindow(self, err):
 
2132
        if self._errorwindow is None:
 
2133
            w = wx.Frame(None, -1, 'BITTORRENT ERROR', size = (1,1),
 
2134
                            style = wx.DEFAULT_FRAME_STYLE|wx.FULL_REPAINT_ON_RESIZE)
 
2135
            panel = wx.Panel(w, -1)
 
2136
 
 
2137
            sizer = wx.FlexGridSizer(cols = 1)
 
2138
            t = ( 'BitTorrent ' + version + '\n' +
 
2139
                  'OS: ' + sys.platform + '\n' +
 
2140
                  'Python version: ' + sys.version + '\n' +
 
2141
                  'wx.Windows version: ' + wx.VERSION_STRING + '\n' )
 
2142
            try:
 
2143
                t += 'Psyco version: ' + hex(psyco.__version__)[2:] + '\n'
 
2144
            except:
 
2145
                pass
 
2146
            try:
 
2147
                t += 'Allocation method: ' + self.config['alloc_type']
 
2148
                if self.dow.storagewrapper.bgalloc_active:
 
2149
                    t += '*'
 
2150
                t += '\n'
 
2151
            except:
 
2152
                pass
 
2153
            sizer.Add(wx.TextCtrl(panel, -1, t + '\n' + err,
 
2154
                                size = (500,300), style = wx.TE_READONLY|wx.TE_MULTILINE))
 
2155
 
 
2156
            sizer.Add(wx.StaticText(panel, -1,
 
2157
                    '\nHelp us iron out the bugs in the engine!'))
 
2158
            linkMail = wx.StaticText(panel, -1,
 
2159
                'Please report this error to '+report_email)
 
2160
            linkMail.SetFont(wx.Font(self.FONT, wx.DEFAULT, wx.NORMAL, wx.NORMAL, True))
 
2161
            linkMail.SetForegroundColour('Blue')
 
2162
            sizer.Add(linkMail)
 
2163
 
 
2164
            def maillink(self):
 
2165
                Thread(target = open_new("mailto:" + report_email
 
2166
                                         + "?subject=autobugreport")).start()
 
2167
            wx.EVT_LEFT_DOWN(linkMail, maillink)
 
2168
 
 
2169
            border = wx.BoxSizer(wx.HORIZONTAL)
 
2170
            border.Add(sizer, 1, wx.EXPAND | wx.ALL, 4)
 
2171
 
 
2172
            panel.SetSizer(border)
 
2173
            panel.SetAutoLayout(True)
 
2174
 
 
2175
            w.Show()
 
2176
            border.Fit(panel)
 
2177
            w.Fit()
 
2178
            self._errorwindow = w
 
2179
 
 
2180
 
 
2181
class btWxApp(wx.App):
 
2182
    def __init__(self, x, params):
 
2183
        self.params = params
 
2184
        wx.App.__init__(self, x)
 
2185
 
 
2186
    def OnInit(self):
 
2187
        doneflag = Event()
 
2188
        self.configfile = configReader()
 
2189
        d = DownloadInfoFrame(doneflag, self.configfile)
 
2190
        self.SetTopWindow(d.frame)
 
2191
        if len(self.params) == 0:
 
2192
            b = wx.FileDialog (d.frame, 'Choose .torrent file to use',
 
2193
                        defaultDir = '', defaultFile = '', wildcard = '*.torrent',
 
2194
                        style = wx.OPEN)
 
2195
 
 
2196
            if b.ShowModal() == wx.ID_OK:
 
2197
                self.params.append (b.GetPath())
 
2198
 
 
2199
        thread = Thread(target = next, args = [self.params, d, doneflag, self.configfile])
 
2200
        thread.setDaemon(False)
 
2201
        thread.start()
 
2202
        return 1
 
2203
 
 
2204
def run(params):
 
2205
    if WXPROFILER:
 
2206
        import profile, pstats
 
2207
        p = profile.Profile()
 
2208
        p.runcall(_run, params)
 
2209
        log = open('profile_data_wx.'+strftime('%y%m%d%H%M%S')+'.txt','a')
 
2210
        normalstdout = sys.stdout
 
2211
        sys.stdout = log
 
2212
#        pstats.Stats(p).strip_dirs().sort_stats('cumulative').print_stats()
 
2213
        pstats.Stats(p).strip_dirs().sort_stats('time').print_stats()
 
2214
        sys.stdout = normalstdout
 
2215
    else:
 
2216
        _run(params)
 
2217
        
 
2218
def _run(params):
 
2219
    app = btWxApp(0, params)
 
2220
    app.MainLoop()
 
2221
 
 
2222
def next(params, d, doneflag, configfile):
 
2223
    if PROFILER:
 
2224
        import profile, pstats
 
2225
        p = profile.Profile()
 
2226
        p.runcall(_next, params, d, doneflag, configfile)
 
2227
        log = open('profile_data.'+strftime('%y%m%d%H%M%S')+'.txt','a')
 
2228
        normalstdout = sys.stdout
 
2229
        sys.stdout = log
 
2230
#        pstats.Stats(p).strip_dirs().sort_stats('cumulative').print_stats()
 
2231
        pstats.Stats(p).strip_dirs().sort_stats('time').print_stats()
 
2232
        sys.stdout = normalstdout
 
2233
    else:
 
2234
        _next(params, d, doneflag, configfile)
 
2235
 
 
2236
def _next(params, d, doneflag, configfile):
 
2237
    err = False
 
2238
    try:
 
2239
        while 1:
 
2240
            try:            
 
2241
                config = parse_params(params, configfile.config)
 
2242
            except ValueError, e:
 
2243
                d.error('error: ' + str(e) + '\nrun with no args for parameter explanations')
 
2244
                break
 
2245
            if not config:
 
2246
                d.displayUsage(get_usage(presets = configfile.config))
 
2247
                break
 
2248
 
 
2249
            myid = createPeerID()
 
2250
            seed(myid)
 
2251
            
 
2252
            rawserver = RawServer(doneflag, config['timeout_check_interval'],
 
2253
                                  config['timeout'], ipv6_enable = config['ipv6_enabled'],
 
2254
                                  failfunc = d.error, errorfunc = d.errorwindow)
 
2255
 
 
2256
            upnp_type = 0
 
2257
            while True:
 
2258
                try:
 
2259
                    listen_port = rawserver.find_and_bind(config['minport'], config['maxport'],
 
2260
                                    config['bind'], ipv6_socket_style = config['ipv6_binds_v4'],
 
2261
                                    upnp = upnp_type, randomizer = config['random_port'])
 
2262
                    break
 
2263
                except socketerror, e:
 
2264
                    if upnp_type and e == UPnP_ERROR:
 
2265
                        d.error('WARNING: COULD NOT FORWARD VIA UPnP')
 
2266
                        upnp_type = 0
 
2267
                        continue
 
2268
                    d.error("Couldn't listen - " + str(e))
 
2269
                    d.failed()
 
2270
                    return
 
2271
            d.connection_stats = rawserver.get_stats()
 
2272
 
 
2273
            response = get_response(config['responsefile'], config['url'], d.error)
 
2274
            if not response:
 
2275
                break
 
2276
 
 
2277
            infohash = sha(bencode(response['info'])).digest()
 
2278
            
 
2279
            torrentdata = configfile.getTorrentData(infohash)
 
2280
            if torrentdata:
 
2281
                oldsave = torrentdata.get('saved as')
 
2282
                d.old_ratesettings = torrentdata.get('rate settings')
 
2283
                s = torrentdata.get('stats')
 
2284
                if s:
 
2285
                    d.old_upload = s['uploaded']
 
2286
                    d.old_download = s['downloaded']
 
2287
            else:
 
2288
                oldsave = None
 
2289
 
 
2290
            dow = BT1Download(d.updateStatus, d.finished, d.error, d.errorwindow, doneflag,
 
2291
                            config, response, infohash, myid, rawserver, listen_port,
 
2292
                            configfile.getConfigDir())
 
2293
            d.dow = dow
 
2294
 
 
2295
            if config['gui_saveas_ask'] == 1:
 
2296
                oldsave = None
 
2297
            if oldsave:
 
2298
                if not dow.checkSaveLocation(oldsave):
 
2299
                    oldsave = None
 
2300
            if oldsave:
 
2301
                def choosefile(default, size, saveas, dir, oldsave = oldsave):
 
2302
                    d.ChooseFileDone(oldsave, size)
 
2303
                    return oldsave
 
2304
            elif config['gui_saveas_ask'] == 0:
 
2305
                def choosefile(default, size, saveas, dir,
 
2306
                               spot = config['gui_default_savedir']):
 
2307
                    spot = os.path.join(spot,default)
 
2308
                    d.ChooseFileDone(spot, size)
 
2309
                    return spot
 
2310
            else:
 
2311
                choosefile = d.chooseFile
 
2312
            savedas = dow.saveAs(choosefile, d.newpath)
 
2313
            if not savedas: 
 
2314
                break
 
2315
 
 
2316
            if not dow.initFiles(old_style = True):
 
2317
                break
 
2318
            if not dow.startEngine():
 
2319
                dow.shutdown()
 
2320
                break
 
2321
            dow.startRerequester()
 
2322
            dow.autoStats()
 
2323
 
 
2324
            if not dow.am_I_finished():
 
2325
                d.updateStatus(activity = 'connecting to peers')
 
2326
            rawserver.listen_forever(dow.getPortHandler())
 
2327
 
 
2328
            ratesettings = {
 
2329
                    'rate setting': d.current_ratesetting,
 
2330
                    'max download rate': config['max_download_rate']
 
2331
                }
 
2332
            if d.current_ratesetting != 'automatic':
 
2333
                ratesettings['uploads'] = config['min_uploads']
 
2334
                ratesettings['max upload rate'] = config['max_upload_rate']
 
2335
            up, dn = dow.get_transfer_stats()
 
2336
            stats = {
 
2337
                    'uploaded': up + d.old_upload,
 
2338
                    'downloaded': dn + d.old_download
 
2339
                }
 
2340
            torrentdata = {
 
2341
                    'saved as': savedas,
 
2342
                    'rate settings': ratesettings,
 
2343
                    'stats': stats
 
2344
                }
 
2345
            dow.shutdown(torrentdata)
 
2346
            break
 
2347
    except:
 
2348
        err = True
 
2349
        data = StringIO()
 
2350
        print_exc(file = data)
 
2351
        print data.getvalue()   # report exception here too
 
2352
        d.errorwindow(data.getvalue())
 
2353
    try:
 
2354
        rawserver.shutdown()
 
2355
    except:
 
2356
        pass
 
2357
    if not d.fin:
 
2358
        d.failed()
 
2359
    if err:
 
2360
        sleep(3600*24*30)   # this will make the app stick in the task manager,
 
2361
                            # but so be it
 
2362
 
 
2363
 
 
2364
if __name__ == '__main__':
 
2365
    if argv[1:] == ['--version']:
 
2366
        print version
 
2367
        exit(0)
 
2368
    run(argv[1:])