diff options
author | Martin Jones <martin.jones@nokia.com> | 2012-03-06 18:03:33 +1000 |
---|---|---|
committer | Qt by Nokia <qt-info@nokia.com> | 2012-03-15 10:14:37 +0100 |
commit | 31467e8649979d06ea2f676768016e6a147eadb9 (patch) | |
tree | b318865886c33aa266141870972adc03900522e0 /src | |
parent | b634c19680cd1d4dd925a18e616844ed420d18ae (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.cpp | 109 | ||||
-rw-r--r-- | src/qml/qml/qqmlcomponent.h | 6 | ||||
-rw-r--r-- | src/qml/qml/qqmlcomponent_p.h | 2 | ||||
-rw-r--r-- | src/qml/qml/qqmltypeloader.cpp | 4 | ||||
-rw-r--r-- | src/qml/qml/qqmltypeloader_p.h | 2 | ||||
-rw-r--r-- | src/qml/qml/v8/qqmlbuiltinfunctions.cpp | 27 | ||||
-rw-r--r-- | src/quick/items/qquickloader.cpp | 9 |
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 |