Fix char conversions in QML

This is a partial revert of 90b06e2773, as it had unwanted side
effects. The original intention was to make assignment from char to
string possible, or more specifically, we wanted a solution where a
QChar could be assigned to a QString, as a character and not a string
representation of its value. While this behavior is desirable for
QChar, we most likely want the opposite for the regular character types.

Task-number: QTBUG-49232
Change-Id: I82d5f72b900fe984c4db1478fd52a9eb69ad2ee6
Reviewed-by: Michael Brasser <michael.brasser@live.com>
Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
This commit is contained in:
Christian Strømme 2016-06-02 12:08:29 +02:00 committed by Christian Stromme
parent 31ca52cee4
commit 35597f3014
4 changed files with 43 additions and 66 deletions

View File

@ -1143,8 +1143,13 @@ static QVariant toVariant(QV4::ExecutionEngine *e, const QV4::Value &value, int
return value.integerValue();
if (value.isNumber())
return value.asDouble();
if (value.isString())
return value.stringValue()->toQString();
if (value.isString()) {
const QString &str = value.toQString();
// QChars are stored as a strings
if (typeHint == QVariant::Char && str.size() == 1)
return str.at(0);
return str;
}
if (const QV4::QQmlLocaleData *ld = value.as<QV4::QQmlLocaleData>())
return ld->d()->locale;
if (const QV4::DateObject *d = value.as<DateObject>())
@ -1284,9 +1289,9 @@ QV4::ReturnedValue QV4::ExecutionEngine::fromVariant(const QVariant &variant)
case QMetaType::UShort:
return QV4::Encode((int)*reinterpret_cast<const unsigned short*>(ptr));
case QMetaType::Char:
return newString(QChar::fromLatin1(*reinterpret_cast<const char *>(ptr)))->asReturnedValue();
return QV4::Encode((int)*reinterpret_cast<const char*>(ptr));
case QMetaType::UChar:
return newString(QChar::fromLatin1(*reinterpret_cast<const unsigned char *>(ptr)))->asReturnedValue();
return QV4::Encode((int)*reinterpret_cast<const unsigned char*>(ptr));
case QMetaType::QChar:
return newString(*reinterpret_cast<const QChar *>(ptr))->asReturnedValue();
case QMetaType::QDateTime:

View File

@ -1327,29 +1327,8 @@ bool QQmlPropertyPrivate::write(QObject *object,
bool ok = false;
QVariant v;
if (variantType == QVariant::String) {
const QString &str = value.toString();
const bool targetIsChar = (propertyType == qMetaTypeId<QChar>()
|| propertyType == qMetaTypeId<char>()
|| propertyType == qMetaTypeId<unsigned char>());
// If the string contains only one character and the target is a char, try converting it.
if (targetIsChar) {
if (str.size() != 1)
return false; // We can only convert if the string contains exactly one character.
const QChar &qChar = str.at(0);
if (propertyType == qMetaTypeId<QChar>()) {
v = qChar;
ok = true;
} else if (propertyType == qMetaTypeId<char>() || propertyType == qMetaTypeId<unsigned char>()) {
const char c = qChar.toLatin1();
v = c;
ok = (qChar == c);
}
} else {
v = QQmlStringConverters::variantFromString(str, propertyType, &ok);
}
}
if (variantType == QVariant::String)
v = QQmlStringConverters::variantFromString(value.toString(), propertyType, &ok);
if (!ok) {
v = value;

View File

@ -66,6 +66,7 @@ private slots:
void qtbug_22535();
void evalAfterInvalidate();
void qobjectDerived();
void qtbug_49232();
private:
QQmlEngine engine;
@ -205,6 +206,8 @@ class TestObject : public QObject
Q_PROPERTY(int a READ a NOTIFY aChanged)
Q_PROPERTY(int b READ b NOTIFY bChanged)
Q_PROPERTY(int c READ c NOTIFY cChanged)
Q_PROPERTY(char d READ d NOTIFY dChanged)
Q_PROPERTY(uchar e READ e NOTIFY eChanged)
public:
TestObject() : _a(10), _b(10), _c(10) {}
@ -218,15 +221,25 @@ public:
int c() const { return _c; }
void setC(int c) { _c = c; emit cChanged(); }
char d() const { return _d; }
void setD(char d) { _d = d; emit dChanged(); }
uchar e() const { return _e; }
void setE(uchar e) { _e = e; emit eChanged(); }
signals:
void aChanged();
void bChanged();
void cChanged();
void dChanged();
void eChanged();
private:
int _a;
int _b;
int _c;
char _d;
uchar _e;
};
#define TEST_CONTEXT_PROPERTY(ctxt, name, value) \
@ -699,6 +712,22 @@ void tst_qqmlcontext::qobjectDerived()
QCOMPARE(command.count, 2);
}
void tst_qqmlcontext::qtbug_49232()
{
TestObject testObject;
testObject.setD('a');
testObject.setE(97);
QQmlEngine engine;
engine.rootContext()->setContextProperty("TestObject", &testObject);
QQmlComponent component(&engine);
component.setData("import QtQuick 2.0; QtObject { property int valueOne: TestObject.d; property int valueTwo: TestObject.e }", QUrl());
QScopedPointer<QObject> obj(component.create());
QCOMPARE(obj->property("valueOne"), QVariant('a'));
QCOMPARE(obj->property("valueTwo"), QVariant(97));
}
QTEST_MAIN(tst_qqmlcontext)
#include "tst_qqmlcontext.moc"

View File

@ -329,11 +329,8 @@ class PropertyObject : public QObject
Q_PROPERTY(MyQmlObject *qmlObject READ qmlObject)
Q_PROPERTY(MyQObject *qObject READ qObject WRITE setQObject NOTIFY qObjectChanged)
Q_PROPERTY(QString stringProperty READ stringProperty WRITE setStringProperty)
Q_PROPERTY(char charProperty READ charProperty WRITE setCharProperty)
Q_PROPERTY(QChar qcharProperty READ qcharProperty WRITE setQcharProperty)
Q_PROPERTY(QChar constQChar READ constQChar STORED false CONSTANT FINAL)
Q_PROPERTY(char constChar READ constChar STORED false CONSTANT FINAL)
Q_PROPERTY(int constInt READ constInt STORED false CONSTANT FINAL)
Q_CLASSINFO("DefaultProperty", "defaultProperty")
public:
@ -370,15 +367,11 @@ public:
}
QString stringProperty() const { return m_stringProperty;}
char charProperty() const { return m_charProperty; }
QChar qcharProperty() const { return m_qcharProperty; }
QChar constQChar() const { return 0x25cf; /* Unicode: black circle */ }
char constChar() const { return 'A'; }
int constInt() const { return 123456; }
void setStringProperty(QString arg) { m_stringProperty = arg; }
void setCharProperty(char arg) { m_charProperty = arg; }
void setQcharProperty(QChar arg) { m_qcharProperty = arg; }
signals:
@ -395,7 +388,6 @@ private:
MyQmlObject m_qmlObject;
MyQObject *m_qObject;
QString m_stringProperty;
char m_charProperty;
QChar m_qcharProperty;
};
@ -1408,23 +1400,14 @@ void tst_qqmlproperty::write()
// Char/string-property
{
PropertyObject o;
QQmlProperty charProperty(&o, "charProperty");
QQmlProperty qcharProperty(&o, "qcharProperty");
QQmlProperty stringProperty(&o, "stringProperty");
const int black_circle = 0x25cf;
QCOMPARE(charProperty.write(QString("foo")), false);
QCOMPARE(charProperty.write('Q'), true);
QCOMPARE(charProperty.read(), QVariant('Q'));
QCOMPARE(charProperty.write(QString("t")), true);
QCOMPARE(charProperty.read(), QVariant('t'));
QCOMPARE(qcharProperty.write(QString("foo")), false);
QCOMPARE(qcharProperty.write('Q'), true);
QCOMPARE(qcharProperty.read(), QVariant('Q'));
QCOMPARE(qcharProperty.write(QString("t")), true);
QCOMPARE(qcharProperty.read(), QVariant('t'));
QCOMPARE(qcharProperty.write(QChar(black_circle)), true);
QCOMPARE(qcharProperty.read(), QVariant(QChar(black_circle)));
@ -1433,19 +1416,10 @@ void tst_qqmlproperty::write()
QCOMPARE(o.stringProperty(), QString("bar"));
QCOMPARE(stringProperty.write(QVariant(1234)), true);
QCOMPARE(stringProperty.read().toString(), QString::number(1234));
QCOMPARE(stringProperty.write('A'), true);
QCOMPARE(stringProperty.read().toString(), QString::number('A'));
QCOMPARE(stringProperty.write(QChar(black_circle)), true);
QCOMPARE(stringProperty.read(), QVariant(QString(QChar(black_circle))));
{ // char -> QString
QQmlComponent component(&engine);
component.setData("import Test 1.0\nPropertyObject { stringProperty: constChar }", QUrl());
PropertyObject *obj = qobject_cast<PropertyObject*>(component.create());
QVERIFY(obj != 0);
if (obj) {
QQmlProperty stringProperty(obj, "stringProperty");
QCOMPARE(stringProperty.read(), QVariant(QString(obj->constChar())));
}
}
QCOMPARE(stringProperty.read(), QVariant(QChar(black_circle)));
{ // QChar -> QString
QQmlComponent component(&engine);
@ -1458,16 +1432,6 @@ void tst_qqmlproperty::write()
}
}
{ // int -> QString
QQmlComponent component(&engine);
component.setData("import Test 1.0\nPropertyObject { stringProperty: constInt }", QUrl());
PropertyObject *obj = qobject_cast<PropertyObject*>(component.create());
QVERIFY(obj != 0);
if (obj) {
QQmlProperty stringProperty(obj, "stringProperty");
QCOMPARE(stringProperty.read(), QVariant(QString::number(obj->constInt())));
}
}
}
// VariantMap-property