aboutsummaryrefslogtreecommitdiffstats
path: root/sources/pyside6/PySide6/QtDesigner/qpydesignercustomwidgetcollection.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'sources/pyside6/PySide6/QtDesigner/qpydesignercustomwidgetcollection.cpp')
-rw-r--r--sources/pyside6/PySide6/QtDesigner/qpydesignercustomwidgetcollection.cpp223
1 files changed, 223 insertions, 0 deletions
diff --git a/sources/pyside6/PySide6/QtDesigner/qpydesignercustomwidgetcollection.cpp b/sources/pyside6/PySide6/QtDesigner/qpydesignercustomwidgetcollection.cpp
new file mode 100644
index 000000000..31f8ec152
--- /dev/null
+++ b/sources/pyside6/PySide6/QtDesigner/qpydesignercustomwidgetcollection.cpp
@@ -0,0 +1,223 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include <qpydesignerextensions.h>
+
+#include <QtCore/QCoreApplication>
+#include <QtCore/QVariant>
+
+#include <shiboken.h>
+#include <bindingmanager.h>
+
+QT_BEGIN_NAMESPACE
+
+static QString pyStringToQString(PyObject *s)
+{
+ const char *utf8 = _PepUnicode_AsString(s);
+ return utf8 ? QString::fromUtf8(utf8) : QString();
+}
+
+// Return a string from keyword argument dict
+static QString kwdString(PyObject *kwds, PyObject *key)
+{
+ QString result;
+ if (PyDict_Contains(kwds, key)) {
+ if (auto value = PyDict_GetItem(kwds, key))
+ result = pyStringToQString(value);
+ }
+ return result;
+}
+
+// Return a bool from keyword argument dict
+static bool kwdBool(PyObject *kwds, PyObject *key)
+{
+ bool result = false;
+ if (PyDict_Contains(kwds, key)) {
+ if (auto value = PyDict_GetItem(kwds, key))
+ result = PyObject_IsTrue(value);
+ }
+ return result;
+}
+
+// PyDesignerCustomWidget: A custom widget registered by type
+// (similar to what is done by QUiLoader.registerCustomWidget()).
+class PyDesignerCustomWidget : public QDesignerCustomWidgetInterface
+{
+public:
+ explicit PyDesignerCustomWidget(PyObject *pyTypeObject) :
+ m_pyTypeObject(pyTypeObject) {}
+
+ QString name() const override;
+ QString group() const override { return m_group; }
+ QString toolTip() const override { return m_toolTip; }
+ QString whatsThis() const override { return toolTip(); }
+ QString includeFile() const override { return m_includeFile; }
+ QIcon icon() const override { return m_icon; }
+ bool isContainer() const override { return m_container; }
+
+ QWidget *createWidget(QWidget *parent) override;
+
+ bool isInitialized() const override { return m_core != nullptr; }
+ void initialize(QDesignerFormEditorInterface *core) override;
+
+ QString domXml() const override { return m_domXml; }
+
+ void setGroup(const QString &group) { m_group = group; }
+ void setToolTip(const QString &toolTip) { m_toolTip = toolTip; }
+ void setIncludeFile(const QString &includeFile) { m_includeFile = includeFile; }
+ void setIcon(const QIcon &icon) { m_icon = icon; }
+ void setDomXml(const QString &domXml) { m_domXml = domXml; }
+ void setContainer(bool container) { m_container = container; }
+
+private:
+ const char *utf8Name() const;
+
+ QDesignerFormEditorInterface *m_core = nullptr;
+ QString m_group;
+ QString m_toolTip;
+ QString m_includeFile;
+ QIcon m_icon;
+ QString m_domXml;
+ PyObject *m_pyTypeObject = nullptr;
+ bool m_container = false;
+};
+
+const char *PyDesignerCustomWidget::utf8Name() const
+{
+ return reinterpret_cast<PyTypeObject *>(m_pyTypeObject)->tp_name;
+}
+
+QString PyDesignerCustomWidget::name() const
+{
+ return QString::fromUtf8(utf8Name());
+}
+
+QWidget *PyDesignerCustomWidget::createWidget(QWidget *parent)
+{
+ // This is a copy of the similar function used for QUiLoader
+ // (see sources/pyside6/plugins/uitools/customwidget.cpp)
+ // Create a python instance and return cpp object
+ PyObject *pyParent = nullptr;
+ bool unknownParent = false;
+ if (parent) {
+ pyParent = reinterpret_cast<PyObject *>(Shiboken::BindingManager::instance().retrieveWrapper(parent));
+ if (pyParent) {
+ Py_INCREF(pyParent);
+ } else {
+ static Shiboken::Conversions::SpecificConverter converter("QWidget*");
+ pyParent = converter.toPython(&parent);
+ unknownParent = true;
+ }
+ } else {
+ Py_INCREF(Py_None);
+ pyParent = Py_None;
+ }
+
+ Shiboken::AutoDecRef pyArgs(PyTuple_New(1));
+ PyTuple_SET_ITEM(pyArgs, 0, pyParent); // tuple will keep pyParent reference
+
+ // Call python constructor
+ auto result = reinterpret_cast<SbkObject *>(PyObject_CallObject(m_pyTypeObject, pyArgs));
+ if (!result) {
+ qWarning("Unable to create a Python custom widget of type \"%s\".", utf8Name());
+ PyErr_Print();
+ return nullptr;
+ }
+
+ if (unknownParent) // if parent does not exist in python, transfer the ownership to cpp
+ Shiboken::Object::releaseOwnership(result);
+ else
+ Shiboken::Object::setParent(pyParent, reinterpret_cast<PyObject *>(result));
+
+ return reinterpret_cast<QWidget *>(Shiboken::Object::cppPointer(result, Py_TYPE(result)));
+}
+
+void PyDesignerCustomWidget::initialize(QDesignerFormEditorInterface *core)
+{
+ m_core = core;
+}
+
+// QPyDesignerCustomWidgetCollection: A QDesignerCustomWidgetCollectionInterface
+// implementation that is instantiated as a singleton and stored as a dynamic
+// property of QCoreApplication. The PySide Designer plugin retrieves it from
+// there. Provides static convenience functions for registering types
+// or adding QDesignerCustomWidgetInterface instances.
+
+static QPyDesignerCustomWidgetCollection *collectionInstance = nullptr;
+
+static const char propertyName[] = "__qt_PySideCustomWidgetCollection";
+
+static void cleanup()
+{
+ delete collectionInstance;
+ collectionInstance = nullptr;
+}
+
+QPyDesignerCustomWidgetCollection::QPyDesignerCustomWidgetCollection() = default;
+
+QPyDesignerCustomWidgetCollection::~QPyDesignerCustomWidgetCollection()
+{
+ qDeleteAll(m_customWidgets);
+}
+
+QList<QDesignerCustomWidgetInterface *> QPyDesignerCustomWidgetCollection::customWidgets() const
+{
+ return m_customWidgets;
+}
+
+QPyDesignerCustomWidgetCollection *QPyDesignerCustomWidgetCollection::instance()
+{
+ if (collectionInstance == nullptr) {
+ collectionInstance = new QPyDesignerCustomWidgetCollection();
+ if (auto coreApp = QCoreApplication::instance()) {
+ QDesignerCustomWidgetCollectionInterface *c = collectionInstance;
+ coreApp->setProperty(propertyName, QVariant::fromValue<void *>(c));
+ qAddPostRoutine(cleanup);
+ } else {
+ qWarning("%s: Cannot find QCoreApplication instance.", Q_FUNC_INFO);
+ }
+ }
+ return collectionInstance;
+}
+
+// Register a custom widget by type and optional keyword arguments providing
+// the parameters of QDesignerCustomWidgetInterface.
+bool QPyDesignerCustomWidgetCollection::_registerCustomWidgetHelper(PyObject *typeArg, PyObject *kwds)
+{
+ if (!PyType_Check(typeArg)) {
+ PyErr_SetString(PyExc_TypeError, "registerCustomWidget() requires a type argument.");
+ return false;
+ }
+
+ auto pyCustomWidget = new PyDesignerCustomWidget(typeArg);
+
+ static PyObject *xmlKey = Shiboken::String::createStaticString("xml");
+ pyCustomWidget->setDomXml(kwdString(kwds, xmlKey));
+ static PyObject *toolTipKey = Shiboken::String::createStaticString("tool_tip");
+ pyCustomWidget->setToolTip(kwdString(kwds, toolTipKey));
+ static PyObject *groupKey = Shiboken::String::createStaticString("group");
+ pyCustomWidget->setGroup(kwdString(kwds, groupKey));
+ static PyObject *moduleKey = Shiboken::String::createStaticString("module");
+ pyCustomWidget->setIncludeFile(kwdString(kwds, moduleKey));
+ static PyObject *containerKey = Shiboken::String::createStaticString("container");
+ pyCustomWidget->setContainer(kwdBool(kwds, containerKey));
+ static PyObject *iconKey = Shiboken::String::createStaticString("icon");
+ const QString iconPath = kwdString(kwds, iconKey);
+ if (!iconPath.isEmpty()) {
+ QIcon icon(iconPath);
+ if (icon.availableSizes().isEmpty())
+ qWarning("%s: Cannot load icon from '%s'.", __FUNCTION__, qPrintable(iconPath));
+ else
+ pyCustomWidget->setIcon(icon);
+ }
+
+ addCustomWidget(pyCustomWidget);
+ return true;
+}
+
+void QPyDesignerCustomWidgetCollection::addCustomWidget(QDesignerCustomWidgetInterface *c)
+{
+ instance()->m_customWidgets.append(c);
+}
+
+QT_END_NAMESPACE