Navigation Menu

Skip to content

Commit

Permalink
Add support for assigning literal value to sequence property
Browse files Browse the repository at this point in the history
It is a language semantic that we allow clients to assign a single
value to a sequence/list property (assuming that the types match).
Now that we support sequence types, this commit adds support for
this semantic by determining whether the built-in type of the literal
corresponds to the associated sequence (eg, int for QList<int>, qreal
for QList<qreal>, bool for QList<bool>, QString for QStringList etc).

Similarly, some value types can be constructed from literal string
values (via string converters) and these need to be handled also.

Task-number: QTBUG-18062
Task-number: QTBUG-21770
Change-Id: Iacd91b2af122cd8f20b7df2fa6056a7d7c52bf53
Reviewed-by: Aaron Kennedy <aaron.kennedy@nokia.com>
  • Loading branch information
Chris Adams authored and Qt by Nokia committed Dec 1, 2011
1 parent f304dd6 commit fdbdbbd
Show file tree
Hide file tree
Showing 12 changed files with 394 additions and 0 deletions.
89 changes: 89 additions & 0 deletions src/declarative/qml/qdeclarativecompiler.cpp
Expand Up @@ -72,6 +72,12 @@
#include <QtCore/qdebug.h>
#include <QtCore/qdatetime.h>

Q_DECLARE_METATYPE(QList<int>)
Q_DECLARE_METATYPE(QList<qreal>)
Q_DECLARE_METATYPE(QList<bool>)
Q_DECLARE_METATYPE(QList<QString>)
Q_DECLARE_METATYPE(QList<QUrl>)

QT_BEGIN_NAMESPACE

DEFINE_BOOL_CONFIG_OPTION(compilerDump, QML_COMPILER_DUMP);
Expand Down Expand Up @@ -235,6 +241,9 @@ bool QDeclarativeCompiler::testLiteralAssignment(QDeclarativeScript::Property *p
case QVariant::String:
if (!v->value.isString()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: string expected"));
break;
case QVariant::StringList: // we expect a string literal. A string list is not a literal assignment.
if (!v->value.isString()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: string or string list expected"));
break;
case QVariant::ByteArray:
if (!v->value.isString()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: byte array expected"));
break;
Expand Down Expand Up @@ -344,6 +353,41 @@ bool QDeclarativeCompiler::testLiteralAssignment(QDeclarativeScript::Property *p
break;
default:
{
// check if assigning a literal value to a list property.
// in each case, check the singular, since an Array of the specified type
// will not go via this literal assignment codepath.
if (type == qMetaTypeId<QList<qreal> >()) {
if (!v->value.isNumber()) {
COMPILE_EXCEPTION(v, tr("Invalid property assignment: real or array of reals expected"));
}
break;
} else if (type == qMetaTypeId<QList<int> >()) {
bool ok = v->value.isNumber();
if (ok) {
double n = v->value.asNumber();
if (double(int(n)) != n)
ok = false;
}
if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: int or array of ints expected"));
break;
} else if (type == qMetaTypeId<QList<bool> >()) {
if (!v->value.isBoolean()) {
COMPILE_EXCEPTION(v, tr("Invalid property assignment: bool or array of bools expected"));
}
break;
} else if (type == qMetaTypeId<QList<QString> >()) { // we expect a string literal. A string list is not a literal assignment.
if (!v->value.isString()) {
COMPILE_EXCEPTION(v, tr("Invalid property assignment: string or array of strings expected"));
}
break;
} else if (type == qMetaTypeId<QList<QUrl> >()) {
if (!v->value.isString()) {
COMPILE_EXCEPTION(v, tr("Invalid property assignment: url or array of urls expected"));
}
break;
}

// otherwise, check for existence of string converter to custom type
QDeclarativeMetaType::StringConverter converter = QDeclarativeMetaType::customStringConverter(type);
if (!converter)
COMPILE_EXCEPTION(v, tr("Invalid property assignment: unsupported type \"%1\"").arg(QString::fromLatin1(QVariant::typeToName((QVariant::Type)type))));
Expand Down Expand Up @@ -440,6 +484,14 @@ void QDeclarativeCompiler::genLiteralAssignment(QDeclarativeScript::Property *pr
output->addInstruction(instr);
}
break;
case QVariant::StringList:
{
Instruction::StoreStringList instr;
instr.propertyIndex = prop->index;
instr.value = output->indexForString(v->value.asString());
output->addInstruction(instr);
}
break;
case QVariant::ByteArray:
{
Instruction::StoreByteArray instr;
Expand Down Expand Up @@ -638,6 +690,43 @@ void QDeclarativeCompiler::genLiteralAssignment(QDeclarativeScript::Property *pr
break;
default:
{
// generate single literal value assignment to a list property if required
if (type == qMetaTypeId<QList<qreal> >()) {
Instruction::StoreDoubleQList instr;
instr.propertyIndex = prop->index;
instr.value = v->value.asNumber();
output->addInstruction(instr);
break;
} else if (type == qMetaTypeId<QList<int> >()) {
Instruction::StoreIntegerQList instr;
instr.propertyIndex = prop->index;
instr.value = int(v->value.asNumber());
output->addInstruction(instr);
break;
} else if (type == qMetaTypeId<QList<bool> >()) {
Instruction::StoreBoolQList instr;
bool b = v->value.asBoolean();
instr.propertyIndex = prop->index;
instr.value = b;
output->addInstruction(instr);
break;
} else if (type == qMetaTypeId<QList<QUrl> >()) {
Instruction::StoreUrlQList instr;
QString string = v->value.asString();
QUrl u = string.isEmpty() ? QUrl() : output->url.resolved(QUrl(string));
instr.propertyIndex = prop->index;
instr.value = output->indexForUrl(u);
output->addInstruction(instr);
break;
} else if (type == qMetaTypeId<QList<QString> >()) {
Instruction::StoreStringQList instr;
instr.propertyIndex = prop->index;
instr.value = output->indexForString(v->value.asString());
output->addInstruction(instr);
break;
}

// otherwise, generate custom type literal assignment
Instruction::AssignCustomType instr;
instr.propertyIndex = prop->index;
instr.primitive = output->indexForString(v->value.asString());
Expand Down
18 changes: 18 additions & 0 deletions src/declarative/qml/qdeclarativeinstruction.cpp
Expand Up @@ -93,21 +93,39 @@ void QDeclarativeCompiledData::dump(QDeclarativeInstruction *instr, int idx)
case QDeclarativeInstruction::StoreDouble:
qWarning().nospace() << idx << "\t\t" << "STORE_DOUBLE\t\t" << instr->storeDouble.propertyIndex << "\t" << instr->storeDouble.value;
break;
case QDeclarativeInstruction::StoreDoubleQList:
qWarning().nospace() << idx << "\t\t" << "STORE_DOUBLE_QLIST\t\t" << instr->storeDouble.propertyIndex << "\t" << instr->storeDouble.value;
break;
case QDeclarativeInstruction::StoreInteger:
qWarning().nospace() << idx << "\t\t" << "STORE_INTEGER\t\t" << instr->storeInteger.propertyIndex << "\t" << instr->storeInteger.value;
break;
case QDeclarativeInstruction::StoreIntegerQList:
qWarning().nospace() << idx << "\t\t" << "STORE_INTEGER_QLIST\t\t" << instr->storeInteger.propertyIndex << "\t" << instr->storeInteger.value;
break;
case QDeclarativeInstruction::StoreBool:
qWarning().nospace() << idx << "\t\t" << "STORE_BOOL\t\t" << instr->storeBool.propertyIndex << "\t" << instr->storeBool.value;
break;
case QDeclarativeInstruction::StoreBoolQList:
qWarning().nospace() << idx << "\t\t" << "STORE_BOOL_QLIST\t\t" << instr->storeBool.propertyIndex << "\t" << instr->storeBool.value;
break;
case QDeclarativeInstruction::StoreString:
qWarning().nospace() << idx << "\t\t" << "STORE_STRING\t\t" << instr->storeString.propertyIndex << "\t" << instr->storeString.value << "\t\t" << primitives.at(instr->storeString.value);
break;
case QDeclarativeInstruction::StoreStringList:
qWarning().nospace() << idx << "\t\t" << "STORE_STRINGLIST\t\t" << instr->storeString.propertyIndex << "\t" << instr->storeString.value << "\t\t" << primitives.at(instr->storeString.value);
break;
case QDeclarativeInstruction::StoreStringQList:
qWarning().nospace() << idx << "\t\t" << "STORE_STRING_QLIST\t\t" << instr->storeString.propertyIndex << "\t" << instr->storeString.value << "\t\t" << primitives.at(instr->storeString.value);
break;
case QDeclarativeInstruction::StoreByteArray:
qWarning().nospace() << idx << "\t\t" << "STORE_BYTEARRAY" << instr->storeByteArray.propertyIndex << "\t" << instr->storeByteArray.value << "\t\t" << datas.at(instr->storeByteArray.value);
break;
case QDeclarativeInstruction::StoreUrl:
qWarning().nospace() << idx << "\t\t" << "STORE_URL\t\t" << instr->storeUrl.propertyIndex << "\t" << instr->storeUrl.value << "\t\t" << urls.at(instr->storeUrl.value);
break;
case QDeclarativeInstruction::StoreUrlQList:
qWarning().nospace() << idx << "\t\t" << "STORE_URL_QLIST\t\t" << instr->storeUrl.propertyIndex << "\t" << instr->storeUrl.value << "\t\t" << urls.at(instr->storeUrl.value);
break;
case QDeclarativeInstruction::StoreColor:
qWarning().nospace() << idx << "\t\t" << "STORE_COLOR\t\t" << instr->storeColor.propertyIndex << "\t\t\t" << QString::number(instr->storeColor.value, 16);
break;
Expand Down
6 changes: 6 additions & 0 deletions src/declarative/qml/qdeclarativeinstruction_p.h
Expand Up @@ -79,12 +79,18 @@ QT_BEGIN_NAMESPACE
F(StoreVarDouble, storeDouble) \
F(StoreVarBool, storeBool) \
F(StoreString, storeString) \
F(StoreStringList, storeString) \
F(StoreStringQList, storeString) \
F(StoreByteArray, storeByteArray) \
F(StoreUrl, storeUrl) \
F(StoreUrlQList, storeUrl) \
F(StoreFloat, storeFloat) \
F(StoreDouble, storeDouble) \
F(StoreDoubleQList, storeDouble) \
F(StoreBool, storeBool) \
F(StoreBoolQList, storeBool) \
F(StoreInteger, storeInteger) \
F(StoreIntegerQList, storeInteger) \
F(StoreColor, storeColor) \
F(StoreDate, storeDate) \
F(StoreTime, storeTime) \
Expand Down
63 changes: 63 additions & 0 deletions src/declarative/qml/qdeclarativeproperty.cpp
Expand Up @@ -61,6 +61,12 @@

#include <math.h>

Q_DECLARE_METATYPE(QList<int>)
Q_DECLARE_METATYPE(QList<qreal>)
Q_DECLARE_METATYPE(QList<bool>)
Q_DECLARE_METATYPE(QList<QString>)
Q_DECLARE_METATYPE(QList<QUrl>)

QT_BEGIN_NAMESPACE

/*!
Expand Down Expand Up @@ -1285,6 +1291,59 @@ 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).
if (variantType == QVariant::Int && propertyType == qMetaTypeId<QList<int> >()) {
QList<int> list;
list << value.toInt();
v = QVariant::fromValue<QList<int> >(list);
ok = true;
} else if (variantType == QVariant::Double && propertyType == qMetaTypeId<QList<qreal> >()) {
QList<qreal> list;
list << value.toReal();
v = QVariant::fromValue<QList<qreal> >(list);
ok = true;
} else if (variantType == QVariant::Bool && propertyType == qMetaTypeId<QList<bool> >()) {
QList<bool> list;
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();
v = QVariant::fromValue<QList<QString> >(list);
ok = true;
} else if (variantType == QVariant::String && propertyType == qMetaTypeId<QStringList>()) {
QStringList list;
list << value.toString();
v = QVariant::fromValue<QStringList>(list);
ok = true;
}
}

if (ok) {
void *a[] = { (void *)v.constData(), 0, &status, &flags};
QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, a);
Expand Down Expand Up @@ -1358,6 +1417,10 @@ bool QDeclarativePropertyPrivate::writeBinding(QObject *object,
value = v8engine->toVariant(result, qMetaTypeId<QList<QObject *> >());
} 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()));
} else if (!isVmeProperty) {
value = v8engine->toVariant(result, type);
}
Expand Down
65 changes: 65 additions & 0 deletions src/declarative/qml/qdeclarativevme.cpp
Expand Up @@ -624,6 +624,27 @@ QObject *QDeclarativeVME::run(QList<QDeclarativeError> *errors,
instr.propertyIndex, a);
QML_END_INSTR(StoreString)

QML_BEGIN_INSTR(StoreStringList)
QObject *target = objects.top();
CLEAN_PROPERTY(target, instr.propertyIndex);

QStringList stringlist(PRIMITIVES.at(instr.value));
void *a[] = { (void *)&stringlist, 0, &status, &flags };
QMetaObject::metacall(target, QMetaObject::WriteProperty,
instr.propertyIndex, a);
QML_END_INSTR(StoreStringList)

QML_BEGIN_INSTR(StoreStringQList)
QObject *target = objects.top();
CLEAN_PROPERTY(target, instr.propertyIndex);

QList<QString> stringqlist;
stringqlist.append(PRIMITIVES.at(instr.value));
void *a[] = { (void *)&stringqlist, 0, &status, &flags };
QMetaObject::metacall(target, QMetaObject::WriteProperty,
instr.propertyIndex, a);
QML_END_INSTR(StoreStringQList)

QML_BEGIN_INSTR(StoreByteArray)
QObject *target = objects.top();
void *a[] = { (void *)&DATAS.at(instr.value), 0, &status, &flags };
Expand All @@ -640,6 +661,17 @@ QObject *QDeclarativeVME::run(QList<QDeclarativeError> *errors,
instr.propertyIndex, a);
QML_END_INSTR(StoreUrl)

QML_BEGIN_INSTR(StoreUrlQList)
QObject *target = objects.top();
CLEAN_PROPERTY(target, instr.propertyIndex);

QList<QUrl> urlqlist;
urlqlist.append(URLS.at(instr.value));
void *a[] = { (void *)&urlqlist, 0, &status, &flags };
QMetaObject::metacall(target, QMetaObject::WriteProperty,
instr.propertyIndex, a);
QML_END_INSTR(StoreUrlQList)

QML_BEGIN_INSTR(StoreFloat)
QObject *target = objects.top();
CLEAN_PROPERTY(target, instr.propertyIndex);
Expand All @@ -660,6 +692,17 @@ QObject *QDeclarativeVME::run(QList<QDeclarativeError> *errors,
instr.propertyIndex, a);
QML_END_INSTR(StoreDouble)

QML_BEGIN_INSTR(StoreDoubleQList)
QObject *target = objects.top();
CLEAN_PROPERTY(target, instr.propertyIndex);

QList<double> doubleqlist;
doubleqlist.append(instr.value);
void *a[] = { (void *)&doubleqlist, 0, &status, &flags };
QMetaObject::metacall(target, QMetaObject::WriteProperty,
instr.propertyIndex, a);
QML_END_INSTR(StoreDoubleQList)

QML_BEGIN_INSTR(StoreBool)
QObject *target = objects.top();
CLEAN_PROPERTY(target, instr.propertyIndex);
Expand All @@ -669,6 +712,17 @@ QObject *QDeclarativeVME::run(QList<QDeclarativeError> *errors,
instr.propertyIndex, a);
QML_END_INSTR(StoreBool)

QML_BEGIN_INSTR(StoreBoolQList)
QObject *target = objects.top();
CLEAN_PROPERTY(target, instr.propertyIndex);

QList<bool> boolqlist;
boolqlist.append(instr.value);
void *a[] = { (void *)&boolqlist, 0, &status, &flags };
QMetaObject::metacall(target, QMetaObject::WriteProperty,
instr.propertyIndex, a);
QML_END_INSTR(StoreBoolQList)

QML_BEGIN_INSTR(StoreInteger)
QObject *target = objects.top();
CLEAN_PROPERTY(target, instr.propertyIndex);
Expand All @@ -678,6 +732,17 @@ QObject *QDeclarativeVME::run(QList<QDeclarativeError> *errors,
instr.propertyIndex, a);
QML_END_INSTR(StoreInteger)

QML_BEGIN_INSTR(StoreIntegerQList)
QObject *target = objects.top();
CLEAN_PROPERTY(target, instr.propertyIndex);

QList<int> intqlist;
intqlist.append(instr.value);
void *a[] = { (void *)&intqlist, 0, &status, &flags };
QMetaObject::metacall(target, QMetaObject::WriteProperty,
instr.propertyIndex, a);
QML_END_INSTR(StoreIntegerQList)

QML_BEGIN_INSTR(StoreColor)
QObject *target = objects.top();
CLEAN_PROPERTY(target, instr.propertyIndex);
Expand Down
@@ -0,0 +1,11 @@
import QtQuick 2.0
import Qt.test 1.0

MySequenceConversionObject {
intListProperty: [1, 2]
qrealListProperty: [1.1, 2.2]
boolListProperty: [false, true]
urlListProperty: [ "http://www.example1.com", "http://www.example2.com" ]
stringListProperty: [ "one", "two" ]
qstringListProperty: [ "one", "two" ]
}
@@ -0,0 +1,11 @@
import QtQuick 2.0
import Qt.test 1.0

MySequenceConversionObject {
intListProperty: 1
qrealListProperty: 1.1
boolListProperty: false
urlListProperty: "http://www.example1.com"
stringListProperty: "one"
qstringListProperty: "two"
}

0 comments on commit fdbdbbd

Please sign in to comment.