]>
Commit | Line | Data |
---|---|---|
1 | #---------------------------------------------------------------------------- | |
2 | ||
3 | # Use Python's bool constants if available, make some if not | |
4 | try: | |
5 | True | |
6 | except NameError: | |
7 | __builtins__.True = 1==1 | |
8 | __builtins__.False = 1==0 | |
9 | def bool(value): return not not value | |
10 | __builtins__.bool = bool | |
11 | ||
12 | ||
13 | ||
14 | # workarounds for bad wxRTTI names | |
15 | __wxPyPtrTypeMap['wxGauge95'] = 'wxGauge' | |
16 | __wxPyPtrTypeMap['wxSlider95'] = 'wxSlider' | |
17 | __wxPyPtrTypeMap['wxStatusBar95'] = 'wxStatusBar' | |
18 | ||
19 | ||
20 | #---------------------------------------------------------------------------- | |
21 | # Load version numbers from __version__... Ensure that major and minor | |
22 | # versions are the same for both wxPython and wxWidgets. | |
23 | ||
24 | from __version__ import * | |
25 | __version__ = VERSION_STRING | |
26 | ||
27 | assert MAJOR_VERSION == _core_.MAJOR_VERSION, "wxPython/wxWidgets version mismatch" | |
28 | assert MINOR_VERSION == _core_.MINOR_VERSION, "wxPython/wxWidgets version mismatch" | |
29 | if RELEASE_VERSION != _core_.RELEASE_VERSION: | |
30 | import warnings | |
31 | warnings.warn("wxPython/wxWidgets release number mismatch") | |
32 | ||
33 | ||
34 | def version(): | |
35 | """Returns a string containing version and port info""" | |
36 | ctype = wx.USE_UNICODE and 'unicode' or 'ansi' | |
37 | if wx.Platform == '__WXMSW__': | |
38 | port = 'msw' | |
39 | elif wx.Platform == '__WXMAC__': | |
40 | port = 'mac' | |
41 | elif wx.Platform == '__WXGTK__': | |
42 | port = 'gtk' | |
43 | if 'gtk2' in wx.PlatformInfo: | |
44 | port = 'gtk2' | |
45 | else: | |
46 | port = '?' | |
47 | ||
48 | return "%s (%s-%s)" % (wx.VERSION_STRING, port, ctype) | |
49 | ||
50 | ||
51 | #---------------------------------------------------------------------------- | |
52 | ||
53 | # Set wxPython's default string<-->unicode conversion encoding from | |
54 | # the locale, but only if Python's default hasn't been changed. (We | |
55 | # assume that if the user has customized it already then that is the | |
56 | # encoding we need to use as well.) | |
57 | # | |
58 | # The encoding selected here is used when string or unicode objects | |
59 | # need to be converted in order to pass them to wxWidgets. Please be | |
60 | # aware that the default encoding within the same locale may be | |
61 | # slightly different on different platforms. For example, please see | |
62 | # http://www.alanwood.net/demos/charsetdiffs.html for differences | |
63 | # between the common latin/roman encodings. | |
64 | ||
65 | default = _sys.getdefaultencoding() | |
66 | if default == 'ascii': | |
67 | import locale | |
68 | import codecs | |
69 | try: | |
70 | if hasattr(locale, 'getpreferredencoding'): | |
71 | default = locale.getpreferredencoding() | |
72 | else: | |
73 | default = locale.getdefaultlocale()[1] | |
74 | codecs.lookup(default) | |
75 | except (ValueError, LookupError, TypeError): | |
76 | default = _sys.getdefaultencoding() | |
77 | del locale | |
78 | del codecs | |
79 | if default: | |
80 | wx.SetDefaultPyEncoding(default) | |
81 | del default | |
82 | ||
83 | #---------------------------------------------------------------------------- | |
84 | ||
85 | class PyDeadObjectError(AttributeError): | |
86 | pass | |
87 | ||
88 | class _wxPyDeadObject(object): | |
89 | """ | |
90 | Instances of wx objects that are OOR capable will have their __class__ | |
91 | changed to this class when the C++ object is deleted. This should help | |
92 | prevent crashes due to referencing a bogus C++ pointer. | |
93 | """ | |
94 | reprStr = "wxPython wrapper for DELETED %s object! (The C++ object no longer exists.)" | |
95 | attrStr = "The C++ part of the %s object has been deleted, attribute access no longer allowed." | |
96 | ||
97 | def __repr__(self): | |
98 | if not hasattr(self, "_name"): | |
99 | self._name = "[unknown]" | |
100 | return self.reprStr % self._name | |
101 | ||
102 | def __getattr__(self, *args): | |
103 | if not hasattr(self, "_name"): | |
104 | self._name = "[unknown]" | |
105 | raise PyDeadObjectError(self.attrStr % self._name) | |
106 | ||
107 | def __nonzero__(self): | |
108 | return 0 | |
109 | ||
110 | ||
111 | ||
112 | class PyUnbornObjectError(AttributeError): | |
113 | pass | |
114 | ||
115 | class _wxPyUnbornObject(object): | |
116 | """ | |
117 | Some stock objects are created when the wx._core module is | |
118 | imported, but their C++ instance is not created until the wx.App | |
119 | object is created and initialized. These object instances will | |
120 | temporarily have their __class__ changed to this class so an | |
121 | exception will be raised if they are used before the C++ instance | |
122 | is ready. | |
123 | """ | |
124 | ||
125 | reprStr = "wxPython wrapper for UNBORN object! (The C++ object is not initialized yet.)" | |
126 | attrStr = "The C++ part of this object has not been initialized, attribute access not allowed." | |
127 | ||
128 | def __repr__(self): | |
129 | #if not hasattr(self, "_name"): | |
130 | # self._name = "[unknown]" | |
131 | return self.reprStr #% self._name | |
132 | ||
133 | def __getattr__(self, *args): | |
134 | #if not hasattr(self, "_name"): | |
135 | # self._name = "[unknown]" | |
136 | raise PyUnbornObjectError(self.attrStr) # % self._name ) | |
137 | ||
138 | def __nonzero__(self): | |
139 | return 0 | |
140 | ||
141 | ||
142 | #---------------------------------------------------------------------------- | |
143 | ||
144 | def CallAfter(callable, *args, **kw): | |
145 | """ | |
146 | Call the specified function after the current and pending event | |
147 | handlers have been completed. This is also good for making GUI | |
148 | method calls from non-GUI threads. Any extra positional or | |
149 | keyword args are passed on to the callable when it is called. | |
150 | ||
151 | :see: `wx.CallLater` | |
152 | """ | |
153 | app = wx.GetApp() | |
154 | assert app is not None, 'No wx.App created yet' | |
155 | ||
156 | if not hasattr(app, "_CallAfterId"): | |
157 | app._CallAfterId = wx.NewEventType() | |
158 | app.Connect(-1, -1, app._CallAfterId, | |
159 | lambda event: event.callable(*event.args, **event.kw) ) | |
160 | evt = wx.PyEvent() | |
161 | evt.SetEventType(app._CallAfterId) | |
162 | evt.callable = callable | |
163 | evt.args = args | |
164 | evt.kw = kw | |
165 | wx.PostEvent(app, evt) | |
166 | ||
167 | #---------------------------------------------------------------------------- | |
168 | ||
169 | ||
170 | class CallLater: | |
171 | """ | |
172 | A convenience class for `wx.Timer`, that calls the given callable | |
173 | object once after the given amount of milliseconds, passing any | |
174 | positional or keyword args. The return value of the callable is | |
175 | availbale after it has been run with the `GetResult` method. | |
176 | ||
177 | If you don't need to get the return value or restart the timer | |
178 | then there is no need to hold a reference to this object. It will | |
179 | hold a reference to itself while the timer is running (the timer | |
180 | has a reference to self.Notify) but the cycle will be broken when | |
181 | the timer completes, automatically cleaning up the wx.CallLater | |
182 | object. | |
183 | ||
184 | :see: `wx.CallAfter` | |
185 | """ | |
186 | def __init__(self, millis, callable, *args, **kwargs): | |
187 | self.millis = millis | |
188 | self.callable = callable | |
189 | self.SetArgs(*args, **kwargs) | |
190 | self.runCount = 0 | |
191 | self.running = False | |
192 | self.hasRun = False | |
193 | self.result = None | |
194 | self.timer = None | |
195 | self.Start() | |
196 | ||
197 | def __del__(self): | |
198 | self.Stop() | |
199 | ||
200 | ||
201 | def Start(self, millis=None, *args, **kwargs): | |
202 | """ | |
203 | (Re)start the timer | |
204 | """ | |
205 | self.hasRun = False | |
206 | if millis is not None: | |
207 | self.millis = millis | |
208 | if args or kwargs: | |
209 | self.SetArgs(*args, **kwargs) | |
210 | self.Stop() | |
211 | self.timer = wx.PyTimer(self.Notify) | |
212 | self.timer.Start(self.millis, wx.TIMER_ONE_SHOT) | |
213 | self.running = True | |
214 | Restart = Start | |
215 | ||
216 | ||
217 | def Stop(self): | |
218 | """ | |
219 | Stop and destroy the timer. | |
220 | """ | |
221 | if self.timer is not None: | |
222 | self.timer.Stop() | |
223 | self.timer = None | |
224 | ||
225 | ||
226 | def GetInterval(self): | |
227 | if self.timer is not None: | |
228 | return self.timer.GetInterval() | |
229 | else: | |
230 | return 0 | |
231 | ||
232 | ||
233 | def IsRunning(self): | |
234 | return self.timer is not None and self.timer.IsRunning() | |
235 | ||
236 | ||
237 | def SetArgs(self, *args, **kwargs): | |
238 | """ | |
239 | (Re)set the args passed to the callable object. This is | |
240 | useful in conjunction with Restart if you want to schedule a | |
241 | new call to the same callable object but with different | |
242 | parameters. | |
243 | """ | |
244 | self.args = args | |
245 | self.kwargs = kwargs | |
246 | ||
247 | ||
248 | def HasRun(self): | |
249 | return self.hasRun | |
250 | ||
251 | def GetResult(self): | |
252 | return self.result | |
253 | ||
254 | def Notify(self): | |
255 | """ | |
256 | The timer has expired so call the callable. | |
257 | """ | |
258 | if self.callable and getattr(self.callable, 'im_self', True): | |
259 | self.runCount += 1 | |
260 | self.running = False | |
261 | self.result = self.callable(*self.args, **self.kwargs) | |
262 | self.hasRun = True | |
263 | if not self.running: | |
264 | # if it wasn't restarted, then cleanup | |
265 | wx.CallAfter(self.Stop) | |
266 | ||
267 | Interval = property(GetInterval) | |
268 | Result = property(GetResult) | |
269 | ||
270 | ||
271 | class FutureCall(CallLater): | |
272 | """A compatibility alias for `CallLater`.""" | |
273 | ||
274 | #---------------------------------------------------------------------------- | |
275 | # Control which items in this module should be documented by epydoc. | |
276 | # We allow only classes and functions, which will help reduce the size | |
277 | # of the docs by filtering out the zillions of constants, EVT objects, | |
278 | # and etc that don't make much sense by themselves, but are instead | |
279 | # documented (or will be) as part of the classes/functions/methods | |
280 | # where they should be used. | |
281 | ||
282 | class __DocFilter: | |
283 | """ | |
284 | A filter for epydoc that only allows non-Ptr classes and | |
285 | functions, in order to reduce the clutter in the API docs. | |
286 | """ | |
287 | def __init__(self, globals): | |
288 | self._globals = globals | |
289 | ||
290 | def __call__(self, name): | |
291 | import types | |
292 | obj = self._globals.get(name, None) | |
293 | ||
294 | # only document classes and function | |
295 | if type(obj) not in [type, types.ClassType, types.FunctionType, types.BuiltinFunctionType]: | |
296 | return False | |
297 | ||
298 | # skip other things that are private or will be documented as part of somethign else | |
299 | if name.startswith('_') or name.startswith('EVT') or name.endswith('_swigregister') or name.endswith('Ptr') : | |
300 | return False | |
301 | ||
302 | # skip functions that are duplicates of static functions in a class | |
303 | if name.find('_') != -1: | |
304 | cls = self._globals.get(name.split('_')[0], None) | |
305 | methname = name.split('_')[1] | |
306 | if hasattr(cls, methname) and type(getattr(cls, methname)) is types.FunctionType: | |
307 | return False | |
308 | ||
309 | return True | |
310 | ||
311 | #---------------------------------------------------------------------------- | |
312 | #---------------------------------------------------------------------------- | |
313 | ||
314 | # Import other modules in this package that should show up in the | |
315 | # "core" wx namespace | |
316 | from _gdi import * | |
317 | from _windows import * | |
318 | from _controls import * | |
319 | from _misc import * | |
320 | ||
321 | #---------------------------------------------------------------------------- | |
322 | #---------------------------------------------------------------------------- |