summaryrefslogtreecommitdiff
path: root/cad/src/utilities/qt4transition.py
blob: 8053074b6ef7baf687e3888ba62ab074f84aa117 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
# Copyright 2006-2007 Nanorex, Inc.  See LICENSE file for details.
"""
qt4transition.py - Useful markers and messages for Qt 4 transition work.

@author: Will
@version: $Id$
@copyright: 2006-2007 Nanorex, Inc.  See LICENSE file for details.
"""

import sys
import traceback
import types

import utilities.debug_prefs as debug_prefs
import utilities.debug as debug

from utilities.objectBrowse import objectBrowse

__already = { }

def __linenum(always = False):
    try:
        raise Exception
    except:
        tb = sys.exc_info()[2]
        f = tb.tb_frame
        f = f.f_back
        f = f.f_back
        key = (f.f_code.co_filename, f.f_lineno)
        got_key = True
        if not __already.has_key(key):
            __already[key] = 1
            got_key = False
        if got_key and not always:
            return False
        else:
            print f.f_code.co_filename, f.f_code.co_name, f.f_lineno
            return True

def qt4here(msg = None, show_traceback = False):
    if show_traceback:
        traceback.print_stack(None, None, sys.stdout)
        if msg is not None:
            print 'Qt 4 HERE: ' + msg
        print
    else:
        __linenum(always = True)
        if msg is not None:
            print 'Qt 4 HERE: ' + msg

def qt4overhaul(msg):
    if __linenum():
        print 'Qt 4 MAJOR CONCEPTUAL OVERHAUL: ' + msg

def qt4message(msg, always = False):
    if debug_prefs.debug_pref("Enable QT4 TODO messages",
                      debug_prefs.Choice_boolean_False,
                      prefs_key = True):
        if __linenum(always):
            print 'Qt 4 MESSAGE: ' + msg

def qt4todo(msg):
    if debug_prefs.debug_pref("Enable QT4 TODO messages",
                      debug_prefs.Choice_boolean_False,
                      prefs_key = True):
        if __linenum():
            print 'Qt 4 TODO: ' + msg
    else:
        return

def multipane_todo(msg):
    if __linenum():
        print 'Multipane TODO: ' + msg

def qt4warning(msg):
    if debug_prefs.debug_pref("Enable QT4 WARNING messages",
                      debug_prefs.Choice_boolean_False,
                      prefs_key = True):
        if __linenum():
            print 'Qt 4 WARNING: ' + msg

def qt4skipit(msg):
    """
    Indicates something I don't think we need for Qt 4
    """
    if __linenum():
        print 'Qt 4 SKIP IT: ' + msg

__nomsg = '128931789ksadjfqwhrhlv128947890127408'

def qt4die(msg = __nomsg, browse = False):
    traceback.print_stack(file = sys.stdout)
    if msg == __nomsg:
        print 'Qt 4 DIE'
    elif browse:
        print 'Qt 4 DIE:', msg
        objectBrowse(msg, maxdepth = 1)
    else:
        if type(msg) is not types.StringType:
            msg = repr(msg)
        print 'Qt 4 DIE: ' + msg
    sys.exit(0)

def qt4exception(msg):
    """
    Indicates something I don't think we definitely shouldn't have for Qt 4
    """
    raise Exception('Qt 4: ' + msg)

def qt4info(msg, name = None, maxdepth = 1, browse = False):
    __linenum(always = True)
    if type(msg) is type('abc'):
        print 'Qt 4 INFO:', repr(msg)
    else:
        print 'Qt 4 INFO:',
        if name is not None: print name,
        print repr(msg)
        if browse:
            objectBrowse(msg, maxdepth = maxdepth, outf = sys.stdout)

def qt4warnDestruction(obj, name = ''):
    message = '* * * * '
    try:
        raise Exception
    except:
        f = sys.exc_info()[2].tb_frame
        f = f.f_back
        message += f.f_code.co_filename + (':%d' % f.f_lineno)
    if name:
        message += ' ' + name
    if debug_prefs.debug_pref("Enable QT4 WARNING messages",
                      debug_prefs.Choice_boolean_False,
                      prefs_key = True):
        print 'Setting up destruction warning', message
    def destruction(ignore, message = message):
        print 'OBJECT DESTROYED (exiting)', message #bruce 070521 revised message
        sys.exit(1)
    from PyQt4.Qt import QObject, SIGNAL
    QObject.connect(obj, SIGNAL("destroyed(QObject *)"), destruction)

def findDefiningClass(cls_or_method, method_name = None):
    """
    Find which base class defines this method

    >>> print findDefiningClass(DeepClass.foo)
    __main__.BaseClass
    >>> print findDefiningClass(ShallowClass.foo)
    __main__.Base2Class
    >>> print findDefiningClass(ShallowClass, 'foo')
    __main__.Base2Class
    >>> x = DeepClass()
    >>> print findDefiningClass(x.foo)
    __main__.BaseClass
    """
    if method_name is not None:
        if type(cls_or_method) is not types.ClassType:
            cls_or_method = cls_or_method.__class__
        method = getattr(cls_or_method, method_name)
    elif type(cls_or_method) is types.MethodType:
        method = getattr(cls_or_method.im_class, cls_or_method.im_func.func_name)
    else:
        method = cls_or_method
    assert method.im_self is None, "Method must be a class method, not an instance mthod"
    def hunt(klass, lst, depth, name = method.im_func.func_name, method = method):
        if hasattr(klass, name) and method.im_func is getattr(klass, name).im_func:
            lst.append((depth, klass))
        for base in klass.__bases__:
            hunt(base, lst, depth + 1)
    lst = [ ]
    hunt(method.im_class, lst, 0)
    lst.sort()
    return lst[-1][1]

def lineage(widget, die = True, depth = 0):
    """
    Trace the parental lineage of a Qt 4 widget: parent,
    grandparent... This is helpful in diagnosing "RuntimeError:
    underlying C/C++ object has been deleted" errors. It is frequently
    wise to kill the program at the first such deletion, so that is the
    default behavior (switchable with die = False).
    """
    if widget is not None:
        from PyQt4.Qt import QObject, SIGNAL
        print (depth * '    ') + repr(widget)
        def destruction(ignore, die = die, message = repr(widget) + " was just destroyed"):
            qt4here(message, show_traceback = True)
            if die:
                sys.exit(1)
        QObject.connect(widget, SIGNAL("destroyed(QObject *)"), destruction)
        lineage(widget.parent(), die, depth + 1)

# ==

if __name__ == '__main__':

    # classes used to test findDefiningClass
    class BaseClass:
        def foo(self):
            print 'bar'
    class Base2Class:
        def foo(self):
            print 'BAR'
    class MiddleClass(BaseClass):
        pass
    class DeepClass(MiddleClass, Base2Class):
        pass
    class ShallowClass(Base2Class, MiddleClass):
        pass

    import doctest
    doctest.testmod()

# end