diff options
author | Lars Knoll <lars.knoll@nokia.com> | 2011-08-31 14:03:16 +0200 |
---|---|---|
committer | Lars Knoll <lars.knoll@nokia.com> | 2011-08-31 14:03:16 +0200 |
commit | 20c3575fc39004d6a556820543982f4a6ebef0be (patch) | |
tree | 9d8be9faae42972c85f0e296cc6dcaf27c3fcc4e | |
parent | 71478352376022faa9be6d79f2a760c289945ff5 (diff) | |
parent | 3108a36914d59d8a0d15bfdb2b5bbb09aa6e54a2 (diff) |
Merge remote-tracking branch 'origin/master' into refactor
Conflicts:
src/declarative/declarative.pro
Change-Id: I9c6d8447e1254c6acd32fa0775ff6a79d0d66acd
33 files changed, 954 insertions, 58 deletions
diff --git a/examples/declarative/particles/asteroid/blackhole.qml b/examples/declarative/particles/asteroid/blackhole.qml index 441f4c38d6..57474f955e 100644 --- a/examples/declarative/particles/asteroid/blackhole.qml +++ b/examples/declarative/particles/asteroid/blackhole.qml @@ -146,7 +146,7 @@ Rectangle{ colorVariation: 0.2 } PointAttractor{ - id: gs; x: root.width/2; y: root.height/2; strength: 4000000; + id: gs; pointX: root.width/2; pointY: root.height/2; strength: 4000000; system: particles physics: PointAttractor.Acceleration proportionalToDistance: PointAttractor.InverseQuadratic diff --git a/examples/declarative/particles/modelparticles/stream.qml b/examples/declarative/particles/modelparticles/stream.qml index 15280f7f21..0938f17cd4 100644 --- a/examples/declarative/particles/modelparticles/stream.qml +++ b/examples/declarative/particles/modelparticles/stream.qml @@ -149,8 +149,8 @@ Item{ PointAttractor{ id: force system: sys - x: root.width/2 - y: root.height/2 + pointX: root.width/2 + pointY: root.height/2 strength: -10000 active: false anchors.centerIn: parent diff --git a/examples/declarative/particles/spaceexplorer/spaceexplorer.qml b/examples/declarative/particles/spaceexplorer/spaceexplorer.qml index 727d711053..cb8acb815e 100644 --- a/examples/declarative/particles/spaceexplorer/spaceexplorer.qml +++ b/examples/declarative/particles/spaceexplorer/spaceexplorer.qml @@ -275,51 +275,51 @@ Rectangle{ system: foreground } PointAttractor{ - id: gs1; x: vorteX; y: vorteY; strength: 800000; proportionalToDistance: PointAttractor.InverseQuadratic; + id: gs1; pointX: vorteX; pointY: vorteY; strength: 800000; system: foreground } Kill{ - x: gs1.x - holeSize; - y: gs1.y - holeSize; + x: gs1.pointX - holeSize; + y: gs1.pointY - holeSize; width: holeSize * 2 height: holeSize * 2 system: foreground } PointAttractor{ - id: gs2; x: vorteX2; y: vorteY2; strength: 800000; proportionalToDistance: PointAttractor.InverseQuadratic; + id: gs2; pointX: vorteX2; pointY: vorteY2; strength: 800000; system: foreground } Kill{ - x: gs2.x - holeSize; - y: gs2.y - holeSize; + x: gs2.pointX - holeSize; + y: gs2.pointY - holeSize; width: holeSize * 2 height: holeSize * 2 system: foreground } PointAttractor{ - id: gs3; x: vorteX3; y: vorteY3; strength: 800000; proportionalToDistance: PointAttractor.InverseQuadratic; + id: gs3; pointX: vorteX3; pointY: vorteY3; strength: 800000; system: foreground } Kill{ - x: gs3.x - holeSize; - y: gs3.y - holeSize; + x: gs3.pointX - holeSize; + y: gs3.pointY - holeSize; width: holeSize * 2 height: holeSize * 2 system: foreground } PointAttractor{ - id: gs4; x: vorteX4; y: vorteY4; strength: 800000; - proportionalToDistance: PointAttractor.Quadratic; + id: gs4; pointX: vorteX4; pointY: vorteY4; strength: 800000; + proportionalToDistance: PointAttractor.InverseQuadratic; system: foreground } Kill{ - x: gs4.x - holeSize; - y: gs4.y - holeSize; + x: gs4.pointX - holeSize; + y: gs4.pointY - holeSize; width: holeSize * 2 height: holeSize * 2 system: foreground diff --git a/src/declarative/declarative.pro b/src/declarative/declarative.pro index 5db77a79dd..d0a3f01148 100644 --- a/src/declarative/declarative.pro +++ b/src/declarative/declarative.pro @@ -8,7 +8,6 @@ MODULE_PRI += ../../modules/qt_declarative.pri QT = core-private gui gui-private network widgets-private sql v8-private -contains(QT_CONFIG, svg): QT += svg DEFINES += QT_BUILD_DECLARATIVE_LIB QT_NO_URL_CAST_FROM_STRING win32-msvc*|win32-icc:QMAKE_LFLAGS += /BASE:0x66000000 solaris-cc*:QMAKE_CXXFLAGS_RELEASE -= -O2 diff --git a/src/declarative/items/qsgloader.cpp b/src/declarative/items/qsgloader.cpp index 999c174ee9..0a0a3b9cc5 100644 --- a/src/declarative/items/qsgloader.cpp +++ b/src/declarative/items/qsgloader.cpp @@ -46,16 +46,21 @@ #include <private/qdeclarativeengine_p.h> #include <private/qdeclarativeglobal_p.h> +#include <private/qdeclarativecomponent_p.h> + +#include <private/qv8_p.h> + QT_BEGIN_NAMESPACE QSGLoaderPrivate::QSGLoaderPrivate() : item(0), component(0), ownComponent(false), updatingSize(false), - itemWidthValid(false), itemHeightValid(false) + itemWidthValid(false), itemHeightValid(false), active(true) { } QSGLoaderPrivate::~QSGLoaderPrivate() { + disposeInitialPropertyValues(); } void QSGLoaderPrivate::itemGeometryChanged(QSGItem *resizeItem, const QRectF &newGeometry, const QRectF &oldGeometry) @@ -72,6 +77,8 @@ void QSGLoaderPrivate::itemGeometryChanged(QSGItem *resizeItem, const QRectF &ne void QSGLoaderPrivate::clear() { + disposeInitialPropertyValues(); + if (ownComponent) { component->deleteLater(); component = 0; @@ -228,6 +235,59 @@ QSGLoader::~QSGLoader() } /*! + \qmlproperty bool QtQuick2::Loader::active + This property is \c true if the Loader is currently active. + The default value for the \l active property is \c true. + + If the Loader is inactive, changing the \l source or \l sourceComponent + will not cause the item to be instantiated until the Loader is made active. + + Setting the value to inactive will cause any \l item loaded by the loader + to be released, but will not affect the \l source or \l sourceComponent. + + The \l status of an inactive loader is always \c Null. + + \sa source, sourceComponent + */ +bool QSGLoader::active() const +{ + Q_D(const QSGLoader); + return d->active; +} + +void QSGLoader::setActive(bool newVal) +{ + Q_D(QSGLoader); + if (d->active != newVal) { + d->active = newVal; + if (newVal == true) { + if (d->loadingFromSource) { + loadFromSource(); + } else { + loadFromSourceComponent(); + } + d->disposeInitialPropertyValues(); // release persistent handles + } else { + if (d->item) { + QSGItemPrivate *p = QSGItemPrivate::get(d->item); + p->removeItemChangeListener(d, QSGItemPrivate::Geometry); + + // We can't delete immediately because our item may have triggered + // the Loader to load a different item. + d->item->setParentItem(0); + d->item->setVisible(false); + d->item->deleteLater(); + d->item = 0; + emit itemChanged(); + } + emit statusChanged(); + } + emit activeChanged(); + } +} + + +/*! \qmlproperty url QtQuick2::Loader::source This property holds the URL of the QML component to instantiate. @@ -248,13 +308,30 @@ QUrl QSGLoader::source() const void QSGLoader::setSource(const QUrl &url) { + setSource(url, true); // clear previous values +} + +void QSGLoader::setSource(const QUrl &url, bool needsClear) +{ Q_D(QSGLoader); if (d->source == url) return; - d->clear(); + if (needsClear) + d->clear(); d->source = url; + d->loadingFromSource = true; + + if (d->active) + loadFromSource(); + else + emit sourceChanged(); +} + +void QSGLoader::loadFromSource() +{ + Q_D(QSGLoader); if (d->source.isEmpty()) { emit sourceChanged(); emit statusChanged(); @@ -308,6 +385,22 @@ void QSGLoader::setSourceComponent(QDeclarativeComponent *comp) d->component = comp; d->ownComponent = false; + d->loadingFromSource = false; + + if (d->active) + loadFromSourceComponent(); + else + emit sourceComponentChanged(); +} + +void QSGLoader::resetSourceComponent() +{ + setSourceComponent(0); +} + +void QSGLoader::loadFromSourceComponent() +{ + Q_D(QSGLoader); if (!d->component) { emit sourceComponentChanged(); emit statusChanged(); @@ -320,9 +413,95 @@ void QSGLoader::setSourceComponent(QDeclarativeComponent *comp) d->load(); } -void QSGLoader::resetSourceComponent() +/*! + \qmlmethod object QtQuick2::Loader::setSource(url source, object properties) + + Creates an object instance of the given \a source component that will have + the given \a properties. The \a properties argument is optional. The instance + will be accessible via the \l item property once loading and instantiation + is complete. + + If the \l active property is \c false at the time when this function is called, + the given \a source component will not be loaded but the \a source and initial + \a properties will be cached. When the loader is made \l active, an instance of + the \a source component will be created with the initial \a properties set. + + Setting the initial property values of an instance of a component in this manner + will \e not trigger any associated \l{Behavior}s. + + Note that the cached \a properties will be cleared if the \l source or \l sourceComponent + is changed after calling this function but prior to setting the loader \l active. + + Example: + \table + \row + \o + \qml + // ExampleComponent.qml + import QtQuick 2.0 + Rectangle { + id: rect + color: "red" + width: 10 + height: 10 + + Behavior on color { + NumberAnimation { + target: rect + property: "width" + to: (rect.width + 20) + duration: 0 + } + } + } + \endqml + \o + \qml + // example.qml + import QtQuick 2.0 + Item { + Loader { + id: squareLoader + onLoaded: console.log(squareLoader.item.width); // prints [10], not [30] + } + + Component.onCompleted: { + squareLoader.setSource("ExampleComponent.qml", { "color": "blue" }); + // will trigger the onLoaded code when complete. + } + } + \endqml + \endtable + + \sa source, active +*/ +void QSGLoader::setSource(QDeclarativeV8Function *args) { - setSourceComponent(0); + Q_ASSERT(args); + Q_D(QSGLoader); + + bool ipvError = false; + args->returnValue(v8::Undefined()); + v8::Handle<v8::Object> ipv = d->extractInitialPropertyValues(args, this, &ipvError); + if (ipvError) + return; + + d->clear(); + QUrl sourceUrl = d->resolveSourceUrl(args); + if (!ipv.IsEmpty()) { + d->initialPropertyValues = qPersistentNew(ipv); + d->qmlGlobalForIpv = qPersistentNew(args->qmlGlobal()); + } + + setSource(sourceUrl, false); // already cleared and set ipv above. +} + +void QSGLoaderPrivate::disposeInitialPropertyValues() +{ + if (!initialPropertyValues.IsEmpty()) + qPersistentDispose(initialPropertyValues); + if (!qmlGlobalForIpv.IsEmpty()) + qPersistentDispose(qmlGlobalForIpv); } void QSGLoaderPrivate::load() @@ -377,7 +556,7 @@ void QSGLoaderPrivate::_q_sourceLoaded() // component to be set to something else. In that case we just // need to cleanup. if (c) - c->completeCreate(); + completeCreateWithInitialPropertyValues(c, obj, initialPropertyValues, qmlGlobalForIpv); delete obj; delete ctxt; return; @@ -402,7 +581,7 @@ void QSGLoaderPrivate::_q_sourceLoaded() delete ctxt; source = QUrl(); } - component->completeCreate(); + completeCreateWithInitialPropertyValues(component, obj, initialPropertyValues, qmlGlobalForIpv); if (ownComponent) emit q->sourceChanged(); else @@ -419,7 +598,7 @@ void QSGLoaderPrivate::_q_sourceLoaded() This property holds the status of QML loading. It can be one of: \list - \o Loader.Null - no QML source has been set + \o Loader.Null - the loader is inactive or no QML source has been set \o Loader.Ready - the QML source has been loaded \o Loader.Loading - the QML source is currently being loaded \o Loader.Error - an error occurred while loading the QML source @@ -458,6 +637,9 @@ QSGLoader::Status QSGLoader::status() const { Q_D(const QSGLoader); + if (!d->active) + return Null; + if (d->component) return static_cast<QSGLoader::Status>(d->component->status()); @@ -548,6 +730,47 @@ void QSGLoader::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeom QSGItem::geometryChanged(newGeometry, oldGeometry); } +QUrl QSGLoaderPrivate::resolveSourceUrl(QDeclarativeV8Function *args) +{ + QV8Engine *v8engine = args->engine(); + QString arg = v8engine->toString((*args)[0]->ToString()); + if (arg.isEmpty()) + return QUrl(); + + QDeclarativeContextData *context = args->context(); + Q_ASSERT(context); + return context->resolvedUrl(QUrl(arg)); +} + +v8::Handle<v8::Object> QSGLoaderPrivate::extractInitialPropertyValues(QDeclarativeV8Function *args, QObject *loader, bool *error) +{ + v8::Local<v8::Object> valuemap; + if (args->Length() >= 2) { + v8::Local<v8::Value> v = (*args)[1]; + if (!v->IsObject() || v->IsArray()) { + *error = true; + qmlInfo(loader) << loader->tr("setSource: value is not an object"); + } else { + *error = false; + valuemap = v8::Local<v8::Object>::Cast(v); + } + } + + 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 832d3a6138..c3ce1607e0 100644 --- a/src/declarative/items/qsgloader_p.h +++ b/src/declarative/items/qsgloader_p.h @@ -57,6 +57,7 @@ class Q_AUTOTEST_EXPORT QSGLoader : public QSGImplicitSizeItem Q_OBJECT Q_ENUMS(Status) + Q_PROPERTY(bool active READ active WRITE setActive NOTIFY activeChanged) Q_PROPERTY(QUrl source READ source WRITE setSource NOTIFY sourceChanged) Q_PROPERTY(QDeclarativeComponent *sourceComponent READ sourceComponent WRITE setSourceComponent RESET resetSourceComponent NOTIFY sourceComponentChanged) Q_PROPERTY(QSGItem *item READ item NOTIFY itemChanged) @@ -67,6 +68,11 @@ public: QSGLoader(QSGItem *parent = 0); virtual ~QSGLoader(); + bool active() const; + void setActive(bool newVal); + + Q_INVOKABLE void setSource(QDeclarativeV8Function *); + QUrl source() const; void setSource(const QUrl &); @@ -82,6 +88,7 @@ public: Q_SIGNALS: void itemChanged(); + void activeChanged(); void sourceChanged(); void sourceComponentChanged(); void statusChanged(); @@ -93,6 +100,9 @@ protected: void componentComplete(); private: + void setSource(const QUrl &sourceUrl, bool needsClear); + void loadFromSource(); + void loadFromSourceComponent(); Q_DISABLE_COPY(QSGLoader) Q_DECLARE_PRIVATE(QSGLoader) Q_PRIVATE_SLOT(d_func(), void _q_sourceLoaded()) diff --git a/src/declarative/items/qsgloader_p_p.h b/src/declarative/items/qsgloader_p_p.h index 306e5ea732..732ec8679d 100644 --- a/src/declarative/items/qsgloader_p_p.h +++ b/src/declarative/items/qsgloader_p_p.h @@ -58,6 +58,8 @@ #include "qsgimplicitsizeitem_p_p.h" #include "qsgitemchangelistener_p.h" +#include <private/qv8_p.h> + QT_BEGIN_NAMESPACE class QDeclarativeContext; @@ -74,13 +76,22 @@ public: void initResize(); void load(); + 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; + v8::Persistent<v8::Object> initialPropertyValues; + v8::Persistent<v8::Object> qmlGlobalForIpv; bool ownComponent : 1; bool updatingSize: 1; bool itemWidthValid : 1; bool itemHeightValid : 1; + bool active : 1; + bool loadingFromSource : 1; void _q_sourceLoaded(); void _q_updateSize(bool loaderGeometryChanged = true); diff --git a/src/declarative/particles/qsgimageparticle.cpp b/src/declarative/particles/qsgimageparticle.cpp index 853a08a890..f269895536 100644 --- a/src/declarative/particles/qsgimageparticle.cpp +++ b/src/declarative/particles/qsgimageparticle.cpp @@ -57,7 +57,7 @@ QT_BEGIN_NAMESPACE //###Switch to define later, for now user-friendly (no compilation) debugging is worth it DEFINE_BOOL_CONFIG_OPTION(qmlParticlesDebug, QML_PARTICLES_DEBUG) -#ifdef Q_WS_MAC +#ifndef QT_OPENGL_ES_2 #define SHADER_DEFINES "#version 120\n" #else #define SHADER_DEFINES "" @@ -864,7 +864,7 @@ QSGGeometryNode* QSGImageParticle::buildParticleNodes() } else if (m_autoRotation || m_rotation || m_rotationVariation || m_rotationSpeed || m_rotationSpeedVariation) { perfLevel = Deformable; - } else if (m_alphaVariation || m_alpha != 1.0 || m_color.isValid() + } else if (m_alphaVariation || m_alpha != 1.0 || m_color.isValid() || m_color_variation || m_redVariation || m_blueVariation || m_greenVariation) { perfLevel = Colored; } else { diff --git a/src/declarative/particles/qsgpointattractor_p.h b/src/declarative/particles/qsgpointattractor_p.h index 298965a5c9..e2cdd0fdca 100644 --- a/src/declarative/particles/qsgpointattractor_p.h +++ b/src/declarative/particles/qsgpointattractor_p.h @@ -52,11 +52,9 @@ QT_MODULE(Declarative) class QSGPointAttractorAffector : public QSGParticleAffector { Q_OBJECT - //Like Gravitational singularity, but linear to distance instead of quadratic - //And affects ds/dt, not da/dt Q_PROPERTY(qreal strength READ strength WRITE setStrength NOTIFY strengthChanged) - Q_PROPERTY(qreal x READ x WRITE setX NOTIFY xChanged)//TODO: Change to pointX, pointY - Q_PROPERTY(qreal y READ y WRITE setY NOTIFY yChanged) + Q_PROPERTY(qreal pointX READ pointX WRITE setPointX NOTIFY pointXChanged) + Q_PROPERTY(qreal pointY READ pointY WRITE setPointY NOTIFY pointYChanged) Q_PROPERTY(PhysicsAffects physics READ physics WRITE setPhysics NOTIFY physicsChanged) Q_PROPERTY(Proportion proportionalToDistance READ proportionalToDistance WRITE setProportionalToDistance NOTIFY proportionalToDistanceChanged) Q_ENUMS(PhysicsAffects) @@ -84,12 +82,12 @@ public: return m_strength; } - qreal x() const + qreal pointX() const { return m_x; } - qreal y() const + qreal pointY() const { return m_y; } @@ -108,9 +106,9 @@ signals: void strengthChanged(qreal arg); - void xChanged(qreal arg); + void pointXChanged(qreal arg); - void yChanged(qreal arg); + void pointYChanged(qreal arg); void physicsChanged(PhysicsAffects arg); @@ -125,19 +123,19 @@ void setStrength(qreal arg) } } -void setX(qreal arg) +void setPointX(qreal arg) { if (m_x != arg) { m_x = arg; - emit xChanged(arg); + emit pointXChanged(arg); } } -void setY(qreal arg) +void setPointY(qreal arg) { if (m_y != arg) { m_y = arg; - emit yChanged(arg); + emit pointYChanged(arg); } } void setPhysics(PhysicsAffects arg) diff --git a/src/declarative/qml/qdeclarativecomponent.cpp b/src/declarative/qml/qdeclarativecomponent.cpp index eea94cef3e..49aa6d99b6 100644 --- a/src/declarative/qml/qdeclarativecomponent.cpp +++ b/src/declarative/qml/qdeclarativecomponent.cpp @@ -55,6 +55,9 @@ #include "private/qdeclarativedebugtrace_p.h" #include "private/qdeclarativeenginedebug_p.h" +#include "private/qv8engine_p.h" +#include "private/qv8include_p.h" + #include <QStack> #include <QStringList> #include <QtCore/qdebug.h> @@ -663,35 +666,45 @@ void QDeclarativeComponent::createObject(QDeclarativeV8Function *args) { Q_ASSERT(args); -#define RETURN(result) { args->returnValue((result)); return; } - Q_D(QDeclarativeComponent); Q_ASSERT(d->engine); - QDeclarativeEngine *engine = d->engine; - QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine); - QV8Engine *v8engine = ep->v8engine(); - - QDeclarativeContext *ctxt = creationContext(); - if (!ctxt) ctxt = engine->rootContext(); + QObject *parent = args->Length()?QDeclarativeEnginePrivate::get(d->engine)->v8engine()->toQObject((*args)[0]):0; v8::Local<v8::Object> valuemap; if (args->Length() >= 2) { v8::Local<v8::Value> v = (*args)[1]; if (!v->IsObject() || v->IsArray()) { qmlInfo(this) << tr("createObject: value is not an object"); - RETURN(v8::Null()); + args->returnValue(v8::Null()); + return; } valuemap = v8::Local<v8::Object>::Cast(v); } - QObject *parent = args->Length()?v8engine->toQObject((*args)[0]):0; + QV8Engine *v8engine = QDeclarativeEnginePrivate::get(d->engine)->v8engine(); + QObject *retn = d->createObjectWithInitialProperties(args->qmlGlobal(), valuemap, parent); + if (!retn) + args->returnValue(v8::Null()); + else + args->returnValue(v8engine->newQObject(retn)); +} + +QObject *QDeclarativeComponentPrivate::createObjectWithInitialProperties(v8::Handle<v8::Object> qmlGlobal, v8::Handle<v8::Object> valuemap, QObject *parentObject) +{ + Q_Q(QDeclarativeComponent); + Q_ASSERT(engine); - QObject *ret = beginCreate(ctxt); + QDeclarativeContext *ctxt = q->creationContext(); + if (!ctxt) ctxt = engine->rootContext(); + + QObject *parent = parentObject; + + QObject *ret = q->beginCreate(ctxt); if (!ret) { - completeCreate(); - RETURN(v8::Null()); + q->completeCreate(); + return 0; } if (parent) { @@ -715,7 +728,14 @@ void QDeclarativeComponent::createObject(QDeclarativeV8Function *args) qWarning("QDeclarativeComponent: Created graphical object was not placed in the graphics scene."); } - v8::Handle<v8::Value> ov = v8engine->newQObject(ret); + return completeCreateObjectWithInitialProperties(qmlGlobal, valuemap, ret); +} + +QObject *QDeclarativeComponentPrivate::completeCreateObjectWithInitialProperties(v8::Handle<v8::Object> qmlGlobal, v8::Handle<v8::Object> valuemap, QObject *toCreate) +{ + QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine); + QV8Engine *v8engine = ep->v8engine(); + v8::Handle<v8::Value> ov = v8engine->newQObject(toCreate); Q_ASSERT(ov->IsObject()); v8::Handle<v8::Object> object = v8::Handle<v8::Object>::Cast(ov); @@ -738,7 +758,7 @@ void QDeclarativeComponent::createObject(QDeclarativeV8Function *args) "})" v8::Local<v8::Script> script = v8engine->qmlModeCompile(SET_ARGS_SOURCE); - v8::Local<v8::Function> function = v8::Local<v8::Function>::Cast(script->Run(args->qmlGlobal())); + v8::Local<v8::Function> function = v8::Local<v8::Function>::Cast(script->Run(qmlGlobal)); // Try catch isn't needed as the function itself is loaded with try/catch v8::Handle<v8::Value> args[] = { object, valuemap }; @@ -746,14 +766,12 @@ void QDeclarativeComponent::createObject(QDeclarativeV8Function *args) } completeCreate(); - - QDeclarativeData *ddata = QDeclarativeData::get(ret); + + QDeclarativeData *ddata = QDeclarativeData::get(toCreate); Q_ASSERT(ddata); ddata->setImplicitDestructible(); - RETURN(object); - -#undef RETURN + return v8engine->toQObject(object); } /*! diff --git a/src/declarative/qml/qdeclarativecomponent_p.h b/src/declarative/qml/qdeclarativecomponent_p.h index 7677f305e2..ba937491b7 100644 --- a/src/declarative/qml/qdeclarativecomponent_p.h +++ b/src/declarative/qml/qdeclarativecomponent_p.h @@ -55,6 +55,7 @@ #include "qdeclarativecomponent.h" +#include "private/qv8_p.h" #include "private/qdeclarativeengine_p.h" #include "private/qdeclarativetypeloader_p.h" #include "private/qbitfield_p.h" @@ -69,6 +70,8 @@ QT_BEGIN_NAMESPACE +class QV8Engine; + class QDeclarativeComponent; class QDeclarativeEngine; class QDeclarativeCompiledData; @@ -83,6 +86,8 @@ public: QObject *beginCreate(QDeclarativeContextData *, const QBitField &); void completeCreate(); + QObject *createObjectWithInitialProperties(v8::Handle<v8::Object> qmlGlobal, v8::Handle<v8::Object> valuemap, QObject *parentObject); + QObject *completeCreateObjectWithInitialProperties(v8::Handle<v8::Object> qmlGlobal, v8::Handle<v8::Object> valuemap, QObject *toCreate); QDeclarativeTypeData *typeData; virtual void typeDataReady(QDeclarativeTypeData *); @@ -115,6 +120,7 @@ public: ConstructionState *state); static void complete(QDeclarativeEnginePrivate *enginePriv, ConstructionState *state); + QDeclarativeEngine *engine; QDeclarativeGuardedContextData creationContext; diff --git a/tests/auto/declarative/qsgloader/data/ActiveComponent.qml b/tests/auto/declarative/qsgloader/data/ActiveComponent.qml new file mode 100644 index 0000000000..24c6f7ad91 --- /dev/null +++ b/tests/auto/declarative/qsgloader/data/ActiveComponent.qml @@ -0,0 +1,11 @@ +import QtQuick 2.0 + +Item { + id: behaviorCounter + property int behaviorCount: 0 + property int canary: 0 + + Behavior on canary { + NumberAnimation { target: behaviorCounter; property: "behaviorCount"; to: (behaviorCounter.behaviorCount + 1); duration: 0 } + } +} diff --git a/tests/auto/declarative/qsgloader/data/InitialPropertyValuesComponent.qml b/tests/auto/declarative/qsgloader/data/InitialPropertyValuesComponent.qml new file mode 100644 index 0000000000..24c6f7ad91 --- /dev/null +++ b/tests/auto/declarative/qsgloader/data/InitialPropertyValuesComponent.qml @@ -0,0 +1,11 @@ +import QtQuick 2.0 + +Item { + id: behaviorCounter + property int behaviorCount: 0 + property int canary: 0 + + Behavior on canary { + NumberAnimation { target: behaviorCounter; property: "behaviorCount"; to: (behaviorCounter.behaviorCount + 1); duration: 0 } + } +} diff --git a/tests/auto/declarative/qsgloader/data/InvalidSourceComponent.qml b/tests/auto/declarative/qsgloader/data/InvalidSourceComponent.qml new file mode 100644 index 0000000000..7efa4a5f61 --- /dev/null +++ b/tests/auto/declarative/qsgloader/data/InvalidSourceComponent.qml @@ -0,0 +1,5 @@ +import QtQuick 2.0 + +Item { + RandomError +} diff --git a/tests/auto/declarative/qsgloader/data/active.1.qml b/tests/auto/declarative/qsgloader/data/active.1.qml new file mode 100644 index 0000000000..2dbd1a0887 --- /dev/null +++ b/tests/auto/declarative/qsgloader/data/active.1.qml @@ -0,0 +1,31 @@ +import QtQuick 2.0 + +Item { + id: root + + Loader { + id: loader + objectName: "loader" + active: false + } + + Component { + id: inlineTestComponent + Item { + id: inlineTestItem + property int someProperty: 5 + } + } + + function doSetSource() { + loader.source = "ActiveComponent.qml"; + } + + function doSetSourceComponent() { + loader.sourceComponent = inlineTestComponent; + } + + function doSetActive() { + loader.active = true; + } +} diff --git a/tests/auto/declarative/qsgloader/data/active.2.qml b/tests/auto/declarative/qsgloader/data/active.2.qml new file mode 100644 index 0000000000..e561744c63 --- /dev/null +++ b/tests/auto/declarative/qsgloader/data/active.2.qml @@ -0,0 +1,18 @@ +import QtQuick 2.0 + +Item { + id: root + + Loader { + id: loader + objectName: "loader" + source: "ActiveComponent.qml"; + + property int statusChangedCount: 0 + onStatusChanged: statusChangedCount = statusChangedCount + 1 + } + + function doSetInactive() { + loader.active = false; + } +} diff --git a/tests/auto/declarative/qsgloader/data/active.3.qml b/tests/auto/declarative/qsgloader/data/active.3.qml new file mode 100644 index 0000000000..0fbba959bb --- /dev/null +++ b/tests/auto/declarative/qsgloader/data/active.3.qml @@ -0,0 +1,18 @@ +import QtQuick 2.0 + +Item { + id: root + + Loader { + id: loader + objectName: "loader" + source: "ActiveComponent.qml"; + + property int sourceChangedCount: 0 + onSourceChanged: sourceChangedCount = sourceChangedCount + 1 + } + + function doSetInactive() { + loader.active = false; + } +} diff --git a/tests/auto/declarative/qsgloader/data/active.4.qml b/tests/auto/declarative/qsgloader/data/active.4.qml new file mode 100644 index 0000000000..63fd46e2da --- /dev/null +++ b/tests/auto/declarative/qsgloader/data/active.4.qml @@ -0,0 +1,26 @@ +import QtQuick 2.0 + +Item { + id: root + + Component { + id: inlineTestComponent + Item { + id: inlineTestItem + property int someProperty: 5 + } + } + + Loader { + id: loader + objectName: "loader" + sourceComponent: inlineTestComponent + + property int sourceComponentChangedCount: 0 + onSourceComponentChanged: sourceComponentChangedCount = sourceComponentChangedCount + 1 + } + + function doSetInactive() { + loader.active = false; + } +} diff --git a/tests/auto/declarative/qsgloader/data/active.5.qml b/tests/auto/declarative/qsgloader/data/active.5.qml new file mode 100644 index 0000000000..903f458a41 --- /dev/null +++ b/tests/auto/declarative/qsgloader/data/active.5.qml @@ -0,0 +1,18 @@ +import QtQuick 2.0 + +Item { + id: root + + Loader { + id: loader + objectName: "loader" + source: "ActiveComponent.qml"; + + property int itemChangedCount: 0 + onItemChanged: itemChangedCount = itemChangedCount + 1 + } + + function doSetInactive() { + loader.active = false; + } +} diff --git a/tests/auto/declarative/qsgloader/data/active.6.qml b/tests/auto/declarative/qsgloader/data/active.6.qml new file mode 100644 index 0000000000..f769a4e184 --- /dev/null +++ b/tests/auto/declarative/qsgloader/data/active.6.qml @@ -0,0 +1,21 @@ +import QtQuick 2.0 + +Item { + id: root + + Loader { + id: loader + objectName: "loader" + + property int activeChangedCount: 0 + onActiveChanged: activeChangedCount = activeChangedCount + 1 + } + + function doSetActive() { + loader.active = true; + } + + function doSetInactive() { + loader.active = false; + } +} diff --git a/tests/auto/declarative/qsgloader/data/initialPropertyValues.1.qml b/tests/auto/declarative/qsgloader/data/initialPropertyValues.1.qml new file mode 100644 index 0000000000..ae371797ce --- /dev/null +++ b/tests/auto/declarative/qsgloader/data/initialPropertyValues.1.qml @@ -0,0 +1,22 @@ +import QtQuick 2.0 + +Item { + id: root + property int initialValue: 0 + property int behaviorCount: 0 + + Loader { + id: loader + objectName: "loader" + + onLoaded: { + loader.item.canary = 1; // will trigger the behavior, setting behaviorCount -> 1 + } + } + + Component.onCompleted: { + loader.source = "InitialPropertyValuesComponent.qml"; + root.initialValue = loader.item.canary; // should be one, since onLoaded will have triggered by now + root.behaviorCount = loader.item.behaviorCount; // should be one, since onLoaded will have triggered by now + } +} diff --git a/tests/auto/declarative/qsgloader/data/initialPropertyValues.2.qml b/tests/auto/declarative/qsgloader/data/initialPropertyValues.2.qml new file mode 100644 index 0000000000..76c7bc2fd6 --- /dev/null +++ b/tests/auto/declarative/qsgloader/data/initialPropertyValues.2.qml @@ -0,0 +1,20 @@ +import QtQuick 2.0 + +Item { + id: root + property int initialValue: 0 + property int behaviorCount: 0 + + Loader { + id: loader + objectName: "loader" + onLoaded: { + root.initialValue = loader.item.canary; // should be two + root.behaviorCount = loader.item.behaviorCount; // should be zero + } + } + + Component.onCompleted: { + loader.setSource("InitialPropertyValuesComponent.qml", {"canary": 2}); + } +} diff --git a/tests/auto/declarative/qsgloader/data/initialPropertyValues.3.qml b/tests/auto/declarative/qsgloader/data/initialPropertyValues.3.qml new file mode 100644 index 0000000000..3b08e6ee42 --- /dev/null +++ b/tests/auto/declarative/qsgloader/data/initialPropertyValues.3.qml @@ -0,0 +1,18 @@ +import QtQuick 2.0 + +Item { + id: root + property int initialValue: 0 + property int behaviorCount: 0 + + Loader { + id: loader + objectName: "loader" + active: false + } + + Component.onCompleted: { + loader.setSource("InitialPropertyValuesComponent.qml", {"canary": 3}); + root.initialValue = loader.item.canary; // error - item should not yet exist. + } +} diff --git a/tests/auto/declarative/qsgloader/data/initialPropertyValues.4.qml b/tests/auto/declarative/qsgloader/data/initialPropertyValues.4.qml new file mode 100644 index 0000000000..e8310044e8 --- /dev/null +++ b/tests/auto/declarative/qsgloader/data/initialPropertyValues.4.qml @@ -0,0 +1,22 @@ +import QtQuick 2.0 + +Item { + id: root + property int initialValue: 0 + property int behaviorCount: 0 + + Loader { + id: loader + objectName: "loader" + active: false + onLoaded: { + root.initialValue = loader.item.canary; // should be four + root.behaviorCount = loader.item.behaviorCount; // should be zero + } + } + + Component.onCompleted: { + loader.setSource("InitialPropertyValuesComponent.qml", {"canary": 4}); + loader.active = true + } +} diff --git a/tests/auto/declarative/qsgloader/data/initialPropertyValues.5.qml b/tests/auto/declarative/qsgloader/data/initialPropertyValues.5.qml new file mode 100644 index 0000000000..03ee599aba --- /dev/null +++ b/tests/auto/declarative/qsgloader/data/initialPropertyValues.5.qml @@ -0,0 +1,20 @@ +import QtQuick 2.0 + +Item { + id: root + property int initialValue: 0 + property int behaviorCount: 0 + + Loader { + id: loader + objectName: "loader" + onLoaded: { + root.initialValue = loader.item.canary; // should be zero, but no error + root.behaviorCount = loader.item.behaviorCount; // should be zero + } + } + + Component.onCompleted: { + loader.setSource("InitialPropertyValuesComponent.qml"); + } +} diff --git a/tests/auto/declarative/qsgloader/data/initialPropertyValues.6.qml b/tests/auto/declarative/qsgloader/data/initialPropertyValues.6.qml new file mode 100644 index 0000000000..66452b512b --- /dev/null +++ b/tests/auto/declarative/qsgloader/data/initialPropertyValues.6.qml @@ -0,0 +1,25 @@ +import QtQuick 2.0 + +Item { + id: root + property int initialValue: 0 + property int behaviorCount: 0 + + Loader { + id: loader + objectName: "loader" + onLoaded: { + root.initialValue = loader.item.canary; // should be six + root.behaviorCount = loader.item.behaviorCount; // should be zero + } + } + + Item { + id: child + property int bindable: 6 + } + + Component.onCompleted: { + loader.setSource("InitialPropertyValuesComponent.qml", {"canary": child.bindable}); + } +} diff --git a/tests/auto/declarative/qsgloader/data/initialPropertyValues.7.qml b/tests/auto/declarative/qsgloader/data/initialPropertyValues.7.qml new file mode 100644 index 0000000000..02349f7ddf --- /dev/null +++ b/tests/auto/declarative/qsgloader/data/initialPropertyValues.7.qml @@ -0,0 +1,29 @@ +import QtQuick 2.0 + +Item { + id: root + property int loaderValue: 0 + property int createObjectValue: 0 + + Loader { + id: loader + objectName: "loader" + onLoaded: { + root.loaderValue = loader.item.canary; // should still be one + } + } + + Item { + id: child + property int bindable: 1; + } + + property InitialPropertyValuesComponent ipvc + Component.onCompleted: { + loader.setSource("InitialPropertyValuesComponent.qml", {"canary": child.bindable}); + var dynComp = Qt.createComponent("InitialPropertyValuesComponent.qml"); + ipvc = dynComp.createObject(root, {"canary": child.bindable}); + child.bindable = 7; // won't cause re-evaluation, since not used in a binding. + root.createObjectValue = ipvc.canary; // should still be one + } +} diff --git a/tests/auto/declarative/qsgloader/data/initialPropertyValues.binding.qml b/tests/auto/declarative/qsgloader/data/initialPropertyValues.binding.qml new file mode 100644 index 0000000000..e0df50a74a --- /dev/null +++ b/tests/auto/declarative/qsgloader/data/initialPropertyValues.binding.qml @@ -0,0 +1,21 @@ +import QtQuick 2.0 + +Item { + id: root + + property InitialPropertyValuesComponent testInstance + testInstance: loader.item + + property int bindable: 1 + property int canaryValue: testInstance.canary + property int behaviorCount: testInstance.behaviorCount + + Loader { + id: loader + objectName: "loader" + } + + Component.onCompleted: { + loader.setSource("InitialPropertyValuesComponent.qml", {"canary": (function() { return root.bindable })}); + } +} diff --git a/tests/auto/declarative/qsgloader/data/initialPropertyValues.error.1.qml b/tests/auto/declarative/qsgloader/data/initialPropertyValues.error.1.qml new file mode 100644 index 0000000000..f324dbddac --- /dev/null +++ b/tests/auto/declarative/qsgloader/data/initialPropertyValues.error.1.qml @@ -0,0 +1,14 @@ +import QtQuick 2.0 + +Item { + id: root + + Loader { + id: loader + objectName: "loader" + } + + Component.onCompleted: { + loader.setSource("InitialPropertyValuesComponent.qml", 3); // invalid initial properties object + } +} diff --git a/tests/auto/declarative/qsgloader/data/initialPropertyValues.error.2.qml b/tests/auto/declarative/qsgloader/data/initialPropertyValues.error.2.qml new file mode 100644 index 0000000000..89aba313c7 --- /dev/null +++ b/tests/auto/declarative/qsgloader/data/initialPropertyValues.error.2.qml @@ -0,0 +1,14 @@ +import QtQuick 2.0 + +Item { + id: root + + Loader { + id: loader + objectName: "loader" + } + + Component.onCompleted: { + loader.setSource("NonexistentSourceComponent.qml", {"canary":3}); + } +} diff --git a/tests/auto/declarative/qsgloader/data/initialPropertyValues.error.3.qml b/tests/auto/declarative/qsgloader/data/initialPropertyValues.error.3.qml new file mode 100644 index 0000000000..c862007402 --- /dev/null +++ b/tests/auto/declarative/qsgloader/data/initialPropertyValues.error.3.qml @@ -0,0 +1,14 @@ +import QtQuick 2.0 + +Item { + id: root + + Loader { + id: loader + objectName: "loader" + } + + Component.onCompleted: { + loader.setSource("InvalidSourceComponent.qml", {"canary":3}); + } +} diff --git a/tests/auto/declarative/qsgloader/data/initialPropertyValues.error.4.qml b/tests/auto/declarative/qsgloader/data/initialPropertyValues.error.4.qml new file mode 100644 index 0000000000..9a80b2156d --- /dev/null +++ b/tests/auto/declarative/qsgloader/data/initialPropertyValues.error.4.qml @@ -0,0 +1,15 @@ +import QtQuick 2.0 + +Item { + id: root + property int canary: loader.item.canary + + Loader { + id: loader + objectName: "loader" + } + + Component.onCompleted: { + loader.setSource("InitialPropertyValuesComponent.qml", 3); // invalid initial properties object + } +} diff --git a/tests/auto/declarative/qsgloader/tst_qsgloader.cpp b/tests/auto/declarative/qsgloader/tst_qsgloader.cpp index c7e01da7ba..daf9e2a58a 100644 --- a/tests/auto/declarative/qsgloader/tst_qsgloader.cpp +++ b/tests/auto/declarative/qsgloader/tst_qsgloader.cpp @@ -41,6 +41,7 @@ #include <qtest.h> #include <QSignalSpy> + #include <QtDeclarative/qdeclarativeengine.h> #include <QtDeclarative/qdeclarativecomponent.h> #include <private/qsgloader_p.h> @@ -79,6 +80,12 @@ private slots: void networkRequestUrl(); void failNetworkRequest(); // void networkComponent(); + void active(); + void initialPropertyValues_data(); + void initialPropertyValues(); + void initialPropertyValuesBinding(); + void initialPropertyValuesError_data(); + void initialPropertyValuesError(); void deleteComponentCrash(); void nonItem(); @@ -465,6 +472,237 @@ void tst_QSGLoader::failNetworkRequest() delete loader; } +void tst_QSGLoader::active() +{ + // check that the item isn't instantiated until active is set to true + { + QDeclarativeComponent component(&engine, TEST_FILE("active.1.qml")); + QObject *object = component.create(); + QVERIFY(object != 0); + QSGLoader *loader = object->findChild<QSGLoader*>("loader"); + + QVERIFY(loader->active() == false); // set manually to false + QVERIFY(loader->item() == 0); + QMetaObject::invokeMethod(object, "doSetSourceComponent"); + QVERIFY(loader->item() == 0); + QMetaObject::invokeMethod(object, "doSetSource"); + QVERIFY(loader->item() == 0); + QMetaObject::invokeMethod(object, "doSetActive"); + QVERIFY(loader->item() != 0); + + delete object; + } + + // check that the status is Null if active is set to false + { + QDeclarativeComponent component(&engine, TEST_FILE("active.2.qml")); + QObject *object = component.create(); + QVERIFY(object != 0); + QSGLoader *loader = object->findChild<QSGLoader*>("loader"); + + QVERIFY(loader->active() == true); // active is true by default + QCOMPARE(loader->status(), QSGLoader::Ready); + int currStatusChangedCount = loader->property("statusChangedCount").toInt(); + QMetaObject::invokeMethod(object, "doSetInactive"); + QCOMPARE(loader->status(), QSGLoader::Null); + QCOMPARE(loader->property("statusChangedCount").toInt(), (currStatusChangedCount+1)); + + delete object; + } + + // check that the source is not cleared if active is set to false + { + QDeclarativeComponent component(&engine, TEST_FILE("active.3.qml")); + QObject *object = component.create(); + QVERIFY(object != 0); + QSGLoader *loader = object->findChild<QSGLoader*>("loader"); + + QVERIFY(loader->active() == true); // active is true by default + QVERIFY(!loader->source().isEmpty()); + int currSourceChangedCount = loader->property("sourceChangedCount").toInt(); + QMetaObject::invokeMethod(object, "doSetInactive"); + QVERIFY(!loader->source().isEmpty()); + QCOMPARE(loader->property("sourceChangedCount").toInt(), currSourceChangedCount); + + delete object; + } + + // check that the sourceComponent is not cleared if active is set to false + { + QDeclarativeComponent component(&engine, TEST_FILE("active.4.qml")); + QObject *object = component.create(); + QVERIFY(object != 0); + QSGLoader *loader = object->findChild<QSGLoader*>("loader"); + + QVERIFY(loader->active() == true); // active is true by default + QVERIFY(loader->sourceComponent() != 0); + int currSourceComponentChangedCount = loader->property("sourceComponentChangedCount").toInt(); + QMetaObject::invokeMethod(object, "doSetInactive"); + QVERIFY(loader->sourceComponent() != 0); + QCOMPARE(loader->property("sourceComponentChangedCount").toInt(), currSourceComponentChangedCount); + + delete object; + } + + // check that the item is released if active is set to false + { + QDeclarativeComponent component(&engine, TEST_FILE("active.5.qml")); + QObject *object = component.create(); + QVERIFY(object != 0); + QSGLoader *loader = object->findChild<QSGLoader*>("loader"); + + QVERIFY(loader->active() == true); // active is true by default + QVERIFY(loader->item() != 0); + int currItemChangedCount = loader->property("itemChangedCount").toInt(); + QMetaObject::invokeMethod(object, "doSetInactive"); + QVERIFY(loader->item() == 0); + QCOMPARE(loader->property("itemChangedCount").toInt(), (currItemChangedCount+1)); + + delete object; + } + + // check that the activeChanged signal is emitted correctly + { + QDeclarativeComponent component(&engine, TEST_FILE("active.6.qml")); + QObject *object = component.create(); + QVERIFY(object != 0); + QSGLoader *loader = object->findChild<QSGLoader*>("loader"); + + QVERIFY(loader->active() == true); // active is true by default + loader->setActive(true); // no effect + QCOMPARE(loader->property("activeChangedCount").toInt(), 0); + loader->setActive(false); // change signal should be emitted + QCOMPARE(loader->property("activeChangedCount").toInt(), 1); + loader->setActive(false); // no effect + QCOMPARE(loader->property("activeChangedCount").toInt(), 1); + loader->setActive(true); // change signal should be emitted + QCOMPARE(loader->property("activeChangedCount").toInt(), 2); + loader->setActive(false); // change signal should be emitted + QCOMPARE(loader->property("activeChangedCount").toInt(), 3); + QMetaObject::invokeMethod(object, "doSetActive"); + QCOMPARE(loader->property("activeChangedCount").toInt(), 4); + QMetaObject::invokeMethod(object, "doSetActive"); + QCOMPARE(loader->property("activeChangedCount").toInt(), 4); + QMetaObject::invokeMethod(object, "doSetInactive"); + QCOMPARE(loader->property("activeChangedCount").toInt(), 5); + loader->setActive(true); // change signal should be emitted + QCOMPARE(loader->property("activeChangedCount").toInt(), 6); + + delete object; + } +} + +void tst_QSGLoader::initialPropertyValues_data() +{ + QTest::addColumn<QUrl>("qmlFile"); + QTest::addColumn<QStringList>("expectedWarnings"); + QTest::addColumn<QStringList>("propertyNames"); + QTest::addColumn<QVariantList>("propertyValues"); + + QTest::newRow("source url with value set in onLoaded, initially active = true") << TEST_FILE("initialPropertyValues.1.qml") + << QStringList() + << (QStringList() << "initialValue" << "behaviorCount") + << (QVariantList() << 1 << 1); + + QTest::newRow("set source with initial property values specified, active = true") << TEST_FILE("initialPropertyValues.2.qml") + << QStringList() + << (QStringList() << "initialValue" << "behaviorCount") + << (QVariantList() << 2 << 0); + + QTest::newRow("set source with initial property values specified, active = false") << TEST_FILE("initialPropertyValues.3.qml") + << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("initialPropertyValues.3.qml").toLocalFile() + QLatin1String(":16: TypeError: Cannot read property 'canary' of null"))) + << (QStringList()) + << (QVariantList()); + + QTest::newRow("set source with initial property values specified, active = false, with active set true later") << TEST_FILE("initialPropertyValues.4.qml") + << QStringList() + << (QStringList() << "initialValue" << "behaviorCount") + << (QVariantList() << 4 << 0); + + QTest::newRow("set source without initial property values specified, active = true") << TEST_FILE("initialPropertyValues.5.qml") + << QStringList() + << (QStringList() << "initialValue" << "behaviorCount") + << (QVariantList() << 0 << 0); + + QTest::newRow("set source with initial property values specified with binding, active = true") << TEST_FILE("initialPropertyValues.6.qml") + << QStringList() + << (QStringList() << "initialValue" << "behaviorCount") + << (QVariantList() << 6 << 0); + + QTest::newRow("ensure initial property value semantics mimic createObject") << TEST_FILE("initialPropertyValues.7.qml") + << QStringList() + << (QStringList() << "loaderValue" << "createObjectValue") + << (QVariantList() << 1 << 1); +} + +void tst_QSGLoader::initialPropertyValues() +{ + QFETCH(QUrl, qmlFile); + QFETCH(QStringList, expectedWarnings); + QFETCH(QStringList, propertyNames); + QFETCH(QVariantList, propertyValues); + + foreach (const QString &warning, expectedWarnings) + QTest::ignoreMessage(QtWarningMsg, warning.toAscii().constData()); + + QDeclarativeComponent component(&engine, qmlFile); + QObject *object = component.create(); + QVERIFY(object != 0); + + for (int i = 0; i < propertyNames.size(); ++i) + QCOMPARE(object->property(propertyNames.at(i).toAscii().constData()), propertyValues.at(i)); + + delete object; +} + +void tst_QSGLoader::initialPropertyValuesBinding() +{ + QDeclarativeComponent component(&engine, TEST_FILE("initialPropertyValues.binding.qml")); + QObject *object = component.create(); + QVERIFY(object != 0); + + QVERIFY(object->setProperty("bindable", QVariant(8))); + QCOMPARE(object->property("canaryValue").toInt(), 8); + + delete object; +} + +void tst_QSGLoader::initialPropertyValuesError_data() +{ + QTest::addColumn<QUrl>("qmlFile"); + QTest::addColumn<QStringList>("expectedWarnings"); + + QTest::newRow("invalid initial property values object") << TEST_FILE("initialPropertyValues.error.1.qml") + << (QStringList() << QString(TEST_FILE("initialPropertyValues.error.1.qml").toString() + ":6:5: QML Loader: setSource: value is not an object")); + + QTest::newRow("nonexistent source url") << TEST_FILE("initialPropertyValues.error.2.qml") + << (QStringList() << QString(TEST_FILE("NonexistentSourceComponent.qml").toString() + ": File not found")); + + QTest::newRow("invalid source url") << TEST_FILE("initialPropertyValues.error.3.qml") + << (QStringList() << QString(TEST_FILE("InvalidSourceComponent.qml").toString() + ":5:1: Syntax error")); + + QTest::newRow("invalid initial property values object with invalid property access") << TEST_FILE("initialPropertyValues.error.4.qml") + << (QStringList() << QString(TEST_FILE("initialPropertyValues.error.4.qml").toString() + ":7:5: QML Loader: setSource: value is not an object") + << QString(TEST_FILE("initialPropertyValues.error.4.qml").toString() + ":5: TypeError: Cannot read property 'canary' of null")); +} + +void tst_QSGLoader::initialPropertyValuesError() +{ + QFETCH(QUrl, qmlFile); + QFETCH(QStringList, expectedWarnings); + + foreach (const QString &warning, expectedWarnings) + QTest::ignoreMessage(QtWarningMsg, warning.toUtf8().constData()); + + QDeclarativeComponent component(&engine, qmlFile); + QObject *object = component.create(); + QVERIFY(object != 0); + QSGLoader *loader = object->findChild<QSGLoader*>("loader"); + QVERIFY(loader != 0); + QVERIFY(loader->item() == 0); + delete object; +} + // QTBUG-9241 void tst_QSGLoader::deleteComponentCrash() { |