diff options
author | Andrew den Exter <andrew.den-exter@nokia.com> | 2011-06-28 14:19:05 +1000 |
---|---|---|
committer | Andrew den Exter <andrew.den-exter@nokia.com> | 2011-06-29 10:45:07 +1000 |
commit | 8cf428d4ebd4c8c246806243730aad3a4f325300 (patch) | |
tree | 9c7a02a7bb234b6a535b917470902eb089841362 | |
parent | 136c84811acda766182e55cd69a5a17b90b7c0c9 (diff) |
Insert script objects directly into the VisualModel cache.
Keeping the visual model data in the cache allows substitution and
potentially retention of state in view items.
-rw-r--r-- | examples/declarative/modelviews/visualdatamodel/Bubble.qml | 2 | ||||
-rw-r--r-- | examples/declarative/modelviews/visualdatamodel/visualdatamodel.qml | 42 | ||||
-rw-r--r-- | src/declarative/items/qsgitemsmodule.cpp | 1 | ||||
-rw-r--r-- | src/declarative/items/qsgvisualitemmodel.cpp | 1078 | ||||
-rw-r--r-- | src/declarative/items/qsgvisualitemmodel_p.h | 71 | ||||
-rw-r--r-- | src/declarative/util/qdeclarativelistcompositor.cpp | 75 | ||||
-rw-r--r-- | src/declarative/util/qdeclarativelistcompositor_p.h | 3 |
7 files changed, 727 insertions, 545 deletions
diff --git a/examples/declarative/modelviews/visualdatamodel/Bubble.qml b/examples/declarative/modelviews/visualdatamodel/Bubble.qml index 870533ff85..de2c80763f 100644 --- a/examples/declarative/modelviews/visualdatamodel/Bubble.qml +++ b/examples/declarative/modelviews/visualdatamodel/Bubble.qml @@ -3,7 +3,7 @@ import QtQuick 2.0 Rectangle { id: content - property int contentHeight: height - senderText.implicitHeight + 2 + property int contentHeight: height - senderText.implicitHeight - 2 x: 1; width: 477 diff --git a/examples/declarative/modelviews/visualdatamodel/visualdatamodel.qml b/examples/declarative/modelviews/visualdatamodel/visualdatamodel.qml index ece72198f2..4a3e511db2 100644 --- a/examples/declarative/modelviews/visualdatamodel/visualdatamodel.qml +++ b/examples/declarative/modelviews/visualdatamodel/visualdatamodel.qml @@ -10,28 +10,13 @@ Rectangle { property int messageCounter: 0 function send(message) { - messageModel.set(messageModel.count - 1, { - "sender": root.sender, - "message": message, - "avatar": "", - "outbound": true, - "time": Qt.formatTime(Date.now()), - "delegateState": "" - }) visualModel.insert(visualModel.count, messageBubble) newMessage() messageView.positionViewAtEnd() } function newMessage() { - messageModel.append({ - "sender": root.sender, - "message": "", - "avatar": "", - "outbound": true, - "time": "", - "delegateState": "composing" - }) + visualModel.appendData({}) var bubble = visualModel.take(visualModel.count - 1, composer) messageBubble = bubble messageBubble.y = 0 // Override the position set by the view. @@ -59,16 +44,25 @@ Rectangle { model: VisualDataModel { id: visualModel + roles: [ + VisualRole { name: "sender"; defaultValue: root.sender }, + VisualRole { name: "message"; defaultValue: "" }, + VisualRole { name: "avatar"; defaultValue: "" }, + VisualRole { name: "outbound"; defaultValue: true }, + VisualRole { name: "time"; defaultValue: "" }, + VisualRole { name: "delegateState"; defaultValue: "composing" } + ] + model: ListModel { id: messageModel } delegate: Bubble {} } - add: Transition { - ParentAnimation { - via: root - NumberAnimation { properties: "y"; duration: 3000; easing.type: Easing.InOutQuad } - } - } +// add: Transition { +// ParentAnimation { +// via: root +// NumberAnimation { properties: "y"; duration: 3000; easing.type: Easing.InOutQuad } +// } +// } } Timer { @@ -78,7 +72,7 @@ Rectangle { onTriggered: { var message = script.get(scriptIndex); - messageModel.insert(messageModel.count - 1, { + messageModel.append({ "sender": message.sender, "message": message.message, "avatar": message.avatar, @@ -88,7 +82,7 @@ Rectangle { }) scriptIndex = (scriptIndex + 1) % script.count - interval = Math.random() * 30000 + //interval = Math.random() * 30000 } } diff --git a/src/declarative/items/qsgitemsmodule.cpp b/src/declarative/items/qsgitemsmodule.cpp index 1637d24c8c..5a62d00d07 100644 --- a/src/declarative/items/qsgitemsmodule.cpp +++ b/src/declarative/items/qsgitemsmodule.cpp @@ -145,6 +145,7 @@ static void qt_sgitems_defineModule(const char *uri, int major, int minor) qmlRegisterType<QSGVisualData>(uri,major,minor,"VisualData"); qmlRegisterType<QSGVisualDataModel>(uri,major,minor,"VisualDataModel"); qmlRegisterType<QSGVisualItemModel>(uri,major,minor,"VisualItemModel"); + qmlRegisterType<QSGVisualModelRole>(uri,major,minor,"VisualRole"); qmlRegisterType<QSGAnchors>(); qmlRegisterType<QSGKeyEvent>(); diff --git a/src/declarative/items/qsgvisualitemmodel.cpp b/src/declarative/items/qsgvisualitemmodel.cpp index e2f7fd84c1..c2328e70e8 100644 --- a/src/declarative/items/qsgvisualitemmodel.cpp +++ b/src/declarative/items/qsgvisualitemmodel.cpp @@ -64,11 +64,21 @@ #include <QtCore/qhash.h> #include <QtCore/qlist.h> +#include <QtScript/qscriptvalue.h> QT_BEGIN_NAMESPACE QHash<QObject*, QSGVisualModelAttached*> QSGVisualModelAttached::attachedProperties; +class VDMDelegateDataType : public QDeclarativeOpenMetaObjectType +{ +public: + VDMDelegateDataType(const QMetaObject *base, QDeclarativeEngine *engine) : QDeclarativeOpenMetaObjectType(base, engine) {} + + void propertyCreated(int, QMetaPropertyBuilder &prop) { + prop.setWritable(false); + } +}; class QSGVisualModelPartsMetaObject : public QDeclarativeOpenMetaObject { @@ -111,15 +121,20 @@ QSGVisualModelParts::QSGVisualModelParts(QSGVisualModel *parent) new QSGVisualModelPartsMetaObject(this); } - +class QSGVisualModelData; class QSGVisualModelPrivate : public QObjectPrivate, public QDeclarativeListCompositor { Q_DECLARE_PUBLIC(QSGVisualModel) public: QSGVisualModelPrivate(QDeclarativeContext *context = 0) - : QObjectPrivate(), QDeclarativeListCompositor(0),context(context), pendingModel(0), parts(0) + : QObjectPrivate(), QDeclarativeListCompositor(0),context(context), delegateDataType(0) + , pendingModel(0), pendingComponent(0), parts(0) , childrenChanged(false), transaction(false) {} + static QSGVisualModelPrivate *get(QSGVisualModel *m) { + return static_cast<QSGVisualModelPrivate *>(QObjectPrivate::get(m)); + } + static void data_append(QDeclarativeListProperty<QObject> *prop, QObject *data) { QSGVisualModelPrivate *d = static_cast<QSGVisualModelPrivate *>(prop->data); QDeclarative_setParent_noEvent(data, prop->object); @@ -144,7 +159,12 @@ public: } static QSGItem *children_at(QDeclarativeListProperty<QSGItem> *prop, int index) { - return static_cast<QSGVisualModelPrivate *>(prop->data)->children.at(index).item; + return qobject_cast<QSGItem *>(static_cast<QSGVisualModelPrivate *>(prop->data)->children.at(index).item); + } + + static void roles_append(QDeclarativeListProperty<QSGVisualModelRole> *prop, QSGVisualModelRole *role) { + QSGVisualModelPrivate *d = static_cast<QSGVisualModelPrivate *>(prop->data); + d->roles.append(role); } void appendModel(QSGVisualData *model) { @@ -166,10 +186,6 @@ public: q, SLOT(_q_itemsRemoved(QSGVisualData*,int,int)), Qt::UniqueConnection); QObject::connect(model, SIGNAL(itemsMoved(QSGVisualData*,int,int,int)), q, SLOT(_q_itemsMoved(QSGVisualData*,int,int,int)), Qt::UniqueConnection); - QObject::connect(model, SIGNAL(createdPackage(QSGVisualData*,int,QDeclarativePackage*)), - q, SLOT(_q_createdPackage(QSGVisualData*,int,QDeclarativePackage*)), Qt::UniqueConnection); - QObject::connect(model, SIGNAL(destroyingPackage(QDeclarativePackage*)), - q, SLOT(_q_destroyingPackage(QDeclarativePackage*)), Qt::UniqueConnection); } void itemAppended() { @@ -186,7 +202,7 @@ public: emit q->childrenChanged(); } - int indexOf(QSGItem *item) const { + int indexOf(QObject *item) const { for (int i = 0; i < children.count(); ++i) if (children.at(i).item == item) return i; @@ -197,8 +213,9 @@ public: Q_Q(QSGVisualModel); foreach (const QDeclarativeChangeSet::Remove &remove, transactionChanges.removes()) emit q->itemsRemoved(remove.start, remove.count()); - foreach (const QDeclarativeChangeSet::Insert &insert, transactionChanges.inserts()) + foreach (const QDeclarativeChangeSet::Insert &insert, transactionChanges.inserts()) { emit q->itemsInserted(insert.start, insert.count()); + } foreach (const QDeclarativeChangeSet::Move &move, transactionChanges.moves()) emit q->itemsMoved(move.start, move.to, move.count()); transactionChanges.clear(); @@ -227,24 +244,34 @@ public: } } + QSGVisualModelData *createScriptData(QDeclarativeComponent *delegate, const QScriptValue &value); + class Item { public: - Item(QSGItem *i) : item(i), ref(0) {} + Item(QObject *i, QSGVisualModelData *data) : item(i), data(data), ref(0) {} void addRef() { ++ref; } bool deref() { return --ref == 0; } - QSGItem *item; + QObject *item; + QDeclarativeGuard<QSGVisualModelData> data; int ref; }; + struct ItemData { + QObject *object; + QSGVisualModelData *data; + }; + QList<Item> children; - QHash<QSGItem *, int> removedItems; + QList<QSGVisualModelRole *> roles; + QHash<QObject *, int> removedItems; QSGVisualModelAttached::List attachedItems; QDeclarativeChangeSet transactionChanges; - QDeclarativeGuard<QDeclarativeContext> context; + VDMDelegateDataType *delegateDataType; QSGVisualData *pendingModel; + QDeclarativeComponent *pendingComponent; QSGVisualModelParts *parts; bool childrenChanged; bool transaction; @@ -256,18 +283,20 @@ protected: bool insertInternalData(int index, const void *data) { childrenChanged = true; - QSGItem *item = static_cast<QSGItem *>(const_cast<void *>(data)); - children.insert(index, Item(item)); + const ItemData *itemData = static_cast<const ItemData *>(data); + children.insert(index, Item(itemData->object, itemData->data)); return true; } void replaceInternalData(int index, const void *data) { childrenChanged = true; + const ItemData *itemData = static_cast<const ItemData *>(data); QSGVisualModelPrivate::Item &item = children[index]; if (item.ref > 0) removedItems.insert(item.item, item.ref); - item.item = static_cast<QSGItem *>(const_cast<void *>(data)); + item.item = itemData->object; + item.data = itemData->data; item.ref = 0; } @@ -280,7 +309,7 @@ protected: removedItems.insert(item.item, item.ref); } QList<Item>::iterator first = children.begin() + index; - QList<Item>::iterator last = first + count - 1; + QList<Item>::iterator last = first + count; children.erase(first, last); } @@ -316,6 +345,187 @@ protected: } }; +class QSGVisualDataParts; +class QSGVisualModelData; +class QSGVisualDataPrivate : public QObjectPrivate +{ +public: + QSGVisualDataPrivate(QDeclarativeContext *); + + static QSGVisualDataPrivate *get(QSGVisualData *m) { + return static_cast<QSGVisualDataPrivate *>(QObjectPrivate::get(m)); + } + + QDeclarativeGuard<QListModelInterface> m_listModelInterface; + QDeclarativeGuard<QAbstractItemModel> m_abstractItemModel; + QString m_part; + + QDeclarativeComponent *m_delegate; + QDeclarativeGuard<QDeclarativeContext> m_context; + QList<int> m_roles; + QHash<QByteArray,int> m_roleNames; + void ensureRoles() { + if (m_roleNames.isEmpty()) { + if (m_listModelInterface) { + m_roles = m_listModelInterface->roles(); + for (int ii = 0; ii < m_roles.count(); ++ii) + m_roleNames.insert(m_listModelInterface->toString(m_roles.at(ii)).toUtf8(), m_roles.at(ii)); + } else if (m_abstractItemModel) { + for (QHash<int,QByteArray>::const_iterator it = m_abstractItemModel->roleNames().begin(); + it != m_abstractItemModel->roleNames().end(); ++it) { + m_roles.append(it.key()); + m_roleNames.insert(*it, it.key()); + } + if (m_roles.count()) + m_roleNames.insert("hasModelChildren", -1); + } else if (m_listAccessor) { + m_roleNames.insert("modelData", 0); + if (m_listAccessor->type() == QDeclarativeListAccessor::Instance) { + if (QObject *object = m_listAccessor->at(0).value<QObject*>()) { + int count = object->metaObject()->propertyCount(); + for (int ii = 1; ii < count; ++ii) { + const QMetaProperty &prop = object->metaObject()->property(ii); + m_roleNames.insert(prop.name(), 0); + } + } + } + } + } + } + + QHash<int,int> m_roleToPropId; + int m_modelDataPropId; + void createMetaData() { + if (!m_metaDataCreated) { + ensureRoles(); + QHash<QByteArray, int> roleNames = m_roleNames; + QSGVisualModelPrivate *parent = QSGVisualModelPrivate::get(static_cast<QSGVisualModel *>(q_ptr->parent())); + for (QList<QSGVisualModelRole *>::iterator it = parent->roles.begin(); it != parent->roles.end(); ++it) { + QByteArray name = (*it)->name().toUtf8(); + int propId = m_delegateDataType->createProperty(name) - m_delegateDataType->propertyOffset(); + QHash<QByteArray, int>::iterator it = roleNames.find(name); + if (it != roleNames.end()) { + m_roleToPropId.insert(*it, propId); + roleNames.erase(it); + } + } + + + if (m_roleNames.count()) { + QHash<QByteArray, int>::const_iterator it = roleNames.begin(); + while (it != roleNames.end()) { + int propId = m_delegateDataType->createProperty(it.key()) - m_delegateDataType->propertyOffset(); + m_roleToPropId.insert(*it, propId); + ++it; + } + // Add modelData property + if (m_roles.count() == 1) + m_modelDataPropId = m_delegateDataType->createProperty("modelData") - m_delegateDataType->propertyOffset(); + m_metaDataCreated = true; + } + } + } + + int modelCount() const { + if (m_listModelInterface) + return qMax(0, m_listModelInterface->count()); + if (m_abstractItemModel) + return qMax(0, m_abstractItemModel->rowCount(m_root)); + if (m_listAccessor) + return m_listAccessor->count(); + return 0; + } + + VDMDelegateDataType *m_delegateDataType; + friend class QSGVisualModelData; + bool m_metaDataCreated : 1; + bool m_metaDataCacheable : 1; + bool m_delegateValidated : 1; + bool m_completePending : 1; + + QSGVisualModelData *data(QObject *item); + + QVariant m_modelVariant; + QDeclarativeListAccessor *m_listAccessor; + + QModelIndex m_root; + QList<QByteArray> watchedRoles; + QList<int> watchedRoleIds; + QList<int> changedRoles; +}; + +class QSGVisualModelDataMetaObject : public QDeclarativeOpenMetaObject +{ +public: + QSGVisualModelDataMetaObject(QObject *parent, QDeclarativeOpenMetaObjectType *type) + : QDeclarativeOpenMetaObject(parent, type) {} + + virtual QVariant initialValue(int); + virtual int createProperty(const char *, const char *); + +private: + friend class QSGVisualModelData; +}; + +class QSGVisualModelDataMetaObject; +class QSGVisualModelData : public QObject +{ +Q_OBJECT +public: + QSGVisualModelData(int index, QSGVisualData *model); + QSGVisualModelData(QDeclarativeComponent *delegate, VDMDelegateDataType *dataType); + ~QSGVisualModelData(); + + Q_PROPERTY(int index READ index NOTIFY indexChanged) + int index() const; + void setIndex(int index); + + int propForRole(int) const; + int modelDataPropertyId() const { + QSGVisualDataPrivate *model = QSGVisualDataPrivate::get(m_model); + return model->m_modelDataPropId; + } + + void setValue(int, const QVariant &); + bool hasValue(int id) const { + return m_meta->hasValue(id); + } + + QSGVisualData *model() const { return m_model; } + QDeclarativeComponent *delegate() const { return m_delegate; } + + void ensureProperties(); + +Q_SIGNALS: + void indexChanged(); + +private: + friend class QSGVisualModelDataMetaObject; + int m_index; + QDeclarativeGuard<QSGVisualData> m_model; + QDeclarativeGuard<QDeclarativeComponent> m_delegate; + QSGVisualModelDataMetaObject *m_meta; +}; + +QSGVisualModelData *QSGVisualModelPrivate::createScriptData(QDeclarativeComponent *delegate, const QScriptValue &value) +{ + Q_Q(QSGVisualModel); + if (!delegateDataType) { + delegateDataType = new VDMDelegateDataType( + &QSGVisualModelData::staticMetaObject, + context ? context->engine() : qmlEngine(q)); + for (QList<QSGVisualModelRole *>::iterator it = roles.begin(); it != roles.end(); ++it) + delegateDataType->createProperty((*it)->name().toUtf8()); + } + QSGVisualModelData *data = new QSGVisualModelData(delegate, delegateDataType); + for (int i = 0; i < roles.count(); ++i) { + QScriptValue property = value.property(roles.at(i)->name()); + data->setValue(i, property.isValid() ? property.toVariant() : roles.at(i)->defaultValue()); + } + QDeclarative_setParent_noEvent(data, q); + return data; +} + QSGVisualModel::QSGVisualModel(QObject *parent) : QObject(*(new QSGVisualModelPrivate), parent) { @@ -339,6 +549,12 @@ QDeclarativeListProperty<QSGItem> QSGVisualModel::children() d->children_count, d->children_at); } +QDeclarativeListProperty<QSGVisualModelRole> QSGVisualModel::roles() +{ + Q_D(QSGVisualModel); + return QDeclarativeListProperty<QSGVisualModelRole>(this, d, d->roles_append); +} + QObject *QSGVisualModel::parts() { Q_D(QSGVisualModel); @@ -353,7 +569,7 @@ int QSGVisualModel::count() const return d->count(); } -QSGItem *QSGVisualModel::item(int index, const QByteArray &viewId, bool complete) +QObject *QSGVisualModel::object(int index, bool complete) { Q_D(QSGVisualModel); int offset = 0; @@ -361,7 +577,7 @@ QSGItem *QSGVisualModel::item(int index, const QByteArray &viewId, bool complete QDeclarativeCompositeRange range = d->at(index, &offset, &internalIndex); if (!range.internal()) { QSGVisualData *model = static_cast<QSGVisualData *>(range.list); - QSGItem *item = model->item(range.index + offset, viewId, complete); + QObject *item = model->object(range.index + offset, complete); QSGVisualModelAttached *attached = QSGVisualModelAttached::properties(item); attached->setModel(this); attached->setData(model); @@ -369,60 +585,129 @@ QSGItem *QSGVisualModel::item(int index, const QByteArray &viewId, bool complete d->attachedItems.insert(attached); if (model->completePending()) d->pendingModel = model; - return item; - } else { - QSGVisualModelPrivate::Item &item = d->children[internalIndex]; - item.addRef(); - return item.item; + QSGVisualModelPrivate::ItemData itemData = { item, item->findChild<QSGVisualModelData *>() }; + internalIndex = d->replaceAt(index, &itemData); + Q_ASSERT(internalIndex != -1); + // createdObject() instead? + if (QDeclarativePackage *package = qobject_cast<QDeclarativePackage *>(item)) + emit createdPackage(index, package); } + QSGVisualModelPrivate::Item &item = d->children[internalIndex]; + if (!item.item) { + if (!item.data || !item.data->delegate()) { + qmlInfo(this) << "No delegate for item"; + return 0; + } + QDeclarativeComponent *delegate = item.data->delegate(); + QDeclarativeContext *ccontext = d->context; + if (!ccontext) ccontext = qmlContext(this); + QDeclarativeContext *ctxt = new QDeclarativeContext(ccontext); + ctxt->setContextProperty(QLatin1String("model"), item.data); + ctxt->setContextObject(item.data); + item.item = delegate->beginCreate(ctxt); + if (complete) { + delegate->completeCreate(); + } else { + d->pendingComponent = delegate; + } + if (item.item) { + QDeclarative_setParent_noEvent(ctxt, item.item); + QDeclarative_setParent_noEvent(item.data, item.item); + } else { + delete ctxt; + qmlInfo(this, delegate->errors()) << "Error creating delegate"; + return 0; + } + } + item.addRef(); + return item.item; +} + +QSGItem *QSGVisualModel::item(int index, bool complete) +{ + QObject *obj = object(index, complete); + if (QSGItem *item = qobject_cast<QSGItem *>(obj)) + return item; + release(obj); + return 0; } -QSGItem *QSGVisualModel::item(int index) +QSGItem *QSGVisualModel::item(int index, const QByteArray &viewId, bool complete) { - return item(index, QByteArray()); + QObject *pobj = object(index, complete); + if (QSGItem *item = qobject_cast<QSGItem *>(pobj)) { + return item; + } else if (QDeclarativePackage *package = qobject_cast<QDeclarativePackage *>(pobj)) { + QObject *iobj = package->part(QString::fromUtf8(viewId)); + if (QSGItem *item = qobject_cast<QSGItem *>(iobj)) + return item; + } + if (pobj) + release(pobj); + return 0; } QSGItem *QSGVisualModel::take(int index, QSGItem *parent) { - Q_D(QSGVisualModel); QSGItem *i = item(index); remove(index, 1); i->setParentItem(parent); - return i; } -QSGVisualModel::ReleaseFlags QSGVisualModel::release(QSGItem *item) +QSGVisualModel::ReleaseFlags QSGVisualModel::release(QObject *object) { Q_D(QSGVisualModel); - QSGVisualModelAttached *attached = QSGVisualModelAttached::properties(item); - if (QSGVisualData *model = attached->m_data) { - return model->release(item); - } else { - int idx = d->indexOf(item); - if (idx >= 0) { - if (d->children[idx].deref()) { - // XXX todo - the original did item->scene()->removeItem(). Why? - item->setParentItem(0); - QDeclarative_setParent_noEvent(item, this); + QSGVisualModel::ReleaseFlags stat = 0; + + int idx = d->indexOf(object); + if (idx >= 0) { + if (d->children[idx].deref()) { + if (QSGVisualData *model = d->children[idx].data->model()) { + d->children[idx].item = 0; // Clearing the data should delete this node. + d->children[idx].data = 0; + d->clearData(idx, 1); + if (QDeclarativePackage *package = qobject_cast<QDeclarativePackage *>(object)) + emit destroyingPackage(package); + model->release(object); + stat |= Destroyed; + } else { + if (QSGItem *item = qobject_cast<QSGItem *>(object)) + item->setParentItem(0); + if (d->children[idx].data) { + d->children[idx].item = 0; + QDeclarative_setParent_noEvent(d->children[idx].data, this); + object->deleteLater(); + stat |= Destroyed; + } else { + QDeclarative_setParent_noEvent(object, this); + stat |= Referenced; + } } } else { - QHash<QSGItem *, int>::iterator it = d->removedItems.find(item); - if (it != d->removedItems.end()) { - if (--(*it) == 0) { - delete it.key(); - d->removedItems.erase(it); - } + stat |= Referenced; + } + } else { + QHash<QObject *, int>::iterator it = d->removedItems.find(object); + if (it != d->removedItems.end()) { + if (--(*it) == 0) { + if (QDeclarativePackage *package = qobject_cast<QDeclarativePackage *>(object)) + emit destroyingPackage(package); + it.key()->deleteLater(); + d->removedItems.erase(it); + return Destroyed; + } else { + stat |= Referenced; } } } - return 0; + return stat; } bool QSGVisualModel::completePending() const { Q_D(const QSGVisualModel); - return d->pendingModel; + return d->pendingModel || d->pendingComponent; } void QSGVisualModel::completeItem() @@ -431,6 +716,9 @@ void QSGVisualModel::completeItem() if (d->pendingModel) { d->pendingModel->completeItem(); d->pendingModel = 0; + } else if (d->pendingComponent) { + d->pendingComponent->completeCreate(); + d->pendingComponent = 0; } } @@ -442,7 +730,7 @@ QString QSGVisualModel::stringValue(int index, const QString &name) return QDeclarativeEngine::contextForObject(d->children.at(index).item)->contextProperty(name).toString(); } -int QSGVisualModel::indexOf(QSGItem *item, QObject *context) const +int QSGVisualModel::indexOf(QObject *item, QObject *context) const { Q_D(const QSGVisualModel); QSGVisualModelAttached *attached = QSGVisualModelAttached::properties(item); @@ -491,9 +779,12 @@ void QSGVisualModel::append(QSGItem *item) d->connectModel(model); inserted = true; } - } else if (d->appendData(item)) { - d->attachedItems.insert(attached); - inserted = true; + } else { + QSGVisualModelPrivate::ItemData itemData = { item, item->findChild<QSGVisualModelData *>() }; + if (d->appendData(&itemData)) { + d->attachedItems.insert(attached); + inserted = true; + } } if (inserted) { QSGVisualModelAttached *attached = QSGVisualModelAttached::properties(item); @@ -540,6 +831,35 @@ void QSGVisualModel::append(QSGVisualModel *sourceModel, int sourceIndex, int co emit sourceModel->countChanged(); } +void QSGVisualModel::append(QDeclarativeComponent *delegate, const QVariant &model, int sourceIndex, int count) +{ + Q_D(QSGVisualModel); + int destinationIndex = d->count(); + + QSGVisualData *data = new QSGVisualData(d->context ? d->context.data() : qmlContext(this), this); + data->setDelegate(delegate); + data->setModel(model); + + d->connectModel(data); + d->appendList(data, sourceIndex, count, false); + + emit itemsInserted(destinationIndex, count); +} + +void QSGVisualModel::append(QDeclarativeComponent *delegate, const QScriptValue &value) +{ + Q_D(QSGVisualModel); + + int destinationIndex = d->count(); + + QSGVisualModelData *data = d->createScriptData(delegate, value); + QSGVisualModelPrivate::ItemData itemData = { 0, data }; + if (d->appendData(&itemData)) + emit itemsInserted(destinationIndex, 1); + else + delete data; +} + void QSGVisualModel::insert(int index, QSGItem *item) { Q_D(QSGVisualModel); @@ -553,9 +873,12 @@ void QSGVisualModel::insert(int index, QSGItem *item) d->connectModel(model); inserted = true; } - } else if (d->insertData(index, item)) { - d->attachedItems.insert(attached); - inserted = true; + } else { + QSGVisualModelPrivate::ItemData itemData = { item, item->findChild<QSGVisualModelData *>() }; + if (d->insertData(index, &itemData)) { + d->attachedItems.insert(attached); + inserted = true; + } } if (inserted) { attached->setModel(this); @@ -604,6 +927,33 @@ void QSGVisualModel::insert(int destinationIndex, QSGVisualModel *sourceModel, i emit sourceModel->countChanged(); } +void QSGVisualModel::insert(int destinationIndex, QDeclarativeComponent *delegate, const QVariant &model, int sourceIndex, int count) +{ + Q_D(QSGVisualModel); + + QSGVisualData *data = new QSGVisualData(d->context ? d->context.data() : qmlContext(this), this); + data->setDelegate(delegate); + data->setModel(model); + + d->connectModel(data); + d->insertList(destinationIndex, data, sourceIndex, count, false); + + emit itemsInserted(destinationIndex, count); +} + +void QSGVisualModel::insert(int index, QDeclarativeComponent *delegate, const QScriptValue &value) +{ + Q_D(QSGVisualModel); + + QSGVisualModelData *data = d->createScriptData(delegate, value); + QSGVisualModelPrivate::ItemData itemData = { 0, data }; + + if (d->appendData(&itemData)) + emit itemsInserted(index, 1); + else + delete data; +} + void QSGVisualModel::remove(int index, int count) { Q_D(QSGVisualModel); @@ -650,7 +1000,14 @@ void QSGVisualModel::_q_itemsInserted(QSGVisualData *model, int index, int count d->listItemsInserted(model, index, index + count, &inserts); if (inserts.count() > 0) { - d->invalidateIndexes(index); + for (int i = 0; i < d->children.count(); ++i) { + QSGVisualModelPrivate::Item &item = d->children[i]; + if (item.data && item.data->model() == model) { + if (item.data->index() >= index) + item.data->setIndex(item.data->index() + count); + } + } + d->invalidateIndexes(inserts.first().start); QDeclarativeEngine *dengine = d->context ? d->context->engine() : qmlEngine(this); QScriptEngine *engine = QDeclarativeEnginePrivate::getScriptEngine(dengine); QScriptValue insertIndexes = engine->newArray(inserts.count()); @@ -679,12 +1036,21 @@ void QSGVisualModel::_q_itemsRemoved(QSGVisualData *model, int index, int count) QVector<QDeclarativeChangeSet::Remove> removes; d->childrenChanged = false; d->listItemsRemoved(model, index, index + count, &removes); - d->transactionChanges.append(removes); - d->invalidateIndexes(index); - d->emitTransactionChanges(); - emit countChanged(); - if (d->childrenChanged) - emit childrenChanged(); + if (!removes.isEmpty()) { + d->transactionChanges.append(removes); + d->invalidateIndexes(removes.first().start); + for (int i = 0; i < d->children.count(); ++i) { + QSGVisualModelPrivate::Item &item = d->children[i]; + if (item.data && item.data->model() == model) { + if (item.data->index() >= index + count) + item.data->setIndex(item.data->index() - count); + } + } + d->emitTransactionChanges(); + emit countChanged(); + if (d->childrenChanged) + emit childrenChanged(); + } } void QSGVisualModel::_q_itemsMoved(QSGVisualData *model, int from, int to, int count) @@ -693,24 +1059,48 @@ void QSGVisualModel::_q_itemsMoved(QSGVisualData *model, int from, int to, int c QVector<QDeclarativeChangeSet::Move> moves; d->childrenChanged = false; d->listItemsMoved(model, from, from + count, to, &moves); - d->transactionChanges.append(moves); - d->invalidateIndexes(qMin(from, to), qMax(from, to) + count); - d->emitTransactionChanges(); - if (d->childrenChanged) - emit childrenChanged(); + if (!moves.isEmpty()) { + d->transactionChanges.append(moves); + const int min = qMin(from, to); + const int max = qMax(from, to) + count; + const int diff = from > to ? count : -count; + for (int i = 0; i < d->children.count(); ++i) { + QSGVisualModelPrivate::Item &item = d->children[i]; + if (item.data && item.data->model() == model) { + if (item.data->index() >= from && item.data->index() < from + count) + item.data->setIndex(item.data->index() - from + to); + else if (item.data->index() >= min && item.data->index() < max) + item.data->setIndex(item.data->index() + diff); + } + } + d->invalidateIndexes(0); + for (int i = 0; i < d->children.count(); ++i) { + QSGVisualModelPrivate::Item &item = d->children[i]; + if (item.data && item.data->model() == model) { + model->updateData(item.data->index(), item.item); + } + } + d->emitTransactionChanges(); + if (d->childrenChanged) + emit childrenChanged(); + } } -void QSGVisualModel::_q_createdPackage(QSGVisualData *model, int index, QDeclarativePackage *package) +void QSGVisualModel::_q_itemsChanged(QSGVisualData *model, int index, int count) { Q_D(QSGVisualModel); - int absoluteIndex = d->absoluteIndexOf(model, index); - if (absoluteIndex != -1) - emit createdPackage(absoluteIndex, package); -} - -void QSGVisualModel::_q_destroyingPackage(QDeclarativePackage *package) -{ - emit destroyingPackage(package); + QVector<QDeclarativeChangeSet::Change> changes; + d->listItemsChanged(model, index, index + count, &changes); + + if (!changes.isEmpty()) { + d->transactionChanges.append(changes); + for (int i = 0; i < d->children.count(); ++i) { + QSGVisualModelPrivate::Item &item = d->children[i]; + if (item.data && item.data->model() == model) + model->updateData(item.data->index(), item.item); + } + d->emitTransactionChanges(); + } } QSGVisualModelAttached *QSGVisualModel::qmlAttachedProperties(QObject *obj) @@ -719,204 +1109,6 @@ QSGVisualModelAttached *QSGVisualModel::qmlAttachedProperties(QObject *obj) } //============================================================================ - -class VDMDelegateDataType : public QDeclarativeOpenMetaObjectType -{ -public: - VDMDelegateDataType(const QMetaObject *base, QDeclarativeEngine *engine) : QDeclarativeOpenMetaObjectType(base, engine) {} - - void propertyCreated(int, QMetaPropertyBuilder &prop) { - prop.setWritable(false); - } -}; - -class QSGVisualDataParts; -class QSGVisualModelData; -class QSGVisualDataPrivate : public QObjectPrivate -{ -public: - QSGVisualDataPrivate(QDeclarativeContext *); - - static QSGVisualDataPrivate *get(QSGVisualData *m) { - return static_cast<QSGVisualDataPrivate *>(QObjectPrivate::get(m)); - } - - QDeclarativeGuard<QListModelInterface> m_listModelInterface; - QDeclarativeGuard<QAbstractItemModel> m_abstractItemModel; - QString m_part; - - QDeclarativeComponent *m_delegate; - QDeclarativeGuard<QDeclarativeContext> m_context; - QList<int> m_roles; - QHash<QByteArray,int> m_roleNames; - void ensureRoles() { - if (m_roleNames.isEmpty()) { - if (m_listModelInterface) { - m_roles = m_listModelInterface->roles(); - for (int ii = 0; ii < m_roles.count(); ++ii) - m_roleNames.insert(m_listModelInterface->toString(m_roles.at(ii)).toUtf8(), m_roles.at(ii)); - } else if (m_abstractItemModel) { - for (QHash<int,QByteArray>::const_iterator it = m_abstractItemModel->roleNames().begin(); - it != m_abstractItemModel->roleNames().end(); ++it) { - m_roles.append(it.key()); - m_roleNames.insert(*it, it.key()); - } - if (m_roles.count()) - m_roleNames.insert("hasModelChildren", -1); - } else if (m_listAccessor) { - m_roleNames.insert("modelData", 0); - if (m_listAccessor->type() == QDeclarativeListAccessor::Instance) { - if (QObject *object = m_listAccessor->at(0).value<QObject*>()) { - int count = object->metaObject()->propertyCount(); - for (int ii = 1; ii < count; ++ii) { - const QMetaProperty &prop = object->metaObject()->property(ii); - m_roleNames.insert(prop.name(), 0); - } - } - } - } - } - } - - QHash<int,int> m_roleToPropId; - int m_modelDataPropId; - void createMetaData() { - if (!m_metaDataCreated) { - ensureRoles(); - if (m_roleNames.count()) { - QHash<QByteArray, int>::const_iterator it = m_roleNames.begin(); - while (it != m_roleNames.end()) { - int propId = m_delegateDataType->createProperty(it.key()) - m_delegateDataType->propertyOffset(); - m_roleToPropId.insert(*it, propId); - ++it; - } - // Add modelData property - if (m_roles.count() == 1) - m_modelDataPropId = m_delegateDataType->createProperty("modelData") - m_delegateDataType->propertyOffset(); - m_metaDataCreated = true; - } - } - } - - struct ObjectRef { - ObjectRef(QObject *object=0) : obj(object), ref(1) {} - QObject *obj; - int ref; - }; - class Cache : public QHash<int, ObjectRef> { - public: - QObject *getItem(int index) { - QObject *item = 0; - QHash<int,ObjectRef>::iterator it = find(index); - if (it != end()) { - (*it).ref++; - item = (*it).obj; - } - return item; - } - QObject *item(int index) { - QObject *item = 0; - QHash<int, ObjectRef>::const_iterator it = find(index); - if (it != end()) - item = (*it).obj; - return item; - } - void insertItem(int index, QObject *obj) { - insert(index, ObjectRef(obj)); - } - bool releaseItem(QObject *obj) { - QHash<int, ObjectRef>::iterator it = begin(); - for (; it != end(); ++it) { - ObjectRef &objRef = *it; - if (objRef.obj == obj) { - if (--objRef.ref == 0) { - erase(it); - return true; - } - break; - } - } - return false; - } - }; - - int modelCount() const { - if (m_listModelInterface) - return qMax(0, m_listModelInterface->count()); - if (m_abstractItemModel) - return qMax(0, m_abstractItemModel->rowCount(m_root)); - if (m_listAccessor) - return m_listAccessor->count(); - return 0; - } - - Cache m_cache; - QHash<QObject *, QDeclarativePackage*> m_packaged; - - VDMDelegateDataType *m_delegateDataType; - friend class QSGVisualModelData; - bool m_metaDataCreated : 1; - bool m_metaDataCacheable : 1; - bool m_delegateValidated : 1; - bool m_completePending : 1; - - QSGVisualModelData *data(QObject *item); - - QVariant m_modelVariant; - QDeclarativeListAccessor *m_listAccessor; - - QModelIndex m_root; - QList<QByteArray> watchedRoles; - QList<int> watchedRoleIds; -}; - -class QSGVisualModelDataMetaObject : public QDeclarativeOpenMetaObject -{ -public: - QSGVisualModelDataMetaObject(QObject *parent, QDeclarativeOpenMetaObjectType *type) - : QDeclarativeOpenMetaObject(parent, type) {} - - virtual QVariant initialValue(int); - virtual int createProperty(const char *, const char *); - -private: - friend class QSGVisualModelData; -}; - -class QSGVisualModelData : public QObject -{ -Q_OBJECT -public: - QSGVisualModelData(int index, QSGVisualData *model); - ~QSGVisualModelData(); - - Q_PROPERTY(int index READ index NOTIFY indexChanged) - int index() const; - void setIndex(int index); - - int propForRole(int) const; - int modelDataPropertyId() const { - QSGVisualDataPrivate *model = QSGVisualDataPrivate::get(m_model); - return model->m_modelDataPropId; - } - - void setValue(int, const QVariant &); - bool hasValue(int id) const { - return m_meta->hasValue(id); - } - - void ensureProperties(); - -Q_SIGNALS: - void indexChanged(); - -private: - friend class QSGVisualModelDataMetaObject; - int m_index; - QDeclarativeGuard<QSGVisualData> m_model; - QSGVisualModelDataMetaObject *m_meta; -}; - int QSGVisualModelData::propForRole(int id) const { QSGVisualDataPrivate *model = QSGVisualDataPrivate::get(m_model); @@ -1001,8 +1193,9 @@ QVariant QSGVisualModelDataMetaObject::initialValue(int propId) } } } - Q_ASSERT(!"Can never be reached"); - return QVariant(); + + QSGVisualModelPrivate *visualModel = QSGVisualModelPrivate::get(static_cast<QSGVisualModel *>(data->m_model->parent())); + return visualModel->roles.at(propId)->defaultValue(); } QSGVisualModelData::QSGVisualModelData(int index, @@ -1013,6 +1206,12 @@ m_meta(new QSGVisualModelDataMetaObject(this, QSGVisualDataPrivate::get(model)-> ensureProperties(); } +QSGVisualModelData::QSGVisualModelData(QDeclarativeComponent *delegate, VDMDelegateDataType *dataType) + : m_index(-1), m_delegate(delegate), m_meta(new QSGVisualModelDataMetaObject(this, dataType)) +{ + m_meta->setCached(true); +} + QSGVisualModelData::~QSGVisualModelData() { } @@ -1231,109 +1430,59 @@ int QSGVisualData::count() const /* Returns ReleaseStatus flags. */ -QSGVisualModel::ReleaseFlags QSGVisualData::release(QSGItem *item) +void QSGVisualData::release(QObject *obj) { - Q_D(QSGVisualData); - QSGVisualModel::ReleaseFlags stat = 0; - QObject *obj = item; - bool inPackage = false; - - QHash<QObject*,QDeclarativePackage*>::iterator it = d->m_packaged.find(item); - if (it != d->m_packaged.end()) { - QDeclarativePackage *package = *it; - d->m_packaged.erase(it); - if (d->m_packaged.contains(item)) - stat |= QSGVisualModel::Referenced; - inPackage = true; - obj = package; // fall through and delete - } - - if (d->m_cache.releaseItem(obj)) { - // Remove any bindings to avoid warnings due to parent change. - QObjectPrivate *p = QObjectPrivate::get(obj); - Q_ASSERT(p->declarativeData); - QDeclarativeData *d = static_cast<QDeclarativeData*>(p->declarativeData); - if (d->ownContext && d->context) - d->context->clearContext(); - - if (inPackage) { - emit destroyingPackage(qobject_cast<QDeclarativePackage*>(obj)); - } else { - // XXX todo - the original did item->scene()->removeItem(). Why? - item->setParentItem(0); - } - stat |= QSGVisualModel::Destroyed; - obj->deleteLater(); - } else if (!inPackage) { - stat |= QSGVisualModel::Referenced; - } + // Remove any bindings to avoid warnings due to parent change. + QObjectPrivate *p = QObjectPrivate::get(obj); + Q_ASSERT(p->declarativeData); + QDeclarativeData *d = static_cast<QDeclarativeData*>(p->declarativeData); + if (d->ownContext && d->context) + d->context->clearContext(); - return stat; + // XXX todo - the original did item->scene()->removeItem(). Why? + if (QSGItem *item = qobject_cast<QSGItem *>(obj)) + item->setParentItem(0); + obj->deleteLater(); } -QSGItem *QSGVisualData::item(int index, const QByteArray &viewId, bool complete) +QObject *QSGVisualData::object(int index, bool complete) { Q_D(QSGVisualData); if (d->modelCount() <= 0 || !d->m_delegate) return 0; - QObject *nobj = d->m_cache.getItem(index); bool needComplete = false; - if (!nobj) { - QDeclarativeContext *ccontext = d->m_context; - if (!ccontext) ccontext = qmlContext(this); - if (!ccontext) ccontext = qmlContext(parent()); - QDeclarativeContext *ctxt = new QDeclarativeContext(ccontext); - QSGVisualModelData *data = new QSGVisualModelData(index, this); - if ((!d->m_listModelInterface || !d->m_abstractItemModel) && d->m_listAccessor - && d->m_listAccessor->type() == QDeclarativeListAccessor::ListProperty) { - ctxt->setContextObject(d->m_listAccessor->at(index).value<QObject*>()); - ctxt = new QDeclarativeContext(ctxt, ctxt); - } - ctxt->setContextProperty(QLatin1String("model"), data); - ctxt->setContextObject(data); - d->m_completePending = false; - nobj = d->m_delegate->beginCreate(ctxt); - if (complete) { - d->m_delegate->completeCreate(); - } else { - d->m_completePending = true; - needComplete = true; - } - if (nobj) { - QDeclarative_setParent_noEvent(ctxt, nobj); - QDeclarative_setParent_noEvent(data, nobj); - d->m_cache.insertItem(index, nobj); - if (QDeclarativePackage *package = qobject_cast<QDeclarativePackage *>(nobj)) - emit createdPackage(this, index, package); - } else { - delete data; - delete ctxt; - qmlInfo(this, d->m_delegate->errors()) << "Error creating delegate"; - } + QDeclarativeContext *ccontext = d->m_context; + if (!ccontext) ccontext = qmlContext(this); + if (!ccontext) ccontext = qmlContext(parent()); + QDeclarativeContext *ctxt = new QDeclarativeContext(ccontext); + QSGVisualModelData *data = new QSGVisualModelData(index, this); + if ((!d->m_listModelInterface || !d->m_abstractItemModel) && d->m_listAccessor + && d->m_listAccessor->type() == QDeclarativeListAccessor::ListProperty) { + ctxt->setContextObject(d->m_listAccessor->at(index).value<QObject*>()); + ctxt = new QDeclarativeContext(ctxt, ctxt); } - QSGItem *item = qobject_cast<QSGItem *>(nobj); - if (!item) { - QDeclarativePackage *package = qobject_cast<QDeclarativePackage *>(nobj); - if (package) { - QObject *o = package->part(QString::fromUtf8(viewId)); - item = qobject_cast<QSGItem *>(o); - if (item) - d->m_packaged.insertMulti(item, package); - } + ctxt->setContextProperty(QLatin1String("model"), data); + ctxt->setContextObject(data); + d->m_completePending = false; + QObject *nobj = d->m_delegate->beginCreate(ctxt); + if (complete) { + d->m_delegate->completeCreate(); + } else { + d->m_completePending = true; + needComplete = true; } - if (!item) { - if (needComplete) - d->m_delegate->completeCreate(); - d->m_cache.releaseItem(nobj); - if (!d->m_delegateValidated) { - qmlInfo(d->m_delegate) << QSGVisualData::tr("Delegate component must be Item type."); - d->m_delegateValidated = true; - } + if (nobj) { + QDeclarative_setParent_noEvent(ctxt, nobj); + QDeclarative_setParent_noEvent(data, nobj); + } else { + delete data; + delete ctxt; + qmlInfo(this, d->m_delegate->errors()) << "Error creating delegate"; } if (d->modelCount()-1 == index && d->m_abstractItemModel && d->m_abstractItemModel->canFetchMore(d->m_root)) d->m_abstractItemModel->fetchMore(d->m_root); - return item; + return nobj; } bool QSGVisualData::completePending() const @@ -1349,7 +1498,7 @@ void QSGVisualData::completeItem() d->m_completePending = false; } -QString QSGVisualData::stringValue(int index, const QString &name) +QString QSGVisualData::stringValue(int index, QObject *nobj, const QString &name) { Q_D(QSGVisualData); if ((!d->m_listModelInterface || !d->m_abstractItemModel) && d->m_listAccessor) { @@ -1364,7 +1513,7 @@ QString QSGVisualData::stringValue(int index, const QString &name) QObject *data = 0; bool tempData = false; - if (QObject *nobj = d->m_cache.item(index)) + if (nobj) data = d->data(nobj); if (!data) { data = new QSGVisualModelData(index, this); @@ -1397,9 +1546,9 @@ QString QSGVisualData::stringValue(int index, const QString &name) return val; } -int QSGVisualData::indexOf(QSGItem *item, QObject *) const +int QSGVisualData::indexOf(QObject *object, QObject *) const { - QVariant val = QDeclarativeEngine::contextForObject(item)->contextProperty(QLatin1String("index")); + QVariant val = QDeclarativeEngine::contextForObject(object)->contextProperty(QLatin1String("index")); return val.toInt(); return -1; } @@ -1411,11 +1560,53 @@ void QSGVisualData::setWatchedRoles(QList<QByteArray> roles) d->watchedRoleIds.clear(); } -void QSGVisualData::_q_itemsChanged(int index, int count, - const QList<int> &roles) +bool QSGVisualData::updateData(int idx, QObject *object) { Q_D(QSGVisualData); bool changed = false; + QSGVisualModelData *data = d->data(object); + for (int roleIdx = 0; roleIdx < d->changedRoles.count(); ++roleIdx) { + int role = d->changedRoles.at(roleIdx); + if (!changed && !d->watchedRoleIds.isEmpty() && d->watchedRoleIds.contains(role)) + changed = true; + int propId = data->propForRole(role); + if (propId != -1) { + if (data->hasValue(propId)) { + if (d->m_listModelInterface) { + data->setValue(propId, d->m_listModelInterface->data(idx, role)); + } else if (d->m_abstractItemModel) { + QModelIndex index = d->m_abstractItemModel->index(idx, 0, d->m_root); + data->setValue(propId, d->m_abstractItemModel->data(index, role)); + } + } + } else { + QString roleName; + if (d->m_listModelInterface) + roleName = d->m_listModelInterface->toString(role); + else if (d->m_abstractItemModel) + roleName = QString::fromUtf8(d->m_abstractItemModel->roleNames().value(role)); + qmlInfo(this) << "Changing role not present in item: " << roleName; + } + } + if (d->changedRoles.count() == 1) { + // Handle the modelData role we add if there is just one role. + int propId = data->modelDataPropertyId(); + if (data->hasValue(propId)) { + int role = d->changedRoles.at(0); + if (d->m_listModelInterface) { + data->setValue(propId, d->m_listModelInterface->data(idx, role)); + } else if (d->m_abstractItemModel) { + QModelIndex index = d->m_abstractItemModel->index(idx, 0, d->m_root); + data->setValue(propId, d->m_abstractItemModel->data(index, role)); + } + } + } + return changed; +} + +void QSGVisualData::_q_itemsChanged(int index, int count, const QList<int> &roles) +{ + Q_D(QSGVisualData); if (!d->watchedRoles.isEmpty() && d->watchedRoleIds.isEmpty()) { foreach (QByteArray r, d->watchedRoles) { if (d->m_roleNames.contains(r)) @@ -1423,154 +1614,28 @@ void QSGVisualData::_q_itemsChanged(int index, int count, } } - for (QHash<int,QSGVisualDataPrivate::ObjectRef>::ConstIterator iter = d->m_cache.begin(); - iter != d->m_cache.end(); ++iter) { - const int idx = iter.key(); - - if (idx >= index && idx < index+count) { - QSGVisualDataPrivate::ObjectRef objRef = *iter; - QSGVisualModelData *data = d->data(objRef.obj); - for (int roleIdx = 0; roleIdx < roles.count(); ++roleIdx) { - int role = roles.at(roleIdx); - if (!changed && !d->watchedRoleIds.isEmpty() && d->watchedRoleIds.contains(role)) - changed = true; - int propId = data->propForRole(role); - if (propId != -1) { - if (data->hasValue(propId)) { - if (d->m_listModelInterface) { - data->setValue(propId, d->m_listModelInterface->data(idx, role)); - } else if (d->m_abstractItemModel) { - QModelIndex index = d->m_abstractItemModel->index(idx, 0, d->m_root); - data->setValue(propId, d->m_abstractItemModel->data(index, role)); - } - } - } else { - QString roleName; - if (d->m_listModelInterface) - roleName = d->m_listModelInterface->toString(role); - else if (d->m_abstractItemModel) - roleName = QString::fromUtf8(d->m_abstractItemModel->roleNames().value(role)); - qmlInfo(this) << "Changing role not present in item: " << roleName; - } - } - if (d->m_roles.count() == 1) { - // Handle the modelData role we add if there is just one role. - int propId = data->modelDataPropertyId(); - if (data->hasValue(propId)) { - int role = d->m_roles.at(0); - if (d->m_listModelInterface) { - data->setValue(propId, d->m_listModelInterface->data(idx, role)); - } else if (d->m_abstractItemModel) { - QModelIndex index = d->m_abstractItemModel->index(idx, 0, d->m_root); - data->setValue(propId, d->m_abstractItemModel->data(index, role)); - } - } - } - } - } - if (changed) - emit itemsChanged(this, index, count); + d->changedRoles = roles; + emit itemsChanged(this, index, count); } void QSGVisualData::_q_itemsInserted(int index, int count) { - Q_D(QSGVisualData); if (!count) return; - // XXX - highly inefficient - QHash<int,QSGVisualDataPrivate::ObjectRef> items; - for (QHash<int,QSGVisualDataPrivate::ObjectRef>::Iterator iter = d->m_cache.begin(); - iter != d->m_cache.end(); ) { - - if (iter.key() >= index) { - QSGVisualDataPrivate::ObjectRef objRef = *iter; - int index = iter.key() + count; - iter = d->m_cache.erase(iter); - - items.insert(index, objRef); - - QSGVisualModelData *data = d->data(objRef.obj); - data->setIndex(index); - } else { - ++iter; - } - } - d->m_cache.unite(items); - emit itemsInserted(this, index, count); } void QSGVisualData::_q_itemsRemoved(int index, int count) { - Q_D(QSGVisualData); if (!count) return; - // XXX - highly inefficient - QHash<int, QSGVisualDataPrivate::ObjectRef> items; - for (QHash<int, QSGVisualDataPrivate::ObjectRef>::Iterator iter = d->m_cache.begin(); - iter != d->m_cache.end(); ) { - if (iter.key() >= index && iter.key() < index + count) { - QSGVisualDataPrivate::ObjectRef objRef = *iter; - iter = d->m_cache.erase(iter); - items.insertMulti(-1, objRef); //XXX perhaps better to maintain separately - QSGVisualModelData *data = d->data(objRef.obj); - data->setIndex(-1); - } else if (iter.key() >= index + count) { - QSGVisualDataPrivate::ObjectRef objRef = *iter; - int index = iter.key() - count; - iter = d->m_cache.erase(iter); - items.insert(index, objRef); - QSGVisualModelData *data = d->data(objRef.obj); - data->setIndex(index); - } else { - ++iter; - } - } - - d->m_cache.unite(items); emit itemsRemoved(this, index, count); } void QSGVisualData::_q_itemsMoved(int from, int to, int count) { - Q_D(QSGVisualData); - // XXX - highly inefficient - QHash<int,QSGVisualDataPrivate::ObjectRef> items; - for (QHash<int,QSGVisualDataPrivate::ObjectRef>::Iterator iter = d->m_cache.begin(); - iter != d->m_cache.end(); ) { - - if (iter.key() >= from && iter.key() < from + count) { - QSGVisualDataPrivate::ObjectRef objRef = *iter; - int index = iter.key() - from + to; - iter = d->m_cache.erase(iter); - - items.insert(index, objRef); - - QSGVisualModelData *data = d->data(objRef.obj); - data->setIndex(index); - } else { - ++iter; - } - } - for (QHash<int,QSGVisualDataPrivate::ObjectRef>::Iterator iter = d->m_cache.begin(); - iter != d->m_cache.end(); ) { - - int diff = from > to ? count : -count; - if (iter.key() >= qMin(from,to) && iter.key() < qMax(from+count,to+count)) { - QSGVisualDataPrivate::ObjectRef objRef = *iter; - int index = iter.key() + diff; - iter = d->m_cache.erase(iter); - - items.insert(index, objRef); - - QSGVisualModelData *data = d->data(objRef.obj); - data->setIndex(index); - } else { - ++iter; - } - } - d->m_cache.unite(items); - + if (!count || from == to) + return; emit itemsMoved(this, from, to, count); } @@ -1709,7 +1774,10 @@ void QSGVisualDataModel::setRootIndex(const QVariant &root) QVariant QSGVisualDataModel::modelIndex(int idx) const { Q_D(const QSGVisualDataModel); - return d->data->modelIndex(idx); + int offset = 0; + int internalIndex = 0; + QDeclarativeCompositeRange range = d->at(idx, &offset, &internalIndex); + return range.list == d->data ? d->data->modelIndex(range.index + offset) : QVariant(); } QVariant QSGVisualDataModel::parentModelIndex() const @@ -1718,6 +1786,16 @@ QVariant QSGVisualDataModel::parentModelIndex() const return d->data->parentModelIndex(); } +void QSGVisualDataModel::appendData(const QScriptValue &value) +{ + append(delegate(), value); +} + +void QSGVisualDataModel::insertData(int index, const QScriptValue &value) +{ + insert(index, delegate(), value); +} + QSGVisualPartModel::QSGVisualPartModel(QSGVisualModel *model, const QByteArray &part, QObject *parent) : QObject(parent), m_model(model), m_part(part) { diff --git a/src/declarative/items/qsgvisualitemmodel_p.h b/src/declarative/items/qsgvisualitemmodel_p.h index 4267f01fe1..d4a7084fa3 100644 --- a/src/declarative/items/qsgvisualitemmodel_p.h +++ b/src/declarative/items/qsgvisualitemmodel_p.h @@ -67,6 +67,7 @@ class QSGVisualDataModelPrivate; class QSGVisualData; class QSGVisualModelAttached; +class QSGVisualModelRole; class QSGVisualModelPrivate; class Q_DECLARATIVE_EXPORT QSGVisualModel : public QObject { @@ -76,6 +77,7 @@ class Q_DECLARATIVE_EXPORT QSGVisualModel : public QObject Q_PROPERTY(int count READ count NOTIFY countChanged) Q_PROPERTY(QDeclarativeListProperty<QObject> data READ data DESIGNABLE false) Q_PROPERTY(QDeclarativeListProperty<QSGItem> children READ children NOTIFY childrenChanged DESIGNABLE false) + Q_PROPERTY(QDeclarativeListProperty<QSGVisualModelRole> roles READ roles CONSTANT) Q_PROPERTY(QObject *parts READ parts CONSTANT) Q_CLASSINFO("DefaultProperty", "data") @@ -88,32 +90,38 @@ public: virtual ~QSGVisualModel() {} int count() const; - QSGItem *item(int index, const QByteArray &, bool complete=true); - ReleaseFlags release(QSGItem *item); + QObject *object(int index, bool complete = true); + ReleaseFlags release(QObject *item); bool completePending() const; void completeItem(); QString stringValue(int index, const QString &role); void setWatchedRoles(QList<QByteArray>) {} - virtual int indexOf(QSGItem *item, QObject *objectContext) const; + virtual int indexOf(QObject *item, QObject *objectContext) const; Q_INVOKABLE QScriptValue getItemInfo(int index) const; QDeclarativeListProperty<QObject> data(); QDeclarativeListProperty<QSGItem> children(); + QDeclarativeListProperty<QSGVisualModelRole> roles(); QObject *parts(); static QSGVisualModelAttached *qmlAttachedProperties(QObject *obj); - Q_INVOKABLE QSGItem *item(int index); + Q_INVOKABLE QSGItem *item(int index, bool complete = true); + Q_INVOKABLE QSGItem *item(int index, const QByteArray &viewId, bool complete = true); Q_INVOKABLE QSGItem *take(int index, QSGItem *parent = 0); public Q_SLOTS: void append(QSGItem *item); void append(QSGVisualModel *sourceModel, int sourceIndex, int count); + void append(QDeclarativeComponent *delegate, const QVariant &model, int sourceIndex, int count); + void append(QDeclarativeComponent *delegate, const QScriptValue &data); void insert(int index, QSGItem *item); void insert(int destinationIndex, QSGVisualModel *sourceModel, int sourceIndex, int count); + void insert(int destinationIndex, QDeclarativeComponent *delegate, const QVariant &model, int sourceIndex, int count); + void insert(int index, QDeclarativeComponent *delegate, const QScriptValue &data); void remove(int index, int count); void move(int from, int to, int count); @@ -140,8 +148,7 @@ private Q_SLOTS: void _q_itemsInserted(QSGVisualData *model, int index, int count); void _q_itemsRemoved(QSGVisualData *model, int index, int count); void _q_itemsMoved(QSGVisualData *model, int from, int to, int count); - void _q_createdPackage(QSGVisualData *model, int index, QDeclarativePackage *package); - void _q_destroyingPackage(QDeclarativePackage *package); + void _q_itemsChanged(QSGVisualData *model, int index, int count); private: Q_DISABLE_COPY(QSGVisualModel) @@ -175,15 +182,16 @@ public: Q_INVOKABLE QVariant parentModelIndex() const; int count() const; - QSGItem *item(int index, const QByteArray &, bool complete=true); - QSGVisualModel::ReleaseFlags release(QSGItem *item); + QObject *object(int index, bool complete=true); + void release(QObject *object); bool completePending() const; void completeItem(); - QString stringValue(int index, const QString &role); + QString stringValue(int index, QObject *object, const QString &role); void setWatchedRoles(QList<QByteArray> roles); - int indexOf(QSGItem *item, QObject *objectContext) const; + int indexOf(QObject *item, QObject *objectContext) const; + bool updateData(int idx, QObject *object); Q_SIGNALS: void itemsInserted(QSGVisualData *data, int index, int count); @@ -191,8 +199,6 @@ Q_SIGNALS: void itemsMoved(QSGVisualData *data, int from, int to, int count); void itemsChanged(QSGVisualData *data, int index, int count); - void createdPackage(QSGVisualData *model, int index, QDeclarativePackage *package); - void destroyingPackage(QDeclarativePackage *package); void rootIndexChanged(); private Q_SLOTS: @@ -211,6 +217,42 @@ private: Q_DISABLE_COPY(QSGVisualData) }; +class QSGVisualModelRole : public QObject +{ + Q_OBJECT + Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged) + Q_PROPERTY(QVariant defaultValue READ defaultValue WRITE setDefaultValue NOTIFY defaultValueChanged) +public: + QSGVisualModelRole(QObject *parent = 0) : QObject(parent) {} + ~QSGVisualModelRole() {} + + QString name() const { return m_name; } + void setName(const QString &name) + { + if (m_name == name) + return; + m_name = name; + emit nameChanged(); + } + + QVariant defaultValue() const { return m_defaultValue; } + void setDefaultValue(const QVariant &value) + { + if (m_defaultValue == value) + return; + m_defaultValue = value; + emit defaultValueChanged(); + } + +Q_SIGNALS: + void nameChanged(); + void defaultValueChanged(); + +private: + QString m_name; + QVariant m_defaultValue; +}; + class QSGVisualModelAttached : public QObject { Q_OBJECT @@ -300,6 +342,10 @@ public: Q_INVOKABLE QVariant modelIndex(int idx) const; Q_INVOKABLE QVariant parentModelIndex() const; +public Q_SLOTS: + void appendData(const QScriptValue &value); + void insertData(int index, const QScriptValue &value); + Q_SIGNALS: void rootIndexChanged(); @@ -329,6 +375,7 @@ QT_END_NAMESPACE QML_DECLARE_TYPE(QSGVisualModel) QML_DECLARE_TYPEINFO(QSGVisualModel, QML_HAS_ATTACHED_PROPERTIES) QML_DECLARE_TYPE(QSGVisualData) +QML_DECLARE_TYPE(QSGVisualModelRole) QML_DECLARE_TYPEINFO(QSGVisualDataModel, QML_HAS_ATTACHED_PROPERTIES) QML_DECLARE_TYPE(QSGVisualItemModel) QML_DECLARE_TYPEINFO(QSGVisualItemModel, QML_HAS_ATTACHED_PROPERTIES) diff --git a/src/declarative/util/qdeclarativelistcompositor.cpp b/src/declarative/util/qdeclarativelistcompositor.cpp index 5f613f811d..b081549e59 100644 --- a/src/declarative/util/qdeclarativelistcompositor.cpp +++ b/src/declarative/util/qdeclarativelistcompositor.cpp @@ -222,7 +222,7 @@ bool QDeclarativeListCompositor::insertData(int index, const void *data) return true; } -bool QDeclarativeListCompositor::replaceAt(int index, const void *data) +int QDeclarativeListCompositor::replaceAt(int index, const void *data) { Q_ASSERT(index >=0 && index < absoluteCount); int internalIndex = 0; @@ -238,9 +238,9 @@ bool QDeclarativeListCompositor::replaceAt(int index, const void *data) if (range->internal()) { replaceInternalData(internalIndex, data); - return true; + return internalIndex; } else if (!insertInternalData(internalIndex, data)) { - return false; + return -1; } range->count -= 1; @@ -248,7 +248,7 @@ bool QDeclarativeListCompositor::replaceAt(int index, const void *data) int removeIndex = range->index + relativeIndex; - if (range->count == 0) { + if (range->count == 0 && !range->append()) { range->flags |= Internal; range->count = 1; } else { @@ -267,15 +267,16 @@ bool QDeclarativeListCompositor::replaceAt(int index, const void *data) } range = insert(range, QDeclarativeCompositeRange( range->list, removeIndex, 1, (range->flags | Internal) & ~Append)); + range->index += 1; } - return true; + return internalIndex; } relativeIndex -= range->count; if (range->internal()) internalIndex += range->count; ++range; } - return false; + return -1; } void QDeclarativeListCompositor::removeAt(int index, int count) @@ -297,8 +298,10 @@ void QDeclarativeListCompositor::removeAt(int index, int count) absoluteCount -= removeCount; int removeIndex = range->index + relativeIndex; - if (range->internal()) + if (range->internal()) { internalCount -= removeCount; + internalRemoveCount += removeCount; + } if (range->count == 0) { if (range->append()) { @@ -616,6 +619,64 @@ void QDeclarativeListCompositor::clear() internalCount = 0; } +void QDeclarativeListCompositor::clearData(int internalIndex, int count) +{ + Q_ASSERT(internalIndex >=0 && internalIndex + count <= internalCount); + + int relativeIndex = internalIndex; + iterator range = ranges.begin(); + while (range != ranges.end() && count > 0) { + if (!range->internal()) { + ++range; + continue; + } + if (relativeIndex < range->count) { + int removeCount = qMin(count, range->count - relativeIndex); + count -= removeCount; + if (!range->list) { + internalIndex += removeCount; + relativeIndex = 0; + continue; + } + + range->count -= removeCount; + internalCount -= removeCount; + + int removeIndex = range->index + relativeIndex; + if (range->count == 0) { + range->flags &= ~Internal; + range->count = removeCount; + // ### Merge with neighbouring nodes if appropriate. + } else { + if (relativeIndex > 0) { + int splitOffset = relativeIndex; + if (range->list) + splitOffset += removeCount; + if (splitOffset < range->count) { + Q_ASSERT(count == 0); + range = insert(range, QDeclarativeCompositeRange( + range->list, range->index, relativeIndex, range->flags & ~Append)); + range->index += splitOffset; + range->count -= splitOffset; + } else { + range->index += relativeIndex; + relativeIndex = 0; + } + } else { + range->index += removeCount; + } + range = insert(range, QDeclarativeCompositeRange( + range->list, removeIndex, removeCount, range->flags & ~Internal)); + } + removeInternalData(internalIndex, removeCount); + ++range; + continue; + } + relativeIndex -= range->count; + ++range; + } +} + int QDeclarativeListCompositor::absoluteIndexOf(int internalIndex) const { int absoluteIndex = 0; diff --git a/src/declarative/util/qdeclarativelistcompositor_p.h b/src/declarative/util/qdeclarativelistcompositor_p.h index 207f9ae4c6..2d2123ad8c 100644 --- a/src/declarative/util/qdeclarativelistcompositor_p.h +++ b/src/declarative/util/qdeclarativelistcompositor_p.h @@ -102,12 +102,13 @@ public: bool appendData(const void *data); void insertList(int index, void *list, int start, int count, bool grow); bool insertData(int index, const void *data); - bool replaceAt(int index, const void *data); + int replaceAt(int index, const void *data); void removeAt(int index, int count); void removeList(void *list, QVector<QDeclarativeChangeSet::Remove> *changes); void move(int from, int to, int count); bool merge(int from, int to); void clear(); + void clearData(int internalIndex, int count); int absoluteIndexOf(int internalIndex) const; int absoluteIndexOf(void *list, int index, int from = 0) const; |