Files
create/src/Gui/PythonWrapper.cpp
2024-02-22 11:47:48 +01:00

831 lines
26 KiB
C++

/***************************************************************************
* Copyright (c) 2021 Werner Mayer <wmayer[at]users.sourceforge.net> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#include "PreCompiled.h"
#ifndef _PreComp_
# include <limits>
# include <unordered_map>
# include <list>
# include <QApplication>
# include <QDir>
# include <QIcon>
# include <QPrinter>
# include <QWidget>
#endif
#include <QMetaType>
// Uncomment this block to remove PySide C++ support and switch to its Python interface
//#undef HAVE_SHIBOKEN2
//#undef HAVE_PYSIDE2
//#undef HAVE_SHIBOKEN6
//#undef HAVE_PYSIDE6
#ifdef FC_OS_WIN32
#undef max
#undef min
#ifdef _MSC_VER
#pragma warning( disable : 4099 )
#pragma warning( disable : 4522 )
#endif
#endif
#if defined(__clang__)
# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wmismatched-tags"
# pragma clang diagnostic ignored "-Wunused-parameter"
# if __clang_major__ > 3
# pragma clang diagnostic ignored "-Wkeyword-macro"
# endif
#elif defined (__GNUC__)
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wunused-parameter"
# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#endif
//-----------------------------------------------------------------------------
//
// shiboken2 and PySide2 specific defines and includes
//
// class and struct used for SbkObject
//
#ifdef HAVE_SHIBOKEN2
# define HAVE_SHIBOKEN
# ifdef HAVE_PYSIDE2
# define HAVE_PYSIDE
// Since version 5.12 shiboken offers a method to get wrapper by class name (typeForTypeName)
// This helps to avoid to include the PySide2 headers since MSVC has a compiler bug when
// compiling together with std::bitset (https://bugreports.qt.io/browse/QTBUG-72073)
// Do not use SHIBOKEN_MICRO_VERSION; it might contain a dot
# define SHIBOKEN_FULL_VERSION QT_VERSION_CHECK(SHIBOKEN_MAJOR_VERSION, SHIBOKEN_MINOR_VERSION, 0)
# if (SHIBOKEN_FULL_VERSION >= QT_VERSION_CHECK(5, 12, 0))
# define HAVE_SHIBOKEN_TYPE_FOR_TYPENAME
# endif
# ifndef HAVE_SHIBOKEN_TYPE_FOR_TYPENAME
# include <pyside2_qtcore_python.h>
# include <pyside2_qtgui_python.h>
# include <pyside2_qtwidgets_python.h>
# endif
# endif // HAVE_PYSIDE2
#endif // HAVE_SHIBOKEN2
//-----------------------------------------------------------------------------
//
// shiboken6 and PySide6 specific defines and includes
//
// class and struct used for SbkObject
//
#ifdef HAVE_SHIBOKEN6
# define HAVE_SHIBOKEN
# ifdef HAVE_PYSIDE6
# define HAVE_PYSIDE
# define HAVE_SHIBOKEN_TYPE_FOR_TYPENAME
# endif // HAVE_PYSIDE6
#endif // HAVE_SHIBOKEN6
//-----------------------------------------------------------------------------
#ifdef HAVE_SHIBOKEN
# undef _POSIX_C_SOURCE
# undef _XOPEN_SOURCE
# include <basewrapper.h>
# include <sbkconverter.h>
# include <sbkmodule.h>
# include <shiboken.h>
#endif // HAVE_SHIBOKEN
#ifdef HAVE_PYSIDE
# include <signalmanager.h>
#endif // HAVE_PYSIDE
//-----------------------------------------------------------------------------
#if defined(__clang__)
# pragma clang diagnostic pop
#elif defined (__GNUC__)
# pragma GCC diagnostic pop
#endif
// Must be imported after PySide headers
#ifndef _PreComp_
# include <QGraphicsItem>
# include <QGraphicsObject>
#endif
#include <App/Application.h>
#include <Base/Interpreter.h>
#include <Base/Quantity.h>
#include <Base/QuantityPy.h>
#include "PythonWrapper.h"
#include "UiLoader.h"
#include "MetaTypes.h"
// NOLINTBEGIN
#if defined(HAVE_SHIBOKEN2)
PyTypeObject** SbkPySide2_QtCoreTypes = nullptr;
PyTypeObject** SbkPySide2_QtGuiTypes = nullptr;
PyTypeObject** SbkPySide2_QtWidgetsTypes = nullptr;
PyTypeObject** SbkPySide2_QtPrintSupportTypes = nullptr;
PyTypeObject** SbkPySide2_QtUiToolsTypes = nullptr;
constexpr auto &SbkPySide_QtCoreTypes = SbkPySide2_QtCoreTypes;
constexpr auto &SbkPySide_QtGuiTypes = SbkPySide2_QtGuiTypes;
constexpr auto &SbkPySide_QtWidgetsTypes = SbkPySide2_QtWidgetsTypes;
constexpr auto &SbkPySide_QtPrintSupportTypes = SbkPySide2_QtPrintSupportTypes;
constexpr auto &SbkPySide_QtUiToolsTypes = SbkPySide2_QtUiToolsTypes;
#if !defined(HAVE_PYSIDE2)
constexpr const char* ModuleShiboken = "shiboken2";
#endif
constexpr const char* ModulePySide = "PySide2";
#elif defined(HAVE_SHIBOKEN6)
PyTypeObject** SbkPySide6_QtCoreTypes = nullptr;
PyTypeObject** SbkPySide6_QtGuiTypes = nullptr;
PyTypeObject** SbkPySide6_QtWidgetsTypes = nullptr;
PyTypeObject** SbkPySide6_QtPrintSupportTypes = nullptr;
PyTypeObject** SbkPySide6_QtUiToolsTypes = nullptr;
constexpr auto &SbkPySide_QtCoreTypes = SbkPySide6_QtCoreTypes;
constexpr auto &SbkPySide_QtGuiTypes = SbkPySide6_QtGuiTypes;
constexpr auto &SbkPySide_QtWidgetsTypes = SbkPySide6_QtWidgetsTypes;
constexpr auto &SbkPySide_QtPrintSupportTypes = SbkPySide6_QtPrintSupportTypes;
constexpr auto &SbkPySide_QtUiToolsTypes = SbkPySide6_QtUiToolsTypes;
#if !defined(HAVE_PYSIDE6)
constexpr const char* ModuleShiboken = "shiboken6";
#endif
constexpr const char* ModulePySide = "PySide6";
#else
static PyTypeObject** SbkPySide_DummyTypes;
constexpr auto &SbkPySide_QtCoreTypes = SbkPySide_DummyTypes;
constexpr auto &SbkPySide_QtGuiTypes = SbkPySide_DummyTypes;
constexpr auto &SbkPySide_QtWidgetsTypes = SbkPySide_DummyTypes;
constexpr auto &SbkPySide_QtPrintSupportTypes = SbkPySide_DummyTypes;
constexpr auto &SbkPySide_QtUiToolsTypes = SbkPySide_DummyTypes;
# if QT_VERSION < QT_VERSION_CHECK(6,0,0)
constexpr const char* ModuleShiboken = "shiboken2";
constexpr const char* ModulePySide = "PySide2";
# else
constexpr const char* ModuleShiboken = "shiboken6";
constexpr const char* ModulePySide = "PySide6";
# endif
#endif
// NOLINTEND
using namespace Gui;
#if defined (HAVE_SHIBOKEN)
/**
Example:
\code
ui = FreeCADGui.UiLoader()
w = ui.createWidget("Gui::InputField")
w.show()
w.property("quantity")
\endcode
*/
PyObject* toPythonFuncQuantityTyped(Base::Quantity cpx)
{
return new Base::QuantityPy(new Base::Quantity(cpx));
}
PyObject* toPythonFuncQuantity(const void* cpp)
{
return toPythonFuncQuantityTyped(*static_cast<const Base::Quantity*>(cpp));
}
void toCppPointerConvFuncQuantity(PyObject* pyobj,void* cpp)
{
*static_cast<Base::Quantity*>(cpp) = *static_cast<Base::QuantityPy*>(pyobj)->getQuantityPtr();
}
PythonToCppFunc toCppPointerCheckFuncQuantity(PyObject* obj)
{
if (PyObject_TypeCheck(obj, &(Base::QuantityPy::Type))) {
return toCppPointerConvFuncQuantity;
}
return nullptr;
}
void BaseQuantity_PythonToCpp_QVariant(PyObject* pyIn, void* cppOut)
{
Base::Quantity* q = static_cast<Base::QuantityPy*>(pyIn)->getQuantityPtr();
*((QVariant*)cppOut) = QVariant::fromValue<Base::Quantity>(*q);
}
PythonToCppFunc isBaseQuantity_PythonToCpp_QVariantConvertible(PyObject* obj)
{
if (PyObject_TypeCheck(obj, &(Base::QuantityPy::Type))) {
return BaseQuantity_PythonToCpp_QVariant;
}
return nullptr;
}
#if defined (HAVE_PYSIDE)
Base::Quantity convertWrapperToQuantity(const PySide::PyObjectWrapper &w)
{
auto pyIn = static_cast<PyObject*>(w);
if (PyObject_TypeCheck(pyIn, &(Base::QuantityPy::Type))) {
return *static_cast<Base::QuantityPy*>(pyIn)->getQuantityPtr();
}
return Base::Quantity(std::numeric_limits<double>::quiet_NaN());
}
#endif
void registerTypes()
{
SbkConverter* convert = Shiboken::Conversions::createConverter(&Base::QuantityPy::Type,
toPythonFuncQuantity);
Shiboken::Conversions::setPythonToCppPointerFunctions(convert,
toCppPointerConvFuncQuantity,
toCppPointerCheckFuncQuantity);
Shiboken::Conversions::registerConverterName(convert, "Base::Quantity");
SbkConverter* qvariant_conv = Shiboken::Conversions::getConverter("QVariant");
if (qvariant_conv) {
// The type QVariant already has a converter from PyBaseObject_Type which will
// come before our own converter.
Shiboken::Conversions::addPythonToCppValueConversion(qvariant_conv,
BaseQuantity_PythonToCpp_QVariant,
isBaseQuantity_PythonToCpp_QVariantConvertible);
}
#if defined (HAVE_PYSIDE)
QMetaType::registerConverter<PySide::PyObjectWrapper, Base::Quantity>(&convertWrapperToQuantity);
#endif
}
#endif
// --------------------------------------------------------
namespace Gui {
static std::string getPySideModuleName(const std::string& moduleName)
{
std::string name(ModulePySide);
name += '.';
name += moduleName;
return name;
}
static bool loadPySideModule(const std::string& moduleName, PyTypeObject**& types)
{
#if defined (HAVE_SHIBOKEN) && defined(HAVE_PYSIDE)
if (!types) {
Shiboken::AutoDecRef requiredModule(Shiboken::Module::import(getPySideModuleName(moduleName).c_str()));
if (requiredModule.isNull()) {
return false;
}
types = Shiboken::Module::getTypes(requiredModule);
}
#else
Q_UNUSED(moduleName)
Q_UNUSED(types)
#endif
return true;
}
#if defined (HAVE_SHIBOKEN) && defined(HAVE_PYSIDE)
template<typename qttype>
#if defined (HAVE_SHIBOKEN2)
SbkObjectType*
#else
PyTypeObject*
#endif
getPyTypeObjectForTypeName()
{
#if defined (HAVE_SHIBOKEN_TYPE_FOR_TYPENAME)
# if defined (HAVE_SHIBOKEN2)
auto sbkType = Shiboken::ObjectType::typeForTypeName(typeid(qttype).name());
if (sbkType) {
return reinterpret_cast<SbkObjectType*>&(sbkType->type);
}
# else
return Shiboken::ObjectType::typeForTypeName(typeid(qttype).name());
# endif
#else
# if defined (HAVE_SHIBOKEN2)
return reinterpret_cast<SbkObjectType*>(Shiboken::SbkType<qttype>());
# else
return Shiboken::SbkType<qttype>();
# endif
#endif
}
template<typename qttype>
qttype* qt_getCppType(PyObject* pyobj)
{
auto type = getPyTypeObjectForTypeName<qttype>();
if (type) {
if (Shiboken::Object::checkType(pyobj)) {
auto skbobj = reinterpret_cast<SbkObject *>(pyobj);
auto pytypeobj = reinterpret_cast<PyTypeObject *>(type);
return static_cast<qttype*>(Shiboken::Object::cppPointer(skbobj, pytypeobj));
}
}
return nullptr;
}
/*!
* \brief The WrapperManager class
* This is a helper class that records the Python wrappers of a QObject and invalidates
* them when the QObject is about to be destroyed.
* This is to make sure that if the Python wrapper doesn't own the QObject it won't be notified
* if the QObject is destroyed.
* \code
* ui = Gui.UiLoader()
* lineedit = ui.createWidget("QLineEdit")
* lineedit.deleteLater()
* # Make sure this won't crash
* lineedit.show()
* \endcode
*/
class WrapperManager : public QObject
{
public:
static WrapperManager& instance()
{
static WrapperManager singleton;
return singleton;
}
/*!
* \brief addQObject
* \param obj
* \param pyobj
* Connects destruction event of a QObject with invalidation of its PythonWrapper via a helper QObject.
*/
void addQObject(QObject* obj, PyObject* pyobj)
{
const auto PyW_unique_name = QString::number(reinterpret_cast <quintptr> (pyobj));
auto PyW_invalidator = findChild <QObject *> (PyW_unique_name, Qt::FindDirectChildrenOnly);
if (PyW_invalidator == nullptr) {
PyW_invalidator = new QObject(this);
PyW_invalidator->setObjectName(PyW_unique_name);
Py_INCREF (pyobj);
}
else {
PyW_invalidator->disconnect();
}
auto destroyedFun = [pyobj](){
Base::PyGILStateLocker lock;
auto sbk_ptr = reinterpret_cast <SbkObject *> (pyobj);
if (sbk_ptr != nullptr) {
Shiboken::Object::setValidCpp(sbk_ptr, false);
}
else {
Base::Console().DeveloperError("WrapperManager", "A QObject has just been destroyed after its Pythonic wrapper.\n");
}
Py_DECREF (pyobj);
};
QObject::connect(PyW_invalidator, &QObject::destroyed, this, destroyedFun);
QObject::connect(obj, &QObject::destroyed, PyW_invalidator, &QObject::deleteLater);
}
private:
void wrapQApplication()
{
// We have to explicitly hold a reference to the wrapper of the QApplication
// as otherwise it can happen that when running the gc the program crashes
// The code snippet below caused a crash on older versions:
// mw = Gui.getMainWindow()
// mw.style()
// import gc
// gc.collect()
auto type = getPyTypeObjectForTypeName<QApplication>();
if (type) {
PyObject* pyobj = Shiboken::Object::newObject(type, qApp, false, false, "QApplication");
addQObject(qApp, pyobj);
}
}
WrapperManager()
{
wrapQApplication();
}
~WrapperManager() override = default;
};
#else
static std::string formatModuleError(const std::string& name)
{
std::string error = "Cannot load " + name + " module";
return error;
}
static PyObject* importShiboken()
{
PyObject* obj = PyImport_ImportModule(ModuleShiboken);
if (obj) {
return obj;
}
throw Py::Exception(PyExc_ImportError, formatModuleError(ModuleShiboken));
}
static PyObject* importPySide(const std::string& moduleName)
{
std::string name = getPySideModuleName(moduleName);
PyObject* obj = PyImport_ImportModule(name.c_str());
if (obj) {
return obj;
}
throw Py::Exception(PyExc_ImportError, formatModuleError(name));
}
template<typename qttype>
qttype* qt_getCppType(PyObject* pyobj)
{
// https://github.com/PySide/Shiboken/blob/master/shibokenmodule/typesystem_shiboken.xml
Py::Module mainmod(importShiboken(), true);
Py::Callable func = mainmod.getDict().getItem("getCppPointer");
Py::Tuple arguments(1);
arguments[0] = Py::asObject(pyobj); // PySide pointer
Py::Tuple result(func.apply(arguments));
return reinterpret_cast<qttype*>(PyLong_AsVoidPtr(result[0].ptr()));
}
template<typename qttype>
Py::Object qt_wrapInstance(qttype object,
const std::string& className,
const std::string& moduleName)
{
Py::Module mainmod(importShiboken(), true);
Py::Callable func = mainmod.getDict().getItem("wrapInstance");
Py::Tuple arguments(2);
arguments[0] = Py::asObject(PyLong_FromVoidPtr((void*)object));
Py::Module qtmod(importPySide(moduleName));
arguments[1] = qtmod.getDict().getItem(className);
return func.apply(arguments);
}
const char* qt_identifyType(QObject* ptr, const std::string& moduleName)
{
Py::Module qtmod(importPySide(moduleName));
const QMetaObject* metaObject = ptr->metaObject();
while (metaObject) {
const char* className = metaObject->className();
if (qtmod.getDict().hasKey(className)) {
return className;
}
metaObject = metaObject->superClass();
}
return nullptr;
}
#endif
}
// --------------------------------------------------------
PythonWrapper::PythonWrapper()
{
#if defined (HAVE_SHIBOKEN)
static bool init;
if (!init) {
init = true;
registerTypes();
}
#endif
}
bool PythonWrapper::toCString(const Py::Object& pyobject, std::string& str)
{
if (PyUnicode_Check(pyobject.ptr())) {
PyObject* unicode = PyUnicode_AsUTF8String(pyobject.ptr());
str = PyBytes_AsString(unicode);
Py_DECREF(unicode);
return true;
}
else if (PyBytes_Check(pyobject.ptr())) {
str = PyBytes_AsString(pyobject.ptr());
return true;
}
#if defined (HAVE_SHIBOKEN) && defined(HAVE_PYSIDE)
if (Shiboken::String::check(pyobject.ptr())) {
const char* s = Shiboken::String::toCString(pyobject.ptr());
if (s) str = s;
return true;
}
#endif
return false;
}
QObject* PythonWrapper::toQObject(const Py::Object& pyobject)
{
return qt_getCppType<QObject>(pyobject.ptr());
}
QGraphicsItem* PythonWrapper::toQGraphicsItem(PyObject* pyPtr)
{
return qt_getCppType<QGraphicsItem>(pyPtr);
}
QGraphicsItem* PythonWrapper::toQGraphicsItem(const Py::Object& pyobject)
{
return toQGraphicsItem(pyobject.ptr());
}
QGraphicsObject* PythonWrapper::toQGraphicsObject(PyObject* pyPtr)
{
return qt_getCppType<QGraphicsObject>(pyPtr);
}
QGraphicsObject* PythonWrapper::toQGraphicsObject(const Py::Object& pyobject)
{
return toQGraphicsObject(pyobject.ptr());
}
Py::Object PythonWrapper::fromQImage(const QImage& img)
{
#if defined (HAVE_SHIBOKEN) && defined(HAVE_PYSIDE)
PyObject* pyobj = Shiboken::Conversions::copyToPython(getPyTypeObjectForTypeName<QImage>(),
const_cast<QImage*>(&img));
if (pyobj) {
return Py::asObject(pyobj);
}
throw Py::RuntimeError("Failed to wrap image");
#else
// Access shiboken/PySide via Python
return qt_wrapInstance<const QImage*>(&img, "QImage", "QtGui");
#endif
}
QImage *PythonWrapper::toQImage(PyObject *pyobj)
{
return qt_getCppType<QImage>(pyobj);
}
Py::Object PythonWrapper::fromQIcon(const QIcon* icon)
{
#if defined (HAVE_SHIBOKEN) && defined(HAVE_PYSIDE)
const char* typeName = typeid(*const_cast<QIcon*>(icon)).name();
PyObject* pyobj = Shiboken::Object::newObject(getPyTypeObjectForTypeName<QIcon>(),
const_cast<QIcon*>(icon), true, false, typeName);
if (pyobj) {
return Py::asObject(pyobj);
}
throw Py::RuntimeError("Failed to wrap icon");
#else
// Access shiboken/PySide via Python
return qt_wrapInstance<const QIcon*>(icon, "QIcon", "QtGui");
#endif
}
QIcon *PythonWrapper::toQIcon(PyObject *pyobj)
{
return qt_getCppType<QIcon>(pyobj);
}
Py::Object PythonWrapper::fromQDir(const QDir& dir)
{
#if defined (HAVE_SHIBOKEN) && defined(HAVE_PYSIDE)
const char* typeName = typeid(dir).name();
PyObject* pyobj = Shiboken::Object::newObject(getPyTypeObjectForTypeName<QDir>(),
const_cast<QDir*>(&dir), false, false, typeName);
if (pyobj) {
return Py::asObject(pyobj);
}
#else
Q_UNUSED(dir)
#endif
throw Py::RuntimeError("Failed to wrap directory");
}
QDir* PythonWrapper::toQDir(PyObject* pyobj)
{
return qt_getCppType<QDir>(pyobj);
}
Py::Object PythonWrapper::fromQPrinter(QPrinter* printer)
{
if (!printer) {
return Py::None();
}
#if defined (HAVE_SHIBOKEN) && defined(HAVE_PYSIDE)
// Access shiboken/PySide via C++
auto type = getPyTypeObjectForTypeName<QPrinter>();
if (!type) {
// XXX: Why is QPrinter special?
#if defined (HAVE_SHIBOKEN2)
type = reinterpret_cast<SbkObjectType*>(Shiboken::Conversions::getPythonTypeObject("QPrinter"));
#else
type = Shiboken::Conversions::getPythonTypeObject("QPrinter");
#endif
}
if (type) {
PyObject* pyobj = Shiboken::Object::newObject(type, printer, false, false, "QPrinter");
return Py::asObject(pyobj);
}
throw Py::RuntimeError("Failed to wrap printer");
#else
// Access shiboken/PySide via Python
return qt_wrapInstance<QPrinter*>(printer, "QPrinter", "QtCore");
#endif
}
Py::Object PythonWrapper::fromQObject(QObject* object, const char* className)
{
if (!object) {
return Py::None();
}
#if defined (HAVE_SHIBOKEN) && defined(HAVE_PYSIDE)
// Access shiboken/PySide via C++
auto type = getPyTypeObjectForTypeName<QObject>();
if (type) {
std::string typeName;
if (className) {
typeName = className;
}
else {
typeName = object->metaObject()->className();
}
PyObject* pyobj = Shiboken::Object::newObject(type, object, false, false, typeName.c_str());
WrapperManager::instance().addQObject(object, pyobj);
return Py::asObject(pyobj);
}
throw Py::RuntimeError("Failed to wrap object");
#else
// Access shiboken/PySide via Python
std::string typeName;
if (className) {
typeName = className;
}
else {
typeName = object->metaObject()->className();
}
return qt_wrapInstance<QObject*>(object, typeName, "QtCore");
#endif
}
Py::Object PythonWrapper::fromQWidget(QWidget* widget, const char* className)
{
#if defined (HAVE_SHIBOKEN) && defined(HAVE_PYSIDE)
// Access shiboken/PySide via C++
auto type = getPyTypeObjectForTypeName<QWidget>();
if (type) {
std::string typeName;
if (className) {
typeName = className;
}
else {
typeName = widget->metaObject()->className();
}
PyObject* pyobj = Shiboken::Object::newObject(type, widget, false, false, typeName.c_str());
WrapperManager::instance().addQObject(widget, pyobj);
return Py::asObject(pyobj);
}
throw Py::RuntimeError("Failed to wrap widget");
#else
// Access shiboken/PySide via Python
std::string typeName;
if (className) {
typeName = className;
}
else {
typeName = widget->metaObject()->className();
}
return qt_wrapInstance<QWidget*>(widget, typeName, "QtWidgets");
#endif
}
const char* PythonWrapper::getWrapperName(QObject* obj) const
{
#if defined (HAVE_SHIBOKEN) && defined(HAVE_PYSIDE)
const QMetaObject* meta = obj->metaObject();
while (meta) {
const char* typeName = meta->className();
PyTypeObject* exactType = Shiboken::Conversions::getPythonTypeObject(typeName);
if (exactType) {
return typeName;
}
meta = meta->superClass();
}
#else
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 "QObject";
}
bool PythonWrapper::loadCoreModule()
{
return loadPySideModule("QtCore", SbkPySide_QtCoreTypes);
}
bool PythonWrapper::loadGuiModule()
{
return loadPySideModule("QtGui", SbkPySide_QtGuiTypes);
}
bool PythonWrapper::loadWidgetsModule()
{
return loadPySideModule("QtWidgets", SbkPySide_QtWidgetsTypes);
}
bool PythonWrapper::loadPrintSupportModule()
{
return loadPySideModule("QtPrintSupport", SbkPySide_QtPrintSupportTypes);
}
bool PythonWrapper::loadUiToolsModule()
{
return loadPySideModule("QtUiTools", SbkPySide_QtUiToolsTypes);
}
void PythonWrapper::createChildrenNameAttributes(PyObject* root, QObject* object)
{
Q_FOREACH (QObject* child, object->children()) {
const QByteArray name = child->objectName().toLocal8Bit();
if (!name.isEmpty() && !name.startsWith("_") && !name.startsWith("qt_")) {
bool hasAttr = PyObject_HasAttrString(root, name.constData());
if (!hasAttr) {
#if defined (HAVE_SHIBOKEN) && defined(HAVE_PYSIDE)
Shiboken::AutoDecRef pyChild(Shiboken::Conversions::pointerToPython(getPyTypeObjectForTypeName<QObject>(), child));
PyObject_SetAttrString(root, name.constData(), pyChild);
#else
const char* className = qt_identifyType(child, "QtWidgets");
if (!className) {
if (qobject_cast<QWidget*>(child)) {
className = "QWidget";
}
else {
className = "QObject";
}
}
Py::Object pyChild(qt_wrapInstance<QObject*>(child, className, "QtWidgets"));
PyObject_SetAttrString(root, name.constData(), pyChild.ptr());
#endif
}
createChildrenNameAttributes(root, child);
}
createChildrenNameAttributes(root, child);
}
}
void PythonWrapper::setParent(PyObject* pyWdg, QObject* parent)
{
#if defined (HAVE_SHIBOKEN) && defined(HAVE_PYSIDE)
if (parent) {
Shiboken::AutoDecRef pyParent(Shiboken::Conversions::pointerToPython(getPyTypeObjectForTypeName<QWidget>(), parent));
Shiboken::Object::setParent(pyParent, pyWdg);
}
#else
Q_UNUSED(pyWdg);
Q_UNUSED(parent);
#endif
}