diff --git a/src/Gui/Application.cpp b/src/Gui/Application.cpp index 3bf5406eaa4d..020d2bd8aa4b 100644 --- a/src/Gui/Application.cpp +++ b/src/Gui/Application.cpp @@ -368,6 +368,11 @@ Application::Application(bool GUIenabled) Base::Interpreter().addType(UiLoaderPy::type_object(), module,"UiLoader"); + // PySide additions + PySideUicModule* pySide = new PySideUicModule(); + Py_INCREF(pySide->module().ptr()); + PyModule_AddObject(module, "PySideUic", pySide->module().ptr()); + //insert Selection module PyObject* pSelectionModule = Py_InitModule3("Selection", SelectionSingleton::Methods, "Selection module"); diff --git a/src/Gui/WidgetFactory.cpp b/src/Gui/WidgetFactory.cpp index 469d78f21f63..e8e4db745337 100644 --- a/src/Gui/WidgetFactory.cpp +++ b/src/Gui/WidgetFactory.cpp @@ -22,6 +22,9 @@ #include "PreCompiled.h" +#ifndef _PreComp_ +# include +#endif // Uncomment this block to remove PySide support and switch back to PyQt // #undef HAVE_SHIBOKEN @@ -54,6 +57,7 @@ PyTypeObject** SbkPySide_QtGuiTypes=NULL; #include #include #include +#include #include "WidgetFactory.h" @@ -280,6 +284,64 @@ QWidget* WidgetFactoryInst::createPrefWidget(const char* sName, QWidget* parent, // ---------------------------------------------------- +PySideUicModule::PySideUicModule() + : Py::ExtensionModule("PySideUic") +{ + add_varargs_method("loadUiType",&PySideUicModule::loadUiType, + "Pyside lacks the \"loadUiType\" command, so we have to convert the ui file to py code in-memory first\n" + "and then execute it in a special frame to retrieve the form_class."); + initialize("PySideUic helper module"); // register with Python +} + +Py::Object PySideUicModule::loadUiType(const Py::Tuple& args) +{ + Base::PyGILStateLocker lock; + PyObject* main = PyImport_AddModule("__main__"); + PyObject* dict = PyModule_GetDict(main); + Py::Dict d(PyDict_Copy(dict), true); + Py::String uiFile(args.getItem(0)); + + QString cmd; + QTextStream str(&cmd); + // https://github.com/albop/dolo/blob/master/bin/load_ui.py + str << "import pysideuic\n" + << "from PySide import QtCore, QtGui\n" + << "import xml.etree.ElementTree as xml\n" + << "from cStringIO import StringIO\n" + << "\n" + << "uiFile = \"" << uiFile.as_string().c_str() << "\"\n" + << "parsed = xml.parse(uiFile)\n" + << "widget_class = parsed.find('widget').get('class')\n" + << "form_class = parsed.find('class').text\n" + << "with open(uiFile, 'r') as f:\n" + << " o = StringIO()\n" + << " frame = {}\n" + << " pysideuic.compileUi(f, o, indent=0)\n" + << " pyc = compile(o.getvalue(), '', 'exec')\n" + << " exec pyc in frame\n" + << " #Fetch the base_class and form class based on their type in the xml from designer\n" + << " form_class = frame['Ui_%s'%form_class]\n" + << " base_class = eval('QtGui.%s'%widget_class)\n"; + + PyObject* result = PyRun_String((const char*)cmd.toLatin1(), Py_file_input, d.ptr(), d.ptr()); + if (result) { + Py_DECREF(result); + if (d.hasKey("form_class") && d.hasKey("base_class")) { + Py::Tuple t(2); + t.setItem(0, d.getItem("form_class")); + t.setItem(1, d.getItem("base_class")); + return t; + } + } + else { + throw Py::Exception(); + } + + return Py::None(); +} + +// ---------------------------------------------------- + UiLoader::UiLoader(QObject* parent) : QUiLoader(parent) { diff --git a/src/Gui/WidgetFactory.h b/src/Gui/WidgetFactory.h index 44690d587036..abba10f42be2 100644 --- a/src/Gui/WidgetFactory.h +++ b/src/Gui/WidgetFactory.h @@ -50,6 +50,17 @@ class GuiExport PythonWrapper Py::Object fromQWidget(QWidget*, const char* className=0); }; +class PySideUicModule : public Py::ExtensionModule +{ + +public: + PySideUicModule(); + virtual ~PySideUicModule() {} + +private: + Py::Object loadUiType(const Py::Tuple& args); +}; + /** * The widget factory provides methods for the dynamic creation of widgets. * To create these widgets once they must be registered to the factory.