section.property cannot deal with nested properties
[profile/ivi/qtdeclarative.git] / src / quick / items / qquickvisualadaptormodel.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
5 **
6 ** This file is part of the QtQml module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
16 **
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
20 **
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
28 **
29 ** Other Usage
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qquickvisualadaptormodel_p.h"
43 #include "qquickvisualdatamodel_p_p.h"
44
45 #include <private/qmetaobjectbuilder_p.h>
46 #include <private/qqmlproperty_p.h>
47
48 QT_BEGIN_NAMESPACE
49
50 template <typename T, typename M> static void setModelDataType(QMetaObjectBuilder *builder, M *metaType)
51 {
52     builder->setFlags(QMetaObjectBuilder::DynamicMetaObject);
53     builder->setClassName(T::staticMetaObject.className());
54     builder->setSuperClass(&T::staticMetaObject);
55     metaType->propertyOffset = T::staticMetaObject.propertyCount();
56     metaType->signalOffset = T::staticMetaObject.methodCount();
57 }
58
59 static void addProperty(QMetaObjectBuilder *builder, int propertyId, const QByteArray &propertyName, const QByteArray &propertyType)
60 {
61     builder->addSignal("__" + QByteArray::number(propertyId) + "()");
62     QMetaPropertyBuilder property = builder->addProperty(
63             propertyName, propertyType, propertyId);
64     property.setWritable(true);
65 }
66
67 static v8::Handle<v8::Value> get_index(v8::Local<v8::String>, const v8::AccessorInfo &info)
68 {
69     QQuickVisualDataModelItem *data = v8_resource_cast<QQuickVisualDataModelItem>(info.This());
70     if (!data)
71         V8THROW_ERROR("Not a valid VisualData object");
72
73     return v8::Int32::New(data->index);
74 }
75
76 static v8::Local<v8::ObjectTemplate> createConstructor()
77 {
78     v8::Local<v8::ObjectTemplate> constructor = v8::ObjectTemplate::New();
79     constructor->SetHasExternalResource(true);
80     constructor->SetAccessor(v8::String::New("index"), get_index);
81     return constructor;
82 }
83
84 class VDMModelDelegateDataType;
85
86 class QQuickVDMCachedModelData : public QQuickVisualDataModelItem
87 {
88 public:
89     QQuickVDMCachedModelData(
90             QQuickVisualDataModelItemMetaType *metaType,
91             VDMModelDelegateDataType *dataType,
92             int index);
93
94     int metaCall(QMetaObject::Call call, int id, void **arguments);
95
96     virtual QVariant value(int role) const = 0;
97     virtual void setValue(int role, const QVariant &value) = 0;
98
99     void setValue(const QString &role, const QVariant &value);
100     bool resolveIndex(const QQuickVisualAdaptorModel &model, int idx);
101
102     static v8::Handle<v8::Value> get_property(v8::Local<v8::String>, const v8::AccessorInfo &info);
103     static void set_property(
104             v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info);
105
106     VDMModelDelegateDataType *type;
107     QVector<QVariant> cachedData;
108 };
109
110 class VDMModelDelegateDataType
111         : public QQmlRefCount
112         , public QQuickVisualAdaptorModel::Accessors
113         , public QAbstractDynamicMetaObject
114 {
115 public:
116     VDMModelDelegateDataType(QQuickVisualAdaptorModel *model)
117         : model(model)
118         , metaObject(0)
119         , propertyCache(0)
120         , propertyOffset(0)
121         , signalOffset(0)
122         , hasModelData(false)
123     {
124     }
125
126     ~VDMModelDelegateDataType()
127     {
128         if (propertyCache)
129             propertyCache->release();
130         free(metaObject);
131
132         qPersistentDispose(constructor);
133     }
134
135     bool notify(
136             const QQuickVisualAdaptorModel &,
137             const QList<QQuickVisualDataModelItem *> &items,
138             int index,
139             int count,
140             const QList<int> &roles) const
141     {
142         bool changed = roles.isEmpty() && !watchedRoles.isEmpty();
143         if (!changed && !watchedRoles.isEmpty() && watchedRoleIds.isEmpty()) {
144             QList<int> roleIds;
145             foreach (const QByteArray &r, watchedRoles) {
146                 QHash<QByteArray, int>::const_iterator it = roleNames.find(r);
147                 if (it != roleNames.end())
148                     roleIds << it.value();
149             }
150             const_cast<VDMModelDelegateDataType *>(this)->watchedRoleIds = roleIds;
151         }
152
153         QVector<int> signalIndexes;
154         for (int i = 0; i < roles.count(); ++i) {
155             const int role = roles.at(i);
156             if (!changed && watchedRoleIds.contains(role))
157                 changed = true;
158
159             int propertyId = propertyRoles.indexOf(role);
160             if (propertyId != -1)
161                 signalIndexes.append(propertyId + signalOffset);
162         }
163         if (roles.isEmpty()) {
164             for (int propertyId = 0; propertyId < propertyRoles.count(); ++propertyId)
165                 signalIndexes.append(propertyId + signalOffset);
166         }
167
168         for (int i = 0, c = items.count();  i < c; ++i) {
169             QQuickVisualDataModelItem *item = items.at(i);
170             const int idx = item->modelIndex();
171             if (idx >= index && idx < index + count) {
172                 for (int i = 0; i < signalIndexes.count(); ++i)
173                     QMetaObject::activate(item, signalIndexes.at(i), 0);
174             }
175         }
176         return changed;
177     }
178
179     void replaceWatchedRoles(
180             QQuickVisualAdaptorModel &,
181             const QList<QByteArray> &oldRoles,
182             const QList<QByteArray> &newRoles) const
183     {
184         VDMModelDelegateDataType *dataType = const_cast<VDMModelDelegateDataType *>(this);
185
186         dataType->watchedRoleIds.clear();
187         foreach (const QByteArray &oldRole, oldRoles)
188             dataType->watchedRoles.removeOne(oldRole);
189         dataType->watchedRoles += newRoles;
190     }
191
192     void initializeConstructor()
193     {
194         constructor = qPersistentNew(createConstructor());
195
196         typedef QHash<QByteArray, int>::const_iterator iterator;
197         for (iterator it = roleNames.constBegin(), end = roleNames.constEnd(); it != end; ++it) {
198             const int propertyId = propertyRoles.indexOf(it.value());
199             const QByteArray &propertyName = it.key();
200
201             constructor->SetAccessor(
202                     v8::String::New(propertyName.constData(), propertyName.length()),
203                     QQuickVDMCachedModelData::get_property,
204                     QQuickVDMCachedModelData::set_property,
205                     v8::Int32::New(propertyId));
206         }
207     }
208
209     // QAbstractDynamicMetaObject
210
211     void objectDestroyed(QObject *)
212     {
213         release();
214     }
215
216     int metaCall(QObject *object, QMetaObject::Call call, int id, void **arguments)
217     {
218         return static_cast<QQuickVDMCachedModelData *>(object)->metaCall(call, id, arguments);
219     }
220
221     v8::Persistent<v8::ObjectTemplate> constructor;
222     QList<int> propertyRoles;
223     QList<int> watchedRoleIds;
224     QList<QByteArray> watchedRoles;
225     QHash<QByteArray, int> roleNames;
226     QQuickVisualAdaptorModel *model;
227     QMetaObject *metaObject;
228     QQmlPropertyCache *propertyCache;
229     int propertyOffset;
230     int signalOffset;
231     bool hasModelData;
232 };
233
234 QQuickVDMCachedModelData::QQuickVDMCachedModelData(
235         QQuickVisualDataModelItemMetaType *metaType, VDMModelDelegateDataType *dataType, int index)
236     : QQuickVisualDataModelItem(metaType, index)
237     , type(dataType)
238 {
239     if (index == -1)
240         cachedData.resize(type->hasModelData ? 1 : type->propertyRoles.count());
241
242     QObjectPrivate::get(this)->metaObject = type;
243
244     type->addref();
245
246     QQmlData *qmldata = QQmlData::get(this, true);
247     qmldata->propertyCache = dataType->propertyCache;
248     qmldata->propertyCache->addref();
249 }
250
251 int QQuickVDMCachedModelData::metaCall(QMetaObject::Call call, int id, void **arguments)
252 {
253     if (call == QMetaObject::ReadProperty && id >= type->propertyOffset) {
254         const int propertyIndex = id - type->propertyOffset;
255         if (index == -1) {
256             if (!cachedData.isEmpty()) {
257                 *static_cast<QVariant *>(arguments[0]) = cachedData.at(
258                     type->hasModelData ? 0 : propertyIndex);
259             }
260         } else  if (*type->model) {
261             *static_cast<QVariant *>(arguments[0]) = value(type->propertyRoles.at(propertyIndex));
262         }
263         return -1;
264     } else if (call == QMetaObject::WriteProperty && id >= type->propertyOffset) {
265         const int propertyIndex = id - type->propertyOffset;
266         if (index == -1) {
267             const QMetaObject *meta = metaObject();
268             if (cachedData.count() > 1) {
269                 cachedData[propertyIndex] = *static_cast<QVariant *>(arguments[0]);
270                 QMetaObject::activate(this, meta, propertyIndex, 0);
271             } else if (cachedData.count() == 1) {
272                 cachedData[0] = *static_cast<QVariant *>(arguments[0]);
273                 QMetaObject::activate(this, meta, 0, 0);
274                 QMetaObject::activate(this, meta, 1, 0);
275             }
276         } else if (*type->model) {
277             setValue(type->propertyRoles.at(propertyIndex), *static_cast<QVariant *>(arguments[0]));
278         }
279         return -1;
280     } else {
281         return qt_metacall(call, id, arguments);
282     }
283 }
284
285 void QQuickVDMCachedModelData::setValue(const QString &role, const QVariant &value)
286 {
287     QHash<QByteArray, int>::iterator it = type->roleNames.find(role.toUtf8());
288     if (it != type->roleNames.end()) {
289         for (int i = 0; i < type->propertyRoles.count(); ++i) {
290             if (type->propertyRoles.at(i) == *it) {
291                 cachedData[i] = value;
292                 return;
293             }
294         }
295     }
296 }
297
298 bool QQuickVDMCachedModelData::resolveIndex(const QQuickVisualAdaptorModel &, int idx)
299 {
300     if (index == -1) {
301         Q_ASSERT(idx >= 0);
302         index = idx;
303         cachedData.clear();
304         emit modelIndexChanged();
305         const QMetaObject *meta = metaObject();
306         const int propertyCount = type->propertyRoles.count();
307         for (int i = 0; i < propertyCount; ++i)
308             QMetaObject::activate(this, meta, i, 0);
309         return true;
310     } else {
311         return false;
312     }
313 }
314
315 v8::Handle<v8::Value> QQuickVDMCachedModelData::get_property(
316         v8::Local<v8::String>, const v8::AccessorInfo &info)
317 {
318     QQuickVisualDataModelItem *data = v8_resource_cast<QQuickVisualDataModelItem>(info.This());
319     if (!data)
320         V8THROW_ERROR("Not a valid VisualData object");
321
322     QQuickVDMCachedModelData *modelData = static_cast<QQuickVDMCachedModelData *>(data);
323     const int propertyId = info.Data()->Int32Value();
324     if (data->index == -1) {
325         if (!modelData->cachedData.isEmpty()) {
326             return data->engine->fromVariant(
327                     modelData->cachedData.at(modelData->type->hasModelData ? 0 : propertyId));
328         }
329     } else if (*modelData->type->model) {
330         return data->engine->fromVariant(
331                 modelData->value(modelData->type->propertyRoles.at(propertyId)));
332     }
333     return v8::Undefined();
334 }
335
336 void QQuickVDMCachedModelData::set_property(
337         v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
338 {
339     QQuickVisualDataModelItem *data = v8_resource_cast<QQuickVisualDataModelItem>(info.This());
340     if (!data)
341         V8THROW_ERROR_SETTER("Not a valid VisualData object");
342
343     const int propertyId = info.Data()->Int32Value();
344     if (data->index == -1) {
345         QQuickVDMCachedModelData *modelData = static_cast<QQuickVDMCachedModelData *>(data);
346         if (!modelData->cachedData.isEmpty()) {
347             if (modelData->cachedData.count() > 1) {
348                 modelData->cachedData[propertyId] = data->engine->toVariant(value, QVariant::Invalid);
349                 QMetaObject::activate(data, data->metaObject(), propertyId, 0);
350             } else if (modelData->cachedData.count() == 1) {
351                 modelData->cachedData[0] = data->engine->toVariant(value, QVariant::Invalid);
352                 QMetaObject::activate(data, data->metaObject(), 0, 0);
353                 QMetaObject::activate(data, data->metaObject(), 1, 0);
354             }
355         }
356     }
357 }
358
359 //-----------------------------------------------------------------
360 // QAbstractItemModel
361 //-----------------------------------------------------------------
362
363 class QQuickVDMAbstractItemModelData : public QQuickVDMCachedModelData
364 {
365     Q_OBJECT
366     Q_PROPERTY(bool hasModelChildren READ hasModelChildren CONSTANT)
367 public:
368     QQuickVDMAbstractItemModelData(
369             QQuickVisualDataModelItemMetaType *metaType,
370             VDMModelDelegateDataType *dataType,
371             int index)
372         : QQuickVDMCachedModelData(metaType, dataType, index)
373     {
374     }
375
376     bool hasModelChildren() const
377     {
378         if (index >= 0 && *type->model) {
379             const QAbstractItemModel * const model = type->model->aim();
380             return model->hasChildren(model->index(index, 0, type->model->rootIndex));
381         } else {
382             return false;
383         }
384     }
385
386     QVariant value(int role) const
387     {
388         return type->model->aim()->index(index, 0, type->model->rootIndex).data(role);
389     }
390
391     void setValue(int role, const QVariant &value)
392     {
393         type->model->aim()->setData(
394                 type->model->aim()->index(index, 0, type->model->rootIndex), value, role);
395     }
396
397     v8::Handle<v8::Value> get()
398     {
399         if (type->constructor.IsEmpty()) {
400             v8::HandleScope handleScope;
401             v8::Context::Scope contextScope(engine->context());
402             type->initializeConstructor();
403             type->constructor->SetAccessor(v8::String::New("hasModelChildren"), get_hasModelChildren);
404         }
405         v8::Local<v8::Object> data = type->constructor->NewInstance();
406         data->SetExternalResource(this);
407         return data;
408     }
409
410     static v8::Handle<v8::Value> get_hasModelChildren(v8::Local<v8::String>, const v8::AccessorInfo &info)
411     {
412         QQuickVisualDataModelItem *data = v8_resource_cast<QQuickVisualDataModelItem>(info.This());
413         if (!data)
414             V8THROW_ERROR("Not a valid VisualData object");
415
416         const QQuickVisualAdaptorModel *const model = static_cast<QQuickVDMCachedModelData *>(data)->type->model;
417         if (data->index >= 0 && *model) {
418             const QAbstractItemModel * const aim = model->aim();
419             return v8::Boolean::New(aim->hasChildren(aim->index(data->index, 0, model->rootIndex)));
420         } else {
421             return v8::Boolean::New(false);
422         }
423     }
424 };
425
426 class VDMAbstractItemModelDataType : public VDMModelDelegateDataType
427 {
428 public:
429     VDMAbstractItemModelDataType(QQuickVisualAdaptorModel *model)
430         : VDMModelDelegateDataType(model)
431     {
432     }
433
434     int count(const QQuickVisualAdaptorModel &model) const
435     {
436         return model.aim()->rowCount(model.rootIndex);
437     }
438
439     void cleanup(QQuickVisualAdaptorModel &model, QQuickVisualDataModel *vdm) const
440     {
441         QAbstractItemModel * const aim = model.aim();
442         if (aim && vdm) {
443             QObject::disconnect(aim, SIGNAL(rowsInserted(QModelIndex,int,int)),
444                                 vdm, SLOT(_q_rowsInserted(QModelIndex,int,int)));
445             QObject::disconnect(aim, SIGNAL(rowsRemoved(QModelIndex,int,int)),
446                                 vdm, SLOT(_q_rowsRemoved(QModelIndex,int,int)));
447             QObject::disconnect(aim, SIGNAL(dataChanged(QModelIndex,QModelIndex)),
448                                 vdm, SLOT(_q_dataChanged(QModelIndex,QModelIndex)));
449             QObject::disconnect(aim, SIGNAL(rowsMoved(QModelIndex,int,int,QModelIndex,int)),
450                                 vdm, SLOT(_q_rowsMoved(QModelIndex,int,int,QModelIndex,int)));
451             QObject::disconnect(aim, SIGNAL(modelReset()),
452                                 vdm, SLOT(_q_modelReset()));
453             QObject::disconnect(aim, SIGNAL(layoutChanged()),
454                                 vdm, SLOT(_q_layoutChanged()));
455         }
456
457         const_cast<VDMAbstractItemModelDataType *>(this)->release();
458     }
459
460     QVariant value(const QQuickVisualAdaptorModel &model, int index, const QString &role) const
461     {
462         QHash<QByteArray, int>::const_iterator it = roleNames.find(role.toUtf8());
463         if (it != roleNames.end()) {
464             return model.aim()->index(index, 0, model.rootIndex).data(*it);
465         } else if (role == QLatin1String("hasModelChildren")) {
466             return QVariant(model.aim()->hasChildren(model.aim()->index(index, 0, model.rootIndex)));
467         } else {
468             return QVariant();
469         }
470     }
471
472     QVariant parentModelIndex(const QQuickVisualAdaptorModel &model) const
473     {
474         return model
475                 ? QVariant::fromValue(model.aim()->parent(model.rootIndex))
476                 : QVariant();
477     }
478
479     QVariant modelIndex(const QQuickVisualAdaptorModel &model, int index) const
480     {
481         return model
482                 ? QVariant::fromValue(model.aim()->index(index, 0, model.rootIndex))
483                 : QVariant();
484     }
485
486     bool canFetchMore(const QQuickVisualAdaptorModel &model) const
487     {
488         return model && model.aim()->canFetchMore(model.rootIndex);
489     }
490
491     void fetchMore(QQuickVisualAdaptorModel &model) const
492     {
493         if (model)
494             model.aim()->fetchMore(model.rootIndex);
495     }
496
497     QQuickVisualDataModelItem *createItem(
498             QQuickVisualAdaptorModel &model,
499             QQuickVisualDataModelItemMetaType *metaType,
500             QQmlEngine *engine,
501             int index) const
502     {
503         VDMAbstractItemModelDataType *dataType = const_cast<VDMAbstractItemModelDataType *>(this);
504         if (!metaObject)
505             dataType->initializeMetaType(model, engine);
506         return new QQuickVDMAbstractItemModelData(metaType, dataType, index);
507     }
508
509     void initializeMetaType(QQuickVisualAdaptorModel &model, QQmlEngine *engine)
510     {
511         QMetaObjectBuilder builder;
512         setModelDataType<QQuickVDMAbstractItemModelData>(&builder, this);
513
514         const QByteArray propertyType = QByteArrayLiteral("QVariant");
515         const QHash<int, QByteArray> names = model.aim()->roleNames();
516         for (QHash<int, QByteArray>::const_iterator it = names.begin(); it != names.end(); ++it) {
517             const int propertyId = propertyRoles.count();
518             propertyRoles.append(it.key());
519             roleNames.insert(it.value(), it.key());
520             addProperty(&builder, propertyId, it.value(), propertyType);
521         }
522         if (propertyRoles.count() == 1) {
523             hasModelData = true;
524             const int role = names.begin().key();
525             const QByteArray propertyName = QByteArrayLiteral("modelData");
526
527             propertyRoles.append(role);
528             roleNames.insert(propertyName, role);
529             addProperty(&builder, 1, propertyName, propertyType);
530         }
531
532         metaObject = builder.toMetaObject();
533         *static_cast<QMetaObject *>(this) = *metaObject;
534         propertyCache = new QQmlPropertyCache(engine, metaObject);
535     }
536 };
537
538 //-----------------------------------------------------------------
539 // QListModelInterface
540 //-----------------------------------------------------------------
541
542 class QQuickVDMListModelInterfaceData : public QQuickVDMCachedModelData
543 {
544 public:
545     QQuickVDMListModelInterfaceData(QQuickVisualDataModelItemMetaType *metaType, VDMModelDelegateDataType *dataType, int index)
546         : QQuickVDMCachedModelData(metaType, dataType, index)
547     {
548     }
549
550     QVariant value(int role) const
551     {
552         return type->model->lmi()->data(index, role);
553     }
554
555     void setValue(int, const QVariant &) {}
556
557     v8::Handle<v8::Value> get()
558     {
559         if (type->constructor.IsEmpty()) {
560             v8::HandleScope handleScope;
561             v8::Context::Scope contextScope(engine->context());
562             type->initializeConstructor();
563         }
564         v8::Local<v8::Object> data = type->constructor->NewInstance();
565         data->SetExternalResource(this);
566         return data;
567     }
568 };
569
570 class VDMListModelInterfaceDataType : public VDMModelDelegateDataType
571 {
572 public:
573     VDMListModelInterfaceDataType(QQuickVisualAdaptorModel *model)
574         : VDMModelDelegateDataType(model)
575     {
576     }
577
578     int count(const QQuickVisualAdaptorModel &model) const
579     {
580         return model.lmi()->count();
581     }
582
583     void cleanup(QQuickVisualAdaptorModel &model, QQuickVisualDataModel *vdm) const
584     {
585         QListModelInterface *lmi = model.lmi();
586         if (lmi && vdm) {
587             QObject::disconnect(lmi, SIGNAL(itemsChanged(int,int,QList<int>)),
588                                 vdm, SLOT(_q_itemsChanged(int,int,QList<int>)));
589             QObject::disconnect(lmi, SIGNAL(itemsInserted(int,int)),
590                                 vdm, SLOT(_q_itemsInserted(int,int)));
591             QObject::disconnect(lmi, SIGNAL(itemsRemoved(int,int)),
592                                 vdm, SLOT(_q_itemsRemoved(int,int)));
593             QObject::disconnect(lmi, SIGNAL(itemsMoved(int,int,int)),
594                                 vdm, SLOT(_q_itemsMoved(int,int,int)));
595         }
596         const_cast<VDMListModelInterfaceDataType *>(this)->release();
597     }
598
599     QVariant value(const QQuickVisualAdaptorModel &model, int index, const QString &role) const
600     {
601         QHash<QByteArray, int>::const_iterator it = roleNames.find(role.toUtf8());
602         return it != roleNames.end() && model
603                 ? model.lmi()->data(index, *it)
604                 : QVariant();
605     }
606
607     QQuickVisualDataModelItem *createItem(
608             QQuickVisualAdaptorModel &model,
609             QQuickVisualDataModelItemMetaType *metaType,
610             QQmlEngine *engine,
611             int index) const
612     {
613         VDMListModelInterfaceDataType *dataType = const_cast<VDMListModelInterfaceDataType *>(this);
614         if (!metaObject)
615             dataType->initializeMetaType(model, engine);
616         return new QQuickVDMListModelInterfaceData(metaType, dataType, index);
617     }
618
619     void initializeMetaType(QQuickVisualAdaptorModel &model, QQmlEngine *engine)
620     {
621         QMetaObjectBuilder builder;
622         setModelDataType<QQuickVDMListModelInterfaceData>(&builder, this);
623
624         const QByteArray propertyType = QByteArrayLiteral("QVariant");
625
626         const QListModelInterface * const listModelInterface = model.lmi();
627         const QList<int> roles = listModelInterface->roles();
628         for (int propertyId = 0; propertyId < roles.count(); ++propertyId) {
629             const int role = roles.at(propertyId);
630             const QString roleName = listModelInterface->toString(role);
631             const QByteArray propertyName = roleName.toUtf8();
632
633             propertyRoles.append(role);
634             roleNames.insert(propertyName, role);
635             addProperty(&builder, propertyId, propertyName, propertyType);
636
637         }
638         if (propertyRoles.count() == 1) {
639             hasModelData = true;
640             const int role = roles.first();
641             const QByteArray propertyName = QByteArrayLiteral("modelData");
642
643             propertyRoles.append(role);
644             roleNames.insert(propertyName, role);
645             addProperty(&builder, 1, propertyName, propertyType);
646         }
647
648         metaObject = builder.toMetaObject();
649         *static_cast<QMetaObject *>(this) = *metaObject;
650         propertyCache = new QQmlPropertyCache(engine, metaObject);
651     }
652 };
653
654 //-----------------------------------------------------------------
655 // QQuickListAccessor
656 //-----------------------------------------------------------------
657
658 class QQuickVDMListAccessorData : public QQuickVisualDataModelItem
659 {
660     Q_OBJECT
661     Q_PROPERTY(QVariant modelData READ modelData WRITE setModelData NOTIFY modelDataChanged)
662 public:
663     QQuickVDMListAccessorData(QQuickVisualDataModelItemMetaType *metaType, int index, const QVariant &value)
664         : QQuickVisualDataModelItem(metaType, index)
665         , cachedData(value)
666     {
667     }
668
669     QVariant modelData() const
670     {
671         return cachedData;
672     }
673
674     void setModelData(const QVariant &data)
675     {
676         if (index == -1 && data != cachedData) {
677             cachedData = data;
678             emit modelDataChanged();
679         }
680     }
681
682     static v8::Handle<v8::Value> get_modelData(v8::Local<v8::String>, const v8::AccessorInfo &info)
683     {
684         QQuickVisualDataModelItem *data = v8_resource_cast<QQuickVisualDataModelItem>(info.This());
685         if (!data)
686             V8THROW_ERROR("Not a valid VisualData object");
687
688         return data->engine->fromVariant(static_cast<QQuickVDMListAccessorData *>(data)->cachedData);
689     }
690
691     static void set_modelData(v8::Local<v8::String>, const v8::Handle<v8::Value> &value, const v8::AccessorInfo &info)
692     {
693         QQuickVisualDataModelItem *data = v8_resource_cast<QQuickVisualDataModelItem>(info.This());
694         if (!data)
695             V8THROW_ERROR_SETTER("Not a valid VisualData object");
696
697         static_cast<QQuickVDMListAccessorData *>(data)->setModelData(
698                 data->engine->toVariant(value, QVariant::Invalid));
699     }
700
701     void setValue(const QString &role, const QVariant &value)
702     {
703         if (role == QLatin1String("modelData"))
704             cachedData = value;
705     }
706
707     bool resolveIndex(const QQuickVisualAdaptorModel &model, int idx)
708     {
709         if (index == -1) {
710             index = idx;
711             cachedData = model.list.at(idx);
712             emit modelIndexChanged();
713             emit modelDataChanged();
714             return true;
715         } else {
716             return false;
717         }
718     }
719
720 Q_SIGNALS:
721     void modelDataChanged();
722
723 private:
724     QVariant cachedData;
725 };
726
727
728 class VDMListDelegateDataType : public QQuickVisualAdaptorModel::Accessors
729 {
730 public:
731     inline VDMListDelegateDataType() {}
732
733     int count(const QQuickVisualAdaptorModel &model) const
734     {
735         return model.list.count();
736     }
737
738     QVariant value(const QQuickVisualAdaptorModel &model, int index, const QString &role) const
739     {
740         return role == QLatin1String("modelData")
741                 ? model.list.at(index)
742                 : QVariant();
743     }
744
745     QQuickVisualDataModelItem *createItem(
746             QQuickVisualAdaptorModel &model,
747             QQuickVisualDataModelItemMetaType *metaType,
748             QQmlEngine *,
749             int index) const
750     {
751         return new QQuickVDMListAccessorData(
752                 metaType,
753                 index,
754                 index >= 0 && index < model.list.count() ? model.list.at(index) : QVariant());
755     }
756 };
757
758 //-----------------------------------------------------------------
759 // QObject
760 //-----------------------------------------------------------------
761
762 class VDMObjectDelegateDataType;
763 class QQuickVDMObjectData : public QQuickVisualDataModelItem, public QQuickVisualAdaptorModelProxyInterface
764 {
765     Q_OBJECT
766     Q_PROPERTY(QObject *modelData READ modelData CONSTANT)
767     Q_INTERFACES(QQuickVisualAdaptorModelProxyInterface)
768 public:
769     QQuickVDMObjectData(
770             QQuickVisualDataModelItemMetaType *metaType,
771             VDMObjectDelegateDataType *dataType,
772             int index,
773             QObject *object);
774
775     QObject *modelData() const { return object; }
776     QObject *proxiedObject() { return object; }
777
778     QQmlGuard<QObject> object;
779 };
780
781 class VDMObjectDelegateDataType : public QQmlRefCount, public QQuickVisualAdaptorModel::Accessors
782 {
783 public:
784     QMetaObject *metaObject;
785     int propertyOffset;
786     int signalOffset;
787     bool shared;
788     QMetaObjectBuilder builder;
789
790     VDMObjectDelegateDataType()
791         : metaObject(0)
792         , propertyOffset(0)
793         , signalOffset(0)
794         , shared(true)
795     {
796     }
797
798     VDMObjectDelegateDataType(const VDMObjectDelegateDataType &type)
799         : QQmlRefCount()
800         , metaObject(0)
801         , propertyOffset(type.propertyOffset)
802         , signalOffset(type.signalOffset)
803         , shared(false)
804         , builder(type.metaObject, QMetaObjectBuilder::Properties
805                 | QMetaObjectBuilder::Signals
806                 | QMetaObjectBuilder::SuperClass
807                 | QMetaObjectBuilder::ClassName)
808     {
809         builder.setFlags(QMetaObjectBuilder::DynamicMetaObject);
810     }
811
812     ~VDMObjectDelegateDataType()
813     {
814         free(metaObject);
815     }
816
817     int count(const QQuickVisualAdaptorModel &model) const
818     {
819         return model.list.count();
820     }
821
822     QVariant value(const QQuickVisualAdaptorModel &model, int index, const QString &role) const
823     {
824         if (QObject *object = model.list.at(index).value<QObject *>())
825             return object->property(role.toUtf8());
826         return QVariant();
827     }
828
829     QQuickVisualDataModelItem *createItem(
830             QQuickVisualAdaptorModel &model,
831             QQuickVisualDataModelItemMetaType *metaType,
832             QQmlEngine *,
833             int index) const
834     {
835         VDMObjectDelegateDataType *dataType = const_cast<VDMObjectDelegateDataType *>(this);
836         if (!metaObject)
837             dataType->initializeMetaType(model);
838         return index >= 0 && index < model.list.count()
839                 ? new QQuickVDMObjectData(metaType, dataType, index, qvariant_cast<QObject *>(model.list.at(index)))
840                 : 0;
841     }
842
843     void initializeMetaType(QQuickVisualAdaptorModel &)
844     {
845         setModelDataType<QQuickVDMObjectData>(&builder, this);
846
847         metaObject = builder.toMetaObject();
848     }
849
850     void cleanup(QQuickVisualAdaptorModel &, QQuickVisualDataModel *) const
851     {
852         const_cast<VDMObjectDelegateDataType *>(this)->release();
853     }
854 };
855
856 class QQuickVDMObjectDataMetaObject : public QAbstractDynamicMetaObject
857 {
858 public:
859     QQuickVDMObjectDataMetaObject(QQuickVDMObjectData *data, VDMObjectDelegateDataType *type)
860         : m_data(data)
861         , m_type(type)
862     {
863         QObjectPrivate *op = QObjectPrivate::get(m_data);
864         *static_cast<QMetaObject *>(this) = *type->metaObject;
865         op->metaObject = this;
866         m_type->addref();
867     }
868
869     ~QQuickVDMObjectDataMetaObject()
870     {
871         m_type->release();
872     }
873
874     int metaCall(QMetaObject::Call call, int id, void **arguments)
875     {
876         static const int objectPropertyOffset = QObject::staticMetaObject.propertyCount();
877         if (id >= m_type->propertyOffset
878                 && (call == QMetaObject::ReadProperty
879                 || call == QMetaObject::WriteProperty
880                 || call == QMetaObject::ResetProperty)) {
881             if (m_data->object)
882                 QMetaObject::metacall(m_data->object, call, id - m_type->propertyOffset + objectPropertyOffset, arguments);
883             return -1;
884         } else if (id >= m_type->signalOffset && call == QMetaObject::InvokeMetaMethod) {
885             QMetaObject::activate(m_data, this, id - m_type->signalOffset, 0);
886             return -1;
887         } else {
888             return m_data->qt_metacall(call, id, arguments);
889         }
890     }
891
892     int createProperty(const char *name, const char *)
893     {
894         if (!m_data->object)
895             return -1;
896         const QMetaObject *metaObject = m_data->object->metaObject();
897         static const int objectPropertyOffset = QObject::staticMetaObject.propertyCount();
898
899         const int previousPropertyCount = propertyCount() - propertyOffset();
900         int propertyIndex = metaObject->indexOfProperty(name);
901         if (propertyIndex == -1)
902             return -1;
903         if (previousPropertyCount + objectPropertyOffset == metaObject->propertyCount())
904             return propertyIndex + m_type->propertyOffset - objectPropertyOffset;
905
906         if (m_type->shared) {
907             VDMObjectDelegateDataType *type = m_type;
908             m_type = new VDMObjectDelegateDataType(*m_type);
909             type->release();
910         }
911
912         const int previousMethodCount = methodCount();
913         int notifierId = previousMethodCount - methodOffset();
914         for (int propertyId = previousPropertyCount; propertyId < metaObject->propertyCount() - objectPropertyOffset; ++propertyId) {
915             QMetaProperty property = metaObject->property(propertyId + objectPropertyOffset);
916             QMetaPropertyBuilder propertyBuilder;
917             if (property.hasNotifySignal()) {
918                 m_type->builder.addSignal("__" + QByteArray::number(propertyId) + "()");
919                 propertyBuilder = m_type->builder.addProperty(property.name(), property.typeName(), notifierId);
920                 ++notifierId;
921             } else {
922                 propertyBuilder = m_type->builder.addProperty(property.name(), property.typeName());
923             }
924             propertyBuilder.setWritable(property.isWritable());
925             propertyBuilder.setResettable(property.isResettable());
926             propertyBuilder.setConstant(property.isConstant());
927         }
928
929         if (m_type->metaObject)
930             free(m_type->metaObject);
931         m_type->metaObject = m_type->builder.toMetaObject();
932         *static_cast<QMetaObject *>(this) = *m_type->metaObject;
933
934         notifierId = previousMethodCount;
935         for (int i = previousPropertyCount; i < metaObject->propertyCount() - objectPropertyOffset; ++i) {
936             QMetaProperty property = metaObject->property(i + objectPropertyOffset);
937             if (property.hasNotifySignal()) {
938                 QQmlPropertyPrivate::connect(
939                         m_data->object, property.notifySignalIndex(), m_data, notifierId);
940                 ++notifierId;
941             }
942         }
943         return propertyIndex + m_type->propertyOffset - objectPropertyOffset;
944     }
945
946     QQuickVDMObjectData *m_data;
947     VDMObjectDelegateDataType *m_type;
948 };
949
950 QQuickVDMObjectData::QQuickVDMObjectData(
951         QQuickVisualDataModelItemMetaType *metaType,
952         VDMObjectDelegateDataType *dataType,
953         int index,
954         QObject *object)
955     : QQuickVisualDataModelItem(metaType, index)
956     , object(object)
957 {
958     new QQuickVDMObjectDataMetaObject(this, dataType);
959 }
960
961 //-----------------------------------------------------------------
962 // QQuickVisualAdaptorModel
963 //-----------------------------------------------------------------
964
965 static const QQuickVisualAdaptorModel::Accessors qt_vdm_null_accessors;
966 static const VDMListDelegateDataType qt_vdm_list_accessors;
967
968 QQuickVisualAdaptorModel::QQuickVisualAdaptorModel()
969     : accessors(&qt_vdm_null_accessors)
970 {
971 }
972
973 QQuickVisualAdaptorModel::~QQuickVisualAdaptorModel()
974 {
975     accessors->cleanup(*this);
976 }
977
978 void QQuickVisualAdaptorModel::setModel(const QVariant &variant, QQuickVisualDataModel *vdm, QQmlEngine *engine)
979 {
980     accessors->cleanup(*this, vdm);
981
982     list.setList(variant, engine);
983
984     if (QObject *object = qvariant_cast<QObject *>(variant)) {
985         setObject(object);
986         if (QAbstractItemModel *model = qobject_cast<QAbstractItemModel *>(object)) {
987             accessors = new VDMAbstractItemModelDataType(this);
988
989             qmlobject_connect(model, QAbstractItemModel, SIGNAL(rowsInserted(QModelIndex,int,int)),
990                               vdm, QQuickVisualDataModel, SLOT(_q_rowsInserted(QModelIndex,int,int)));
991             qmlobject_connect(model, QAbstractItemModel, SIGNAL(rowsRemoved(QModelIndex,int,int)),
992                               vdm,  QQuickVisualDataModel, SLOT(_q_rowsRemoved(QModelIndex,int,int)));
993             qmlobject_connect(model, QAbstractItemModel, SIGNAL(dataChanged(QModelIndex,QModelIndex)),
994                               vdm, QQuickVisualDataModel, SLOT(_q_dataChanged(QModelIndex,QModelIndex)));
995             qmlobject_connect(model, QAbstractItemModel, SIGNAL(rowsMoved(QModelIndex,int,int,QModelIndex,int)),
996                               vdm, QQuickVisualDataModel, SLOT(_q_rowsMoved(QModelIndex,int,int,QModelIndex,int)));
997             qmlobject_connect(model, QAbstractItemModel, SIGNAL(modelReset()),
998                               vdm, QQuickVisualDataModel, SLOT(_q_modelReset()));
999             qmlobject_connect(model, QAbstractItemModel, SIGNAL(layoutChanged()),
1000                               vdm, QQuickVisualDataModel, SLOT(_q_layoutChanged()));
1001         } else if (QListModelInterface *model = qobject_cast<QListModelInterface *>(object)) {
1002             accessors = new VDMListModelInterfaceDataType(this);
1003
1004             qmlobject_connect(model, QListModelInterface, SIGNAL(itemsChanged(int,int,QList<int>)),
1005                               vdm, QQuickVisualDataModel, SLOT(_q_itemsChanged(int,int,QList<int>)));
1006             qmlobject_connect(model, QListModelInterface, SIGNAL(itemsInserted(int,int)),
1007                               vdm, QQuickVisualDataModel, SLOT(_q_itemsInserted(int,int)));
1008             qmlobject_connect(model, QListModelInterface, SIGNAL(itemsRemoved(int,int)),
1009                               vdm, QQuickVisualDataModel, SLOT(_q_itemsRemoved(int,int)));
1010             qmlobject_connect(model, QListModelInterface, SIGNAL(itemsMoved(int,int,int)),
1011                               vdm, QQuickVisualDataModel, SLOT(_q_itemsMoved(int,int,int)));
1012         } else {
1013             accessors = new VDMObjectDelegateDataType;
1014         }
1015     } else if (list.type() == QQuickListAccessor::ListProperty) {
1016         setObject(static_cast<const QQmlListReference *>(variant.constData())->object());
1017         accessors = new VDMObjectDelegateDataType;
1018     } else if (list.type() != QQuickListAccessor::Invalid) {
1019         Q_ASSERT(list.type() != QQuickListAccessor::Instance);  // Should have cast to QObject.
1020         setObject(0);
1021         accessors = &qt_vdm_list_accessors;
1022     } else {
1023         setObject(0);
1024         accessors = &qt_vdm_null_accessors;
1025     }
1026 }
1027
1028 void QQuickVisualAdaptorModel::objectDestroyed(QObject *)
1029 {
1030     setModel(QVariant(), 0, 0);
1031 }
1032
1033 QT_END_NAMESPACE
1034
1035 QML_DECLARE_TYPE(QListModelInterface)
1036
1037 #include <qquickvisualadaptormodel.moc>