| OLD | NEW |
| (Empty) |
| 1 | |
| 2 # Copyright (c) 2001-2004 Twisted Matrix Laboratories. | |
| 3 # See LICENSE for details. | |
| 4 | |
| 5 """Utilities for building L{PB<twisted.spread.pb>} clients with L{Tkinter}. | |
| 6 """ | |
| 7 from Tkinter import * | |
| 8 from tkSimpleDialog import _QueryString | |
| 9 from tkFileDialog import _Dialog | |
| 10 from twisted.spread import pb | |
| 11 from twisted.internet import reactor | |
| 12 from twisted import copyright | |
| 13 | |
| 14 import string | |
| 15 | |
| 16 #normalFont = Font("-adobe-courier-medium-r-normal-*-*-120-*-*-m-*-iso8859-1") | |
| 17 #boldFont = Font("-adobe-courier-bold-r-normal-*-*-120-*-*-m-*-iso8859-1") | |
| 18 #errorFont = Font("-adobe-courier-medium-o-normal-*-*-120-*-*-m-*-iso8859-1") | |
| 19 | |
| 20 class _QueryPassword(_QueryString): | |
| 21 def body(self, master): | |
| 22 | |
| 23 w = Label(master, text=self.prompt, justify=LEFT) | |
| 24 w.grid(row=0, padx=5, sticky=W) | |
| 25 | |
| 26 self.entry = Entry(master, name="entry",show="*") | |
| 27 self.entry.grid(row=1, padx=5, sticky=W+E) | |
| 28 | |
| 29 if self.initialvalue: | |
| 30 self.entry.insert(0, self.initialvalue) | |
| 31 self.entry.select_range(0, END) | |
| 32 | |
| 33 return self.entry | |
| 34 | |
| 35 def askpassword(title, prompt, **kw): | |
| 36 '''get a password from the user | |
| 37 | |
| 38 @param title: the dialog title | |
| 39 @param prompt: the label text | |
| 40 @param **kw: see L{SimpleDialog} class | |
| 41 | |
| 42 @returns: a string | |
| 43 ''' | |
| 44 d = apply(_QueryPassword, (title, prompt), kw) | |
| 45 return d.result | |
| 46 | |
| 47 def grid_setexpand(widget): | |
| 48 cols,rows=widget.grid_size() | |
| 49 for i in range(cols): | |
| 50 widget.columnconfigure(i,weight=1) | |
| 51 for i in range(rows): | |
| 52 widget.rowconfigure(i,weight=1) | |
| 53 | |
| 54 class CList(Frame): | |
| 55 def __init__(self,parent,labels,disablesorting=0,**kw): | |
| 56 Frame.__init__(self,parent) | |
| 57 self.labels=labels | |
| 58 self.lists=[] | |
| 59 self.disablesorting=disablesorting | |
| 60 kw["exportselection"]=0 | |
| 61 for i in range(len(labels)): | |
| 62 b=Button(self,text=labels[i],anchor=W,height=1,pady=0) | |
| 63 b.config(command=lambda s=self,i=i:s.setSort(i)) | |
| 64 b.grid(column=i,row=0,sticky=N+E+W) | |
| 65 box=apply(Listbox,(self,),kw) | |
| 66 box.grid(column=i,row=1,sticky=N+E+S+W) | |
| 67 self.lists.append(box) | |
| 68 grid_setexpand(self) | |
| 69 self.rowconfigure(0,weight=0) | |
| 70 self._callall("bind",'<Button-1>',self.Button1) | |
| 71 self._callall("bind",'<B1-Motion>',self.Button1) | |
| 72 self.bind('<Up>',self.UpKey) | |
| 73 self.bind('<Down>',self.DownKey) | |
| 74 self.sort=None | |
| 75 | |
| 76 def _callall(self,funcname,*args,**kw): | |
| 77 rets=[] | |
| 78 for l in self.lists: | |
| 79 func=getattr(l,funcname) | |
| 80 ret=apply(func,args,kw) | |
| 81 if ret!=None: rets.append(ret) | |
| 82 if rets: return rets | |
| 83 | |
| 84 def Button1(self,e): | |
| 85 index=self.nearest(e.y) | |
| 86 self.select_clear(0,END) | |
| 87 self.select_set(index) | |
| 88 self.activate(index) | |
| 89 return "break" | |
| 90 | |
| 91 def UpKey(self,e): | |
| 92 index=self.index(ACTIVE) | |
| 93 if index: | |
| 94 self.select_clear(0,END) | |
| 95 self.select_set(index-1) | |
| 96 return "break" | |
| 97 | |
| 98 def DownKey(self,e): | |
| 99 index=self.index(ACTIVE) | |
| 100 if index!=self.size()-1: | |
| 101 self.select_clear(0,END) | |
| 102 self.select_set(index+1) | |
| 103 return "break" | |
| 104 | |
| 105 def setSort(self,index): | |
| 106 if self.sort==None: | |
| 107 self.sort=[index,1] | |
| 108 elif self.sort[0]==index: | |
| 109 self.sort[1]=-self.sort[1] | |
| 110 else: | |
| 111 self.sort=[index,1] | |
| 112 self._sort() | |
| 113 | |
| 114 def _sort(self): | |
| 115 if self.disablesorting: | |
| 116 return | |
| 117 if self.sort==None: | |
| 118 return | |
| 119 ind,direc=self.sort | |
| 120 li=list(self.get(0,END)) | |
| 121 li.sort(lambda x,y,i=ind,d=direc:d*cmp(x[i],y[i])) | |
| 122 self.delete(0,END) | |
| 123 for l in li: | |
| 124 self._insert(END,l) | |
| 125 def activate(self,index): | |
| 126 self._callall("activate",index) | |
| 127 | |
| 128 # def bbox(self,index): | |
| 129 # return self._callall("bbox",index) | |
| 130 | |
| 131 def curselection(self): | |
| 132 return self.lists[0].curselection() | |
| 133 | |
| 134 def delete(self,*args): | |
| 135 apply(self._callall,("delete",)+args) | |
| 136 | |
| 137 def get(self,*args): | |
| 138 bad=apply(self._callall,("get",)+args) | |
| 139 if len(args)==1: | |
| 140 return bad | |
| 141 ret=[] | |
| 142 for i in range(len(bad[0])): | |
| 143 r=[] | |
| 144 for j in range(len(bad)): | |
| 145 r.append(bad[j][i]) | |
| 146 ret.append(r) | |
| 147 return ret | |
| 148 | |
| 149 def index(self,index): | |
| 150 return self.lists[0].index(index) | |
| 151 | |
| 152 def insert(self,index,items): | |
| 153 self._insert(index,items) | |
| 154 self._sort() | |
| 155 | |
| 156 def _insert(self,index,items): | |
| 157 for i in range(len(items)): | |
| 158 self.lists[i].insert(index,items[i]) | |
| 159 | |
| 160 def nearest(self,y): | |
| 161 return self.lists[0].nearest(y) | |
| 162 | |
| 163 def see(self,index): | |
| 164 self._callall("see",index) | |
| 165 | |
| 166 def size(self): | |
| 167 return self.lists[0].size() | |
| 168 | |
| 169 def selection_anchor(self,index): | |
| 170 self._callall("selection_anchor",index) | |
| 171 | |
| 172 select_anchor=selection_anchor | |
| 173 | |
| 174 def selection_clear(self,*args): | |
| 175 apply(self._callall,("selection_clear",)+args) | |
| 176 | |
| 177 select_clear=selection_clear | |
| 178 | |
| 179 def selection_includes(self,index): | |
| 180 return self.lists[0].select_includes(index) | |
| 181 | |
| 182 select_includes=selection_includes | |
| 183 | |
| 184 def selection_set(self,*args): | |
| 185 apply(self._callall,("selection_set",)+args) | |
| 186 | |
| 187 select_set=selection_set | |
| 188 | |
| 189 def xview(self,*args): | |
| 190 if not args: return self.lists[0].xview() | |
| 191 apply(self._callall,("xview",)+args) | |
| 192 | |
| 193 def yview(self,*args): | |
| 194 if not args: return self.lists[0].yview() | |
| 195 apply(self._callall,("yview",)+args) | |
| 196 | |
| 197 class ProgressBar: | |
| 198 def __init__(self, master=None, orientation="horizontal", | |
| 199 min=0, max=100, width=100, height=18, | |
| 200 doLabel=1, appearance="sunken", | |
| 201 fillColor="blue", background="gray", | |
| 202 labelColor="yellow", labelFont="Verdana", | |
| 203 labelText="", labelFormat="%d%%", | |
| 204 value=0, bd=2): | |
| 205 # preserve various values | |
| 206 self.master=master | |
| 207 self.orientation=orientation | |
| 208 self.min=min | |
| 209 self.max=max | |
| 210 self.width=width | |
| 211 self.height=height | |
| 212 self.doLabel=doLabel | |
| 213 self.fillColor=fillColor | |
| 214 self.labelFont= labelFont | |
| 215 self.labelColor=labelColor | |
| 216 self.background=background | |
| 217 self.labelText=labelText | |
| 218 self.labelFormat=labelFormat | |
| 219 self.value=value | |
| 220 self.frame=Frame(master, relief=appearance, bd=bd) | |
| 221 self.canvas=Canvas(self.frame, height=height, width=width, bd=0, | |
| 222 highlightthickness=0, background=background) | |
| 223 self.scale=self.canvas.create_rectangle(0, 0, width, height, | |
| 224 fill=fillColor) | |
| 225 self.label=self.canvas.create_text(self.canvas.winfo_reqwidth() / 2, | |
| 226 height / 2, text=labelText, | |
| 227 anchor="c", fill=labelColor, | |
| 228 font=self.labelFont) | |
| 229 self.update() | |
| 230 self.canvas.pack(side='top', fill='x', expand='no') | |
| 231 | |
| 232 def updateProgress(self, newValue, newMax=None): | |
| 233 if newMax: | |
| 234 self.max = newMax | |
| 235 self.value = newValue | |
| 236 self.update() | |
| 237 | |
| 238 def update(self): | |
| 239 # Trim the values to be between min and max | |
| 240 value=self.value | |
| 241 if value > self.max: | |
| 242 value = self.max | |
| 243 if value < self.min: | |
| 244 value = self.min | |
| 245 # Adjust the rectangle | |
| 246 if self.orientation == "horizontal": | |
| 247 self.canvas.coords(self.scale, 0, 0, | |
| 248 float(value) / self.max * self.width, self.height) | |
| 249 else: | |
| 250 self.canvas.coords(self.scale, 0, | |
| 251 self.height - (float(value) / | |
| 252 self.max*self.height), | |
| 253 self.width, self.height) | |
| 254 # Now update the colors | |
| 255 self.canvas.itemconfig(self.scale, fill=self.fillColor) | |
| 256 self.canvas.itemconfig(self.label, fill=self.labelColor) | |
| 257 # And update the label | |
| 258 if self.doLabel: | |
| 259 if value: | |
| 260 if value >= 0: | |
| 261 pvalue = int((float(value) / float(self.max)) * | |
| 262 100.0) | |
| 263 else: | |
| 264 pvalue = 0 | |
| 265 self.canvas.itemconfig(self.label, text=self.labelFormat | |
| 266 % pvalue) | |
| 267 else: | |
| 268 self.canvas.itemconfig(self.label, text='') | |
| 269 else: | |
| 270 self.canvas.itemconfig(self.label, text=self.labelFormat % | |
| 271 self.labelText) | |
| 272 self.canvas.update_idletasks() | |
| 273 | |
| 274 class DirectoryBrowser(_Dialog): | |
| 275 command = "tk_chooseDirectory" | |
| 276 | |
| 277 def askdirectory(**options): | |
| 278 "Ask for a directory to save to." | |
| 279 | |
| 280 return apply(DirectoryBrowser, (), options).show() | |
| 281 | |
| 282 class GenericLogin(Toplevel): | |
| 283 def __init__(self,callback,buttons): | |
| 284 Toplevel.__init__(self) | |
| 285 self.callback=callback | |
| 286 Label(self,text="Twisted v%s"%copyright.version).grid(column=0,row=0,col
umnspan=2) | |
| 287 self.entries={} | |
| 288 row=1 | |
| 289 for stuff in buttons: | |
| 290 label,value=stuff[:2] | |
| 291 if len(stuff)==3: | |
| 292 dict=stuff[2] | |
| 293 else: dict={} | |
| 294 Label(self,text=label+": ").grid(column=0,row=row) | |
| 295 e=apply(Entry,(self,),dict) | |
| 296 e.grid(column=1,row=row) | |
| 297 e.insert(0,value) | |
| 298 self.entries[label]=e | |
| 299 row=row+1 | |
| 300 Button(self,text="Login",command=self.doLogin).grid(column=0,row=row) | |
| 301 Button(self,text="Cancel",command=self.close).grid(column=1,row=row) | |
| 302 self.protocol('WM_DELETE_WINDOW',self.close) | |
| 303 | |
| 304 def close(self): | |
| 305 self.tk.quit() | |
| 306 self.destroy() | |
| 307 | |
| 308 def doLogin(self): | |
| 309 values={} | |
| 310 for k in self.entries.keys(): | |
| 311 values[string.lower(k)]=self.entries[k].get() | |
| 312 self.callback(values) | |
| 313 self.destroy() | |
| 314 | |
| 315 class Login(Toplevel): | |
| 316 def __init__(self, | |
| 317 callback, | |
| 318 referenced = None, | |
| 319 initialUser = "guest", | |
| 320 initialPassword = "guest", | |
| 321 initialHostname = "localhost", | |
| 322 initialService = "", | |
| 323 initialPortno = pb.portno): | |
| 324 Toplevel.__init__(self) | |
| 325 version_label = Label(self,text="Twisted v%s" % copyright.version) | |
| 326 self.pbReferenceable = referenced | |
| 327 self.pbCallback = callback | |
| 328 # version_label.show() | |
| 329 self.username = Entry(self) | |
| 330 self.password = Entry(self,show='*') | |
| 331 self.hostname = Entry(self) | |
| 332 self.service = Entry(self) | |
| 333 self.port = Entry(self) | |
| 334 | |
| 335 self.username.insert(0,initialUser) | |
| 336 self.password.insert(0,initialPassword) | |
| 337 self.service.insert(0,initialService) | |
| 338 self.hostname.insert(0,initialHostname) | |
| 339 self.port.insert(0,str(initialPortno)) | |
| 340 | |
| 341 userlbl=Label(self,text="Username:") | |
| 342 passlbl=Label(self,text="Password:") | |
| 343 servicelbl=Label(self,text="Service:") | |
| 344 hostlbl=Label(self,text="Hostname:") | |
| 345 portlbl=Label(self,text="Port #:") | |
| 346 self.logvar=StringVar() | |
| 347 self.logvar.set("Protocol PB-%s"%pb.Broker.version) | |
| 348 self.logstat = Label(self,textvariable=self.logvar) | |
| 349 self.okbutton = Button(self,text="Log In", command=self.login) | |
| 350 | |
| 351 version_label.grid(column=0,row=0,columnspan=2) | |
| 352 z=0 | |
| 353 for i in [[userlbl,self.username], | |
| 354 [passlbl,self.password], | |
| 355 [hostlbl,self.hostname], | |
| 356 [servicelbl,self.service], | |
| 357 [portlbl,self.port]]: | |
| 358 i[0].grid(column=0,row=z+1) | |
| 359 i[1].grid(column=1,row=z+1) | |
| 360 z = z+1 | |
| 361 | |
| 362 self.logstat.grid(column=0,row=6,columnspan=2) | |
| 363 self.okbutton.grid(column=0,row=7,columnspan=2) | |
| 364 | |
| 365 self.protocol('WM_DELETE_WINDOW',self.tk.quit) | |
| 366 | |
| 367 def loginReset(self): | |
| 368 self.logvar.set("Idle.") | |
| 369 | |
| 370 def loginReport(self, txt): | |
| 371 self.logvar.set(txt) | |
| 372 self.after(30000, self.loginReset) | |
| 373 | |
| 374 def login(self): | |
| 375 host = self.hostname.get() | |
| 376 port = self.port.get() | |
| 377 service = self.service.get() | |
| 378 try: | |
| 379 port = int(port) | |
| 380 except: | |
| 381 pass | |
| 382 user = self.username.get() | |
| 383 pswd = self.password.get() | |
| 384 pb.connect(host, port, user, pswd, service, | |
| 385 client=self.pbReferenceable).addCallback(self.pbCallback).add
Errback( | |
| 386 self.couldNotConnect) | |
| 387 | |
| 388 def couldNotConnect(self,f): | |
| 389 self.loginReport("could not connect:"+f.getErrorMessage()) | |
| 390 | |
| 391 if __name__=="__main__": | |
| 392 root=Tk() | |
| 393 o=CList(root,["Username","Online","Auto-Logon","Gateway"]) | |
| 394 o.pack() | |
| 395 for i in range(0,16,4): | |
| 396 o.insert(END,[i,i+1,i+2,i+3]) | |
| 397 mainloop() | |
| OLD | NEW |