aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorMartin Jones <martin.jones@nokia.com>2011-10-07 16:20:39 +1000
committerQt by Nokia <qt-info@nokia.com>2011-10-10 10:23:17 +0200
commit9da11998e8f9b896daf64c2663e06caecd9491d8 (patch)
tree17c58784f3d239d9dec0e10ae745d0f6931f6eec /src
parentb8ccc462e88a51834c2623697c1caa3dd1aa35ec (diff)
Add "asynchronous" property to Loader.
Use an incubator to perform non-blocking instantiation of components. Change-Id: I589bfc8ba7bf3368dc44fab3a82afb7e0d66032c Fixes: QTBUG-21791 Reviewed-on: http://codereview.qt-project.org/6216 Sanity-Review: Qt Sanity Bot <qt_sanity_bot@ovi.com> Reviewed-by: Aaron Kennedy <aaron.kennedy@nokia.com>
Diffstat (limited to 'src')
-rw-r--r--src/declarative/items/qsgloader.cpp207
-rw-r--r--src/declarative/items/qsgloader_p.h5
-rw-r--r--src/declarative/items/qsgloader_p_p.h22
-rw-r--r--src/declarative/qml/qdeclarativecomponent.cpp6
-rw-r--r--src/declarative/qml/qdeclarativecomponent_p.h2
5 files changed, 167 insertions, 75 deletions
diff --git a/src/declarative/items/qsgloader.cpp b/src/declarative/items/qsgloader.cpp
index 93f32b81a1..e655e179cd 100644
--- a/src/declarative/items/qsgloader.cpp
+++ b/src/declarative/items/qsgloader.cpp
@@ -53,14 +53,15 @@
QT_BEGIN_NAMESPACE
QSGLoaderPrivate::QSGLoaderPrivate()
- : item(0), component(0), updatingSize(false),
+ : item(0), component(0), itemContext(0), incubator(0), updatingSize(false),
itemWidthValid(false), itemHeightValid(false),
- active(true), loadingFromSource(false)
+ active(true), loadingFromSource(false), asynchronous(false)
{
}
QSGLoaderPrivate::~QSGLoaderPrivate()
{
+ delete incubator;
disposeInitialPropertyValues();
}
@@ -80,6 +81,9 @@ void QSGLoaderPrivate::clear()
{
disposeInitialPropertyValues();
+ if (incubator)
+ incubator->clear();
+
if (loadingFromSource && component) {
component->deleteLater();
component = 0;
@@ -526,72 +530,106 @@ void QSGLoaderPrivate::load()
}
}
-void QSGLoaderPrivate::_q_sourceLoaded()
+void QSGLoaderIncubator::setInitialState(QObject *o)
+{
+ loader->setInitialState(o);
+}
+
+void QSGLoaderPrivate::setInitialState(QObject *obj)
{
Q_Q(QSGLoader);
- if (component) {
- if (!component->errors().isEmpty()) {
- QDeclarativeEnginePrivate::warning(qmlEngine(q), component->errors());
- if (loadingFromSource)
- emit q->sourceChanged();
- else
- emit q->sourceComponentChanged();
- emit q->statusChanged();
- emit q->progressChanged();
- disposeInitialPropertyValues(); // cleanup
- return;
- }
+ QSGItem *item = qobject_cast<QSGItem*>(obj);
+ if (item) {
+ QDeclarative_setParent_noEvent(itemContext, obj);
+ QDeclarative_setParent_noEvent(item, q);
+ item->setParentItem(q);
+ }
- QDeclarativeContext *creationContext = component->creationContext();
- if (!creationContext) creationContext = qmlContext(q);
- QDeclarativeContext *ctxt = new QDeclarativeContext(creationContext);
- ctxt->setContextObject(q);
-
- QDeclarativeGuard<QDeclarativeComponent> c = component;
- QObject *obj = component->beginCreate(ctxt);
- if (component != c) {
- // component->create could trigger a change in source that causes
- // component to be set to something else. In that case we just
- // need to cleanup.
- if (c)
- completeCreateWithInitialPropertyValues(c, obj, initialPropertyValues, qmlGlobalForIpv);
- delete obj;
- delete ctxt;
- disposeInitialPropertyValues(); // cleanup
- return;
- }
- if (obj) {
- item = qobject_cast<QSGItem *>(obj);
- if (item) {
- QDeclarative_setParent_noEvent(ctxt, obj);
- QDeclarative_setParent_noEvent(item, q);
- item->setParentItem(q);
-// item->setFocus(true);
- initResize();
- } else {
- qmlInfo(q) << QSGLoader::tr("Loader does not support loading non-visual elements.");
- delete obj;
- delete ctxt;
- }
+ if (initialPropertyValues.IsEmpty())
+ return;
+
+ QDeclarativeComponentPrivate *d = QDeclarativeComponentPrivate::get(component);
+ Q_ASSERT(d && d->engine);
+ d->initializeObjectWithInitialProperties(qmlGlobalForIpv, initialPropertyValues, obj);
+}
+
+void QSGLoaderIncubator::statusChanged(Status status)
+{
+ loader->incubatorStateChanged(status);
+}
+
+void QSGLoaderPrivate::incubatorStateChanged(QDeclarativeIncubator::Status status)
+{
+ Q_Q(QSGLoader);
+ if (status == QDeclarativeIncubator::Loading || status == QDeclarativeIncubator::Null)
+ return;
+
+ if (status == QDeclarativeIncubator::Ready) {
+ QObject *obj = incubator->object();
+ item = qobject_cast<QSGItem*>(obj);
+ if (item) {
+ initResize();
} else {
- if (!component->errors().isEmpty())
- QDeclarativeEnginePrivate::warning(qmlEngine(q), component->errors());
+ qmlInfo(q) << QSGLoader::tr("Loader does not support loading non-visual elements.");
+ delete itemContext;
+ itemContext = 0;
delete obj;
- delete ctxt;
- source = QUrl();
}
- completeCreateWithInitialPropertyValues(component, obj, initialPropertyValues, qmlGlobalForIpv);
+ } else if (status == QDeclarativeIncubator::Error) {
+ if (!incubator->errors().isEmpty())
+ QDeclarativeEnginePrivate::warning(qmlEngine(q), incubator->errors());
+ delete itemContext;
+ itemContext = 0;
+ delete incubator->object();
+ source = QUrl();
+ }
+ if (loadingFromSource)
+ emit q->sourceChanged();
+ else
+ emit q->sourceComponentChanged();
+ emit q->statusChanged();
+ emit q->progressChanged();
+ emit q->itemChanged();
+ emit q->loaded();
+ disposeInitialPropertyValues(); // cleanup
+}
+
+void QSGLoaderPrivate::_q_sourceLoaded()
+{
+ Q_Q(QSGLoader);
+ if (!component || !component->errors().isEmpty()) {
+ if (component)
+ QDeclarativeEnginePrivate::warning(qmlEngine(q), component->errors());
if (loadingFromSource)
emit q->sourceChanged();
else
emit q->sourceComponentChanged();
emit q->statusChanged();
emit q->progressChanged();
- emit q->itemChanged();
- emit q->loaded();
+ disposeInitialPropertyValues(); // cleanup
+ return;
}
- disposeInitialPropertyValues(); // cleanup
+
+ QDeclarativeContext *creationContext = component->creationContext();
+ if (!creationContext) creationContext = qmlContext(q);
+ itemContext = new QDeclarativeContext(creationContext);
+ itemContext->setContextObject(q);
+
+ if (incubator) {
+ bool async = incubator->incubationMode() == QDeclarativeIncubator::Asynchronous;
+ if (asynchronous != async) {
+ delete incubator;
+ incubator = 0;
+ }
+ }
+ if (!incubator)
+ incubator = new QSGLoaderIncubator(this, asynchronous ? QDeclarativeIncubator::Asynchronous : QDeclarativeIncubator::AsynchronousIfNested);
+
+ component->create(*incubator, itemContext);
+
+ if (incubator->status() == QDeclarativeIncubator::Loading)
+ emit q->statusChanged();
}
/*!
@@ -641,8 +679,29 @@ QSGLoader::Status QSGLoader::status() const
if (!d->active)
return Null;
- if (d->component)
- return static_cast<QSGLoader::Status>(d->component->status());
+ if (d->component) {
+ switch (d->component->status()) {
+ case QDeclarativeComponent::Loading:
+ return Loading;
+ case QDeclarativeComponent::Error:
+ return Error;
+ case QDeclarativeComponent::Null:
+ return Null;
+ default:
+ break;
+ }
+ }
+
+ if (d->incubator) {
+ switch (d->incubator->status()) {
+ case QDeclarativeIncubator::Loading:
+ return Loading;
+ case QDeclarativeIncubator::Error:
+ return Error;
+ default:
+ break;
+ }
+ }
if (d->item)
return Ready;
@@ -692,6 +751,30 @@ qreal QSGLoader::progress() const
return 0.0;
}
+/*!
+\qmlproperty bool QtQuick2::Loader::asynchronous
+
+This property holds whether the component will be instantiated asynchronously.
+
+Note that this property affects object instantiation only; it is unrelated to
+loading a component asynchronously via a network.
+*/
+bool QSGLoader::asynchronous() const
+{
+ Q_D(const QSGLoader);
+ return d->asynchronous;
+}
+
+void QSGLoader::setAsynchronous(bool a)
+{
+ Q_D(QSGLoader);
+ if (d->asynchronous == a)
+ return;
+
+ d->asynchronous = a;
+ emit asynchronousChanged();
+}
+
void QSGLoaderPrivate::_q_updateSize(bool loaderGeometryChanged)
{
Q_Q(QSGLoader);
@@ -765,18 +848,6 @@ v8::Handle<v8::Object> QSGLoaderPrivate::extractInitialPropertyValues(QDeclarati
return valuemap;
}
-void QSGLoaderPrivate::completeCreateWithInitialPropertyValues(QDeclarativeComponent *component, QObject *object, v8::Handle<v8::Object> initialPropertyValues, v8::Handle<v8::Object> qmlGlobal)
-{
- if (initialPropertyValues.IsEmpty()) {
- component->completeCreate();
- return;
- }
-
- QDeclarativeComponentPrivate *d = QDeclarativeComponentPrivate::get(component);
- Q_ASSERT(d && d->engine);
- d->completeCreateObjectWithInitialProperties(qmlGlobal, initialPropertyValues, object);
-}
-
#include <moc_qsgloader_p.cpp>
QT_END_NAMESPACE
diff --git a/src/declarative/items/qsgloader_p.h b/src/declarative/items/qsgloader_p.h
index c3ce1607e0..3a41e79915 100644
--- a/src/declarative/items/qsgloader_p.h
+++ b/src/declarative/items/qsgloader_p.h
@@ -63,6 +63,7 @@ class Q_AUTOTEST_EXPORT QSGLoader : public QSGImplicitSizeItem
Q_PROPERTY(QSGItem *item READ item NOTIFY itemChanged)
Q_PROPERTY(Status status READ status NOTIFY statusChanged)
Q_PROPERTY(qreal progress READ progress NOTIFY progressChanged)
+ Q_PROPERTY(bool asynchronous READ asynchronous WRITE setAsynchronous NOTIFY asynchronousChanged)
public:
QSGLoader(QSGItem *parent = 0);
@@ -84,6 +85,9 @@ public:
Status status() const;
qreal progress() const;
+ bool asynchronous() const;
+ void setAsynchronous(bool a);
+
QSGItem *item() const;
Q_SIGNALS:
@@ -94,6 +98,7 @@ Q_SIGNALS:
void statusChanged();
void progressChanged();
void loaded();
+ void asynchronousChanged();
protected:
void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry);
diff --git a/src/declarative/items/qsgloader_p_p.h b/src/declarative/items/qsgloader_p_p.h
index 13292ffc54..ea8c11d413 100644
--- a/src/declarative/items/qsgloader_p_p.h
+++ b/src/declarative/items/qsgloader_p_p.h
@@ -57,11 +57,27 @@
#include "qsgloader_p.h"
#include "qsgimplicitsizeitem_p_p.h"
#include "qsgitemchangelistener_p.h"
+#include "qdeclarativeincubator.h"
#include <private/qv8_p.h>
QT_BEGIN_NAMESPACE
+
+class QSGLoaderPrivate;
+class QSGLoaderIncubator : public QDeclarativeIncubator
+{
+public:
+ QSGLoaderIncubator(QSGLoaderPrivate *l, IncubationMode mode) : QDeclarativeIncubator(mode), loader(l) {}
+
+protected:
+ virtual void statusChanged(Status);
+ virtual void setInitialState(QObject *);
+
+private:
+ QSGLoaderPrivate *loader;
+};
+
class QDeclarativeContext;
class QSGLoaderPrivate : public QSGImplicitSizeItemPrivate, public QSGItemChangeListener
{
@@ -76,14 +92,17 @@ public:
void initResize();
void load();
+ void incubatorStateChanged(QDeclarativeIncubator::Status status);
+ void setInitialState(QObject *o);
void disposeInitialPropertyValues();
QUrl resolveSourceUrl(QDeclarativeV8Function *args);
v8::Handle<v8::Object> extractInitialPropertyValues(QDeclarativeV8Function *args, QObject *loader, bool *error);
- void completeCreateWithInitialPropertyValues(QDeclarativeComponent *component, QObject *object, v8::Handle<v8::Object> initialPropertyValues, v8::Handle<v8::Object> qmlGlobal);
QUrl source;
QSGItem *item;
QDeclarativeComponent *component;
+ QDeclarativeContext *itemContext;
+ QSGLoaderIncubator *incubator;
v8::Persistent<v8::Object> initialPropertyValues;
v8::Persistent<v8::Object> qmlGlobalForIpv;
bool updatingSize: 1;
@@ -91,6 +110,7 @@ public:
bool itemHeightValid : 1;
bool active : 1;
bool loadingFromSource : 1;
+ bool asynchronous : 1;
void _q_sourceLoaded();
void _q_updateSize(bool loaderGeometryChanged = true);
diff --git a/src/declarative/qml/qdeclarativecomponent.cpp b/src/declarative/qml/qdeclarativecomponent.cpp
index f9be4ca9f6..8aeeb78a56 100644
--- a/src/declarative/qml/qdeclarativecomponent.cpp
+++ b/src/declarative/qml/qdeclarativecomponent.cpp
@@ -1107,7 +1107,7 @@ void QDeclarativeComponent::incubateObject(QDeclarativeV8Function *args)
}
// XXX used by QSGLoader
-QObject *QDeclarativeComponentPrivate::completeCreateObjectWithInitialProperties(v8::Handle<v8::Object> qmlGlobal, v8::Handle<v8::Object> valuemap, QObject *toCreate)
+void QDeclarativeComponentPrivate::initializeObjectWithInitialProperties(v8::Handle<v8::Object> qmlGlobal, v8::Handle<v8::Object> valuemap, QObject *toCreate)
{
QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine);
QV8Engine *v8engine = ep->v8engine();
@@ -1126,13 +1126,9 @@ QObject *QDeclarativeComponentPrivate::completeCreateObjectWithInitialProperties
v8::Handle<v8::Function>::Cast(function)->Call(v8engine->global(), 2, args);
}
- completeCreate();
-
QDeclarativeData *ddata = QDeclarativeData::get(toCreate);
Q_ASSERT(ddata);
ddata->setImplicitDestructible();
-
- return v8engine->toQObject(object);
}
diff --git a/src/declarative/qml/qdeclarativecomponent_p.h b/src/declarative/qml/qdeclarativecomponent_p.h
index 7e6f9c2d30..bbbf8bdfb7 100644
--- a/src/declarative/qml/qdeclarativecomponent_p.h
+++ b/src/declarative/qml/qdeclarativecomponent_p.h
@@ -87,7 +87,7 @@ public:
QObject *beginCreate(QDeclarativeContextData *);
void completeCreate();
- QObject *completeCreateObjectWithInitialProperties(v8::Handle<v8::Object> qmlGlobal, v8::Handle<v8::Object> valuemap, QObject *toCreate);
+ void initializeObjectWithInitialProperties(v8::Handle<v8::Object> qmlGlobal, v8::Handle<v8::Object> valuemap, QObject *toCreate);
QDeclarativeTypeData *typeData;
virtual void typeDataReady(QDeclarativeTypeData *);