From f5cb65b35e076facbce45e896902a34da7036135 Mon Sep 17 00:00:00 2001 From: Chris Adams Date: Tue, 26 Jun 2012 18:02:35 +1000 Subject: Fix broken value-type support by allowing property definition In QtQuick 1.x the "variant" property type was supported, which could be used to allow value type properties to be defined in QML. In QtQuick 2.0, we have deprecated the "variant" property, but its replacement ("var") is not suited for defining lightweight C++ type values (such as QColor, QFont, QRectF, QVector3D etc). This commit allows those QML basic types to be used in QML once more, by supporting them in the property definition syntax. Note that since some value types are provided by QtQuick and others are provided by QtQml, if a client imports only QtQml they can define but not use properties of certain types (eg, font). Task-number: QTBUG-21034 Task-number: QTBUG-18217 Change-Id: Ia951a8522f223408d27293bb96c276281a710277 Reviewed-by: Matthew Vogt --- src/qml/doc/src/syntax/objectattributes.qdoc | 2 +- src/qml/doc/src/typesystem/basictypes.qdoc | 118 ++++ src/qml/qml/qqmlcompiler.cpp | 8 + src/qml/qml/qqmlengine.cpp | 14 +- src/qml/qml/qqmlglobal.cpp | 37 +- src/qml/qml/qqmlglobal_p.h | 13 +- src/qml/qml/qqmlscript.cpp | 8 + src/qml/qml/qqmlscript_p.h | 4 +- src/qml/qml/qqmlvaluetype.cpp | 18 +- src/qml/qml/qqmlvaluetype_p.h | 14 +- src/qml/qml/qqmlvmemetaobject.cpp | 66 ++- src/qml/qml/v8/qqmlbuiltinfunctions.cpp | 102 +++- src/qml/qml/v8/qqmlbuiltinfunctions_p.h | 4 + src/qml/qml/v8/qv8engine.cpp | 6 + src/qml/qml/v8/qv8valuetypewrapper.cpp | 9 + src/qml/qml/v8/qv8valuetypewrapper_p.h | 1 + src/quick/util/qquickglobal.cpp | 608 ++++++++++++++++++--- src/quick/util/qquickvaluetypes.cpp | 14 +- tests/auto/qml/qml.pro | 1 + tests/auto/qml/qqmlglobal/tst_qqmlglobal.cpp | 8 - tests/auto/qml/qqmlqt/data/font.qml | 8 + tests/auto/qml/qqmlqt/data/matrix4x4.qml | 9 + tests/auto/qml/qqmlqt/data/quaternion.qml | 8 + tests/auto/qml/qqmlqt/data/vector2.qml | 8 + tests/auto/qml/qqmlqt/tst_qqmlqt.cpp | 100 +++- .../data/comparisonSemantics.qml | 95 ++++ .../qqmlvaluetypeproviders/data/cppIntegration.qml | 98 ++++ .../data/jsObjectConversion.qml | 48 ++ .../data/qtqmlValueTypes.qml | 48 ++ .../data/qtquickValueTypes.qml | 119 ++++ .../qqmlvaluetypeproviders.pro | 16 + .../auto/qml/qqmlvaluetypeproviders/testtypes.cpp | 46 ++ tests/auto/qml/qqmlvaluetypeproviders/testtypes.h | 195 +++++++ .../tst_qqmlvaluetypeproviders.cpp | 173 ++++++ 34 files changed, 1894 insertions(+), 132 deletions(-) create mode 100644 tests/auto/qml/qqmlqt/data/font.qml create mode 100644 tests/auto/qml/qqmlqt/data/matrix4x4.qml create mode 100644 tests/auto/qml/qqmlqt/data/quaternion.qml create mode 100644 tests/auto/qml/qqmlqt/data/vector2.qml create mode 100644 tests/auto/qml/qqmlvaluetypeproviders/data/comparisonSemantics.qml create mode 100644 tests/auto/qml/qqmlvaluetypeproviders/data/cppIntegration.qml create mode 100644 tests/auto/qml/qqmlvaluetypeproviders/data/jsObjectConversion.qml create mode 100644 tests/auto/qml/qqmlvaluetypeproviders/data/qtqmlValueTypes.qml create mode 100644 tests/auto/qml/qqmlvaluetypeproviders/data/qtquickValueTypes.qml create mode 100644 tests/auto/qml/qqmlvaluetypeproviders/qqmlvaluetypeproviders.pro create mode 100644 tests/auto/qml/qqmlvaluetypeproviders/testtypes.cpp create mode 100644 tests/auto/qml/qqmlvaluetypeproviders/testtypes.h create mode 100644 tests/auto/qml/qqmlvaluetypeproviders/tst_qqmlvaluetypeproviders.cpp diff --git a/src/qml/doc/src/syntax/objectattributes.qdoc b/src/qml/doc/src/syntax/objectattributes.qdoc index 1562aa6b1f..bfedd19d76 100644 --- a/src/qml/doc/src/syntax/objectattributes.qdoc +++ b/src/qml/doc/src/syntax/objectattributes.qdoc @@ -146,7 +146,7 @@ property int volume: "four" // generates an error; the property's object will n Likewise if a property is assigned a value of the wrong type during run time, the new value will not be assigned, and an error will be generated. -See \l {QML Basic Types} for a list of the types of properties that are supported by default. Additionally, any available \l {QML Object Types}QML object type} may also be used as a property type. +See \l {QML Basic Types} for a list of the types of properties that are supported by default. Additionally, any available \l {QML Object Types}{QML object type} may also be used as a property type. \section3 Special property types diff --git a/src/qml/doc/src/typesystem/basictypes.qdoc b/src/qml/doc/src/typesystem/basictypes.qdoc index 96aaf86d84..94ff682ee3 100644 --- a/src/qml/doc/src/typesystem/basictypes.qdoc +++ b/src/qml/doc/src/typesystem/basictypes.qdoc @@ -49,6 +49,10 @@ Basic types can be used to refer to: \section1 Supported Basic Types +Most basic types are supported by the engine by default and do not require an +\l {Import Statements}{Import Statement} to be used, unlike QML object types. +Some basic types which contain multiple property-value pairs (also known as \c{value types}) +do require an import, as they are provided by the QtQuick module. The basic types supported in QML are listed below: \annotatedlist qmlbasictypes @@ -119,6 +123,8 @@ property is only invoked when the property is reassigned to a different object v Item { width: 100; height: 200 } \endqml + This basic type is provided by the QML language. + \sa {QML Basic Types} */ @@ -137,6 +143,8 @@ property is only invoked when the property is reassigned to a different object v } \endqml + This basic type is provided by the QML language. + \sa {QML Basic Types} */ @@ -157,6 +165,8 @@ property is only invoked when the property is reassigned to a different object v {http://en.wikipedia.org/wiki/IEEE_754} {IEEE floating point} format. + This basic type is provided by the QML language. + \sa {QML Basic Types} */ @@ -176,6 +186,8 @@ property is only invoked when the property is reassigned to a different object v } \endqml + This basic type is provided by the QML language. + \sa {QML Basic Types} */ @@ -201,6 +213,8 @@ property is only invoked when the property is reassigned to a different object v \l{qtqml-cppintegration-data.html}{passed into QML from C++} is automatically converted into a \c string value, and vice-versa. + This basic type is provided by the QML language. + \sa {QML Basic Types} */ @@ -270,6 +284,8 @@ property is only invoked when the property is reassigned to a different object v Image { source: encodeURIComponent("/tmp/test#1.png") } \endqml + This basic type is provided by the QML language. + \sa {QML Basic Types} */ @@ -314,6 +330,8 @@ property is only invoked when the property is reassigned to a different object v \l{qtqml-cppintegration-data.html}{passed into QML from C++} is automatically converted into a \c color value, and vice-versa. + This basic type is provided by the QtQuick import. + \sa {QML Basic Types} */ @@ -341,6 +359,8 @@ property is only invoked when the property is reassigned to a different object v converted into a \c point value. When a \c point value is passed to C++, it is automatically converted into a QPointF value. + This basic type is provided by the QML language. + \sa {QML Basic Types} */ @@ -378,6 +398,8 @@ property is only invoked when the property is reassigned to a different object v converted into a \c size value, and vice-versa. When a \c size value is passed to C++, it is automatically converted into a QSizeF value. + This basic type is provided by the QML language. + \sa {QML Basic Types} */ @@ -417,6 +439,7 @@ property is only invoked when the property is reassigned to a different object v converted into a \c rect value, and vice-versa. When a \c rect value is passed to C++, it is automatically converted into a QRectF value. + This basic type is provided by the QML language. \sa {QML Basic Types} */ @@ -441,6 +464,13 @@ property is only invoked when the property is reassigned to a different object v \l{qtqml-cppintegration-data.html}{passed into QML from C++} is automatically converted into a \c date value, and vice-versa. + Note that the date type has comparison semantics which match + those of the JavaScript Date object. To compare the value + of two date properties, you should compare their "toString()" + values. + + This basic type is provided by the QML language. + \sa {QML Basic Types} */ @@ -468,6 +498,8 @@ property is only invoked when the property is reassigned to a different object v \l{qtqml-cppintegration-data.html}{passed into QML from C++} is automatically converted into a \c time value, and vice-versa. + This basic type is provided by the QML language. + \sa {QML Basic Types} */ @@ -475,6 +507,7 @@ property is only invoked when the property is reassigned to a different object v \qmlbasictype font \ingroup qmlbasictypes \brief a font value with the properties of QFont. + \target fontbasictypedocs The \c font type refers to a font value with the properties of QFont. @@ -498,6 +531,8 @@ property is only invoked when the property is reassigned to a different object v \l{qtqml-cppintegration-data.html}{passed into QML from C++} is automatically converted into a \c font value, and vice-versa. + This basic type is provided by the QtQuick import. + \sa {QML Basic Types} */ @@ -572,6 +607,8 @@ property is only invoked when the property is reassigned to a different object v lists stored by the \c var type can be manipulated with greater flexibility from within QML. + This basic type is provided by the QML language. + \sa {QML Basic Types} */ @@ -643,6 +680,8 @@ property is only invoked when the property is reassigned to a different object v For more information regarding the usage of a scarce resource, please see \l{Scarce Resources in JavaScript}. + This basic type is provided by the QML language. + \sa {QML Basic Types} */ @@ -758,6 +797,27 @@ property is only invoked when the property is reassigned to a different object v extra data such as the object's JavaScript prototype chain is also lost in the process. + This basic type is provided by the QML language. + + \sa {QML Basic Types} +*/ + +/*! + \qmlbasictype vector2d + \ingroup qmlbasictypes + + \brief A vector2d type has x and y attributes. + + A \c vector2d type has \c x and \c y attributes, otherwise + it is similar to the \c vector3d type. Please see the + documentation about the \c vector3d type for more information. + + To create a \c vector2d value, specify it as a "x,y" string, + or define the components individually, or compose it with + the Qt.vector2d() function. + + This basic type is provided by the QtQuick import. + \sa {QML Basic Types} */ @@ -790,6 +850,61 @@ property is only invoked when the property is reassigned to a different object v \l{qtqml-cppintegration-data.html}{passed into QML from C++} is automatically converted into a \c vector3d value, and vice-versa. + This basic type is provided by the QtQuick import. + + \sa {QML Basic Types} +*/ + +/*! + \qmlbasictype vector4d + \ingroup qmlbasictypes + + \brief A vector4d type has x, y, z and w attributes. + + A \c vector4d type has \c x, \c y, \c z and \c w attributes, + otherwise it is similar to the \c vector3d type. Please see the + documentation about the \c vector3d type for more information. + + To create a \c vector4d value, specify it as a "x,y,z,w" string, + or define the components individually, or compose it with + the Qt.vector4d() function. + + This basic type is provided by the QtQuick import. + + \sa {QML Basic Types} +*/ + +/*! + \qmlbasictype quaternion + \ingroup qmlbasictypes + + \brief A quaternion type has scalar, x, y, and z attributes. + + A \c quaternion type has \c scalar, \c x, \c y and \c z attributes, + otherwise it is similar to the \c vector3d type. Please see the + documentation about the \c vector3d type for more information. + + To create a \c quaternion value, specify it as a "scalar,x,y,z" string, + or define the components individually, or compose it with + the Qt.quaternion() function. + + This basic type is provided by the QtQuick import. + + \sa {QML Basic Types} +*/ + +/*! + \qmlbasictype matrix4x4 + \ingroup qmlbasictypes + + \brief A matrix4x4 type is a 4-row and 4-column matrix + + A \c matrix4x4 type has sixteen values, but these values are + largely opaque to QML. Values of this type can be composed with + the Qt.matrix4x4() function. + + This basic type is provided by the QtQuick import. + \sa {QML Basic Types} */ @@ -815,6 +930,9 @@ property is only invoked when the property is reassigned to a different object v \l{qtqml-cppintegration-data.html}{passed into QML from C++} is automatically converted into an \c enumeration value, and vice-versa. + This basic type is provided by the QML language. Some enumeration values + are provided by the QtQuick import. + \sa {QML Basic Types} */ diff --git a/src/qml/qml/qqmlcompiler.cpp b/src/qml/qml/qqmlcompiler.cpp index 6f2792570f..539b6c402a 100644 --- a/src/qml/qml/qqmlcompiler.cpp +++ b/src/qml/qml/qqmlcompiler.cpp @@ -2806,10 +2806,18 @@ bool QQmlCompiler::buildDynamicMeta(QQmlScript::Object *obj, DynamicMetaMode mod { Object::DynamicProperty::String, QMetaType::QString }, { Object::DynamicProperty::Url, QMetaType::QUrl }, { Object::DynamicProperty::Color, QMetaType::QColor }, + { Object::DynamicProperty::Font, QMetaType::QFont }, { Object::DynamicProperty::Time, QMetaType::QTime }, { Object::DynamicProperty::Date, QMetaType::QDate }, { Object::DynamicProperty::DateTime, QMetaType::QDateTime }, { Object::DynamicProperty::Rect, QMetaType::QRectF }, + { Object::DynamicProperty::Point, QMetaType::QPointF }, + { Object::DynamicProperty::Size, QMetaType::QSizeF }, + { Object::DynamicProperty::Vector2D, QMetaType::QVector2D }, + { Object::DynamicProperty::Vector3D, QMetaType::QVector3D }, + { Object::DynamicProperty::Vector4D, QMetaType::QVector4D }, + { Object::DynamicProperty::Matrix4x4, QMetaType::QMatrix4x4 }, + { Object::DynamicProperty::Quaternion, QMetaType::QQuaternion } }; static const int builtinTypeCount = sizeof(builtinTypes) / sizeof(TypeData); diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp index 229a071789..e3db9d478a 100644 --- a/src/qml/qml/qqmlengine.cpp +++ b/src/qml/qml/qqmlengine.cpp @@ -271,16 +271,26 @@ the \l Qt::LeftButton and \l Qt::RightButton enumeration values as \c Qt.LeftBut \section1 Types + The Qt object also contains helper functions for creating objects of specific data types. This is primarily useful when setting the properties of an item when the property has one of the following types: - \list -\li \c color - use \l{Qt::rgba()}{Qt.rgba()}, \l{Qt::hsla()}{Qt.hsla()}, \l{Qt::darker()}{Qt.darker()}, \l{Qt::lighter()}{Qt.lighter()} or \l{Qt::tint()}{Qt.tint()} \li \c rect - use \l{Qt::rect()}{Qt.rect()} \li \c point - use \l{Qt::point()}{Qt.point()} \li \c size - use \l{Qt::size()}{Qt.size()} +\endlist + +If the QtQuick module has been imported, the following helper functions for +creating objects of specific data types are also available for clients to use: +\list +\li \c color - use \l{Qt::rgba()}{Qt.rgba()}, \l{Qt::hsla()}{Qt.hsla()}, \l{Qt::darker()}{Qt.darker()}, \l{Qt::lighter()}{Qt.lighter()} or \l{Qt::tint()}{Qt.tint()} +\li \c font - use \l{Qt::font()}{Qt.font()} +\li \c vector2d - use \l{Qt::vector2d()}{Qt.vector2d()} \li \c vector3d - use \l{Qt::vector3d()}{Qt.vector3d()} +\li \c vector4d - use \l{Qt::vector4d()}{Qt.vector4d()} +\li \c quaternion - use \l{Qt::quaternion()}{Qt.quaternion()} +\li \c matrix4x4 - use \l{Qt::matrix4x4()}{Qt.matrix4x4()} \endlist There are also string based constructors for these types. See \l{qdeclarativebasictypes.html}{QML Basic Types} for more information. diff --git a/src/qml/qml/qqmlglobal.cpp b/src/qml/qml/qqmlglobal.cpp index 6f4942963f..0ebc802dec 100644 --- a/src/qml/qml/qqmlglobal.cpp +++ b/src/qml/qml/qqmlglobal.cpp @@ -175,42 +175,58 @@ QVariant QQmlValueTypeProvider::createVariantFromString(int type, const QString return QVariant(); } -bool QQmlValueTypeProvider::equalValueType(int type, const void *lhs, const void *rhs) +QVariant QQmlValueTypeProvider::createVariantFromJsObject(int type, QQmlV8Handle obj, QV8Engine *e, bool *ok) +{ + QVariant v; + + QQmlValueTypeProvider *p = this; + do { + if (p->variantFromJsObject(type, obj, e, &v)) { + if (ok) *ok = true; + return v; + } + } while ((p = p->next)); + + if (ok) *ok = false; + return QVariant(); +} + +bool QQmlValueTypeProvider::equalValueType(int type, const void *lhs, const void *rhs, size_t rhsSize) { Q_ASSERT(lhs); Q_ASSERT(rhs); QQmlValueTypeProvider *p = this; do { - if (p->equal(type, lhs, rhs)) + if (p->equal(type, lhs, rhs, rhsSize)) return true; } while ((p = p->next)); return false; } -bool QQmlValueTypeProvider::storeValueType(int type, const void *src, void *dst, size_t n) +bool QQmlValueTypeProvider::storeValueType(int type, const void *src, void *dst, size_t dstSize) { Q_ASSERT(src); Q_ASSERT(dst); QQmlValueTypeProvider *p = this; do { - if (p->store(type, src, dst, n)) + if (p->store(type, src, dst, dstSize)) return true; } while ((p = p->next)); return false; } -bool QQmlValueTypeProvider::readValueType(int srcType, const void *src, int dstType, void *dst) +bool QQmlValueTypeProvider::readValueType(int srcType, const void *src, size_t srcSize, int dstType, void *dst) { Q_ASSERT(src); Q_ASSERT(dst); QQmlValueTypeProvider *p = this; do { - if (p->read(srcType, src, dstType, dst)) + if (p->read(srcType, src, srcSize, dstType, dst)) return true; } while ((p = p->next)); @@ -240,9 +256,10 @@ bool QQmlValueTypeProvider::createFromString(int, const QString &, void *, size_ bool QQmlValueTypeProvider::createStringFrom(int, const void *, QString *) { return false; } bool QQmlValueTypeProvider::variantFromString(const QString &, QVariant *) { return false; } bool QQmlValueTypeProvider::variantFromString(int, const QString &, QVariant *) { return false; } -bool QQmlValueTypeProvider::equal(int, const void *, const void *) { return false; } +bool QQmlValueTypeProvider::variantFromJsObject(int, QQmlV8Handle, QV8Engine *, QVariant *) { return false; } +bool QQmlValueTypeProvider::equal(int, const void *, const void *, size_t) { return false; } bool QQmlValueTypeProvider::store(int, const void *, void *, size_t) { return false; } -bool QQmlValueTypeProvider::read(int, const void *, int, void *) { return false; } +bool QQmlValueTypeProvider::read(int, const void *, size_t, int, void *) { return false; } bool QQmlValueTypeProvider::write(int, const void *, void *, size_t) { return false; } static QQmlValueTypeProvider *valueTypeProvider = 0; @@ -266,10 +283,6 @@ Q_QML_PRIVATE_EXPORT void QQml_addValueTypeProvider(QQmlValueTypeProvider *newPr Q_AUTOTEST_EXPORT QQmlValueTypeProvider *QQml_valueTypeProvider(void) { - if (valueTypeProvider == 0) { - qWarning() << "Warning: QQml_valueTypeProvider: no value type provider has been set!"; - } - static QQmlValueTypeProvider **providerPtr = getValueTypeProvider(); return *providerPtr; } diff --git a/src/qml/qml/qqmlglobal_p.h b/src/qml/qml/qqmlglobal_p.h index b3e8eb6421..b10457bd29 100644 --- a/src/qml/qml/qqmlglobal_p.h +++ b/src/qml/qml/qqmlglobal_p.h @@ -46,6 +46,7 @@ #include #include #include +#include QT_BEGIN_HEADER @@ -208,7 +209,7 @@ inline void QQml_setParent_noEvent(QObject *object, QObject *parent) class QQmlValueType; - +class QV8Engine; class Q_QML_PRIVATE_EXPORT QQmlValueTypeProvider { public: @@ -226,10 +227,11 @@ public: QVariant createVariantFromString(const QString &); QVariant createVariantFromString(int, const QString &, bool *); + QVariant createVariantFromJsObject(int, QQmlV8Handle, QV8Engine *, bool*); - bool equalValueType(int, const void *, const void *); + bool equalValueType(int, const void *, const void *, size_t); bool storeValueType(int, const void *, void *, size_t); - bool readValueType(int, const void *, int, void *); + bool readValueType(int, const void *, size_t, int, void *); bool writeValueType(int, const void *, void *, size_t); private: @@ -245,10 +247,11 @@ private: virtual bool variantFromString(const QString &, QVariant *); virtual bool variantFromString(int, const QString &, QVariant *); + virtual bool variantFromJsObject(int, QQmlV8Handle, QV8Engine *, QVariant *); - virtual bool equal(int, const void *, const void *); + virtual bool equal(int, const void *, const void *, size_t); virtual bool store(int, const void *, void *, size_t); - virtual bool read(int, const void *, int, void *); + virtual bool read(int, const void *, size_t, int, void *); virtual bool write(int, const void *, void *, size_t); friend Q_QML_PRIVATE_EXPORT void QQml_addValueTypeProvider(QQmlValueTypeProvider *); diff --git a/src/qml/qml/qqmlscript.cpp b/src/qml/qml/qqmlscript.cpp index f4a928c784..469b5d5291 100644 --- a/src/qml/qml/qqmlscript.cpp +++ b/src/qml/qml/qqmlscript.cpp @@ -912,6 +912,14 @@ bool ProcessAST::visit(AST::UiPublicMember *node) // { "date", strlen("date"), Object::DynamicProperty::Date }, { "date", strlen("date"), Object::DynamicProperty::DateTime }, { "rect", strlen("rect"), Object::DynamicProperty::Rect }, + { "point", strlen("point"), Object::DynamicProperty::Point }, + { "size", strlen("size"), Object::DynamicProperty::Size }, + { "font", strlen("font"), Object::DynamicProperty::Font }, + { "vector2d", strlen("vector2d"), Object::DynamicProperty::Vector2D }, + { "vector3d", strlen("vector3d"), Object::DynamicProperty::Vector3D }, + { "vector4d", strlen("vector4d"), Object::DynamicProperty::Vector4D }, + { "quaternion", strlen("quaternion"), Object::DynamicProperty::Quaternion }, + { "matrix4x4", strlen("matrix4x4"), Object::DynamicProperty::Matrix4x4 }, { "variant", strlen("variant"), Object::DynamicProperty::Variant }, { "var", strlen("var"), Object::DynamicProperty::Var } }; diff --git a/src/qml/qml/qqmlscript_p.h b/src/qml/qml/qqmlscript_p.h index 486c573754..718faa33ca 100644 --- a/src/qml/qml/qqmlscript_p.h +++ b/src/qml/qml/qqmlscript_p.h @@ -381,7 +381,9 @@ public: DynamicProperty(); enum Type { Var, Variant, Int, Bool, Real, String, Url, Color, - Time, Date, DateTime, Rect, Alias, Custom, CustomList }; + Font, Time, Date, DateTime, Rect, Point, Size, + Vector2D, Vector3D, Vector4D, Matrix4x4, Quaternion, + Alias, Custom, CustomList }; quint32 isDefaultProperty:1; quint32 isReadOnly:1; diff --git a/src/qml/qml/qqmlvaluetype.cpp b/src/qml/qml/qqmlvaluetype.cpp index c0759a31b4..165024adfe 100644 --- a/src/qml/qml/qqmlvaluetype.cpp +++ b/src/qml/qml/qqmlvaluetype.cpp @@ -112,14 +112,14 @@ QQmlValueType *QQmlValueTypeFactory::valueType(int t) return rv; } -QQmlValueType::QQmlValueType(QObject *parent) -: QObject(parent) +QQmlValueType::QQmlValueType(int userType, QObject *parent) +: QObject(parent), m_userType(userType) { } QQmlPointFValueType::QQmlPointFValueType(QObject *parent) - : QQmlValueTypeBase(parent) + : QQmlValueTypeBase(QMetaType::QPointF, parent) { } @@ -150,7 +150,7 @@ void QQmlPointFValueType::setY(qreal y) QQmlPointValueType::QQmlPointValueType(QObject *parent) - : QQmlValueTypeBase(parent) + : QQmlValueTypeBase(QMetaType::QPoint, parent) { } @@ -181,7 +181,7 @@ void QQmlPointValueType::setY(int y) QQmlSizeFValueType::QQmlSizeFValueType(QObject *parent) - : QQmlValueTypeBase(parent) + : QQmlValueTypeBase(QMetaType::QSizeF, parent) { } @@ -212,7 +212,7 @@ void QQmlSizeFValueType::setHeight(qreal h) QQmlSizeValueType::QQmlSizeValueType(QObject *parent) - : QQmlValueTypeBase(parent) + : QQmlValueTypeBase(QMetaType::QSize, parent) { } @@ -243,7 +243,7 @@ void QQmlSizeValueType::setHeight(int h) QQmlRectFValueType::QQmlRectFValueType(QObject *parent) - : QQmlValueTypeBase(parent) + : QQmlValueTypeBase(QMetaType::QRectF, parent) { } @@ -294,7 +294,7 @@ void QQmlRectFValueType::setHeight(qreal h) QQmlRectValueType::QQmlRectValueType(QObject *parent) - : QQmlValueTypeBase(parent) + : QQmlValueTypeBase(QMetaType::QRect, parent) { } @@ -345,7 +345,7 @@ void QQmlRectValueType::setHeight(int h) QQmlEasingValueType::QQmlEasingValueType(QObject *parent) - : QQmlValueTypeBase(parent) + : QQmlValueTypeBase(QMetaType::QEasingCurve, parent) { } diff --git a/src/qml/qml/qqmlvaluetype_p.h b/src/qml/qml/qqmlvaluetype_p.h index f704da2c8e..02be333037 100644 --- a/src/qml/qml/qqmlvaluetype_p.h +++ b/src/qml/qml/qqmlvaluetype_p.h @@ -69,7 +69,7 @@ class Q_QML_PRIVATE_EXPORT QQmlValueType : public QObject { Q_OBJECT public: - QQmlValueType(QObject *parent = 0); + QQmlValueType(int userType, QObject *parent = 0); virtual void read(QObject *, int) = 0; virtual void write(QObject *, int, QQmlPropertyPrivate::WriteFlags flags) = 0; virtual QVariant value() = 0; @@ -80,6 +80,11 @@ public: virtual void onLoad() {} + inline int userType() const + { + return m_userType; + } + protected: inline void readProperty(QObject *obj, int idx, void *p) { @@ -94,6 +99,9 @@ protected: void *a[] = { p, 0, &status, &flags }; QMetaObject::metacall(obj, QMetaObject::WriteProperty, idx, a); } + +private: + int m_userType; }; template @@ -102,8 +110,8 @@ class QQmlValueTypeBase : public QQmlValueType public: typedef T ValueType; - QQmlValueTypeBase(QObject *parent) - : QQmlValueType(parent) + QQmlValueTypeBase(int userType, QObject *parent) + : QQmlValueType(userType, parent) { } diff --git a/src/qml/qml/qqmlvmemetaobject.cpp b/src/qml/qml/qqmlvmemetaobject.cpp index 1c07dd676e..c982856453 100644 --- a/src/qml/qml/qqmlvmemetaobject.cpp +++ b/src/qml/qml/qqmlvmemetaobject.cpp @@ -101,6 +101,8 @@ public: inline const QDate &asQDate(); inline const QDateTime &asQDateTime(); inline const QRectF &asQRectF(); + inline const QPointF &asQPointF(); + inline const QSizeF &asQSizeF(); inline const QJSValue &asQJSValue(); inline void setValue(QObject *v, QQmlVMEMetaObject *target, int index); @@ -114,6 +116,8 @@ public: inline void setValue(const QDate &); inline void setValue(const QDateTime &); inline void setValue(const QRectF &); + inline void setValue(const QPointF &); + inline void setValue(const QSizeF &); inline void setValue(const QJSValue &); inline void setDataType(int t); @@ -176,6 +180,12 @@ void QQmlVMEVariant::cleanup() } else if (type == QMetaType::QRectF) { ((QRectF *)dataPtr())->~QRectF(); type = QVariant::Invalid; + } else if (type == QMetaType::QPointF) { + ((QPointF *)dataPtr())->~QPointF(); + type = QVariant::Invalid; + } else if (type == QMetaType::QSizeF) { + ((QSizeF *)dataPtr())->~QSizeF(); + type = QVariant::Invalid; } else if (type == qMetaTypeId()) { ((QVariant *)dataPtr())->~QVariant(); type = QVariant::Invalid; @@ -297,6 +307,22 @@ const QRectF &QQmlVMEVariant::asQRectF() return *(QRectF *)(dataPtr()); } +const QSizeF &QQmlVMEVariant::asQSizeF() +{ + if (type != QMetaType::QSizeF) + setValue(QSizeF()); + + return *(QSizeF *)(dataPtr()); +} + +const QPointF &QQmlVMEVariant::asQPointF() +{ + if (type != QMetaType::QPointF) + setValue(QPointF()); + + return *(QPointF *)(dataPtr()); +} + const QJSValue &QQmlVMEVariant::asQJSValue() { if (type != qMetaTypeId()) @@ -419,6 +445,28 @@ void QQmlVMEVariant::setValue(const QRectF &v) } } +void QQmlVMEVariant::setValue(const QPointF &v) +{ + if (type != QMetaType::QPointF) { + cleanup(); + type = QMetaType::QPointF; + new (dataPtr()) QPointF(v); + } else { + *(QPointF *)(dataPtr()) = v; + } +} + +void QQmlVMEVariant::setValue(const QSizeF &v) +{ + if (type != QMetaType::QSizeF) { + cleanup(); + type = QMetaType::QSizeF; + new (dataPtr()) QSizeF(v); + } else { + *(QSizeF *)(dataPtr()) = v; + } +} + void QQmlVMEVariant::setValue(const QJSValue &v) { if (type != qMetaTypeId()) { @@ -685,6 +733,12 @@ int QQmlVMEMetaObject::metaCall(QMetaObject::Call c, int _id, void **a) case QVariant::RectF: *reinterpret_cast(a[0]) = data[id].asQRectF(); break; + case QVariant::SizeF: + *reinterpret_cast(a[0]) = data[id].asQSizeF(); + break; + case QVariant::PointF: + *reinterpret_cast(a[0]) = data[id].asQPointF(); + break; case QMetaType::QObjectStar: *reinterpret_cast(a[0]) = data[id].asQObject(); break; @@ -692,7 +746,7 @@ int QQmlVMEMetaObject::metaCall(QMetaObject::Call c, int _id, void **a) *reinterpret_cast(a[0]) = readPropertyAsVariant(id); break; default: - QQml_valueTypeProvider()->readValueType(data[id].dataType(), data[id].dataPtr(), t, a[0]); + QQml_valueTypeProvider()->readValueType(data[id].dataType(), data[id].dataPtr(), data->dataSize(), t, a[0]); break; } if (t == qMetaTypeId >()) { @@ -739,6 +793,14 @@ int QQmlVMEMetaObject::metaCall(QMetaObject::Call c, int _id, void **a) needActivate = *reinterpret_cast(a[0]) != data[id].asQRectF(); data[id].setValue(*reinterpret_cast(a[0])); break; + case QVariant::SizeF: + needActivate = *reinterpret_cast(a[0]) != data[id].asQSizeF(); + data[id].setValue(*reinterpret_cast(a[0])); + break; + case QVariant::PointF: + needActivate = *reinterpret_cast(a[0]) != data[id].asQPointF(); + data[id].setValue(*reinterpret_cast(a[0])); + break; case QMetaType::QObjectStar: needActivate = *reinterpret_cast(a[0]) != data[id].asQObject(); data[id].setValue(*reinterpret_cast(a[0]), this, id); @@ -748,7 +810,7 @@ int QQmlVMEMetaObject::metaCall(QMetaObject::Call c, int _id, void **a) break; default: data[id].ensureValueType(t); - needActivate = !QQml_valueTypeProvider()->equalValueType(t, a[0], data[id].dataPtr()); + needActivate = !QQml_valueTypeProvider()->equalValueType(t, a[0], data[id].dataPtr(), data[id].dataSize()); QQml_valueTypeProvider()->writeValueType(t, a[0], data[id].dataPtr(), data[id].dataSize()); break; } diff --git a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp index deaf5f5c80..5abc7cf7bb 100644 --- a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp +++ b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp @@ -494,6 +494,23 @@ v8::Handle size(const v8::Arguments &args) return V8ENGINE()->fromVariant(QVariant::fromValue(QSizeF(w, h))); } +/*! +\qmlmethod Qt::vector2d(real x, real y) +Returns a Vector2D with the specified \c x and \c y. +*/ +v8::Handle vector2d(const v8::Arguments &args) +{ + if (args.Length() != 2) + V8THROW_ERROR("Qt.vector2d(): Invalid arguments"); + + float xy[3]; + xy[0] = args[0]->ToNumber()->Value(); + xy[1] = args[1]->ToNumber()->Value(); + + const void *params[] = { xy }; + return V8ENGINE()->fromVariant(QQml_valueTypeProvider()->createValueType(QMetaType::QVector2D, 1, params)); +} + /*! \qmlmethod Qt::vector3d(real x, real y, real z) Returns a Vector3D with the specified \c x, \c y and \c z. @@ -501,7 +518,7 @@ Returns a Vector3D with the specified \c x, \c y and \c z. v8::Handle vector3d(const v8::Arguments &args) { if (args.Length() != 3) - V8THROW_ERROR("Qt.vector(): Invalid arguments"); + V8THROW_ERROR("Qt.vector3d(): Invalid arguments"); float xyz[3]; xyz[0] = args[0]->ToNumber()->Value(); @@ -531,6 +548,89 @@ v8::Handle vector4d(const v8::Arguments &args) return V8ENGINE()->fromVariant(QQml_valueTypeProvider()->createValueType(QMetaType::QVector4D, 1, params)); } +/*! +\qmlmethod Qt::quaternion(real scalar, real x, real y, real z) +Returns a Quaternion with the specified \c scalar, \c x, \c y, and \c z. +*/ +v8::Handle quaternion(const v8::Arguments &args) +{ + if (args.Length() != 4) + V8THROW_ERROR("Qt.quaternion(): Invalid arguments"); + + double sxyz[4]; + sxyz[0] = args[0]->ToNumber()->Value(); + sxyz[1] = args[1]->ToNumber()->Value(); + sxyz[2] = args[2]->ToNumber()->Value(); + sxyz[3] = args[3]->ToNumber()->Value(); + + const void *params[] = { sxyz }; + return V8ENGINE()->fromVariant(QQml_valueTypeProvider()->createValueType(QMetaType::QQuaternion, 1, params)); +} + +/*! +\qmlmethod Qt::font(object fontSpecifier) +Returns a Font with the properties specified in the \c fontSpecifier object +or the nearest matching font. The \c fontSpecifier object should contain +key-value pairs where valid keys are the \l{fontbasictypedocs}{font} type's +subproperty names, and the values are valid values for each subproperty. +Invalid keys will be ignored. +*/ +v8::Handle font(const v8::Arguments &args) +{ + if (args.Length() != 1 || !args[0]->IsObject()) + V8THROW_ERROR("Qt.font(): Invalid arguments"); + + v8::Handle obj = args[0]->ToObject(); + bool ok = false; + QVariant v = QQml_valueTypeProvider()->createVariantFromJsObject(QMetaType::QFont, QQmlV8Handle::fromHandle(obj), V8ENGINE(), &ok); + if (!ok) + V8THROW_ERROR("Qt.font(): Invalid argument: no valid font subproperties specified"); + return V8ENGINE()->fromVariant(v); +} + +/*! +\qmlmethod Qt::matrix4x4(real m11, real m12, real m13, real m14, real m21, real m22, real m23, real m24, real m31, real m32, real m33, real m34, real m41, real m42, real m43, real m44) +Returns a Matrix4x4 with the specified values. +Alternatively, the function may be called with a single argument +where that argument is a JavaScript array which contains the sixteen +matrix values. +*/ +v8::Handle matrix4x4(const v8::Arguments &args) +{ + if (args.Length() == 1 && args[0]->IsObject()) { + v8::Handle obj = args[0]->ToObject(); + bool ok = false; + QVariant v = QQml_valueTypeProvider()->createVariantFromJsObject(QMetaType::QMatrix4x4, QQmlV8Handle::fromHandle(obj), V8ENGINE(), &ok); + if (!ok) + V8THROW_ERROR("Qt.matrix4x4(): Invalid argument: not a valid matrix4x4 values array"); + return V8ENGINE()->fromVariant(v); + } + + if (args.Length() != 16) + V8THROW_ERROR("Qt.matrix4x4(): Invalid arguments"); + + float vals[16]; + vals[0] = args[0]->ToNumber()->Value(); + vals[1] = args[1]->ToNumber()->Value(); + vals[2] = args[2]->ToNumber()->Value(); + vals[3] = args[3]->ToNumber()->Value(); + vals[4] = args[4]->ToNumber()->Value(); + vals[5] = args[5]->ToNumber()->Value(); + vals[6] = args[6]->ToNumber()->Value(); + vals[7] = args[7]->ToNumber()->Value(); + vals[8] = args[8]->ToNumber()->Value(); + vals[9] = args[9]->ToNumber()->Value(); + vals[10] = args[10]->ToNumber()->Value(); + vals[11] = args[11]->ToNumber()->Value(); + vals[12] = args[12]->ToNumber()->Value(); + vals[13] = args[13]->ToNumber()->Value(); + vals[14] = args[14]->ToNumber()->Value(); + vals[15] = args[15]->ToNumber()->Value(); + + const void *params[] = { vals }; + return V8ENGINE()->fromVariant(QQml_valueTypeProvider()->createValueType(QMetaType::QMatrix4x4, 1, params)); +} + /*! \qmlmethod color Qt::lighter(color baseColor, real factor) Returns a color lighter than \c baseColor by the \c factor provided. diff --git a/src/qml/qml/v8/qqmlbuiltinfunctions_p.h b/src/qml/qml/v8/qqmlbuiltinfunctions_p.h index bbfe88a292..0f43298338 100644 --- a/src/qml/qml/v8/qqmlbuiltinfunctions_p.h +++ b/src/qml/qml/v8/qqmlbuiltinfunctions_p.h @@ -75,11 +75,15 @@ v8::Handle consoleException(const v8::Arguments &args); v8::Handle isQtObject(const v8::Arguments &args); v8::Handle rgba(const v8::Arguments &args); v8::Handle hsla(const v8::Arguments &args); +v8::Handle font(const v8::Arguments &args); v8::Handle rect(const v8::Arguments &args); v8::Handle point(const v8::Arguments &args); v8::Handle size(const v8::Arguments &args); +v8::Handle vector2d(const v8::Arguments &args); v8::Handle vector3d(const v8::Arguments &args); v8::Handle vector4d(const v8::Arguments &args); +v8::Handle quaternion(const v8::Arguments &args); +v8::Handle matrix4x4(const v8::Arguments &args); v8::Handle lighter(const v8::Arguments &args); v8::Handle darker(const v8::Arguments &args); v8::Handle tint(const v8::Arguments &args); diff --git a/src/qml/qml/v8/qv8engine.cpp b/src/qml/qml/v8/qv8engine.cpp index 732a04d437..be3c7def85 100644 --- a/src/qml/qml/v8/qv8engine.cpp +++ b/src/qml/qml/v8/qv8engine.cpp @@ -605,11 +605,17 @@ void QV8Engine::initializeGlobal(v8::Handle global) qt->Set(v8::String::New("isQtObject"), V8FUNCTION(isQtObject, this)); qt->Set(v8::String::New("rgba"), V8FUNCTION(rgba, this)); qt->Set(v8::String::New("hsla"), V8FUNCTION(hsla, this)); + qt->Set(v8::String::New("font"), V8FUNCTION(font, this)); + qt->Set(v8::String::New("rect"), V8FUNCTION(rect, this)); qt->Set(v8::String::New("point"), V8FUNCTION(point, this)); qt->Set(v8::String::New("size"), V8FUNCTION(size, this)); + + qt->Set(v8::String::New("vector2d"), V8FUNCTION(vector2d, this)); qt->Set(v8::String::New("vector3d"), V8FUNCTION(vector3d, this)); qt->Set(v8::String::New("vector4d"), V8FUNCTION(vector4d, this)); + qt->Set(v8::String::New("quaternion"), V8FUNCTION(quaternion, this)); + qt->Set(v8::String::New("matrix4x4"), V8FUNCTION(matrix4x4, this)); qt->Set(v8::String::New("formatDate"), V8FUNCTION(formatDate, this)); qt->Set(v8::String::New("formatTime"), V8FUNCTION(formatTime, this)); diff --git a/src/qml/qml/v8/qv8valuetypewrapper.cpp b/src/qml/qml/v8/qv8valuetypewrapper.cpp index cf2c13fce9..cdee5a4771 100644 --- a/src/qml/qml/v8/qv8valuetypewrapper.cpp +++ b/src/qml/qml/v8/qv8valuetypewrapper.cpp @@ -44,6 +44,7 @@ #include #include +#include QT_BEGIN_NAMESPACE @@ -148,6 +149,14 @@ v8::Local QV8ValueTypeWrapper::newValueType(const QVariant &value, Q return rv; } +QVariant QV8ValueTypeWrapper::toVariant(v8::Handle obj, int typeHint, bool *succeeded) +{ + // NOTE: obj must not be an external resource object (ie, wrapper object) + // instead, it is a normal js object which one of the value-type providers + // may know how to convert to the given type. + return QQml_valueTypeProvider()->createVariantFromJsObject(typeHint, QQmlV8Handle::fromHandle(obj), m_engine, succeeded); +} + QVariant QV8ValueTypeWrapper::toVariant(v8::Handle obj) { QV8ValueTypeResource *r = v8_resource_cast(obj); diff --git a/src/qml/qml/v8/qv8valuetypewrapper_p.h b/src/qml/qml/v8/qv8valuetypewrapper_p.h index b80d3cbbba..76b0087828 100644 --- a/src/qml/qml/v8/qv8valuetypewrapper_p.h +++ b/src/qml/qml/v8/qv8valuetypewrapper_p.h @@ -75,6 +75,7 @@ public: v8::Local newValueType(QObject *, int, QQmlValueType *); v8::Local newValueType(const QVariant &, QQmlValueType *); + QVariant toVariant(v8::Handle, int typeHint, bool *succeeded); QVariant toVariant(v8::Handle); QVariant toVariant(QV8ObjectResource *); diff --git a/src/quick/util/qquickglobal.cpp b/src/quick/util/qquickglobal.cpp index 99caf218a6..1708cf7331 100644 --- a/src/quick/util/qquickglobal.cpp +++ b/src/quick/util/qquickglobal.cpp @@ -42,6 +42,8 @@ #include #include #include +#include +#include #include #include @@ -188,6 +190,32 @@ private: class QQuickValueTypeProvider : public QQmlValueTypeProvider { public: + +#if defined(QT_NO_DEBUG) && !defined(QT_FORCE_ASSERTS) + #define ASSERT_VALID_SIZE(size, min) Q_UNUSED(size) +#else + #define ASSERT_VALID_SIZE(size, min) Q_ASSERT(size >= min) +#endif + + static QVector2D vector2DFromString(const QString &s, bool *ok) + { + if (s.count(QLatin1Char(',')) == 1) { + int index = s.indexOf(QLatin1Char(',')); + + bool xGood, yGood; + qreal xCoord = s.left(index).toDouble(&xGood); + qreal yCoord = s.mid(index+1).toDouble(&yGood); + + if (xGood && yGood) { + if (ok) *ok = true; + return QVector2D(xCoord, yCoord); + } + } + + if (ok) *ok = false; + return QVector2D(); + } + static QVector3D vector3DFromString(const QString &s, bool *ok) { if (s.count(QLatin1Char(',')) == 2) { @@ -232,67 +260,292 @@ public: return QVector4D(); } + static QQuaternion quaternionFromString(const QString &s, bool *ok) + { + if (s.count(QLatin1Char(',')) == 3) { + int index = s.indexOf(QLatin1Char(',')); + int index2 = s.indexOf(QLatin1Char(','), index+1); + int index3 = s.indexOf(QLatin1Char(','), index2+1); + + bool sGood, xGood, yGood, zGood; + qreal sCoord = s.left(index).toDouble(&sGood); + qreal xCoord = s.mid(index+1, index2-index-1).toDouble(&xGood); + qreal yCoord = s.mid(index2+1, index3-index2-1).toDouble(&yGood); + qreal zCoord = s.mid(index3+1).toDouble(&zGood); + + if (sGood && xGood && yGood && zGood) { + if (ok) *ok = true; + return QQuaternion(sCoord, xCoord, yCoord, zCoord); + } + } + + if (ok) *ok = false; + return QQuaternion(); + } + + static QMatrix4x4 matrix4x4FromString(const QString &s, bool *ok) + { + if (s.count(QLatin1Char(',')) == 15) { + qreal matValues[16]; + bool vOK = true; + QString mutableStr = s; + for (int i = 0; vOK && i < 16; ++i) { + int cidx = mutableStr.indexOf(QLatin1Char(',')); + matValues[i] = mutableStr.left(cidx).toDouble(&vOK); + mutableStr = mutableStr.mid(cidx + 1); + } + + if (vOK) { + if (ok) *ok = true; + return QMatrix4x4(matValues); + } + } + + if (ok) *ok = false; + return QMatrix4x4(); + } + + static QFont fontFromObject(QQmlV8Handle object, QV8Engine *e, bool *ok) + { + if (ok) *ok = false; + QFont retn; + v8::Handle obj = object.toHandle()->ToObject(); + + v8::Handle vbold = obj->Get(v8::String::New("bold")); + v8::Handle vcap = obj->Get(v8::String::New("capitalization")); + v8::Handle vfam = obj->Get(v8::String::New("family")); + v8::Handle vital = obj->Get(v8::String::New("italic")); + v8::Handle vlspac = obj->Get(v8::String::New("letterSpacing")); + v8::Handle vpixsz = obj->Get(v8::String::New("pixelSize")); + v8::Handle vpntsz = obj->Get(v8::String::New("pointSize")); + v8::Handle vstrk = obj->Get(v8::String::New("strikeout")); + v8::Handle vundl = obj->Get(v8::String::New("underline")); + v8::Handle vweight = obj->Get(v8::String::New("weight")); + v8::Handle vwspac = obj->Get(v8::String::New("wordSpacing")); + + // pull out the values, set ok to true if at least one valid field is given. + if (!vbold.IsEmpty() && !vbold->IsNull() && !vbold->IsUndefined() && vbold->IsBoolean()) { + retn.setBold(vbold->BooleanValue()); + if (ok) *ok = true; + } + if (!vcap.IsEmpty() && !vcap->IsNull() && !vcap->IsUndefined() && vcap->IsInt32()) { + retn.setCapitalization(static_cast(vcap->Int32Value())); + if (ok) *ok = true; + } + if (!vfam.IsEmpty() && !vfam->IsNull() && !vfam->IsUndefined() && vfam->IsString()) { + retn.setFamily(e->toString(vfam->ToString())); + if (ok) *ok = true; + } + if (!vital.IsEmpty() && !vital->IsNull() && !vital->IsUndefined() && vital->IsBoolean()) { + retn.setItalic(vital->BooleanValue()); + if (ok) *ok = true; + } + if (!vlspac.IsEmpty() && !vlspac->IsNull() && !vlspac->IsUndefined() && vlspac->IsNumber()) { + retn.setLetterSpacing(QFont::AbsoluteSpacing, vlspac->NumberValue()); + if (ok) *ok = true; + } + if (!vpixsz.IsEmpty() && !vpixsz->IsNull() && !vpixsz->IsUndefined() && vpixsz->IsInt32()) { + retn.setPixelSize(vpixsz->Int32Value()); + if (ok) *ok = true; + } + if (!vpntsz.IsEmpty() && !vpntsz->IsNull() && !vpntsz->IsUndefined() && vpntsz->IsNumber()) { + retn.setPointSize(vpntsz->NumberValue()); + if (ok) *ok = true; + } + if (!vstrk.IsEmpty() && !vstrk->IsNull() && !vstrk->IsUndefined() && vstrk->IsBoolean()) { + retn.setStrikeOut(vstrk->BooleanValue()); + if (ok) *ok = true; + } + if (!vundl.IsEmpty() && !vundl->IsNull() && !vundl->IsUndefined() && vundl->IsBoolean()) { + retn.setUnderline(vundl->BooleanValue()); + if (ok) *ok = true; + } + if (!vweight.IsEmpty() && !vweight->IsNull() && !vweight->IsUndefined() && vweight->IsInt32()) { + retn.setWeight(static_cast(vweight->Int32Value())); + if (ok) *ok = true; + } + if (!vwspac.IsEmpty() && !vwspac->IsNull() && !vwspac->IsUndefined() && vwspac->IsNumber()) { + retn.setWordSpacing(vwspac->NumberValue()); + if (ok) *ok = true; + } + + return retn; + } + + static QMatrix4x4 matrix4x4FromObject(QQmlV8Handle object, bool *ok) + { + if (ok) *ok = false; + v8::Handle obj = object.toHandle()->ToObject(); + if (!obj->IsArray()) + return QMatrix4x4(); + + v8::Handle array = v8::Handle::Cast(obj); + if (array->Length() != 16) + return QMatrix4x4(); + + qreal matVals[16]; + for (uint32_t i = 0; i < 16; ++i) { + v8::Handle v = array->Get(i); + if (!v->IsNumber()) + return QMatrix4x4(); + matVals[i] = v->NumberValue(); + } + + if (ok) *ok = true; + return QMatrix4x4(matVals); + } + + template + bool typedCreate(QQmlValueType *&v) + { + v = new T; + return true; + } + bool create(int type, QQmlValueType *&v) { switch (type) { case QMetaType::QColor: - v = new QQuickColorValueType; - return true; + return typedCreate(v); + case QMetaType::QFont: + return typedCreate(v); case QMetaType::QVector2D: - v = new QQuickVector2DValueType; - return true; + return typedCreate(v); case QMetaType::QVector3D: - v = new QQuickVector3DValueType; - return true; + return typedCreate(v); case QMetaType::QVector4D: - v = new QQuickVector4DValueType; - return true; + return typedCreate(v); case QMetaType::QQuaternion: - v = new QQuickQuaternionValueType; - return true; + return typedCreate(v); case QMetaType::QMatrix4x4: - v = new QQuickMatrix4x4ValueType; - return true; - case QMetaType::QFont: - v = new QQuickFontValueType; - return true; + return typedCreate(v); default: - return false; + break; } + + return false; } - bool init(int type, void *data, size_t n) + template + bool typedInit(void *data, size_t dataSize) { - if (type == QMetaType::QColor) { - Q_ASSERT(n >= sizeof(QColor)); - QColor *color = reinterpret_cast(data); - new (color) QColor(); + ASSERT_VALID_SIZE(dataSize, sizeof(T)); + T *t = reinterpret_cast(data); + new (t) T(); + return true; + } + + bool init(int type, void *data, size_t dataSize) + { + switch (type) { + case QMetaType::QColor: + return typedInit(data, dataSize); + case QMetaType::QFont: + return typedInit(data, dataSize); + case QMetaType::QVector2D: + return typedInit(data, dataSize); + case QMetaType::QVector3D: + return typedInit(data, dataSize); + case QMetaType::QVector4D: + return typedInit(data, dataSize); + case QMetaType::QQuaternion: + return typedInit(data, dataSize); + case QMetaType::QMatrix4x4: + { + if (dataSize >= sizeof(QMatrix4x4)) + return typedInit(data, dataSize); + + // special case: init matrix-containing qvariant. + Q_ASSERT(dataSize >= sizeof(QVariant)); + QVariant *matvar = reinterpret_cast(data); + new (matvar) QVariant(QMatrix4x4()); return true; + } + default: break; } return false; } - bool destroy(int type, void *data, size_t n) + template + bool typedDestroy(void *data, size_t dataSize) { - if (type == QMetaType::QColor) { - Q_ASSERT(n >= sizeof(QColor)); - QColor *color = reinterpret_cast(data); - color->~QColor(); + ASSERT_VALID_SIZE(dataSize, sizeof(T)); + T *t = reinterpret_cast(data); + t->~T(); + return true; + } + + bool destroy(int type, void *data, size_t dataSize) + { + switch (type) { + case QMetaType::QColor: + return typedDestroy(data, dataSize); + case QMetaType::QFont: + return typedDestroy(data, dataSize); + case QMetaType::QVector2D: + return typedDestroy(data, dataSize); + case QMetaType::QVector3D: + return typedDestroy(data, dataSize); + case QMetaType::QVector4D: + return typedDestroy(data, dataSize); + case QMetaType::QQuaternion: + return typedDestroy(data, dataSize); + case QMetaType::QMatrix4x4: + { + if (dataSize >= sizeof(QMatrix4x4)) + return typedDestroy(data, dataSize); + + // special case: destroying matrix-containing qvariant. + Q_ASSERT(dataSize >= sizeof(QVariant)); + QVariant *matvar = reinterpret_cast(data); + matvar->~QVariant(); return true; + } + default: break; } return false; } - bool copy(int type, const void *src, void *dst, size_t n) + template + bool typedCopyConstruct(const void *src, void *dst, size_t dstSize) { - if (type == QMetaType::QColor) { - Q_ASSERT(n >= sizeof(QColor)); - const QColor *srcColor = reinterpret_cast(src); - QColor *dstColor = reinterpret_cast(dst); - new (dstColor) QColor(*srcColor); + ASSERT_VALID_SIZE(dstSize, sizeof(T)); + const T *srcT = reinterpret_cast(src); + T *destT = reinterpret_cast(dst); + new (destT) T(*srcT); + return true; + } + + bool copy(int type, const void *src, void *dst, size_t dstSize) + { + switch (type) { + case QMetaType::QColor: + return typedCopyConstruct(src, dst, dstSize); + case QMetaType::QFont: + return typedCopyConstruct(src, dst, dstSize); + case QMetaType::QVector2D: + return typedCopyConstruct(src, dst, dstSize); + case QMetaType::QVector3D: + return typedCopyConstruct(src, dst, dstSize); + case QMetaType::QVector4D: + return typedCopyConstruct(src, dst, dstSize); + case QMetaType::QQuaternion: + return typedCopyConstruct(src, dst, dstSize); + case QMetaType::QMatrix4x4: + { + if (dstSize >= sizeof(QMatrix4x4)) + return typedCopyConstruct(src, dst, dstSize); + + // special case: copying matrix into variant. + Q_ASSERT(dstSize >= sizeof(QVariant)); + const QMatrix4x4 *srcMatrix = reinterpret_cast(src); + QVariant *dstMatrixVar = reinterpret_cast(dst); + new (dstMatrixVar) QVariant(*srcMatrix); return true; + } + default: break; } return false; @@ -301,6 +554,16 @@ public: bool create(int type, int argc, const void *argv[], QVariant *v) { switch (type) { + case QMetaType::QFont: // must specify via js-object. + break; + case QMetaType::QVector2D: + if (argc == 1) { + const float *xy = reinterpret_cast(argv[0]); + QVector2D v2(xy[0], xy[1]); + *v = QVariant(v2); + return true; + } + break; case QMetaType::QVector3D: if (argc == 1) { const float *xyz = reinterpret_cast(argv[0]); @@ -317,37 +580,66 @@ public: return true; } break; + case QMetaType::QQuaternion: + if (argc == 1) { + const double *sxyz = reinterpret_cast(argv[0]); + QQuaternion q(sxyz[0], sxyz[1], sxyz[2], sxyz[3]); + *v = QVariant(q); + return true; + } + break; + case QMetaType::QMatrix4x4: + if (argc == 1) { + const float *vals = reinterpret_cast(argv[0]); + QMatrix4x4 m(vals[0], vals[1], vals[2], vals[3], + vals[4], vals[5], vals[6], vals[7], + vals[8], vals[9], vals[10], vals[11], + vals[12], vals[13], vals[14], vals[15]); + *v = QVariant(m); + return true; + } + break; + default: break; } return false; } - bool createFromString(int type, const QString &s, void *data, size_t n) + template + bool createFromStringTyped(void *data, size_t dataSize, T initValue) + { + ASSERT_VALID_SIZE(dataSize, sizeof(T)); + T *t = reinterpret_cast(data); + new (t) T(initValue); + return true; + } + + bool createFromString(int type, const QString &s, void *data, size_t dataSize) { bool ok = false; switch (type) { case QMetaType::QColor: - { - Q_ASSERT(n >= sizeof(QColor)); - QColor *color = reinterpret_cast(data); - new (color) QColor(QQuickColorProvider::QColorFromString(s)); - return true; - } + return createFromStringTyped(data, dataSize, QQuickColorProvider::QColorFromString(s)); + case QMetaType::QVector2D: + return createFromStringTyped(data, dataSize, vector2DFromString(s, &ok)); case QMetaType::QVector3D: - { - Q_ASSERT(n >= sizeof(QVector3D)); - QVector3D *v3 = reinterpret_cast(data); - new (v3) QVector3D(vector3DFromString(s, &ok)); - return true; - } + return createFromStringTyped(data, dataSize, vector3DFromString(s, &ok)); case QMetaType::QVector4D: + return createFromStringTyped(data, dataSize, vector4DFromString(s, &ok)); + case QMetaType::QQuaternion: + return createFromStringTyped(data, dataSize, quaternionFromString(s, &ok)); + case QMetaType::QMatrix4x4: { - Q_ASSERT(n >= sizeof(QVector4D)); - QVector4D *v4 = reinterpret_cast(data); - new (v4) QVector4D(vector4DFromString(s, &ok)); + if (dataSize >= sizeof(QMatrix4x4)) + return createFromStringTyped(data, dataSize, matrix4x4FromString(s, &ok)); + + Q_ASSERT(dataSize >= sizeof(QVariant)); + QVariant *matVar = reinterpret_cast(data); + new (matVar) QVariant(matrix4x4FromString(s, &ok)); return true; } + default: break; } return false; @@ -374,6 +666,12 @@ public: bool ok = false; + QVector2D v2 = vector2DFromString(s, &ok); + if (ok) { + *v = QVariant::fromValue(v2); + return true; + } + QVector3D v3 = vector3DFromString(s, &ok); if (ok) { *v = QVariant::fromValue(v3); @@ -386,6 +684,18 @@ public: return true; } + QQuaternion q = quaternionFromString(s, &ok); + if (ok) { + *v = QVariant::fromValue(q); + return true; + } + + QMatrix4x4 m = matrix4x4FromString(s, &ok); + if (ok) { + *v = QVariant::fromValue(m); + return true; + } + return false; } @@ -400,99 +710,245 @@ public: *v = QVariant::fromValue(c); return true; } + case QMetaType::QVector2D: + { + *v = QVariant::fromValue(vector2DFromString(s, &ok)); + return true; + } case QMetaType::QVector3D: + { *v = QVariant::fromValue(vector3DFromString(s, &ok)); return true; + } case QMetaType::QVector4D: + { *v = QVariant::fromValue(vector4DFromString(s, &ok)); return true; + } + case QMetaType::QQuaternion: + { + *v = QVariant::fromValue(quaternionFromString(s, &ok)); + return true; + } + case QMetaType::QMatrix4x4: + { + *v = QVariant::fromValue(matrix4x4FromString(s, &ok)); + return true; + } + default: + break; } return false; } + bool variantFromJsObject(int type, QQmlV8Handle object, QV8Engine *e, QVariant *v) + { + // must be called with a valid v8 context. + Q_ASSERT(object.toHandle()->IsObject()); + bool ok = false; + switch (type) { + case QMetaType::QFont: + *v = QVariant::fromValue(fontFromObject(object, e, &ok)); + break; + case QMetaType::QMatrix4x4: + *v = QVariant::fromValue(matrix4x4FromObject(object, &ok)); + default: break; + } + + return ok; + } + template bool typedEqual(const void *lhs, const void *rhs) { return (*(reinterpret_cast(lhs)) == *(reinterpret_cast(rhs))); } - bool equal(int type, const void *lhs, const void *rhs) + bool equal(int type, const void *lhs, const void *rhs, size_t rhsSize) { switch (type) { case QMetaType::QColor: return typedEqual(lhs, rhs); + case QMetaType::QFont: + return typedEqual(lhs, rhs); + case QMetaType::QVector2D: + return typedEqual(lhs, rhs); case QMetaType::QVector3D: return typedEqual(lhs, rhs); case QMetaType::QVector4D: return typedEqual(lhs, rhs); + case QMetaType::QQuaternion: + return typedEqual(lhs, rhs); + case QMetaType::QMatrix4x4: + { + if (rhsSize >= sizeof(QMatrix4x4)) + return typedEqual(lhs, rhs); + + Q_ASSERT(rhsSize >= sizeof(QVariant)); + QMatrix4x4 rhsmat = reinterpret_cast(rhs)->value(); + return typedEqual(lhs, &rhsmat); + } + default: break; } return false; } - bool store(int type, const void *src, void *dst, size_t n) + template + bool typedStore(const void *src, void *dst, size_t dstSize) + { + ASSERT_VALID_SIZE(dstSize, sizeof(T)); + const T *srcT = reinterpret_cast(src); + T *dstT = reinterpret_cast(dst); + new (dstT) T(*srcT); + return true; + } + + bool store(int type, const void *src, void *dst, size_t dstSize) { switch (type) { case QMetaType::QColor: { - Q_ASSERT(n >= sizeof(QColor)); + Q_ASSERT(dstSize >= sizeof(QColor)); const QRgb *rgb = reinterpret_cast(src); QColor *color = reinterpret_cast(dst); new (color) QColor(QColor::fromRgba(*rgb)); return true; } + case QMetaType::QFont: + return typedStore(src, dst, dstSize); + case QMetaType::QVector2D: + return typedStore(src, dst, dstSize); case QMetaType::QVector3D: - { - Q_ASSERT(n >= sizeof(QVector3D)); - const QVector3D *srcVector = reinterpret_cast(src); - QVector3D *dstVector = reinterpret_cast(dst); - new (dstVector) QVector3D(*srcVector); - return true; - } + return typedStore(src, dst, dstSize); case QMetaType::QVector4D: + return typedStore(src, dst, dstSize); + case QMetaType::QQuaternion: + return typedStore(src, dst, dstSize); + case QMetaType::QMatrix4x4: { - Q_ASSERT(n >= sizeof(QVector4D)); - const QVector4D *srcVector = reinterpret_cast(src); - QVector4D *dstVector = reinterpret_cast(dst); - new (dstVector) QVector4D(*srcVector); + if (dstSize >= sizeof(QMatrix4x4)) + return typedStore(src, dst, dstSize); + + // special case: storing matrix into variant + // eg, QVMEMO QVMEVariant data cell is big enough to store + // QVariant, but not large enough to store QMatrix4x4. + Q_ASSERT(dstSize >= sizeof(QVariant)); + const QMatrix4x4 *srcMat = reinterpret_cast(src); + QVariant *dstMatVar = reinterpret_cast(dst); + new (dstMatVar) QVariant(*srcMat); return true; } + default: break; } return false; } - bool read(int srcType, const void *src, int dstType, void *dst) + template + bool typedRead(int srcType, const void *src, size_t srcSize, int dstType, void *dst) + { + T *dstT = reinterpret_cast(dst); + if (srcType == dstType) { + ASSERT_VALID_SIZE(srcSize, sizeof(T)); + const T *srcT = reinterpret_cast(src); + *dstT = *srcT; + } else { + *dstT = T(); + } + return true; + } + + bool read(int srcType, const void *src, size_t srcSize, int dstType, void *dst) { - if (dstType == QMetaType::QColor) { - QColor *dstColor = reinterpret_cast(dst); - if (srcType == QMetaType::QColor) { - const QColor *srcColor = reinterpret_cast(src); - *dstColor = *srcColor; + switch (dstType) { + case QMetaType::QColor: + return typedRead(srcType, src, srcSize, dstType, dst); + case QMetaType::QFont: + return typedRead(srcType, src, srcSize, dstType, dst); + case QMetaType::QVector2D: + return typedRead(srcType, src, srcSize, dstType, dst); + case QMetaType::QVector3D: + return typedRead(srcType, src, srcSize, dstType, dst); + case QMetaType::QVector4D: + return typedRead(srcType, src, srcSize, dstType, dst); + case QMetaType::QQuaternion: + return typedRead(srcType, src, srcSize, dstType, dst); + case QMetaType::QMatrix4x4: + { + if (srcSize >= sizeof(QMatrix4x4)) + return typedRead(srcType, src, srcSize, dstType, dst); + + // the source data may be stored in a QVariant. + QMatrix4x4 *dstMat = reinterpret_cast(dst); + if (srcType == dstType) { + Q_ASSERT(srcSize >= sizeof(QVariant)); + const QVariant *srcMatVar = reinterpret_cast(src); + *dstMat = srcMatVar->value(); } else { - *dstColor = QColor(); + *dstMat = QMatrix4x4(); } return true; + } + default: break; } return false; } - bool write(int type, const void *src, void *dst, size_t n) + template + bool typedWrite(const void *src, void *dst, size_t dstSize) { - if (type == QMetaType::QColor) { - Q_ASSERT(n >= sizeof(QColor)); - const QColor *srcColor = reinterpret_cast(src); - QColor *dstColor = reinterpret_cast(dst); - if (*dstColor != *srcColor) { - *dstColor = *srcColor; + ASSERT_VALID_SIZE(dstSize, sizeof(T)); + const T *srcT = reinterpret_cast(src); + T *dstT = reinterpret_cast(dst); + if (*dstT != *srcT) { + *dstT = *srcT; + return true; + } + return false; + } + + bool write(int type, const void *src, void *dst, size_t dstSize) + { + switch (type) { + case QMetaType::QColor: + return typedWrite(src, dst, dstSize); + case QMetaType::QFont: + return typedWrite(src, dst, dstSize); + case QMetaType::QVector2D: + return typedWrite(src, dst, dstSize); + case QMetaType::QVector3D: + return typedWrite(src, dst, dstSize); + case QMetaType::QVector4D: + return typedWrite(src, dst, dstSize); + case QMetaType::QQuaternion: + return typedWrite(src, dst, dstSize); + case QMetaType::QMatrix4x4: + { + if (dstSize >= sizeof(QMatrix4x4)) + return typedWrite(src, dst, dstSize); + + // special case: storing matrix into variant + // eg, QVMEMO QVMEVariant data cell is big enough to store + // QVariant, but not large enough to store QMatrix4x4. + Q_ASSERT(dstSize >= sizeof(QVariant)); + const QMatrix4x4 *srcMat = reinterpret_cast(src); + QVariant *dstMatVar = reinterpret_cast(dst); + QMatrix4x4 dstMatVal = dstMatVar->value(); + if (dstMatVal != *srcMat) { + *dstMatVar = QVariant(*srcMat); return true; } + return false; + } + default: break; } return false; } +#undef ASSERT_VALID_SIZE }; diff --git a/src/quick/util/qquickvaluetypes.cpp b/src/quick/util/qquickvaluetypes.cpp index e3da2658b4..4224847311 100644 --- a/src/quick/util/qquickvaluetypes.cpp +++ b/src/quick/util/qquickvaluetypes.cpp @@ -57,7 +57,7 @@ namespace QQuickValueTypes { } QQuickColorValueType::QQuickColorValueType(QObject *parent) - : QQmlValueTypeBase(parent) + : QQmlValueTypeBase(QMetaType::QColor, parent) { } @@ -109,7 +109,7 @@ void QQuickColorValueType::setA(qreal a) QQuickVector2DValueType::QQuickVector2DValueType(QObject *parent) - : QQmlValueTypeBase(parent) + : QQmlValueTypeBase(QMetaType::QVector2D, parent) { } @@ -140,7 +140,7 @@ void QQuickVector2DValueType::setY(qreal y) QQuickVector3DValueType::QQuickVector3DValueType(QObject *parent) - : QQmlValueTypeBase(parent) + : QQmlValueTypeBase(QMetaType::QVector3D, parent) { } @@ -181,7 +181,7 @@ void QQuickVector3DValueType::setZ(qreal z) QQuickVector4DValueType::QQuickVector4DValueType(QObject *parent) - : QQmlValueTypeBase(parent) + : QQmlValueTypeBase(QMetaType::QVector4D, parent) { } @@ -232,7 +232,7 @@ void QQuickVector4DValueType::setW(qreal w) QQuickQuaternionValueType::QQuickQuaternionValueType(QObject *parent) - : QQmlValueTypeBase(parent) + : QQmlValueTypeBase(QMetaType::QQuaternion, parent) { } @@ -283,7 +283,7 @@ void QQuickQuaternionValueType::setZ(qreal z) QQuickMatrix4x4ValueType::QQuickMatrix4x4ValueType(QObject *parent) - : QQmlValueTypeBase(parent) + : QQmlValueTypeBase(QMetaType::QMatrix4x4, parent) { } @@ -298,7 +298,7 @@ QString QQuickMatrix4x4ValueType::toString() const QQuickFontValueType::QQuickFontValueType(QObject *parent) - : QQmlValueTypeBase(parent), + : QQmlValueTypeBase(QMetaType::QFont, parent), pixelSizeSet(false), pointSizeSet(false) { diff --git a/tests/auto/qml/qml.pro b/tests/auto/qml/qml.pro index 48613a4ce5..2c5d367b88 100644 --- a/tests/auto/qml/qml.pro +++ b/tests/auto/qml/qml.pro @@ -38,6 +38,7 @@ PRIVATETESTS += \ qqmlpropertymap \ qqmlsqldatabase \ qqmlvaluetypes \ + qqmlvaluetypeproviders \ qquickbinding \ qquickchangeset \ qquickconnection \ diff --git a/tests/auto/qml/qqmlglobal/tst_qqmlglobal.cpp b/tests/auto/qml/qqmlglobal/tst_qqmlglobal.cpp index e2cdd50883..e32c13b98e 100644 --- a/tests/auto/qml/qqmlglobal/tst_qqmlglobal.cpp +++ b/tests/auto/qml/qqmlglobal/tst_qqmlglobal.cpp @@ -53,7 +53,6 @@ public: private slots: void initTestCase(); - void valueTypeProviderWarning(); void colorProviderWarning(); void guiProviderWarning(); }; @@ -62,13 +61,6 @@ void tst_qqmlglobal::initTestCase() { } -void tst_qqmlglobal::valueTypeProviderWarning() -{ - const QLatin1String expected("Warning: QQml_valueTypeProvider: no value type provider has been set! "); - QTest::ignoreMessage(QtWarningMsg, expected.data()); - QQml_valueTypeProvider(); -} - void tst_qqmlglobal::colorProviderWarning() { const QLatin1String expected("Warning: QQml_colorProvider: no color provider has been set! "); diff --git a/tests/auto/qml/qqmlqt/data/font.qml b/tests/auto/qml/qqmlqt/data/font.qml new file mode 100644 index 0000000000..9ebf460caf --- /dev/null +++ b/tests/auto/qml/qqmlqt/data/font.qml @@ -0,0 +1,8 @@ +import QtQuick 2.0 + +QtObject { + property variant test1: Qt.font({ family: "Arial", pointSize: 22 }); + property variant test2: Qt.font({ family: "Arial", pointSize: 20, weight: Font.DemiBold, italic: true }); + property variant test3: Qt.font("Arial", 22); + property variant test4: Qt.font({ something: "Arial", other: 22 }); +} diff --git a/tests/auto/qml/qqmlqt/data/matrix4x4.qml b/tests/auto/qml/qqmlqt/data/matrix4x4.qml new file mode 100644 index 0000000000..0185fcb635 --- /dev/null +++ b/tests/auto/qml/qqmlqt/data/matrix4x4.qml @@ -0,0 +1,9 @@ +import QtQuick 2.0 + +QtObject { + property variant test1: Qt.matrix4x4(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); + property variant test2: Qt.matrix4x4([1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4]); + property variant test3: Qt.matrix4x4(1,2,3,4,5,6); + property variant test4: Qt.matrix4x4([1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5]); + property variant test5: Qt.matrix4x4({ test: 5, subprop: "hello" }); +} diff --git a/tests/auto/qml/qqmlqt/data/quaternion.qml b/tests/auto/qml/qqmlqt/data/quaternion.qml new file mode 100644 index 0000000000..6203bd1e32 --- /dev/null +++ b/tests/auto/qml/qqmlqt/data/quaternion.qml @@ -0,0 +1,8 @@ +import QtQuick 2.0 + +QtObject { + property variant test1: Qt.quaternion(2, 17, 0.9, 0.6); + property variant test2: Qt.quaternion(102, -10, -982.1, 10); + property variant test3: Qt.quaternion(102, -10, -982.1); + property variant test4: Qt.quaternion(102, -10, -982.1, 10, 15); +} diff --git a/tests/auto/qml/qqmlqt/data/vector2.qml b/tests/auto/qml/qqmlqt/data/vector2.qml new file mode 100644 index 0000000000..1ca513eaba --- /dev/null +++ b/tests/auto/qml/qqmlqt/data/vector2.qml @@ -0,0 +1,8 @@ +import QtQuick 2.0 + +QtObject { + property variant test1: Qt.vector2d(1, 0.9); + property variant test2: Qt.vector2d(102, -982.1); + property variant test3: Qt.vector2d(102); + property variant test4: Qt.vector2d(102, -982.1, 10); +} diff --git a/tests/auto/qml/qqmlqt/tst_qqmlqt.cpp b/tests/auto/qml/qqmlqt/tst_qqmlqt.cpp index c81e6771b8..6fd6fc8822 100644 --- a/tests/auto/qml/qqmlqt/tst_qqmlqt.cpp +++ b/tests/auto/qml/qqmlqt/tst_qqmlqt.cpp @@ -48,12 +48,15 @@ #include #include #include -#include #include #include #include +#include #include #include +#include +#include +#include #include "../../shared/util.h" class tst_qqmlqt : public QQmlDataTest @@ -69,8 +72,12 @@ private slots: void rect(); void point(); void size(); - void vector(); + void vector2d(); + void vector3d(); void vector4d(); + void quaternion(); + void matrix4x4(); + void font(); void lighter(); void darker(); void tint(); @@ -217,12 +224,32 @@ void tst_qqmlqt::size() delete object; } -void tst_qqmlqt::vector() +void tst_qqmlqt::vector2d() +{ + QQmlComponent component(&engine, testFileUrl("vector2.qml")); + + QString warning1 = component.url().toString() + ":6: Error: Qt.vector2d(): Invalid arguments"; + QString warning2 = component.url().toString() + ":7: Error: Qt.vector2d(): Invalid arguments"; + QTest::ignoreMessage(QtWarningMsg, qPrintable(warning1)); + QTest::ignoreMessage(QtWarningMsg, qPrintable(warning2)); + + QObject *object = component.create(); + QVERIFY(object != 0); + + QCOMPARE(qvariant_cast(object->property("test1")), QVector2D(1, 0.9)); + QCOMPARE(qvariant_cast(object->property("test2")), QVector2D(102, -982.1)); + QCOMPARE(qvariant_cast(object->property("test3")), QVector2D()); + QCOMPARE(qvariant_cast(object->property("test4")), QVector2D()); + + delete object; +} + +void tst_qqmlqt::vector3d() { QQmlComponent component(&engine, testFileUrl("vector.qml")); - QString warning1 = component.url().toString() + ":6: Error: Qt.vector(): Invalid arguments"; - QString warning2 = component.url().toString() + ":7: Error: Qt.vector(): Invalid arguments"; + QString warning1 = component.url().toString() + ":6: Error: Qt.vector3d(): Invalid arguments"; + QString warning2 = component.url().toString() + ":7: Error: Qt.vector3d(): Invalid arguments"; QTest::ignoreMessage(QtWarningMsg, qPrintable(warning1)); QTest::ignoreMessage(QtWarningMsg, qPrintable(warning2)); @@ -257,6 +284,69 @@ void tst_qqmlqt::vector4d() delete object; } +void tst_qqmlqt::quaternion() +{ + QQmlComponent component(&engine, testFileUrl("quaternion.qml")); + + QString warning1 = component.url().toString() + ":6: Error: Qt.quaternion(): Invalid arguments"; + QString warning2 = component.url().toString() + ":7: Error: Qt.quaternion(): Invalid arguments"; + QTest::ignoreMessage(QtWarningMsg, qPrintable(warning1)); + QTest::ignoreMessage(QtWarningMsg, qPrintable(warning2)); + + QObject *object = component.create(); + QVERIFY(object != 0); + + QCOMPARE(qvariant_cast(object->property("test1")), QQuaternion(2, 17, 0.9, 0.6)); + QCOMPARE(qvariant_cast(object->property("test2")), QQuaternion(102, -10, -982.1, 10)); + QCOMPARE(qvariant_cast(object->property("test3")), QQuaternion()); + QCOMPARE(qvariant_cast(object->property("test4")), QQuaternion()); + + delete object; +} + +void tst_qqmlqt::matrix4x4() +{ + QQmlComponent component(&engine, testFileUrl("matrix4x4.qml")); + + QString warning1 = component.url().toString() + ":6: Error: Qt.matrix4x4(): Invalid arguments"; + QString warning2 = component.url().toString() + ":7: Error: Qt.matrix4x4(): Invalid argument: not a valid matrix4x4 values array"; + QString warning3 = component.url().toString() + ":8: Error: Qt.matrix4x4(): Invalid argument: not a valid matrix4x4 values array"; + QTest::ignoreMessage(QtWarningMsg, qPrintable(warning1)); + QTest::ignoreMessage(QtWarningMsg, qPrintable(warning2)); + QTest::ignoreMessage(QtWarningMsg, qPrintable(warning3)); + + QObject *object = component.create(); + QVERIFY(object != 0); + + QCOMPARE(qvariant_cast(object->property("test1")), QMatrix4x4(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16)); + QCOMPARE(qvariant_cast(object->property("test2")), QMatrix4x4(1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4)); + QCOMPARE(qvariant_cast(object->property("test3")), QMatrix4x4()); + QCOMPARE(qvariant_cast(object->property("test4")), QMatrix4x4()); + QCOMPARE(qvariant_cast(object->property("test5")), QMatrix4x4()); + + delete object; +} + +void tst_qqmlqt::font() +{ + QQmlComponent component(&engine, testFileUrl("font.qml")); + + QString warning1 = component.url().toString() + ":6: Error: Qt.font(): Invalid arguments"; + QString warning2 = component.url().toString() + ":7: Error: Qt.font(): Invalid argument: no valid font subproperties specified"; + QTest::ignoreMessage(QtWarningMsg, qPrintable(warning1)); + QTest::ignoreMessage(QtWarningMsg, qPrintable(warning2)); + + QObject *object = component.create(); + QVERIFY(object != 0); + + QCOMPARE(qvariant_cast(object->property("test1")), QFont("Arial", 22)); + QCOMPARE(qvariant_cast(object->property("test2")), QFont("Arial", 20, QFont::DemiBold, true)); + QCOMPARE(qvariant_cast(object->property("test3")), QFont()); + QCOMPARE(qvariant_cast(object->property("test4")), QFont()); + + delete object; +} + void tst_qqmlqt::lighter() { QQmlComponent component(&engine, testFileUrl("lighter.qml")); diff --git a/tests/auto/qml/qqmlvaluetypeproviders/data/comparisonSemantics.qml b/tests/auto/qml/qqmlvaluetypeproviders/data/comparisonSemantics.qml new file mode 100644 index 0000000000..e37cf9bc8d --- /dev/null +++ b/tests/auto/qml/qqmlvaluetypeproviders/data/comparisonSemantics.qml @@ -0,0 +1,95 @@ +import QtQuick 2.0 + +QtObject { + property bool comparisonSuccess: false + + property date d: new Date(1999, 8, 8) + property date d2: new Date(1998, 8, 8) + + property rect g: Qt.rect(1, 2, 3, 4) + property rect g2: Qt.rect(5, 6, 7, 8) + property point p: Qt.point(1, 2) + property point p2: Qt.point(3, 4) + property size z: Qt.size(1, 2) + property size z2: Qt.size(3, 4) + + property vector2d v2: Qt.vector2d(1,2) + property vector2d v22: Qt.vector2d(3,4) + property vector3d v3: Qt.vector3d(1,2,3) + property vector3d v32: Qt.vector3d(4,5,6) + property vector4d v4: Qt.vector4d(1,2,3,4) + property vector4d v42: Qt.vector4d(5,6,7,8) + property quaternion q: Qt.quaternion(1,2,3,4) + property quaternion q2: Qt.quaternion(5,6,7,8) + property matrix4x4 m: Qt.matrix4x4(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16) + property matrix4x4 m2: Qt.matrix4x4(21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36) + property color c: "red" + property color c2: "blue" + property font f: Qt.font({family: "Arial", pointSize: 20}) + property font f2: Qt.font({family: "Arial", pointSize: 22}) + + Component.onCompleted: { + comparisonSuccess = true; + + // same type comparison. + if (d == d2) comparisonSuccess = false; + d = d2; + if (d == d2) comparisonSuccess = false; // QML date uses same comparison semantics as JS date! + if (d.toString() != d2.toString()) comparisonSuccess = false; + + if (g == g2) comparisonSuccess = false; + g = g2; + if (g != g2) comparisonSuccess = false; + + if (p == p2) comparisonSuccess = false; + p = p2; + if (p != p2) comparisonSuccess = false; + + if (z == z2) comparisonSuccess = false; + z = z2; + if (z != z2) comparisonSuccess = false; + + if (v2 == v22) comparisonSuccess = false; + v2 = v22; + if (v2 != v22) comparisonSuccess = false; + + if (v3 == v32) comparisonSuccess = false; + v3 = v32; + if (v3 != v32) comparisonSuccess = false; + + if (v4 == v42) comparisonSuccess = false; + v4 = v42; + if (v4 != v42) comparisonSuccess = false; + + if (q == q2) comparisonSuccess = false; + q = q2; + if (q != q2) comparisonSuccess = false; + + if (m == m2) comparisonSuccess = false; + m = m2; + if (m != m2) comparisonSuccess = false; + + if (c == c2) comparisonSuccess = false; + c = c2; + if (c != c2) comparisonSuccess = false; + + if (f == f2) comparisonSuccess = false; + f = f2; + if (f != f2) comparisonSuccess = false; + + // cross-type comparison. + p = Qt.point(1,2); + z = Qt.size(1,2); + v2 = Qt.vector2d(1,2); + if (p == z || p == v2 || z == v2) comparisonSuccess = false; + if (z == p || v2 == p || v2 == z) comparisonSuccess = false; + + g = Qt.rect(1,2,3,4); + q = Qt.quaternion(1,2,3,4); + v4 = Qt.vector4d(1,2,3,4); + if (g == q || g == v4 || q == v4) comparisonSuccess = false; + if (q == g || v4 == g || v4 == q) comparisonSuccess = false; + + if (c == f) comparisonSuccess = false; + } +} diff --git a/tests/auto/qml/qqmlvaluetypeproviders/data/cppIntegration.qml b/tests/auto/qml/qqmlvaluetypeproviders/data/cppIntegration.qml new file mode 100644 index 0000000000..06756f7a18 --- /dev/null +++ b/tests/auto/qml/qqmlvaluetypeproviders/data/cppIntegration.qml @@ -0,0 +1,98 @@ +import QtQuick 2.0 +import Test 1.0 + +MyTypeObject { + property bool success: false + + // the values come from the MyTypeObject property definitions, + // which were defined in C++. + + property rect g: rectf + property point p: pointf + property size z: sizef + + property vector2d v2: vector2 + property vector3d v3: vector + property vector4d v4: vector4 + property quaternion q: quaternion + property matrix4x4 m: matrix + property color c: color + property font f: font + + Component.onCompleted: { + success = true; + + // ensure that the semantics of the properties + // defined in C++ match those of the properties + // defined in QML, and that we can compare/assign etc. + + if (g != rectf) success = false; + g = Qt.rect(1,2,3,4); + if (g == rectf) success = false; + g = rectf; + if (g != rectf) success = false; + g = rect; + if (g != rect) success = false; + g = rectf; // for the cpp-size value comparison. + + if (p != pointf) success = false; + p = Qt.point(1,2); + if (p == pointf) success = false; + p = pointf; + if (p != pointf) success = false; + p = point; + if (p != point) success = false; + p = pointf; // for the cpp-size value comparison. + + if (z != sizef) success = false; + z = Qt.size(1,2); + if (z == sizef) success = false; + z = sizef; + if (z != sizef) success = false; + z = size; + if (z != size) success = false; + z = sizef; // for the cpp-size value comparison. + + if (v2 != vector2) success = false; + v2 = Qt.vector2d(1,2); + if (v2 == vector2) success = false; + v2 = vector2; + if (v2 != vector2) success = false; + + if (v3 != vector) success = false; + v3 = Qt.vector3d(1,2,3); + if (v3 == vector) success = false; + v3 = vector; + if (v3 != vector) success = false; + + if (v4 != vector4) success = false; + v4 = Qt.vector4d(1,2,3,4); + if (v4 == vector4) success = false; + v4 = vector4; + if (v4 != vector4) success = false; + + if (q != quaternion) success = false; + q = Qt.quaternion(1,2,3,4); + if (q == quaternion) success = false; + q = quaternion; + if (q != quaternion) success = false; + + if (m != matrix) success = false; + m = Qt.matrix4x4(120, 230, 340, 450, 560, 670, 780, 890, 900, 1010, 1120, 1230, 1340, 1450, 1560, 1670); + if (m == matrix) success = false; + m = matrix; + if (m != matrix) success = false; + + if (c != color) success = false; + c = Qt.rgba(1,0,0,.5); + if (c == color) success = false; + c = color; + if (c != color) success = false; + + if (f != font) success = false; + f = Qt.font({family: "Arial", pointSize: 15, weight: Font.DemiBold, italic: false}); + if (f == font) success = false; + f = font; + if (f != font) success = false; + } +} diff --git a/tests/auto/qml/qqmlvaluetypeproviders/data/jsObjectConversion.qml b/tests/auto/qml/qqmlvaluetypeproviders/data/jsObjectConversion.qml new file mode 100644 index 0000000000..cd51b6c8cb --- /dev/null +++ b/tests/auto/qml/qqmlvaluetypeproviders/data/jsObjectConversion.qml @@ -0,0 +1,48 @@ +import QtQuick 2.0 + +QtObject { + property bool qtquickTypeSuccess: false + + // currently, only conversion from js object to font and matrix is supported. + property matrix4x4 m: Qt.matrix4x4(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16) + property matrix4x4 m2: Qt.matrix4x4([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]) + property font f: Qt.font({ family: "Arial", pointSize: 10, weight: Font.Bold, italic: true }) + property font f2: Qt.font({ family: "Arial", pointSize: 10, weight: Font.Bold, italic: true }) + + Component.onCompleted: { + qtquickTypeSuccess = true; + + // check that the initialisation worked + if (m != m2) qtquickTypeSuccess = false; + if (f != f2) qtquickTypeSuccess = false; + + // check that assignment works + m = Qt.matrix4x4(1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4) + m2 = Qt.matrix4x4([1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4]) + if (m != m2) qtquickTypeSuccess = false; + f = Qt.font({ family: "Arial", pointSize: 16, weight: Font.Black, italic: false }); + f2 = Qt.font({ family: "Arial", pointSize: 16, weight: Font.Black, italic: false }); + if (f != f2) qtquickTypeSuccess = false; + + // ensure that equality works as required. + if (m2 != Qt.matrix4x4([1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4])) qtquickTypeSucces = false; + if (f2 != Qt.font({ family: "Arial", pointSize: 16, weight: Font.Black, italic: false })) qtquickTypeSuccess = false; + + // just to ensure comparison of values from js object assigned values is consistent. + m = Qt.matrix4x4(5,5,5,5,2,2,2,2,3,3,3,3,4,4,4,4); + m2 = Qt.matrix4x4([6,6,6,6,2,2,2,2,3,3,3,3,4,4,4,4]); + if (m == m2) qtquickTypeSuccess = false; + m = Qt.matrix4x4(6,6,6,6,2,2,2,2,3,3,3,3,4,4,4,4); + if (m != m2) qtquickTypeSuccess = false; + m = Qt.matrix4x4([7,7,7,7,2,2,2,2,3,3,3,3,4,4,4,4]); + if (m == m2) qtquickTypeSuccess = false; + m = Qt.matrix4x4([6,6,6,6,2,2,2,2,3,3,3,3,4,4,4,4]); + if (m != m2) qtquickTypeSuccess = false; + + f = Qt.font({ family: "Arial", pointSize: 10, weight: Font.Bold, italic: true }); + f2 = Qt.font({ family: "Arial", pointSize: 16, weight: Font.Black, italic: false }); + if (f == f2) qtquickTypeSuccess = false; + f = Qt.font({ family: "Arial", pointSize: 16, weight: Font.Black, italic: false }); + if (f != f2) qtquickTypeSuccess = false; + } +} diff --git a/tests/auto/qml/qqmlvaluetypeproviders/data/qtqmlValueTypes.qml b/tests/auto/qml/qqmlvaluetypeproviders/data/qtqmlValueTypes.qml new file mode 100644 index 0000000000..30bc92d8af --- /dev/null +++ b/tests/auto/qml/qqmlvaluetypeproviders/data/qtqmlValueTypes.qml @@ -0,0 +1,48 @@ +import QtQml 2.0 + +QtObject { + property bool qtqmlTypeSuccess: false + property bool qtquickTypeSuccess: false + + property int i: 10 + property bool b: true + property real r: 5.5 + property string s: "Hello" + + property date d: new Date(1999, 8, 8) + + property rect g: Qt.rect(1, 2, 3, 4) + property point p: Qt.point(1, 2) + property size z: Qt.size(1, 2) + + // the following property types are valid syntax in QML + // but their valuetype implementation is provided by QtQuick. + // Thus, we can define properties of the type, but not use them. + property vector2d v2 + property vector3d v3 + property vector4d v4 + property quaternion q + property matrix4x4 m + property color c + property font f + + Component.onCompleted: { + qtqmlTypeSuccess = true; + qtquickTypeSuccess = true; + + // test that the base qtqml provided types work + if (i != 10) qtqmlTypeSuccess = false; + if (b != true) qtqmlTypeSuccess = false; + if (r != 5.5) qtqmlTypeSuccess = false; + if (s != "Hello") qtqmlTypeSuccess = false; + if (d.toDateString() != (new Date(1999,8,8)).toDateString()) qtqmlTypeSuccess = false; + if (g != Qt.rect(1, 2, 3, 4)) qtqmlTypeSuccess = false; + if (p != Qt.point(1, 2)) qtqmlTypeSuccess = false; + if (z != Qt.size(1, 2)) qtqmlTypeSuccess = false; + + // This should also work, as the base value types are provided by QtQml. + if (g.x != 1 || g.y != 2 || g.width != 3 || g.height != 4) qtqmlTypeSuccess = false; + if (p.x != 1 || p.y != 2) qtqmlTypeSuccess = false; + if (z.width != 1 || z.height != 2) qtqmlTypeSuccess = false; + } +} diff --git a/tests/auto/qml/qqmlvaluetypeproviders/data/qtquickValueTypes.qml b/tests/auto/qml/qqmlvaluetypeproviders/data/qtquickValueTypes.qml new file mode 100644 index 0000000000..f723dc3e2e --- /dev/null +++ b/tests/auto/qml/qqmlvaluetypeproviders/data/qtquickValueTypes.qml @@ -0,0 +1,119 @@ +import QtQuick 2.0 + +QtObject { + property bool qtqmlTypeSuccess: false + property bool qtquickTypeSuccess: false + + property int i: 10 + property bool b: true + property real r: 5.5 + property string s: "Hello" + + property date d: new Date(1999, 8, 8) + + property rect g: Qt.rect(1, 2, 3, 4) + property point p: Qt.point(1, 2) + property size z: Qt.size(1, 2) + + property vector2d v2: Qt.vector2d(1,2) + property vector3d v3: Qt.vector3d(1,2,3) + property vector4d v4: Qt.vector4d(1,2,3,4) + property quaternion q: Qt.quaternion(1,2,3,4) + property matrix4x4 m: Qt.matrix4x4(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16) + property color c: "red" + property color c2: "red" + property font f: Qt.font({ family: "Arial", pointSize: 20 }) + + // ensure that group property specification works as expected. + property font f2 + f2.family: "Arial" + f2.pointSize: 45 + f2.italic: true + v22.x: 5 + v22.y: 10 + property vector2d v22 + property font f3 // note: cannot specify grouped subproperties inline with property declaration :-/ + f3 { + family: "Arial" + pointSize: 45 + italic: true + } + + Component.onCompleted: { + qtqmlTypeSuccess = true; + qtquickTypeSuccess = true; + + // check base types still work even though we imported QtQuick + if (i != 10) qtqmlTypeSuccess = false; + if (b != true) qtqmlTypeSuccess = false; + if (r != 5.5) qtqmlTypeSuccess = false; + if (s != "Hello") qtqmlTypeSuccess = false; + if (d.toDateString() != (new Date(1999,8,8)).toDateString()) qtqmlTypeSuccess = false; + + // check language-provided value types still work. + if (g != Qt.rect(1, 2, 3, 4)) qtqmlTypeSuccess = false; + if (g.x != 1 || g.y != 2 || g.width != 3 || g.height != 4) qtqmlTypeSuccess = false; + if (p != Qt.point(1, 2)) qtqmlTypeSuccess = false; + if (p.x != 1 || p.y != 2) qtqmlTypeSuccess = false; + if (z != Qt.size(1, 2)) qtqmlTypeSuccess = false; + if (z.width != 1 || z.height != 2) qtqmlTypeSuccess = false; + + // Check that the value type provider for vector3d and other non-QtQml value-types is provided by QtQuick. + if (v2.x != 1 || v2.y != 2) qtquickTypeSuccess = false; + if (v2 != Qt.vector2d(1,2)) qtquickTypeSuccess = false; + if (v3.x != 1 || v3.y != 2 || v3.z != 3) qtquickTypeSuccess = false; + if (v3 != Qt.vector3d(1,2,3)) qtquickTypeSuccess = false; + if (v4.x != 1 || v4.y != 2 || v4.z != 3 || v4.w != 4) qtquickTypeSuccess = false; + if (v4 != Qt.vector4d(1,2,3,4)) qtquickTypeSuccess = false; + if (q.scalar != 1 || q.x != 2 || q.y != 3 || q.z != 4) qtquickTypeSuccess = false; + if (q != Qt.quaternion(1,2,3,4)) qtquickTypeSuccess = false; + if (m != Qt.matrix4x4(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16)) qtquickTypeSuccess = false; + if (c != Qt.rgba(1,0,0,1)) qtquickTypeSuccess = false; + if (c != c2) qtquickTypeSuccess = false; // can compare two colors directly. + if (f.family != "Arial" || f.pointSize != 20) qtquickTypeSuccess = false; + if (f != Qt.font({ family: "Arial", pointSize: 20 })) qtquickTypeSuccess = false; + if (f2.family != "Arial" || f2.pointSize != 45 || f2.italic != true) qtquickTypeSuccess = false; + if (f2 != f3) qtquickTypeSuccess = false; + if (v22.x != 5 || v22.y != 10) qtquickTypeSuccess = false; + + // font has some optional parameters. + var defaultFont = Qt.font({ family: "Arial", pointSize: 22 }); // normal should be default weight. + var lightFont = Qt.font({ family: "Arial", pointSize: 22, weight: Font.Light }); + var normalFont = Qt.font({ family: "Arial", pointSize: 22, weight: Font.Normal }); + var demiboldFont = Qt.font({ family: "Arial", pointSize: 22, weight: Font.DemiBold }); + var boldFont = Qt.font({ family: "Arial", pointSize: 22, weight: Font.Bold }); + var blackFont = Qt.font({ family: "Arial", pointSize: 22, weight: Font.Black }); + + f = Qt.font({ family: "Arial", pointSize: 22, weight: Font.Light }); + if (f.family != "Arial" || f.pointSize != 22 || f.weight != lightFont.weight || f.weight == normalFont.weight) qtquickTypeSuccess = false; + f = Qt.font({ family: "Arial", pointSize: 22, weight: Font.Normal, italic: true }); + if (f.family != "Arial" || f.pointSize != 22 || f.weight != normalFont.weight || f.italic != true) qtquickTypeSuccess = false; + f = Qt.font({ family: "Arial", pointSize: 22, weight: Font.DemiBold, italic: false }); + if (f.family != "Arial" || f.pointSize != 22 || f.weight != demiboldFont.weight || f.italic != false) qtquickTypeSuccess = false; + f = Qt.font({ family: "Arial", pointSize: 22, weight: Font.Bold }); // italic should be false by default + if (f.family != "Arial" || f.pointSize != 22 || f.weight != boldFont.weight || f.italic != false) qtquickTypeSuccess = false; + f = Qt.font({ family: "Arial", pointSize: 22, weight: Font.Black }); // italic should be false by default + if (f.family != "Arial" || f.pointSize != 22 || f.weight != blackFont.weight || f.italic != false) qtquickTypeSuccess = false; + + // Check the string conversion codepaths. + v2 = "5,6"; + if (v2 != Qt.vector2d(5,6)) qtquickTypeSuccess = false; + if (v2.toString() != "QVector2D(5, 6)") qtquickTypeSuccess = false; + v3 = "5,6,7"; + if (v3 != Qt.vector3d(5,6,7)) qtquickTypeSuccess = false; + if (v3.toString() != "QVector3D(5, 6, 7)") qtquickTypeSuccess = false; + v4 = "5,6,7,8"; + if (v4 != Qt.vector4d(5,6,7,8)) qtquickTypeSuccess = false; + if (v4.toString() != "QVector4D(5, 6, 7, 8)") qtquickTypeSuccess = false; + q = "5,6,7,8"; + if (q != Qt.quaternion(5,6,7,8)) qtquickTypeSuccess = false; + if (q.toString() != "QQuaternion(5, 6, 7, 8)") qtquickTypeSuccess = false; + m = "4,4,4,4,5,5,5,5,6,6,6,6,7,7,7,7"; + if (m != Qt.matrix4x4(4,4,4,4,5,5,5,5,6,6,6,6,7,7,7,7)) qtquickTypeSuccess = false; + if (m.toString() != "QMatrix4x4(4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7)") qtquickTypeSuccess = false; + c = "blue"; + if (c.toString() != Qt.rgba(0,0,1,0).toString()) qtquickTypeSuccess = false; + if (c.toString() != "#0000FF" && c.toString() != "#0000ff") qtquickTypeSuccess = false; // color string converter is special + // no string converter for fonts. + } +} diff --git a/tests/auto/qml/qqmlvaluetypeproviders/qqmlvaluetypeproviders.pro b/tests/auto/qml/qqmlvaluetypeproviders/qqmlvaluetypeproviders.pro new file mode 100644 index 0000000000..fb670606e2 --- /dev/null +++ b/tests/auto/qml/qqmlvaluetypeproviders/qqmlvaluetypeproviders.pro @@ -0,0 +1,16 @@ +CONFIG += testcase +TARGET = tst_qqmlvaluetypeproviders +macx:CONFIG -= app_bundle + +HEADERS += testtypes.h + +SOURCES += tst_qqmlvaluetypeproviders.cpp \ + testtypes.cpp + +include (../../shared/util.pri) + +TESTDATA = data/* + +CONFIG += parallel_test + +QT += core-private gui-private v8-private qml-private quick-private gui testlib diff --git a/tests/auto/qml/qqmlvaluetypeproviders/testtypes.cpp b/tests/auto/qml/qqmlvaluetypeproviders/testtypes.cpp new file mode 100644 index 0000000000..c70179744c --- /dev/null +++ b/tests/auto/qml/qqmlvaluetypeproviders/testtypes.cpp @@ -0,0 +1,46 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include "testtypes.h" + +void registerTypes() +{ + qmlRegisterType("Test", 1, 0, "MyTypeObject"); +} diff --git a/tests/auto/qml/qqmlvaluetypeproviders/testtypes.h b/tests/auto/qml/qqmlvaluetypeproviders/testtypes.h new file mode 100644 index 0000000000..bdd5ce656b --- /dev/null +++ b/tests/auto/qml/qqmlvaluetypeproviders/testtypes.h @@ -0,0 +1,195 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#ifndef TESTTYPES_H +#define TESTTYPES_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +class MyTypeObject : public QObject +{ + Q_OBJECT + + Q_PROPERTY(QPoint point READ point WRITE setPoint NOTIFY changed) + Q_PROPERTY(QPointF pointf READ pointf WRITE setPointf NOTIFY changed) + Q_PROPERTY(QPointF pointfpoint READ pointfpoint WRITE setPointfpoint NOTIFY changed) + Q_PROPERTY(QSize size READ size WRITE setSize NOTIFY changed) + Q_PROPERTY(QSizeF sizef READ sizef WRITE setSizef NOTIFY changed) + Q_PROPERTY(QSizeF sizefsize READ sizefsize WRITE setSizefsize NOTIFY changed) + Q_PROPERTY(QSize sizereadonly READ size NOTIFY changed) + Q_PROPERTY(QRect rect READ rect WRITE setRect NOTIFY changed) + Q_PROPERTY(QRectF rectf READ rectf WRITE setRectf NOTIFY changed) + Q_PROPERTY(QRectF rectfrect READ rectfrect WRITE setRectfrect NOTIFY changed) + Q_PROPERTY(QVector2D vector2 READ vector2 WRITE setVector2 NOTIFY changed) + Q_PROPERTY(QVector3D vector READ vector WRITE setVector NOTIFY changed) + Q_PROPERTY(QVector4D vector4 READ vector4 WRITE setVector4 NOTIFY changed) + Q_PROPERTY(QQuaternion quaternion READ quaternion WRITE setQuaternion NOTIFY changed) + Q_PROPERTY(QMatrix4x4 matrix READ matrix WRITE setMatrix NOTIFY changed) + Q_PROPERTY(QFont font READ font WRITE setFont NOTIFY changed) + Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY changed) + Q_PROPERTY(QVariant variant READ variant NOTIFY changed) + +public: + MyTypeObject() : + m_point(10, 4), + m_pointf(11.3, -10.9), + m_pointfpoint(10.0, 4.0), + m_size(1912, 1913), + m_sizef(0.1, 100923.2), + m_sizefsize(1912.0, 1913.0), + m_rect(2, 3, 109, 102), + m_rectf(103.8, 99.2, 88.1, 77.6), + m_rectfrect(2.0, 3.0, 109.0, 102.0), + m_vector2(32.88, 1.3), + m_vector(23.88, 3.1, 4.3), + m_vector4(54.2, 23.88, 3.1, 4.3), + m_quaternion(4.3, 54.2, 23.88, 3.1), + m_matrix(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16) + { + m_font.setFamily("Arial"); + m_font.setBold(true); + m_font.setWeight(QFont::DemiBold); + m_font.setItalic(true); + m_font.setUnderline(true); + m_font.setOverline(true); + m_font.setStrikeOut(true); + m_font.setPointSize(29); + m_font.setCapitalization(QFont::AllLowercase); + m_font.setLetterSpacing(QFont::AbsoluteSpacing, 10.2); + m_font.setWordSpacing(19.7); + m_color.setRedF(0.2); + m_color.setGreenF(0.88); + m_color.setBlueF(0.6); + m_color.setAlphaF(0.34); + } + + QPoint m_point; + QPoint point() const { return m_point; } + void setPoint(const QPoint &v) { m_point = v; emit changed(); } + + QPointF m_pointf; + QPointF pointf() const { return m_pointf; } + void setPointf(const QPointF &v) { m_pointf = v; emit changed(); } + + QPointF m_pointfpoint; + QPointF pointfpoint() const { return m_pointfpoint; } + void setPointfpoint(const QPointF &v) { m_pointfpoint = v; emit changed(); } + + QSize m_size; + QSize size() const { return m_size; } + void setSize(const QSize &v) { m_size = v; emit changed(); } + + QSizeF m_sizef; + QSizeF sizef() const { return m_sizef; } + void setSizef(const QSizeF &v) { m_sizef = v; emit changed(); } + + QSizeF m_sizefsize; + QSizeF sizefsize() const { return m_sizefsize; } + void setSizefsize(const QSizeF &v) { m_sizefsize = v; emit changed(); } + + QRect m_rect; + QRect rect() const { return m_rect; } + void setRect(const QRect &v) { m_rect = v; emit changed(); } + + QRectF m_rectf; + QRectF rectf() const { return m_rectf; } + void setRectf(const QRectF &v) { m_rectf = v; emit changed(); } + + QRectF m_rectfrect; + QRectF rectfrect() const { return m_rectfrect; } + void setRectfrect(const QRectF &v) { m_rectfrect = v; emit changed(); } + + QVector2D m_vector2; + QVector2D vector2() const { return m_vector2; } + void setVector2(const QVector2D &v) { m_vector2 = v; emit changed(); } + + QVector3D m_vector; + QVector3D vector() const { return m_vector; } + void setVector(const QVector3D &v) { m_vector = v; emit changed(); } + + QVector4D m_vector4; + QVector4D vector4() const { return m_vector4; } + void setVector4(const QVector4D &v) { m_vector4 = v; emit changed(); } + + QQuaternion m_quaternion; + QQuaternion quaternion() const { return m_quaternion; } + void setQuaternion(const QQuaternion &v) { m_quaternion = v; emit changed(); } + + QMatrix4x4 m_matrix; + QMatrix4x4 matrix() const { return m_matrix; } + void setMatrix(const QMatrix4x4 &v) { m_matrix = v; emit changed(); } + + QFont m_font; + QFont font() const { return m_font; } + void setFont(const QFont &v) { m_font = v; emit changed(); } + + QColor m_color; + QColor color() const { return m_color; } + void setColor(const QColor &v) { m_color = v; emit changed(); } + + QVariant variant() const { return sizef(); } + + void emitRunScript() { emit runScript(); } + +signals: + void changed(); + void runScript(); + +public slots: + QSize method() { return QSize(13, 14); } +}; + +void registerTypes(); + +#endif // TESTTYPES_H diff --git a/tests/auto/qml/qqmlvaluetypeproviders/tst_qqmlvaluetypeproviders.cpp b/tests/auto/qml/qqmlvaluetypeproviders/tst_qqmlvaluetypeproviders.cpp new file mode 100644 index 0000000000..d811767489 --- /dev/null +++ b/tests/auto/qml/qqmlvaluetypeproviders/tst_qqmlvaluetypeproviders.cpp @@ -0,0 +1,173 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include +#include +#include +#include +#include "../../shared/util.h" +#include "testtypes.h" + +QT_BEGIN_NAMESPACE +extern int qt_defaultDpi(void); +QT_END_NAMESPACE + +// There is some overlap between the qqmllanguage and qqmlvaluetypes +// test here, but it needs to be separate to ensure that no QML plugins +// are loaded prior to these tests, which could contaminate the type +// system with more providers. + +class tst_qqmlvaluetypeproviders : public QQmlDataTest +{ + Q_OBJECT +public: + tst_qqmlvaluetypeproviders() {} + +private slots: + void initTestCase(); + + void qtqmlValueTypes(); // This test function _must_ be the first test function run. + void qtquickValueTypes(); + void comparisonSemantics(); + void cppIntegration(); + void jsObjectConversion(); +}; + +void tst_qqmlvaluetypeproviders::initTestCase() +{ + QQmlDataTest::initTestCase(); + registerTypes(); +} + +void tst_qqmlvaluetypeproviders::qtqmlValueTypes() +{ + QQmlEngine e; + QQmlComponent component(&e, testFileUrl("qtqmlValueTypes.qml")); + QVERIFY(!component.isError()); + QVERIFY(component.errors().isEmpty()); + QObject *object = component.create(); + QVERIFY(object != 0); + QVERIFY(object->property("qtqmlTypeSuccess").toBool()); + QVERIFY(object->property("qtquickTypeSuccess").toBool()); + delete object; +} + +void tst_qqmlvaluetypeproviders::qtquickValueTypes() +{ + QQmlEngine e; + QQmlComponent component(&e, testFileUrl("qtquickValueTypes.qml")); + QVERIFY(!component.isError()); + QVERIFY(component.errors().isEmpty()); + QObject *object = component.create(); + QVERIFY(object != 0); + QVERIFY(object->property("qtqmlTypeSuccess").toBool()); + QVERIFY(object->property("qtquickTypeSuccess").toBool()); + delete object; +} + +void tst_qqmlvaluetypeproviders::comparisonSemantics() +{ + QQmlEngine e; + QQmlComponent component(&e, testFileUrl("comparisonSemantics.qml")); + QVERIFY(!component.isError()); + QVERIFY(component.errors().isEmpty()); + QObject *object = component.create(); + QVERIFY(object != 0); + QVERIFY(object->property("comparisonSuccess").toBool()); + delete object; +} + +void tst_qqmlvaluetypeproviders::cppIntegration() +{ + QQmlEngine e; + QQmlComponent component(&e, testFileUrl("cppIntegration.qml")); + QVERIFY(!component.isError()); + QVERIFY(component.errors().isEmpty()); + QObject *object = component.create(); + QVERIFY(object != 0); + + // ensure accessing / comparing / assigning cpp-defined props + // and qml-defined props works in QML. + QVERIFY(object->property("success").toBool()); + + // ensure types match + QCOMPARE(object->property("g").userType(), object->property("rectf").userType()); + QCOMPARE(object->property("p").userType(), object->property("pointf").userType()); + QCOMPARE(object->property("z").userType(), object->property("sizef").userType()); + QCOMPARE(object->property("v2").userType(), object->property("vector2").userType()); + QCOMPARE(object->property("v3").userType(), object->property("vector").userType()); + QCOMPARE(object->property("v4").userType(), object->property("vector4").userType()); + QCOMPARE(object->property("q").userType(), object->property("quaternion").userType()); + QCOMPARE(object->property("m").userType(), object->property("matrix").userType()); + QCOMPARE(object->property("c").userType(), object->property("color").userType()); + QCOMPARE(object->property("f").userType(), object->property("font").userType()); + + // ensure values match + QCOMPARE(object->property("g").value(), object->property("rectf").value()); + QCOMPARE(object->property("p").value(), object->property("pointf").value()); + QCOMPARE(object->property("z").value(), object->property("sizef").value()); + QCOMPARE(object->property("v2").value(), object->property("vector2").value()); + QCOMPARE(object->property("v3").value(), object->property("vector").value()); + QCOMPARE(object->property("v4").value(), object->property("vector4").value()); + QCOMPARE(object->property("q").value(), object->property("quaternion").value()); + QCOMPARE(object->property("m").value(), object->property("matrix").value()); + QCOMPARE(object->property("c").value(), object->property("color").value()); + QCOMPARE(object->property("f").value(), object->property("font").value()); + + delete object; +} + +void tst_qqmlvaluetypeproviders::jsObjectConversion() +{ + QQmlEngine e; + QQmlComponent component(&e, testFileUrl("jsObjectConversion.qml")); + QVERIFY(!component.isError()); + QVERIFY(component.errors().isEmpty()); + QObject *object = component.create(); + QVERIFY(object != 0); + QVERIFY(object->property("qtquickTypeSuccess").toBool()); + delete object; +} + +QTEST_MAIN(tst_qqmlvaluetypeproviders) + +#include "tst_qqmlvaluetypeproviders.moc" -- cgit v1.2.3