From 918a70f5a4920cb3149aa12f75d1687ca3d7df43 Mon Sep 17 00:00:00 2001 From: Robin Dunn Date: Fri, 24 Feb 2017 14:32:40 -0800 Subject: [PATCH] Add mapped type for wxPGVariant and switch all wxVariant in propgrid to this type. This allows the variant types only available in propgrid to be used the same as the core variant types. --- etg/_propgrid.py | 3 +- etg/propgrid.py | 7 ++ etg/propgridadvprops.py | 7 ++ etg/propgrideditors.py | 7 ++ etg/propgridiface.py | 8 ++ etg/propgridpagestate.py | 7 ++ etg/propgridproperty.py | 7 ++ etg/propgridprops.py | 7 ++ src/pgvariant.sip | 186 ++++++++++++++++++++++++++++++++++++ unittests/test_pgvariant.py | 82 ++++++++++++++++ 10 files changed, 320 insertions(+), 1 deletion(-) create mode 100644 src/pgvariant.sip create mode 100644 unittests/test_pgvariant.py diff --git a/etg/_propgrid.py b/etg/_propgrid.py index 5e15dddc..706b2cc9 100644 --- a/etg/_propgrid.py +++ b/etg/_propgrid.py @@ -23,7 +23,8 @@ ITEMS = [ ] # The list of other ETG scripts and back-end generator modules that are # included as part of this module. These should all be items that are put in # the wxWidgets "propgrid" library in a multi-lib build. -INCLUDES = [ 'propgriddefs', +INCLUDES = [ 'pgvariant', + 'propgriddefs', 'propgridproperty', 'propgrideditors', 'propgridpagestate', diff --git a/etg/propgrid.py b/etg/propgrid.py index 02ef96b3..70d0eafb 100644 --- a/etg/propgrid.py +++ b/etg/propgrid.py @@ -87,6 +87,13 @@ def run(): """) + # Switch all wxVariant types to wxPGVariant, so the propgrid-specific + # version of the MappedType will be used for converting to/from Python + # objects. + for item in module.allItems(): + if hasattr(item, 'type') and 'wxVariant' in item.type: + item.type = item.type.replace('wxVariant', 'wxPGVariant') + #----------------------------------------------------------------- tools.doCommonTweaks(module) tools.runGenerators(module) diff --git a/etg/propgridadvprops.py b/etg/propgridadvprops.py index 940adc9b..c0ff20ae 100644 --- a/etg/propgridadvprops.py +++ b/etg/propgridadvprops.py @@ -52,6 +52,13 @@ def run(): m.find('value').default = 'wxArrayString()' + # Switch all wxVariant types to wxPGVariant, so the propgrid-specific + # version of the MappedType will be used for converting to/from Python + # objects. + for item in module.allItems(): + if hasattr(item, 'type') and 'wxVariant' in item.type: + item.type = item.type.replace('wxVariant', 'wxPGVariant') + #----------------------------------------------------------------- tools.doCommonTweaks(module) tools.runGenerators(module) diff --git a/etg/propgrideditors.py b/etg/propgrideditors.py index c96a59f7..ef7dc83d 100644 --- a/etg/propgrideditors.py +++ b/etg/propgrideditors.py @@ -45,6 +45,13 @@ def run(): tools.fixWindowClass(c) + # Switch all wxVariant types to wxPGVariant, so the propgrid-specific + # version of the MappedType will be used for converting to/from Python + # objects. + for item in module.allItems(): + if hasattr(item, 'type') and 'wxVariant' in item.type: + item.type = item.type.replace('wxVariant', 'wxPGVariant') + #----------------------------------------------------------------- tools.doCommonTweaks(module) tools.runGenerators(module) diff --git a/etg/propgridiface.py b/etg/propgridiface.py index 3dfb2ecf..07ef3f08 100644 --- a/etg/propgridiface.py +++ b/etg/propgridiface.py @@ -148,6 +148,14 @@ def run(): item.type = 'const wxPGPropArgCls &' + # Switch all wxVariant types to wxPGVariant, so the propgrid-specific + # version of the MappedType will be used for converting to/from Python + # objects. + for item in module.allItems(): + if hasattr(item, 'type') and 'wxVariant' in item.type: + item.type = item.type.replace('wxVariant', 'wxPGVariant') + + #----------------------------------------------------------------- tools.doCommonTweaks(module) tools.runGenerators(module) diff --git a/etg/propgridpagestate.py b/etg/propgridpagestate.py index ccc75741..baed289c 100644 --- a/etg/propgridpagestate.py +++ b/etg/propgridpagestate.py @@ -52,6 +52,13 @@ def run(): module.find('wxPG_IT_CHILDREN').ignore() + # Switch all wxVariant types to wxPGVariant, so the propgrid-specific + # version of the MappedType will be used for converting to/from Python + # objects. + for item in module.allItems(): + if hasattr(item, 'type') and 'wxVariant' in item.type: + item.type = item.type.replace('wxVariant', 'wxPGVariant') + #----------------------------------------------------------------- tools.doCommonTweaks(module) tools.runGenerators(module) diff --git a/etg/propgridproperty.py b/etg/propgridproperty.py index 909136b3..719b1450 100644 --- a/etg/propgridproperty.py +++ b/etg/propgridproperty.py @@ -162,6 +162,13 @@ def run(): """) + # Switch all wxVariant types to wxPGVariant, so the propgrid-specific + # version of the MappedType will be used for converting to/from Python + # objects. + for item in module.allItems(): + if hasattr(item, 'type') and 'wxVariant' in item.type: + item.type = item.type.replace('wxVariant', 'wxPGVariant') + #----------------------------------------------------------------- tools.doCommonTweaks(module) tools.runGenerators(module) diff --git a/etg/propgridprops.py b/etg/propgridprops.py index 3826685d..2dfe9b1b 100644 --- a/etg/propgridprops.py +++ b/etg/propgridprops.py @@ -91,6 +91,13 @@ def run(): tools.fixWindowClass(c, hideVirtuals=False, ignoreProtected=False) + # Switch all wxVariant types to wxPGVariant, so the propgrid-specific + # version of the MappedType will be used for converting to/from Python + # objects. + for item in module.allItems(): + if hasattr(item, 'type') and 'wxVariant' in item.type: + item.type = item.type.replace('wxVariant', 'wxPGVariant') + #----------------------------------------------------------------- tools.doCommonTweaks(module) tools.runGenerators(module) diff --git a/src/pgvariant.sip b/src/pgvariant.sip new file mode 100644 index 00000000..5249e3ac --- /dev/null +++ b/src/pgvariant.sip @@ -0,0 +1,186 @@ +//-------------------------------------------------------------------------- +// Name: pgvariant.sip +// Purpose: MappedType for wxPGVariant +// +// Author: Robin Dunn +// +// Created: 24-Feb-2017 +// Copyright: (c) 2017 by Total Control Software +// Licence: wxWindows license +//-------------------------------------------------------------------------- + +%ModuleHeaderCode +// A wxPGVariant is really the same thing as a wxVariant. We just create +// this new type so a different %MappedType can be created for it that +// also supports the variant data types that are in the propgrid APIs +// instead of core. +typedef wxVariant wxPGVariant; +typedef wxVariantList wxPGVariantList; + +wxVariant wxPGVariant_in_helper(PyObject* source); +PyObject* wxPGVariant_out_helper(const wxVariant& value); +%End + + +%ModuleCode +wxVariant wxPGVariant_in_helper(PyObject* obj) +{ + wxVariant value; + + if (wxPyWrappedPtr_TypeCheck(obj, wxT("wxFont"))) { + wxFont* ptr; + wxPyConvertWrappedPtr(obj, (void**)&ptr, wxT("wxFont")); + value << *ptr; + } + + else if (wxPyWrappedPtr_TypeCheck(obj, wxT("wxPoint"))) { + wxPoint* ptr; + wxPyConvertWrappedPtr(obj, (void**)&ptr, wxT("wxPoint")); + value << *ptr; + } + + else if (wxPyWrappedPtr_TypeCheck(obj, wxT("wxSize"))) { + wxSize* ptr; + wxPyConvertWrappedPtr(obj, (void**)&ptr, wxT("wxSize")); + value << *ptr; + } + + else if (sipCanConvertToType(obj, sipType_wxArrayInt, 0)) { + wxArrayInt* ptr; + int state = 0; + int isErr = 0; + ptr = (wxArrayInt*)sipConvertToType(obj, sipType_wxArrayInt, NULL, 0, &state, &isErr); + value << *ptr; + sipReleaseType(ptr, sipType_wxArrayInt, state); + } + + else + value = wxVariant_in_helper(obj); + return value; +} + + +PyObject* wxPGVariant_out_helper(const wxVariant& value) +{ + PyObject* obj; + + if ( value.IsType("wxFont") ) { + wxFont val; + val << value; + obj = wxPyConstructObject(new wxFont(val), "wxFont", true); + } + + else if ( value.IsType("wxPoint") ) { + const wxPoint& val = wxPointRefFromVariant(value); + obj = wxPyConstructObject(new wxPoint(val), "wxPoint", true); + } + + else if ( value.IsType("wxSize") ) { + const wxSize& val = wxSizeRefFromVariant(value); + obj = wxPyConstructObject(new wxSize(val), "wxSize", true); + } + + else if ( value.IsType("wxArrayInt") ) { + const wxArrayInt& arr = wxArrayIntRefFromVariant(value); + obj = sipConvertFromType((void*)&arr, sipType_wxArrayInt, NULL); + } + + else + obj = wxVariant_out_helper(value); + return obj; +} +%End + + + +%MappedType wxPGVariant /AllowNone/ +{ + %ConvertToTypeCode + // Code to test a PyObject for compatibility. + if (!sipIsErr) { + // Any type should work since we'll just use the PyObject directly + // if the type is not one that is explicitly supported. + return TRUE; + } + + // Code to create a new wxVariant from the PyObject + wxVariant* value = new wxVariant(wxPGVariant_in_helper(sipPy)); + *sipCppPtr = value; + return sipGetState(sipTransferObj); + %End + + + %ConvertFromTypeCode + // Code to convert a wxVariant to a PyObject. + if (sipCpp == NULL) { + return Py_None; + } else { + return wxPGVariant_out_helper(*sipCpp); + } + %End +}; + + + +// Add a typemap for wxVariantList +%MappedType wxPGVariantList +{ + %ConvertToTypeCode + // Code to test a PyObject for compatibility. + if (!sipIsErr) { + // Any type sequence type is okay. + int success = PySequence_Check(sipPy); + if (!success) + PyErr_SetString(PyExc_TypeError, "Sequence type expected."); + return success; + } + + // Code to create a new wxVariantList from the PyObject sequence + wxVariantList* value = new wxVariantList(); + Py_ssize_t len = PySequence_Length(sipPy); + Py_ssize_t idx = 0; + while (idx < len) { + PyObject* item = PySequence_GetItem(sipPy, idx); + value->Append(new wxVariant(wxPGVariant_in_helper(item))); + Py_DECREF(item); + } + *sipCppPtr = value; + return sipGetState(sipTransferObj); + %End + + + %ConvertFromTypeCode + // Code to convert a wxVariantList to a Python list. + if (sipCpp == NULL) { + return Py_None; + } else { + size_t idx = 0; + PyObject* value = PyList_New(0); + for (idx=0; idx < sipCpp->GetCount(); idx++) { + PyObject* item = wxPGVariant_out_helper(sipCpp->Item(idx)); + PyList_Append(value, item); + } + return value; + } + %End +}; + + + + + +// Used just for unit testing the MappedType code, it can be removed later +%ModuleCode +wxPGVariant testPGVariantTypemap(const wxPGVariant& var) +{ + wxVariant local = var; // force a copy + return local; +} + +wxString testPGVariantTypeName(const wxPGVariant& var) +{ + return var.GetType(); +} +%End +wxPGVariant testPGVariantTypemap(const wxPGVariant& var); +wxString testPGVariantTypeName(const wxPGVariant& var); diff --git a/unittests/test_pgvariant.py b/unittests/test_pgvariant.py new file mode 100644 index 00000000..daec0b27 --- /dev/null +++ b/unittests/test_pgvariant.py @@ -0,0 +1,82 @@ +import unittest +from unittests import wtc +import wx +import wx.propgrid as pg + +import six + +#--------------------------------------------------------------------------- + +class pgvariant_Tests(wtc.WidgetTestCase): + + + @unittest.skipIf(not hasattr(pg, 'testPGVariantTypemap'), '') + def test_pgvariant1(self): + d1 = wx.Point(123,456) + d2 = pg.testPGVariantTypemap(d1) + assert isinstance(d2, wx.Point) + assert d1 == d2 + + @unittest.skipIf(not hasattr(pg, 'testPGVariantTypeName'), '') + def test_pgvariant2(self): + d1 = wx.Point(123,456) + assert pg.testPGVariantTypeName(d1) == 'wxPoint' + + + + @unittest.skipIf(not hasattr(pg, 'testPGVariantTypemap'), '') + def test_pgvariant3(self): + d1 = wx.Size(123,456) + d2 = pg.testPGVariantTypemap(d1) + assert isinstance(d2, wx.Size) + assert d1 == d2 + + @unittest.skipIf(not hasattr(pg, 'testPGVariantTypeName'), '') + def test_pgvariant4(self): + d1 = wx.Size(123,456) + assert pg.testPGVariantTypeName(d1) == 'wxSize' + + + + @unittest.skipIf(not hasattr(pg, 'testPGVariantTypemap'), '') + def test_pgvariant5(self): + d1 = wx.Font( wx.FontInfo(10).Bold().Underlined() ) + d2 = pg.testPGVariantTypemap(d1) + assert isinstance(d2, wx.Font) + assert d2.PointSize == 10 + + @unittest.skipIf(not hasattr(pg, 'testPGVariantTypeName'), '') + def test_pgvariant6(self): + d1 = wx.Font( wx.FontInfo(10).Bold().Underlined() ) + assert pg.testPGVariantTypeName(d1) == 'wxFont' + + + + @unittest.skipIf(not hasattr(pg, 'testPGVariantTypemap'), '') + def test_pgvariant7(self): + d1 = [0,1,2,3,4,5,6,7,8,9] + d2 = pg.testPGVariantTypemap(d1) + assert isinstance(d2, list) + assert d1 == d2 + + d1 = (123,456) + d2 = pg.testPGVariantTypemap(d1) + assert isinstance(d2, list) + assert list(d1) == d2 + + @unittest.skipIf(not hasattr(pg, 'testPGVariantTypeName'), '') + def test_pgvariant8(self): + d1 = [0,1,2,3,4,5,6,7,8,9] + assert pg.testPGVariantTypeName(d1) == 'wxArrayInt' + + d1 = (123,456) + assert pg.testPGVariantTypeName(d1) == 'wxArrayInt' + + + + + +#--------------------------------------------------------------------------- + +if __name__ == '__main__': + unittest.main()