1#!/usr/bin/env python
2
3# This is a rough collection of tests that can not be automated.
4# To add a new test, create a function with name ending in '_test'.
5
6import os
7import string
8import time
9import sys
10import Test
11import Tkinter
12import Pmw
13
14# ----------------------------------------------------------------------
15
16def scrolledframeflashing_test():
17    # Script which demonstrates continuous flashing of dynamic scrollbars
18    # in Pmw.ScrolledFrame.
19    #
20    # When this script is run, the two scrollbars will be continuously
21    # mapped and unmapped and the window will continuously change size.
22
23    frame = Tkinter.Frame(root)
24    frame.pack(fill = 'both', expand = 1)
25
26    sf = Pmw.ScrolledFrame(frame, borderframe = 0)
27    sf.pack(fill = 'both', expand = 1)
28
29    inner = Tkinter.Frame(sf.interior(),
30            width = 401,
31            height = 300,
32            borderwidth = 0,
33            highlightthickness = 0,
34    )
35    inner.pack(fill = 'both', expand = 1)
36
37# ----------------------------------------------------------------------
38
39def scrolledlistboxflashing_test():
40    # Script which demonstrates continuous flashing of dynamic scrollbars
41    # in Pmw.ScrolledListBox.
42    #
43    # When this script is run, the two scrollbars will be continuously
44    # mapped and unmapped and the window will continuously change size.
45
46    frame = Tkinter.Frame(root)
47    frame.pack(fill = 'both', expand = 1)
48
49    sf = Pmw.ScrolledListBox(frame,
50            listbox_width = 20,
51            listbox_height = 10
52    )
53    sf.pack(fill = 'both', expand = 1)
54    for i in range(11):
55        sf.insert('end', '2' * 20)
56
57# ----------------------------------------------------------------------
58
59def scrolledlistboxflashing2_test():
60    # Another script which demonstrates continuous flashing of dynamic
61    # scrollbars in Pmw.ScrolledListBox under Pmw.0.8.
62    #
63    # When this script is run, the two scrollbars will be continuously
64    # mapped and unmapped and the window will continuously change size.
65    #
66    # (This did not display error when tried with Pmw.0.8, 99/8/3)
67
68    def insert():
69        sectionList = ['1', '2', '3', '4', '5', '6', '7', '8', '9',
70            '123456789012345678901']
71        for counter in sectionList:
72          slb.insert('end', counter)
73
74    def clear():
75        slb.delete(0, 'end')
76
77    global slb
78    slb = Pmw.ScrolledListBox(root)
79    slb.pack()
80
81    root.after(2000,insert)
82    root.after(3000,clear)
83    root.after(4000,insert)
84
85    root.geometry('400x400')
86
87# ----------------------------------------------------------------------
88
89def scrolledtextflashing_test():
90    # Script which demonstrates continuous flashing of dynamic scrollbars
91    # in Pmw.ScrolledText.
92    #
93    # When this script is run, the two scrollbars will be continuously
94    # mapped and unmapped and the window will continuously change size.
95
96    frame = Tkinter.Frame(root)
97    frame.pack(fill = 'both', expand = 1)
98
99    sf = Pmw.ScrolledText(frame,
100            text_width = 20,
101            text_height = 10,
102            text_wrap = 'none',
103            borderframe = 0
104    )
105    sf.pack(fill = 'both', expand = 1)
106    for i in range(11):
107        sf.insert('end', '2' * 20)
108        if i != 10:
109            sf.insert('end', '\n')
110
111# ----------------------------------------------------------------------
112
113def scrolledcanvasflashing_test():
114    # Script which demonstrates continuous flashing of dynamic scrollbars
115    # in Pmw.ScrolledCanvas.
116    #
117    # When this script is run, the two scrollbars will be continuously
118    # mapped and unmapped and the window will continuously change size.
119
120    frame = Tkinter.Frame(root)
121    frame.pack(fill = 'both', expand = 1)
122
123    sf = Pmw.ScrolledCanvas(frame,
124            canvas_scrollregion = (0, 0, 301, 200),
125            canvas_width=300,
126            canvas_height=200,
127            borderframe = 0
128    )
129    sf.pack(fill = 'both', expand = 1)
130
131# ----------------------------------------------------------------------
132
133def scrolledframeflashing2_test():
134    # The two scrollbars will be continuously mapped and unmapped, but
135    # the toplevel window will remain the same size.
136
137    root.geometry('550x500')
138
139    frame = Tkinter.Frame()
140    frame.pack()
141
142    sf = Pmw.ScrolledFrame(frame, borderframe = 0)
143    sf.pack(fill = 'both')
144
145    inner = Tkinter.Frame(sf.interior(),
146            width = 401,
147            height = 300,
148            borderwidth = 0,
149            highlightthickness = 0,
150    )
151    inner.pack()
152
153# ----------------------------------------------------------------------
154
155def reinitialise_test():
156    global text
157    text = """
158    Demonstrates bug in Pmw.0.8.1 and earlier.
159    Click on this button, click on OK in the dialog, then Exit below.
160    When this window appears again, clicking on this button gives
161    an error:
162    TclError: can't invoke "wm" command:  application has been destroyed
163    """
164    class test:
165        def __init__(self):
166            root = Tkinter.Tk()
167            Pmw.initialise(root)
168            self.messagedialog = Pmw.MessageDialog(message_text = 'Testing')
169            self.messagedialog.withdraw()
170            button = Tkinter.Button(
171                    text = text, command = self.messagedialog.activate)
172            button.pack(pady = 20)
173            exit = Tkinter.Button(text = 'Exit', command = root.destroy)
174            exit.pack(pady = 20)
175            root.mainloop()
176
177    test()
178    test()
179
180# ----------------------------------------------------------------------
181
182def componentgroup_test():
183    def addbutton(bb):
184        bb.configure(Button_background = 'yellow')
185        bb.add('Apples')
186        bb.after(3000, lambda bb = bb:
187                bb.configure(Button_background = 'green'))
188
189    bb = Pmw.ButtonBox(Button_background = 'red')
190    bb.add('Bananas')
191    bb.pack()
192
193    mb = Pmw.MenuBar(Button_background = 'red')
194    mb.configure(Button_background = 'yellow')
195    mb.pack()
196
197    pw = Pmw.PanedWidget(Frame_background = 'red')
198    pw.configure(Frame_background = 'yellow')
199    pw.pack()
200
201    rs = Pmw.RadioSelect(Button_background = 'red')
202    rs.configure(Button_background = 'yellow')
203    rs.pack()
204
205    bb.after(3000, lambda bb = bb, addbutton = addbutton: addbutton(bb))
206
207# ----------------------------------------------------------------------
208
209def balloon_test():
210
211    # TODO
212
213    # Test that the balloon does not reappear if the mouse button is
214    # pressed down inside a widget and then, while the mouse button is
215    # being held down, the mouse is moved outside of the widget and
216    # then moved back over the widget.
217
218    # Test that when a widget is destroyed while a balloon is being
219    # displayed for it then the balloon is withdrawn.
220
221    # Test that when a widget is destroyed while a balloon is being
222    # displayed for another widget then the balloon is not withdrawn.
223
224    # Test that there is no eror when a widget is destroyed during the
225    # initwait period (between when the mouse enters the widget and
226    # when the initwait timer goes off).
227
228    # Test that if unbind() is called on a widget that triggered the
229    # balloon to be displayed then the balloon is withdrawn.  Also
230    # test that if another widget triggered the balloon then the
231    # balloon is not withdrawn.
232
233    # Test that if tagunbind() is called on a canvas or text item that
234    # triggered the balloon to be displayed then the balloon is
235    # withdrawn.  Also test that if another widget or item triggered
236    # the balloon then the balloon is not withdrawn.
237
238    pass
239
240# ----------------------------------------------------------------------
241
242# A class which prints out a message when an instance is deleted.
243class MyToplevel(Tkinter.Toplevel):
244
245    def __init__(self):
246        Tkinter.Toplevel.__init__(self)
247
248    def __del__(self):
249        print 'Window deleted'
250
251def _runMemoryLeakTest():
252    global top
253    top = MyToplevel()
254    Pmw.MegaToplevel(top)
255    Pmw.AboutDialog(top)
256    Pmw.ComboBoxDialog(top)
257    Pmw.CounterDialog(top)
258    Pmw.Dialog(top)
259    Pmw.MessageDialog(top)
260    Pmw.PromptDialog(top)
261    Pmw.SelectionDialog(top)
262    Pmw.TextDialog(top)
263
264    Pmw.ButtonBox(top).pack()
265    Pmw.ComboBox(top).pack()
266    Pmw.Counter(top).pack()
267    Pmw.EntryField(top).pack()
268    Pmw.Group(top).pack()
269    Pmw.LabeledWidget(top).pack()
270    Pmw.MenuBar(top).pack()
271    Pmw.MessageBar(top).pack()
272    Pmw.NoteBook(top).pack()
273    Pmw.OptionMenu(top).pack()
274    Pmw.PanedWidget(top).pack()
275    Pmw.RadioSelect(top).pack()
276    Pmw.ScrolledCanvas(top).pack()
277    Pmw.ScrolledField(top).pack()
278    Pmw.ScrolledFrame(top).pack()
279    Pmw.ScrolledListBox(top).pack()
280    Pmw.ScrolledText(top).pack()
281    Pmw.TimeCounter(top).pack()
282
283def _killMemoryLeakTest():
284    global top
285    top.destroy()
286    del top
287
288memoryLeakMessage = """
289Click on the "Run test" button to create instances of
290all Pmw megawidgets. Then click on the "Destroy" button.
291The message "Window deleted" should be printed to
292standard output.
293"""
294def memoryleak_test():
295    label = Tkinter.Label(text = memoryLeakMessage)
296    label.pack()
297    run = Tkinter.Button(text = 'Run test', command = _runMemoryLeakTest)
298    run.pack()
299    kill = Tkinter.Button(text = 'Destroy', command = _killMemoryLeakTest)
300    kill.pack()
301
302# ----------------------------------------------------------------------
303
304def memoryleak2_test():
305
306    print 'This test continuously creates and deletes megawidgets and'
307    print 'their components.  It calls the "top" program, so'
308    print 'may not work on non-Unix operating systems. Run it for a long,'
309    print 'long time and check that the process memory size does not'
310    print 'continue to increase.  Kill with <Control-C>.'
311
312    pid = os.getpid()
313
314    label = Tkinter.Label()
315    label.pack()
316
317    # Setup each test:
318
319    # 1. Create/delete all megawidgets:
320    megawidgets = (
321        Pmw.AboutDialog, Pmw.Balloon, Pmw.ButtonBox, Pmw.ComboBox,
322        Pmw.ComboBoxDialog, Pmw.Counter, Pmw.CounterDialog, Pmw.Dialog,
323        Pmw.EntryField, Pmw.Group, Pmw.HistoryText, Pmw.LabeledWidget,
324        Pmw.MainMenuBar, Pmw.MenuBar, Pmw.MessageBar, Pmw.MessageDialog,
325        Pmw.NoteBook, Pmw.OptionMenu, Pmw.PanedWidget, Pmw.PromptDialog,
326        Pmw.RadioSelect, Pmw.ScrolledCanvas, Pmw.ScrolledField,
327        Pmw.ScrolledFrame, Pmw.ScrolledListBox, Pmw.ScrolledText,
328        Pmw.SelectionDialog, Pmw.TextDialog, Pmw.TimeCounter,
329    )
330
331    # 2. Balloon binding:
332    toplevel = Tkinter.Toplevel()
333    balloon = Pmw.Balloon(toplevel)
334    button = Tkinter.Button(toplevel)
335    button.pack()
336    canvas = Tkinter.Canvas(toplevel)
337    item = canvas.create_rectangle(0, 0, 100, 100)
338    canvas.pack()
339
340    # 3. Adding and deleting menu:
341    toplevel = Tkinter.Toplevel()
342    mainmenu = Pmw.MainMenuBar(toplevel)
343    mainmenu.addmenu('Foo', 'help')
344    toplevel.configure(menu = mainmenu)
345
346    # 4. Adding and deleting notebook page:
347    toplevel = Tkinter.Toplevel()
348    notebook = Pmw.NoteBook(toplevel)
349    notebook.pack()
350
351    # 5. Adding and deleting panedwidget pane:
352    toplevel = Tkinter.Toplevel()
353    panedwidget = Pmw.PanedWidget(toplevel)
354    panedwidget.pack()
355    panedwidget.insert('Foo', size = 100)
356
357    # 6. Adding and deleting MenuBar menu:
358    toplevel = Tkinter.Toplevel()
359    menubar = Pmw.MenuBar(toplevel)
360    menubar.pack()
361
362    # 7. Setting OptionMenu items:
363    toplevel = Tkinter.Toplevel()
364    optionmenu = Pmw.OptionMenu(toplevel, items = ('XXX', 'YYY', 'ZZZ'))
365    optionmenu.pack()
366
367    # 8. Setting Tkinter.Canvas scrollcommand option:
368    toplevel = Tkinter.Toplevel()
369    scrollcanvas = Pmw.ScrolledCanvas(toplevel)
370    scrollcanvas.pack()
371
372    global prevSize
373    prevSize = -1
374
375    # Loop and run each test:
376    count = 0
377    while 1:
378        count = count + 1
379        label.configure(text = count)
380
381        # 1. Create/delete all megawidgets:
382        for widgetClass in megawidgets:
383            widget = widgetClass()
384            if widgetClass == Pmw.MainMenuBar:
385                root.configure(menu = widget)
386            elif hasattr(widgetClass, 'pack'):
387                widget.pack()
388            root.update()
389            widget.destroy()
390
391        # 2. Balloon binding:
392        balloon.bind(button, 'help')
393        balloon.tagbind(canvas, item, 'help')
394            # tagbind leaks due to a bug in Tkinter (v1.127) Canvas - it adds
395            # bindings to self._tagcommands but does not delete them.
396        root.update()
397
398        # 3. Adding and deleting MainMenuBar menu:
399        mainmenu.addmenu('File', 'help')
400        root.update()
401        mainmenu.deletemenu('File')
402        root.update()
403
404        # 4. Adding and deleting notebook page:
405        notebook.insert('File')
406        root.update()
407        notebook.delete('File')
408        root.update()
409
410        # 5. Adding and deleting panedwidget pane:
411        panedwidget.insert('File', size = 100)
412        root.update()
413        panedwidget.delete('File')
414        root.update()
415
416        # 6. Adding and deleting MenuBar menu:
417        menubar.addmenu('File', 'help')
418        root.update()
419        menubar.deletemenu('File')
420        root.update()
421
422        # 7. Setting OptionMenu items:
423        optionmenu.setitems(('aaa', 'bbb', 'ccc'))
424        root.update()
425
426        # 8. Setting Tkinter.Canvas scrollcommand option:
427        scrollcanvas.configure(hscrollmode = 'static')
428        scrollcanvas.configure(hscrollmode = 'dynamic')
429
430        # Check memory usage:
431        # lines = os.popen('top').readlines()
432        lines = os.popen('top -b -n 1 -p %d' % pid).readlines()
433        for line in lines:
434            # if string.find(line, 'python1.5.2') > 0:
435            if string.find(line, '^ *%d' % pid) > 0:
436                break
437        # size = string.atoi(string.lstrip(line[27:32]))
438        size = string.atoi(string.lstrip(line[22:29]))
439        if prevSize != size:
440            print time.strftime('%H:%M:%S', time.localtime(time.time())),
441            print line[:-1]
442            prevSize = size
443
444# ----------------------------------------------------------------------
445
446def usageExit():
447    print 'Usage:', sys.argv[0], '<test>'
448    print '  where <test> is one of:'
449    for test in tests:
450        print '   ', test
451    sys.exit()
452
453tests = []
454for name in locals().keys():
455    if name[-5:] == '_test':
456        tests.append(name)
457tests.sort()
458
459if len(sys.argv) != 2:
460    usageExit()
461
462testName = sys.argv[1]
463if testName not in tests:
464    print 'Unknown test "' + testName + '"'
465    usageExit()
466
467if testName == 'reinitialise_test':
468    # Run this by itself, since it calls Tkinter.Tk, mainloop, etc.
469    reinitialise_test()
470    sys.exit()
471
472# Use Pmw version in this distribution:
473Test.initialise()
474root = Test.root
475root.deiconify()
476
477# To use a different version of Pmw, comment out the three above lines
478# and the "import Test" line and uncomment these three:
479#   root = Tkinter.Tk()
480#   Pmw.setversion('1.0')
481#   Pmw.initialise(root)
482
483testFunction = locals()[testName]
484testFunction()
485
486if testName != 'memoryleak2_test':
487    # This does not use mainloop.
488    root.mainloop()
489