generic wrapper/unwrapper for PySide and PyQt classes

This commit is contained in:
wmayer
2018-08-18 19:21:23 +02:00
parent de66ab3d1a
commit e701f75c25

View File

@@ -31,9 +31,11 @@
# include <QMetaType>
#endif
// Uncomment this block to remove PySide support and switch back to PyQt
// #undef HAVE_SHIBOKEN
// #undef HAVE_PYSIDE
// Uncomment this block to remove PySide C++ support and switch to its Python interface
//#undef HAVE_SHIBOKEN
//#undef HAVE_PYSIDE
//#undef HAVE_SHIBOKEN2
//#undef HAVE_PYSIDE2
#ifdef FC_OS_WIN32
#undef max
@@ -187,6 +189,63 @@ void registerTypes()
// --------------------------------------------------------
namespace Gui {
template<typename qttype>
Py::Object qt_wrapInstance(qttype object, const char* className,
const char* shiboken, const char* pyside,
const char* wrap)
{
PyObject* module = PyImport_ImportModule(shiboken);
if (!module) {
std::string error = "Cannot load ";
error += shiboken;
error += " module";
throw Py::Exception(PyExc_ImportError, error);
}
Py::Module mainmod(module, true);
Py::Callable func = mainmod.getDict().getItem(wrap);
Py::Tuple arguments(2);
arguments[0] = Py::asObject(PyLong_FromVoidPtr((void*)object));
module = PyImport_ImportModule(pyside);
if (!module) {
std::string error = "Cannot load ";
error += pyside;
error += " module";
throw Py::Exception(PyExc_ImportError, error);
}
Py::Module qtmod(module);
arguments[1] = qtmod.getDict().getItem(className);
return func.apply(arguments);
}
void* qt_getCppPointer(const Py::Object& pyobject, const char* shiboken, const char* unwrap)
{
// https://github.com/PySide/Shiboken/blob/master/shibokenmodule/typesystem_shiboken.xml
PyObject* module = PyImport_ImportModule(shiboken);
if (!module) {
std::string error = "Cannot load ";
error += shiboken;
error += " module";
throw Py::Exception(PyExc_ImportError, error);
}
Py::Module mainmod(module, true);
Py::Callable func = mainmod.getDict().getItem(unwrap);
Py::Tuple arguments(1);
arguments[0] = pyobject; //PySide pointer
Py::Tuple result(func.apply(arguments));
void* ptr = PyLong_AsVoidPtr(result[0].ptr());
return ptr;
}
}
// --------------------------------------------------------
PythonWrapper::PythonWrapper()
{
#if defined (HAVE_SHIBOKEN)
@@ -235,7 +294,6 @@ QObject* PythonWrapper::toQObject(const Py::Object& pyobject)
{
// http://pastebin.com/JByDAF5Z
#if defined (HAVE_SHIBOKEN) && defined(HAVE_PYSIDE)
#if 1
PyTypeObject * type = Shiboken::SbkType<QObject>();
if (type) {
if (Shiboken::Object::checkType(pyobject.ptr())) {
@@ -244,33 +302,20 @@ QObject* PythonWrapper::toQObject(const Py::Object& pyobject)
return reinterpret_cast<QObject*>(cppobject);
}
}
#else // does the same using shiboken's Python interface
// https://github.com/PySide/Shiboken/blob/master/shibokenmodule/typesystem_shiboken.xml
PyObject* module = PyImport_ImportModule((char*)"shiboken");
if (!module)
throw Py::Exception(PyExc_ImportError, "Cannot load shiboken module");
Py::Module mainmod(module, true);
Py::Callable func = mainmod.getDict().getItem("getCppPointer");
Py::Tuple arguments(1);
arguments[0] = pyobject; //PySide pointer
Py::Tuple result(func.apply(arguments));
void* ptr = PyLong_AsVoidPtr(result[0].ptr());
#elif QT_VERSION >= 0x050000
// Access shiboken2/PySide2 via Python
//
void* ptr = qt_getCppPointer(pyobject, "shiboken2", "getCppPointer");
return reinterpret_cast<QObject*>(ptr);
#else
// Access shiboken/PySide via Python
//
void* ptr = qt_getCppPointer(pyobject, "shiboken", "getCppPointer");
return reinterpret_cast<QObject*>(ptr);
#endif
#else
PyObject* module = PyImport_ImportModule((char*)"sip");
if (!module)
throw Py::Exception(PyExc_ImportError, "Cannot load sip module");
Py::Module mainmod(module, true);
Py::Callable func = mainmod.getDict().getItem("unwrapinstance");
Py::Tuple arguments(1);
arguments[0] = pyobject; //PyQt pointer
Py::Object result = func.apply(arguments);
void* ptr = PyLong_AsVoidPtr(result.ptr());
#if 0 // Unwrapping using sip/PyQt
void* ptr = qt_getCppPointer(pyobject, "sip", "unwrapinstance");
return reinterpret_cast<QObject*>(ptr);
#endif
@@ -285,8 +330,14 @@ Py::Object PythonWrapper::fromQIcon(const QIcon* icon)
const_cast<QIcon*>(icon), true, false, typeName);
if (pyobj)
return Py::asObject(pyobj);
#elif QT_VERSION >= 0x050000
// Access shiboken2/PySide2 via Python
//
return qt_wrapInstance<const QIcon*>(icon, "QIcon", "shiboken2", "PySide2.QtGui", "wrapInstance");
#else
Q_UNUSED(icon);
// Access shiboken/PySide via Python
//
return qt_wrapInstance<const QIcon*>(icon, "QIcon", "shiboken", "PySide.QtGui", "wrapInstance");
#endif
throw Py::RuntimeError("Failed to wrap icon");
}
@@ -294,7 +345,8 @@ Py::Object PythonWrapper::fromQIcon(const QIcon* icon)
Py::Object PythonWrapper::fromQWidget(QWidget* widget, const char* className)
{
#if defined (HAVE_SHIBOKEN) && defined(HAVE_PYSIDE)
#if 1
// Access shiboken/PySide via C++
//
PyTypeObject * type = Shiboken::SbkType<QWidget>();
if (type) {
SbkObjectType* sbk_type = reinterpret_cast<SbkObjectType*>(type);
@@ -307,50 +359,24 @@ Py::Object PythonWrapper::fromQWidget(QWidget* widget, const char* className)
return Py::asObject(pyobj);
}
throw Py::RuntimeError("Failed to wrap widget");
#else // does the same using shiboken's Python interface
PyObject* module = PyImport_ImportModule((char*)"shiboken");
if (!module)
throw Py::Exception(PyExc_ImportError, "Cannot load shiboken module");
Py::Module mainmod(module, true);
Py::Callable func = mainmod.getDict().getItem("wrapInstance");
Py::Tuple arguments(2);
arguments[0] = Py::asObject(PyLong_FromVoidPtr(widget));
module = PyImport_ImportModule((char*)"PySide.QtGui");
if (!module)
throw Py::Exception(PyExc_ImportError, "Cannot load PySide.QtGui module");
Py::Module qtmod(module);
arguments[1] = qtmod.getDict().getItem(className);
return func.apply(arguments);
#endif
#elif QT_VERSION >= 0x050000
// Access shiboken2/PySide2 via Python
//
return qt_wrapInstance<QWidget*>(widget, className, "shiboken2", "PySide2.QtWidgets", "wrapInstance");
#else
// Access shiboken/PySide via Python
//
return qt_wrapInstance<QWidget*>(widget, className, "shiboken", "PySide.QtGui", "wrapInstance");
#endif
#if 0 // Unwrapping using sip/PyQt
Q_UNUSED(className);
PyObject* module = PyImport_ImportModule((char*)"sip");
if (!module)
throw Py::Exception(PyExc_ImportError, "Cannot load sip module");
Py::Module sipmod(module, true);
Py::Callable func = sipmod.getDict().getItem("wrapinstance");
Py::Tuple arguments(2);
arguments[0] = Py::asObject(PyLong_FromVoidPtr(widget));
#if QT_VERSION >= 0x050000
module = PyImport_ImportModule((char*)"PyQt5.QtWidgets");
if (!module)
throw Py::Exception(PyExc_ImportError, "Cannot load PyQt5.QtWidgets module");
return qt_wrapInstance<QWidget*>(widget, "QWidget", "sip", "PyQt5.QtWidgets", "wrapinstance");
#else
module = PyImport_ImportModule((char*)"PyQt4.Qt");
if (!module)
throw Py::Exception(PyExc_ImportError, "Cannot load PyQt4.Qt module");
return qt_wrapInstance<QWidget*>(widget, "QWidget", "sip", "PyQt4.Qt", "wrapinstance");
#endif
Py::Module qtmod(module);
arguments[1] = qtmod.getDict().getItem("QWidget");
return func.apply(arguments);
#endif
}
@@ -366,10 +392,17 @@ const char* PythonWrapper::getWrapperName(QObject* obj) const
meta = meta->superClass();
}
#else
Q_UNUSED(obj);
QUiLoader ui;
QStringList names = ui.availableWidgets();
const QMetaObject* meta = obj->metaObject();
while (meta) {
const char* typeName = meta->className();
if (names.indexOf(QLatin1String(typeName)) >= 0)
return typeName;
meta = meta->superClass();
}
#endif
return nullptr;
return "QObject";
}
bool PythonWrapper::loadCoreModule()