From 8e87197c2afa19df1fb15cb9b6b3cc17c3d4c0d6 Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Thu, 1 Apr 2010 15:29:26 +1000 Subject: Optimization: Improve allocation strategy for QDeclarativeDeclarativeData This improves the declarative/creation/itemtree_qml benchmark by 6% --- src/corelib/kernel/qobject.cpp | 8 ++-- src/corelib/kernel/qobject_p.h | 5 +-- src/declarative/qml/qdeclarativecompiler.cpp | 45 ++++++++++++++-------- .../qml/qdeclarativedeclarativedata_p.h | 8 +++- src/declarative/qml/qdeclarativeengine.cpp | 14 +++++++ src/declarative/qml/qdeclarativeinstruction.cpp | 2 + src/declarative/qml/qdeclarativeinstruction_p.h | 7 ++++ src/declarative/qml/qdeclarativemetatype.cpp | 10 +++++ src/declarative/qml/qdeclarativemetatype_p.h | 4 ++ src/declarative/qml/qdeclarativevme.cpp | 22 ++++++++++- 10 files changed, 101 insertions(+), 24 deletions(-) diff --git a/src/corelib/kernel/qobject.cpp b/src/corelib/kernel/qobject.cpp index dbc6be2..dfd6a08 100644 --- a/src/corelib/kernel/qobject.cpp +++ b/src/corelib/kernel/qobject.cpp @@ -125,8 +125,10 @@ extern "C" Q_CORE_EXPORT void qt_removeObject(QObject *) } } +void (*QDeclarativeData::destroyed)(QDeclarativeData *, QObject *) = 0; +void (*QDeclarativeData::parentChanged)(QDeclarativeData *, QObject *, QObject *) = 0; + QObjectData::~QObjectData() {} -QDeclarativeData::~QDeclarativeData() {} QObjectPrivate::QObjectPrivate(int version) : threadData(0), connectionLists(0), senders(0), currentSender(0), currentChildBeingDeleted(0) @@ -876,7 +878,7 @@ QObject::~QObject() } if (d->declarativeData) - d->declarativeData->destroyed(this); + QDeclarativeData::destroyed(d->declarativeData, this); { QMutex *signalSlotMutex = 0; @@ -2025,7 +2027,7 @@ void QObjectPrivate::setParent_helper(QObject *o) } } if (!wasDeleted && declarativeData) - declarativeData->parentChanged(q, o); + QDeclarativeData::parentChanged(declarativeData, q, o); } /*! diff --git a/src/corelib/kernel/qobject_p.h b/src/corelib/kernel/qobject_p.h index 3b59abb..e5d904c 100644 --- a/src/corelib/kernel/qobject_p.h +++ b/src/corelib/kernel/qobject_p.h @@ -87,9 +87,8 @@ enum { QObjectPrivateVersion = QT_VERSION }; class Q_CORE_EXPORT QDeclarativeData { public: - virtual ~QDeclarativeData(); - virtual void destroyed(QObject *) = 0; - virtual void parentChanged(QObject *, QObject *) = 0; + static void (*destroyed)(QDeclarativeData *, QObject *); + static void (*parentChanged)(QDeclarativeData *, QObject *, QObject *); }; class Q_CORE_EXPORT QObjectPrivate : public QObjectData diff --git a/src/declarative/qml/qdeclarativecompiler.cpp b/src/declarative/qml/qdeclarativecompiler.cpp index 56af5f5..27fecfb 100644 --- a/src/declarative/qml/qdeclarativecompiler.cpp +++ b/src/declarative/qml/qdeclarativecompiler.cpp @@ -881,23 +881,38 @@ void QDeclarativeCompiler::genObject(QDeclarativeParser::Object *obj) } // Create the object - QDeclarativeInstruction create; - create.type = QDeclarativeInstruction::CreateObject; - create.line = obj->location.start.line; - create.create.column = obj->location.start.column; - create.create.data = -1; - if (!obj->custom.isEmpty()) - create.create.data = output->indexForByteArray(obj->custom); - create.create.type = obj->type; - if (!output->types.at(create.create.type).type && - !obj->bindingBitmask.isEmpty()) { - Q_ASSERT(obj->bindingBitmask.size() % 4 == 0); - create.create.bindingBits = - output->indexForByteArray(obj->bindingBitmask); + if (obj->custom.isEmpty() && output->types.at(obj->type).type && + obj != compileState.root) { + + QDeclarativeInstruction create; + create.type = QDeclarativeInstruction::CreateSimpleObject; + create.line = obj->location.start.line; + create.createSimple.create = output->types.at(obj->type).type->createFunction(); + create.createSimple.typeSize = output->types.at(obj->type).type->createSize(); + create.createSimple.column = obj->location.start.column; + output->bytecode << create; + } else { - create.create.bindingBits = -1; + + QDeclarativeInstruction create; + create.type = QDeclarativeInstruction::CreateObject; + create.line = obj->location.start.line; + create.create.column = obj->location.start.column; + create.create.data = -1; + if (!obj->custom.isEmpty()) + create.create.data = output->indexForByteArray(obj->custom); + create.create.type = obj->type; + if (!output->types.at(create.create.type).type && + !obj->bindingBitmask.isEmpty()) { + Q_ASSERT(obj->bindingBitmask.size() % 4 == 0); + create.create.bindingBits = + output->indexForByteArray(obj->bindingBitmask); + } else { + create.create.bindingBits = -1; + } + output->bytecode << create; + } - output->bytecode << create; // Setup the synthesized meta object if necessary if (!obj->metadata.isEmpty()) { diff --git a/src/declarative/qml/qdeclarativedeclarativedata_p.h b/src/declarative/qml/qdeclarativedeclarativedata_p.h index d1d063a..dfc3113 100644 --- a/src/declarative/qml/qdeclarativedeclarativedata_p.h +++ b/src/declarative/qml/qdeclarativedeclarativedata_p.h @@ -64,6 +64,10 @@ class QDeclarativeAbstractBinding; class QDeclarativeContext; class QDeclarativePropertyCache; class QDeclarativeContextData; +// This class is structured in such a way, that simply zero'ing it is the +// default state for elemental object allocations. This is crucial in the +// workings of the QDeclarativeInstruction::CreateSimpleObject instruction. +// Don't change anything here without first considering that case! class Q_AUTOTEST_EXPORT QDeclarativeDeclarativeData : public QDeclarativeData { public: @@ -73,8 +77,8 @@ public: bindingBits(0), lineNumber(0), columnNumber(0), deferredComponent(0), deferredIdx(0), attachedProperties(0), propertyCache(0), guards(0) {} - virtual void destroyed(QObject *); - virtual void parentChanged(QObject *, QObject *); + void destroyed(QObject *); + void parentChanged(QObject *, QObject *); void setImplicitDestructible() { if (!explicitIndestructibleSet) indestructible = false; diff --git a/src/declarative/qml/qdeclarativeengine.cpp b/src/declarative/qml/qdeclarativeengine.cpp index 3e570e5..65dd72b 100644 --- a/src/declarative/qml/qdeclarativeengine.cpp +++ b/src/declarative/qml/qdeclarativeengine.cpp @@ -346,6 +346,17 @@ Q_GLOBAL_STATIC(QDeclarativeEngineDebugServer, qmlEngineDebugServer); typedef QMap StringStringMap; Q_GLOBAL_STATIC(StringStringMap, qmlEnginePluginsWithRegisteredTypes); // stores the uri + +static void QDeclarativeDeclarativeData_destroyed(QDeclarativeData *d, QObject *o) +{ + static_cast(d)->destroyed(o); +} + +static void QDeclarativeDeclarativeData_parentChanged(QDeclarativeData *d, QObject *o, QObject *p) +{ + static_cast(d)->parentChanged(o, p); +} + void QDeclarativeEnginePrivate::init() { Q_Q(QDeclarativeEngine); @@ -353,6 +364,9 @@ void QDeclarativeEnginePrivate::init() qRegisterMetaType("QDeclarativeScriptString"); qRegisterMetaType("QScriptValue"); + QDeclarativeData::destroyed = QDeclarativeDeclarativeData_destroyed; + QDeclarativeData::parentChanged = QDeclarativeDeclarativeData_parentChanged; + contextClass = new QDeclarativeContextScriptClass(q); objectClass = new QDeclarativeObjectScriptClass(q); valueTypeClass = new QDeclarativeValueTypeScriptClass(q); diff --git a/src/declarative/qml/qdeclarativeinstruction.cpp b/src/declarative/qml/qdeclarativeinstruction.cpp index 9083ab3..36e5a2d 100644 --- a/src/declarative/qml/qdeclarativeinstruction.cpp +++ b/src/declarative/qml/qdeclarativeinstruction.cpp @@ -60,6 +60,8 @@ void QDeclarativeCompiledData::dump(QDeclarativeInstruction *instr, int idx) break; case QDeclarativeInstruction::CreateObject: qWarning().nospace() << idx << "\t\t" << line << "\t" << "CREATE\t\t\t" << instr->create.type << "\t\t\t" << types.at(instr->create.type).className; + case QDeclarativeInstruction::CreateSimpleObject: + qWarning().nospace() << idx << "\t\t" << line << "\t" << "CREATE_SIMPLE\t\t" << instr->createSimple.typeSize; break; case QDeclarativeInstruction::SetId: qWarning().nospace() << idx << "\t\t" << line << "\t" << "SETID\t\t\t" << instr->setId.value << "\t\t\t" << primitives.at(instr->setId.value); diff --git a/src/declarative/qml/qdeclarativeinstruction_p.h b/src/declarative/qml/qdeclarativeinstruction_p.h index 877179d..1f3c964 100644 --- a/src/declarative/qml/qdeclarativeinstruction_p.h +++ b/src/declarative/qml/qdeclarativeinstruction_p.h @@ -74,6 +74,7 @@ public: // top of the stack. Init, /* init */ CreateObject, /* create */ + CreateSimpleObject, /* createSimple */ SetId, /* setId */ SetDefault, CreateComponent, /* createComponent */ @@ -175,6 +176,11 @@ public: int bindingBits; ushort column; }; + struct CreateSimpleInstruction { + void (*create)(void *); + int typeSize; + ushort column; + }; struct StoreMetaInstruction { int data; int aliasData; @@ -305,6 +311,7 @@ public: union { InitInstruction init; CreateInstruction create; + CreateSimpleInstruction createSimple; StoreMetaInstruction storeMeta; SetIdInstruction setId; AssignValueSourceInstruction assignValueSource; diff --git a/src/declarative/qml/qdeclarativemetatype.cpp b/src/declarative/qml/qdeclarativemetatype.cpp index c512d97..6f99f95 100644 --- a/src/declarative/qml/qdeclarativemetatype.cpp +++ b/src/declarative/qml/qdeclarativemetatype.cpp @@ -313,6 +313,16 @@ QDeclarativeCustomParser *QDeclarativeType::customParser() const return d->m_customParser; } +QDeclarativeType::CreateFunc QDeclarativeType::createFunction() const +{ + return d->m_newFunc; +} + +int QDeclarativeType::createSize() const +{ + return d->m_allocationSize; +} + bool QDeclarativeType::isCreatable() const { return d->m_newFunc != 0; diff --git a/src/declarative/qml/qdeclarativemetatype_p.h b/src/declarative/qml/qdeclarativemetatype_p.h index b3ec5e3..96e3c74 100644 --- a/src/declarative/qml/qdeclarativemetatype_p.h +++ b/src/declarative/qml/qdeclarativemetatype_p.h @@ -115,6 +115,10 @@ public: QObject *create() const; void create(QObject **, void **, size_t) const; + typedef void (*CreateFunc)(void *); + CreateFunc createFunction() const; + int createSize() const; + QDeclarativeCustomParser *customParser() const; bool isCreatable() const; diff --git a/src/declarative/qml/qdeclarativevme.cpp b/src/declarative/qml/qdeclarativevme.cpp index 2338bc3..6498e6c 100644 --- a/src/declarative/qml/qdeclarativevme.cpp +++ b/src/declarative/qml/qdeclarativevme.cpp @@ -236,13 +236,33 @@ QObject *QDeclarativeVME::run(QDeclarativeVMEStack &stack, } } else { QDeclarative_setParent_noEvent(o, parent); - // o->setParent(parent); } } stack.push(o); } break; + case QDeclarativeInstruction::CreateSimpleObject: + { + QObject *o = (QObject *)operator new(instr.createSimple.typeSize + + sizeof(QDeclarativeDeclarativeData)); + ::bzero(o, instr.createSimple.typeSize + sizeof(QDeclarativeDeclarativeData)); + instr.createSimple.create(o); + + QDeclarativeDeclarativeData *ddata = + (QDeclarativeDeclarativeData *)(((const char *)o) + instr.createSimple.typeSize); + ddata->lineNumber = instr.line; + ddata->columnNumber = instr.createSimple.column; + + QObjectPrivate::get(o)->declarativeData = ddata; + ctxt->addObject(o); + QObject *parent = stack.top(); + QDeclarative_setParent_noEvent(o, parent); + + stack.push(o); + } + break; + case QDeclarativeInstruction::SetId: { QObject *target = stack.top(); -- cgit v0.12 From b8b4613800abfe1bc8861011c7152d6d242414e1 Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Thu, 1 Apr 2010 15:59:59 +1000 Subject: Optimization: Minor object allocation speedup --- src/declarative/qml/qdeclarativevme.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/declarative/qml/qdeclarativevme.cpp b/src/declarative/qml/qdeclarativevme.cpp index 6498e6c..0bdc4d5 100644 --- a/src/declarative/qml/qdeclarativevme.cpp +++ b/src/declarative/qml/qdeclarativevme.cpp @@ -255,7 +255,13 @@ QObject *QDeclarativeVME::run(QDeclarativeVMEStack &stack, ddata->columnNumber = instr.createSimple.column; QObjectPrivate::get(o)->declarativeData = ddata; - ctxt->addObject(o); + + ddata->nextContextObject = ctxt->contextObjects; + if (ddata->nextContextObject) + ddata->nextContextObject->prevContextObject = &ddata->nextContextObject; + ddata->prevContextObject = &ctxt->contextObjects; + ctxt->contextObjects = ddata; + QObject *parent = stack.top(); QDeclarative_setParent_noEvent(o, parent); -- cgit v0.12 From 8907d7cc427e5f1022c6f25944a123e65391c4f2 Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Thu, 1 Apr 2010 17:11:36 +1000 Subject: Crash: Assign context in CreateSimpleObject too --- src/declarative/qml/qdeclarativevme.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/declarative/qml/qdeclarativevme.cpp b/src/declarative/qml/qdeclarativevme.cpp index 0bdc4d5..487ec0c 100644 --- a/src/declarative/qml/qdeclarativevme.cpp +++ b/src/declarative/qml/qdeclarativevme.cpp @@ -255,13 +255,13 @@ QObject *QDeclarativeVME::run(QDeclarativeVMEStack &stack, ddata->columnNumber = instr.createSimple.column; QObjectPrivate::get(o)->declarativeData = ddata; - - ddata->nextContextObject = ctxt->contextObjects; + ddata->context = ddata->outerContext = ctxt; + ddata->nextContextObject = ctxt->contextObjects; if (ddata->nextContextObject) - ddata->nextContextObject->prevContextObject = &ddata->nextContextObject; - ddata->prevContextObject = &ctxt->contextObjects; - ctxt->contextObjects = ddata; - + ddata->nextContextObject->prevContextObject = &ddata->nextContextObject; + ddata->prevContextObject = &ctxt->contextObjects; + ctxt->contextObjects = ddata; + QObject *parent = stack.top(); QDeclarative_setParent_noEvent(o, parent); -- cgit v0.12 From 739c1c6a4322c0d48afd2a24e3dc2156fee577e1 Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Thu, 1 Apr 2010 17:17:37 +1000 Subject: Optimization: Only allocate QScriptValue if we need too --- src/declarative/qml/qdeclarativedeclarativedata_p.h | 6 ++++-- src/declarative/qml/qdeclarativeengine.cpp | 7 ++++--- src/declarative/qml/qdeclarativeobjectscriptclass.cpp | 10 +++++----- 3 files changed, 13 insertions(+), 10 deletions(-) diff --git a/src/declarative/qml/qdeclarativedeclarativedata_p.h b/src/declarative/qml/qdeclarativedeclarativedata_p.h index dfc3113..aea775b 100644 --- a/src/declarative/qml/qdeclarativedeclarativedata_p.h +++ b/src/declarative/qml/qdeclarativedeclarativedata_p.h @@ -75,7 +75,7 @@ public: : ownMemory(true), ownContext(false), indestructible(true), explicitIndestructibleSet(false), context(0), outerContext(0), bindings(0), nextContextObject(0), prevContextObject(0), bindingBitsSize(0), bindingBits(0), lineNumber(0), columnNumber(0), deferredComponent(0), deferredIdx(0), - attachedProperties(0), propertyCache(0), guards(0) {} + attachedProperties(0), scriptValue(0), propertyCache(0), guards(0) {} void destroyed(QObject *); void parentChanged(QObject *, QObject *); @@ -113,7 +113,9 @@ public: QHash *attachedProperties; - QScriptValue scriptValue; + // ### Can we make this QScriptValuePrivate so we incur no additional allocation + // cost? + QScriptValue *scriptValue; QDeclarativePropertyCache *propertyCache; QDeclarativeGuard *guards; diff --git a/src/declarative/qml/qdeclarativeengine.cpp b/src/declarative/qml/qdeclarativeengine.cpp index 65dd72b..cf5fc3b 100644 --- a/src/declarative/qml/qdeclarativeengine.cpp +++ b/src/declarative/qml/qdeclarativeengine.cpp @@ -862,15 +862,16 @@ void QDeclarativeDeclarativeData::destroyed(QObject *object) if (ownContext) context->destroy(); + if (scriptValue) + delete scriptValue; + if (ownMemory) delete this; - else - this->~QDeclarativeDeclarativeData(); } void QDeclarativeDeclarativeData::parentChanged(QObject *, QObject *parent) { - if (!parent && scriptValue.isValid()) scriptValue = QScriptValue(); + if (!parent && scriptValue) { delete scriptValue; scriptValue = 0; } } bool QDeclarativeDeclarativeData::hasBindingBit(int bit) const diff --git a/src/declarative/qml/qdeclarativeobjectscriptclass.cpp b/src/declarative/qml/qdeclarativeobjectscriptclass.cpp index 84c9bef..1424508 100644 --- a/src/declarative/qml/qdeclarativeobjectscriptclass.cpp +++ b/src/declarative/qml/qdeclarativeobjectscriptclass.cpp @@ -109,11 +109,11 @@ QScriptValue QDeclarativeObjectScriptClass::newQObject(QObject *object, int type return scriptEngine->undefinedValue(); } else if (!ddata->indestructible && !object->parent()) { return newObject(scriptEngine, this, new ObjectData(object, type)); - } else if (!ddata->scriptValue.isValid()) { - ddata->scriptValue = newObject(scriptEngine, this, new ObjectData(object, type)); - return ddata->scriptValue; - } else if (ddata->scriptValue.engine() == QDeclarativeEnginePrivate::getScriptEngine(engine)) { - return ddata->scriptValue; + } else if (!ddata->scriptValue) { + ddata->scriptValue = new QScriptValue(newObject(scriptEngine, this, new ObjectData(object, type))); + return *ddata->scriptValue; + } else if (ddata->scriptValue->engine() == QDeclarativeEnginePrivate::getScriptEngine(engine)) { + return *ddata->scriptValue; } else { return newObject(scriptEngine, this, new ObjectData(object, type)); } -- cgit v0.12 From 56ba9096ad78302214a200b0eea7033f3880b0b7 Mon Sep 17 00:00:00 2001 From: Michael Brasser Date: Wed, 31 Mar 2010 15:31:47 +1000 Subject: Expand test. --- .../qdeclarativestyledtext/tst_qdeclarativestyledtext.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/auto/declarative/qdeclarativestyledtext/tst_qdeclarativestyledtext.cpp b/tests/auto/declarative/qdeclarativestyledtext/tst_qdeclarativestyledtext.cpp index 7b1293e..e475d42 100644 --- a/tests/auto/declarative/qdeclarativestyledtext/tst_qdeclarativestyledtext.cpp +++ b/tests/auto/declarative/qdeclarativestyledtext/tst_qdeclarativestyledtext.cpp @@ -71,11 +71,16 @@ void tst_qdeclarativestyledtext::textOutput_data() QTest::newRow("missing ") << "text" << "text"; QTest::newRow("bad nest") << "text italic" << "text italic"; QTest::newRow("font color") << "red text" << "red text"; + QTest::newRow("font color: single quote") << "red text" << "red text"; QTest::newRow("font size") << "text" << "text"; QTest::newRow("font empty") << "text" << "text"; QTest::newRow("font bad 1") << "text" << "text"; QTest::newRow("font bad 2") << "text" << ""; QTest::newRow("extra close") << "text" << "text"; + QTest::newRow("extra space") << "text" << "text"; + QTest::newRow("entities") << "<b>this & that</b>" << "this & that"; + QTest::newRow("newline") << "text
more text" << QLatin1String("text") + QChar(QChar::LineSeparator) + QLatin1String("more text") ; + QTest::newRow("self-closing newline") << "text
more text" << QLatin1String("text") + QChar(QChar::LineSeparator) + QLatin1String("more text") ; QTest::newRow("empty") << "" << ""; } -- cgit v0.12 From 32fdd579afc2933ccc5fc658553cf18cf2057ff2 Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Wed, 7 Apr 2010 12:30:34 +1000 Subject: Compile Apply the ~QObject QDeclarativeData logic to ~QWidget --- src/gui/kernel/qwidget.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/kernel/qwidget.cpp b/src/gui/kernel/qwidget.cpp index e88026c..9353d10 100644 --- a/src/gui/kernel/qwidget.cpp +++ b/src/gui/kernel/qwidget.cpp @@ -1478,7 +1478,7 @@ QWidget::~QWidget() QObjectPrivate::clearGuards(this); if (d->declarativeData) { - d->declarativeData->destroyed(this); + QDeclarativeData::destroyed(d->declarativeData, this); d->declarativeData = 0; // don't activate again in ~QObject } -- cgit v0.12 From 973cfce37fcdd1ce330f237eaa76930db55a73f6 Mon Sep 17 00:00:00 2001 From: Bea Lam Date: Wed, 7 Apr 2010 11:53:16 +1000 Subject: Add QListModelInterface::modelReset() signal and emit this in XmlListModel when all data has changed. --- src/declarative/3rdparty/qlistmodelinterface.cpp | 6 +++ src/declarative/3rdparty/qlistmodelinterface_p.h | 1 + .../graphicsitems/qdeclarativevisualitemmodel.cpp | 2 + src/declarative/util/qdeclarativexmllistmodel.cpp | 25 +++++----- src/declarative/util/qdeclarativexmllistmodel_p.h | 1 + .../tst_qdeclarativexmllistmodel.cpp | 54 ++++++++-------------- 6 files changed, 43 insertions(+), 46 deletions(-) diff --git a/src/declarative/3rdparty/qlistmodelinterface.cpp b/src/declarative/3rdparty/qlistmodelinterface.cpp index 98d6a5b..20501a0 100644 --- a/src/declarative/3rdparty/qlistmodelinterface.cpp +++ b/src/declarative/3rdparty/qlistmodelinterface.cpp @@ -106,4 +106,10 @@ QT_BEGIN_NAMESPACE \a roles changed. */ +/*! \fn void QListModelInterface::modelReset() + Emit this signal when all of the model data has changed. + This is more efficient than forcing the receivier to handle multiple + inserted and removed signals etc. +*/ + QT_END_NAMESPACE diff --git a/src/declarative/3rdparty/qlistmodelinterface_p.h b/src/declarative/3rdparty/qlistmodelinterface_p.h index 07592ad..da91d12 100644 --- a/src/declarative/3rdparty/qlistmodelinterface_p.h +++ b/src/declarative/3rdparty/qlistmodelinterface_p.h @@ -72,6 +72,7 @@ class Q_DECLARATIVE_EXPORT QListModelInterface : public QObject void itemsRemoved(int index, int count); void itemsMoved(int from, int to, int count); void itemsChanged(int index, int count, const QList &roles); + void modelReset(); protected: QListModelInterface(QObjectPrivate &dd, QObject *parent) diff --git a/src/declarative/graphicsitems/qdeclarativevisualitemmodel.cpp b/src/declarative/graphicsitems/qdeclarativevisualitemmodel.cpp index 2938f51..172362c 100644 --- a/src/declarative/graphicsitems/qdeclarativevisualitemmodel.cpp +++ b/src/declarative/graphicsitems/qdeclarativevisualitemmodel.cpp @@ -662,6 +662,7 @@ void QDeclarativeVisualDataModel::setModel(const QVariant &model) this, SLOT(_q_itemsRemoved(int,int))); QObject::disconnect(d->m_listModelInterface, SIGNAL(itemsMoved(int,int,int)), this, SLOT(_q_itemsMoved(int,int,int))); + QObject::disconnect(d->m_listModelInterface, SIGNAL(modelReset()), this, SLOT(_q_modelReset())); d->m_listModelInterface = 0; } else if (d->m_abstractItemModel) { QObject::disconnect(d->m_abstractItemModel, SIGNAL(rowsInserted(const QModelIndex &,int,int)), @@ -705,6 +706,7 @@ void QDeclarativeVisualDataModel::setModel(const QVariant &model) this, SLOT(_q_itemsRemoved(int,int))); QObject::connect(d->m_listModelInterface, SIGNAL(itemsMoved(int,int,int)), this, SLOT(_q_itemsMoved(int,int,int))); + QObject::connect(d->m_listModelInterface, SIGNAL(modelReset()), this, SLOT(_q_modelReset())); d->m_metaDataCacheable = true; if (d->m_delegate && d->m_listModelInterface->count()) emit itemsInserted(0, d->m_listModelInterface->count()); diff --git a/src/declarative/util/qdeclarativexmllistmodel.cpp b/src/declarative/util/qdeclarativexmllistmodel.cpp index b33af06..11c7305 100644 --- a/src/declarative/util/qdeclarativexmllistmodel.cpp +++ b/src/declarative/util/qdeclarativexmllistmodel.cpp @@ -878,21 +878,22 @@ void QDeclarativeXmlListModel::queryCompleted(const QDeclarativeXmlQueryResult & } } if (!hasKeys) { - if (!(origCount == 0 && d->size == 0)) { - emit itemsRemoved(0, origCount); - emit itemsInserted(0, d->size); - emit countChanged(); - } + if (!(origCount == 0 && d->size == 0)) + emit modelReset(); } else { + if (result.removed.count() == 1 && result.removed[0].first == 0 + && result.removed[0].second == origCount) { + emit modelReset(); + } else { + for (int i=0; istatus); diff --git a/src/declarative/util/qdeclarativexmllistmodel_p.h b/src/declarative/util/qdeclarativexmllistmodel_p.h index 7b85476..fd410a7 100644 --- a/src/declarative/util/qdeclarativexmllistmodel_p.h +++ b/src/declarative/util/qdeclarativexmllistmodel_p.h @@ -124,6 +124,7 @@ Q_SIGNALS: void xmlChanged(); void queryChanged(); void namespaceDeclarationsChanged(); + void modelReset(); public Q_SLOTS: // ### need to use/expose Expiry to guess when to call this? diff --git a/tests/auto/declarative/qdeclarativexmllistmodel/tst_qdeclarativexmllistmodel.cpp b/tests/auto/declarative/qdeclarativexmllistmodel/tst_qdeclarativexmllistmodel.cpp index 74da79e..ba0f9a7 100644 --- a/tests/auto/declarative/qdeclarativexmllistmodel/tst_qdeclarativexmllistmodel.cpp +++ b/tests/auto/declarative/qdeclarativexmllistmodel/tst_qdeclarativexmllistmodel.cpp @@ -378,17 +378,16 @@ void tst_qdeclarativexmllistmodel::reload() QSignalSpy spyInsert(model, SIGNAL(itemsInserted(int,int))); QSignalSpy spyRemove(model, SIGNAL(itemsRemoved(int,int))); QSignalSpy spyCount(model, SIGNAL(countChanged())); + QSignalSpy spyReset(model, SIGNAL(modelReset())); model->reload(); - QTRY_COMPARE(spyCount.count(), 1); - QTRY_COMPARE(spyInsert.count(), 1); - QTRY_COMPARE(spyRemove.count(), 1); - - QCOMPARE(spyInsert[0][0].toInt(), 0); - QCOMPARE(spyInsert[0][1].toInt(), 9); + QTRY_COMPARE(spyReset.count(), 1); + QCOMPARE(spyCount.count(), 0); + QCOMPARE(spyInsert.count(), 0); + QCOMPARE(spyRemove.count(), 0); - QCOMPARE(spyRemove[0][0].toInt(), 0); - QCOMPARE(spyRemove[0][1].toInt(), 9); + QCOMPARE(model->data(0, model->roles().first()).toString(), QString("Polly")); + QCOMPARE(model->data(model->count()-1, model->roles().first()).toString(), QString("Tiny")); delete model; } @@ -416,15 +415,15 @@ void tst_qdeclarativexmllistmodel::useKeys() QSignalSpy spyInsert(model, SIGNAL(itemsInserted(int,int))); QSignalSpy spyRemove(model, SIGNAL(itemsRemoved(int,int))); QSignalSpy spyCount(model, SIGNAL(countChanged())); + QSignalSpy spyReset(model, SIGNAL(modelReset())); model->setXml(newXml); - if (oldCount != newData.count()) { - QTRY_COMPARE(model->count(), newData.count()); - QCOMPARE(spyCount.count(), 1); + if (insertRanges.isEmpty() && removeRanges.isEmpty()) { + QTRY_COMPARE(spyReset.count(), 1); } else { QTRY_VERIFY(spyInsert.count() > 0 || spyRemove.count() > 0); - QCOMPARE(spyCount.count(), 0); + QCOMPARE(spyCount.count() == 0, oldCount == newData.count()); } QList roles = model->roles(); @@ -513,21 +512,14 @@ void tst_qdeclarativexmllistmodel::useKeys_data() << makeItemXmlAndData("", &modelData) << modelData << QList() - << (QList() << qMakePair(0, 3)); + << QList(); QTest::newRow("replace item") << makeItemXmlAndData("name=A,age=25,sport=Football") << 1 << makeItemXmlAndData("name=ZZZ,age=25,sport=Football", &modelData) << modelData - << (QList() << qMakePair(0, 1)) - << (QList() << qMakePair(0, 1)); - - QTest::newRow("add and remove simultaneously, in different spots") - << makeItemXmlAndData("name=A,age=25,sport=Football;name=B,age=35,sport=Athletics;name=C,age=45,sport=Curling;name=D,age=55,sport=Golf") << 4 - << makeItemXmlAndData("name=B,age=35,sport=Athletics;name=E,age=65,sport=Fencing", &modelData) - << modelData - << (QList() << qMakePair(1, 1)) - << (QList() << qMakePair(0, 1) << qMakePair(2,2)); + << QList() + << QList(); QTest::newRow("insert at start, remove at end i.e. rss feed") << makeItemXmlAndData("name=C,age=45,sport=Curling;name=D,age=55,sport=Golf;name=E,age=65,sport=Fencing") << 3 @@ -547,8 +539,8 @@ void tst_qdeclarativexmllistmodel::useKeys_data() << makeItemXmlAndData("name=A,age=25,sport=Football;name=B,age=35") << 2 << makeItemXmlAndData("name=C,age=45,sport=Curling;name=D,age=55,sport=Golf", &modelData) << modelData - << (QList() << qMakePair(0, 2)) - << (QList() << qMakePair(0, 2)); + << QList() + << QList(); } void tst_qdeclarativexmllistmodel::noKeysValueChanges() @@ -608,20 +600,14 @@ void tst_qdeclarativexmllistmodel::keysChanged() QSignalSpy spyInsert(model, SIGNAL(itemsInserted(int,int))); QSignalSpy spyRemove(model, SIGNAL(itemsRemoved(int,int))); QSignalSpy spyCount(model, SIGNAL(countChanged())); + QSignalSpy spyReset(model, SIGNAL(modelReset())); QVERIFY(QMetaObject::invokeMethod(model, "disableNameKey")); model->setXml(xml); - QTRY_VERIFY(spyInsert.count() > 0 && spyRemove.count() > 0); - - QCOMPARE(spyInsert.count(), 1); - QCOMPARE(spyInsert[0][0].toInt(), 0); - QCOMPARE(spyInsert[0][1].toInt(), 2); - - QCOMPARE(spyRemove.count(), 1); - QCOMPARE(spyRemove[0][0].toInt(), 0); - QCOMPARE(spyRemove[0][1].toInt(), 2); - + QTRY_COMPARE(spyReset.count(), 1); + QCOMPARE(spyInsert.count(), 0); + QCOMPARE(spyRemove.count(), 0); QCOMPARE(spyCount.count(), 0); delete model; -- cgit v0.12 From 062e30769c2b04a5d8d0906c39a2bcb35defd3a2 Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Wed, 7 Apr 2010 13:00:08 +1000 Subject: Allow iteration over the Item.children property QTBUG-9645 --- src/gui/graphicsview/qgraphicsitem.cpp | 20 +++++++++++-- src/gui/graphicsview/qgraphicsitem_p.h | 5 +++- .../qdeclarativeitem/data/childrenProperty.qml | 14 +++++++++ .../qdeclarativeitem/data/resourcesProperty.qml | 21 ++++++++++++++ .../qdeclarativeitem/tst_qdeclarativeitem.cpp | 33 ++++++++++++++++++++++ 5 files changed, 90 insertions(+), 3 deletions(-) create mode 100644 tests/auto/declarative/qdeclarativeitem/data/childrenProperty.qml create mode 100644 tests/auto/declarative/qdeclarativeitem/data/resourcesProperty.qml diff --git a/src/gui/graphicsview/qgraphicsitem.cpp b/src/gui/graphicsview/qgraphicsitem.cpp index f106b3d..3245aec 100644 --- a/src/gui/graphicsview/qgraphicsitem.cpp +++ b/src/gui/graphicsview/qgraphicsitem.cpp @@ -7614,11 +7614,26 @@ void QGraphicsObject::updateMicroFocus() QGraphicsItem::updateMicroFocus(); } -void QGraphicsItemPrivate::append(QDeclarativeListProperty *list, QGraphicsObject *item) +void QGraphicsItemPrivate::children_append(QDeclarativeListProperty *list, QGraphicsObject *item) { QGraphicsItemPrivate::get(item)->setParentItemHelper(static_cast(list->object), /*newParentVariant=*/0, /*thisPointerVariant=*/0); } +int QGraphicsItemPrivate::children_count(QDeclarativeListProperty *list) +{ + QGraphicsItemPrivate *d = QGraphicsItemPrivate::get(static_cast(list->object)); + return d->children.count(); +} + +QGraphicsObject *QGraphicsItemPrivate::children_at(QDeclarativeListProperty *list, int index) +{ + QGraphicsItemPrivate *d = QGraphicsItemPrivate::get(static_cast(list->object)); + if (index >= 0 && index < d->children.count()) + return d->children.at(index)->toGraphicsObject(); + else + return 0; +} + /*! Returns a list of this item's children. @@ -7631,7 +7646,8 @@ QDeclarativeListProperty QGraphicsItemPrivate::childrenList() Q_Q(QGraphicsItem); if (isObject) { QGraphicsObject *that = static_cast(q); - return QDeclarativeListProperty(that, &children, QGraphicsItemPrivate::append); + return QDeclarativeListProperty(that, &children, children_append, + children_count, children_at); } else { //QGraphicsItem is not supported for this property return QDeclarativeListProperty(); diff --git a/src/gui/graphicsview/qgraphicsitem_p.h b/src/gui/graphicsview/qgraphicsitem_p.h index 73b8f04..922581d 100644 --- a/src/gui/graphicsview/qgraphicsitem_p.h +++ b/src/gui/graphicsview/qgraphicsitem_p.h @@ -480,9 +480,12 @@ public: void resetFocusProxy(); virtual void subFocusItemChange(); + static void children_append(QDeclarativeListProperty *list, QGraphicsObject *item); + static int children_count(QDeclarativeListProperty *list); + static QGraphicsObject *children_at(QDeclarativeListProperty *list, int); + inline QTransform transformToParent() const; inline void ensureSortedChildren(); - static void append(QDeclarativeListProperty *list, QGraphicsObject *item); static inline bool insertionOrder(QGraphicsItem *a, QGraphicsItem *b); void ensureSequentialSiblingIndex(); inline void sendScenePosChange(); diff --git a/tests/auto/declarative/qdeclarativeitem/data/childrenProperty.qml b/tests/auto/declarative/qdeclarativeitem/data/childrenProperty.qml new file mode 100644 index 0000000..dcd4061 --- /dev/null +++ b/tests/auto/declarative/qdeclarativeitem/data/childrenProperty.qml @@ -0,0 +1,14 @@ +import Qt 4.6 + +Item { + id: root + + property bool test1: root.children.length == 3 + property bool test2: root.children[0] == item1 + property bool test3: root.children[1] == item2 + property bool test4: root.children[2] == item3 + property bool test5: root.children[3] == null + + children: [ Item { id: item1 }, Item { id: item2 }, Item { id: item3 } ] +} + diff --git a/tests/auto/declarative/qdeclarativeitem/data/resourcesProperty.qml b/tests/auto/declarative/qdeclarativeitem/data/resourcesProperty.qml new file mode 100644 index 0000000..fa299be --- /dev/null +++ b/tests/auto/declarative/qdeclarativeitem/data/resourcesProperty.qml @@ -0,0 +1,21 @@ +import Qt 4.6 + +Item { + id: root + + property bool test1 + property bool test2 + property bool test3 + property bool test4 + property bool test5 + + Component.onCompleted: { + test1 = (root.resources.length >= 3) + test2 = root.resources[0] == item1 + test3 = root.resources[1] == item2 + test4 = root.resources[2] == item3 + test5 = root.resources[10] == null + } + + resources: [ Item { id: item1 }, Item { id: item2 }, Item { id: item3 } ] +} diff --git a/tests/auto/declarative/qdeclarativeitem/tst_qdeclarativeitem.cpp b/tests/auto/declarative/qdeclarativeitem/tst_qdeclarativeitem.cpp index 46f3517..a6171ae 100644 --- a/tests/auto/declarative/qdeclarativeitem/tst_qdeclarativeitem.cpp +++ b/tests/auto/declarative/qdeclarativeitem/tst_qdeclarativeitem.cpp @@ -64,6 +64,9 @@ private slots: void transforms(); void transforms_data(); + void childrenProperty(); + void resourcesProperty(); + private: template T *findItem(QGraphicsObject *parent, const QString &objectName); @@ -429,6 +432,36 @@ void tst_QDeclarativeItem::transforms() QCOMPARE(item->sceneMatrix(), matrix); } +void tst_QDeclarativeItem::childrenProperty() +{ + QDeclarativeComponent component(&engine, SRCDIR "/data/childrenProperty.qml"); + + QObject *o = component.create(); + QVERIFY(o != 0); + + QCOMPARE(o->property("test1").toBool(), true); + QCOMPARE(o->property("test2").toBool(), true); + QCOMPARE(o->property("test3").toBool(), true); + QCOMPARE(o->property("test4").toBool(), true); + QCOMPARE(o->property("test5").toBool(), true); + delete o; +} + +void tst_QDeclarativeItem::resourcesProperty() +{ + QDeclarativeComponent component(&engine, SRCDIR "/data/resourcesProperty.qml"); + + QObject *o = component.create(); + QVERIFY(o != 0); + + QCOMPARE(o->property("test1").toBool(), true); + QCOMPARE(o->property("test2").toBool(), true); + QCOMPARE(o->property("test3").toBool(), true); + QCOMPARE(o->property("test4").toBool(), true); + QCOMPARE(o->property("test5").toBool(), true); + delete o; +} + void tst_QDeclarativeItem::propertyChanges() { QDeclarativeView *canvas = new QDeclarativeView(0); -- cgit v0.12