2
* This file is part of the Shiboken Python Bindings Generator project.
4
* Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
6
* Contact: PySide team <contact@pyside.org>
8
* This library is free software; you can redistribute it and/or
9
* modify it under the terms of the GNU Lesser General Public
10
* License as published by the Free Software Foundation; either
11
* version 2.1 of the License, or (at your option) any later version.
13
* This library is distributed in the hope that it will be useful,
14
* but WITHOUT ANY WARRANTY; without even the implied warranty of
15
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16
* Lesser General Public License for more details.
18
* You should have received a copy of the GNU Lesser General Public
19
* License along with this library; if not, write to the Free Software
20
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23
#include "pysideqmlregistertype.h"
26
#include <QDeclarativeEngine>
29
#include <typeresolver.h>
34
#include <dynamicqmetaobject.h>
35
#include <pysideproperty.h>
37
// auto generated headers
38
#include "qdeclarativeitem_wrapper.h"
39
#include "pyside_qtcore_python.h"
40
#include "pyside_qtdeclarative_python.h"
42
#ifndef PYSIDE_MAX_QML_TYPES
43
// Maximum number of different types the user cna export to QML using qmlRegisterType.
44
#define PYSIDE_MAX_QML_TYPES 50
47
// Forward declarations
48
static void propListMetaCall(PySideProperty* pp, PyObject* self, QMetaObject::Call call, void** args);
51
// All registered python types
52
static PyObject* pyTypes[PYSIDE_MAX_QML_TYPES];
53
static void (*createFuncs[PYSIDE_MAX_QML_TYPES])(void*);
55
/// QDeclarativeItem will create objects using placement new then this pointer is non-null.
56
void* PySide::nextQmlElementMemoryAddr = 0;
57
// Mutex used to avoid race condition on PySide::nextQmlElementMemoryAddr
58
static QMutex nextQmlElementMutex;
61
struct ElementFactoryBase
63
static void createInto(void* memory)
65
QMutexLocker locker(&nextQmlElementMutex);
66
PySide::nextQmlElementMemoryAddr = memory;
67
Shiboken::GilState state;
68
PyObject* obj = PyObject_CallObject(pyTypes[N], 0);
69
if (!obj || PyErr_Occurred())
71
PySide::nextQmlElementMemoryAddr = 0;
76
struct ElementFactory : ElementFactoryBase<N>
80
createFuncs[N] = &ElementFactoryBase<N>::createInto;
81
ElementFactory<N-1>::init();
86
struct ElementFactory<0> : ElementFactoryBase<0>
90
createFuncs[0] = &ElementFactoryBase<0>::createInto;
94
int PySide::qmlRegisterType(PyObject* pyObj, const char* uri, int versionMajor, int versionMinor, const char* qmlName)
96
using namespace Shiboken;
98
static PyTypeObject* declarativeItemType = TypeResolver::get("QDeclarativeItem*")->pythonType();
99
assert(declarativeItemType);
100
static int nextType = 0;
102
if (nextType >= PYSIDE_MAX_QML_TYPES) {
103
PyErr_Format(PyExc_TypeError, "QML doesn't really like language bindings, so you can only export %d types to QML.", PYSIDE_MAX_QML_TYPES);
107
if (pyObj->ob_type != &SbkObjectType_Type) {
108
PyErr_Format(PyExc_TypeError, "A shiboken-based python type expected, got %s.", pyObj->ob_type->tp_name);
112
if (!PySequence_Contains(((PyTypeObject*)pyObj)->tp_mro, (PyObject*)declarativeItemType)) {
113
PyErr_Format(PyExc_TypeError, "A type inherited from %s expected, got %s.", declarativeItemType->tp_name, ((PyTypeObject*)pyObj)->tp_name);
117
QMetaObject* metaObject = reinterpret_cast<QMetaObject*>(ObjectType::getTypeUserData(reinterpret_cast<SbkObjectType*>(pyObj)));
118
Q_ASSERT(metaObject);
120
// All ready... now the ugly code begins... :-)
121
pyTypes[nextType] = pyObj;
123
// Init proxy object static meta object
124
QDeclarativePrivate::RegisterType type;
126
type.typeId = qMetaTypeId<QDeclarativeItem*>();
127
type.listId = qMetaTypeId<QDeclarativeListProperty<QDeclarativeItem> >();
128
type.objectSize = sizeof(QDeclarativeItemWrapper);
129
type.create = createFuncs[nextType];
131
type.versionMajor = versionMajor;
132
type.versionMinor = versionMinor;
133
type.elementName = qmlName;
134
type.metaObject = metaObject;
136
type.attachedPropertiesFunction = QDeclarativePrivate::attachedPropertiesFunc<QDeclarativeItem>();
137
type.attachedPropertiesMetaObject = QDeclarativePrivate::attachedPropertiesMetaObject<QDeclarativeItem>();
139
type.parserStatusCast = QDeclarativePrivate::StaticCastSelector<QDeclarativeItem,QDeclarativeParserStatus>::cast();
140
type.valueSourceCast = QDeclarativePrivate::StaticCastSelector<QDeclarativeItem,QDeclarativePropertyValueSource>::cast();
141
type.valueInterceptorCast = QDeclarativePrivate::StaticCastSelector<QDeclarativeItem,QDeclarativePropertyValueInterceptor>::cast();
143
type.extensionObjectCreate = 0;
144
type.extensionMetaObject = 0;
145
type.customParser = 0;
147
int qmlTypeId = QDeclarativePrivate::qmlregister(QDeclarativePrivate::TypeRegistration, &type);
155
// This is the user data we store in the property.
156
struct DeclarativeListProperty
165
static int propListTpInit(PyObject* self, PyObject* args, PyObject* kwds)
167
static const char *kwlist[] = {"type", "append", "at", "clear", "count", 0};
168
PySideProperty* pySelf = reinterpret_cast<PySideProperty*>(self);
169
DeclarativeListProperty* data = new DeclarativeListProperty;
170
memset(data, 0, sizeof(DeclarativeListProperty));
172
if (!PyArg_ParseTupleAndKeywords(args, kwds,
173
"OO|OOO:QtDeclarative.ListProperty", (char**) kwlist,
181
PySide::Property::setMetaCallHandler(pySelf, &propListMetaCall);
182
PySide::Property::setTypeName(pySelf, "QDeclarativeListProperty<QDeclarativeItem>");
183
PySide::Property::setUserData(pySelf, data);
188
void propListTpFree(void* self)
190
PySideProperty* pySelf = reinterpret_cast<PySideProperty*>(self);
191
delete reinterpret_cast<DeclarativeListProperty*>(PySide::Property::userData(pySelf));
192
// calls base type constructor
193
pySelf->ob_type->tp_base->tp_free(self);
196
PyTypeObject PropertyListType = {
197
PyObject_HEAD_INIT(0)
199
"ListProperty", /*tp_name*/
200
sizeof(PySideProperty), /*tp_basicsize*/
209
0, /*tp_as_sequence*/
217
Py_TPFLAGS_DEFAULT, /*tp_flags*/
221
0, /*tp_richcompare */
222
0, /*tp_weaklistoffset */
228
&PySidePropertyType, /*tp_base */
232
0, /*tp_dictoffset */
233
propListTpInit, /*tp_init */
236
propListTpFree, /*tp_free */
241
0, /*tp_subclasses */
248
// Implementation of QDeclarativeListProperty<T>::AppendFunction callback
249
void propListAppender(QDeclarativeListProperty<QDeclarativeItem>* propList, QDeclarativeItem* item)
251
Shiboken::GilState state;
252
Shiboken::AutoDecRef args(Shiboken::makeTuple(propList->object, item));
254
DeclarativeListProperty* data = reinterpret_cast<DeclarativeListProperty*>(propList->data);
255
Shiboken::AutoDecRef retVal(PyObject_CallObject(data->append, args));
257
if (PyErr_Occurred())
261
// Implementation of QDeclarativeListProperty<T>::CountFunction callback
262
int propListCount(QDeclarativeListProperty<QDeclarativeItem>* propList)
264
Shiboken::GilState state;
265
Shiboken::AutoDecRef args(Shiboken::makeTuple(propList->object));
267
DeclarativeListProperty* data = reinterpret_cast<DeclarativeListProperty*>(propList->data);
268
Shiboken::AutoDecRef retVal(PyObject_CallObject(data->count, args));
271
if (PyErr_Occurred())
273
else if (Shiboken::Converter<int>::isConvertible(retVal))
274
return Shiboken::Converter<int>::toCpp(retVal);
279
// Implementation of QDeclarativeListProperty<T>::AtFunction callback
280
QDeclarativeItem* propListAt(QDeclarativeListProperty<QDeclarativeItem>* propList, int index)
282
Shiboken::GilState state;
283
Shiboken::AutoDecRef args(Shiboken::makeTuple(propList->object, index));
285
DeclarativeListProperty* data = reinterpret_cast<DeclarativeListProperty*>(propList->data);
286
Shiboken::AutoDecRef retVal(PyObject_CallObject(data->at, args));
288
if (PyErr_Occurred())
290
else if (PyType_IsSubtype(Py_TYPE(retVal), data->type))
291
return Shiboken::Converter<QDeclarativeItem*>::toCpp(retVal);
296
// Implementation of QDeclarativeListProperty<T>::ClearFunction callback
297
void propListClear(QDeclarativeListProperty<QDeclarativeItem>* propList)
299
Shiboken::GilState state;
300
Shiboken::AutoDecRef args(Shiboken::makeTuple(propList->object));
302
DeclarativeListProperty* data = reinterpret_cast<DeclarativeListProperty*>(propList->data);
303
Shiboken::AutoDecRef retVal(PyObject_CallObject(data->clear, args));
305
if (PyErr_Occurred())
309
// qt_metacall specialization for ListProperties
310
static void propListMetaCall(PySideProperty* pp, PyObject* self, QMetaObject::Call call, void** args)
312
if (call != QMetaObject::ReadProperty)
315
DeclarativeListProperty* data = reinterpret_cast<DeclarativeListProperty*>(PySide::Property::userData(pp));
316
QDeclarativeListProperty<QDeclarativeItem> declProp(Shiboken::Converter<QObject*>::toCpp(self), data, &propListAppender);
319
declProp.count = &propListCount;
321
declProp.at = &propListAt;
323
declProp.clear = &propListClear;
325
// Copy the data to the memory location requested by the meta call
327
*reinterpret_cast<QDeclarativeListProperty<QDeclarativeItem>*>(v) = declProp;
331
void PySide::initQmlSupport(PyObject* module)
333
ElementFactory<PYSIDE_MAX_QML_TYPES - 1>::init();
335
// Export DeclarativeListProperty type
336
if (PyType_Ready(&PropertyListType) < 0)
339
Py_INCREF((PyObject*)&PropertyListType);
340
PyModule_AddObject(module, PropertyListType.tp_name, (PyObject*)&PropertyListType);