From 2a812493bc97983b85110f853d3dbe57b54667d8 Mon Sep 17 00:00:00 2001 From: Glenn Watson Date: Fri, 11 Nov 2011 10:47:33 +1000 Subject: Support JS objects in ListModel via QVariantMap Added support for the new listmodel implementation to store and retrieve JS objects via QVariantMap. Storing JS objects in a listmodel is significantly slower than storing native datatypes at the moment (this may be improved in the future). Also note that it's not currently possible to bind to fields within the JS object. Change-Id: I3b1a11ace7cdec754c1a2bb2b2d1b7edf561864d Reviewed-by: Martin Jones --- src/declarative/util/qdeclarativelistmodel.cpp | 142 +++++++++++++++++++++---- 1 file changed, 121 insertions(+), 21 deletions(-) (limited to 'src/declarative/util/qdeclarativelistmodel.cpp') diff --git a/src/declarative/util/qdeclarativelistmodel.cpp b/src/declarative/util/qdeclarativelistmodel.cpp index 2cc52fb949..dceb0045e3 100644 --- a/src/declarative/util/qdeclarativelistmodel.cpp +++ b/src/declarative/util/qdeclarativelistmodel.cpp @@ -64,6 +64,17 @@ enum { MIN_LISTMODEL_UID = 1024 }; QAtomicInt ListModel::uidCounter(MIN_LISTMODEL_UID); +template +static bool isMemoryUsed(const char *mem) +{ + for (size_t i=0 ; i < sizeof(T) ; ++i) { + if (mem[i] != 0) + return true; + } + + return false; +} + static QString roleTypeName(ListLayout::Role::DataType t) { QString result; @@ -108,8 +119,8 @@ const ListLayout::Role &ListLayout::getRoleOrCreate(v8::Handle key, const ListLayout::Role &ListLayout::createRole(const QString &key, ListLayout::Role::DataType type) { - const int dataSizes[] = { sizeof(QString), sizeof(double), sizeof(bool), sizeof(ListModel *), sizeof(QDeclarativeGuard) }; - const int dataAlignments[] = { sizeof(QString), sizeof(double), sizeof(bool), sizeof(ListModel *), sizeof(QObject *) }; + const int dataSizes[] = { sizeof(QString), sizeof(double), sizeof(bool), sizeof(ListModel *), sizeof(QDeclarativeGuard), sizeof(QVariantMap) }; + const int dataAlignments[] = { sizeof(QString), sizeof(double), sizeof(bool), sizeof(ListModel *), sizeof(QObject *), sizeof(QVariantMap) }; Role *r = new Role; r->name = key; @@ -401,7 +412,7 @@ ListModel *ListModel::getListProperty(int elementIndex, const ListLayout::Role & return e->getListProperty(role); } -void ListModel::set(int elementIndex, v8::Handle object, QList *roles) +void ListModel::set(int elementIndex, v8::Handle object, QList *roles, QV8Engine *eng) { ListElement *e = elements[elementIndex]; @@ -434,7 +445,7 @@ void ListModel::set(int elementIndex, v8::Handle object, QList int arrayLength = subArray->Length(); for (int j=0 ; j < arrayLength ; ++j) { v8::Handle subObject = subArray->Get(j)->ToObject(); - subModel->append(subObject); + subModel->append(subObject, eng); } roleIndex = e->setListProperty(r, subModel); @@ -448,6 +459,10 @@ void ListModel::set(int elementIndex, v8::Handle object, QList const ListLayout::Role &role = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::QObject); if (role.type == ListLayout::Role::QObject) e->setQObjectProperty(role, o); + } else { + const ListLayout::Role &role = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::VariantMap); + if (role.type == ListLayout::Role::VariantMap) + e->setVariantMapProperty(role, propertyValue->ToObject(), eng); } } else if (propertyValue.IsEmpty() || propertyValue->IsUndefined() || propertyValue->IsNull()) { const ListLayout::Role *r = m_layout->getExistingRole(propertyName); @@ -464,7 +479,7 @@ void ListModel::set(int elementIndex, v8::Handle object, QList } } -void ListModel::set(int elementIndex, v8::Handle object) +void ListModel::set(int elementIndex, v8::Handle object, QV8Engine *eng) { ListElement *e = elements[elementIndex]; @@ -499,7 +514,7 @@ void ListModel::set(int elementIndex, v8::Handle object) int arrayLength = subArray->Length(); for (int j=0 ; j < arrayLength ; ++j) { v8::Handle subObject = subArray->Get(j)->ToObject(); - subModel->append(subObject); + subModel->append(subObject, eng); } e->setListPropertyFast(r, subModel); @@ -516,6 +531,10 @@ void ListModel::set(int elementIndex, v8::Handle object) const ListLayout::Role &r = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::QObject); if (r.type == ListLayout::Role::QObject) e->setQObjectPropertyFast(r, o); + } else { + const ListLayout::Role &role = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::VariantMap); + if (role.type == ListLayout::Role::VariantMap) + e->setVariantMapFast(role, propertyValue->ToObject(), eng); } } else if (propertyValue.IsEmpty() || propertyValue->IsUndefined() || propertyValue->IsNull()) { const ListLayout::Role *r = m_layout->getExistingRole(propertyName); @@ -543,16 +562,16 @@ void ListModel::remove(int index) updateCacheIndices(); } -void ListModel::insert(int elementIndex, v8::Handle object) +void ListModel::insert(int elementIndex, v8::Handle object, QV8Engine *eng) { insertElement(elementIndex); - set(elementIndex, object); + set(elementIndex, object, eng); } -int ListModel::append(v8::Handle object) +int ListModel::append(v8::Handle object, QV8Engine *eng) { int elementIndex = appendElement(); - set(elementIndex, object); + set(elementIndex, object, eng); return elementIndex; } @@ -577,7 +596,7 @@ int ListModel::setOrCreateProperty(int elementIndex, const QString &key, const Q return roleIndex; } -int ListModel::setExistingProperty(int elementIndex, const QString &key, v8::Handle data) +int ListModel::setExistingProperty(int elementIndex, const QString &key, v8::Handle data, QV8Engine *eng) { int roleIndex = -1; @@ -585,7 +604,7 @@ int ListModel::setExistingProperty(int elementIndex, const QString &key, v8::Han ListElement *e = elements[elementIndex]; const ListLayout::Role *r = m_layout->getExistingRole(key); if (r) - roleIndex = e->setJsProperty(*r, data); + roleIndex = e->setJsProperty(*r, data, eng); } return roleIndex; @@ -622,6 +641,17 @@ QObject *ListElement::getQObjectProperty(const ListLayout::Role &role) return o->data(); } +QVariantMap *ListElement::getVariantMapProperty(const ListLayout::Role &role) +{ + QVariantMap *map = 0; + + char *mem = getPropertyMemory(role); + if (isMemoryUsed(mem)) + map = reinterpret_cast(mem); + + return map; +} + QDeclarativeGuard *ListElement::getGuardProperty(const ListLayout::Role &role) { char *mem = getPropertyMemory(role); @@ -699,6 +729,14 @@ QVariant ListElement::getProperty(const ListLayout::Role &role, const QDeclarati data = QVariant::fromValue(object); } break; + case ListLayout::Role::VariantMap: + { + if (isMemoryUsed(mem)) { + QVariantMap *map = reinterpret_cast(mem); + data = *map; + } + } + break; default: break; } @@ -807,6 +845,43 @@ int ListElement::setQObjectProperty(const ListLayout::Role &role, QObject *o) return roleIndex; } +int ListElement::setVariantMapProperty(const ListLayout::Role &role, v8::Handle o, QV8Engine *eng) +{ + int roleIndex = -1; + + if (role.type == ListLayout::Role::VariantMap) { + char *mem = getPropertyMemory(role); + if (isMemoryUsed(mem)) { + QVariantMap *map = reinterpret_cast(mem); + map->~QMap(); + } + new (mem) QVariantMap(eng->variantMapFromJS(o)); + roleIndex = role.index; + } + + return roleIndex; +} + +int ListElement::setVariantMapProperty(const ListLayout::Role &role, QVariantMap *m) +{ + int roleIndex = -1; + + if (role.type == ListLayout::Role::VariantMap) { + char *mem = getPropertyMemory(role); + if (isMemoryUsed(mem)) { + QVariantMap *map = reinterpret_cast(mem); + map->~QMap(); + } + if (m) + new (mem) QVariantMap(*m); + else + new (mem) QVariantMap; + roleIndex = role.index; + } + + return roleIndex; +} + void ListElement::setStringPropertyFast(const ListLayout::Role &role, const QString &s) { char *mem = getPropertyMemory(role); @@ -840,6 +915,13 @@ void ListElement::setListPropertyFast(const ListLayout::Role &role, ListModel *m *value = m; } +void ListElement::setVariantMapFast(const ListLayout::Role &role, v8::Handle o, QV8Engine *eng) +{ + char *mem = getPropertyMemory(role); + QVariantMap *map = new (mem) QVariantMap; + *map = eng->variantMapFromJS(o); +} + void ListElement::clearProperty(const ListLayout::Role &role) { switch (role.type) { @@ -858,6 +940,9 @@ void ListElement::clearProperty(const ListLayout::Role &role) case ListLayout::Role::QObject: setQObjectProperty(role, 0); break; + case ListLayout::Role::VariantMap: + setVariantMapProperty(role, 0); + break; default: break; } @@ -918,6 +1003,12 @@ void ListElement::sync(ListElement *src, ListLayout *srcLayout, ListElement *tar QVariant v = src->getProperty(srcRole, 0, 0); target->setVariantProperty(targetRole, v); } + case ListLayout::Role::VariantMap: + { + QVariantMap *map = src->getVariantMapProperty(srcRole); + target->setVariantMapProperty(targetRole, map); + } + break; default: break; } @@ -955,6 +1046,13 @@ void ListElement::destroy(ListLayout *layout) guard->~QDeclarativeGuard(); } break; + case ListLayout::Role::VariantMap: + { + QVariantMap *map = getVariantMapProperty(r); + if (map) + map->~QMap(); + } + break; default: // other types don't need explicit cleanup. break; @@ -993,7 +1091,7 @@ int ListElement::setVariantProperty(const ListLayout::Role &role, const QVariant return roleIndex; } -int ListElement::setJsProperty(const ListLayout::Role &role, v8::Handle d) +int ListElement::setJsProperty(const ListLayout::Role &role, v8::Handle d, QV8Engine *eng) { // Check if this key exists yet int roleIndex = -1; @@ -1013,7 +1111,7 @@ int ListElement::setJsProperty(const ListLayout::Role &role, v8::HandleLength(); for (int j=0 ; j < arrayLength ; ++j) { v8::Handle subObject = subArray->Get(j)->ToObject(); - subModel->append(subObject); + subModel->append(subObject, eng); } roleIndex = setListProperty(role, subModel); } else if (d->IsBoolean()) { @@ -1023,6 +1121,8 @@ int ListElement::setJsProperty(const ListLayout::Role &role, v8::HandleresourceType() == QV8ObjectResource::QObjectType) { QObject *o = QV8QObjectWrapper::toQObject(r); roleIndex = setQObjectProperty(role, o); + } else if (role.type == ListLayout::Role::VariantMap) { + roleIndex = setVariantMapProperty(role, d->ToObject(), eng); } } else if (d.IsEmpty() || d->IsUndefined() || d->IsNull()) { clearProperty(role); @@ -1085,7 +1185,7 @@ void ModelNodeMetaObject::propertyWritten(int index) v8::Handle v = eng->fromVariant(value); - int roleIndex = m_obj->m_model->m_listModel->setExistingProperty(m_obj->m_elementIndex, propName, v); + int roleIndex = m_obj->m_model->m_listModel->setExistingProperty(m_obj->m_elementIndex, propName, v, eng); if (roleIndex != -1) { QList roles; roles << roleIndex; @@ -1408,13 +1508,13 @@ void QDeclarativeListModel::insert(QDeclarativeV8Function *args) int objectArrayLength = objectArray->Length(); for (int i=0 ; i < objectArrayLength ; ++i) { v8::Handle argObject = objectArray->Get(i)->ToObject(); - m_listModel->insert(index+i, argObject); + m_listModel->insert(index+i, argObject, args->engine()); } emitItemsInserted(index, objectArrayLength); } else if (arg1->IsObject()) { v8::Handle argObject = arg1->ToObject(); - m_listModel->insert(index, argObject); + m_listModel->insert(index, argObject, args->engine()); emitItemsInserted(index, 1); } else { qmlInfo(this) << tr("insert: value is not an object"); @@ -1474,13 +1574,13 @@ void QDeclarativeListModel::append(QDeclarativeV8Function *args) int index = m_listModel->elementCount(); for (int i=0 ; i < objectArrayLength ; ++i) { v8::Handle argObject = objectArray->Get(i)->ToObject(); - m_listModel->append(argObject); + m_listModel->append(argObject, args->engine()); } emitItemsInserted(index, objectArrayLength); } else if (arg->IsObject()) { v8::Handle argObject = arg->ToObject(); - int index = m_listModel->append(argObject); + int index = m_listModel->append(argObject, args->engine()); emitItemsInserted(index, 1); } else { @@ -1568,12 +1668,12 @@ void QDeclarativeListModel::set(int index, const QDeclarativeV8Handle &handle) v8::Handle object = valuemap->ToObject(); if (index == count()) { - m_listModel->insert(index, object); + m_listModel->insert(index, object, engine()); emitItemsInserted(index, 1); } else { QList roles; - m_listModel->set(index, object, &roles); + m_listModel->set(index, object, &roles, engine()); if (roles.count()) emitItemsChanged(index, 1, roles); -- cgit v1.2.3