diff options
author | Liang Qi <liang.qi@qt.io> | 2016-08-01 13:14:04 +0200 |
---|---|---|
committer | Liang Qi <liang.qi@qt.io> | 2016-08-01 13:14:04 +0200 |
commit | 6839f03051d2950e4721cbb5ee88fa7b07109588 (patch) | |
tree | d5cdfeeb6e59953f5109ef87a1be08f69fcddf7a /src | |
parent | cc5ead1b3c8ce79c240b70bdfcfb687fe60e50f5 (diff) | |
parent | fe92db0a0eeed502ef851930b3404b38c4a03f4f (diff) |
Merge remote-tracking branch 'origin/5.6' into 5.7
Conflicts:
tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp
tests/auto/quick/qquickitem/tst_qquickitem.cpp
Change-Id: If261f8eea84dfa5944bb55de999d1f70aba528fd
Diffstat (limited to 'src')
-rw-r--r-- | src/qml/compiler/qqmltypecompiler.cpp | 24 | ||||
-rw-r--r-- | src/qml/compiler/qv4codegen.cpp | 116 | ||||
-rw-r--r-- | src/qml/doc/src/cppintegration/data.qdoc | 2 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4value_p.h | 4 | ||||
-rw-r--r-- | src/qml/qml/qqmlcomponent.cpp | 2 | ||||
-rw-r--r-- | src/qml/qml/qqmlobjectcreator.cpp | 26 | ||||
-rw-r--r-- | src/qml/qml/qqmlopenmetaobject.cpp | 2 | ||||
-rw-r--r-- | src/quick/doc/src/concepts/modelviewsdata/cppmodels.qdoc | 105 | ||||
-rw-r--r-- | src/quick/items/qquickitemanimation.cpp | 42 | ||||
-rw-r--r-- | src/quick/items/qquickwindow.cpp | 6 | ||||
-rw-r--r-- | src/quick/scenegraph/qsgdefaultlayer.cpp | 31 | ||||
-rw-r--r-- | src/quick/scenegraph/qsgthreadedrenderloop.cpp | 2 |
12 files changed, 288 insertions, 74 deletions
diff --git a/src/qml/compiler/qqmltypecompiler.cpp b/src/qml/compiler/qqmltypecompiler.cpp index da00496cb2..f49996a3b8 100644 --- a/src/qml/compiler/qqmltypecompiler.cpp +++ b/src/qml/compiler/qqmltypecompiler.cpp @@ -2250,6 +2250,17 @@ bool QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache *propertyCa } } break; + case QVariant::Vector2D: { + struct { + float xp; + float yp; + } vec; + if (!QQmlStringConverters::createFromString(QMetaType::QVector2D, binding->valueAsString(qmlUnit), &vec, sizeof(vec))) { + recordError(binding->valueLocation, tr("Invalid property assignment: 2D vector expected")); + return false; + } + } + break; case QVariant::Vector3D: { struct { float xp; @@ -2275,6 +2286,19 @@ bool QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache *propertyCa } } 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))) { + recordError(binding->valueLocation, tr("Invalid property assignment: quaternion expected")); + return false; + } + } + break; case QVariant::RegExp: recordError(binding->valueLocation, tr("Invalid property assignment: regular expression expected; use /pattern/ syntax")); return false; diff --git a/src/qml/compiler/qv4codegen.cpp b/src/qml/compiler/qv4codegen.cpp index f5733b96f0..ad28e4d6d1 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); @@ -2223,7 +2288,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)); @@ -2235,7 +2303,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); @@ -2725,7 +2796,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/jsruntime/qv4value_p.h b/src/qml/jsruntime/qv4value_p.h index 39d488a42c..b2d64213f5 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 28eaae190b..c64851cac5 100644 --- a/src/qml/qml/qqmlcomponent.cpp +++ b/src/qml/qml/qqmlcomponent.cpp @@ -1152,7 +1152,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 eec9e5e2c9..831965f36a 100644 --- a/src/qml/qml/qqmlobjectcreator.cpp +++ b/src/qml/qml/qqmlobjectcreator.cpp @@ -514,6 +514,18 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv); } 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); + argv[0] = reinterpret_cast<void *>(&vec); + QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv); + } + break; case QVariant::Vector3D: { struct { float xp; @@ -541,6 +553,20 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv); } 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); + argv[0] = reinterpret_cast<void *>(&vec); + QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv); + } + 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/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/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp index aedd586a4f..46ae993a18 100644 --- a/src/quick/items/qquickwindow.cpp +++ b/src/quick/items/qquickwindow.cpp @@ -1633,6 +1633,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(); diff --git a/src/quick/scenegraph/qsgdefaultlayer.cpp b/src/quick/scenegraph/qsgdefaultlayer.cpp index ceab64478b..2f1c1d454c 100644 --- a/src/quick/scenegraph/qsgdefaultlayer.cpp +++ b/src/quick/scenegraph/qsgdefaultlayer.cpp @@ -48,29 +48,6 @@ DEFINE_BOOL_CONFIG_OPTION(qmlFboOverlay, QML_FBO_OVERLAY) #endif DEFINE_BOOL_CONFIG_OPTION(qmlFboFlushBeforeDetach, QML_FBO_FLUSH_BEFORE_DETACH) - - -static QOpenGLFramebufferObject *createFramebuffer(const QSize &size, - QOpenGLFramebufferObjectFormat format) -{ -#ifdef Q_OS_MACOS - QOpenGLContext *context = QOpenGLContext::currentContext(); - if (context->hasExtension("GL_ARB_framebuffer_sRGB") - && context->hasExtension("GL_EXT_texture_sRGB") - && context->hasExtension("GL_EXT_texture_sRGB_decode")) - format.setInternalTextureFormat(GL_SRGB8_ALPHA8_EXT); -#endif - QOpenGLFramebufferObject *fbo = new QOpenGLFramebufferObject(size, format); -#ifdef Q_OS_MACOS - if (format.internalTextureFormat() == GL_SRGB8_ALPHA8_EXT) { - QOpenGLFunctions *funcs = context->functions(); - funcs->glBindTexture(GL_TEXTURE_2D, fbo->texture()); - funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SRGB_DECODE_EXT, GL_SKIP_DECODE_EXT); - } -#endif - return fbo; -} - namespace { class BindableFbo : public QSGBindable @@ -353,7 +330,7 @@ void QSGDefaultLayer::grab() format.setInternalTextureFormat(m_format); format.setSamples(m_context->openglContext()->format().samples()); - m_secondaryFbo = createFramebuffer(m_size, format); + m_secondaryFbo = new QOpenGLFramebufferObject(m_size, format); m_depthStencilBuffer = m_context->depthStencilBufferForFbo(m_secondaryFbo); } else { QOpenGLFramebufferObjectFormat format; @@ -362,14 +339,14 @@ void QSGDefaultLayer::grab() if (m_recursive) { deleteFboLater = true; delete m_secondaryFbo; - m_secondaryFbo = createFramebuffer(m_size, format); + m_secondaryFbo = new QOpenGLFramebufferObject(m_size, format); funcs->glBindTexture(GL_TEXTURE_2D, m_secondaryFbo->texture()); updateBindOptions(true); m_depthStencilBuffer = m_context->depthStencilBufferForFbo(m_secondaryFbo); } else { delete m_fbo; delete m_secondaryFbo; - m_fbo = createFramebuffer(m_size, format); + m_fbo = new QOpenGLFramebufferObject(m_size, format); m_secondaryFbo = 0; funcs->glBindTexture(GL_TEXTURE_2D, m_fbo->texture()); updateBindOptions(true); @@ -383,7 +360,7 @@ void QSGDefaultLayer::grab() Q_ASSERT(m_fbo); Q_ASSERT(!m_multisampling); - m_secondaryFbo = createFramebuffer(m_size, m_fbo->format()); + m_secondaryFbo = new QOpenGLFramebufferObject(m_size, m_fbo->format()); funcs->glBindTexture(GL_TEXTURE_2D, m_secondaryFbo->texture()); updateBindOptions(true); } diff --git a/src/quick/scenegraph/qsgthreadedrenderloop.cpp b/src/quick/scenegraph/qsgthreadedrenderloop.cpp index 7c3405b715..96abd4267b 100644 --- a/src/quick/scenegraph/qsgthreadedrenderloop.cpp +++ b/src/quick/scenegraph/qsgthreadedrenderloop.cpp @@ -599,7 +599,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) |