(file) Return to btdownloadgui.py CVS log (file) (dir) Up to [Development] / shadowsclient

File: [Development] / shadowsclient / btdownloadgui.py (download) / (as text)
Revision: 1.51, Tue Jan 27 22:21:54 2004 UTC (6 years, 7 months ago) by theshadow
Branch: MAIN
Changes since 1.50: +43 -41 lines
added "hidden" peer_id field in advanced window

#!/usr/bin/env python

# Written by Bram Cohen and Myers Carpenter
# Modifications by various people
# see LICENSE.txt for license information

from BitTorrent import PSYCO
if PSYCO.psyco:
    try:
        import psyco
        assert psyco.__version__ >= 0x010100f0
        psyco.full()
    except:
        pass

from sys import argv, version
assert version >= '2', "Install Python 2.0 or greater"

from BitTorrent.download import Download
from BitTorrent.ConnChoice import *
from BitTorrent.ConfigReader import configReader
from BitTorrent.bencode import bencode
from threading import Event, Thread
from os.path import *
from os import getcwd
from wxPython.wx import *
from time import strftime, time, localtime
from webbrowser import open_new
from traceback import print_exc
from StringIO import StringIO
from sha import sha
import re
import sys, os
from BitTorrent import version

true = 1
false = 0

PROFILER = false

basepath=os.path.abspath(os.path.dirname(sys.argv[0]))

def hours(n):
    if n == -1:
        return '<unknown>'
    if n == 0:
        return 'complete!'
    n = int(n)
    h, r = divmod(n, 60 * 60)
    m, sec = divmod(r, 60)
    if h > 1000000:
        return '<unknown>'
    if h > 0:
        return '%d hour(s) %02d min %02d sec' % (h, m, sec)
    else:
        return '%d min %02d sec' % (m, sec)

def size_format(s):
    if (s < 1024):
        r = str(s) + 'B'
    elif (s < 1048576):
        r = str(int(s/1024)) + 'KiB'
    elif (s < 1073741824L):
        r = str(int(s/1048576)) + 'MiB'
    elif (s < 1099511627776L):
        r = str(int((s/1073741824.0)*100.0)/100.0) + 'GiB'
    else:
        r = str(int((s/1099511627776.0)*100.0)/100.0) + 'TiB'
    return(r)

def comma_format(s):
    r = str(s)
    for i in range(len(r)-3, 0, -3):
        r = r[:i]+','+r[i:]
    return(r)

wxEVT_INVOKE = wxNewEventType()

def EVT_INVOKE(win, func):
    win.Connect(-1, -1, wxEVT_INVOKE, func)

class InvokeEvent(wxPyEvent):
    def __init__(self, func = None, args = None, kwargs = None):
        wxPyEvent.__init__(self)
        self.SetEventType(wxEVT_INVOKE)
        self.func = func
        self.args = args
        self.kwargs = kwargs

def pr(event):
    print 'augh!'


class DownloadInfoFrame:
    def __init__(self, flag, configfile):
        try:
            self.FONT = configfile.configfileargs['gui_font']
            self.default_font = wxFont(self.FONT, wxDEFAULT, wxNORMAL, wxNORMAL, false)
            frame = wxFrame(None, -1, 'BitTorrent ' + version + ' download')
            self.aaa = 0
            self.flag = flag
            self.uiflag = Event()
            self.fin = false
            self.aboutBox = None
            self.detailBox = None
            self.advBox = None
            self.creditsBox = None
            self.statusIconHelpBox = None
            self.reannouncelast = 0
            self.spinlock = 0
            self.scrollock = 0
            self.lastError = 0
            self.spewwait = time()
            self.config = None
            self.updateSpinnerFlag = 0
            self.updateSliderFlag = 0
            self.statusIconValue = ' '
            self.iconized = 0
            self.checking = None
            self.activity = 'Starting up...'
            self.firstupdate = true
            self.shuttingdown = false
            self.ispaused = false
            self.bgalloc_periods = 0
            self.gui_lastupdate = time()
            self.gui_fractiondone = None
            self.fileList = None
            self.lastexternalannounce = ''
            self.refresh_details = false
            self._errorwindow = None
            self.lastuploadsettings = 0
            self.filename = None
            if sys.platform == 'win32':
                self.invokeLaterEvent = InvokeEvent()
                self.invokeLaterList = []

            wxInitAllImageHandlers()
            self.statusIcons={
                'startup':wxIcon(os.path.join(basepath,'white.ico'), wxBITMAP_TYPE_ICO),
                'disconnected':wxIcon(os.path.join(basepath,'black.ico'), wxBITMAP_TYPE_ICO),
                'noconnections':wxIcon(os.path.join(basepath,'red.ico'), wxBITMAP_TYPE_ICO),
                'nocompletes':wxIcon(os.path.join(basepath,'blue.ico'), wxBITMAP_TYPE_ICO),
                'noincoming':wxIcon(os.path.join(basepath,'yellow.ico'), wxBITMAP_TYPE_ICO),
                'allgood':wxIcon(os.path.join(basepath,'green.ico'), wxBITMAP_TYPE_ICO)
                }

            self.filestatusIcons = wxImageList(16, 16)
            self.filestatusIcons.Add(wxBitmap(os.path.join(basepath,'black1.ico'),wxBITMAP_TYPE_ICO))
            self.filestatusIcons.Add(wxBitmap(os.path.join(basepath,'yellow1.ico'), wxBITMAP_TYPE_ICO))
            self.filestatusIcons.Add(wxBitmap(os.path.join(basepath,'green1.ico'), wxBITMAP_TYPE_ICO))

            self.allocbuttonBitmap = wxBitmap(os.path.join(basepath,'alloc.gif'), wxBITMAP_TYPE_GIF)

            if (sys.platform == 'win32'):
                self.icon = wxIcon(os.path.join(basepath,'icon_bt.ico'), wxBITMAP_TYPE_ICO)
            self.starttime = time ()

            self.frame = frame
            if (sys.platform == 'win32'):
                self.frame.SetIcon(self.icon)

            panel = wxPanel(frame, -1)

            def StaticText(text, font = self.FONT, underline = false, color = None, panel = panel):
                x = wxStaticText(panel, -1, text, style = wxALIGN_LEFT)
                x.SetFont(wxFont(font, wxDEFAULT, wxNORMAL, wxNORMAL, underline))
                if color is not None:
                    x.SetForegroundColour(color)
                return x

            colSizer = wxFlexGridSizer(cols = 1, vgap = 3)

            border = wxBoxSizer(wxHORIZONTAL)
            border.Add(colSizer, 1, wxEXPAND | wxALL, 4)
            panel.SetSizer(border)
            panel.SetAutoLayout(true)

            topboxsizer = wxFlexGridSizer(cols = 3, vgap = 0)
            topboxsizer.AddGrowableCol (0)

            fnsizer = wxFlexGridSizer(cols = 1, vgap = 0)
            fnsizer.AddGrowableCol (0)
            fnsizer.AddGrowableRow (1)

            fileNameText = StaticText('', self.FONT+4)
            fnsizer.Add(fileNameText, 1, wxALIGN_BOTTOM|wxEXPAND)
            self.fileNameText = fileNameText

            fnsizer2 = wxFlexGridSizer(cols = 8, vgap = 0)
            fnsizer2.AddGrowableCol (0)

            fileSizeText = StaticText('')
            fnsizer2.Add(fileSizeText, 1, wxALIGN_BOTTOM|wxEXPAND)
            self.fileSizeText = fileSizeText

            fileDetails = StaticText('Details', self.FONT, true, 'Blue')
            fnsizer2.Add(fileDetails, 0, wxALIGN_BOTTOM)                                     

            fnsizer2.Add(StaticText('  '))

            advText = StaticText('Advanced', self.FONT, true, 'Blue')
            fnsizer2.Add(advText, 0, wxALIGN_BOTTOM)
            fnsizer2.Add(StaticText('  '))

            prefsText = StaticText('Prefs', self.FONT, true, 'Blue')
            fnsizer2.Add(prefsText, 0, wxALIGN_BOTTOM)
            fnsizer2.Add(StaticText('  '))

            aboutText = StaticText('About', self.FONT, true, 'Blue')
            fnsizer2.Add(aboutText, 0, wxALIGN_BOTTOM)

            fnsizer2.Add(StaticText('  '))
            fnsizer.Add(fnsizer2,0,wxEXPAND)
            topboxsizer.Add(fnsizer,0,wxEXPAND)
            topboxsizer.Add(StaticText('  '))

            self.statusIcon = wxEmptyBitmap(32,32)
            statidata = wxMemoryDC()
            statidata.SelectObject(self.statusIcon)
            statidata.SetPen(wxTRANSPARENT_PEN)
            statidata.SetBrush(wxBrush(wx.wxSystemSettings_GetColour(wxSYS_COLOUR_MENU),wxSOLID))
            statidata.DrawRectangle(0,0,32,32)
            self.statusIconPtr = wxStaticBitmap(panel, -1, self.statusIcon)
            topboxsizer.Add(self.statusIconPtr)

            self.fnsizer = fnsizer
            self.fnsizer2 = fnsizer2
            self.topboxsizer = topboxsizer
            colSizer.Add(topboxsizer, 0, wxEXPAND)

            self.gauge = wxGauge(panel, -1, range = 1000, style = wxGA_SMOOTH)
            colSizer.Add(self.gauge, 0, wxEXPAND)
#        self.gauge.SetForegroundColour(wx.wxSystemSettings_GetColour(wxSYS_COLOUR_3DSHADOW))

            timeSizer = wxFlexGridSizer(cols = 2)
            timeSizer.Add(StaticText('Time elapsed / estimated : '))
            self.timeText = StaticText(self.activity+'                    ')
            timeSizer.Add(self.timeText)
            timeSizer.AddGrowableCol(1)
            colSizer.Add(timeSizer)

            destSizer = wxFlexGridSizer(cols = 2, hgap = 8)
            self.fileDestLabel = StaticText('Download to:')
            destSizer.Add(self.fileDestLabel)
            self.fileDestText = StaticText('')
            destSizer.Add(self.fileDestText, flag = wxEXPAND)
            destSizer.AddGrowableCol(1)
            colSizer.Add(destSizer, flag = wxEXPAND)
            self.destSizer = destSizer

            statSizer = wxFlexGridSizer(cols = 3, hgap = 8)

            self.ratesSizer = wxFlexGridSizer(cols = 2)
            self.infoSizer = wxFlexGridSizer(cols = 2)

            self.ratesSizer.Add(StaticText('   Download rate: '))
            self.downRateText = StaticText('0 kB/s       ')
            self.ratesSizer.Add(self.downRateText, flag = wxEXPAND)

            self.downTextLabel = StaticText('Downloaded: ')
            self.infoSizer.Add(self.downTextLabel)
            self.downText = StaticText('0.00 MiB        ')
            self.infoSizer.Add(self.downText, flag = wxEXPAND)

            self.ratesSizer.Add(StaticText('   Upload rate: '))
            self.upRateText = StaticText('0 kB/s       ')
            self.ratesSizer.Add(self.upRateText, flag = wxEXPAND)

            self.upTextLabel = StaticText('Uploaded: ')
            self.infoSizer.Add(self.upTextLabel)
            self.upText = StaticText('0.00 MiB        ')
            self.infoSizer.Add(self.upText, flag = wxEXPAND)

            shareSizer = wxFlexGridSizer(cols = 2, hgap = 8)
            shareSizer.Add(StaticText('Share rating:'))
            self.shareRatingText = StaticText('')
            shareSizer.AddGrowableCol(1)
            shareSizer.Add(self.shareRatingText, flag = wxEXPAND)

            statSizer.Add(self.ratesSizer)
            statSizer.Add(self.infoSizer)
            statSizer.Add(shareSizer, flag = wxALIGN_CENTER_VERTICAL)
            colSizer.Add (statSizer)

            torrentSizer = wxFlexGridSizer(cols = 1)
            self.peerStatusText = StaticText('')
            torrentSizer.Add(self.peerStatusText, 0, wxEXPAND)
            self.seedStatusText = StaticText('')
            torrentSizer.Add(self.seedStatusText, 0, wxEXPAND)
            torrentSizer.AddGrowableCol(0)
            colSizer.Add(torrentSizer, 0, wxEXPAND)
            self.torrentSizer = torrentSizer

            self.errorTextSizer = wxFlexGridSizer(cols = 1)
            self.errorText = StaticText('', self.FONT, false, 'Red')
            self.errorTextSizer.Add(self.errorText, 0, wxEXPAND)
            colSizer.Add(self.errorTextSizer, 0, wxEXPAND)

            cancelSizer=wxGridSizer(cols = 2, hgap = 40)
            self.pauseButton = wxButton(panel, -1, 'Pause')
#        self.pauseButton.SetFont(self.default_font)
            cancelSizer.Add(self.pauseButton, 0, wxALIGN_CENTER)

            self.cancelButton = wxButton(panel, -1, 'Cancel')
#        self.cancelButton.SetFont(self.default_font)
            cancelSizer.Add(self.cancelButton, 0, wxALIGN_CENTER)
            colSizer.Add(cancelSizer, 0, wxALIGN_CENTER)

            # Setting options

            slideSizer = wxFlexGridSizer(cols = 7, hgap = 0, vgap = 5)

            # dropdown

            self.connChoiceLabel = StaticText('Settings for ')
            slideSizer.Add (self.connChoiceLabel, 0, wxALIGN_LEFT|wxALIGN_CENTER_VERTICAL)
            self.connChoice = wxChoice (panel, -1, (-1, -1), (self.FONT*11, -1),
                                        choices = connChoiceList)
            self.connChoice.SetFont(self.default_font)
            self.connChoice.SetSelection(0)
            slideSizer.Add (self.connChoice, 0, wxALIGN_CENTER)
            self.rateSpinnerLabel = StaticText(' Upload rate (kB/s) ')
            slideSizer.Add (self.rateSpinnerLabel, 0, wxALIGN_RIGHT|wxALIGN_CENTER_VERTICAL)

            # max upload rate

            self.rateSpinner = wxSpinCtrl (panel, -1, "", (-1,-1), (50, -1))
            self.rateSpinner.SetFont(self.default_font)
            self.rateSpinner.SetRange(0,5000)
            self.rateSpinner.SetValue(0)
            slideSizer.Add (self.rateSpinner, 0, wxALIGN_CENTER|wxALIGN_CENTER_VERTICAL)

            self.rateLowerText = StaticText('  %5d' % (0))
            self.rateUpperText = StaticText('%5d' % (5000))
            self.rateslider = wxSlider(panel, -1, 0, 0, 5000, (-1, -1), (80, -1))

            slideSizer.Add(self.rateLowerText, 0, wxALIGN_RIGHT|wxALIGN_CENTER_VERTICAL)
            slideSizer.Add(self.rateslider,    0, wxALIGN_CENTER|wxALIGN_CENTER_VERTICAL)
            slideSizer.Add(self.rateUpperText, 0, wxALIGN_LEFT|wxALIGN_CENTER_VERTICAL)

            slideSizer.Add(StaticText(''), 0, wxALIGN_LEFT)

            self.bgallocText = StaticText('', self.FONT+2, false, 'Red')
            slideSizer.Add(self.bgallocText, 0, wxALIGN_LEFT)

            # max uploads

            self.connSpinnerLabel = StaticText(' Max uploads ')
            slideSizer.Add (self.connSpinnerLabel, 0, wxALIGN_RIGHT|wxALIGN_CENTER_VERTICAL)
            self.connSpinner = wxSpinCtrl (panel, -1, "", (-1,-1), (50, -1))
            self.connSpinner.SetFont(self.default_font)
            self.connSpinner.SetRange(4,100)
            self.connSpinner.SetValue(4)
            slideSizer.Add (self.connSpinner, 0, wxALIGN_CENTER|wxALIGN_CENTER_VERTICAL)

            self.connLowerText = StaticText('  %5d' % (4))
            self.connUpperText = StaticText('%5d' % (100))
            self.connslider = wxSlider(panel, -1, 4, 4, 100, (-1, -1), (80, -1))

            slideSizer.Add(self.connLowerText, 0, wxALIGN_RIGHT|wxALIGN_CENTER_VERTICAL)
            slideSizer.Add(self.connslider,    0, wxALIGN_CENTER|wxALIGN_CENTER_VERTICAL)
            slideSizer.Add(self.connUpperText, 0, wxALIGN_LEFT|wxALIGN_CENTER_VERTICAL)

            colSizer.Add(slideSizer, 1, wxALL|wxALIGN_CENTER|wxEXPAND, 0)

            self.unlimitedLabel = StaticText('0 kB/s means unlimited. Tip: your download rate is proportional to your upload rate', self.FONT-2)
            colSizer.Add(self.unlimitedLabel, 0, wxALIGN_CENTER)

            EVT_LEFT_DOWN(aboutText, self.about)
            EVT_LEFT_DOWN(fileDetails, self.details)
            EVT_LEFT_DOWN(self.statusIconPtr,self.statusIconHelp)
            EVT_LEFT_DOWN(advText, self.advanced)
            EVT_LEFT_DOWN(prefsText, self.openConfigMenu)
            EVT_CLOSE(frame, self.done)
            EVT_BUTTON(frame, self.pauseButton.GetId(), self.pause)
            EVT_BUTTON(frame, self.cancelButton.GetId(), self.done)
            EVT_INVOKE(frame, self.onInvoke)
            EVT_SCROLL(self.rateslider, self.onRateScroll)
            EVT_SCROLL(self.connslider, self.onConnScroll)
            EVT_CHOICE(self.connChoice, -1, self.onConnChoice)
            EVT_SPINCTRL(self.connSpinner, -1, self.onConnSpinner)
            EVT_SPINCTRL(self.rateSpinner, -1, self.onRateSpinner)
            if (sys.platform == 'win32'):
                EVT_ICONIZE(self.frame, self.onIconify)

            colSizer.AddGrowableCol (0)
            colSizer.AddGrowableRow (6)
            self.frame.Show()
            border.Fit(panel)
            self.frame.Fit()
            self.panel = panel
            self.border = border
            self.addwidth = aboutText.GetBestSize().GetWidth() + fileDetails.GetBestSize().GetWidth() + (self.FONT*14)
            self.fnsizer = fnsizer
            self.colSizer = colSizer
            minsize = self.colSizer.GetSize()
            minsize.SetWidth (minsize.GetWidth())
            minsize.SetHeight (minsize.GetHeight())
            self.colSizer.SetMinSize (minsize)
            self.colSizer.Fit(self.frame)
            colSizer.Fit(frame)
        except:
            self.exception()

    if sys.platform == 'win32':     # windows-only optimization
        def onInvoke(self, event):
            while self.invokeLaterList:
                func,args,kwargs = self.invokeLaterList[0]
                if self.uiflag.isSet():
                    return
                try:
                    apply(func,args,kwargs)
                except:
                    self.exception()
                del self.invokeLaterList[0]

        def invokeLater(self, func, args = [], kwargs = {}):
            if not self.uiflag.isSet():
                self.invokeLaterList.append((func,args,kwargs))
                if len(self.invokeLaterList) == 1:
                    wxPostEvent(self.frame, self.invokeLaterEvent)
    else:
        def onInvoke(self, event):
            if not self.uiflag.isSet():
                try:
                    apply(event.func, event.args, event.kwargs)
                except:
                    self.exception()

        def invokeLater(self, func, args = [], kwargs = {}):
            if not self.uiflag.isSet():
                wxPostEvent(self.frame, InvokeEvent(func, args, kwargs))


    def setStatusIcon(self, name):
        if name != self.statusIconValue:
            self.statusIconValue = name;
            statidata = wxMemoryDC()
            statidata.SelectObject(self.statusIcon)
            statidata.BeginDrawing()
            statidata.DrawIcon(self.statusIcons[name],0,0)
            statidata.EndDrawing()
            statidata.SelectObject(wxNullBitmap)
            self.statusIconPtr.Refresh()


    def createStatusIcon(self, name):
        iconbuffer = wxEmptyBitmap(32,32)
        bbdata = wxMemoryDC()
        bbdata.SelectObject(iconbuffer)
        bbdata.SetPen(wxTRANSPARENT_PEN)
        bbdata.SetBrush(wxBrush(wx.wxSystemSettings_GetColour(wxSYS_COLOUR_MENU),wxSOLID))
        bbdata.DrawRectangle(0,0,32,32)
        bbdata.DrawIcon(self.statusIcons[name],0,0)
        return iconbuffer


    def onIconify(self, evt):
        try:
            if self.configfile.configfileargs['win32_taskbar_icon']:
                if not hasattr(self.frame, "tbicon"):
                    self.frame.tbicon = wxTaskBarIcon()
                    self.frame.tbicon.SetIcon(self.icon, "BitTorrent")
                    # setup a taskbar icon, and catch some events from it
                    EVT_TASKBAR_LEFT_DCLICK(self.frame.tbicon, self.onTaskBarActivate)
                    EVT_TASKBAR_RIGHT_UP(self.frame.tbicon, self.onTaskBarMenu)
                    EVT_MENU(self.frame.tbicon, self.TBMENU_RESTORE, self.onTaskBarActivate)
                    EVT_MENU(self.frame.tbicon, self.TBMENU_CLOSE, self.done)
                self.frame.Hide()
            else:
                EVT_ICONIZE(self.frame, self.onIconifyDummy)
                if self.iconized:
                    self.frame.Iconize(false)
                    self.iconized = false
                else:
                    self.frame.Iconize(true)
                    self.iconized = true
                EVT_ICONIZE(self.frame, self.onIconify)
                # rant here -- why in god's name can't a function called by an event
                # trigger the event without calling itself?
                # self.frame.Iconize(not self.frame.IsIconized()) should do this job...
        except:
            self.exception()

    def onIconifyDummy(self, evt):
        return

    def onTaskBarActivate(self, evt):
        try:
            if self.frame.IsIconized():
                self.frame.Iconize(false)
            if not self.frame.IsShown():
                self.frame.Show(true)
                self.frame.Raise()
            if hasattr(self.frame, "tbicon"):
                del self.frame.tbicon
        except:
            self.exception()

    TBMENU_RESTORE = 1000
    TBMENU_CLOSE   = 1001

    def onTaskBarMenu(self, evt):
        menu = wxMenu()
        menu.Append(self.TBMENU_RESTORE, "Restore BitTorrent")
        menu.Append(self.TBMENU_CLOSE,   "Close")
        self.frame.tbicon.PopupMenu(menu)
        menu.Destroy()


    def _try_get_config(self):
        if self.config is None:
            self.config = self.dow.getConfig()
        return self.config != None


    def onRateScroll(self, event):
        try:
            if (self.scrollock == 0):
                self.scrollock = 1
                if not self._try_get_config():
                    return
                self.updateSpinnerFlag = 1
                self.dow.setUploadRate(self.rateslider.GetValue() * 1000
                            * connChoices[self.connChoice.GetSelection()]['rate'].get('div',1))
                self.scrollock = 0
        except:
            self.exception()

    def onConnScroll(self, event):
        try:
            if not self._try_get_config():
                return
            self.connSpinner.SetValue (self.connslider.GetValue ())
            self.dow.setConns(self.connslider.GetValue())
        except:
            self.exception()

    def onRateSpinner(self, event):
        try:
            if not self._try_get_config():
                return
            if (self.spinlock == 0):
                self.spinlock = 1
                spinnerValue = self.rateSpinner.GetValue()
                div = connChoices[self.connChoice.GetSelection()]['rate'].get('div',1)
                if div > 1:
                    if spinnerValue > (self.config['max_upload_rate']/1000):
                        round_up = div - 1
                    else:
                        round_up = 0
                    newValue = int((spinnerValue + round_up) / div) * div
                    if newValue != spinnerValue:
                        self.rateSpinner.SetValue(newValue)
                else:
                    newValue = spinnerValue
                self.dow.setUploadRate(newValue * 1000)
                self.updateSliderFlag = 1
                self.spinlock = 0
        except:
            self.exception()

    def onConnSpinner(self, event):
        try:
            if not self._try_get_config():
                return
            self.connslider.SetValue (self.connSpinner.GetValue())
            self.dow.setConns(self.connslider.GetValue())
        except:
            self.exception()

    def onConnChoice(self, event):
        try:
            if not self._try_get_config():
                return
            num = self.connChoice.GetSelection()
            if connChoices[num].has_key('super-seed'):  # selecting super-seed is now a toggle
                self.dow.set_super_seed()               # one way change, don't go back
                num = self.lastuploadsettings
                self.connChoice.SetSelection(num)
                return
            self.lastuploadsettings = num
            self.rateSpinner.SetRange (connChoices[num]['rate']['min'],
                                   connChoices[num]['rate']['max'])
            self.rateSpinner.SetValue (connChoices[num]['rate']['def'])
            self.rateslider.SetRange (
                connChoices[num]['rate']['min']/connChoices[num]['rate'].get('div',1),
                connChoices[num]['rate']['max']/connChoices[num]['rate'].get('div',1))
            self.rateslider.SetValue (
                connChoices[num]['rate']['def']/connChoices[num]['rate'].get('div',1))
            self.rateLowerText.SetLabel ('  %d' % (connChoices[num]['rate']['min']))
            self.rateUpperText.SetLabel ('%d' % (connChoices[num]['rate']['max']))
            self.connSpinner.SetRange (connChoices[num]['conn']['min'],
                                       connChoices[num]['conn']['max'])
            self.connSpinner.SetValue (connChoices[num]['conn']['def'])
            self.connslider.SetRange (connChoices[num]['conn']['min'],
                                      connChoices[num]['conn']['max'])
            self.connslider.SetValue (connChoices[num]['conn']['def'])
            self.connLowerText.SetLabel ('  %d' % (connChoices[num]['conn']['min']))
            self.connUpperText.SetLabel ('%d' % (connChoices[num]['conn']['max']))
            self.onConnScroll (0)
            self.onRateScroll (0)
            self.dow.setInitiate(connChoices[num].get('initiate', 40))
        except:
            self.exception()


    def about(self, event):
        try:
            if (self.aboutBox is not None):
                try:
                    self.aboutBox.Close ()
                except wxPyDeadObjectError, e:
                    self.aboutBox = None

            self.aboutBox = wxFrame(None, -1, 'About BitTorrent', size = (1,1))
            if (sys.platform == 'win32'):
                self.aboutBox.SetIcon(self.icon)

            panel = wxPanel(self.aboutBox, -1)

            def StaticText(text, font = self.FONT, underline = false, color = None, panel = panel):
                x = wxStaticText(panel, -1, text, style = wxALIGN_LEFT)
                x.SetFont(wxFont(font, wxDEFAULT, wxNORMAL, wxNORMAL, underline))
                if color is not None:
                    x.SetForegroundColour(color)
                return x

            colSizer = wxFlexGridSizer(cols = 1, vgap = 3)

            titleSizer = wxBoxSizer(wxHORIZONTAL)
            aboutTitle = StaticText('BitTorrent ' + version + '  ', self.FONT+4)
            titleSizer.Add (aboutTitle)
            linkDonate = StaticText('Donate to Bram', self.FONT, true, 'Blue')
            titleSizer.Add (linkDonate, 1, wxALIGN_BOTTOM&wxEXPAND)
            colSizer.Add(titleSizer, 0, wxEXPAND)

            colSizer.Add(StaticText('created by Bram Cohen, Copyright 2001-2003,'))
            colSizer.Add(StaticText('experimental version maintained by John Hoffman 2003'))
            colSizer.Add(StaticText('modified from experimental version by Eike Frost 2003'))
            credits = StaticText('full credits\n', self.FONT, true, 'Blue')
            colSizer.Add(credits);

            si = ( 'exact Version String: ' + version + '\n' +
                   'Python version: ' + sys.version + '\n' +
                   'wxWindows version: ' + wxVERSION_STRING + '\n' )
            try:
                si += 'Psyco version: ' + hex(psyco.__version__)[2:] + '\n'
            except:
                pass
            colSizer.Add(StaticText(si))

            babble1 = StaticText(
             'This is an experimental, unofficial build of BitTorrent.\n' +
             'It is Free Software under an MIT-Style license.')
            babble2 = StaticText('BitTorrent Homepage (link)', self.FONT, true, 'Blue')
            babble3 = StaticText("TheSHAD0W's Client Homepage (link)", self.FONT, true, 'Blue')
            babble4 = StaticText("Eike Frost's Client Homepage (link)", self.FONT, true, 'Blue')
            babble6 = StaticText('License Terms (link)', self.FONT, true, 'Blue')
            colSizer.Add (babble1)
            colSizer.Add (babble2)
            colSizer.Add (babble3)
            colSizer.Add (babble4)
            colSizer.Add (babble6)

            okButton = wxButton(panel, -1, 'Ok')
#        okButton.SetFont(self.default_font)
            colSizer.Add(okButton, 0, wxALIGN_RIGHT)
            colSizer.AddGrowableCol(0)

            border = wxBoxSizer(wxHORIZONTAL)
            border.Add(colSizer, 1, wxEXPAND | wxALL, 4)
            panel.SetSizer(border)
            panel.SetAutoLayout(true)

            def donatelink(self):
                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()
            EVT_LEFT_DOWN(linkDonate, donatelink)
            def aboutlink(self):
                Thread(target = open_new('http://bitconjurer.org/BitTorrent/')).start()
            EVT_LEFT_DOWN(babble2, aboutlink)
            def shadlink(self):
                Thread(target = open_new('http://bt.degreez.net/')).start()
            EVT_LEFT_DOWN(babble3, shadlink)
            def explink(self):
                Thread(target = open_new('http://ei.kefro.st/projects/btclient/')).start()
            EVT_LEFT_DOWN(babble4, explink)
            def licenselink(self):
                Thread(target = open_new('http://ei.kefro.st/projects/btclient/LICENSE.TXT')).start()
            EVT_LEFT_DOWN(babble6, licenselink)
            EVT_LEFT_DOWN(credits, self.credits)

            def closeAbout(self, frame = self):
                frame.aboutBox.Close ()
            EVT_BUTTON(self.aboutBox, okButton.GetId(), closeAbout)
            def kill(self, frame = self):
                frame.aboutBox.Destroy()
                frame.aboutBox = None
            EVT_CLOSE(self.aboutBox, kill)

            self.aboutBox.Show ()
            border.Fit(panel)
            self.aboutBox.Fit()
        except:
            self.exception()


    def details(self, event):
        try:
            metainfo = self.dow.getResponse()
            if metainfo is None:
                return
            if metainfo.has_key('announce'):
                announce = metainfo['announce']
            else:
                announce = None
            if metainfo.has_key('announce-list'):
                announce_list = metainfo['announce-list']
            else:
                announce_list = None
            info = metainfo['info']
            info_hash = sha(bencode(info))
            piece_length = info['piece length']

            if (self.detailBox is not None):
                try:
                    self.detailBox.Close ()
                except wxPyDeadObjectError, e:
                    self.detailBox = None

            self.detailBox = wxFrame(None, -1, 'Torrent Details ', size = wxSize(405,230))
            if (sys.platform == 'win32'):
                self.detailBox.SetIcon(self.icon)

            panel = wxPanel(self.detailBox, -1, size = wxSize (400,220))

            def StaticText(text, font = self.FONT, underline = false, color = None, panel = panel):
                x = wxStaticText(panel, -1, text, style = wxALIGN_CENTER_VERTICAL)
                x.SetFont(wxFont(font, wxDEFAULT, wxNORMAL, wxNORMAL, underline))
                if color is not None:
                    x.SetForegroundColour(color)
                return x

            colSizer = wxFlexGridSizer(cols = 1, vgap = 3)
            colSizer.AddGrowableCol(0)

            titleSizer = wxBoxSizer(wxHORIZONTAL)
            aboutTitle = StaticText('Details about ' + self.filename, self.FONT+4)

            titleSizer.Add (aboutTitle)
            colSizer.Add (titleSizer)

            detailSizer = wxFlexGridSizer(cols = 2, vgap = 6)

            if info.has_key('length'):
                detailSizer.Add(StaticText('file name :'))
                detailSizer.Add(StaticText(info['name']))
                if info.has_key('md5sum'):
                    detailSizer.Add(StaticText('MD5 hash :'))
                    detailSizer.Add(StaticText(info['md5sum']))
                file_length = info['length']
                name = "file size"
            else:
                detail1Sizer = wxFlexGridSizer(cols = 1, vgap = 6)
                detail1Sizer.Add(StaticText('directory name : ' + info['name']))
                colSizer.Add (detail1Sizer)
                bgallocButton = wxBitmapButton(panel, -1, self.allocbuttonBitmap, size = (52,20))
                def bgalloc(self, frame = self):
                    if frame.dow.storagewrapper is not None:
                        frame.dow.storagewrapper.bgalloc()
                EVT_BUTTON(self.detailBox, bgallocButton.GetId(), bgalloc)

                bgallocbuttonSizer = wxFlexGridSizer(cols = 3, hgap = 4, vgap = 0)
                bgallocbuttonSizer.Add(StaticText('(finish allocation)'), -1, wxALIGN_CENTER_VERTICAL)
                bgallocbuttonSizer.Add(bgallocButton, -1, wxALIGN_CENTER)
                colSizer.Add(bgallocbuttonSizer, -1, wxALIGN_RIGHT)

                file_length = 0

                fileList = wxListCtrl(panel, -1, wxPoint(-1,-1), (325,100), wxLC_REPORT)
                self.fileList = fileList
                fileList.SetImageList(self.filestatusIcons, wxIMAGE_LIST_SMALL)

                fileList.SetAutoLayout (true)
                fileList.InsertColumn(0, "file")
                fileList.InsertColumn(1, "", format=wxLIST_FORMAT_RIGHT, width=55)
                fileList.InsertColumn(2, "")

                for i in range(len(info['files'])):
                    x = wxListItem()
#                x.SetFont(self.default_font)
                    fileList.InsertItem(x)

                x = 0
                for file in info['files']:
                    path = ' '
                    for item in file['path']:
                        if (path != ''):
                            path = path + "/"
                        path = path + item
                    path += ' (' + str(file['length']) + ')'
                    fileList.SetStringItem(x, 0, path)
                    if file.has_key('md5sum'):
                        fileList.SetStringItem(x, 2, '    [' + str(file['md5sum']) + ']')
                    x += 1
                    file_length += file['length']
                fileList.SetColumnWidth(0,wxLIST_AUTOSIZE)
                fileList.SetColumnWidth(2,wxLIST_AUTOSIZE)

                name = 'archive size'
                colSizer.Add(fileList, 1, wxEXPAND)
                colSizer.AddGrowableRow(3)

            detailSizer.Add(StaticText('info_hash :'),0,wxALIGN_CENTER_VERTICAL)
            detailSizer.Add(wxTextCtrl(panel, -1, info_hash.hexdigest(), size = (325, -1), style = wxTE_READONLY))
            num_pieces = int((file_length+piece_length-1)/piece_length)
            detailSizer.Add(StaticText(name + ' : '))
            detailSizer.Add(StaticText('%s (%s bytes)' % (size_format(file_length), comma_format(file_length))))
            detailSizer.Add(StaticText('pieces : '))
            if num_pieces > 1:
                detailSizer.Add(StaticText('%i (%s bytes each)' % (num_pieces, comma_format(piece_length))))
            else:
                detailSizer.Add(StaticText('1'))

            if announce_list is None:
                detailSizer.Add(StaticText('announce url : '),0,wxALIGN_CENTER_VERTICAL)
                detailSizer.Add(wxTextCtrl(panel, -1, announce, size = (325, -1), style = wxTE_READONLY))
            else:
                detailSizer.Add(StaticText(''))
                trackerList = wxListCtrl(panel, -1, wxPoint(-1,-1), (325,75), wxLC_REPORT)
                trackerList.SetAutoLayout (true)
                trackerList.InsertColumn(0, "")
                trackerList.InsertColumn(1, "announce urls")

                for tier in range(len(announce_list)):
                    for t in range(len(announce_list[tier])):
                        i = wxListItem()
#                    i.SetFont(self.default_font)
                        trackerList.InsertItem(i)
                if announce is not None:
                    for l in [1,2]:
                        i = wxListItem()
#                    i.SetFont(self.default_font)
                        trackerList.InsertItem(i)

                x = 0
                for tier in range(len(announce_list)):
                    for t in range(len(announce_list[tier])):
                        if t == 0:
                            trackerList.SetStringItem(x, 0, 'tier '+str(tier)+':')
                        trackerList.SetStringItem(x, 1, announce_list[tier][t])
                        x += 1
                if announce is not None:
                    trackerList.SetStringItem(x+1, 0, 'single:')
                    trackerList.SetStringItem(x+1, 1, announce)
                trackerList.SetColumnWidth(0,wxLIST_AUTOSIZE)
                trackerList.SetColumnWidth(1,wxLIST_AUTOSIZE)
                detailSizer.Add(trackerList)

            if announce is None and announce_list is not None:
                announce = announce_list[0][0]
            if announce is not None:
                detailSizer.Add(StaticText('likely tracker :'))
                p = re.compile( '(.*/)[^/]+')
                turl = p.sub (r'\1', announce)
                trackerUrl = StaticText(turl, self.FONT, true, 'Blue')
                detailSizer.Add(trackerUrl)
            if metainfo.has_key('comment'):
                detailSizer.Add(StaticText('comment :'))
                detailSizer.Add(StaticText(metainfo['comment']))
            if metainfo.has_key('creation date'):
                detailSizer.Add(StaticText('creation date :'))
                try:
                    detailSizer.Add(StaticText(
                        strftime('%x %X',localtime(metainfo['creation date']))))
                except:
                    try:
                        detailSizer.Add(StaticText(metainfo['creation date']))
                    except:
                        detailSizer.Add(StaticText('<cannot read date>'))

            detailSizer.AddGrowableCol(1)
            colSizer.Add (detailSizer, 1, wxEXPAND)

            okButton = wxButton(panel, -1, 'Ok')
#        okButton.SetFont(self.default_font)
            colSizer.Add(okButton, 0, wxALIGN_RIGHT)
            colSizer.AddGrowableCol(0)

            if not self.configfile.configfileargs['gui_stretchwindow']:
                aboutTitle.SetSize((400,-1))
            else:
                panel.SetAutoLayout(true)

            border = wxBoxSizer(wxHORIZONTAL)
            border.Add(colSizer, 1, wxEXPAND | wxALL, 4)
            panel.SetSizer(border)
            panel.SetAutoLayout(true)

            def closeDetail(self, frame = self):
                frame.detailBox.Close ()
            EVT_BUTTON(self.detailBox, okButton.GetId(), closeDetail)
            def kill(self, frame = self):
                frame.detailBox.Destroy()
                frame.detailBox = None
                frame.fileList = None
                frame.dow.filedatflag.clear()
            EVT_CLOSE(self.detailBox, kill)

            def trackerurl(self, turl = turl):
                Thread(target = open_new(turl)).start()

            EVT_LEFT_DOWN(trackerUrl, trackerurl)

            self.detailBox.Show ()
            border.Fit(panel)
            self.detailBox.Fit()

            self.refresh_details = true
            self.dow.filedatflag.set()
        except:
            self.exception()


    def credits(self, event):
        try:
            if (self.creditsBox is not None):
                try:
                    self.creditsBox.Close ()
                except wxPyDeadObjectError, e:
                    self.creditsBox = None

            self.creditsBox = wxFrame(None, -1, 'Credits', size = (1,1))
            if (sys.platform == 'win32'):
                self.creditsBox.SetIcon(self.icon)

            panel = wxPanel(self.creditsBox, -1)        

            def StaticText(text, font = self.FONT, underline = false, color = None, panel = panel):
                x = wxStaticText(panel, -1, text, style = wxALIGN_LEFT)
                x.SetFont(wxFont(font, wxDEFAULT, wxNORMAL, wxNORMAL, underline))
                if color is not None:
                    x.SetForegroundColour(color)
                return x

            colSizer = wxFlexGridSizer(cols = 1, vgap = 3)

            titleSizer = wxBoxSizer(wxHORIZONTAL)
            aboutTitle = StaticText('Credits', self.FONT+4)
            titleSizer.Add (aboutTitle)
            colSizer.Add (titleSizer)
            colSizer.Add (StaticText(
              'The following people have all helped with this\n' +
              'version of BitTorrent in some way (in no particular order) -\n'));
            creditSizer = wxFlexGridSizer(cols = 3)
            creditSizer.Add(StaticText(
              'Bill Bumgarner\n' +
              'David Creswick\n' +
              'Andrew Loewenstern\n' +
              'Ross Cohen\n' +
              'Jeremy Avnet\n' +
              'Greg Broiles\n' +
              'Barry Cohen\n' +
              'Bram Cohen\n' +
              'sayke\n' +
              'Steve Jenson\n' +
              'Myers Carpenter\n' +
              'Francis Crick\n' +
              'Petru Paler\n' +
              'Jeff Darcy\n' +
              'John Gilmore\n' +
              'Xavier Bassery\n' +
              'Pav Lucistnik'))
            creditSizer.Add(StaticText('  '))
            creditSizer.Add(StaticText(
              'Yann Vernier\n' +
              'Pat Mahoney\n' +
              'Boris Zbarsky\n' +
              'Eric Tiedemann\n' +
              'Henry "Pi" James\n' +
              'Loring Holden\n' +
              'Robert Stone\n' +
              'Michael Janssen\n' +
              'Eike Frost\n' +
              'Andrew Todd\n' +
              'otaku\n' +
              'Edward Keyes\n' +
              'John Hoffman\n' +
              'Uoti Urpala\n' +
              'Jon Wolf\n' +
              'Christoph Hohmann'))
            colSizer.Add (creditSizer, flag = wxALIGN_CENTER_HORIZONTAL)
            okButton = wxButton(panel, -1, 'Ok')
#        okButton.SetFont(self.default_font)
            colSizer.Add(okButton, 0, wxALIGN_RIGHT)
            colSizer.AddGrowableCol(0)

            border = wxBoxSizer(wxHORIZONTAL)
            border.Add(colSizer, 1, wxEXPAND | wxALL, 4)
            panel.SetSizer(border)
            panel.SetAutoLayout(true)

            def closeCredits(self, frame = self):
                frame.creditsBox.Close ()
            EVT_BUTTON(self.creditsBox, okButton.GetId(), closeCredits)
            def kill(self, frame = self):
                frame.creditsBox.Destroy()
                frame.creditsBox = None
            EVT_CLOSE(self.creditsBox, kill)

            self.creditsBox.Show()
            border.Fit(panel)
            self.creditsBox.Fit()
        except:
            self.exception()


    def statusIconHelp(self, event):
        try:
            if (self.statusIconHelpBox is not None):
                try:
                    self.statusIconHelpBox.Close ()
                except wxPyDeadObjectError, e:
                    self.statusIconHelpBox = None

            self.statusIconHelpBox = wxFrame(None, -1, 'Help with the BitTorrent Status Light', size = (1,1))
            if (sys.platform == 'win32'):
                self.statusIconHelpBox.SetIcon(self.icon)

            panel = wxPanel(self.statusIconHelpBox, -1)

            def StaticText(text, font = self.FONT, underline = false, color = None, panel = panel):
                x = wxStaticText(panel, -1, text, style = wxALIGN_LEFT)
                x.SetFont(wxFont(font, wxDEFAULT, wxNORMAL, wxNORMAL, underline))
                if color is not None:
                    x.SetForegroundColour(color)
                return x

            fullsizer = wxFlexGridSizer(cols = 1, vgap = 13)
            colsizer = wxFlexGridSizer(cols = 2, hgap = 13, vgap = 13)

            disconnectedicon=self.createStatusIcon('disconnected')
            colsizer.Add(wxStaticBitmap(panel, -1, disconnectedicon))
            colsizer.Add(StaticText(
                'Waiting to connect to the tracker.\n' +
                'If the status light stays black for a long time the tracker\n' +
                'you are trying to connect to may not be working.  Unless you\n' +
                'are receiving a message telling you otherwise, please wait,\n' +
                'and BitTorrent will automatically try to reconnect for you.'), 1, wxALIGN_CENTER_VERTICAL)

            noconnectionsicon=self.createStatusIcon('noconnections')
            colsizer.Add(wxStaticBitmap(panel, -1, noconnectionsicon))
            colsizer.Add(StaticText(
                'You have no connections with other clients.\n' +
                'Please be patient.  If after several minutes the status\n' +
                'light remains red, this torrent may be old and abandoned.'), 1, wxALIGN_CENTER_VERTICAL)

            noincomingicon=self.createStatusIcon('noincoming')
            colsizer.Add(wxStaticBitmap(panel, -1, noincomingicon))
            colsizer.Add(StaticText(
                'You have not received any incoming connections from others.\n' +
                'It may only be because no one has tried.  If you never see\n' +
                'the status light turn green, it may indicate your system\n' +
                'is behind a firewall or proxy server.  Please look into\n' +
                'routing BitTorrent through your firewall in order to receive\n' +
                'the best possible download rate.'), 1, wxALIGN_CENTER_VERTICAL)

            nocompletesicon=self.createStatusIcon('nocompletes')
            colsizer.Add(wxStaticBitmap(panel, -1, nocompletesicon))
            colsizer.Add(StaticText(
                'There are no complete copies among the clients you are\n' +
                'connected to.  Don\'t panic, other clients in the torrent\n' +
                "you can't see may have the missing data.\n" +
                'If the status light remains blue, you may have problems\n' +
                'completing your download.'), 1, wxALIGN_CENTER_VERTICAL)

            allgoodicon=self.createStatusIcon('allgood')
            colsizer.Add(wxStaticBitmap(panel, -1, allgoodicon))
            colsizer.Add(StaticText(
                'The torrent is operating properly.'), 1, wxALIGN_CENTER_VERTICAL)

            fullsizer.Add(colsizer, 0, wxALIGN_CENTER)
            colsizer2 = wxFlexGridSizer(cols = 1, hgap = 13)

            colsizer2.Add(StaticText(
                'Please note that the status light is not omniscient, and that it may\n' +
                'be wrong in many instances.  A torrent with a blue light may complete\n' +
                "normally, and an occasional yellow light doesn't mean your computer\n" +
                'has suddenly become firewalled.'), 1, wxALIGN_CENTER_VERTICAL)

            colspacer = StaticText('  ')
            colsizer2.Add(colspacer)

            okButton = wxButton(panel, -1, 'Ok')
#        okButton.SetFont(self.default_font)
            colsizer2.Add(okButton, 0, wxALIGN_CENTER)
            fullsizer.Add(colsizer2, 0, wxALIGN_CENTER)

            border = wxBoxSizer(wxHORIZONTAL)
            border.Add(fullsizer, 1, wxEXPAND | wxALL, 4)

            panel.SetSizer(border)
            panel.SetAutoLayout(true)


            def closeHelp(self, frame = self):
                frame.statusIconHelpBox.Close ()
            EVT_BUTTON(self.statusIconHelpBox, okButton.GetId(), closeHelp)

            self.statusIconHelpBox.Show ()
            border.Fit(panel)
            self.statusIconHelpBox.Fit()
        except:
            self.exception()


    def openConfigMenu(self, event):
        try:
            self.configfile.configMenu(self)
        except:
            self.exception()


    def advanced(self, event):
        try:
            if self.filename is None:
                return
            if (self.advBox is not None):
                try:
                    self.advBox.Close ()
                except wxPyDeadObjectError, e:
                    self.advBox = None

            self.advBox = wxFrame(None, -1, 'BitTorrent Advanced', size = wxSize(200,200))
            if (sys.platform == 'win32'):
                self.advBox.SetIcon(self.icon)

            panel = wxPanel(self.advBox, -1, size = wxSize (200,200))

            def StaticText(text, font = self.FONT, underline = false, color = None, panel = panel):
                x = wxStaticText(panel, -1, text, style = wxALIGN_LEFT)
                x.SetFont(wxFont(font, wxDEFAULT, wxNORMAL, wxNORMAL, underline))
                if color is not None:
                    x.SetForegroundColour(color)
                return x

            colSizer = wxFlexGridSizer (cols = 1, vgap = 1)
            colSizer.Add (StaticText('Advanced Info for ' + self.filename, self.FONT+4))

            try:    # get system font width
                fw = wxSystemSettings_GetFont(wxSYS_DEFAULT_GUI_FONT).GetPointSize()+1
            except:
                fw = wxSystemSettings_GetFont(wxSYS_SYSTEM_FONT).GetPointSize()+1

            spewList = wxListCtrl(panel, -1, wxPoint(-1,-1), (fw*66,350), wxLC_REPORT|wxLC_HRULES|wxLC_VRULES)
            self.spewList = spewList
            spewList.SetAutoLayout (true)

            colSizer.Add(spewList, -1, wxEXPAND)

            colSizer.Add(StaticText(''))
            self.storagestats1 = StaticText('')
            self.storagestats2 = StaticText('')
            colSizer.Add(self.storagestats1, -1, wxEXPAND)
            colSizer.Add(self.storagestats2, -1, wxEXPAND)
            colSizer.Add(StaticText(''))

            buttonSizer = wxFlexGridSizer (cols = 5, hgap = 20)

            reannounceButton = wxButton(panel, -1, 'Manual Announce')
#        reannounceButton.SetFont(self.default_font)
            buttonSizer.Add (reannounceButton)

            extannounceButton = wxButton(panel, -1, 'External Announce')
#        extannounceButton.SetFont(self.default_font)
            buttonSizer.Add (extannounceButton)

            bgallocButton = wxButton(panel, -1, 'Finish Allocation')
#        bgallocButton.SetFont(self.default_font)
            buttonSizer.Add (bgallocButton)

            buttonSizer.Add(StaticText(''))

            okButton = wxButton(panel, -1, 'Ok')
#        okButton.SetFont(self.default_font)
            buttonSizer.Add (okButton)

            colSizer.Add (buttonSizer, 0, wxALIGN_CENTER)
#        colSizer.SetMinSize ((578,350))
            colSizer.AddGrowableCol(0)
            colSizer.AddGrowableRow(1)

            panel.SetSizer(colSizer)
            panel.SetAutoLayout(true)

            spewList.InsertColumn(0, "Optimistic Unchoke", format=wxLIST_FORMAT_CENTER, width=fw*2)
            spewList.InsertColumn(1, "Peer ID", width=0)
            spewList.InsertColumn(2, "IP", width=fw*11)
            spewList.InsertColumn(3, "Local/Remote", format=wxLIST_FORMAT_CENTER, width=fw*3)
            spewList.InsertColumn(4, "Up", format=wxLIST_FORMAT_RIGHT, width=fw*6)
            spewList.InsertColumn(5, "Interested", format=wxLIST_FORMAT_CENTER, width=fw*2)
            spewList.InsertColumn(6, "Choking", format=wxLIST_FORMAT_CENTER, width=fw*2)
            spewList.InsertColumn(7, "Down", format=wxLIST_FORMAT_RIGHT, width=fw*6)
            spewList.InsertColumn(8, "Interesting", format=wxLIST_FORMAT_CENTER, width=fw*2)
            spewList.InsertColumn(9, "Choked", format=wxLIST_FORMAT_CENTER, width=fw*2)
            spewList.InsertColumn(10, "Snubbed", format=wxLIST_FORMAT_CENTER, width=fw*2)
            spewList.InsertColumn(11, "Downloaded", format=wxLIST_FORMAT_RIGHT, width=fw*7)
            spewList.InsertColumn(12, "Uploaded", format=wxLIST_FORMAT_RIGHT, width=fw*7)
            spewList.InsertColumn(13, "Completed", format=wxLIST_FORMAT_RIGHT, width=fw*6)
            spewList.InsertColumn(14, "Peer Download Speed", format=wxLIST_FORMAT_RIGHT, width=fw*6)

            def reannounce(self, frame = self):
                if (time () - frame.reannouncelast > 60):
                    frame.reannouncelast = time ()
                    frame.dow.reannounce()
            EVT_BUTTON(self.advBox, reannounceButton.GetId(), reannounce)

            self.advextannouncebox = None
            def reannounce_external(self, frame = self):
                if (frame.advextannouncebox is not None):
                    try:
                        frame.advextannouncebox.Close ()
                    except wxPyDeadObjectError, e:
                        frame.advextannouncebox = None

                frame.advextannouncebox = wxFrame(None, -1, 'External Announce', size = (1,1))
                if (sys.platform == 'win32'):
                    frame.advextannouncebox.SetIcon(frame.icon)

                panel = wxPanel(frame.advextannouncebox, -1)

                fullsizer = wxFlexGridSizer(cols = 1, vgap = 13)
                msg = wxStaticText(panel, -1, "Enter tracker anounce URL:")
                msg.SetFont(frame.default_font)
                fullsizer.Add(msg)

                frame.advexturl = wxTextCtrl(parent = panel, id = -1, value = '',
                                    size = (255, 20), style = wxTE_PROCESS_TAB)
                frame.advexturl.SetFont(frame.default_font)
                frame.advexturl.SetValue(frame.lastexternalannounce)
                fullsizer.Add(frame.advexturl)

                buttonSizer = wxFlexGridSizer (cols = 2, hgap = 10)

                okButton = wxButton(panel, -1, 'OK')
#            okButton.SetFont(frame.default_font)
                buttonSizer.Add (okButton)

                cancelButton = wxButton(panel, -1, 'Cancel')
#            cancelButton.SetFont(frame.default_font)
                buttonSizer.Add (cancelButton)

                fullsizer.Add (buttonSizer, 0, wxALIGN_CENTER)

                border = wxBoxSizer(wxHORIZONTAL)
                border.Add(fullsizer, 1, wxEXPAND | wxALL, 4)

                panel.SetSizer(border)
                panel.SetAutoLayout(true)

                def ok(self, frame = frame):
                    special = frame.advexturl.GetValue()
                    if special:
                        frame.lastexternalannounce = special
                        if (time () - frame.reannouncelast > 60):
                            frame.reannouncelast = time ()
                            frame.dow.reannounce(special)
                    frame.advextannouncebox.Close()
                EVT_BUTTON(frame.advextannouncebox, okButton.GetId(), ok)

                def cancel(self, frame = frame):
                    frame.advextannouncebox.Close()
                EVT_BUTTON(frame.advextannouncebox, cancelButton.GetId(), cancel)

                def kill(self, frame = frame):
                    frame.advextannouncebox.Destroy()
                    frame.advextannouncebox = None
                EVT_CLOSE(frame.advextannouncebox, kill)

                frame.advextannouncebox.Show ()
                fullsizer.Fit(panel)
                frame.advextannouncebox.Fit()

            EVT_BUTTON(self.advBox, extannounceButton.GetId(), reannounce_external)

            def bgalloc(self, frame = self):
                if frame.dow.storagewrapper is not None:
                    frame.dow.storagewrapper.bgalloc()
            EVT_BUTTON(self.advBox, bgallocButton.GetId(), bgalloc)

            def closeAdv(self, frame = self):
                frame.advBox.Close ()
            def killAdv(self, frame = self):
                frame.dow.spewflag.clear()
                frame.advBox.Destroy()
                frame.advBox = None
                if (frame.advextannouncebox is not None):
                    try:
                        frame.advextannouncebox.Close ()
                    except wxPyDeadObjectError, e:
                        pass
                    frame.advextannouncebox = None
            EVT_BUTTON(self.advBox, okButton.GetId(), closeAdv)
            EVT_CLOSE(self.advBox, killAdv)

            self.advBox.Show ()
            colSizer.Fit(panel)
            self.advBox.Fit()
            self.dow.spewflag.set()
        except:
            self.exception()


    def displayUsage(self, text):
        try:
            start = self.dow.getUsageText()
            if text[:len(start)] != start:
                return false

            self.done(None)
            self.usageBox = wxFrame(None, -1, 'Usage', size = (480,400))
            if (sys.platform == 'win32'):
                self.usageBox.SetIcon(self.icon)

            panel = wxScrolledWindow(self.usageBox, -1)
            colSizer = wxFlexGridSizer(cols = 1)

            colSizer.Add (wxStaticText(panel, -1, text))
            okButton = wxButton(panel, -1, 'Ok')
#        okButton.SetFont(self.default_font)
            colSizer.Add(okButton, 0, wxALIGN_RIGHT)
            colSizer.AddGrowableCol(0)


            def closeUsage(self, frame = self):
                frame.usageBox.Close()
            EVT_BUTTON(self.usageBox, okButton.GetId(), closeUsage)
            def kill(self, frame = self):
                frame.usageBox.Destroy()
                frame.usageBox = None
            EVT_CLOSE(self.usageBox, kill)

            self.usageBox.Show ()
            panel.FitInside()
            panel.SetSizer(colSizer)
            panel.SetAutoLayout(true)
            panel.SetScrollRate(0,1)
            self.usageBox.Fit()

            return true        
        except:
            self.exception()


    def updateStatus(self, fractionDone = None,
            timeEst = None, downRate = None, upRate = None,
            activity = None, statistics = None, spew = None, sizeDone = None,
            **kws):
        if activity is not None:
            self.activity = activity
        if fractionDone is not None:
            self.gui_fractiondone = fractionDone
        if self.gui_lastupdate + 0.05 > time():   # refreshing too fast, skip it
            return
        if not self.ispaused:
            self.invokeLater(self.onUpdateStatus,
                     [timeEst, downRate, upRate, statistics, spew, sizeDone])

    def onUpdateStatus(self, timeEst, downRate, upRate, statistics, spew, sizeDone):
        if self.gui_lastupdate + 0.05 > time():   # refreshing too fast, skip it
            return

        if self.firstupdate:
            self.connChoice.SetStringSelection(self.configfile.configfileargs['gui_ratesettingsdefault'])
            self.onConnChoice(0)         # force config selection for default value
            self.gauge.SetForegroundColour(self.configfile.checkingcolor)
            self.firstupdate = false

        if statistics is None:
            self.setStatusIcon('startup')
        elif statistics.numPeers + statistics.numSeeds + statistics.numOldSeeds == 0:
            if statistics.last_failed:
                self.setStatusIcon('disconnected')
            else:
                self.setStatusIcon('noconnections')
        elif ( not statistics.external_connection_made
            and not self.configfile.configfileargs['gui_forcegreenonfirewall'] ):
            self.setStatusIcon('noincoming')
        elif ( (statistics.numSeeds + statistics.numOldSeeds == 0)
               and ( (self.fin and statistics.numCopies < 1)
                    or (not self.fin and statistics.numCopies2 < 1) ) ):
            self.setStatusIcon('nocompletes')
        else:
            self.setStatusIcon('allgood')

        if self.updateSliderFlag == 1:
            self.updateSliderFlag = 0
            newValue = (self.rateSpinner.GetValue()
                         / connChoices[self.connChoice.GetSelection()]['rate'].get('div',1))
            if self.rateslider.GetValue() != newValue:
                self.rateslider.SetValue(newValue)

        if self.updateSpinnerFlag == 1:
            self.updateSpinnerFlag = 0
            cc = connChoices[self.connChoice.GetSelection()]
            if cc.has_key('rate'):
                newValue = (self.rateslider.GetValue() * cc['rate'].get('div',1))
                if self.rateSpinner.GetValue() != newValue:
                    self.rateSpinner.SetValue(newValue)
        if self.fin:
            if statistics is not None:
                if statistics.numOldSeeds > 0 or statistics.numCopies > 1:
                    self.gauge.SetValue(1000)
                else:
                    self.gauge.SetValue(int(1000*statistics.numCopies))
        elif self.gui_fractiondone is not None:
            gaugelevel = int(self.gui_fractiondone * 1000)
            self.gauge.SetValue(gaugelevel)
            if statistics is not None and statistics.downTotal is not None:
                if self.configfile.configfileargs['gui_displaymiscstats']:
                    self.frame.SetTitle('%.1f%% (%.2f MiB) %s - BitTorrent %s' % (float(gaugelevel)/10, float(sizeDone) / (1<<20), self.filename, version))
                else:
                    self.frame.SetTitle('%.1f%% %s - BitTorrent %s' % (float(gaugelevel)/10, self.filename, version))
                self.gauge.SetForegroundColour(self.configfile.downloadcolor)
            else:
                self.frame.SetTitle('%.0f%% %s - BitTorrent %s' % (float(gaugelevel)/10, self.filename, version))
        if timeEst is not None:
            self.timeText.SetLabel(hours(time () - self.starttime) + ' / ' + hours(timeEst))
        else:
            if self.fin:
                self.timeText.SetLabel(self.activity)
            else:
                self.timeText.SetLabel(hours(time () - self.starttime) + ' / ' + self.activity)
        if downRate is not None:
            self.downRateText.SetLabel('%.0f kB/s' % (float(downRate) / 1000))
        if upRate is not None:
            self.upRateText.SetLabel('%.0f kB/s' % (float(upRate) / 1000))
        if hasattr(self.frame, "tbicon"):
            icontext='BitTorrent '
            if self.gui_fractiondone is not None and not self.fin:
                if statistics is not None and statistics.downTotal is not None:
                    icontext=icontext+' %.1f%% (%.2f MiB)' % (self.gui_fractiondone*100, float(sizeDone) / (1<<20))
                else:
                    icontext=icontext+' %.0f%%' % (self.gui_fractiondone*100)
            if upRate is not None:
                icontext=icontext+' u:%.0f kB/s' % (float(upRate) / 1000)
            if downRate is not None:
                icontext=icontext+' d:%.0f kB/s' % (float(downRate) / 1000)
            icontext+=' %s' % self.filename
            self.frame.tbicon.SetIcon(self.icon,icontext)
        if statistics is not None:
            if self.configfile.configfileargs['gui_displaymiscstats']:
                self.downText.SetLabel('%.2f MiB' % (float(statistics.downTotal) / (1 << 20)))
                self.upText.SetLabel('%.2f MiB' % (float(statistics.upTotal) / (1 << 20)))
            if (statistics.shareRating < 0) or (statistics.shareRating > 1000):
                self.shareRatingText.SetLabel('oo :-D')
                self.shareRatingText.SetForegroundColour('Forest Green')
            else:
                shareSmiley = ''
                color = 'Black'
                if ((statistics.shareRating >= 0) and (statistics.shareRating < 0.5)):
                    shareSmiley = ':-('
                    color = 'Red'
                else:
                    if ((statistics.shareRating >= 0.5) and (statistics.shareRating < 1.0)):
                        shareSmiley = ':-|'
                        color = 'Orange'
                    else:
                        if (statistics.shareRating >= 1.0):
                            shareSmiley = ':-)'
                            color = 'Forest Green'
                self.shareRatingText.SetLabel('%.3f %s' % (statistics.shareRating, shareSmiley))
                self.shareRatingText.SetForegroundColour(color)

            if self.configfile.configfileargs['gui_displaystats']:
                if not self.fin:
                    self.seedStatusText.SetLabel('connected to %d seeds; also seeing %.3f distributed copies' % (statistics.numSeeds,0.001*int(1000*statistics.numCopies2)))
                else:
                    self.seedStatusText.SetLabel('%d seeds seen recently; also seeing %.3f distributed copies' % (statistics.numOldSeeds,0.001*int(1000*statistics.numCopies)))
                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)))
        if ((time () - self.lastError) > 300):
            self.errorText.SetLabel('')

        if ( self.configfile.configfileargs['gui_displaymiscstats']
            and statistics is not None and statistics.backgroundallocating ):
            self.bgalloc_periods += 1
            if self.bgalloc_periods > 3:
                self.bgalloc_periods = 0
            self.bgallocText.SetLabel('ALLOCATING'+(' .'*self.bgalloc_periods))
        elif self.dow.superseedflag.isSet():
            self.bgallocText.SetLabel('SUPER-SEED')
        else:
            self.bgallocText.SetLabel('')


        if spew is not None and (time()-self.spewwait>1):
            if (self.advBox is not None):
                self.spewwait = time()
                spewList = self.spewList
                spewlen = len(spew)+2
                if statistics is not None:
                    kickbanlen = len(statistics.peers_kicked)+len(statistics.peers_banned)
                    if kickbanlen:
                        spewlen += kickbanlen+1
                else:
                    kickbanlen = 0
                for x in range(spewlen-spewList.GetItemCount()):
                    i = wxListItem()
#                   i.SetFont(self.default_font)
                    spewList.InsertItem(i)
                for x in range(spewlen,spewList.GetItemCount()):
                    spewList.DeleteItem(len(spew)+1)

                tot_uprate = 0.0
                tot_downrate = 0.0
                for x in range(len(spew)):
                    if (spew[x]['optimistic'] == 1):
                        a = '*'
                    else:
                        a = ' '
                    spewList.SetStringItem(x, 0, a)
                    spewList.SetStringItem(x, 1, spew[x]['id'])
                    spewList.SetStringItem(x, 2, spew[x]['ip'])
                    spewList.SetStringItem(x, 3, spew[x]['direction'])
                    if spew[x]['uprate'] > 100:
                        spewList.SetStringItem(x, 4, '%.0f kB/s' % (float(spew[x]['uprate']) / 1000))
                    else:
                        spewList.SetStringItem(x, 4, ' ')
                    tot_uprate += spew[x]['uprate']
                    if (spew[x]['uinterested'] == 1):
                        a = '*'
                    else:
                        a = ' '
                    spewList.SetStringItem(x, 5, a)
                    if (spew[x]['uchoked'] == 1):
                        a = '*'
                    else:
                        a = ' '
                    spewList.SetStringItem(x, 6, a)

                    if spew[x]['downrate'] > 100:
                        spewList.SetStringItem(x, 7, '%.0f kB/s' % (float(spew[x]['downrate']) / 1000))
                    else:
                        spewList.SetStringItem(x, 7, ' ')
                    tot_downrate += spew[x]['downrate']

                    if (spew[x]['dinterested'] == 1):
                        a = '*'
                    else:
                        a = ' '
                    spewList.SetStringItem(x, 8, a)
                    if (spew[x]['dchoked'] == 1):
                        a = '*'
                    else:
                        a = ' '
                    spewList.SetStringItem(x, 9, a)
                    if (spew[x]['snubbed'] == 1):
                        a = '*'
                    else:
                        a = ' '
                    spewList.SetStringItem(x, 10, a)
                    spewList.SetStringItem(x, 11, '%.2f MiB' % (float(spew[x]['dtotal']) / (1 << 20)))
                    if spew[x]['utotal'] is not None:
                        a = '%.2f MiB' % (float(spew[x]['utotal']) / (1 << 20))
                    else:
                        a = ''
                    spewList.SetStringItem(x, 12, a)
                    spewList.SetStringItem(x, 13, '%.1f%%' % (float(int(spew[x]['completed']*1000))/10))
                    if spew[x]['speed'] is not None:
                        a = '%.0f kB/s' % (float(spew[x]['speed']) / 1000)
                    else:
                        a = ''
                    spewList.SetStringItem(x, 14, a)

                x = len(spew)
                for i in range(15):
                    spewList.SetStringItem(x, i, '')

                x += 1
                spewList.SetStringItem(x, 2, '         TOTALS:')
                spewList.SetStringItem(x, 4, '%.0f kB/s' % (float(tot_uprate) / 1000))
                spewList.SetStringItem(x, 7, '%.0f kB/s' % (float(tot_downrate) / 1000))
                if statistics is not None:
                    spewList.SetStringItem(x, 11, '%.2f MiB' % (float(statistics.downTotal) / (1 << 20)))
                    spewList.SetStringItem(x, 12, '%.2f MiB' % (float(statistics.upTotal) / (1 << 20)))
                else:
                    spewList.SetStringItem(x, 11, '')
                    spewList.SetStringItem(x, 12, '')
                for i in [0,2,4,5,7,8,9,12,13,14]:
                    spewList.SetStringItem(x, i, '')

                if kickbanlen:
                    x += 1
                    for i in range(14):
                        spewList.SetStringItem(x, i, '')

                    for ip in statistics.peers_kicked:
                        x += 1
                        spewList.SetStringItem(x, 2, ip)
                        spewList.SetStringItem(x, 4, 'KICKED')
                        for i in [0,2,4,5,6,7,8,9,10,11,12,13,14]:
                            spewList.SetStringItem(x, i, '')

                    for ip in statistics.peers_banned:
                        x += 1
                        spewList.SetStringItem(x, 2, ip)
                        spewList.SetStringItem(x, 4, 'BANNED')
                        for i in [0,2,4,5,6,7,8,9,10,11,12,13]:
                            spewList.SetStringItem(x, i, '')

                if statistics is not None:
                    self.storagestats1.SetLabel(
                        '          currently downloading %d pieces (%d just started), %d pieces partially retrieved'
                                        % ( statistics.storage_active,
                                            statistics.storage_new,
                                            statistics.storage_dirty ) )
                    self.storagestats2.SetLabel(
                        '          %d of %d pieces complete (%d just downloaded), %d failed hash check'
                                        % ( statistics.storage_numcomplete,
                                            statistics.storage_totalpieces,
                                            statistics.storage_justdownloaded,
                                            statistics.storage_numflunked ) )

        if ( self.fileList is not None and statistics is not None
                and (statistics.filelistupdated or self.refresh_details) ):
            self.refresh_details = false
            statistics.filelistupdated = false
            for i in range(len(statistics.filecomplete)):
                if statistics.fileinplace[i]:
                    self.fileList.SetItemImage(i,2,2)
                    self.fileList.SetStringItem(i,1,"done")
                elif statistics.filecomplete[i]:
                    self.fileList.SetItemImage(i,1,1)
                    self.fileList.SetStringItem(i,1,"100%")
                else:
                    frac = int((len(statistics.filepieces2[i])-len(statistics.filepieces[i]))*100
                            /len(statistics.filepieces2[i]))
                    if frac > 0:
                        self.fileList.SetStringItem(i,1,'%d%%' % (frac))

        if self.configfile.configReset:     # whoopee!  Set everything invisible! :-)
            self.configfile.configReset = false

            self.dow.config['security'] = self.configfile.configfileargs['security']

            statsdisplayflag = self.configfile.configfileargs['gui_displaymiscstats']
            self.downTextLabel.Show(statsdisplayflag)
            self.upTextLabel.Show(statsdisplayflag)
            self.fileDestLabel.Show(statsdisplayflag)
            self.fileDestText.Show(statsdisplayflag)
            self.colSizer.Layout()

            self.downText.SetLabel('')          # blank these to flush them
            self.upText.SetLabel('')
            self.seedStatusText.SetLabel('')
            self.peerStatusText.SetLabel('')

            ratesettingsmode = self.configfile.configfileargs['gui_ratesettingsmode']
            ratesettingsflag1 = true    #\ settings
            ratesettingsflag2 = false   #/ for 'basic'
            if ratesettingsmode == 'none':
                ratesettingsflag1 = false
            elif ratesettingsmode == 'full':
                ratesettingsflag2 = true
            self.connChoiceLabel.Show(ratesettingsflag1)
            self.connChoice.Show(ratesettingsflag1)
            self.rateSpinnerLabel.Show(ratesettingsflag2)
            self.rateSpinner.Show(ratesettingsflag2)
            self.rateLowerText.Show(ratesettingsflag2)
            self.rateUpperText.Show(ratesettingsflag2)
            self.rateslider.Show(ratesettingsflag2)
            self.connSpinnerLabel.Show(ratesettingsflag2)
            self.connSpinner.Show(ratesettingsflag2)
            self.connLowerText.Show(ratesettingsflag2)
            self.connUpperText.Show(ratesettingsflag2)
            self.connslider.Show(ratesettingsflag2)
            self.unlimitedLabel.Show(ratesettingsflag2)

            if statistics is None or statistics.downTotal is None:
                self.gauge.SetForegroundColour(self.configfile.checkingcolor)
                self.gauge.SetBackgroundColour(wx.wxSystemSettings_GetColour(wxSYS_COLOUR_MENU))
            elif self.fin:
                self.gauge.SetForegroundColour(self.configfile.seedingcolor)
                self.gauge.SetBackgroundColour(self.configfile.downloadcolor)
            else:
                self.gauge.SetForegroundColour(self.configfile.downloadcolor)
                self.gauge.SetBackgroundColour(wx.wxSystemSettings_GetColour(wxSYS_COLOUR_MENU))

        self.frame.Layout()
        self.frame.Refresh()

        self.gui_lastupdate = time()
        self.gui_fractiondone = None


    def finished(self):
        self.fin = true
        self.invokeLater(self.onFinishEvent)

    def failed(self):
        self.fin = true
        self.invokeLater(self.onFailEvent)

    def error(self, errormsg):
        self.invokeLater(self.onErrorEvent, [errormsg])

    def onFinishEvent(self):
        self.activity = hours(time () - self.starttime) + ' / ' +'Download Succeeded!'
        self.cancelButton.SetLabel('Finish')
        self.gauge.SetBackgroundColour(self.configfile.downloadcolor)
        self.gauge.SetValue(0)
        self.gauge.SetForegroundColour(self.configfile.seedingcolor)
        self.frame.SetTitle('%s - Upload - BitTorrent %s' % (self.filename, version))
        if (sys.platform == 'win32'):
            self.icon = wxIcon(os.path.join(basepath,'icon_done.ico'), wxBITMAP_TYPE_ICO)
            self.frame.SetIcon(self.icon)
        if hasattr(self.frame, "tbicon"):
            self.frame.tbicon.SetIcon(self.icon, "BitTorrent - Finished")
        self.downRateText.SetLabel('')

    def onFailEvent(self):
        if not self.shuttingdown:
            self.timeText.SetLabel(hours(time () - self.starttime) + ' / ' +'Failed!')
            self.activity = 'Failed!'
            self.cancelButton.SetLabel('Close')
            self.gauge.SetValue(0)
            self.downRateText.SetLabel('')
            self.setStatusIcon('startup')

    def onErrorEvent(self, errormsg):
        if not self.displayUsage(errormsg):
            if errormsg[:2] == '  ':    # indent at least 2 spaces means a warning message
                self.errorText.SetLabel(errormsg)
                self.lastError = time ()
            else:
                self.errorText.SetLabel(strftime('ERROR (%I:%M %p) -\n') + errormsg)
                self.lastError = time ()


    def chooseFile(self, default, size, saveas, dir):
        f = Event()
        bucket = [None]
        self.invokeLater(self.onChooseFile, [default, bucket, f, size, dir, saveas])
        f.wait()
        return bucket[0]

    def onChooseFile(self, default, bucket, f, size, dir, saveas):
        if saveas == '':
            if self.configfile.configfileargs['gui_default_savedir'] != '':
                start_dir = self.configfile.configfileargs['gui_default_savedir']
            else:
                start_dir = self.configfile.configfileargs['last_saved']
            if not isdir(start_dir):    # if it's not set properly
                start_dir = '/'    # yes, this hack does work in Windows
            if dir:
                if isdir(join(start_dir,default)):
                    start_dir = join(start_dir,default)
                dl = wxDirDialog(self.frame,
                        'Choose a directory to save to, pick a partial download to resume',
                        defaultPath = start_dir, style = wxDD_DEFAULT_STYLE | wxDD_NEW_DIR_BUTTON)
            else:
                dl = wxFileDialog(self.frame,
                        'Choose file to save as, pick a partial download to resume', 
                        defaultDir = start_dir, defaultFile = default, wildcard = '*',
                        style = wxSAVE)

            if dl.ShowModal() != wxID_OK:
                f.set()
                self.done(None)
                return

            d = dl.GetPath()
            bucket[0] = d
            d1,d2 = split(d)
            if d2 == default:
                d = d1
            self.configfile.WriteLastSaved(d)

        else:
            bucket[0] = saveas
            default = basename(saveas)

        self.fileNameText.SetLabel('%s' % (default))
        self.fileSizeText.SetLabel('(%.2f MiB)' % (float(size) / (1 << 20)))
        self.timeText.SetLabel(hours(time () - self.starttime) + ' / ' + self.activity)
        self.fileDestText.SetLabel(bucket[0])
        self.filename = default
        self.frame.SetTitle(default + '- BitTorrent ' + version)

        minsize = self.fileNameText.GetBestSize()
        if (not self.configfile.configfileargs['gui_stretchwindow'] or
                            minsize.GetWidth() < self.addwidth):
            minsize.SetWidth(self.addwidth)
        self.fnsizer.SetMinSize (minsize)
        minsize.SetHeight(self.fileSizeText.GetBestSize().GetHeight())
        self.fnsizer2.SetMinSize (minsize)
        minsize.SetWidth(minsize.GetWidth()+(self.FONT*8))
        minsize.SetHeight(self.fileNameText.GetBestSize().GetHeight()+self.fileSizeText.GetBestSize().GetHeight())
        minsize.SetHeight(2*self.errorText.GetBestSize().GetHeight())
        self.errorTextSizer.SetMinSize(minsize)
        self.topboxsizer.SetMinSize(minsize)

        # Kludge to make details and about catch the event
        self.frame.SetSize ((self.frame.GetSizeTuple()[0]+1, self.frame.GetSizeTuple()[1]+1))
        self.frame.SetSize ((self.frame.GetSizeTuple()[0]-1, self.frame.GetSizeTuple()[1]-1))
        self.colSizer.Fit(self.frame)
        self.frame.Layout()
        self.frame.Refresh()
        f.set()

    def newpath(self, path):
        self.invokeLater(self.onNewpath, [path])

    def onNewpath(self, path):
        self.fileDestText.SetLabel(path)

    def pause(self, event):
        self.invokeLater(self.onPause)

    def onPause(self):
        if self.ispaused:
            self.ispaused = false
            self.pauseButton.SetLabel('Pause')
            self.dow.Unpause()
        else:
            if self.dow.Pause():
                self.ispaused = true
                self.pauseButton.SetLabel('Resume')
                self.downRateText.SetLabel(' ')
                self.upRateText.SetLabel(' ')
                self.seedStatusText.SetLabel(' ')
                self.peerStatusText.SetLabel(' ')
                self.setStatusIcon('startup')

    def done(self, event):
        self.uiflag.set()
        self.flag.set()
        self.shuttingdown = true
        if hasattr(self.frame, "tbicon"):
            self.frame.tbicon.Destroy()
            del self.frame.tbicon
        if self.ispaused:
            self.dow.Unpause()
        if (self.detailBox is not None):
            try:
                self.detailBox.Close ()
            except wxPyDeadObjectError, e:
                self.detailBox = None
        if (self.aboutBox is not None):
            try:
                self.aboutBox.Close ()
            except wxPyDeadObjectError, e:
                self.aboutBox = None
        if (self.creditsBox is not None):
            try:
                self.creditsBox.Close ()
            except wxPyDeadObjectError, e:
                self.creditsBox = None
        if (self.advBox is not None):
            try:
                self.advBox.Close ()
            except wxPyDeadObjectError, e:
                self.advBox = None

        if (self.statusIconHelpBox is not None):
            try:
                self.statusIconHelpBox.Close ()
            except wxPyDeadObjectError, e:
                self.statusIconHelpBox = None
        self.configfile.Close()
        self.frame.Destroy()

    def exception(self):
        data = StringIO()
        print_exc(file = data)
        print data.getvalue()   # report exception here too
        self.on_errorwindow(data.getvalue())

    def errorwindow(self, err):
        self.invokeLater(self.on_errorwindow,[err])

    def on_errorwindow(self, err):
        if self._errorwindow is None:
            w = wxFrame(None, -1, 'BITTORRENT ERROR', size = (1,1))
            panel = wxPanel(w, -1)
            sizer = wxFlexGridSizer(cols = 1)

            t = ( 'BitTorrent ' + version + '\n' +
                  'OS: ' + sys.platform + '\n' +
                  'Python version: ' + sys.version + '\n' +
                  'wxWindows version: ' + wxVERSION_STRING + '\n' )

            try:
                t += 'Psyco version: ' + hex(psyco.__version__)[2:] + '\n'
            except:
                pass
            try:
                t += 'Allocation method: ' + self.config['alloc_type']
                if self.dow.storagewrapper.bgalloc_active:
                    t += '*'
                t += '\n'
            except:
                pass

            sizer.Add(wxTextCtrl(panel, -1, t + '\n' + err,
                                size = (500,300), style = wxTE_READONLY|wxTE_MULTILINE))

            sizer.Add(wxStaticText(panel, -1,
                    '\nHelp us iron out the bugs in the engine!' +
                    '\nPlease report this error to info@degreez.net'))

            border = wxBoxSizer(wxHORIZONTAL)
            border.Add(sizer, 1, wxEXPAND | wxALL, 4)

            panel.SetSizer(border)
            panel.SetAutoLayout(true)

            w.Show()
            border.Fit(panel)
            w.Fit()
            self._errorwindow = w


class btWxApp(wxApp):
    def __init__(self, x, params):
        self.params = params
        self.configfile = configReader()
        wxApp.__init__(self, x)

    def OnInit(self):
        doneflag = Event()
        d = DownloadInfoFrame(doneflag, self.configfile)
        self.SetTopWindow(d.frame)
        if len(self.params) == 0:
            b = wxFileDialog (d.frame, 'Choose .torrent file to use',
                        defaultDir = '', defaultFile = '', wildcard = '*.torrent',
                        style = wxOPEN)

            if b.ShowModal() == wxID_OK:
                self.params.append (b.GetPath())

        thread = Thread(target = next, args = [self.params, d, doneflag, self.configfile])
        thread.setDaemon(false)
        thread.start()
        return 1

def run(params):
    app = btWxApp(0, params)
    app.MainLoop()

def next(params, d, doneflag, configfile):
    if PROFILER:
        import profile, pstats
        p = profile.Profile()
        p.runcall(_next, params, d, doneflag, configfile)
        log = open('profile_data.'+strftime('%y%m%d%H%M%S')+'.txt','a')
        normalstdout = sys.stdout
        sys.stdout = log
#        pstats.Stats(p).strip_dirs().sort_stats('cumulative').print_stats()
        pstats.Stats(p).strip_dirs().sort_stats('time').print_stats()
        sys.stdout = normalstdout
    else:
        _next(params, d, doneflag, configfile)

def _next(params, d, doneflag, configfile):
    dow = Download()
    d.dow = dow
    configfile.setDownloadDefaults(dow.getDefaults())
    d.configfile = configfile
    d.configfileargs = d.configfile.configfileargs
    try:
        dow.download(params, d.chooseFile, d.updateStatus, d.finished, d.error, doneflag, 100,
                     d.newpath, d.configfileargs, d.errorwindow)
    except:
        data = StringIO()
        print_exc(file = data)
        print data.getvalue()   # report exception here too
        d.errorwindow(data.getvalue())
    if not d.fin:
        d.failed()


if __name__ == '__main__':
    if argv[1:] == ['--version']:
        print version
        sys.exit(0)
    run(argv[1:])

No CVS admin address has been configured
Powered by
ViewCVS 0.9.3