ListModel: support URLs
Fixes: QTBUG-88379 Change-Id: I6e2ea550d8f8972c5fdcdc21a5e3851992c591a5 Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
This commit is contained in:
parent
6a605df673
commit
bf547fb272
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue