~ubuntu-branches/ubuntu/natty/pyside/natty

« back to all changes in this revision

Viewing changes to PySide/QtDeclarative/pysideqmlregistertype.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Didier Raboud
  • Date: 2011-02-18 18:01:00 UTC
  • mfrom: (1.1.6 upstream)
  • mto: This revision was merged to the branch mainline in revision 9.
  • Revision ID: james.westby@ubuntu.com-20110218180100-y8aqmcdbcbd6gpeh
Tags: upstream-1.0.0~rc1
ImportĀ upstreamĀ versionĀ 1.0.0~rc1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * This file is part of the Shiboken Python Bindings Generator project.
 
3
 *
 
4
 * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
 
5
 *
 
6
 * Contact: PySide team <contact@pyside.org>
 
7
 *
 
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.
 
12
 *
 
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.
 
17
 *
 
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
 
21
 */
 
22
 
 
23
#include "pysideqmlregistertype.h"
 
24
// Qt
 
25
#include <QObject>
 
26
#include <QDeclarativeEngine>
 
27
#include <QMutex>
 
28
// shiboken
 
29
#include <typeresolver.h>
 
30
#include <gilstate.h>
 
31
#include <sbkdbg.h>
 
32
// pyside
 
33
#include <pyside.h>
 
34
#include <dynamicqmetaobject.h>
 
35
#include <pysideproperty.h>
 
36
 
 
37
// auto generated headers
 
38
#include "qdeclarativeitem_wrapper.h"
 
39
#include "pyside_qtcore_python.h"
 
40
#include "pyside_qtdeclarative_python.h"
 
41
 
 
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
 
45
#endif
 
46
 
 
47
// Forward declarations
 
48
static void propListMetaCall(PySideProperty* pp, PyObject* self, QMetaObject::Call call, void** args);
 
49
 
 
50
 
 
51
// All registered python types
 
52
static PyObject* pyTypes[PYSIDE_MAX_QML_TYPES];
 
53
static void (*createFuncs[PYSIDE_MAX_QML_TYPES])(void*);
 
54
 
 
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;
 
59
 
 
60
template<int N>
 
61
struct ElementFactoryBase
 
62
{
 
63
    static void createInto(void* memory)
 
64
    {
 
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())
 
70
            PyErr_Print();
 
71
        PySide::nextQmlElementMemoryAddr = 0;
 
72
    }
 
73
};
 
74
 
 
75
template<int N>
 
76
struct ElementFactory : ElementFactoryBase<N>
 
77
{
 
78
    static void init()
 
79
    {
 
80
        createFuncs[N] = &ElementFactoryBase<N>::createInto;
 
81
        ElementFactory<N-1>::init();
 
82
    }
 
83
};
 
84
 
 
85
template<>
 
86
struct  ElementFactory<0> : ElementFactoryBase<0>
 
87
{
 
88
    static void init()
 
89
    {
 
90
        createFuncs[0] = &ElementFactoryBase<0>::createInto;
 
91
    }
 
92
};
 
93
 
 
94
int PySide::qmlRegisterType(PyObject* pyObj, const char* uri, int versionMajor, int versionMinor, const char* qmlName)
 
95
{
 
96
    using namespace Shiboken;
 
97
 
 
98
    static PyTypeObject* declarativeItemType = TypeResolver::get("QDeclarativeItem*")->pythonType();
 
99
    assert(declarativeItemType);
 
100
    static int nextType = 0;
 
101
 
 
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);
 
104
        return -1;
 
105
    }
 
106
 
 
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);
 
109
        return -1;
 
110
    }
 
111
 
 
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);
 
114
        return -1;
 
115
    }
 
116
 
 
117
    QMetaObject* metaObject = reinterpret_cast<QMetaObject*>(ObjectType::getTypeUserData(reinterpret_cast<SbkObjectType*>(pyObj)));
 
118
    Q_ASSERT(metaObject);
 
119
 
 
120
    // All ready... now the ugly code begins... :-)
 
121
    pyTypes[nextType] = pyObj;
 
122
 
 
123
    // Init proxy object static meta object
 
124
    QDeclarativePrivate::RegisterType type;
 
125
    type.version = 0;
 
126
    type.typeId = qMetaTypeId<QDeclarativeItem*>();
 
127
    type.listId = qMetaTypeId<QDeclarativeListProperty<QDeclarativeItem> >();
 
128
    type.objectSize = sizeof(QDeclarativeItemWrapper);
 
129
    type.create = createFuncs[nextType];
 
130
    type.uri = uri;
 
131
    type.versionMajor = versionMajor;
 
132
    type.versionMinor = versionMinor;
 
133
    type.elementName = qmlName;
 
134
    type.metaObject = metaObject;
 
135
 
 
136
    type.attachedPropertiesFunction = QDeclarativePrivate::attachedPropertiesFunc<QDeclarativeItem>();
 
137
    type.attachedPropertiesMetaObject = QDeclarativePrivate::attachedPropertiesMetaObject<QDeclarativeItem>();
 
138
 
 
139
    type.parserStatusCast = QDeclarativePrivate::StaticCastSelector<QDeclarativeItem,QDeclarativeParserStatus>::cast();
 
140
    type.valueSourceCast = QDeclarativePrivate::StaticCastSelector<QDeclarativeItem,QDeclarativePropertyValueSource>::cast();
 
141
    type.valueInterceptorCast = QDeclarativePrivate::StaticCastSelector<QDeclarativeItem,QDeclarativePropertyValueInterceptor>::cast();
 
142
 
 
143
    type.extensionObjectCreate = 0;
 
144
    type.extensionMetaObject = 0;
 
145
    type.customParser = 0;
 
146
 
 
147
    int qmlTypeId = QDeclarativePrivate::qmlregister(QDeclarativePrivate::TypeRegistration, &type);
 
148
    ++nextType;
 
149
    return qmlTypeId;
 
150
}
 
151
 
 
152
extern "C"
 
153
{
 
154
 
 
155
// This is the user data we store in the property.
 
156
struct DeclarativeListProperty
 
157
{
 
158
    PyTypeObject* type;
 
159
    PyObject* append;
 
160
    PyObject* at;
 
161
    PyObject* clear;
 
162
    PyObject* count;
 
163
};
 
164
 
 
165
static int propListTpInit(PyObject* self, PyObject* args, PyObject* kwds)
 
166
{
 
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));
 
171
 
 
172
    if (!PyArg_ParseTupleAndKeywords(args, kwds,
 
173
                                     "OO|OOO:QtDeclarative.ListProperty", (char**) kwlist,
 
174
                                     &data->type,
 
175
                                     &data->append,
 
176
                                     &data->at,
 
177
                                     &data->clear,
 
178
                                     &data->count)) {
 
179
        return 0;
 
180
    }
 
181
    PySide::Property::setMetaCallHandler(pySelf, &propListMetaCall);
 
182
    PySide::Property::setTypeName(pySelf, "QDeclarativeListProperty<QDeclarativeItem>");
 
183
    PySide::Property::setUserData(pySelf, data);
 
184
 
 
185
    return 1;
 
186
}
 
187
 
 
188
void propListTpFree(void* self)
 
189
{
 
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);
 
194
}
 
195
 
 
196
PyTypeObject PropertyListType = {
 
197
    PyObject_HEAD_INIT(0)
 
198
    0,                         /*ob_size*/
 
199
    "ListProperty",            /*tp_name*/
 
200
    sizeof(PySideProperty),    /*tp_basicsize*/
 
201
    0,                         /*tp_itemsize*/
 
202
    0,                         /*tp_dealloc*/
 
203
    0,                         /*tp_print*/
 
204
    0,                         /*tp_getattr*/
 
205
    0,                         /*tp_setattr*/
 
206
    0,                         /*tp_compare*/
 
207
    0,                         /*tp_repr*/
 
208
    0,                         /*tp_as_number*/
 
209
    0,                         /*tp_as_sequence*/
 
210
    0,                         /*tp_as_mapping*/
 
211
    0,                         /*tp_hash */
 
212
    0,                         /*tp_call*/
 
213
    0,                         /*tp_str*/
 
214
    0,                         /*tp_getattro*/
 
215
    0,                         /*tp_setattro*/
 
216
    0,                         /*tp_as_buffer*/
 
217
    Py_TPFLAGS_DEFAULT,        /*tp_flags*/
 
218
    0,                         /*tp_doc */
 
219
    0,                         /*tp_traverse */
 
220
    0,                         /*tp_clear */
 
221
    0,                         /*tp_richcompare */
 
222
    0,                         /*tp_weaklistoffset */
 
223
    0,                         /*tp_iter */
 
224
    0,                         /*tp_iternext */
 
225
    0,                         /*tp_methods */
 
226
    0,                         /*tp_members */
 
227
    0,                         /*tp_getset */
 
228
    &PySidePropertyType,       /*tp_base */
 
229
    0,                         /*tp_dict */
 
230
    0,                         /*tp_descr_get */
 
231
    0,                         /*tp_descr_set */
 
232
    0,                         /*tp_dictoffset */
 
233
    propListTpInit,            /*tp_init */
 
234
    0,                         /*tp_alloc */
 
235
    0,                         /*tp_new */
 
236
    propListTpFree,            /*tp_free */
 
237
    0,                         /*tp_is_gc */
 
238
    0,                         /*tp_bases */
 
239
    0,                         /*tp_mro */
 
240
    0,                         /*tp_cache */
 
241
    0,                         /*tp_subclasses */
 
242
    0,                         /*tp_weaklist */
 
243
    0,                         /*tp_del */
 
244
};
 
245
 
 
246
} // extern "C"
 
247
 
 
248
// Implementation of QDeclarativeListProperty<T>::AppendFunction callback
 
249
void propListAppender(QDeclarativeListProperty<QDeclarativeItem>* propList, QDeclarativeItem* item)
 
250
{
 
251
    Shiboken::GilState state;
 
252
    Shiboken::AutoDecRef args(Shiboken::makeTuple(propList->object, item));
 
253
 
 
254
    DeclarativeListProperty* data = reinterpret_cast<DeclarativeListProperty*>(propList->data);
 
255
    Shiboken::AutoDecRef retVal(PyObject_CallObject(data->append, args));
 
256
 
 
257
    if (PyErr_Occurred())
 
258
        PyErr_Print();
 
259
}
 
260
 
 
261
// Implementation of QDeclarativeListProperty<T>::CountFunction callback
 
262
int propListCount(QDeclarativeListProperty<QDeclarativeItem>* propList)
 
263
{
 
264
    Shiboken::GilState state;
 
265
    Shiboken::AutoDecRef args(Shiboken::makeTuple(propList->object));
 
266
 
 
267
    DeclarativeListProperty* data = reinterpret_cast<DeclarativeListProperty*>(propList->data);
 
268
    Shiboken::AutoDecRef retVal(PyObject_CallObject(data->count, args));
 
269
 
 
270
    // Check return type
 
271
    if (PyErr_Occurred())
 
272
        PyErr_Print();
 
273
    else if (Shiboken::Converter<int>::isConvertible(retVal))
 
274
        return Shiboken::Converter<int>::toCpp(retVal);
 
275
 
 
276
    return 0;
 
277
}
 
278
 
 
279
// Implementation of QDeclarativeListProperty<T>::AtFunction callback
 
280
QDeclarativeItem* propListAt(QDeclarativeListProperty<QDeclarativeItem>* propList, int index)
 
281
{
 
282
    Shiboken::GilState state;
 
283
    Shiboken::AutoDecRef args(Shiboken::makeTuple(propList->object, index));
 
284
 
 
285
    DeclarativeListProperty* data = reinterpret_cast<DeclarativeListProperty*>(propList->data);
 
286
    Shiboken::AutoDecRef retVal(PyObject_CallObject(data->at, args));
 
287
 
 
288
    if (PyErr_Occurred())
 
289
        PyErr_Print();
 
290
    else if (PyType_IsSubtype(Py_TYPE(retVal), data->type))
 
291
        return Shiboken::Converter<QDeclarativeItem*>::toCpp(retVal);
 
292
 
 
293
    return 0;
 
294
}
 
295
 
 
296
// Implementation of QDeclarativeListProperty<T>::ClearFunction callback
 
297
void propListClear(QDeclarativeListProperty<QDeclarativeItem>* propList)
 
298
{
 
299
    Shiboken::GilState state;
 
300
    Shiboken::AutoDecRef args(Shiboken::makeTuple(propList->object));
 
301
 
 
302
    DeclarativeListProperty* data = reinterpret_cast<DeclarativeListProperty*>(propList->data);
 
303
    Shiboken::AutoDecRef retVal(PyObject_CallObject(data->clear, args));
 
304
 
 
305
    if (PyErr_Occurred())
 
306
        PyErr_Print();
 
307
}
 
308
 
 
309
// qt_metacall specialization for ListProperties
 
310
static void propListMetaCall(PySideProperty* pp, PyObject* self, QMetaObject::Call call, void** args)
 
311
{
 
312
    if (call != QMetaObject::ReadProperty)
 
313
        return;
 
314
 
 
315
    DeclarativeListProperty* data = reinterpret_cast<DeclarativeListProperty*>(PySide::Property::userData(pp));
 
316
    QDeclarativeListProperty<QDeclarativeItem> declProp(Shiboken::Converter<QObject*>::toCpp(self), data, &propListAppender);
 
317
 
 
318
    if (data->count)
 
319
        declProp.count = &propListCount;
 
320
    if (data->at)
 
321
        declProp.at = &propListAt;
 
322
    if (data->clear)
 
323
        declProp.clear = &propListClear;
 
324
 
 
325
    // Copy the data to the memory location requested by the meta call
 
326
    void* v = args[0];
 
327
    *reinterpret_cast<QDeclarativeListProperty<QDeclarativeItem>*>(v) = declProp;
 
328
}
 
329
 
 
330
 
 
331
void PySide::initQmlSupport(PyObject* module)
 
332
{
 
333
    ElementFactory<PYSIDE_MAX_QML_TYPES - 1>::init();
 
334
 
 
335
    // Export DeclarativeListProperty type
 
336
    if (PyType_Ready(&PropertyListType) < 0)
 
337
        return;
 
338
 
 
339
    Py_INCREF((PyObject*)&PropertyListType);
 
340
    PyModule_AddObject(module, PropertyListType.tp_name, (PyObject*)&PropertyListType);
 
341
 
 
342
}
 
343
 
 
344