aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/qml/common/qv4compileddata_p.h30
-rw-r--r--src/qml/compiler/qqmlirbuilder.cpp59
-rw-r--r--src/qml/compiler/qqmlirbuilder_p.h13
-rw-r--r--src/qml/parser/qqmljs.g95
-rw-r--r--src/qml/parser/qqmljsast.cpp8
-rw-r--r--src/qml/parser/qqmljsast_p.h25
-rw-r--r--src/qml/parser/qqmljsastfwd_p.h1
-rw-r--r--src/qml/parser/qqmljsastvisitor_p.h3
-rw-r--r--src/qml/parser/qqmljslexer.cpp2
-rw-r--r--src/qml/qml/qqmlincubator_p.h4
-rw-r--r--src/qml/qml/qqmlobjectcreator.cpp42
-rw-r--r--src/qml/qml/qqmlobjectcreator_p.h2
-rw-r--r--src/qml/qml/qqmlpropertycache.cpp13
-rw-r--r--src/qml/qml/qqmlpropertycache_p.h1
-rw-r--r--src/quick/handlers/qquickhoverhandler.cpp51
-rw-r--r--src/quick/handlers/qquickpointerhandler.cpp84
-rw-r--r--src/quick/handlers/qquickpointerhandler_p.h13
-rw-r--r--src/quick/handlers/qquickpointerhandler_p_p.h2
-rw-r--r--src/quick/items/qquickevents.cpp2
-rw-r--r--src/quick/items/qquickimagebase.cpp20
-rw-r--r--src/quick/items/qquickimagebase_p.h6
-rw-r--r--src/quick/items/qquickimagebase_p_p.h1
-rw-r--r--src/quick/items/qquickitem.cpp78
-rw-r--r--src/quick/items/qquickitem_p.h5
-rw-r--r--src/quick/items/qquickwindow.cpp37
-rw-r--r--src/quick/items/qquickwindow_p.h3
-rw-r--r--src/quick/util/qquickbehavior.cpp76
-rw-r--r--src/quick/util/qquickbehavior_p.h4
-rw-r--r--src/quick/util/qquickglobal.cpp60
-rw-r--r--src/quick/util/qquickimageprovider.cpp18
-rw-r--r--src/quick/util/qquickpixmapcache.cpp14
-rw-r--r--src/quick/util/qquickpixmapcache_p.h5
-rw-r--r--src/quick/util/qquickvaluetypes.cpp42
-rw-r--r--src/quick/util/qquickvaluetypes_p.h52
-rw-r--r--tests/auto/qml/debugger/qdebugmessageservice/tst_qdebugmessageservice.cpp2
-rw-r--r--tests/auto/qml/debugger/qqmldebugjs/tst_qqmldebugjs.cpp2
-rw-r--r--tests/auto/qml/debugger/qqmlenginecontrol/tst_qqmlenginecontrol.cpp10
-rw-r--r--tests/auto/qml/debugger/qqmlenginedebuginspectorintegrationtest/tst_qqmlenginedebuginspectorintegration.cpp2
-rw-r--r--tests/auto/qml/debugger/qqmlinspector/tst_qqmlinspector.cpp2
-rw-r--r--tests/auto/qml/debugger/qqmlpreview/tst_qqmlpreview.cpp2
-rw-r--r--tests/auto/qml/debugger/qqmlprofilerservice/tst_qqmlprofilerservice.cpp32
-rw-r--r--tests/auto/qml/debugger/shared/debugutil.cpp2
-rw-r--r--tests/auto/qml/debugger/shared/debugutil_p.h5
-rw-r--r--tests/auto/qml/qmlformat/tst_qmlformat.cpp1
-rw-r--r--tests/auto/qml/qqmllanguage/data/NonRequiredBase.qml5
-rw-r--r--tests/auto/qml/qqmllanguage/data/RequiredBase.qml3
-rw-r--r--tests/auto/qml/qqmllanguage/data/requiredProperties.3.qml6
-rw-r--r--tests/auto/qml/qqmllanguage/data/requiredProperties.4.qml5
-rw-r--r--tests/auto/qml/qqmllanguage/data/requiredProperties.5.qml1
-rw-r--r--tests/auto/qml/qqmllanguage/data/requiredProperties.6.qml3
-rw-r--r--tests/auto/qml/qqmllanguage/data/requiredProperties.7.qml5
-rw-r--r--tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp30
-rw-r--r--tests/auto/qml/qqmlparser/data/annotations/View1.qml76
-rw-r--r--tests/auto/qml/qqmlparser/data/noannotations/View1.qml76
-rw-r--r--tests/auto/qml/qqmlparser/tst_qqmlparser.cpp63
-rw-r--r--tests/auto/quick/pointerhandlers/qquickdraghandler/data/draggables.qml5
-rw-r--r--tests/auto/quick/pointerhandlers/qquickdraghandler/tst_qquickdraghandler.cpp15
-rw-r--r--tests/auto/quick/pointerhandlers/qquickhoverhandler/data/lesHoverables.qml12
-rw-r--r--tests/auto/quick/pointerhandlers/qquickhoverhandler/tst_qquickhoverhandler.cpp46
-rw-r--r--tests/auto/quick/qquickbehaviors/data/targetProperty.qml16
-rw-r--r--tests/auto/quick/qquickbehaviors/tst_qquickbehaviors.cpp22
-rw-r--r--tests/auto/quick/qquickimage/data/ProPhoto.jpgbin0 -> 30900 bytes
-rw-r--r--tests/auto/quick/qquickimage/data/image.qml5
-rw-r--r--tests/auto/quick/qquickimage/tst_qquickimage.cpp98
-rw-r--r--tests/auto/quick/qquickwindow/tst_qquickwindow.cpp4
-rw-r--r--tests/manual/pointer/sidebar.qml7
-rw-r--r--tests/manual/scenegraph_lancelot/data/shaders/gridmesh/attributes.qml65
-rw-r--r--tests/manual/scenegraph_lancelot/data/shaders/source/switch_3.qml9
68 files changed, 1348 insertions, 160 deletions
diff --git a/src/qml/common/qv4compileddata_p.h b/src/qml/common/qv4compileddata_p.h
index b9841a76b4..7d6ef14854 100644
--- a/src/qml/common/qv4compileddata_p.h
+++ b/src/qml/common/qv4compileddata_p.h
@@ -77,7 +77,7 @@ QT_BEGIN_NAMESPACE
// Also change the comment behind the number to describe the latest change. This has the added
// benefit that if another patch changes the version too, it will result in a merge conflict, and
// not get removed silently.
-#define QV4_DATA_STRUCTURE_VERSION 0x29 // Change version format
+#define QV4_DATA_STRUCTURE_VERSION 0x30// support additional required property features
class QIODevice;
class QQmlTypeNameCache;
@@ -672,6 +672,12 @@ struct Property
};
static_assert(sizeof(Property) == 12, "Property structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
+struct RequiredPropertyExtraData {
+ quint32_le nameIndex;
+};
+
+static_assert (sizeof(RequiredPropertyExtraData) == 4, "RequiredPropertyExtraData structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
+
struct Alias {
enum Flags : unsigned int {
IsReadOnly = 0x1,
@@ -742,13 +748,16 @@ struct Object
Location locationOfIdProperty;
quint32_le offsetToInlineComponents;
quint16_le nInlineComponents;
+ quint32_le offsetToRequiredPropertyExtraData;
+ quint16_le nRequiredPropertyExtraData;
// Function[]
// Property[]
// Signal[]
// Binding[]
// InlineComponent[]
+// RequiredPropertyExtraData[]
- static int calculateSizeExcludingSignalsAndEnums(int nFunctions, int nProperties, int nAliases, int nEnums, int nSignals, int nBindings, int nNamedObjectsInComponent, int nInlineComponents)
+ static int calculateSizeExcludingSignalsAndEnums(int nFunctions, int nProperties, int nAliases, int nEnums, int nSignals, int nBindings, int nNamedObjectsInComponent, int nInlineComponents, int nRequiredPropertyExtraData)
{
return ( sizeof(Object)
+ nFunctions * sizeof(quint32)
@@ -759,6 +768,7 @@ struct Object
+ nBindings * sizeof(Binding)
+ nNamedObjectsInComponent * sizeof(int)
+ nInlineComponents * sizeof(InlineComponent)
+ + nRequiredPropertyExtraData * sizeof(RequiredPropertyExtraData)
+ 0x7
) & ~0x7;
}
@@ -812,6 +822,16 @@ struct Object
return reinterpret_cast<const InlineComponent*>(reinterpret_cast<const char *>(this) + offsetToInlineComponents);
}
+ const RequiredPropertyExtraData *requiredPropertyExtraDataAt(int idx) const
+ {
+ return requiredPropertyExtraDataTable() + idx;
+ }
+
+ const RequiredPropertyExtraData *requiredPropertyExtraDataTable() const
+ {
+ return reinterpret_cast<const RequiredPropertyExtraData*>(reinterpret_cast<const char *>(this) + offsetToRequiredPropertyExtraData);
+ }
+
// --- QQmlPropertyCacheCreator interface
int propertyCount() const { return nProperties; }
int aliasCount() const { return nAliases; }
@@ -840,10 +860,14 @@ struct Object
InlineComponentIterator inlineComponentsBegin() const {return InlineComponentIterator(this, 0);}
InlineComponentIterator inlineComponentsEnd() const {return InlineComponentIterator(this, nInlineComponents);}
+ typedef TableIterator<RequiredPropertyExtraData, Object, &Object::requiredPropertyExtraDataAt> RequiredPropertyExtraDataIterator;
+ RequiredPropertyExtraDataIterator requiredPropertyExtraDataBegin() const {return RequiredPropertyExtraDataIterator(this, 0); };
+ RequiredPropertyExtraDataIterator requiredPropertyExtraDataEnd() const {return RequiredPropertyExtraDataIterator(this, nRequiredPropertyExtraData); };
+
int namedObjectsInComponentCount() const { return nNamedObjectsInComponent; }
// ---
};
-static_assert(sizeof(Object) == 76, "Object structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
+static_assert(sizeof(Object) == 84, "Object structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
struct Import
{
diff --git a/src/qml/compiler/qqmlirbuilder.cpp b/src/qml/compiler/qqmlirbuilder.cpp
index be02a08f82..4de7734ecf 100644
--- a/src/qml/compiler/qqmlirbuilder.cpp
+++ b/src/qml/compiler/qqmlirbuilder.cpp
@@ -64,6 +64,33 @@ using namespace QQmlJS;
return false; \
}
+void Object::simplifyRequiredProperties() {
+ // if a property of the current object was marked as required
+ // do not store that information in the ExtraData
+ // but rather mark the property as required
+ QSet<int> required;
+ for (auto it = this->requiredPropertyExtraDataBegin(); it != this->requiredPropertyExtraDataEnd(); ++it)
+ required.insert(it->nameIndex);
+ if (required.isEmpty())
+ return;
+ for (auto it = this->propertiesBegin(); it != this->propertiesEnd(); ++it) {
+ auto requiredIt = required.find(it->nameIndex);
+ if (requiredIt != required.end()) {
+ it->isRequired = true;
+ required.erase(requiredIt);
+ }
+ }
+ QmlIR::RequiredPropertyExtraData *prev = nullptr;
+ auto current = this->requiredPropertyExtraDatas->first;
+ while (current) {
+ if (required.contains(current->nameIndex))
+ prev = current;
+ else
+ requiredPropertyExtraDatas->unlink(prev, current);
+ current = current->next;
+ }
+}
+
bool Parameter::init(QV4::Compiler::JSUnitGenerator *stringGenerator, const QString &parameterName,
const QString &typeName)
{
@@ -162,6 +189,7 @@ void Object::init(QQmlJS::MemoryPool *pool, int typeNameIndex, int idIndex, cons
functions = pool->New<PoolList<Function> >();
functionsAndExpressions = pool->New<PoolList<CompiledFunctionOrExpression> >();
inlineComponents = pool->New<PoolList<InlineComponent>>();
+ requiredPropertyExtraDatas = pool->New<PoolList<RequiredPropertyExtraData>>();
declarationsOverride = nullptr;
}
@@ -287,6 +315,11 @@ void Object::appendInlineComponent(InlineComponent *ic)
inlineComponents->append(ic);
}
+void Object::appendRequiredPropertyExtraData(RequiredPropertyExtraData *extraData)
+{
+ requiredPropertyExtraDatas->append(extraData);
+}
+
QString Object::appendBinding(Binding *b, bool isListBinding)
{
const bool bindingToDefaultProperty = (b->propertyNameIndex == quint32(0));
@@ -448,6 +481,10 @@ bool IRBuilder::generateFromQml(const QString &code, const QString &url, Documen
qSwap(_imports, output->imports);
qSwap(_pragmas, output->pragmas);
qSwap(_objects, output->objects);
+
+ for (auto object: output->objects)
+ object->simplifyRequiredProperties();
+
return errors.isEmpty();
}
@@ -982,6 +1019,14 @@ bool IRBuilder::visit(QQmlJS::AST::UiSourceElement *node)
return false;
}
+bool IRBuilder::visit(AST::UiRequired *ast)
+{
+ auto extraData = New<RequiredPropertyExtraData>();
+ extraData->nameIndex = registerString(ast->name.toString());
+ _object->appendRequiredPropertyExtraData(extraData);
+ return false;
+}
+
QString IRBuilder::asString(QQmlJS::AST::UiQualifiedId *node)
{
QString s;
@@ -1577,7 +1622,7 @@ void QmlUnitGenerator::generate(Document &output, const QV4::CompiledData::Depen
uint nextOffset = objectOffset + objectOffsetTableSize;
for (Object *o : qAsConst(output.objects)) {
objectOffsets.insert(o, nextOffset);
- nextOffset += QV4::CompiledData::Object::calculateSizeExcludingSignalsAndEnums(o->functionCount(), o->propertyCount(), o->aliasCount(), o->enumCount(), o->signalCount(), o->bindingCount(), o->namedObjectsInComponent.size(), o->inlineComponentCount());
+ nextOffset += QV4::CompiledData::Object::calculateSizeExcludingSignalsAndEnums(o->functionCount(), o->propertyCount(), o->aliasCount(), o->enumCount(), o->signalCount(), o->bindingCount(), o->namedObjectsInComponent.size(), o->inlineComponentCount(), o->requiredPropertyExtraDataCount());
int signalTableSize = 0;
for (const Signal *s = o->firstSignal(); s; s = s->next)
@@ -1660,6 +1705,10 @@ void QmlUnitGenerator::generate(Document &output, const QV4::CompiledData::Depen
objectToWrite->offsetToInlineComponents = nextOffset;
nextOffset += objectToWrite->nInlineComponents * sizeof (QV4::CompiledData::InlineComponent);
+ objectToWrite->nRequiredPropertyExtraData = o->requiredPropertyExtraDataCount();
+ objectToWrite->offsetToRequiredPropertyExtraData = nextOffset;
+ nextOffset += objectToWrite->nRequiredPropertyExtraData * sizeof(QV4::CompiledData::RequiredPropertyExtraData);
+
quint32_le *functionsTable = reinterpret_cast<quint32_le *>(objectPtr + objectToWrite->offsetToFunctions);
for (const Function *f = o->firstFunction(); f; f = f->next)
*functionsTable++ = o->runtimeFunctionIndices.at(f->index);
@@ -1739,6 +1788,14 @@ void QmlUnitGenerator::generate(Document &output, const QV4::CompiledData::Depen
*icToWrite = *ic;
inlineComponentPtr += sizeof(QV4::CompiledData::InlineComponent);
}
+
+ char *requiredPropertyExtraDataPtr = objectPtr + objectToWrite->offsetToRequiredPropertyExtraData;
+ for (auto it = o->requiredPropertyExtraDataBegin(); it != o->requiredPropertyExtraDataEnd(); ++it) {
+ const RequiredPropertyExtraData *extraData = it.ptr;
+ QV4::CompiledData::RequiredPropertyExtraData *extraDataToWrite = reinterpret_cast<QV4::CompiledData::RequiredPropertyExtraData*>(requiredPropertyExtraDataPtr);
+ *extraDataToWrite = *extraData;
+ requiredPropertyExtraDataPtr += sizeof(QV4::CompiledData::RequiredPropertyExtraData);
+ }
}
if (!output.javaScriptCompilationUnit.data) {
diff --git a/src/qml/compiler/qqmlirbuilder_p.h b/src/qml/compiler/qqmlirbuilder_p.h
index ea27e65f86..ae74254a42 100644
--- a/src/qml/compiler/qqmlirbuilder_p.h
+++ b/src/qml/compiler/qqmlirbuilder_p.h
@@ -285,6 +285,11 @@ struct Alias : public QV4::CompiledData::Alias
Alias *next;
};
+struct RequiredPropertyExtraData : public QV4::CompiledData::RequiredPropertyExtraData
+{
+ RequiredPropertyExtraData *next;
+};
+
struct Function
{
QV4::CompiledData::Location location;
@@ -341,6 +346,9 @@ public:
int functionCount() const { return functions->count; }
const InlineComponent *inlineComponent() const { return inlineComponents->first; }
int inlineComponentCount() const { return inlineComponents->count; }
+ const RequiredPropertyExtraData *requiredPropertyExtraData() const {return requiredPropertyExtraDatas->first; }
+ int requiredPropertyExtraDataCount() const { return requiredPropertyExtraDatas->count; }
+ void simplifyRequiredProperties();
PoolList<Binding>::Iterator bindingsBegin() const { return bindings->begin(); }
PoolList<Binding>::Iterator bindingsEnd() const { return bindings->end(); }
@@ -356,6 +364,8 @@ public:
PoolList<Function>::Iterator functionsEnd() const { return functions->end(); }
PoolList<InlineComponent>::Iterator inlineComponentsBegin() const { return inlineComponents->begin(); }
PoolList<InlineComponent>::Iterator inlineComponentsEnd() const { return inlineComponents->end(); }
+ PoolList<RequiredPropertyExtraData>::Iterator requiredPropertyExtraDataBegin() const {return requiredPropertyExtraDatas->begin(); }
+ PoolList<RequiredPropertyExtraData>::Iterator requiredPropertyExtraDataEnd() const {return requiredPropertyExtraDatas->end(); }
// If set, then declarations for this object (and init bindings for these) should go into the
// specified object. Used for declarations inside group properties.
@@ -369,6 +379,7 @@ public:
QString appendAlias(Alias *prop, const QString &aliasName, bool isDefaultProperty, const QQmlJS::AST::SourceLocation &defaultToken, QQmlJS::AST::SourceLocation *errorLocation);
void appendFunction(QmlIR::Function *f);
void appendInlineComponent(InlineComponent *ic);
+ void appendRequiredPropertyExtraData(RequiredPropertyExtraData *extraData);
QString appendBinding(Binding *b, bool isListBinding);
Binding *findBinding(quint32 nameIndex) const;
@@ -393,6 +404,7 @@ private:
PoolList<Binding> *bindings;
PoolList<Function> *functions;
PoolList<InlineComponent> *inlineComponents;
+ PoolList<RequiredPropertyExtraData> *requiredPropertyExtraDatas;
};
struct Q_QMLCOMPILER_PRIVATE_EXPORT Pragma
@@ -469,6 +481,7 @@ public:
bool visit(QQmlJS::AST::UiPublicMember *ast) override;
bool visit(QQmlJS::AST::UiScriptBinding *ast) override;
bool visit(QQmlJS::AST::UiSourceElement *ast) override;
+ bool visit(QQmlJS::AST::UiRequired *ast) override;
void throwRecursionDepthError() override
{
diff --git a/src/qml/parser/qqmljs.g b/src/qml/parser/qqmljs.g
index 2b00caf378..879de92e5f 100644
--- a/src/qml/parser/qqmljs.g
+++ b/src/qml/parser/qqmljs.g
@@ -73,7 +73,7 @@
%token T_VAR "var" T_VOID "void" T_WHILE "while"
%token T_WITH "with" T_XOR "^" T_XOR_EQ "^="
%token T_NULL "null" T_TRUE "true" T_FALSE "false"
-%token T_CONST "const" T_LET "let"
+%token T_CONST "const" T_LET "let" T_AT "@"
%token T_DEBUGGER "debugger"
%token T_RESERVED_WORD "reserved word"
%token T_MULTILINE_STRING_LITERAL "multiline string literal"
@@ -739,7 +739,7 @@ TopLevel: T_FEED_JS_EXPRESSION Expression;
} break;
./
-TopLevel: T_FEED_UI_OBJECT_MEMBER UiObjectMember;
+TopLevel: T_FEED_UI_OBJECT_MEMBER UiAnnotatedObjectMember;
/.
case $rule_number: {
sym(1).Node = sym(2).Node;
@@ -913,21 +913,84 @@ Empty: ;
} break;
./
-UiRootMember: UiObjectDefinition;
+UiRootMember: UiAnnotatedObject;
/.
case $rule_number: {
sym(1).Node = new (pool) AST::UiObjectMemberList(sym(1).UiObjectMember);
} break;
./
-UiObjectMemberList: UiObjectMember;
+UiSimpleQualifiedId: T_IDENTIFIER;
+/.
+ case $rule_number: {
+ AST::IdentifierExpression *node = new (pool) AST::IdentifierExpression(stringRef(1));
+ node->identifierToken = loc(1);
+ sym(1).Node = node;
+ } break;
+./
+
+UiSimpleQualifiedId: UiSimpleQualifiedId T_DOT T_IDENTIFIER;
+/.
+ case $rule_number: {
+ AST::FieldMemberExpression *node = new (pool) AST::FieldMemberExpression(sym(1).Expression, stringRef(3));
+ node->dotToken = loc(2);
+ node->identifierToken = loc(3);
+ sym(1).Node = node;
+ } break;
+./
+
+UiAnnotationObjectDefinition: UiSimpleQualifiedId UiObjectInitializer;
+/.
+ case $rule_number: {
+ if (AST::UiQualifiedId *qualifiedId = reparseAsQualifiedId(sym(1).Expression)) {
+ sym(1).UiQualifiedId = qualifiedId;
+ } else {
+ sym(1).UiQualifiedId = 0;
+
+ diagnostic_messages.append(compileError(loc(1),
+ QLatin1String("Expected a qualified name id")));
+
+ return false;
+ }
+ AST::UiObjectDefinition *node = new (pool) AST::UiObjectDefinition(sym(1).UiQualifiedId, sym(2).UiObjectInitializer);
+ sym(1).Node = node;
+ } break;
+./
+
+UiAnnotation: T_AT UiAnnotationObjectDefinition;
+
+UiAnnotationList: UiAnnotation;
+/.
+ case $rule_number: {
+ sym(1).Node = new (pool) AST::UiArrayMemberList(sym(1).UiObjectMember);
+ } break;
+./
+
+UiAnnotationList: UiAnnotationList UiAnnotation;
+/.
+ case $rule_number: {
+ AST::UiArrayMemberList *node = new (pool) AST::UiArrayMemberList(sym(1).UiArrayMemberList, sym(3).UiObjectMember);
+ sym(1).Node = node;
+ } break;
+./
+
+UiAnnotatedObject: UiAnnotationList UiObjectDefinition;
+/.
+ case $rule_number: {
+ sym(1).Node = sym(2).Node;
+ } break;
+./
+
+UiAnnotatedObject: UiObjectDefinition;
+
+UiObjectMemberList: UiAnnotatedObjectMember;
/.
case $rule_number: {
sym(1).Node = new (pool) AST::UiObjectMemberList(sym(1).UiObjectMember);
} break;
./
-UiObjectMemberList: UiObjectMemberList UiObjectMember;
+UiObjectMemberList: UiObjectMemberList UiAnnotatedObjectMember;
/.
case $rule_number: {
AST::UiObjectMemberList *node = new (pool) AST:: UiObjectMemberList(sym(1).UiObjectMemberList, sym(2).UiObjectMember);
@@ -979,6 +1042,15 @@ UiObjectDefinition: UiQualifiedId UiObjectInitializer;
} break;
./
+UiAnnotatedObjectMember: UiAnnotationList UiObjectMember;
+/.
+ case $rule_number: {
+ sym(1).Node = sym(2).Node;
+ } break;
+./
+
+UiAnnotatedObjectMember: UiObjectMember;
+
UiObjectMember: UiObjectDefinition;
UiObjectMember: UiQualifiedId T_COLON ExpressionStatementLookahead T_LBRACKET UiArrayMemberList T_RBRACKET;
@@ -1278,6 +1350,18 @@ OptionalSemicolon: | Semicolon;
and then we would miss a semicolon (see tests/auto/quick/qquickvisualdatamodel/data/objectlist.qml)*/
./
+UiRequired: T_REQUIRED QmlIdentifier Semicolon;
+/.
+ case $rule_number: {
+ AST::UiRequired *node = new (pool) AST::UiRequired(stringRef(2));
+ node->requiredToken = loc(1);
+ node->semicolonToken = loc(3);
+ sym(1).Node = node;
+ } break;
+./
+
+UiObjectMember: UiRequired;
+
UiObjectMember: T_REQUIRED UiObjectMemberPropertyNoInitialiser;
/.
case $rule_number: {
@@ -1288,7 +1372,6 @@ UiObjectMember: T_REQUIRED UiObjectMemberPropertyNoInitialiser;
} break;
./
-
UiObjectMemberWithScriptStatement: T_PROPERTY UiPropertyType QmlIdentifier T_COLON UiScriptStatement OptionalSemicolon;
/.
case $rule_number: {
diff --git a/src/qml/parser/qqmljsast.cpp b/src/qml/parser/qqmljsast.cpp
index aa3e8ab5e3..416916c547 100644
--- a/src/qml/parser/qqmljsast.cpp
+++ b/src/qml/parser/qqmljsast.cpp
@@ -1554,6 +1554,14 @@ void UiInlineComponent::accept0(Visitor *visitor)
visitor->endVisit(this);
}
+void UiRequired::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ }
+
+ visitor->endVisit(this);
+}
+
} } // namespace QQmlJS::AST
QT_END_NAMESPACE
diff --git a/src/qml/parser/qqmljsast_p.h b/src/qml/parser/qqmljsast_p.h
index a7c95eee2d..446704be91 100644
--- a/src/qml/parser/qqmljsast_p.h
+++ b/src/qml/parser/qqmljsast_p.h
@@ -259,7 +259,8 @@ public:
Kind_UiHeaderItemList,
Kind_UiEnumDeclaration,
Kind_UiEnumMemberList,
- Kind_UiVersionSpecifier
+ Kind_UiVersionSpecifier,
+ Kind_UiRequired
};
inline Node() {}
@@ -3106,6 +3107,28 @@ public:
SourceLocation semicolonToken;
};
+class QML_PARSER_EXPORT UiRequired: public Node
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(UiRequired)
+
+ UiRequired(QStringRef name)
+ :name(name)
+ { kind = K; }
+
+ void accept0(Visitor *visitor) override;
+
+ SourceLocation firstSourceLocation() const override
+ { return requiredToken; }
+
+ SourceLocation lastSourceLocation() const override
+ { return semicolonToken; }
+
+ QStringRef name;
+ SourceLocation requiredToken;
+ SourceLocation semicolonToken;
+};
+
class QML_PARSER_EXPORT UiHeaderItemList: public Node
{
public:
diff --git a/src/qml/parser/qqmljsastfwd_p.h b/src/qml/parser/qqmljsastfwd_p.h
index 8a8ee2dfae..fe260e2bb5 100644
--- a/src/qml/parser/qqmljsastfwd_p.h
+++ b/src/qml/parser/qqmljsastfwd_p.h
@@ -183,6 +183,7 @@ class UiHeaderItemList;
class UiEnumDeclaration;
class UiEnumMemberList;
class UiVersionSpecifier;
+class UiRequired;
} // namespace AST
} // namespace QQmlJS
diff --git a/src/qml/parser/qqmljsastvisitor_p.h b/src/qml/parser/qqmljsastvisitor_p.h
index d6b92990ad..fcc48da1d3 100644
--- a/src/qml/parser/qqmljsastvisitor_p.h
+++ b/src/qml/parser/qqmljsastvisitor_p.h
@@ -414,6 +414,9 @@ public:
virtual bool visit(TypeAnnotation *) { return true; }
virtual void endVisit(TypeAnnotation *) {}
+ virtual bool visit(UiRequired *) { return true; }
+ virtual void endVisit(UiRequired *) {}
+
virtual void throwRecursionDepthError() = 0;
quint16 recursionDepth() const { return m_recursionDepth; }
diff --git a/src/qml/parser/qqmljslexer.cpp b/src/qml/parser/qqmljslexer.cpp
index 80d883e52f..0c61679f0b 100644
--- a/src/qml/parser/qqmljslexer.cpp
+++ b/src/qml/parser/qqmljslexer.cpp
@@ -719,6 +719,8 @@ again:
case ')': return T_RPAREN;
case '(': return T_LPAREN;
+ case '@': return T_AT;
+
case '&':
if (_char == QLatin1Char('=')) {
scanChar();
diff --git a/src/qml/qml/qqmlincubator_p.h b/src/qml/qml/qqmlincubator_p.h
index aadb147bd5..a674ff274f 100644
--- a/src/qml/qml/qqmlincubator_p.h
+++ b/src/qml/qml/qqmlincubator_p.h
@@ -61,9 +61,7 @@
QT_BEGIN_NAMESPACE
-class QQmlPropertyData;
-struct RequiredPropertyInfo;
-using RequiredProperties = QHash<QQmlPropertyData*, RequiredPropertyInfo>;
+class RequiredProperties;
class QQmlIncubator;
class Q_QML_PRIVATE_EXPORT QQmlIncubatorPrivate : public QQmlEnginePrivate::Incubator
diff --git a/src/qml/qml/qqmlobjectcreator.cpp b/src/qml/qml/qqmlobjectcreator.cpp
index a26cdba53a..6cc2bf49c8 100644
--- a/src/qml/qml/qqmlobjectcreator.cpp
+++ b/src/qml/qml/qqmlobjectcreator.cpp
@@ -1505,23 +1505,45 @@ bool QQmlObjectCreator::populateInstance(int index, QObject *instance, QObject *
if (_compiledObject->flags & QV4::CompiledData::Object::HasDeferredBindings)
_ddata->deferData(_compiledObjectIndex, compilationUnit, context);
+ QSet<QString> postHocRequired;
+ for (auto it = _compiledObject->requiredPropertyExtraDataBegin(); it != _compiledObject->requiredPropertyExtraDataEnd(); ++it)
+ postHocRequired.insert(stringAt(it->nameIndex));
+ bool hadInheritedRequiredProperties = !postHocRequired.empty();
+
for (int propertyIndex = 0; propertyIndex != _compiledObject->propertyCount(); ++propertyIndex) {
const QV4::CompiledData::Property* property = _compiledObject->propertiesBegin() + propertyIndex;
QQmlPropertyData *propertyData = _propertyCache->property(_propertyCache->propertyOffset() + propertyIndex);
- if (property->isRequired) {
- sharedState->hadRequiredProperties = true;
- sharedState->requiredProperties.insert(propertyData,
- RequiredPropertyInfo {compilationUnit->stringAt(property->nameIndex), compilationUnit->finalUrl(), property->location, {}});
- }
+ // only compute stringAt if there's a chance for the lookup to succeed
+ auto postHocIt = postHocRequired.isEmpty() ? postHocRequired.end() : postHocRequired.find(stringAt(property->nameIndex));
+ if (!property->isRequired && postHocRequired.end() == postHocIt)
+ continue;
+ if (postHocIt != postHocRequired.end())
+ postHocRequired.erase(postHocIt);
+ sharedState->hadRequiredProperties = true;
+ sharedState->requiredProperties.insert(propertyData,
+ RequiredPropertyInfo {compilationUnit->stringAt(property->nameIndex), compilationUnit->finalUrl(), property->location, {}});
+
}
for (int i = 0; i <= _propertyCache->propertyOffset(); ++i) {
- QQmlPropertyData *propertyData = _propertyCache->property(i);
- if (propertyData && propertyData->isRequired()) {
- sharedState->hadRequiredProperties = true;
- sharedState->requiredProperties.insert(propertyData, RequiredPropertyInfo {propertyData->name(_qobject), compilationUnit->finalUrl(), _compiledObject->location, {}});
- }
+ QQmlPropertyData *propertyData = _propertyCache->maybeUnresolvedProperty(i);
+ if (!propertyData)
+ continue;
+ if (!propertyData->isRequired() && postHocRequired.isEmpty())
+ continue;
+ QString name = propertyData->name(_qobject);
+ auto postHocIt = postHocRequired.find(name);
+ if (!propertyData->isRequired() && postHocRequired.end() == postHocIt )
+ continue;
+
+ if (postHocIt != postHocRequired.end())
+ postHocRequired.erase(postHocIt);
+
+ sharedState->hadRequiredProperties = true;
+ sharedState->requiredProperties.insert(propertyData, RequiredPropertyInfo {name, compilationUnit->finalUrl(), _compiledObject->location, {}});
}
+ if (!postHocRequired.isEmpty() && hadInheritedRequiredProperties)
+ recordError({}, QLatin1String("Property %1 was marked as required but does not exist").arg(*postHocRequired.begin()));
if (_compiledObject->nFunctions > 0)
setupFunctions();
diff --git a/src/qml/qml/qqmlobjectcreator_p.h b/src/qml/qml/qqmlobjectcreator_p.h
index f8ad90be15..bca450addb 100644
--- a/src/qml/qml/qqmlobjectcreator_p.h
+++ b/src/qml/qml/qqmlobjectcreator_p.h
@@ -86,7 +86,7 @@ struct RequiredPropertyInfo
QVector<AliasToRequiredInfo> aliasesToRequired;
};
-using RequiredProperties = QHash<QQmlPropertyData*, RequiredPropertyInfo>;
+class RequiredProperties : public QHash<QQmlPropertyData*, RequiredPropertyInfo> {};
struct QQmlObjectCreatorSharedState : public QSharedData
{
diff --git a/src/qml/qml/qqmlpropertycache.cpp b/src/qml/qml/qqmlpropertycache.cpp
index 8d91fa29e4..540e6afda1 100644
--- a/src/qml/qml/qqmlpropertycache.cpp
+++ b/src/qml/qml/qqmlpropertycache.cpp
@@ -400,6 +400,19 @@ const QMetaObject *QQmlPropertyCache::createMetaObject()
return _metaObject;
}
+QQmlPropertyData *QQmlPropertyCache::maybeUnresolvedProperty(int index) const
+{
+ if (index < 0 || index >= (propertyIndexCacheStart + propertyIndexCache.count()))
+ return nullptr;
+
+ QQmlPropertyData *rv = nullptr;
+ if (index < propertyIndexCacheStart)
+ return _parent->maybeUnresolvedProperty(index);
+ else
+ rv = const_cast<QQmlPropertyData *>(&propertyIndexCache.at(index - propertyIndexCacheStart));
+ return rv;
+}
+
QQmlPropertyData *QQmlPropertyCache::defaultProperty() const
{
return property(defaultPropertyName(), nullptr, nullptr);
diff --git a/src/qml/qml/qqmlpropertycache_p.h b/src/qml/qml/qqmlpropertycache_p.h
index 9c576aab39..9e6eaf9778 100644
--- a/src/qml/qml/qqmlpropertycache_p.h
+++ b/src/qml/qml/qqmlpropertycache_p.h
@@ -120,6 +120,7 @@ public:
}
QQmlPropertyData *property(int) const;
+ QQmlPropertyData *maybeUnresolvedProperty(int) const;
QQmlPropertyData *method(int) const;
QQmlPropertyData *signal(int index) const;
QQmlEnumData *qmlEnum(int) const;
diff --git a/src/quick/handlers/qquickhoverhandler.cpp b/src/quick/handlers/qquickhoverhandler.cpp
index 79cb288af8..1216eda477 100644
--- a/src/quick/handlers/qquickhoverhandler.cpp
+++ b/src/quick/handlers/qquickhoverhandler.cpp
@@ -64,6 +64,9 @@ Q_LOGGING_CATEGORY(lcHoverHandler, "qt.quick.handler.hover")
properties can be used to narrow the behavior to detect hovering of
specific kinds of devices or while holding a modifier key.
+ The \l cursorShape property allows changing the cursor whenever
+ \l hovered changes to \c true.
+
\sa MouseArea, PointHandler
*/
@@ -125,4 +128,52 @@ void QQuickHoverHandler::setHovered(bool hovered)
}
}
+/*!
+ \since 5.15
+ \qmlproperty Qt::CursorShape QtQuick::HoverHandler::cursorShape
+ This property holds the cursor shape that will appear whenever
+ \l hovered is \c true and no other handler is overriding it.
+
+ The available cursor shapes are:
+ \list
+ \li Qt.ArrowCursor
+ \li Qt.UpArrowCursor
+ \li Qt.CrossCursor
+ \li Qt.WaitCursor
+ \li Qt.IBeamCursor
+ \li Qt.SizeVerCursor
+ \li Qt.SizeHorCursor
+ \li Qt.SizeBDiagCursor
+ \li Qt.SizeFDiagCursor
+ \li Qt.SizeAllCursor
+ \li Qt.BlankCursor
+ \li Qt.SplitVCursor
+ \li Qt.SplitHCursor
+ \li Qt.PointingHandCursor
+ \li Qt.ForbiddenCursor
+ \li Qt.WhatsThisCursor
+ \li Qt.BusyCursor
+ \li Qt.OpenHandCursor
+ \li Qt.ClosedHandCursor
+ \li Qt.DragCopyCursor
+ \li Qt.DragMoveCursor
+ \li Qt.DragLinkCursor
+ \endlist
+
+ The default value of this property is not set, which allows any active
+ handler on the same \l parentItem to determine the cursor shape.
+ This property can be reset to the initial condition by setting it to
+ \c undefined.
+
+ If any handler with defined \c cursorShape is
+ \l {PointerHandler::active}{active}, that cursor will appear.
+ Else if the HoverHandler has a defined \c cursorShape, that cursor will appear.
+ Otherwise, the \l {QQuickItem::cursor()}{cursor} of \l parentItem will appear.
+
+ \note When this property has not been set, or has been set to \c undefined,
+ if you read the value it will return \c Qt.ArrowCursor.
+
+ \sa Qt::CursorShape, QQuickItem::cursor()
+*/
+
QT_END_NAMESPACE
diff --git a/src/quick/handlers/qquickpointerhandler.cpp b/src/quick/handlers/qquickpointerhandler.cpp
index c498c96454..adb753e000 100644
--- a/src/quick/handlers/qquickpointerhandler.cpp
+++ b/src/quick/handlers/qquickpointerhandler.cpp
@@ -51,7 +51,6 @@ Q_LOGGING_CATEGORY(lcPointerHandlerActive, "qt.quick.handler.active")
\qmltype PointerHandler
\qmlabstract
\since 5.10
- \preliminary
\instantiates QQuickPointerHandler
\inqmlmodule QtQuick
\brief Abstract handler for pointer events.
@@ -154,6 +153,87 @@ void QQuickPointerHandler::resetDragThreshold()
}
/*!
+ \since 5.15
+ \qmlproperty Qt::CursorShape PointerHandler::cursorShape
+ This property holds the cursor shape that will appear whenever the mouse is
+ hovering over the \l parentItem while \l active is \c true.
+
+ The available cursor shapes are:
+ \list
+ \li Qt.ArrowCursor
+ \li Qt.UpArrowCursor
+ \li Qt.CrossCursor
+ \li Qt.WaitCursor
+ \li Qt.IBeamCursor
+ \li Qt.SizeVerCursor
+ \li Qt.SizeHorCursor
+ \li Qt.SizeBDiagCursor
+ \li Qt.SizeFDiagCursor
+ \li Qt.SizeAllCursor
+ \li Qt.BlankCursor
+ \li Qt.SplitVCursor
+ \li Qt.SplitHCursor
+ \li Qt.PointingHandCursor
+ \li Qt.ForbiddenCursor
+ \li Qt.WhatsThisCursor
+ \li Qt.BusyCursor
+ \li Qt.OpenHandCursor
+ \li Qt.ClosedHandCursor
+ \li Qt.DragCopyCursor
+ \li Qt.DragMoveCursor
+ \li Qt.DragLinkCursor
+ \endlist
+
+ The default value is not set, which allows the \l {QQuickItem::cursor()}{cursor}
+ of \l parentItem to appear. This property can be reset to the same initial
+ condition by setting it to undefined.
+
+ \note When this property has not been set, or has been set to \c undefined,
+ if you read the value it will return \c Qt.ArrowCursor.
+
+ \sa Qt::CursorShape, QQuickItem::cursor(), HoverHandler::cursorShape
+*/
+#if QT_CONFIG(cursor)
+Qt::CursorShape QQuickPointerHandler::cursorShape() const
+{
+ Q_D(const QQuickPointerHandler);
+ return d->cursorShape;
+}
+
+void QQuickPointerHandler::setCursorShape(Qt::CursorShape shape)
+{
+ Q_D(QQuickPointerHandler);
+ if (d->cursorSet && shape == d->cursorShape)
+ return;
+ d->cursorShape = shape;
+ d->cursorSet = true;
+ QQuickItemPrivate *itemPriv = QQuickItemPrivate::get(parentItem());
+ itemPriv->hasCursorHandler = true;
+ itemPriv->setHasCursorInChild(true);
+ emit cursorShapeChanged();
+}
+
+void QQuickPointerHandler::resetCursorShape()
+{
+ Q_D(QQuickPointerHandler);
+ if (!d->cursorSet)
+ return;
+ d->cursorShape = Qt::ArrowCursor;
+ d->cursorSet = false;
+ QQuickItemPrivate *itemPriv = QQuickItemPrivate::get(parentItem());
+ itemPriv->hasCursorHandler = false;
+ itemPriv->setHasCursorInChild(itemPriv->hasCursor);
+ emit cursorShapeChanged();
+}
+
+bool QQuickPointerHandler::isCursorShapeExplicitlySet() const
+{
+ Q_D(const QQuickPointerHandler);
+ return d->cursorSet;
+}
+#endif
+
+/*!
Notification that the grab has changed in some way which is relevant to this handler.
The \a grabber (subject) will be the Input Handler whose state is changing,
or null if the state change regards an Item.
@@ -597,11 +677,13 @@ QQuickPointerHandlerPrivate::QQuickPointerHandlerPrivate()
: grabPermissions(QQuickPointerHandler::CanTakeOverFromItems |
QQuickPointerHandler::CanTakeOverFromHandlersOfDifferentType |
QQuickPointerHandler::ApprovesTakeOverByAnything)
+ , cursorShape(Qt::ArrowCursor)
, enabled(true)
, active(false)
, targetExplicitlySet(false)
, hadKeepMouseGrab(false)
, hadKeepTouchGrab(false)
+ , cursorSet(false)
{
}
diff --git a/src/quick/handlers/qquickpointerhandler_p.h b/src/quick/handlers/qquickpointerhandler_p.h
index 34ae9ce2c2..7262f4bcd3 100644
--- a/src/quick/handlers/qquickpointerhandler_p.h
+++ b/src/quick/handlers/qquickpointerhandler_p.h
@@ -72,6 +72,9 @@ class Q_QUICK_PRIVATE_EXPORT QQuickPointerHandler : public QObject, public QQmlP
Q_PROPERTY(GrabPermissions grabPermissions READ grabPermissions WRITE setGrabPermissions NOTIFY grabPermissionChanged)
Q_PROPERTY(qreal margin READ margin WRITE setMargin NOTIFY marginChanged)
Q_PROPERTY(int dragThreshold READ dragThreshold WRITE setDragThreshold RESET resetDragThreshold NOTIFY dragThresholdChanged REVISION 15)
+#if QT_CONFIG(cursor)
+ Q_PROPERTY(Qt::CursorShape cursorShape READ cursorShape WRITE setCursorShape RESET resetCursorShape NOTIFY cursorShapeChanged REVISION 15)
+#endif
QML_NAMED_ELEMENT(PointerHandler)
QML_UNCREATABLE("PointerHandler is an abstract base class.")
@@ -119,6 +122,13 @@ public:
void setDragThreshold(int t);
void resetDragThreshold();
+#if QT_CONFIG(cursor)
+ Qt::CursorShape cursorShape() const;
+ void setCursorShape(Qt::CursorShape shape);
+ void resetCursorShape();
+ bool isCursorShapeExplicitlySet() const;
+#endif
+
Q_SIGNALS:
void enabledChanged();
void activeChanged();
@@ -128,6 +138,9 @@ Q_SIGNALS:
void grabChanged(QQuickEventPoint::GrabTransition transition, QQuickEventPoint *point);
void grabPermissionChanged();
void canceled(QQuickEventPoint *point);
+#if QT_CONFIG(cursor)
+ Q_REVISION(15) void cursorShapeChanged();
+#endif
protected:
QQuickPointerHandler(QQuickPointerHandlerPrivate &dd, QQuickItem *parent);
diff --git a/src/quick/handlers/qquickpointerhandler_p_p.h b/src/quick/handlers/qquickpointerhandler_p_p.h
index 5727b1ef55..db053fb6b4 100644
--- a/src/quick/handlers/qquickpointerhandler_p_p.h
+++ b/src/quick/handlers/qquickpointerhandler_p_p.h
@@ -79,11 +79,13 @@ public:
qreal m_margin = 0;
qint16 dragThreshold = -1; // -1 means use the platform default
uint8_t grabPermissions : 8;
+ Qt::CursorShape cursorShape : 6;
bool enabled : 1;
bool active : 1;
bool targetExplicitlySet : 1;
bool hadKeepMouseGrab : 1; // some handlers override target()->setKeepMouseGrab(); this remembers previous state
bool hadKeepTouchGrab : 1; // some handlers override target()->setKeepTouchGrab(); this remembers previous state
+ bool cursorSet : 1;
};
QT_END_NAMESPACE
diff --git a/src/quick/items/qquickevents.cpp b/src/quick/items/qquickevents.cpp
index 03280e4c1f..469dc3cb4d 100644
--- a/src/quick/items/qquickevents.cpp
+++ b/src/quick/items/qquickevents.cpp
@@ -1626,6 +1626,8 @@ bool QQuickSinglePointEvent::allPointsGrabbed() const
QMouseEvent *QQuickPointerMouseEvent::asMouseEvent(const QPointF &localPos) const
{
+ if (!m_event)
+ return nullptr;
auto event = static_cast<QMouseEvent *>(m_event);
event->setLocalPos(localPos);
return event;
diff --git a/src/quick/items/qquickimagebase.cpp b/src/quick/items/qquickimagebase.cpp
index 2118f67387..8849c2005c 100644
--- a/src/quick/items/qquickimagebase.cpp
+++ b/src/quick/items/qquickimagebase.cpp
@@ -396,6 +396,10 @@ void QQuickImageBase::requestFinished()
d->frameCount = d->pix.frameCount();
emit frameCountChanged();
}
+ if (d->colorSpace != d->pix.colorSpace()) {
+ d->colorSpace = d->pix.colorSpace();
+ emit colorSpaceChanged();
+ }
update();
}
@@ -488,6 +492,22 @@ void QQuickImageBase::setAutoTransform(bool transform)
emitAutoTransformBaseChanged();
}
+QColorSpace QQuickImageBase::colorSpace() const
+{
+ Q_D(const QQuickImageBase);
+ return d->colorSpace;
+}
+
+void QQuickImageBase::setColorSpace(const QColorSpace &colorSpace)
+{
+ Q_D(QQuickImageBase);
+ if (d->colorSpace == colorSpace)
+ return;
+ d->colorSpace = colorSpace;
+ d->providerOptions.setTargetColorSpace(colorSpace);
+ emit colorSpaceChanged();
+}
+
QT_END_NAMESPACE
#include "moc_qquickimagebase_p.cpp"
diff --git a/src/quick/items/qquickimagebase_p.h b/src/quick/items/qquickimagebase_p.h
index 238b31b2e5..095547a2cf 100644
--- a/src/quick/items/qquickimagebase_p.h
+++ b/src/quick/items/qquickimagebase_p.h
@@ -53,6 +53,7 @@
#include "qquickimplicitsizeitem_p.h"
#include <private/qtquickglobal_p.h>
+#include <QtGui/qcolorspace.h>
QT_BEGIN_NAMESPACE
@@ -70,6 +71,7 @@ class Q_QUICK_PRIVATE_EXPORT QQuickImageBase : public QQuickImplicitSizeItem
Q_PROPERTY(bool mirror READ mirror WRITE setMirror NOTIFY mirrorChanged)
Q_PROPERTY(int currentFrame READ currentFrame WRITE setCurrentFrame NOTIFY currentFrameChanged REVISION 14)
Q_PROPERTY(int frameCount READ frameCount NOTIFY frameCountChanged REVISION 14)
+ Q_PROPERTY(QColorSpace colorSpace READ colorSpace WRITE setColorSpace NOTIFY colorSpaceChanged REVISION 15)
QML_NAMED_ELEMENT(ImageBase);
QML_ADDED_IN_MINOR_VERSION(14)
@@ -122,6 +124,9 @@ public:
virtual void setAutoTransform(bool transform);
bool autoTransform() const;
+ QColorSpace colorSpace() const;
+ virtual void setColorSpace(const QColorSpace &colorSpace);
+
static void resolve2xLocalFile(const QUrl &url, qreal targetDevicePixelRatio, QUrl *sourceUrl, qreal *sourceDevicePixelRatio);
// Use a virtual rather than a signal->signal to avoid the huge
@@ -139,6 +144,7 @@ Q_SIGNALS:
Q_REVISION(14) void currentFrameChanged();
Q_REVISION(14) void frameCountChanged();
Q_REVISION(15) void sourceClipRectChanged();
+ Q_REVISION(15) void colorSpaceChanged();
protected:
void loadEmptyUrl();
diff --git a/src/quick/items/qquickimagebase_p_p.h b/src/quick/items/qquickimagebase_p_p.h
index 00a9295ef0..ebb7568caf 100644
--- a/src/quick/items/qquickimagebase_p_p.h
+++ b/src/quick/items/qquickimagebase_p_p.h
@@ -88,6 +88,7 @@ public:
qreal devicePixelRatio;
QRectF sourceClipRect;
QQuickImageProviderOptions providerOptions;
+ QColorSpace colorSpace;
int currentFrame;
int frameCount;
bool async : 1;
diff --git a/src/quick/items/qquickitem.cpp b/src/quick/items/qquickitem.cpp
index 03cdeb5bef..fe8df6fb64 100644
--- a/src/quick/items/qquickitem.cpp
+++ b/src/quick/items/qquickitem.cpp
@@ -3244,6 +3244,7 @@ QQuickItemPrivate::QQuickItemPrivate()
#else
, touchEnabled(false)
#endif
+ , hasCursorHandler(false)
, dirtyAttributes(0)
, nextDirtyItem(nullptr)
, prevDirtyItem(nullptr)
@@ -7472,14 +7473,14 @@ void QQuickItem::setAcceptTouchEvents(bool enabled)
d->touchEnabled = enabled;
}
-void QQuickItemPrivate::setHasCursorInChild(bool hasCursor)
+void QQuickItemPrivate::setHasCursorInChild(bool hc)
{
#if QT_CONFIG(cursor)
Q_Q(QQuickItem);
// if we're asked to turn it off (because of an unsetcursor call, or a node
// removal) then we should make sure it's really ok to turn it off.
- if (!hasCursor && subtreeCursorEnabled) {
+ if (!hc && subtreeCursorEnabled) {
if (hasCursor)
return; // nope! sorry, I have a cursor myself
for (QQuickItem *otherChild : qAsConst(childItems)) {
@@ -7489,14 +7490,14 @@ void QQuickItemPrivate::setHasCursorInChild(bool hasCursor)
}
}
- subtreeCursorEnabled = hasCursor;
+ subtreeCursorEnabled = hc;
QQuickItem *parent = q->parentItem();
if (parent) {
QQuickItemPrivate *parentPrivate = QQuickItemPrivate::get(parent);
- parentPrivate->setHasCursorInChild(hasCursor);
+ parentPrivate->setHasCursorInChild(hc);
}
#else
- Q_UNUSED(hasCursor);
+ Q_UNUSED(hc);
#endif
}
@@ -7573,17 +7574,20 @@ void QQuickItem::setCursor(const QCursor &cursor)
}
}
+ QPointF updateCursorPos;
if (!d->hasCursor) {
- d->setHasCursorInChild(true);
d->hasCursor = true;
if (d->window) {
QWindow *renderWindow = QQuickRenderControl::renderWindowFor(d->window);
QWindow *window = renderWindow ? renderWindow : d->window;
QPointF pos = window->mapFromGlobal(QGuiApplicationPrivate::lastCursorPosition.toPoint());
if (contains(mapFromScene(pos)))
- QQuickWindowPrivate::get(d->window)->updateCursor(pos);
+ updateCursorPos = pos;
}
}
+ d->setHasCursorInChild(d->hasCursor || d->hasCursorHandler);
+ if (!updateCursorPos.isNull())
+ QQuickWindowPrivate::get(d->window)->updateCursor(updateCursorPos);
}
/*!
@@ -7597,8 +7601,8 @@ void QQuickItem::unsetCursor()
Q_D(QQuickItem);
if (!d->hasCursor)
return;
- d->setHasCursorInChild(false);
d->hasCursor = false;
+ d->setHasCursorInChild(d->hasCursorHandler);
if (d->extra.isAllocated())
d->extra->cursor = QCursor();
@@ -7611,6 +7615,64 @@ void QQuickItem::unsetCursor()
}
}
+/*!
+ \internal
+ Returns the cursor that should actually be shown, allowing the given
+ \handler to override the Item cursor if it is active or hovered.
+
+ \sa cursor(), setCursor(), QtQuick::PointerHandler::cursor
+*/
+QCursor QQuickItemPrivate::effectiveCursor(const QQuickPointerHandler *handler) const
+{
+ Q_Q(const QQuickItem);
+ if (!handler)
+ return q->cursor();
+ bool hoverCursorSet = false;
+ QCursor hoverCursor;
+ bool activeCursorSet = false;
+ QCursor activeCursor;
+ if (const QQuickHoverHandler *hoverHandler = qobject_cast<const QQuickHoverHandler *>(handler)) {
+ hoverCursorSet = hoverHandler->isCursorShapeExplicitlySet();
+ hoverCursor = hoverHandler->cursorShape();
+ } else if (handler->active()) {
+ activeCursorSet = handler->isCursorShapeExplicitlySet();
+ activeCursor = handler->cursorShape();
+ }
+ if (activeCursorSet)
+ return activeCursor;
+ if (hoverCursorSet)
+ return hoverCursor;
+ return q->cursor();
+}
+
+/*!
+ \internal
+ Returns the Pointer Handler that is currently attempting to set the cursor shape,
+ or null if there is no such handler.
+
+ \sa QtQuick::PointerHandler::cursor
+*/
+QQuickPointerHandler *QQuickItemPrivate::effectiveCursorHandler() const
+{
+ if (!hasPointerHandlers())
+ return nullptr;
+ QQuickPointerHandler *retHoverHandler = nullptr;
+ for (QQuickPointerHandler *h : extra->pointerHandlers) {
+ if (!h->isCursorShapeExplicitlySet())
+ continue;
+ QQuickHoverHandler *hoverHandler = qmlobject_cast<QQuickHoverHandler *>(h);
+ // For now, we don't expect multiple hover handlers in one Item, so we choose the first one found;
+ // but a future use case could be to have different cursors for different tablet stylus devices.
+ // In that case, this function needs more information: which device did the event come from.
+ // TODO Qt 6: add QPointerDevice* as argument to this function? (it doesn't exist yet in Qt 5)
+ if (!retHoverHandler && hoverHandler)
+ retHoverHandler = hoverHandler;
+ if (!hoverHandler && h->active())
+ return h;
+ }
+ return retHoverHandler;
+}
+
#endif
/*!
diff --git a/src/quick/items/qquickitem_p.h b/src/quick/items/qquickitem_p.h
index 3c0517cb3b..841d91bb40 100644
--- a/src/quick/items/qquickitem_p.h
+++ b/src/quick/items/qquickitem_p.h
@@ -471,6 +471,7 @@ public:
bool isTabFence:1;
bool replayingPressEvent:1;
bool touchEnabled:1;
+ bool hasCursorHandler:1;
enum DirtyType {
TransformOrigin = 0x00000001,
@@ -651,6 +652,10 @@ public:
void setHasCursorInChild(bool hasCursor);
void setHasHoverInChild(bool hasHover);
+#if QT_CONFIG(cursor)
+ QCursor effectiveCursor(const QQuickPointerHandler *handler) const;
+ QQuickPointerHandler *effectiveCursorHandler() const;
+#endif
virtual void updatePolish() { }
};
diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp
index 3bb6c19dce..491334f439 100644
--- a/src/quick/items/qquickwindow.cpp
+++ b/src/quick/items/qquickwindow.cpp
@@ -560,6 +560,7 @@ QQuickWindowPrivate::QQuickWindowPrivate()
, activeFocusItem(nullptr)
#if QT_CONFIG(cursor)
, cursorItem(nullptr)
+ , cursorHandler(nullptr)
#endif
#if QT_CONFIG(quick_draganddrop)
, dragGrabber(nullptr)
@@ -2967,26 +2968,27 @@ void QQuickWindowPrivate::updateCursor(const QPointF &scenePos)
{
Q_Q(QQuickWindow);
- QQuickItem *oldCursorItem = cursorItem;
- cursorItem = findCursorItem(contentItem, scenePos);
+ auto cursorItemAndHandler = findCursorItemAndHandler(contentItem, scenePos);
- if (cursorItem != oldCursorItem) {
+ if (cursorItem != cursorItemAndHandler.first || cursorHandler != cursorItemAndHandler.second) {
QWindow *renderWindow = QQuickRenderControl::renderWindowFor(q);
QWindow *window = renderWindow ? renderWindow : q;
+ cursorItem = cursorItemAndHandler.first;
+ cursorHandler = cursorItemAndHandler.second;
if (cursorItem)
- window->setCursor(cursorItem->cursor());
+ window->setCursor(QQuickItemPrivate::get(cursorItem)->effectiveCursor(cursorHandler));
else
window->unsetCursor();
}
}
-QQuickItem *QQuickWindowPrivate::findCursorItem(QQuickItem *item, const QPointF &scenePos)
+QPair<QQuickItem*, QQuickPointerHandler*> QQuickWindowPrivate::findCursorItemAndHandler(QQuickItem *item, const QPointF &scenePos) const
{
QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
if (itemPrivate->flags & QQuickItem::ItemClipsChildrenToShape) {
QPointF p = item->mapFromScene(scenePos);
if (!item->contains(p))
- return nullptr;
+ return {nullptr, nullptr};
}
if (itemPrivate->subtreeCursorEnabled) {
@@ -2995,17 +2997,24 @@ QQuickItem *QQuickWindowPrivate::findCursorItem(QQuickItem *item, const QPointF
QQuickItem *child = children.at(ii);
if (!child->isVisible() || !child->isEnabled() || QQuickItemPrivate::get(child)->culled)
continue;
- if (QQuickItem *cursorItem = findCursorItem(child, scenePos))
- return cursorItem;
+ auto ret = findCursorItemAndHandler(child, scenePos);
+ if (ret.first)
+ return ret;
+ }
+ if (itemPrivate->hasCursor || itemPrivate->hasCursorHandler) {
+ QPointF p = item->mapFromScene(scenePos);
+ if (!item->contains(p))
+ return {nullptr, nullptr};
+ if (itemPrivate->hasCursorHandler) {
+ if (auto handler = itemPrivate->effectiveCursorHandler())
+ return {item, handler};
+ }
+ if (itemPrivate->hasCursor)
+ return {item, nullptr};
}
}
- if (itemPrivate->hasCursor) {
- QPointF p = item->mapFromScene(scenePos);
- if (item->contains(p))
- return item;
- }
- return nullptr;
+ return {nullptr, nullptr};
}
#endif
diff --git a/src/quick/items/qquickwindow_p.h b/src/quick/items/qquickwindow_p.h
index ef10ba3fe8..6e6dc7a400 100644
--- a/src/quick/items/qquickwindow_p.h
+++ b/src/quick/items/qquickwindow_p.h
@@ -134,6 +134,7 @@ public:
// Keeps track of the item currently receiving mouse events
#if QT_CONFIG(cursor)
QQuickItem *cursorItem;
+ QQuickPointerHandler *cursorHandler;
#endif
#if QT_CONFIG(quick_draganddrop)
QQuickDragGrabber *dragGrabber;
@@ -197,7 +198,7 @@ public:
#endif
#if QT_CONFIG(cursor)
void updateCursor(const QPointF &scenePos);
- QQuickItem *findCursorItem(QQuickItem *item, const QPointF &scenePos);
+ QPair<QQuickItem*, QQuickPointerHandler*> findCursorItemAndHandler(QQuickItem *item, const QPointF &scenePos) const;
#endif
QList<QQuickItem*> hoverItems;
diff --git a/src/quick/util/qquickbehavior.cpp b/src/quick/util/qquickbehavior.cpp
index eee8562a2a..ceda5589b2 100644
--- a/src/quick/util/qquickbehavior.cpp
+++ b/src/quick/util/qquickbehavior.cpp
@@ -185,6 +185,80 @@ QVariant QQuickBehavior::targetValue() const
return d->targetValue;
}
+/*!
+ \readonly
+ \qmlpropertygroup QtQuick::Behavior::targetProperty
+ \qmlproperty string QtQuick::Behavior::targetProperty.name
+ \qmlproperty Object QtQuick::Behavior::targetProperty.object
+
+ \table
+ \header
+ \li Property
+ \li Description
+ \row
+ \li name
+ \li This property holds the name of the property being controlled by this Behavior.
+ \row
+ \li object
+ \li This property holds the object of the property being controlled by this Behavior.
+ \endtable
+
+ This property can be used to define custom behaviors based on the name or the object of
+ the property being controlled.
+
+ The following example defines a Behavior fading out and fading in its target object
+ when the property it controls changes:
+ \qml
+ // FadeBehavior.qml
+ import QtQuick 2.15
+
+ Behavior {
+ id: root
+ property Item fadeTarget: targetProperty.object
+ SequentialAnimation {
+ NumberAnimation {
+ target: root.fadeTarget
+ property: "opacity"
+ to: 0
+ easing.type: Easing.InQuad
+ }
+ PropertyAction { } // actually change the controlled property between the 2 other animations
+ NumberAnimation {
+ target: root.fadeTarget
+ property: "opacity"
+ to: 1
+ easing.type: Easing.OutQuad
+ }
+ }
+ }
+ \endqml
+
+ This can be used to animate a text when it changes:
+ \qml
+ import QtQuick 2.15
+
+ Text {
+ id: root
+ property int counter
+ text: counter
+ FadeBehavior on text {}
+ Timer {
+ running: true
+ repeat: true
+ interval: 1000
+ onTriggered: ++root.counter
+ }
+ }
+ \endqml
+
+ \since QtQuick 2.15
+*/
+QQmlProperty QQuickBehavior::targetProperty() const
+{
+ Q_D(const QQuickBehavior);
+ return d->property;
+}
+
void QQuickBehavior::write(const QVariant &value)
{
Q_D(QQuickBehavior);
@@ -265,6 +339,8 @@ void QQuickBehavior::setTarget(const QQmlProperty &property)
if (finalizedIdx < 0)
finalizedIdx = metaObject()->indexOfSlot("componentFinalized()");
engPriv->registerFinalizeCallback(this, finalizedIdx);
+
+ Q_EMIT targetPropertyChanged();
}
void QQuickBehavior::componentFinalized()
diff --git a/src/quick/util/qquickbehavior_p.h b/src/quick/util/qquickbehavior_p.h
index fa9cf6d6bc..a57a26d822 100644
--- a/src/quick/util/qquickbehavior_p.h
+++ b/src/quick/util/qquickbehavior_p.h
@@ -70,6 +70,7 @@ class Q_QUICK_PRIVATE_EXPORT QQuickBehavior : public QObject, public QQmlPropert
Q_PROPERTY(QQuickAbstractAnimation *animation READ animation WRITE setAnimation)
Q_PROPERTY(bool enabled READ enabled WRITE setEnabled NOTIFY enabledChanged)
Q_PROPERTY(QVariant targetValue READ targetValue NOTIFY targetValueChanged REVISION 13)
+ Q_PROPERTY(QQmlProperty targetProperty READ targetProperty NOTIFY targetPropertyChanged REVISION 15)
Q_CLASSINFO("DeferredPropertyNames", "animation")
QML_NAMED_ELEMENT(Behavior)
@@ -88,9 +89,12 @@ public:
QVariant targetValue() const;
+ QQmlProperty targetProperty() const;
+
Q_SIGNALS:
void enabledChanged();
void targetValueChanged();
+ void targetPropertyChanged();
private Q_SLOTS:
void componentFinalized();
diff --git a/src/quick/util/qquickglobal.cpp b/src/quick/util/qquickglobal.cpp
index 85bc78dee8..3ea2f88712 100644
--- a/src/quick/util/qquickglobal.cpp
+++ b/src/quick/util/qquickglobal.cpp
@@ -273,6 +273,52 @@ public:
return QMatrix4x4();
}
+ static QColorSpace colorSpaceFromObject(const QV4::Value &object, QV4::ExecutionEngine *v4, bool *ok)
+ {
+ if (ok)
+ *ok = false;
+ QColorSpace retn;
+ QV4::Scope scope(v4);
+ QV4::ScopedObject obj(scope, object);
+ if (!obj) {
+ if (ok)
+ *ok = false;
+ return retn;
+ }
+
+ QV4::ScopedString s(scope);
+
+ QV4::ScopedValue vName(scope, obj->get((s = v4->newString(QStringLiteral("namedColorSpace")))));
+ if (vName->isInt32()) {
+ if (ok)
+ *ok = true;
+ return QColorSpace((QColorSpace::NamedColorSpace)vName->toInt32());
+ }
+
+ QV4::ScopedValue vPri(scope, obj->get((s = v4->newString(QStringLiteral("primaries")))));
+ QV4::ScopedValue vTra(scope, obj->get((s = v4->newString(QStringLiteral("transferFunction")))));
+ if (!vPri->isInt32() || !vTra->isInt32()) {
+ if (ok)
+ *ok = false;
+ return retn;
+ }
+
+ QColorSpace::Primaries pri = static_cast<QColorSpace::Primaries>(vPri->integerValue());
+ QColorSpace::TransferFunction tra = static_cast<QColorSpace::TransferFunction>(vTra->integerValue());
+ float gamma = 0.0f;
+ if (tra == QColorSpace::TransferFunction::Gamma) {
+ QV4::ScopedValue vGam(scope, obj->get((s = v4->newString(QStringLiteral("gamma")))));
+ if (!vGam->isNumber()) {
+ if (ok)
+ *ok = false;
+ return retn;
+ }
+ gamma = vGam->toNumber();
+ }
+ if (ok) *ok = true;
+ return QColorSpace(pri, tra, gamma);
+ }
+
static QFont fontFromObject(const QV4::Value &object, QV4::ExecutionEngine *v4, bool *ok)
{
if (ok)
@@ -402,6 +448,8 @@ public:
switch (type) {
case QMetaType::QColor:
return &QQuickColorValueType::staticMetaObject;
+ case QMetaType::QColorSpace:
+ return &QQuickColorSpaceValueType::staticMetaObject;
case QMetaType::QFont:
return &QQuickFontValueType::staticMetaObject;
case QMetaType::QVector2D:
@@ -427,6 +475,9 @@ public:
case QMetaType::QColor:
dst.setValue<QColor>(QColor());
return true;
+ case QMetaType::QColorSpace:
+ dst.setValue<QColorSpace>(QColorSpace());
+ return true;
case QMetaType::QFont:
dst.setValue<QFont>(QFont());
return true;
@@ -647,6 +698,9 @@ public:
#endif
bool ok = false;
switch (type) {
+ case QMetaType::QColorSpace:
+ *v = QVariant::fromValue(colorSpaceFromObject(object, v4, &ok));
+ break;
case QMetaType::QFont:
*v = QVariant::fromValue(fontFromObject(object, v4, &ok));
break;
@@ -669,6 +723,8 @@ public:
switch (type) {
case QMetaType::QColor:
return typedEqual<QColor>(lhs, rhs);
+ case QMetaType::QColorSpace:
+ return typedEqual<QColorSpace>(lhs, rhs);
case QMetaType::QFont:
return typedEqual<QFont>(lhs, rhs);
case QMetaType::QVector2D:
@@ -732,6 +788,8 @@ public:
switch (dstType) {
case QMetaType::QColor:
return typedRead<QColor>(src, dstType, dst);
+ case QMetaType::QColorSpace:
+ return typedRead<QColorSpace>(src, dstType, dst);
case QMetaType::QFont:
return typedRead<QFont>(src, dstType, dst);
case QMetaType::QVector2D:
@@ -766,6 +824,8 @@ public:
switch (type) {
case QMetaType::QColor:
return typedWrite<QColor>(src, dst);
+ case QMetaType::QColorSpace:
+ return typedWrite<QColorSpace>(src, dst);
case QMetaType::QFont:
return typedWrite<QFont>(src, dst);
case QMetaType::QVector2D:
diff --git a/src/quick/util/qquickimageprovider.cpp b/src/quick/util/qquickimageprovider.cpp
index db82b2d807..80873e2ad5 100644
--- a/src/quick/util/qquickimageprovider.cpp
+++ b/src/quick/util/qquickimageprovider.cpp
@@ -43,6 +43,7 @@
#include "qquickpixmapcache_p.h"
#include <QtQuick/private/qsgcontext_p.h>
#include <private/qqmlglobal_p.h>
+#include <QtGui/qcolorspace.h>
QT_BEGIN_NAMESPACE
@@ -510,6 +511,7 @@ public:
{
}
+ QColorSpace targetColorSpace;
QQuickImageProviderOptions::AutoTransform autoTransform = QQuickImageProviderOptions::UsePluginDefaultTransform;
bool preserveAspectRatioCrop = false;
bool preserveAspectRatioFit = false;
@@ -558,7 +560,8 @@ bool QQuickImageProviderOptions::operator==(const QQuickImageProviderOptions &ot
{
return d->autoTransform == other.d->autoTransform &&
d->preserveAspectRatioCrop == other.d->preserveAspectRatioCrop &&
- d->preserveAspectRatioFit == other.d->preserveAspectRatioFit;
+ d->preserveAspectRatioFit == other.d->preserveAspectRatioFit &&
+ d->targetColorSpace == other.d->targetColorSpace;
}
/*!
@@ -602,6 +605,19 @@ void QQuickImageProviderOptions::setPreserveAspectRatioFit(bool preserveAspectRa
d->preserveAspectRatioFit = preserveAspectRatioFit;
}
+/*!
+ Returns the color space the image provider should return the image in.
+*/
+QColorSpace QQuickImageProviderOptions::targetColorSpace() const
+{
+ return d->targetColorSpace;
+}
+
+void QQuickImageProviderOptions::setTargetColorSpace(const QColorSpace &colorSpace)
+{
+ d->targetColorSpace = colorSpace;
+}
+
QQuickImageProviderWithOptions::QQuickImageProviderWithOptions(ImageType type, Flags flags)
: QQuickAsyncImageProvider()
{
diff --git a/src/quick/util/qquickpixmapcache.cpp b/src/quick/util/qquickpixmapcache.cpp
index bdd1e2c514..2ae9debbc9 100644
--- a/src/quick/util/qquickpixmapcache.cpp
+++ b/src/quick/util/qquickpixmapcache.cpp
@@ -318,6 +318,7 @@ public:
QSize requestSize;
QQuickImageProviderOptions providerOptions;
QQuickImageProviderOptions::AutoTransform appliedTransform;
+ QColorSpace targetColorSpace;
QQuickTextureFactory *textureFactory;
@@ -436,6 +437,12 @@ static bool readImage(const QUrl& url, QIODevice *dev, QImage *image, QString *e
maybeRemoveAlpha(image);
if (impsize && impsize->width() < 0)
*impsize = image->size();
+ if (providerOptions.targetColorSpace().isValid()) {
+ if (image->colorSpace().isValid())
+ image->convertToColorSpace(providerOptions.targetColorSpace());
+ else
+ image->setColorSpace(providerOptions.targetColorSpace());
+ }
return true;
} else {
if (errorString)
@@ -1763,6 +1770,13 @@ bool QQuickPixmap::connectDownloadProgress(QObject *object, int method)
return QMetaObject::connect(d->reply, QQuickPixmapReply::downloadProgressIndex, object, method);
}
+QColorSpace QQuickPixmap::colorSpace() const
+{
+ if (!d || !d->textureFactory)
+ return QColorSpace();
+ return d->textureFactory->image().colorSpace();
+}
+
QT_END_NAMESPACE
#include <qquickpixmapcache.moc>
diff --git a/src/quick/util/qquickpixmapcache_p.h b/src/quick/util/qquickpixmapcache_p.h
index 65d102af71..87724d6210 100644
--- a/src/quick/util/qquickpixmapcache_p.h
+++ b/src/quick/util/qquickpixmapcache_p.h
@@ -117,6 +117,9 @@ public:
bool preserveAspectRatioFit() const;
void setPreserveAspectRatioFit(bool preserveAspectRatioFit);
+ QColorSpace targetColorSpace() const;
+ void setTargetColorSpace(const QColorSpace &colorSpace);
+
private:
QSharedDataPointer<QQuickImageProviderOptionsPrivate> d;
};
@@ -156,6 +159,8 @@ public:
void setImage(const QImage &);
void setPixmap(const QQuickPixmap &other);
+ QColorSpace colorSpace() const;
+
QQuickTextureFactory *textureFactory() const;
QRect rect() const;
diff --git a/src/quick/util/qquickvaluetypes.cpp b/src/quick/util/qquickvaluetypes.cpp
index f9cd28cb24..517ed5da38 100644
--- a/src/quick/util/qquickvaluetypes.cpp
+++ b/src/quick/util/qquickvaluetypes.cpp
@@ -41,6 +41,7 @@
#include <qtquickglobal.h>
#include <private/qqmlvaluetype_p.h>
+#include <private/qcolorspace_p.h>
#include <private/qfont_p.h>
@@ -784,6 +785,47 @@ void QQuickFontValueType::setPreferShaping(bool enable)
v.setStyleStrategy(static_cast<QFont::StyleStrategy>(v.styleStrategy() | QFont::PreferNoShaping));
}
+QQuickColorSpaceValueType::NamedColorSpace QQuickColorSpaceValueType::namedColorSpace() const noexcept
+{
+ if (const auto *p = QColorSpacePrivate::get(v))
+ return (QQuickColorSpaceValueType::NamedColorSpace)p->namedColorSpace;
+ return QQuickColorSpaceValueType::Unknown;
+}
+void QQuickColorSpaceValueType::setNamedColorSpace(QQuickColorSpaceValueType::NamedColorSpace namedColorSpace)
+{
+ v = { (QColorSpace::NamedColorSpace)namedColorSpace };
+}
+
+QQuickColorSpaceValueType::Primaries QQuickColorSpaceValueType::primaries() const noexcept
+{
+ return (QQuickColorSpaceValueType::Primaries)v.primaries();
+}
+
+void QQuickColorSpaceValueType::setPrimaries(QQuickColorSpaceValueType::Primaries primariesId)
+{
+ v.setPrimaries((QColorSpace::Primaries)primariesId);
+}
+
+QQuickColorSpaceValueType::TransferFunction QQuickColorSpaceValueType::transferFunction() const noexcept
+{
+ return (QQuickColorSpaceValueType::TransferFunction)v.transferFunction();
+}
+
+void QQuickColorSpaceValueType::setTransferFunction(QQuickColorSpaceValueType::TransferFunction transferFunction)
+{
+ v.setTransferFunction((QColorSpace::TransferFunction)transferFunction, v.gamma());
+}
+
+float QQuickColorSpaceValueType::gamma() const noexcept
+{
+ return v.gamma();
+}
+
+void QQuickColorSpaceValueType::setGamma(float gamma)
+{
+ v.setTransferFunction(v.transferFunction(), gamma);
+}
+
QT_END_NAMESPACE
#include "moc_qquickvaluetypes_p.cpp"
diff --git a/src/quick/util/qquickvaluetypes_p.h b/src/quick/util/qquickvaluetypes_p.h
index 91a5ea83e5..5c22e5c087 100644
--- a/src/quick/util/qquickvaluetypes_p.h
+++ b/src/quick/util/qquickvaluetypes_p.h
@@ -56,6 +56,7 @@
#include <private/qqmlvaluetype_p.h>
#include <QtGui/QColor>
+#include <QtGui/QColorSpace>
#include <QtGui/QVector2D>
#include <QtGui/QVector3D>
#include <QtGui/QVector4D>
@@ -408,6 +409,57 @@ public:
void setPreferShaping(bool b);
};
+class QQuickColorSpaceValueType
+{
+ QColorSpace v;
+ Q_GADGET
+
+ Q_PROPERTY(NamedColorSpace namedColorSpace READ namedColorSpace WRITE setNamedColorSpace FINAL)
+ Q_PROPERTY(Primaries primaries READ primaries WRITE setPrimaries FINAL)
+ Q_PROPERTY(TransferFunction transferFunction READ transferFunction WRITE setTransferFunction FINAL)
+ Q_PROPERTY(float gamma READ gamma WRITE setGamma FINAL)
+
+ QML_NAMED_ELEMENT(ColorSpace)
+ Q_CLASSINFO("RegisterEnumClassesUnscoped", "false")
+
+public:
+ enum NamedColorSpace {
+ Unknown = 0,
+ SRgb,
+ SRgbLinear,
+ AdobeRgb,
+ DisplayP3,
+ ProPhotoRgb
+ };
+ Q_ENUM(NamedColorSpace)
+
+ enum class Primaries {
+ Custom = 0,
+ SRgb,
+ AdobeRgb,
+ DciP3D65,
+ ProPhotoRgb
+ };
+ Q_ENUM(Primaries)
+ enum class TransferFunction {
+ Custom = 0,
+ Linear,
+ Gamma,
+ SRgb,
+ ProPhotoRgb
+ };
+ Q_ENUM(TransferFunction)
+
+ NamedColorSpace namedColorSpace() const noexcept;
+ void setNamedColorSpace(NamedColorSpace namedColorSpace);
+ Primaries primaries() const noexcept;
+ void setPrimaries(Primaries primariesId);
+ TransferFunction transferFunction() const noexcept;
+ void setTransferFunction(TransferFunction transferFunction);
+ float gamma() const noexcept;
+ void setGamma(float gamma);
+};
+
QT_END_NAMESPACE
#endif // QQUICKVALUETYPES_P_H
diff --git a/tests/auto/qml/debugger/qdebugmessageservice/tst_qdebugmessageservice.cpp b/tests/auto/qml/debugger/qdebugmessageservice/tst_qdebugmessageservice.cpp
index 1c1f785560..ec7ee15d34 100644
--- a/tests/auto/qml/debugger/qdebugmessageservice/tst_qdebugmessageservice.cpp
+++ b/tests/auto/qml/debugger/qdebugmessageservice/tst_qdebugmessageservice.cpp
@@ -135,7 +135,7 @@ QList<QQmlDebugClient *> tst_QDebugMessageService::createClients()
void tst_QDebugMessageService::retrieveDebugOutput()
{
- QCOMPARE(QQmlDebugTest::connect(QLibraryInfo::location(QLibraryInfo::BinariesPath) + "/qml",
+ QCOMPARE(QQmlDebugTest::connectTo(QLibraryInfo::location(QLibraryInfo::BinariesPath) + "/qml",
QString(), testFile(QMLFILE), true), ConnectSuccess);
QTRY_VERIFY(m_client->logBuffer.size() >= 2);
diff --git a/tests/auto/qml/debugger/qqmldebugjs/tst_qqmldebugjs.cpp b/tests/auto/qml/debugger/qqmldebugjs/tst_qqmldebugjs.cpp
index 5b6c43bc0c..3f424d16f2 100644
--- a/tests/auto/qml/debugger/qqmldebugjs/tst_qqmldebugjs.cpp
+++ b/tests/auto/qml/debugger/qqmldebugjs/tst_qqmldebugjs.cpp
@@ -180,7 +180,7 @@ QQmlDebugTest::ConnectResult tst_QQmlDebugJS::init(bool qmlscene, const QString
const QString executable = qmlscene
? QLibraryInfo::location(QLibraryInfo::BinariesPath) + "/qmlscene"
: debugJsServerPath("qqmldebugjs");
- return QQmlDebugTest::connect(
+ return QQmlDebugTest::connectTo(
executable, restrictServices ? QStringLiteral("V8Debugger") : QString(),
testFile(qmlFile), blockMode);
}
diff --git a/tests/auto/qml/debugger/qqmlenginecontrol/tst_qqmlenginecontrol.cpp b/tests/auto/qml/debugger/qqmlenginecontrol/tst_qqmlenginecontrol.cpp
index a8c43b1c75..c8915fb840 100644
--- a/tests/auto/qml/debugger/qqmlenginecontrol/tst_qqmlenginecontrol.cpp
+++ b/tests/auto/qml/debugger/qqmlenginecontrol/tst_qqmlenginecontrol.cpp
@@ -66,7 +66,7 @@ class tst_QQmlEngineControl : public QQmlDebugTest
Q_OBJECT
private:
- ConnectResult connect(const QString &testFile, bool restrictServices);
+ ConnectResult connectTo(const QString &testFile, bool restrictServices);
QList<QQmlDebugClient *> createClients() override;
void engine_data();
@@ -79,10 +79,10 @@ private slots:
void stopEngine();
};
-QQmlDebugTest::ConnectResult tst_QQmlEngineControl::connect(const QString &file,
+QQmlDebugTest::ConnectResult tst_QQmlEngineControl::connectTo(const QString &file,
bool restrictServices)
{
- return QQmlDebugTest::connect(QLibraryInfo::location(QLibraryInfo::BinariesPath) + "/qmlscene",
+ return QQmlDebugTest::connectTo(QLibraryInfo::location(QLibraryInfo::BinariesPath) + "/qmlscene",
restrictServices ? QStringLiteral("EngineControl") : QString(),
testFile(file), true);
}
@@ -109,7 +109,7 @@ void tst_QQmlEngineControl::startEngine_data()
void tst_QQmlEngineControl::startEngine()
{
QFETCH(bool, restrictMode);
- QCOMPARE(connect("test.qml", restrictMode), ConnectSuccess);
+ QCOMPARE(connectTo("test.qml", restrictMode), ConnectSuccess);
QTRY_VERIFY(!m_client->blockedEngines().empty());
m_client->releaseEngine(m_client->blockedEngines().last());
@@ -130,7 +130,7 @@ void tst_QQmlEngineControl::stopEngine()
{
QFETCH(bool, restrictMode);
- QCOMPARE(connect("exit.qml", restrictMode), ConnectSuccess);
+ QCOMPARE(connectTo("exit.qml", restrictMode), ConnectSuccess);
QTRY_VERIFY(!m_client->blockedEngines().empty());
m_client->releaseEngine(m_client->blockedEngines().last());
diff --git a/tests/auto/qml/debugger/qqmlenginedebuginspectorintegrationtest/tst_qqmlenginedebuginspectorintegration.cpp b/tests/auto/qml/debugger/qqmlenginedebuginspectorintegrationtest/tst_qqmlenginedebuginspectorintegration.cpp
index 980e2be1f1..9830f1a9bd 100644
--- a/tests/auto/qml/debugger/qqmlenginedebuginspectorintegrationtest/tst_qqmlenginedebuginspectorintegration.cpp
+++ b/tests/auto/qml/debugger/qqmlenginedebuginspectorintegrationtest/tst_qqmlenginedebuginspectorintegration.cpp
@@ -87,7 +87,7 @@ QQmlEngineDebugObjectReference tst_QQmlEngineDebugInspectorIntegration::findRoot
QQmlDebugTest::ConnectResult tst_QQmlEngineDebugInspectorIntegration::init(bool restrictServices)
{
- return QQmlDebugTest::connect(
+ return QQmlDebugTest::connectTo(
QLibraryInfo::location(QLibraryInfo::BinariesPath) + "/qml",
restrictServices ? QStringLiteral("QmlDebugger,QmlInspector") : QString(),
testFile("qtquick2.qml"), true);
diff --git a/tests/auto/qml/debugger/qqmlinspector/tst_qqmlinspector.cpp b/tests/auto/qml/debugger/qqmlinspector/tst_qqmlinspector.cpp
index 6685558bb5..b5f45f1eeb 100644
--- a/tests/auto/qml/debugger/qqmlinspector/tst_qqmlinspector.cpp
+++ b/tests/auto/qml/debugger/qqmlinspector/tst_qqmlinspector.cpp
@@ -64,7 +64,7 @@ private slots:
QQmlDebugTest::ConnectResult tst_QQmlInspector::startQmlProcess(const QString &qmlFile,
bool restrictServices)
{
- return QQmlDebugTest::connect(QLibraryInfo::location(QLibraryInfo::BinariesPath) + "/qml",
+ return QQmlDebugTest::connectTo(QLibraryInfo::location(QLibraryInfo::BinariesPath) + "/qml",
restrictServices ? QStringLiteral("QmlInspector") : QString(),
testFile(qmlFile), true);
}
diff --git a/tests/auto/qml/debugger/qqmlpreview/tst_qqmlpreview.cpp b/tests/auto/qml/debugger/qqmlpreview/tst_qqmlpreview.cpp
index 15eb4012ac..bfec776614 100644
--- a/tests/auto/qml/debugger/qqmlpreview/tst_qqmlpreview.cpp
+++ b/tests/auto/qml/debugger/qqmlpreview/tst_qqmlpreview.cpp
@@ -74,7 +74,7 @@ private slots:
QQmlDebugTest::ConnectResult tst_QQmlPreview::startQmlProcess(const QString &qmlFile)
{
- return QQmlDebugTest::connect(QLibraryInfo::location(QLibraryInfo::BinariesPath) + "/qml",
+ return QQmlDebugTest::connectTo(QLibraryInfo::location(QLibraryInfo::BinariesPath) + "/qml",
QStringLiteral("QmlPreview"), testFile(qmlFile), true);
}
diff --git a/tests/auto/qml/debugger/qqmlprofilerservice/tst_qqmlprofilerservice.cpp b/tests/auto/qml/debugger/qqmlprofilerservice/tst_qqmlprofilerservice.cpp
index 085eb7b87a..c2a774b42d 100644
--- a/tests/auto/qml/debugger/qqmlprofilerservice/tst_qqmlprofilerservice.cpp
+++ b/tests/auto/qml/debugger/qqmlprofilerservice/tst_qqmlprofilerservice.cpp
@@ -201,7 +201,7 @@ private:
CheckType = CheckMessageType | CheckDetailType | CheckLine | CheckColumn | CheckFileEndsWith
};
- ConnectResult connect(bool block, const QString &file, bool recordFromStart = true,
+ ConnectResult connectTo(bool block, const QString &file, bool recordFromStart = true,
uint flushInterval = 0, bool restrictServices = true,
const QString &executable
= QLibraryInfo::location(QLibraryInfo::BinariesPath) + "/qmlscene");
@@ -246,7 +246,7 @@ private:
#define VERIFY(type, position, expected, checks, numbers) \
QVERIFY(verify(type, position, expected, checks, numbers))
-QQmlDebugTest::ConnectResult tst_QQmlProfilerService::connect(
+QQmlDebugTest::ConnectResult tst_QQmlProfilerService::connectTo(
bool block, const QString &file, bool recordFromStart, uint flushInterval,
bool restrictServices, const QString &executable)
{
@@ -255,7 +255,7 @@ QQmlDebugTest::ConnectResult tst_QQmlProfilerService::connect(
m_isComplete = false;
// ### Still using qmlscene due to QTBUG-33377
- return QQmlDebugTest::connect(
+ return QQmlDebugTest::connectTo(
executable,
restrictServices ? "CanvasFrameRate,EngineControl,DebugMessages" : QString(),
testFile(file), block);
@@ -542,7 +542,7 @@ void tst_QQmlProfilerService::connect()
QFETCH(bool, restrictMode);
QFETCH(bool, traceEnabled);
- QCOMPARE(connect(blockMode, "test.qml", traceEnabled, 0, restrictMode), ConnectSuccess);
+ QCOMPARE(connectTo(blockMode, "test.qml", traceEnabled, 0, restrictMode), ConnectSuccess);
if (!traceEnabled)
m_client->client->setRecording(true);
@@ -556,7 +556,7 @@ void tst_QQmlProfilerService::connect()
void tst_QQmlProfilerService::pixmapCacheData()
{
- QCOMPARE(connect(true, "pixmapCacheTest.qml"), ConnectSuccess);
+ QCOMPARE(connectTo(true, "pixmapCacheTest.qml"), ConnectSuccess);
// Don't wait for readyReadStandardOutput before the loop. It may have already arrived.
while (m_process->output().indexOf(QLatin1String("image loaded")) == -1 &&
@@ -594,7 +594,7 @@ void tst_QQmlProfilerService::pixmapCacheData()
void tst_QQmlProfilerService::scenegraphData()
{
- QCOMPARE(connect(true, "scenegraphTest.qml"), ConnectSuccess);
+ QCOMPARE(connectTo(true, "scenegraphTest.qml"), ConnectSuccess);
while (!m_process->output().contains(QLatin1String("tick")))
QVERIFY(QQmlDebugTest::waitForSignal(m_process, SIGNAL(readyReadStandardOutput())));
@@ -654,7 +654,7 @@ void tst_QQmlProfilerService::scenegraphData()
void tst_QQmlProfilerService::profileOnExit()
{
- QCOMPARE(connect(true, "exit.qml"), ConnectSuccess);
+ QCOMPARE(connectTo(true, "exit.qml"), ConnectSuccess);
checkProcessTerminated();
checkTraceReceived();
@@ -663,7 +663,7 @@ void tst_QQmlProfilerService::profileOnExit()
void tst_QQmlProfilerService::controlFromJS()
{
- QCOMPARE(connect(true, "controlFromJS.qml", false), ConnectSuccess);
+ QCOMPARE(connectTo(true, "controlFromJS.qml", false), ConnectSuccess);
QTRY_VERIFY(m_client->numLoadedEventTypes() > 0);
m_client->client->setRecording(false);
@@ -673,7 +673,7 @@ void tst_QQmlProfilerService::controlFromJS()
void tst_QQmlProfilerService::signalSourceLocation()
{
- QCOMPARE(connect(true, "signalSourceLocation.qml"), ConnectSuccess);
+ QCOMPARE(connectTo(true, "signalSourceLocation.qml"), ConnectSuccess);
while (!(m_process->output().contains(QLatin1String("500"))))
QVERIFY(QQmlDebugTest::waitForSignal(m_process, SIGNAL(readyReadStandardOutput())));
@@ -694,7 +694,7 @@ void tst_QQmlProfilerService::signalSourceLocation()
void tst_QQmlProfilerService::javascript()
{
- QCOMPARE(connect(true, "javascript.qml"), ConnectSuccess);
+ QCOMPARE(connectTo(true, "javascript.qml"), ConnectSuccess);
while (!(m_process->output().contains(QLatin1String("done"))))
QVERIFY(QQmlDebugTest::waitForSignal(m_process, SIGNAL(readyReadStandardOutput())));
@@ -722,7 +722,7 @@ void tst_QQmlProfilerService::javascript()
void tst_QQmlProfilerService::flushInterval()
{
- QCOMPARE(connect(true, "timer.qml", true, 1), ConnectSuccess);
+ QCOMPARE(connectTo(true, "timer.qml", true, 1), ConnectSuccess);
// Make sure we get multiple messages
QTRY_VERIFY(m_client->qmlMessages.length() > 0);
@@ -736,7 +736,7 @@ void tst_QQmlProfilerService::flushInterval()
void tst_QQmlProfilerService::translationBinding()
{
- QCOMPARE(connect(true, "qstr.qml"), ConnectSuccess);
+ QCOMPARE(connectTo(true, "qstr.qml"), ConnectSuccess);
checkProcessTerminated();
checkTraceReceived();
@@ -752,7 +752,7 @@ void tst_QQmlProfilerService::translationBinding()
void tst_QQmlProfilerService::memory()
{
- QCOMPARE(connect(true, "memory.qml"), ConnectSuccess);
+ QCOMPARE(connectTo(true, "memory.qml"), ConnectSuccess);
checkProcessTerminated();
checkTraceReceived();
@@ -781,7 +781,7 @@ static bool hasCompileEvents(const QVector<QQmlProfilerEventType> &types)
void tst_QQmlProfilerService::compile()
{
// Flush interval so that we actually get the events before we stop recording.
- connect(true, "test.qml", true, 100);
+ connectTo(true, "test.qml", true, 100);
QVERIFY(m_client);
@@ -820,7 +820,7 @@ void tst_QQmlProfilerService::compile()
void tst_QQmlProfilerService::multiEngine()
{
- QCOMPARE(connect(true, "quit.qml", true, 0, false, debugJsServerPath("qqmlprofilerservice")),
+ QCOMPARE(connectTo(true, "quit.qml", true, 0, false, debugJsServerPath("qqmlprofilerservice")),
ConnectSuccess);
QSignalSpy spy(m_client->client, SIGNAL(complete(qint64)));
@@ -837,7 +837,7 @@ void tst_QQmlProfilerService::multiEngine()
void tst_QQmlProfilerService::batchOverflow()
{
// The trace client checks that the events are received in order.
- QCOMPARE(connect(true, "batchOverflow.qml"), ConnectSuccess);
+ QCOMPARE(connectTo(true, "batchOverflow.qml"), ConnectSuccess);
checkProcessTerminated();
checkTraceReceived();
checkJsHeap();
diff --git a/tests/auto/qml/debugger/shared/debugutil.cpp b/tests/auto/qml/debugger/shared/debugutil.cpp
index 68446b53a4..3787f34bc2 100644
--- a/tests/auto/qml/debugger/shared/debugutil.cpp
+++ b/tests/auto/qml/debugger/shared/debugutil.cpp
@@ -120,7 +120,7 @@ void QQmlDebugTestClient::messageReceived(const QByteArray &ba)
emit serverMessage(ba);
}
-QQmlDebugTest::ConnectResult QQmlDebugTest::connect(
+QQmlDebugTest::ConnectResult QQmlDebugTest::connectTo(
const QString &executable, const QString &services, const QString &extraArgs,
bool block)
{
diff --git a/tests/auto/qml/debugger/shared/debugutil_p.h b/tests/auto/qml/debugger/shared/debugutil_p.h
index 1c32590305..190909dc44 100644
--- a/tests/auto/qml/debugger/shared/debugutil_p.h
+++ b/tests/auto/qml/debugger/shared/debugutil_p.h
@@ -53,7 +53,6 @@ public:
static QString clientStateString(const QQmlDebugClient *client);
static QString connectionStateString(const QQmlDebugConnection *connection);
-protected:
enum ConnectResult {
ConnectSuccess,
ProcessFailed,
@@ -64,7 +63,9 @@ protected:
RestrictFailed
};
- ConnectResult connect(const QString &executable, const QString &services,
+ Q_ENUM(ConnectResult)
+protected:
+ ConnectResult connectTo(const QString &executable, const QString &services,
const QString &extraArgs, bool block);
virtual QQmlDebugProcess *createProcess(const QString &executable);
diff --git a/tests/auto/qml/qmlformat/tst_qmlformat.cpp b/tests/auto/qml/qmlformat/tst_qmlformat.cpp
index 3201fa5ace..b10eaf26f1 100644
--- a/tests/auto/qml/qmlformat/tst_qmlformat.cpp
+++ b/tests/auto/qml/qmlformat/tst_qmlformat.cpp
@@ -113,7 +113,6 @@ void TestQmlformat::initTestCase()
m_invalidFiles << "tests/auto/qml/qqmllanguage/data/fuzzed.2.qml";
m_invalidFiles << "tests/auto/qml/qqmllanguage/data/fuzzed.3.qml";
m_invalidFiles << "tests/auto/qml/qqmllanguage/data/requiredProperties.2.qml";
- m_invalidFiles << "tests/auto/qml/qqmllanguage/data/requiredProperties.3.qml";
m_invalidFiles << "tests/auto/qml/qqmllanguage/data/nullishCoalescing_LHS_And.qml";
m_invalidFiles << "tests/auto/qml/qqmllanguage/data/nullishCoalescing_LHS_And.qml";
m_invalidFiles << "tests/auto/qml/qqmllanguage/data/nullishCoalescing_LHS_Or.qml";
diff --git a/tests/auto/qml/qqmllanguage/data/NonRequiredBase.qml b/tests/auto/qml/qqmllanguage/data/NonRequiredBase.qml
new file mode 100644
index 0000000000..60d45c2b1e
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/NonRequiredBase.qml
@@ -0,0 +1,5 @@
+import QtQuick 2.15
+
+Item {
+ property int i
+}
diff --git a/tests/auto/qml/qqmllanguage/data/RequiredBase.qml b/tests/auto/qml/qqmllanguage/data/RequiredBase.qml
new file mode 100644
index 0000000000..4effdbf1c7
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/RequiredBase.qml
@@ -0,0 +1,3 @@
+NonRequiredBase {
+ required i
+}
diff --git a/tests/auto/qml/qqmllanguage/data/requiredProperties.3.qml b/tests/auto/qml/qqmllanguage/data/requiredProperties.3.qml
new file mode 100644
index 0000000000..2585cf361e
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/requiredProperties.3.qml
@@ -0,0 +1,6 @@
+import QtQuick 2.15
+
+Item {
+ property int i;
+ required i;
+}
diff --git a/tests/auto/qml/qqmllanguage/data/requiredProperties.4.qml b/tests/auto/qml/qqmllanguage/data/requiredProperties.4.qml
new file mode 100644
index 0000000000..1126f845c9
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/requiredProperties.4.qml
@@ -0,0 +1,5 @@
+import QtQuick 2.15
+
+Item {
+ required objectName
+}
diff --git a/tests/auto/qml/qqmllanguage/data/requiredProperties.5.qml b/tests/auto/qml/qqmllanguage/data/requiredProperties.5.qml
new file mode 100644
index 0000000000..c2d155b123
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/requiredProperties.5.qml
@@ -0,0 +1 @@
+RequiredBase {}
diff --git a/tests/auto/qml/qqmllanguage/data/requiredProperties.6.qml b/tests/auto/qml/qqmllanguage/data/requiredProperties.6.qml
new file mode 100644
index 0000000000..e8802aef20
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/requiredProperties.6.qml
@@ -0,0 +1,3 @@
+RequiredBase {
+ i: 42
+}
diff --git a/tests/auto/qml/qqmllanguage/data/requiredProperties.7.qml b/tests/auto/qml/qqmllanguage/data/requiredProperties.7.qml
new file mode 100644
index 0000000000..40987f5c56
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/requiredProperties.7.qml
@@ -0,0 +1,5 @@
+import QtQuick 2.15
+
+Item {
+ required blub
+}
diff --git a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp
index 5027c0825f..b4ad9bd7b3 100644
--- a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp
+++ b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp
@@ -1675,6 +1675,36 @@ void tst_qqmllanguage::requiredProperty()
QQmlComponent component(&engine, testFileUrl("requiredProperties.2.qml"));
QVERIFY(!component.errors().empty());
}
+ {
+ QQmlComponent component(&engine, testFileUrl("requiredProperties.4.qml"));
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(!component.errors().empty());
+ QVERIFY(component.errorString().contains("Required property objectName was not initialized"));
+ }
+ {
+ QQmlComponent component(&engine, testFileUrl("requiredProperties.3.qml"));
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(!component.errors().empty());
+ QVERIFY(component.errorString().contains("Required property i was not initialized"));
+ }
+ {
+ QQmlComponent component(&engine, testFileUrl("requiredProperties.5.qml"));
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(!component.errors().empty());
+ QVERIFY(component.errorString().contains("Required property i was not initialized"));
+ }
+ {
+ QQmlComponent component(&engine, testFileUrl("requiredProperties.6.qml"));
+ VERIFY_ERRORS(0);
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(object);
+ }
+ {
+ QQmlComponent component(&engine, testFileUrl("requiredProperties.7.qml"));
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(!component.errors().empty());
+ QVERIFY(component.errorString().contains("Property blub was marked as required but does not exist"));
+ }
}
class MyClassWithRequiredProperty : public QObject
diff --git a/tests/auto/qml/qqmlparser/data/annotations/View1.qml b/tests/auto/qml/qqmlparser/data/annotations/View1.qml
new file mode 100644
index 0000000000..2d3d7d2cfd
--- /dev/null
+++ b/tests/auto/qml/qqmlparser/data/annotations/View1.qml
@@ -0,0 +1,76 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt Charts module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL$
+** 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 https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 or (at your option) any later version
+** approved by the KDE Free Qt Foundation. The licenses are as published by
+** the Free Software Foundation and appearing in the file LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//![2]
+import QtQuick 2.0
+//![2]
+import QtCharts 2.0
+
+@Pippo{ atg1:3 }
+@Annotation2{}
+Item {
+ @Annotate{}
+ anchors.fill: parent
+ @AnnotateMore{
+ property int x: 5
+ }
+ @AnnotateALot{}
+ property variant othersSlice: 0
+
+ //![1]
+ ChartView {
+ id: chart
+ title: "Top-5 car brand shares in Finland"
+ anchors.fill: parent
+ legend.alignment: Qt.AlignBottom
+ antialiasing: true
+
+@ExtraAnnotation{
+ signal pippo
+}
+ PieSeries {
+ id: pieSeries
+ PieSlice { label: "Volkswagen"; value: 13.5 }
+ PieSlice { label: "Toyota"; value: 10.9 }
+ PieSlice { label: "Ford"; value: 8.6 }
+ PieSlice { label: "Skoda"; value: 8.2 }
+ PieSlice { label: "Volvo"; value: 6.8 }
+ }
+ }
+
+@SuperComplete{
+binding: late
+}
+ Component.onCompleted: {
+ // You can also manipulate slices dynamically, like append a slice or set a slice exploded
+ othersSlice = pieSeries.append("Others", 52.0);
+ pieSeries.find("Volkswagen").exploded = true;
+ }
+ //![1]
+}
diff --git a/tests/auto/qml/qqmlparser/data/noannotations/View1.qml b/tests/auto/qml/qqmlparser/data/noannotations/View1.qml
new file mode 100644
index 0000000000..945bce3a44
--- /dev/null
+++ b/tests/auto/qml/qqmlparser/data/noannotations/View1.qml
@@ -0,0 +1,76 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt Charts module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL$
+** 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 https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 or (at your option) any later version
+** approved by the KDE Free Qt Foundation. The licenses are as published by
+** the Free Software Foundation and appearing in the file LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//![2]
+import QtQuick 2.0
+//![2]
+import QtCharts 2.0
+
+
+
+Item {
+
+ anchors.fill: parent
+
+
+
+
+ property variant othersSlice: 0
+
+ //![1]
+ ChartView {
+ id: chart
+ title: "Top-5 car brand shares in Finland"
+ anchors.fill: parent
+ legend.alignment: Qt.AlignBottom
+ antialiasing: true
+
+
+
+
+ PieSeries {
+ id: pieSeries
+ PieSlice { label: "Volkswagen"; value: 13.5 }
+ PieSlice { label: "Toyota"; value: 10.9 }
+ PieSlice { label: "Ford"; value: 8.6 }
+ PieSlice { label: "Skoda"; value: 8.2 }
+ PieSlice { label: "Volvo"; value: 6.8 }
+ }
+ }
+
+
+
+
+ Component.onCompleted: {
+ // You can also manipulate slices dynamically, like append a slice or set a slice exploded
+ othersSlice = pieSeries.append("Others", 52.0);
+ pieSeries.find("Volkswagen").exploded = true;
+ }
+ //![1]
+}
diff --git a/tests/auto/qml/qqmlparser/tst_qqmlparser.cpp b/tests/auto/qml/qqmlparser/tst_qqmlparser.cpp
index 76b56bd303..0b88358d4a 100644
--- a/tests/auto/qml/qqmlparser/tst_qqmlparser.cpp
+++ b/tests/auto/qml/qqmlparser/tst_qqmlparser.cpp
@@ -65,6 +65,8 @@ private slots:
void semicolonPartOfExpressionStatement();
void typeAssertion_data();
void typeAssertion();
+ void annotations_data();
+ void annotations();
private:
QStringList excludedDirs;
@@ -521,6 +523,67 @@ void tst_qqmlparser::typeAssertion()
QVERIFY(parser.parse());
}
+void tst_qqmlparser::annotations_data()
+{
+ QTest::addColumn<QString>("file");
+ QTest::addColumn<QString>("refFile");
+
+ QString tests = dataDirectory() + "/annotations/";
+ QString compare = dataDirectory() + "/noannotations/";
+
+ QStringList files;
+ files << findFiles(QDir(tests));
+
+ QStringList refFiles;
+ refFiles << findFiles(QDir(compare));
+
+ for (const QString &file: qAsConst(files)) {
+ auto fileNameStart = file.lastIndexOf(QDir::separator());
+ QStringRef fileName(&file, fileNameStart, file.length()-fileNameStart);
+ auto ref=std::find_if(refFiles.constBegin(),refFiles.constEnd(), [fileName](const QString &s){ return s.endsWith(fileName); });
+ if (ref != refFiles.constEnd())
+ QTest::newRow(qPrintable(file)) << file << *ref;
+ else
+ QTest::newRow(qPrintable(file)) << file << QString();
+ }
+}
+
+void tst_qqmlparser::annotations()
+{
+ using namespace QQmlJS;
+
+ QFETCH(QString, file);
+ QFETCH(QString, refFile);
+
+ QString code;
+ QString refCode;
+
+ QFile f(file);
+ if (f.open(QFile::ReadOnly))
+ code = QString::fromUtf8(f.readAll());
+ QFile refF(refFile);
+ if (!refFile.isEmpty() && refF.open(QFile::ReadOnly))
+ refCode = QString::fromUtf8(refF.readAll());
+
+ const bool qmlMode = true;
+
+ Engine engine;
+ Lexer lexer(&engine);
+ lexer.setCode(code, 1, qmlMode);
+ Parser parser(&engine);
+ QVERIFY(parser.parse());
+
+ if (!refCode.isEmpty()) {
+ Engine engine2;
+ Lexer lexer2(&engine2);
+ lexer2.setCode(refCode, 1, qmlMode);
+ Parser parser2(&engine2);
+ QVERIFY(parser2.parse());
+
+ // to do: compare for equality skipping annotations
+ }
+}
+
QTEST_MAIN(tst_qqmlparser)
#include "tst_qqmlparser.moc"
diff --git a/tests/auto/quick/pointerhandlers/qquickdraghandler/data/draggables.qml b/tests/auto/quick/pointerhandlers/qquickdraghandler/data/draggables.qml
index 7b3601bea0..81fa20f3bb 100644
--- a/tests/auto/quick/pointerhandlers/qquickdraghandler/data/draggables.qml
+++ b/tests/auto/quick/pointerhandlers/qquickdraghandler/data/draggables.qml
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2020 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the manual tests of the Qt Toolkit.
@@ -26,7 +26,7 @@
**
****************************************************************************/
-import QtQuick 2.12
+import QtQuick 2.15
Item {
id: root
@@ -47,6 +47,7 @@ Item {
DragHandler {
id: dragHandler
objectName: "DragHandler " + (index + 1)
+ cursorShape: Qt.ClosedHandCursor
}
Text {
diff --git a/tests/auto/quick/pointerhandlers/qquickdraghandler/tst_qquickdraghandler.cpp b/tests/auto/quick/pointerhandlers/qquickdraghandler/tst_qquickdraghandler.cpp
index 65c5ac9ef4..47cfd27817 100644
--- a/tests/auto/quick/pointerhandlers/qquickdraghandler/tst_qquickdraghandler.cpp
+++ b/tests/auto/quick/pointerhandlers/qquickdraghandler/tst_qquickdraghandler.cpp
@@ -249,8 +249,11 @@ void tst_DragHandler::mouseDrag()
QPointF ballCenter = ball->clipRect().center();
QPointF scenePressPos = ball->mapToScene(ballCenter);
QPoint p1 = scenePressPos.toPoint();
- QTest::mousePress(window, static_cast<Qt::MouseButton>(int(dragButton)), Qt::NoModifier, p1);
+ QTest::mousePress(window, static_cast<Qt::MouseButton>(int(dragButton)), Qt::NoModifier, p1, 500);
QVERIFY(!dragHandler->active());
+#if QT_CONFIG(cursor)
+ QCOMPARE(window->cursor().shape(), Qt::ArrowCursor);
+#endif
if (shouldDrag) {
QCOMPARE(dragHandler->centroid().position(), ballCenter);
QCOMPARE(dragHandler->centroid().pressPosition(), ballCenter);
@@ -265,6 +268,9 @@ void tst_DragHandler::mouseDrag()
QTRY_VERIFY(dragHandler->centroid().velocity().x() > 0);
QCOMPARE(centroidChangedSpy.count(), 2);
QVERIFY(!dragHandler->active());
+#if QT_CONFIG(cursor)
+ QCOMPARE(window->cursor().shape(), Qt::ArrowCursor);
+#endif
}
p1 += QPoint(1, 0);
QTest::mouseMove(window, p1);
@@ -292,6 +298,9 @@ void tst_DragHandler::mouseDrag()
QCOMPARE(dragHandler->translation().y(), 0.0);
QVERIFY(dragHandler->centroid().velocity().x() > 0);
QCOMPARE(centroidChangedSpy.count(), 4);
+#if QT_CONFIG(cursor)
+ QCOMPARE(window->cursor().shape(), Qt::ClosedHandCursor);
+#endif
}
QTest::mouseRelease(window, static_cast<Qt::MouseButton>(int(dragButton)), Qt::NoModifier, p1);
QTRY_VERIFY(!dragHandler->active());
@@ -300,6 +309,10 @@ void tst_DragHandler::mouseDrag()
QCOMPARE(ball->mapToScene(ballCenter).toPoint(), p1);
QCOMPARE(translationChangedSpy.count(), shouldDrag ? 1 : 0);
QCOMPARE(centroidChangedSpy.count(), shouldDrag ? 5 : 0);
+#if QT_CONFIG(cursor)
+ QTest::mouseMove(window, p1 + QPoint(1, 0)); // TODO after fixing QTBUG-53987, don't send mouseMove
+ QCOMPARE(window->cursor().shape(), Qt::ArrowCursor);
+#endif
}
void tst_DragHandler::mouseDragThreshold_data()
diff --git a/tests/auto/quick/pointerhandlers/qquickhoverhandler/data/lesHoverables.qml b/tests/auto/quick/pointerhandlers/qquickhoverhandler/data/lesHoverables.qml
index 011dc4e75f..38a19c57c5 100644
--- a/tests/auto/quick/pointerhandlers/qquickhoverhandler/data/lesHoverables.qml
+++ b/tests/auto/quick/pointerhandlers/qquickhoverhandler/data/lesHoverables.qml
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2018 The Qt Company Ltd.
+** Copyright (C) 2020 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the test suite of the Qt Toolkit.
@@ -26,7 +26,7 @@
**
****************************************************************************/
-import QtQuick 2.12
+import QtQuick 2.15
Rectangle {
id: root
@@ -52,6 +52,7 @@ Rectangle {
id: buttonMA
objectName: "buttonMA"
hoverEnabled: true
+ cursorShape: Qt.UpArrowCursor
anchors.fill: parent
onClicked: console.log("clicked MA")
}
@@ -74,9 +75,12 @@ Rectangle {
id: buttonHH
objectName: "buttonHH"
acceptedDevices: PointerDevice.AllDevices
+ cursorShape: tapHandler.pressed ? Qt.BusyCursor : Qt.PointingHandCursor
}
- TapHandler { }
+ TapHandler {
+ id: tapHandler
+ }
Text {
anchors.centerIn: parent
@@ -127,6 +131,7 @@ Rectangle {
HoverHandler {
id: topSidebarHH
objectName: "topSidebarHH"
+ cursorShape: Qt.OpenHandCursor
}
Loader {
@@ -152,6 +157,7 @@ Rectangle {
id: bottomSidebarMA
objectName: "bottomSidebarMA"
hoverEnabled: true
+ cursorShape: Qt.ClosedHandCursor
anchors.fill: parent
}
diff --git a/tests/auto/quick/pointerhandlers/qquickhoverhandler/tst_qquickhoverhandler.cpp b/tests/auto/quick/pointerhandlers/qquickhoverhandler/tst_qquickhoverhandler.cpp
index 575139f851..61f2752dd2 100644
--- a/tests/auto/quick/pointerhandlers/qquickhoverhandler/tst_qquickhoverhandler.cpp
+++ b/tests/auto/quick/pointerhandlers/qquickhoverhandler/tst_qquickhoverhandler.cpp
@@ -104,30 +104,45 @@ void tst_HoverHandler::hoverHandlerAndUnderlyingHoverHandler()
QCOMPARE(sidebarHoveredSpy.count(), 0);
QCOMPARE(buttonHH->isHovered(), false);
QCOMPARE(buttonHoveredSpy.count(), 0);
+#if QT_CONFIG(cursor)
+ QCOMPARE(window->cursor().shape(), Qt::ArrowCursor);
+#endif
QTest::mouseMove(window, rightOfButton);
QCOMPARE(topSidebarHH->isHovered(), true);
QCOMPARE(sidebarHoveredSpy.count(), 1);
QCOMPARE(buttonHH->isHovered(), false);
QCOMPARE(buttonHoveredSpy.count(), 0);
+#if QT_CONFIG(cursor)
+ QCOMPARE(window->cursor().shape(), Qt::OpenHandCursor);
+#endif
QTest::mouseMove(window, buttonCenter);
QCOMPARE(topSidebarHH->isHovered(), true);
QCOMPARE(sidebarHoveredSpy.count(), 1);
QCOMPARE(buttonHH->isHovered(), true);
QCOMPARE(buttonHoveredSpy.count(), 1);
+#if QT_CONFIG(cursor)
+ QCOMPARE(window->cursor().shape(), Qt::PointingHandCursor);
+#endif
QTest::mouseMove(window, rightOfButton);
QCOMPARE(topSidebarHH->isHovered(), true);
QCOMPARE(sidebarHoveredSpy.count(), 1);
QCOMPARE(buttonHH->isHovered(), false);
QCOMPARE(buttonHoveredSpy.count(), 2);
+#if QT_CONFIG(cursor)
+ QCOMPARE(window->cursor().shape(), Qt::OpenHandCursor);
+#endif
QTest::mouseMove(window, outOfSidebar);
QCOMPARE(topSidebarHH->isHovered(), false);
QCOMPARE(sidebarHoveredSpy.count(), 2);
QCOMPARE(buttonHH->isHovered(), false);
QCOMPARE(buttonHoveredSpy.count(), 2);
+#if QT_CONFIG(cursor)
+ QCOMPARE(window->cursor().shape(), Qt::ArrowCursor);
+#endif
}
void tst_HoverHandler::mouseAreaAndUnderlyingHoverHandler()
@@ -153,30 +168,45 @@ void tst_HoverHandler::mouseAreaAndUnderlyingHoverHandler()
QCOMPARE(sidebarHoveredSpy.count(), 0);
QCOMPARE(buttonMA->hovered(), false);
QCOMPARE(buttonHoveredSpy.count(), 0);
+#if QT_CONFIG(cursor)
+ QCOMPARE(window->cursor().shape(), Qt::ArrowCursor);
+#endif
QTest::mouseMove(window, rightOfButton);
QCOMPARE(topSidebarHH->isHovered(), true);
QCOMPARE(sidebarHoveredSpy.count(), 1);
QCOMPARE(buttonMA->hovered(), false);
QCOMPARE(buttonHoveredSpy.count(), 0);
+#if QT_CONFIG(cursor)
+ QCOMPARE(window->cursor().shape(), Qt::OpenHandCursor);
+#endif
QTest::mouseMove(window, buttonCenter);
QCOMPARE(topSidebarHH->isHovered(), true);
QCOMPARE(sidebarHoveredSpy.count(), 1);
QCOMPARE(buttonMA->hovered(), true);
QCOMPARE(buttonHoveredSpy.count(), 1);
+#if QT_CONFIG(cursor)
+ QCOMPARE(window->cursor().shape(), Qt::UpArrowCursor);
+#endif
QTest::mouseMove(window, rightOfButton);
QCOMPARE(topSidebarHH->isHovered(), true);
QCOMPARE(sidebarHoveredSpy.count(), 1);
QCOMPARE(buttonMA->hovered(), false);
QCOMPARE(buttonHoveredSpy.count(), 2);
+#if QT_CONFIG(cursor)
+ QCOMPARE(window->cursor().shape(), Qt::OpenHandCursor);
+#endif
QTest::mouseMove(window, outOfSidebar);
QCOMPARE(topSidebarHH->isHovered(), false);
QCOMPARE(sidebarHoveredSpy.count(), 2);
QCOMPARE(buttonMA->hovered(), false);
QCOMPARE(buttonHoveredSpy.count(), 2);
+#if QT_CONFIG(cursor)
+ QCOMPARE(window->cursor().shape(), Qt::ArrowCursor);
+#endif
}
void tst_HoverHandler::hoverHandlerAndUnderlyingMouseArea()
@@ -204,30 +234,45 @@ void tst_HoverHandler::hoverHandlerAndUnderlyingMouseArea()
QCOMPARE(sidebarHoveredSpy.count(), 0);
QCOMPARE(buttonHH->isHovered(), false);
QCOMPARE(buttonHoveredSpy.count(), 0);
+#if QT_CONFIG(cursor)
+ QCOMPARE(window->cursor().shape(), Qt::ArrowCursor);
+#endif
QTest::mouseMove(window, rightOfButton);
QCOMPARE(bottomSidebarMA->hovered(), true);
QCOMPARE(sidebarHoveredSpy.count(), 1);
QCOMPARE(buttonHH->isHovered(), false);
QCOMPARE(buttonHoveredSpy.count(), 0);
+#if QT_CONFIG(cursor)
+ QCOMPARE(window->cursor().shape(), Qt::ClosedHandCursor);
+#endif
QTest::mouseMove(window, buttonCenter);
QCOMPARE(bottomSidebarMA->hovered(), false);
QCOMPARE(sidebarHoveredSpy.count(), 2);
QCOMPARE(buttonHH->isHovered(), true);
QCOMPARE(buttonHoveredSpy.count(), 1);
+#if QT_CONFIG(cursor)
+ QCOMPARE(window->cursor().shape(), Qt::PointingHandCursor);
+#endif
QTest::mouseMove(window, rightOfButton);
QCOMPARE(bottomSidebarMA->hovered(), true);
QCOMPARE(sidebarHoveredSpy.count(), 3);
QCOMPARE(buttonHH->isHovered(), false);
QCOMPARE(buttonHoveredSpy.count(), 2);
+#if QT_CONFIG(cursor)
+ QCOMPARE(window->cursor().shape(), Qt::ClosedHandCursor);
+#endif
QTest::mouseMove(window, outOfSidebar);
QCOMPARE(bottomSidebarMA->hovered(), false);
QCOMPARE(sidebarHoveredSpy.count(), 4);
QCOMPARE(buttonHH->isHovered(), false);
QCOMPARE(buttonHoveredSpy.count(), 2);
+#if QT_CONFIG(cursor)
+ QCOMPARE(window->cursor().shape(), Qt::ArrowCursor);
+#endif
}
void tst_HoverHandler::movingItemWithHoverHandler()
@@ -255,6 +300,7 @@ void tst_HoverHandler::movingItemWithHoverHandler()
QVERIFY(QTest::qWaitForWindowExposed(window));
QTRY_COMPARE(paddleHH->isHovered(), true);
+ // TODO check the cursor shape after fixing QTBUG-53987
paddle->setX(100);
QTRY_COMPARE(paddleHH->isHovered(), false);
diff --git a/tests/auto/quick/qquickbehaviors/data/targetProperty.qml b/tests/auto/quick/qquickbehaviors/data/targetProperty.qml
new file mode 100644
index 0000000000..18abd46010
--- /dev/null
+++ b/tests/auto/quick/qquickbehaviors/data/targetProperty.qml
@@ -0,0 +1,16 @@
+import QtQuick 2.15
+
+Item {
+ readonly property QtObject xBehaviorObject: xBehavior.targetProperty.object
+ readonly property string xBehaviorName: xBehavior.targetProperty.name
+ readonly property QtObject emptyBehaviorObject: emptyBehavior.targetProperty.object
+ readonly property string emptyBehaviorName: emptyBehavior.targetProperty.name
+ Behavior on x {
+ id: xBehavior
+ objectName: "xBehavior"
+ }
+ Behavior {
+ id: emptyBehavior
+ objectName: "emptyBehavior"
+ }
+}
diff --git a/tests/auto/quick/qquickbehaviors/tst_qquickbehaviors.cpp b/tests/auto/quick/qquickbehaviors/tst_qquickbehaviors.cpp
index 64e32dcdfd..3b46019f64 100644
--- a/tests/auto/quick/qquickbehaviors/tst_qquickbehaviors.cpp
+++ b/tests/auto/quick/qquickbehaviors/tst_qquickbehaviors.cpp
@@ -75,6 +75,7 @@ private slots:
void innerBehaviorOverwritten();
void oneWay();
void safeToDelete();
+ void targetProperty();
};
void tst_qquickbehaviors::simpleBehavior()
@@ -656,6 +657,27 @@ void tst_qquickbehaviors::safeToDelete()
QVERIFY(c.create());
}
+Q_DECLARE_METATYPE(QQmlProperty)
+void tst_qquickbehaviors::targetProperty()
+{
+ QQmlEngine engine;
+ QQmlComponent c(&engine, testFileUrl("targetProperty.qml"));
+ QScopedPointer<QQuickItem> item(qobject_cast<QQuickItem*>(c.create()));
+ QVERIFY2(!item.isNull(), qPrintable(c.errorString()));
+
+ QQuickBehavior* xBehavior =
+ qobject_cast<QQuickBehavior*>(item->findChild<QQuickBehavior*>("xBehavior"));
+ QCOMPARE(xBehavior->property("targetProperty").value<QQmlProperty>(), QQmlProperty(item.data(), "x"));
+ QCOMPARE(item->property("xBehaviorObject").value<QObject*>(), item.data());
+ QCOMPARE(item->property("xBehaviorName").toString(), "x");
+
+ QQuickBehavior* emptyBehavior =
+ qobject_cast<QQuickBehavior*>(item->findChild<QQuickBehavior*>("emptyBehavior"));
+ QCOMPARE(emptyBehavior->property("targetProperty").value<QQmlProperty>().isValid(), false);
+ QCOMPARE(item->property("emptyBehaviorObject").value<QObject*>(), nullptr);
+ QCOMPARE(item->property("emptyBehaviorName").toString(), "");
+}
+
QTEST_MAIN(tst_qquickbehaviors)
diff --git a/tests/auto/quick/qquickimage/data/ProPhoto.jpg b/tests/auto/quick/qquickimage/data/ProPhoto.jpg
new file mode 100644
index 0000000000..481d35ca8e
--- /dev/null
+++ b/tests/auto/quick/qquickimage/data/ProPhoto.jpg
Binary files differ
diff --git a/tests/auto/quick/qquickimage/data/image.qml b/tests/auto/quick/qquickimage/data/image.qml
new file mode 100644
index 0000000000..09a577cc6f
--- /dev/null
+++ b/tests/auto/quick/qquickimage/data/image.qml
@@ -0,0 +1,5 @@
+import QtQuick 2.15
+
+Image {
+ source: "heart.png"
+}
diff --git a/tests/auto/quick/qquickimage/tst_qquickimage.cpp b/tests/auto/quick/qquickimage/tst_qquickimage.cpp
index abc7cd86bd..f0b44743b9 100644
--- a/tests/auto/quick/qquickimage/tst_qquickimage.cpp
+++ b/tests/auto/quick/qquickimage/tst_qquickimage.cpp
@@ -51,6 +51,7 @@
#include "../../shared/testhttpserver.h"
#include "../shared/visualtestutil.h"
+// #define DEBUG_WRITE_OUTPUT
using namespace QQuickVisualTestUtil;
@@ -89,6 +90,8 @@ private slots:
void imageCrash_QTBUG_32513();
void sourceSize_data();
void sourceSize();
+ void sourceClipRect_data();
+ void sourceClipRect();
void progressAndStatusChanges();
void sourceSizeChanges();
void correctStatus();
@@ -99,6 +102,7 @@ private slots:
void urlInterceptor();
void multiFrame_data();
void multiFrame();
+ void colorSpace();
private:
QQmlEngine engine;
@@ -879,6 +883,72 @@ void tst_qquickimage::sourceSizeChanges()
delete img;
}
+void tst_qquickimage::sourceClipRect_data()
+{
+ QTest::addColumn<QRectF>("sourceClipRect");
+ QTest::addColumn<QSize>("sourceSize");
+ QTest::addColumn<QList<QPoint>>("redPixelLocations");
+ QTest::addColumn<QList<QPoint>>("bluePixelLocations");
+
+ QTest::newRow("unclipped") << QRectF() << QSize()
+ << (QList<QPoint>() << QPoint(80, 80) << QPoint(150, 256))
+ << (QList<QPoint>() << QPoint(28, 28) << QPoint(215, 215));
+ QTest::newRow("upperLeft") << QRectF(10, 10, 100, 100) << QSize()
+ << (QList<QPoint>() << QPoint(99, 99))
+ << (QList<QPoint>() << QPoint(100, 100) << QPoint(28, 28));
+ QTest::newRow("lowerRight") << QRectF(200, 200, 20, 20) << QSize()
+ << (QList<QPoint>() << QPoint(0, 0))
+ << (QList<QPoint>() << QPoint(14, 14));
+ QTest::newRow("miniMiddle") << QRectF(20, 20, 60, 60) << QSize(100, 100)
+ << (QList<QPoint>() << QPoint(59, 0) << QPoint(6, 12) << QPoint(42, 42))
+ << (QList<QPoint>() << QPoint(54, 54) << QPoint(15, 59));
+}
+
+void tst_qquickimage::sourceClipRect()
+{
+ QFETCH(QRectF, sourceClipRect);
+ QFETCH(QSize, sourceSize);
+ QFETCH(QList<QPoint>, redPixelLocations);
+ QFETCH(QList<QPoint>, bluePixelLocations);
+
+ QScopedPointer<QQuickView> window(new QQuickView(nullptr));
+
+ window->setColor(Qt::blue);
+ window->setSource(testFileUrl("image.qml"));
+ window->show();
+ QVERIFY(QTest::qWaitForWindowExposed(window.data()));
+
+ QQuickImage *image = qobject_cast<QQuickImage*>(window->rootObject());
+ QVERIFY(image);
+
+ image->setSourceSize(sourceSize);
+ QCOMPARE(image->implicitWidth(), sourceSize.isValid() ? sourceSize.width() : 300);
+ QCOMPARE(image->implicitHeight(), sourceSize.isValid() ? sourceSize.height() : 300);
+ image->setSourceClipRect(sourceClipRect);
+ QCOMPARE(image->implicitWidth(), sourceClipRect.isNull() ? 300 : sourceClipRect.width());
+ QCOMPARE(image->implicitHeight(), sourceClipRect.isNull() ? 300 : sourceClipRect.height());
+
+ if ((QGuiApplication::platformName() == QLatin1String("offscreen"))
+ || (QGuiApplication::platformName() == QLatin1String("minimal")))
+ QSKIP("Skipping due to grabWindow not functional on offscreen/minimimal platforms");
+ QImage contents = window->grabWindow();
+ if (contents.width() < sourceClipRect.width())
+ QSKIP("Skipping due to grabWindow not functional");
+#ifdef DEBUG_WRITE_OUTPUT
+ contents.save("/tmp/sourceClipRect_" + QLatin1String(QTest::currentDataTag()) + ".png");
+#endif
+ for (auto p : redPixelLocations) {
+ QRgb color = contents.pixel(p);
+ QVERIFY(qRed(color) > 0xc0);
+ QVERIFY(qBlue(color) < 0x0f);
+ }
+ for (auto p : bluePixelLocations){
+ QRgb color = contents.pixel(p);
+ QVERIFY(qBlue(color) > 0xc0);
+ QVERIFY(qRed(color) < 0x0f);
+ }
+}
+
void tst_qquickimage::progressAndStatusChanges()
{
TestHTTPServer server;
@@ -1190,6 +1260,34 @@ void tst_qquickimage::multiFrame()
QVERIFY(qBlue(color) < 0xc0);
}
+void tst_qquickimage::colorSpace()
+{
+ QString componentStr1 = "import QtQuick 2.15\n"
+ "Image { source: srcImage; }";
+ QQmlComponent component1(&engine);
+ component1.setData(componentStr1.toLatin1(), QUrl::fromLocalFile(""));
+ engine.rootContext()->setContextProperty("srcImage", testFileUrl("ProPhoto.jpg"));
+
+ QScopedPointer<QQuickImage> object1 { qobject_cast<QQuickImage*>(component1.create())};
+ QVERIFY(object1);
+ QTRY_COMPARE(object1->status(), QQuickImageBase::Ready);
+ QCOMPARE(object1->colorSpace(), QColorSpace(QColorSpace::ProPhotoRgb));
+
+ QString componentStr2 = "import QtQuick 2.15\n"
+ "Image {\n"
+ " source: srcImage;\n"
+ " colorSpace.namedColorSpace: ColorSpace.SRgb;\n"
+ "}";
+
+ QQmlComponent component2(&engine);
+ component2.setData(componentStr2.toLatin1(), QUrl::fromLocalFile(""));
+
+ QScopedPointer<QQuickImage> object2 { qobject_cast<QQuickImage*>(component2.create())};
+ QVERIFY(object2);
+ QTRY_COMPARE(object2->status(), QQuickImageBase::Ready);
+ QCOMPARE(object2->colorSpace(), QColorSpace(QColorSpace::SRgb));
+}
+
QTEST_MAIN(tst_qquickimage)
#include "tst_qquickimage.moc"
diff --git a/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp b/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp
index 5b6b11c746..bf58ce961c 100644
--- a/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp
+++ b/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp
@@ -1797,22 +1797,26 @@ void tst_qquickwindow::cursor()
window.resize(320, 290);
QQuickItem parentItem;
+ parentItem.setObjectName("parentItem");
parentItem.setPosition(QPointF(0, 0));
parentItem.setSize(QSizeF(180, 180));
parentItem.setParentItem(window.contentItem());
QQuickItem childItem;
+ childItem.setObjectName("childItem");
childItem.setPosition(QPointF(60, 90));
childItem.setSize(QSizeF(120, 120));
childItem.setParentItem(&parentItem);
QQuickItem clippingItem;
+ clippingItem.setObjectName("clippingItem");
clippingItem.setPosition(QPointF(120, 120));
clippingItem.setSize(QSizeF(180, 180));
clippingItem.setClip(true);
clippingItem.setParentItem(window.contentItem());
QQuickItem clippedItem;
+ clippedItem.setObjectName("clippedItem");
clippedItem.setPosition(QPointF(-30, -30));
clippedItem.setSize(QSizeF(120, 120));
clippedItem.setParentItem(&clippingItem);
diff --git a/tests/manual/pointer/sidebar.qml b/tests/manual/pointer/sidebar.qml
index 827dbd1980..b7370a4fb7 100644
--- a/tests/manual/pointer/sidebar.qml
+++ b/tests/manual/pointer/sidebar.qml
@@ -26,7 +26,7 @@
**
****************************************************************************/
-import QtQuick 2.12
+import QtQuick 2.15
import "content"
Rectangle {
@@ -53,6 +53,7 @@ Rectangle {
id: buttonMA
objectName: "buttonMA"
hoverEnabled: true
+ cursorShape: Qt.UpArrowCursor
anchors.fill: parent
onClicked: console.log("clicked MA")
}
@@ -75,9 +76,11 @@ Rectangle {
id: buttonHH
objectName: "buttonHH"
acceptedDevices: PointerDevice.AllDevices
+ cursorShape: tapHandler.pressed ? Qt.BusyCursor : Qt.PointingHandCursor
}
TapHandler {
+ id: tapHandler
onTapped: tapFlash.start()
}
@@ -148,6 +151,7 @@ Rectangle {
HoverHandler {
id: topSidebarHH
objectName: "topSidebarHH"
+ cursorShape: Qt.OpenHandCursor
}
Loader {
@@ -173,6 +177,7 @@ Rectangle {
id: bottomSidebarMA
objectName: "bottomSidebarMA"
hoverEnabled: true
+ cursorShape: Qt.ClosedHandCursor
anchors.fill: parent
}
diff --git a/tests/manual/scenegraph_lancelot/data/shaders/gridmesh/attributes.qml b/tests/manual/scenegraph_lancelot/data/shaders/gridmesh/attributes.qml
deleted file mode 100644
index 17d9aadf95..0000000000
--- a/tests/manual/scenegraph_lancelot/data/shaders/gridmesh/attributes.qml
+++ /dev/null
@@ -1,65 +0,0 @@
-import QtQuick 2.0
-
-Rectangle {
- width: 320
- height: 480
-
- Text {
- id: text
- font.pixelSize: 80
- text: "Shaderz!"
- }
-
- ShaderEffectSource {
- id: source
- sourceItem: text
- hideSource: true
- smooth: true
- }
- Column {
- ShaderEffect {
- width: 320
- height: 160
- property variant source: source
- vertexShader: "
- uniform highp mat4 qt_Matrix;
- attribute highp vec4 qt_Vertex;
- attribute highp vec2 qt_MultiTexCoord0;
- varying highp vec2 qt_TexCoord0;
- void main() {
- gl_Position = qt_Matrix * qt_Vertex;
- qt_TexCoord0 = qt_MultiTexCoord0;
- }"
- }
- ShaderEffect {
- width: 320
- height: 160
- property variant source: source
- vertexShader: "
- attribute highp vec2 qt_MultiTexCoord0;
- uniform highp mat4 qt_Matrix;
- attribute highp vec4 qt_Vertex;
- varying highp vec2 qt_TexCoord0;
- void main() {
- gl_Position = qt_Matrix * qt_Vertex;
- qt_TexCoord0 = qt_MultiTexCoord0;
- }"
- }
- ShaderEffect {
- width: 320
- height: 160
- property variant source: source
- vertexShader: "
- attribute highp vec2 qt_MultiTexCoord0;
- uniform highp mat4 qt_Matrix;
- attribute highp vec4 qt_Vertex;
- varying highp vec2 qt_TexCoord0;
- uniform highp float width;
- uniform highp float height;
- void main() {
- gl_Position = qt_Matrix * qt_Vertex;
- qt_TexCoord0 = qt_Vertex.xy / vec2(width, height);
- }"
- }
- }
-}
diff --git a/tests/manual/scenegraph_lancelot/data/shaders/source/switch_3.qml b/tests/manual/scenegraph_lancelot/data/shaders/source/switch_3.qml
index 0d3c1fc4ee..c02dfba9e2 100644
--- a/tests/manual/scenegraph_lancelot/data/shaders/source/switch_3.qml
+++ b/tests/manual/scenegraph_lancelot/data/shaders/source/switch_3.qml
@@ -47,14 +47,7 @@ Item {
property variant source: source
- fragmentShader: "
- uniform lowp sampler2D source;
- varying highp vec2 qt_TexCoord0;
- uniform lowp float qt_Opacity;
- void main() {
- gl_FragColor = vec4(qt_TexCoord0.x, qt_TexCoord0.y, 1, 1) * texture2D(source, qt_TexCoord0).a;
- }
- "
+ fragmentShader: "qrc:shaders/gradient.frag"
}