From 3241b1ece15403ef1e2576990e456d48d9551be1 Mon Sep 17 00:00:00 2001 From: wmayer Date: Thu, 16 Jul 2015 00:10:23 +0200 Subject: [PATCH] + Support preference pages for Python widget class --- src/Gui/ApplicationPy.cpp | 31 ++++++++---- src/Gui/WidgetFactory.cpp | 100 ++++++++++++++++++++++++++++++++++++++ src/Gui/WidgetFactory.h | 48 ++++++++++++++++++ 3 files changed, 169 insertions(+), 10 deletions(-) diff --git a/src/Gui/ApplicationPy.cpp b/src/Gui/ApplicationPy.cpp index cc81e2cb2848..cae2b288b8be 100644 --- a/src/Gui/ApplicationPy.cpp +++ b/src/Gui/ApplicationPy.cpp @@ -532,20 +532,31 @@ PyObject* Application::sCreateDialog(PyObject * /*self*/, PyObject *args,PyObjec PyObject* Application::sAddPreferencePage(PyObject * /*self*/, PyObject *args,PyObject * /*kwd*/) { char *fn, *grp; - if (!PyArg_ParseTuple(args, "ss", &fn,&grp)) // convert args: Python->C - return NULL; // NULL triggers exception + if (PyArg_ParseTuple(args, "ss", &fn,&grp)) { + QFileInfo fi(QString::fromUtf8(fn)); + if (!fi.exists()) { + PyErr_SetString(PyExc_RuntimeError, "UI file does not exist"); + return 0; + } - QFileInfo fi(QString::fromUtf8(fn)); - if (!fi.exists()) { - PyErr_SetString(PyExc_RuntimeError, "UI file does not exist"); - return 0; + // add to the preferences dialog + new PrefPageUiProducer(fn, grp); + + Py_INCREF(Py_None); + return Py_None; } + PyErr_Clear(); - // add to the preferences dialog - new PrefPageUiProducer(fn, grp); + PyObject* dlg; + if (PyArg_ParseTuple(args, "O!s", &PyClass_Type, &dlg, &grp)) { + // add to the preferences dialog + new PrefPagePyProducer(Py::Object(dlg), grp); - Py_INCREF(Py_None); - return Py_None; + Py_INCREF(Py_None); + return Py_None; + } + + return 0; } PyObject* Application::sActivateWorkbenchHandler(PyObject * /*self*/, PyObject *args,PyObject * /*kwd*/) diff --git a/src/Gui/WidgetFactory.cpp b/src/Gui/WidgetFactory.cpp index cc5dfa74754b..189d4344b957 100644 --- a/src/Gui/WidgetFactory.cpp +++ b/src/Gui/WidgetFactory.cpp @@ -729,6 +729,106 @@ void* PrefPageUiProducer::Produce () const // ---------------------------------------------------- +PrefPagePyProducer::PrefPagePyProducer (const Py::Object& p, const char* group) + : type(p) +{ + std::string str; + Base::PyGILStateLocker lock; + if (type.hasAttr("__name__")) { + str = static_cast(Py::String(type.getAttr("__name__"))); + } + + WidgetFactoryInst::instance().AddProducer(str.c_str(), this); + Gui::Dialog::DlgPreferencesImp::addPage(str, group); +} + +PrefPagePyProducer::~PrefPagePyProducer () +{ + Base::PyGILStateLocker lock; + type = Py::None(); +} + +void* PrefPagePyProducer::Produce () const +{ + Base::PyGILStateLocker lock; + Py::Callable method(type); + Py::Tuple args; + Py::Object page = method.apply(args); + return new Gui::Dialog::PreferencePagePython(page); +} + +// ---------------------------------------------------- + +using namespace Gui::Dialog; + +PreferencePagePython::PreferencePagePython(const Py::Object& p, QWidget* parent) + : PreferencePage(parent), page(p) +{ + Base::PyGILStateLocker lock; + if (page.hasAttr(std::string("form"))) { + Py::Object widget(page.getAttr(std::string("form"))); + + Gui::PythonWrapper wrap; + if (wrap.loadCoreModule()) { + QObject* object = wrap.toQObject(widget); + if (object) { + QWidget* form = qobject_cast(object); + if (form) { + this->setWindowTitle(form->windowTitle()); + QVBoxLayout *layout = new QVBoxLayout; + layout->addWidget(form); + setLayout(layout); + } + } + } + } +} + +PreferencePagePython::~PreferencePagePython() +{ + Base::PyGILStateLocker lock; + page = Py::None(); +} + +void PreferencePagePython::changeEvent(QEvent *e) +{ + QWidget::changeEvent(e); +} + +void PreferencePagePython::loadSettings() +{ + Base::PyGILStateLocker lock; + try { + if (page.hasAttr(std::string("loadSettings"))) { + Py::Callable method(page.getAttr(std::string("loadSettings"))); + Py::Tuple args; + method.apply(args); + } + } + catch (Py::Exception&) { + Base::PyException e; // extract the Python error text + e.ReportException(); + } +} + +void PreferencePagePython::saveSettings() +{ + Base::PyGILStateLocker lock; + try { + if (page.hasAttr(std::string("saveSettings"))) { + Py::Callable method(page.getAttr(std::string("saveSettings"))); + Py::Tuple args; + method.apply(args); + } + } + catch (Py::Exception&) { + Base::PyException e; // extract the Python error text + e.ReportException(); + } +} + +// ---------------------------------------------------- + /* TRANSLATOR Gui::ContainerDialog */ /** diff --git a/src/Gui/WidgetFactory.h b/src/Gui/WidgetFactory.h index 50c8e11c2810..fb328bca0c96 100644 --- a/src/Gui/WidgetFactory.h +++ b/src/Gui/WidgetFactory.h @@ -236,6 +236,28 @@ class GuiExport PrefPageUiProducer : public Base::AbstractProducer QString fn; }; +/** + * The PrefPagePyProducer class provides the ability to create preference pages + * dynamically from a Python class. + * @author Werner Mayer + */ +class GuiExport PrefPagePyProducer : public Base::AbstractProducer +{ +public: + /** + * Register a special type of preference page to the WidgetFactoryInst. + */ + PrefPagePyProducer (const Py::Object&, const char* group); + virtual ~PrefPagePyProducer (); + /** + * Creates an instance of the specified widget. + */ + virtual void* Produce () const; + +private: + Py::Object type; +}; + // -------------------------------------------------------------------- /** @@ -435,6 +457,32 @@ public Q_SLOTS: QObject* mySender; }; +// ---------------------------------------------------- +namespace Dialog { + +/** Subclass that embeds a form from a Python class. + * \author Werner Mayer + */ +class GuiExport PreferencePagePython : public PreferencePage +{ + Q_OBJECT + +public: + PreferencePagePython(const Py::Object& dlg, QWidget* parent = 0); + virtual ~PreferencePagePython(); + + void loadSettings(); + void saveSettings(); + +protected: + void changeEvent(QEvent *e); + +private: + Py::Object page; +}; + +} // namespace Dialog + } // namespace Gui #endif // GUI_WIDGETFACTORY_H