aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorMartin Jones <martin.jones@nokia.com>2012-03-06 18:03:33 +1000
committerQt by Nokia <qt-info@nokia.com>2012-03-15 10:14:37 +0100
commit31467e8649979d06ea2f676768016e6a147eadb9 (patch)
treeb318865886c33aa266141870972adc03900522e0 /src
parentb634c19680cd1d4dd925a18e616844ed420d18ae (diff)
Allow threaded compilation in an async Loader
Enables threaded compilation for a Loader "source". Change-Id: I2d60a3ace07aab58f3b8f069e45a2864178c959f Reviewed-by: Chris Adams <christopher.adams@nokia.com>
Diffstat (limited to 'src')
-rw-r--r--src/qml/qml/qqmlcomponent.cpp109
-rw-r--r--src/qml/qml/qqmlcomponent.h6
-rw-r--r--src/qml/qml/qqmlcomponent_p.h2
-rw-r--r--src/qml/qml/qqmltypeloader.cpp4
-rw-r--r--src/qml/qml/qqmltypeloader_p.h2
-rw-r--r--src/qml/qml/v8/qqmlbuiltinfunctions.cpp27
-rw-r--r--src/quick/items/qquickloader.cpp9
7 files changed, 132 insertions, 27 deletions
diff --git a/src/qml/qml/qqmlcomponent.cpp b/src/qml/qml/qqmlcomponent.cpp
index a73fe7cd63..6cd5cf6cec 100644
--- a/src/qml/qml/qqmlcomponent.cpp
+++ b/src/qml/qml/qqmlcomponent.cpp
@@ -280,6 +280,16 @@ static inline QString buildTypeNameForDebug(const QMetaObject *metaObject)
\value Error An error has occurred. Call errors() to retrieve a list of \{QQmlError}{errors}.
*/
+/*!
+ \enum QQmlComponent::CompilationMode
+
+ Specifies whether the QQmlComponent should load the component immediately, or asynchonously.
+
+ \value PreferSynchronous Prefer loading/compiling the component immediately, blocking the thread.
+ This is not always possible, e.g. remote URLs will always load asynchronously.
+ \value Asynchronous Load/compile the component in a background thread.
+*/
+
void QQmlComponentPrivate::typeDataReady(QQmlTypeData *)
{
Q_Q(QQmlComponent);
@@ -288,8 +298,10 @@ void QQmlComponentPrivate::typeDataReady(QQmlTypeData *)
fromTypeData(typeData);
typeData = 0;
+ progress = 1.0;
emit q->statusChanged(q->status());
+ emit q->progressChanged(progress);
}
void QQmlComponentPrivate::typeDataProgress(QQmlTypeData *, qreal p)
@@ -476,7 +488,24 @@ QQmlComponent::QQmlComponent(QQmlEngine *engine, const QUrl &url, QObject *paren
{
Q_D(QQmlComponent);
d->engine = engine;
- loadUrl(url);
+ d->loadUrl(url);
+}
+
+/*!
+ Create a QQmlComponent from the given \a url and give it the
+ specified \a parent and \a engine. If \a mode is \l Asynchronous,
+ the component will be loaded and compiled asynchronously.
+
+ Ensure that the URL provided is full and correct, in particular, use
+ \l QUrl::fromLocalFile() when loading a file from the local filesystem.
+
+ \sa loadUrl()
+*/QQmlComponent::QQmlComponent(QQmlEngine *engine, const QUrl &url, CompilationMode mode, QObject *parent)
+: QObject(*(new QQmlComponentPrivate), parent)
+{
+ Q_D(QQmlComponent);
+ d->engine = engine;
+ d->loadUrl(url, mode);
}
/*!
@@ -491,7 +520,23 @@ QQmlComponent::QQmlComponent(QQmlEngine *engine, const QString &fileName,
{
Q_D(QQmlComponent);
d->engine = engine;
- loadUrl(d->engine->baseUrl().resolved(QUrl::fromLocalFile(fileName)));
+ d->loadUrl(d->engine->baseUrl().resolved(QUrl::fromLocalFile(fileName)));
+}
+
+/*!
+ Create a QQmlComponent from the given \a fileName and give it the specified
+ \a parent and \a engine. If \a mode is \l Asynchronous,
+ the component will be loaded and compiled asynchronously.
+
+ \sa loadUrl()
+*/
+QQmlComponent::QQmlComponent(QQmlEngine *engine, const QString &fileName,
+ CompilationMode mode, QObject *parent)
+: QObject(*(new QQmlComponentPrivate), parent)
+{
+ Q_D(QQmlComponent);
+ d->engine = engine;
+ d->loadUrl(d->engine->baseUrl().resolved(QUrl::fromLocalFile(fileName)), mode);
}
/*!
@@ -558,35 +603,63 @@ QQmlContext *QQmlComponent::creationContext() const
void QQmlComponent::loadUrl(const QUrl &url)
{
Q_D(QQmlComponent);
+ d->loadUrl(url);
+}
- d->clear();
+/*!
+ Load the QQmlComponent from the provided \a url.
+ If \a mode is \l Asynchronous, the component will be loaded and compiled asynchronously.
+
+ Ensure that the URL provided is full and correct, in particular, use
+ \l QUrl::fromLocalFile() when loading a file from the local filesystem.
+*/
+void QQmlComponent::loadUrl(const QUrl &url, QQmlComponent::CompilationMode mode)
+{
+ Q_D(QQmlComponent);
+ d->loadUrl(url, mode);
+}
+
+void QQmlComponentPrivate::loadUrl(const QUrl &newUrl, QQmlComponent::CompilationMode mode)
+{
+ Q_Q(QQmlComponent);
+ clear();
- if ((url.isRelative() && !url.isEmpty())
- || url.scheme() == QLatin1String("file")) // Workaround QTBUG-11929
- d->url = d->engine->baseUrl().resolved(url);
+ if ((newUrl.isRelative() && !newUrl.isEmpty())
+ || newUrl.scheme() == QLatin1String("file")) // Workaround QTBUG-11929
+ url = engine->baseUrl().resolved(newUrl);
else
- d->url = url;
+ url = newUrl;
- if (url.isEmpty()) {
+ if (newUrl.isEmpty()) {
QQmlError error;
- error.setDescription(tr("Invalid empty URL"));
- d->state.errors << error;
+ error.setDescription(q->tr("Invalid empty URL"));
+ state.errors << error;
return;
}
- QQmlTypeData *data = QQmlEnginePrivate::get(d->engine)->typeLoader.get(d->url);
+ if (progress != 0.0) {
+ progress = 0.0;
+ emit q->progressChanged(progress);
+ }
+
+ QQmlDataLoader::Mode loaderMode = (mode == QQmlComponent::Asynchronous)
+ ? QQmlDataLoader::Asynchronous
+ : QQmlDataLoader::PreferSynchronous;
+
+ QQmlTypeData *data = QQmlEnginePrivate::get(engine)->typeLoader.get(url, loaderMode);
if (data->isCompleteOrError()) {
- d->fromTypeData(data);
- d->progress = 1.0;
+ fromTypeData(data);
+ progress = 1.0;
} else {
- d->typeData = data;
- d->typeData->registerCallback(d);
- d->progress = data->progress();
+ typeData = data;
+ typeData->registerCallback(this);
+ progress = data->progress();
}
- emit statusChanged(status());
- emit progressChanged(d->progress);
+ emit q->statusChanged(q->status());
+ if (progress != 0.0)
+ emit q->progressChanged(progress);
}
/*!
diff --git a/src/qml/qml/qqmlcomponent.h b/src/qml/qml/qqmlcomponent.h
index 1265fb1c7d..9fc9388e41 100644
--- a/src/qml/qml/qqmlcomponent.h
+++ b/src/qml/qml/qqmlcomponent.h
@@ -73,10 +73,15 @@ class Q_QML_EXPORT QQmlComponent : public QObject
Q_PROPERTY(QUrl url READ url CONSTANT)
public:
+ Q_ENUMS(CompilationMode)
+ enum CompilationMode { PreferSynchronous, Asynchronous };
+
QQmlComponent(QObject *parent = 0);
QQmlComponent(QQmlEngine *, QObject *parent=0);
QQmlComponent(QQmlEngine *, const QString &fileName, QObject *parent = 0);
+ QQmlComponent(QQmlEngine *, const QString &fileName, CompilationMode mode, QObject *parent = 0);
QQmlComponent(QQmlEngine *, const QUrl &url, QObject *parent = 0);
+ QQmlComponent(QQmlEngine *, const QUrl &url, CompilationMode mode, QObject *parent = 0);
virtual ~QQmlComponent();
Q_ENUMS(Status)
@@ -108,6 +113,7 @@ public:
public Q_SLOTS:
void loadUrl(const QUrl &url);
+ void loadUrl(const QUrl &url, CompilationMode mode);
void setData(const QByteArray &, const QUrl &baseUrl);
Q_SIGNALS:
diff --git a/src/qml/qml/qqmlcomponent_p.h b/src/qml/qml/qqmlcomponent_p.h
index dda5bd0b71..9e220b5e95 100644
--- a/src/qml/qml/qqmlcomponent_p.h
+++ b/src/qml/qml/qqmlcomponent_p.h
@@ -86,6 +86,8 @@ class Q_QML_PRIVATE_EXPORT QQmlComponentPrivate : public QObjectPrivate, public
public:
QQmlComponentPrivate() : typeData(0), progress(0.), start(-1), cc(0), engine(0), creationContext(0), profiler(0) {}
+ void loadUrl(const QUrl &newUrl, QQmlComponent::CompilationMode mode = QQmlComponent::PreferSynchronous);
+
QObject *beginCreate(QQmlContextData *);
void completeCreate();
void initializeObjectWithInitialProperties(v8::Handle<v8::Object> qmlGlobal, v8::Handle<v8::Object> valuemap, QObject *toCreate);
diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp
index 0082d55c48..36ba530338 100644
--- a/src/qml/qml/qqmltypeloader.cpp
+++ b/src/qml/qml/qqmltypeloader.cpp
@@ -1171,7 +1171,7 @@ This enum defines the options that control the way type data is handled.
/*!
Returns a QQmlTypeData for the specified \a url. The QQmlTypeData may be cached.
*/
-QQmlTypeData *QQmlTypeLoader::get(const QUrl &url)
+QQmlTypeData *QQmlTypeLoader::get(const QUrl &url, Mode mode)
{
Q_ASSERT(!url.isRelative() &&
(QQmlEnginePrivate::urlToLocalFileOrQrc(url).isEmpty() ||
@@ -1184,7 +1184,7 @@ QQmlTypeData *QQmlTypeLoader::get(const QUrl &url)
if (!typeData) {
typeData = new QQmlTypeData(url, None, this);
m_typeCache.insert(url, typeData);
- QQmlDataLoader::load(typeData);
+ QQmlDataLoader::load(typeData, mode);
}
typeData->addref();
diff --git a/src/qml/qml/qqmltypeloader_p.h b/src/qml/qml/qqmltypeloader_p.h
index 0dd7adecac..c8c2756bd5 100644
--- a/src/qml/qml/qqmltypeloader_p.h
+++ b/src/qml/qml/qqmltypeloader_p.h
@@ -236,7 +236,7 @@ public:
};
Q_DECLARE_FLAGS(Options, Option)
- QQmlTypeData *get(const QUrl &url);
+ QQmlTypeData *get(const QUrl &url, Mode mode = PreferSynchronous);
QQmlTypeData *get(const QByteArray &, const QUrl &url, Options = None);
void clearCache();
diff --git a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp
index 11a233d093..b9f2b627da 100644
--- a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp
+++ b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp
@@ -1120,7 +1120,7 @@ v8::Handle<v8::Value> createQmlObject(const v8::Arguments &args)
}
/*!
-\qmlmethod object Qt::createComponent(url)
+\qmlmethod object Qt::createComponent(url, mode)
Returns a \l Component object created using the QML file at the specified \a url,
or \c null if an empty string was given.
@@ -1129,6 +1129,12 @@ The returned component's \l Component::status property indicates whether the
component was successfully created. If the status is \c Component.Error,
see \l Component::errorString() for an error description.
+If the optional \a mode parameter is set to \c Component.Asynchronous, the
+component will be loaded in a background thread. The Component::status property
+will be \c Component.Loading while it is loading. The status will change to
+\c Component.Ready if the component loads successfully, or \c Component.Error
+if loading fails.
+
Call \l {Component::createObject()}{Component.createObject()} on the returned
component to create an object instance of the component.
@@ -1143,8 +1149,9 @@ use \l{QML:Qt::createQmlObject()}{Qt.createQmlObject()}.
*/
v8::Handle<v8::Value> createComponent(const v8::Arguments &args)
{
- if (args.Length() != 1)
- V8THROW_ERROR("Qt.createComponent(): Invalid arguments");
+ const char *invalidArgs = "Qt.createComponent(): Invalid arguments";
+ if (args.Length() < 1 || args.Length() > 2)
+ V8THROW_ERROR(invalidArgs);
QV8Engine *v8engine = V8ENGINE();
QQmlEngine *engine = v8engine->engine();
@@ -1159,8 +1166,20 @@ v8::Handle<v8::Value> createComponent(const v8::Arguments &args)
if (arg.isEmpty())
return v8::Null();
+ QQmlComponent::CompilationMode compileMode = QQmlComponent::PreferSynchronous;
+ if (args.Length() == 2) {
+ if (args[1]->IsInt32()) {
+ int mode = args[1]->Int32Value();
+ if (mode != int(QQmlComponent::PreferSynchronous) && mode != int(QQmlComponent::Asynchronous))
+ V8THROW_ERROR(invalidArgs);
+ compileMode = QQmlComponent::CompilationMode(mode);
+ } else {
+ V8THROW_ERROR(invalidArgs);
+ }
+ }
+
QUrl url = context->resolvedUrl(QUrl(arg));
- QQmlComponent *c = new QQmlComponent(engine, url, engine);
+ QQmlComponent *c = new QQmlComponent(engine, url, compileMode, engine);
QQmlComponentPrivate::get(c)->creationContext = effectiveContext;
QQmlData::get(c, true)->setImplicitDestructible();
return v8engine->newQObject(c);
diff --git a/src/quick/items/qquickloader.cpp b/src/quick/items/qquickloader.cpp
index 8877385b46..59cb37c15d 100644
--- a/src/quick/items/qquickloader.cpp
+++ b/src/quick/items/qquickloader.cpp
@@ -344,7 +344,8 @@ void QQuickLoader::loadFromSource()
}
if (isComponentComplete()) {
- d->component = new QQmlComponent(qmlEngine(this), d->source, this);
+ QQmlComponent::CompilationMode mode = d->asynchronous ? QQmlComponent::Asynchronous : QQmlComponent::PreferSynchronous;
+ d->component = new QQmlComponent(qmlEngine(this), d->source, mode, this);
d->load();
}
}
@@ -711,7 +712,8 @@ void QQuickLoader::componentComplete()
QQuickItem::componentComplete();
if (active()) {
if (d->loadingFromSource) {
- d->component = new QQmlComponent(qmlEngine(this), d->source, this);
+ QQmlComponent::CompilationMode mode = d->asynchronous ? QQmlComponent::Asynchronous : QQmlComponent::PreferSynchronous;
+ d->component = new QQmlComponent(qmlEngine(this), d->source, mode, this);
}
d->load();
}
@@ -752,6 +754,9 @@ qreal QQuickLoader::progress() const
This property holds whether the component will be instantiated asynchronously.
+When used in conjunction with the \l source property, loading and compilation
+will also be performed in a background thread.
+
Loading asynchronously creates the objects declared by the component
across multiple frames, and reduces the
likelihood of glitches in animation. When loading asynchronously the status