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
This commit is contained in:
Liang Qi 2016-08-01 13:14:04 +02:00
commit 6839f03051
23 changed files with 454 additions and 76 deletions

View File

@ -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;

View File

@ -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());

View File

@ -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.

View File

@ -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; }

View File

@ -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.

View File

@ -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;

View File

@ -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]));

View File

@ -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

View File

@ -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;

View File

@ -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();

View File

@ -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);
}

View File

@ -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)

View File

@ -324,6 +324,7 @@ private slots:
void qtbug_46022();
void qtbug_52340();
void qtbug_54589();
void qtbug_54687();
private:
// static void propertyVarWeakRefCallback(v8::Persistent<v8::Value> object, void* parameter);
@ -7925,6 +7926,12 @@ void tst_qqmlecmascript::qtbug_54589()
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)

View File

@ -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 }

View File

@ -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>
@ -242,8 +244,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)
@ -524,6 +528,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;
@ -533,6 +546,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;
@ -586,7 +608,9 @@ signals:
void boolPropertyChanged();
void variantPropertyChanged();
void vectorPropertyChanged();
void vector2PropertyChanged();
void vector4PropertyChanged();
void quaternionPropertyChanged();
void urlPropertyChanged();
};

View File

@ -677,6 +677,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));

View File

@ -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"

View File

@ -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"

View File

@ -5,6 +5,7 @@ SUBDIRS += \
compilation \
javascript \
holistic \
qqmlchangeset \
qqmlcomponent \
qqmlimage \
qqmlmetaproperty \

View File

@ -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

View File

@ -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"

View File

@ -134,7 +134,7 @@ private:
};
extern uint qt_qhash_seed;
Q_CORE_EXPORT extern QBasicAtomicInt qt_qhash_seed;
int main(int argc, char *argv[])
{

View File

@ -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
}