diff options
author | Fabian Kosmale <fabian.kosmale@qt.io> | 2020-11-10 16:50:46 +0100 |
---|---|---|
committer | Fabian Kosmale <fabian.kosmale@qt.io> | 2020-11-12 10:23:12 +0100 |
commit | bf547fb272f568e438ed9c2fe48427b5a054f93a (patch) | |
tree | 0d4c8a6f1579a6d50fdb196410502e2028d5025d | |
parent | 6a605df673380ffe4e7ee24417175f58ba7972a4 (diff) |
ListModel: support URLs
Fixes: QTBUG-88379
Change-Id: I6e2ea550d8f8972c5fdcdc21a5e3851992c591a5
Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
-rw-r--r-- | src/qmlmodels/qqmllistmodel.cpp | 96 | ||||
-rw-r--r-- | src/qmlmodels/qqmllistmodel_p_p.h | 4 | ||||
-rw-r--r-- | tests/auto/qml/qqmllistmodel/data/urls.qml | 19 | ||||
-rw-r--r-- | tests/auto/qml/qqmllistmodel/tst_qqmllistmodel.cpp | 11 |
4 files changed, 127 insertions, 3 deletions
diff --git a/src/qmlmodels/qqmllistmodel.cpp b/src/qmlmodels/qqmllistmodel.cpp index 0d556a2e0e..921b4d41f2 100644 --- a/src/qmlmodels/qqmllistmodel.cpp +++ b/src/qmlmodels/qqmllistmodel.cpp @@ -50,6 +50,7 @@ #include <private/qv4object_p.h> #include <private/qv4dateobject_p.h> +#include <private/qv4urlobject_p.h> #include <private/qv4objectiterator_p.h> #include <private/qv4alloca_p.h> #include <private/qv4lookup_p.h> @@ -89,7 +90,7 @@ static QString roleTypeName(ListLayout::Role::DataType t) static const QString roleTypeNames[] = { QStringLiteral("String"), QStringLiteral("Number"), QStringLiteral("Bool"), QStringLiteral("List"), QStringLiteral("QObject"), QStringLiteral("VariantMap"), - QStringLiteral("DateTime"), QStringLiteral("Function") + QStringLiteral("DateTime"), QStringLiteral("Url"), QStringLiteral("Function") }; if (t > ListLayout::Role::Invalid && t < ListLayout::Role::MaxDataType) @@ -128,8 +129,8 @@ const ListLayout::Role &ListLayout::getRoleOrCreate(QV4::String *key, Role::Data const ListLayout::Role &ListLayout::createRole(const QString &key, ListLayout::Role::DataType type) { - const int dataSizes[] = { sizeof(StringOrTranslation), sizeof(double), sizeof(bool), sizeof(ListModel *), sizeof(QPointer<QObject>), sizeof(QVariantMap), sizeof(QDateTime), sizeof(QJSValue) }; - const int dataAlignments[] = { sizeof(StringOrTranslation), sizeof(double), sizeof(bool), sizeof(ListModel *), sizeof(QObject *), sizeof(QVariantMap), sizeof(QDateTime), sizeof(QJSValue) }; + const int dataSizes[] = { sizeof(StringOrTranslation), sizeof(double), sizeof(bool), sizeof(ListModel *), sizeof(QPointer<QObject>), sizeof(QVariantMap), sizeof(QDateTime), sizeof(QUrl), sizeof(QJSValue) }; + const int dataAlignments[] = { sizeof(StringOrTranslation), sizeof(double), sizeof(bool), sizeof(ListModel *), sizeof(QObject *), sizeof(QVariantMap), sizeof(QDateTime), sizeof(QUrl), sizeof(QJSValue) }; Role *r = new Role; r->name = key; @@ -226,6 +227,7 @@ const ListLayout::Role *ListLayout::getRoleOrCreate(const QString &key, const QV case QMetaType::QString: type = Role::String; break; case QMetaType::QVariantMap: type = Role::VariantMap; break; case QMetaType::QDateTime: type = Role::DateTime; break; + case QMetaType::QUrl: type = Role::Url; break; default: { if (data.userType() == qMetaTypeId<QJSValue>() && data.value<QJSValue>().isCallable()) { @@ -587,6 +589,10 @@ void ListModel::set(int elementIndex, QV4::Object *object, QVector<int> *roles) const ListLayout::Role &r = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::DateTime); QDateTime dt = dd->toQDateTime(); roleIndex = e->setDateTimeProperty(r, dt); + } else if (QV4::UrlObject *url = propertyValue->as<QV4::UrlObject>()) { + const ListLayout::Role &r = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::Url); + QUrl qurl = QUrl(url->href()); + roleIndex = e->setUrlProperty(r, qurl); } else if (QV4::FunctionObject *f = propertyValue->as<QV4::FunctionObject>()) { const ListLayout::Role &r = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::Function); QV4::ScopedFunctionObject func(scope, f); @@ -599,6 +605,11 @@ void ListModel::set(int elementIndex, QV4::Object *object, QVector<int> *roles) const ListLayout::Role &role = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::QObject); if (role.type == ListLayout::Role::QObject) roleIndex = e->setQObjectProperty(role, o); + } else if (QVariant maybeUrl = o->engine()->toVariant(o->asReturnedValue(), QMetaType::QUrl, true); + maybeUrl.metaType() == QMetaType::fromType<QUrl>()) { + const ListLayout::Role &r = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::Url); + QUrl qurl = maybeUrl.toUrl(); + roleIndex = e->setUrlProperty(r, qurl); } else { const ListLayout::Role &role = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::VariantMap); if (role.type == ListLayout::Role::VariantMap) { @@ -673,6 +684,12 @@ void ListModel::set(int elementIndex, QV4::Object *object, ListModel::SetElement QDateTime dt = date->toQDateTime(); e->setDateTimePropertyFast(r, dt); } + } else if (QV4::UrlObject *url = propertyValue->as<QV4::UrlObject>()){ + const ListLayout::Role &r = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::Url); + if (r.type == ListLayout::Role::Url) { + QUrl qurl = QUrl(url->href()); // does what the private UrlObject->toQUrl would do + e->setUrlPropertyFast(r, qurl); + } } else if (QV4::Object *o = propertyValue->as<QV4::Object>()) { if (QV4::QObjectWrapper *wrapper = o->as<QV4::QObjectWrapper>()) { QObject *o = wrapper->object(); @@ -680,6 +697,15 @@ void ListModel::set(int elementIndex, QV4::Object *object, ListModel::SetElement if (r.type == ListLayout::Role::QObject) e->setQObjectPropertyFast(r, o); } else { + QVariant maybeUrl = o->engine()->toVariant(o->asReturnedValue(), QMetaType::QUrl, true); + if (maybeUrl.metaType() == QMetaType::fromType<QUrl>()) { + const QUrl qurl = maybeUrl.toUrl(); + const ListLayout::Role &r = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::Url); + if (r.type == ListLayout::Role::Url) { + e->setUrlPropertyFast(r, qurl); + } + return; + } const ListLayout::Role &role = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::VariantMap); if (role.type == ListLayout::Role::VariantMap) e->setVariantMapFast(role, o); @@ -823,6 +849,17 @@ QDateTime *ListElement::getDateTimeProperty(const ListLayout::Role &role) return dt; } +QUrl *ListElement::getUrlProperty(const ListLayout::Role &role) +{ + QUrl *url = nullptr; + + char *mem = getPropertyMemory(role); + if (isMemoryUsed<QUrl>(mem)) + url = reinterpret_cast<QUrl *>(mem); + + return url; +} + QJSValue *ListElement::getFunctionProperty(const ListLayout::Role &role) { QJSValue *f = nullptr; @@ -927,6 +964,14 @@ QVariant ListElement::getProperty(const ListLayout::Role &role, const QQmlListMo } } break; + case ListLayout::Role::Url: + { + if (isMemoryUsed<QUrl>(mem)) { + QUrl *url = reinterpret_cast<QUrl *>(mem); + data = *url; + } + } + break; case ListLayout::Role::Function: { if (isMemoryUsed<QJSValue>(mem)) { @@ -1099,6 +1144,23 @@ int ListElement::setDateTimeProperty(const ListLayout::Role &role, const QDateTi return roleIndex; } +int ListElement::setUrlProperty(const ListLayout::Role &role, const QUrl &url) +{ + int roleIndex = -1; + + if (role.type == ListLayout::Role::Url) { + char *mem = getPropertyMemory(role); + if (isMemoryUsed<QUrl>(mem)) { + QUrl *qurl = reinterpret_cast<QUrl *>(mem); + qurl->~QUrl(); + } + new (mem) QUrl(url); + roleIndex = role.index; + } + + return roleIndex; +} + int ListElement::setFunctionProperty(const ListLayout::Role &role, const QJSValue &f) { int roleIndex = -1; @@ -1177,6 +1239,12 @@ void ListElement::setDateTimePropertyFast(const ListLayout::Role &role, const QD new (mem) QDateTime(dt); } +void ListElement::setUrlPropertyFast(const ListLayout::Role &role, const QUrl &url) +{ + char *mem = getPropertyMemory(role); + new (mem) QUrl(url); +} + void ListElement::setFunctionPropertyFast(const ListLayout::Role &role, const QJSValue &f) { char *mem = getPropertyMemory(role); @@ -1204,6 +1272,9 @@ void ListElement::clearProperty(const ListLayout::Role &role) case ListLayout::Role::DateTime: setDateTimeProperty(role, QDateTime()); break; + case ListLayout::Role::Url: + setUrlProperty(role, QUrl()); + break; case ListLayout::Role::VariantMap: setVariantMapProperty(role, (QVariantMap *)nullptr); break; @@ -1336,6 +1407,13 @@ void ListElement::destroy(ListLayout *layout) dt->~QDateTime(); } break; + case ListLayout::Role::Url: + { + QUrl *url = getUrlProperty(r); + if (url) + url->~QUrl(); + break; + } case ListLayout::Role::Function: { QJSValue *f = getFunctionProperty(r); @@ -1388,6 +1466,9 @@ int ListElement::setVariantProperty(const ListLayout::Role &role, const QVariant case ListLayout::Role::DateTime: roleIndex = setDateTimeProperty(role, d.toDateTime()); break; + case ListLayout::Role::Url: + roleIndex = setUrlProperty(role, d.toUrl()); + break; case ListLayout::Role::Function: roleIndex = setFunctionProperty(role, d.value<QJSValue>()); break; @@ -1433,6 +1514,10 @@ int ListElement::setJsProperty(const ListLayout::Role &role, const QV4::Value &d QV4::Scoped<QV4::DateObject> dd(scope, d); QDateTime dt = dd->toQDateTime(); roleIndex = setDateTimeProperty(role, dt); + } else if (d.as<QV4::UrlObject>()) { + QV4::Scoped<QV4::UrlObject> url(scope, d); + QUrl qurl = QUrl(url->href()); + roleIndex = setUrlProperty(role, qurl); } else if (d.as<QV4::FunctionObject>()) { QV4::ScopedFunctionObject f(scope, d); QJSValue jsv; @@ -1446,6 +1531,11 @@ int ListElement::setJsProperty(const ListLayout::Role &role, const QV4::Value &d roleIndex = setQObjectProperty(role, o); } else if (role.type == ListLayout::Role::VariantMap) { roleIndex = setVariantMapProperty(role, o); + } else if (role.type == ListLayout::Role::Url) { + QVariant maybeUrl = o->engine()->toVariant(o.asReturnedValue(), QMetaType::QUrl, true); + if (maybeUrl.metaType() == QMetaType::fromType<QUrl>()) { + roleIndex = setUrlProperty(role, maybeUrl.toUrl()); + } } } else if (d.isNullOrUndefined()) { clearProperty(role); diff --git a/src/qmlmodels/qqmllistmodel_p_p.h b/src/qmlmodels/qqmllistmodel_p_p.h index 9e1258c1d9..4435fdfc7f 100644 --- a/src/qmlmodels/qqmllistmodel_p_p.h +++ b/src/qmlmodels/qqmllistmodel_p_p.h @@ -216,6 +216,7 @@ public: QObject, VariantMap, DateTime, + Url, Function, MaxDataType @@ -305,6 +306,7 @@ private: int setVariantMapProperty(const ListLayout::Role &role, QV4::Object *o); int setVariantMapProperty(const ListLayout::Role &role, QVariantMap *m); int setDateTimeProperty(const ListLayout::Role &role, const QDateTime &dt); + int setUrlProperty(const ListLayout::Role &role, const QUrl &url); int setFunctionProperty(const ListLayout::Role &role, const QJSValue &f); int setTranslationProperty(const ListLayout::Role &role, const QV4::CompiledData::Binding *b); @@ -315,6 +317,7 @@ private: void setListPropertyFast(const ListLayout::Role &role, ListModel *m); void setVariantMapFast(const ListLayout::Role &role, QV4::Object *o); void setDateTimePropertyFast(const ListLayout::Role &role, const QDateTime &dt); + void setUrlPropertyFast(const ListLayout::Role &role, const QUrl &url); void setFunctionPropertyFast(const ListLayout::Role &role, const QJSValue &f); void clearProperty(const ListLayout::Role &role); @@ -326,6 +329,7 @@ private: QPointer<QObject> *getGuardProperty(const ListLayout::Role &role); QVariantMap *getVariantMapProperty(const ListLayout::Role &role); QDateTime *getDateTimeProperty(const ListLayout::Role &role); + QUrl *getUrlProperty(const ListLayout::Role &role); QJSValue *getFunctionProperty(const ListLayout::Role &role); inline char *getPropertyMemory(const ListLayout::Role &role); diff --git a/tests/auto/qml/qqmllistmodel/data/urls.qml b/tests/auto/qml/qqmllistmodel/data/urls.qml new file mode 100644 index 0000000000..b7fe57402e --- /dev/null +++ b/tests/auto/qml/qqmllistmodel/data/urls.qml @@ -0,0 +1,19 @@ +import QtQuick 2 +import QtQml.Models 2 + +Item { + id: root + readonly property url url1: "http://qt-project.org" + property var result1 + property var result2 + ListModel {id: myModel} + + Component.onCompleted: { + myModel.append({"url": new URL("http://qt.io")}) + myModel.append({"url": url1}) + const entry1 = myModel.get(0) + root.result1 = entry1.url; + const entry2 = myModel.get(1) + root.result2 = entry2.url; + } +} diff --git a/tests/auto/qml/qqmllistmodel/tst_qqmllistmodel.cpp b/tests/auto/qml/qqmllistmodel/tst_qqmllistmodel.cpp index c2f9cfbc11..3d0aaf1147 100644 --- a/tests/auto/qml/qqmllistmodel/tst_qqmllistmodel.cpp +++ b/tests/auto/qml/qqmllistmodel/tst_qqmllistmodel.cpp @@ -121,6 +121,7 @@ private slots: void empty_element_warning_data(); void datetime(); void datetime_data(); + void url(); void about_to_be_signals(); void modify_through_delegate(); void bindingsOnGetResult(); @@ -1392,6 +1393,16 @@ void tst_qqmllistmodel::datetime_data() QTest::newRow("dt4") << "{append({'date':dt0});setProperty(0,'date',dt1);get(0).date}" << dt1; } +void tst_qqmllistmodel::url() +{ + QQmlEngine engine; + QQmlComponent comp(&engine, testFileUrl("urls.qml")); + QScopedPointer<QObject> o {comp.create()}; + QVERIFY(o); + QCOMPARE(o->property("result1").toUrl(), QUrl("http://qt.io")); + QCOMPARE(o->property("result2").toUrl(), QUrl("http://qt-project.org")); +} + void tst_qqmllistmodel::datetime() { QFETCH(QString, qml); |