From dcc810fd6ae3042fb2877d617e21818b81b33ead Mon Sep 17 00:00:00 2001 From: Kent Hansen Date: Tue, 22 Nov 2011 13:26:20 +0100 Subject: Move QDeclarativeListModel and friends from util/ to qml/ QDeclarativeWorkerScript depends on QDeclarativeListModel et al, so the latter should also reside under qml/. Note that QDeclarativeOpenMetaObject also had to be moved, since QDeclarativeListModel depends on it. Change-Id: I164cba0e530d22b5771056a2acde12a18d5e83e1 Reviewed-by: Roberto Raggi --- src/declarative/qml/qdeclarativeengine.cpp | 4 +- src/declarative/qml/qdeclarativelistmodel.cpp | 2053 ++++++++++++++++++++ src/declarative/qml/qdeclarativelistmodel_p.h | 175 ++ src/declarative/qml/qdeclarativelistmodel_p_p.h | 325 ++++ .../qml/qdeclarativelistmodelworkeragent.cpp | 221 +++ .../qml/qdeclarativelistmodelworkeragent_p.h | 161 ++ src/declarative/qml/qdeclarativeopenmetaobject.cpp | 384 ++++ src/declarative/qml/qdeclarativeopenmetaobject_p.h | 131 ++ src/declarative/qml/qdeclarativeworkerscript.cpp | 4 +- src/declarative/qml/qlistmodelinterface.cpp | 104 + src/declarative/qml/qlistmodelinterface_p.h | 84 + src/declarative/qml/qml.pri | 9 + src/declarative/util/qdeclarativelistmodel.cpp | 2053 -------------------- src/declarative/util/qdeclarativelistmodel_p.h | 175 -- src/declarative/util/qdeclarativelistmodel_p_p.h | 325 ---- .../util/qdeclarativelistmodelworkeragent.cpp | 221 --- .../util/qdeclarativelistmodelworkeragent_p.h | 161 -- .../util/qdeclarativeopenmetaobject.cpp | 384 ---- .../util/qdeclarativeopenmetaobject_p.h | 131 -- .../util/qdeclarativepropertychanges.cpp | 2 +- src/declarative/util/qdeclarativepropertymap.cpp | 2 +- src/declarative/util/qdeclarativeutilmodule.cpp | 9 - src/declarative/util/qdeclarativeutilmodule_p.h | 1 - src/declarative/util/qlistmodelinterface.cpp | 104 - src/declarative/util/qlistmodelinterface_p.h | 84 - src/declarative/util/util.pri | 9 - 26 files changed, 3654 insertions(+), 3662 deletions(-) create mode 100644 src/declarative/qml/qdeclarativelistmodel.cpp create mode 100644 src/declarative/qml/qdeclarativelistmodel_p.h create mode 100644 src/declarative/qml/qdeclarativelistmodel_p_p.h create mode 100644 src/declarative/qml/qdeclarativelistmodelworkeragent.cpp create mode 100644 src/declarative/qml/qdeclarativelistmodelworkeragent_p.h create mode 100644 src/declarative/qml/qdeclarativeopenmetaobject.cpp create mode 100644 src/declarative/qml/qdeclarativeopenmetaobject_p.h create mode 100644 src/declarative/qml/qlistmodelinterface.cpp create mode 100644 src/declarative/qml/qlistmodelinterface_p.h delete mode 100644 src/declarative/util/qdeclarativelistmodel.cpp delete mode 100644 src/declarative/util/qdeclarativelistmodel_p.h delete mode 100644 src/declarative/util/qdeclarativelistmodel_p_p.h delete mode 100644 src/declarative/util/qdeclarativelistmodelworkeragent.cpp delete mode 100644 src/declarative/util/qdeclarativelistmodelworkeragent_p.h delete mode 100644 src/declarative/util/qdeclarativeopenmetaobject.cpp delete mode 100644 src/declarative/util/qdeclarativeopenmetaobject_p.h delete mode 100644 src/declarative/util/qlistmodelinterface.cpp delete mode 100644 src/declarative/util/qlistmodelinterface_p.h diff --git a/src/declarative/qml/qdeclarativeengine.cpp b/src/declarative/qml/qdeclarativeengine.cpp index 05db2e8e21..b677a876b4 100644 --- a/src/declarative/qml/qdeclarativeengine.cpp +++ b/src/declarative/qml/qdeclarativeengine.cpp @@ -56,6 +56,7 @@ #include "qdeclarativesqldatabase_p.h" #include "qdeclarativescriptstring.h" #include "qdeclarativeglobal_p.h" +#include "qdeclarativelistmodel_p.h" #include "qdeclarativeworkerscript_p.h" #include "qdeclarativecomponent_p.h" #include "qdeclarativenetworkaccessmanagerfactory.h" @@ -103,7 +104,6 @@ void qmlRegisterBaseTypes(const char *uri, int versionMajor, int versionMinor) { QDeclarativeEnginePrivate::registerBaseTypes(uri, versionMajor, versionMinor); QDeclarativeValueTypeFactory::registerBaseTypes(uri, versionMajor, versionMinor); - QDeclarativeUtilModule::registerBaseTypes(uri, versionMajor, versionMinor); } /*! @@ -168,6 +168,8 @@ void QDeclarativeEnginePrivate::registerBaseTypes(const char *uri, int versionMa { qmlRegisterType(uri,versionMajor,versionMinor,"Component"); qmlRegisterType(uri,versionMajor,versionMinor,"QtObject"); + qmlRegisterType(uri, versionMajor, versionMinor,"ListElement"); + qmlRegisterCustomType(uri, versionMajor, versionMinor,"ListModel", new QDeclarativeListModelParser); qmlRegisterType(uri,versionMajor,versionMinor,"WorkerScript"); } diff --git a/src/declarative/qml/qdeclarativelistmodel.cpp b/src/declarative/qml/qdeclarativelistmodel.cpp new file mode 100644 index 0000000000..9e4d7269cd --- /dev/null +++ b/src/declarative/qml/qdeclarativelistmodel.cpp @@ -0,0 +1,2053 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qdeclarativelistmodel_p_p.h" +#include "qdeclarativelistmodelworkeragent_p.h" +#include "qdeclarativeopenmetaobject_p.h" +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +Q_DECLARE_METATYPE(QListModelInterface *) + +QT_BEGIN_NAMESPACE + +// Set to 1024 as a debugging aid - easier to distinguish uids from indices of elements/models. +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; + const char *roleTypeNames[] = { "String", "Number", "Bool", "List", "QObject" }; + + if (t > ListLayout::Role::Invalid && t < ListLayout::Role::MaxDataType) + result = QString::fromLatin1(roleTypeNames[t]); + + return result; +} + +const ListLayout::Role &ListLayout::getRoleOrCreate(const QString &key, Role::DataType type) +{ + QStringHash::Node *node = roleHash.findNode(key); + if (node) { + const Role &r = *node->value; + if (type != r.type) + qmlInfo(0) << QString::fromLatin1("Can't assign to existing role '%1' of different type [%2 -> %3]").arg(r.name).arg(roleTypeName(type)).arg(roleTypeName(r.type)); + return r; + } + + return createRole(key, type); +} + +const ListLayout::Role &ListLayout::getRoleOrCreate(v8::Handle key, Role::DataType type) +{ + QHashedV8String hashedKey(key); + QStringHash::Node *node = roleHash.findNode(hashedKey); + if (node) { + const Role &r = *node->value; + if (type != r.type) + qmlInfo(0) << QString::fromLatin1("Can't assign to existing role '%1' of different type [%2 -> %3]").arg(r.name).arg(roleTypeName(type)).arg(roleTypeName(r.type)); + return r; + } + + QString qkey; + qkey.resize(key->Length()); + key->Write(reinterpret_cast(qkey.data())); + + return createRole(qkey, type); +} + +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), sizeof(QVariantMap) }; + const int dataAlignments[] = { sizeof(QString), sizeof(double), sizeof(bool), sizeof(ListModel *), sizeof(QObject *), sizeof(QVariantMap) }; + + Role *r = new Role; + r->name = key; + r->type = type; + + if (type == Role::List) { + r->subLayout = new ListLayout; + } else { + r->subLayout = 0; + } + + int dataSize = dataSizes[type]; + int dataAlignment = dataAlignments[type]; + + int dataOffset = (currentBlockOffset + dataAlignment-1) & ~(dataAlignment-1); + if (dataOffset + dataSize > ListElement::BLOCK_SIZE) { + r->blockIndex = ++currentBlock; + r->blockOffset = 0; + currentBlockOffset = dataSize; + } else { + r->blockIndex = currentBlock; + r->blockOffset = dataOffset; + currentBlockOffset = dataOffset + dataSize; + } + + int roleIndex = roles.count(); + r->index = roleIndex; + + roles.append(r); + roleHash.insert(key, r); + + return *r; +} + +ListLayout::ListLayout(const ListLayout *other) : currentBlock(0), currentBlockOffset(0) +{ + for (int i=0 ; i < other->roles.count() ; ++i) { + Role *role = new Role(other->roles[i]); + roles.append(role); + roleHash.insert(role->name, role); + } + currentBlockOffset = other->currentBlockOffset; + currentBlock = other->currentBlock; +} + +ListLayout::~ListLayout() +{ + for (int i=0 ; i < roles.count() ; ++i) { + delete roles[i]; + } +} + +void ListLayout::sync(ListLayout *src, ListLayout *target) +{ + int roleOffset = target->roles.count(); + int newRoleCount = src->roles.count() - roleOffset; + + for (int i=0 ; i < newRoleCount ; ++i) { + Role *role = new Role(src->roles[roleOffset + i]); + target->roles.append(role); + target->roleHash.insert(role->name, role); + } + + target->currentBlockOffset = src->currentBlockOffset; + target->currentBlock = src->currentBlock; +} + +ListLayout::Role::Role(const Role *other) +{ + name = other->name; + type = other->type; + blockIndex = other->blockIndex; + blockOffset = other->blockOffset; + index = other->index; + if (other->subLayout) + subLayout = new ListLayout(other->subLayout); + else + subLayout = 0; +} + +ListLayout::Role::~Role() +{ + delete subLayout; +} + +const ListLayout::Role *ListLayout::getRoleOrCreate(const QString &key, const QVariant &data) +{ + Role::DataType type; + + switch (data.type()) { + case QVariant::Double: type = Role::Number; break; + case QVariant::Int: type = Role::Number; break; + case QVariant::UserType: type = Role::List; break; + case QVariant::Bool: type = Role::Bool; break; + case QVariant::String: type = Role::String; break; + default: type = Role::Invalid; break; + } + + if (type == Role::Invalid) { + qmlInfo(0) << "Can't create role for unsupported data type"; + return 0; + } + + return &getRoleOrCreate(key, type); +} + +const ListLayout::Role *ListLayout::getExistingRole(const QString &key) +{ + Role *r = 0; + QStringHash::Node *node = roleHash.findNode(key); + if (node) + r = node->value; + return r; +} + +const ListLayout::Role *ListLayout::getExistingRole(v8::Handle key) +{ + Role *r = 0; + QHashedV8String hashedKey(key); + QStringHash::Node *node = roleHash.findNode(hashedKey); + if (node) + r = node->value; + return r; +} + +ModelObject *ListModel::getOrCreateModelObject(QDeclarativeListModel *model, int elementIndex) +{ + ListElement *e = elements[elementIndex]; + if (e->m_objectCache == 0) { + e->m_objectCache = new ModelObject(model, elementIndex); + } + return e->m_objectCache; +} + +void ListModel::sync(ListModel *src, ListModel *target, QHash *targetModelHash) +{ + // Sanity check + target->m_uid = src->m_uid; + if (targetModelHash) + targetModelHash->insert(target->m_uid, target); + + // Build hash of elements <-> uid for each of the lists + QHash elementHash; + for (int i=0 ; i < target->elements.count() ; ++i) { + ListElement *e = target->elements.at(i); + int uid = e->getUid(); + ElementSync sync; + sync.target = e; + elementHash.insert(uid, sync); + } + for (int i=0 ; i < src->elements.count() ; ++i) { + ListElement *e = src->elements.at(i); + int uid = e->getUid(); + + QHash::iterator it = elementHash.find(uid); + if (it == elementHash.end()) { + ElementSync sync; + sync.src = e; + elementHash.insert(uid, sync); + } else { + ElementSync &sync = it.value(); + sync.src = e; + } + } + + // Get list of elements that are in the target but no longer in the source. These get deleted first. + QHash::iterator it = elementHash.begin(); + QHash::iterator end = elementHash.end(); + while (it != end) { + const ElementSync &s = it.value(); + if (s.src == 0) { + s.target->destroy(target->m_layout); + target->elements.removeOne(s.target); + delete s.target; + } + ++it; + } + + // Sync the layouts + ListLayout::sync(src->m_layout, target->m_layout); + + // Clear the target list, and append in correct order from the source + target->elements.clear(); + for (int i=0 ; i < src->elements.count() ; ++i) { + ListElement *srcElement = src->elements.at(i); + it = elementHash.find(srcElement->getUid()); + const ElementSync &s = it.value(); + ListElement *targetElement = s.target; + if (targetElement == 0) { + targetElement = new ListElement(srcElement->getUid()); + } + ListElement::sync(srcElement, src->m_layout, targetElement, target->m_layout, targetModelHash); + target->elements.append(targetElement); + } + + target->updateCacheIndices(); + + // Update values stored in target meta objects + for (int i=0 ; i < target->elements.count() ; ++i) { + ListElement *e = target->elements[i]; + if (e->m_objectCache) + e->m_objectCache->updateValues(); + } +} + +int ListModel::allocateUid() +{ + return uidCounter.fetchAndAddOrdered(1); +} + +ListModel::ListModel(ListLayout *layout, QDeclarativeListModel *modelCache, int uid) : m_layout(layout), m_modelCache(modelCache) +{ + if (uid == -1) + uid = allocateUid(); + m_uid = uid; +} + +void ListModel::destroy() +{ + clear(); + m_uid = -1; + m_layout = 0; + if (m_modelCache && m_modelCache->m_primary == false) + delete m_modelCache; + m_modelCache = 0; +} + +int ListModel::appendElement() +{ + int elementIndex = elements.count(); + newElement(elementIndex); + return elementIndex; +} + +void ListModel::insertElement(int index) +{ + newElement(index); + updateCacheIndices(); +} + +void ListModel::move(int from, int to, int n) +{ + if (from > to) { + // Only move forwards - flip if backwards moving + int tfrom = from; + int tto = to; + from = tto; + to = tto+n; + n = tfrom-tto; + } + + QPODVector store; + for (int i=0 ; i < (to-from) ; ++i) + store.append(elements[from+n+i]); + for (int i=0 ; i < n ; ++i) + store.append(elements[from+i]); + for (int i=0 ; i < store.count() ; ++i) + elements[from+i] = store[i]; + + updateCacheIndices(); +} + +void ListModel::newElement(int index) +{ + ListElement *e = new ListElement; + elements.insert(index, e); +} + +void ListModel::updateCacheIndices() +{ + for (int i=0 ; i < elements.count() ; ++i) { + ListElement *e = elements.at(i); + if (e->m_objectCache) { + e->m_objectCache->m_elementIndex = i; + } + } +} + +QVariant ListModel::getProperty(int elementIndex, int roleIndex, const QDeclarativeListModel *owner, QV8Engine *eng) +{ + ListElement *e = elements[elementIndex]; + const ListLayout::Role &r = m_layout->getExistingRole(roleIndex); + return e->getProperty(r, owner, eng); +} + +ListModel *ListModel::getListProperty(int elementIndex, const ListLayout::Role &role) +{ + ListElement *e = elements[elementIndex]; + return e->getListProperty(role); +} + +void ListModel::set(int elementIndex, v8::Handle object, QList *roles, QV8Engine *eng) +{ + ListElement *e = elements[elementIndex]; + + v8::Local propertyNames = object->GetPropertyNames(); + int propertyCount = propertyNames->Length(); + + for (int i=0 ; i < propertyCount ; ++i) { + v8::Local propertyName = propertyNames->Get(i)->ToString(); + v8::Local propertyValue = object->Get(propertyName); + + // Check if this key exists yet + int roleIndex = -1; + + // Add the value now + if (propertyValue->IsString()) { + const ListLayout::Role &r = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::String); + v8::Handle jsString = propertyValue->ToString(); + QString qstr; + qstr.resize(jsString->Length()); + jsString->Write(reinterpret_cast(qstr.data())); + roleIndex = e->setStringProperty(r, qstr); + } else if (propertyValue->IsNumber()) { + const ListLayout::Role &r = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::Number); + roleIndex = e->setDoubleProperty(r, propertyValue->NumberValue()); + } else if (propertyValue->IsArray()) { + const ListLayout::Role &r = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::List); + ListModel *subModel = new ListModel(r.subLayout, 0, -1); + + v8::Handle subArray = v8::Handle::Cast(propertyValue); + int arrayLength = subArray->Length(); + for (int j=0 ; j < arrayLength ; ++j) { + v8::Handle subObject = subArray->Get(j)->ToObject(); + subModel->append(subObject, eng); + } + + roleIndex = e->setListProperty(r, subModel); + } else if (propertyValue->IsBoolean()) { + const ListLayout::Role &r = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::Bool); + roleIndex = e->setBoolProperty(r, propertyValue->BooleanValue()); + } else if (propertyValue->IsObject()) { + QV8ObjectResource *r = (QV8ObjectResource *) propertyValue->ToObject()->GetExternalResource(); + if (r && r->resourceType() == QV8ObjectResource::QObjectType) { + QObject *o = QV8QObjectWrapper::toQObject(r); + 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); + if (r) + e->clearProperty(*r); + } + + if (roleIndex != -1) + roles->append(roleIndex); + } + + if (e->m_objectCache) { + e->m_objectCache->updateValues(*roles); + } +} + +void ListModel::set(int elementIndex, v8::Handle object, QV8Engine *eng) +{ + ListElement *e = elements[elementIndex]; + + v8::Local propertyNames = object->GetPropertyNames(); + int propertyCount = propertyNames->Length(); + + for (int i=0 ; i < propertyCount ; ++i) { + v8::Local propertyName = propertyNames->Get(i)->ToString(); + v8::Local propertyValue = object->Get(propertyName); + + // Add the value now + if (propertyValue->IsString()) { + const ListLayout::Role &r = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::String); + if (r.type == ListLayout::Role::String) { + v8::Handle jsString = propertyValue->ToString(); + QString qstr; + qstr.resize(jsString->Length()); + jsString->Write(reinterpret_cast(qstr.data())); + e->setStringPropertyFast(r, qstr); + } + } else if (propertyValue->IsNumber()) { + const ListLayout::Role &r = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::Number); + if (r.type == ListLayout::Role::Number) { + e->setDoublePropertyFast(r, propertyValue->NumberValue()); + } + } else if (propertyValue->IsArray()) { + const ListLayout::Role &r = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::List); + if (r.type == ListLayout::Role::List) { + ListModel *subModel = new ListModel(r.subLayout, 0, -1); + + v8::Handle subArray = v8::Handle::Cast(propertyValue); + int arrayLength = subArray->Length(); + for (int j=0 ; j < arrayLength ; ++j) { + v8::Handle subObject = subArray->Get(j)->ToObject(); + subModel->append(subObject, eng); + } + + e->setListPropertyFast(r, subModel); + } + } else if (propertyValue->IsBoolean()) { + const ListLayout::Role &r = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::Bool); + if (r.type == ListLayout::Role::Bool) { + e->setBoolPropertyFast(r, propertyValue->BooleanValue()); + } + } else if (propertyValue->IsObject()) { + QV8ObjectResource *r = (QV8ObjectResource *) propertyValue->ToObject()->GetExternalResource(); + if (r && r->resourceType() == QV8ObjectResource::QObjectType) { + QObject *o = QV8QObjectWrapper::toQObject(r); + 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); + if (r) + e->clearProperty(*r); + } + } +} + +void ListModel::clear() +{ + int elementCount = elements.count(); + for (int i=0 ; i < elementCount ; ++i) { + elements[i]->destroy(m_layout); + delete elements[i]; + } + elements.clear(); +} + +void ListModel::remove(int index, int count) +{ + for (int i=0 ; i < count ; ++i) { + elements[index+i]->destroy(m_layout); + delete elements[index+i]; + } + elements.remove(index, count); + updateCacheIndices(); +} + +void ListModel::insert(int elementIndex, v8::Handle object, QV8Engine *eng) +{ + insertElement(elementIndex); + set(elementIndex, object, eng); +} + +int ListModel::append(v8::Handle object, QV8Engine *eng) +{ + int elementIndex = appendElement(); + set(elementIndex, object, eng); + return elementIndex; +} + +int ListModel::setOrCreateProperty(int elementIndex, const QString &key, const QVariant &data) +{ + int roleIndex = -1; + + if (elementIndex >= 0 && elementIndex < elements.count()) { + ListElement *e = elements[elementIndex]; + const ListLayout::Role *r = m_layout->getRoleOrCreate(key, data); + if (r) { + roleIndex = e->setVariantProperty(*r, data); + + if (roleIndex != -1 && e->m_objectCache) { + QList roles; + roles << roleIndex; + e->m_objectCache->updateValues(roles); + } + } + } + + return roleIndex; +} + +int ListModel::setExistingProperty(int elementIndex, const QString &key, v8::Handle data, QV8Engine *eng) +{ + int roleIndex = -1; + + if (elementIndex >= 0 && elementIndex < elements.count()) { + ListElement *e = elements[elementIndex]; + const ListLayout::Role *r = m_layout->getExistingRole(key); + if (r) + roleIndex = e->setJsProperty(*r, data, eng); + } + + return roleIndex; +} + +inline char *ListElement::getPropertyMemory(const ListLayout::Role &role) +{ + ListElement *e = this; + int blockIndex = 0; + while (blockIndex < role.blockIndex) { + if (e->next == 0) { + e->next = new ListElement; + e->next->uid = uid; + } + e = e->next; + ++blockIndex; + } + + char *mem = &e->data[role.blockOffset]; + return mem; +} + +QString *ListElement::getStringProperty(const ListLayout::Role &role) +{ + char *mem = getPropertyMemory(role); + QString *s = reinterpret_cast(mem); + return s->data_ptr() ? s : 0; +} + +QObject *ListElement::getQObjectProperty(const ListLayout::Role &role) +{ + char *mem = getPropertyMemory(role); + QDeclarativeGuard *o = reinterpret_cast *>(mem); + 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); + + bool existingGuard = false; + for (size_t i=0 ; i < sizeof(QDeclarativeGuard) ; ++i) { + if (mem[i] != 0) { + existingGuard = true; + break; + } + } + + QDeclarativeGuard *o = 0; + + if (existingGuard) + o = reinterpret_cast *>(mem); + + return o; +} + +ListModel *ListElement::getListProperty(const ListLayout::Role &role) +{ + char *mem = getPropertyMemory(role); + ListModel **value = reinterpret_cast(mem); + return *value; +} + +QVariant ListElement::getProperty(const ListLayout::Role &role, const QDeclarativeListModel *owner, QV8Engine *eng) +{ + char *mem = getPropertyMemory(role); + + QVariant data; + + switch (role.type) { + case ListLayout::Role::Number: + { + double *value = reinterpret_cast(mem); + data = *value; + } + break; + case ListLayout::Role::String: + { + QString *value = reinterpret_cast(mem); + if (value->data_ptr() != 0) + data = *value; + } + break; + case ListLayout::Role::Bool: + { + bool *value = reinterpret_cast(mem); + data = *value; + } + break; + case ListLayout::Role::List: + { + ListModel **value = reinterpret_cast(mem); + ListModel *model = *value; + + if (model) { + if (model->m_modelCache == 0) { + model->m_modelCache = new QDeclarativeListModel(owner, model, eng); + QDeclarativeEngine::setContextForObject(model->m_modelCache, QDeclarativeEngine::contextForObject(owner)); + } + + QObject *object = model->m_modelCache; + data = QVariant::fromValue(object); + } + } + break; + case ListLayout::Role::QObject: + { + QDeclarativeGuard *guard = reinterpret_cast *>(mem); + QObject *object = guard->data(); + if (object) + data = QVariant::fromValue(object); + } + break; + case ListLayout::Role::VariantMap: + { + if (isMemoryUsed(mem)) { + QVariantMap *map = reinterpret_cast(mem); + data = *map; + } + } + break; + default: + break; + } + + return data; +} + +int ListElement::setStringProperty(const ListLayout::Role &role, const QString &s) +{ + int roleIndex = -1; + + if (role.type == ListLayout::Role::String) { + char *mem = getPropertyMemory(role); + QString *c = reinterpret_cast(mem); + bool changed; + if (c->data_ptr() == 0) { + new (mem) QString(s); + changed = true; + } else { + changed = c->compare(s) != 0; + *c = s; + } + if (changed) + roleIndex = role.index; + } + + return roleIndex; +} + +int ListElement::setDoubleProperty(const ListLayout::Role &role, double d) +{ + int roleIndex = -1; + + if (role.type == ListLayout::Role::Number) { + char *mem = getPropertyMemory(role); + double *value = new (mem) double; + bool changed = *value != d; + *value = d; + if (changed) + roleIndex = role.index; + } + + return roleIndex; +} + +int ListElement::setBoolProperty(const ListLayout::Role &role, bool b) +{ + int roleIndex = -1; + + if (role.type == ListLayout::Role::Bool) { + char *mem = getPropertyMemory(role); + bool *value = new (mem) bool; + bool changed = *value != b; + *value = b; + if (changed) + roleIndex = role.index; + } + + return roleIndex; +} + +int ListElement::setListProperty(const ListLayout::Role &role, ListModel *m) +{ + int roleIndex = -1; + + if (role.type == ListLayout::Role::List) { + char *mem = getPropertyMemory(role); + ListModel **value = new (mem) ListModel *; + if (*value) { + (*value)->destroy(); + delete *value; + } + *value = m; + roleIndex = role.index; + } + + return roleIndex; +} + +int ListElement::setQObjectProperty(const ListLayout::Role &role, QObject *o) +{ + int roleIndex = -1; + + if (role.type == ListLayout::Role::QObject) { + char *mem = getPropertyMemory(role); + QDeclarativeGuard *g = reinterpret_cast *>(mem); + bool existingGuard = false; + for (size_t i=0 ; i < sizeof(QDeclarativeGuard) ; ++i) { + if (mem[i] != 0) { + existingGuard = true; + break; + } + } + bool changed; + if (existingGuard) { + changed = g->data() != o; + g->~QDeclarativeGuard(); + } else { + changed = true; + } + new (mem) QDeclarativeGuard(o); + if (changed) + roleIndex = role.index; + } + + 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); + new (mem) QString(s); +} + +void ListElement::setDoublePropertyFast(const ListLayout::Role &role, double d) +{ + char *mem = getPropertyMemory(role); + double *value = new (mem) double; + *value = d; +} + +void ListElement::setBoolPropertyFast(const ListLayout::Role &role, bool b) +{ + char *mem = getPropertyMemory(role); + bool *value = new (mem) bool; + *value = b; +} + +void ListElement::setQObjectPropertyFast(const ListLayout::Role &role, QObject *o) +{ + char *mem = getPropertyMemory(role); + new (mem) QDeclarativeGuard(o); +} + +void ListElement::setListPropertyFast(const ListLayout::Role &role, ListModel *m) +{ + char *mem = getPropertyMemory(role); + ListModel **value = new (mem) ListModel *; + *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) { + case ListLayout::Role::String: + setStringProperty(role, QString()); + break; + case ListLayout::Role::Number: + setDoubleProperty(role, 0.0); + break; + case ListLayout::Role::Bool: + setBoolProperty(role, false); + break; + case ListLayout::Role::List: + setListProperty(role, 0); + break; + case ListLayout::Role::QObject: + setQObjectProperty(role, 0); + break; + case ListLayout::Role::VariantMap: + setVariantMapProperty(role, 0); + break; + default: + break; + } +} + +ListElement::ListElement() +{ + m_objectCache = 0; + uid = ListModel::allocateUid(); + next = 0; + qMemSet(data, 0, sizeof(data)); +} + +ListElement::ListElement(int existingUid) +{ + m_objectCache = 0; + uid = existingUid; + next = 0; + qMemSet(data, 0, sizeof(data)); +} + +ListElement::~ListElement() +{ + delete next; +} + +void ListElement::sync(ListElement *src, ListLayout *srcLayout, ListElement *target, ListLayout *targetLayout, QHash *targetModelHash) +{ + for (int i=0 ; i < srcLayout->roleCount() ; ++i) { + const ListLayout::Role &srcRole = srcLayout->getExistingRole(i); + const ListLayout::Role &targetRole = targetLayout->getExistingRole(i); + + switch (srcRole.type) { + case ListLayout::Role::List: + { + ListModel *srcSubModel = src->getListProperty(srcRole); + ListModel *targetSubModel = target->getListProperty(targetRole); + + if (srcSubModel) { + if (targetSubModel == 0) { + targetSubModel = new ListModel(targetRole.subLayout, 0, srcSubModel->getUid()); + target->setListPropertyFast(targetRole, targetSubModel); + } + ListModel::sync(srcSubModel, targetSubModel, targetModelHash); + } + } + break; + case ListLayout::Role::QObject: + { + QObject *object = src->getQObjectProperty(srcRole); + target->setQObjectProperty(targetRole, object); + } + break; + case ListLayout::Role::String: + case ListLayout::Role::Number: + case ListLayout::Role::Bool: + { + 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; + } + } + +} + +void ListElement::destroy(ListLayout *layout) +{ + if (layout) { + for (int i=0 ; i < layout->roleCount() ; ++i) { + const ListLayout::Role &r = layout->getExistingRole(i); + + switch (r.type) { + case ListLayout::Role::String: + { + QString *string = getStringProperty(r); + if (string) + string->~QString(); + } + break; + case ListLayout::Role::List: + { + ListModel *model = getListProperty(r); + if (model) { + model->destroy(); + delete model; + } + } + break; + case ListLayout::Role::QObject: + { + QDeclarativeGuard *guard = getGuardProperty(r); + if (guard) + 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; + } + } + + delete m_objectCache; + } + + if (next) + next->destroy(0); + uid = -1; +} + +int ListElement::setVariantProperty(const ListLayout::Role &role, const QVariant &d) +{ + int roleIndex = -1; + + switch (role.type) { + case ListLayout::Role::Number: + roleIndex = setDoubleProperty(role, d.toDouble()); + break; + case ListLayout::Role::String: + roleIndex = setStringProperty(role, d.toString()); + break; + case ListLayout::Role::Bool: + roleIndex = setBoolProperty(role, d.toBool()); + break; + case ListLayout::Role::List: + roleIndex = setListProperty(role, d.value()); + break; + default: + break; + } + + return roleIndex; +} + +int ListElement::setJsProperty(const ListLayout::Role &role, v8::Handle d, QV8Engine *eng) +{ + // Check if this key exists yet + int roleIndex = -1; + + // Add the value now + if (d->IsString()) { + v8::Handle jsString = d->ToString(); + QString qstr; + qstr.resize(jsString->Length()); + jsString->Write(reinterpret_cast(qstr.data())); + roleIndex = setStringProperty(role, qstr); + } else if (d->IsNumber()) { + roleIndex = setDoubleProperty(role, d->NumberValue()); + } else if (d->IsArray()) { + ListModel *subModel = new ListModel(role.subLayout, 0, -1); + v8::Handle subArray = v8::Handle::Cast(d); + int arrayLength = subArray->Length(); + for (int j=0 ; j < arrayLength ; ++j) { + v8::Handle subObject = subArray->Get(j)->ToObject(); + subModel->append(subObject, eng); + } + roleIndex = setListProperty(role, subModel); + } else if (d->IsBoolean()) { + roleIndex = setBoolProperty(role, d->BooleanValue()); + } else if (d->IsObject()) { + QV8ObjectResource *r = (QV8ObjectResource *) d->ToObject()->GetExternalResource(); + if (role.type == ListLayout::Role::QObject && r && r->resourceType() == 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); + } + + return roleIndex; +} + +ModelObject::ModelObject(QDeclarativeListModel *model, int elementIndex) +: m_model(model), m_elementIndex(elementIndex), m_meta(new ModelNodeMetaObject(this)) +{ + updateValues(); + setNodeUpdatesEnabled(true); +} + +void ModelObject::updateValues() +{ + int roleCount = m_model->m_listModel->roleCount(); + for (int i=0 ; i < roleCount ; ++i) { + const ListLayout::Role &role = m_model->m_listModel->getExistingRole(i); + QByteArray name = role.name.toUtf8(); + const QVariant &data = m_model->data(m_elementIndex, i); + setValue(name, data, role.type == ListLayout::Role::List); + } +} + +void ModelObject::updateValues(const QList &roles) +{ + int roleCount = roles.count(); + for (int i=0 ; i < roleCount ; ++i) { + int roleIndex = roles.at(i); + const ListLayout::Role &role = m_model->m_listModel->getExistingRole(roleIndex); + QByteArray name = role.name.toUtf8(); + const QVariant &data = m_model->data(m_elementIndex, roleIndex); + setValue(name, data, role.type == ListLayout::Role::List); + } +} + +ModelNodeMetaObject::ModelNodeMetaObject(ModelObject *object) +: QDeclarativeOpenMetaObject(object), m_enabled(false), m_obj(object) +{ +} + +ModelNodeMetaObject::~ModelNodeMetaObject() +{ +} + +void ModelNodeMetaObject::propertyWritten(int index) +{ + if (!m_enabled) + return; + + QV8Engine *eng = m_obj->m_model->engine(); + + QString propName = QString::fromUtf8(name(index)); + QVariant value = operator[](index); + + v8::HandleScope handle_scope; + v8::Context::Scope scope(eng->context()); + + v8::Handle v = eng->fromVariant(value); + + int roleIndex = m_obj->m_model->m_listModel->setExistingProperty(m_obj->m_elementIndex, propName, v, eng); + if (roleIndex != -1) { + QList roles; + roles << roleIndex; + m_obj->m_model->emitItemsChanged(m_obj->m_elementIndex, 1, roles); + } +} + +QDeclarativeListModelParser::ListInstruction *QDeclarativeListModelParser::ListModelData::instructions() const +{ + return (QDeclarativeListModelParser::ListInstruction *)((char *)this + sizeof(ListModelData)); +} + +/*! + \qmlclass ListModel QDeclarativeListModel + \inqmlmodule QtQuick 2 + \ingroup qml-working-with-data + \brief The ListModel element defines a free-form list data source. + + The ListModel is a simple container of ListElement definitions, each containing data roles. + The contents can be defined dynamically, or explicitly in QML. + + The number of elements in the model can be obtained from its \l count property. + A number of familiar methods are also provided to manipulate the contents of the + model, including append(), insert(), move(), remove() and set(). These methods + accept dictionaries as their arguments; these are translated to ListElement objects + by the model. + + Elements can be manipulated via the model using the setProperty() method, which + allows the roles of the specified element to be set and changed. + + \section1 Example Usage + + The following example shows a ListModel containing three elements, with the roles + "name" and "cost". + + \div {class="float-right"} + \inlineimage listmodel.png + \enddiv + + \snippet doc/src/snippets/declarative/listmodel.qml 0 + + \clearfloat + Roles (properties) in each element must begin with a lower-case letter and + should be common to all elements in a model. The ListElement documentation + provides more guidelines for how elements should be defined. + + Since the example model contains an \c id property, it can be referenced + by views, such as the ListView in this example: + + \snippet doc/src/snippets/declarative/listmodel-simple.qml 0 + \dots 8 + \snippet doc/src/snippets/declarative/listmodel-simple.qml 1 + + It is possible for roles to contain list data. In the following example we + create a list of fruit attributes: + + \snippet doc/src/snippets/declarative/listmodel-nested.qml model + + The delegate displays all the fruit attributes: + + \div {class="float-right"} + \inlineimage listmodel-nested.png + \enddiv + + \snippet doc/src/snippets/declarative/listmodel-nested.qml delegate + + \clearfloat + \section1 Modifying List Models + + The content of a ListModel may be created and modified using the clear(), + append(), set(), insert() and setProperty() methods. For example: + + \snippet doc/src/snippets/declarative/listmodel-modify.qml delegate + + Note that when creating content dynamically the set of available properties + cannot be changed once set. Whatever properties are first added to the model + are the only permitted properties in the model. + + \section1 Using Threaded List Models with WorkerScript + + ListModel can be used together with WorkerScript access a list model + from multiple threads. This is useful if list modifications are + synchronous and take some time: the list operations can be moved to a + different thread to avoid blocking of the main GUI thread. + + Here is an example that uses WorkerScript to periodically append the + current time to a list model: + + \snippet examples/declarative/threading/threadedlistmodel/timedisplay.qml 0 + + The included file, \tt dataloader.js, looks like this: + + \snippet examples/declarative/threading/threadedlistmodel/dataloader.js 0 + + The timer in the main example sends messages to the worker script by calling + \l WorkerScript::sendMessage(). When this message is received, + \l{WorkerScript::onMessage}{WorkerScript.onMessage()} is invoked in \c dataloader.js, + which appends the current time to the list model. + + Note the call to sync() from the \l{WorkerScript::onMessage}{WorkerScript.onMessage()} + handler. You must call sync() or else the changes made to the list from the external + thread will not be reflected in the list model in the main thread. + + \sa {qmlmodels}{Data Models}, {declarative/threading/threadedlistmodel}{Threaded ListModel example}, QtDeclarative +*/ + +QDeclarativeListModel::QDeclarativeListModel(QObject *parent) +: QListModelInterface(parent) +{ + m_mainThread = true; + m_primary = true; + m_agent = 0; + + m_layout = new ListLayout; + m_listModel = new ListModel(m_layout, this, -1); + + m_engine = 0; +} + +QDeclarativeListModel::QDeclarativeListModel(const QDeclarativeListModel *owner, ListModel *data, QV8Engine *eng, QObject *parent) +: QListModelInterface(parent) +{ + m_mainThread = owner->m_mainThread; + m_primary = false; + m_agent = owner->m_agent; + + m_layout = 0; + m_listModel = data; + + m_engine = eng; +} + +QDeclarativeListModel::QDeclarativeListModel(QDeclarativeListModel *orig, QDeclarativeListModelWorkerAgent *agent) +: QListModelInterface(agent) +{ + m_mainThread = false; + m_primary = true; + m_agent = agent; + + m_layout = new ListLayout(orig->m_layout); + m_listModel = new ListModel(m_layout, this, orig->m_listModel->getUid()); + ListModel::sync(orig->m_listModel, m_listModel, 0); + + m_engine = 0; +} + +QDeclarativeListModel::~QDeclarativeListModel() +{ + if (m_primary) { + m_listModel->destroy(); + delete m_listModel; + + if (m_mainThread && m_agent) + m_agent->release(); + } + + m_listModel = 0; + + delete m_layout; + m_layout = 0; +} + +QV8Engine *QDeclarativeListModel::engine() const +{ + if (m_engine == 0) { + m_engine = QDeclarativeEnginePrivate::getV8Engine(qmlEngine(this)); + } + + return m_engine; +} + +void QDeclarativeListModel::emitItemsChanged(int index, int count, const QList &roles) +{ + if (m_mainThread) { + emit itemsChanged(index, count, roles); + } else { + m_agent->data.changedChange(this, index, count, roles); + } +} + +void QDeclarativeListModel::emitItemsRemoved(int index, int count) +{ + if (m_mainThread) { + emit itemsRemoved(index, count); + emit countChanged(); + } else { + if (index == 0 && count == this->count()) + m_agent->data.clearChange(this); + m_agent->data.removeChange(this, index, count); + } +} + +void QDeclarativeListModel::emitItemsInserted(int index, int count) +{ + if (m_mainThread) { + emit itemsInserted(index, count); + emit countChanged(); + } else { + m_agent->data.insertChange(this, index, count); + } +} + +void QDeclarativeListModel::emitItemsMoved(int from, int to, int n) +{ + if (m_mainThread) { + emit itemsMoved(from, to, n); + } else { + m_agent->data.moveChange(this, from, n, to); + } +} + +QDeclarativeListModelWorkerAgent *QDeclarativeListModel::agent() +{ + if (m_agent) + return m_agent; + + m_agent = new QDeclarativeListModelWorkerAgent(this); + return m_agent; +} + +QList QDeclarativeListModel::roles() const +{ + QList rolesArray; + + for (int i=0 ; i < m_listModel->roleCount() ; ++i) + rolesArray << i; + + return rolesArray; +} + +QString QDeclarativeListModel::toString(int role) const +{ + const ListLayout::Role &r = m_listModel->getExistingRole(role); + return r.name; +} + +QVariant QDeclarativeListModel::data(int index, int role) const +{ + if (index >= count() || index < 0) + return QVariant(); + + return m_listModel->getProperty(index, role, this, engine()); +} + +/*! + \qmlproperty int QtQuick2::ListModel::count + The number of data entries in the model. +*/ +int QDeclarativeListModel::count() const +{ + return m_listModel->elementCount(); +} + +/*! + \qmlmethod QtQuick2::ListModel::clear() + + Deletes all content from the model. + + \sa append() remove() +*/ +void QDeclarativeListModel::clear() +{ + int cleared = count(); + + m_listModel->clear(); + emitItemsRemoved(0, cleared); +} + +/*! + \qmlmethod QtQuick2::ListModel::remove(int index, int count = 1) + + Deletes the content at \a index from the model. + + \sa clear() +*/ +void QDeclarativeListModel::remove(QDeclarativeV8Function *args) +{ + int argLength = args->Length(); + + if (argLength == 1 || argLength == 2) { + int index = (*args)[0]->Int32Value(); + int removeCount = (argLength == 2 ? ((*args)[1]->Int32Value()) : 1); + + if (index < 0 || index+removeCount > count() || removeCount <= 0) { + qmlInfo(this) << tr("remove: indices [%1 - %2] out of range [0 - %3]").arg(index).arg(index+removeCount).arg(count()); + return; + } + + m_listModel->remove(index, removeCount); + emitItemsRemoved(index, removeCount); + } else { + qmlInfo(this) << tr("remove: incorrect number of arguments"); + } +} + +/*! + \qmlmethod QtQuick2::ListModel::insert(int index, jsobject dict) + + Adds a new item to the list model at position \a index, with the + values in \a dict. + + \code + fruitModel.insert(2, {"cost": 5.95, "name":"Pizza"}) + \endcode + + The \a index must be to an existing item in the list, or one past + the end of the list (equivalent to append). + + \sa set() append() +*/ + +void QDeclarativeListModel::insert(QDeclarativeV8Function *args) +{ + if (args->Length() == 2) { + + v8::Handle arg0 = (*args)[0]; + int index = arg0->Int32Value(); + + if (index < 0 || index > count()) { + qmlInfo(this) << tr("insert: index %1 out of range").arg(index); + return; + } + + v8::Handle arg1 = (*args)[1]; + + if (arg1->IsArray()) { + v8::Handle objectArray = v8::Handle::Cast(arg1); + int objectArrayLength = objectArray->Length(); + for (int i=0 ; i < objectArrayLength ; ++i) { + v8::Handle argObject = objectArray->Get(i)->ToObject(); + 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, args->engine()); + emitItemsInserted(index, 1); + } else { + qmlInfo(this) << tr("insert: value is not an object"); + } + } else { + qmlInfo(this) << tr("insert: value is not an object"); + } +} + +/*! + \qmlmethod QtQuick2::ListModel::move(int from, int to, int n) + + Moves \a n items \a from one position \a to another. + + The from and to ranges must exist; for example, to move the first 3 items + to the end of the list: + + \code + fruitModel.move(0, fruitModel.count - 3, 3) + \endcode + + \sa append() +*/ +void QDeclarativeListModel::move(int from, int to, int n) +{ + if (n==0 || from==to) + return; + if (!canMove(from, to, n)) { + qmlInfo(this) << tr("move: out of range"); + return; + } + + m_listModel->move(from, to, n); + emitItemsMoved(from, to, n); +} + +/*! + \qmlmethod QtQuick2::ListModel::append(jsobject dict) + + Adds a new item to the end of the list model, with the + values in \a dict. + + \code + fruitModel.append({"cost": 5.95, "name":"Pizza"}) + \endcode + + \sa set() remove() +*/ +void QDeclarativeListModel::append(QDeclarativeV8Function *args) +{ + if (args->Length() == 1) { + v8::Handle arg = (*args)[0]; + + if (arg->IsArray()) { + v8::Handle objectArray = v8::Handle::Cast(arg); + int objectArrayLength = objectArray->Length(); + int index = m_listModel->elementCount(); + for (int i=0 ; i < objectArrayLength ; ++i) { + v8::Handle argObject = objectArray->Get(i)->ToObject(); + m_listModel->append(argObject, args->engine()); + } + emitItemsInserted(index, objectArrayLength); + } else if (arg->IsObject()) { + v8::Handle argObject = arg->ToObject(); + + int index = m_listModel->append(argObject, args->engine()); + emitItemsInserted(index, 1); + + } else { + qmlInfo(this) << tr("append: value is not an object"); + } + } else { + qmlInfo(this) << tr("append: value is not an object"); + } +} + +/*! + \qmlmethod object QtQuick2::ListModel::get(int index) + + Returns the item at \a index in the list model. This allows the item + data to be accessed or modified from JavaScript: + + \code + Component.onCompleted: { + fruitModel.append({"cost": 5.95, "name":"Jackfruit"}); + console.log(fruitModel.get(0).cost); + fruitModel.get(0).cost = 10.95; + } + \endcode + + The \a index must be an element in the list. + + Note that properties of the returned object that are themselves objects + will also be models, and this get() method is used to access elements: + + \code + fruitModel.append(..., "attributes": + [{"name":"spikes","value":"7mm"}, + {"name":"color","value":"green"}]); + fruitModel.get(0).attributes.get(1).value; // == "green" + \endcode + + \warning The returned object is not guaranteed to remain valid. It + should not be used in \l{Property Binding}{property bindings}. + + \sa append() +*/ +QDeclarativeV8Handle QDeclarativeListModel::get(int index) const +{ + v8::Handle result = v8::Undefined(); + + if (index >= 0 && index < m_listModel->elementCount()) { + QV8Engine *v8engine = engine(); + + ModelObject *object = m_listModel->getOrCreateModelObject(const_cast(this), index); + result = v8engine->newQObject(object); + } + + return QDeclarativeV8Handle::fromHandle(result); +} + +/*! + \qmlmethod QtQuick2::ListModel::set(int index, jsobject dict) + + Changes the item at \a index in the list model with the + values in \a dict. Properties not appearing in \a dict + are left unchanged. + + \code + fruitModel.set(3, {"cost": 5.95, "name":"Pizza"}) + \endcode + + If \a index is equal to count() then a new item is appended to the + list. Otherwise, \a index must be an element in the list. + + \sa append() +*/ +void QDeclarativeListModel::set(int index, const QDeclarativeV8Handle &handle) +{ + v8::Handle valuemap = handle.toHandle(); + + if (!valuemap->IsObject() || valuemap->IsArray()) { + qmlInfo(this) << tr("set: value is not an object"); + return; + } + if (index > count() || index < 0) { + qmlInfo(this) << tr("set: index %1 out of range").arg(index); + return; + } + + v8::Handle object = valuemap->ToObject(); + + if (index == count()) { + m_listModel->insert(index, object, engine()); + emitItemsInserted(index, 1); + } else { + + QList roles; + m_listModel->set(index, object, &roles, engine()); + + if (roles.count()) + emitItemsChanged(index, 1, roles); + } +} + +/*! + \qmlmethod QtQuick2::ListModel::setProperty(int index, string property, variant value) + + Changes the \a property of the item at \a index in the list model to \a value. + + \code + fruitModel.setProperty(3, "cost", 5.95) + \endcode + + The \a index must be an element in the list. + + \sa append() +*/ +void QDeclarativeListModel::setProperty(int index, const QString& property, const QVariant& value) +{ + if (count() == 0 || index >= count() || index < 0) { + qmlInfo(this) << tr("set: index %1 out of range").arg(index); + return; + } + + int roleIndex = m_listModel->setOrCreateProperty(index, property, value); + if (roleIndex != -1) { + + QList roles; + roles << roleIndex; + + emitItemsChanged(index, 1, roles); + } +} + +/*! + \qmlmethod QtQuick2::ListModel::sync() + + Writes any unsaved changes to the list model after it has been modified + from a worker script. +*/ +void QDeclarativeListModel::sync() +{ + // This is just a dummy method to make it look like sync() exists in + // ListModel (and not just QDeclarativeListModelWorkerAgent) and to let + // us document sync(). + qmlInfo(this) << "List sync() can only be called from a WorkerScript"; +} + +bool QDeclarativeListModelParser::compileProperty(const QDeclarativeCustomParserProperty &prop, QList &instr, QByteArray &data) +{ + QList values = prop.assignedValues(); + for(int ii = 0; ii < values.count(); ++ii) { + const QVariant &value = values.at(ii); + + if(value.userType() == qMetaTypeId()) { + QDeclarativeCustomParserNode node = + qvariant_cast(value); + + if (node.name() != listElementTypeName) { + const QMetaObject *mo = resolveType(node.name()); + if (mo != &QDeclarativeListElement::staticMetaObject) { + error(node, QDeclarativeListModel::tr("ListElement: cannot contain nested elements")); + return false; + } + listElementTypeName = node.name(); // cache right name for next time + } + + { + ListInstruction li; + li.type = ListInstruction::Push; + li.dataIdx = -1; + instr << li; + } + + QList props = node.properties(); + for(int jj = 0; jj < props.count(); ++jj) { + const QDeclarativeCustomParserProperty &nodeProp = props.at(jj); + if (nodeProp.name().isEmpty()) { + error(nodeProp, QDeclarativeListModel::tr("ListElement: cannot contain nested elements")); + return false; + } + if (nodeProp.name() == QStringLiteral("id")) { + error(nodeProp, QDeclarativeListModel::tr("ListElement: cannot use reserved \"id\" property")); + return false; + } + + ListInstruction li; + int ref = data.count(); + data.append(nodeProp.name().toUtf8()); + data.append('\0'); + li.type = ListInstruction::Set; + li.dataIdx = ref; + instr << li; + + if(!compileProperty(nodeProp, instr, data)) + return false; + + li.type = ListInstruction::Pop; + li.dataIdx = -1; + instr << li; + } + + { + ListInstruction li; + li.type = ListInstruction::Pop; + li.dataIdx = -1; + instr << li; + } + + } else { + + QDeclarativeScript::Variant variant = + qvariant_cast(value); + + int ref = data.count(); + + QByteArray d; + d += char(variant.type()); // type tag + if (variant.isString()) { + d += variant.asString().toUtf8(); + } else if (variant.isNumber()) { + d += QByteArray::number(variant.asNumber(),'g',20); + } else if (variant.isBoolean()) { + d += char(variant.asBoolean()); + } else if (variant.isScript()) { + if (definesEmptyList(variant.asScript())) { + d[0] = char(QDeclarativeScript::Variant::Invalid); // marks empty list + } else { + QByteArray script = variant.asScript().toUtf8(); + int v = evaluateEnum(script); + if (v<0) { + using namespace QDeclarativeJS; + AST::Node *node = variant.asAST(); + AST::StringLiteral *literal = 0; + if (AST::CallExpression *callExpr = AST::cast(node)) { + if (AST::IdentifierExpression *idExpr = AST::cast(callExpr->base)) { + if (idExpr->name == QLatin1String("QT_TR_NOOP") || idExpr->name == QLatin1String("QT_TRID_NOOP")) { + if (callExpr->arguments && !callExpr->arguments->next) + literal = AST::cast(callExpr->arguments->expression); + if (!literal) { + error(prop, QDeclarativeListModel::tr("ListElement: improperly specified %1").arg(idExpr->name.toString())); + return false; + } + } else if (idExpr->name == QLatin1String("QT_TRANSLATE_NOOP")) { + if (callExpr->arguments && callExpr->arguments->next && !callExpr->arguments->next->next) + literal = AST::cast(callExpr->arguments->next->expression); + if (!literal) { + error(prop, QDeclarativeListModel::tr("ListElement: improperly specified QT_TRANSLATE_NOOP")); + return false; + } + } + } + } + + if (literal) { + d[0] = char(QDeclarativeScript::Variant::String); + d += literal->value.toUtf8(); + } else { + error(prop, QDeclarativeListModel::tr("ListElement: cannot use script for property value")); + return false; + } + } else { + d[0] = char(QDeclarativeScript::Variant::Number); + d += QByteArray::number(v); + } + } + } + d.append('\0'); + data.append(d); + + ListInstruction li; + li.type = ListInstruction::Value; + li.dataIdx = ref; + instr << li; + } + } + + return true; +} + +QByteArray QDeclarativeListModelParser::compile(const QList &customProps) +{ + QList instr; + QByteArray data; + listElementTypeName = QString(); // unknown + + for(int ii = 0; ii < customProps.count(); ++ii) { + const QDeclarativeCustomParserProperty &prop = customProps.at(ii); + if(!prop.name().isEmpty()) { // isn't default property + error(prop, QDeclarativeListModel::tr("ListModel: undefined property '%1'").arg(prop.name())); + return QByteArray(); + } + + if(!compileProperty(prop, instr, data)) { + return QByteArray(); + } + } + + int size = sizeof(ListModelData) + + instr.count() * sizeof(ListInstruction) + + data.count(); + + QByteArray rv; + rv.resize(size); + + ListModelData *lmd = (ListModelData *)rv.data(); + lmd->dataOffset = sizeof(ListModelData) + + instr.count() * sizeof(ListInstruction); + lmd->instrCount = instr.count(); + for (int ii = 0; ii < instr.count(); ++ii) + lmd->instructions()[ii] = instr.at(ii); + ::memcpy(rv.data() + lmd->dataOffset, data.constData(), data.count()); + + return rv; +} + +void QDeclarativeListModelParser::setCustomData(QObject *obj, const QByteArray &d) +{ + QDeclarativeListModel *rv = static_cast(obj); + + QV8Engine *engine = QDeclarativeEnginePrivate::getV8Engine(qmlEngine(rv)); + rv->m_engine = engine; + + const ListModelData *lmd = (const ListModelData *)d.constData(); + const char *data = ((const char *)lmd) + lmd->dataOffset; + + QStack stack; + + for (int ii = 0; ii < lmd->instrCount; ++ii) { + const ListInstruction &instr = lmd->instructions()[ii]; + + switch(instr.type) { + case ListInstruction::Push: + { + ListModel *subModel = 0; + + if (stack.count() == 0) { + subModel = rv->m_listModel; + } else { + const DataStackElement &e0 = stack.at(stack.size() - 1); + DataStackElement &e1 = stack[stack.size() - 2]; + + const ListLayout::Role &role = e1.model->getOrCreateListRole(e0.name); + if (role.type == ListLayout::Role::List) { + subModel = e1.model->getListProperty(e1.elementIndex, role); + + if (subModel == 0) { + subModel = new ListModel(role.subLayout, 0, -1); + QVariant vModel = QVariant::fromValue(subModel); + e1.model->setOrCreateProperty(e1.elementIndex, e0.name, vModel); + } + } + } + + DataStackElement e; + e.model = subModel; + e.elementIndex = subModel ? subModel->appendElement() : -1; + stack.push(e); + } + break; + + case ListInstruction::Pop: + stack.pop(); + break; + + case ListInstruction::Value: + { + const DataStackElement &e0 = stack.at(stack.size() - 1); + DataStackElement &e1 = stack[stack.size() - 2]; + + QString name = e0.name; + QVariant value; + + switch (QDeclarativeScript::Variant::Type(data[instr.dataIdx])) { + case QDeclarativeScript::Variant::Invalid: + { + const ListLayout::Role &role = e1.model->getOrCreateListRole(e0.name); + ListModel *emptyModel = new ListModel(role.subLayout, 0, -1); + value = QVariant::fromValue(emptyModel); + } + break; + case QDeclarativeScript::Variant::Boolean: + value = bool(data[1 + instr.dataIdx]); + break; + case QDeclarativeScript::Variant::Number: + value = QByteArray(data + 1 + instr.dataIdx).toDouble(); + break; + case QDeclarativeScript::Variant::String: + value = QString::fromUtf8(data + 1 + instr.dataIdx); + break; + default: + Q_ASSERT("Format error in ListInstruction"); + } + + e1.model->setOrCreateProperty(e1.elementIndex, name, value); + } + break; + + case ListInstruction::Set: + { + DataStackElement e; + e.name = QString::fromUtf8(data + instr.dataIdx); + stack.push(e); + } + break; + } + } +} + +bool QDeclarativeListModelParser::definesEmptyList(const QString &s) +{ + if (s.startsWith(QLatin1Char('[')) && s.endsWith(QLatin1Char(']'))) { + for (int i=1; i +#include + +#include +#include +#include +#include +#include +#include "qlistmodelinterface_p.h" + +#include +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Declarative) + +class QDeclarativeListModelWorkerAgent; +class ListModel; +class ListLayout; + +class Q_DECLARATIVE_PRIVATE_EXPORT QDeclarativeListModel : public QListModelInterface +{ + Q_OBJECT + Q_PROPERTY(int count READ count NOTIFY countChanged) + +public: + QDeclarativeListModel(QObject *parent=0); + ~QDeclarativeListModel(); + + virtual QList roles() const; + virtual QString toString(int role) const; + virtual int count() const; + virtual QVariant data(int index, int role) const; + + Q_INVOKABLE void clear(); + Q_INVOKABLE void remove(QDeclarativeV8Function *args); + Q_INVOKABLE void append(QDeclarativeV8Function *args); + Q_INVOKABLE void insert(QDeclarativeV8Function *args); + Q_INVOKABLE QDeclarativeV8Handle get(int index) const; + Q_INVOKABLE void set(int index, const QDeclarativeV8Handle &); + Q_INVOKABLE void setProperty(int index, const QString& property, const QVariant& value); + Q_INVOKABLE void move(int from, int to, int count); + Q_INVOKABLE void sync(); + + QDeclarativeListModelWorkerAgent *agent(); + +Q_SIGNALS: + void countChanged(); + +private: + friend class QDeclarativeListModelParser; + friend class QDeclarativeListModelWorkerAgent; + friend class ModelObject; + friend class ModelNodeMetaObject; + friend class ListModel; + friend class ListElement; + + // Constructs a flat list model for a worker agent + QDeclarativeListModel(QDeclarativeListModel *orig, QDeclarativeListModelWorkerAgent *agent); + QDeclarativeListModel(const QDeclarativeListModel *owner, ListModel *data, QV8Engine *eng, QObject *parent=0); + + QV8Engine *engine() const; + + inline bool canMove(int from, int to, int n) const { return !(from+n > count() || to+n > count() || from < 0 || to < 0 || n < 0); } + + ListLayout *m_layout; + ListModel *m_listModel; + + QDeclarativeListModelWorkerAgent *m_agent; + bool m_mainThread; + bool m_primary; + mutable QV8Engine *m_engine; + + void emitItemsChanged(int index, int count, const QList &roles); + void emitItemsRemoved(int index, int count); + void emitItemsInserted(int index, int count); + void emitItemsMoved(int from, int to, int n); +}; + +// ### FIXME +class QDeclarativeListElement : public QObject +{ +Q_OBJECT +}; + +class QDeclarativeListModelParser : public QDeclarativeCustomParser +{ +public: + QDeclarativeListModelParser() : QDeclarativeCustomParser(QDeclarativeCustomParser::AcceptsSignalHandlers) {} + QByteArray compile(const QList &); + void setCustomData(QObject *, const QByteArray &); + +private: + struct ListInstruction + { + enum { Push, Pop, Value, Set } type; + int dataIdx; + }; + struct ListModelData + { + int dataOffset; + int instrCount; + ListInstruction *instructions() const; + }; + bool compileProperty(const QDeclarativeCustomParserProperty &prop, QList &instr, QByteArray &data); + + bool definesEmptyList(const QString &); + + QString listElementTypeName; + + struct DataStackElement + { + DataStackElement() : model(0), elementIndex(0) {} + + QString name; + ListModel *model; + int elementIndex; + }; +}; + +QT_END_NAMESPACE + +QML_DECLARE_TYPE(QDeclarativeListModel) +QML_DECLARE_TYPE(QDeclarativeListElement) + +QT_END_HEADER + +#endif // QDECLARATIVELISTMODEL_H diff --git a/src/declarative/qml/qdeclarativelistmodel_p_p.h b/src/declarative/qml/qdeclarativelistmodel_p_p.h new file mode 100644 index 0000000000..ab6c2b25cc --- /dev/null +++ b/src/declarative/qml/qdeclarativelistmodel_p_p.h @@ -0,0 +1,325 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDECLARATIVELISTMODEL_P_P_H +#define QDECLARATIVELISTMODEL_P_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qdeclarativelistmodel_p.h" +#include +#include "qdeclarativeopenmetaobject_p.h" +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Declarative) + +class ModelObject; + +class ModelNodeMetaObject : public QDeclarativeOpenMetaObject +{ +public: + ModelNodeMetaObject(ModelObject *object); + ~ModelNodeMetaObject(); + + bool m_enabled; + +protected: + void propertyWritten(int index); + +private: + + ModelObject *m_obj; +}; + +class ModelObject : public QObject +{ + Q_OBJECT +public: + ModelObject(QDeclarativeListModel *model, int elementIndex); + + void setValue(const QByteArray &name, const QVariant &val, bool force) + { + if (force) { + QVariant existingValue = m_meta->value(name); + if (existingValue.isValid()) { + (*m_meta)[name] = QVariant(); + } + } + m_meta->setValue(name, val); + } + + void setNodeUpdatesEnabled(bool enable) + { + m_meta->m_enabled = enable; + } + + void updateValues(); + void updateValues(const QList &roles); + + QDeclarativeListModel *m_model; + int m_elementIndex; + +private: + ModelNodeMetaObject *m_meta; +}; + +class ListLayout +{ +public: + ListLayout() : currentBlock(0), currentBlockOffset(0) {} + ListLayout(const ListLayout *other); + ~ListLayout(); + + class Role + { + public: + + Role() : type(Invalid), blockIndex(-1), blockOffset(-1), index(-1), subLayout(0) {} + explicit Role(const Role *other); + ~Role(); + + // This enum must be kept in sync with the roleTypeNames variable in qdeclarativelistmodel.cpp + enum DataType + { + Invalid = -1, + + String, + Number, + Bool, + List, + QObject, + VariantMap, + + MaxDataType + }; + + QString name; + DataType type; + int blockIndex; + int blockOffset; + int index; + ListLayout *subLayout; + }; + + const Role *getRoleOrCreate(const QString &key, const QVariant &data); + const Role &getRoleOrCreate(v8::Handle key, Role::DataType type); + const Role &getRoleOrCreate(const QString &key, Role::DataType type); + + const Role &getExistingRole(int index) { return *roles.at(index); } + const Role *getExistingRole(const QString &key); + const Role *getExistingRole(v8::Handle key); + + int roleCount() const { return roles.count(); } + + static void sync(ListLayout *src, ListLayout *target); + +private: + const Role &createRole(const QString &key, Role::DataType type); + + int currentBlock; + int currentBlockOffset; + QVector roles; + QStringHash roleHash; +}; + +class ListElement +{ +public: + + ListElement(); + ListElement(int existingUid); + ~ListElement(); + + static void sync(ListElement *src, ListLayout *srcLayout, ListElement *target, ListLayout *targetLayout, QHash *targetModelHash); + + enum + { + BLOCK_SIZE = 64 - sizeof(int) - sizeof(ListElement *) - sizeof(ModelObject *) + }; + +private: + + void destroy(ListLayout *layout); + + int setVariantProperty(const ListLayout::Role &role, const QVariant &d); + + int setJsProperty(const ListLayout::Role &role, v8::Handle d, QV8Engine *eng); + + int setStringProperty(const ListLayout::Role &role, const QString &s); + int setDoubleProperty(const ListLayout::Role &role, double n); + int setBoolProperty(const ListLayout::Role &role, bool b); + int setListProperty(const ListLayout::Role &role, ListModel *m); + int setQObjectProperty(const ListLayout::Role &role, QObject *o); + int setVariantMapProperty(const ListLayout::Role &role, v8::Handle o, QV8Engine *eng); + int setVariantMapProperty(const ListLayout::Role &role, QVariantMap *m); + + void setStringPropertyFast(const ListLayout::Role &role, const QString &s); + void setDoublePropertyFast(const ListLayout::Role &role, double n); + void setBoolPropertyFast(const ListLayout::Role &role, bool b); + void setQObjectPropertyFast(const ListLayout::Role &role, QObject *o); + void setListPropertyFast(const ListLayout::Role &role, ListModel *m); + void setVariantMapFast(const ListLayout::Role &role, v8::Handle o, QV8Engine *eng); + + void clearProperty(const ListLayout::Role &role); + + QVariant getProperty(const ListLayout::Role &role, const QDeclarativeListModel *owner, QV8Engine *eng); + ListModel *getListProperty(const ListLayout::Role &role); + QString *getStringProperty(const ListLayout::Role &role); + QObject *getQObjectProperty(const ListLayout::Role &role); + QDeclarativeGuard *getGuardProperty(const ListLayout::Role &role); + QVariantMap *getVariantMapProperty(const ListLayout::Role &role); + + inline char *getPropertyMemory(const ListLayout::Role &role); + + int getUid() const { return uid; } + + char data[BLOCK_SIZE]; + ListElement *next; + + int uid; + ModelObject *m_objectCache; + + friend class ListModel; +}; + +class ListModel +{ +public: + + ListModel(ListLayout *layout, QDeclarativeListModel *modelCache, int uid); + ~ListModel() {} + + void destroy(); + + int setOrCreateProperty(int elementIndex, const QString &key, const QVariant &data); + int setExistingProperty(int uid, const QString &key, v8::Handle data, QV8Engine *eng); + + QVariant getProperty(int elementIndex, int roleIndex, const QDeclarativeListModel *owner, QV8Engine *eng); + ListModel *getListProperty(int elementIndex, const ListLayout::Role &role); + + int roleCount() const + { + return m_layout->roleCount(); + } + + const ListLayout::Role &getExistingRole(int index) + { + return m_layout->getExistingRole(index); + } + + const ListLayout::Role &getOrCreateListRole(const QString &name) + { + return m_layout->getRoleOrCreate(name, ListLayout::Role::List); + } + + int elementCount() const + { + return elements.count(); + } + + void set(int elementIndex, v8::Handle object, QList *roles, QV8Engine *eng); + void set(int elementIndex, v8::Handle object, QV8Engine *eng); + + int append(v8::Handle object, QV8Engine *eng); + void insert(int elementIndex, v8::Handle object, QV8Engine *eng); + + void clear(); + void remove(int index, int count); + + int appendElement(); + void insertElement(int index); + + void move(int from, int to, int n); + + int getUid() const { return m_uid; } + + static int allocateUid(); + + static void sync(ListModel *src, ListModel *target, QHash *srcModelHash); + + ModelObject *getOrCreateModelObject(QDeclarativeListModel *model, int elementIndex); + +private: + QPODVector elements; + ListLayout *m_layout; + int m_uid; + + QDeclarativeListModel *m_modelCache; + + struct ElementSync + { + ElementSync() : src(0), target(0) {} + + ListElement *src; + ListElement *target; + }; + + void newElement(int index); + + void updateCacheIndices(); + + friend class ListElement; + friend class QDeclarativeListModelWorkerAgent; + + static QAtomicInt uidCounter; +}; + +QT_END_NAMESPACE + +Q_DECLARE_METATYPE(ListModel *); + +QT_END_HEADER + +#endif // QDECLARATIVELISTMODEL_P_P_H + diff --git a/src/declarative/qml/qdeclarativelistmodelworkeragent.cpp b/src/declarative/qml/qdeclarativelistmodelworkeragent.cpp new file mode 100644 index 0000000000..c01025cd45 --- /dev/null +++ b/src/declarative/qml/qdeclarativelistmodelworkeragent.cpp @@ -0,0 +1,221 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qdeclarativelistmodelworkeragent_p.h" +#include "qdeclarativelistmodel_p_p.h" +#include +#include +#include + +#include +#include +#include + + +QT_BEGIN_NAMESPACE + + +void QDeclarativeListModelWorkerAgent::Data::clearChange(QDeclarativeListModel *model) +{ + int uid = model->m_listModel->getUid(); + + for (int i=0 ; i < changes.count() ; ++i) { + if (changes[i].modelUid == uid) { + changes.removeAt(i); + --i; + } + } +} + +void QDeclarativeListModelWorkerAgent::Data::insertChange(QDeclarativeListModel *model, int index, int count) +{ + Change c = { model->m_listModel->getUid(), Change::Inserted, index, count, 0, QList() }; + changes << c; +} + +void QDeclarativeListModelWorkerAgent::Data::removeChange(QDeclarativeListModel *model, int index, int count) +{ + Change c = { model->m_listModel->getUid(), Change::Removed, index, count, 0, QList() }; + changes << c; +} + +void QDeclarativeListModelWorkerAgent::Data::moveChange(QDeclarativeListModel *model, int index, int count, int to) +{ + Change c = { model->m_listModel->getUid(), Change::Moved, index, count, to, QList() }; + changes << c; +} + +void QDeclarativeListModelWorkerAgent::Data::changedChange(QDeclarativeListModel *model, int index, int count, const QList &roles) +{ + Change c = { model->m_listModel->getUid(), Change::Changed, index, count, 0, roles }; + changes << c; +} + +QDeclarativeListModelWorkerAgent::QDeclarativeListModelWorkerAgent(QDeclarativeListModel *model) +: m_ref(1), m_orig(model), m_copy(new QDeclarativeListModel(model, this)) +{ +} + +void QDeclarativeListModelWorkerAgent::setV8Engine(QV8Engine *eng) +{ + m_copy->m_engine = eng; +} + +void QDeclarativeListModelWorkerAgent::addref() +{ + m_ref.ref(); +} + +void QDeclarativeListModelWorkerAgent::release() +{ + bool del = !m_ref.deref(); + + if (del) + delete this; +} + +int QDeclarativeListModelWorkerAgent::count() const +{ + return m_copy->count(); +} + +void QDeclarativeListModelWorkerAgent::clear() +{ + m_copy->clear(); +} + +void QDeclarativeListModelWorkerAgent::remove(QDeclarativeV8Function *args) +{ + m_copy->remove(args); +} + +void QDeclarativeListModelWorkerAgent::append(QDeclarativeV8Function *args) +{ + m_copy->append(args); +} + +void QDeclarativeListModelWorkerAgent::insert(QDeclarativeV8Function *args) +{ + m_copy->insert(args); +} + +QDeclarativeV8Handle QDeclarativeListModelWorkerAgent::get(int index) const +{ + return m_copy->get(index); +} + +void QDeclarativeListModelWorkerAgent::set(int index, const QDeclarativeV8Handle &value) +{ + m_copy->set(index, value); +} + +void QDeclarativeListModelWorkerAgent::setProperty(int index, const QString& property, const QVariant& value) +{ + m_copy->setProperty(index, property, value); +} + +void QDeclarativeListModelWorkerAgent::move(int from, int to, int count) +{ + m_copy->move(from, to, count); +} + +void QDeclarativeListModelWorkerAgent::sync() +{ + Sync *s = new Sync; + s->data = data; + s->list = m_copy; + data.changes.clear(); + + mutex.lock(); + QCoreApplication::postEvent(this, s); + syncDone.wait(&mutex); + mutex.unlock(); +} + +bool QDeclarativeListModelWorkerAgent::event(QEvent *e) +{ + if (e->type() == QEvent::User) { + + QMutexLocker locker(&mutex); + Sync *s = static_cast(e); + + const QList &changes = s->data.changes; + + bool cc = m_orig->count() != s->list->count(); + + QHash targetModelHash; + ListModel::sync(s->list->m_listModel, m_orig->m_listModel, &targetModelHash); + + for (int ii = 0; ii < changes.count(); ++ii) { + const Change &change = changes.at(ii); + + ListModel *model = targetModelHash.value(change.modelUid); + + if (model && model->m_modelCache) { + switch (change.type) { + case Change::Inserted: + emit model->m_modelCache->itemsInserted(change.index, change.count); + break; + case Change::Removed: + emit model->m_modelCache->itemsRemoved(change.index, change.count); + break; + case Change::Moved: + emit model->m_modelCache->itemsMoved(change.index, change.to, change.count); + break; + case Change::Changed: + emit model->m_modelCache->itemsChanged(change.index, change.count, change.roles); + break; + } + } + } + + syncDone.wakeAll(); + locker.unlock(); + + if (cc) + emit m_orig->countChanged(); + } + + return QObject::event(e); +} + +QT_END_NAMESPACE + diff --git a/src/declarative/qml/qdeclarativelistmodelworkeragent_p.h b/src/declarative/qml/qdeclarativelistmodelworkeragent_p.h new file mode 100644 index 0000000000..05c36473a5 --- /dev/null +++ b/src/declarative/qml/qdeclarativelistmodelworkeragent_p.h @@ -0,0 +1,161 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDECLARATIVELISTMODELWORKERAGENT_P_H +#define QDECLARATIVELISTMODELWORKERAGENT_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include + +#include +#include +#include + +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Declarative) + +class QDeclarativeListModel; + +class QDeclarativeListModelWorkerAgent : public QObject +{ + Q_OBJECT + Q_PROPERTY(int count READ count) + +public: + QDeclarativeListModelWorkerAgent(QDeclarativeListModel *); + + void setV8Engine(QV8Engine *eng); + + void addref(); + void release(); + + int count() const; + + Q_INVOKABLE void clear(); + Q_INVOKABLE void remove(QDeclarativeV8Function *args); + Q_INVOKABLE void append(QDeclarativeV8Function *args); + Q_INVOKABLE void insert(QDeclarativeV8Function *args); + Q_INVOKABLE QDeclarativeV8Handle get(int index) const; + Q_INVOKABLE void set(int index, const QDeclarativeV8Handle &); + Q_INVOKABLE void setProperty(int index, const QString& property, const QVariant& value); + Q_INVOKABLE void move(int from, int to, int count); + Q_INVOKABLE void sync(); + + struct VariantRef + { + VariantRef() : a(0) {} + VariantRef(const VariantRef &r) : a(r.a) { if (a) a->addref(); } + VariantRef(QDeclarativeListModelWorkerAgent *_a) : a(_a) { if (a) a->addref(); } + ~VariantRef() { if (a) a->release(); } + + VariantRef &operator=(const VariantRef &o) { + if (o.a) o.a->addref(); + if (a) a->release(); a = o.a; + return *this; + } + + QDeclarativeListModelWorkerAgent *a; + }; +protected: + virtual bool event(QEvent *); + +private: + friend class QDeclarativeWorkerScriptEnginePrivate; + friend class QDeclarativeListModel; + + struct Change + { + int modelUid; + enum { Inserted, Removed, Moved, Changed } type; + int index; // Inserted/Removed/Moved/Changed + int count; // Inserted/Removed/Moved/Changed + int to; // Moved + QList roles; + }; + + struct Data + { + QList changes; + + void clearChange(QDeclarativeListModel *model); + void insertChange(QDeclarativeListModel *model, int index, int count); + void removeChange(QDeclarativeListModel *model, int index, int count); + void moveChange(QDeclarativeListModel *model, int index, int count, int to); + void changedChange(QDeclarativeListModel *model, int index, int count, const QList &roles); + }; + Data data; + + struct Sync : public QEvent { + Sync() : QEvent(QEvent::User) {} + Data data; + QDeclarativeListModel *list; + }; + + QAtomicInt m_ref; + QDeclarativeListModel *m_orig; + QDeclarativeListModel *m_copy; + QMutex mutex; + QWaitCondition syncDone; +}; + +QT_END_NAMESPACE + +Q_DECLARE_METATYPE(QDeclarativeListModelWorkerAgent::VariantRef) + +QT_END_HEADER + +#endif // QDECLARATIVEWORKERSCRIPT_P_H + diff --git a/src/declarative/qml/qdeclarativeopenmetaobject.cpp b/src/declarative/qml/qdeclarativeopenmetaobject.cpp new file mode 100644 index 0000000000..d4dd8242c4 --- /dev/null +++ b/src/declarative/qml/qdeclarativeopenmetaobject.cpp @@ -0,0 +1,384 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qdeclarativeopenmetaobject_p.h" +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + + +class QDeclarativeOpenMetaObjectTypePrivate +{ +public: + QDeclarativeOpenMetaObjectTypePrivate() : mem(0), cache(0), engine(0) {} + + void init(const QMetaObject *metaObj); + + int propertyOffset; + int signalOffset; + QHash names; + QMetaObjectBuilder mob; + QMetaObject *mem; + QDeclarativePropertyCache *cache; + QDeclarativeEngine *engine; + QSet referers; +}; + +QDeclarativeOpenMetaObjectType::QDeclarativeOpenMetaObjectType(const QMetaObject *base, QDeclarativeEngine *engine) + : QDeclarativeCleanup(engine), d(new QDeclarativeOpenMetaObjectTypePrivate) +{ + d->engine = engine; + d->init(base); +} + +QDeclarativeOpenMetaObjectType::~QDeclarativeOpenMetaObjectType() +{ + if (d->mem) + qFree(d->mem); + if (d->cache) + d->cache->release(); + delete d; +} + +void QDeclarativeOpenMetaObjectType::clear() +{ + d->engine = 0; +} + +int QDeclarativeOpenMetaObjectType::propertyOffset() const +{ + return d->propertyOffset; +} + +int QDeclarativeOpenMetaObjectType::signalOffset() const +{ + return d->signalOffset; +} + +int QDeclarativeOpenMetaObjectType::createProperty(const QByteArray &name) +{ + int id = d->mob.propertyCount(); + d->mob.addSignal("__" + QByteArray::number(id) + "()"); + QMetaPropertyBuilder build = d->mob.addProperty(name, "QVariant", id); + propertyCreated(id, build); + qFree(d->mem); + d->mem = d->mob.toMetaObject(); + d->names.insert(name, id); + QSet::iterator it = d->referers.begin(); + while (it != d->referers.end()) { + QDeclarativeOpenMetaObject *omo = *it; + *static_cast(omo) = *d->mem; + if (d->cache) + d->cache->update(d->engine, omo); + ++it; + } + + return d->propertyOffset + id; +} + +void QDeclarativeOpenMetaObjectType::propertyCreated(int id, QMetaPropertyBuilder &builder) +{ + if (d->referers.count()) + (*d->referers.begin())->propertyCreated(id, builder); +} + +void QDeclarativeOpenMetaObjectTypePrivate::init(const QMetaObject *metaObj) +{ + if (!mem) { + mob.setSuperClass(metaObj); + mob.setClassName(metaObj->className()); + mob.setFlags(QMetaObjectBuilder::DynamicMetaObject); + + mem = mob.toMetaObject(); + + propertyOffset = mem->propertyOffset(); + signalOffset = mem->methodOffset(); + } +} + +//---------------------------------------------------------------------------- + +class QDeclarativeOpenMetaObjectPrivate +{ +public: + QDeclarativeOpenMetaObjectPrivate(QDeclarativeOpenMetaObject *_q) + : q(_q), parent(0), type(0), cacheProperties(false) {} + + inline QVariant &getData(int idx) { + while (data.count() <= idx) + data << QPair(QVariant(), false); + QPair &prop = data[idx]; + if (!prop.second) { + prop.first = q->initialValue(idx); + prop.second = true; + } + return prop.first; + } + + inline void writeData(int idx, const QVariant &value) { + while (data.count() <= idx) + data << QPair(QVariant(), false); + QPair &prop = data[idx]; + prop.first = value; + prop.second = true; + } + + inline bool hasData(int idx) const { + if (idx >= data.count()) + return false; + return data[idx].second; + } + + bool autoCreate; + QDeclarativeOpenMetaObject *q; + QAbstractDynamicMetaObject *parent; + QList > data; + QObject *object; + QDeclarativeOpenMetaObjectType *type; + bool cacheProperties; +}; + +QDeclarativeOpenMetaObject::QDeclarativeOpenMetaObject(QObject *obj, bool automatic) +: d(new QDeclarativeOpenMetaObjectPrivate(this)) +{ + d->autoCreate = automatic; + d->object = obj; + + d->type = new QDeclarativeOpenMetaObjectType(obj->metaObject(), 0); + d->type->d->referers.insert(this); + + QObjectPrivate *op = QObjectPrivate::get(obj); + d->parent = static_cast(op->metaObject); + *static_cast(this) = *d->type->d->mem; + op->metaObject = this; +} + +QDeclarativeOpenMetaObject::QDeclarativeOpenMetaObject(QObject *obj, QDeclarativeOpenMetaObjectType *type, bool automatic) +: d(new QDeclarativeOpenMetaObjectPrivate(this)) +{ + d->autoCreate = automatic; + d->object = obj; + + d->type = type; + d->type->addref(); + d->type->d->referers.insert(this); + + QObjectPrivate *op = QObjectPrivate::get(obj); + d->parent = static_cast(op->metaObject); + *static_cast(this) = *d->type->d->mem; + op->metaObject = this; +} + +QDeclarativeOpenMetaObject::~QDeclarativeOpenMetaObject() +{ + if (d->parent) + delete d->parent; + d->type->d->referers.remove(this); + d->type->release(); + delete d; +} + +QDeclarativeOpenMetaObjectType *QDeclarativeOpenMetaObject::type() const +{ + return d->type; +} + +int QDeclarativeOpenMetaObject::metaCall(QMetaObject::Call c, int id, void **a) +{ + if (( c == QMetaObject::ReadProperty || c == QMetaObject::WriteProperty) + && id >= d->type->d->propertyOffset) { + int propId = id - d->type->d->propertyOffset; + if (c == QMetaObject::ReadProperty) { + propertyRead(propId); + *reinterpret_cast(a[0]) = d->getData(propId); + } else if (c == QMetaObject::WriteProperty) { + if (propId <= d->data.count() || d->data[propId].first != *reinterpret_cast(a[0])) { + propertyWrite(propId); + d->writeData(propId, *reinterpret_cast(a[0])); + propertyWritten(propId); + activate(d->object, d->type->d->signalOffset + propId, 0); + } + } + return -1; + } else { + if (d->parent) + return d->parent->metaCall(c, id, a); + else + return d->object->qt_metacall(c, id, a); + } +} + +QAbstractDynamicMetaObject *QDeclarativeOpenMetaObject::parent() const +{ + return d->parent; +} + +QVariant QDeclarativeOpenMetaObject::value(int id) const +{ + return d->getData(id); +} + +void QDeclarativeOpenMetaObject::setValue(int id, const QVariant &value) +{ + d->writeData(id, value); + activate(d->object, id + d->type->d->signalOffset, 0); +} + +QVariant QDeclarativeOpenMetaObject::value(const QByteArray &name) const +{ + QHash::ConstIterator iter = d->type->d->names.find(name); + if (iter == d->type->d->names.end()) + return QVariant(); + + return d->getData(*iter); +} + +QVariant &QDeclarativeOpenMetaObject::operator[](const QByteArray &name) +{ + QHash::ConstIterator iter = d->type->d->names.find(name); + Q_ASSERT(iter != d->type->d->names.end()); + + return d->getData(*iter); +} + +QVariant &QDeclarativeOpenMetaObject::operator[](int id) +{ + return d->getData(id); +} + +void QDeclarativeOpenMetaObject::setValue(const QByteArray &name, const QVariant &val) +{ + QHash::ConstIterator iter = d->type->d->names.find(name); + + int id = -1; + if (iter == d->type->d->names.end()) { + id = createProperty(name.constData(), "") - d->type->d->propertyOffset; + } else { + id = *iter; + } + + if (id >= 0) { + QVariant &dataVal = d->getData(id); + if (dataVal == val) + return; + + dataVal = val; + activate(d->object, id + d->type->d->signalOffset, 0); + } +} + +// returns true if this value has been initialized by a call to either value() or setValue() +bool QDeclarativeOpenMetaObject::hasValue(int id) const +{ + return d->hasData(id); +} + +void QDeclarativeOpenMetaObject::setCached(bool c) +{ + if (c == d->cacheProperties || !d->type->d->engine) + return; + + d->cacheProperties = c; + + QDeclarativeData *qmldata = QDeclarativeData::get(d->object, true); + if (d->cacheProperties) { + if (!d->type->d->cache) + d->type->d->cache = new QDeclarativePropertyCache(d->type->d->engine, this); + qmldata->propertyCache = d->type->d->cache; + d->type->d->cache->addref(); + } else { + if (d->type->d->cache) + d->type->d->cache->release(); + qmldata->propertyCache = 0; + } +} + + +int QDeclarativeOpenMetaObject::createProperty(const char *name, const char *) +{ + if (d->autoCreate) + return d->type->createProperty(name); + else + return -1; +} + +void QDeclarativeOpenMetaObject::propertyRead(int) +{ +} + +void QDeclarativeOpenMetaObject::propertyWrite(int) +{ +} + +void QDeclarativeOpenMetaObject::propertyWritten(int) +{ +} + +void QDeclarativeOpenMetaObject::propertyCreated(int, QMetaPropertyBuilder &) +{ +} + +QVariant QDeclarativeOpenMetaObject::initialValue(int) +{ + return QVariant(); +} + +int QDeclarativeOpenMetaObject::count() const +{ + return d->type->d->names.count(); +} + +QByteArray QDeclarativeOpenMetaObject::name(int idx) const +{ + Q_ASSERT(idx >= 0 && idx < d->type->d->names.count()); + + return d->type->d->mob.property(idx).name(); +} + +QObject *QDeclarativeOpenMetaObject::object() const +{ + return d->object; +} + +QT_END_NAMESPACE diff --git a/src/declarative/qml/qdeclarativeopenmetaobject_p.h b/src/declarative/qml/qdeclarativeopenmetaobject_p.h new file mode 100644 index 0000000000..e5cfee7eb6 --- /dev/null +++ b/src/declarative/qml/qdeclarativeopenmetaobject_p.h @@ -0,0 +1,131 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDECLARATIVEOPENMETAOBJECT_H +#define QDECLARATIVEOPENMETAOBJECT_H + +#include +#include + +#include +#include +#include +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Declarative) + +class QDeclarativeEngine; +class QMetaPropertyBuilder; +class QDeclarativeOpenMetaObjectTypePrivate; +class Q_DECLARATIVE_PRIVATE_EXPORT QDeclarativeOpenMetaObjectType : public QDeclarativeRefCount, public QDeclarativeCleanup +{ +public: + QDeclarativeOpenMetaObjectType(const QMetaObject *base, QDeclarativeEngine *engine); + ~QDeclarativeOpenMetaObjectType(); + + int createProperty(const QByteArray &name); + + int propertyOffset() const; + int signalOffset() const; + +protected: + virtual void propertyCreated(int, QMetaPropertyBuilder &); + virtual void clear(); + +private: + QDeclarativeOpenMetaObjectTypePrivate *d; + friend class QDeclarativeOpenMetaObject; + friend class QDeclarativeOpenMetaObjectPrivate; +}; + +class QDeclarativeOpenMetaObjectPrivate; +class Q_DECLARATIVE_PRIVATE_EXPORT QDeclarativeOpenMetaObject : public QAbstractDynamicMetaObject +{ +public: + QDeclarativeOpenMetaObject(QObject *, bool = true); + QDeclarativeOpenMetaObject(QObject *, QDeclarativeOpenMetaObjectType *, bool = true); + ~QDeclarativeOpenMetaObject(); + + QVariant value(const QByteArray &) const; + void setValue(const QByteArray &, const QVariant &); + QVariant value(int) const; + void setValue(int, const QVariant &); + QVariant &operator[](const QByteArray &); + QVariant &operator[](int); + bool hasValue(int) const; + + int count() const; + QByteArray name(int) const; + + QObject *object() const; + virtual QVariant initialValue(int); + + // Be careful - once setCached(true) is called createProperty() is no + // longer automatically called for new properties. + void setCached(bool); + + QDeclarativeOpenMetaObjectType *type() const; + +protected: + virtual int metaCall(QMetaObject::Call _c, int _id, void **_a); + virtual int createProperty(const char *, const char *); + + virtual void propertyRead(int); + virtual void propertyWrite(int); + virtual void propertyWritten(int); + virtual void propertyCreated(int, QMetaPropertyBuilder &); + + QAbstractDynamicMetaObject *parent() const; + +private: + QDeclarativeOpenMetaObjectPrivate *d; + friend class QDeclarativeOpenMetaObjectType; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QDECLARATIVEOPENMETAOBJECT_H diff --git a/src/declarative/qml/qdeclarativeworkerscript.cpp b/src/declarative/qml/qdeclarativeworkerscript.cpp index 98aaddceef..793bc24aa3 100644 --- a/src/declarative/qml/qdeclarativeworkerscript.cpp +++ b/src/declarative/qml/qdeclarativeworkerscript.cpp @@ -40,8 +40,8 @@ ****************************************************************************/ #include "qdeclarativeworkerscript_p.h" -#include -#include +#include "qdeclarativelistmodel_p.h" +#include "qdeclarativelistmodelworkeragent_p.h" #include "qdeclarativeengine_p.h" #include "qdeclarativeexpression_p.h" diff --git a/src/declarative/qml/qlistmodelinterface.cpp b/src/declarative/qml/qlistmodelinterface.cpp new file mode 100644 index 0000000000..4461456516 --- /dev/null +++ b/src/declarative/qml/qlistmodelinterface.cpp @@ -0,0 +1,104 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclaractive module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qlistmodelinterface_p.h" + +QT_BEGIN_NAMESPACE + +/*! + \internal + \class QListModelInterface + \brief The QListModelInterface class can be subclassed to provide C++ models to QDeclarativeGraphics Views + + This class is comprised primarily of pure virtual functions which + you must implement in a subclass. You can then use the subclass + as a model for a QDeclarativeGraphics view, such as a QDeclarativeListView. +*/ + +/*! \fn QListModelInterface::QListModelInterface(QObject *parent) + Constructs a QListModelInterface with the specified \a parent. +*/ + + /*! \fn QListModelInterface::QListModelInterface(QObjectPrivate &dd, QObject *parent) + + \internal + */ + +/*! \fn QListModelInterface::~QListModelInterface() + The destructor is virtual. + */ + +/*! \fn int QListModelInterface::count() const + Returns the number of data entries in the model. +*/ + +/*! \fn QVariant QListModelInterface::data(int index, int role) const + Returns the data at the given \a index for the specified \a roles. +*/ + +/*! \fn QList QListModelInterface::roles() const + Returns the list of roles for which the list model interface + provides data. +*/ + +/*! \fn QString QListModelInterface::toString(int role) const + Returns a string description of the specified \a role. +*/ + +/*! \fn void QListModelInterface::itemsInserted(int index, int count) + Emit this signal when \a count items are inserted at \a index. + */ + +/*! \fn void QListModelInterface::itemsRemoved(int index, int count) + Emit this signal when \a count items are removed at \a index. + */ + +/*! \fn void QListModelInterface::itemsMoved(int from, int to, int count) + Emit this signal when \a count items are moved from index \a from + to index \a to. + */ + +/*! \fn void QListModelInterface::itemsChanged(int index, int count, const QList &roles) + Emit this signal when \a count items at \a index have had their + \a roles changed. + */ + +QT_END_NAMESPACE diff --git a/src/declarative/qml/qlistmodelinterface_p.h b/src/declarative/qml/qlistmodelinterface_p.h new file mode 100644 index 0000000000..340dfac258 --- /dev/null +++ b/src/declarative/qml/qlistmodelinterface_p.h @@ -0,0 +1,84 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QLISTMODELINTERFACE_H +#define QLISTMODELINTERFACE_H + +#include +#include + +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Declarative) + +class Q_DECLARATIVE_PRIVATE_EXPORT QListModelInterface : public QObject +{ + Q_OBJECT + public: + QListModelInterface(QObject *parent = 0) : QObject(parent) {} + virtual ~QListModelInterface() {} + + virtual int count() const = 0; + virtual QVariant data(int index, int role) const = 0; + + virtual QList roles() const = 0; + virtual QString toString(int role) const = 0; + + Q_SIGNALS: + void itemsInserted(int index, int count); + void itemsRemoved(int index, int count); + void itemsMoved(int from, int to, int count); + void itemsChanged(int index, int count, const QList &roles); + + protected: + QListModelInterface(QObjectPrivate &dd, QObject *parent) + : QObject(dd, parent) {} +}; + + +QT_END_NAMESPACE + +QT_END_HEADER +#endif //QTREEMODELINTERFACE_H diff --git a/src/declarative/qml/qml.pri b/src/declarative/qml/qml.pri index 444183eeab..928854ad62 100644 --- a/src/declarative/qml/qml.pri +++ b/src/declarative/qml/qml.pri @@ -1,6 +1,9 @@ SOURCES += \ $$PWD/qdeclarativeapplication.cpp \ $$PWD/qdeclarativeinstruction.cpp \ + $$PWD/qdeclarativelistmodel.cpp \ + $$PWD/qdeclarativelistmodelworkeragent.cpp \ + $$PWD/qdeclarativeopenmetaobject.cpp \ $$PWD/qdeclarativevmemetaobject.cpp \ $$PWD/qdeclarativeengine.cpp \ $$PWD/qdeclarativeexpression.cpp \ @@ -45,10 +48,15 @@ SOURCES += \ $$PWD/qdeclarativeimport.cpp \ $$PWD/qdeclarativelist.cpp \ $$PWD/qdeclarativelocale.cpp \ + $$PWD/qlistmodelinterface.cpp HEADERS += \ $$PWD/qdeclarativeglobal_p.h \ $$PWD/qdeclarativeinstruction_p.h \ + $$PWD/qdeclarativelistmodel_p.h\ + $$PWD/qdeclarativelistmodel_p_p.h\ + $$PWD/qdeclarativelistmodelworkeragent_p.h \ + $$PWD/qdeclarativeopenmetaobject_p.h \ $$PWD/qdeclarativevmemetaobject_p.h \ $$PWD/qdeclarative.h \ $$PWD/qdeclarativeapplication_p.h \ @@ -109,6 +117,7 @@ HEADERS += \ $$PWD/qdeclarativenullablevalue_p_p.h \ $$PWD/qdeclarativescriptstring_p.h \ $$PWD/qdeclarativelocale_p.h \ + $$PWD/qlistmodelinterface_p.h QT += sql include(parser/parser.pri) diff --git a/src/declarative/util/qdeclarativelistmodel.cpp b/src/declarative/util/qdeclarativelistmodel.cpp deleted file mode 100644 index 9e4d7269cd..0000000000 --- a/src/declarative/util/qdeclarativelistmodel.cpp +++ /dev/null @@ -1,2053 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the QtDeclarative module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** This file may be used under the terms of the GNU Lesser General Public -** License version 2.1 as published by the Free Software Foundation and -** appearing in the file LICENSE.LGPL included in the packaging of this -** file. Please review the following information to ensure the GNU Lesser -** General Public License version 2.1 requirements will be met: -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qdeclarativelistmodel_p_p.h" -#include "qdeclarativelistmodelworkeragent_p.h" -#include "qdeclarativeopenmetaobject_p.h" -#include -#include - -#include -#include -#include -#include -#include - -#include -#include -#include - -Q_DECLARE_METATYPE(QListModelInterface *) - -QT_BEGIN_NAMESPACE - -// Set to 1024 as a debugging aid - easier to distinguish uids from indices of elements/models. -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; - const char *roleTypeNames[] = { "String", "Number", "Bool", "List", "QObject" }; - - if (t > ListLayout::Role::Invalid && t < ListLayout::Role::MaxDataType) - result = QString::fromLatin1(roleTypeNames[t]); - - return result; -} - -const ListLayout::Role &ListLayout::getRoleOrCreate(const QString &key, Role::DataType type) -{ - QStringHash::Node *node = roleHash.findNode(key); - if (node) { - const Role &r = *node->value; - if (type != r.type) - qmlInfo(0) << QString::fromLatin1("Can't assign to existing role '%1' of different type [%2 -> %3]").arg(r.name).arg(roleTypeName(type)).arg(roleTypeName(r.type)); - return r; - } - - return createRole(key, type); -} - -const ListLayout::Role &ListLayout::getRoleOrCreate(v8::Handle key, Role::DataType type) -{ - QHashedV8String hashedKey(key); - QStringHash::Node *node = roleHash.findNode(hashedKey); - if (node) { - const Role &r = *node->value; - if (type != r.type) - qmlInfo(0) << QString::fromLatin1("Can't assign to existing role '%1' of different type [%2 -> %3]").arg(r.name).arg(roleTypeName(type)).arg(roleTypeName(r.type)); - return r; - } - - QString qkey; - qkey.resize(key->Length()); - key->Write(reinterpret_cast(qkey.data())); - - return createRole(qkey, type); -} - -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), sizeof(QVariantMap) }; - const int dataAlignments[] = { sizeof(QString), sizeof(double), sizeof(bool), sizeof(ListModel *), sizeof(QObject *), sizeof(QVariantMap) }; - - Role *r = new Role; - r->name = key; - r->type = type; - - if (type == Role::List) { - r->subLayout = new ListLayout; - } else { - r->subLayout = 0; - } - - int dataSize = dataSizes[type]; - int dataAlignment = dataAlignments[type]; - - int dataOffset = (currentBlockOffset + dataAlignment-1) & ~(dataAlignment-1); - if (dataOffset + dataSize > ListElement::BLOCK_SIZE) { - r->blockIndex = ++currentBlock; - r->blockOffset = 0; - currentBlockOffset = dataSize; - } else { - r->blockIndex = currentBlock; - r->blockOffset = dataOffset; - currentBlockOffset = dataOffset + dataSize; - } - - int roleIndex = roles.count(); - r->index = roleIndex; - - roles.append(r); - roleHash.insert(key, r); - - return *r; -} - -ListLayout::ListLayout(const ListLayout *other) : currentBlock(0), currentBlockOffset(0) -{ - for (int i=0 ; i < other->roles.count() ; ++i) { - Role *role = new Role(other->roles[i]); - roles.append(role); - roleHash.insert(role->name, role); - } - currentBlockOffset = other->currentBlockOffset; - currentBlock = other->currentBlock; -} - -ListLayout::~ListLayout() -{ - for (int i=0 ; i < roles.count() ; ++i) { - delete roles[i]; - } -} - -void ListLayout::sync(ListLayout *src, ListLayout *target) -{ - int roleOffset = target->roles.count(); - int newRoleCount = src->roles.count() - roleOffset; - - for (int i=0 ; i < newRoleCount ; ++i) { - Role *role = new Role(src->roles[roleOffset + i]); - target->roles.append(role); - target->roleHash.insert(role->name, role); - } - - target->currentBlockOffset = src->currentBlockOffset; - target->currentBlock = src->currentBlock; -} - -ListLayout::Role::Role(const Role *other) -{ - name = other->name; - type = other->type; - blockIndex = other->blockIndex; - blockOffset = other->blockOffset; - index = other->index; - if (other->subLayout) - subLayout = new ListLayout(other->subLayout); - else - subLayout = 0; -} - -ListLayout::Role::~Role() -{ - delete subLayout; -} - -const ListLayout::Role *ListLayout::getRoleOrCreate(const QString &key, const QVariant &data) -{ - Role::DataType type; - - switch (data.type()) { - case QVariant::Double: type = Role::Number; break; - case QVariant::Int: type = Role::Number; break; - case QVariant::UserType: type = Role::List; break; - case QVariant::Bool: type = Role::Bool; break; - case QVariant::String: type = Role::String; break; - default: type = Role::Invalid; break; - } - - if (type == Role::Invalid) { - qmlInfo(0) << "Can't create role for unsupported data type"; - return 0; - } - - return &getRoleOrCreate(key, type); -} - -const ListLayout::Role *ListLayout::getExistingRole(const QString &key) -{ - Role *r = 0; - QStringHash::Node *node = roleHash.findNode(key); - if (node) - r = node->value; - return r; -} - -const ListLayout::Role *ListLayout::getExistingRole(v8::Handle key) -{ - Role *r = 0; - QHashedV8String hashedKey(key); - QStringHash::Node *node = roleHash.findNode(hashedKey); - if (node) - r = node->value; - return r; -} - -ModelObject *ListModel::getOrCreateModelObject(QDeclarativeListModel *model, int elementIndex) -{ - ListElement *e = elements[elementIndex]; - if (e->m_objectCache == 0) { - e->m_objectCache = new ModelObject(model, elementIndex); - } - return e->m_objectCache; -} - -void ListModel::sync(ListModel *src, ListModel *target, QHash *targetModelHash) -{ - // Sanity check - target->m_uid = src->m_uid; - if (targetModelHash) - targetModelHash->insert(target->m_uid, target); - - // Build hash of elements <-> uid for each of the lists - QHash elementHash; - for (int i=0 ; i < target->elements.count() ; ++i) { - ListElement *e = target->elements.at(i); - int uid = e->getUid(); - ElementSync sync; - sync.target = e; - elementHash.insert(uid, sync); - } - for (int i=0 ; i < src->elements.count() ; ++i) { - ListElement *e = src->elements.at(i); - int uid = e->getUid(); - - QHash::iterator it = elementHash.find(uid); - if (it == elementHash.end()) { - ElementSync sync; - sync.src = e; - elementHash.insert(uid, sync); - } else { - ElementSync &sync = it.value(); - sync.src = e; - } - } - - // Get list of elements that are in the target but no longer in the source. These get deleted first. - QHash::iterator it = elementHash.begin(); - QHash::iterator end = elementHash.end(); - while (it != end) { - const ElementSync &s = it.value(); - if (s.src == 0) { - s.target->destroy(target->m_layout); - target->elements.removeOne(s.target); - delete s.target; - } - ++it; - } - - // Sync the layouts - ListLayout::sync(src->m_layout, target->m_layout); - - // Clear the target list, and append in correct order from the source - target->elements.clear(); - for (int i=0 ; i < src->elements.count() ; ++i) { - ListElement *srcElement = src->elements.at(i); - it = elementHash.find(srcElement->getUid()); - const ElementSync &s = it.value(); - ListElement *targetElement = s.target; - if (targetElement == 0) { - targetElement = new ListElement(srcElement->getUid()); - } - ListElement::sync(srcElement, src->m_layout, targetElement, target->m_layout, targetModelHash); - target->elements.append(targetElement); - } - - target->updateCacheIndices(); - - // Update values stored in target meta objects - for (int i=0 ; i < target->elements.count() ; ++i) { - ListElement *e = target->elements[i]; - if (e->m_objectCache) - e->m_objectCache->updateValues(); - } -} - -int ListModel::allocateUid() -{ - return uidCounter.fetchAndAddOrdered(1); -} - -ListModel::ListModel(ListLayout *layout, QDeclarativeListModel *modelCache, int uid) : m_layout(layout), m_modelCache(modelCache) -{ - if (uid == -1) - uid = allocateUid(); - m_uid = uid; -} - -void ListModel::destroy() -{ - clear(); - m_uid = -1; - m_layout = 0; - if (m_modelCache && m_modelCache->m_primary == false) - delete m_modelCache; - m_modelCache = 0; -} - -int ListModel::appendElement() -{ - int elementIndex = elements.count(); - newElement(elementIndex); - return elementIndex; -} - -void ListModel::insertElement(int index) -{ - newElement(index); - updateCacheIndices(); -} - -void ListModel::move(int from, int to, int n) -{ - if (from > to) { - // Only move forwards - flip if backwards moving - int tfrom = from; - int tto = to; - from = tto; - to = tto+n; - n = tfrom-tto; - } - - QPODVector store; - for (int i=0 ; i < (to-from) ; ++i) - store.append(elements[from+n+i]); - for (int i=0 ; i < n ; ++i) - store.append(elements[from+i]); - for (int i=0 ; i < store.count() ; ++i) - elements[from+i] = store[i]; - - updateCacheIndices(); -} - -void ListModel::newElement(int index) -{ - ListElement *e = new ListElement; - elements.insert(index, e); -} - -void ListModel::updateCacheIndices() -{ - for (int i=0 ; i < elements.count() ; ++i) { - ListElement *e = elements.at(i); - if (e->m_objectCache) { - e->m_objectCache->m_elementIndex = i; - } - } -} - -QVariant ListModel::getProperty(int elementIndex, int roleIndex, const QDeclarativeListModel *owner, QV8Engine *eng) -{ - ListElement *e = elements[elementIndex]; - const ListLayout::Role &r = m_layout->getExistingRole(roleIndex); - return e->getProperty(r, owner, eng); -} - -ListModel *ListModel::getListProperty(int elementIndex, const ListLayout::Role &role) -{ - ListElement *e = elements[elementIndex]; - return e->getListProperty(role); -} - -void ListModel::set(int elementIndex, v8::Handle object, QList *roles, QV8Engine *eng) -{ - ListElement *e = elements[elementIndex]; - - v8::Local propertyNames = object->GetPropertyNames(); - int propertyCount = propertyNames->Length(); - - for (int i=0 ; i < propertyCount ; ++i) { - v8::Local propertyName = propertyNames->Get(i)->ToString(); - v8::Local propertyValue = object->Get(propertyName); - - // Check if this key exists yet - int roleIndex = -1; - - // Add the value now - if (propertyValue->IsString()) { - const ListLayout::Role &r = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::String); - v8::Handle jsString = propertyValue->ToString(); - QString qstr; - qstr.resize(jsString->Length()); - jsString->Write(reinterpret_cast(qstr.data())); - roleIndex = e->setStringProperty(r, qstr); - } else if (propertyValue->IsNumber()) { - const ListLayout::Role &r = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::Number); - roleIndex = e->setDoubleProperty(r, propertyValue->NumberValue()); - } else if (propertyValue->IsArray()) { - const ListLayout::Role &r = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::List); - ListModel *subModel = new ListModel(r.subLayout, 0, -1); - - v8::Handle subArray = v8::Handle::Cast(propertyValue); - int arrayLength = subArray->Length(); - for (int j=0 ; j < arrayLength ; ++j) { - v8::Handle subObject = subArray->Get(j)->ToObject(); - subModel->append(subObject, eng); - } - - roleIndex = e->setListProperty(r, subModel); - } else if (propertyValue->IsBoolean()) { - const ListLayout::Role &r = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::Bool); - roleIndex = e->setBoolProperty(r, propertyValue->BooleanValue()); - } else if (propertyValue->IsObject()) { - QV8ObjectResource *r = (QV8ObjectResource *) propertyValue->ToObject()->GetExternalResource(); - if (r && r->resourceType() == QV8ObjectResource::QObjectType) { - QObject *o = QV8QObjectWrapper::toQObject(r); - 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); - if (r) - e->clearProperty(*r); - } - - if (roleIndex != -1) - roles->append(roleIndex); - } - - if (e->m_objectCache) { - e->m_objectCache->updateValues(*roles); - } -} - -void ListModel::set(int elementIndex, v8::Handle object, QV8Engine *eng) -{ - ListElement *e = elements[elementIndex]; - - v8::Local propertyNames = object->GetPropertyNames(); - int propertyCount = propertyNames->Length(); - - for (int i=0 ; i < propertyCount ; ++i) { - v8::Local propertyName = propertyNames->Get(i)->ToString(); - v8::Local propertyValue = object->Get(propertyName); - - // Add the value now - if (propertyValue->IsString()) { - const ListLayout::Role &r = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::String); - if (r.type == ListLayout::Role::String) { - v8::Handle jsString = propertyValue->ToString(); - QString qstr; - qstr.resize(jsString->Length()); - jsString->Write(reinterpret_cast(qstr.data())); - e->setStringPropertyFast(r, qstr); - } - } else if (propertyValue->IsNumber()) { - const ListLayout::Role &r = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::Number); - if (r.type == ListLayout::Role::Number) { - e->setDoublePropertyFast(r, propertyValue->NumberValue()); - } - } else if (propertyValue->IsArray()) { - const ListLayout::Role &r = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::List); - if (r.type == ListLayout::Role::List) { - ListModel *subModel = new ListModel(r.subLayout, 0, -1); - - v8::Handle subArray = v8::Handle::Cast(propertyValue); - int arrayLength = subArray->Length(); - for (int j=0 ; j < arrayLength ; ++j) { - v8::Handle subObject = subArray->Get(j)->ToObject(); - subModel->append(subObject, eng); - } - - e->setListPropertyFast(r, subModel); - } - } else if (propertyValue->IsBoolean()) { - const ListLayout::Role &r = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::Bool); - if (r.type == ListLayout::Role::Bool) { - e->setBoolPropertyFast(r, propertyValue->BooleanValue()); - } - } else if (propertyValue->IsObject()) { - QV8ObjectResource *r = (QV8ObjectResource *) propertyValue->ToObject()->GetExternalResource(); - if (r && r->resourceType() == QV8ObjectResource::QObjectType) { - QObject *o = QV8QObjectWrapper::toQObject(r); - 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); - if (r) - e->clearProperty(*r); - } - } -} - -void ListModel::clear() -{ - int elementCount = elements.count(); - for (int i=0 ; i < elementCount ; ++i) { - elements[i]->destroy(m_layout); - delete elements[i]; - } - elements.clear(); -} - -void ListModel::remove(int index, int count) -{ - for (int i=0 ; i < count ; ++i) { - elements[index+i]->destroy(m_layout); - delete elements[index+i]; - } - elements.remove(index, count); - updateCacheIndices(); -} - -void ListModel::insert(int elementIndex, v8::Handle object, QV8Engine *eng) -{ - insertElement(elementIndex); - set(elementIndex, object, eng); -} - -int ListModel::append(v8::Handle object, QV8Engine *eng) -{ - int elementIndex = appendElement(); - set(elementIndex, object, eng); - return elementIndex; -} - -int ListModel::setOrCreateProperty(int elementIndex, const QString &key, const QVariant &data) -{ - int roleIndex = -1; - - if (elementIndex >= 0 && elementIndex < elements.count()) { - ListElement *e = elements[elementIndex]; - const ListLayout::Role *r = m_layout->getRoleOrCreate(key, data); - if (r) { - roleIndex = e->setVariantProperty(*r, data); - - if (roleIndex != -1 && e->m_objectCache) { - QList roles; - roles << roleIndex; - e->m_objectCache->updateValues(roles); - } - } - } - - return roleIndex; -} - -int ListModel::setExistingProperty(int elementIndex, const QString &key, v8::Handle data, QV8Engine *eng) -{ - int roleIndex = -1; - - if (elementIndex >= 0 && elementIndex < elements.count()) { - ListElement *e = elements[elementIndex]; - const ListLayout::Role *r = m_layout->getExistingRole(key); - if (r) - roleIndex = e->setJsProperty(*r, data, eng); - } - - return roleIndex; -} - -inline char *ListElement::getPropertyMemory(const ListLayout::Role &role) -{ - ListElement *e = this; - int blockIndex = 0; - while (blockIndex < role.blockIndex) { - if (e->next == 0) { - e->next = new ListElement; - e->next->uid = uid; - } - e = e->next; - ++blockIndex; - } - - char *mem = &e->data[role.blockOffset]; - return mem; -} - -QString *ListElement::getStringProperty(const ListLayout::Role &role) -{ - char *mem = getPropertyMemory(role); - QString *s = reinterpret_cast(mem); - return s->data_ptr() ? s : 0; -} - -QObject *ListElement::getQObjectProperty(const ListLayout::Role &role) -{ - char *mem = getPropertyMemory(role); - QDeclarativeGuard *o = reinterpret_cast *>(mem); - 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); - - bool existingGuard = false; - for (size_t i=0 ; i < sizeof(QDeclarativeGuard) ; ++i) { - if (mem[i] != 0) { - existingGuard = true; - break; - } - } - - QDeclarativeGuard *o = 0; - - if (existingGuard) - o = reinterpret_cast *>(mem); - - return o; -} - -ListModel *ListElement::getListProperty(const ListLayout::Role &role) -{ - char *mem = getPropertyMemory(role); - ListModel **value = reinterpret_cast(mem); - return *value; -} - -QVariant ListElement::getProperty(const ListLayout::Role &role, const QDeclarativeListModel *owner, QV8Engine *eng) -{ - char *mem = getPropertyMemory(role); - - QVariant data; - - switch (role.type) { - case ListLayout::Role::Number: - { - double *value = reinterpret_cast(mem); - data = *value; - } - break; - case ListLayout::Role::String: - { - QString *value = reinterpret_cast(mem); - if (value->data_ptr() != 0) - data = *value; - } - break; - case ListLayout::Role::Bool: - { - bool *value = reinterpret_cast(mem); - data = *value; - } - break; - case ListLayout::Role::List: - { - ListModel **value = reinterpret_cast(mem); - ListModel *model = *value; - - if (model) { - if (model->m_modelCache == 0) { - model->m_modelCache = new QDeclarativeListModel(owner, model, eng); - QDeclarativeEngine::setContextForObject(model->m_modelCache, QDeclarativeEngine::contextForObject(owner)); - } - - QObject *object = model->m_modelCache; - data = QVariant::fromValue(object); - } - } - break; - case ListLayout::Role::QObject: - { - QDeclarativeGuard *guard = reinterpret_cast *>(mem); - QObject *object = guard->data(); - if (object) - data = QVariant::fromValue(object); - } - break; - case ListLayout::Role::VariantMap: - { - if (isMemoryUsed(mem)) { - QVariantMap *map = reinterpret_cast(mem); - data = *map; - } - } - break; - default: - break; - } - - return data; -} - -int ListElement::setStringProperty(const ListLayout::Role &role, const QString &s) -{ - int roleIndex = -1; - - if (role.type == ListLayout::Role::String) { - char *mem = getPropertyMemory(role); - QString *c = reinterpret_cast(mem); - bool changed; - if (c->data_ptr() == 0) { - new (mem) QString(s); - changed = true; - } else { - changed = c->compare(s) != 0; - *c = s; - } - if (changed) - roleIndex = role.index; - } - - return roleIndex; -} - -int ListElement::setDoubleProperty(const ListLayout::Role &role, double d) -{ - int roleIndex = -1; - - if (role.type == ListLayout::Role::Number) { - char *mem = getPropertyMemory(role); - double *value = new (mem) double; - bool changed = *value != d; - *value = d; - if (changed) - roleIndex = role.index; - } - - return roleIndex; -} - -int ListElement::setBoolProperty(const ListLayout::Role &role, bool b) -{ - int roleIndex = -1; - - if (role.type == ListLayout::Role::Bool) { - char *mem = getPropertyMemory(role); - bool *value = new (mem) bool; - bool changed = *value != b; - *value = b; - if (changed) - roleIndex = role.index; - } - - return roleIndex; -} - -int ListElement::setListProperty(const ListLayout::Role &role, ListModel *m) -{ - int roleIndex = -1; - - if (role.type == ListLayout::Role::List) { - char *mem = getPropertyMemory(role); - ListModel **value = new (mem) ListModel *; - if (*value) { - (*value)->destroy(); - delete *value; - } - *value = m; - roleIndex = role.index; - } - - return roleIndex; -} - -int ListElement::setQObjectProperty(const ListLayout::Role &role, QObject *o) -{ - int roleIndex = -1; - - if (role.type == ListLayout::Role::QObject) { - char *mem = getPropertyMemory(role); - QDeclarativeGuard *g = reinterpret_cast *>(mem); - bool existingGuard = false; - for (size_t i=0 ; i < sizeof(QDeclarativeGuard) ; ++i) { - if (mem[i] != 0) { - existingGuard = true; - break; - } - } - bool changed; - if (existingGuard) { - changed = g->data() != o; - g->~QDeclarativeGuard(); - } else { - changed = true; - } - new (mem) QDeclarativeGuard(o); - if (changed) - roleIndex = role.index; - } - - 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); - new (mem) QString(s); -} - -void ListElement::setDoublePropertyFast(const ListLayout::Role &role, double d) -{ - char *mem = getPropertyMemory(role); - double *value = new (mem) double; - *value = d; -} - -void ListElement::setBoolPropertyFast(const ListLayout::Role &role, bool b) -{ - char *mem = getPropertyMemory(role); - bool *value = new (mem) bool; - *value = b; -} - -void ListElement::setQObjectPropertyFast(const ListLayout::Role &role, QObject *o) -{ - char *mem = getPropertyMemory(role); - new (mem) QDeclarativeGuard(o); -} - -void ListElement::setListPropertyFast(const ListLayout::Role &role, ListModel *m) -{ - char *mem = getPropertyMemory(role); - ListModel **value = new (mem) ListModel *; - *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) { - case ListLayout::Role::String: - setStringProperty(role, QString()); - break; - case ListLayout::Role::Number: - setDoubleProperty(role, 0.0); - break; - case ListLayout::Role::Bool: - setBoolProperty(role, false); - break; - case ListLayout::Role::List: - setListProperty(role, 0); - break; - case ListLayout::Role::QObject: - setQObjectProperty(role, 0); - break; - case ListLayout::Role::VariantMap: - setVariantMapProperty(role, 0); - break; - default: - break; - } -} - -ListElement::ListElement() -{ - m_objectCache = 0; - uid = ListModel::allocateUid(); - next = 0; - qMemSet(data, 0, sizeof(data)); -} - -ListElement::ListElement(int existingUid) -{ - m_objectCache = 0; - uid = existingUid; - next = 0; - qMemSet(data, 0, sizeof(data)); -} - -ListElement::~ListElement() -{ - delete next; -} - -void ListElement::sync(ListElement *src, ListLayout *srcLayout, ListElement *target, ListLayout *targetLayout, QHash *targetModelHash) -{ - for (int i=0 ; i < srcLayout->roleCount() ; ++i) { - const ListLayout::Role &srcRole = srcLayout->getExistingRole(i); - const ListLayout::Role &targetRole = targetLayout->getExistingRole(i); - - switch (srcRole.type) { - case ListLayout::Role::List: - { - ListModel *srcSubModel = src->getListProperty(srcRole); - ListModel *targetSubModel = target->getListProperty(targetRole); - - if (srcSubModel) { - if (targetSubModel == 0) { - targetSubModel = new ListModel(targetRole.subLayout, 0, srcSubModel->getUid()); - target->setListPropertyFast(targetRole, targetSubModel); - } - ListModel::sync(srcSubModel, targetSubModel, targetModelHash); - } - } - break; - case ListLayout::Role::QObject: - { - QObject *object = src->getQObjectProperty(srcRole); - target->setQObjectProperty(targetRole, object); - } - break; - case ListLayout::Role::String: - case ListLayout::Role::Number: - case ListLayout::Role::Bool: - { - 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; - } - } - -} - -void ListElement::destroy(ListLayout *layout) -{ - if (layout) { - for (int i=0 ; i < layout->roleCount() ; ++i) { - const ListLayout::Role &r = layout->getExistingRole(i); - - switch (r.type) { - case ListLayout::Role::String: - { - QString *string = getStringProperty(r); - if (string) - string->~QString(); - } - break; - case ListLayout::Role::List: - { - ListModel *model = getListProperty(r); - if (model) { - model->destroy(); - delete model; - } - } - break; - case ListLayout::Role::QObject: - { - QDeclarativeGuard *guard = getGuardProperty(r); - if (guard) - 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; - } - } - - delete m_objectCache; - } - - if (next) - next->destroy(0); - uid = -1; -} - -int ListElement::setVariantProperty(const ListLayout::Role &role, const QVariant &d) -{ - int roleIndex = -1; - - switch (role.type) { - case ListLayout::Role::Number: - roleIndex = setDoubleProperty(role, d.toDouble()); - break; - case ListLayout::Role::String: - roleIndex = setStringProperty(role, d.toString()); - break; - case ListLayout::Role::Bool: - roleIndex = setBoolProperty(role, d.toBool()); - break; - case ListLayout::Role::List: - roleIndex = setListProperty(role, d.value()); - break; - default: - break; - } - - return roleIndex; -} - -int ListElement::setJsProperty(const ListLayout::Role &role, v8::Handle d, QV8Engine *eng) -{ - // Check if this key exists yet - int roleIndex = -1; - - // Add the value now - if (d->IsString()) { - v8::Handle jsString = d->ToString(); - QString qstr; - qstr.resize(jsString->Length()); - jsString->Write(reinterpret_cast(qstr.data())); - roleIndex = setStringProperty(role, qstr); - } else if (d->IsNumber()) { - roleIndex = setDoubleProperty(role, d->NumberValue()); - } else if (d->IsArray()) { - ListModel *subModel = new ListModel(role.subLayout, 0, -1); - v8::Handle subArray = v8::Handle::Cast(d); - int arrayLength = subArray->Length(); - for (int j=0 ; j < arrayLength ; ++j) { - v8::Handle subObject = subArray->Get(j)->ToObject(); - subModel->append(subObject, eng); - } - roleIndex = setListProperty(role, subModel); - } else if (d->IsBoolean()) { - roleIndex = setBoolProperty(role, d->BooleanValue()); - } else if (d->IsObject()) { - QV8ObjectResource *r = (QV8ObjectResource *) d->ToObject()->GetExternalResource(); - if (role.type == ListLayout::Role::QObject && r && r->resourceType() == 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); - } - - return roleIndex; -} - -ModelObject::ModelObject(QDeclarativeListModel *model, int elementIndex) -: m_model(model), m_elementIndex(elementIndex), m_meta(new ModelNodeMetaObject(this)) -{ - updateValues(); - setNodeUpdatesEnabled(true); -} - -void ModelObject::updateValues() -{ - int roleCount = m_model->m_listModel->roleCount(); - for (int i=0 ; i < roleCount ; ++i) { - const ListLayout::Role &role = m_model->m_listModel->getExistingRole(i); - QByteArray name = role.name.toUtf8(); - const QVariant &data = m_model->data(m_elementIndex, i); - setValue(name, data, role.type == ListLayout::Role::List); - } -} - -void ModelObject::updateValues(const QList &roles) -{ - int roleCount = roles.count(); - for (int i=0 ; i < roleCount ; ++i) { - int roleIndex = roles.at(i); - const ListLayout::Role &role = m_model->m_listModel->getExistingRole(roleIndex); - QByteArray name = role.name.toUtf8(); - const QVariant &data = m_model->data(m_elementIndex, roleIndex); - setValue(name, data, role.type == ListLayout::Role::List); - } -} - -ModelNodeMetaObject::ModelNodeMetaObject(ModelObject *object) -: QDeclarativeOpenMetaObject(object), m_enabled(false), m_obj(object) -{ -} - -ModelNodeMetaObject::~ModelNodeMetaObject() -{ -} - -void ModelNodeMetaObject::propertyWritten(int index) -{ - if (!m_enabled) - return; - - QV8Engine *eng = m_obj->m_model->engine(); - - QString propName = QString::fromUtf8(name(index)); - QVariant value = operator[](index); - - v8::HandleScope handle_scope; - v8::Context::Scope scope(eng->context()); - - v8::Handle v = eng->fromVariant(value); - - int roleIndex = m_obj->m_model->m_listModel->setExistingProperty(m_obj->m_elementIndex, propName, v, eng); - if (roleIndex != -1) { - QList roles; - roles << roleIndex; - m_obj->m_model->emitItemsChanged(m_obj->m_elementIndex, 1, roles); - } -} - -QDeclarativeListModelParser::ListInstruction *QDeclarativeListModelParser::ListModelData::instructions() const -{ - return (QDeclarativeListModelParser::ListInstruction *)((char *)this + sizeof(ListModelData)); -} - -/*! - \qmlclass ListModel QDeclarativeListModel - \inqmlmodule QtQuick 2 - \ingroup qml-working-with-data - \brief The ListModel element defines a free-form list data source. - - The ListModel is a simple container of ListElement definitions, each containing data roles. - The contents can be defined dynamically, or explicitly in QML. - - The number of elements in the model can be obtained from its \l count property. - A number of familiar methods are also provided to manipulate the contents of the - model, including append(), insert(), move(), remove() and set(). These methods - accept dictionaries as their arguments; these are translated to ListElement objects - by the model. - - Elements can be manipulated via the model using the setProperty() method, which - allows the roles of the specified element to be set and changed. - - \section1 Example Usage - - The following example shows a ListModel containing three elements, with the roles - "name" and "cost". - - \div {class="float-right"} - \inlineimage listmodel.png - \enddiv - - \snippet doc/src/snippets/declarative/listmodel.qml 0 - - \clearfloat - Roles (properties) in each element must begin with a lower-case letter and - should be common to all elements in a model. The ListElement documentation - provides more guidelines for how elements should be defined. - - Since the example model contains an \c id property, it can be referenced - by views, such as the ListView in this example: - - \snippet doc/src/snippets/declarative/listmodel-simple.qml 0 - \dots 8 - \snippet doc/src/snippets/declarative/listmodel-simple.qml 1 - - It is possible for roles to contain list data. In the following example we - create a list of fruit attributes: - - \snippet doc/src/snippets/declarative/listmodel-nested.qml model - - The delegate displays all the fruit attributes: - - \div {class="float-right"} - \inlineimage listmodel-nested.png - \enddiv - - \snippet doc/src/snippets/declarative/listmodel-nested.qml delegate - - \clearfloat - \section1 Modifying List Models - - The content of a ListModel may be created and modified using the clear(), - append(), set(), insert() and setProperty() methods. For example: - - \snippet doc/src/snippets/declarative/listmodel-modify.qml delegate - - Note that when creating content dynamically the set of available properties - cannot be changed once set. Whatever properties are first added to the model - are the only permitted properties in the model. - - \section1 Using Threaded List Models with WorkerScript - - ListModel can be used together with WorkerScript access a list model - from multiple threads. This is useful if list modifications are - synchronous and take some time: the list operations can be moved to a - different thread to avoid blocking of the main GUI thread. - - Here is an example that uses WorkerScript to periodically append the - current time to a list model: - - \snippet examples/declarative/threading/threadedlistmodel/timedisplay.qml 0 - - The included file, \tt dataloader.js, looks like this: - - \snippet examples/declarative/threading/threadedlistmodel/dataloader.js 0 - - The timer in the main example sends messages to the worker script by calling - \l WorkerScript::sendMessage(). When this message is received, - \l{WorkerScript::onMessage}{WorkerScript.onMessage()} is invoked in \c dataloader.js, - which appends the current time to the list model. - - Note the call to sync() from the \l{WorkerScript::onMessage}{WorkerScript.onMessage()} - handler. You must call sync() or else the changes made to the list from the external - thread will not be reflected in the list model in the main thread. - - \sa {qmlmodels}{Data Models}, {declarative/threading/threadedlistmodel}{Threaded ListModel example}, QtDeclarative -*/ - -QDeclarativeListModel::QDeclarativeListModel(QObject *parent) -: QListModelInterface(parent) -{ - m_mainThread = true; - m_primary = true; - m_agent = 0; - - m_layout = new ListLayout; - m_listModel = new ListModel(m_layout, this, -1); - - m_engine = 0; -} - -QDeclarativeListModel::QDeclarativeListModel(const QDeclarativeListModel *owner, ListModel *data, QV8Engine *eng, QObject *parent) -: QListModelInterface(parent) -{ - m_mainThread = owner->m_mainThread; - m_primary = false; - m_agent = owner->m_agent; - - m_layout = 0; - m_listModel = data; - - m_engine = eng; -} - -QDeclarativeListModel::QDeclarativeListModel(QDeclarativeListModel *orig, QDeclarativeListModelWorkerAgent *agent) -: QListModelInterface(agent) -{ - m_mainThread = false; - m_primary = true; - m_agent = agent; - - m_layout = new ListLayout(orig->m_layout); - m_listModel = new ListModel(m_layout, this, orig->m_listModel->getUid()); - ListModel::sync(orig->m_listModel, m_listModel, 0); - - m_engine = 0; -} - -QDeclarativeListModel::~QDeclarativeListModel() -{ - if (m_primary) { - m_listModel->destroy(); - delete m_listModel; - - if (m_mainThread && m_agent) - m_agent->release(); - } - - m_listModel = 0; - - delete m_layout; - m_layout = 0; -} - -QV8Engine *QDeclarativeListModel::engine() const -{ - if (m_engine == 0) { - m_engine = QDeclarativeEnginePrivate::getV8Engine(qmlEngine(this)); - } - - return m_engine; -} - -void QDeclarativeListModel::emitItemsChanged(int index, int count, const QList &roles) -{ - if (m_mainThread) { - emit itemsChanged(index, count, roles); - } else { - m_agent->data.changedChange(this, index, count, roles); - } -} - -void QDeclarativeListModel::emitItemsRemoved(int index, int count) -{ - if (m_mainThread) { - emit itemsRemoved(index, count); - emit countChanged(); - } else { - if (index == 0 && count == this->count()) - m_agent->data.clearChange(this); - m_agent->data.removeChange(this, index, count); - } -} - -void QDeclarativeListModel::emitItemsInserted(int index, int count) -{ - if (m_mainThread) { - emit itemsInserted(index, count); - emit countChanged(); - } else { - m_agent->data.insertChange(this, index, count); - } -} - -void QDeclarativeListModel::emitItemsMoved(int from, int to, int n) -{ - if (m_mainThread) { - emit itemsMoved(from, to, n); - } else { - m_agent->data.moveChange(this, from, n, to); - } -} - -QDeclarativeListModelWorkerAgent *QDeclarativeListModel::agent() -{ - if (m_agent) - return m_agent; - - m_agent = new QDeclarativeListModelWorkerAgent(this); - return m_agent; -} - -QList QDeclarativeListModel::roles() const -{ - QList rolesArray; - - for (int i=0 ; i < m_listModel->roleCount() ; ++i) - rolesArray << i; - - return rolesArray; -} - -QString QDeclarativeListModel::toString(int role) const -{ - const ListLayout::Role &r = m_listModel->getExistingRole(role); - return r.name; -} - -QVariant QDeclarativeListModel::data(int index, int role) const -{ - if (index >= count() || index < 0) - return QVariant(); - - return m_listModel->getProperty(index, role, this, engine()); -} - -/*! - \qmlproperty int QtQuick2::ListModel::count - The number of data entries in the model. -*/ -int QDeclarativeListModel::count() const -{ - return m_listModel->elementCount(); -} - -/*! - \qmlmethod QtQuick2::ListModel::clear() - - Deletes all content from the model. - - \sa append() remove() -*/ -void QDeclarativeListModel::clear() -{ - int cleared = count(); - - m_listModel->clear(); - emitItemsRemoved(0, cleared); -} - -/*! - \qmlmethod QtQuick2::ListModel::remove(int index, int count = 1) - - Deletes the content at \a index from the model. - - \sa clear() -*/ -void QDeclarativeListModel::remove(QDeclarativeV8Function *args) -{ - int argLength = args->Length(); - - if (argLength == 1 || argLength == 2) { - int index = (*args)[0]->Int32Value(); - int removeCount = (argLength == 2 ? ((*args)[1]->Int32Value()) : 1); - - if (index < 0 || index+removeCount > count() || removeCount <= 0) { - qmlInfo(this) << tr("remove: indices [%1 - %2] out of range [0 - %3]").arg(index).arg(index+removeCount).arg(count()); - return; - } - - m_listModel->remove(index, removeCount); - emitItemsRemoved(index, removeCount); - } else { - qmlInfo(this) << tr("remove: incorrect number of arguments"); - } -} - -/*! - \qmlmethod QtQuick2::ListModel::insert(int index, jsobject dict) - - Adds a new item to the list model at position \a index, with the - values in \a dict. - - \code - fruitModel.insert(2, {"cost": 5.95, "name":"Pizza"}) - \endcode - - The \a index must be to an existing item in the list, or one past - the end of the list (equivalent to append). - - \sa set() append() -*/ - -void QDeclarativeListModel::insert(QDeclarativeV8Function *args) -{ - if (args->Length() == 2) { - - v8::Handle arg0 = (*args)[0]; - int index = arg0->Int32Value(); - - if (index < 0 || index > count()) { - qmlInfo(this) << tr("insert: index %1 out of range").arg(index); - return; - } - - v8::Handle arg1 = (*args)[1]; - - if (arg1->IsArray()) { - v8::Handle objectArray = v8::Handle::Cast(arg1); - int objectArrayLength = objectArray->Length(); - for (int i=0 ; i < objectArrayLength ; ++i) { - v8::Handle argObject = objectArray->Get(i)->ToObject(); - 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, args->engine()); - emitItemsInserted(index, 1); - } else { - qmlInfo(this) << tr("insert: value is not an object"); - } - } else { - qmlInfo(this) << tr("insert: value is not an object"); - } -} - -/*! - \qmlmethod QtQuick2::ListModel::move(int from, int to, int n) - - Moves \a n items \a from one position \a to another. - - The from and to ranges must exist; for example, to move the first 3 items - to the end of the list: - - \code - fruitModel.move(0, fruitModel.count - 3, 3) - \endcode - - \sa append() -*/ -void QDeclarativeListModel::move(int from, int to, int n) -{ - if (n==0 || from==to) - return; - if (!canMove(from, to, n)) { - qmlInfo(this) << tr("move: out of range"); - return; - } - - m_listModel->move(from, to, n); - emitItemsMoved(from, to, n); -} - -/*! - \qmlmethod QtQuick2::ListModel::append(jsobject dict) - - Adds a new item to the end of the list model, with the - values in \a dict. - - \code - fruitModel.append({"cost": 5.95, "name":"Pizza"}) - \endcode - - \sa set() remove() -*/ -void QDeclarativeListModel::append(QDeclarativeV8Function *args) -{ - if (args->Length() == 1) { - v8::Handle arg = (*args)[0]; - - if (arg->IsArray()) { - v8::Handle objectArray = v8::Handle::Cast(arg); - int objectArrayLength = objectArray->Length(); - int index = m_listModel->elementCount(); - for (int i=0 ; i < objectArrayLength ; ++i) { - v8::Handle argObject = objectArray->Get(i)->ToObject(); - m_listModel->append(argObject, args->engine()); - } - emitItemsInserted(index, objectArrayLength); - } else if (arg->IsObject()) { - v8::Handle argObject = arg->ToObject(); - - int index = m_listModel->append(argObject, args->engine()); - emitItemsInserted(index, 1); - - } else { - qmlInfo(this) << tr("append: value is not an object"); - } - } else { - qmlInfo(this) << tr("append: value is not an object"); - } -} - -/*! - \qmlmethod object QtQuick2::ListModel::get(int index) - - Returns the item at \a index in the list model. This allows the item - data to be accessed or modified from JavaScript: - - \code - Component.onCompleted: { - fruitModel.append({"cost": 5.95, "name":"Jackfruit"}); - console.log(fruitModel.get(0).cost); - fruitModel.get(0).cost = 10.95; - } - \endcode - - The \a index must be an element in the list. - - Note that properties of the returned object that are themselves objects - will also be models, and this get() method is used to access elements: - - \code - fruitModel.append(..., "attributes": - [{"name":"spikes","value":"7mm"}, - {"name":"color","value":"green"}]); - fruitModel.get(0).attributes.get(1).value; // == "green" - \endcode - - \warning The returned object is not guaranteed to remain valid. It - should not be used in \l{Property Binding}{property bindings}. - - \sa append() -*/ -QDeclarativeV8Handle QDeclarativeListModel::get(int index) const -{ - v8::Handle result = v8::Undefined(); - - if (index >= 0 && index < m_listModel->elementCount()) { - QV8Engine *v8engine = engine(); - - ModelObject *object = m_listModel->getOrCreateModelObject(const_cast(this), index); - result = v8engine->newQObject(object); - } - - return QDeclarativeV8Handle::fromHandle(result); -} - -/*! - \qmlmethod QtQuick2::ListModel::set(int index, jsobject dict) - - Changes the item at \a index in the list model with the - values in \a dict. Properties not appearing in \a dict - are left unchanged. - - \code - fruitModel.set(3, {"cost": 5.95, "name":"Pizza"}) - \endcode - - If \a index is equal to count() then a new item is appended to the - list. Otherwise, \a index must be an element in the list. - - \sa append() -*/ -void QDeclarativeListModel::set(int index, const QDeclarativeV8Handle &handle) -{ - v8::Handle valuemap = handle.toHandle(); - - if (!valuemap->IsObject() || valuemap->IsArray()) { - qmlInfo(this) << tr("set: value is not an object"); - return; - } - if (index > count() || index < 0) { - qmlInfo(this) << tr("set: index %1 out of range").arg(index); - return; - } - - v8::Handle object = valuemap->ToObject(); - - if (index == count()) { - m_listModel->insert(index, object, engine()); - emitItemsInserted(index, 1); - } else { - - QList roles; - m_listModel->set(index, object, &roles, engine()); - - if (roles.count()) - emitItemsChanged(index, 1, roles); - } -} - -/*! - \qmlmethod QtQuick2::ListModel::setProperty(int index, string property, variant value) - - Changes the \a property of the item at \a index in the list model to \a value. - - \code - fruitModel.setProperty(3, "cost", 5.95) - \endcode - - The \a index must be an element in the list. - - \sa append() -*/ -void QDeclarativeListModel::setProperty(int index, const QString& property, const QVariant& value) -{ - if (count() == 0 || index >= count() || index < 0) { - qmlInfo(this) << tr("set: index %1 out of range").arg(index); - return; - } - - int roleIndex = m_listModel->setOrCreateProperty(index, property, value); - if (roleIndex != -1) { - - QList roles; - roles << roleIndex; - - emitItemsChanged(index, 1, roles); - } -} - -/*! - \qmlmethod QtQuick2::ListModel::sync() - - Writes any unsaved changes to the list model after it has been modified - from a worker script. -*/ -void QDeclarativeListModel::sync() -{ - // This is just a dummy method to make it look like sync() exists in - // ListModel (and not just QDeclarativeListModelWorkerAgent) and to let - // us document sync(). - qmlInfo(this) << "List sync() can only be called from a WorkerScript"; -} - -bool QDeclarativeListModelParser::compileProperty(const QDeclarativeCustomParserProperty &prop, QList &instr, QByteArray &data) -{ - QList values = prop.assignedValues(); - for(int ii = 0; ii < values.count(); ++ii) { - const QVariant &value = values.at(ii); - - if(value.userType() == qMetaTypeId()) { - QDeclarativeCustomParserNode node = - qvariant_cast(value); - - if (node.name() != listElementTypeName) { - const QMetaObject *mo = resolveType(node.name()); - if (mo != &QDeclarativeListElement::staticMetaObject) { - error(node, QDeclarativeListModel::tr("ListElement: cannot contain nested elements")); - return false; - } - listElementTypeName = node.name(); // cache right name for next time - } - - { - ListInstruction li; - li.type = ListInstruction::Push; - li.dataIdx = -1; - instr << li; - } - - QList props = node.properties(); - for(int jj = 0; jj < props.count(); ++jj) { - const QDeclarativeCustomParserProperty &nodeProp = props.at(jj); - if (nodeProp.name().isEmpty()) { - error(nodeProp, QDeclarativeListModel::tr("ListElement: cannot contain nested elements")); - return false; - } - if (nodeProp.name() == QStringLiteral("id")) { - error(nodeProp, QDeclarativeListModel::tr("ListElement: cannot use reserved \"id\" property")); - return false; - } - - ListInstruction li; - int ref = data.count(); - data.append(nodeProp.name().toUtf8()); - data.append('\0'); - li.type = ListInstruction::Set; - li.dataIdx = ref; - instr << li; - - if(!compileProperty(nodeProp, instr, data)) - return false; - - li.type = ListInstruction::Pop; - li.dataIdx = -1; - instr << li; - } - - { - ListInstruction li; - li.type = ListInstruction::Pop; - li.dataIdx = -1; - instr << li; - } - - } else { - - QDeclarativeScript::Variant variant = - qvariant_cast(value); - - int ref = data.count(); - - QByteArray d; - d += char(variant.type()); // type tag - if (variant.isString()) { - d += variant.asString().toUtf8(); - } else if (variant.isNumber()) { - d += QByteArray::number(variant.asNumber(),'g',20); - } else if (variant.isBoolean()) { - d += char(variant.asBoolean()); - } else if (variant.isScript()) { - if (definesEmptyList(variant.asScript())) { - d[0] = char(QDeclarativeScript::Variant::Invalid); // marks empty list - } else { - QByteArray script = variant.asScript().toUtf8(); - int v = evaluateEnum(script); - if (v<0) { - using namespace QDeclarativeJS; - AST::Node *node = variant.asAST(); - AST::StringLiteral *literal = 0; - if (AST::CallExpression *callExpr = AST::cast(node)) { - if (AST::IdentifierExpression *idExpr = AST::cast(callExpr->base)) { - if (idExpr->name == QLatin1String("QT_TR_NOOP") || idExpr->name == QLatin1String("QT_TRID_NOOP")) { - if (callExpr->arguments && !callExpr->arguments->next) - literal = AST::cast(callExpr->arguments->expression); - if (!literal) { - error(prop, QDeclarativeListModel::tr("ListElement: improperly specified %1").arg(idExpr->name.toString())); - return false; - } - } else if (idExpr->name == QLatin1String("QT_TRANSLATE_NOOP")) { - if (callExpr->arguments && callExpr->arguments->next && !callExpr->arguments->next->next) - literal = AST::cast(callExpr->arguments->next->expression); - if (!literal) { - error(prop, QDeclarativeListModel::tr("ListElement: improperly specified QT_TRANSLATE_NOOP")); - return false; - } - } - } - } - - if (literal) { - d[0] = char(QDeclarativeScript::Variant::String); - d += literal->value.toUtf8(); - } else { - error(prop, QDeclarativeListModel::tr("ListElement: cannot use script for property value")); - return false; - } - } else { - d[0] = char(QDeclarativeScript::Variant::Number); - d += QByteArray::number(v); - } - } - } - d.append('\0'); - data.append(d); - - ListInstruction li; - li.type = ListInstruction::Value; - li.dataIdx = ref; - instr << li; - } - } - - return true; -} - -QByteArray QDeclarativeListModelParser::compile(const QList &customProps) -{ - QList instr; - QByteArray data; - listElementTypeName = QString(); // unknown - - for(int ii = 0; ii < customProps.count(); ++ii) { - const QDeclarativeCustomParserProperty &prop = customProps.at(ii); - if(!prop.name().isEmpty()) { // isn't default property - error(prop, QDeclarativeListModel::tr("ListModel: undefined property '%1'").arg(prop.name())); - return QByteArray(); - } - - if(!compileProperty(prop, instr, data)) { - return QByteArray(); - } - } - - int size = sizeof(ListModelData) + - instr.count() * sizeof(ListInstruction) + - data.count(); - - QByteArray rv; - rv.resize(size); - - ListModelData *lmd = (ListModelData *)rv.data(); - lmd->dataOffset = sizeof(ListModelData) + - instr.count() * sizeof(ListInstruction); - lmd->instrCount = instr.count(); - for (int ii = 0; ii < instr.count(); ++ii) - lmd->instructions()[ii] = instr.at(ii); - ::memcpy(rv.data() + lmd->dataOffset, data.constData(), data.count()); - - return rv; -} - -void QDeclarativeListModelParser::setCustomData(QObject *obj, const QByteArray &d) -{ - QDeclarativeListModel *rv = static_cast(obj); - - QV8Engine *engine = QDeclarativeEnginePrivate::getV8Engine(qmlEngine(rv)); - rv->m_engine = engine; - - const ListModelData *lmd = (const ListModelData *)d.constData(); - const char *data = ((const char *)lmd) + lmd->dataOffset; - - QStack stack; - - for (int ii = 0; ii < lmd->instrCount; ++ii) { - const ListInstruction &instr = lmd->instructions()[ii]; - - switch(instr.type) { - case ListInstruction::Push: - { - ListModel *subModel = 0; - - if (stack.count() == 0) { - subModel = rv->m_listModel; - } else { - const DataStackElement &e0 = stack.at(stack.size() - 1); - DataStackElement &e1 = stack[stack.size() - 2]; - - const ListLayout::Role &role = e1.model->getOrCreateListRole(e0.name); - if (role.type == ListLayout::Role::List) { - subModel = e1.model->getListProperty(e1.elementIndex, role); - - if (subModel == 0) { - subModel = new ListModel(role.subLayout, 0, -1); - QVariant vModel = QVariant::fromValue(subModel); - e1.model->setOrCreateProperty(e1.elementIndex, e0.name, vModel); - } - } - } - - DataStackElement e; - e.model = subModel; - e.elementIndex = subModel ? subModel->appendElement() : -1; - stack.push(e); - } - break; - - case ListInstruction::Pop: - stack.pop(); - break; - - case ListInstruction::Value: - { - const DataStackElement &e0 = stack.at(stack.size() - 1); - DataStackElement &e1 = stack[stack.size() - 2]; - - QString name = e0.name; - QVariant value; - - switch (QDeclarativeScript::Variant::Type(data[instr.dataIdx])) { - case QDeclarativeScript::Variant::Invalid: - { - const ListLayout::Role &role = e1.model->getOrCreateListRole(e0.name); - ListModel *emptyModel = new ListModel(role.subLayout, 0, -1); - value = QVariant::fromValue(emptyModel); - } - break; - case QDeclarativeScript::Variant::Boolean: - value = bool(data[1 + instr.dataIdx]); - break; - case QDeclarativeScript::Variant::Number: - value = QByteArray(data + 1 + instr.dataIdx).toDouble(); - break; - case QDeclarativeScript::Variant::String: - value = QString::fromUtf8(data + 1 + instr.dataIdx); - break; - default: - Q_ASSERT("Format error in ListInstruction"); - } - - e1.model->setOrCreateProperty(e1.elementIndex, name, value); - } - break; - - case ListInstruction::Set: - { - DataStackElement e; - e.name = QString::fromUtf8(data + instr.dataIdx); - stack.push(e); - } - break; - } - } -} - -bool QDeclarativeListModelParser::definesEmptyList(const QString &s) -{ - if (s.startsWith(QLatin1Char('[')) && s.endsWith(QLatin1Char(']'))) { - for (int i=1; i -#include - -#include -#include -#include -#include -#include -#include - -#include -#include - -QT_BEGIN_HEADER - -QT_BEGIN_NAMESPACE - -QT_MODULE(Declarative) - -class QDeclarativeListModelWorkerAgent; -class ListModel; -class ListLayout; - -class Q_DECLARATIVE_PRIVATE_EXPORT QDeclarativeListModel : public QListModelInterface -{ - Q_OBJECT - Q_PROPERTY(int count READ count NOTIFY countChanged) - -public: - QDeclarativeListModel(QObject *parent=0); - ~QDeclarativeListModel(); - - virtual QList roles() const; - virtual QString toString(int role) const; - virtual int count() const; - virtual QVariant data(int index, int role) const; - - Q_INVOKABLE void clear(); - Q_INVOKABLE void remove(QDeclarativeV8Function *args); - Q_INVOKABLE void append(QDeclarativeV8Function *args); - Q_INVOKABLE void insert(QDeclarativeV8Function *args); - Q_INVOKABLE QDeclarativeV8Handle get(int index) const; - Q_INVOKABLE void set(int index, const QDeclarativeV8Handle &); - Q_INVOKABLE void setProperty(int index, const QString& property, const QVariant& value); - Q_INVOKABLE void move(int from, int to, int count); - Q_INVOKABLE void sync(); - - QDeclarativeListModelWorkerAgent *agent(); - -Q_SIGNALS: - void countChanged(); - -private: - friend class QDeclarativeListModelParser; - friend class QDeclarativeListModelWorkerAgent; - friend class ModelObject; - friend class ModelNodeMetaObject; - friend class ListModel; - friend class ListElement; - - // Constructs a flat list model for a worker agent - QDeclarativeListModel(QDeclarativeListModel *orig, QDeclarativeListModelWorkerAgent *agent); - QDeclarativeListModel(const QDeclarativeListModel *owner, ListModel *data, QV8Engine *eng, QObject *parent=0); - - QV8Engine *engine() const; - - inline bool canMove(int from, int to, int n) const { return !(from+n > count() || to+n > count() || from < 0 || to < 0 || n < 0); } - - ListLayout *m_layout; - ListModel *m_listModel; - - QDeclarativeListModelWorkerAgent *m_agent; - bool m_mainThread; - bool m_primary; - mutable QV8Engine *m_engine; - - void emitItemsChanged(int index, int count, const QList &roles); - void emitItemsRemoved(int index, int count); - void emitItemsInserted(int index, int count); - void emitItemsMoved(int from, int to, int n); -}; - -// ### FIXME -class QDeclarativeListElement : public QObject -{ -Q_OBJECT -}; - -class QDeclarativeListModelParser : public QDeclarativeCustomParser -{ -public: - QDeclarativeListModelParser() : QDeclarativeCustomParser(QDeclarativeCustomParser::AcceptsSignalHandlers) {} - QByteArray compile(const QList &); - void setCustomData(QObject *, const QByteArray &); - -private: - struct ListInstruction - { - enum { Push, Pop, Value, Set } type; - int dataIdx; - }; - struct ListModelData - { - int dataOffset; - int instrCount; - ListInstruction *instructions() const; - }; - bool compileProperty(const QDeclarativeCustomParserProperty &prop, QList &instr, QByteArray &data); - - bool definesEmptyList(const QString &); - - QString listElementTypeName; - - struct DataStackElement - { - DataStackElement() : model(0), elementIndex(0) {} - - QString name; - ListModel *model; - int elementIndex; - }; -}; - -QT_END_NAMESPACE - -QML_DECLARE_TYPE(QDeclarativeListModel) -QML_DECLARE_TYPE(QDeclarativeListElement) - -QT_END_HEADER - -#endif // QDECLARATIVELISTMODEL_H diff --git a/src/declarative/util/qdeclarativelistmodel_p_p.h b/src/declarative/util/qdeclarativelistmodel_p_p.h deleted file mode 100644 index ab6c2b25cc..0000000000 --- a/src/declarative/util/qdeclarativelistmodel_p_p.h +++ /dev/null @@ -1,325 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the QtDeclarative module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** This file may be used under the terms of the GNU Lesser General Public -** License version 2.1 as published by the Free Software Foundation and -** appearing in the file LICENSE.LGPL included in the packaging of this -** file. Please review the following information to ensure the GNU Lesser -** General Public License version 2.1 requirements will be met: -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QDECLARATIVELISTMODEL_P_P_H -#define QDECLARATIVELISTMODEL_P_P_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists purely as an -// implementation detail. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include "qdeclarativelistmodel_p.h" -#include -#include "qdeclarativeopenmetaobject_p.h" -#include - -QT_BEGIN_HEADER - -QT_BEGIN_NAMESPACE - -QT_MODULE(Declarative) - -class ModelObject; - -class ModelNodeMetaObject : public QDeclarativeOpenMetaObject -{ -public: - ModelNodeMetaObject(ModelObject *object); - ~ModelNodeMetaObject(); - - bool m_enabled; - -protected: - void propertyWritten(int index); - -private: - - ModelObject *m_obj; -}; - -class ModelObject : public QObject -{ - Q_OBJECT -public: - ModelObject(QDeclarativeListModel *model, int elementIndex); - - void setValue(const QByteArray &name, const QVariant &val, bool force) - { - if (force) { - QVariant existingValue = m_meta->value(name); - if (existingValue.isValid()) { - (*m_meta)[name] = QVariant(); - } - } - m_meta->setValue(name, val); - } - - void setNodeUpdatesEnabled(bool enable) - { - m_meta->m_enabled = enable; - } - - void updateValues(); - void updateValues(const QList &roles); - - QDeclarativeListModel *m_model; - int m_elementIndex; - -private: - ModelNodeMetaObject *m_meta; -}; - -class ListLayout -{ -public: - ListLayout() : currentBlock(0), currentBlockOffset(0) {} - ListLayout(const ListLayout *other); - ~ListLayout(); - - class Role - { - public: - - Role() : type(Invalid), blockIndex(-1), blockOffset(-1), index(-1), subLayout(0) {} - explicit Role(const Role *other); - ~Role(); - - // This enum must be kept in sync with the roleTypeNames variable in qdeclarativelistmodel.cpp - enum DataType - { - Invalid = -1, - - String, - Number, - Bool, - List, - QObject, - VariantMap, - - MaxDataType - }; - - QString name; - DataType type; - int blockIndex; - int blockOffset; - int index; - ListLayout *subLayout; - }; - - const Role *getRoleOrCreate(const QString &key, const QVariant &data); - const Role &getRoleOrCreate(v8::Handle key, Role::DataType type); - const Role &getRoleOrCreate(const QString &key, Role::DataType type); - - const Role &getExistingRole(int index) { return *roles.at(index); } - const Role *getExistingRole(const QString &key); - const Role *getExistingRole(v8::Handle key); - - int roleCount() const { return roles.count(); } - - static void sync(ListLayout *src, ListLayout *target); - -private: - const Role &createRole(const QString &key, Role::DataType type); - - int currentBlock; - int currentBlockOffset; - QVector roles; - QStringHash roleHash; -}; - -class ListElement -{ -public: - - ListElement(); - ListElement(int existingUid); - ~ListElement(); - - static void sync(ListElement *src, ListLayout *srcLayout, ListElement *target, ListLayout *targetLayout, QHash *targetModelHash); - - enum - { - BLOCK_SIZE = 64 - sizeof(int) - sizeof(ListElement *) - sizeof(ModelObject *) - }; - -private: - - void destroy(ListLayout *layout); - - int setVariantProperty(const ListLayout::Role &role, const QVariant &d); - - int setJsProperty(const ListLayout::Role &role, v8::Handle d, QV8Engine *eng); - - int setStringProperty(const ListLayout::Role &role, const QString &s); - int setDoubleProperty(const ListLayout::Role &role, double n); - int setBoolProperty(const ListLayout::Role &role, bool b); - int setListProperty(const ListLayout::Role &role, ListModel *m); - int setQObjectProperty(const ListLayout::Role &role, QObject *o); - int setVariantMapProperty(const ListLayout::Role &role, v8::Handle o, QV8Engine *eng); - int setVariantMapProperty(const ListLayout::Role &role, QVariantMap *m); - - void setStringPropertyFast(const ListLayout::Role &role, const QString &s); - void setDoublePropertyFast(const ListLayout::Role &role, double n); - void setBoolPropertyFast(const ListLayout::Role &role, bool b); - void setQObjectPropertyFast(const ListLayout::Role &role, QObject *o); - void setListPropertyFast(const ListLayout::Role &role, ListModel *m); - void setVariantMapFast(const ListLayout::Role &role, v8::Handle o, QV8Engine *eng); - - void clearProperty(const ListLayout::Role &role); - - QVariant getProperty(const ListLayout::Role &role, const QDeclarativeListModel *owner, QV8Engine *eng); - ListModel *getListProperty(const ListLayout::Role &role); - QString *getStringProperty(const ListLayout::Role &role); - QObject *getQObjectProperty(const ListLayout::Role &role); - QDeclarativeGuard *getGuardProperty(const ListLayout::Role &role); - QVariantMap *getVariantMapProperty(const ListLayout::Role &role); - - inline char *getPropertyMemory(const ListLayout::Role &role); - - int getUid() const { return uid; } - - char data[BLOCK_SIZE]; - ListElement *next; - - int uid; - ModelObject *m_objectCache; - - friend class ListModel; -}; - -class ListModel -{ -public: - - ListModel(ListLayout *layout, QDeclarativeListModel *modelCache, int uid); - ~ListModel() {} - - void destroy(); - - int setOrCreateProperty(int elementIndex, const QString &key, const QVariant &data); - int setExistingProperty(int uid, const QString &key, v8::Handle data, QV8Engine *eng); - - QVariant getProperty(int elementIndex, int roleIndex, const QDeclarativeListModel *owner, QV8Engine *eng); - ListModel *getListProperty(int elementIndex, const ListLayout::Role &role); - - int roleCount() const - { - return m_layout->roleCount(); - } - - const ListLayout::Role &getExistingRole(int index) - { - return m_layout->getExistingRole(index); - } - - const ListLayout::Role &getOrCreateListRole(const QString &name) - { - return m_layout->getRoleOrCreate(name, ListLayout::Role::List); - } - - int elementCount() const - { - return elements.count(); - } - - void set(int elementIndex, v8::Handle object, QList *roles, QV8Engine *eng); - void set(int elementIndex, v8::Handle object, QV8Engine *eng); - - int append(v8::Handle object, QV8Engine *eng); - void insert(int elementIndex, v8::Handle object, QV8Engine *eng); - - void clear(); - void remove(int index, int count); - - int appendElement(); - void insertElement(int index); - - void move(int from, int to, int n); - - int getUid() const { return m_uid; } - - static int allocateUid(); - - static void sync(ListModel *src, ListModel *target, QHash *srcModelHash); - - ModelObject *getOrCreateModelObject(QDeclarativeListModel *model, int elementIndex); - -private: - QPODVector elements; - ListLayout *m_layout; - int m_uid; - - QDeclarativeListModel *m_modelCache; - - struct ElementSync - { - ElementSync() : src(0), target(0) {} - - ListElement *src; - ListElement *target; - }; - - void newElement(int index); - - void updateCacheIndices(); - - friend class ListElement; - friend class QDeclarativeListModelWorkerAgent; - - static QAtomicInt uidCounter; -}; - -QT_END_NAMESPACE - -Q_DECLARE_METATYPE(ListModel *); - -QT_END_HEADER - -#endif // QDECLARATIVELISTMODEL_P_P_H - diff --git a/src/declarative/util/qdeclarativelistmodelworkeragent.cpp b/src/declarative/util/qdeclarativelistmodelworkeragent.cpp deleted file mode 100644 index c01025cd45..0000000000 --- a/src/declarative/util/qdeclarativelistmodelworkeragent.cpp +++ /dev/null @@ -1,221 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the QtDeclarative module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** This file may be used under the terms of the GNU Lesser General Public -** License version 2.1 as published by the Free Software Foundation and -** appearing in the file LICENSE.LGPL included in the packaging of this -** file. Please review the following information to ensure the GNU Lesser -** General Public License version 2.1 requirements will be met: -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qdeclarativelistmodelworkeragent_p.h" -#include "qdeclarativelistmodel_p_p.h" -#include -#include -#include - -#include -#include -#include - - -QT_BEGIN_NAMESPACE - - -void QDeclarativeListModelWorkerAgent::Data::clearChange(QDeclarativeListModel *model) -{ - int uid = model->m_listModel->getUid(); - - for (int i=0 ; i < changes.count() ; ++i) { - if (changes[i].modelUid == uid) { - changes.removeAt(i); - --i; - } - } -} - -void QDeclarativeListModelWorkerAgent::Data::insertChange(QDeclarativeListModel *model, int index, int count) -{ - Change c = { model->m_listModel->getUid(), Change::Inserted, index, count, 0, QList() }; - changes << c; -} - -void QDeclarativeListModelWorkerAgent::Data::removeChange(QDeclarativeListModel *model, int index, int count) -{ - Change c = { model->m_listModel->getUid(), Change::Removed, index, count, 0, QList() }; - changes << c; -} - -void QDeclarativeListModelWorkerAgent::Data::moveChange(QDeclarativeListModel *model, int index, int count, int to) -{ - Change c = { model->m_listModel->getUid(), Change::Moved, index, count, to, QList() }; - changes << c; -} - -void QDeclarativeListModelWorkerAgent::Data::changedChange(QDeclarativeListModel *model, int index, int count, const QList &roles) -{ - Change c = { model->m_listModel->getUid(), Change::Changed, index, count, 0, roles }; - changes << c; -} - -QDeclarativeListModelWorkerAgent::QDeclarativeListModelWorkerAgent(QDeclarativeListModel *model) -: m_ref(1), m_orig(model), m_copy(new QDeclarativeListModel(model, this)) -{ -} - -void QDeclarativeListModelWorkerAgent::setV8Engine(QV8Engine *eng) -{ - m_copy->m_engine = eng; -} - -void QDeclarativeListModelWorkerAgent::addref() -{ - m_ref.ref(); -} - -void QDeclarativeListModelWorkerAgent::release() -{ - bool del = !m_ref.deref(); - - if (del) - delete this; -} - -int QDeclarativeListModelWorkerAgent::count() const -{ - return m_copy->count(); -} - -void QDeclarativeListModelWorkerAgent::clear() -{ - m_copy->clear(); -} - -void QDeclarativeListModelWorkerAgent::remove(QDeclarativeV8Function *args) -{ - m_copy->remove(args); -} - -void QDeclarativeListModelWorkerAgent::append(QDeclarativeV8Function *args) -{ - m_copy->append(args); -} - -void QDeclarativeListModelWorkerAgent::insert(QDeclarativeV8Function *args) -{ - m_copy->insert(args); -} - -QDeclarativeV8Handle QDeclarativeListModelWorkerAgent::get(int index) const -{ - return m_copy->get(index); -} - -void QDeclarativeListModelWorkerAgent::set(int index, const QDeclarativeV8Handle &value) -{ - m_copy->set(index, value); -} - -void QDeclarativeListModelWorkerAgent::setProperty(int index, const QString& property, const QVariant& value) -{ - m_copy->setProperty(index, property, value); -} - -void QDeclarativeListModelWorkerAgent::move(int from, int to, int count) -{ - m_copy->move(from, to, count); -} - -void QDeclarativeListModelWorkerAgent::sync() -{ - Sync *s = new Sync; - s->data = data; - s->list = m_copy; - data.changes.clear(); - - mutex.lock(); - QCoreApplication::postEvent(this, s); - syncDone.wait(&mutex); - mutex.unlock(); -} - -bool QDeclarativeListModelWorkerAgent::event(QEvent *e) -{ - if (e->type() == QEvent::User) { - - QMutexLocker locker(&mutex); - Sync *s = static_cast(e); - - const QList &changes = s->data.changes; - - bool cc = m_orig->count() != s->list->count(); - - QHash targetModelHash; - ListModel::sync(s->list->m_listModel, m_orig->m_listModel, &targetModelHash); - - for (int ii = 0; ii < changes.count(); ++ii) { - const Change &change = changes.at(ii); - - ListModel *model = targetModelHash.value(change.modelUid); - - if (model && model->m_modelCache) { - switch (change.type) { - case Change::Inserted: - emit model->m_modelCache->itemsInserted(change.index, change.count); - break; - case Change::Removed: - emit model->m_modelCache->itemsRemoved(change.index, change.count); - break; - case Change::Moved: - emit model->m_modelCache->itemsMoved(change.index, change.to, change.count); - break; - case Change::Changed: - emit model->m_modelCache->itemsChanged(change.index, change.count, change.roles); - break; - } - } - } - - syncDone.wakeAll(); - locker.unlock(); - - if (cc) - emit m_orig->countChanged(); - } - - return QObject::event(e); -} - -QT_END_NAMESPACE - diff --git a/src/declarative/util/qdeclarativelistmodelworkeragent_p.h b/src/declarative/util/qdeclarativelistmodelworkeragent_p.h deleted file mode 100644 index 05c36473a5..0000000000 --- a/src/declarative/util/qdeclarativelistmodelworkeragent_p.h +++ /dev/null @@ -1,161 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the QtDeclarative module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** This file may be used under the terms of the GNU Lesser General Public -** License version 2.1 as published by the Free Software Foundation and -** appearing in the file LICENSE.LGPL included in the packaging of this -** file. Please review the following information to ensure the GNU Lesser -** General Public License version 2.1 requirements will be met: -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QDECLARATIVELISTMODELWORKERAGENT_P_H -#define QDECLARATIVELISTMODELWORKERAGENT_P_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists purely as an -// implementation detail. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include - -#include -#include -#include - -#include - -QT_BEGIN_HEADER - -QT_BEGIN_NAMESPACE - -QT_MODULE(Declarative) - -class QDeclarativeListModel; - -class QDeclarativeListModelWorkerAgent : public QObject -{ - Q_OBJECT - Q_PROPERTY(int count READ count) - -public: - QDeclarativeListModelWorkerAgent(QDeclarativeListModel *); - - void setV8Engine(QV8Engine *eng); - - void addref(); - void release(); - - int count() const; - - Q_INVOKABLE void clear(); - Q_INVOKABLE void remove(QDeclarativeV8Function *args); - Q_INVOKABLE void append(QDeclarativeV8Function *args); - Q_INVOKABLE void insert(QDeclarativeV8Function *args); - Q_INVOKABLE QDeclarativeV8Handle get(int index) const; - Q_INVOKABLE void set(int index, const QDeclarativeV8Handle &); - Q_INVOKABLE void setProperty(int index, const QString& property, const QVariant& value); - Q_INVOKABLE void move(int from, int to, int count); - Q_INVOKABLE void sync(); - - struct VariantRef - { - VariantRef() : a(0) {} - VariantRef(const VariantRef &r) : a(r.a) { if (a) a->addref(); } - VariantRef(QDeclarativeListModelWorkerAgent *_a) : a(_a) { if (a) a->addref(); } - ~VariantRef() { if (a) a->release(); } - - VariantRef &operator=(const VariantRef &o) { - if (o.a) o.a->addref(); - if (a) a->release(); a = o.a; - return *this; - } - - QDeclarativeListModelWorkerAgent *a; - }; -protected: - virtual bool event(QEvent *); - -private: - friend class QDeclarativeWorkerScriptEnginePrivate; - friend class QDeclarativeListModel; - - struct Change - { - int modelUid; - enum { Inserted, Removed, Moved, Changed } type; - int index; // Inserted/Removed/Moved/Changed - int count; // Inserted/Removed/Moved/Changed - int to; // Moved - QList roles; - }; - - struct Data - { - QList changes; - - void clearChange(QDeclarativeListModel *model); - void insertChange(QDeclarativeListModel *model, int index, int count); - void removeChange(QDeclarativeListModel *model, int index, int count); - void moveChange(QDeclarativeListModel *model, int index, int count, int to); - void changedChange(QDeclarativeListModel *model, int index, int count, const QList &roles); - }; - Data data; - - struct Sync : public QEvent { - Sync() : QEvent(QEvent::User) {} - Data data; - QDeclarativeListModel *list; - }; - - QAtomicInt m_ref; - QDeclarativeListModel *m_orig; - QDeclarativeListModel *m_copy; - QMutex mutex; - QWaitCondition syncDone; -}; - -QT_END_NAMESPACE - -Q_DECLARE_METATYPE(QDeclarativeListModelWorkerAgent::VariantRef) - -QT_END_HEADER - -#endif // QDECLARATIVEWORKERSCRIPT_P_H - diff --git a/src/declarative/util/qdeclarativeopenmetaobject.cpp b/src/declarative/util/qdeclarativeopenmetaobject.cpp deleted file mode 100644 index d4dd8242c4..0000000000 --- a/src/declarative/util/qdeclarativeopenmetaobject.cpp +++ /dev/null @@ -1,384 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the QtDeclarative module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** This file may be used under the terms of the GNU Lesser General Public -** License version 2.1 as published by the Free Software Foundation and -** appearing in the file LICENSE.LGPL included in the packaging of this -** file. Please review the following information to ensure the GNU Lesser -** General Public License version 2.1 requirements will be met: -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qdeclarativeopenmetaobject_p.h" -#include -#include -#include -#include - -QT_BEGIN_NAMESPACE - - -class QDeclarativeOpenMetaObjectTypePrivate -{ -public: - QDeclarativeOpenMetaObjectTypePrivate() : mem(0), cache(0), engine(0) {} - - void init(const QMetaObject *metaObj); - - int propertyOffset; - int signalOffset; - QHash names; - QMetaObjectBuilder mob; - QMetaObject *mem; - QDeclarativePropertyCache *cache; - QDeclarativeEngine *engine; - QSet referers; -}; - -QDeclarativeOpenMetaObjectType::QDeclarativeOpenMetaObjectType(const QMetaObject *base, QDeclarativeEngine *engine) - : QDeclarativeCleanup(engine), d(new QDeclarativeOpenMetaObjectTypePrivate) -{ - d->engine = engine; - d->init(base); -} - -QDeclarativeOpenMetaObjectType::~QDeclarativeOpenMetaObjectType() -{ - if (d->mem) - qFree(d->mem); - if (d->cache) - d->cache->release(); - delete d; -} - -void QDeclarativeOpenMetaObjectType::clear() -{ - d->engine = 0; -} - -int QDeclarativeOpenMetaObjectType::propertyOffset() const -{ - return d->propertyOffset; -} - -int QDeclarativeOpenMetaObjectType::signalOffset() const -{ - return d->signalOffset; -} - -int QDeclarativeOpenMetaObjectType::createProperty(const QByteArray &name) -{ - int id = d->mob.propertyCount(); - d->mob.addSignal("__" + QByteArray::number(id) + "()"); - QMetaPropertyBuilder build = d->mob.addProperty(name, "QVariant", id); - propertyCreated(id, build); - qFree(d->mem); - d->mem = d->mob.toMetaObject(); - d->names.insert(name, id); - QSet::iterator it = d->referers.begin(); - while (it != d->referers.end()) { - QDeclarativeOpenMetaObject *omo = *it; - *static_cast(omo) = *d->mem; - if (d->cache) - d->cache->update(d->engine, omo); - ++it; - } - - return d->propertyOffset + id; -} - -void QDeclarativeOpenMetaObjectType::propertyCreated(int id, QMetaPropertyBuilder &builder) -{ - if (d->referers.count()) - (*d->referers.begin())->propertyCreated(id, builder); -} - -void QDeclarativeOpenMetaObjectTypePrivate::init(const QMetaObject *metaObj) -{ - if (!mem) { - mob.setSuperClass(metaObj); - mob.setClassName(metaObj->className()); - mob.setFlags(QMetaObjectBuilder::DynamicMetaObject); - - mem = mob.toMetaObject(); - - propertyOffset = mem->propertyOffset(); - signalOffset = mem->methodOffset(); - } -} - -//---------------------------------------------------------------------------- - -class QDeclarativeOpenMetaObjectPrivate -{ -public: - QDeclarativeOpenMetaObjectPrivate(QDeclarativeOpenMetaObject *_q) - : q(_q), parent(0), type(0), cacheProperties(false) {} - - inline QVariant &getData(int idx) { - while (data.count() <= idx) - data << QPair(QVariant(), false); - QPair &prop = data[idx]; - if (!prop.second) { - prop.first = q->initialValue(idx); - prop.second = true; - } - return prop.first; - } - - inline void writeData(int idx, const QVariant &value) { - while (data.count() <= idx) - data << QPair(QVariant(), false); - QPair &prop = data[idx]; - prop.first = value; - prop.second = true; - } - - inline bool hasData(int idx) const { - if (idx >= data.count()) - return false; - return data[idx].second; - } - - bool autoCreate; - QDeclarativeOpenMetaObject *q; - QAbstractDynamicMetaObject *parent; - QList > data; - QObject *object; - QDeclarativeOpenMetaObjectType *type; - bool cacheProperties; -}; - -QDeclarativeOpenMetaObject::QDeclarativeOpenMetaObject(QObject *obj, bool automatic) -: d(new QDeclarativeOpenMetaObjectPrivate(this)) -{ - d->autoCreate = automatic; - d->object = obj; - - d->type = new QDeclarativeOpenMetaObjectType(obj->metaObject(), 0); - d->type->d->referers.insert(this); - - QObjectPrivate *op = QObjectPrivate::get(obj); - d->parent = static_cast(op->metaObject); - *static_cast(this) = *d->type->d->mem; - op->metaObject = this; -} - -QDeclarativeOpenMetaObject::QDeclarativeOpenMetaObject(QObject *obj, QDeclarativeOpenMetaObjectType *type, bool automatic) -: d(new QDeclarativeOpenMetaObjectPrivate(this)) -{ - d->autoCreate = automatic; - d->object = obj; - - d->type = type; - d->type->addref(); - d->type->d->referers.insert(this); - - QObjectPrivate *op = QObjectPrivate::get(obj); - d->parent = static_cast(op->metaObject); - *static_cast(this) = *d->type->d->mem; - op->metaObject = this; -} - -QDeclarativeOpenMetaObject::~QDeclarativeOpenMetaObject() -{ - if (d->parent) - delete d->parent; - d->type->d->referers.remove(this); - d->type->release(); - delete d; -} - -QDeclarativeOpenMetaObjectType *QDeclarativeOpenMetaObject::type() const -{ - return d->type; -} - -int QDeclarativeOpenMetaObject::metaCall(QMetaObject::Call c, int id, void **a) -{ - if (( c == QMetaObject::ReadProperty || c == QMetaObject::WriteProperty) - && id >= d->type->d->propertyOffset) { - int propId = id - d->type->d->propertyOffset; - if (c == QMetaObject::ReadProperty) { - propertyRead(propId); - *reinterpret_cast(a[0]) = d->getData(propId); - } else if (c == QMetaObject::WriteProperty) { - if (propId <= d->data.count() || d->data[propId].first != *reinterpret_cast(a[0])) { - propertyWrite(propId); - d->writeData(propId, *reinterpret_cast(a[0])); - propertyWritten(propId); - activate(d->object, d->type->d->signalOffset + propId, 0); - } - } - return -1; - } else { - if (d->parent) - return d->parent->metaCall(c, id, a); - else - return d->object->qt_metacall(c, id, a); - } -} - -QAbstractDynamicMetaObject *QDeclarativeOpenMetaObject::parent() const -{ - return d->parent; -} - -QVariant QDeclarativeOpenMetaObject::value(int id) const -{ - return d->getData(id); -} - -void QDeclarativeOpenMetaObject::setValue(int id, const QVariant &value) -{ - d->writeData(id, value); - activate(d->object, id + d->type->d->signalOffset, 0); -} - -QVariant QDeclarativeOpenMetaObject::value(const QByteArray &name) const -{ - QHash::ConstIterator iter = d->type->d->names.find(name); - if (iter == d->type->d->names.end()) - return QVariant(); - - return d->getData(*iter); -} - -QVariant &QDeclarativeOpenMetaObject::operator[](const QByteArray &name) -{ - QHash::ConstIterator iter = d->type->d->names.find(name); - Q_ASSERT(iter != d->type->d->names.end()); - - return d->getData(*iter); -} - -QVariant &QDeclarativeOpenMetaObject::operator[](int id) -{ - return d->getData(id); -} - -void QDeclarativeOpenMetaObject::setValue(const QByteArray &name, const QVariant &val) -{ - QHash::ConstIterator iter = d->type->d->names.find(name); - - int id = -1; - if (iter == d->type->d->names.end()) { - id = createProperty(name.constData(), "") - d->type->d->propertyOffset; - } else { - id = *iter; - } - - if (id >= 0) { - QVariant &dataVal = d->getData(id); - if (dataVal == val) - return; - - dataVal = val; - activate(d->object, id + d->type->d->signalOffset, 0); - } -} - -// returns true if this value has been initialized by a call to either value() or setValue() -bool QDeclarativeOpenMetaObject::hasValue(int id) const -{ - return d->hasData(id); -} - -void QDeclarativeOpenMetaObject::setCached(bool c) -{ - if (c == d->cacheProperties || !d->type->d->engine) - return; - - d->cacheProperties = c; - - QDeclarativeData *qmldata = QDeclarativeData::get(d->object, true); - if (d->cacheProperties) { - if (!d->type->d->cache) - d->type->d->cache = new QDeclarativePropertyCache(d->type->d->engine, this); - qmldata->propertyCache = d->type->d->cache; - d->type->d->cache->addref(); - } else { - if (d->type->d->cache) - d->type->d->cache->release(); - qmldata->propertyCache = 0; - } -} - - -int QDeclarativeOpenMetaObject::createProperty(const char *name, const char *) -{ - if (d->autoCreate) - return d->type->createProperty(name); - else - return -1; -} - -void QDeclarativeOpenMetaObject::propertyRead(int) -{ -} - -void QDeclarativeOpenMetaObject::propertyWrite(int) -{ -} - -void QDeclarativeOpenMetaObject::propertyWritten(int) -{ -} - -void QDeclarativeOpenMetaObject::propertyCreated(int, QMetaPropertyBuilder &) -{ -} - -QVariant QDeclarativeOpenMetaObject::initialValue(int) -{ - return QVariant(); -} - -int QDeclarativeOpenMetaObject::count() const -{ - return d->type->d->names.count(); -} - -QByteArray QDeclarativeOpenMetaObject::name(int idx) const -{ - Q_ASSERT(idx >= 0 && idx < d->type->d->names.count()); - - return d->type->d->mob.property(idx).name(); -} - -QObject *QDeclarativeOpenMetaObject::object() const -{ - return d->object; -} - -QT_END_NAMESPACE diff --git a/src/declarative/util/qdeclarativeopenmetaobject_p.h b/src/declarative/util/qdeclarativeopenmetaobject_p.h deleted file mode 100644 index e5cfee7eb6..0000000000 --- a/src/declarative/util/qdeclarativeopenmetaobject_p.h +++ /dev/null @@ -1,131 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the QtDeclarative module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** This file may be used under the terms of the GNU Lesser General Public -** License version 2.1 as published by the Free Software Foundation and -** appearing in the file LICENSE.LGPL included in the packaging of this -** file. Please review the following information to ensure the GNU Lesser -** General Public License version 2.1 requirements will be met: -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QDECLARATIVEOPENMETAOBJECT_H -#define QDECLARATIVEOPENMETAOBJECT_H - -#include -#include - -#include -#include -#include -#include - -QT_BEGIN_HEADER - -QT_BEGIN_NAMESPACE - -QT_MODULE(Declarative) - -class QDeclarativeEngine; -class QMetaPropertyBuilder; -class QDeclarativeOpenMetaObjectTypePrivate; -class Q_DECLARATIVE_PRIVATE_EXPORT QDeclarativeOpenMetaObjectType : public QDeclarativeRefCount, public QDeclarativeCleanup -{ -public: - QDeclarativeOpenMetaObjectType(const QMetaObject *base, QDeclarativeEngine *engine); - ~QDeclarativeOpenMetaObjectType(); - - int createProperty(const QByteArray &name); - - int propertyOffset() const; - int signalOffset() const; - -protected: - virtual void propertyCreated(int, QMetaPropertyBuilder &); - virtual void clear(); - -private: - QDeclarativeOpenMetaObjectTypePrivate *d; - friend class QDeclarativeOpenMetaObject; - friend class QDeclarativeOpenMetaObjectPrivate; -}; - -class QDeclarativeOpenMetaObjectPrivate; -class Q_DECLARATIVE_PRIVATE_EXPORT QDeclarativeOpenMetaObject : public QAbstractDynamicMetaObject -{ -public: - QDeclarativeOpenMetaObject(QObject *, bool = true); - QDeclarativeOpenMetaObject(QObject *, QDeclarativeOpenMetaObjectType *, bool = true); - ~QDeclarativeOpenMetaObject(); - - QVariant value(const QByteArray &) const; - void setValue(const QByteArray &, const QVariant &); - QVariant value(int) const; - void setValue(int, const QVariant &); - QVariant &operator[](const QByteArray &); - QVariant &operator[](int); - bool hasValue(int) const; - - int count() const; - QByteArray name(int) const; - - QObject *object() const; - virtual QVariant initialValue(int); - - // Be careful - once setCached(true) is called createProperty() is no - // longer automatically called for new properties. - void setCached(bool); - - QDeclarativeOpenMetaObjectType *type() const; - -protected: - virtual int metaCall(QMetaObject::Call _c, int _id, void **_a); - virtual int createProperty(const char *, const char *); - - virtual void propertyRead(int); - virtual void propertyWrite(int); - virtual void propertyWritten(int); - virtual void propertyCreated(int, QMetaPropertyBuilder &); - - QAbstractDynamicMetaObject *parent() const; - -private: - QDeclarativeOpenMetaObjectPrivate *d; - friend class QDeclarativeOpenMetaObjectType; -}; - -QT_END_NAMESPACE - -QT_END_HEADER - -#endif // QDECLARATIVEOPENMETAOBJECT_H diff --git a/src/declarative/util/qdeclarativepropertychanges.cpp b/src/declarative/util/qdeclarativepropertychanges.cpp index e9dc559d5e..d6035fa9d2 100644 --- a/src/declarative/util/qdeclarativepropertychanges.cpp +++ b/src/declarative/util/qdeclarativepropertychanges.cpp @@ -41,7 +41,7 @@ #include "qdeclarativepropertychanges_p.h" -#include "qdeclarativeopenmetaobject_p.h" +#include #include #include diff --git a/src/declarative/util/qdeclarativepropertymap.cpp b/src/declarative/util/qdeclarativepropertymap.cpp index 1149683ea6..af8e7f64fb 100644 --- a/src/declarative/util/qdeclarativepropertymap.cpp +++ b/src/declarative/util/qdeclarativepropertymap.cpp @@ -42,7 +42,7 @@ #include "qdeclarativepropertymap.h" #include -#include "qdeclarativeopenmetaobject_p.h" +#include #include diff --git a/src/declarative/util/qdeclarativeutilmodule.cpp b/src/declarative/util/qdeclarativeutilmodule.cpp index 4df3115eaf..511ccd3f36 100644 --- a/src/declarative/util/qdeclarativeutilmodule.cpp +++ b/src/declarative/util/qdeclarativeutilmodule.cpp @@ -47,8 +47,6 @@ #include "qdeclarativeconnections_p.h" #include "qdeclarativesmoothedanimation_p.h" #include "qdeclarativefontloader_p.h" -#include "qdeclarativelistaccessor_p.h" -#include "qdeclarativelistmodel_p.h" #include "qdeclarativepackage_p.h" #include "qdeclarativepropertychanges_p.h" #include "qdeclarativespringanimation_p.h" @@ -67,12 +65,6 @@ #include #include -void QDeclarativeUtilModule::registerBaseTypes(const char *uri, int versionMajor, int versionMinor) -{ - qmlRegisterType(uri, versionMajor, versionMinor,"ListElement"); - qmlRegisterCustomType(uri, versionMajor, versionMinor,"ListModel", new QDeclarativeListModelParser); -} - void QDeclarativeUtilModule::defineModule() { qmlRegisterUncreatableType("QtQuick",2,0,"InputPanel", QInputPanel::tr("InputPanel is an abstract class")); @@ -115,5 +107,4 @@ void QDeclarativeUtilModule::defineModule() qmlRegisterCustomType("QtQuick",2,0,"PropertyChanges", new QDeclarativePropertyChangesParser); qmlRegisterCustomType("QtQuick",2,0,"Connections", new QDeclarativeConnectionsParser); - registerBaseTypes("QtQuick",2,0); } diff --git a/src/declarative/util/qdeclarativeutilmodule_p.h b/src/declarative/util/qdeclarativeutilmodule_p.h index 42a1e02097..7304f6fd77 100644 --- a/src/declarative/util/qdeclarativeutilmodule_p.h +++ b/src/declarative/util/qdeclarativeutilmodule_p.h @@ -53,7 +53,6 @@ QT_MODULE(Declarative) class QDeclarativeUtilModule { public: - static void registerBaseTypes(const char *uri, int versionMajor, int versionMinor); static void defineModule(); }; diff --git a/src/declarative/util/qlistmodelinterface.cpp b/src/declarative/util/qlistmodelinterface.cpp deleted file mode 100644 index 4461456516..0000000000 --- a/src/declarative/util/qlistmodelinterface.cpp +++ /dev/null @@ -1,104 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the QtDeclaractive module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** This file may be used under the terms of the GNU Lesser General Public -** License version 2.1 as published by the Free Software Foundation and -** appearing in the file LICENSE.LGPL included in the packaging of this -** file. Please review the following information to ensure the GNU Lesser -** General Public License version 2.1 requirements will be met: -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qlistmodelinterface_p.h" - -QT_BEGIN_NAMESPACE - -/*! - \internal - \class QListModelInterface - \brief The QListModelInterface class can be subclassed to provide C++ models to QDeclarativeGraphics Views - - This class is comprised primarily of pure virtual functions which - you must implement in a subclass. You can then use the subclass - as a model for a QDeclarativeGraphics view, such as a QDeclarativeListView. -*/ - -/*! \fn QListModelInterface::QListModelInterface(QObject *parent) - Constructs a QListModelInterface with the specified \a parent. -*/ - - /*! \fn QListModelInterface::QListModelInterface(QObjectPrivate &dd, QObject *parent) - - \internal - */ - -/*! \fn QListModelInterface::~QListModelInterface() - The destructor is virtual. - */ - -/*! \fn int QListModelInterface::count() const - Returns the number of data entries in the model. -*/ - -/*! \fn QVariant QListModelInterface::data(int index, int role) const - Returns the data at the given \a index for the specified \a roles. -*/ - -/*! \fn QList QListModelInterface::roles() const - Returns the list of roles for which the list model interface - provides data. -*/ - -/*! \fn QString QListModelInterface::toString(int role) const - Returns a string description of the specified \a role. -*/ - -/*! \fn void QListModelInterface::itemsInserted(int index, int count) - Emit this signal when \a count items are inserted at \a index. - */ - -/*! \fn void QListModelInterface::itemsRemoved(int index, int count) - Emit this signal when \a count items are removed at \a index. - */ - -/*! \fn void QListModelInterface::itemsMoved(int from, int to, int count) - Emit this signal when \a count items are moved from index \a from - to index \a to. - */ - -/*! \fn void QListModelInterface::itemsChanged(int index, int count, const QList &roles) - Emit this signal when \a count items at \a index have had their - \a roles changed. - */ - -QT_END_NAMESPACE diff --git a/src/declarative/util/qlistmodelinterface_p.h b/src/declarative/util/qlistmodelinterface_p.h deleted file mode 100644 index 340dfac258..0000000000 --- a/src/declarative/util/qlistmodelinterface_p.h +++ /dev/null @@ -1,84 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the QtDeclarative module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** This file may be used under the terms of the GNU Lesser General Public -** License version 2.1 as published by the Free Software Foundation and -** appearing in the file LICENSE.LGPL included in the packaging of this -** file. Please review the following information to ensure the GNU Lesser -** General Public License version 2.1 requirements will be met: -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QLISTMODELINTERFACE_H -#define QLISTMODELINTERFACE_H - -#include -#include - -#include - -QT_BEGIN_HEADER - -QT_BEGIN_NAMESPACE - -QT_MODULE(Declarative) - -class Q_DECLARATIVE_PRIVATE_EXPORT QListModelInterface : public QObject -{ - Q_OBJECT - public: - QListModelInterface(QObject *parent = 0) : QObject(parent) {} - virtual ~QListModelInterface() {} - - virtual int count() const = 0; - virtual QVariant data(int index, int role) const = 0; - - virtual QList roles() const = 0; - virtual QString toString(int role) const = 0; - - Q_SIGNALS: - void itemsInserted(int index, int count); - void itemsRemoved(int index, int count); - void itemsMoved(int from, int to, int count); - void itemsChanged(int index, int count, const QList &roles); - - protected: - QListModelInterface(QObjectPrivate &dd, QObject *parent) - : QObject(dd, parent) {} -}; - - -QT_END_NAMESPACE - -QT_END_HEADER -#endif //QTREEMODELINTERFACE_H diff --git a/src/declarative/util/util.pri b/src/declarative/util/util.pri index a93fff7f89..e476db7925 100644 --- a/src/declarative/util/util.pri +++ b/src/declarative/util/util.pri @@ -12,9 +12,7 @@ SOURCES += \ $$PWD/qdeclarativepropertychanges.cpp \ $$PWD/qdeclarativestategroup.cpp \ $$PWD/qdeclarativetransition.cpp \ - $$PWD/qdeclarativelistmodel.cpp\ $$PWD/qdeclarativelistaccessor.cpp \ - $$PWD/qdeclarativeopenmetaobject.cpp \ $$PWD/qdeclarativetimeline.cpp \ $$PWD/qdeclarativetimer.cpp \ $$PWD/qdeclarativebind.cpp \ @@ -23,11 +21,9 @@ SOURCES += \ $$PWD/qdeclarativebehavior.cpp \ $$PWD/qdeclarativefontloader.cpp \ $$PWD/qdeclarativestyledtext.cpp \ - $$PWD/qdeclarativelistmodelworkeragent.cpp \ $$PWD/qdeclarativepath.cpp \ $$PWD/qdeclarativechangeset.cpp \ $$PWD/qdeclarativelistcompositor.cpp \ - $$PWD/qlistmodelinterface.cpp \ $$PWD/qdeclarativepathinterpolator.cpp \ $$PWD/qdeclarativesvgparser.cpp @@ -48,10 +44,7 @@ HEADERS += \ $$PWD/qdeclarativetransitionmanager_p_p.h \ $$PWD/qdeclarativestategroup_p.h \ $$PWD/qdeclarativetransition_p.h \ - $$PWD/qdeclarativelistmodel_p.h\ - $$PWD/qdeclarativelistmodel_p_p.h\ $$PWD/qdeclarativelistaccessor_p.h \ - $$PWD/qdeclarativeopenmetaobject_p.h \ $$PWD/qdeclarativetimeline_p_p.h \ $$PWD/qdeclarativetimer_p.h \ $$PWD/qdeclarativebind_p.h \ @@ -60,12 +53,10 @@ HEADERS += \ $$PWD/qdeclarativebehavior_p.h \ $$PWD/qdeclarativefontloader_p.h \ $$PWD/qdeclarativestyledtext_p.h \ - $$PWD/qdeclarativelistmodelworkeragent_p.h \ $$PWD/qdeclarativepath_p.h \ $$PWD/qdeclarativepath_p_p.h \ $$PWD/qdeclarativechangeset_p.h \ $$PWD/qdeclarativelistcompositor_p.h \ - $$PWD/qlistmodelinterface_p.h \ $$PWD/qdeclarativepathinterpolator_p.h \ $$PWD/qdeclarativesvgparser_p.h -- cgit v1.2.3