# Written by Arno Bakker # see LICENSE.txt for license information import wx import os import sys from traceback import print_exc from Swapper.CacheDB.CacheDBHandler import FriendDBHandler from managefriends import createImageList DEBUG = False def _createImageList(utility,friends): if len(friends) == 0: return None height = 0 width = 0 list = [] for friend in friends: if friend['name'] is not None: filename = nickname2iconfilename(utility, friend['name']) if not os.access(filename, os.F_OK): # fallback name, don't use nickname2... here filename = os.path.join(utility.getPath(), 'icons', 'joe32.bmp') bm = wx.Bitmap(filename,wx.BITMAP_TYPE_BMP) if bm.GetWidth() > width: width = bm.GetWidth() if bm.GetHeight() > height: height = bm.GetHeight() list.append(bm) imgList = wx.ImageList(width,height) for bm in list: imgList.Add(bm) return imgList def nickname2iconfilename(utility,name): return os.path.join(utility.getConfigPath(), 'icons', name+'.bmp') ################################################################ # # Class: DownloadHelperPanel # # Panel for coordinating the help of friends in downloading # a torrent # ################################################################ class DownloadHelperPanel(wx.Panel): def __init__(self, parent, dialog): wx.Panel.__init__(self, parent, -1) self.utility = dialog.utility engine = dialog.torrent.connection.engine if engine is not None: self.coordinator = engine.getDownloadhelpCoordinator() # If the torrent is stopped, don't allow helping if engine is None or self.coordinator is None: if engine is None: msg = self.utility.lang.get('dlhelpdisabledstop') else: msg = self.utility.lang.get('dlhelpdisabledhelper') mainbox = wx.BoxSizer(wx.VERTICAL) mainbox.Add(wx.StaticText(self, -1, msg), 0, wx.EXPAND|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5) self.SetSizerAndFit(mainbox) return # 0. Read friends from DB, and figure out who's already helping # for this torrent friends = FriendDBHandler().getFriends() helpingFriends = self.coordinator.get_asked_helpers_copy() if DEBUG: print >> sys.stderr,"dlhelperframe: friends is",friends print >> sys.stderr,"dlhelperframe: helping friends is",helpingFriends # 1. Create list of images of all friends type = wx.LC_LIST #type = wx.LC_REPORT imgList = None if type != wx.LC_REPORT: try: imgList = createImageList(self.utility,friends) except: print_exc() # disable icons type = wx.LC_REPORT # 2. Filter out friends already helping for left window self.remainingFriends = [] for index in range(len(friends)): friend = friends[index] flag = 0 for helper in helpingFriends: if friend['permid'] == helper['permid']: helper['tempiconindex'] = index flag = 1 break if flag: continue friend['tempiconindex'] = index self.remainingFriends.append(friend) # 3. TODO: remove entries from helpingFriends that are no longer friends # 4. Build GUI mainbox = wx.BoxSizer(wx.VERTICAL) topbox = wx.BoxSizer(wx.HORIZONTAL) botbox = wx.BoxSizer(wx.HORIZONTAL) # 4a. Friends in left window friendsbox = wx.BoxSizer(wx.VERTICAL) friendsbox.Add(wx.StaticText(self, -1, self.utility.lang.get('availcandidates')), 0, wx.EXPAND|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5) self.leftListCtl = FriendList(self,self.remainingFriends,type,imgList) #self.leftListCtl.SetToolTipString(self.utility.lang.get('multiannouncehelp')) friendsbox.Add(self.leftListCtl, 1, wx.EXPAND|wx.TOP, 5) topbox.Add(friendsbox, 1, wx.EXPAND) # 4b. +/- buttons in between operatorbox = wx.BoxSizer(wx.VERTICAL) button = wx.Button(self, -1, self.utility.lang.get('requestdlhelp'), style = wx.BU_EXACTFIT) button.SetToolTipString(self.utility.lang.get('requestdlhelp_help')) wx.EVT_BUTTON(self, button.GetId(), self.add_helper) operatorbox.Add(button, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALL, 3) button2 = wx.Button(self, -1, self.utility.lang.get('stopdlhelp'), style = wx.BU_EXACTFIT) button2.SetToolTipString(self.utility.lang.get('stopdlhelp_help')) wx.EVT_BUTTON(self, button2.GetId(), self.remove_helper) operatorbox.Add(button2, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALL, 3) topbox.Add(operatorbox, 0, wx.ALIGN_CENTER_VERTICAL) # 4c. Selected helpers in right window helperbox = wx.BoxSizer(wx.VERTICAL) helperbox.Add(wx.StaticText(self, -1, self.utility.lang.get('helpers')), 0, wx.EXPAND|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5) self.rightListCtl = FriendList(self,helpingFriends,type,imgList) #self.rightListCtl.SetToolTipString(self.utility.lang.get('httpseedshelp')) helperbox.Add(self.rightListCtl, 1, wx.EXPAND|wx.ALL, 5) topbox.Add(helperbox, 1, wx.EXPAND) # 5. Show GUI mainbox.Add(topbox, 0, wx.EXPAND|wx.ALL) mainbox.Add(botbox, 0, wx.ALIGN_CENTER_HORIZONTAL|wx.ALL, 5) #self.SetSizerAndFit(mainbox) self.SetSizer(mainbox) self.SetAutoLayout(True) def add_helper(self, event = None): changed_list = self.add_friends(self.leftListCtl,self.rightListCtl) self.make_it_so(True,changed_list) def remove_helper(self, event = None): changed_list = self.add_friends(self.rightListCtl,self.leftListCtl) self.make_it_so(False,changed_list) def add_friends(self,left,right): item = -1 itemList = [] while 1: item = left.GetNextItem(item,wx.LIST_NEXT_ALL,wx.LIST_STATE_SELECTED) if item == -1: break else: itemList.append(item) if len(itemList) > 0: friendsList = left.removeFriends(itemList) right.addFriends(friendsList) return friendsList else: return [] def make_it_so(self, add, changed_list): helpingFriends = self.rightListCtl.getFriends() remainingFriends = self.leftListCtl.getFriends() if DEBUG: print >> sys.stderr,"dlhelperframe: before exec: remaining friends is",remainingFriends print >> sys.stderr,"dlhelperframe: before exec: helping friends is",helpingFriends self.coordinator.stop_help(remainingFriends, force = False) self.coordinator.request_help(helpingFriends, force = False) def editFriend(self, event = None): pass ################################################################ # # Class: FriendList # # ListCtrl for managing friends # ################################################################ class FriendList(wx.ListCtrl): def __init__(self, parent, friends, type, imgList): self.type = type self.imgList = imgList style = wx.VSCROLL|wx.SIMPLE_BORDER|self.type|wx.LC_VRULES|wx.CLIP_CHILDREN if (sys.platform == 'win32'): style |= wx.LC_ALIGN_TOP wx.ListCtrl.__init__(self, parent, -1, style=style) self.SetMinSize(wx.Size(200, 300)) self.parent = parent self.friends = friends self.utility = parent.utility self.SetImageList(imgList,wx.IMAGE_LIST_SMALL) self.Bind(wx.EVT_LIST_ITEM_ACTIVATED, self.OnActivated) self.loadList() def loadList(self): if self.type == wx.LC_REPORT: try: # get system font width fw = wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT).GetPointSize()+1 except: fw = wx.SystemSettings_GetFont(wx.SYS_SYSTEM_FONT).GetPointSize()+1 self.InsertColumn(0, self.utility.lang.get('name'), format=wx.LIST_FORMAT_CENTER, width=fw*6) self.updateAll() self.Show(True) def updateAll(self): self.DeleteAllItems() i = 0; for friend in self.friends: self.addItem(i,friend) i += 1 def OnActivated(self, event): self.parent.editFriend(event) def addItem(self,i,friend): if self.type != wx.LC_REPORT: label = friend['name'] if not label: label = friend['ip'] self.InsertImageStringItem(i,label,friend['tempiconindex']) else: self.InsertStringItem(i, friend['name']) def removeFriends(self,itemList): # Assumption: friends in list are in insert-order, i.e., not sorted afterwards! friendList = [] # Make sure item ids stay the same during delete itemList.sort() itemList.reverse() for item in itemList: friend = self.friends[item] friendList.append(friend) del self.friends[item] self.DeleteItem(item) return friendList def addFriends(self,friendList): flag = 0 i = self.GetItemCount() for friend in friendList: for chum in self.friends: if friend['permid'] == chum['permid']: # here we must use 'permid' to distinguish flag = 1 break if flag: continue self.friends.append(friend) self.addItem(i,friend) i += 1 def getFriends(self): return self.friends