aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHugo Parente Lima <hugo.pl@gmail.com>2010-12-01 15:44:17 -0200
committerHugo Parente Lima <hugo.pl@gmail.com>2012-03-08 16:47:56 -0300
commitf02876e6c9acecdd1f202aeb5c2721fde581a0ac (patch)
treed452ffc30b73fb6847c8faa3407c82f4491672d3
parent8fb60373627f5d9978df2b9f38d0180f5897477a (diff)
Initial implementation of qmlRegisterType.
It's fully functional, but need some adjustaments in the build system that will be done in the next few days. Reviewer: Luciano Wolf <luciano.wolf@openbossa.org> Marcelo Lira <marcelo.lira@openbossa.org>
-rw-r--r--PySide/QtDeclarative/CMakeLists.txt1
-rw-r--r--PySide/QtDeclarative/pysideqmlregistertype.cpp143
-rw-r--r--PySide/QtDeclarative/pysideqmlregistertype.h38
-rw-r--r--PySide/QtDeclarative/typesystem_declarative.xml41
4 files changed, 223 insertions, 0 deletions
diff --git a/PySide/QtDeclarative/CMakeLists.txt b/PySide/QtDeclarative/CMakeLists.txt
index 1788adcdf..98673f7a3 100644
--- a/PySide/QtDeclarative/CMakeLists.txt
+++ b/PySide/QtDeclarative/CMakeLists.txt
@@ -1,6 +1,7 @@
project(QtDeclarative)
set(QtDeclarative_SRC
+${CMAKE_CURRENT_SOURCE_DIR}/pysideqmlregistertype.cpp
${CMAKE_CURRENT_BINARY_DIR}/PySide/QtDeclarative/qdeclarativecomponent_wrapper.cpp
${CMAKE_CURRENT_BINARY_DIR}/PySide/QtDeclarative/qdeclarativecontext_wrapper.cpp
${CMAKE_CURRENT_BINARY_DIR}/PySide/QtDeclarative/qdeclarativeengine_wrapper.cpp
diff --git a/PySide/QtDeclarative/pysideqmlregistertype.cpp b/PySide/QtDeclarative/pysideqmlregistertype.cpp
new file mode 100644
index 000000000..8980aa66e
--- /dev/null
+++ b/PySide/QtDeclarative/pysideqmlregistertype.cpp
@@ -0,0 +1,143 @@
+/*
+ * This file is part of the Shiboken Python Bindings Generator project.
+ *
+ * Copyright (C) 2009-2010 Nokia Corporation and/or its subsidiary(-ies).
+ *
+ * Contact: PySide team <contact@pyside.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "pysideqmlregistertype.h"
+#include <Python.h>
+#include <QObject>
+#include <QDeclarativeEngine>
+#include <QMutex>
+#include <typeresolver.h>
+#include "qdeclarativeitem_wrapper.h"
+#include <sbkdbg.h>
+
+#ifndef PYSIDE_MAX_QML_TYPES
+// Maximum number of different types the user cna export to QML using qmlRegisterType.
+#define PYSIDE_MAX_QML_TYPES 50
+#endif
+
+// All registered python types
+static PyObject* pyTypes[PYSIDE_MAX_QML_TYPES];
+static void (*createFuncs[PYSIDE_MAX_QML_TYPES])(void*);
+
+/// QDeclarativeItem will create objects using placement new then this pointer is non-null.
+void* PySide::nextQmlElementMemoryAddr = 0;
+// Mutex used to avoid race condition on PySide::nextQmlElementMemoryAddr
+static QMutex nextQmlElementMutex;
+
+template<int N>
+struct ElementFactoryBase
+{
+ static void createInto(void* memory)
+ {
+ QMutexLocker locker(&nextQmlElementMutex);
+ PySide::nextQmlElementMemoryAddr = memory;
+ PyObject* obj = PyObject_CallObject(pyTypes[N], 0);
+ if (!obj || PyErr_Occurred())
+ PyErr_Print();
+ PySide::nextQmlElementMemoryAddr = 0;
+ }
+};
+
+template<int N>
+struct ElementFactory : ElementFactoryBase<N>
+{
+ static void init()
+ {
+ createFuncs[N] = &ElementFactoryBase<N>::createInto;
+ ElementFactory<N-1>::init();
+ }
+};
+
+template<>
+struct ElementFactory<0> : ElementFactoryBase<0>
+{
+ static void init()
+ {
+ createFuncs[0] = &ElementFactoryBase<0>::createInto;
+ }
+};
+
+void PySide::initQmlSupport()
+{
+ ElementFactory<PYSIDE_MAX_QML_TYPES - 1>::init();
+}
+
+int PySide::qmlRegisterType(PyObject* pyObj, const char* uri, int versionMajor, int versionMinor, const char* qmlName)
+{
+ using namespace Shiboken;
+
+ static PyTypeObject* declarativeItemType = TypeResolver::get("QDeclarativeItem*")->pythonType();
+ assert(declarativeItemType);
+ static int nextType = 0;
+
+ if (nextType >= PYSIDE_MAX_QML_TYPES) {
+ PyErr_Format(PyExc_TypeError, "QML doesn't really like language bindings, so you can only export %d types to QML.", PYSIDE_MAX_QML_TYPES);
+ return -1;
+ }
+
+ if (pyObj->ob_type != &SbkObjectType_Type) {
+ PyErr_Format(PyExc_TypeError, "A shiboken-based python type expected, got %s.", pyObj->ob_type->tp_name);
+ return -1;
+ }
+
+ if (!PySequence_Contains(((PyTypeObject*)pyObj)->tp_mro, (PyObject*)declarativeItemType)) {
+ PyErr_Format(PyExc_TypeError, "A type inherited from %s expected, got %s.", declarativeItemType->tp_name, ((PyTypeObject*)pyObj)->tp_name);
+ return -1;
+ }
+
+ QMetaObject* metaObject = reinterpret_cast<QMetaObject*>(ObjectType::getTypeUserData(reinterpret_cast<SbkObjectType*>(pyObj)));
+ if (!metaObject) {
+ PyErr_SetString(PyExc_TypeError, "FIXME: metaobject not initialized, this error msg should not exists at all!!");
+ return -1;
+ }
+
+ // All ready... now the ugly code begins... :-)
+ pyTypes[nextType] = pyObj;
+
+ // Init proxy object static meta object
+ QDeclarativePrivate::RegisterType type;
+ type.version = 0;
+ type.typeId = qMetaTypeId<QDeclarativeItem*>();
+ type.listId = qMetaTypeId<QDeclarativeListProperty<QDeclarativeItem> >();
+ type.objectSize = sizeof(QDeclarativeItemWrapper);
+ type.create = createFuncs[nextType];
+ type.uri = uri;
+ type.versionMajor = versionMajor;
+ type.versionMinor = versionMinor;
+ type.elementName = qmlName;
+ type.metaObject = metaObject;
+
+ type.attachedPropertiesFunction = QDeclarativePrivate::attachedPropertiesFunc<QDeclarativeItem>();
+ type.attachedPropertiesMetaObject = QDeclarativePrivate::attachedPropertiesMetaObject<QDeclarativeItem>();
+
+ type.parserStatusCast = QDeclarativePrivate::StaticCastSelector<QDeclarativeItem,QDeclarativeParserStatus>::cast();
+ type.valueSourceCast = QDeclarativePrivate::StaticCastSelector<QDeclarativeItem,QDeclarativePropertyValueSource>::cast();
+ type.valueInterceptorCast = QDeclarativePrivate::StaticCastSelector<QDeclarativeItem,QDeclarativePropertyValueInterceptor>::cast();
+
+ type.extensionObjectCreate = 0;
+ type.extensionMetaObject = 0;
+ type.customParser = 0;
+
+ int qmlTypeId = QDeclarativePrivate::qmlregister(QDeclarativePrivate::TypeRegistration, &type);
+ ++nextType;
+ return qmlTypeId;
+}
diff --git a/PySide/QtDeclarative/pysideqmlregistertype.h b/PySide/QtDeclarative/pysideqmlregistertype.h
new file mode 100644
index 000000000..3f83b2900
--- /dev/null
+++ b/PySide/QtDeclarative/pysideqmlregistertype.h
@@ -0,0 +1,38 @@
+/*
+ * This file is part of the Shiboken Python Bindings Generator project.
+ *
+ * Copyright (C) 2009-2010 Nokia Corporation and/or its subsidiary(-ies).
+ *
+ * Contact: PySide team <contact@pyside.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef PYSIDEQMLREGISTERTYPE_H
+#define PYSIDEQMLREGISTERTYPE_H
+
+#include <basewrapper.h>
+
+namespace PySide
+{
+
+extern void* nextQmlElementMemoryAddr;
+
+void initQmlSupport();
+int qmlRegisterType(PyObject* pyObj, const char* uri, int versionMajor, int versionMinor, const char* qmlName);
+
+}
+
+#endif
diff --git a/PySide/QtDeclarative/typesystem_declarative.xml b/PySide/QtDeclarative/typesystem_declarative.xml
index 75c63e093..cc666024a 100644
--- a/PySide/QtDeclarative/typesystem_declarative.xml
+++ b/PySide/QtDeclarative/typesystem_declarative.xml
@@ -23,14 +23,44 @@
<load-typesystem name="typesystem_network.xml" generate="no"/>
<load-typesystem name="typesystem_gui.xml" generate="no"/>
+ <add-function signature="qmlRegisterType(PyTypeObject, const char*, int, int, const char*)" return-type="int">
+ <inject-documentation format="target" mode="append">
+ This function registers the Python type in the QML system with the name qmlName, in the library imported from uri having the version number composed from versionMajor and versionMinor.
+ Returns the QML type id.
+
+ For example, this registers a Python class MySliderItem as a QML type named Slider for version 1.0 of a module called "com.mycompany.qmlcomponents":
+
+ ::
+
+ qmlRegisterType(MySliderItem, "com.mycompany.qmlcomponents", 1, 0, "Slider")
+
+ Once this is registered, the type can be used in QML by importing the specified module name and version number:
+
+ ::
+
+ import com.mycompany.qmlcomponents 1.0
+
+ Slider { ... }
+
+ Note that it's perfectly reasonable for a library to register types to older versions than the actual version of the library. Indeed, it is normal for the new library to allow QML written to previous versions to continue to work, even if more advanced versions of some of its types are available.
+ </inject-documentation>
+
+ <inject-code class="target">
+ %PYARG_0 = %CONVERTTOPYTHON[int](PySide::qmlRegisterType(%1, %2, %3, %4, %5));
+ </inject-code>
+ </add-function>
+
<enum-type identified-by-value="QML_HAS_ATTACHED_PROPERTIES" since="4.7">
<extra-includes>
<include file-name="QtDeclarative" location="global"/>
+ <!-- FIXME The include tag doesn't work on modules -->
+ <include file-name="pysideqmlregistertype.h" location="local"/>
</extra-includes>
</enum-type>
<inject-code>
Shiboken::TypeResolver::createValueTypeResolver&lt; QList&lt;QObject*&gt; &gt;("QList&lt;QObject*&gt;");
+ PySide::initQmlSupport();
</inject-code>
<object-type name="QDeclarativeExtensionInterface"/>
@@ -60,7 +90,18 @@
<enum-type name="ImageType" />
</object-type>
<object-type name="QDeclarativeItem">
+ <extra-includes>
+ <include file-name="pysideqmlregistertype.h" location="local"/>
+ </extra-includes>
<enum-type name="TransformOrigin" />
+ <modify-function signature="QDeclarativeItem(QDeclarativeItem*)">
+ <inject-code class="target">
+ if (PySide::nextQmlElementMemoryAddr)
+ %0 = new (PySide::nextQmlElementMemoryAddr) ::QDeclarativePrivate::QDeclarativeElement&lt;%TYPE>();
+ else
+ %0 = new %TYPE(%1);
+ </inject-code>
+ </modify-function>
</object-type>
<value-type name="QDeclarativeListReference" />