diff options
author | Andrew den Exter <andrew.den-exter@nokia.com> | 2011-06-29 16:45:21 +1000 |
---|---|---|
committer | Andrew den Exter <andrew.den-exter@nokia.com> | 2011-06-29 16:45:21 +1000 |
commit | b961cb8f0d7d69c0343dd18a442be240fa178bf7 (patch) | |
tree | baddd8a9034e190f871687fccc6e5ac0e98c06f9 | |
parent | 8cf428d4ebd4c8c246806243730aad3a4f325300 (diff) |
Add model data accessor and merge function to VisualModel.
This provides a way to find an override a tempory item when the real
thing appears in the model data.
4 files changed, 110 insertions, 13 deletions
diff --git a/examples/declarative/modelviews/visualdatamodel/Bubble.qml b/examples/declarative/modelviews/visualdatamodel/Bubble.qml index de2c80763f..da41af8a47 100644 --- a/examples/declarative/modelviews/visualdatamodel/Bubble.qml +++ b/examples/declarative/modelviews/visualdatamodel/Bubble.qml @@ -5,6 +5,11 @@ Rectangle { property int contentHeight: height - senderText.implicitHeight - 2 + function send() { + state = "sending" + root.sending() + } + x: 1; width: 477 height: Math.max(messageText.implicitHeight, 48) + senderText.implicitHeight + 6 @@ -15,6 +20,12 @@ Rectangle { state: delegateState + Timer { + id: sendTimer + interval: 1000 + onTriggered: root.sent(messageId, sender, message, avatar) + } + Item { id: avatarItem @@ -70,7 +81,7 @@ Rectangle { anchors.fill: parent - onClicked: root.send(editorLoader.item.text) + onClicked: content.send() } } } @@ -103,8 +114,10 @@ Rectangle { wrapMode: Text.WordWrap focus: true - Keys.onReturnPressed: root.send(text) - Keys.onEnterPressed: root.send(text) + text: message + + Keys.onReturnPressed: content.send() + Keys.onEnterPressed: content.send() } } @@ -129,12 +142,19 @@ Rectangle { text: time } - states: State { - name: "composing" + states: [ + State { + name: "composing" + PropertyChanges { target: editorLoader; sourceComponent: editorComponent } + PropertyChanges { target: sendLoader; sourceComponent: sendComponent } + }, + State { + name: "sending" + PropertyChanges { target: editorLoader; sourceComponent: editorComponent } + PropertyChanges { target: sendTimer; running: true } + } - PropertyChanges { target: editorLoader; sourceComponent: editorComponent } - PropertyChanges { target: sendLoader; sourceComponent: sendComponent } - } + ] transitions: Transition { from: "composing" diff --git a/examples/declarative/modelviews/visualdatamodel/visualdatamodel.qml b/examples/declarative/modelviews/visualdatamodel/visualdatamodel.qml index 4a3e511db2..0374ac9da6 100644 --- a/examples/declarative/modelviews/visualdatamodel/visualdatamodel.qml +++ b/examples/declarative/modelviews/visualdatamodel/visualdatamodel.qml @@ -9,14 +9,26 @@ Rectangle { property string sender: "Me" property int messageCounter: 0 - function send(message) { + function sending() { visualModel.insert(visualModel.count, messageBubble) newMessage() messageView.positionViewAtEnd() } + function sent(messageId, sender, message, avatar) { + messageModel.append({ + "messageId": messageId, + "sender": sender, + "message": message, + "avatar": avatar, + "outbound": true, + "time": Qt.formatTime(Date.now()), + "delegateState": "" + }) + } + function newMessage() { - visualModel.appendData({}) + visualModel.appendData({ "messageId": ++messageCounter }) var bubble = visualModel.take(visualModel.count - 1, composer) messageBubble = bubble messageBubble.y = 0 // Override the position set by the view. @@ -45,6 +57,7 @@ Rectangle { id: visualModel roles: [ + VisualRole { name: "messageId"; }, VisualRole { name: "sender"; defaultValue: root.sender }, VisualRole { name: "message"; defaultValue: "" }, VisualRole { name: "avatar"; defaultValue: "" }, @@ -55,6 +68,28 @@ Rectangle { model: ListModel { id: messageModel } delegate: Bubble {} + + onUpdated: { + var delta = 0 + for (var i = 0; i < inserts.length; ++i) { + for (var j = inserts[i].start - delta; j < inserts[i].end - delta; ++j) { + var message = visualModel.get(j) + if (!message.outbound) + continue; + for (var k = inserts[i].start - 1 - delta; k >= 0; ++k) { + var existing = visualModel.get(k); + if (!existing.outbound) + continue; + if (message.messageId == existing.messageId) { + visualModel.merge(j, k) + ++delta + --j + break; + } + } + } + } + } } // add: Transition { @@ -73,6 +108,7 @@ Rectangle { var message = script.get(scriptIndex); messageModel.append({ + "messageId": -1, "sender": message.sender, "message": message.message, "avatar": message.avatar, diff --git a/src/declarative/items/qsgvisualitemmodel.cpp b/src/declarative/items/qsgvisualitemmodel.cpp index c2328e70e8..3a3b1596f8 100644 --- a/src/declarative/items/qsgvisualitemmodel.cpp +++ b/src/declarative/items/qsgvisualitemmodel.cpp @@ -73,11 +73,13 @@ QHash<QObject*, QSGVisualModelAttached*> QSGVisualModelAttached::attachedPropert class VDMDelegateDataType : public QDeclarativeOpenMetaObjectType { public: - VDMDelegateDataType(const QMetaObject *base, QDeclarativeEngine *engine) : QDeclarativeOpenMetaObjectType(base, engine) {} + VDMDelegateDataType(const QMetaObject *base, QDeclarativeEngine *engine) : QDeclarativeOpenMetaObjectType(base, engine), m_caching(false) {} void propertyCreated(int, QMetaPropertyBuilder &prop) { - prop.setWritable(false); + prop.setWritable(m_caching); } + + bool m_caching; }; class QSGVisualModelPartsMetaObject : public QDeclarativeOpenMetaObject @@ -400,6 +402,7 @@ public: ensureRoles(); QHash<QByteArray, int> roleNames = m_roleNames; QSGVisualModelPrivate *parent = QSGVisualModelPrivate::get(static_cast<QSGVisualModel *>(q_ptr->parent())); + m_delegateDataType->m_caching = true; 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(); @@ -409,7 +412,7 @@ public: roleNames.erase(it); } } - + m_delegateDataType->m_caching = false; if (m_roleNames.count()) { QHash<QByteArray, int>::const_iterator it = roleNames.begin(); @@ -514,6 +517,7 @@ QSGVisualModelData *QSGVisualModelPrivate::createScriptData(QDeclarativeComponen delegateDataType = new VDMDelegateDataType( &QSGVisualModelData::staticMetaObject, context ? context->engine() : qmlEngine(q)); + delegateDataType->m_caching = true; for (QList<QSGVisualModelRole *>::iterator it = roles.begin(); it != roles.end(); ++it) delegateDataType->createProperty((*it)->name().toUtf8()); } @@ -655,6 +659,23 @@ QSGItem *QSGVisualModel::take(int index, QSGItem *parent) return i; } +QScriptValue QSGVisualModel::get(int index) +{ + Q_D(QSGVisualModel); + QDeclarativeEngine *dengine = d->context ? d->context->engine() : qmlEngine(this); + QScriptEngine *engine = QDeclarativeEnginePrivate::getScriptEngine(dengine); + int offset = 0; + int internalIndex = 0; + QDeclarativeCompositeRange range = d->at(index, &offset, &internalIndex); + if (range.internal()) { + return engine->newQObject(d->children[internalIndex].data); + } else { + return engine->newQObject( + new QSGVisualModelData(range.index + offset, static_cast<QSGVisualData *>(range.list)), + QScriptEngine::ScriptOwnership); + } +} + QSGVisualModel::ReleaseFlags QSGVisualModel::release(QObject *object) { Q_D(QSGVisualModel); @@ -989,6 +1010,24 @@ void QSGVisualModel::move(int from, int to, int count) } } +void QSGVisualModel::merge(int from, int to) +{ + Q_D(QSGVisualModel); + if (from == to) + return; + if (!d->transaction) + d->childrenChanged = false; + if (!d->merge(from, to)) { + qmlInfo(this) << "Items cannot be merged" << from << to; + } else if (d->transaction) { + d->transactionChanges.insertRemove(from, 1); + } else { + emit itemsRemoved(from, 1); + if (d->childrenChanged) + emit childrenChanged(); + } +} + void QSGVisualModel::_q_itemsInserted(QSGVisualData *model, int index, int count) { Q_D(QSGVisualModel); diff --git a/src/declarative/items/qsgvisualitemmodel_p.h b/src/declarative/items/qsgvisualitemmodel_p.h index d4a7084fa3..cc8a93c8d9 100644 --- a/src/declarative/items/qsgvisualitemmodel_p.h +++ b/src/declarative/items/qsgvisualitemmodel_p.h @@ -109,6 +109,7 @@ public: static QSGVisualModelAttached *qmlAttachedProperties(QObject *obj); + Q_INVOKABLE QScriptValue get(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); @@ -124,6 +125,7 @@ public Q_SLOTS: void insert(int index, QDeclarativeComponent *delegate, const QScriptValue &data); void remove(int index, int count); void move(int from, int to, int count); + void merge(int from, int to); Q_SIGNALS: void childrenChanged(); |