aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--doc/src/declarative/extending.qdoc23
-rw-r--r--src/declarative/qml/v8/qv8sequencewrapper.cpp21
-rw-r--r--src/declarative/qml/v8/qv8sequencewrapper_p.h2
-rw-r--r--src/declarative/qml/v8/qv8sequencewrapper_p_p.h67
-rw-r--r--tests/auto/declarative/qdeclarativeecmascript/data/sequenceConversion.array.qml41
-rw-r--r--tests/auto/declarative/qdeclarativeecmascript/tst_qdeclarativeecmascript.cpp12
6 files changed, 156 insertions, 10 deletions
diff --git a/doc/src/declarative/extending.qdoc b/doc/src/declarative/extending.qdoc
index c1c7547ec2..385469c29f 100644
--- a/doc/src/declarative/extending.qdoc
+++ b/doc/src/declarative/extending.qdoc
@@ -252,7 +252,7 @@ In particular, QML currently supports:
\o \c {QList<int>}
\o \c {QList<qreal>}
\o \c {QList<bool>}
- \o \c {QList<QString>}
+ \o \c {QList<QString>} and \c{QStringList}
\o \c {QList<QUrl>}
\endlist
@@ -274,6 +274,27 @@ modified directly.
Other sequence types are not supported transparently, and instead an instance of any other
sequence type will be passed between QML and C++ as an opaque QVariantList.
+\bold {Important Note:} There are some minor differences between the semantics of such
+sequence Array types and default JavaScript Array types which result from the use of a
+C++ storage type in the implementation. In particular, deleting an element from an Array
+will result in a default-constructed value replacing that element, rather than an
+Undefined value. Similarly, setting the length property of the Array to a value larger
+than its current value will result in the Array being padded out to the specified length
+with default-constructed elements rather than Undefined elements.
+
+The default-constructed values for each sequence type are as follows:
+\table
+\row \o QList<int> \o integer value 0
+\row \o QList<qreal> \o real value 0.0
+\row \o QList<bool> \o boolean value \c {false}
+\row \o QList<QString> and QStringList \o empty QString
+\row \o QList<QUrl> \o empty QUrl
+\endtable
+
+If you wish to remove elements from a sequence rather than simply replace them with default
+constructed values, do not use the indexed delete operator ("delete sequence[i]") but instead
+use the \c {splice} function ("sequence.splice(startIndex, deleteCount)").
+
\section1 Inheritance and Coercion
\snippet examples/declarative/cppextensions/referenceexamples/coercion/example.qml 0
diff --git a/src/declarative/qml/v8/qv8sequencewrapper.cpp b/src/declarative/qml/v8/qv8sequencewrapper.cpp
index f63b5da4ea..267e8ec4e6 100644
--- a/src/declarative/qml/v8/qv8sequencewrapper.cpp
+++ b/src/declarative/qml/v8/qv8sequencewrapper.cpp
@@ -66,10 +66,10 @@ void QV8SequenceWrapper::init(QV8Engine *engine)
m_valueOf = qPersistentNew<v8::Function>(v8::FunctionTemplate::New(ValueOf)->GetFunction());
v8::Local<v8::FunctionTemplate> ft = v8::FunctionTemplate::New();
ft->InstanceTemplate()->SetFallbackPropertyHandler(Getter, Setter);
- ft->InstanceTemplate()->SetIndexedPropertyHandler(IndexedGetter, IndexedSetter, 0, 0, IndexedEnumerator);
- ft->InstanceTemplate()->SetAccessor(v8::String::New("length"), LengthGetter, 0,
+ ft->InstanceTemplate()->SetIndexedPropertyHandler(IndexedGetter, IndexedSetter, 0, IndexedDeleter, IndexedEnumerator);
+ ft->InstanceTemplate()->SetAccessor(v8::String::New("length"), LengthGetter, LengthSetter,
v8::Handle<v8::Value>(), v8::DEFAULT,
- v8::PropertyAttribute(v8::ReadOnly | v8::DontDelete | v8::DontEnum));
+ v8::PropertyAttribute(v8::DontDelete | v8::DontEnum));
ft->InstanceTemplate()->SetAccessor(v8::String::New("toString"), ToStringGetter, 0,
m_toString, v8::DEFAULT,
v8::PropertyAttribute(v8::ReadOnly | v8::DontDelete | v8::DontEnum));
@@ -184,6 +184,13 @@ v8::Handle<v8::Value> QV8SequenceWrapper::IndexedGetter(quint32 index, const v8:
return sr->indexedGetter(index);
}
+v8::Handle<v8::Boolean> QV8SequenceWrapper::IndexedDeleter(quint32 index, const v8::AccessorInfo &info)
+{
+ QV8SequenceResource *sr = v8_resource_cast<QV8SequenceResource>(info.This());
+ Q_ASSERT(sr);
+ return sr->indexedDeleter(index);
+}
+
v8::Handle<v8::Array> QV8SequenceWrapper::IndexedEnumerator(const v8::AccessorInfo &info)
{
QV8SequenceResource *sr = v8_resource_cast<QV8SequenceResource>(info.This());
@@ -199,6 +206,14 @@ v8::Handle<v8::Value> QV8SequenceWrapper::LengthGetter(v8::Local<v8::String> pro
return v8::Integer::NewFromUnsigned(sr->lengthGetter());
}
+void QV8SequenceWrapper::LengthSetter(v8::Local<v8::String> property, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
+{
+ Q_UNUSED(property);
+ QV8SequenceResource *sr = v8_resource_cast<QV8SequenceResource>(info.This());
+ Q_ASSERT(sr);
+ sr->lengthSetter(value);
+}
+
v8::Handle<v8::Value> QV8SequenceWrapper::ToStringGetter(v8::Local<v8::String> property, const v8::AccessorInfo &info)
{
Q_UNUSED(property);
diff --git a/src/declarative/qml/v8/qv8sequencewrapper_p.h b/src/declarative/qml/v8/qv8sequencewrapper_p.h
index da0f7eacca..0ddeed9eda 100644
--- a/src/declarative/qml/v8/qv8sequencewrapper_p.h
+++ b/src/declarative/qml/v8/qv8sequencewrapper_p.h
@@ -88,8 +88,10 @@ private:
static v8::Handle<v8::Value> IndexedGetter(quint32 index, const v8::AccessorInfo &info);
static v8::Handle<v8::Value> IndexedSetter(quint32 index, v8::Local<v8::Value> value, const v8::AccessorInfo &info);
+ static v8::Handle<v8::Boolean> IndexedDeleter(quint32 index, const v8::AccessorInfo &info);
static v8::Handle<v8::Array> IndexedEnumerator(const v8::AccessorInfo &info);
static v8::Handle<v8::Value> LengthGetter(v8::Local<v8::String> property, const v8::AccessorInfo &info);
+ static void LengthSetter(v8::Local<v8::String> property, v8::Local<v8::Value> value, const v8::AccessorInfo &info);
static v8::Handle<v8::Value> ToStringGetter(v8::Local<v8::String> property, const v8::AccessorInfo &info);
static v8::Handle<v8::Value> ToString(const v8::Arguments &args);
static v8::Handle<v8::Value> ValueOfGetter(v8::Local<v8::String> property, const v8::AccessorInfo &info);
diff --git a/src/declarative/qml/v8/qv8sequencewrapper_p_p.h b/src/declarative/qml/v8/qv8sequencewrapper_p_p.h
index eea595ed6b..a947d52013 100644
--- a/src/declarative/qml/v8/qv8sequencewrapper_p_p.h
+++ b/src/declarative/qml/v8/qv8sequencewrapper_p_p.h
@@ -82,8 +82,10 @@ public:
virtual bool isEqual(const QV8SequenceResource *v) = 0;
virtual quint32 lengthGetter() = 0;
+ virtual void lengthSetter(v8::Handle<v8::Value> value) = 0;
virtual v8::Handle<v8::Value> indexedSetter(quint32 index, v8::Handle<v8::Value> value) = 0;
virtual v8::Handle<v8::Value> indexedGetter(quint32 index) = 0;
+ virtual v8::Handle<v8::Boolean> indexedDeleter(quint32 index) = 0;
virtual v8::Handle<v8::Array> indexedEnumerator() = 0;
virtual v8::Handle<v8::Value> toString() = 0;
@@ -286,6 +288,48 @@ static QString convertUrlToString(QV8Engine *, const QUrl &v)
} \
return c.count(); \
} \
+ void lengthSetter(v8::Handle<v8::Value> value) \
+ { \
+ /* Get the new required length */ \
+ if (value.IsEmpty() || !value->IsUint32()) \
+ return; \
+ quint32 newLength = value->Uint32Value(); \
+ /* Read the sequence from the QObject property if we're a reference */ \
+ if (objectType == QV8SequenceResource::Reference) { \
+ if (!object) \
+ return; \
+ void *a[] = { &c, 0 }; \
+ QMetaObject::metacall(object, QMetaObject::ReadProperty, propertyIndex, a); \
+ } \
+ /* Determine whether we need to modify the sequence */ \
+ quint32 count = c.count(); \
+ if (newLength == count) { \
+ return; \
+ } else if (newLength > count) { \
+ /* according to ECMA262r3 we need to insert */ \
+ /* undefined values increasing length to newLength. */ \
+ /* We cannot, so we insert default-values instead. */ \
+ while (newLength > count++) { \
+ c.append(DefaultValue); \
+ } \
+ } else { \
+ /* according to ECMA262r3 we need to remove */ \
+ /* elements until the sequence is the required length. */ \
+ while (newLength < count) { \
+ count--; \
+ c.removeAt(count); \
+ } \
+ } \
+ /* write back if required. */ \
+ if (objectType == QV8SequenceResource::Reference) { \
+ /* write back. already checked that object is non-null, so skip that check here. */ \
+ int status = -1; \
+ QDeclarativePropertyPrivate::WriteFlags flags = QDeclarativePropertyPrivate::DontRemoveBinding; \
+ void *a[] = { &c, 0, &status, &flags }; \
+ QMetaObject::metacall(object, QMetaObject::WriteProperty, propertyIndex, a); \
+ } \
+ return; \
+ } \
v8::Handle<v8::Value> indexedSetter(quint32 index, v8::Handle<v8::Value> value) \
{ \
if (objectType == QV8SequenceResource::Reference) { \
@@ -331,6 +375,29 @@ static QString convertUrlToString(QV8Engine *, const QUrl &v)
return ConversionToV8fn(engine, c.at(index)); \
return v8::Undefined(); \
} \
+ v8::Handle<v8::Boolean> indexedDeleter(quint32 index) \
+ { \
+ if (objectType == QV8SequenceResource::Reference) { \
+ if (!object) \
+ return v8::Boolean::New(false); \
+ void *a[] = { &c, 0 }; \
+ QMetaObject::metacall(object, QMetaObject::ReadProperty, propertyIndex, a); \
+ } \
+ if (index < c.count()) { \
+ /* according to ECMA262r3 it should be Undefined, */ \
+ /* but we cannot, so we insert a default-value instead. */ \
+ c.replace(index, DefaultValue); \
+ if (objectType == QV8SequenceResource::Reference) { \
+ /* write back. already checked that object is non-null, so skip that check here. */ \
+ int status = -1; \
+ QDeclarativePropertyPrivate::WriteFlags flags = QDeclarativePropertyPrivate::DontRemoveBinding; \
+ void *a[] = { &c, 0, &status, &flags }; \
+ QMetaObject::metacall(object, QMetaObject::WriteProperty, propertyIndex, a); \
+ } \
+ return v8::Boolean::New(true); \
+ } \
+ return v8::Boolean::New(false); \
+ } \
v8::Handle<v8::Array> indexedEnumerator() \
{ \
if (objectType == QV8SequenceResource::Reference) { \
diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/sequenceConversion.array.qml b/tests/auto/declarative/qdeclarativeecmascript/data/sequenceConversion.array.qml
index 5eaa225708..52abda1e55 100644
--- a/tests/auto/declarative/qdeclarativeecmascript/data/sequenceConversion.array.qml
+++ b/tests/auto/declarative/qdeclarativeecmascript/data/sequenceConversion.array.qml
@@ -79,26 +79,67 @@ Item {
if (msco.intListProperty[199] != 200) success = false;
if (msco.intListProperty.length != 200) success = false;
+ // test indexed deleter
+ msco.intListProperty = [ 1, 2, 3, 4, 5 ];
+ delete msco.intListProperty[-1];
+ expected = [ 1, 2, 3, 4, 5 ];
+ if (msco.intListProperty.toString() != expected.toString()) success = false;
+ delete msco.intListProperty[0];
+ expected = [ 0, 2, 3, 4, 5 ];
+ if (msco.intListProperty.toString() != expected.toString()) success = false;
+ delete msco.intListProperty[2];
+ expected = [ 0, 2, 0, 4, 5 ];
+ if (msco.intListProperty.toString() != expected.toString()) success = false;
+ delete msco.intListProperty[7];
+ expected = [ 0, 2, 0, 4, 5 ];
+ if (msco.intListProperty.toString() != expected.toString()) success = false;
+
// other operations are defined on the array prototype; see if they work.
+
+ // splice
msco.intListProperty = [ 0, 1, 2, 3, 4, 5, 6, 7 ];
msco.intListProperty.splice(1,3, 33, 44, 55, 66);
expected = [ 0, 33, 44, 55, 66, 4, 5, 6, 7 ];
if (msco.intListProperty.toString() != expected.toString()) success = false;
+ msco.intListProperty = [ 0, 1, 2, 3, 4, 5, 6, 7 ];
+ msco.intListProperty.splice(1, 3);
+ expected = [ 0, 4, 5, 6, 7 ];
+ if (msco.intListProperty.toString() != expected.toString()) success = false;
msco.qrealListProperty = [ 0.1, 1.1, 2.1, 3.1, 4.1, 5.1, 6.1, 7.1 ];
msco.qrealListProperty.splice(1,3, 33.33, 44.44, 55.55, 66.66);
expected = [ 0.1, 33.33, 44.44, 55.55, 66.66, 4.1, 5.1, 6.1, 7.1 ];
if (msco.qrealListProperty.toString() != expected.toString()) success = false;
+ msco.qrealListProperty = [ 0.1, 1.1, 2.1, 3.1, 4.1, 5.1, 6.1, 7.1 ];
+ msco.qrealListProperty.splice(1,3);
+ expected = [ 0.1, 4.1, 5.1, 6.1, 7.1 ];
+ if (msco.qrealListProperty.toString() != expected.toString()) success = false;
msco.boolListProperty = [ false, true, true, false, false, true, false, true ];
msco.boolListProperty.splice(1,3, false, true, false, false);
expected = [ false, false, true, false, false, false, true, false, true ];
if (msco.boolListProperty.toString() != expected.toString()) success = false;
+ msco.boolListProperty = [ false, true, true, false, false, true, false, true ];
+ msco.boolListProperty.splice(1,3);
+ expected = [ false, false, true, false, true ];
+ if (msco.boolListProperty.toString() != expected.toString()) success = false;
msco.stringListProperty = [ "one", "two", "three", "four", "five", "six", "seven", "eight" ];
msco.stringListProperty.splice(1,3, "nine", "ten", "eleven", "twelve");
expected = [ "one", "nine", "ten", "eleven", "twelve", "five", "six", "seven", "eight" ];
if (msco.stringListProperty.toString() != expected.toString()) success = false;
+ msco.stringListProperty = [ "one", "two", "three", "four", "five", "six", "seven", "eight" ];
+ msco.stringListProperty.splice(0,3);
+ expected = [ "four", "five", "six", "seven", "eight" ];
+ if (msco.stringListProperty.toString() != expected.toString()) success = false;
+
+ // pop
+ msco.intListProperty = [ 0, 1, 2, 3, 4, 5, 6, 7 ];
+ var poppedVal = msco.intListProperty.pop();
+ expected = [ 0, 1, 2, 3, 4, 5, 6 ];
+ if (msco.intListProperty.toString() != expected.toString()) success = false;
+ expected = 7;
+ if (poppedVal != expected) success = false;
}
property variant variantList: [ 1, 2, 3, 4, 5 ];
diff --git a/tests/auto/declarative/qdeclarativeecmascript/tst_qdeclarativeecmascript.cpp b/tests/auto/declarative/qdeclarativeecmascript/tst_qdeclarativeecmascript.cpp
index 426f9663d2..a95d4380fa 100644
--- a/tests/auto/declarative/qdeclarativeecmascript/tst_qdeclarativeecmascript.cpp
+++ b/tests/auto/declarative/qdeclarativeecmascript/tst_qdeclarativeecmascript.cpp
@@ -4225,14 +4225,14 @@ void tst_qdeclarativeecmascript::sequenceConversionArray()
QDeclarativeComponent component(&engine, qmlFile);
QObject *object = component.create();
QVERIFY(object != 0);
- //QMetaObject::invokeMethod(object, "indexedAccess");
- //QVERIFY(object->property("success").toBool());
- //QMetaObject::invokeMethod(object, "arrayOperations");
- //QVERIFY(object->property("success").toBool());
+ QMetaObject::invokeMethod(object, "indexedAccess");
+ QVERIFY(object->property("success").toBool());
+ QMetaObject::invokeMethod(object, "arrayOperations");
+ QVERIFY(object->property("success").toBool());
QMetaObject::invokeMethod(object, "testEqualitySemantics");
QVERIFY(object->property("success").toBool());
- //QMetaObject::invokeMethod(object, "testReferenceDeletion");
- //QCOMPARE(object->property("referenceDeletion").toBool(), true);
+ QMetaObject::invokeMethod(object, "testReferenceDeletion");
+ QCOMPARE(object->property("referenceDeletion").toBool(), true);
delete object;
}