aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorLiang Qi <liang.qi@qt.io>2016-08-01 13:14:04 +0200
committerLiang Qi <liang.qi@qt.io>2016-08-01 13:14:04 +0200
commit6839f03051d2950e4721cbb5ee88fa7b07109588 (patch)
treed5cdfeeb6e59953f5109ef87a1be08f69fcddf7a /src
parentcc5ead1b3c8ce79c240b70bdfcfb687fe60e50f5 (diff)
parentfe92db0a0eeed502ef851930b3404b38c4a03f4f (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.cpp24
-rw-r--r--src/qml/compiler/qv4codegen.cpp116
-rw-r--r--src/qml/doc/src/cppintegration/data.qdoc2
-rw-r--r--src/qml/jsruntime/qv4value_p.h4
-rw-r--r--src/qml/qml/qqmlcomponent.cpp2
-rw-r--r--src/qml/qml/qqmlobjectcreator.cpp26
-rw-r--r--src/qml/qml/qqmlopenmetaobject.cpp2
-rw-r--r--src/quick/doc/src/concepts/modelviewsdata/cppmodels.qdoc105
-rw-r--r--src/quick/items/qquickitemanimation.cpp42
-rw-r--r--src/quick/items/qquickwindow.cpp6
-rw-r--r--src/quick/scenegraph/qsgdefaultlayer.cpp31
-rw-r--r--src/quick/scenegraph/qsgthreadedrenderloop.cpp2
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)