Skip to content

Commit

Permalink
Correctly resolve elements of QList<QUrl> properties
Browse files Browse the repository at this point in the history
Previously, the value of a QList<QUrl> sequence was only resolved if
there was only one element in the sequence.  This commit ensures that
all elements in the sequence are resolved correctly.

Task-number: QTBUG-23131
Change-Id: Id27748853fe01ae22800fbd02d062e268ad7ec70
Reviewed-by: Roberto Raggi <roberto.raggi@nokia.com>
  • Loading branch information
Chris Adams authored and Qt by Nokia committed Dec 19, 2011
1 parent 6859056 commit 8460eae
Show file tree
Hide file tree
Showing 3 changed files with 101 additions and 25 deletions.
65 changes: 40 additions & 25 deletions src/declarative/qml/qdeclarativeproperty.cpp
Expand Up @@ -1052,6 +1052,39 @@ QVariant QDeclarativePropertyPrivate::readValueProperty()
}
}

// helper function to allow assignment / binding to QList<QUrl> properties.
static QVariant resolvedUrlSequence(const QVariant &value, QDeclarativeContextData *context)
{
QList<QUrl> urls;
if (value.userType() == qMetaTypeId<QUrl>()) {
urls.append(value.toUrl());
} else if (value.userType() == qMetaTypeId<QString>()) {
urls.append(QUrl(value.toString()));
} else if (value.userType() == qMetaTypeId<QByteArray>()) {
urls.append(QUrl(QString::fromUtf8(value.toByteArray())));
} else if (value.userType() == qMetaTypeId<QList<QUrl> >()) {
urls = value.value<QList<QUrl> >();
} else if (value.userType() == qMetaTypeId<QStringList>()) {
QStringList urlStrings = value.value<QStringList>();
for (int i = 0; i < urlStrings.size(); ++i)
urls.append(QUrl(urlStrings.at(i)));
} else if (value.userType() == qMetaTypeId<QList<QString> >()) {
QList<QString> urlStrings = value.value<QList<QString> >();
for (int i = 0; i < urlStrings.size(); ++i)
urls.append(QUrl(urlStrings.at(i)));
} // note: QList<QByteArray> is not currently supported.

QList<QUrl> resolvedUrls;
for (int i = 0; i < urls.size(); ++i) {
QUrl u = urls.at(i);
if (context && u.isRelative() && !u.isEmpty())
u = context->resolvedUrl(u);
resolvedUrls.append(u);
}

return QVariant::fromValue<QList<QUrl> >(resolvedUrls);
}

//writeEnumProperty MIRRORS the relelvant bit of QMetaProperty::write AND MUST BE KEPT IN SYNC!
bool QDeclarativePropertyPrivate::writeEnumProperty(const QMetaProperty &prop, int idx, QObject *object, const QVariant &value, int flags)
{
Expand Down Expand Up @@ -1194,6 +1227,11 @@ bool QDeclarativePropertyPrivate::write(QObject *object,
void *argv[] = { &u, 0, &status, &flags };
QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, argv);

} else if (propertyType == qMetaTypeId<QList<QUrl> >()) {
QList<QUrl> urlSeq = resolvedUrlSequence(value, context).value<QList<QUrl> >();
int status = -1;
void *argv[] = { &urlSeq, 0, &status, &flags };
QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, argv);
} else if (variantType == propertyType) {

void *a[] = { (void *)value.constData(), 0, &status, &flags };
Expand Down Expand Up @@ -1299,6 +1337,7 @@ bool QDeclarativePropertyPrivate::write(QObject *object,
if (!ok) {
// the only other option is that they are assigning a single value
// to a sequence type property (eg, an int to a QList<int> property).
// Note that we've already handled single-value assignment to QList<QUrl> properties.
if (variantType == QVariant::Int && propertyType == qMetaTypeId<QList<int> >()) {
QList<int> list;
list << value.toInt();
Expand All @@ -1314,28 +1353,6 @@ bool QDeclarativePropertyPrivate::write(QObject *object,
list << value.toBool();
v = QVariant::fromValue<QList<bool> >(list);
ok = true;
} else if ((variantType == QVariant::Url || variantType == QVariant::String || variantType == QVariant::ByteArray)
&& propertyType == qMetaTypeId<QList<QUrl> >()) {
QUrl u;
bool found = false;
if (variantType == QVariant::Url) {
u = value.toUrl();
found = true;
} else if (variantType == QVariant::ByteArray) {
u = QUrl(QString::fromUtf8(value.toByteArray()));
found = true;
} else if (variantType == QVariant::String) {
u = QUrl(value.toString());
found = true;
}
if (!found)
return false;
if (context && u.isRelative() && !u.isEmpty())
u = context->resolvedUrl(u);
QList<QUrl> list;
list << u;
v = QVariant::fromValue<QList<QUrl> >(list);
ok = true;
} else if (variantType == QVariant::String && propertyType == qMetaTypeId<QList<QString> >()) {
QList<QString> list;
list << value.toString();
Expand Down Expand Up @@ -1423,9 +1440,7 @@ bool QDeclarativePropertyPrivate::writeBinding(QObject *object,
} else if (result->IsNull() && core.isQObject()) {
value = QVariant::fromValue((QObject *)0);
} else if (core.propType == qMetaTypeId<QList<QUrl> >()) {
value = v8engine->toVariant(result, qMetaTypeId<QList<QUrl> >());
if (value.userType() == qMetaTypeId<QString>())
value = QVariant(QUrl(value.toString()));
value = resolvedUrlSequence(v8engine->toVariant(result, qMetaTypeId<QList<QUrl> >()), context);
} else if (!isVmeProperty) {
value = v8engine->toVariant(result, type);
}
Expand Down
@@ -0,0 +1,42 @@
import QtQuick 2.0
import Qt.test 1.0

Item {
// single url assignment to url list property
MySequenceConversionObject {
id: msco1
objectName: "msco1"
}

// single url binding to url list property
MySequenceConversionObject {
id: msco2
objectName: "msco2"
urlListProperty: "example.html"
}

// multiple url assignment to url list property
MySequenceConversionObject {
id: msco3
objectName: "msco3"
}

// multiple url binding to url list property
MySequenceConversionObject {
id: msco4
objectName: "msco4"
urlListProperty: [ "example.html", "example2.html" ]
}

// multiple url binding to url list property - already resolved
MySequenceConversionObject {
id: msco5
objectName: "msco5"
urlListProperty: [ Qt.resolvedUrl("example.html"), Qt.resolvedUrl("example2.html") ]
}

Component.onCompleted: {
msco1.urlListProperty = "example.html";
msco3.urlListProperty = [ "example.html", "example2.html" ];
}
}
Expand Up @@ -4709,6 +4709,25 @@ void tst_qdeclarativeecmascript::assignSequenceTypes()
QCOMPARE(object->urlListProperty(), (QList<QUrl>() << QUrl(TEST_FILE("example.html"))));
delete object;
}

// test QList<QUrl> literal assignment and binding assignment causes url resolution when required
{
QDeclarativeComponent component(&engine, TEST_FILE("assignSequenceTypes.7.qml"));
QObject *object = component.create();
QVERIFY(object != 0);
MySequenceConversionObject *msco1 = object->findChild<MySequenceConversionObject *>(QLatin1String("msco1"));
MySequenceConversionObject *msco2 = object->findChild<MySequenceConversionObject *>(QLatin1String("msco2"));
MySequenceConversionObject *msco3 = object->findChild<MySequenceConversionObject *>(QLatin1String("msco3"));
MySequenceConversionObject *msco4 = object->findChild<MySequenceConversionObject *>(QLatin1String("msco4"));
MySequenceConversionObject *msco5 = object->findChild<MySequenceConversionObject *>(QLatin1String("msco5"));
QVERIFY(msco1 != 0 && msco2 != 0 && msco3 != 0 && msco4 != 0 && msco5 != 0);
QCOMPARE(msco1->urlListProperty(), (QList<QUrl>() << QUrl(TEST_FILE("example.html"))));
QCOMPARE(msco2->urlListProperty(), (QList<QUrl>() << QUrl(TEST_FILE("example.html"))));
QCOMPARE(msco3->urlListProperty(), (QList<QUrl>() << QUrl(TEST_FILE("example.html")) << QUrl(TEST_FILE("example2.html"))));
QCOMPARE(msco4->urlListProperty(), (QList<QUrl>() << QUrl(TEST_FILE("example.html")) << QUrl(TEST_FILE("example2.html"))));
QCOMPARE(msco5->urlListProperty(), (QList<QUrl>() << QUrl(TEST_FILE("example.html")) << QUrl(TEST_FILE("example2.html"))));
delete object;
}
}

// Test that assigning a null object works
Expand Down

0 comments on commit 8460eae

Please sign in to comment.