diff -rNu3 pyslsk-1.1.0pre1/pysoulseek/config.py slsk-tmp/pysoulseek/config.py --- pyslsk-1.1.0pre1/pysoulseek/config.py 2003-03-30 14:43:01.000000000 +0200 +++ slsk-tmp/pysoulseek/config.py 2003-04-05 01:07:55.000000000 +0200 @@ -29,26 +29,36 @@ self.parser.read([self.filename]) self.sections = {"server":{"server":None,"login":None,"passw":None, \ "portrange": (2234,2239), "enc":"utf-8","userlist":[], \ + "autosearch":[], \ "banlist":[], "ignorelist":[],"autojoin":["pyslsk"],"autoaway":15}, \ "transfers":{"downloaddir":None,"sharedownloaddir":1,"shared":None, \ "uploadbandwidth":100,"uselimit":0,"uploadlimit":100,"limitby":1, "usecustomban":0,"customban":"don't bother to retry", \ + "preferfriends":0, "useupslots":0, "uploadslots":2, \ "downloads":[],"sharedfiles":{},"sharedfilesstreams":{}, \ "sharedindex":{},"sharedmtimes":{},"rescanonstartup":0}, \ "userinfo":{"descr":"''","pic":""},"logging": \ {"logsdir":os.path.expanduser("~"),"privatechat":0,"chatrooms":0}, \ - "searches":{"maxresults":50}} + "searches":{"maxresults":50}, \ + "ui":{"chatme":"FOREST GREEN", "chatremote":"","chatlocal":"BLUE", \ + "chathilite":"", "search":"","searchq":"GREY", "decimalsep":","}} try: f = open(filename+".shares") self.sharesdb = cPickle.load(f) f.close() except: self.sharesdb = None + try: + f = open(filename+".alias") + self.aliases = cPickle.load(f) + f.close() + except: + self.aliases = {} def needConfig(self): for i in self.sections.keys(): for j in self.sections[i].keys(): - if self.sections[i][j] is None or self.sections[i][j] == '' and i != "userinfo": + if self.sections[i][j] is None or self.sections[i][j] == '' and i not in ("userinfo", "ui"): return 1 return 0 @@ -60,7 +70,7 @@ print "Bogus config section:",i elif j not in self.sections[i].keys(): print "Bogus config option",j,"section",i - elif j in ['login','passw','enc','downloaddir','customban','descr','pic','logsdir']: + elif j in ['login','passw','enc','downloaddir','customban','descr','pic','logsdir'] or i == "ui": self.sections[i][j] = val else: try: @@ -102,3 +112,34 @@ cPickle.dump(sharesdb, f) f.close() + def writeAliases(self): + f = open(self.filename+".alias","w") + cPickle.dump(self.aliases, f, 1) + f.close() + + def AddAlias(self, rest): + if rest: + args = rest.split(" ", 1) + if len(args) == 2: + if args[0] in ("alias", "unalias"): + return "I will not alias that!\n" + self.aliases[args[0]] = args[1] + self.writeAliases() + if self.aliases.has_key(args[0]): + return "Alias %s: %s\n" % (args[0], self.aliases[args[0]]) + else: + return "No such alias (%s)\n" % rest + else: + m = "\nAliases:\n" + for i in self.aliases.keys(): + m = m + "%s: %s\n" % (i, self.aliases[i]) + return m+"\n" + + def Unalias(self, rest): + if rest and self.aliases.has_key(rest): + x = self.aliases[rest] + del self.aliases[rest] + self.writeAliases() + return "Removed alias %s: %s\n" % (rest, x) + else: + return "No such alias (%s)\n" % rest diff -rNu3 pyslsk-1.1.0pre1/pysoulseek/pysoulseek.py slsk-tmp/pysoulseek/pysoulseek.py --- pyslsk-1.1.0pre1/pysoulseek/pysoulseek.py 2003-04-04 22:51:32.000000000 +0200 +++ slsk-tmp/pysoulseek/pysoulseek.py 2003-04-04 23:42:06.000000000 +0200 @@ -603,9 +603,15 @@ pic = None descr = eval(self.config.sections["userinfo"]["descr"]) if self.transfers is not None: - totalupl = self.transfers.getTotalUploadsAllowed() queuesize = self.transfers.getUploadQueueSizes()[0] - slotsavail = not self.transfers.bandwidthLimitReached() + if self.config.sections["transfers"]["useupslots"]: + totalupl = self.config.sections["transfers"]["uploadslots"] + slotsavail = totalupl - self.transfers.activeUploads() + if slotsavail < 0: + slotsavail = 0 + else: + totalupl = self.transfers.getTotalUploadsAllowed() + slotsavail = not self.transfers.bandwidthLimitReached() self.queue.put(slskmessages.UserInfoReply(msg.conn.conn,descr,pic,totalupl, queuesize,slotsavail)) self.logMessage("%s %s" %(msg.__class__, vars(msg)),1) @@ -843,7 +849,13 @@ results.remove(i) queuesizes = self.transfers.getUploadQueueSizes() - slotsavail = not self.transfers.bandwidthLimitReached() + if self.config.sections["transfers"]["useupslots"]: + totalupl = self.config.sections["transfers"]["uploadslots"] + slotsavail = totalupl - self.transfers.activeUploads() + if slotsavail < 0: + slotsavail = 0 + else: + slotsavail = not self.transfers.bandwidthLimitReached() if len(resultsogg) > 0: message = slskmessages.FileSearchResult(None, user, searchid,resultsogg,slotsavail, self.speed, queuesizes[1]) self.ProcessRequestToPeer(user, message) diff -rNu3 pyslsk-1.1.0pre1/pysoulseek/transfers.py slsk-tmp/pysoulseek/transfers.py --- pyslsk-1.1.0pre1/pysoulseek/transfers.py 2003-04-04 23:26:18.000000000 +0200 +++ slsk-tmp/pysoulseek/transfers.py 2003-04-05 01:20:42.000000000 +0200 @@ -349,15 +349,28 @@ return 1 return 0 + def activeUploads(self): + uploads = 0 + for i in self.uploads: + if i.conn is not None and i.speed is not None: + uploads = uploads + 1 + return uploads + def bandwidthLimitReached(self): maxbandwidth = self.eventprocessor.config.sections["transfers"]["uploadbandwidth"] - bandwidth = 0 + maxslots = self.eventprocessor.config.sections["transfers"]["uploadslots"] + useupslots = self.eventprocessor.config.sections["transfers"]["useupslots"] + bandwidth = uploads = 0 curtime = time.time() for i in self.uploads: if i.conn is not None and i.speed is not None: bandwidth = bandwidth + i.speed + uploads = uploads + 1 # self.eventprocessor.logMessage("%i %i " %(bandwidth, maxbandwidth),1) - if bandwidth > maxbandwidth: + if useupslots: + if uploads >= maxslots: + return 1 + elif bandwidth > maxbandwidth: return 1 return 0 @@ -629,9 +642,16 @@ transfercandidate = None list = [i for i in self.uploads if not self.userTransfers(i.user) and i.status == "Queued"] listogg = [i for i in list if i.filename[-4:].lower() == ".ogg"] + if self.eventprocessor.config.sections["transfers"]["preferfriends"]: + userlist = [i[0] for i in self.eventprocessor.userlist.userlist] + listfriends = [i for i in list if i.user in userlist] + else: + listfriends = [] listprivileged = [i for i in list if i.user in self.privilegedusers] if len(listogg) > 0: list = listogg + if len(listfriends) > 0: + list = listfriends if len(listprivileged) > 0: list = listprivileged if len(list) == 0: @@ -649,16 +669,23 @@ if i.conn is msg.conn.conn: user = i.username + userlist = [i[0] for i in self.eventprocessor.userlist.userlist] + preferfriends = self.eventprocessor.config.sections["transfers"]["preferfriends"] list = {user:time.time()} listogg = {user:time.time()} + listfriend = {user:time.time()} listpriv = {user:time.time()} countogg = 0 countpriv = 0 + countfriend = 0 for i in self.uploads: if i.status == "Queued": if i.user in self.privilegedusers: listpriv[i.user] = i.timequeued countpriv += 1 + elif i.user in userlist and preferfriends: + listfriend[i.user] = i.timequeued + countfriend += 1 elif i.filename[-4:].lower() == ".ogg": listogg[i.user] = i.timequeued countogg += 1 @@ -668,11 +695,14 @@ place = 0 if user in self.privilegedusers: list = listpriv + elif user in userlist and preferfriends: + list = listfriend + place = place + countpriv elif msg.file[-4:].lower() == ".ogg": list = listogg - place = place + countpriv + place = place + countpriv + countfriend else: - place = place + countpriv + countogg + place = place + countpriv + countfriend + countogg for i in list.keys(): if list[i] < list[user]: place = place + 1 diff -rNu3 pyslsk-1.1.0pre1/pysoulseek/utils.py slsk-tmp/pysoulseek/utils.py --- pyslsk-1.1.0pre1/pysoulseek/utils.py 2003-04-02 01:10:50.000000000 +0200 +++ slsk-tmp/pysoulseek/utils.py 2003-04-05 02:55:19.000000000 +0200 @@ -9,7 +9,7 @@ import os,dircache import mp3 -version = "1.1.0pre1" +version = "1.1.0pre1-hyriand-1" def getServerList(url): """ Parse server text file from http://www.slsk.org and @@ -201,3 +201,96 @@ d[x] = x return d.values() +def Humanize(number,fashion): + if fashion == "" or fashion == "": + return str(number) + elif fashion == "": + fashion = " " + number = str(number) + ret = "" + while number[-3:]: + part, number = number[-3:], number[:-3] + ret = "%s%s%s" % (part, fashion, ret) + return ret[:-1] + +def expand_alias(aliases, cmd): + def getpart(line): + if line[0] != "(": + return "" + ix = 1 + ret = "" + level = 0 + while ix < len(line): + if line[ix] == "(": + level = level + 1 + if line[ix] == ")": + if level == 0: + return ret + else: + level = level - 1 + ret = ret + line[ix] + ix = ix + 1 + return "" + + if not cmd: + return None + if cmd[0] != "/": + return None + cmd = cmd[1:].split(" ") + if not aliases.has_key(cmd[0]): + return None + alias = aliases[cmd[0]] + ret = "" + i = 0 + while i < len(alias): + if alias[i:i+2] == "$(": + arg=getpart(alias[i+1:]) + if not arg: + ret = ret + "$" + i = i + 1 + continue + i = i + len(arg) + 3 + args = arg.split("=",1) + if len(args) > 1: + default = args[1] + else: + default = "" + args = args[0].split(":") + if len(args) == 1: + first = last = int(args[0]) + else: + if args[0]: + first = int(args[0]) + else: + first = 1 + if args[1]: + last = int(args[1]) + else: + last = len(cmd) + v = string.join(cmd[first:last+1]) + if not v: v = default + ret = ret + v + elif alias[i:i+2] == "|(": + arg = getpart(alias[i+1:]) + if not arg: + ret = ret + "|" + i = i + 1 + continue + i = i + len(arg) + 3 + for j in range(len(cmd)-1, -1, -1): + arg = arg.replace("$%i" % j, cmd[j]) + arg = arg.replace("$@", string.join(cmd[1:], " ")) + stdin, stdout = os.popen2(arg) + v = stdout.read().split("\n") + r = "" + for l in v: + l = l.strip() + if l: + r = r + l + "\n" + ret = ret + r.strip() + stdin.close() + stdout.close() + else: + ret = ret + alias[i] + i = i + 1 + return ret diff -rNu3 pyslsk-1.1.0pre1/pysoulseek/wxgui/about.py slsk-tmp/pysoulseek/wxgui/about.py --- pyslsk-1.1.0pre1/pysoulseek/wxgui/about.py 2003-03-29 18:10:27.000000000 +0100 +++ slsk-tmp/pysoulseek/wxgui/about.py 2003-04-04 23:51:26.000000000 +0200 @@ -23,7 +23,7 @@ ok.SetDefault() sizer.Add(wxStaticBitmap(self,-1,img,size=wxSize(img.GetWidth(), img.GetHeight())), flag=wxALL, border = 5) - sizer.Add(wxStaticText(self,-1,"PySoulSeek "+version+"\nCopyright (c) 2001-2003 by Alexander Kanavin\nhttp://www.sensi.org/~ak/\nak@sensi.org\n\nReleased under the GNU general public license\n\nSee MAINTAINERS file for the list of contributors",style=wxALIGN_CENTRE), flag = wxALL, border = 5) + sizer.Add(wxStaticText(self,-1,"PySoulSeek "+version+"\nCopyright (c) 2001-2003 by Alexander Kanavin\nhttp://www.sensi.org/~ak/\nak@sensi.org\n\nModified by Hyriand\nhttp://thegraveyard.org/pyslsk/\nhyriand@thegraveyard.org\n\nReleased under the GNU general public license\n\nSee MAINTAINERS file for the list of contributors",style=wxALIGN_CENTRE), flag = wxALL, border = 5) mainsizer.Add(sizer, flag=wxALL,border = 5) mainsizer.Add(ok, flag = wxALL|wxALIGN_CENTER,border = 10) @@ -59,6 +59,9 @@ "/whois /w user", "Request user info for user 'user'", "/ip user", "Show IP for user 'user'", "", "", + "/alias /al [command [definition]]", "Add a new alias", + "/unalias /un command", "Remove an alias", + "", "", "/ban user", "Add user 'user' to your ban list", "/unban user", "Remove user 'user' from your ban list", "/ignore user", "Add user 'user' to your ignore list", @@ -84,6 +87,9 @@ "/whois /w [user]", "Request user info for user 'user'", "/ip [user]", "Show IP for user 'user'", "", "", + "/alias /al [command [definition]]", "Add a new alias", + "/unalias /un command", "Remove an alias", + "", "", "/ban [user]", "Add user 'user' to your ban list", "/unban [user]", "Remove user 'user' from your ban list", "/ignore [user]", "Add user 'user' to your ignore list", @@ -113,3 +119,49 @@ self.SetSizer(mainsizer) self.SetAutoLayout(True) mainsizer.Fit(self) + +class AboutFilters(wxDialog): + def __init__(self, parent, id, title): + + wxDialog.__init__(self,parent,id,title) + + sizer = wxStaticBoxSizer(wxStaticBox(self,-1,""),wxHORIZONTAL) + + mainsizer = wxBoxSizer(wxVERTICAL) + + ok = wxButton(self, wxID_OK, "OK") + ok.SetDefault() + + sizer.Add(wxStaticText(self,-1,"""Search filtering + +You can use this to refine which results are displayed. The full results +from the server are always available if you clear all the search terms. + +You can filter by: + +Included text: Files are shown if they contain this text. Case is insensitive, +but word order is important. "Spears Brittany" will not show any "Brittany Spears" + +Excluded text: As above, but files will not be displayed if the text matches + +Size: Shows results based on size. use > and < to find files larger or smaller. +Files exactly the same as this term will always match. Use = to specify an exact +match. Use k or m to specify kilo or megabytes. >10M will find files larger than +10 megabytes. <4000k will find files smaller than 4000k. + +Bitrate: Find files based on bitrate. Use < and > to find lower or higher. >192 +finds 192 and higher, <192 finds 192 or lower. =192 only finds 192. for VBR, the +average bitrate is used. + +Free slot: Show only those results from users which have at least one upload slot +free. + +To set the filter, press Enter. This will apply to any existing results, and any +more that are returned. To filter in a different way, just set the relevant terms. +You do not need to do another search to apply a different filter.""",style=wxALIGN_CENTRE), flag = wxALL, border = 5) + + mainsizer.Add(sizer, flag=wxALL,border = 5) + mainsizer.Add(ok, flag = wxALL|wxALIGN_CENTER,border = 10) + self.SetSizer(mainsizer) + self.SetAutoLayout(True) + mainsizer.Fit(self) diff -rNu3 pyslsk-1.1.0pre1/pysoulseek/wxgui/chat.py slsk-tmp/pysoulseek/wxgui/chat.py --- pyslsk-1.1.0pre1/pysoulseek/wxgui/chat.py 2003-04-02 19:54:55.000000000 +0200 +++ slsk-tmp/pysoulseek/wxgui/chat.py 2003-04-04 23:59:29.000000000 +0200 @@ -16,6 +16,7 @@ from sortablelist import sortableListCtrl from wxPython.wx import * import locale +from pysoulseek.utils import Humanize,expand_alias def GetCompletion(part, list): @@ -436,12 +437,12 @@ return username elif col == 1: if not sort: - return locale.format("%s",self.parent.users[username].avgspeed,1) + return Humanize(self.parent.users[username].avgspeed,self.parent.frame.np.config.sections["ui"]["decimalsep"]) else: return self.parent.users[username].avgspeed elif col == 2: if not sort: - return locale.format("%s",self.parent.users[username].files,1) + return Humanize(self.parent.users[username].files,self.parent.frame.np.config.sections["ui"]["decimalsep"]) else: return self.parent.users[username].files else: @@ -536,7 +537,11 @@ def OnEnter(self, event): """ Processes chat phrase that we entered. """ text = self.frame.np.encode(self.mychatphrase.GetLineText(0)) + result = expand_alias(self.frame.np.config.aliases, text) + if result is not None: + text = result if len(text) == 0: + self.mychatphrase.Clear() return s = text.split(" ", 1) cmd = s[0] @@ -544,7 +549,11 @@ rest = s[1] else: rest = "" - if cmd in ("/join", "/j"): + if cmd in ("/alias", "/al"): + self.chat.AppendText(self.frame.np.config.AddAlias(rest)) + elif cmd in ("/unalias", "/un"): + self.chat.AppendText(self.frame.np.config.Unalias(rest)) + elif cmd in ("/join", "/j"): if rest: self.queue.put(slskmessages.JoinRoom(rest)) elif cmd in ("/leave", "/part", "/l", "/p"): @@ -682,18 +691,18 @@ if text[:4] == "/me ": str = "%s * %s %s\n" %(time.strftime("%X"),msg.user,text[4:]) - color = "FOREST GREEN" + color = self.frame.np.config.sections["ui"]["chatme"] else: str = "%s [%s] %s\n" %(time.strftime("%X"),msg.user,text) if msg.user == self.frame.np.config.sections["server"]["login"]: - color = wxBLUE + color = self.frame.np.config.sections["ui"]["chatlocal"] elif text.upper().find(self.frame.np.config.sections["server"]["login"].upper()) >= 0: - color = wxRED + color = self.frame.np.config.sections["ui"]["chathilite"] highlight = True else: - color = None + color = self.frame.np.config.sections["ui"]["chatremote"] - if color is not None: + if color is not None and color != "": self.chat.SetDefaultStyle(wxTextAttr(color)) self.chat.AppendUserText(self.frame.np.decode(str,wxUSE_UNICODE),msg.user,color) self.chat.SetDefaultStyle(wxTextAttr()) @@ -755,9 +764,11 @@ timestamp = self.np.encode(time.strftime("%c",time.localtime())) if text[:4] == "/me ": str = "%s * %s %s\n" %(timestamp,msg.user,text[4:]) - color = "FOREST GREEN" + color = self.np.config.sections["ui"]["chatme"] else: str = "%s [%s] %s\n" %(timestamp,msg.user,text) + color = self.np.config.sections["ui"]["chatremote"] + if color == "": color = None self.users[msg.user].AddText(self.np.decode(str,wxUSE_UNICODE),color) self.np.frame.OnPageUpdated(self) @@ -851,6 +862,14 @@ if self.logctrl.GetValue() == 1: self.OnLogCheckClick(None) + try: + logfile = open(os.path.join(self.parent.np.config.sections["logging"]["logsdir"], string.replace(self.user, os.sep, "-") + ".log"), 'r', 0) + except: + return + lines = logfile.readlines() + for i in lines[-15:]: + self.AddText(i, 'brown') + self.AddText('----------------------------------------------------\n', 'purple') def OnRightUp(self,event): pt = event.GetPosition() @@ -895,10 +914,12 @@ timestamp = self.parent.np.encode(time.strftime("%c",time.localtime())) if text[:4] == "/me ": str = "%s * %s %s\n" %(timestamp,username,text[4:]) - color = "FOREST GREEN" + color = self.parent.np.config.sections["ui"]["chatme"] else: str = "%s %s\n" %(timestamp,text) - color = wxBLUE + color = self.parent.np.config.sections["ui"]["chatlocal"] + if color == "": + color = None if len(text) > 0: self.AddText(self.parent.np.decode(str, wxUSE_UNICODE), color) @@ -909,6 +930,12 @@ def OnEnter(self, event): """ Sends our chat phrase and updates the window.""" text = self.parent.np.encode(self.mychatphrase.GetLineText(0)) + result = expand_alias(self.parent.np.config.aliases, text) + if result is not None: + text = result + if len(text) == 0: + self.mychatphrase.Clear() + return s = text.split(" ", 1) cmd = s[0] if len(s) > 1: @@ -920,7 +947,11 @@ truerest = "" else: truerest = rest - if cmd in ("/away", "/a"): + if cmd in ("/alias", "/al"): + self.chat.AppendText(self.parent.np.config.AddAlias(truerest)) + elif cmd in ("/unalias", "/un"): + self.chat.AppendText(self.parent.np.config.Unalias(truerest)) + elif cmd in ("/away", "/a"): self.parent.np.frame.OnAway(event) elif cmd in ("/quit", "/q"): self.parent.np.frame.Close() diff -rNu3 pyslsk-1.1.0pre1/pysoulseek/wxgui/configwindow.py slsk-tmp/pysoulseek/wxgui/configwindow.py --- pyslsk-1.1.0pre1/pysoulseek/wxgui/configwindow.py 2003-04-04 22:45:41.000000000 +0200 +++ slsk-tmp/pysoulseek/wxgui/configwindow.py 2003-04-05 01:51:51.000000000 +0200 @@ -129,6 +129,46 @@ self._list.sort() self.listbox.Set(self._list) +class ColourPicker: + def __init__(self, parent, id, title): + self.button = wxButton(parent, -1, title) + self.textctrl = wxTextCtrl(parent, -1, size=wxSize(125,25), style=wxTE_READONLY|wxTE_RICH|wxTE_MULTILINE) + self.button2 = wxButton(parent, -1, "Default") + self.parent = parent + self._value = "" + EVT_BUTTON(parent, self.button.GetId(), self.OnClick) + EVT_BUTTON(parent, self.button2.GetId(), self.OnClear) + + def OnClick(self, event): + colour = wxColourData() + colour.SetColour(self._value) + dlg = wxColourDialog(self.parent, colour) + if dlg.ShowModal() == wxID_OK: + colour = dlg.GetColourData().GetColour() + if colour: + colourname = wxTheColourDatabase.FindName(colour) + if colourname: + self.SetValue(colourname) + else: + self.SetValue("#%2x%2x%2x" % (colour.Red(),colour.Green(),colour.Blue())) + else: + self.SetValue("") + dlg.Destroy() + + def OnClear(self,event): + self.SetValue("") + + def GetValue(self): + return self._value + + def SetValue(self, value): + self._value = value + self.textctrl.Clear() + style = self.textctrl.GetDefaultStyle() + self.textctrl.SetDefaultStyle(wxTextAttr(value)) + self.textctrl.AppendText(value.capitalize()) + self.textctrl.SetDefaultStyle(style) + class ServerPanel(wxPanel): def __init__(self,parent, encodings): wxPanel.__init__(self, parent, -1) @@ -198,6 +238,10 @@ self.uploadlimit = wxTextCtrl(self, -1, size=wxSize(30,25)) self.limittransfer = wxRadioButton(self, -1, "per transfer", style=wxRB_GROUP) self.limittotal = wxRadioButton(self, -1, "total for all transfers") + self.upload_use_width = wxRadioButton(self,-1,"upload speed exceeds ",style=wxRB_GROUP) + self.upload_use_slots = wxRadioButton(self,-1,"number of uploads exceeds ") + self.upslots = wxTextCtrl(self,-1,size=wxSize(30,25)) + self.preferfriends = wxCheckBox(self, -1, "Let users in my list download first") EVT_BUTTON(self,self.downloaddirchoose.GetId(),self.OnDownloadChoose) EVT_BUTTON(self,self.uploaddiradd.GetId(),self.OnUploadAdd) @@ -205,6 +249,8 @@ EVT_BUTTON(self,self.uploaddirrescan.GetId(),self.OnUploadRescan) EVT_CHECKBOX(self,self.sharedownloadctrl.GetId(),self.OnShareDownload) EVT_CHECKBOX(self,self.useuploadlimit.GetId(),self.OnUseUploadLimit) + EVT_RADIOBUTTON(self,self.upload_use_width.GetId(),self.OnUploadChoose) + EVT_RADIOBUTTON(self,self.upload_use_slots.GetId(),self.OnUploadChoose) downloadsizer = wxBoxSizer(wxHORIZONTAL) downloadsizer.Add(self.downloaddirctrl) @@ -220,9 +266,14 @@ uploadsizer.Add(uploadbuttonssizer) bandwidthsizer = wxBoxSizer(wxHORIZONTAL) + bandwidthsizer.Add(self.upload_use_width) bandwidthsizer.Add(self.uploadbandwidth, flag=wxLEFT, border=10) bandwidthsizer.Add(wxStaticText(self, -1, " KBytes/sec"),flag=wxALIGN_CENTER) + upslotssizer = wxBoxSizer(wxHORIZONTAL) + upslotssizer.Add(self.upload_use_slots) + upslotssizer.Add(self.upslots) + limitsizer = wxFlexGridSizer(cols=3, rows=2) limitsizer.Add(self.uploadlimit, flag=wxLEFT, border = 10) limitsizer.Add(wxStaticText(self, -1, " KBytes/sec "), flag=wxALIGN_CENTER) @@ -238,10 +289,12 @@ transferssizer.Add(wxStaticText(self, -1, "Shared directories:"),flag=wxTOP|wxLEFT, border = 10) transferssizer.Add(uploadsizer, flag=wxLEFT|wxRIGHT, border = 10) transferssizer.Add(self.rescanonstartup, flag=wxLEFT|wxTOP, border = 10) - transferssizer.Add(wxStaticText(self, -1, "Locally queue uploads if total upload speed exceeds:"),flag=wxTOP|wxLEFT, border = 10) - transferssizer.Add(bandwidthsizer,flag=wxLEFT|wxBOTTOM, border = 10) + transferssizer.Add(wxStaticText(self, -1, "Locally queue uploads if:"),flag=wxTOP|wxLEFT, border = 10) + transferssizer.Add(bandwidthsizer,flag=wxLEFT, border = 10) + transferssizer.Add(upslotssizer,flag=wxBOTTOM|wxLEFT, border = 10) transferssizer.Add(self.useuploadlimit, flag=wxLEFT, border = 10) transferssizer.Add(limitsizer, flag=wxLEFT|wxBOTTOM, border = 10) + transferssizer.Add(self.preferfriends, flag=wxLEFT|wxBOTTOM, border = 10) self.needrescan = 0 @@ -297,6 +350,15 @@ shared.append(encode(self.downloaddirctrl.GetValue())) self.sharedfiles,self.sharedfilesstreams,self.sharedindex,self.sharedmtimes = utils.rescandirs(shared, self.sharedmtimes, self.sharedfiles, self.sharedfilesstreams, self.sharedindex, wxYield) + def OnUploadChoose(self,event): + if self.upload_use_width.GetValue(): + self.upslots.Enable(False) + self.uploadbandwidth.Enable(True) + else: + self.upslots.Enable(True) + self.uploadbandwidth.Enable(False) + + class UserinfoPanel(wxPanel): def __init__(self,parent): wxPanel.__init__(self, parent, -1) @@ -328,6 +390,42 @@ self.pic.SetValue(pic) +class UiPanel(wxPanel): + def __init__(self,parent): + wxPanel.__init__(self, parent, -1) + + self.colourchatremote = ColourPicker(self, -1, "Remote text:") + self.colourchatlocal = ColourPicker(self, -1, "Local text:") + self.colourchatme = ColourPicker(self, -1, "/me text:") + self.colourhighlight = ColourPicker(self, -1, "Highlight colour:") + self.coloursearchnoqueue = ColourPicker(self, -1, "Without queue:") + self.coloursearchqueue = ColourPicker(self, -1, "With queue:") + self.decimalsep = wxComboBox(self, -1, style=wxCB_DROPDOWN|wxCB_READONLY, choices = ["", ",", ".", ""]) + + uisizer=wxStaticBoxSizer(wxStaticBox(self,-1,"Colours:"),wxVERTICAL) + uisizer.Add(wxStaticText(self,-1,"Chat colours:"), flag=wxLEFT|wxTOP, border = 10) + chatcoloursgrid = wxFlexGridSizer(cols=3, vgap=2, hgap=5) + for i in self.colourchatremote, self.colourchatlocal, self.colourchatme, self.colourhighlight: + chatcoloursgrid.Add(i.button, flag=wxEXPAND) + chatcoloursgrid.Add(i.textctrl) + chatcoloursgrid.Add(i.button2) + uisizer.Add(chatcoloursgrid, flag=wxEXPAND|wxLEFT, border=15) + uisizer.Add(wxStaticText(self,-1,"Search result colours:"),flag=wxLEFT|wxTOP, border=10) + searchcoloursgrid = wxFlexGridSizer(cols=3,vgap=2,hgap=5) + for i in self.coloursearchnoqueue, self.coloursearchqueue: + searchcoloursgrid.Add(i.button, flag=wxEXPAND) + searchcoloursgrid.Add(i.textctrl) + searchcoloursgrid.Add(i.button2) + uisizer.Add(searchcoloursgrid, flag=wxEXPAND|wxLEFT, border=15) + decimalsepsizer = wxBoxSizer(wxHORIZONTAL) + decimalsepsizer.Add(wxStaticText(self, -1, "Decimal separator:"), flag=wxALIGN_CENTER|wxRIGHT, border = 5) + decimalsepsizer.Add(self.decimalsep) + uisizer.Add(decimalsepsizer, flag=wxTOP|wxLEFT, border=10) + + self.SetSizer(uisizer) + self.SetAutoLayout(True) + + class MiscPanel(wxPanel): def __init__(self,parent): wxPanel.__init__(self, parent, -1) @@ -399,10 +497,12 @@ self.serverpanel = ServerPanel(nb, parent.np.getencodings()) self.transferspanel = TransfersPanel(nb) self.userinfopanel = UserinfoPanel(nb) + self.uipanel = UiPanel(nb) self.miscpanel = MiscPanel(nb) nb.AddPage(self.serverpanel,"Server") nb.AddPage(self.transferspanel,"Transfers") nb.AddPage(self.userinfopanel,"Personal info") + nb.AddPage(self.uipanel,"Interface") nb.AddPage(self.miscpanel,"Miscellaneous") @@ -429,6 +529,7 @@ userinfo = config.sections["userinfo"] logging = config.sections["logging"] searches = config.sections["searches"] + ui = config.sections["ui"] if server["server"] is not None: self.serverpanel.serverctrl.SetValue(string.join([str(i) for i in server["server"]],":")) if server["login"] is not None: @@ -477,6 +578,16 @@ self.miscpanel.usecustomban.SetValue(transfers["usecustomban"]) if transfers["customban"] is not None: self.miscpanel.customban.SetValue(transfers["customban"]) + if transfers["preferfriends"] is not None: + self.transferspanel.preferfriends.SetValue(transfers["preferfriends"]) + if transfers["uploadslots"] is not None: + self.transferspanel.upslots.SetValue(str(transfers["uploadslots"])) + if transfers["useupslots"] is not None: + if transfers["useupslots"]: + self.transferspanel.upload_use_slots.SetValue(True); + else: + self.transferspanel.upload_use_width.SetValue(True); + self.transferspanel.OnUploadChoose(None) if userinfo["descr"] is not None: self.userinfopanel.descr.SetValue(eval(userinfo["descr"])) if userinfo["pic"] is not None: @@ -489,6 +600,20 @@ self.miscpanel.loggingchatctrl.SetValue(logging["chatrooms"]) if searches["maxresults"] is not None: self.miscpanel.maxresults.SetValue(str(searches["maxresults"])) + if ui["chatremote"] is not None: + self.uipanel.colourchatremote.SetValue(ui["chatremote"]) + if ui["chatlocal"] is not None: + self.uipanel.colourchatlocal.SetValue(ui["chatlocal"]) + if ui["chatme"] is not None: + self.uipanel.colourchatme.SetValue(ui["chatme"]) + if ui["chatme"] is not None: + self.uipanel.colourhighlight.SetValue(ui["chathilite"]) + if ui["search"] is not None: + self.uipanel.coloursearchnoqueue.SetValue(ui["search"]) + if ui["searchq"] is not None: + self.uipanel.coloursearchqueue.SetValue(ui["searchq"]) + if ui["decimalsep"] is not None: + self.uipanel.decimalsep.SetValue(ui["decimalsep"]) def GetSettings(self): @@ -530,6 +655,11 @@ portrange = (firstport, lastport) except: portrange = (2234, 2239) + try: + uploadslots = int(encode(self.transferspanel.upslots.GetValue())) + except: + uploadslots = None + useupslots = encode(self.transferspanel.upload_use_slots.GetValue()) banlist = [] for i in self.miscpanel.banlist.getList(): banlist.append(encode(i)) @@ -551,6 +681,9 @@ "sharedmtimes":self.transferspanel.sharedmtimes, \ "rescanonstartup":encode(self.transferspanel.rescanonstartup.GetValue()),\ "uploadbandwidth":uploadbandwidth, \ + "uploadslots":uploadslots, \ + "useupslots":useupslots, \ + "preferfriends":encode(self.transferspanel.preferfriends.GetValue()), \ "uselimit":encode(self.transferspanel.useuploadlimit.GetValue()), \ "usecustomban":encode(self.miscpanel.usecustomban.GetValue()), \ "customban":encode(self.miscpanel.customban.GetValue()), \ @@ -562,4 +695,11 @@ "logsdir":encode(self.miscpanel.logsdirctrl.GetValue()), \ "privatechat":encode(self.miscpanel.loggingprivatectrl.GetValue()), \ "chatrooms":encode(self.miscpanel.loggingchatctrl.GetValue())}, - "searches":{"maxresults":maxresults}} + "searches":{"maxresults":maxresults}, \ + "ui":{"chatremote":encode(self.uipanel.colourchatremote.GetValue()), \ + "chatlocal":encode(self.uipanel.colourchatlocal.GetValue()), \ + "chatme":encode(self.uipanel.colourchatme.GetValue()), \ + "chathilite":encode(self.uipanel.colourhighlight.GetValue()), \ + "search":encode(self.uipanel.coloursearchnoqueue.GetValue()), \ + "searchq":encode(self.uipanel.coloursearchqueue.GetValue()), + "decimalsep":encode(self.uipanel.decimalsep.GetValue())}} diff -rNu3 pyslsk-1.1.0pre1/pysoulseek/wxgui/frame.py slsk-tmp/pysoulseek/wxgui/frame.py --- pyslsk-1.1.0pre1/pysoulseek/wxgui/frame.py 2003-04-04 21:58:26.000000000 +0200 +++ slsk-tmp/pysoulseek/wxgui/frame.py 2003-04-05 00:24:17.000000000 +0200 @@ -136,6 +136,9 @@ aboutPrivateID = wxNewId() helpmenu.Append(aboutPrivateID, '&Private chat commands', 'About private chat commands') EVT_MENU(self,aboutPrivateID, self.OnAboutPrivateCommands) + aboutFiltersID = wxNewId() + helpmenu.Append(aboutFiltersID, '&Search filters', 'About search filtering') + EVT_MENU(self,aboutFiltersID, self.OnAboutFilters) helpmenu.AppendSeparator() aboutID = wxNewId() helpmenu.Append(aboutID, '&About', 'About PySoulSeek') @@ -336,6 +339,9 @@ def OnAboutPrivateCommands(self, event): about.AboutCommands(self, -1, "About Chat Commands", True).ShowModal() + def OnAboutFilters(self, event): + about.AboutFilters(self, -1, "About Search Filters").ShowModal() + def ConnectError(self,msg): self.mainmenu.Enable(self.connectID,1) self.mainmenu.Enable(self.disconnectID,0) diff -rNu3 pyslsk-1.1.0pre1/pysoulseek/wxgui/search.py slsk-tmp/pysoulseek/wxgui/search.py --- pyslsk-1.1.0pre1/pysoulseek/wxgui/search.py 2003-04-04 17:17:07.000000000 +0200 +++ slsk-tmp/pysoulseek/wxgui/search.py 2003-04-05 01:43:54.000000000 +0200 @@ -17,6 +17,7 @@ from sortablelist import sortableListCtrl from wxPython.wx import * import locale +from pysoulseek.utils import Humanize class SearchWindow(wxPanel): """ A search window with notebook that contains search results. @@ -35,6 +36,8 @@ self.search = wxTextCtrl(self,-1, style = wxTE_PROCESS_ENTER) self.searchbutton = wxButton(self, -1, "Search") self.resultsnb = notebook.IconNotebook(self, -1, style = wxCLIP_CHILDREN) + timerid = wxNewId() + self.timer = wxTimer(self, timerid) sizerh = wxBoxSizer(wxHORIZONTAL) sizerh.Add(self.search,1,wxALIGN_CENTER) sizerh.Add(self.searchbutton,0,wxALIGN_CENTER) @@ -48,8 +51,23 @@ EVT_BUTTON(self, self.searchbutton.GetId(), self.OnSearch) EVT_TEXT_ENTER(self,self.search.GetId(), self.OnSearch) + EVT_TIMER(self, timerid, self.OnTimer) self.searches = {} + self.AutoSearch() + self.timer.Start(60*60*1000) + + def AutoSearch(self): + for i in self.frame.np.config.sections["server"]["autosearch"]: + for j in self.searches.keys(): + if self.searches[j][1] == i and self.searches[j][2]: + self.queue.put(slskmessages.FileSearch(j,i)) + break + else: + self.DoGlobalSearch(i, True) + + def OnTimer(self, event): + self.AutoSearch() def OnSearch(self, event): """ Process search request""" @@ -63,10 +81,13 @@ self.DoRoomsSearch(text) self.search.Clear() - def DoGlobalSearch(self, text): + def DoGlobalSearch(self, text, auto=False): requestid = wxNewId() - tab, list = self.MakeSearchTab() - self.searches[requestid] = (list,text) + tab, list = self.MakeSearchTab(requestid) + tab.text = text + if auto: + tab.rememberctrl.SetValue(1) + self.searches[requestid] = [list, text, auto] self.resultsnb.AddPage(tab,text) self.queue.put(slskmessages.FileSearch(requestid,text)) @@ -87,8 +108,8 @@ def DoPeerSearch(self, text, users, title = ""): requestid = wxNewId() - tab, list = self.MakeSearchTab() - self.searches[requestid] = (list,text) + tab, list = self.MakeSearchTab(requestid, False) + self.searches[requestid] = [list,text,None] self.resultsnb.AddPage(tab,"%s (%s)" %(text,title)) for user in users: self.processrequest(user, slskmessages.FileSearchRequest(None,requestid,text)) @@ -99,23 +120,41 @@ if self.searches.has_key(msg.token): if self.searches[msg.token][0] is None: text = self.searches[msg.token][1] - tab, list = self.MakeSearchTab() - self.searches[msg.token] = (list, text) + remember = self.searches[msg.token][2] + tab, list = self.MakeSearchTab(msg.token, not remember is None) + tab.text = text + self.searches[msg.token] = [list, text, remember] self.resultsnb.AddPage(tab,text) - self.searches[msg.token][0].AddResult(msg, username) - self.onupdate(self) - self.resultsnb.OnPageUpdated(self.searches[msg.token][0].parent) + if self.searches[msg.token][0].AddResult(msg, username): + self.onupdate(self) + self.resultsnb.OnPageUpdated(self.searches[msg.token][0].parent) - def MakeSearchTab(self): + def MakeSearchTab(self, requestid, canRemeber = True): """ Create a result window, which is a notebook tab. """ panel = wxPanel(self.resultsnb, -1) + panel.filterin = wxTextCtrl(panel, -1, value = "", size = wxSize(55,20), style = wxTE_PROCESS_ENTER) + panel.filterout = wxTextCtrl(panel, -1, value = "", size = wxSize(55,20), style = wxTE_PROCESS_ENTER) + panel.filtersize = wxTextCtrl(panel, -1, value = "", size = wxSize(55,20), style = wxTE_PROCESS_ENTER) + panel.filterbr = wxTextCtrl(panel, -1, value = "", size = wxSize(45,20), style = wxTE_PROCESS_ENTER) + panel.filterfree = wxCheckBox(panel, -1, label = "free slot") close = wxButton(panel, -1, "Close") closeignore = wxButton(panel, -1, "Close and ignore") - list = SearchList(panel, -1, self.processrequest, self.privatechat, self.info, self.browse, self.transfers,self.frame) + panel.rememberctrl = wxCheckBox(panel, -1, label = "Remember") + list = SearchList(panel, -1, self.processrequest, self.privatechat, self.info, self.browse, self.transfers,self.frame, self, requestid) sizerh = wxBoxSizer(wxHORIZONTAL) + sizerh.Add(wxStaticText(panel, -1, label = " Filter In: "), flag = wxALIGN_CENTER) + sizerh.Add(panel.filterin) + sizerh.Add(wxStaticText(panel, -1, label = " Filter Out: "), flag = wxALIGN_CENTER) + sizerh.Add(panel.filterout) + sizerh.Add(wxStaticText(panel, -1, label = " Size: "), flag = wxALIGN_CENTER) + sizerh.Add(panel.filtersize) + sizerh.Add(wxStaticText(panel, -1, label = " Bitrate: "), flag = wxALIGN_CENTER) + sizerh.Add(panel.filterbr) + sizerh.Add(panel.filterfree, flag = wxALIGN_CENTER|wxLEFT, border=5) sizerh.Add(60,10,1,wxEXPAND) sizerh.Add(closeignore) sizerh.Add(close) + sizerh.Add(panel.rememberctrl) sizerv = wxBoxSizer(wxVERTICAL) sizerv.Add(sizerh,0,wxEXPAND) sizerv.Add(list,1,wxEXPAND) @@ -123,6 +162,14 @@ panel.SetAutoLayout(True) EVT_BUTTON(self, close.GetId(), self.OnClose) EVT_BUTTON(self, closeignore.GetId(), self.OnCloseIgnore) + EVT_TEXT_ENTER(self, panel.filterin.GetId(), list.OnRefilter) + EVT_TEXT_ENTER(self, panel.filterout.GetId(), list.OnRefilter) + EVT_TEXT_ENTER(self, panel.filtersize.GetId(), list.OnRefilter) + EVT_TEXT_ENTER(self, panel.filterbr.GetId(), list.OnRefilter) + EVT_CHECKBOX(self, panel.filterfree.GetId(), list.OnRefilter) + EVT_CHECKBOX(self, panel.rememberctrl.GetId(), list.OnRememberCheckClick) + if not canRemeber: + panel.rememberctrl.Enable(0) return panel,list def Close(self, ignore): @@ -131,7 +178,11 @@ selected = self.resultsnb.GetPage(selectednum) for i in self.searches.keys(): if self.searches[i][0] is not None and self.searches[i][0].GetParent() == selected: - self.searches[i] = (None,self.searches[i][1]) + self.searches[i] = [None,self.searches[i][1], self.searches[i][2]] + if self.searches[i][1] in self.frame.np.config.sections["server"]["autosearch"]: + self.frame.np.config.sections["server"]["autosearch"].remove(self.searches[i][1]) + self.frame.np.config.setConfig({"server":{"autosearch":self.frame.np.config.sections["server"]["autosearch"]}}) + self.frame.np.config.writeConfig() if ignore: del self.searches[i] @@ -148,7 +199,7 @@ class SearchList(sortableListCtrl): """ List of search results.""" - def __init__(self, parent, id, processrequest, privatechat, info, browse, transfers,frame,style = wxLC_REPORT|wxLC_VIRTUAL|wxLC_VRULES|wxSUNKEN_BORDER): + def __init__(self, parent, id, processrequest, privatechat, info, browse, transfers,frame, search, requestid, style = wxLC_REPORT|wxLC_VIRTUAL|wxLC_VRULES|wxSUNKEN_BORDER): sortableListCtrl.__init__(self,parent,id,style = style) self.InsertColumn(0,"", width = 30,format=wxLIST_FORMAT_RIGHT) self.InsertColumn(1,"Filename", width=250) @@ -175,8 +226,14 @@ self.browse = browse self.transfers = transfers self.frame = frame + self.search = search + self.requestid = requestid + self.foundUsers = [] self.results = [] + self.results_visible = [] + + self.UpdateColours() self.menu = wxMenu() downloadID=wxNewId() @@ -208,12 +265,16 @@ EVT_RIGHT_UP(self,self.OnRightUp) + def UpdateColours(self): + self.normal.SetTextColour(self.frame.np.config.sections["ui"]["search"]) + self.grey.SetTextColour(self.frame.np.config.sections["ui"]["searchq"]) + def OnRightUp(self,event): """ Pops up a menu on a right-click in users list.""" pt = event.GetPosition() item, flags = self.HitTest(pt) self.id = item - self.selecteduser = self.results[self.id][2] + self.selecteduser = self.results_visible[self.id][2] if item >= 0: self.SetItemState(item,wxLIST_STATE_FOCUSED,wxLIST_STATE_FOCUSED) self.PopupMenu(self.menu, pt) @@ -244,18 +305,80 @@ item = self.GetNextItem(item,wxLIST_NEXT_ALL,wxLIST_STATE_SELECTED|wxLIST_STATE_FOCUSED) if item == -1: break - self.transfers.getFile(self.results[item][2],self.results[item][9]+self.results[item][1]) + self.transfers.getFile(self.results_visible[item][2],self.results_visible[item][9]+self.results_visible[item][1]) def OnDownloadFolder(self,event): - self.processrequest(self.selecteduser, slskmessages.FolderContentsRequest(None,self.results[self.id][9])) + self.processrequest(self.selecteduser, slskmessages.FolderContentsRequest(None,self.results_visible[self.id][9])) + def checkDigit(self, filter, value, factorize = True): + op = ">=" + if filter[:1] in (">", "<", "="): + op, filter = filter[:1]+"=", filter[1:] + + if not filter: + return True + + factor = 1 + if factorize: + if filter.lower()[-1] == "g": + factor = 1024*1024*1024 + filter = filter[:-1] + elif filter.lower()[-1] == "m": + factor = 1024*1024 + filter = filter[:-1] + elif filter.lower()[-1] == "k": + factor = 1024 + filter = filter[:-1] + + if not filter: + return True + + if not filter.isdigit(): + return True + + filter = long(filter) * factor + + if eval(str(value)+op+str(filter)): + return True + + return False + + def checkFilter(self, name, size, br, free): + filterin = self.parent.filterin.GetLineText(0) + filterout = self.parent.filterout.GetLineText(0) + filtersize = self.parent.filtersize.GetLineText(0).replace(" ", "") + filterbr = self.parent.filterbr.GetLineText(0).replace(" ", "") + shown = True + + if self.parent.filterfree.GetValue() and not free: + shown = False + + if name.replace("_", " ").lower().find(filterin.lower()) == -1: + shown = False + + if shown and filterout and name.replace("_"," ").lower().find(filterout.lower()) >= 0: + shown = False + + if shown and filtersize and not self.checkDigit(filtersize, size): + shown = False + + if shown and filterbr and not self.checkDigit(filterbr, br, False): + shown = False + + return shown + def AddResult(self, msg, username): """ Add a result to the list.""" + if username in self.foundUsers: + return 0 + self.foundUsers.append(username) + results = 0 for i in msg.list: name = i[1].split('\\')[-1] dir = i[1][:-len(name)] user = username size = i[2] + br = 0 if i[3] == 'mp3' and len(i[4]) == 3: attrs = i[4] @@ -265,6 +388,7 @@ brs = '' bitrate = str(attrs[0]) + brs length = '%i:%02i' %(attrs[1] / 60, attrs[1] % 60) + br = attrs[0] elif i[3] == '': bitrate = length = "" else: @@ -273,24 +397,28 @@ immdownload = "Y" else: immdownload = "" - self.results.append([len(self.results)+1,name,user,size,msg.ulspeed,msg.inqueue,immdownload,bitrate,length,dir]) - if self.sortcol != -1: + self.results.append([len(self.results)+1,name,user,size,msg.ulspeed,msg.inqueue,immdownload,bitrate,length,dir,br]) + if self.checkFilter(name, size, br, immdownload): + self.results_visible.append([len(self.results)+1,name,user,size,msg.ulspeed,msg.inqueue,immdownload,bitrate,length,dir,br]) + results += 1 + if results and self.sortcol != -1: self.SortList(self.sortcol, self.sortorder) - self.SetItemCount(len(self.results)) + self.SetItemCount(len(self.results_visible)) + return results def OnGetItemText(self, item, col): import types - text = self.results[item][col] + text = self.results_visible[item][col] if type(text) == types.StringType: if len(text) > 0: return self.frame.np.decode(text,wxUSE_UNICODE) else: return '' else: - return locale.format("%s",text,1) + return Humanize(text,self.frame.np.config.sections["ui"]["decimalsep"]) def OnGetItemAttr(self, item): - if self.results[item][6] == "": + if self.results_visible[item][6] == 0: return self.grey else: return self.normal @@ -298,9 +426,27 @@ def OnGetItemImage(self, item): return -1 + def refilter(self): + self.results_visible = [i for i in self.results if self.checkFilter(i[1], i[3], i[10], i[6])] + self.SetItemCount(len(self.results_visible)) + + def OnRefilter(self, event): + self.refilter() + def SortList(self, col, order): + self.refilter() if order == 0: - self.results.sort(lambda x,y: self.cmp(x[col],y[col])) + self.results_visible.sort(lambda x,y: self.cmp(x[col],y[col])) else: - self.results.sort(lambda y,x: self.cmp(x[col],y[col])) + self.results_visible.sort(lambda y,x: self.cmp(x[col],y[col])) + def OnRememberCheckClick(self, event): + """ This is called when the 'Remember' checkbox is clicked """ + v = self.parent.rememberctrl.GetValue() + if v == 1: + self.frame.np.config.sections["server"]["autosearch"].append(self.parent.text) + else: + self.frame.np.config.sections["server"]["autosearch"].remove(self.parent.text) + self.frame.np.config.setConfig({"server":{"autosearch":self.frame.np.config.sections["server"]["autosearch"]}}) + self.frame.np.config.writeConfig() + self.search.searches[self.requestid][2] = v diff -rNu3 pyslsk-1.1.0pre1/pysoulseek/wxgui/transfers.py slsk-tmp/pysoulseek/wxgui/transfers.py --- pyslsk-1.1.0pre1/pysoulseek/wxgui/transfers.py 2003-04-04 19:29:44.000000000 +0200 +++ slsk-tmp/pysoulseek/wxgui/transfers.py 2003-04-05 01:02:39.000000000 +0200 @@ -11,6 +11,7 @@ import time from sortablelist import sortableListCtrl import locale +from types import StringType class TransfersList(sortableListCtrl): """ This is a list control for transfers. Gets transfer data from transfer @@ -30,6 +31,26 @@ self.update(None) + def Humanize(self, size): + if size is None: + return None + priv = "" + if type(size) is StringType and size[-13:] == " (privileged)": + size, priv = size[:-13], size[-13:] + try: + s = int(size) + if s > 1024*1024*1024: + r = "%.2f GB" % ((float(s) / (1024.0*1024.0*1024.0))) + elif s > 1024*1024: + r = "%.2f MB" % ((float(s) / (1024.0*1024.0))) + elif s > 1024: + r = "%.2f KB" % ((float(s) / 1024.0)) + else: + r = str(size) + return r + priv + except: + return size + priv + def update(self, item): if item is not None: if item in self.list: @@ -53,9 +74,9 @@ if col == 1: return item.user if col == 2: - return item.status + return self.Humanize(item.status) if col == 3: - return locale.format("%s",item.size,1) + return self.Humanize(item.size) if col == 4: if item.speed is not None: return "%.1f" %(item.speed) diff -rNu3 pyslsk-1.1.0pre1/pysoulseek/wxgui/userinfobrowse.py slsk-tmp/pysoulseek/wxgui/userinfobrowse.py --- pyslsk-1.1.0pre1/pysoulseek/wxgui/userinfobrowse.py 2003-04-04 16:13:30.000000000 +0200 +++ slsk-tmp/pysoulseek/wxgui/userinfobrowse.py 2003-04-05 01:06:06.000000000 +0200 @@ -17,6 +17,8 @@ from sortablelist import sortableListCtrl from wxPython.wx import * import locale +from pysoulseek.utils import Humanize +import string class UserNotebook(notebook.IconNotebook): """ This is a notebook with user's information. Used to show either @@ -86,16 +88,15 @@ self.image = None buttonsizer = wxBoxSizer(wxVERTICAL) + buttonsizer.Add(self.chat, 0, wxEXPAND|wxTOP|wxLEFT|wxRIGHT, border=10) + buttonsizer.Add(self.browse,0,wxEXPAND|wxTOP|wxLEFT|wxRIGHT, border=10) + buttonsizer.Add(self.getip, 0, wxEXPAND|wxTOP|wxLEFT|wxRIGHT, border=10) + buttonsizer.Add(self.addtolist,0,wxEXPAND|wxTOP|wxLEFT|wxRIGHT, border=10) + buttonsizer.Add(self.ban,0,wxEXPAND|wxTOP|wxLEFT|wxRIGHT, border=10) + buttonsizer.Add(self.savepic,0,wxEXPAND|wxTOP|wxLEFT|wxRIGHT, border=10) buttonsizer.Add(0,0,1,wxEXPAND) - buttonsizer.Add(self.chat, 0, wxEXPAND, border=10) - buttonsizer.Add(self.browse,0,wxEXPAND, border=10) - buttonsizer.Add(self.addtolist,0,wxEXPAND, border=10) - buttonsizer.Add(self.getip, 0, wxEXPAND, border=10) - buttonsizer.Add(self.ban,0,wxEXPAND, border=10) - buttonsizer.Add(self.savepic,0,wxEXPAND, border=10) - buttonsizer.Add(self.refresh,0,wxEXPAND, border=10) - buttonsizer.Add(10,10,0,wxEXPAND) - buttonsizer.Add(self.close,0,wxEXPAND, border=10) + buttonsizer.Add(self.refresh,0,wxEXPAND|wxLEFT|wxRIGHT, border=10) + buttonsizer.Add(self.close,0,wxEXPAND|wxALL, border=10) sizerv = wxBoxSizer(wxVERTICAL) sizerv.Add(wxStaticText(self,-1, "Self-description:")) @@ -204,7 +205,7 @@ class FileListCtrl(sortableListCtrl): """ This is a list of a user's files in a particular directory""" - def __init__(self, parent, id, style = wxLC_REPORT|wxLC_VIRTUAL|wxSUNKEN_BORDER|wxLC_VRULES): + def __init__(self, parent, id, frame, style = wxLC_REPORT|wxLC_VIRTUAL|wxSUNKEN_BORDER|wxLC_VRULES): sortableListCtrl.__init__(self,parent,id,style = style) self.InsertColumn(0,"Filename", width=200) self.InsertColumn(1,"Size",width=100,format=wxLIST_FORMAT_RIGHT) @@ -215,6 +216,8 @@ self.dir = None self.parent = parent + self.frame = frame + self.curtreeitem = None def SetFileList(self, list): """ Actually sets the list.""" @@ -237,7 +240,7 @@ return item[1] if col == 1: if not sort: - return locale.format("%s", item[2], 1) + return Humanize(item[2],self.frame.np.config.sections["ui"]["decimalsep"]) else: return item[2] if col == 2 or col == 3: @@ -293,7 +296,7 @@ self.refresh = wxButton(self, -1, "Refresh") splitter = wxSplitterWindow(self,-1,style=wxNO_3D|wxSP_3DSASH) self.tree = DirTreeCtrl(splitter, -1) - self.listctrl = FileListCtrl(splitter,-1) + self.listctrl = FileListCtrl(splitter,-1,frame) sizerlowh = wxBoxSizer(wxHORIZONTAL) sizerlowh.Add(self.gauge,0,wxEXPAND) @@ -342,6 +345,9 @@ downloaddirID=wxNewId() self.treemenu.Append(downloaddirID, 'Download Directory') EVT_MENU(self.tree,downloaddirID, self.OnDownloadDir) + recdownloaddirID=wxNewId() + self.treemenu.Append(recdownloaddirID, 'Recursively Download Dir') + EVT_MENU(self.tree,recdownloaddirID, self.OnRecDownloadDir) downloadfileID=wxNewId() self.listmenu.Append(downloadfileID, 'Download File(s)') EVT_MENU(self.listctrl,downloadfileID, self.OnDownloadFile) @@ -431,7 +437,8 @@ def OnTreeSelChanged(self, event): """ On selection of a tree item, display the filelist""" - self.listctrl.SetFileList(self.tree.GetPyData(event.GetItem())) + self.curtreeitem = event.GetItem() + self.listctrl.SetFileList(self.tree.GetPyData(self.curtreeitem)) def OnDownloadDir(self,event): """ Get every file in the directory """ @@ -509,3 +516,21 @@ list.extend(self.FindNodes(node[i][1],text)) return list + def OnRecDownloadDir(self,event): + """ Download directory recursively """ + self.RecDownloadDir(self.curtreeitem) + + def RecDownloadDir(self,item, path = ""): + """ Download directory recursively """ + import os + (dir, flist) = self.tree.GetPyData(item) + ldir = string.split(dir,'\\')[-1] # local directory + ldir = os.path.join(path,ldir) + for i in flist: # Get the files in this dir + self.transfers.getFile(self.user, dir+'\\'+i[1], ldir) + + if self.tree.ItemHasChildren(item): # Get the other dirs + i, cookie = self.tree.GetFirstChild(item, 0) + while i.IsOk(): + self.RecDownloadDir(i, ldir) + i, cookie = self.tree.GetNextChild(item, cookie)