mirror of
https://github.com/wxWidgets/Phoenix.git
synced 2026-01-04 19:10:09 +01:00
SIP now does the RightThing with __[sg]etattr__ methods, so use them to provide a simpler implementation for wx.PyEvent and wx.PyCommandEvent. Put any attributes set from Python into a separate dictionary object, and copy that dictionary in Clone().
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxPython/Phoenix/trunk@66489 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
248
src/pyevent.sip
248
src/pyevent.sip
@@ -1,4 +1,4 @@
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//--------------------------------------------------------------------------
|
||||
// Name: pyevent.sip
|
||||
// Purpose: A set of event classes that can be derived from in Python
|
||||
// and that preserve their attributes when cloned.
|
||||
@@ -8,145 +8,185 @@
|
||||
// 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 copying any
|
||||
// attributes added to the Python object for the original event over to the
|
||||
// new cloned event in the Clone method.
|
||||
// The wxPyEvent and wxPyCommandEvent classes can be derived from in Python
|
||||
// and passed through the event system without losing anything.
|
||||
|
||||
%ModuleHeaderCode
|
||||
// This class holds a Python dictionary object and is used to store any
|
||||
// attributes that are set from Python code for the wx.PyEvent and
|
||||
// wx.PyCommandEvent classes. This dictionary is used to make it easy to
|
||||
// transport those attributes over to the clone when wx needs to make a copy
|
||||
// of the event instance.
|
||||
|
||||
// NOTE: This class is intentionally not exposed to SIP (see wxPyEvent
|
||||
// and wxPyCommandEvent)
|
||||
class wxPyEvtDict
|
||||
{
|
||||
public:
|
||||
wxPyEvtDict()
|
||||
{
|
||||
m_dict = PyDict_New();
|
||||
}
|
||||
|
||||
wxPyEvtDict(const wxPyEvtDict& other)
|
||||
{
|
||||
m_dict = PyDict_Copy(other.m_dict);
|
||||
}
|
||||
|
||||
~wxPyEvtDict()
|
||||
{
|
||||
wxPyBlock_t blocked = wxPyBeginBlockThreads();
|
||||
Py_DECREF(m_dict);
|
||||
m_dict = NULL;
|
||||
wxPyEndBlockThreads(blocked);
|
||||
}
|
||||
|
||||
PyObject* _getDict()
|
||||
{
|
||||
Py_INCREF(m_dict);
|
||||
return m_dict;
|
||||
}
|
||||
|
||||
PyObject* __getattr__(PyObject* name)
|
||||
{
|
||||
PyObject* value = NULL;
|
||||
wxPyBlock_t blocked = wxPyBeginBlockThreads();
|
||||
if (PyDict_Contains(m_dict, name)) {
|
||||
value = PyDict_GetItem(m_dict, name);
|
||||
Py_INCREF(value);
|
||||
}
|
||||
else {
|
||||
PyErr_SetObject(PyExc_AttributeError, name);
|
||||
}
|
||||
wxPyEndBlockThreads(blocked);
|
||||
return value;
|
||||
}
|
||||
|
||||
void __setattr__(PyObject* name, PyObject* value)
|
||||
{
|
||||
wxPyBlock_t blocked = wxPyBeginBlockThreads();
|
||||
PyDict_SetItem(m_dict, name, value);
|
||||
wxPyEndBlockThreads(blocked);
|
||||
}
|
||||
|
||||
void __delattr__(PyObject* name)
|
||||
{
|
||||
wxPyBlock_t blocked = wxPyBeginBlockThreads();
|
||||
if (PyDict_Contains(m_dict, name))
|
||||
PyDict_DelItem(m_dict, name);
|
||||
else
|
||||
PyErr_SetObject(PyExc_AttributeError, name);
|
||||
wxPyEndBlockThreads(blocked);
|
||||
}
|
||||
|
||||
protected:
|
||||
PyObject* m_dict;
|
||||
};
|
||||
%End
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
// TODO: Use this comment for a docstring
|
||||
class wxPyEvent : wxEvent
|
||||
{
|
||||
%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. Note that since wx.PyEvent is taking care of
|
||||
preserving the extra attributes that have been set then you do not need to
|
||||
implement the Clone method in your derived classes.
|
||||
|
||||
// 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 {
|
||||
:see: `wx.PyCommandEvent`
|
||||
%End
|
||||
// first declare the C++ version of the class
|
||||
%TypeCode
|
||||
class wxPyEvent : public wxEvent
|
||||
class wxPyEvent : public wxEvent, public wxPyEvtDict
|
||||
{
|
||||
DECLARE_DYNAMIC_CLASS(wxPyEvent)
|
||||
public:
|
||||
wxPyEvent(int winid=0, wxEventType commandType = wxEVT_NULL)
|
||||
: wxEvent(winid, commandType) {}
|
||||
public:
|
||||
wxPyEvent(int id=0, wxEventType eventType = wxEVT_NULL)
|
||||
: wxEvent(id, eventType) {}
|
||||
|
||||
// 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;
|
||||
}
|
||||
virtual wxEvent* Clone() const { return new wxPyEvent(*this); }
|
||||
};
|
||||
IMPLEMENT_DYNAMIC_CLASS(wxPyEvent, wxEvent);
|
||||
%End
|
||||
|
||||
public:
|
||||
wxPyEvent(int winid=0, wxEventType eventType = wxEVT_NULL );
|
||||
|
||||
virtual wxEvent* Clone() const /Factory, NoArgParser/;
|
||||
wxPyEvent(int id=0, wxEventType eventType = wxEVT_NULL );
|
||||
virtual wxEvent* Clone() const /Factory/;
|
||||
|
||||
SIP_PYOBJECT __getattr__(SIP_PYOBJECT name);
|
||||
%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;
|
||||
sipRes = sipCpp->__getattr__(name);
|
||||
%End
|
||||
|
||||
void __setattr__(SIP_PYOBJECT name, SIP_PYOBJECT value);
|
||||
%MethodCode
|
||||
sipCpp->__setattr__(name, value);
|
||||
%End
|
||||
|
||||
void __delattr__(SIP_PYOBJECT name);
|
||||
%MethodCode
|
||||
sipCpp->__delattr__(name);
|
||||
%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 {
|
||||
class wxPyCommandEvent : wxCommandEvent
|
||||
{
|
||||
%Docstring
|
||||
wx.PyCommandEvent can be used as a base class for implementing custom event types
|
||||
in Python. You should derive 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. Note that since wx.PyCommandEvent is taking care of
|
||||
preserving the extra attributes that have been set then you do not need to
|
||||
implement the Clone method in your derived classes.
|
||||
|
||||
:see: `wx.PyEvent`
|
||||
%End
|
||||
// first declare the C++ version of the class
|
||||
%TypeCode
|
||||
class wxPyCommandEvent : public wxCommandEvent
|
||||
class wxPyCommandEvent : public wxCommandEvent, public wxPyEvtDict
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
virtual wxEvent* Clone() const { return new wxPyCommandEvent(*this); }
|
||||
};
|
||||
IMPLEMENT_DYNAMIC_CLASS(wxPyCommandEvent, wxCommandEvent);
|
||||
%End
|
||||
|
||||
public:
|
||||
wxPyCommandEvent(wxEventType eventType = wxEVT_NULL, int id=0);
|
||||
|
||||
virtual wxEvent* Clone() const /Factory, NoArgParser/;
|
||||
virtual wxEvent* Clone() const /Factory/;
|
||||
SIP_PYOBJECT _getDict();
|
||||
|
||||
SIP_PYOBJECT __getattr__(SIP_PYOBJECT name);
|
||||
%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;
|
||||
sipRes = sipCpp->__getattr__(name);
|
||||
%End
|
||||
|
||||
void __setattr__(SIP_PYOBJECT name, SIP_PYOBJECT value);
|
||||
%MethodCode
|
||||
sipCpp->__setattr__(name, value);
|
||||
%End
|
||||
|
||||
void __delattr__(SIP_PYOBJECT name);
|
||||
%MethodCode
|
||||
sipCpp->__delattr__(name);
|
||||
%End
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
// TODO: Temporary testing code, get rid of this later
|
||||
%ModuleCode
|
||||
|
||||
@@ -73,7 +73,7 @@ class PyEvents(unittest2.TestCase):
|
||||
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(rc1 == rc2 == rc3)
|
||||
self.assertTrue(evt1.attr == evt2.attr)
|
||||
|
||||
#def test_AA(self):
|
||||
|
||||
Reference in New Issue
Block a user