Add wxProcess, utils.h and the wx.Py events.

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxPython/Phoenix/trunk@66461 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Robin Dunn
2010-12-27 18:53:41 +00:00
parent 49f7460098
commit 8fffd8c53e
5 changed files with 387 additions and 0 deletions

View File

@@ -53,6 +53,9 @@ INCLUDES = [ 'defs',
'tooltip',
'layout',
'event',
'pyevent',
'process',
'utils',
'evtloop',
'apptrait',

45
etg/process.py Normal file
View File

@@ -0,0 +1,45 @@
#---------------------------------------------------------------------------
# Name: etg/process.py
# Author: Robin Dunn
#
# Created: 19-Dec-2010
# Copyright: (c) 2010 by Total Control Software
# License: wxWindows License
#---------------------------------------------------------------------------
import etgtools
import etgtools.tweaker_tools as tools
PACKAGE = "wx"
MODULE = "_core"
NAME = "process" # Base name of the file to generate to for this script
DOCSTRING = ""
# The classes and/or the basename of the Doxygen XML files to be processed by
# this script.
ITEMS = [ 'wxProcess' ]
#---------------------------------------------------------------------------
def run():
# Parse the XML file(s) building a collection of Extractor objects
module = etgtools.ModuleDef(PACKAGE, MODULE, NAME, DOCSTRING)
etgtools.parseDoxyXML(module, ITEMS)
#-----------------------------------------------------------------
# Tweak the parsed meta objects in the module object as needed for
# customizing the generated code and docstrings.
#-----------------------------------------------------------------
tools.doCommonTweaks(module)
tools.runGenerators(module)
#---------------------------------------------------------------------------
if __name__ == '__main__':
run()

76
etg/utils.py Normal file
View File

@@ -0,0 +1,76 @@
#---------------------------------------------------------------------------
# Name: etg/utils.py
# Author: Robin Dunn
#
# Created: 19-Dec-2010
# Copyright: (c) 2010 by Total Control Software
# License: wxWindows License
#---------------------------------------------------------------------------
import etgtools
import etgtools.tweaker_tools as tools
PACKAGE = "wx"
MODULE = "_core"
NAME = "utils" # Base name of the file to generate to for this script
DOCSTRING = ""
# The classes and/or the basename of the Doxygen XML files to be processed by
# this script.
ITEMS = [ 'utils_8h.xml',
'power_8h.xml',
'wxWindowDisabler',
'wxBusyCursor',
'wxVersionInfo',
]
#---------------------------------------------------------------------------
def run():
# Parse the XML file(s) building a collection of Extractor objects
module = etgtools.ModuleDef(PACKAGE, MODULE, NAME, DOCSTRING)
etgtools.parseDoxyXML(module, ITEMS)
#-----------------------------------------------------------------
# Tweak the parsed meta objects in the module object as needed for
# customizing the generated code and docstrings.
module.addHeaderCode('#include <wx/utils.h>')
module.addHeaderCode('#include <wx/power.h>')
c = module.find('wxWindowDisabler')
assert isinstance(c, etgtools.ClassDef)
c.addPrivateCopyCtor()
module.find('wxQsort').ignore()
module.find('wxGetEmailAddress').findOverload('buf').ignore()
module.find('wxGetHostName').findOverload('buf').ignore()
module.find('wxGetUserId').findOverload('buf').ignore()
module.find('wxGetUserName').findOverload('buf').ignore()
module.find('CMPFUNCDATA').ignore()
module.find('wxLoadUserResource').ignore()
module.find('wxGetFreeMemory').ignore()
module.find('wxGetLinuxDistributionInfo').ignore()
module.find('wxGetDisplayName').ignore()
module.find('wxSetDisplayName').ignore()
module.find('wxPostDelete').ignore()
# ignore all the environment related functions
for item in module.allItems():
if 'Env' in item.name:
item.ignore()
module.find('wxGetenv').ignore()
# Keep just the first wxExecute overload
f = module.find('wxExecute')
f.overloads = []
#-----------------------------------------------------------------
tools.doCommonTweaks(module)
tools.runGenerators(module)
#---------------------------------------------------------------------------
if __name__ == '__main__':
run()

161
src/pyevent.sip Normal file
View File

@@ -0,0 +1,161 @@
/////////////////////////////////////////////////////////////////////////////
// Name: pyevent.sip
// Purpose: A set of event classes that can be derived from in Python
// and that preserve their attributes when cloned.
//
// Author: Robin Dunn
//
// Created: 18-Dec-2010
// Copyright: (c) 2010 by Total Control Software
// Licence: wxWindows license
/////////////////////////////////////////////////////////////////////////////
// These Event classes can be derived from in Python and passed through the
// event system without loosing anything. They do this by keeping a seaparate
// dictionary for storring any extra attributes set from Python code. When the
// event object is cloned then the clone gets a new reference to the same
// dictionary held by the original object.
//---------------------------------------------------------------------------
// TODO: Use this comment for a docstring
// wx.PyEvent can be used as a base class for implementing custom event
// types in Python. You should derive from this class instead of
// `wx.Event` because this class is Python-aware and is able to transport
// its Python bits safely through the wxWidgets event system and have
// them still be there when the event handler is invoked.
// :see: `wx.PyCommandEvent`
class wxPyEvent : wxEvent {
%TypeCode
class wxPyEvent : public wxEvent
{
DECLARE_DYNAMIC_CLASS(wxPyEvent)
public:
wxPyEvent(int winid=0, wxEventType commandType = wxEVT_NULL)
: wxEvent(winid, commandType) {}
// Create a new instance of the Python object for the cloned event,
// and then copy the attributes from the original Python instance to
// the clone.
virtual wxEvent* Clone() const
{
wxPyEvent* newEvent = new wxPyEvent(*this);
wxPyBlock_t blocked = wxPyBeginBlockThreads();
PyObject* thisObj = sipGetPyObject((void*)this, sipType_wxPyEvent);
PyObject* newObj = sipConvertFromType((void*)newEvent,
sipType_wxPyEvent,
NULL);
PyObject* newDict = PyObject_GetAttrString(newObj, "__dict__");
PyObject* thisDict = PyObject_GetAttrString(thisObj, "__dict__");
PyDict_Update(newDict, thisDict);
Py_DECREF(newDict);
Py_DECREF(thisDict);
wxPyEndBlockThreads(blocked);
return newEvent;
}
};
IMPLEMENT_DYNAMIC_CLASS(wxPyEvent, wxEvent);
%End
public:
wxPyEvent(int winid=0, wxEventType eventType = wxEVT_NULL );
virtual wxEvent* Clone() const /Factory, NoArgParser/;
%MethodCode
PyObject *sipParseErr = NULL;
bool sipSelfWasArg = (!sipSelf || sipIsDerived((sipSimpleWrapper *)sipSelf));
wxPyEvent *sipCpp;
if (sipParseArgs(&sipParseErr, sipArgs, "B", &sipSelf, sipType_wxPyEvent, &sipCpp))
{
wxEvent *sipRes;
sipRes = (sipSelfWasArg ? sipCpp->wxPyEvent::Clone() : sipCpp->Clone());
// Note that this MethodCode is nearly identical to what is normally generated,
// except for the following lines. wxPyEvent::Clone already made a PyObject,
// so just fetch it.
PyObject* obj = sipGetPyObject(sipRes, sipType_wxPyEvent);
sipTransferBack(obj);
return obj;
}
sipNoMethod(sipParseErr, sipName_PyEvent, sipName_Clone, NULL); //doc_wxPyEvent_Clone);
return NULL;
%End
};
// wx.PyCommandEvent can be used as a base class for implementing custom
// event types in Python, where the event should travel up to parent
// windows looking for a handler. You should derived from this class
// instead of `wx.CommandEvent` because this class is Python-aware and is
// able to transport its Python bits safely through the wxWidgets event
// system and have them still be there when the event handler is invoked.
// :see: `wx.PyEvent`
class wxPyCommandEvent : wxCommandEvent {
%TypeCode
class wxPyCommandEvent : public wxCommandEvent
{
DECLARE_DYNAMIC_CLASS(wxPyCommandEvent)
public:
wxPyCommandEvent(wxEventType eventType = wxEVT_NULL, int id=0)
: wxCommandEvent(eventType, id) {}
// Create a new instance of the Python object for the cloned event,
// and then copy the attributes from the original Python instance to
// the clone.
virtual wxEvent* Clone() const
{
wxPyCommandEvent* newEvent = new wxPyCommandEvent(*this);
wxPyBlock_t blocked = wxPyBeginBlockThreads();
PyObject* thisObj = sipGetPyObject((void*)this, sipType_wxPyCommandEvent);
PyObject* newObj = sipConvertFromNewType((void*)newEvent,
sipType_wxPyCommandEvent,
NULL);
PyObject* newDict = PyObject_GetAttrString(newObj, "__dict__");
PyObject* thisDict = PyObject_GetAttrString(thisObj, "__dict__");
PyDict_Update(newDict, thisDict);
Py_DECREF(newDict);
Py_DECREF(thisDict);
wxPyEndBlockThreads(blocked);
return newEvent;
}
};
IMPLEMENT_DYNAMIC_CLASS(wxPyCommandEvent, wxCommandEvent);
%End
public:
wxPyCommandEvent(wxEventType eventType = wxEVT_NULL, int id=0);
virtual wxEvent* Clone() const /Factory, NoArgParser/;
%MethodCode
PyObject *sipParseErr = NULL;
bool sipSelfWasArg = (!sipSelf || sipIsDerived((sipSimpleWrapper *)sipSelf));
wxPyCommandEvent *sipCpp;
if (sipParseArgs(&sipParseErr, sipArgs, "B", &sipSelf, sipType_wxPyCommandEvent, &sipCpp))
{
wxEvent *sipRes;
sipRes = (sipSelfWasArg ? sipCpp->wxPyCommandEvent::Clone() : sipCpp->Clone());
// Note that this MethodCode is nearly identical to what is normally generated,
// except for the following lines. wxPyCommandEvent::Clone already made a PyObject,
// so just fetch it.
PyObject* obj = sipGetPyObject(sipRes, sipType_wxPyCommandEvent);
sipTransferBack(obj);
return obj;
}
sipNoMethod(sipParseErr, sipName_PyCommandEvent, sipName_Clone, NULL); //doc_wxPyEvent_Clone);
return NULL;
%End
};
// TODO: Temporary testing code, get rid of this later
%ModuleCode
wxEvent* testCppClone(wxEvent& evt)
{
return evt.Clone();
}
%End
wxEvent* testCppClone(wxEvent& evt);

102
unittests/test_pyevent.py Normal file
View File

@@ -0,0 +1,102 @@
import sys
import unittest2
import wxPhoenix as wx
##import os; print 'PID:', os.getpid(); raw_input('Ready to start, press enter...')
from wxPhoenix import siplib
#---------------------------------------------------------------------------
class PyEvents(unittest2.TestCase):
def test_PyEvent(self):
id = wx.NewId()
typ = wx.NewEventType()
evt = wx.PyEvent(id, typ)
evt.newAttr = "hello"
evt2 = evt.Clone()
self.assertTrue(type(evt2) == wx.PyEvent)
self.assertTrue(evt is not evt2)
self.assertTrue(getattr(evt2, 'newAttr'))
self.assertTrue(evt.newAttr == evt2.newAttr)
self.assertTrue(evt.Id == evt2.Id)
self.assertTrue(evt.EventType == evt2.EventType)
def test_PyCommandEvent(self):
id = wx.NewId()
typ = wx.NewEventType()
evt = wx.PyCommandEvent(id, typ)
evt.newAttr = "hello"
evt2 = evt.Clone()
self.assertTrue(type(evt2) == wx.PyCommandEvent)
self.assertTrue(evt is not evt2)
self.assertTrue(getattr(evt2, 'newAttr'))
self.assertTrue(evt.newAttr == evt2.newAttr)
self.assertTrue(evt.Id == evt2.Id)
self.assertTrue(evt.EventType == evt2.EventType)
def test_PyEvtCloneRefCounts(self):
# Since we're doing some funky stuff under the covers with Clone, make
# sure that the reference counts on everything (before and after)
# still make sense
evt1 = wx.PyEvent()
rc1 = sys.getrefcount(evt1)
evt1.attr = 'Howdy!'
evt2 = evt1.Clone()
rc2 = sys.getrefcount(evt2)
rc3 = sys.getrefcount(evt1)
#print '\n****', rc1, rc2, rc3
self.assertTrue(rc1 == rc2 == rc3)
self.assertTrue(evt1.attr == evt2.attr)
def test_CppClone(self):
# test what happens when Clone is called from C++
if hasattr(wx, 'testCppClone'):
evt1 = wx.PyEvent()
evt1.attr = 'testCppClone'
evt2 = wx.testCppClone(evt1)
self.assertTrue(evt1.attr == evt2.attr)
def test_CppCloneRefCounts(self):
# Since we're doing some funky stuff under the covers with Clone, make
# sure that the reference counts on everything (before and after)
# still make sense
if hasattr(wx, 'testCppClone'):
evt1 = wx.PyEvent()
rc1 = sys.getrefcount(evt1)
evt1.attr = 'Howdy!'
evt2 = wx.testCppClone(evt1)
rc2 = sys.getrefcount(evt2)
rc3 = sys.getrefcount(evt1)
#print '\n****', rc1, rc2, rc3
##self.assertTrue(rc1 == rc2 == rc3) TODO: rc2 has an extra refcount. Why?
self.assertTrue(evt1.attr == evt2.attr)
#def test_AA(self):
#class MyEvent(wx.PyEvent):
#def __init__(self, name):
#wx.PyEvent.__init__(self)
#self.name = name
#def __del__(self):
#print '\n-=-=-= __del__:', self.name
#evt1 = MyEvent('orig')
#evt2 = evt1.Clone()
#evt2.name += ' clone'
#evt3 = wx.testCppClone(evt1)
#evt3.name += ' clone2'
#print sys.getrefcount(evt1), sys.getrefcount(evt2), sys.getrefcount(evt3)
#print siplib.ispyowned(evt1), siplib.ispyowned(evt2), siplib.ispyowned(evt3)
#del evt1, evt2
#print 'deleted'
#evt3.Destroy()
#---------------------------------------------------------------------------
if __name__ == '__main__':
unittest2.main()