summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIonut Alexandrescu <ionut.alexandrescu@qt.io>2017-02-20 13:27:22 +0100
committerIonut Alexandrescu <ionut.alexandrescu@qt.io>2017-02-21 12:30:30 +0000
commitbf1bd3abc9a2d990014fa8be451e0239fe12e198 (patch)
tree2d635481c7f3d92a686282c55c0d916e19b99dad
parent3e537dd3dcf5608241282d8437fb1593d2e6fa17 (diff)
Add a javascript push method binding to QQmlListProperty
Create a PropertyList prototype, and add the push method to QQmlListProperty that call the append function if it has been defined. Added a unit test and updated the documentation. Change-Id: I2647766e98b60bf0546f6d6ed1422a616e0d3a07 Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
-rw-r--r--src/qml/doc/src/qmllanguageref/typesystem/basictypes.qdoc3
-rw-r--r--src/qml/jsruntime/qv4engine.cpp2
-rw-r--r--src/qml/jsruntime/qv4engine_p.h2
-rw-r--r--src/qml/qml/qqmllistwrapper.cpp25
-rw-r--r--src/qml/qml/qqmllistwrapper_p.h8
-rw-r--r--tests/auto/qml/qqmllistreference/data/propertyList.qml12
-rw-r--r--tests/auto/qml/qqmllistreference/qqmllistreference.pro2
-rw-r--r--tests/auto/qml/qqmllistreference/tst_qqmllistreference.cpp24
8 files changed, 77 insertions, 1 deletions
diff --git a/src/qml/doc/src/qmllanguageref/typesystem/basictypes.qdoc b/src/qml/doc/src/qmllanguageref/typesystem/basictypes.qdoc
index ffbf2282a6..a486b47f03 100644
--- a/src/qml/doc/src/qmllanguageref/typesystem/basictypes.qdoc
+++ b/src/qml/doc/src/qmllanguageref/typesystem/basictypes.qdoc
@@ -324,6 +324,9 @@ property is only invoked when the property is reassigned to a different object v
\li Values in the list are accessed using the \c [index] syntax
\endlist
+ Values can be dynamically added to the list by using the \c push method,
+ as if it were a JavaScript Array
+
A \c list can only store QML objects, and cannot contain any
\l {QML Basic Types}{basic type} values. (To store basic types within a
list, use the \l var type instead.)
diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp
index 084ddc9010..f925c9184c 100644
--- a/src/qml/jsruntime/qv4engine.cpp
+++ b/src/qml/jsruntime/qv4engine.cpp
@@ -258,6 +258,7 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory)
arrayClass = emptyClass->addMember(id_length(), Attr_NotConfigurable|Attr_NotEnumerable);
jsObjects[ArrayProto] = memoryManager->allocObject<ArrayPrototype>(arrayClass, objectPrototype());
+ jsObjects[PropertyListProto] = memoryManager->allocObject<PropertyListPrototype>();
InternalClass *argsClass = emptyClass->addMember(id_length(), Attr_NotEnumerable);
argumentsObjectClass = argsClass->addMember(id_callee(), Attr_Data|Attr_NotEnumerable);
@@ -360,6 +361,7 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory)
static_cast<NumberPrototype *>(numberPrototype())->init(this, numberCtor());
static_cast<BooleanPrototype *>(booleanPrototype())->init(this, booleanCtor());
static_cast<ArrayPrototype *>(arrayPrototype())->init(this, arrayCtor());
+ static_cast<PropertyListPrototype *>(propertyListPrototype())->init(this);
static_cast<DatePrototype *>(datePrototype())->init(this, dateCtor());
static_cast<FunctionPrototype *>(functionPrototype())->init(this, functionCtor());
static_cast<RegExpPrototype *>(regExpPrototype())->init(this, regExpCtor());
diff --git a/src/qml/jsruntime/qv4engine_p.h b/src/qml/jsruntime/qv4engine_p.h
index 1c20ad30aa..69aa389c44 100644
--- a/src/qml/jsruntime/qv4engine_p.h
+++ b/src/qml/jsruntime/qv4engine_p.h
@@ -157,6 +157,7 @@ public:
IntegerNull, // Has to come after the RootContext to make the context stack safe
ObjectProto,
ArrayProto,
+ PropertyListProto,
StringProto,
NumberProto,
BooleanProto,
@@ -225,6 +226,7 @@ public:
Object *objectPrototype() const { return reinterpret_cast<Object *>(jsObjects + ObjectProto); }
Object *arrayPrototype() const { return reinterpret_cast<Object *>(jsObjects + ArrayProto); }
+ Object *propertyListPrototype() const { return reinterpret_cast<Object *>(jsObjects + PropertyListProto); }
Object *stringPrototype() const { return reinterpret_cast<Object *>(jsObjects + StringProto); }
Object *numberPrototype() const { return reinterpret_cast<Object *>(jsObjects + NumberProto); }
Object *booleanPrototype() const { return reinterpret_cast<Object *>(jsObjects + BooleanProto); }
diff --git a/src/qml/qml/qqmllistwrapper.cpp b/src/qml/qml/qqmllistwrapper.cpp
index 8aa107dc17..d94f7c56e4 100644
--- a/src/qml/qml/qqmllistwrapper.cpp
+++ b/src/qml/qml/qqmllistwrapper.cpp
@@ -165,4 +165,29 @@ void QmlListWrapper::advanceIterator(Managed *m, ObjectIterator *it, Value *name
return QV4::Object::advanceIterator(m, it, name, index, p, attrs);
}
+void PropertyListPrototype::init(ExecutionEngine *)
+{
+ defineDefaultProperty(QStringLiteral("push"), method_push, 1);
+}
+
+void PropertyListPrototype::method_push(const BuiltinFunction *, Scope &scope, CallData *callData)
+{
+ ScopedObject instance(scope, callData->thisObject.toObject(scope.engine));
+ if (!instance)
+ RETURN_UNDEFINED();
+ QmlListWrapper *w = instance->as<QmlListWrapper>();
+ if (!w)
+ RETURN_UNDEFINED();
+ if (!w->d()->property().append)
+ THROW_GENERIC_ERROR("List doesn't define an Append function");
+
+ QV4::ScopedObject so(scope);
+ for (int i = 0; i < callData->argc; ++i)
+ {
+ so = callData->args[i].toObject(scope.engine);
+ if (QV4::QObjectWrapper *wrapper = so->as<QV4::QObjectWrapper>())
+ w->d()->property().append(&w->d()->property(), wrapper->object() );
+ }
+}
+
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmllistwrapper_p.h b/src/qml/qml/qqmllistwrapper_p.h
index d01b332159..b914c681f2 100644
--- a/src/qml/qml/qqmllistwrapper_p.h
+++ b/src/qml/qml/qqmllistwrapper_p.h
@@ -86,6 +86,7 @@ struct Q_QML_EXPORT QmlListWrapper : Object
{
V4_OBJECT2(QmlListWrapper, Object)
V4_NEEDS_DESTROY
+ V4_PROTOTYPE(propertyListPrototype)
static ReturnedValue create(ExecutionEngine *engine, QObject *object, int propId, int propType);
static ReturnedValue create(ExecutionEngine *engine, const QQmlListProperty<QObject> &prop, int propType);
@@ -98,6 +99,13 @@ struct Q_QML_EXPORT QmlListWrapper : Object
static void advanceIterator(Managed *m, ObjectIterator *it, Value *name, uint *index, Property *p, PropertyAttributes *attributes);
};
+struct PropertyListPrototype : Object
+{
+ void init(ExecutionEngine *engine);
+
+ static void method_push(const BuiltinFunction *, Scope &, CallData *callData);
+};
+
}
QT_END_NAMESPACE
diff --git a/tests/auto/qml/qqmllistreference/data/propertyList.qml b/tests/auto/qml/qqmllistreference/data/propertyList.qml
new file mode 100644
index 0000000000..c791c6dcf0
--- /dev/null
+++ b/tests/auto/qml/qqmllistreference/data/propertyList.qml
@@ -0,0 +1,12 @@
+import QtQuick 2.7
+
+Item {
+ id:root
+
+ Component.onCompleted : {
+ var st1 = Qt.createQmlObject( "import QtQuick 2.7; State{ name: 'MyState1' }", root, "dynamicState1" );
+ var st2 = Qt.createQmlObject( "import QtQuick 2.7; State{ name: 'MyState2' }", root, "dynamicState2" );
+ root.states.push( st1, st2 );
+ root.state = "MyState2";
+ }
+}
diff --git a/tests/auto/qml/qqmllistreference/qqmllistreference.pro b/tests/auto/qml/qqmllistreference/qqmllistreference.pro
index dceb7d1133..110d0d9c81 100644
--- a/tests/auto/qml/qqmllistreference/qqmllistreference.pro
+++ b/tests/auto/qml/qqmllistreference/qqmllistreference.pro
@@ -8,4 +8,4 @@ include (../../shared/util.pri)
TESTDATA = data/*
-QT += core-private gui-private qml-private testlib
+QT += core-private gui-private quick-private qml-private testlib
diff --git a/tests/auto/qml/qqmllistreference/tst_qqmllistreference.cpp b/tests/auto/qml/qqmllistreference/tst_qqmllistreference.cpp
index 4d33359eaa..5c16a48378 100644
--- a/tests/auto/qml/qqmllistreference/tst_qqmllistreference.cpp
+++ b/tests/auto/qml/qqmllistreference/tst_qqmllistreference.cpp
@@ -36,6 +36,7 @@
#include <QtQml/qqmlprivate.h>
#include <QtQml/qqmlproperty.h>
#include <QDebug>
+#include <private/qquickstate_p.h>
#include "../../shared/util.h"
class tst_qqmllistreference : public QQmlDataTest
@@ -65,6 +66,7 @@ private slots:
void qmlmetaproperty();
void engineTypes();
void variantToList();
+ void listProperty();
};
class TestType : public QObject
@@ -618,6 +620,28 @@ void tst_qqmllistreference::variantToList()
delete o;
}
+void tst_qqmllistreference::listProperty()
+{
+ QQmlEngine engine;
+ QQmlComponent component(&engine, testFileUrl("propertyList.qml"));
+
+ QScopedPointer<QObject> object( component.create() );
+ QVERIFY(object != 0);
+
+ QCOMPARE( object->property("state").toString(), QStringLiteral("MyState2") );
+ QQmlListReference list( object.data(), "states");
+ QCOMPARE( list.count(), 2 );
+
+ QQuickState* state1 = dynamic_cast<QQuickState*>( list.at( 0 ) );
+ QVERIFY(state1 != 0);
+ QCOMPARE( state1->name(), QStringLiteral("MyState1") );
+ QQuickState* state2 = dynamic_cast<QQuickState*>( list.at( 1 ) );
+ QVERIFY(state2 != 0);
+
+ QCOMPARE( state2->name(), QStringLiteral("MyState2") );
+}
+
+
QTEST_MAIN(tst_qqmllistreference)
#include "tst_qqmllistreference.moc"