Component.incubateObject() autotest
authorAaron Kennedy <aaron.kennedy@nokia.com>
Fri, 7 Oct 2011 03:16:47 +0000 (13:16 +1000)
committerQt by Nokia <qt-info@nokia.com>
Tue, 11 Oct 2011 23:31:11 +0000 (01:31 +0200)
Change-Id: I37f76d5b273ae4f032c4de5ac8fcbff4204b78fe
Reviewed-on: http://codereview.qt-project.org/6200
Reviewed-by: Aaron Kennedy <aaron.kennedy@nokia.com>
Sanity-Review: Aaron Kennedy <aaron.kennedy@nokia.com>

src/declarative/qml/qdeclarativecomponent.cpp
tests/auto/declarative/qdeclarativecomponent/data/incubateObject.qml [new file with mode: 0644]
tests/auto/declarative/qdeclarativecomponent/tst_qdeclarativecomponent.cpp

index 8aeeb78..eafe853 100644 (file)
@@ -1052,6 +1052,57 @@ void QDeclarativeComponent::createObject(QDeclarativeV8Function *args)
         args->returnValue(object);
 }
 
+/*!
+    \qmlmethod object Component::incubateObject(Item parent, object properties, enum mode)
+
+    Creates an incubator for instance of this component.  Incubators allow new component 
+    instances to be instantiated asynchronously and not cause freezes in the UI.
+
+    The \a parent argument specifies the parent the created instance will have.  Omitting the 
+    parameter or passing null will create anobject with no parent.  In this case, a reference
+    to the created object must be maintained by the application of the object will eventually
+    be garbage collected.
+
+    The \a properties argument is specified as a map of property-value items which will be
+    set on the created object during its construction.  \a mode may be Qt.Synchronous or 
+    Qt.Asynchronous and controls whether the instance is created synchronously or asynchronously. 
+    The default is asynchronously.  In some circumstances, even if Qt.Synchronous is specified,
+    the incubator may create the object asynchronously.  This happens if the component calling
+    incubateObject() is itself being created asynchronously.
+
+    All three arguments are optional.
+
+    If successful, the method returns an incubator, otherwise null.  The incubator has the following
+    properties:
+
+    \list
+    \i status The status of the incubator.  Valid values are Component.Ready, Component.Loading and
+       Component.Error.
+    \i object The created object instance.  Will only be available once the incubator is in the 
+       Ready status.
+    \i onStatusChanged Specifies a callback function to be invoked when the status changes.  The
+       status is passed as a parameter to the callback.
+    \i forceCompletion() Call to complete incubation synchronously.
+    \endlist
+
+    The following example demonstrates how to use an incubator:
+
+    \js
+        var component = Qt.createComponent("Button.qml");
+
+        var incubator = component.incubateObject(parent, { x: 10, y: 10 });
+        if (incubator.status != Component.Ready) {
+            incubator.onStatusChanged = function(status) {
+                if (status == Component.Ready) {
+                    print ("Object", incubator.object, "is now ready!");
+                }
+            }
+        } else {
+            print ("Object", incubator.object, "is ready immediately!");
+        }
+    \endjs
+*/
+
 void QDeclarativeComponent::incubateObject(QDeclarativeV8Function *args)
 {
     Q_D(QDeclarativeComponent);
@@ -1067,12 +1118,14 @@ void QDeclarativeComponent::incubateObject(QDeclarativeV8Function *args)
 
     if (args->Length() >= 2) {
         v8::Local<v8::Value> v = (*args)[1];
-        if (!v->IsObject() || v->IsArray()) {
+        if (v->IsNull()) {
+        } else if (!v->IsObject() || v->IsArray()) {
             qmlInfo(this) << tr("createObject: value is not an object");
             args->returnValue(v8::Null());
             return;
+        } else {
+            valuemap = v8::Local<v8::Object>::Cast(v);
         }
-        valuemap = v8::Local<v8::Object>::Cast(v);
     }
 
     if (args->Length() >= 3) {
@@ -1159,7 +1212,7 @@ QDeclarativeComponentExtension::QDeclarativeComponentExtension(QV8Engine *engine
 #define INITIALPROPERTIES_SOURCE \
         "(function(object, values) {"\
             "try {"\
-                "for(var property in values) {"\
+                "for(var property in values) {" \
                     "try {"\
                         "var properties = property.split(\".\");"\
                         "var o = object;"\
@@ -1242,7 +1295,7 @@ void QV8IncubatorResource::setInitialState(QObject *o)
         v8::Context::Scope scope(engine->context());
 
         v8::Handle<v8::Value> function = e->initialProperties->Run(qmlGlobal);
-        v8::Handle<v8::Value> args[] = { me, valuemap };
+        v8::Handle<v8::Value> args[] = { engine->newQObject(o), valuemap };
         v8::Handle<v8::Function>::Cast(function)->Call(engine->global(), 2, args);
 
         qPersistentDispose(valuemap);
diff --git a/tests/auto/declarative/qdeclarativecomponent/data/incubateObject.qml b/tests/auto/declarative/qdeclarativecomponent/data/incubateObject.qml
new file mode 100644 (file)
index 0000000..c11319d
--- /dev/null
@@ -0,0 +1,36 @@
+import QtQuick 2.0
+
+Item{
+    id: root
+
+    property bool test1: false
+    property bool test2: false
+
+    property var i
+
+    Component{ 
+        id: component
+        Item {
+            property int dummy: 13
+            property int dummy2: 26
+        } 
+    }
+
+    Component.onCompleted: {
+        i = component.incubateObject(null, { dummy2: 19 });
+
+        if (i.status != Component.Loading) return;
+        if (i.object != null) return;
+
+        i.onStatusChanged = function(status) {
+            if (status != Component.Ready) return;
+            if (i.object == null) return;
+            if (i.object.dummy != 13) return;
+            if (i.object.dummy2 != 19) return;
+            test2 = true;
+        }
+
+        test1 = true;
+    }
+}
+
index fe947fd..8914881 100644 (file)
 #include <QtDeclarative/qdeclarativecomponent.h>
 #include <QtDeclarative/qsgitem.h>
 #include <QtDeclarative/qdeclarativeproperty.h>
+#include <QtDeclarative/qdeclarativeincubator.h>
 #include <qcolor.h>
+#include "../../../shared/util.h"
+
+#ifdef Q_OS_SYMBIAN
+// In Symbian OS test data is located in applications private dir
+#define SRCDIR "."
+#endif
+
+class MyIC : public QObject, public QDeclarativeIncubationController
+{
+    Q_OBJECT
+public:
+    MyIC() { startTimer(5); }
+protected:
+    virtual void timerEvent(QTimerEvent*) {
+        incubateFor(5);
+    }
+};
 
 class tst_qdeclarativecomponent : public QObject
 {
     Q_OBJECT
 public:
-    tst_qdeclarativecomponent() { }
+    tst_qdeclarativecomponent() { engine.setIncubationController(&ic); }
 
 private slots:
     void null();
     void loadEmptyUrl();
     void qmlCreateObject();
     void qmlCreateObjectWithProperties();
+    void qmlIncubateObject();
 
 private:
     QDeclarativeEngine engine;
+    MyIC ic;
 };
 
 void tst_qdeclarativecomponent::null()
@@ -91,6 +111,19 @@ void tst_qdeclarativecomponent::loadEmptyUrl()
     QCOMPARE(error.description(), QLatin1String("Invalid empty URL"));
 }
 
+void tst_qdeclarativecomponent::qmlIncubateObject()
+{
+    QDeclarativeComponent component(&engine, QUrl::fromLocalFile(SRCDIR "/data/incubateObject.qml"));
+    QObject *object = component.create();
+    QVERIFY(object != 0);
+    QCOMPARE(object->property("test1").toBool(), true);
+    QCOMPARE(object->property("test2").toBool(), false);
+
+    QTRY_VERIFY(object->property("test2").toBool() == true);
+
+    delete object;
+}
+
 void tst_qdeclarativecomponent::qmlCreateObject()
 {
     QDeclarativeEngine engine;