]> git.saurik.com Git - wxWidgets.git/blob - wxPython/src/_core_ex.py
Add wx.version()
[wxWidgets.git] / wxPython / src / _core_ex.py
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 default = locale.getdefaultlocale()[1]
71 codecs.lookup(default)
72 except (ValueError, LookupError, TypeError):
73 default = _sys.getdefaultencoding()
74 del locale
75 del codecs
76 if default:
77 wx.SetDefaultPyEncoding(default)
78 del default
79
80 #----------------------------------------------------------------------------
81
82 class PyDeadObjectError(AttributeError):
83 pass
84
85 class _wxPyDeadObject(object):
86 """
87 Instances of wx objects that are OOR capable will have their __class__
88 changed to this class when the C++ object is deleted. This should help
89 prevent crashes due to referencing a bogus C++ pointer.
90 """
91 reprStr = "wxPython wrapper for DELETED %s object! (The C++ object no longer exists.)"
92 attrStr = "The C++ part of the %s object has been deleted, attribute access no longer allowed."
93
94 def __repr__(self):
95 if not hasattr(self, "_name"):
96 self._name = "[unknown]"
97 return self.reprStr % self._name
98
99 def __getattr__(self, *args):
100 if not hasattr(self, "_name"):
101 self._name = "[unknown]"
102 raise PyDeadObjectError(self.attrStr % self._name)
103
104 def __nonzero__(self):
105 return 0
106
107
108
109 class PyUnbornObjectError(AttributeError):
110 pass
111
112 class _wxPyUnbornObject(object):
113 """
114 Some stock objects are created when the wx._core module is
115 imported, but their C++ instance is not created until the wx.App
116 object is created and initialized. These object instances will
117 temporarily have their __class__ changed to this class so an
118 exception will be raised if they are used before the C++ instance
119 is ready.
120 """
121
122 reprStr = "wxPython wrapper for UNBORN object! (The C++ object is not initialized yet.)"
123 attrStr = "The C++ part of this object has not been initialized, attribute access not allowed."
124
125 def __repr__(self):
126 #if not hasattr(self, "_name"):
127 # self._name = "[unknown]"
128 return self.reprStr #% self._name
129
130 def __getattr__(self, *args):
131 #if not hasattr(self, "_name"):
132 # self._name = "[unknown]"
133 raise PyUnbornObjectError(self.attrStr) # % self._name )
134
135 def __nonzero__(self):
136 return 0
137
138
139 #----------------------------------------------------------------------------
140
141 def CallAfter(callable, *args, **kw):
142 """
143 Call the specified function after the current and pending event
144 handlers have been completed. This is also good for making GUI
145 method calls from non-GUI threads. Any extra positional or
146 keyword args are passed on to the callable when it is called.
147
148 :see: `wx.CallLater`
149 """
150 app = wx.GetApp()
151 assert app is not None, 'No wx.App created yet'
152
153 if not hasattr(app, "_CallAfterId"):
154 app._CallAfterId = wx.NewEventType()
155 app.Connect(-1, -1, app._CallAfterId,
156 lambda event: event.callable(*event.args, **event.kw) )
157 evt = wx.PyEvent()
158 evt.SetEventType(app._CallAfterId)
159 evt.callable = callable
160 evt.args = args
161 evt.kw = kw
162 wx.PostEvent(app, evt)
163
164 #----------------------------------------------------------------------------
165
166
167 class CallLater:
168 """
169 A convenience class for `wx.Timer`, that calls the given callable
170 object once after the given amount of milliseconds, passing any
171 positional or keyword args. The return value of the callable is
172 availbale after it has been run with the `GetResult` method.
173
174 If you don't need to get the return value or restart the timer
175 then there is no need to hold a reference to this object. It will
176 hold a reference to itself while the timer is running (the timer
177 has a reference to self.Notify) but the cycle will be broken when
178 the timer completes, automatically cleaning up the wx.CallLater
179 object.
180
181 :see: `wx.CallAfter`
182 """
183 def __init__(self, millis, callable, *args, **kwargs):
184 self.millis = millis
185 self.callable = callable
186 self.SetArgs(*args, **kwargs)
187 self.runCount = 0
188 self.running = False
189 self.hasRun = False
190 self.result = None
191 self.timer = None
192 self.Start()
193
194 def __del__(self):
195 self.Stop()
196
197
198 def Start(self, millis=None, *args, **kwargs):
199 """
200 (Re)start the timer
201 """
202 self.hasRun = False
203 if millis is not None:
204 self.millis = millis
205 if args or kwargs:
206 self.SetArgs(*args, **kwargs)
207 self.Stop()
208 self.timer = wx.PyTimer(self.Notify)
209 self.timer.Start(self.millis, wx.TIMER_ONE_SHOT)
210 self.running = True
211 Restart = Start
212
213
214 def Stop(self):
215 """
216 Stop and destroy the timer.
217 """
218 if self.timer is not None:
219 self.timer.Stop()
220 self.timer = None
221
222
223 def GetInterval(self):
224 if self.timer is not None:
225 return self.timer.GetInterval()
226 else:
227 return 0
228
229
230 def IsRunning(self):
231 return self.timer is not None and self.timer.IsRunning()
232
233
234 def SetArgs(self, *args, **kwargs):
235 """
236 (Re)set the args passed to the callable object. This is
237 useful in conjunction with Restart if you want to schedule a
238 new call to the same callable object but with different
239 parameters.
240 """
241 self.args = args
242 self.kwargs = kwargs
243
244
245 def HasRun(self):
246 return self.hasRun
247
248 def GetResult(self):
249 return self.result
250
251 def Notify(self):
252 """
253 The timer has expired so call the callable.
254 """
255 if self.callable and getattr(self.callable, 'im_self', True):
256 self.runCount += 1
257 self.running = False
258 self.result = self.callable(*self.args, **self.kwargs)
259 self.hasRun = True
260 if not self.running:
261 # if it wasn't restarted, then cleanup
262 wx.CallAfter(self.Stop)
263
264 Interval = property(GetInterval)
265 Result = property(GetResult)
266
267
268 class FutureCall(CallLater):
269 """A compatibility alias for `CallLater`."""
270
271 #----------------------------------------------------------------------------
272 # Control which items in this module should be documented by epydoc.
273 # We allow only classes and functions, which will help reduce the size
274 # of the docs by filtering out the zillions of constants, EVT objects,
275 # and etc that don't make much sense by themselves, but are instead
276 # documented (or will be) as part of the classes/functions/methods
277 # where they should be used.
278
279 class __DocFilter:
280 """
281 A filter for epydoc that only allows non-Ptr classes and
282 functions, in order to reduce the clutter in the API docs.
283 """
284 def __init__(self, globals):
285 self._globals = globals
286
287 def __call__(self, name):
288 import types
289 obj = self._globals.get(name, None)
290
291 # only document classes and function
292 if type(obj) not in [type, types.ClassType, types.FunctionType, types.BuiltinFunctionType]:
293 return False
294
295 # skip other things that are private or will be documented as part of somethign else
296 if name.startswith('_') or name.startswith('EVT') or name.endswith('_swigregister') or name.endswith('Ptr') :
297 return False
298
299 # skip functions that are duplicates of static functions in a class
300 if name.find('_') != -1:
301 cls = self._globals.get(name.split('_')[0], None)
302 methname = name.split('_')[1]
303 if hasattr(cls, methname) and type(getattr(cls, methname)) is types.FunctionType:
304 return False
305
306 return True
307
308 #----------------------------------------------------------------------------
309 #----------------------------------------------------------------------------
310
311 # Import other modules in this package that should show up in the
312 # "core" wx namespace
313 from _gdi import *
314 from _windows import *
315 from _controls import *
316 from _misc import *
317
318 #----------------------------------------------------------------------------
319 #----------------------------------------------------------------------------