~certify-web-dev/twisted/certify-trunk

« back to all changes in this revision

Viewing changes to twisted/scripts/tkmktap.py

  • Committer: Bazaar Package Importer
  • Author(s): Matthias Klose
  • Date: 2007-01-17 14:52:35 UTC
  • mfrom: (1.1.5 upstream) (2.1.2 etch)
  • Revision ID: james.westby@ubuntu.com-20070117145235-btmig6qfmqfen0om
Tags: 2.5.0-0ubuntu1
New upstream version, compatible with python2.5.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
 
2
 
# Copyright (c) 2001-2004 Twisted Matrix Laboratories.
3
 
# See LICENSE for details.
4
 
 
5
 
#
6
 
 
7
 
"""Implementation module for the graphical version of the `mktap` command.
8
 
"""
9
 
 
10
 
# System imports
11
 
import Tkinter, tkMessageBox, tkFileDialog, StringIO, os
12
 
import traceback
13
 
 
14
 
# Twisted imports
15
 
from twisted.application import service
16
 
from twisted.internet import tksupport, reactor
17
 
from twisted.scripts import mktap
18
 
from twisted.python import usage, reflect
19
 
from twisted.copyright import version
20
 
 
21
 
 
22
 
class TkMkAppFrame(Tkinter.Frame):
23
 
    """
24
 
    A frame with all the necessary widgets to configure a Twisted Application.
25
 
    """
26
 
 
27
 
    # Plugin currently selected
28
 
    coil = None
29
 
    
30
 
    # Options instance currently displayed
31
 
    options = None
32
 
 
33
 
    # Frame options are displayed in
34
 
    optFrame = None
35
 
 
36
 
    def __init__(self, master, coil):
37
 
        Tkinter.Frame.__init__(self, master)
38
 
 
39
 
        self.setupMkTap()
40
 
        self.reset(coil)
41
 
 
42
 
 
43
 
    def setupMkTap(self):
44
 
        # Create all of the "mktap" option widgets
45
 
        appFrame = Tkinter.Frame(self)
46
 
 
47
 
        f = Tkinter.Frame(appFrame)
48
 
        listLabel = Tkinter.Label(f, text='TAp Format')
49
 
        self.typeList = Tkinter.Listbox(f, background='white')
50
 
        self.typeList['height'] = 3
51
 
        for t in ('pickle', 'xml', 'source'):
52
 
            self.typeList.insert(Tkinter.END, t)
53
 
        self.typeList.selection_set(0)
54
 
 
55
 
        listLabel.pack(side=Tkinter.TOP)
56
 
        self.typeList.pack(side=Tkinter.TOP)
57
 
        f.pack(side=Tkinter.LEFT, anchor=Tkinter.N)
58
 
 
59
 
        f = Tkinter.Frame(appFrame)
60
 
        tapLabel = Tkinter.Label(f, text='TAp Filename')
61
 
        tapButton = Tkinter.Button(f, text="Choose", command=self.pickTapFile)
62
 
        self.tapfile = Tkinter.Entry(f, background='white')
63
 
 
64
 
        tapLabel.pack(side=Tkinter.LEFT)
65
 
        self.tapfile.pack(side=Tkinter.LEFT)
66
 
        tapButton.pack(side=Tkinter.LEFT)
67
 
        f.pack(side=Tkinter.TOP, anchor=Tkinter.E)
68
 
 
69
 
        f = Tkinter.Frame(appFrame)
70
 
        nameLabel = Tkinter.Label(f, text='Application Process Name')
71
 
        self.appname = Tkinter.Entry(f, background='white')
72
 
 
73
 
        nameLabel.pack(side=Tkinter.LEFT)
74
 
        self.appname.pack(side=Tkinter.LEFT)
75
 
        f.pack(side=Tkinter.TOP, anchor=Tkinter.E)
76
 
 
77
 
        f = Tkinter.Frame(appFrame)
78
 
        encLabel = Tkinter.Label(f, text='Passphrase')
79
 
        self.passphrase = Tkinter.Entry(f, background='white')
80
 
 
81
 
        encLabel.pack(side=Tkinter.LEFT)
82
 
        self.passphrase.pack(side=Tkinter.LEFT)
83
 
        f.pack(side=Tkinter.TOP, anchor=Tkinter.E)
84
 
 
85
 
        f = Tkinter.Frame(appFrame)
86
 
        self.append = Tkinter.BooleanVar()
87
 
        appLabel = Tkinter.Label(f, text='Append')
88
 
        appButton = Tkinter.Checkbutton(f, variable=self.append)
89
 
 
90
 
        appLabel.pack(side=Tkinter.LEFT)
91
 
        appButton.pack(side=Tkinter.LEFT)
92
 
        f.pack(side=Tkinter.LEFT, anchor=Tkinter.E)
93
 
 
94
 
        f = Tkinter.Frame(appFrame)
95
 
        s = Tkinter.StringVar()
96
 
        s.set(not hasattr(os, 'getuid') and '0' or str(os.getuid()))
97
 
        uidLabel = Tkinter.Label(f, text='UID')
98
 
        self.uid = Tkinter.Entry(f, text=s, background='white')
99
 
 
100
 
        uidLabel.pack(side=Tkinter.LEFT)
101
 
        self.uid.pack(side=Tkinter.LEFT)
102
 
        f.pack(side=Tkinter.BOTTOM)
103
 
 
104
 
        f = Tkinter.Frame(appFrame)
105
 
        s = Tkinter.StringVar()
106
 
        s.set(not hasattr(os, 'getgid') and '0' or str(os.getgid()))
107
 
        gidLabel = Tkinter.Label(f, text='GID')
108
 
        self.gid = Tkinter.Entry(f, text=s, background='white')
109
 
 
110
 
        gidLabel.pack(side=Tkinter.LEFT)
111
 
        self.gid.pack(side=Tkinter.LEFT)
112
 
        f.pack(side=Tkinter.BOTTOM)
113
 
 
114
 
        appFrame.grid(row=0, column=0, columnspan=3, sticky=Tkinter.N + Tkinter.S)
115
 
 
116
 
 
117
 
    def pickTapFile(self):
118
 
        r = tkFileDialog.askopenfilename()
119
 
        if r:
120
 
            self.tapfile.delete(0, Tkinter.END)
121
 
            self.tapfile.insert(Tkinter.END, r)
122
 
 
123
 
 
124
 
    def reset(self, coil):
125
 
        """
126
 
        Remove the existing coil-specific widgets and then create and add
127
 
        new ones based on the given plugin object.
128
 
        """
129
 
        if coil is self.coil:
130
 
            return
131
 
 
132
 
        try:
133
 
            opt = coil.load().Options()
134
 
        except:
135
 
            f = StringIO.StringIO()
136
 
            traceback.print_exc(file=f)
137
 
            # XXX - Why is this so narrow?
138
 
            tkMessageBox.showerror(title="Options Error", message=f.getvalue(), parent=self)
139
 
            return
140
 
 
141
 
        if self.optFrame:
142
 
            self.optFrame.forget()
143
 
            self.optFrame.destroy()
144
 
            self.optFrame = None
145
 
 
146
 
        self.coil = coil
147
 
        self.options = opt
148
 
        self.optFrame = TkConfigFrame(self, self.options)
149
 
        self.optFrame.grid(row=1, column=0)
150
 
 
151
 
#        self.tapfile.delete(0, Tkinter.END)
152
 
#        try:
153
 
#            self.tapfile.insert(Tkinter.END, self.coil.tapname)
154
 
#        except AttributeError:
155
 
#            self.tapfile.insert(Tkinter.END, self.coil.name)
156
 
    
157
 
    
158
 
    def copyOptions(self):
159
 
        # Snarf the data out of the widgets and place them into the Options
160
 
        # instance.
161
 
        extra = self.optFrame.updateConfig(self.options)
162
 
    
163
 
        self.options['filename'] = self.tapfile.get()
164
 
        self.options['appname'] = self.appname.get()
165
 
        self.options['passphrase'] = self.passphrase.get()
166
 
 
167
 
        self.options['append'] = self.append.get()
168
 
        self.options['encrypted'] = len(self.options['passphrase'])
169
 
 
170
 
        self.options['uid'] = int(self.uid.get())
171
 
        self.options['gid'] = int(self.gid.get())
172
 
        
173
 
        try:
174
 
            self.options['type'] = self.typeList.curselection()[0]
175
 
        except IndexError:
176
 
            raise usage.UsageError("Select a TAp Format")
177
 
        self.options['help'] = 0
178
 
        
179
 
        if extra:
180
 
            try:
181
 
                # XXX - this is wrong.  It needs to respect quotes, etc.
182
 
                self.options.parseArgs(extra.split())
183
 
            except TypeError:
184
 
                raise usage.UsageError("Wrong number of extra arguments")
185
 
        self.options.postOptions()
186
 
 
187
 
 
188
 
    def createApplication(self):
189
 
        if not self.options:
190
 
            tkMessageBox.showerror(message="Select an Application first")
191
 
            return
192
 
 
193
 
        try:
194
 
            self.copyOptions()
195
 
        except usage.UsageError, e:
196
 
            tkMessageBox.showerror(message=str(e))
197
 
            return
198
 
 
199
 
        exists = os.path.exists(self.options['filename'])
200
 
        if self.options['append'] and exists:
201
 
            a = service.loadApplication(
202
 
                self.options['filename'],
203
 
                self.options['type'],
204
 
                self.options['passphrase']
205
 
            )
206
 
        else:
207
 
            if exists:
208
 
                overwrite = tkMessageBox.askyesno(title='File Exists', message='Overwrite?')
209
 
                if not overwrite:
210
 
                    return
211
 
            a = service.Application(self.coil.name, self.options['uid'], self.options['gid'])
212
 
 
213
 
        try:
214
 
            s = mktap.makeService(
215
 
                self.coil.load(),
216
 
                self.options['appname'],
217
 
                self.options
218
 
            )
219
 
        except usage.UsageError:
220
 
            f = StringIO.StringIO()
221
 
            traceback.print_stack(file=f)
222
 
            tkMessageBox.showerror(title="Usage Error", message=f.getvalue(), parent=self)
223
 
        else:
224
 
            try:
225
 
                mktap.addToApplication(
226
 
                    s, self.coil.name, self.options['append'],
227
 
                    self.options['appname'], self.options['type'],
228
 
                    self.options['encrypted'], self.options['uid'],
229
 
                    self.options['gid'],
230
 
                )
231
 
            except:
232
 
                f = StringIO.StringIO()
233
 
                traceback.print_exc(file=f)
234
 
                print f.getvalue()
235
 
                tkMessageBox.showerror(title="Usage Error", message=f.getvalue(), parent=self)
236
 
            else:
237
 
                filename = self.options['filename']
238
 
                if not filename:
239
 
                    filename = self.coil.name
240
 
                tkMessageBox.showinfo(message="Wrote " + filename)
241
 
 
242
 
 
243
 
    def destroy(self):
244
 
        reactor.crash()
245
 
        Tkinter.Frame.destroy(self)
246
 
 
247
 
 
248
 
#
249
 
# This class was written based on code from Drew "drewp" Pertulla
250
 
# (<drewp (at) bigasterisk (dot) com>) - without his help, tkmktap
251
 
# would be an ugly POS.
252
 
#
253
 
class ParameterLine(Tkinter.Frame):
254
 
    def __init__(self, master, lines, label, desc, default, cmd, **kw):
255
 
        Tkinter.Frame.__init__(self, master, relief='raised', bd=1, **kw)
256
 
        
257
 
        self.lines = lines
258
 
 
259
 
        l = Tkinter.Label(
260
 
            self, text=label, wraplen=200,
261
 
            width=30, anchor='w', justify='left'
262
 
        )
263
 
 
264
 
        s = Tkinter.StringVar()
265
 
        if default:
266
 
            s.set(default)
267
 
        self.entry = Tkinter.Entry(self, text=s, background='white')
268
 
        self.flag = label
269
 
 
270
 
        more = Tkinter.Button(
271
 
            self, text='+',
272
 
            command=lambda f = cmd, a = label, b = default, c = desc: f(a, b, c)
273
 
        )
274
 
 
275
 
        l.pack(side=Tkinter.LEFT, fill='y')
276
 
        self.entry.pack(side=Tkinter.LEFT)
277
 
        more.pack(side=Tkinter.LEFT)
278
 
 
279
 
        l.bind("<Enter>", self.highlight)
280
 
        l.bind("<Leave>", self.unhighlight)
281
 
 
282
 
        l.bind("<ButtonPress-1>", self.press)
283
 
        l.bind("<B1-ButtonRelease>", self.release)
284
 
        l.bind("<B1-Motion>", self.motion)
285
 
 
286
 
 
287
 
    def highlight(self, ev, hicolor = 'gray90'):
288
 
        # make the label light up when you mouseover
289
 
        ev.widget._oldcolor = self.cget('bg')
290
 
        ev.widget.config(bg=hicolor)
291
 
 
292
 
 
293
 
    def unhighlight(self, ev):
294
 
        # make the label return to its old setting
295
 
        try:
296
 
            ev.widget.config(bg=ev.widget._oldcolor)
297
 
            del ev.widget._oldcolor
298
 
        except:
299
 
            pass
300
 
 
301
 
 
302
 
    # make the frame change order when you drag it (by its label)
303
 
    def press(self, ev):
304
 
        # save old attrs
305
 
        self._oldrelief = self.cget('relief'), self.cget('bd')
306
 
        # thicken the border
307
 
        self.config(relief='raised', bd=3)
308
 
    
309
 
    
310
 
    def motion(self, ev):
311
 
        this = self.lines.index(self)
312
 
        framey = ev.y + self.winfo_y()   # get mouse y coord in parent frame
313
 
        replace = this   # replace will be the index of the row to swap with
314
 
        for i, l in zip(range(len(self.lines)), self.lines):
315
 
            y1 = l.winfo_y()
316
 
            y2 = y1 + l.winfo_height()
317
 
            if y1 < framey < y2:
318
 
                replace = i
319
 
        if replace != this:
320
 
            # we moved over another row-- swap them
321
 
            self.lines[replace], self.lines[this] = self.lines[this], self.lines[replace]
322
 
 
323
 
            # and re-assign all rows in the new order
324
 
            for i, l in zip(range(len(self.lines)), self.lines):
325
 
                l.grid(row=i, column=0)
326
 
 
327
 
 
328
 
    def release(self, ev):
329
 
        # restore the old border width
330
 
        try:
331
 
            rel, bd = self._oldrelief
332
 
            self.config(relief=rel, bd=bd)
333
 
            del self._oldrelief
334
 
        except:
335
 
            pass
336
 
 
337
 
 
338
 
class TkConfigFrame(Tkinter.Frame):
339
 
    optFrame = None
340
 
    paramFrame = None
341
 
    commandFrame = None
342
 
 
343
 
    subCmdFrame = None
344
 
    previousCommand = None
345
 
 
346
 
    optFlags = None
347
 
    paramLines = None
348
 
    
349
 
    def __init__(self, master, options):
350
 
        Tkinter.Frame.__init__(self, master)
351
 
        self.options = options
352
 
        
353
 
        self.setupOptFlags()
354
 
        self.setupOptParameters()
355
 
        self.setupSubCommands()
356
 
        self.setupExtra()
357
 
 
358
 
 
359
 
    def getOptFlags(self):
360
 
        return self.optFlags
361
 
    
362
 
    
363
 
    def getOptParameters(self):
364
 
        r = []
365
 
        for p in self.paramLines:
366
 
            r.append((p.flag, p.entry.get()))
367
 
        return r
368
 
 
369
 
 
370
 
    def updateConfig(self, options):
371
 
        for (opt, var) in self.getOptFlags():
372
 
            var = var.get()
373
 
 
374
 
            if not var:
375
 
                continue # XXX - this is poor - add a '-' button to remove options 
376
 
 
377
 
            f = getattr(options, 'opt_' + opt, None)
378
 
            if f:
379
 
                f()
380
 
            else:
381
 
                options[opt] = var
382
 
 
383
 
        for (opt, var) in self.getOptParameters():
384
 
 
385
 
            if not var:
386
 
                continue # XXX - this is poor - add a '-' button to remove options 
387
 
 
388
 
            f = getattr(options, 'opt_' + opt, None)
389
 
            if f:
390
 
                f(var)
391
 
            else:
392
 
                options[opt] = var
393
 
        return self.extra.get()
394
 
 
395
 
 
396
 
    def setupOptFlags(self):
397
 
        self.optFlags = []
398
 
        flags = []
399
 
        if hasattr(self.options, 'optFlags'):
400
 
            flags.extend(self.options.optFlags)
401
 
 
402
 
        d = {}
403
 
        soFar = {}
404
 
        for meth in reflect.prefixedMethodNames(self.options.__class__, 'opt_'):
405
 
            full = 'opt_' + meth
406
 
            func = getattr(self.options, full)
407
 
 
408
 
            if not usage.flagFunction(func) or meth in ('help', 'version'):
409
 
                continue
410
 
            
411
 
            if soFar.has_key(func):
412
 
                continue
413
 
            soFar[func] = 1
414
 
            
415
 
            existing = d.setdefault(func, meth)
416
 
            if existing != meth:
417
 
                if len(existing) < len(meth):
418
 
                    d[func] = meth
419
 
            
420
 
            for (func, name) in d.items():
421
 
                flags.append((name, None, func.__doc__))
422
 
            
423
 
            if len(flags):
424
 
                self.optFrame = f = Tkinter.Frame(self)
425
 
                for (flag, _, desc) in flags:
426
 
                    b = Tkinter.BooleanVar()
427
 
                    c = Tkinter.Checkbutton(f, text=desc, variable=b, wraplen=200)
428
 
                    c.pack(anchor=Tkinter.W)
429
 
                    self.optFlags.append((flag, b))
430
 
                f.grid(row=1, column=1)
431
 
 
432
 
 
433
 
    def setupOptParameters(self):
434
 
        params = []
435
 
        if hasattr(self.options, 'optParameters'):
436
 
            params.extend(self.options.optParameters)
437
 
 
438
 
        d = {}
439
 
        soFar = {}
440
 
        for meth in reflect.prefixedMethodNames(self.options.__class__, 'opt_'):
441
 
            full = 'opt_' + meth
442
 
            func = getattr(self.options, full)
443
 
 
444
 
            if usage.flagFunction(func) or soFar.has_key(func):
445
 
                continue
446
 
            
447
 
            soFar[func] = 1
448
 
 
449
 
            existing = d.setdefault(func, meth)
450
 
            if existing != meth:
451
 
                if len(existing) < len(meth):
452
 
                    d[func] = meth
453
 
        for (func, name) in d.items():
454
 
            params.append((name, None, None, func.__doc__))
455
 
 
456
 
        if len(params):
457
 
            self.paramFrame = Tkinter.Frame(self)
458
 
            self.paramLines = []
459
 
            for (flag, _, default, desc) in params:
460
 
                try:
461
 
                    default = self.options[flag]
462
 
                except KeyError:
463
 
                    pass
464
 
                self.makeField(flag, default, desc)
465
 
            self.paramFrame.grid(row=1, column=2)
466
 
 
467
 
 
468
 
 
469
 
    def makeField(self, flag, default, desc):
470
 
        line = ParameterLine(
471
 
            self.paramFrame, self.paramLines, flag, desc, default,
472
 
            cmd=self.makeField
473
 
        )
474
 
        self.paramLines.append(line)
475
 
        line.grid(row=len(self.paramLines), column=0)
476
 
 
477
 
 
478
 
    def setupSubCommands(self):
479
 
        self.optMap = {}
480
 
        if hasattr(self.options, 'subCommands'):
481
 
            self.commandFrame = f = Tkinter.Frame(self)
482
 
            self.cmdList = Tkinter.Listbox(f)
483
 
            for (cmd, _, opt, desc) in self.options.subCommands:
484
 
                self.cmdList.insert(Tkinter.END, cmd)
485
 
                self.optMap[cmd] = opt()
486
 
            self.cmdList.pack()
487
 
            self.subCmdPoll = reactor.callLater(0.1, self.pollSubCommands)
488
 
            f.grid(row=1, column=3)
489
 
 
490
 
 
491
 
    def setupExtra(self):
492
 
        f = Tkinter.Frame(self)
493
 
        l = Tkinter.Label(f, text='Extra Options')
494
 
        self.extra = Tkinter.Entry(f, background='white')
495
 
        l.pack()
496
 
        self.extra.pack(fill='y')
497
 
        f.grid(row=2, column=1, columnspan=2)
498
 
 
499
 
 
500
 
    def pollSubCommands(self):
501
 
        s = self.cmdList.curselection()
502
 
        if len(s):
503
 
            s = s[0]
504
 
            if s != self.previousCommand:
505
 
                if self.subOptFrame:
506
 
                    self.subOptFrame.forget()
507
 
                    self.subOptFrame.destroy()
508
 
                    self.subOptFrame = TkConfigFrame(self.commandFrame, self.optMap[s])
509
 
                    self.subOptFrame.pack()
510
 
        self.subCmdPoll = reactor.callLater(0.1, self.pollSubCommands)
511
 
    
512
 
    
513
 
class TkAppMenu(Tkinter.Menu):
514
 
    def __init__(self, master, create, callback, items):
515
 
        Tkinter.Menu.__init__(self, master)
516
 
 
517
 
        cmdMenu = Tkinter.Menu(self)
518
 
        self.add_cascade(label="Actions", menu=cmdMenu)
519
 
        
520
 
        cmdMenu.add_command(label='Create', command=create)
521
 
        cmdMenu.add_separator()
522
 
        cmdMenu.add_command(label='Quit', command=reactor.crash)
523
 
 
524
 
        tapMenu = Tkinter.Menu(self)
525
 
        self.add_cascade(label="Applications", menu=tapMenu)
526
 
 
527
 
        for item in items:
528
 
            tapMenu.add_command(
529
 
                label=item, command=lambda i=item, c = callback: c(i)
530
 
            )
531
 
 
532
 
 
533
 
def run():
534
 
    taps = mktap.loadPlugins()
535
 
    r = Tkinter.Tk()
536
 
    r.withdraw()
537
 
    
538
 
    keyList = taps.keys()
539
 
    keyList.sort()
540
 
 
541
 
    config = TkMkAppFrame(r, None)
542
 
    menu = TkAppMenu(
543
 
        r,
544
 
        config.createApplication,
545
 
        lambda i, d = taps, c = config: c.reset(d[i]),
546
 
        keyList
547
 
    )
548
 
 
549
 
    config.pack()
550
 
    r['menu'] = menu
551
 
 
552
 
    r.title('Twisted Application Maker ' + version)
553
 
    r.deiconify()
554
 
    tksupport.install(r)
555
 
    reactor.run()
556
 
 
557
 
if __name__ == '__main__':
558
 
    run()