From 289f118d0966a9314907f3e5e9d23805adb22c46 Mon Sep 17 00:00:00 2001 From: Robin Dunn Date: Thu, 22 Dec 2011 18:46:45 +0000 Subject: [PATCH] Move more Python code to extractor objects. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxPython/Phoenix/trunk@70092 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- etg/_core.py | 19 ++++ etg/app.py | 288 +++++++++++++++++++++++++++++++++++++++++++++++-- src/app_ex.py | 263 -------------------------------------------- src/core_ex.py | 18 ---- 4 files changed, 297 insertions(+), 291 deletions(-) delete mode 100644 src/app_ex.py diff --git a/etg/_core.py b/etg/_core.py index 74241048..eca7a4cc 100644 --- a/etg/_core.py +++ b/etg/_core.py @@ -203,6 +203,25 @@ def run(): module.addInclude(INCLUDES) module.includePyCode('src/core_ex.py', order=10) + module.addPyFunction('version', '()', + doc="""Returns a string containing version and port info""", + body="""\ + if wx.Port == '__WXMSW__': + port = 'msw' + elif wx.Port == '__WXMAC__': + if 'wxOSX-carbon' in wx.PortInfo: + port = 'osx-carbon' + else: + port = 'osx-cocoa' + elif wx.Port == '__WXGTK__': + port = 'gtk' + if 'gtk2' in wx.PortInfo: + port = 'gtk2' + else: + port = '???' + return "%s %s (phoenix)" % (wx.VERSION_STRING, port) + """) + module.addPyFunction('CallAfter', '(callableObj, *args, **kw)', doc="""\ Call the specified function after the current and pending event diff --git a/etg/app.py b/etg/app.py index 8d4e7316..8b116264 100644 --- a/etg/app.py +++ b/etg/app.py @@ -9,6 +9,7 @@ import etgtools import etgtools.tweaker_tools as tools +from etgtools import PyFunctionDef, PyCodeDef, PyPropertyDef PACKAGE = "wx" MODULE = "_core" @@ -21,8 +22,7 @@ ITEMS = [ 'wxAppConsole', 'wxApp', ] -OTHERDEPS = [ 'src/app_ex.py', # Some extra app-related Python code - 'src/app_ex.cpp', # and some C++ code too +OTHERDEPS = [ 'src/app_ex.cpp', # and some C++ code too ] #--------------------------------------------------------------------------- @@ -94,12 +94,14 @@ def run(): c.find('ProcessMessage').ignore() c.addCppMethod('void', 'MacHideApp', '()', - doc="Hide all application windows just as the user can do with the\nsystem Hide command. Mac only.", + doc="""\ + Hide all application windows just as the user can do with the + system Hide command. Mac only.""", body="""\ - #ifdef __WXMAC__ - self->MacHideApp(); - #endif - """) + #ifdef __WXMAC__ + self->MacHideApp(); + #endif + """) # Remove the virtualness from these methods for m in [ 'GetDisplayMode', 'GetLayoutDirection', 'GetTopWindow', 'IsActive', @@ -183,12 +185,278 @@ def run(): f.type = 'wxPyApp*' f.briefDoc = "Returns the current application object." f.detailedDoc = [] + + + #------------------------------------------------------- + # Now add extractor objects for the main App class as a Python class, + # deriving from the wx.PyApp class that we created above. Also define the + # stdio helper class too. + - # This includes Python code for the on-demand output window, the Python - # derived wx.App class, etc. - module.includePyCode('src/app_ex.py') + module.addPyClass('PyOnDemandOutputWindow', ['object'], + doc="""\ + A class that can be used for redirecting Python's stdout and + stderr streams. It will do nothing until something is wrriten to + the stream at which point it will create a Frame with a text area + and write the text there. + """, + items=[ + PyFunctionDef('__init__', '(self, title="wxPython: stdout/stderr")', + body="""\ + self.frame = None + self.title = title + self.pos = wx.DefaultPosition + self.size = (450, 300) + self.parent = None + """), + + PyFunctionDef('SetParent', '(self, parent)', + doc="""Set the window to be used as the popup Frame's parent.""", + body="""self.parent = parent"""), + PyFunctionDef('CreateOutputWindow', '(self, txt)', + doc="", + body="""\ + self.frame = wx.Frame(self.parent, -1, self.title, self.pos, self.size, + style=wx.DEFAULT_FRAME_STYLE) + self.text = wx.TextCtrl(self.frame, -1, "", + style=wx.TE_MULTILINE|wx.TE_READONLY) + self.text.AppendText(txt) + self.frame.Show(True) + self.frame.Bind(wx.EVT_CLOSE, self.OnCloseWindow) + """), + + PyFunctionDef('OnCloseWindow', '(self, event)', + doc="", + body="""\ + if self.frame is not None: + self.frame.Destroy() + self.frame = None + self.text = None + self.parent = None + """), + + # These methods provide the file-like output behaviour. + PyFunctionDef('write', '(self, text)', + doc="""\ + Create the output window if needed and write the string to it. + If not called in the context of the gui thread then CallAfter is + used to do the work there. + """, + body="""\ + if self.frame is None: + if not wx.Thread.IsMain(): + wx.CallAfter(self.CreateOutputWindow, text) + else: + self.CreateOutputWindow(text) + else: + if not wx.Thread.IsMain(): + wx.CallAfter(self.text.AppendText, text) + else: + self.text.AppendText(text) + """), + + PyFunctionDef('close', '(self)', + doc="", + body="""\ + if self.frame is not None: + wx.CallAfter(self.frame.Close) + """), + + PyFunctionDef('flush', '(self)', 'pass'), + ]) + + + module.addPyClass('App', ['PyApp'], + doc="""\ + The ``wx.App`` class represents the application and is used to: + + * bootstrap the wxPython system and initialize the underlying + gui toolkit + * set and get application-wide properties + * implement the native windowing system main message or event loop, + and to dispatch events to window instances + * etc. + + Every wx application must have a single ``wx.App`` instance, and all + creation of UI objects should be delayed until after the ``wx.App`` object + has been created in order to ensure that the gui platform and wxWidgets + have been fully initialized. + + Normally you would derive from this class and implement an ``OnInit`` + method that creates a frame and then calls ``self.SetTopWindow(frame)``, + however ``wx.App`` is also usable on it's own without derivation. + """, + + items=[ + PyCodeDef('outputWindowClass = PyOnDemandOutputWindow'), + + PyFunctionDef('__init__', '(self, redirect=False, filename=None, useBestVisual=False, clearSigInt=True)', + doc="""\ + Construct a ``wx.App`` object. + + :param redirect: Should ``sys.stdout`` and ``sys.stderr`` be + redirected? Defaults to False. If ``filename`` is None + then output will be redirected to a window that pops up + as needed. (You can control what kind of window is created + for the output by resetting the class variable + ``outputWindowClass`` to a class of your choosing.) + + :param filename: The name of a file to redirect output to, if + redirect is True. + + :param useBestVisual: Should the app try to use the best + available visual provided by the system (only relevant on + systems that have more than one visual.) This parameter + must be used instead of calling `SetUseBestVisual` later + on because it must be set before the underlying GUI + toolkit is initialized. + + :param clearSigInt: Should SIGINT be cleared? This allows the + app to terminate upon a Ctrl-C in the console like other + GUI apps will. + + :note: You should override OnInit to do applicaition + initialization to ensure that the system, toolkit and + wxWidgets are fully initialized. + """, + body="""\ + PyApp.__init__(self) + + # make sure we can create a GUI + if not self.IsDisplayAvailable(): + + if wx.Port == "__WXMAC__": + msg = "This program needs access to the screen. Please run with a\\n" \\ + "Framework build of python, and only when you are logged in\\n" \\ + "on the main display of your Mac." + + elif wx.Port == "__WXGTK__": + msg ="Unable to access the X Display, is $DISPLAY set properly?" + + else: + msg = "Unable to create GUI" + # TODO: more description is needed for wxMSW... + + raise SystemExit(msg) + + # This has to be done before OnInit + self.SetUseBestVisual(useBestVisual) + + # Set the default handler for SIGINT. This fixes a problem + # where if Ctrl-C is pressed in the console that started this + # app then it will not appear to do anything, (not even send + # KeyboardInterrupt???) but will later segfault on exit. By + # setting the default handler then the app will exit, as + # expected (depending on platform.) + if clearSigInt: + try: + import signal + signal.signal(signal.SIGINT, signal.SIG_DFL) + except: + pass + + # Save and redirect the stdio to a window? + self.stdioWin = None + self.saveStdio = (_sys.stdout, _sys.stderr) + if redirect: + self.RedirectStdio(filename) + + # Use Python's install prefix as the default + wx.StandardPaths.Get().SetInstallPrefix(_sys.prefix) + + # Until the new native control for wxMac is up to par, still use the generic one. + ##wx.SystemOptions.SetOptionInt("mac.listctrl.always_use_generic", 1) + + # This finishes the initialization of wxWindows and then calls + # the OnInit that should be present in the derived class + self._BootstrapApp() + """), + + PyFunctionDef('OnPreInit', '(self)', + doc="""\ + Things that must be done after _BootstrapApp has done its thing, but + would be nice if they were already done by the time that OnInit is + called. This can be overridden in derived classes, but be sure to call + this method from there. + """, + body="wx.StockGDI._initStockObjects()"), + + PyFunctionDef('__del__', '(self)', + doc="", + body="""\ + # Just in case the MainLoop was overridden without calling RestoreStio + self.RestoreStdio() + """), + + PyFunctionDef('SetTopWindow', '(self, frame)', + doc="""\ + Set the \"main\" top level window, which will be used for the parent of + the on-demand output window as well as for dialogs that do not have + an explicit parent set. + """, + body="""\ + if self.stdioWin: + self.stdioWin.SetParent(frame) + wx.PyApp.SetTopWindow(self, frame) + """), + + PyFunctionDef('MainLoop', '(self)', + doc="""Execute the main GUI event loop""", + body="""\ + rv = wx.PyApp.MainLoop(self) + self.RestoreStdio() + return rv + """), + + PyFunctionDef('RedirectStdio', '(self, filename=None)', + doc="""Redirect sys.stdout and sys.stderr to a file or a popup window.""", + body="""\ + if filename: + _sys.stdout = _sys.stderr = open(filename, 'a') + else: + self.stdioWin = self.outputWindowClass() + _sys.stdout = _sys.stderr = self.stdioWin + """), + + PyFunctionDef('RestoreStdio', '(self)', + doc="", + body="""\ + try: + _sys.stdout, _sys.stderr = self.saveStdio + except: + pass + """), + + PyFunctionDef('SetOutputWindowAttributes', '(self, title=None, pos=None, size=None)', + doc="""\ + Set the title, position and/or size of the output window if the stdio + has been redirected. This should be called before any output would + cause the output window to be created. + """, + body="""\ + if self.stdioWin: + if title is not None: + self.stdioWin.title = title + if pos is not None: + self.stdioWin.pos = pos + if size is not None: + self.stdioWin.size = size + """), + ]) + + + + + module.addPyClass('PySimpleApp', ['App'], deprecated=True, + doc="""This class is deprecated. Please use wx.App instead.""", + items=[ + PyFunctionDef('__init__', '(self, *args, **kw)', + body="App.__init__(self, *args, **kw)") + ]) + + module.find('wxInitialize').ignore() module.find('wxUninitialize').ignore() diff --git a/src/app_ex.py b/src/app_ex.py deleted file mode 100644 index e5c06155..00000000 --- a/src/app_ex.py +++ /dev/null @@ -1,263 +0,0 @@ - -class PyOnDemandOutputWindow: - """ - A class that can be used for redirecting Python's stdout and - stderr streams. It will do nothing until something is wrriten to - the stream at which point it will create a Frame with a text area - and write the text there. - """ - def __init__(self, title="wxPython: stdout/stderr"): - self.frame = None - self.title = title - self.pos = wx.DefaultPosition - self.size = (450, 300) - self.parent = None - - def SetParent(self, parent): - """Set the window to be used as the popup Frame's parent.""" - self.parent = parent - - - def CreateOutputWindow(self, st): - self.frame = wx.Frame(self.parent, -1, self.title, self.pos, self.size, - style=wx.DEFAULT_FRAME_STYLE) - self.text = wx.TextCtrl(self.frame, -1, "", - style=wx.TE_MULTILINE|wx.TE_READONLY) - self.text.AppendText(st) - self.frame.Show(True) - self.frame.Bind(wx.EVT_CLOSE, self.OnCloseWindow) - - - def OnCloseWindow(self, event): - if self.frame is not None: - self.frame.Destroy() - self.frame = None - self.text = None - self.parent = None - - - # These methods provide the file-like output behaviour. - def write(self, text): - """ - Create the output window if needed and write the string to it. - If not called in the context of the gui thread then uses - CallAfter to do the work there. - """ - if self.frame is None: - if not wx.Thread.IsMain(): - wx.CallAfter(self.CreateOutputWindow, text) - else: - self.CreateOutputWindow(text) - else: - if not wx.Thread.IsMain(): - wx.CallAfter(self.text.AppendText, text) - else: - self.text.AppendText(text) - - - def close(self): - if self.frame is not None: - wx.CallAfter(self.frame.Close) - - - def flush(self): - pass - - - -#---------------------------------------------------------------------- - -class App(wx.PyApp): - """ - The ``wx.App`` class represents the application and is used to: - - * bootstrap the wxPython system and initialize the underlying - gui toolkit - * set and get application-wide properties - * implement the native windowing system main message or event loop, - and to dispatch events to window instances - * etc. - - Every wx application must have a single ``wx.App`` instance, and all - creation of UI objects should be delayed until after the ``wx.App`` object - has been created in order to ensure that the gui platform and wxWidgets - have been fully initialized. - - Normally you would derive from this class and implement an ``OnInit`` - method that creates a frame and then calls ``self.SetTopWindow(frame)``, - however ``wx.App`` is also usable on it's own without derivation. - """ - - outputWindowClass = PyOnDemandOutputWindow - - def __init__(self, - redirect=False, - filename=None, - useBestVisual=False, - clearSigInt=True): - """ - Construct a ``wx.App`` object. - - :param redirect: Should ``sys.stdout`` and ``sys.stderr`` be - redirected? Defaults to False. If ``filename`` is None - then output will be redirected to a window that pops up - as needed. (You can control what kind of window is created - for the output by resetting the class variable - ``outputWindowClass`` to a class of your choosing.) - - :param filename: The name of a file to redirect output to, if - redirect is True. - - :param useBestVisual: Should the app try to use the best - available visual provided by the system (only relevant on - systems that have more than one visual.) This parameter - must be used instead of calling `SetUseBestVisual` later - on because it must be set before the underlying GUI - toolkit is initialized. - - :param clearSigInt: Should SIGINT be cleared? This allows the - app to terminate upon a Ctrl-C in the console like other - GUI apps will. - - :note: You should override OnInit to do applicaition - initialization to ensure that the system, toolkit and - wxWidgets are fully initialized. - """ - - wx.PyApp.__init__(self) - - # make sure we can create a GUI - if not self.IsDisplayAvailable(): - - if wx.Port == "__WXMAC__": - msg = """This program needs access to the screen. -Please run with a Framework build of python, and only when you are -logged in on the main display of your Mac.""" - - elif wx.Port == "__WXGTK__": - msg ="Unable to access the X Display, is $DISPLAY set properly?" - - else: - msg = "Unable to create GUI" - # TODO: more description is needed for wxMSW... - - raise SystemExit(msg) - - # This has to be done before OnInit - self.SetUseBestVisual(useBestVisual) - - # Set the default handler for SIGINT. This fixes a problem - # where if Ctrl-C is pressed in the console that started this - # app then it will not appear to do anything, (not even send - # KeyboardInterrupt???) but will later segfault on exit. By - # setting the default handler then the app will exit, as - # expected (depending on platform.) - if clearSigInt: - try: - import signal - signal.signal(signal.SIGINT, signal.SIG_DFL) - except: - pass - - # Save and redirect the stdio to a window? - self.stdioWin = None - self.saveStdio = (_sys.stdout, _sys.stderr) - if redirect: - self.RedirectStdio(filename) - - # Use Python's install prefix as the default - wx.StandardPaths.Get().SetInstallPrefix(_sys.prefix) - -## # Until the new native control for wxMac is up to par, still use the generic one. -## wx.SystemOptions.SetOptionInt("mac.listctrl.always_use_generic", 1) - - # This finishes the initialization of wxWindows and then calls - # the OnInit that should be present in the derived class - self._BootstrapApp() - - - def OnPreInit(self): - """ - Things that must be done after _BootstrapApp has done its thing, but - would be nice if they were already done by the time that OnInit is - called. - """ - wx.StockGDI._initStockObjects() - - - def __del__(self): - self.RestoreStdio() # Just in case the MainLoop was overridden without calling RestoreStio - - - def Destroy(self): -## self.this.own(False) - wx.PyApp.Destroy(self) - - def SetTopWindow(self, frame): - """Set the \"main\" top level window""" - if self.stdioWin: - self.stdioWin.SetParent(frame) - wx.PyApp.SetTopWindow(self, frame) - - - def MainLoop(self): - """Execute the main GUI event loop""" - rv = wx.PyApp.MainLoop(self) - self.RestoreStdio() - return rv - - - def RedirectStdio(self, filename=None): - """Redirect sys.stdout and sys.stderr to a file or a popup window.""" - if filename: - _sys.stdout = _sys.stderr = open(filename, 'a') - else: - self.stdioWin = self.outputWindowClass() - _sys.stdout = _sys.stderr = self.stdioWin - - - def RestoreStdio(self): - try: - _sys.stdout, _sys.stderr = self.saveStdio - except: - pass - - - def SetOutputWindowAttributes(self, title=None, pos=None, size=None): - """ - Set the title, position and/or size of the output window if the stdio - has been redirected. This should be called before any output would - cause the output window to be created. - """ - if self.stdioWin: - if title is not None: - self.stdioWin.title = title - if pos is not None: - self.stdioWin.pos = pos - if size is not None: - self.stdioWin.size = size - -#---------------------------------------------------------------------------- - -@wx.deprecated -class PySimpleApp(App): - """ - This class is deprecated. Please use wx.App instead. - """ - def __init__(self, *args, **kw): - App.__init__(self, *args, **kw) - - -## #---------------------------------------------------------------------------- -## # DO NOT hold any other references to this object. This is how we -## # know when to cleanup system resources that wxWidgets is holding. When -## # the sys module is unloaded, the refcount on sys.__wxPythonCleanup -## # goes to zero and it calls the wx.App_CleanUp function. - -## #class __wxPyCleanup: -## #def __init__(self): -## #self.cleanup = _core_.App_CleanUp -## #def __del__(self): -## #self.cleanup() - -## #_sys.__wxPythonCleanup = __wxPyCleanup() diff --git a/src/core_ex.py b/src/core_ex.py index 52a30317..52f3677e 100644 --- a/src/core_ex.py +++ b/src/core_ex.py @@ -17,24 +17,6 @@ if RELEASE_NUMBER != _core.RELEASE_NUMBER: warnings.warn("wxPython/wxWidgets release number mismatch") del _core - -def version(): - """Returns a string containing version and port info""" - if wx.Port == '__WXMSW__': - port = 'msw' - elif wx.Port == '__WXMAC__': - if 'wxOSX-carbon' in wx.PortInfo: - port = 'osx-carbon' - else: - port = 'osx-cocoa' - elif wx.Port == '__WXGTK__': - port = 'gtk' - if 'gtk2' in wx.PortInfo: - port = 'gtk2' - else: - port = '???' - return "%s %s (phoenix)" % (wx.VERSION_STRING, port) - import warnings class wxPyDeprecationWarning(DeprecationWarning):