#!/bin/env python

# This is a rough collection of tests that can not be automated.
# To add a new test, create a function with name ending in '_bug'.

import os
import string
import time
import sys
import Test
import Tkinter
import Pmw

# ----------------------------------------------------------------------

def scrolledframeflashing_bug():
    # Script which demonstrates continuous flashing of dynamic scrollbars
    # in Pmw.ScrolledFrame.
    #
    # When this script is run, the two scrollbars will be continuously
    # mapped and unmapped and the window will continuously change size.

    frame = Tkinter.Frame(root)
    frame.pack(fill = 'both', expand = 1)

    sf = Pmw.ScrolledFrame(frame, borderframe = 0)
    sf.pack(fill = 'both', expand = 1)

    inner = Tkinter.Frame(sf.interior(),
            width = 401,
            height = 300,
            borderwidth = 0,
            highlightthickness = 0,
    )
    inner.pack(fill = 'both', expand = 1)

# ----------------------------------------------------------------------

def scrolledlistboxflashing_bug():
    # Script which demonstrates continuous flashing of dynamic scrollbars
    # in Pmw.ScrolledListBox.
    #
    # When this script is run, the two scrollbars will be continuously
    # mapped and unmapped and the window will continuously change size.

    frame = Tkinter.Frame(root)
    frame.pack(fill = 'both', expand = 1)

    sf = Pmw.ScrolledListBox(frame,
            listbox_width = 20,
            listbox_height = 10
    )
    sf.pack(fill = 'both', expand = 1)
    for i in range(11):
        sf.insert('end', '2' * 20)

# ----------------------------------------------------------------------

def scrolledlistboxflashing2_bug():
    # Another script which demonstrates continuous flashing of dynamic
    # scrollbars in Pmw.ScrolledListBox under Pmw.0.8.
    #
    # When this script is run, the two scrollbars will be continuously
    # mapped and unmapped and the window will continuously change size.
    #
    # (This did not display error when tried with Pmw.0.8, 99/8/3)

    def insert():
        sectionList = ['1', '2', '3', '4', '5', '6', '7', '8', '9',
            '123456789012345678901']
        for counter in sectionList: 
          slb.insert('end', counter)
          
    def clear():
        slb.delete(0, 'end')
        
    global slb
    slb = Pmw.ScrolledListBox(root)
    slb.pack()

    root.after(2000,insert)
    root.after(3000,clear) 
    root.after(4000,insert)

    root.geometry('400x400')

# ----------------------------------------------------------------------

def scrolledtextflashing_bug():
    # Script which demonstrates continuous flashing of dynamic scrollbars
    # in Pmw.ScrolledText.
    #
    # When this script is run, the two scrollbars will be continuously
    # mapped and unmapped and the window will continuously change size.

    frame = Tkinter.Frame(root)
    frame.pack(fill = 'both', expand = 1)

    sf = Pmw.ScrolledText(frame,
            text_width = 20,
            text_height = 10,
            text_wrap = 'none',
            borderframe = 0
    )
    sf.pack(fill = 'both', expand = 1)
    for i in range(11):
        sf.insert('end', '2' * 20)
        if i != 10:
            sf.insert('end', '\n')

# ----------------------------------------------------------------------

def scrolledcanvasflashing_bug():
    # Script which demonstrates continuous flashing of dynamic scrollbars
    # in Pmw.ScrolledCanvas.
    #
    # When this script is run, the two scrollbars will be continuously
    # mapped and unmapped and the window will continuously change size.

    frame = Tkinter.Frame(root)
    frame.pack(fill = 'both', expand = 1)

    sf = Pmw.ScrolledCanvas(frame,
            canvas_scrollregion = (0, 0, 301, 200),
            canvas_width=300,
            canvas_height=200,
            borderframe = 0
    )
    sf.pack(fill = 'both', expand = 1)

# ----------------------------------------------------------------------

def scrolledframeflashing2_bug():
    # The two scrollbars will be continuously mapped and unmapped, but
    # the toplevel window will remain the same size.

    root.geometry('550x500')

    frame = Tkinter.Frame()
    frame.pack()

    sf = Pmw.ScrolledFrame(frame, borderframe = 0)
    sf.pack(fill = 'both')

    inner = Tkinter.Frame(sf.interior(),
            width = 401,
            height = 300,
            borderwidth = 0,
            highlightthickness = 0,
    )
    inner.pack()

# ----------------------------------------------------------------------

def reinitialise_bug():
    global text
    text = """
    Demonstrates bug in Pmw.0.8.1 and earlier.
    Click on this button, click on OK in the dialog, then Exit below.
    When this window appears again, clicking on this button gives
    an error:
    TclError: can't invoke "wm" command:  application has been destroyed
    """
    class test:
        def __init__(self):
            root = Tkinter.Tk()
            Pmw.initialise(root)
            self.messagedialog = Pmw.MessageDialog(message_text = 'Testing')
            self.messagedialog.withdraw()
            button = Tkinter.Button(
                    text = text, command = self.messagedialog.activate)
            button.pack(pady = 20)
            exit = Tkinter.Button(text = 'Exit', command = root.destroy)
            exit.pack(pady = 20)
            root.mainloop()

    test()
    test()

# ----------------------------------------------------------------------

def componentgroup_bug():
    global changecolour
    def changecolour():
        b.configure(Button_background = 'yellow')

    def addbutton():
        b.configure(Button_background = 'green')
        b.add('OK')
        b.after(3000, changecolour)

    global b
    b = Pmw.ButtonBox(Button_background = 'red')
    b.pack()

    mb = Pmw.MenuBar(Button_background = 'red')
    mb.configure(Button_background = 'yellow')
    mb.pack()

    mb = Pmw.PanedWidget(Frame_background = 'red')
    mb.configure(Frame_background = 'yellow')
    mb.pack()

    mb = Pmw.RadioSelect(Button_background = 'red')
    mb.configure(Button_background = 'yellow')
    mb.pack()

    b.after(3000, addbutton)

# ----------------------------------------------------------------------

# A class which prints out a message when an instance is deleted.
class MyToplevel(Tkinter.Toplevel):

    def __init__(self):
        Tkinter.Toplevel.__init__(self)

    def __del__(self):
        print 'Window deleted'

def _runMemoryLeakTest():
    global top
    top = MyToplevel()
    Pmw.MegaToplevel(top)
    Pmw.AboutDialog(top)
    Pmw.ComboBoxDialog(top)
    Pmw.CounterDialog(top)
    Pmw.Dialog(top)
    Pmw.MessageDialog(top)
    Pmw.PromptDialog(top)
    Pmw.SelectionDialog(top)
    Pmw.TextDialog(top)

    Pmw.ButtonBox(top).pack()
    Pmw.ComboBox(top).pack()
    Pmw.Counter(top).pack()
    Pmw.EntryField(top).pack()
    Pmw.Group(top).pack()
    Pmw.LabeledWidget(top).pack()
    Pmw.MenuBar(top).pack()
    Pmw.MessageBar(top).pack()
    Pmw.NoteBook(top).pack()
    Pmw.OptionMenu(top).pack()
    Pmw.PanedWidget(top).pack()
    Pmw.RadioSelect(top).pack()
    Pmw.ScrolledCanvas(top).pack()
    Pmw.ScrolledField(top).pack()
    Pmw.ScrolledFrame(top).pack()
    Pmw.ScrolledListBox(top).pack()
    Pmw.ScrolledText(top).pack()
    Pmw.TimeCounter(top).pack()

def _killMemoryLeakTest():
    global top
    top.destroy()
    del top

memoryLeakMessage = """
Click on the "Run test" button to create instances of
all Pmw megawidgets. Then click on the "Destroy" button.
The message "Window deleted" should be printed to
standard output.
"""
def memoryleak_bug():
    label = Tkinter.Label(text = memoryLeakMessage)
    label.pack()
    run = Tkinter.Button(text = 'Run test', command = _runMemoryLeakTest)
    run.pack()
    kill = Tkinter.Button(text = 'Destroy', command = _killMemoryLeakTest)
    kill.pack()

# ----------------------------------------------------------------------

def memoryleak2_bug():

    print 'This test continuously creates and deletes megawidgets and'
    print 'their components.  It calls the "top" program, so'
    print 'may not work on non-Unix operating systems. Run it for a long,'
    print 'long time and check that the process memory size does not'
    print 'continue to increase.  Kill with <Control-C>.'

    pid = os.getpid()

    label = Tkinter.Label()
    label.pack()

    # Setup each test:

    # 1. Create/delete all megawidgets:
    megawidgets = (
        Pmw.AboutDialog, Pmw.Balloon, Pmw.ButtonBox, Pmw.ComboBox,
        Pmw.ComboBoxDialog, Pmw.Counter, Pmw.CounterDialog, Pmw.Dialog,
        Pmw.EntryField, Pmw.Group, Pmw.HistoryText, Pmw.LabeledWidget,
        Pmw.MainMenuBar, Pmw.MenuBar, Pmw.MessageBar, Pmw.MessageDialog,
        Pmw.NoteBook, Pmw.OptionMenu, Pmw.PanedWidget, Pmw.PromptDialog,
        Pmw.RadioSelect, Pmw.ScrolledCanvas, Pmw.ScrolledField,
        Pmw.ScrolledFrame, Pmw.ScrolledListBox, Pmw.ScrolledText,
        Pmw.SelectionDialog, Pmw.TextDialog, Pmw.TimeCounter,
    )

    # 2. Balloon binding:
    toplevel = Tkinter.Toplevel()
    balloon = Pmw.Balloon(toplevel)
    button = Tkinter.Button(toplevel)
    button.pack()
    canvas = Tkinter.Canvas(toplevel)
    item = canvas.create_rectangle(0, 0, 100, 100)
    canvas.pack()

    # 3. Adding and deleting menu:
    toplevel = Tkinter.Toplevel()
    mainmenu = Pmw.MainMenuBar(toplevel)
    mainmenu.addmenu('Foo', 'help')
    toplevel.configure(menu = mainmenu)

    # 4. Adding and deleting notebook page:
    toplevel = Tkinter.Toplevel()
    notebook = Pmw.NoteBook(toplevel)
    notebook.pack()

    # 5. Adding and deleting panedwidget pane:
    toplevel = Tkinter.Toplevel()
    panedwidget = Pmw.PanedWidget(toplevel)
    panedwidget.pack()
    panedwidget.insert('Foo', size = 100)

    # 6. Adding and deleting MenuBar menu:
    toplevel = Tkinter.Toplevel()
    menubar = Pmw.MenuBar(toplevel)
    menubar.pack()

    # 7. Setting OptionMenu items:
    toplevel = Tkinter.Toplevel()
    optionmenu = Pmw.OptionMenu(toplevel, items = ('XXX', 'YYY', 'ZZZ'))
    optionmenu.pack()

    # 8. Setting Tkinter.Canvas scrollcommand option:
    toplevel = Tkinter.Toplevel()
    scrollcanvas = Pmw.ScrolledCanvas(toplevel)
    scrollcanvas.pack()

    global prevSize
    prevSize = -1

    # Loop and run each test:
    count = 0
    while 1:
        count = count + 1
        label.configure(text = count)

        # 1. Create/delete all megawidgets:
        for widgetClass in megawidgets:
            widget = widgetClass()
            if widgetClass == Pmw.MainMenuBar:
                root.configure(menu = widget)
            elif hasattr(widgetClass, 'pack'):
                widget.pack()
            root.update()
            widget.destroy()

        # 2. Balloon binding:
        balloon.bind(button, 'help')
        balloon.tagbind(canvas, item, 'help')
            # tagbind leaks due to a bug in Tkinter (v1.127) Canvas - it adds
            # bindings to self._tagcommands but does not delete them.
        root.update()

        # 3. Adding and deleting MainMenuBar menu:
        mainmenu.addmenu('File', 'help')
        root.update()
        mainmenu.deletemenu('File')
        root.update()

        # 4. Adding and deleting notebook page:
        notebook.insert('File')
        root.update()
        notebook.delete('File')
        root.update()

        # 5. Adding and deleting panedwidget pane:
        panedwidget.insert('File', size = 100)
        root.update()
        panedwidget.delete('File')
        root.update()

        # 6. Adding and deleting MenuBar menu:
        menubar.addmenu('File', 'help')
        root.update()
        menubar.deletemenu('File')
        root.update()

        # 7. Setting OptionMenu items:
        optionmenu.setitems(('aaa', 'bbb', 'ccc'))
        root.update()

        # 8. Setting Tkinter.Canvas scrollcommand option:
        scrollcanvas.configure(hscrollmode = 'static')
        scrollcanvas.configure(hscrollmode = 'dynamic')

        # Check memory usage:
        # lines = os.popen('top').readlines()
        lines = os.popen('top -b -n 1 -p %d' % pid).readlines()
        for line in lines:
            # if string.find(line, 'python1.5.2') > 0:
            if string.find(line, '^ *%d' % pid) > 0:
                break
        # size = string.atoi(string.lstrip(line[27:32]))
        size = string.atoi(string.lstrip(line[22:29]))
        if prevSize != size:
            print time.strftime('%H:%M:%S', time.localtime(time.time())),
            print line[:-1]
            prevSize = size

# ----------------------------------------------------------------------

def usageExit():
    print 'Usage:', sys.argv[0], '<test>'
    print '  where <test> is one of:'
    for test in tests:
        print '   ', test
    sys.exit()

tests = []
for name in locals().keys():
    if name[-4:] == '_bug':
        tests.append(name)
tests.sort()

if len(sys.argv) != 2:
    usageExit()

testName = sys.argv[1]
if testName not in tests:
    print 'Unknown test "' + testName + '"'
    usageExit()

if testName == 'reinitialise_bug':
    # Run this by itself, since it calls Tkinter.Tk, mainloop, etc.
    reinitialise_bug()
    sys.exit()

# Use Pmw version in this distribution:
Test.initialise()
root = Test.root
root.deiconify()

# To use a different version of Pmw, comment out the three above lines
# and the "import Test" line and uncomment these three:
#   root = Tkinter.Tk()
#   Pmw.setversion('0.8')
#   Pmw.initialise(root, fontScheme = 'pmw1')

testFunction = locals()[testName]
testFunction()

if testName != 'memoryleak2_bug':
    # This does not use mainloop.
    root.mainloop()
