source: sasview/src/sas/sasview/wxcruft.py @ 5251ec6

magnetic_scattrelease-4.2.2ticket-1009ticket-1249
Last change on this file since 5251ec6 was 5251ec6, checked in by Paul Kienzle <pkienzle@…>, 6 years ago

improved support for py37 in sasgui

  • Property mode set to 100644
File size: 4.6 KB
Line 
1from __future__ import print_function
2
3import inspect
4import wx
5from wx import Timer
6
7def call_later_fix():
8    # TODO: test if we need the fix
9    wx.CallLater = CallLater
10    wx.FutureCall = FutureCall
11    wx.PyTimer = PyTimer
12
13def trace_new_id():
14    wx.NewId = NewId
15
16def NewId():
17    import wx._misc
18    id = wx._misc.NewId()
19    path, line, function = _get_caller()
20    if path == "sas/guiframe/utils.py":
21        # Special case: NewId is being called via an IdList request; we
22        # want to which widget triggered the request, not that it was
23        # triggered via IdList.
24        path, line, function = _get_caller(2)
25        tag = " via IdList"
26    elif path.endswith("/wxcruft.py"):
27        # Special case: NewId is being called via CallLater; we want to
28        # know where the CallLater was invoked.
29        path, line, function = _get_caller(1)
30        tag = " via CallLater"
31    else:
32        tag = ""
33    print("NewId %d from %s(%d):%s%s"%(id, path, line, function, tag))
34    return id
35
36def _get_caller(distance=0):
37    frame = inspect.stack()[distance+2]
38    path = frame[1]
39    index = path.find('/sas/')
40    if index == -1: index = path.find('\\sas\\')
41    return path[index+1:], frame[2], frame[3]
42
43
44
45# ==========================================================================
46# Hacked versions of CallLater and PyTimer so that the main GUI loop doesn't
47# eat wx ids.
48# Changed lines are marked #PAK
49# ==========================================================================
50
51# For backwards compatibility with 2.4
52class PyTimer(Timer):
53    def __init__(self, notify, *args, **kw):  #PAK
54        Timer.__init__(self, *args, **kw)     #PAK
55        self.notify = notify
56
57    def Notify(self):
58        if self.notify:
59            self.notify()
60
61
62class CallLater:
63    """
64    A convenience class for `wx.Timer`, that calls the given callable
65    object once after the given amount of milliseconds, passing any
66    positional or keyword args.  The return value of the callable is
67    availbale after it has been run with the `GetResult` method.
68
69    If you don't need to get the return value or restart the timer
70    then there is no need to hold a reference to this object.
71
72    :see: `wx.CallAfter`
73    """
74
75    __RUNNING = set()
76
77    def __init__(self, millis, callableObj, *args, **kwargs):
78        # print "=================== entering CallLater constructor"
79        assert callable(callableObj), "callableObj is not callable"
80        self.millis = millis
81        self.callable = callableObj
82        self.SetArgs(*args, **kwargs)
83        self.runCount = 0
84        self.running = False
85        self.hasRun = False
86        self.result = None
87        self.timer = None
88        self.id = wx.NewId()  # PAK
89        self.Start()
90
91
92    def Start(self, millis=None, *args, **kwargs):
93        """
94        (Re)start the timer
95        """
96        self.hasRun = False
97        if millis is not None:
98            self.millis = millis
99        if args or kwargs:
100            self.SetArgs(*args, **kwargs)
101        self.Stop()
102        self.timer = PyTimer(self.Notify, id=self.id)  # PAK
103        self.timer.Start(self.millis, wx.TIMER_ONE_SHOT)
104        self.running = True
105        self.__RUNNING.add(self)
106    Restart = Start
107
108
109    def Stop(self):
110        """
111        Stop and destroy the timer.
112        """
113        if self.timer is not None:
114            self.timer.Stop()
115            self.timer = None
116        self.__RUNNING.discard(self)
117
118
119    def GetInterval(self):
120        if self.timer is not None:
121            return self.timer.GetInterval()
122        else:
123            return 0
124
125
126    def IsRunning(self):
127        return self.timer is not None and self.timer.IsRunning()
128
129
130    def SetArgs(self, *args, **kwargs):
131        """
132        (Re)set the args passed to the callable object.  This is
133        useful in conjunction with Restart if you want to schedule a
134        new call to the same callable object but with different
135        parameters.
136        """
137        self.args = args
138        self.kwargs = kwargs
139
140
141    def HasRun(self):
142        return self.hasRun
143
144
145    def GetResult(self):
146        return self.result
147
148
149    def Notify(self):
150        """
151        The timer has expired so call the callable.
152        """
153        if self.callable and getattr(self.callable, 'im_self', True):
154            self.runCount += 1
155            self.running = False
156            self.result = self.callable(*self.args, **self.kwargs)
157        self.hasRun = True
158        if not self.running:
159            # if it wasn't restarted, then cleanup
160            wx.CallAfter(self.Stop)
161
162    Interval = property(GetInterval)
163    Result = property(GetResult)
164
165
166class FutureCall(CallLater):
167    """A compatibility alias for `CallLater`."""
Note: See TracBrowser for help on using the repository browser.