diff options
47 files changed, 817 insertions, 121 deletions
diff --git a/examples/qml/tutorials/extending-qml/chapter4-customPropertyTypes/piechart.cpp b/examples/qml/tutorials/extending-qml/chapter4-customPropertyTypes/piechart.cpp index 965e5152c1..d963b6d1b4 100644 --- a/examples/qml/tutorials/extending-qml/chapter4-customPropertyTypes/piechart.cpp +++ b/examples/qml/tutorials/extending-qml/chapter4-customPropertyTypes/piechart.cpp @@ -41,7 +41,7 @@ #include "pieslice.h" PieChart::PieChart(QQuickItem *parent) - : QQuickItem(parent) + : QQuickItem(parent), m_pieSlice(0) { } diff --git a/examples/qml/tutorials/extending-qml/chapter5-listproperties/pieslice.cpp b/examples/qml/tutorials/extending-qml/chapter5-listproperties/pieslice.cpp index ceb0041ec8..50c018e33e 100644 --- a/examples/qml/tutorials/extending-qml/chapter5-listproperties/pieslice.cpp +++ b/examples/qml/tutorials/extending-qml/chapter5-listproperties/pieslice.cpp @@ -42,7 +42,7 @@ #include <QPainter> PieSlice::PieSlice(QQuickItem *parent) - : QQuickPaintedItem(parent) + : QQuickPaintedItem(parent), m_fromAngle(0), m_angleSpan(0) { } diff --git a/examples/quick/demos/demos.pro b/examples/quick/demos/demos.pro index 9aac7bf6f7..e6937683ab 100644 --- a/examples/quick/demos/demos.pro +++ b/examples/quick/demos/demos.pro @@ -5,9 +5,8 @@ SUBDIRS = samegame \ tweetsearch \ maroon \ photosurface \ + photoviewer \ stocqt qtHaveModule(xmlpatterns): SUBDIRS += rssnews -EXAMPLE_FILES = \ - photoviewer diff --git a/examples/quick/demos/photoviewer/deployment.pri b/examples/quick/demos/photoviewer/deployment.pri deleted file mode 100644 index 0d58a25c61..0000000000 --- a/examples/quick/demos/photoviewer/deployment.pri +++ /dev/null @@ -1,19 +0,0 @@ -android { - x86 { - target.path = /libs/x86 - } else: armeabi-v7a { - target.path = /libs/armeabi-v7a - } else { - target.path = /libs/armeabi - } - export(target.path) - INSTALLS += target -} else:unix { - isEmpty(target.path) { - target.path = /opt/$${TARGET}/bin - export(target.path) - } - INSTALLS += target -} - -export(INSTALLS) diff --git a/examples/quick/demos/photoviewer/photoviewer.pro b/examples/quick/demos/photoviewer/photoviewer.pro index 704e2ce003..4bfdb86f31 100644 --- a/examples/quick/demos/photoviewer/photoviewer.pro +++ b/examples/quick/demos/photoviewer/photoviewer.pro @@ -15,8 +15,5 @@ TRANSLATIONS += i18n/qml_fr.ts \ RESOURCES += qml.qrc -# Additional import path used to resolve QML modules in Qt Creator's code model -QML_IMPORT_PATH = - -# Default rules for deployment. -include(deployment.pri) +target.path = $$[QT_INSTALL_EXAMPLES]/quick/demos/photoviewer +INSTALLS += target diff --git a/examples/quick/scenegraph/simplematerial/doc/src/simplematerial.qdoc b/examples/quick/scenegraph/simplematerial/doc/src/simplematerial.qdoc index 278f154781..d6eb711929 100644 --- a/examples/quick/scenegraph/simplematerial/doc/src/simplematerial.qdoc +++ b/examples/quick/scenegraph/simplematerial/doc/src/simplematerial.qdoc @@ -102,8 +102,8 @@ state and we use it to update the shader program with the current color. The previous state is passed in as a second parameter so that the user can update only that which has changed. In our - usecase, where all the colors are different, the updateState will - be called once for every node. + use case, where all the colors are different, the updateState() + function will be called once for every node. \snippet scenegraph/simplematerial/simplematerial.cpp 7 diff --git a/src/imports/localstorage/plugin.cpp b/src/imports/localstorage/plugin.cpp index 7d96f11768..f59ccc551e 100644 --- a/src/imports/localstorage/plugin.cpp +++ b/src/imports/localstorage/plugin.cpp @@ -149,7 +149,12 @@ public: using namespace QV4; +QT_WARNING_PUSH +#if (Q_CC_GNU >= 600) +QT_WARNING_DISABLE_GCC("-Wtautological-compare") +#endif DEFINE_OBJECT_VTABLE(QV4::QQmlSqlDatabaseWrapper); +QT_WARNING_POP diff --git a/src/qml/compiler/qqmlpropertyvalidator.cpp b/src/qml/compiler/qqmlpropertyvalidator.cpp index 9ea52e240d..c644330e97 100644 --- a/src/qml/compiler/qqmlpropertyvalidator.cpp +++ b/src/qml/compiler/qqmlpropertyvalidator.cpp @@ -492,6 +492,16 @@ QQmlCompileError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache } } break; + case QVariant::Vector2D: { + struct { + float xp; + float yp; + } vec; + if (!QQmlStringConverters::createFromString(QMetaType::QVector2D, binding->valueAsString(qmlUnit), &vec, sizeof(vec))) { + return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: 2D vector expected")); + } + } + break; case QVariant::Vector3D: { struct { float xp; @@ -515,6 +525,18 @@ QQmlCompileError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache } } break; + case QVariant::Quaternion: { + struct { + float wp; + float xp; + float yp; + float zp; + } vec; + if (!QQmlStringConverters::createFromString(QMetaType::QQuaternion, binding->valueAsString(qmlUnit), &vec, sizeof(vec))) { + return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: quaternion expected")); + } + } + break; case QVariant::RegExp: return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: regular expression expected; use /pattern/ syntax")); default: { diff --git a/src/qml/compiler/qv4codegen.cpp b/src/qml/compiler/qv4codegen.cpp index 7a444e8c57..4130ad08d7 100644 --- a/src/qml/compiler/qv4codegen.cpp +++ b/src/qml/compiler/qv4codegen.cpp @@ -1058,6 +1058,8 @@ bool Codegen::visit(ArrayLiteral *ast) current->expr = _block->CONST(IR::MissingType, 0); } Result expr = expression(it->expression); + if (hasError) + return false; IR::ExprList *arg = _function->New<IR::ExprList>(); if (!current) { @@ -1100,6 +1102,8 @@ bool Codegen::visit(ArrayMemberExpression *ast) Result base = expression(ast->base); Result index = expression(ast->expression); + if (hasError) + return false; _expr.code = subscript(*base, *index); return false; } @@ -1139,10 +1143,16 @@ bool Codegen::visit(BinaryExpression *ast) const unsigned r = _block->newTemp(); - move(_block->TEMP(r), *expression(ast->left)); + Result lhs = expression(ast->left); + if (hasError) + return false; + move(_block->TEMP(r), *lhs); setLocation(cjump(_block->TEMP(r), iftrue, endif), ast->operatorToken); _block = iftrue; - move(_block->TEMP(r), *expression(ast->right)); + Result rhs = expression(ast->right); + if (hasError) + return false; + move(_block->TEMP(r), *rhs); _block->JUMP(endif); _expr.code = _block->TEMP(r); @@ -1160,10 +1170,16 @@ bool Codegen::visit(BinaryExpression *ast) IR::BasicBlock *endif = _function->newBasicBlock(exceptionHandler()); const unsigned r = _block->newTemp(); - move(_block->TEMP(r), *expression(ast->left)); + Result lhs = expression(ast->left); + if (hasError) + return false; + move(_block->TEMP(r), *lhs); setLocation(cjump(_block->TEMP(r), endif, iffalse), ast->operatorToken); _block = iffalse; - move(_block->TEMP(r), *expression(ast->right)); + Result rhs = expression(ast->right); + if (hasError) + return false; + move(_block->TEMP(r), *rhs); _block->JUMP(endif); _block = endif; @@ -1173,6 +1189,8 @@ bool Codegen::visit(BinaryExpression *ast) } IR::Expr* left = *expression(ast->left); + if (hasError) + return false; switch (ast->op) { case QSOperator::Or: @@ -1182,17 +1200,19 @@ bool Codegen::visit(BinaryExpression *ast) case QSOperator::Assign: { if (throwSyntaxErrorOnEvalOrArgumentsInStrictMode(left, ast->left->lastSourceLocation())) return false; - IR::Expr* right = *expression(ast->right); + Result right = expression(ast->right); + if (hasError) + return false; if (!left->isLValue()) { throwReferenceError(ast->operatorToken, QStringLiteral("left-hand side of assignment operator is not an lvalue")); return false; } if (_expr.accept(nx)) { - move(left, right); + move(left, *right); } else { const unsigned t = _block->newTemp(); - move(_block->TEMP(t), right); + move(_block->TEMP(t), *right); move(left, _block->TEMP(t)); _expr.code = _block->TEMP(t); } @@ -1212,17 +1232,19 @@ bool Codegen::visit(BinaryExpression *ast) case QSOperator::InplaceXor: { if (throwSyntaxErrorOnEvalOrArgumentsInStrictMode(left, ast->left->lastSourceLocation())) return false; - IR::Expr* right = *expression(ast->right); + Result right = expression(ast->right); + if (hasError) + return false; if (!left->isLValue()) { throwSyntaxError(ast->operatorToken, QStringLiteral("left-hand side of inplace operator is not an lvalue")); return false; } if (_expr.accept(nx)) { - move(left, right, baseOp(ast->op)); + move(left, *right, baseOp(ast->op)); } else { const unsigned t = _block->newTemp(); - move(_block->TEMP(t), right); + move(_block->TEMP(t), *right); move(left, _block->TEMP(t), baseOp(ast->op)); _expr.code = left; } @@ -1245,12 +1267,14 @@ bool Codegen::visit(BinaryExpression *ast) left = _block->TEMP(t); } - IR::Expr* right = *expression(ast->right); + Result right = expression(ast->right); + if (hasError) + return false; if (_expr.accept(cx)) { - setLocation(cjump(binop(IR::binaryOperator(ast->op), left, right, ast->operatorToken), _expr.iftrue, _expr.iffalse), ast->operatorToken); + setLocation(cjump(binop(IR::binaryOperator(ast->op), left, *right, ast->operatorToken), _expr.iftrue, _expr.iffalse), ast->operatorToken); } else { - IR::Expr *e = binop(IR::binaryOperator(ast->op), left, right, ast->operatorToken); + IR::Expr *e = binop(IR::binaryOperator(ast->op), left, *right, ast->operatorToken); if (e->asConst() || e->asString()) _expr.code = e; else { @@ -1279,9 +1303,11 @@ bool Codegen::visit(BinaryExpression *ast) left = _block->TEMP(t); } - IR::Expr* right = *expression(ast->right); + Result right = expression(ast->right); + if (hasError) + return false; - IR::Expr *e = binop(IR::binaryOperator(ast->op), left, right, ast->operatorToken); + IR::Expr *e = binop(IR::binaryOperator(ast->op), left, *right, ast->operatorToken); if (e->asConst() || e->asString()) _expr.code = e; else { @@ -1306,11 +1332,15 @@ bool Codegen::visit(CallExpression *ast) IR::ExprList *args = 0, **args_it = &args; for (ArgumentList *it = ast->arguments; it; it = it->next) { Result arg = expression(it->expression); + if (hasError) + return false; IR::Expr *actual = argument(*arg); *args_it = _function->New<IR::ExprList>(); (*args_it)->init(actual); args_it = &(*args_it)->next; } + if (hasError) + return false; _expr.code = call(*base, args); return false; } @@ -1329,11 +1359,17 @@ bool Codegen::visit(ConditionalExpression *ast) condition(ast->expression, iftrue, iffalse); _block = iftrue; - move(_block->TEMP(t), *expression(ast->ok)); + Result ok = expression(ast->ok); + if (hasError) + return false; + move(_block->TEMP(t), *ok); _block->JUMP(endif); _block = iffalse; - move(_block->TEMP(t), *expression(ast->ko)); + Result ko = expression(ast->ko); + if (hasError) + return false; + move(_block->TEMP(t), *ko); _block->JUMP(endif); _block = endif; @@ -1349,6 +1385,8 @@ bool Codegen::visit(DeleteExpression *ast) return false; IR::Expr* expr = *expression(ast->expression); + if (hasError) + return false; // Temporaries cannot be deleted IR::ArgLocal *al = expr->asArgLocal(); if (al && al->index < static_cast<unsigned>(_env->members.size())) { @@ -1410,7 +1448,8 @@ bool Codegen::visit(FieldMemberExpression *ast) return false; Result base = expression(ast->base); - _expr.code = member(*base, _function->newString(ast->name.toString())); + if (!hasError) + _expr.code = member(*base, _function->newString(ast->name.toString())); return false; } @@ -1501,6 +1540,8 @@ bool Codegen::visit(NewExpression *ast) return false; Result base = expression(ast->expression); + if (hasError) + return false; IR::Expr *expr = *base; if (expr && !expr->asTemp() && !expr->asArgLocal() && !expr->asName() && !expr->asMember()) { const unsigned t = _block->newTemp(); @@ -1517,6 +1558,8 @@ bool Codegen::visit(NewMemberExpression *ast) return false; Result base = expression(ast->base); + if (hasError) + return false; IR::Expr *expr = *base; if (expr && !expr->asTemp() && !expr->asArgLocal() && !expr->asName() && !expr->asMember()) { const unsigned t = _block->newTemp(); @@ -1527,6 +1570,8 @@ bool Codegen::visit(NewMemberExpression *ast) IR::ExprList *args = 0, **args_it = &args; for (ArgumentList *it = ast->arguments; it; it = it->next) { Result arg = expression(it->expression); + if (hasError) + return false; IR::Expr *actual = argument(*arg); *args_it = _function->New<IR::ExprList>(); (*args_it)->init(actual); @@ -1544,6 +1589,8 @@ bool Codegen::visit(NotExpression *ast) return false; Result expr = expression(ast->expression); + if (hasError) + return false; const unsigned r = _block->newTemp(); setLocation(move(_block->TEMP(r), unop(IR::OpNot, *expr, ast->notToken)), ast->notToken); _expr.code = _block->TEMP(r); @@ -1601,6 +1648,8 @@ bool Codegen::visit(ObjectLiteral *ast) QString name = it->assignment->name->asString(); if (PropertyNameAndValue *nv = AST::cast<AST::PropertyNameAndValue *>(it->assignment)) { Result value = expression(nv->value); + if (hasError) + return false; ObjectPropertyValue &v = valueMap[name]; if (v.hasGetter() || v.hasSetter() || (_function->isStrict && v.value)) { throwSyntaxError(nv->lastSourceLocation(), @@ -1731,6 +1780,8 @@ bool Codegen::visit(PostDecrementExpression *ast) return false; Result expr = expression(ast->base); + if (hasError) + return false; if (!expr->isLValue()) { throwReferenceError(ast->base->lastSourceLocation(), QStringLiteral("Invalid left-hand side expression in postfix operation")); return false; @@ -1757,6 +1808,8 @@ bool Codegen::visit(PostIncrementExpression *ast) return false; Result expr = expression(ast->base); + if (hasError) + return false; if (!expr->isLValue()) { throwReferenceError(ast->base->lastSourceLocation(), QStringLiteral("Invalid left-hand side expression in postfix operation")); return false; @@ -1783,6 +1836,8 @@ bool Codegen::visit(PreDecrementExpression *ast) return false; Result expr = expression(ast->expression); + if (hasError) + return false; if (!expr->isLValue()) { throwReferenceError(ast->expression->lastSourceLocation(), QStringLiteral("Prefix ++ operator applied to value that is not a reference.")); return false; @@ -1808,6 +1863,8 @@ bool Codegen::visit(PreIncrementExpression *ast) return false; Result expr = expression(ast->expression); + if (hasError) + return false; if (!expr->isLValue()) { throwReferenceError(ast->expression->lastSourceLocation(), QStringLiteral("Prefix ++ operator applied to value that is not a reference.")); return false; @@ -1860,6 +1917,8 @@ bool Codegen::visit(TildeExpression *ast) return false; Result expr = expression(ast->expression); + if (hasError) + return false; const unsigned t = _block->newTemp(); setLocation(move(_block->TEMP(t), unop(IR::OpCompl, *expr, ast->tildeToken)), ast->tildeToken); _expr.code = _block->TEMP(t); @@ -1885,6 +1944,8 @@ bool Codegen::visit(TypeOfExpression *ast) return false; Result expr = expression(ast->expression); + if (hasError) + return false; IR::ExprList *args = _function->New<IR::ExprList>(); args->init(reference(*expr)); _expr.code = call(_block->NAME(IR::Name::builtin_typeof, ast->typeofToken.startLine, ast->typeofToken.startColumn), args); @@ -1897,6 +1958,8 @@ bool Codegen::visit(UnaryMinusExpression *ast) return false; Result expr = expression(ast->expression); + if (hasError) + return false; const unsigned t = _block->newTemp(); setLocation(move(_block->TEMP(t), unop(IR::OpUMinus, *expr, ast->minusToken)), ast->minusToken); _expr.code = _block->TEMP(t); @@ -1909,6 +1972,8 @@ bool Codegen::visit(UnaryPlusExpression *ast) return false; Result expr = expression(ast->expression); + if (hasError) + return false; const unsigned t = _block->newTemp(); setLocation(move(_block->TEMP(t), unop(IR::OpUPlus, *expr, ast->plusToken)), ast->plusToken); _expr.code = _block->TEMP(t); @@ -2224,7 +2289,10 @@ bool Codegen::visit(ForEachStatement *ast) IR::BasicBlock *foreachend = _function->newBasicBlock(exceptionHandler()); int objectToIterateOn = _block->newTemp(); - move(_block->TEMP(objectToIterateOn), *expression(ast->expression)); + Result expr = expression(ast->expression); + if (hasError) + return false; + move(_block->TEMP(objectToIterateOn), *expr); IR::ExprList *args = _function->New<IR::ExprList>(); args->init(_block->TEMP(objectToIterateOn)); @@ -2236,7 +2304,10 @@ bool Codegen::visit(ForEachStatement *ast) _block = foreachbody; int temp = _block->newTemp(); - move(*expression(ast->initialiser), _block->TEMP(temp)); + Result init = expression(ast->initialiser); + if (hasError) + return false; + move(*init, _block->TEMP(temp)); statement(ast->statement); _block->JUMP(foreachin); @@ -2726,7 +2797,10 @@ bool Codegen::visit(WithStatement *ast) _function->hasWith = true; const int withObject = _block->newTemp(); - _block->MOVE(_block->TEMP(withObject), *expression(ast->expression)); + Result src = expression(ast->expression); + if (hasError) + return false; + _block->MOVE(_block->TEMP(withObject), *src); // need an exception handler for with to cleanup the with scope IR::BasicBlock *withExceptionHandler = _function->newBasicBlock(exceptionHandler()); diff --git a/src/qml/doc/src/cppintegration/data.qdoc b/src/qml/doc/src/cppintegration/data.qdoc index 0d875bd10f..7bb4d701e2 100644 --- a/src/qml/doc/src/cppintegration/data.qdoc +++ b/src/qml/doc/src/cppintegration/data.qdoc @@ -381,6 +381,8 @@ Message { } \endqml +To use an enum as a \l {QFlags}{flags} type in QML, see \l Q_FLAG(). + \note The names of enum values must begin with a capital letter in order to be accessible from QML. diff --git a/src/qml/doc/src/qmllanguageref/syntax/objectattributes.qdoc b/src/qml/doc/src/qmllanguageref/syntax/objectattributes.qdoc index 04d0d0ed2e..de0515e5d0 100644 --- a/src/qml/doc/src/qmllanguageref/syntax/objectattributes.qdoc +++ b/src/qml/doc/src/qmllanguageref/syntax/objectattributes.qdoc @@ -729,7 +729,7 @@ Rectangle { MouseArea { anchors.fill: parent onPressed: root.activated(mouse.x, mouse.y) - onRelased: root.deactivated() + onReleased: root.deactivated() } } \endqml diff --git a/src/qml/jsruntime/qv4internalclass.cpp b/src/qml/jsruntime/qv4internalclass.cpp index f46f581168..bac45e18c8 100644 --- a/src/qml/jsruntime/qv4internalclass.cpp +++ b/src/qml/jsruntime/qv4internalclass.cpp @@ -147,8 +147,8 @@ static void insertHoleIntoPropertyData(Object *object, int idx) static void removeFromPropertyData(Object *object, int idx, bool accessor = false) { int inlineSize = object->d()->inlineMemberSize; - int icSize = object->internalClass()->size; int delta = (accessor ? 2 : 1); + int oldSize = object->internalClass()->size + delta; int to = idx; int from = to + delta; if (from < inlineSize) { @@ -156,15 +156,15 @@ static void removeFromPropertyData(Object *object, int idx, bool accessor = fals to = inlineSize - delta; from = inlineSize; } - if (to < inlineSize && from < icSize) { + if (to < inlineSize && from < oldSize) { Q_ASSERT(from >= inlineSize); memcpy(object->propertyData(to), object->d()->propertyData(from), (inlineSize - to)*sizeof(Value)); to = inlineSize; from = inlineSize + delta; } - if (from < icSize + delta) { + if (from < oldSize) { Q_ASSERT(to >= inlineSize && from > to); - memmove(object->propertyData(to), object->d()->propertyData(from), (icSize + delta - to)*sizeof(Value)); + memmove(object->propertyData(to), object->d()->propertyData(from), (oldSize - to)*sizeof(Value)); } } diff --git a/src/qml/jsruntime/qv4value_p.h b/src/qml/jsruntime/qv4value_p.h index d24a5c4c76..dae4d11767 100644 --- a/src/qml/jsruntime/qv4value_p.h +++ b/src/qml/jsruntime/qv4value_p.h @@ -102,13 +102,13 @@ public: Q_ALWAYS_INLINE quint64 rawValue() const { return _val; } Q_ALWAYS_INLINE void setRawValue(quint64 raw) { _val = raw; } -#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN +#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN || defined(QV4_USE_64_BIT_VALUE_ENCODING) static inline int valueOffset() { return 0; } static inline int tagOffset() { return 4; } Q_ALWAYS_INLINE void setTagValue(quint32 tag, quint32 value) { _val = quint64(tag) << 32 | value; } Q_ALWAYS_INLINE quint32 value() const { return _val & quint64(~quint32(0)); } Q_ALWAYS_INLINE quint32 tag() const { return _val >> 32; } -#else // !Q_LITTLE_ENDIAN +#else // !Q_LITTLE_ENDIAN && !defined(QV4_USE_64_BIT_VALUE_ENCODING) static inline int valueOffset() { return 4; } static inline int tagOffset() { return 0; } Q_ALWAYS_INLINE void setTagValue(quint32 tag, quint32 value) { _val = quint64(value) << 32 | tag; } diff --git a/src/qml/qml/qqmlcomponent.cpp b/src/qml/qml/qqmlcomponent.cpp index 175b84e7c5..9c7b4fe1c0 100644 --- a/src/qml/qml/qqmlcomponent.cpp +++ b/src/qml/qml/qqmlcomponent.cpp @@ -1135,7 +1135,7 @@ static void QQmlComponent_setQmlParent(QObject *me, QObject *parent) } /*! - \qmlmethod object Component::createObject(Item parent, object properties) + \qmlmethod object Component::createObject(QtObject parent, object properties) Creates and returns an object instance of this component that will have the given \a parent and \a properties. The \a properties argument is optional. diff --git a/src/qml/qml/qqmlobjectcreator.cpp b/src/qml/qml/qqmlobjectcreator.cpp index f2b3276778..3000f3e695 100644 --- a/src/qml/qml/qqmlobjectcreator.cpp +++ b/src/qml/qml/qqmlobjectcreator.cpp @@ -480,6 +480,17 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const property->writeProperty(_qobject, &value, propertyWriteFlags); } break; + case QVariant::Vector2D: { + struct { + float xp; + float yp; + } vec; + bool ok = QQmlStringConverters::createFromString(QMetaType::QVector2D, binding->valueAsString(qmlUnit), &vec, sizeof(vec)); + Q_ASSERT(ok); + Q_UNUSED(ok); + property->writeProperty(_qobject, &vec, propertyWriteFlags); + } + break; case QVariant::Vector3D: { struct { float xp; @@ -505,6 +516,19 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const property->writeProperty(_qobject, &vec, propertyWriteFlags); } break; + case QVariant::Quaternion: { + struct { + float wp; + float xp; + float yp; + float zp; + } vec; + bool ok = QQmlStringConverters::createFromString(QMetaType::QQuaternion, binding->valueAsString(qmlUnit), &vec, sizeof(vec)); + Q_ASSERT(ok); + Q_UNUSED(ok); + property->writeProperty(_qobject, &vec, propertyWriteFlags); + } + break; case QVariant::RegExp: Q_ASSERT(!"not possible"); break; diff --git a/src/qml/qml/qqmlopenmetaobject.cpp b/src/qml/qml/qqmlopenmetaobject.cpp index 22c4072aec..0fd9e63bde 100644 --- a/src/qml/qml/qqmlopenmetaobject.cpp +++ b/src/qml/qml/qqmlopenmetaobject.cpp @@ -278,7 +278,7 @@ int QQmlOpenMetaObject::metaCall(QObject *o, QMetaObject::Call c, int id, void * propertyRead(propId); *reinterpret_cast<QVariant *>(a[0]) = d->getData(propId); } else if (c == QMetaObject::WriteProperty) { - if (propId <= d->data.count() || d->data[propId].first != *reinterpret_cast<QVariant *>(a[0])) { + if (propId >= d->data.count() || d->data[propId].first != *reinterpret_cast<QVariant *>(a[0])) { propertyWrite(propId); QPair<QVariant, bool> &prop = d->getDataRef(propId); prop.first = propertyWriteValue(propId, *reinterpret_cast<QVariant *>(a[0])); diff --git a/src/quick/doc/src/concepts/modelviewsdata/cppmodels.qdoc b/src/quick/doc/src/concepts/modelviewsdata/cppmodels.qdoc index cb281a2d4a..a764402c2f 100644 --- a/src/quick/doc/src/concepts/modelviewsdata/cppmodels.qdoc +++ b/src/quick/doc/src/concepts/modelviewsdata/cppmodels.qdoc @@ -156,6 +156,111 @@ with list models of QAbstractItemModel type: \li \l DelegateModel::parentModelIndex() returns a QModelIndex which can be assigned to DelegateModel::rootIndex \endlist +\section2 SQL Models + +Qt provides C++ classes that support SQL data models. These classes work +transparently on the underlying SQL data, reducing the need to run SQL +queries for basic SQL operations such as create, insert, or update. +For more details about these classes, see \l{Using the SQL Model Classes}. + +Although the C++ classes provide complete feature sets to operate on SQL +data, they do not provide data access to QML. So you must implement a +C++ custom data model as a subclass of one of these classes, and expose it +to QML either as a type or context property. + +\section3 Read-only Data Model + +The custom model must reimplement the following methods to enable read-only +access to the data from QML: + +\list +\li \l{QAbstractItemModel::}{roleNames}() to expose the role names to the + QML frontend. For example, the following version returns the selected + table's field names as role names: + \code + QHash<int, QByteArray> SqlQueryModel::roleNames() const + { + QHash<int, QByteArray> roles; + // record() returns an empty QSqlRecord + for (int i = 0; i < this->record().count(); i ++) { + roles.insert(Qt::UserRole + i + 1, record().fieldName(i).toUtf8()); + } + return roles; + } + \endcode +\li \l{QSqlQueryModel::}{data}() to expose SQL data to the QML frontend. + For example, the following implementation returns data for the given + model index: + \code + QVariant SqlQueryModel::data(const QModelIndex &index, int role) const + { + QVariant value; + + if (index.isValid()) { + if (role < Qt::UserRole) { + value = QSqlQueryModel::data(index, role); + } else { + int columnIdx = role - Qt::UserRole - 1; + QModelIndex modelIndex = this->index(index.row(), columnIdx); + value = QSqlQueryModel::data(modelIndex, Qt::DisplayRole); + } + } + return value; + } + \endcode +\endlist + +The QSqlQueryModel class is good enough to implement a custom read-only +model that represents data in an SQL database. The +\l{Qt Quick Controls 2 - Chat Tutorial}{chat tutorial} example +demonstrates this very well by implementing a custom model to fetch the +contact details from an SQLite database. + +\section3 Editable Data Model + +Besides the \c roleNames() and \c data(), the editable models must reimplement +the \l{QSqlTableModel::}{setData} method to save changes to existing SQL data. +The following version of the method checks if the given model index is valid +and the \c role is equal to \l Qt::EditRole, before calling the parent class +version: + +\code +bool SqlEditableModel::setData(const QModelIndex &item, const QVariant &value, int role) +{ + if (item.isValid() && role == Qt::EditRole) { + QSqlTableModel::setData(item, value,role); + emit dataChanged(item, item); + return true; + } + return false; + +} +\endcode + +\note It is important to emit the \l{QAbstractItemModel::}{dataChanged}() +signal after saving the changes. + +Unlike the C++ item views such as QListView or QTableView, the \c setData() +method must be explicitly invoked from QML whenever appropriate. For example, +on the \l[QML]{TextField::}{editingFinished}() or \l[QML]{TextField::}{accepted}() +signal of \l[QtQuickControls]{TextField}. Depending on the +\l{QSqlTableModel::}{EditStrategy} used by the model, the changes are either +queued for submission later or submitted immediately. + +You can also insert new data into the model by calling +\l {QSqlTableModel::insertRecord}(). In the following example snippet, +a QSqlRecord is populated with book details and appended to the +model: + +\code + ... + QSqlRecord newRecord = record(); + newRecord.setValue("author", "John Grisham"); + newRecord.setValue("booktitle", "The Litigators"); + insertRecord(rowCount(), newRecord); + ... +\endcode + \section2 Exposing C++ Data Models to QML The above examples use QQmlContext::setContextProperty() to set diff --git a/src/quick/items/qquickflickable.cpp b/src/quick/items/qquickflickable.cpp index a09088dfed..dcba5c2d71 100644 --- a/src/quick/items/qquickflickable.cpp +++ b/src/quick/items/qquickflickable.cpp @@ -1590,13 +1590,13 @@ qreal QQuickFlickable::minXExtent() const qreal QQuickFlickable::maxXExtent() const { Q_D(const QQuickFlickable); - return qMin<qreal>(0, width() - vWidth() - d->hData.endMargin); + return qMin<qreal>(minXExtent(), width() - vWidth() - d->hData.endMargin); } /* returns -ve */ qreal QQuickFlickable::maxYExtent() const { Q_D(const QQuickFlickable); - return qMin<qreal>(0, height() - vHeight() - d->vData.endMargin); + return qMin<qreal>(minYExtent(), height() - vHeight() - d->vData.endMargin); } void QQuickFlickable::componentComplete() diff --git a/src/quick/items/qquickitem.cpp b/src/quick/items/qquickitem.cpp index 07a415eecd..8905faf973 100644 --- a/src/quick/items/qquickitem.cpp +++ b/src/quick/items/qquickitem.cpp @@ -2090,6 +2090,9 @@ void QQuickItemPrivate::updateSubFocusItem(QQuickItem *scope, bool focus) \value ItemDevicePixelRatioHasChanged The device pixel ratio of the screen the item is on has changed. ItemChangedData::realValue contains the new device pixel ratio. + + \value ItemAntialiasingHasChanged The antialiasing has changed. The current + (boolean) value can be found in QQuickItem::antialiasing. */ /*! diff --git a/src/quick/items/qquickitemanimation.cpp b/src/quick/items/qquickitemanimation.cpp index 962f410095..027c07ec07 100644 --- a/src/quick/items/qquickitemanimation.cpp +++ b/src/quick/items/qquickitemanimation.cpp @@ -200,6 +200,27 @@ QPointF QQuickParentAnimationPrivate::computeTransformOrigin(QQuickItem::Transfo } } +struct QQuickParentAnimationData : public QAbstractAnimationAction +{ + QQuickParentAnimationData() : reverse(false) {} + ~QQuickParentAnimationData() { qDeleteAll(pc); } + + QQuickStateActions actions; + //### reverse should probably apply on a per-action basis + bool reverse; + QList<QQuickParentChange *> pc; + void doAction() Q_DECL_OVERRIDE + { + for (int ii = 0; ii < actions.count(); ++ii) { + const QQuickStateAction &action = actions.at(ii); + if (reverse) + action.event->reverse(); + else + action.event->execute(); + } + } +}; + QAbstractAnimationJob* QQuickParentAnimation::transition(QQuickStateActions &actions, QQmlProperties &modified, TransitionDirection direction, @@ -207,27 +228,6 @@ QAbstractAnimationJob* QQuickParentAnimation::transition(QQuickStateActions &act { Q_D(QQuickParentAnimation); - struct QQuickParentAnimationData : public QAbstractAnimationAction - { - QQuickParentAnimationData() : reverse(false) {} - ~QQuickParentAnimationData() { qDeleteAll(pc); } - - QQuickStateActions actions; - //### reverse should probably apply on a per-action basis - bool reverse; - QList<QQuickParentChange *> pc; - void doAction() Q_DECL_OVERRIDE - { - for (int ii = 0; ii < actions.count(); ++ii) { - const QQuickStateAction &action = actions.at(ii); - if (reverse) - action.event->reverse(); - else - action.event->execute(); - } - } - }; - QQuickParentAnimationData *data = new QQuickParentAnimationData; QQuickParentAnimationData *viaData = new QQuickParentAnimationData; diff --git a/src/quick/items/qquicktextedit.cpp b/src/quick/items/qquicktextedit.cpp index eb568c48d4..d6d9d53a3b 100644 --- a/src/quick/items/qquicktextedit.cpp +++ b/src/quick/items/qquicktextedit.cpp @@ -1489,8 +1489,8 @@ void QQuickTextEdit::setSelectByKeyboard(bool on) If true, the user can use the mouse to select text in some platform-specific way. Note that for some platforms this may - not be an appropriate interaction (eg. may conflict with how - the text needs to behave inside a Flickable. + not be an appropriate interaction; it may conflict with how + the text needs to behave inside a Flickable, for example. */ bool QQuickTextEdit::selectByMouse() const { diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp index 56466fdbd1..a2c82c30a0 100644 --- a/src/quick/items/qquickwindow.cpp +++ b/src/quick/items/qquickwindow.cpp @@ -707,10 +707,10 @@ bool QQuickWindowPrivate::translateTouchToMouse(QQuickItem *item, QTouchEvent *e lastMousePosition = me->windowPos(); bool accepted = me->isAccepted(); - bool delivered = deliverHoverEvent(contentItem, me->windowPos(), last, me->modifiers(), accepted); + bool delivered = deliverHoverEvent(contentItem, me->windowPos(), last, me->modifiers(), me->timestamp(), accepted); if (!delivered) { //take care of any exits - accepted = clearHover(); + accepted = clearHover(me->timestamp()); } me->setAccepted(accepted); break; @@ -1488,7 +1488,7 @@ QQuickItem *QQuickWindow::mouseGrabberItem() const } -bool QQuickWindowPrivate::clearHover() +bool QQuickWindowPrivate::clearHover(ulong timestamp) { Q_Q(QQuickWindow); if (hoverItems.isEmpty()) @@ -1498,7 +1498,7 @@ bool QQuickWindowPrivate::clearHover() bool accepted = false; foreach (QQuickItem* item, hoverItems) - accepted = sendHoverEvent(QEvent::HoverLeave, item, pos, pos, QGuiApplication::keyboardModifiers(), true) || accepted; + accepted = sendHoverEvent(QEvent::HoverLeave, item, pos, pos, QGuiApplication::keyboardModifiers(), timestamp, true) || accepted; hoverItems.clear(); return accepted; } @@ -1678,6 +1678,12 @@ bool QQuickWindowPrivate::deliverMouseEvent(QMouseEvent *event) } if (mouseGrabberItem) { + if (event->button() != Qt::NoButton + && mouseGrabberItem->acceptedMouseButtons() + && !(mouseGrabberItem->acceptedMouseButtons() & event->button())) { + event->ignore(); + return false; + } QPointF localPos = mouseGrabberItem->mapFromScene(event->windowPos()); QScopedPointer<QMouseEvent> me(cloneMouseEvent(event, &localPos)); me->accept(); @@ -1692,13 +1698,15 @@ bool QQuickWindowPrivate::deliverMouseEvent(QMouseEvent *event) bool QQuickWindowPrivate::sendHoverEvent(QEvent::Type type, QQuickItem *item, const QPointF &scenePos, const QPointF &lastScenePos, - Qt::KeyboardModifiers modifiers, bool accepted) + Qt::KeyboardModifiers modifiers, ulong timestamp, + bool accepted) { Q_Q(QQuickWindow); const QTransform transform = QQuickItemPrivate::get(item)->windowToItemTransform(); //create copy of event QHoverEvent hoverEvent(type, transform.map(scenePos), transform.map(lastScenePos), modifiers); + hoverEvent.setTimestamp(timestamp); hoverEvent.setAccepted(accepted); QSet<QQuickItem *> hasFiltered; @@ -1712,7 +1720,7 @@ bool QQuickWindowPrivate::sendHoverEvent(QEvent::Type type, QQuickItem *item, } bool QQuickWindowPrivate::deliverHoverEvent(QQuickItem *item, const QPointF &scenePos, const QPointF &lastScenePos, - Qt::KeyboardModifiers modifiers, bool &accepted) + Qt::KeyboardModifiers modifiers, ulong timestamp, bool &accepted) { Q_Q(QQuickWindow); QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item); @@ -1730,7 +1738,7 @@ bool QQuickWindowPrivate::deliverHoverEvent(QQuickItem *item, const QPointF &sce QQuickItem *child = children.at(ii); if (!child->isVisible() || !child->isEnabled() || QQuickItemPrivate::get(child)->culled) continue; - if (deliverHoverEvent(child, scenePos, lastScenePos, modifiers, accepted)) + if (deliverHoverEvent(child, scenePos, lastScenePos, modifiers, timestamp, accepted)) return true; } } @@ -1740,7 +1748,7 @@ bool QQuickWindowPrivate::deliverHoverEvent(QQuickItem *item, const QPointF &sce if (item->contains(p)) { if (!hoverItems.isEmpty() && hoverItems[0] == item) { //move - accepted = sendHoverEvent(QEvent::HoverMove, item, scenePos, lastScenePos, modifiers, accepted); + accepted = sendHoverEvent(QEvent::HoverMove, item, scenePos, lastScenePos, modifiers, timestamp, accepted); } else { QList<QQuickItem *> itemsToHover; QQuickItem* parent = item; @@ -1751,12 +1759,12 @@ bool QQuickWindowPrivate::deliverHoverEvent(QQuickItem *item, const QPointF &sce // Leaving from previous hovered items until we reach the item or one of its ancestors. while (!hoverItems.isEmpty() && !itemsToHover.contains(hoverItems[0])) { QQuickItem *hoverLeaveItem = hoverItems.takeFirst(); - sendHoverEvent(QEvent::HoverLeave, hoverLeaveItem, scenePos, lastScenePos, modifiers, accepted); + sendHoverEvent(QEvent::HoverLeave, hoverLeaveItem, scenePos, lastScenePos, modifiers, timestamp, accepted); } if (!hoverItems.isEmpty() && hoverItems[0] == item){//Not entering a new Item // ### Shouldn't we send moves for the parent items as well? - accepted = sendHoverEvent(QEvent::HoverMove, item, scenePos, lastScenePos, modifiers, accepted); + accepted = sendHoverEvent(QEvent::HoverMove, item, scenePos, lastScenePos, modifiers, timestamp, accepted); } else { // Enter items that are not entered yet. int startIdx = -1; @@ -1775,7 +1783,7 @@ bool QQuickWindowPrivate::deliverHoverEvent(QQuickItem *item, const QPointF &sce // itemToHoverPrivate->window here prevents that case. if (itemToHoverPrivate->window == q && itemToHoverPrivate->hoverEnabled) { hoverItems.prepend(itemToHover); - sendHoverEvent(QEvent::HoverEnter, itemToHover, scenePos, lastScenePos, modifiers, accepted); + sendHoverEvent(QEvent::HoverEnter, itemToHover, scenePos, lastScenePos, modifiers, timestamp, accepted); } } } @@ -2076,10 +2084,10 @@ void QQuickWindowPrivate::handleMouseEvent(QMouseEvent *event) lastMousePosition = event->windowPos(); bool accepted = event->isAccepted(); - bool delivered = deliverHoverEvent(contentItem, event->windowPos(), last, event->modifiers(), accepted); + bool delivered = deliverHoverEvent(contentItem, event->windowPos(), last, event->modifiers(), event->timestamp(), accepted); if (!delivered) { //take care of any exits - accepted = clearHover(); + accepted = clearHover(event->timestamp()); } event->setAccepted(accepted); return; @@ -2110,7 +2118,7 @@ void QQuickWindowPrivate::flushFrameSynchronousEvents() // whether it has moved into a position where it is now under the cursor. if (!mouseGrabberItem && !lastMousePosition.isNull()) { bool accepted = false; - bool delivered = deliverHoverEvent(contentItem, lastMousePosition, lastMousePosition, QGuiApplication::keyboardModifiers(), accepted); + bool delivered = deliverHoverEvent(contentItem, lastMousePosition, lastMousePosition, QGuiApplication::keyboardModifiers(), 0, accepted); if (!delivered) clearHover(); // take care of any exits } diff --git a/src/quick/items/qquickwindow_p.h b/src/quick/items/qquickwindow_p.h index 71f2bb5778..40a361a897 100644 --- a/src/quick/items/qquickwindow_p.h +++ b/src/quick/items/qquickwindow_p.h @@ -165,14 +165,14 @@ public: bool deliverTouchCancelEvent(QTouchEvent *); void deliverDelayedTouchEvent(); void flushFrameSynchronousEvents(); - bool deliverHoverEvent(QQuickItem *, const QPointF &scenePos, const QPointF &lastScenePos, Qt::KeyboardModifiers modifiers, bool &accepted); + bool deliverHoverEvent(QQuickItem *, const QPointF &scenePos, const QPointF &lastScenePos, Qt::KeyboardModifiers modifiers, ulong timestamp, bool &accepted); bool deliverMatchingPointsToItem(QQuickItem *item, QTouchEvent *event, QSet<int> *acceptedNewPoints, const QSet<int> &matchingNewPoints, const QList<QTouchEvent::TouchPoint> &matchingPoints, QSet<QQuickItem*> *filtered); static QTouchEvent *touchEventForItem(QQuickItem *target, const QTouchEvent &originalEvent, bool alwaysCheckBounds = false); static QTouchEvent *touchEventWithPoints(const QTouchEvent &event, const QList<QTouchEvent::TouchPoint> &newPoints); bool sendFilteredTouchEvent(QQuickItem *target, QQuickItem *item, QTouchEvent *event, QSet<QQuickItem*> *filtered); bool sendHoverEvent(QEvent::Type, QQuickItem *, const QPointF &scenePos, const QPointF &lastScenePos, - Qt::KeyboardModifiers modifiers, bool accepted); - bool clearHover(); + Qt::KeyboardModifiers modifiers, ulong timestamp, bool accepted); + bool clearHover(ulong timestamp = 0); #ifndef QT_NO_DRAGANDDROP void deliverDragEvent(QQuickDragGrabber *, QEvent *); bool deliverDragEvent(QQuickDragGrabber *, QQuickItem *, QDragMoveEvent *); diff --git a/src/quick/scenegraph/qsgthreadedrenderloop.cpp b/src/quick/scenegraph/qsgthreadedrenderloop.cpp index 3ff32b360d..6b9c67b2bd 100644 --- a/src/quick/scenegraph/qsgthreadedrenderloop.cpp +++ b/src/quick/scenegraph/qsgthreadedrenderloop.cpp @@ -600,7 +600,7 @@ void QSGRenderThread::syncAndRender() #endif Q_QUICK_SG_PROFILE_RECORD(QQuickProfiler::SceneGraphRenderLoopFrame); - if (!syncResultedInChanges && !repaintRequested) { + if (!syncResultedInChanges && !repaintRequested && sgrc->isValid()) { qCDebug(QSG_LOG_RENDERLOOP) << QSG_RT_PAD << "- no changes, render aborted"; int waitTime = vsyncDelta - (int) waitTimer.elapsed(); if (waitTime > 0) diff --git a/src/quick/scenegraph/util/qsgatlastexture.cpp b/src/quick/scenegraph/util/qsgatlastexture.cpp index 098a4a666b..40c3293c7b 100644 --- a/src/quick/scenegraph/util/qsgatlastexture.cpp +++ b/src/quick/scenegraph/util/qsgatlastexture.cpp @@ -158,13 +158,13 @@ Atlas::Atlas(const QSize &size) wrongfullyReportsBgra8888Support = false; const char *ext = (const char *) QOpenGLContext::currentContext()->functions()->glGetString(GL_EXTENSIONS); - if (!wrongfullyReportsBgra8888Support + if (ext && !wrongfullyReportsBgra8888Support && (strstr(ext, "GL_EXT_bgra") || strstr(ext, "GL_EXT_texture_format_BGRA8888") || strstr(ext, "GL_IMG_texture_format_BGRA8888"))) { m_internalFormat = m_externalFormat = GL_BGRA; #if defined(Q_OS_DARWIN) && !defined(Q_OS_OSX) - } else if (strstr(ext, "GL_APPLE_texture_format_BGRA8888")) { + } else if (ext && strstr(ext, "GL_APPLE_texture_format_BGRA8888")) { m_internalFormat = GL_RGBA; m_externalFormat = GL_BGRA; #endif // IOS || TVOS diff --git a/tests/auto/qml/debugger/qqmlprofilerservice/tst_qqmlprofilerservice.cpp b/tests/auto/qml/debugger/qqmlprofilerservice/tst_qqmlprofilerservice.cpp index 52c9953970..c4b17aa60a 100644 --- a/tests/auto/qml/debugger/qqmlprofilerservice/tst_qqmlprofilerservice.cpp +++ b/tests/auto/qml/debugger/qqmlprofilerservice/tst_qqmlprofilerservice.cpp @@ -609,12 +609,11 @@ void tst_QQmlProfilerService::scenegraphData() checkTraceReceived(); checkJsHeap(); - - // check that at least one frame was rendered - // there should be a SGPolishAndSync + SGRendererFrame + SGRenderLoopFrame sequence - // (though we can't be sure to get the SGRenderLoopFrame in the threaded renderer) + // Check that at least one frame was rendered. + // There should be a SGContextFrame + SGRendererFrame + SGRenderLoopFrame sequence, + // but we can't be sure to get the SGRenderLoopFrame in the threaded renderer. // - // since the rendering happens in a different thread, there could be other unrelated events + // Since the rendering happens in a different thread, there could be other unrelated events // interleaved. Also, events could carry the same time stamps and be sorted in an unexpected way // if the clocks are acting up. qint64 contextFrameTime = -1; @@ -643,8 +642,13 @@ void tst_QQmlProfilerService::scenegraphData() foreach (const QQmlProfilerData &msg, m_client->asynchronousMessages) { if (msg.detailType == QQmlProfilerDefinitions::SceneGraphRenderLoopFrame) { - QVERIFY(msg.time >= renderFrameTime); - break; + if (msg.time >= contextFrameTime) { + // Make sure SceneGraphRenderLoopFrame is not between SceneGraphContextFrame and + // SceneGraphRendererFrame. A SceneGraphRenderLoopFrame before everything else is + // OK as the scene graph might decide to do an initial rendering. + QVERIFY(msg.time >= renderFrameTime); + break; + } } } } diff --git a/tests/auto/qml/qqmlecmascript/data/qtbug_54589.qml b/tests/auto/qml/qqmlecmascript/data/qtbug_54589.qml new file mode 100644 index 0000000000..8f7d5f2a70 --- /dev/null +++ b/tests/auto/qml/qqmlecmascript/data/qtbug_54589.qml @@ -0,0 +1,16 @@ +import QtQuick 2.0 + +QtObject { + function checkPropertyDeletion() { + var o = { + x: 1, + y: 2 + }; + o.z = 3 + delete o.y; + + return (o.x === 1 && o.y === undefined && o.z === 3) + } + + property bool result: checkPropertyDeletion() +} diff --git a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp index 07b5e55384..de3ead917f 100644 --- a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp +++ b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp @@ -324,6 +324,8 @@ private slots: void switchExpression(); void qtbug_46022(); void qtbug_52340(); + void qtbug_54589(); + void qtbug_54687(); private: // static void propertyVarWeakRefCallback(v8::Persistent<v8::Value> object, void* parameter); @@ -7965,6 +7967,22 @@ void tst_qqmlecmascript::qtbug_52340() QVERIFY(returnValue.toBool()); } +void tst_qqmlecmascript::qtbug_54589() +{ + QQmlComponent component(&engine, testFileUrl("qtbug_54589.qml")); + + QScopedPointer<QObject> obj(component.create()); + QVERIFY(obj != 0); + QCOMPARE(obj->property("result").toBool(), true); +} + +void tst_qqmlecmascript::qtbug_54687() +{ + QJSEngine e; + // it's simple: this shouldn't crash. + engine.evaluate("12\n----12"); +} + QTEST_MAIN(tst_qqmlecmascript) #include "tst_qqmlecmascript.moc" diff --git a/tests/auto/qml/qqmllanguage/data/assignBasicTypes.qml b/tests/auto/qml/qqmllanguage/data/assignBasicTypes.qml index c91cf581b3..52027232db 100644 --- a/tests/auto/qml/qqmllanguage/data/assignBasicTypes.qml +++ b/tests/auto/qml/qqmllanguage/data/assignBasicTypes.qml @@ -26,7 +26,9 @@ MyTypeObject { boolProperty: true variantProperty: "Hello World!" vectorProperty: "10,1,2.2" + vector2Property: "2, 3" vector4Property: "10,1,2.2,2.3" + quaternionProperty: "4,5,6,7" urlProperty: "main.qml?with%3cencoded%3edata" objectProperty: MyTypeObject { intProperty: 8 } diff --git a/tests/auto/qml/qqmllanguage/testtypes.h b/tests/auto/qml/qqmllanguage/testtypes.h index f41f13c561..af7dc155d0 100644 --- a/tests/auto/qml/qqmllanguage/testtypes.h +++ b/tests/auto/qml/qqmllanguage/testtypes.h @@ -33,8 +33,10 @@ #include <QtCore/qdatetime.h> #include <QtGui/qmatrix.h> #include <QtGui/qcolor.h> +#include <QtGui/qvector2d.h> #include <QtGui/qvector3d.h> #include <QtGui/qvector4d.h> +#include <QtGui/qquaternion.h> #include <QtQml/qqml.h> #include <QtQml/qqmlcomponent.h> #include <QtQml/qqmlparserstatus.h> @@ -241,8 +243,10 @@ class MyTypeObject : public QObject Q_PROPERTY(QRectF rectFProperty READ rectFProperty WRITE setRectFProperty NOTIFY rectFPropertyChanged) Q_PROPERTY(bool boolProperty READ boolProperty WRITE setBoolProperty NOTIFY boolPropertyChanged) Q_PROPERTY(QVariant variantProperty READ variantProperty WRITE setVariantProperty NOTIFY variantPropertyChanged) + Q_PROPERTY(QVector2D vector2Property READ vector2Property WRITE setVector2Property NOTIFY vector2PropertyChanged) Q_PROPERTY(QVector3D vectorProperty READ vectorProperty WRITE setVectorProperty NOTIFY vectorPropertyChanged) Q_PROPERTY(QVector4D vector4Property READ vector4Property WRITE setVector4Property NOTIFY vector4PropertyChanged) + Q_PROPERTY(QQuaternion quaternionProperty READ quaternionProperty WRITE setQuaternionProperty NOTIFY quaternionPropertyChanged) Q_PROPERTY(QUrl urlProperty READ urlProperty WRITE setUrlProperty NOTIFY urlPropertyChanged) Q_PROPERTY(QQmlScriptString scriptProperty READ scriptProperty WRITE setScriptProperty) @@ -523,6 +527,15 @@ public: emit vectorPropertyChanged(); } + QVector2D vector2PropertyValue; + QVector2D vector2Property() const { + return vector2PropertyValue; + } + void setVector2Property(const QVector2D &v) { + vector2PropertyValue = v; + emit vector2PropertyChanged(); + } + QVector4D vector4PropertyValue; QVector4D vector4Property() const { return vector4PropertyValue; @@ -532,6 +545,15 @@ public: emit vector4PropertyChanged(); } + QQuaternion quaternionPropertyValue; + QQuaternion quaternionProperty() const { + return quaternionPropertyValue; + } + void setQuaternionProperty(const QQuaternion &v) { + quaternionPropertyValue = v; + emit quaternionPropertyChanged(); + } + QUrl urlPropertyValue; QUrl urlProperty() const { return urlPropertyValue; @@ -585,7 +607,9 @@ signals: void boolPropertyChanged(); void variantPropertyChanged(); void vectorPropertyChanged(); + void vector2PropertyChanged(); void vector4PropertyChanged(); + void quaternionPropertyChanged(); void urlPropertyChanged(); }; diff --git a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp index 1df7c4157e..1a035be5e0 100644 --- a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp +++ b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp @@ -682,6 +682,7 @@ void tst_qqmllanguage::assignBasicTypes() QCOMPARE(object->boolProperty(), true); QCOMPARE(object->variantProperty(), QVariant("Hello World!")); QCOMPARE(object->vectorProperty(), QVector3D(10, 1, 2.2f)); + QCOMPARE(object->vector2Property(), QVector2D(2, 3)); QCOMPARE(object->vector4Property(), QVector4D(10, 1, 2.2f, 2.3f)); const QUrl encoded = QUrl::fromEncoded("main.qml?with%3cencoded%3edata", QUrl::TolerantMode); QCOMPARE(object->urlProperty(), component.url().resolved(encoded)); diff --git a/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp b/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp index 7e00147963..63d7f1c12b 100644 --- a/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp +++ b/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp @@ -2078,15 +2078,15 @@ void tst_qqmlproperty::floatToStringPrecision() QFETCH(QString, qtString); QFETCH(QString, jsString); - const char *name = propertyName.toLatin1().constData(); + QByteArray name = propertyName.toLatin1(); QCOMPARE(obj->property(name).toDouble(), number); QCOMPARE(obj->property(name).toString(), qtString); - const char *name1 = (propertyName + QLatin1Char('1')).toLatin1().constData(); + QByteArray name1 = (propertyName + QLatin1Char('1')).toLatin1(); QCOMPARE(obj->property(name1).toDouble(), number); QCOMPARE(obj->property(name1).toString(), qtString); - const char *name2 = (propertyName + QLatin1Char('2')).toLatin1().constData(); + QByteArray name2 = (propertyName + QLatin1Char('2')).toLatin1(); QCOMPARE(obj->property(name2).toDouble(), number); QCOMPARE(obj->property(name2).toString(), jsString); diff --git a/tests/auto/qml/qqmlpropertymap/tst_qqmlpropertymap.cpp b/tests/auto/qml/qqmlpropertymap/tst_qqmlpropertymap.cpp index e0c2324dc6..b8ea98df2b 100644 --- a/tests/auto/qml/qqmlpropertymap/tst_qqmlpropertymap.cpp +++ b/tests/auto/qml/qqmlpropertymap/tst_qqmlpropertymap.cpp @@ -60,6 +60,7 @@ private slots: void QTBUG_35233(); void disallowExtending(); void QTBUG_35906(); + void QTBUG_48136(); }; class LazyPropertyMap : public QQmlPropertyMap, public QQmlParserStatus @@ -462,6 +463,40 @@ void tst_QQmlPropertyMap::QTBUG_35906() QCOMPARE(value.toInt(), 42); } +void tst_QQmlPropertyMap::QTBUG_48136() +{ + static const char key[] = "mykey"; + QQmlPropertyMap map; + + // + // Test that the notify signal is emitted correctly + // + + const int propIndex = map.metaObject()->indexOfProperty(key); + const QMetaProperty prop = map.metaObject()->property(propIndex); + QSignalSpy notifySpy(&map, QByteArray::number(QSIGNAL_CODE) + prop.notifySignal().methodSignature()); + + map.insert(key, 42); + QCOMPARE(notifySpy.count(), 1); + map.insert(key, 43); + QCOMPARE(notifySpy.count(), 2); + map.insert(key, 43); + QCOMPARE(notifySpy.count(), 2); + map.insert(key, 44); + QCOMPARE(notifySpy.count(), 3); + + // + // Test that the valueChanged signal is emitted correctly + // + QSignalSpy valueChangedSpy(&map, &QQmlPropertyMap::valueChanged); + map.setProperty(key, 44); + QCOMPARE(valueChangedSpy.count(), 0); + map.setProperty(key, 45); + QCOMPARE(valueChangedSpy.count(), 1); + map.setProperty(key, 45); + QCOMPARE(valueChangedSpy.count(), 1); +} + QTEST_MAIN(tst_QQmlPropertyMap) #include "tst_qqmlpropertymap.moc" diff --git a/tests/auto/quick/qquickflickable/data/ratios_smallContent.qml b/tests/auto/quick/qquickflickable/data/ratios_smallContent.qml new file mode 100644 index 0000000000..07bad683ee --- /dev/null +++ b/tests/auto/quick/qquickflickable/data/ratios_smallContent.qml @@ -0,0 +1,19 @@ +import QtQuick 2.0 + +Flickable { + property double heightRatioIs: visibleArea.heightRatio + property double widthRatioIs: visibleArea.widthRatio + + width: 200 + height: 200 + contentWidth: item.width + contentHeight: item.height + topMargin: 20 + leftMargin: 40 + + Item { + id: item + width: 100 + height: 100 + } +} diff --git a/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp b/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp index 2742f5c1e2..e1678b9acd 100644 --- a/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp +++ b/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp @@ -90,6 +90,7 @@ private slots: void movementFromProgrammaticFlick(); void cleanup(); void contentSize(); + void ratios_smallContent(); private: void flickWithTouch(QQuickWindow *window, QTouchDevice *touchDevice, const QPoint &from, const QPoint &to); @@ -1814,6 +1815,33 @@ void tst_qquickflickable::contentSize() QCOMPARE(chspy.count(), 1); } +// QTBUG-53726 +void tst_qquickflickable::ratios_smallContent() +{ + QScopedPointer<QQuickView> window(new QQuickView); + window->setSource(testFileUrl("ratios_smallContent.qml")); + QTRY_COMPARE(window->status(), QQuickView::Ready); + QQuickViewTestUtil::centerOnScreen(window.data()); + QQuickViewTestUtil::moveMouseAway(window.data()); + window->setTitle(QTest::currentTestFunction()); + window->show(); + QVERIFY(QTest::qWaitForWindowExposed(window.data())); + QQuickItem *root = window->rootObject(); + QVERIFY(root); + QQuickFlickable *obj = qobject_cast<QQuickFlickable*>(root); + QVERIFY(obj != 0); + + //doublecheck the item, as specified by contentWidth/Height, fits in the view + //use tryCompare to allow a bit of stabilization in component's properties + QTRY_COMPARE(obj->leftMargin() + obj->contentWidth() + obj->rightMargin() <= obj->width(), true); + QTRY_COMPARE(obj->topMargin() + obj->contentHeight() + obj->bottomMargin() <= obj->height(), true); + + //the whole item fits in the flickable, heightRatio should be 1 + QCOMPARE(obj->property("heightRatioIs").toDouble(), 1.); + QCOMPARE(obj->property("widthRatioIs").toDouble(), 1.); +} + + QTEST_MAIN(tst_qquickflickable) #include "tst_qquickflickable.moc" diff --git a/tests/auto/quick/qquickitem/tst_qquickitem.cpp b/tests/auto/quick/qquickitem/tst_qquickitem.cpp index 4b2c86697e..9fedfb21ab 100644 --- a/tests/auto/quick/qquickitem/tst_qquickitem.cpp +++ b/tests/auto/quick/qquickitem/tst_qquickitem.cpp @@ -169,6 +169,8 @@ private slots: void childAt(); + void ignoreButtonPressNotInAcceptedMouseButtons(); + private: enum PaintOrderOp { @@ -2009,6 +2011,28 @@ void tst_qquickitem::childAt() QVERIFY(!root->childAt(19,19)); } +void tst_qquickitem::ignoreButtonPressNotInAcceptedMouseButtons() +{ + // Verify the fix for QTBUG-31861 + TestItem item; + QCOMPARE(item.acceptedMouseButtons(), Qt::MouseButtons(Qt::NoButton)); + + QQuickWindow window; + item.setSize(QSizeF(200,100)); + item.setParentItem(window.contentItem()); + + item.setAcceptedMouseButtons(Qt::LeftButton); + QCOMPARE(item.acceptedMouseButtons(), Qt::MouseButtons(Qt::LeftButton)); + + QTest::mousePress(&window, Qt::LeftButton, 0, QPoint(50, 50)); + QTest::mousePress(&window, Qt::RightButton, 0, QPoint(50, 50)); // ignored because it's not LeftButton + QTest::mouseRelease(&window, Qt::RightButton, 0, QPoint(50, 50)); // ignored because it didn't grab the RightButton press + QTest::mouseRelease(&window, Qt::LeftButton, 0, QPoint(50, 50)); + + QCOMPARE(item.pressCount, 1); + QCOMPARE(item.releaseCount, 1); +} + QTEST_MAIN(tst_qquickitem) #include "tst_qquickitem.moc" diff --git a/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp b/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp index b83edec996..bf9df7850d 100644 --- a/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp +++ b/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp @@ -653,11 +653,9 @@ void tst_QQuickListView::inserted_more(QQuickItemView::VerticalLayoutDirection v #endif QList<FxViewItem *> visibleItems = QQuickItemViewPrivate::get(listview)->visibleItems; - for (QList<FxViewItem *>::const_iterator itemIt = visibleItems.begin(); itemIt != visibleItems.end(); ++itemIt) - { + for (QList<FxViewItem *>::const_iterator itemIt = visibleItems.begin(); itemIt != visibleItems.end(); ++itemIt) { FxViewItem *item = *itemIt; - if (item->item->position().y() >= 0 && item->item->position().y() < listview->height()) - { + if (item->item->position().y() >= 0 && item->item->position().y() < listview->height()) { QVERIFY(!QQuickItemPrivate::get(item->item)->culled); } } diff --git a/tests/auto/quick/qquickshadereffect/data/MyIcon.qml b/tests/auto/quick/qquickshadereffect/data/MyIcon.qml new file mode 100644 index 0000000000..b83da321f2 --- /dev/null +++ b/tests/auto/quick/qquickshadereffect/data/MyIcon.qml @@ -0,0 +1,76 @@ +/**************************************************************************** +** +** Copyright (C) 2016 Canonical Limited and/or its subsidiary(-ies). +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.4 + +Item { + id: root + + property alias source: image.source + property bool shaderActive: false + + implicitWidth: image.width + + Image { + id: image + objectName: "image" + anchors { top: parent.top; bottom: parent.bottom } + sourceSize.height: height + + visible: !shaderActive + } + + ShaderEffect { + id: colorizedImage + + anchors.fill: parent + visible: shaderActive && image.status == Image.Ready + supportsAtlasTextures: true + + property Image source: visible ? image : null + + fragmentShader: " + varying highp vec2 qt_TexCoord0; + uniform sampler2D source; + void main() { + gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0); + }" + } +} diff --git a/tests/auto/quick/qquickshadereffect/data/twoImagesOneShaderEffect.qml b/tests/auto/quick/qquickshadereffect/data/twoImagesOneShaderEffect.qml new file mode 100644 index 0000000000..d1292f74b8 --- /dev/null +++ b/tests/auto/quick/qquickshadereffect/data/twoImagesOneShaderEffect.qml @@ -0,0 +1,61 @@ +/**************************************************************************** +** +** Copyright (C) 2016 Canonical Limited and/or its subsidiary(-ies). +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.4 + +Item { + width: 400 + height: 700 + + MyIcon { + id: icon + + height: 24 + source: "star.png" + shaderActive: true + } + + MyIcon { + anchors.top: icon.bottom + + height: 24 + source: "star.png" + } +} diff --git a/tests/auto/quick/qquickshadereffect/tst_qquickshadereffect.cpp b/tests/auto/quick/qquickshadereffect/tst_qquickshadereffect.cpp index 54b64fdee9..fe33dbd4d8 100644 --- a/tests/auto/quick/qquickshadereffect/tst_qquickshadereffect.cpp +++ b/tests/auto/quick/qquickshadereffect/tst_qquickshadereffect.cpp @@ -77,6 +77,7 @@ private slots: void deleteSourceItem(); void deleteShaderEffectSource(); + void twoImagesOneShaderEffect(); private: enum PresenceFlags { @@ -306,6 +307,19 @@ void tst_qquickshadereffect::deleteShaderEffectSource() delete view; } +void tst_qquickshadereffect::twoImagesOneShaderEffect() +{ + // purely to ensure that deleting the sourceItem of a shader doesn't cause a crash + QQuickView *view = new QQuickView(0); + view->setSource(QUrl::fromLocalFile(testFile("twoImagesOneShaderEffect.qml"))); + view->show(); + QVERIFY(QTest::qWaitForWindowExposed(view)); + QVERIFY(view); + QObject *obj = view->rootObject(); + QVERIFY(obj); + delete view; +} + QTEST_MAIN(tst_qquickshadereffect) #include "tst_qquickshadereffect.moc" diff --git a/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp b/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp index 329bbbed60..d9bdf47041 100644 --- a/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp +++ b/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp @@ -361,6 +361,7 @@ private slots: void testRenderJob(); void testHoverChildMouseEventFilter(); + void testHoverTimestamp(); private: QTouchDevice *touchDevice; QTouchDevice *touchDeviceWithVelocity; @@ -2317,6 +2318,90 @@ void tst_qquickwindow::testHoverChildMouseEventFilter() QCOMPARE(middleItem->eventCount(QEvent::HoverEnter), 0); } +class HoverTimestampConsumer : public QQuickItem +{ + Q_OBJECT +public: + HoverTimestampConsumer(QQuickItem *parent = 0) + : QQuickItem(parent) + { + setAcceptHoverEvents(true); + } + + void hoverEnterEvent(QHoverEvent *event) { hoverTimestamps << event->timestamp(); } + void hoverLeaveEvent(QHoverEvent *event) { hoverTimestamps << event->timestamp(); } + void hoverMoveEvent(QHoverEvent *event) { hoverTimestamps << event->timestamp(); } + + QList<ulong> hoverTimestamps; +}; + +// Checks that a QHoverEvent carries the timestamp of the QMouseEvent that caused it. +// QTBUG-54600 +void tst_qquickwindow::testHoverTimestamp() +{ + QQuickWindow window; + + window.resize(200, 200); + window.setPosition(100, 100); + window.setTitle(QTest::currentTestFunction()); + window.show(); + QVERIFY(QTest::qWaitForWindowActive(&window)); + + HoverTimestampConsumer *hoverConsumer = new HoverTimestampConsumer(window.contentItem()); + hoverConsumer->setWidth(100); + hoverConsumer->setHeight(100); + hoverConsumer->setX(50); + hoverConsumer->setY(50); + + // First position, outside + { + QMouseEvent mouseEvent(QEvent::MouseMove, QPointF(40, 40), QPointF(40, 40), QPointF(140, 140), + Qt::NoButton, Qt::NoButton, Qt::NoModifier, Qt::MouseEventNotSynthesized); + mouseEvent.setTimestamp(10); + QVERIFY(QCoreApplication::sendEvent(&window, &mouseEvent)); + } + + // Enter + { + QMouseEvent mouseEvent(QEvent::MouseMove, QPointF(50, 50), QPointF(50, 50), QPointF(150, 150), + Qt::NoButton, Qt::NoButton, Qt::NoModifier, Qt::MouseEventNotSynthesized); + mouseEvent.setTimestamp(20); + QVERIFY(QCoreApplication::sendEvent(&window, &mouseEvent)); + } + QCOMPARE(hoverConsumer->hoverTimestamps.size(), 1); + QCOMPARE(hoverConsumer->hoverTimestamps.last(), 20UL); + + // Move + { + QMouseEvent mouseEvent(QEvent::MouseMove, QPointF(60, 60), QPointF(60, 60), QPointF(160, 160), + Qt::NoButton, Qt::NoButton, Qt::NoModifier, Qt::MouseEventNotSynthesized); + mouseEvent.setTimestamp(30); + QVERIFY(QCoreApplication::sendEvent(&window, &mouseEvent)); + } + QCOMPARE(hoverConsumer->hoverTimestamps.size(), 2); + QCOMPARE(hoverConsumer->hoverTimestamps.last(), 30UL); + + // Move + { + QMouseEvent mouseEvent(QEvent::MouseMove, QPointF(100, 100), QPointF(100, 100), QPointF(200, 200), + Qt::NoButton, Qt::NoButton, Qt::NoModifier, Qt::MouseEventNotSynthesized); + mouseEvent.setTimestamp(40); + QVERIFY(QCoreApplication::sendEvent(&window, &mouseEvent)); + } + QCOMPARE(hoverConsumer->hoverTimestamps.size(), 3); + QCOMPARE(hoverConsumer->hoverTimestamps.last(), 40UL); + + // Leave + { + QMouseEvent mouseEvent(QEvent::MouseMove, QPointF(160, 160), QPointF(160, 160), QPointF(260, 260), + Qt::NoButton, Qt::NoButton, Qt::NoModifier, Qt::MouseEventNotSynthesized); + mouseEvent.setTimestamp(5); + QVERIFY(QCoreApplication::sendEvent(&window, &mouseEvent)); + } + QCOMPARE(hoverConsumer->hoverTimestamps.size(), 4); + QCOMPARE(hoverConsumer->hoverTimestamps.last(), 5UL); +} + QTEST_MAIN(tst_qquickwindow) #include "tst_qquickwindow.moc" diff --git a/tests/benchmarks/qml/qml.pro b/tests/benchmarks/qml/qml.pro index d3ce69c713..5d48ec0067 100644 --- a/tests/benchmarks/qml/qml.pro +++ b/tests/benchmarks/qml/qml.pro @@ -5,6 +5,7 @@ SUBDIRS += \ compilation \ javascript \ holistic \ + qqmlchangeset \ qqmlcomponent \ qqmlimage \ qqmlmetaproperty \ diff --git a/tests/benchmarks/qml/qqmlchangeset/qqmlchangeset.pro b/tests/benchmarks/qml/qqmlchangeset/qqmlchangeset.pro new file mode 100644 index 0000000000..fc0ccdf8ed --- /dev/null +++ b/tests/benchmarks/qml/qqmlchangeset/qqmlchangeset.pro @@ -0,0 +1,10 @@ +CONFIG += benchmark +TEMPLATE = app +TARGET = tst_qqmlchangeset +QT += qml quick-private testlib +osx:CONFIG -= app_bundle + +SOURCES += tst_qqmlchangeset.cpp + +DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0 + diff --git a/tests/benchmarks/qml/qqmlchangeset/tst_qqmlchangeset.cpp b/tests/benchmarks/qml/qqmlchangeset/tst_qqmlchangeset.cpp new file mode 100644 index 0000000000..bbfb52343c --- /dev/null +++ b/tests/benchmarks/qml/qqmlchangeset/tst_qqmlchangeset.cpp @@ -0,0 +1,60 @@ +/**************************************************************************** +** +** Copyright (C) 2016 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Milian Wolff <milian.wolff@kdab.com> +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <qtest.h> + +#include <QDebug> + +#include <private/qqmlchangeset_p.h> + +class tst_qqmlchangeset : public QObject +{ + Q_OBJECT + +private slots: + void move(); +}; + +void tst_qqmlchangeset::move() +{ + QBENCHMARK { + QQmlChangeSet set; + const int MAX_ROWS = 30000; + for (int i = 0; i < MAX_ROWS; ++i) { + set.move(i, MAX_ROWS - 1 - i, 1, i); + } + } +} + +QTEST_MAIN(tst_qqmlchangeset) +#include "tst_qqmlchangeset.moc" diff --git a/tests/manual/scenegraph_lancelot/scenegrabber/main.cpp b/tests/manual/scenegraph_lancelot/scenegrabber/main.cpp index a4b1a1be70..5098d51134 100644 --- a/tests/manual/scenegraph_lancelot/scenegrabber/main.cpp +++ b/tests/manual/scenegraph_lancelot/scenegrabber/main.cpp @@ -134,7 +134,7 @@ private: }; -extern uint qt_qhash_seed; +Q_CORE_EXPORT extern QBasicAtomicInt qt_qhash_seed; int main(int argc, char *argv[]) { diff --git a/tests/manual/v4/test262 b/tests/manual/v4/test262 -Subproject 0b5af3dcec772bb06b4d685a20b2859cda59d18 +Subproject 9741ac4655808ac46c127e3d1d8ba3d27ada618 diff --git a/tools/qmlplugindump/qmlplugindump.pro b/tools/qmlplugindump/qmlplugindump.pro index e45a7fad83..b38eea2554 100644 --- a/tools/qmlplugindump/qmlplugindump.pro +++ b/tools/qmlplugindump/qmlplugindump.pro @@ -17,7 +17,7 @@ macx { # Prevent qmlplugindump from popping up in the dock when launched. # We embed the Info.plist file, so the application doesn't need to # be a bundle. - QMAKE_LFLAGS += -sectcreate __TEXT __info_plist $$shell_quote($$PWD/Info.plist) + QMAKE_LFLAGS += -Wl,-sectcreate,__TEXT,__info_plist,$$shell_quote($$PWD/Info.plist) CONFIG -= app_bundle } |