1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the QtDeclarative module of the Qt Toolkit.
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #include "qquickvisualadaptormodel_p.h"
43 #include "qquickvisualdatamodel_p_p.h"
45 #include <private/qdeclarativeengine_p.h>
46 #include <private/qdeclarativelistaccessor_p.h>
47 #include <private/qdeclarativepropertycache_p.h>
48 #include <private/qlistmodelinterface_p.h>
49 #include <private/qmetaobjectbuilder_p.h>
50 #include <private/qintrusivelist_p.h>
51 #include <private/qobject_p.h>
55 class VDMDelegateDataType : public QDeclarativeRefCount
67 VDMDelegateDataType(const VDMDelegateDataType &type)
70 , propertyOffset(type.propertyOffset)
71 , signalOffset(type.signalOffset)
73 , builder(type.metaObject, QMetaObjectBuilder::Properties
74 | QMetaObjectBuilder::Signals
75 | QMetaObjectBuilder::SuperClass
76 | QMetaObjectBuilder::ClassName)
78 builder.setFlags(QMetaObjectBuilder::DynamicMetaObject);
81 ~VDMDelegateDataType()
84 propertyCache->release();
88 QMetaObject *metaObject;
89 QDeclarativePropertyCache *propertyCache;
93 QMetaObjectBuilder builder;
96 typedef QIntrusiveList<QQuickVisualDataModelItem, &QQuickVisualDataModelItem::cacheNode> QQuickVisualDataModelItemCache;
98 class QQuickVisualDataModelItemMetaObject;
99 class QQuickVisualAdaptorModelPrivate : public QObjectPrivate
101 Q_DECLARE_PUBLIC(QQuickVisualAdaptorModel)
103 QQuickVisualAdaptorModelPrivate()
106 , m_delegateDataType(0)
107 , createItem(&initializeModelData)
108 , stringValue(&initializeStringValue)
112 , m_objectList(false)
116 ~QQuickVisualAdaptorModelPrivate()
118 qPersistentDispose(m_constructor);
121 static QQuickVisualAdaptorModelPrivate *get(QQuickVisualAdaptorModel *m) {
122 return static_cast<QQuickVisualAdaptorModelPrivate *>(QObjectPrivate::get(m));
125 void addProperty(int role, int propertyId, const char *propertyName, const char *propertyType, bool isModelData = false);
126 template <typename T> void setModelDataType()
128 createItem = &T::create;
129 stringValue = &T::stringValue;
130 m_delegateDataType->builder.setFlags(QMetaObjectBuilder::DynamicMetaObject);
131 m_delegateDataType->builder.setClassName(T::staticMetaObject.className());
132 m_delegateDataType->builder.setSuperClass(&T::staticMetaObject);
133 m_delegateDataType->propertyOffset = T::staticMetaObject.propertyCount();
134 m_delegateDataType->signalOffset = T::staticMetaObject.methodCount();
137 void createMetaObject();
139 static QQuickVisualDataModelItem *initializeModelData(
140 QQuickVisualDataModelItemMetaType *metaType, QQuickVisualAdaptorModel *model, int index) {
141 QQuickVisualAdaptorModelPrivate *d = get(model);
142 d->createMetaObject();
143 return d->createItem(metaType, model, index);
146 static QString initializeStringValue(QQuickVisualAdaptorModelPrivate *model, int index, const QString &name) {
147 model->createMetaObject();
148 return model->stringValue(model, index, name);
151 typedef QQuickVisualDataModelItem *(*CreateModelData)(QQuickVisualDataModelItemMetaType *metaType, QQuickVisualAdaptorModel *model, int index);
152 typedef QString (*StringValue)(QQuickVisualAdaptorModelPrivate *model, int index, const QString &name);
154 struct PropertyData {
156 bool isModelData : 1;
159 int modelCount() const {
160 if (m_listModelInterface)
161 return m_listModelInterface->count();
162 if (m_abstractItemModel)
163 return m_abstractItemModel->rowCount(m_root);
165 return m_listAccessor->count();
169 QDeclarativeGuard<QDeclarativeEngine> m_engine;
170 QDeclarativeGuard<QListModelInterface> m_listModelInterface;
171 QDeclarativeGuard<QAbstractItemModel> m_abstractItemModel;
172 QDeclarativeListAccessor *m_listAccessor;
173 VDMDelegateDataType *m_delegateDataType;
174 CreateModelData createItem;
175 StringValue stringValue;
176 v8::Persistent<v8::Function> m_constructor;
181 QQuickVisualAdaptorModel::Flags m_flags;
182 bool m_objectList : 1;
184 QVariant m_modelVariant;
188 QList<int> watchedRoleIds;
189 QList<QByteArray> watchedRoles;
190 QHash<QByteArray,int> m_roleNames;
191 QVector<PropertyData> m_propertyData;
192 QQuickVisualDataModelItemCache m_cache;
195 class QQuickVDMCachedModelData : public QQuickVisualDataModelItem
198 virtual QVariant value(QQuickVisualAdaptorModelPrivate *model, int role) const = 0;
199 virtual void setValue(QQuickVisualAdaptorModelPrivate *model, int role, const QVariant &value) = 0;
201 void setValue(const QString &role, const QVariant &value)
203 QQuickVisualAdaptorModelPrivate *d = QQuickVisualAdaptorModelPrivate::get(model);
204 QHash<QByteArray, int>::iterator it = d->m_roleNames.find(role.toUtf8());
205 if (it != d->m_roleNames.end()) {
206 for (int i = 0; i < d->m_propertyData.count(); ++i) {
207 if (d->m_propertyData.at(i).role == *it) {
208 cachedData[i] = value;
215 bool resolveIndex(int idx)
217 if (index[0] == -1) {
219 QQuickVisualAdaptorModelPrivate *d = QQuickVisualAdaptorModelPrivate::get(model);
222 emit modelIndexChanged();
223 const QMetaObject *meta = metaObject();
224 const int propertyCount = d->m_propertyData.count();
225 for (int i = 0; i < propertyCount; ++i)
226 QMetaObject::activate(this, meta, i, 0);
233 static v8::Handle<v8::Value> get_property(v8::Local<v8::String>, const v8::AccessorInfo &info)
235 QQuickVisualDataModelItem *data = v8_resource_cast<QQuickVisualDataModelItem>(info.This());
237 V8THROW_ERROR("Not a valid VisualData object");
239 QQuickVisualAdaptorModelPrivate *model = QQuickVisualAdaptorModelPrivate::get(data->model);
240 QQuickVDMCachedModelData *modelData = static_cast<QQuickVDMCachedModelData *>(data);
241 const int propertyId = info.Data()->Int32Value();
242 if (data->index[0] == -1) {
243 if (!modelData->cachedData.isEmpty()) {
244 return data->engine->fromVariant(
245 modelData->cachedData.at(modelData->cachedData.count() > 1 ? propertyId : 0));
248 return data->engine->fromVariant(
249 modelData->value(model, model->m_propertyData.at(propertyId).role));
251 return v8::Undefined();
254 static void set_property(
255 v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
257 QQuickVisualDataModelItem *data = v8_resource_cast<QQuickVisualDataModelItem>(info.This());
259 V8THROW_ERROR_SETTER("Not a valid VisualData object");
261 const int propertyId = info.Data()->Int32Value();
262 if (data->index[0] == -1) {
263 QQuickVDMCachedModelData *modelData = static_cast<QQuickVDMCachedModelData *>(data);
264 if (!modelData->cachedData.isEmpty()) {
265 if (modelData->cachedData.count() > 1) {
266 modelData->cachedData[propertyId] = data->engine->toVariant(value, QVariant::Invalid);
267 QMetaObject::activate(data, data->metaObject(), propertyId, 0);
268 } else if (modelData->cachedData.count() == 1) {
269 modelData->cachedData[0] = data->engine->toVariant(value, QVariant::Invalid);
270 QMetaObject::activate(data, data->metaObject(), 0, 0);
271 QMetaObject::activate(data, data->metaObject(), 1, 0);
277 v8::Handle<v8::Value> get()
279 QQuickVisualAdaptorModelPrivate *d = QQuickVisualAdaptorModelPrivate::get(model);
281 v8::Local<v8::Object> data = d->m_constructor->NewInstance();
282 data->SetExternalResource(this);
287 QQuickVDMCachedModelData(
288 QQuickVisualDataModelItemMetaType *metaType, QQuickVisualAdaptorModel *model, int index)
289 : QQuickVisualDataModelItem(metaType, model, index)
292 cachedData.resize(QQuickVisualAdaptorModelPrivate::get(model)->m_roleCount);
295 QVector<QVariant> cachedData;
298 class QQuickVisualDataModelItemMetaObject : public QAbstractDynamicMetaObject
301 QQuickVisualDataModelItemMetaObject(QQuickVisualDataModelItem *data, VDMDelegateDataType *type)
305 QObjectPrivate *op = QObjectPrivate::get(m_data);
306 *static_cast<QMetaObject *>(this) = *type->metaObject;
307 op->metaObject = this;
311 ~QQuickVisualDataModelItemMetaObject() { m_type->release(); }
313 static v8::Handle<v8::Value> get_index(v8::Local<v8::String>, const v8::AccessorInfo &info)
315 QQuickVisualDataModelItem *data = v8_resource_cast<QQuickVisualDataModelItem>(info.This());
317 V8THROW_ERROR("Not a valid VisualData object");
319 return v8::Int32::New(data->index[0]);
322 QQuickVisualDataModelItem *m_data;
323 VDMDelegateDataType *m_type;
326 class QQuickVDMCachedModelDataMetaObject : public QQuickVisualDataModelItemMetaObject
329 QQuickVDMCachedModelDataMetaObject(QQuickVisualDataModelItem *object, VDMDelegateDataType *type)
330 : QQuickVisualDataModelItemMetaObject(object, type) {}
332 int metaCall(QMetaObject::Call call, int id, void **arguments)
334 if (call == QMetaObject::ReadProperty && id >= m_type->propertyOffset) {
335 QQuickVisualAdaptorModelPrivate *model = QQuickVisualAdaptorModelPrivate::get(m_data->model);
336 const int propertyIndex = id - m_type->propertyOffset;
337 if (m_data->index[0] == -1) {
338 QQuickVDMCachedModelData *data = static_cast<QQuickVDMCachedModelData *>(m_data);
339 if (!data->cachedData.isEmpty()) {
340 *static_cast<QVariant *>(arguments[0]) = data->cachedData.count() > 1
341 ? data->cachedData.at(propertyIndex)
342 : data->cachedData.at(0);
345 *static_cast<QVariant *>(arguments[0]) = static_cast<QQuickVDMCachedModelData *>(
346 m_data)->value(model, model->m_propertyData.at(propertyIndex).role);
349 } else if (call == QMetaObject::WriteProperty && id >= m_type->propertyOffset) {
350 QQuickVisualAdaptorModelPrivate *model = QQuickVisualAdaptorModelPrivate::get(m_data->model);
351 const int propertyIndex = id - m_type->propertyOffset;
352 if (m_data->index[0] == -1) {
353 QQuickVDMCachedModelData *data = static_cast<QQuickVDMCachedModelData *>(m_data);
354 if (data->cachedData.count() > 1) {
355 data->cachedData[propertyIndex] = *static_cast<QVariant *>(arguments[0]);
356 activate(data, this, propertyIndex, 0);
357 } else if (data->cachedData.count() == 1) {
358 data->cachedData[0] = *static_cast<QVariant *>(arguments[0]);
359 activate(data, this, 0, 0);
360 activate(data, this, 1, 0);
363 static_cast<QQuickVDMCachedModelData *>(m_data)->setValue(
365 model->m_propertyData.at(propertyIndex).role,
366 *static_cast<QVariant *>(arguments[0]));
370 return m_data->qt_metacall(call, id, arguments);
375 class QQuickVDMAbstractItemModelData : public QQuickVDMCachedModelData
378 Q_PROPERTY(bool hasModelChildren READ hasModelChildren CONSTANT)
380 bool hasModelChildren() const
382 QQuickVisualAdaptorModelPrivate *d = QQuickVisualAdaptorModelPrivate::get(model);
383 return d->m_abstractItemModel->hasChildren(d->m_abstractItemModel->index(index[0], 0, d->m_root));
386 static QQuickVisualDataModelItem *create(
387 QQuickVisualDataModelItemMetaType *metaType, QQuickVisualAdaptorModel *model, int index) {
388 return new QQuickVDMAbstractItemModelData(metaType, model, index); }
390 static QString stringValue(QQuickVisualAdaptorModelPrivate *model, int index, const QString &role)
392 QHash<QByteArray, int>::const_iterator it = model->m_roleNames.find(role.toUtf8());
393 if (it != model->m_roleNames.end()) {
394 return model->m_abstractItemModel->index(index, 0, model->m_root).data(*it).toString();
395 } else if (role == QLatin1String("hasModelChildren")) {
396 return QVariant(model->m_abstractItemModel->hasChildren(
397 model->m_abstractItemModel->index(index, 0, model->m_root))).toString();
403 QVariant value(QQuickVisualAdaptorModelPrivate *model, int role) const
405 return model->m_abstractItemModel
406 ? model->m_abstractItemModel->index(index[0], 0, model->m_root).data(role)
410 void setValue(QQuickVisualAdaptorModelPrivate *model, int role, const QVariant &value)
412 model->m_abstractItemModel->setData(
413 model->m_abstractItemModel->index(index[0], 0, model->m_root), value, role);
416 static v8::Handle<v8::Value> get_hasModelChildren(v8::Local<v8::String>, const v8::AccessorInfo &info)
418 QQuickVisualDataModelItem *data = v8_resource_cast<QQuickVisualDataModelItem>(info.This());
420 V8THROW_ERROR("Not a valid VisualData object");
422 QQuickVisualAdaptorModelPrivate *model = QQuickVisualAdaptorModelPrivate::get(data->model);
424 return v8::Boolean::New(model->m_abstractItemModel->hasChildren(
425 model->m_abstractItemModel->index(data->index[0], 0, model->m_root)));
429 QQuickVDMAbstractItemModelData(
430 QQuickVisualDataModelItemMetaType *metaType, QQuickVisualAdaptorModel *model, int index)
431 : QQuickVDMCachedModelData(metaType, model, index)
433 new QQuickVDMCachedModelDataMetaObject(
434 this, QQuickVisualAdaptorModelPrivate::get(model)->m_delegateDataType);
438 class QQuickVDMListModelInterfaceDataMetaObject : public QQuickVisualDataModelItemMetaObject
441 QQuickVDMListModelInterfaceDataMetaObject(QQuickVisualDataModelItem *object, VDMDelegateDataType *type)
442 : QQuickVisualDataModelItemMetaObject(object, type) {}
444 int metaCall(QMetaObject::Call call, int id, void **arguments)
446 if (call == QMetaObject::ReadProperty && id >= m_type->propertyOffset) {
447 QQuickVisualAdaptorModelPrivate *model = QQuickVisualAdaptorModelPrivate::get(m_data->model);
448 if (m_data->index[0] == -1 || !model->m_listModelInterface)
450 *static_cast<QVariant *>(arguments[0]) = model->m_listModelInterface->data(
451 m_data->index[0], model->m_propertyData.at(id - m_type->propertyOffset).role);
454 return m_data->qt_metacall(call, id, arguments);
460 class QQuickVDMListModelInterfaceData : public QQuickVDMCachedModelData
463 static QQuickVisualDataModelItem *create(
464 QQuickVisualDataModelItemMetaType *metaType, QQuickVisualAdaptorModel *model, int index) {
465 return new QQuickVDMListModelInterfaceData(metaType, model, index); }
467 static QString stringValue(QQuickVisualAdaptorModelPrivate *model, int index, const QString &role)
469 QHash<QByteArray, int>::const_iterator it = model->m_roleNames.find(role.toUtf8());
470 return it != model->m_roleNames.end()
471 ? model->m_listModelInterface->data(index, *it).toString()
475 QVariant value(QQuickVisualAdaptorModelPrivate *model, int role) const
477 return model->m_listModelInterface
478 ? model->m_listModelInterface->data(index[0], role)
482 void setValue(QQuickVisualAdaptorModelPrivate *, int, const QVariant &) {}
485 QQuickVDMListModelInterfaceData(QQuickVisualDataModelItemMetaType *metaType, QQuickVisualAdaptorModel *model, int index)
486 : QQuickVDMCachedModelData(metaType, model, index)
488 new QQuickVDMCachedModelDataMetaObject(
489 this, QQuickVisualAdaptorModelPrivate::get(model)->m_delegateDataType);
493 class QQuickVDMListAccessorData : public QQuickVisualDataModelItem
496 Q_PROPERTY(QVariant modelData READ modelData WRITE setModelData NOTIFY modelDataChanged)
498 QVariant modelData() const
500 QQuickVisualAdaptorModelPrivate *d = QQuickVisualAdaptorModelPrivate::get(model);
501 return index[0] != -1 && d->m_listAccessor
502 ? d->m_listAccessor->at(index[0])
506 void setModelData(const QVariant &data)
508 if (index[0] == -1 && data != cachedData) {
510 emit modelDataChanged();
514 static QQuickVisualDataModelItem *create(
515 QQuickVisualDataModelItemMetaType *metaType, QQuickVisualAdaptorModel *model, int index) {
516 return new QQuickVDMListAccessorData(metaType, model, index); }
518 static QString stringValue(QQuickVisualAdaptorModelPrivate *model, int index, const QString &role)
520 return role == QLatin1String("modelData")
521 ? model->m_listAccessor->at(index).toString()
525 static v8::Handle<v8::Value> get_modelData(v8::Local<v8::String>, const v8::AccessorInfo &info)
527 QQuickVisualDataModelItem *data = v8_resource_cast<QQuickVisualDataModelItem>(info.This());
529 V8THROW_ERROR("Not a valid VisualData object");
531 QQuickVisualAdaptorModelPrivate *d = QQuickVisualAdaptorModelPrivate::get(data->model);
532 if (data->index[0] == -1 || !d->m_listAccessor)
533 return data->engine->fromVariant(static_cast<QQuickVDMListAccessorData *>(data)->cachedData);
535 return data->engine->fromVariant(d->m_listAccessor->at(data->index[0]));
538 static void set_modelData(v8::Local<v8::String>, const v8::Handle<v8::Value> &value, const v8::AccessorInfo &info)
540 QQuickVisualDataModelItem *data = v8_resource_cast<QQuickVisualDataModelItem>(info.This());
542 V8THROW_ERROR_SETTER("Not a valid VisualData object");
544 if (data->index[0] == -1) {
545 static_cast<QQuickVDMListAccessorData *>(data)->setModelData(
546 data->engine->toVariant(value, QVariant::Invalid));
550 void setValue(const QString &role, const QVariant &value)
552 if (role == QLatin1String("modelData"))
556 bool resolveIndex(int idx)
558 if (index[0] == -1) {
561 emit modelIndexChanged();
562 emit modelDataChanged();
570 void modelDataChanged();
573 QQuickVDMListAccessorData(QQuickVisualDataModelItemMetaType *metaType, QQuickVisualAdaptorModel *model, int index)
574 : QQuickVisualDataModelItem(metaType, model, index)
581 class QQuickVDMObjectDataMetaObject : public QQuickVisualDataModelItemMetaObject
584 QQuickVDMObjectDataMetaObject(QQuickVisualDataModelItem *data, VDMDelegateDataType *type)
585 : QQuickVisualDataModelItemMetaObject(data, type)
586 , m_object(QQuickVisualAdaptorModelPrivate::get(data->model)->m_listAccessor->at(data->index[0]).value<QObject *>())
589 int metaCall(QMetaObject::Call call, int id, void **arguments)
591 static const int objectPropertyOffset = QObject::staticMetaObject.propertyCount();
592 if (id >= m_type->propertyOffset
593 && (call == QMetaObject::ReadProperty
594 || call == QMetaObject::WriteProperty
595 || call == QMetaObject::ResetProperty)) {
597 QMetaObject::metacall(m_object, call, id - m_type->propertyOffset + objectPropertyOffset, arguments);
599 } else if (id >= m_type->signalOffset && call == QMetaObject::InvokeMetaMethod) {
600 QMetaObject::activate(m_data, this, id, 0);
603 return m_data->qt_metacall(call, id, arguments);
607 int createProperty(const char *name, const char *)
611 const QMetaObject *metaObject = m_object->metaObject();
612 static const int objectPropertyOffset = QObject::staticMetaObject.propertyCount();
614 const int previousPropertyCount = propertyCount() - propertyOffset();
615 int propertyIndex = metaObject->indexOfProperty(name);
616 if (propertyIndex == -1)
618 if (previousPropertyCount + objectPropertyOffset == metaObject->propertyCount())
619 return propertyIndex + m_type->propertyOffset - objectPropertyOffset;
621 if (m_type->shared) {
622 VDMDelegateDataType *type = m_type;
623 m_type = new VDMDelegateDataType(*m_type);
627 const int previousMethodCount = methodCount();
628 int notifierId = previousMethodCount;
629 for (int propertyId = previousPropertyCount; propertyId < metaObject->propertyCount() - objectPropertyOffset; ++propertyId) {
630 QMetaProperty property = metaObject->property(propertyId + objectPropertyOffset);
631 QMetaPropertyBuilder propertyBuilder;
632 if (property.hasNotifySignal()) {
633 m_type->builder.addSignal("__" + QByteArray::number(propertyId) + "()");
634 propertyBuilder = m_type->builder.addProperty(property.name(), property.typeName(), notifierId);
637 propertyBuilder = m_type->builder.addProperty(property.name(), property.typeName());
639 propertyBuilder.setWritable(property.isWritable());
640 propertyBuilder.setResettable(property.isResettable());
641 propertyBuilder.setConstant(property.isConstant());
644 if (m_type->metaObject)
645 qFree(m_type->metaObject);
646 m_type->metaObject = m_type->builder.toMetaObject();
647 *static_cast<QMetaObject *>(this) = *m_type->metaObject;
649 notifierId = previousMethodCount;
650 for (int i = previousPropertyCount; i < metaObject->propertyCount() - objectPropertyOffset; ++i) {
651 QMetaProperty property = metaObject->property(i + objectPropertyOffset);
652 if (property.hasNotifySignal()) {
653 QDeclarativePropertyPrivate::connect(
654 m_object, property.notifySignalIndex(), m_data, notifierId);
658 return propertyIndex + m_type->propertyOffset - objectPropertyOffset;
661 QDeclarativeGuard<QObject> m_object;
664 class QQuickVDMObjectData : public QQuickVisualDataModelItem, public QQuickVisualAdaptorModelProxyInterface
667 Q_PROPERTY(QObject *modelData READ modelData CONSTANT)
668 Q_INTERFACES(QQuickVisualAdaptorModelProxyInterface)
670 QObject *modelData() const { return m_metaObject->m_object; }
671 QObject *proxiedObject() { return m_metaObject->m_object; }
673 static QQuickVisualDataModelItem *create(
674 QQuickVisualDataModelItemMetaType *metaType, QQuickVisualAdaptorModel *model, int index) {
675 return index >= 0 ? new QQuickVDMObjectData(metaType, model, index) : 0; }
677 static QString stringValue(QQuickVisualAdaptorModelPrivate *model, int index, const QString &name)
679 if (QObject *object = model->m_listAccessor->at(index).value<QObject *>())
680 return object->property(name.toUtf8()).toString();
685 QQuickVDMObjectData(QQuickVisualDataModelItemMetaType *metaType, QQuickVisualAdaptorModel *model, int index)
686 : QQuickVisualDataModelItem(metaType, model, index)
687 , m_metaObject(new QQuickVDMObjectDataMetaObject(this, QQuickVisualAdaptorModelPrivate::get(model)->m_delegateDataType))
691 QQuickVDMObjectDataMetaObject *m_metaObject;
694 void QQuickVisualAdaptorModelPrivate::addProperty(
695 int role, int propertyId, const char *propertyName, const char *propertyType, bool isModelData)
697 PropertyData propertyData;
698 propertyData.role = role;
699 propertyData.isModelData = isModelData;
700 m_delegateDataType->builder.addSignal("__" + QByteArray::number(propertyId) + "()");
701 QMetaPropertyBuilder property = m_delegateDataType->builder.addProperty(
702 propertyName, propertyType, propertyId);
703 property.setWritable(true); // No, yes, yes no?
705 m_propertyData.append(propertyData);
708 void QQuickVisualAdaptorModelPrivate::createMetaObject()
710 Q_ASSERT(!m_delegateDataType);
712 m_objectList = false;
713 m_propertyData.clear();
715 QV8Engine *v8Engine = QDeclarativeEnginePrivate::getV8Engine(m_engine);
717 v8::HandleScope handleScope;
718 v8::Context::Scope contextScope(v8Engine->context());
719 v8::Local<v8::FunctionTemplate> ft = v8::FunctionTemplate::New();
720 ft->InstanceTemplate()->SetHasExternalResource(true);
721 ft->PrototypeTemplate()->SetAccessor(
722 v8::String::New("index"), QQuickVisualDataModelItemMetaObject::get_index);
725 && m_listAccessor->type() != QDeclarativeListAccessor::ListProperty
726 && m_listAccessor->type() != QDeclarativeListAccessor::Instance) {
727 createItem = &QQuickVDMListAccessorData::create;
728 stringValue = &QQuickVDMListAccessorData::stringValue;
729 ft->PrototypeTemplate()->SetAccessor(
730 v8::String::New("modelData"), QQuickVDMListAccessorData::get_modelData);
731 m_constructor = qPersistentNew<v8::Function>(ft->GetFunction());
735 m_delegateDataType = new VDMDelegateDataType;
736 if (m_listModelInterface) {
737 setModelDataType<QQuickVDMListModelInterfaceData>();
738 QList<int> roles = m_listModelInterface->roles();
739 for (int propertyId = 0; propertyId < roles.count(); ++propertyId) {
740 const int role = roles.at(propertyId);
741 const QString roleName = m_listModelInterface->toString(role);
742 const QByteArray propertyName = roleName.toUtf8();
743 addProperty(role, propertyId, propertyName, "QVariant");
744 ft->PrototypeTemplate()->SetAccessor(
745 v8Engine->toString(roleName),
746 QQuickVDMListModelInterfaceData::get_property,
747 QQuickVDMListModelInterfaceData::set_property,
748 v8::Int32::New(propertyId));
749 m_roleNames.insert(propertyName, role);
751 m_roleCount = m_propertyData.count();
752 if (m_propertyData.count() == 1) {
753 addProperty(roles.first(), 1, "modelData", "QVariant", true);
754 ft->PrototypeTemplate()->SetAccessor(
755 v8::String::New("modelData"),
756 QQuickVDMListModelInterfaceData::get_property,
757 QQuickVDMListModelInterfaceData::set_property,
759 m_roleNames.insert("modelData", roles.first());
761 } else if (m_abstractItemModel) {
762 setModelDataType<QQuickVDMAbstractItemModelData>();
763 QHash<int, QByteArray> roleNames = m_abstractItemModel->roleNames();
764 for (QHash<int, QByteArray>::const_iterator it = roleNames.begin(); it != roleNames.end(); ++it) {
765 const int propertyId = m_propertyData.count();
766 addProperty(it.key(), propertyId, it.value(), "QVariant");
767 ft->PrototypeTemplate()->SetAccessor(
768 v8::String::New(it.value().constData(), it.value().length()),
769 QQuickVDMAbstractItemModelData::get_property,
770 QQuickVDMAbstractItemModelData::set_property,
771 v8::Int32::New(propertyId));
772 m_roleNames.insert(it.value(), it.key());
774 m_roleCount = m_propertyData.count();
775 if (m_propertyData.count() == 1) {
776 addProperty(roleNames.begin().key(), 1, "modelData", "QVariant", true);
777 ft->PrototypeTemplate()->SetAccessor(
778 v8::String::New("modelData"),
779 QQuickVDMAbstractItemModelData::get_property,
780 QQuickVDMAbstractItemModelData::set_property,
782 m_roleNames.insert("modelData", roleNames.begin().key());
784 ft->PrototypeTemplate()->SetAccessor(
785 v8::String::New("hasModelChildren"),
786 QQuickVDMAbstractItemModelData::get_hasModelChildren);
787 } else if (m_listAccessor) {
788 setModelDataType<QQuickVDMObjectData>();
790 m_flags = QQuickVisualAdaptorModel::ProxiedObject;
792 Q_ASSERT(!"No model set on VisualDataModel");
795 m_delegateDataType->metaObject = m_delegateDataType->builder.toMetaObject();
797 m_delegateDataType->propertyCache = new QDeclarativePropertyCache(
798 m_engine, m_delegateDataType->metaObject);
799 m_constructor = qPersistentNew<v8::Function>(ft->GetFunction());
803 //---------------------------------------------------------------------------
805 QQuickVisualAdaptorModel::QQuickVisualAdaptorModel(QObject *parent)
806 : QObject(*(new QQuickVisualAdaptorModelPrivate), parent)
810 QQuickVisualAdaptorModel::~QQuickVisualAdaptorModel()
812 Q_D(QQuickVisualAdaptorModel);
813 if (d->m_listAccessor)
814 delete d->m_listAccessor;
815 if (d->m_delegateDataType)
816 d->m_delegateDataType->release();
819 QQuickVisualAdaptorModel::Flags QQuickVisualAdaptorModel::flags() const
821 Q_D(const QQuickVisualAdaptorModel);
825 QVariant QQuickVisualAdaptorModel::model() const
827 Q_D(const QQuickVisualAdaptorModel);
828 return d->m_modelVariant;
831 void QQuickVisualAdaptorModel::setModel(const QVariant &model, QDeclarativeEngine *engine)
833 Q_D(QQuickVisualAdaptorModel);
834 delete d->m_listAccessor;
835 d->m_engine = engine;
836 d->m_listAccessor = 0;
837 d->m_modelVariant = model;
838 if (d->m_listModelInterface) {
839 // Assume caller has released all items.
840 QObject::disconnect(d->m_listModelInterface, SIGNAL(itemsChanged(int,int,QList<int>)),
841 this, SLOT(_q_itemsChanged(int,int,QList<int>)));
842 QObject::disconnect(d->m_listModelInterface, SIGNAL(itemsInserted(int,int)),
843 this, SLOT(_q_itemsInserted(int,int)));
844 QObject::disconnect(d->m_listModelInterface, SIGNAL(itemsRemoved(int,int)),
845 this, SLOT(_q_itemsRemoved(int,int)));
846 QObject::disconnect(d->m_listModelInterface, SIGNAL(itemsMoved(int,int,int)),
847 this, SLOT(_q_itemsMoved(int,int,int)));
848 d->m_listModelInterface = 0;
849 } else if (d->m_abstractItemModel) {
850 QObject::disconnect(d->m_abstractItemModel, SIGNAL(rowsInserted(QModelIndex,int,int)),
851 this, SLOT(_q_rowsInserted(QModelIndex,int,int)));
852 QObject::disconnect(d->m_abstractItemModel, SIGNAL(rowsRemoved(QModelIndex,int,int)),
853 this, SLOT(_q_rowsRemoved(QModelIndex,int,int)));
854 QObject::disconnect(d->m_abstractItemModel, SIGNAL(dataChanged(QModelIndex,QModelIndex)),
855 this, SLOT(_q_dataChanged(QModelIndex,QModelIndex)));
856 QObject::disconnect(d->m_abstractItemModel, SIGNAL(rowsMoved(QModelIndex,int,int,QModelIndex,int)),
857 this, SLOT(_q_rowsMoved(QModelIndex,int,int,QModelIndex,int)));
858 QObject::disconnect(d->m_abstractItemModel, SIGNAL(modelReset()), this, SLOT(_q_modelReset()));
859 QObject::disconnect(d->m_abstractItemModel, SIGNAL(layoutChanged()), this, SLOT(_q_layoutChanged()));
860 d->m_abstractItemModel = 0;
864 d->m_roleNames.clear();
866 d->m_flags = QQuickVisualAdaptorModel::Flags();
867 if (d->m_delegateDataType)
868 d->m_delegateDataType->release();
869 d->m_delegateDataType = 0;
870 d->createItem = &QQuickVisualAdaptorModelPrivate::initializeModelData;
871 d->stringValue = &QQuickVisualAdaptorModelPrivate::initializeStringValue;
872 qPersistentDispose(d->m_constructor);
875 emit itemsRemoved(0, d->m_count);
877 QObject *object = qvariant_cast<QObject *>(model);
878 if (object && (d->m_listModelInterface = qobject_cast<QListModelInterface *>(object))) {
879 QObject::connect(d->m_listModelInterface, SIGNAL(itemsChanged(int,int,QList<int>)),
880 this, SLOT(_q_itemsChanged(int,int,QList<int>)));
881 QObject::connect(d->m_listModelInterface, SIGNAL(itemsInserted(int,int)),
882 this, SLOT(_q_itemsInserted(int,int)));
883 QObject::connect(d->m_listModelInterface, SIGNAL(itemsRemoved(int,int)),
884 this, SLOT(_q_itemsRemoved(int,int)));
885 QObject::connect(d->m_listModelInterface, SIGNAL(itemsMoved(int,int,int)),
886 this, SLOT(_q_itemsMoved(int,int,int)));
887 if ((d->m_count = d->m_listModelInterface->count()))
888 emit itemsInserted(0, d->m_count);
890 } else if (object && (d->m_abstractItemModel = qobject_cast<QAbstractItemModel *>(object))) {
891 QObject::connect(d->m_abstractItemModel, SIGNAL(rowsInserted(QModelIndex,int,int)),
892 this, SLOT(_q_rowsInserted(QModelIndex,int,int)));
893 QObject::connect(d->m_abstractItemModel, SIGNAL(rowsRemoved(QModelIndex,int,int)),
894 this, SLOT(_q_rowsRemoved(QModelIndex,int,int)));
895 QObject::connect(d->m_abstractItemModel, SIGNAL(dataChanged(QModelIndex,QModelIndex)),
896 this, SLOT(_q_dataChanged(QModelIndex,QModelIndex)));
897 QObject::connect(d->m_abstractItemModel, SIGNAL(rowsMoved(QModelIndex,int,int,QModelIndex,int)),
898 this, SLOT(_q_rowsMoved(QModelIndex,int,int,QModelIndex,int)));
899 QObject::connect(d->m_abstractItemModel, SIGNAL(modelReset()), this, SLOT(_q_modelReset()));
900 QObject::connect(d->m_abstractItemModel, SIGNAL(layoutChanged()), this, SLOT(_q_layoutChanged()));
902 if ((d->m_count = d->m_abstractItemModel->rowCount(d->m_root)))
903 emit itemsInserted(0, d->m_count);
907 d->m_listAccessor = new QDeclarativeListAccessor;
908 d->m_listAccessor->setList(model, d->m_engine);
909 if ((d->m_count = d->m_listAccessor->count()))
910 emit itemsInserted(0, d->m_count);
913 QVariant QQuickVisualAdaptorModel::rootIndex() const
915 Q_D(const QQuickVisualAdaptorModel);
916 return QVariant::fromValue(d->m_root);
919 void QQuickVisualAdaptorModel::setRootIndex(const QVariant &root)
921 Q_D(QQuickVisualAdaptorModel);
922 QModelIndex modelIndex = qvariant_cast<QModelIndex>(root);
923 if (d->m_root != modelIndex) {
924 int oldCount = d->modelCount();
925 d->m_root = modelIndex;
926 if (d->m_abstractItemModel && d->m_abstractItemModel->canFetchMore(modelIndex))
927 d->m_abstractItemModel->fetchMore(modelIndex);
928 int newCount = d->modelCount();
930 emit itemsRemoved(0, oldCount);
932 emit itemsInserted(0, newCount);
933 emit rootIndexChanged();
937 QVariant QQuickVisualAdaptorModel::modelIndex(int idx) const
939 Q_D(const QQuickVisualAdaptorModel);
940 if (d->m_abstractItemModel)
941 return QVariant::fromValue(d->m_abstractItemModel->index(idx, 0, d->m_root));
942 return QVariant::fromValue(QModelIndex());
945 QVariant QQuickVisualAdaptorModel::parentModelIndex() const
947 Q_D(const QQuickVisualAdaptorModel);
948 if (d->m_abstractItemModel)
949 return QVariant::fromValue(d->m_abstractItemModel->parent(d->m_root));
950 return QVariant::fromValue(QModelIndex());
953 int QQuickVisualAdaptorModel::count() const
955 Q_D(const QQuickVisualAdaptorModel);
956 return d->modelCount();
959 QQuickVisualDataModelItem *QQuickVisualAdaptorModel::createItem(QQuickVisualDataModelItemMetaType *metaType, int index)
961 Q_D(QQuickVisualAdaptorModel);
963 if (QQuickVisualDataModelItem *item = d->createItem(metaType, this, index)) {
964 d->m_cache.insert(item);
966 if (d->m_delegateDataType && d->m_delegateDataType->propertyCache) {
967 QDeclarativeData *qmldata = QDeclarativeData::get(item, true);
968 qmldata->propertyCache = d->m_delegateDataType->propertyCache;
969 qmldata->propertyCache->addref();
976 QString QQuickVisualAdaptorModel::stringValue(int index, const QString &name)
978 Q_D(QQuickVisualAdaptorModel);
979 return d->stringValue(d, index, name);
982 bool QQuickVisualAdaptorModel::canFetchMore() const
984 Q_D(const QQuickVisualAdaptorModel);
985 return d->m_abstractItemModel && d->m_abstractItemModel->canFetchMore(d->m_root);
988 void QQuickVisualAdaptorModel::fetchMore()
990 Q_D(QQuickVisualAdaptorModel);
991 if (d->m_abstractItemModel)
992 d->m_abstractItemModel->fetchMore(d->m_root);
995 void QQuickVisualAdaptorModel::replaceWatchedRoles(const QList<QByteArray> &oldRoles, const QList<QByteArray> &newRoles)
997 Q_D(QQuickVisualAdaptorModel);
998 d->watchedRoleIds.clear();
999 foreach (const QByteArray &oldRole, oldRoles)
1000 d->watchedRoles.removeOne(oldRole);
1001 d->watchedRoles += newRoles;
1004 void QQuickVisualAdaptorModel::_q_itemsChanged(int index, int count, const QList<int> &roles)
1006 Q_D(QQuickVisualAdaptorModel);
1007 bool changed = roles.isEmpty();
1008 if (!d->watchedRoles.isEmpty() && d->watchedRoleIds.isEmpty()) {
1009 foreach (QByteArray r, d->watchedRoles) {
1010 if (d->m_roleNames.contains(r))
1011 d->watchedRoleIds << d->m_roleNames.value(r);
1015 QVector<int> signalIndexes;
1016 for (int i = 0; i < roles.count(); ++i) {
1017 const int role = roles.at(i);
1018 if (!changed && d->watchedRoleIds.contains(role))
1020 for (int propertyId = 0; propertyId < d->m_propertyData.count(); ++propertyId) {
1021 if (d->m_propertyData.at(propertyId).role == role)
1022 signalIndexes.append(propertyId + d->m_delegateDataType->signalOffset);
1025 if (roles.isEmpty()) {
1026 for (int propertyId = 0; propertyId < d->m_propertyData.count(); ++propertyId)
1027 signalIndexes.append(propertyId + d->m_delegateDataType->signalOffset);
1030 typedef QQuickVisualDataModelItemCache::iterator iterator;
1031 for (iterator it = d->m_cache.begin(); it != d->m_cache.end(); ++it) {
1032 const int idx = it->modelIndex();
1033 if (idx >= index && idx < index + count) {
1034 QQuickVisualDataModelItem *data = *it;
1035 for (int i = 0; i < signalIndexes.count(); ++i)
1036 QMetaObject::activate(data, signalIndexes.at(i), 0);
1040 emit itemsChanged(index, count);
1043 void QQuickVisualAdaptorModel::_q_itemsInserted(int index, int count)
1045 Q_D(QQuickVisualAdaptorModel);
1048 d->m_count += count;
1050 typedef QQuickVisualDataModelItemCache::iterator iterator;
1051 for (iterator it = d->m_cache.begin(); it != d->m_cache.end(); ++it) {
1052 if (it->modelIndex() >= index)
1053 it->setModelIndex(it->modelIndex() + count);
1056 emit itemsInserted(index, count);
1059 void QQuickVisualAdaptorModel::_q_itemsRemoved(int index, int count)
1061 Q_D(QQuickVisualAdaptorModel);
1064 d->m_count -= count;
1066 typedef QQuickVisualDataModelItemCache::iterator iterator;
1067 for (iterator it = d->m_cache.begin(); it != d->m_cache.end(); ++it) {
1068 if (it->modelIndex() >= index + count)
1069 it->setModelIndex(it->modelIndex() - count);
1070 else if (it->modelIndex() >= index)
1071 it->setModelIndex(-1);
1074 emit itemsRemoved(index, count);
1077 void QQuickVisualAdaptorModel::_q_itemsMoved(int from, int to, int count)
1079 Q_D(QQuickVisualAdaptorModel);
1080 const int minimum = qMin(from, to);
1081 const int maximum = qMax(from, to) + count;
1082 const int difference = from > to ? count : -count;
1084 typedef QQuickVisualDataModelItemCache::iterator iterator;
1085 for (iterator it = d->m_cache.begin(); it != d->m_cache.end(); ++it) {
1086 if (it->modelIndex() >= from && it->modelIndex() < from + count)
1087 it->setModelIndex(it->modelIndex() - from + to);
1088 else if (it->modelIndex() >= minimum && it->modelIndex() < maximum)
1089 it->setModelIndex(it->modelIndex() + difference);
1091 emit itemsMoved(from, to, count);
1094 void QQuickVisualAdaptorModel::_q_rowsInserted(const QModelIndex &parent, int begin, int end)
1096 Q_D(QQuickVisualAdaptorModel);
1097 if (parent == d->m_root)
1098 _q_itemsInserted(begin, end - begin + 1);
1101 void QQuickVisualAdaptorModel::_q_rowsRemoved(const QModelIndex &parent, int begin, int end)
1103 Q_D(QQuickVisualAdaptorModel);
1104 if (parent == d->m_root)
1105 _q_itemsRemoved(begin, end - begin + 1);
1108 void QQuickVisualAdaptorModel::_q_rowsMoved(const QModelIndex &sourceParent, int sourceStart, int sourceEnd, const QModelIndex &destinationParent, int destinationRow)
1110 Q_D(QQuickVisualAdaptorModel);
1111 const int count = sourceEnd - sourceStart + 1;
1112 if (destinationParent == d->m_root && sourceParent == d->m_root) {
1113 _q_itemsMoved(sourceStart, sourceStart > destinationRow ? destinationRow : destinationRow-count, count);
1114 } else if (sourceParent == d->m_root) {
1115 _q_itemsRemoved(sourceStart, count);
1116 } else if (destinationParent == d->m_root) {
1117 _q_itemsInserted(destinationRow, count);
1121 void QQuickVisualAdaptorModel::_q_dataChanged(const QModelIndex &begin, const QModelIndex &end)
1123 Q_D(QQuickVisualAdaptorModel);
1124 if (begin.parent() == d->m_root)
1125 _q_itemsChanged(begin.row(), end.row() - begin.row() + 1, d->m_roles);
1128 void QQuickVisualAdaptorModel::_q_layoutChanged()
1130 Q_D(QQuickVisualAdaptorModel);
1131 _q_itemsChanged(0, count(), d->m_roles);
1134 void QQuickVisualAdaptorModel::_q_modelReset()
1136 Q_D(QQuickVisualAdaptorModel);
1137 int oldCount = d->m_count;
1138 d->m_root = QModelIndex();
1139 d->m_count = d->modelCount();
1140 emit modelReset(oldCount, d->m_count);
1141 emit rootIndexChanged();
1142 if (d->m_abstractItemModel && d->m_abstractItemModel->canFetchMore(d->m_root))
1143 d->m_abstractItemModel->fetchMore(d->m_root);
1148 QML_DECLARE_TYPE(QListModelInterface)
1150 #include <qquickvisualadaptormodel.moc>