diff options
-rw-r--r-- | src/declarative/qml/qmlcompiler.cpp | 8 | ||||
-rw-r--r-- | src/declarative/qml/qmlcomponent.cpp | 188 | ||||
-rw-r--r-- | src/declarative/qml/qmlcomponent_p.h | 25 | ||||
-rw-r--r-- | src/declarative/qml/qmlcompositetypemanager.cpp | 2 | ||||
-rw-r--r-- | src/declarative/qml/qmlengine.cpp | 16 | ||||
-rw-r--r-- | src/declarative/qml/qmlengine_p.h | 2 | ||||
-rw-r--r-- | src/declarative/qml/qmlinstruction.cpp | 2 | ||||
-rw-r--r-- | src/declarative/qml/qmlvme.cpp | 1 | ||||
-rw-r--r-- | tests/auto/declarative/qmlecmascript/data/deferredProperties.qml | 5 | ||||
-rw-r--r-- | tests/auto/declarative/qmlecmascript/testtypes.h | 15 | ||||
-rw-r--r-- | tests/auto/declarative/qmlecmascript/tst_qmlecmascript.cpp | 3 |
11 files changed, 173 insertions, 94 deletions
diff --git a/src/declarative/qml/qmlcompiler.cpp b/src/declarative/qml/qmlcompiler.cpp index 9147c4a..3f0dd84 100644 --- a/src/declarative/qml/qmlcompiler.cpp +++ b/src/declarative/qml/qmlcompiler.cpp @@ -902,6 +902,14 @@ void QmlCompiler::genObjectBody(QmlParser::Object *obj) int deferIdx = output->bytecode.count(); output->bytecode << defer; + QmlInstruction init; + init.type = QmlInstruction::Init; + init.init.bindingsSize = compileState.bindings.count(); // XXX - bigger than necessary + init.init.parserStatusSize = compileState.parserStatusCount; // XXX - bigger than necessary + init.init.contextCache = -1; + init.init.compiledBinding = -1; + output->bytecode << init; + foreach(Property *prop, obj->valueProperties) { if (!prop->isDeferred) continue; diff --git a/src/declarative/qml/qmlcomponent.cpp b/src/declarative/qml/qmlcomponent.cpp index 0bd51c3..2d53b0b 100644 --- a/src/declarative/qml/qmlcomponent.cpp +++ b/src/declarative/qml/qmlcomponent.cpp @@ -162,7 +162,7 @@ void QmlComponentPrivate::fromTypeData(QmlCompositeTypeData *data) if (!c) { Q_ASSERT(data->status == QmlCompositeTypeData::Error); - errors = data->errors; + state.errors = data->errors; } else { @@ -202,7 +202,7 @@ QmlComponent::~QmlComponent() { Q_D(QmlComponent); - if (d->completePending) { + if (d->state.completePending) { qWarning("QmlComponent: Component destroyed while completion pending"); d->completeCreate(); } @@ -213,11 +213,6 @@ QmlComponent::~QmlComponent() } if (d->cc) d->cc->release(); - - for(int ii = 0; ii < d->bindValues.count(); ++ii) - QmlEnginePrivate::clear(d->bindValues[ii]); - for(int ii = 0; ii < d->parserStatus.count(); ++ii) - QmlEnginePrivate::clear(d->parserStatus[ii]); } /*! @@ -230,7 +225,7 @@ QmlComponent::Status QmlComponent::status() const if (d->typeData) return Loading; - else if (!d->errors.isEmpty()) + else if (!d->state.errors.isEmpty()) return Error; else if (d->engine && d->cc) return Ready; @@ -483,7 +478,7 @@ QList<QmlError> QmlComponent::errors() const { Q_D(const QmlComponent); if (isError()) - return d->errors; + return d->state.errors; else return QList<QmlError>(); } @@ -498,7 +493,7 @@ QString QmlComponent::errorsString() const QString ret; if(!isError()) return ret; - foreach(const QmlError &e, d->errors) { + foreach(const QmlError &e, d->state.errors) { ret += e.url().toString() + QLatin1Char(':') + QString::number(e.line()) + QLatin1Char(' ') + e.description() + QLatin1Char('\n'); @@ -617,7 +612,7 @@ QmlComponentPrivate::beginCreate(QmlContext *context, const QBitField &bindings) return 0; } - if (completePending) { + if (state.completePending) { qWarning("QmlComponent: Cannot create new component instance before completing the previous"); return 0; } @@ -627,8 +622,7 @@ QmlComponentPrivate::beginCreate(QmlContext *context, const QBitField &bindings) return 0; } - if (!QmlEnginePrivate::get(engine)->rootComponent) - QmlEnginePrivate::get(engine)->rootComponent = q; + QmlEnginePrivate *ep = QmlEnginePrivate::get(engine); QmlContextPrivate *contextPriv = static_cast<QmlContextPrivate *>(QObjectPrivate::get(context)); @@ -637,29 +631,7 @@ QmlComponentPrivate::beginCreate(QmlContext *context, const QBitField &bindings) static_cast<QmlContextPrivate*>(ctxt->d_func())->imports = cc->importCache; cc->importCache->addref(); - QmlVME vme; - QObject *rv = vme.run(ctxt, cc, start, count, bindings); - - if (vme.isError()) - errors = vme.errors(); - - QmlEnginePrivate *ep = QmlEnginePrivate::get(engine); - if (ep->rootComponent == q) { - ep->rootComponent = 0; - - bindValues = ep->bindValues; - parserStatus = ep->parserStatus; - componentAttacheds = ep->componentAttacheds; - if (componentAttacheds) - componentAttacheds->prev = &componentAttacheds; - - ep->componentAttacheds = 0; - ep->bindValues.clear(); - ep->parserStatus.clear(); - completePending = true; - QmlEnginePrivate::get(engine)->inProgressCreations++; - } - + QObject *rv = begin(ctxt, ep, cc, start, count, &state, bindings); if (rv) { QmlGraphics_setParent_noEvent(ctxt, rv); @@ -672,40 +644,85 @@ QmlComponentPrivate::beginCreate(QmlContext *context, const QBitField &bindings) return rv; } -/*! - This method provides more advanced control over component instance creation. - In general, programmers should use QmlComponent::create() to create a - component. +QObject * QmlComponentPrivate::begin(QmlContext *ctxt, QmlEnginePrivate *enginePriv, + QmlCompiledData *component, int start, int count, + ConstructionState *state, const QBitField &bindings) +{ + bool isRoot = !enginePriv->inBeginCreate; + enginePriv->inBeginCreate = true; - Complete a component creation begin with QmlComponent::beginCreate(). -*/ -void QmlComponent::completeCreate() + QmlVME vme; + QObject *rv = vme.run(ctxt, component, start, count, bindings); + + if (vme.isError()) + state->errors = vme.errors(); + + if (isRoot) { + enginePriv->inBeginCreate = false; + + state->bindValues = enginePriv->bindValues; + state->parserStatus = enginePriv->parserStatus; + state->componentAttacheds = enginePriv->componentAttacheds; + if (state->componentAttacheds) + state->componentAttacheds->prev = &state->componentAttacheds; + + enginePriv->componentAttacheds = 0; + enginePriv->bindValues.clear(); + enginePriv->parserStatus.clear(); + state->completePending = true; + enginePriv->inProgressCreations++; + } + + return rv; +} + +void QmlComponentPrivate::beginDeferred(QmlContext *ctxt, QmlEnginePrivate *enginePriv, + QObject *object, ConstructionState *state) { - Q_D(QmlComponent); - d->completeCreate(); + bool isRoot = !enginePriv->inBeginCreate; + enginePriv->inBeginCreate = true; + + QmlVME vme; + vme.runDeferred(object); + + if (vme.isError()) + state->errors = vme.errors(); + + if (isRoot) { + enginePriv->inBeginCreate = false; + + state->bindValues = enginePriv->bindValues; + state->parserStatus = enginePriv->parserStatus; + state->componentAttacheds = enginePriv->componentAttacheds; + if (state->componentAttacheds) + state->componentAttacheds->prev = &state->componentAttacheds; + + enginePriv->componentAttacheds = 0; + enginePriv->bindValues.clear(); + enginePriv->parserStatus.clear(); + state->completePending = true; + enginePriv->inProgressCreations++; + } } -void QmlComponentPrivate::completeCreate() +void QmlComponentPrivate::complete(QmlEnginePrivate *enginePriv, ConstructionState *state) { - if (completePending) { - { -#ifdef Q_ENABLE_PERFORMANCE_LOG - QmlPerfTimer<QmlPerf::BindInit> bi; -#endif - for (int ii = 0; ii < bindValues.count(); ++ii) { - QmlEnginePrivate::SimpleList<QmlAbstractBinding> bv = - bindValues.at(ii); - for (int jj = 0; jj < bv.count; ++jj) { - if(bv.at(jj)) - bv.at(jj)->setEnabled(true, QmlMetaProperty::BypassInterceptor | QmlMetaProperty::DontRemoveBinding); - } - QmlEnginePrivate::clear(bv); + if (state->completePending) { + + for (int ii = 0; ii < state->bindValues.count(); ++ii) { + QmlEnginePrivate::SimpleList<QmlAbstractBinding> bv = + state->bindValues.at(ii); + for (int jj = 0; jj < bv.count; ++jj) { + if(bv.at(jj)) + bv.at(jj)->setEnabled(true, QmlMetaProperty::BypassInterceptor | + QmlMetaProperty::DontRemoveBinding); } + QmlEnginePrivate::clear(bv); } - for (int ii = 0; ii < parserStatus.count(); ++ii) { + for (int ii = 0; ii < state->parserStatus.count(); ++ii) { QmlEnginePrivate::SimpleList<QmlParserStatus> ps = - parserStatus.at(ii); + state->parserStatus.at(ii); for (int jj = ps.count - 1; jj >= 0; --jj) { QmlParserStatus *status = ps.at(jj); @@ -717,28 +734,49 @@ void QmlComponentPrivate::completeCreate() QmlEnginePrivate::clear(ps); } - while (componentAttacheds) { - QmlComponentAttached *a = componentAttacheds; - if (a->next) a->next->prev = &componentAttacheds; - componentAttacheds = a->next; + while (state->componentAttacheds) { + QmlComponentAttached *a = state->componentAttacheds; + if (a->next) a->next->prev = &state->componentAttacheds; + state->componentAttacheds = a->next; a->prev = 0; a->next = 0; emit a->completed(); } - bindValues.clear(); - parserStatus.clear(); - completePending = false; - QmlEnginePrivate *p = QmlEnginePrivate::get(engine); - p->inProgressCreations--; - if (0 == p->inProgressCreations) { - while (p->erroredBindings) { - qWarning().nospace() << qPrintable(p->erroredBindings->error.toString()); - p->erroredBindings->removeError(); + state->bindValues.clear(); + state->parserStatus.clear(); + state->completePending = false; + + enginePriv->inProgressCreations--; + if (0 == enginePriv->inProgressCreations) { + while (enginePriv->erroredBindings) { + qWarning().nospace() << qPrintable(enginePriv->erroredBindings->error.toString()); + enginePriv->erroredBindings->removeError(); } } } } +/*! + This method provides more advanced control over component instance creation. + In general, programmers should use QmlComponent::create() to create a + component. + + Complete a component creation begin with QmlComponent::beginCreate(). +*/ +void QmlComponent::completeCreate() +{ + Q_D(QmlComponent); + d->completeCreate(); +} + +void QmlComponentPrivate::completeCreate() +{ + if (state.completePending) { + QmlEnginePrivate *ep = QmlEnginePrivate::get(engine); + complete(ep, &state); + } +} + QmlComponentAttached::QmlComponentAttached(QObject *parent) : QObject(parent), prev(0), next(0) { @@ -760,7 +798,7 @@ QmlComponentAttached *QmlComponent::qmlAttachedProperties(QObject *obj) QmlComponentAttached *a = new QmlComponentAttached(obj); QmlEngine *engine = qmlEngine(obj); - if (!engine || !QmlEnginePrivate::get(engine)->rootComponent) + if (!engine || !QmlEnginePrivate::get(engine)->inBeginCreate) return a; QmlEnginePrivate *p = QmlEnginePrivate::get(engine); diff --git a/src/declarative/qml/qmlcomponent_p.h b/src/declarative/qml/qmlcomponent_p.h index 1372d98..4039a61 100644 --- a/src/declarative/qml/qmlcomponent_p.h +++ b/src/declarative/qml/qmlcomponent_p.h @@ -79,8 +79,7 @@ class QmlComponentPrivate : public QObjectPrivate Q_DECLARE_PUBLIC(QmlComponent) public: - QmlComponentPrivate() : typeData(0), progress(0.), start(-1), count(-1), cc(0), componentAttacheds(0), completePending(false), engine(0), creationContext(0) {} - + QmlComponentPrivate() : typeData(0), progress(0.), start(-1), count(-1), cc(0), engine(0), creationContext(0) {} QObject *create(QmlContext *context, const QBitField &); QObject *beginCreate(QmlContext *, const QBitField &); @@ -92,7 +91,6 @@ public: void fromTypeData(QmlCompositeTypeData *data); - QList<QmlError> errors; QUrl url; qreal progress; @@ -100,11 +98,22 @@ public: int count; QmlCompiledData *cc; - QList<QmlEnginePrivate::SimpleList<QmlAbstractBinding> > bindValues; - QList<QmlEnginePrivate::SimpleList<QmlParserStatus> > parserStatus; - QmlComponentAttached *componentAttacheds; - - bool completePending; + struct ConstructionState { + ConstructionState() : componentAttacheds(0), completePending(false) {} + QList<QmlEnginePrivate::SimpleList<QmlAbstractBinding> > bindValues; + QList<QmlEnginePrivate::SimpleList<QmlParserStatus> > parserStatus; + QmlComponentAttached *componentAttacheds; + QList<QmlError> errors; + bool completePending; + }; + ConstructionState state; + + static QObject *begin(QmlContext *ctxt, QmlEnginePrivate *enginePriv, + QmlCompiledData *component, int start, int count, + ConstructionState *state, const QBitField &bindings = QBitField()); + static void beginDeferred(QmlContext *ctxt, QmlEnginePrivate *enginePriv, + QObject *object, ConstructionState *state); + static void complete(QmlEnginePrivate *enginePriv, ConstructionState *state); QmlEngine *engine; QmlContext *creationContext; diff --git a/src/declarative/qml/qmlcompositetypemanager.cpp b/src/declarative/qml/qmlcompositetypemanager.cpp index 9590718..d59fe4e 100644 --- a/src/declarative/qml/qmlcompositetypemanager.cpp +++ b/src/declarative/qml/qmlcompositetypemanager.cpp @@ -106,7 +106,7 @@ QmlComponent *QmlCompositeTypeData::toComponent(QmlEngine *engine) } else { component = new QmlComponent(engine, 0); component->d_func()->url = imports.baseUrl(); - component->d_func()->errors = errors; + component->d_func()->state.errors = errors; } } diff --git a/src/declarative/qml/qmlengine.cpp b/src/declarative/qml/qmlengine.cpp index f541631..988962b 100644 --- a/src/declarative/qml/qmlengine.cpp +++ b/src/declarative/qml/qmlengine.cpp @@ -62,6 +62,7 @@ #include "qmlscriptstring.h" #include "qmlglobal_p.h" #include "qmlworkerscript_p.h" +#include "qmlcomponent_p.h" #include <qfxperf_p_p.h> @@ -117,7 +118,7 @@ QmlEnginePrivate::QmlEnginePrivate(QmlEngine *e) isDebugging(false), contextClass(0), sharedContext(0), sharedScope(0), objectClass(0), valueTypeClass(0), globalClass(0), cleanup(0), erroredBindings(0), inProgressCreations(0), scriptEngine(this), workerScriptEngine(0), componentAttacheds(0), - rootComponent(0), networkAccessManager(0), typeManager(e), uniqueId(1) + inBeginCreate(false), networkAccessManager(0), typeManager(e), uniqueId(1) { globalClass = new QmlGlobalScriptClass(&scriptEngine); } @@ -495,11 +496,20 @@ void qmlExecuteDeferred(QObject *object) QmlDeclarativeData *data = QmlDeclarativeData::get(object); if (data && data->deferredComponent) { - QmlVME vme; - vme.runDeferred(object); + + QmlEnginePrivate *ep = QmlEnginePrivate::get(data->context->engine()); + + QmlComponentPrivate::ConstructionState state; + QmlComponentPrivate::beginDeferred(data->context, ep, object, &state); data->deferredComponent->release(); data->deferredComponent = 0; + + QmlComponentPrivate::complete(ep, &state); + + if (!state.errors.isEmpty()) + qWarning() << state.errors; + } } diff --git a/src/declarative/qml/qmlengine_p.h b/src/declarative/qml/qmlengine_p.h index 96297ea..8f2f0fb 100644 --- a/src/declarative/qml/qmlengine_p.h +++ b/src/declarative/qml/qmlengine_p.h @@ -205,7 +205,7 @@ public: QList<SimpleList<QmlParserStatus> > parserStatus; QmlComponentAttached *componentAttacheds; - QmlComponent *rootComponent; + bool inBeginCreate; mutable QNetworkAccessManager *networkAccessManager; QmlCompositeTypeManager typeManager; diff --git a/src/declarative/qml/qmlinstruction.cpp b/src/declarative/qml/qmlinstruction.cpp index 67db9c6..c873803 100644 --- a/src/declarative/qml/qmlinstruction.cpp +++ b/src/declarative/qml/qmlinstruction.cpp @@ -56,7 +56,7 @@ void QmlCompiledData::dump(QmlInstruction *instr, int idx) switch(instr->type) { case QmlInstruction::Init: - qWarning().nospace() << idx << "\t\t" << line << "\t" << "INIT"; + qWarning().nospace() << idx << "\t\t" << line << "\t" << "INIT\t\t\t" << instr->init.bindingsSize << "\t" << instr->init.parserStatusSize << "\t" << instr->init.contextCache << "\t" << instr->init.compiledBinding; break; case QmlInstruction::CreateObject: qWarning().nospace() << idx << "\t\t" << line << "\t" << "CREATE\t\t\t" << instr->create.type << "\t\t\t" << types.at(instr->create.type).className; diff --git a/src/declarative/qml/qmlvme.cpp b/src/declarative/qml/qmlvme.cpp index ae7bf51..58cd92f 100644 --- a/src/declarative/qml/qmlvme.cpp +++ b/src/declarative/qml/qmlvme.cpp @@ -131,7 +131,6 @@ void QmlVME::runDeferred(QObject *object) run(stack, ctxt, comp, start, count, QBitField()); } -QBitField bindingSkipList; QObject *QmlVME::run(QmlVMEStack<QObject *> &stack, QmlContext *ctxt, QmlCompiledData *comp, int start, int count, diff --git a/tests/auto/declarative/qmlecmascript/data/deferredProperties.qml b/tests/auto/declarative/qmlecmascript/data/deferredProperties.qml index 9dabafe..e01f708 100644 --- a/tests/auto/declarative/qmlecmascript/data/deferredProperties.qml +++ b/tests/auto/declarative/qmlecmascript/data/deferredProperties.qml @@ -1,7 +1,10 @@ import Qt.test 1.0 MyDeferredObject { + id: root value: 10 - objectProperty: MyQmlObject {} + objectProperty: MyQmlObject { + value: root.value + } objectProperty2: MyQmlObject { id: blah } } diff --git a/tests/auto/declarative/qmlecmascript/testtypes.h b/tests/auto/declarative/qmlecmascript/testtypes.h index ff20487..7c02995 100644 --- a/tests/auto/declarative/qmlecmascript/testtypes.h +++ b/tests/auto/declarative/qmlecmascript/testtypes.h @@ -67,13 +67,14 @@ class MyQmlObject : public QObject Q_PROPERTY(int deleteOnSet READ deleteOnSet WRITE setDeleteOnSet) Q_PROPERTY(bool trueProperty READ trueProperty CONSTANT) Q_PROPERTY(bool falseProperty READ falseProperty CONSTANT) + Q_PROPERTY(int value READ value WRITE setValue) Q_PROPERTY(QString stringProperty READ stringProperty WRITE setStringProperty NOTIFY stringChanged) Q_PROPERTY(QObject *objectProperty READ objectProperty WRITE setObjectProperty NOTIFY objectChanged) Q_PROPERTY(QmlList<QObject *> *objectQmlListProperty READ objectQmlListProperty CONSTANT) Q_PROPERTY(QList<QObject *> *objectListProperty READ objectListProperty CONSTANT) public: - MyQmlObject(): m_methodCalled(false), m_methodIntCalled(false), m_object(0) {} + MyQmlObject(): m_methodCalled(false), m_methodIntCalled(false), m_object(0), m_value(0) {} enum MyEnum { EnumValue1 = 0, EnumValue2 = 1 }; enum MyEnum2 { EnumValue3 = 2, EnumValue4 = 3 }; @@ -112,6 +113,9 @@ public: int deleteOnSet() const { return 1; } void setDeleteOnSet(int v) { if(v) delete this; } + + int value() const { return m_value; } + void setValue(int v) { m_value = v; } signals: void basicSignal(); void argumentSignal(int a, QString b, qreal c); @@ -135,6 +139,7 @@ private: QString m_string; QmlConcreteList<QObject *> m_objectQmlList; QList<QObject *> m_objectQList; + int m_value; }; QML_DECLARE_TYPEINFO(MyQmlObject, QML_HAS_ATTACHED_PROPERTIES) @@ -204,7 +209,7 @@ public: class MyDeferredObject : public QObject { Q_OBJECT - Q_PROPERTY(int value READ value WRITE setValue) + Q_PROPERTY(int value READ value WRITE setValue NOTIFY valueChanged) Q_PROPERTY(QObject *objectProperty READ objectProperty WRITE setObjectProperty); Q_PROPERTY(QObject *objectProperty2 READ objectProperty2 WRITE setObjectProperty2); Q_CLASSINFO("DeferredPropertyNames", "value,objectProperty,objectProperty2"); @@ -213,13 +218,17 @@ public: MyDeferredObject() : m_value(0), m_object(0), m_object2(0) {} int value() const { return m_value; } - void setValue(int v) { m_value = v; } + void setValue(int v) { m_value = v; emit valueChanged(); } QObject *objectProperty() const { return m_object; } void setObjectProperty(QObject *obj) { m_object = obj; } QObject *objectProperty2() const { return m_object2; } void setObjectProperty2(QObject *obj) { m_object2 = obj; } + +signals: + void valueChanged(); + private: int m_value; QObject *m_object; diff --git a/tests/auto/declarative/qmlecmascript/tst_qmlecmascript.cpp b/tests/auto/declarative/qmlecmascript/tst_qmlecmascript.cpp index b9a2241..24681b9 100644 --- a/tests/auto/declarative/qmlecmascript/tst_qmlecmascript.cpp +++ b/tests/auto/declarative/qmlecmascript/tst_qmlecmascript.cpp @@ -432,6 +432,9 @@ void tst_qmlecmascript::deferredProperties() MyQmlObject *qmlObject = qobject_cast<MyQmlObject *>(object->objectProperty()); QVERIFY(qmlObject != 0); + QCOMPARE(qmlObject->value(), 10); + object->setValue(19); + QCOMPARE(qmlObject->value(), 19); } void tst_qmlecmascript::extensionObjects() |