summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/declarative/qml/qmlcompiler.cpp8
-rw-r--r--src/declarative/qml/qmlcomponent.cpp188
-rw-r--r--src/declarative/qml/qmlcomponent_p.h25
-rw-r--r--src/declarative/qml/qmlcompositetypemanager.cpp2
-rw-r--r--src/declarative/qml/qmlengine.cpp16
-rw-r--r--src/declarative/qml/qmlengine_p.h2
-rw-r--r--src/declarative/qml/qmlinstruction.cpp2
-rw-r--r--src/declarative/qml/qmlvme.cpp1
-rw-r--r--tests/auto/declarative/qmlecmascript/data/deferredProperties.qml5
-rw-r--r--tests/auto/declarative/qmlecmascript/testtypes.h15
-rw-r--r--tests/auto/declarative/qmlecmascript/tst_qmlecmascript.cpp3
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()