From bb2eb659880e9b736c5a69a03c45c3419802306d Mon Sep 17 00:00:00 2001 From: Conrad Huang Date: Sat, 27 Jun 2015 15:18:56 -0700 Subject: [PATCH 1/4] Implement SetExtraControlCreator for wx.FileDialog --- etg/filedlg.py | 61 +++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 56 insertions(+), 5 deletions(-) diff --git a/etg/filedlg.py b/etg/filedlg.py index 5ec041f45..db3751781 100644 --- a/etg/filedlg.py +++ b/etg/filedlg.py @@ -35,13 +35,64 @@ def run(): isinstance(c, etgtools.ClassDef) module.addGlobalStr('wxFileDialogNameStr', c) module.find('wxFileSelectorDefaultWildcardStr').ignore() - - - # TODO: add this back. We'll need a way to pass it a callable that can be - # called from a C ExtraControlCreatorFunction function - c.find('SetExtraControlCreator').ignore() + c.find('ExtraControlCreatorFunction').ignore() + c.find('SetExtraControlCreator').ignore() + c.addHeaderCode("""\ + wxWindow* _callPythonExtraControlCreator(wxWindow* w) + { + wxPyThreadBlocker blocker; + wxWindow* cw = NULL; + PyObject* pyw = sipGetPyObject(w, sipType_wxWindow); + PyObject* ccf = PyObject_GetAttrString(pyw, "_wxExtraControlCreatorFunction"); + if (ccf == NULL) + PyErr_SetString(PyExc_RuntimeError, + "extra control creator function disappeared"); + else { + PyObject* pycw = PyObject_CallFunction(ccf, "O", pyw); + if (pycw != Py_None) { + if (!sipCanConvertToType(pycw, sipType_wxWindow, SIP_NOT_NONE)) + PyErr_Format(PyExc_ValueError, + "control creator did not return wxWindow: %R", pycw); + else { + int iserr = 0; + cw = (wxWindow*) sipConvertToType(pycw, sipType_wxWindow, NULL, + SIP_NOT_NONE, NULL, &iserr); + if (iserr) { + PyErr_Format(PyExc_ValueError, + "conversion failure for control creator " + "return value: %R", pycw); + cw = NULL; + } + } + } + } + return cw; + } + """) + c.addCppMethod('bool', 'SetExtraControlCreator', '(PyObject* ccf)', + doc="""\ + Set extra control creator function to be called during dialog creation""", + body="""\ + bool status = true; + { + wxPyThreadBlocker blocker; + PyObject* pySelf = sipGetPyObject(self, sipType_wxWindow); + if (pySelf == NULL) { + PyErr_SetString(PyExc_ValueError, "expecting wxWindow object"); + status = false; + } + else if (!PyCallable_Check(ccf)) { + PyErr_SetString(PyExc_ValueError, "expecting function or callable object"); + status = false; + } + else if (PyObject_SetAttrString(pySelf, "_wxExtraControlCreatorFunction", ccf) < 0) + status = false; + self->SetExtraControlCreator(_callPythonExtraControlCreator); + } + return status; + """) c.find('GetFilenames').ignore() c.addCppMethod('wxArrayString*', 'GetFilenames', '()', doc="""\ From 8b81aaba8aa8e7af3d48cd531c142602df77d29c Mon Sep 17 00:00:00 2001 From: Conrad Huang Date: Sat, 27 Jun 2015 18:23:19 -0700 Subject: [PATCH 2/4] Check for SetExtraControlCreator callback failure --- etg/filedlg.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/etg/filedlg.py b/etg/filedlg.py index db3751781..b25aab4c3 100644 --- a/etg/filedlg.py +++ b/etg/filedlg.py @@ -51,7 +51,7 @@ def run(): "extra control creator function disappeared"); else { PyObject* pycw = PyObject_CallFunction(ccf, "O", pyw); - if (pycw != Py_None) { + if (pycw != NULL && pycw != Py_None) { if (!sipCanConvertToType(pycw, sipType_wxWindow, SIP_NOT_NONE)) PyErr_Format(PyExc_ValueError, "control creator did not return wxWindow: %R", pycw); From eba2d5f32f3ce60c04aec60f1c4deb6aae5e0a2b Mon Sep 17 00:00:00 2001 From: Robin Dunn Date: Fri, 11 Oct 2019 16:40:04 -0700 Subject: [PATCH 3/4] code cleanup and formatting changes --- etg/filedlg.py | 43 +++++++++++++++++++++++-------------------- 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/etg/filedlg.py b/etg/filedlg.py index 2b836e890..c834c312d 100644 --- a/etg/filedlg.py +++ b/etg/filedlg.py @@ -38,8 +38,8 @@ def run(): module.find('wxFileSelectorDefaultWildcardStr').ignore() c.find('ExtraControlCreatorFunction').ignore() - c.find('SetExtraControlCreator').ignore() + c.addHeaderCode("""\ wxWindow* _callPythonExtraControlCreator(wxWindow* w) { @@ -49,21 +49,21 @@ def run(): PyObject* ccf = PyObject_GetAttrString(pyw, "_wxExtraControlCreatorFunction"); if (ccf == NULL) PyErr_SetString(PyExc_RuntimeError, - "extra control creator function disappeared"); + "extra control creator function disappeared"); else { PyObject* pycw = PyObject_CallFunction(ccf, "O", pyw); if (pycw != NULL && pycw != Py_None) { if (!sipCanConvertToType(pycw, sipType_wxWindow, SIP_NOT_NONE)) PyErr_Format(PyExc_ValueError, - "control creator did not return wxWindow: %R", pycw); + "control creator did not return wxWindow: %R", pycw); else { int iserr = 0; cw = (wxWindow*) sipConvertToType(pycw, sipType_wxWindow, NULL, - SIP_NOT_NONE, NULL, &iserr); + SIP_NOT_NONE, NULL, &iserr); if (iserr) { - PyErr_Format(PyExc_ValueError, - "conversion failure for control creator " - "return value: %R", pycw); + PyErr_Format( + PyExc_ValueError, + "conversion failure for control creator return value: %R", pycw); cw = NULL; } } @@ -72,29 +72,32 @@ def run(): return cw; } """) + c.addCppMethod('bool', 'SetExtraControlCreator', '(PyObject* ccf)', doc="""\ Set extra control creator function to be called during dialog creation""", body="""\ bool status = true; { - wxPyThreadBlocker blocker; - PyObject* pySelf = sipGetPyObject(self, sipType_wxWindow); - if (pySelf == NULL) { - PyErr_SetString(PyExc_ValueError, "expecting wxWindow object"); - status = false; - } - else if (!PyCallable_Check(ccf)) { - PyErr_SetString(PyExc_ValueError, "expecting function or callable object"); - status = false; - } - else if (PyObject_SetAttrString(pySelf, "_wxExtraControlCreatorFunction", ccf) < 0) - status = false; - self->SetExtraControlCreator(_callPythonExtraControlCreator); + wxPyThreadBlocker blocker; + PyObject* pySelf = sipGetPyObject(self, sipType_wxWindow); + if (pySelf == NULL) { + PyErr_SetString(PyExc_ValueError, "expecting wxWindow object"); + status = false; + } + else if (!PyCallable_Check(ccf)) { + PyErr_SetString(PyExc_ValueError, "expecting function or callable object"); + status = false; + } + else if (PyObject_SetAttrString(pySelf, "_wxExtraControlCreatorFunction", ccf) < 0) + status = false; + else + self->SetExtraControlCreator(_callPythonExtraControlCreator); } return status; """) + c.find('GetFilenames').ignore() c.addCppMethod('wxArrayString*', 'GetFilenames', '()', doc="""\ Returns a list of filenames chosen in the dialog. This function From 28fa0ae37447d47ee32b1c1a16ccd848c2ae0822 Mon Sep 17 00:00:00 2001 From: Robin Dunn Date: Tue, 15 Oct 2019 09:56:34 -0700 Subject: [PATCH 4/4] Some tweaks and code reorg, and a note about why it isn't working so far... --- etg/filedlg.py | 54 ++++++++++++++++++++++++++++---------------------- 1 file changed, 30 insertions(+), 24 deletions(-) diff --git a/etg/filedlg.py b/etg/filedlg.py index c834c312d..4cb0bfcc0 100644 --- a/etg/filedlg.py +++ b/etg/filedlg.py @@ -38,15 +38,17 @@ def run(): module.find('wxFileSelectorDefaultWildcardStr').ignore() c.find('ExtraControlCreatorFunction').ignore() - c.find('SetExtraControlCreator').ignore() - c.addHeaderCode("""\ - wxWindow* _callPythonExtraControlCreator(wxWindow* w) + c.addCppCode("""\ + #define ECCF_ATTR_NAME "_wxExtraControlCreatorFunction" + static + wxWindow* wxFileDialog_CallPythonExtraControlCreator(wxWindow* w) { wxPyThreadBlocker blocker; wxWindow* cw = NULL; PyObject* pyw = sipGetPyObject(w, sipType_wxWindow); - PyObject* ccf = PyObject_GetAttrString(pyw, "_wxExtraControlCreatorFunction"); + + PyObject* ccf = PyObject_GetAttrString(pyw, ECCF_ATTR_NAME); if (ccf == NULL) PyErr_SetString(PyExc_RuntimeError, "extra control creator function disappeared"); @@ -73,27 +75,31 @@ def run(): } """) - c.addCppMethod('bool', 'SetExtraControlCreator', '(PyObject* ccf)', - doc="""\ - Set extra control creator function to be called during dialog creation""", - body="""\ - bool status = true; - { - wxPyThreadBlocker blocker; - PyObject* pySelf = sipGetPyObject(self, sipType_wxWindow); - if (pySelf == NULL) { - PyErr_SetString(PyExc_ValueError, "expecting wxWindow object"); - status = false; - } - else if (!PyCallable_Check(ccf)) { - PyErr_SetString(PyExc_ValueError, "expecting function or callable object"); - status = false; - } - else if (PyObject_SetAttrString(pySelf, "_wxExtraControlCreatorFunction", ccf) < 0) - status = false; - else - self->SetExtraControlCreator(_callPythonExtraControlCreator); +# NOTE: The creator function may be called with a window other than this dialog +# (at least on Windows) So we will need a new way to store and find the PyObject +# for the creator function. + + secc = c.find('SetExtraControlCreator') + secc.find('creator').type = 'PyObject*' + secc.argsString = '(PyObject* creator)' + secc.setCppCode("""\ + bool status; + wxPyThreadBlocker blocker; + PyObject* pySelf = sipGetPyObject(self, sipType_wxFileDialog); + + if (pySelf == NULL) { + // This should not ever happen, but just in case... + PyErr_SetString(PyExc_ValueError, "expecting wxFileDialog object"); + status = false; + } + else if (!PyCallable_Check(creator)) { + PyErr_SetString(PyExc_ValueError, "expecting function or callable object"); + status = false; } + else if (PyObject_SetAttrString(pySelf, ECCF_ATTR_NAME, creator) != 0) + status = false; + else + status = self->SetExtraControlCreator(wxFileDialog_CallPythonExtraControlCreator); return status; """)