Merge tag 'v6.2.13-lts' into tqtc/lts-6.2-opensource
Qt 6.2.13-lts release Conflicts solved: dependencies.yaml Change-Id: I3cbe1ce4293179888e236dd1a3a299cd2c66c950
This commit is contained in:
commit
c6fdadd916
|
@ -1,2 +1,2 @@
|
||||||
set(QT_REPO_MODULE_VERSION "6.2.12")
|
set(QT_REPO_MODULE_VERSION "6.2.13")
|
||||||
set(QT_REPO_MODULE_PRERELEASE_VERSION_SEGMENT "")
|
set(QT_REPO_MODULE_PRERELEASE_VERSION_SEGMENT "")
|
||||||
|
|
|
@ -5,4 +5,4 @@ DEFINES += QT_NO_JAVA_STYLE_ITERATORS
|
||||||
|
|
||||||
QQC2_SOURCE_TREE = $$PWD
|
QQC2_SOURCE_TREE = $$PWD
|
||||||
|
|
||||||
MODULE_VERSION = 6.2.12
|
MODULE_VERSION = 6.2.13
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
dependencies:
|
dependencies:
|
||||||
../tqtc-qtbase:
|
../tqtc-qtbase:
|
||||||
ref: 3a82051eade32b34c2f4f6f652a9d8ef0db96c71
|
ref: a963a536e623499cc56b0231c35dc5790a4bbc29
|
||||||
required: true
|
required: true
|
||||||
../tqtc-qtimageformats:
|
../tqtc-qtimageformats:
|
||||||
ref: 8dd102eea4bf0e6d683f9f8bdfe74c5d63a626c8
|
ref: 282852e3eff8909bfa157d80d1ff7c72fd1662d6
|
||||||
required: false
|
required: false
|
||||||
../tqtc-qtshadertools:
|
../tqtc-qtshadertools:
|
||||||
ref: ebe45c38bffcf8c3487949045f9ecf9c8a5f7e30
|
ref: 4e8c28a3dc8d4dd6e237f7cc4235c078147385a2
|
||||||
required: false
|
required: false
|
||||||
../tqtc-qtsvg:
|
../tqtc-qtsvg:
|
||||||
ref: 2563e58640a7a85144ed64641f00c7e5edbabb68
|
ref: 0463e412eeadba6dcf1b84b9c655550f93656e7d
|
||||||
required: false
|
required: false
|
||||||
|
|
|
@ -11,7 +11,7 @@ layout(location = 0) out vec4 fragColor;
|
||||||
layout(std140, binding = 0) uniform buf {
|
layout(std140, binding = 0) uniform buf {
|
||||||
mat4 qt_Matrix;
|
mat4 qt_Matrix;
|
||||||
vec4 color;
|
vec4 color;
|
||||||
vec2 textureSize;
|
vec2 texCoordScale;
|
||||||
float qt_Opacity;
|
float qt_Opacity;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Binary file not shown.
|
@ -9,7 +9,7 @@ layout(location = 1) out vec2 vShadeCoord;
|
||||||
layout(std140, binding = 0) uniform buf {
|
layout(std140, binding = 0) uniform buf {
|
||||||
mat4 qt_Matrix;
|
mat4 qt_Matrix;
|
||||||
vec4 color;
|
vec4 color;
|
||||||
vec2 textureSize;
|
vec2 texCoordScale;
|
||||||
float qt_Opacity;
|
float qt_Opacity;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -17,6 +17,6 @@ out gl_PerVertex { vec4 gl_Position; };
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
gl_Position = qt_Matrix * aVertex;
|
gl_Position = qt_Matrix * aVertex;
|
||||||
vTexCoord = aVertex.xy * textureSize;
|
vTexCoord = aVertex.xy * texCoordScale;
|
||||||
vShadeCoord = aTexCoord;
|
vShadeCoord = aTexCoord;
|
||||||
}
|
}
|
||||||
|
|
Binary file not shown.
|
@ -42,5 +42,6 @@ import QML
|
||||||
Member {
|
Member {
|
||||||
property string alias
|
property string alias
|
||||||
property bool isFlag: false
|
property bool isFlag: false
|
||||||
|
property bool isScoped: false
|
||||||
property var values: []
|
property var values: []
|
||||||
}
|
}
|
||||||
|
|
|
@ -240,8 +240,7 @@ void QQuickParticleDataHeap::insertTimed(QQuickParticleData* data, int time)
|
||||||
|
|
||||||
int QQuickParticleDataHeap::top()
|
int QQuickParticleDataHeap::top()
|
||||||
{
|
{
|
||||||
if (m_end == 0)
|
Q_ASSERT(!isEmpty());
|
||||||
return 1 << 30;
|
|
||||||
return m_data[0].time;
|
return m_data[0].time;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -391,7 +390,7 @@ bool QQuickParticleGroupData::recycle()
|
||||||
{
|
{
|
||||||
m_latestAliveParticles.clear();
|
m_latestAliveParticles.clear();
|
||||||
|
|
||||||
while (dataHeap.top() <= m_system->timeInt) {
|
while (!dataHeap.isEmpty() && dataHeap.top() <= m_system->timeInt) {
|
||||||
for (QQuickParticleData *datum : dataHeap.pop()) {
|
for (QQuickParticleData *datum : dataHeap.pop()) {
|
||||||
if (!datum->stillAlive(m_system)) {
|
if (!datum->stillAlive(m_system)) {
|
||||||
freeList.free(datum->index);
|
freeList.free(datum->index);
|
||||||
|
|
|
@ -117,6 +117,8 @@ public:
|
||||||
|
|
||||||
int top();
|
int top();
|
||||||
|
|
||||||
|
bool isEmpty() const { return m_end == 0; }
|
||||||
|
|
||||||
QSet<QQuickParticleData*> pop();
|
QSet<QQuickParticleData*> pop();
|
||||||
|
|
||||||
void clear();
|
void clear();
|
||||||
|
|
|
@ -1334,14 +1334,14 @@ struct TypeReferenceMap : QHash<int, TypeReference>
|
||||||
if (!formal->type.indexIsBuiltinType()) {
|
if (!formal->type.indexIsBuiltinType()) {
|
||||||
TypeReference &r
|
TypeReference &r
|
||||||
= this->add(formal->type.typeNameIndexOrBuiltinType(), it->location);
|
= this->add(formal->type.typeNameIndexOrBuiltinType(), it->location);
|
||||||
r.errorWhenNotFound = true;
|
r.errorWhenNotFound = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!it->returnType.indexIsBuiltinType()) {
|
if (!it->returnType.indexIsBuiltinType()) {
|
||||||
TypeReference &r
|
TypeReference &r
|
||||||
= this->add(it->returnType.typeNameIndexOrBuiltinType(), it->location);
|
= this->add(it->returnType.typeNameIndexOrBuiltinType(), it->location);
|
||||||
r.errorWhenNotFound = true;
|
r.errorWhenNotFound = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2497,16 +2497,15 @@ bool ExecutionEngine::metaTypeFromJS(const Value &value, QMetaType metaType, voi
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (metaType == QMetaType::fromType<QQmlListReference>()) {
|
if (const QV4::QmlListWrapper *wrapper = value.as<QV4::QmlListWrapper>()) {
|
||||||
if (const QV4::QmlListWrapper *wrapper = value.as<QV4::QmlListWrapper>()) {
|
if (metaType == QMetaType::fromType<QQmlListReference>()) {
|
||||||
*reinterpret_cast<QQmlListReference *>(data) = wrapper->toListReference();
|
*reinterpret_cast<QQmlListReference *>(data) = wrapper->toListReference();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (metaType == QMetaType::fromType<QQmlListProperty<QObject>>()) {
|
const auto wrapperPrivate = wrapper->d();
|
||||||
if (const QV4::QmlListWrapper *wrapper = value.as<QV4::QmlListWrapper>()) {
|
if (QMetaType(wrapperPrivate->propertyType) == metaType) {
|
||||||
*reinterpret_cast<QQmlListProperty<QObject> *>(data) = wrapper->d()->property();
|
*reinterpret_cast<QQmlListProperty<QObject> *>(data) = wrapperPrivate->property();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -147,21 +147,18 @@ ReturnedValue ESTable::get(const Value &key, bool *hasValue) const
|
||||||
// Removes the given \a key from the table
|
// Removes the given \a key from the table
|
||||||
bool ESTable::remove(const Value &key)
|
bool ESTable::remove(const Value &key)
|
||||||
{
|
{
|
||||||
bool found = false;
|
for (uint index = 0; index < m_size; ++index) {
|
||||||
uint idx = 0;
|
if (m_keys[index].sameValueZero(key)) {
|
||||||
for (; idx < m_size; ++idx) {
|
// Remove the element at |index| by moving all elements to the right
|
||||||
if (m_keys[idx].sameValueZero(key)) {
|
// of |index| one place to the left.
|
||||||
found = true;
|
size_t count = (m_size - (index + 1)) * sizeof(Value);
|
||||||
break;
|
memmove(m_keys + index, m_keys + index + 1, count);
|
||||||
|
memmove(m_values + index, m_values + index + 1, count);
|
||||||
|
m_size--;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
if (found == true) {
|
|
||||||
memmove(m_keys + idx, m_keys + idx + 1, (m_size - idx)*sizeof(Value));
|
|
||||||
memmove(m_values + idx, m_values + idx + 1, (m_size - idx)*sizeof(Value));
|
|
||||||
m_size--;
|
|
||||||
}
|
|
||||||
return found;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns the size of the table. Note that the size may not match the underlying allocation.
|
// Returns the size of the table. Note that the size may not match the underlying allocation.
|
||||||
|
|
|
@ -53,12 +53,13 @@
|
||||||
|
|
||||||
#include "qv4value_p.h"
|
#include "qv4value_p.h"
|
||||||
|
|
||||||
|
class tst_qv4estable;
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
namespace QV4
|
namespace QV4 {
|
||||||
{
|
|
||||||
|
|
||||||
class ESTable
|
class Q_AUTOTEST_EXPORT ESTable
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ESTable();
|
ESTable();
|
||||||
|
@ -76,13 +77,15 @@ public:
|
||||||
void removeUnmarkedKeys();
|
void removeUnmarkedKeys();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
friend class ::tst_qv4estable;
|
||||||
|
|
||||||
Value *m_keys = nullptr;
|
Value *m_keys = nullptr;
|
||||||
Value *m_values = nullptr;
|
Value *m_values = nullptr;
|
||||||
uint m_size = 0;
|
uint m_size = 0;
|
||||||
uint m_capacity = 0;
|
uint m_capacity = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
} // namespace QV4
|
||||||
|
|
||||||
QT_END_NAMESPACE
|
QT_END_NAMESPACE
|
||||||
|
|
||||||
|
|
|
@ -146,8 +146,8 @@ struct Q_QML_EXPORT SparseArray
|
||||||
{
|
{
|
||||||
SparseArray();
|
SparseArray();
|
||||||
~SparseArray() {
|
~SparseArray() {
|
||||||
if (root())
|
if (SparseArrayNode *n = root())
|
||||||
freeTree(header.left, alignof(SparseArrayNode));
|
freeTree(n, alignof(SparseArrayNode));
|
||||||
}
|
}
|
||||||
|
|
||||||
SparseArray(const SparseArray &other);
|
SparseArray(const SparseArray &other);
|
||||||
|
@ -323,37 +323,45 @@ inline QList<int> SparseArray::keys() const
|
||||||
|
|
||||||
inline const SparseArrayNode *SparseArray::lowerBound(uint akey) const
|
inline const SparseArrayNode *SparseArray::lowerBound(uint akey) const
|
||||||
{
|
{
|
||||||
const SparseArrayNode *lb = root()->lowerBound(akey);
|
if (SparseArrayNode *n = root()) {
|
||||||
if (!lb)
|
if (const SparseArrayNode *lb = n->lowerBound(akey))
|
||||||
lb = end();
|
return lb;
|
||||||
return lb;
|
}
|
||||||
|
|
||||||
|
return end();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
inline SparseArrayNode *SparseArray::lowerBound(uint akey)
|
inline SparseArrayNode *SparseArray::lowerBound(uint akey)
|
||||||
{
|
{
|
||||||
SparseArrayNode *lb = root()->lowerBound(akey);
|
if (SparseArrayNode *n = root()) {
|
||||||
if (!lb)
|
if (SparseArrayNode *lb = n->lowerBound(akey))
|
||||||
lb = end();
|
return lb;
|
||||||
return lb;
|
}
|
||||||
|
|
||||||
|
return end();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
inline const SparseArrayNode *SparseArray::upperBound(uint akey) const
|
inline const SparseArrayNode *SparseArray::upperBound(uint akey) const
|
||||||
{
|
{
|
||||||
const SparseArrayNode *ub = root()->upperBound(akey);
|
if (SparseArrayNode *n = root()) {
|
||||||
if (!ub)
|
if (const SparseArrayNode *ub = n->upperBound(akey))
|
||||||
ub = end();
|
return ub;
|
||||||
return ub;
|
}
|
||||||
|
|
||||||
|
return end();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
inline SparseArrayNode *SparseArray::upperBound(uint akey)
|
inline SparseArrayNode *SparseArray::upperBound(uint akey)
|
||||||
{
|
{
|
||||||
SparseArrayNode *ub = root()->upperBound(akey);
|
if (SparseArrayNode *n = root()) {
|
||||||
if (!ub)
|
if (SparseArrayNode *ub = n->upperBound(akey))
|
||||||
ub = end();
|
return ub;
|
||||||
return ub;
|
}
|
||||||
|
|
||||||
|
return end();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -251,7 +251,7 @@ struct QV4QPointer {
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QtSharedPointer::ExternalRefCountData *d;
|
QtSharedPointer::ExternalRefCountData *d;
|
||||||
QObject *qObject;
|
T *qObject;
|
||||||
};
|
};
|
||||||
Q_STATIC_ASSERT(std::is_trivial< QV4QPointer<QObject> >::value);
|
Q_STATIC_ASSERT(std::is_trivial< QV4QPointer<QObject> >::value);
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -697,7 +697,13 @@ void qmlRegisterTypeAndRevisions<QQmlTypeNotAvailable, void>(
|
||||||
|
|
||||||
QQmlEngine *AOTCompiledContext::qmlEngine() const
|
QQmlEngine *AOTCompiledContext::qmlEngine() const
|
||||||
{
|
{
|
||||||
return qmlContext ? qmlContext->engine() : nullptr;
|
return engine->handle()->qmlEngine();
|
||||||
|
}
|
||||||
|
|
||||||
|
static QQmlPropertyCapture *propertyCapture(const AOTCompiledContext *aotContext)
|
||||||
|
{
|
||||||
|
QQmlEngine *engine = aotContext->qmlEngine();
|
||||||
|
return engine ? QQmlEnginePrivate::get(aotContext->qmlEngine())->propertyCapture : nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
QJSValue AOTCompiledContext::jsMetaType(int index) const
|
QJSValue AOTCompiledContext::jsMetaType(int index) const
|
||||||
|
@ -722,31 +728,23 @@ void AOTCompiledContext::setReturnValueUndefined() const
|
||||||
|
|
||||||
static void captureFallbackProperty(
|
static void captureFallbackProperty(
|
||||||
QObject *object, int coreIndex, int notifyIndex, bool isConstant,
|
QObject *object, int coreIndex, int notifyIndex, bool isConstant,
|
||||||
QQmlContextData *qmlContext)
|
const AOTCompiledContext *aotContext)
|
||||||
{
|
{
|
||||||
if (!qmlContext || isConstant)
|
if (isConstant)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
QQmlEngine *engine = qmlContext->engine();
|
if (QQmlPropertyCapture *capture = propertyCapture(aotContext))
|
||||||
Q_ASSERT(engine);
|
|
||||||
QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine);
|
|
||||||
Q_ASSERT(ep);
|
|
||||||
if (QQmlPropertyCapture *capture = ep->propertyCapture)
|
|
||||||
capture->captureProperty(object, coreIndex, notifyIndex);
|
capture->captureProperty(object, coreIndex, notifyIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void captureObjectProperty(
|
static void captureObjectProperty(
|
||||||
QObject *object, const QQmlPropertyCache *propertyCache,
|
QObject *object, const QQmlPropertyCache *propertyCache,
|
||||||
const QQmlPropertyData *property, QQmlContextData *qmlContext)
|
const QQmlPropertyData *property, const AOTCompiledContext *aotContext)
|
||||||
{
|
{
|
||||||
if (!qmlContext || property->isConstant())
|
if (property->isConstant())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
QQmlEngine *engine = qmlContext->engine();
|
if (QQmlPropertyCapture *capture = propertyCapture(aotContext))
|
||||||
Q_ASSERT(engine);
|
|
||||||
QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine);
|
|
||||||
Q_ASSERT(ep);
|
|
||||||
if (QQmlPropertyCapture *capture = ep->propertyCapture)
|
|
||||||
capture->captureProperty(object, propertyCache, property);
|
capture->captureProperty(object, propertyCache, property);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -762,7 +760,7 @@ static bool inherits(const QQmlPropertyCache *descendent, const QQmlPropertyCach
|
||||||
enum class ObjectPropertyResult { OK, NeedsInit, Deleted };
|
enum class ObjectPropertyResult { OK, NeedsInit, Deleted };
|
||||||
|
|
||||||
static ObjectPropertyResult loadObjectProperty(
|
static ObjectPropertyResult loadObjectProperty(
|
||||||
QV4::Lookup *l, QObject *object, void *target, QQmlContextData *qmlContext)
|
QV4::Lookup *l, QObject *object, void *target, const AOTCompiledContext *aotContext)
|
||||||
{
|
{
|
||||||
QQmlData *qmlData = QQmlData::get(object);
|
QQmlData *qmlData = QQmlData::get(object);
|
||||||
if (!qmlData)
|
if (!qmlData)
|
||||||
|
@ -779,13 +777,13 @@ static ObjectPropertyResult loadObjectProperty(
|
||||||
if (qmlData->hasPendingBindingBit(coreIndex))
|
if (qmlData->hasPendingBindingBit(coreIndex))
|
||||||
qmlData->flushPendingBinding(coreIndex);
|
qmlData->flushPendingBinding(coreIndex);
|
||||||
|
|
||||||
captureObjectProperty(object, propertyCache, property, qmlContext);
|
captureObjectProperty(object, propertyCache, property, aotContext);
|
||||||
property->readProperty(object, target);
|
property->readProperty(object, target);
|
||||||
return ObjectPropertyResult::OK;
|
return ObjectPropertyResult::OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ObjectPropertyResult loadFallbackProperty(
|
static ObjectPropertyResult loadFallbackProperty(
|
||||||
QV4::Lookup *l, QObject *object, void *target, QQmlContextData *qmlContext)
|
QV4::Lookup *l, QObject *object, void *target, const AOTCompiledContext *aotContext)
|
||||||
{
|
{
|
||||||
QQmlData *qmlData = QQmlData::get(object);
|
QQmlData *qmlData = QQmlData::get(object);
|
||||||
if (qmlData && qmlData->isQueuedForDeletion)
|
if (qmlData && qmlData->isQueuedForDeletion)
|
||||||
|
@ -803,7 +801,7 @@ static ObjectPropertyResult loadFallbackProperty(
|
||||||
qmlData->flushPendingBinding(coreIndex);
|
qmlData->flushPendingBinding(coreIndex);
|
||||||
|
|
||||||
captureFallbackProperty(object, coreIndex, l->qobjectFallbackLookup.notifyIndex,
|
captureFallbackProperty(object, coreIndex, l->qobjectFallbackLookup.notifyIndex,
|
||||||
l->qobjectFallbackLookup.isConstant, qmlContext);
|
l->qobjectFallbackLookup.isConstant, aotContext);
|
||||||
|
|
||||||
void *a[] = { target, nullptr };
|
void *a[] = { target, nullptr };
|
||||||
metaObject->metacall(object, QMetaObject::ReadProperty, coreIndex, a);
|
metaObject->metacall(object, QMetaObject::ReadProperty, coreIndex, a);
|
||||||
|
@ -984,7 +982,7 @@ bool AOTCompiledContext::captureLookup(uint index, QObject *object) const
|
||||||
|| l->getter == QV4::Lookup::getterQObject) {
|
|| l->getter == QV4::Lookup::getterQObject) {
|
||||||
const QQmlPropertyData *property = l->qobjectLookup.propertyData;
|
const QQmlPropertyData *property = l->qobjectLookup.propertyData;
|
||||||
QQmlData::flushPendingBinding(object, property->coreIndex());
|
QQmlData::flushPendingBinding(object, property->coreIndex());
|
||||||
captureObjectProperty(object, l->qobjectLookup.propertyCache, property, qmlContext);
|
captureObjectProperty(object, l->qobjectLookup.propertyCache, property, this);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -993,7 +991,7 @@ bool AOTCompiledContext::captureLookup(uint index, QObject *object) const
|
||||||
QQmlData::flushPendingBinding(object, coreIndex);
|
QQmlData::flushPendingBinding(object, coreIndex);
|
||||||
captureFallbackProperty(
|
captureFallbackProperty(
|
||||||
object, coreIndex, l->qobjectFallbackLookup.notifyIndex,
|
object, coreIndex, l->qobjectFallbackLookup.notifyIndex,
|
||||||
l->qobjectFallbackLookup.isConstant, qmlContext);
|
l->qobjectFallbackLookup.isConstant, this);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1007,7 +1005,7 @@ bool AOTCompiledContext::captureQmlContextPropertyLookup(uint index) const
|
||||||
&& l->qmlContextPropertyGetter == QV4::QQmlContextWrapper::lookupContextObjectProperty) {
|
&& l->qmlContextPropertyGetter == QV4::QQmlContextWrapper::lookupContextObjectProperty) {
|
||||||
const QQmlPropertyData *property = l->qobjectLookup.propertyData;
|
const QQmlPropertyData *property = l->qobjectLookup.propertyData;
|
||||||
QQmlData::flushPendingBinding(qmlScopeObject, property->coreIndex());
|
QQmlData::flushPendingBinding(qmlScopeObject, property->coreIndex());
|
||||||
captureObjectProperty(qmlScopeObject, l->qobjectLookup.propertyCache, property, qmlContext);
|
captureObjectProperty(qmlScopeObject, l->qobjectLookup.propertyCache, property, this);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1015,7 +1013,7 @@ bool AOTCompiledContext::captureQmlContextPropertyLookup(uint index) const
|
||||||
const int coreIndex = l->qobjectFallbackLookup.coreIndex;
|
const int coreIndex = l->qobjectFallbackLookup.coreIndex;
|
||||||
QQmlData::flushPendingBinding(qmlScopeObject, coreIndex);
|
QQmlData::flushPendingBinding(qmlScopeObject, coreIndex);
|
||||||
captureFallbackProperty(qmlScopeObject, coreIndex, l->qobjectFallbackLookup.notifyIndex,
|
captureFallbackProperty(qmlScopeObject, coreIndex, l->qobjectFallbackLookup.notifyIndex,
|
||||||
l->qobjectFallbackLookup.isConstant, qmlContext);
|
l->qobjectFallbackLookup.isConstant, this);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1267,9 +1265,9 @@ bool AOTCompiledContext::loadScopeObjectPropertyLookup(uint index, void *target)
|
||||||
|
|
||||||
ObjectPropertyResult result = ObjectPropertyResult::NeedsInit;
|
ObjectPropertyResult result = ObjectPropertyResult::NeedsInit;
|
||||||
if (l->qmlContextPropertyGetter == QV4::QQmlContextWrapper::lookupScopeObjectProperty)
|
if (l->qmlContextPropertyGetter == QV4::QQmlContextWrapper::lookupScopeObjectProperty)
|
||||||
result = loadObjectProperty(l, qmlScopeObject, target, qmlContext);
|
result = loadObjectProperty(l, qmlScopeObject, target, this);
|
||||||
else if (l->qmlContextPropertyGetter == QV4::QQmlContextWrapper::lookupScopeFallbackProperty)
|
else if (l->qmlContextPropertyGetter == QV4::QQmlContextWrapper::lookupScopeFallbackProperty)
|
||||||
result = loadFallbackProperty(l, qmlScopeObject, target, qmlContext);
|
result = loadFallbackProperty(l, qmlScopeObject, target, this);
|
||||||
else
|
else
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -1405,9 +1403,9 @@ bool AOTCompiledContext::getObjectLookup(uint index, QObject *object, void *targ
|
||||||
|
|
||||||
ObjectPropertyResult result = ObjectPropertyResult::NeedsInit;
|
ObjectPropertyResult result = ObjectPropertyResult::NeedsInit;
|
||||||
if (l->getter == QV4::Lookup::getterQObject)
|
if (l->getter == QV4::Lookup::getterQObject)
|
||||||
result = loadObjectProperty(l, object, target, qmlContext);
|
result = loadObjectProperty(l, object, target, this);
|
||||||
else if (l->getter == QV4::Lookup::getterFallback)
|
else if (l->getter == QV4::Lookup::getterFallback)
|
||||||
result = loadFallbackProperty(l, object, target, qmlContext);
|
result = loadFallbackProperty(l, object, target, this);
|
||||||
else
|
else
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
|
|
@ -812,17 +812,21 @@ static void removeOldBinding(QObject *object, QQmlPropertyIndex index, QQmlPrope
|
||||||
oldBinding = data->bindings;
|
oldBinding = data->bindings;
|
||||||
|
|
||||||
while (oldBinding && (oldBinding->targetPropertyIndex().coreIndex() != coreIndex ||
|
while (oldBinding && (oldBinding->targetPropertyIndex().coreIndex() != coreIndex ||
|
||||||
oldBinding->targetPropertyIndex().hasValueTypeIndex()))
|
oldBinding->targetPropertyIndex().hasValueTypeIndex())) {
|
||||||
oldBinding = oldBinding->nextBinding();
|
oldBinding = oldBinding->nextBinding();
|
||||||
|
}
|
||||||
|
|
||||||
if (!oldBinding)
|
if (valueTypeIndex != -1
|
||||||
return;
|
&& oldBinding
|
||||||
|
&& oldBinding->isValueTypeProxy()) {
|
||||||
if (valueTypeIndex != -1 && oldBinding->isValueTypeProxy())
|
|
||||||
oldBinding = static_cast<QQmlValueTypeProxyBinding *>(oldBinding.data())->binding(index);
|
oldBinding = static_cast<QQmlValueTypeProxyBinding *>(oldBinding.data())->binding(index);
|
||||||
|
}
|
||||||
|
|
||||||
if (!oldBinding)
|
if (!oldBinding) {
|
||||||
|
// Clear the binding bit so that the binding doesn't appear later for any reason
|
||||||
|
data->clearBindingBit(coreIndex);
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!(flags & QQmlPropertyPrivate::DontEnable))
|
if (!(flags & QQmlPropertyPrivate::DontEnable))
|
||||||
oldBinding->setEnabled(false, {});
|
oldBinding->setEnabled(false, {});
|
||||||
|
|
|
@ -345,7 +345,9 @@ void QQmlTypeData::done()
|
||||||
++it) {
|
++it) {
|
||||||
const TypeReference &type = *it;
|
const TypeReference &type = *it;
|
||||||
Q_ASSERT(!type.typeData || type.typeData->isCompleteOrError() || type.type.isInlineComponentType());
|
Q_ASSERT(!type.typeData || type.typeData->isCompleteOrError() || type.type.isInlineComponentType());
|
||||||
if (type.type.isInlineComponentType() && !type.type.pendingResolutionName().isEmpty()) {
|
if (type.errorWhenNotFound
|
||||||
|
&& type.type.isInlineComponentType()
|
||||||
|
&& !type.type.pendingResolutionName().isEmpty()) {
|
||||||
auto containingType = type.type.containingType();
|
auto containingType = type.type.containingType();
|
||||||
auto objectId = containingType.lookupInlineComponentIdByName(type.type.pendingResolutionName());
|
auto objectId = containingType.lookupInlineComponentIdByName(type.type.pendingResolutionName());
|
||||||
if (objectId < 0) { // can be any negative number if we tentatively resolved it in QQmlImport but it actually was not an inline component
|
if (objectId < 0) { // can be any negative number if we tentatively resolved it in QQmlImport but it actually was not an inline component
|
||||||
|
@ -365,7 +367,7 @@ void QQmlTypeData::done()
|
||||||
type.type.setInlineComponentObjectId(objectId);
|
type.type.setInlineComponentObjectId(objectId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (type.typeData && type.typeData->isError()) {
|
if (type.errorWhenNotFound && type.typeData && type.typeData->isError()) {
|
||||||
const QString typeName = stringAt(it.key());
|
const QString typeName = stringAt(it.key());
|
||||||
|
|
||||||
QList<QQmlError> errors = type.typeData->errors();
|
QList<QQmlError> errors = type.typeData->errors();
|
||||||
|
@ -887,6 +889,7 @@ void QQmlTypeData::resolveTypes()
|
||||||
ref.version = version;
|
ref.version = version;
|
||||||
ref.location = unresolvedRef->location;
|
ref.location = unresolvedRef->location;
|
||||||
ref.needsCreation = unresolvedRef->needsCreation;
|
ref.needsCreation = unresolvedRef->needsCreation;
|
||||||
|
ref.errorWhenNotFound = unresolvedRef->errorWhenNotFound;
|
||||||
m_resolvedTypes.insert(unresolvedRef.key(), ref);
|
m_resolvedTypes.insert(unresolvedRef.key(), ref);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -930,8 +933,12 @@ QQmlError QQmlTypeData::buildTypeResolutionCaches(
|
||||||
} else {
|
} else {
|
||||||
objectId = resolvedType->type.inlineComponentId();
|
objectId = resolvedType->type.inlineComponentId();
|
||||||
}
|
}
|
||||||
Q_ASSERT(objectId != -1);
|
|
||||||
ref->setTypePropertyCache(resolvedType->typeData->compilationUnit()->propertyCaches.at(objectId));
|
if (objectId >= 0) {
|
||||||
|
ref->setTypePropertyCache(
|
||||||
|
resolvedType->typeData->compilationUnit()->propertyCaches.at(objectId));
|
||||||
|
}
|
||||||
|
|
||||||
ref->setType(qmlType);
|
ref->setType(qmlType);
|
||||||
Q_ASSERT(ref->type().isInlineComponentType());
|
Q_ASSERT(ref->type().isInlineComponentType());
|
||||||
}
|
}
|
||||||
|
|
|
@ -62,16 +62,16 @@ class Q_AUTOTEST_EXPORT QQmlTypeData : public QQmlTypeLoader::Blob
|
||||||
public:
|
public:
|
||||||
struct TypeReference
|
struct TypeReference
|
||||||
{
|
{
|
||||||
TypeReference() : version(QTypeRevision::zero()), needsCreation(true) {}
|
|
||||||
|
|
||||||
QV4::CompiledData::Location location;
|
QV4::CompiledData::Location location;
|
||||||
QQmlType type;
|
QQmlType type;
|
||||||
QTypeRevision version;
|
QTypeRevision version = QTypeRevision::zero();
|
||||||
QQmlRefPointer<QQmlTypeData> typeData;
|
QQmlRefPointer<QQmlTypeData> typeData;
|
||||||
bool selfReference = false;
|
|
||||||
QString prefix; // used by CompositeSingleton types
|
QString prefix; // used by CompositeSingleton types
|
||||||
|
bool selfReference = false;
|
||||||
|
bool needsCreation = true;
|
||||||
|
bool errorWhenNotFound = true;
|
||||||
|
|
||||||
QString qualifiedName() const;
|
QString qualifiedName() const;
|
||||||
bool needsCreation;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ScriptReference
|
struct ScriptReference
|
||||||
|
|
|
@ -1340,6 +1340,7 @@ void QQmlJSImportVisitor::endVisit(UiArrayBinding *)
|
||||||
bool QQmlJSImportVisitor::visit(QQmlJS::AST::UiEnumDeclaration *uied)
|
bool QQmlJSImportVisitor::visit(QQmlJS::AST::UiEnumDeclaration *uied)
|
||||||
{
|
{
|
||||||
QQmlJSMetaEnum qmlEnum(uied->name.toString());
|
QQmlJSMetaEnum qmlEnum(uied->name.toString());
|
||||||
|
qmlEnum.setIsQml(true);
|
||||||
for (const auto *member = uied->members; member; member = member->next) {
|
for (const auto *member = uied->members; member; member = member->next) {
|
||||||
qmlEnum.addKey(member->member.toString());
|
qmlEnum.addKey(member->member.toString());
|
||||||
qmlEnum.addValue(int(member->value));
|
qmlEnum.addValue(int(member->value));
|
||||||
|
|
|
@ -66,6 +66,8 @@ class QQmlJSMetaEnum
|
||||||
QString m_alias;
|
QString m_alias;
|
||||||
QSharedPointer<const QQmlJSScope> m_type;
|
QSharedPointer<const QQmlJSScope> m_type;
|
||||||
bool m_isFlag = false;
|
bool m_isFlag = false;
|
||||||
|
bool m_isScoped = false;
|
||||||
|
bool m_isQml = false;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
QQmlJSMetaEnum() = default;
|
QQmlJSMetaEnum() = default;
|
||||||
|
@ -82,6 +84,12 @@ public:
|
||||||
bool isFlag() const { return m_isFlag; }
|
bool isFlag() const { return m_isFlag; }
|
||||||
void setIsFlag(bool isFlag) { m_isFlag = isFlag; }
|
void setIsFlag(bool isFlag) { m_isFlag = isFlag; }
|
||||||
|
|
||||||
|
bool isScoped() const { return m_isScoped; }
|
||||||
|
void setIsScoped(bool v) { m_isScoped = v; }
|
||||||
|
|
||||||
|
bool isQml() const { return m_isQml; }
|
||||||
|
void setIsQml(bool v) { m_isQml = v; }
|
||||||
|
|
||||||
void addKey(const QString &key) { m_keys.append(key); }
|
void addKey(const QString &key) { m_keys.append(key); }
|
||||||
QStringList keys() const { return m_keys; }
|
QStringList keys() const { return m_keys; }
|
||||||
|
|
||||||
|
@ -102,7 +110,8 @@ public:
|
||||||
&& a.m_name == b.m_name
|
&& a.m_name == b.m_name
|
||||||
&& a.m_alias == b.m_alias
|
&& a.m_alias == b.m_alias
|
||||||
&& a.m_isFlag == b.m_isFlag
|
&& a.m_isFlag == b.m_isFlag
|
||||||
&& a.m_type == b.m_type;
|
&& a.m_type == b.m_type
|
||||||
|
&& a.m_isScoped == b.m_isScoped;
|
||||||
}
|
}
|
||||||
|
|
||||||
friend bool operator!=(const QQmlJSMetaEnum &a, const QQmlJSMetaEnum &b)
|
friend bool operator!=(const QQmlJSMetaEnum &a, const QQmlJSMetaEnum &b)
|
||||||
|
@ -112,7 +121,8 @@ public:
|
||||||
|
|
||||||
friend size_t qHash(const QQmlJSMetaEnum &e, size_t seed = 0)
|
friend size_t qHash(const QQmlJSMetaEnum &e, size_t seed = 0)
|
||||||
{
|
{
|
||||||
return qHashMulti(seed, e.m_keys, e.m_values, e.m_name, e.m_alias, e.m_isFlag, e.m_type);
|
return qHashMulti(
|
||||||
|
seed, e.m_keys, e.m_values, e.m_name, e.m_alias, e.m_isFlag, e.m_type, e.m_isScoped);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -418,9 +418,11 @@ void QQmlJSTypeDescriptionReader::readEnum(UiObjectDefinition *ast, const QQmlJS
|
||||||
metaEnum.setIsFlag(readBoolBinding(script));
|
metaEnum.setIsFlag(readBoolBinding(script));
|
||||||
} else if (name == QLatin1String("values")) {
|
} else if (name == QLatin1String("values")) {
|
||||||
readEnumValues(script, &metaEnum);
|
readEnumValues(script, &metaEnum);
|
||||||
|
} else if (name == QLatin1String("isScoped")) {
|
||||||
|
metaEnum.setIsScoped(readBoolBinding(script));
|
||||||
} else {
|
} else {
|
||||||
addWarning(script->firstSourceLocation(),
|
addWarning(script->firstSourceLocation(),
|
||||||
tr("Expected only name and values script bindings."));
|
tr("Expected only name, alias, isFlag, values, or isScoped."));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1699,9 +1699,12 @@ bool ModelObject::virtualPut(Managed *m, PropertyKey id, const Value &value, Val
|
||||||
|
|
||||||
ExecutionEngine *eng = that->engine();
|
ExecutionEngine *eng = that->engine();
|
||||||
const int elementIndex = that->d()->elementIndex();
|
const int elementIndex = that->d()->elementIndex();
|
||||||
int roleIndex = that->d()->m_model->m_listModel->setExistingProperty(elementIndex, propName, value, eng);
|
if (QQmlListModel *model = that->d()->m_model) {
|
||||||
if (roleIndex != -1)
|
const int roleIndex
|
||||||
that->d()->m_model->emitItemsChanged(elementIndex, 1, QVector<int>(1, roleIndex));
|
= model->listModel()->setExistingProperty(elementIndex, propName, value, eng);
|
||||||
|
if (roleIndex != -1)
|
||||||
|
model->emitItemsChanged(elementIndex, 1, QVector<int>(1, roleIndex));
|
||||||
|
}
|
||||||
|
|
||||||
ModelNodeMetaObject *mo = ModelNodeMetaObject::get(that->object());
|
ModelNodeMetaObject *mo = ModelNodeMetaObject::get(that->object());
|
||||||
if (mo->initialized())
|
if (mo->initialized())
|
||||||
|
@ -1717,7 +1720,11 @@ ReturnedValue ModelObject::virtualGet(const Managed *m, PropertyKey id, const Va
|
||||||
const ModelObject *that = static_cast<const ModelObject*>(m);
|
const ModelObject *that = static_cast<const ModelObject*>(m);
|
||||||
Scope scope(that);
|
Scope scope(that);
|
||||||
ScopedString name(scope, id.asStringOrSymbol());
|
ScopedString name(scope, id.asStringOrSymbol());
|
||||||
const ListLayout::Role *role = that->d()->m_model->m_listModel->getExistingRole(name);
|
QQmlListModel *model = that->d()->m_model;
|
||||||
|
if (!model)
|
||||||
|
return QObjectWrapper::virtualGet(m, id, receiver, hasProperty);
|
||||||
|
|
||||||
|
const ListLayout::Role *role = model->listModel()->getExistingRole(name);
|
||||||
if (!role)
|
if (!role)
|
||||||
return QObjectWrapper::virtualGet(m, id, receiver, hasProperty);
|
return QObjectWrapper::virtualGet(m, id, receiver, hasProperty);
|
||||||
if (hasProperty)
|
if (hasProperty)
|
||||||
|
@ -1730,7 +1737,7 @@ ReturnedValue ModelObject::virtualGet(const Managed *m, PropertyKey id, const Va
|
||||||
}
|
}
|
||||||
|
|
||||||
const int elementIndex = that->d()->elementIndex();
|
const int elementIndex = that->d()->elementIndex();
|
||||||
QVariant value = that->d()->m_model->data(elementIndex, role->index);
|
QVariant value = model->data(elementIndex, role->index);
|
||||||
return that->engine()->fromVariant(value);
|
return that->engine()->fromVariant(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1753,16 +1760,19 @@ PropertyKey ModelObjectOwnPropertyKeyIterator::next(const Object *o, Property *p
|
||||||
const ModelObject *that = static_cast<const ModelObject *>(o);
|
const ModelObject *that = static_cast<const ModelObject *>(o);
|
||||||
|
|
||||||
ExecutionEngine *v4 = that->engine();
|
ExecutionEngine *v4 = that->engine();
|
||||||
if (roleNameIndex < that->listModel()->roleCount()) {
|
|
||||||
|
QQmlListModel *model = that->d()->m_model;
|
||||||
|
ListModel *listModel = model ? model->listModel() : nullptr;
|
||||||
|
if (listModel && roleNameIndex < listModel->roleCount()) {
|
||||||
Scope scope(that->engine());
|
Scope scope(that->engine());
|
||||||
const ListLayout::Role &role = that->listModel()->getExistingRole(roleNameIndex);
|
const ListLayout::Role &role = listModel->getExistingRole(roleNameIndex);
|
||||||
++roleNameIndex;
|
++roleNameIndex;
|
||||||
ScopedString roleName(scope, v4->newString(role.name));
|
ScopedString roleName(scope, v4->newString(role.name));
|
||||||
if (attrs)
|
if (attrs)
|
||||||
*attrs = QV4::Attr_Data;
|
*attrs = QV4::Attr_Data;
|
||||||
if (pd) {
|
if (pd) {
|
||||||
|
|
||||||
QVariant value = that->d()->m_model->data(that->d()->elementIndex(), role.index);
|
QVariant value = model->data(that->d()->elementIndex(), role.index);
|
||||||
if (auto recursiveListModel = qvariant_cast<QQmlListModel*>(value)) {
|
if (auto recursiveListModel = qvariant_cast<QQmlListModel*>(value)) {
|
||||||
auto size = recursiveListModel->count();
|
auto size = recursiveListModel->count();
|
||||||
auto array = ScopedArrayObject{scope, v4->newArrayObject(size)};
|
auto array = ScopedArrayObject{scope, v4->newArrayObject(size)};
|
||||||
|
|
|
@ -115,6 +115,8 @@ public:
|
||||||
bool dynamicRoles() const { return m_dynamicRoles; }
|
bool dynamicRoles() const { return m_dynamicRoles; }
|
||||||
void setDynamicRoles(bool enableDynamicRoles);
|
void setDynamicRoles(bool enableDynamicRoles);
|
||||||
|
|
||||||
|
ListModel *listModel() const { return m_listModel; }
|
||||||
|
|
||||||
Q_SIGNALS:
|
Q_SIGNALS:
|
||||||
void countChanged();
|
void countChanged();
|
||||||
|
|
||||||
|
|
|
@ -161,13 +161,23 @@ struct ModelObject : public QObjectWrapper {
|
||||||
{
|
{
|
||||||
QObjectWrapper::init(object);
|
QObjectWrapper::init(object);
|
||||||
m_model = model;
|
m_model = model;
|
||||||
QObjectPrivate *op = QObjectPrivate::get(object);
|
|
||||||
m_nodeModelMetaObject = static_cast<ModelNodeMetaObject *>(op->metaObject);
|
|
||||||
}
|
}
|
||||||
void destroy() { QObjectWrapper::destroy(); }
|
|
||||||
int elementIndex() const { return m_nodeModelMetaObject->m_elementIndex; }
|
void destroy()
|
||||||
QQmlListModel *m_model;
|
{
|
||||||
ModelNodeMetaObject *m_nodeModelMetaObject;
|
m_model.destroy();
|
||||||
|
QObjectWrapper::destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
int elementIndex() const {
|
||||||
|
if (const QObject *o = object()) {
|
||||||
|
const QObjectPrivate *op = QObjectPrivate::get(o);
|
||||||
|
return static_cast<ModelNodeMetaObject *>(op->metaObject)->m_elementIndex;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
QV4QPointer<QQmlListModel> m_model;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -177,8 +187,6 @@ struct ModelObject : public QObjectWrapper
|
||||||
V4_OBJECT2(ModelObject, QObjectWrapper)
|
V4_OBJECT2(ModelObject, QObjectWrapper)
|
||||||
V4_NEEDS_DESTROY
|
V4_NEEDS_DESTROY
|
||||||
|
|
||||||
ListModel *listModel() const { return d()->m_model->m_listModel; }
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
static bool virtualPut(Managed *m, PropertyKey id, const Value& value, Value *receiver);
|
static bool virtualPut(Managed *m, PropertyKey id, const Value& value, Value *receiver);
|
||||||
static ReturnedValue virtualGet(const Managed *m, PropertyKey id, const Value *receiver, bool *hasProperty);
|
static ReturnedValue virtualGet(const Managed *m, PropertyKey id, const Value *receiver, bool *hasProperty);
|
||||||
|
|
|
@ -118,15 +118,67 @@
|
||||||
\snippet src_qmltest_qquicktest_snippet.cpp 1
|
\snippet src_qmltest_qquicktest_snippet.cpp 1
|
||||||
|
|
||||||
Where "example" is the identifier to use to uniquely identify
|
Where "example" is the identifier to use to uniquely identify
|
||||||
this set of tests. Finally, add \c{CONFIG += qmltestcase} to the project
|
this set of tests.
|
||||||
file:
|
|
||||||
|
\if defined(onlinedocs)
|
||||||
|
\tab {run-qtquicktest}{tab-cmake}{CMake}{checked}
|
||||||
|
\tab {run-qtquicktest}{tab-qmake}{qmake}{}
|
||||||
|
\tabcontent {tab-cmake}
|
||||||
|
\else
|
||||||
|
\section1 Using CMake
|
||||||
|
\endif
|
||||||
|
Configure your CMakeLists.txt file and build your project using your
|
||||||
|
favorite generator.
|
||||||
|
\badcode
|
||||||
|
cmake_minimum_required(VERSION 3.2)
|
||||||
|
|
||||||
|
project(tst_example LANGUAGES CXX)
|
||||||
|
|
||||||
|
enable_testing()
|
||||||
|
|
||||||
|
find_package(Qt6 REQUIRED COMPONENTS QuickTest Qml)
|
||||||
|
|
||||||
|
#[[The test harness scans the specified source directory recursively
|
||||||
|
for "tst_*.qml" files. By default, it looks in the current directory,
|
||||||
|
which is usually where the executable is. This command makes it look
|
||||||
|
in the project's source directory instead.]]
|
||||||
|
add_definitions(-DQUICK_TEST_SOURCE_DIR="${CMAKE_CURRENT_SOURCE_DIR}")
|
||||||
|
|
||||||
|
qt_standard_project_setup(REQUIRES 6.6)
|
||||||
|
|
||||||
|
add_executable(tst_example tst_example.cpp)
|
||||||
|
|
||||||
|
add_test(NAME tst_example COMMAND tst_example)
|
||||||
|
|
||||||
|
target_link_libraries(tst_example
|
||||||
|
PRIVATE
|
||||||
|
Qt6::QuickTest
|
||||||
|
Qt6::Qml
|
||||||
|
)
|
||||||
|
\endcode
|
||||||
|
\if defined(onlinedocs)
|
||||||
|
\endtabcontent
|
||||||
|
\tabcontent {tab-qmake}
|
||||||
|
\else
|
||||||
|
\section1 Using qmake
|
||||||
|
\endif
|
||||||
|
Add \c{CONFIG += qmltestcase} to your project file:
|
||||||
|
\badcode
|
||||||
|
TEMPLATE = app
|
||||||
|
TARGET = tst_example
|
||||||
|
CONFIG += warn_on qmltestcase
|
||||||
|
SOURCES += tst_example.cpp
|
||||||
|
\endcode
|
||||||
|
|
||||||
|
If \c IMPORTPATH is specified in your .pro file, each import path added to \c IMPORTPATH
|
||||||
|
will be passed as a command-line argument when the test is run using "make check":
|
||||||
|
|
||||||
\badcode
|
\badcode
|
||||||
TEMPLATE = app
|
IMPORTPATH += $$PWD/../imports/my_module1 $$PWD/../imports/my_module2
|
||||||
TARGET = tst_example
|
|
||||||
CONFIG += warn_on qmltestcase
|
|
||||||
SOURCES += tst_example.cpp
|
|
||||||
\endcode
|
\endcode
|
||||||
|
\if defined(onlinedocs)
|
||||||
|
\endtabcontent
|
||||||
|
\endif
|
||||||
|
|
||||||
The test harness scans the specified source directory recursively
|
The test harness scans the specified source directory recursively
|
||||||
for "tst_*.qml" files. If \c{QUICK_TEST_SOURCE_DIR} is not defined,
|
for "tst_*.qml" files. If \c{QUICK_TEST_SOURCE_DIR} is not defined,
|
||||||
|
@ -160,12 +212,6 @@
|
||||||
If your test case needs QML imports, then you can add them as
|
If your test case needs QML imports, then you can add them as
|
||||||
\c{-import} options to the test program command-line.
|
\c{-import} options to the test program command-line.
|
||||||
|
|
||||||
If \c IMPORTPATH is specified in your .pro file, each import path added to \c IMPORTPATH
|
|
||||||
will be passed as a command-line argument when the test is run using "make check":
|
|
||||||
|
|
||||||
\badcode
|
|
||||||
IMPORTPATH += $$PWD/../imports/my_module1 $$PWD/../imports/my_module2
|
|
||||||
\endcode
|
|
||||||
|
|
||||||
The \c{-functions} command-line option will return a list of the current
|
The \c{-functions} command-line option will return a list of the current
|
||||||
tests functions. It is possible to run a single test function using the name
|
tests functions. It is possible to run a single test function using the name
|
||||||
|
|
|
@ -112,10 +112,16 @@ void QmlTypesClassDescription::collectLocalAnonymous(
|
||||||
const auto classInfos = classDef->value(QLatin1String("classInfos")).toArray();
|
const auto classInfos = classDef->value(QLatin1String("classInfos")).toArray();
|
||||||
for (const QJsonValue classInfo : classInfos) {
|
for (const QJsonValue classInfo : classInfos) {
|
||||||
const QJsonObject obj = classInfo.toObject();
|
const QJsonObject obj = classInfo.toObject();
|
||||||
if (obj[QStringLiteral("name")].toString() == QStringLiteral("DefaultProperty"))
|
const QString name = obj[QStringLiteral("name")].toString();
|
||||||
defaultProp = obj[QStringLiteral("value")].toString();
|
const auto value = [&]() { return obj[QStringLiteral("value")].toString(); };
|
||||||
if (obj[QStringLiteral("name")].toString() == QStringLiteral("ParentProperty"))
|
if (name == QStringLiteral("DefaultProperty")) {
|
||||||
parentProp = obj[QStringLiteral("value")].toString();
|
defaultProp = value();
|
||||||
|
} else if (name == QStringLiteral("ParentProperty")) {
|
||||||
|
parentProp = value();
|
||||||
|
} else if (name == QStringLiteral("RegisterEnumClassesUnscoped")
|
||||||
|
&& value() == QStringLiteral("false")) {
|
||||||
|
registerEnumClassesScoped = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
collectInterfaces(classDef);
|
collectInterfaces(classDef);
|
||||||
|
@ -143,6 +149,9 @@ void QmlTypesClassDescription::collect(
|
||||||
} else if (name == QLatin1String("ParentProperty")) {
|
} else if (name == QLatin1String("ParentProperty")) {
|
||||||
if (mode != RelatedType && parentProp.isEmpty())
|
if (mode != RelatedType && parentProp.isEmpty())
|
||||||
parentProp = value;
|
parentProp = value;
|
||||||
|
} else if (name == QLatin1String("RegisterEnumClassesUnscoped")) {
|
||||||
|
if (mode != RelatedType && value == QLatin1String("false"))
|
||||||
|
registerEnumClassesScoped = true;
|
||||||
} else if (name == QLatin1String("QML.AddedInVersion")) {
|
} else if (name == QLatin1String("QML.AddedInVersion")) {
|
||||||
const QTypeRevision revision = QTypeRevision::fromEncodedVersion(value.toInt());
|
const QTypeRevision revision = QTypeRevision::fromEncodedVersion(value.toInt());
|
||||||
if (mode == TopLevel) {
|
if (mode == TopLevel) {
|
||||||
|
@ -192,10 +201,12 @@ void QmlTypesClassDescription::collect(
|
||||||
if (const QJsonObject *other = findType(foreign, foreignTypeName)) {
|
if (const QJsonObject *other = findType(foreign, foreignTypeName)) {
|
||||||
classDef = other;
|
classDef = other;
|
||||||
|
|
||||||
// Default properties are always local.
|
// Default properties and enum classes are always local.
|
||||||
defaultProp.clear();
|
defaultProp.clear();
|
||||||
|
registerEnumClassesScoped = false;
|
||||||
|
|
||||||
// Foreign type can have a default property or an attached types
|
// Foreign type can have a default property or an attached types
|
||||||
|
// or RegisterEnumClassesUnscoped classinfo.
|
||||||
const auto classInfos = classDef->value(QLatin1String("classInfos")).toArray();
|
const auto classInfos = classDef->value(QLatin1String("classInfos")).toArray();
|
||||||
for (const QJsonValue classInfo : classInfos) {
|
for (const QJsonValue classInfo : classInfos) {
|
||||||
const QJsonObject obj = classInfo.toObject();
|
const QJsonObject obj = classInfo.toObject();
|
||||||
|
@ -205,6 +216,9 @@ void QmlTypesClassDescription::collect(
|
||||||
defaultProp = foreignValue;
|
defaultProp = foreignValue;
|
||||||
} else if (parentProp.isEmpty() && foreignName == QLatin1String("ParentProperty")) {
|
} else if (parentProp.isEmpty() && foreignName == QLatin1String("ParentProperty")) {
|
||||||
parentProp = foreignValue;
|
parentProp = foreignValue;
|
||||||
|
} else if (foreignName == QLatin1String("RegisterEnumClassesUnscoped")) {
|
||||||
|
if (foreignValue == QLatin1String("false"))
|
||||||
|
registerEnumClassesScoped = true;
|
||||||
} else if (foreignName == QLatin1String("QML.Attached")) {
|
} else if (foreignName == QLatin1String("QML.Attached")) {
|
||||||
attachedType = foreignValue;
|
attachedType = foreignValue;
|
||||||
collectRelated(foreignValue, types, foreign, defaultRevision);
|
collectRelated(foreignValue, types, foreign, defaultRevision);
|
||||||
|
|
|
@ -55,6 +55,7 @@ struct QmlTypesClassDescription
|
||||||
bool isSingleton = false;
|
bool isSingleton = false;
|
||||||
bool isRootClass = false;
|
bool isRootClass = false;
|
||||||
bool hasCustomParser = false;
|
bool hasCustomParser = false;
|
||||||
|
bool registerEnumClassesScoped = false;
|
||||||
QStringList implementsInterfaces;
|
QStringList implementsInterfaces;
|
||||||
|
|
||||||
enum CollectMode {
|
enum CollectMode {
|
||||||
|
|
|
@ -244,7 +244,8 @@ void QmlTypesCreator::writeMethods(const QJsonArray &methods, const QString &typ
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void QmlTypesCreator::writeEnums(const QJsonArray &enums)
|
void QmlTypesCreator::writeEnums(
|
||||||
|
const QJsonArray &enums, QmlTypesCreator::EnumClassesMode enumClassesMode)
|
||||||
{
|
{
|
||||||
for (const QJsonValue item : enums) {
|
for (const QJsonValue item : enums) {
|
||||||
const QJsonObject obj = item.toObject();
|
const QJsonObject obj = item.toObject();
|
||||||
|
@ -263,6 +264,13 @@ void QmlTypesCreator::writeEnums(const QJsonArray &enums)
|
||||||
auto isFlag = obj.find(QLatin1String("isFlag"));
|
auto isFlag = obj.find(QLatin1String("isFlag"));
|
||||||
if (isFlag != obj.end() && isFlag->toBool())
|
if (isFlag != obj.end() && isFlag->toBool())
|
||||||
m_qml.writeBooleanBinding(isFlag.key(), true);
|
m_qml.writeBooleanBinding(isFlag.key(), true);
|
||||||
|
|
||||||
|
if (enumClassesMode == EnumClassesMode::Scoped) {
|
||||||
|
const auto isClass = obj.find(QLatin1String("isClass"));
|
||||||
|
if (isClass != obj.end() && isClass->toBool())
|
||||||
|
m_qml.writeBooleanBinding(QLatin1String("isScoped"), true);
|
||||||
|
}
|
||||||
|
|
||||||
m_qml.writeArrayBinding(QLatin1String("values"), valueList);
|
m_qml.writeArrayBinding(QLatin1String("values"), valueList);
|
||||||
m_qml.writeEndObject();
|
m_qml.writeEndObject();
|
||||||
}
|
}
|
||||||
|
@ -382,7 +390,11 @@ void QmlTypesCreator::writeComponents()
|
||||||
writeClassProperties(collector);
|
writeClassProperties(collector);
|
||||||
|
|
||||||
if (const QJsonObject *classDef = collector.resolvedClass) {
|
if (const QJsonObject *classDef = collector.resolvedClass) {
|
||||||
writeEnums(members(classDef, enumsKey, m_version));
|
writeEnums(
|
||||||
|
members(classDef, enumsKey, m_version),
|
||||||
|
collector.registerEnumClassesScoped
|
||||||
|
? EnumClassesMode::Scoped
|
||||||
|
: EnumClassesMode::Unscoped);
|
||||||
|
|
||||||
writeProperties(members(classDef, propertiesKey, m_version));
|
writeProperties(members(classDef, propertiesKey, m_version));
|
||||||
|
|
||||||
|
@ -411,7 +423,11 @@ void QmlTypesCreator::writeComponents()
|
||||||
collector.collectLocalAnonymous(&component, m_ownTypes, m_foreignTypes, m_version);
|
collector.collectLocalAnonymous(&component, m_ownTypes, m_foreignTypes, m_version);
|
||||||
|
|
||||||
writeClassProperties(collector);
|
writeClassProperties(collector);
|
||||||
writeEnums(members(&component, enumsKey, m_version));
|
writeEnums(
|
||||||
|
members(&component, enumsKey, m_version),
|
||||||
|
collector.registerEnumClassesScoped
|
||||||
|
? EnumClassesMode::Scoped
|
||||||
|
: EnumClassesMode::Unscoped);
|
||||||
|
|
||||||
writeProperties(members(&component, propertiesKey, m_version));
|
writeProperties(members(&component, propertiesKey, m_version));
|
||||||
|
|
||||||
|
|
|
@ -53,7 +53,10 @@ private:
|
||||||
void writeType(const QJsonObject &property, const QString &key);
|
void writeType(const QJsonObject &property, const QString &key);
|
||||||
void writeProperties(const QJsonArray &properties);
|
void writeProperties(const QJsonArray &properties);
|
||||||
void writeMethods(const QJsonArray &methods, const QString &type);
|
void writeMethods(const QJsonArray &methods, const QString &type);
|
||||||
void writeEnums(const QJsonArray &enums);
|
|
||||||
|
enum class EnumClassesMode { Scoped, Unscoped };
|
||||||
|
void writeEnums(const QJsonArray &enums, EnumClassesMode enumClassesMode);
|
||||||
|
|
||||||
void writeComponents();
|
void writeComponents();
|
||||||
|
|
||||||
QByteArray m_output;
|
QByteArray m_output;
|
||||||
|
|
|
@ -0,0 +1,74 @@
|
||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (C) 2024 The Qt Company Ltd.
|
||||||
|
** Contact: https://www.qt.io/licensing/
|
||||||
|
**
|
||||||
|
** This file is part of the documentation of the Qt Toolkit.
|
||||||
|
**
|
||||||
|
** $QT_BEGIN_LICENSE:BSD$
|
||||||
|
** 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.
|
||||||
|
**
|
||||||
|
** BSD License Usage
|
||||||
|
** Alternatively, you may use this file under the terms of the BSD license
|
||||||
|
** as follows:
|
||||||
|
**
|
||||||
|
** "Redistribution and use in source and binary forms, with or without
|
||||||
|
** modification, are permitted provided that the following conditions are
|
||||||
|
** met:
|
||||||
|
** * Redistributions of source code must retain the above copyright
|
||||||
|
** notice, this list of conditions and the following disclaimer.
|
||||||
|
** * Redistributions in binary form must reproduce the above copyright
|
||||||
|
** notice, this list of conditions and the following disclaimer in
|
||||||
|
** the documentation and/or other materials provided with the
|
||||||
|
** distribution.
|
||||||
|
** * Neither the name of The Qt Company Ltd nor the names of its
|
||||||
|
** contributors may be used to endorse or promote products derived
|
||||||
|
** from this software without specific prior written permission.
|
||||||
|
**
|
||||||
|
**
|
||||||
|
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
|
||||||
|
**
|
||||||
|
** $QT_END_LICENSE$
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
import QtQuick
|
||||||
|
|
||||||
|
//! [entire]
|
||||||
|
Item {
|
||||||
|
width: 320
|
||||||
|
height: 240
|
||||||
|
//![draggable]
|
||||||
|
Rectangle {
|
||||||
|
width: 24
|
||||||
|
height: 24
|
||||||
|
border.color: "steelblue"
|
||||||
|
Text {
|
||||||
|
text: "it's\ntiny"
|
||||||
|
font.pixelSize: 7
|
||||||
|
rotation: -45
|
||||||
|
anchors.centerIn: parent
|
||||||
|
}
|
||||||
|
|
||||||
|
DragHandler {
|
||||||
|
margin: 12
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//![draggable]
|
||||||
|
}
|
||||||
|
//! [entire]
|
|
@ -0,0 +1,168 @@
|
||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (C) 2024 The Qt Company Ltd.
|
||||||
|
** Contact: https://www.qt.io/licensing/
|
||||||
|
**
|
||||||
|
** This file is part of the documentation of the Qt Toolkit.
|
||||||
|
**
|
||||||
|
** $QT_BEGIN_LICENSE:BSD$
|
||||||
|
** 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.
|
||||||
|
**
|
||||||
|
** BSD License Usage
|
||||||
|
** Alternatively, you may use this file under the terms of the BSD license
|
||||||
|
** as follows:
|
||||||
|
**
|
||||||
|
** "Redistribution and use in source and binary forms, with or without
|
||||||
|
** modification, are permitted provided that the following conditions are
|
||||||
|
** met:
|
||||||
|
** * Redistributions of source code must retain the above copyright
|
||||||
|
** notice, this list of conditions and the following disclaimer.
|
||||||
|
** * Redistributions in binary form must reproduce the above copyright
|
||||||
|
** notice, this list of conditions and the following disclaimer in
|
||||||
|
** the documentation and/or other materials provided with the
|
||||||
|
** distribution.
|
||||||
|
** * Neither the name of The Qt Company Ltd nor the names of its
|
||||||
|
** contributors may be used to endorse or promote products derived
|
||||||
|
** from this software without specific prior written permission.
|
||||||
|
**
|
||||||
|
**
|
||||||
|
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
|
||||||
|
**
|
||||||
|
** $QT_END_LICENSE$
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
pragma ComponentBehavior: Bound
|
||||||
|
import QtQml
|
||||||
|
import QtQuick
|
||||||
|
import QtQml.Models
|
||||||
|
|
||||||
|
//! [entire]
|
||||||
|
GridView {
|
||||||
|
id: root
|
||||||
|
width: 320
|
||||||
|
height: 480
|
||||||
|
cellWidth: 80
|
||||||
|
cellHeight: 80
|
||||||
|
interactive: false
|
||||||
|
|
||||||
|
displaced: Transition {
|
||||||
|
NumberAnimation {
|
||||||
|
properties: "x,y"
|
||||||
|
easing.type: Easing.OutQuad
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
model: DelegateModel {
|
||||||
|
id: visualModel
|
||||||
|
model: 24
|
||||||
|
property var dropTarget: undefined
|
||||||
|
property bool copy: false
|
||||||
|
delegate: DropArea {
|
||||||
|
id: delegateRoot
|
||||||
|
|
||||||
|
width: 80
|
||||||
|
height: 80
|
||||||
|
|
||||||
|
onEntered: drag => {
|
||||||
|
if (visualModel.copy) {
|
||||||
|
if (drag.source !== icon)
|
||||||
|
visualModel.dropTarget = icon
|
||||||
|
} else {
|
||||||
|
visualModel.items.move(drag.source.DelegateModel.itemsIndex, icon.DelegateModel.itemsIndex)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: icon
|
||||||
|
objectName: DelegateModel.itemsIndex
|
||||||
|
|
||||||
|
property string text
|
||||||
|
Component.onCompleted: {
|
||||||
|
color = Qt.rgba(0.2 + (48 - DelegateModel.itemsIndex) * Math.random() / 48,
|
||||||
|
0.3 + DelegateModel.itemsIndex * Math.random() / 48,
|
||||||
|
0.4 * Math.random(),
|
||||||
|
1.0)
|
||||||
|
text = DelegateModel.itemsIndex
|
||||||
|
}
|
||||||
|
border.color: visualModel.dropTarget === this ? "black" : "transparent"
|
||||||
|
border.width: 2
|
||||||
|
radius: 3
|
||||||
|
width: 72
|
||||||
|
height: 72
|
||||||
|
anchors {
|
||||||
|
horizontalCenter: parent.horizontalCenter
|
||||||
|
verticalCenter: parent.verticalCenter
|
||||||
|
}
|
||||||
|
|
||||||
|
states: [
|
||||||
|
State {
|
||||||
|
when: dragHandler.active || controlDragHandler.active
|
||||||
|
ParentChange {
|
||||||
|
target: icon
|
||||||
|
parent: root
|
||||||
|
}
|
||||||
|
|
||||||
|
AnchorChanges {
|
||||||
|
target: icon
|
||||||
|
anchors {
|
||||||
|
horizontalCenter: undefined
|
||||||
|
verticalCenter: undefined
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
Text {
|
||||||
|
anchors.centerIn: parent
|
||||||
|
color: "white"
|
||||||
|
font.pointSize: 14
|
||||||
|
text: controlDragHandler.active ? "+" : icon.text
|
||||||
|
}
|
||||||
|
|
||||||
|
//! [draghandlers]
|
||||||
|
DragHandler {
|
||||||
|
id: dragHandler
|
||||||
|
acceptedModifiers: Qt.NoModifier
|
||||||
|
onActiveChanged: if (!active) visualModel.dropTarget = undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
DragHandler {
|
||||||
|
id: controlDragHandler
|
||||||
|
acceptedModifiers: Qt.ControlModifier
|
||||||
|
onActiveChanged: {
|
||||||
|
visualModel.copy = active
|
||||||
|
if (!active) {
|
||||||
|
visualModel.dropTarget.text = icon.text
|
||||||
|
visualModel.dropTarget.color = icon.color
|
||||||
|
visualModel.dropTarget = undefined
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//! [draghandlers]
|
||||||
|
|
||||||
|
Drag.active: dragHandler.active || controlDragHandler.active
|
||||||
|
Drag.source: icon
|
||||||
|
Drag.hotSpot.x: 36
|
||||||
|
Drag.hotSpot.y: 36
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//! [entire]
|
|
@ -86,7 +86,8 @@ Q_LOGGING_CATEGORY(lcDragHandler, "qt.quick.handler.drag")
|
||||||
\c target is an Item, \c centroid is the point at which the drag begins and
|
\c target is an Item, \c centroid is the point at which the drag begins and
|
||||||
to which the \c target will be moved (subject to constraints).
|
to which the \c target will be moved (subject to constraints).
|
||||||
|
|
||||||
At this time, drag-and-drop is not yet supported.
|
DragHandler can be used together with the \l Drag attached property to
|
||||||
|
implement drag-and-drop.
|
||||||
|
|
||||||
\sa Drag, MouseArea, {Pointer Handlers Example}
|
\sa Drag, MouseArea, {Pointer Handlers Example}
|
||||||
*/
|
*/
|
||||||
|
@ -134,7 +135,7 @@ void QQuickDragHandler::onGrabChanged(QQuickPointerHandler *grabber, QPointingDe
|
||||||
The snap mode configures snapping of the \l target item's center to the \l eventPoint.
|
The snap mode configures snapping of the \l target item's center to the \l eventPoint.
|
||||||
|
|
||||||
Possible values:
|
Possible values:
|
||||||
\value DragHandler.SnapNever Never snap
|
\value DragHandler.NoSnap Never snap
|
||||||
\value DragHandler.SnapAuto The \l target snaps if the \l eventPoint was pressed outside of the \l target
|
\value DragHandler.SnapAuto The \l target snaps if the \l eventPoint was pressed outside of the \l target
|
||||||
item \e and the \l target is a descendant of \l {PointerHandler::}{parent} item (default)
|
item \e and the \l target is a descendant of \l {PointerHandler::}{parent} item (default)
|
||||||
\value DragHandler.SnapWhenPressedOutsideTarget The \l target snaps if the \l eventPoint was pressed outside of the \l target
|
\value DragHandler.SnapWhenPressedOutsideTarget The \l target snaps if the \l eventPoint was pressed outside of the \l target
|
||||||
|
@ -394,6 +395,93 @@ void QQuickDragHandler::setActiveTranslation(const QVector2D &trans)
|
||||||
\c {0, 0} again.
|
\c {0, 0} again.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\qmlproperty flags QtQuick::DragHandler::acceptedButtons
|
||||||
|
|
||||||
|
The mouse buttons that can activate this DragHandler.
|
||||||
|
|
||||||
|
By default, this property is set to
|
||||||
|
\l {QtQuick::MouseEvent::button} {Qt.LeftButton}.
|
||||||
|
It can be set to an OR combination of mouse buttons, and will ignore events
|
||||||
|
from other buttons.
|
||||||
|
|
||||||
|
For example, if a component (such as TextEdit) already handles
|
||||||
|
left-button drags in its own way, it can be augmented with a
|
||||||
|
DragHandler that does something different when dragged via the
|
||||||
|
right button:
|
||||||
|
|
||||||
|
\snippet pointerHandlers/dragHandlerAcceptedButtons.qml 0
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\qmlproperty flags DragHandler::acceptedDevices
|
||||||
|
|
||||||
|
The types of pointing devices that can activate this DragHandler.
|
||||||
|
|
||||||
|
By default, this property is set to
|
||||||
|
\l{QInputDevice::DeviceType}{PointerDevice.AllDevices}.
|
||||||
|
If you set it to an OR combination of device types, it will ignore events
|
||||||
|
from non-matching devices.
|
||||||
|
|
||||||
|
\note Not all platforms are yet able to distinguish mouse and touchpad; and
|
||||||
|
on those that do, you often want to make mouse and touchpad behavior the same.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\qmlproperty flags DragHandler::acceptedModifiers
|
||||||
|
|
||||||
|
If this property is set, it will require the given keyboard modifiers to
|
||||||
|
be pressed in order to react to pointer events, and otherwise ignore them.
|
||||||
|
|
||||||
|
For example, two DragHandlers can perform two different drag-and-drop
|
||||||
|
operations, depending on whether the \c Control modifier is pressed:
|
||||||
|
|
||||||
|
\snippet pointerHandlers/draggableGridView.qml entire
|
||||||
|
|
||||||
|
If this property is set to \c Qt.KeyboardModifierMask (the default value),
|
||||||
|
then the DragHandler ignores the modifier keys.
|
||||||
|
|
||||||
|
If you set \c acceptedModifiers to an OR combination of modifier keys,
|
||||||
|
it means \e all of those modifiers must be pressed to activate the handler.
|
||||||
|
|
||||||
|
The available modifiers are as follows:
|
||||||
|
|
||||||
|
\value NoModifier No modifier key is allowed.
|
||||||
|
\value ShiftModifier A Shift key on the keyboard must be pressed.
|
||||||
|
\value ControlModifier A Ctrl key on the keyboard must be pressed.
|
||||||
|
\value AltModifier An Alt key on the keyboard must be pressed.
|
||||||
|
\value MetaModifier A Meta key on the keyboard must be pressed.
|
||||||
|
\value KeypadModifier A keypad button must be pressed.
|
||||||
|
\value GroupSwitchModifier X11 only (unless activated on Windows by a command line argument).
|
||||||
|
A Mode_switch key on the keyboard must be pressed.
|
||||||
|
\value KeyboardModifierMask The handler does not care which modifiers are pressed.
|
||||||
|
|
||||||
|
\sa Qt::KeyboardModifier
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\qmlproperty flags DragHandler::acceptedPointerTypes
|
||||||
|
|
||||||
|
The types of pointing instruments (finger, stylus, eraser, etc.)
|
||||||
|
that can activate this DragHandler.
|
||||||
|
|
||||||
|
By default, this property is set to
|
||||||
|
\l {QPointingDevice::PointerType} {PointerDevice.AllPointerTypes}.
|
||||||
|
If you set it to an OR combination of device types, it will ignore events
|
||||||
|
from non-matching \l {PointerDevice}{devices}.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\qmlproperty real DragHandler::margin
|
||||||
|
|
||||||
|
The margin beyond the bounds of the \l {PointerHandler::parent}{parent}
|
||||||
|
item within which an \l eventPoint can activate this handler. For example,
|
||||||
|
you can make it easier to drag small items by allowing the user to drag
|
||||||
|
from a position nearby:
|
||||||
|
|
||||||
|
\snippet pointerHandlers/dragHandlerMargin.qml draggable
|
||||||
|
*/
|
||||||
|
|
||||||
QT_END_NAMESPACE
|
QT_END_NAMESPACE
|
||||||
|
|
||||||
#include "moc_qquickdraghandler_p.cpp"
|
#include "moc_qquickdraghandler_p.cpp"
|
||||||
|
|
|
@ -1404,9 +1404,53 @@ void QQuickGridView::setHighlightFollowsCurrentItem(bool autoHighlight)
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\qmlproperty int QtQuick::GridView::count
|
\qmlproperty int QtQuick::GridView::count
|
||||||
This property holds the number of items in the view.
|
This property holds the number of items in the model.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\qmlproperty bool QtQuick::GridView::reuseItems
|
||||||
|
|
||||||
|
This property enables you to reuse items that are instantiated
|
||||||
|
from the \l delegate. If set to \c false, any currently
|
||||||
|
pooled items are destroyed.
|
||||||
|
|
||||||
|
This property is \c false by default.
|
||||||
|
|
||||||
|
\since 5.15
|
||||||
|
|
||||||
|
\sa {Reusing items}, pooled(), reused()
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\qmlattachedsignal QtQuick::GridView::pooled()
|
||||||
|
|
||||||
|
This signal is emitted after an item has been added to the reuse
|
||||||
|
pool. You can use it to pause ongoing timers or animations inside
|
||||||
|
the item, or free up resources that cannot be reused.
|
||||||
|
|
||||||
|
This signal is emitted only if the \l reuseItems property is \c true.
|
||||||
|
|
||||||
|
\sa {Reusing items}, reuseItems, reused()
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\qmlattachedsignal QtQuick::GridView::reused()
|
||||||
|
|
||||||
|
This signal is emitted after an item has been reused. At this point, the
|
||||||
|
item has been taken out of the pool and placed inside the content view,
|
||||||
|
and the model properties such as \c index and \c row have been updated.
|
||||||
|
|
||||||
|
Other properties that are not provided by the model does not change when an
|
||||||
|
item is reused. You should avoid storing any state inside a delegate, but if
|
||||||
|
you do, manually reset that state on receiving this signal.
|
||||||
|
|
||||||
|
This signal is emitted when the item is reused, and not the first time the
|
||||||
|
item is created.
|
||||||
|
|
||||||
|
This signal is emitted only if the \l reuseItems property is \c true.
|
||||||
|
|
||||||
|
\sa {Reusing items}, reuseItems, pooled()
|
||||||
|
*/
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\qmlproperty Component QtQuick::GridView::highlight
|
\qmlproperty Component QtQuick::GridView::highlight
|
||||||
|
|
|
@ -1721,7 +1721,7 @@ void QQuickListViewPrivate::fixup(AxisData &data, qreal minExtent, qreal maxExte
|
||||||
updateHighlight();
|
updateHighlight();
|
||||||
bottomItem = currentItem;
|
bottomItem = currentItem;
|
||||||
}
|
}
|
||||||
qreal pos;
|
qreal pos = 0;
|
||||||
bool isInBounds = -position() > maxExtent && -position() <= minExtent;
|
bool isInBounds = -position() > maxExtent && -position() <= minExtent;
|
||||||
|
|
||||||
if (header && !topItem && isInBounds) {
|
if (header && !topItem && isInBounds) {
|
||||||
|
@ -1802,6 +1802,19 @@ void QQuickListViewPrivate::fixup(AxisData &data, qreal minExtent, qreal maxExte
|
||||||
QQuickItemViewPrivate::fixup(data, minExtent, maxExtent);
|
QQuickItemViewPrivate::fixup(data, minExtent, maxExtent);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
// If we have the CurrentLabelAtStart flag set, then we need to consider
|
||||||
|
// the section size while calculating the position
|
||||||
|
if (sectionCriteria
|
||||||
|
&& (sectionCriteria->labelPositioning() & QQuickViewSection::CurrentLabelAtStart)
|
||||||
|
&& currentSectionItem) {
|
||||||
|
auto sectionSize = (orient == QQuickListView::Vertical) ? currentSectionItem->height()
|
||||||
|
: currentSectionItem->width();
|
||||||
|
if (isContentFlowReversed())
|
||||||
|
pos += sectionSize;
|
||||||
|
else
|
||||||
|
pos -= sectionSize;
|
||||||
|
}
|
||||||
|
|
||||||
pos = qBound(-minExtent, pos, -maxExtent);
|
pos = qBound(-minExtent, pos, -maxExtent);
|
||||||
|
|
||||||
qreal dist = qAbs(data.move + pos);
|
qreal dist = qAbs(data.move + pos);
|
||||||
|
@ -2380,7 +2393,7 @@ QQuickListView::~QQuickListView()
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\qmlproperty int QtQuick::ListView::count
|
\qmlproperty int QtQuick::ListView::count
|
||||||
This property holds the number of items in the view.
|
This property holds the number of items in the model.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
|
|
@ -3297,11 +3297,18 @@ void QQuickTableViewPrivate::syncSyncView()
|
||||||
q->setColumnSpacing(syncView->columnSpacing());
|
q->setColumnSpacing(syncView->columnSpacing());
|
||||||
updateContentWidth();
|
updateContentWidth();
|
||||||
|
|
||||||
if (syncView->leftColumn() != q->leftColumn()) {
|
if (scheduledRebuildOptions & RebuildOption::LayoutOnly) {
|
||||||
// The left column is no longer the same as the left
|
if (syncView->leftColumn() != q->leftColumn()
|
||||||
// column in syncView. This requires a rebuild.
|
|| syncView->d_func()->loadedTableOuterRect.left() != loadedTableOuterRect.left()) {
|
||||||
scheduledRebuildOptions |= QQuickTableViewPrivate::RebuildOption::CalculateNewTopLeftColumn;
|
// The left column is no longer the same, or at the same pos, as the left column in
|
||||||
scheduledRebuildOptions.setFlag(RebuildOption::ViewportOnly);
|
// syncView. This can happen if syncView did a relayout that caused its left column
|
||||||
|
// to be resized so small that it ended up outside the viewport. It can also happen
|
||||||
|
// if the syncView loaded and unloaded columns after the relayout. We therefore need
|
||||||
|
// to sync our own left column and pos to be the same, which we do by rebuilding the
|
||||||
|
// whole viewport instead of just doing a plain LayoutOnly.
|
||||||
|
scheduledRebuildOptions |= QQuickTableViewPrivate::RebuildOption::CalculateNewTopLeftColumn;
|
||||||
|
scheduledRebuildOptions.setFlag(RebuildOption::ViewportOnly);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3309,11 +3316,18 @@ void QQuickTableViewPrivate::syncSyncView()
|
||||||
q->setRowSpacing(syncView->rowSpacing());
|
q->setRowSpacing(syncView->rowSpacing());
|
||||||
updateContentHeight();
|
updateContentHeight();
|
||||||
|
|
||||||
if (syncView->topRow() != q->topRow()) {
|
if (scheduledRebuildOptions & RebuildOption::LayoutOnly) {
|
||||||
// The top row is no longer the same as the top
|
if (syncView->topRow() != q->topRow()
|
||||||
// row in syncView. This requires a rebuild.
|
|| syncView->d_func()->loadedTableOuterRect.top() != loadedTableOuterRect.top()) {
|
||||||
scheduledRebuildOptions |= QQuickTableViewPrivate::RebuildOption::CalculateNewTopLeftRow;
|
// The top row is no longer the same, or at the same pos, as the top row in
|
||||||
scheduledRebuildOptions.setFlag(RebuildOption::ViewportOnly);
|
// syncView. This can happen if syncView did a relayout that caused its top row
|
||||||
|
// to be resized so small that it ended up outside the viewport. It can also happen
|
||||||
|
// if the syncView loaded and unloaded rows after the relayout. We therefore need
|
||||||
|
// to sync our own top row and pos to be the same, which we do by rebuilding the
|
||||||
|
// whole viewport instead of just doing a plain LayoutOnly.
|
||||||
|
scheduledRebuildOptions |= QQuickTableViewPrivate::RebuildOption::CalculateNewTopLeftRow;
|
||||||
|
scheduledRebuildOptions.setFlag(RebuildOption::ViewportOnly);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2462,8 +2462,10 @@ void QQuickText::geometryChange(const QRectF &newGeometry, const QRectF &oldGeom
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (!heightChanged && widthMaximum) {
|
} else if (!heightChanged && widthMaximum) {
|
||||||
if (!qFuzzyIsNull(oldGeometry.width())) {
|
if (oldGeometry.width() > 0) {
|
||||||
// no change to height, width is adequate and wasn't 0 before
|
// no change to height, width is adequate and wasn't 0 before
|
||||||
|
// (old width could also be negative if it was 0 and the margins
|
||||||
|
// were set)
|
||||||
goto geomChangeDone;
|
goto geomChangeDone;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -190,7 +190,12 @@ void QSGDistanceFieldGlyphCache::update()
|
||||||
distanceFields.reserve(pendingGlyphsSize);
|
distanceFields.reserve(pendingGlyphsSize);
|
||||||
for (int i = 0; i < pendingGlyphsSize; ++i) {
|
for (int i = 0; i < pendingGlyphsSize; ++i) {
|
||||||
GlyphData &gd = glyphData(m_pendingGlyphs.at(i));
|
GlyphData &gd = glyphData(m_pendingGlyphs.at(i));
|
||||||
distanceFields.append(QDistanceField(gd.path,
|
|
||||||
|
QSize size = QSize(qCeil(gd.texCoord.width + gd.texCoord.xMargin * 2),
|
||||||
|
qCeil(gd.texCoord.height + gd.texCoord.yMargin * 2));
|
||||||
|
|
||||||
|
distanceFields.append(QDistanceField(size,
|
||||||
|
gd.path,
|
||||||
m_pendingGlyphs.at(i),
|
m_pendingGlyphs.at(i),
|
||||||
m_doubleGlyphResolution));
|
m_doubleGlyphResolution));
|
||||||
gd.path = QPainterPath(); // no longer needed, so release memory used by the painter path
|
gd.path = QPainterPath(); // no longer needed, so release memory used by the painter path
|
||||||
|
|
|
@ -83,11 +83,14 @@ void QSGDefaultGlyphNode::update()
|
||||||
QRawFont font = m_glyphs.rawFont();
|
QRawFont font = m_glyphs.rawFont();
|
||||||
QMargins margins(0, 0, 0, 0);
|
QMargins margins(0, 0, 0, 0);
|
||||||
|
|
||||||
if (m_style == QQuickText::Normal) {
|
const auto *fontEngine = QRawFontPrivate::get(font)->fontEngine;
|
||||||
|
const bool isColorFont = fontEngine->glyphFormat == QFontEngine::Format_ARGB;
|
||||||
|
|
||||||
|
if (m_style == QQuickText::Normal || isColorFont) {
|
||||||
QFontEngine::GlyphFormat glyphFormat;
|
QFontEngine::GlyphFormat glyphFormat;
|
||||||
|
|
||||||
// Don't try to override glyph format of color fonts
|
// Don't try to override glyph format of color fonts
|
||||||
if (QRawFontPrivate::get(font)->fontEngine->glyphFormat == QFontEngine::Format_ARGB) {
|
if (isColorFont) {
|
||||||
glyphFormat = QFontEngine::Format_None;
|
glyphFormat = QFontEngine::Format_None;
|
||||||
} else {
|
} else {
|
||||||
switch (m_preferredAntialiasingMode) {
|
switch (m_preferredAntialiasingMode) {
|
||||||
|
|
|
@ -310,6 +310,11 @@ void QQuickAbstractAnimation::setRunning(bool r)
|
||||||
// Therefore, the state of d->running will in that case be different than r if we are back in
|
// Therefore, the state of d->running will in that case be different than r if we are back in
|
||||||
// the root stack frame of the recursive calls to setRunning()
|
// the root stack frame of the recursive calls to setRunning()
|
||||||
emit runningChanged(d->running);
|
emit runningChanged(d->running);
|
||||||
|
} else if (d->animationInstance) {
|
||||||
|
// If there was a recursive call, make sure the d->running is set correctly
|
||||||
|
d->running = d->animationInstance->isRunning();
|
||||||
|
} else {
|
||||||
|
d->running = r;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -482,7 +482,7 @@ void QQuickGridLayoutBase::itemVisibilityChanged(QQuickItem *item)
|
||||||
void QQuickGridLayoutBase::rearrange(const QSizeF &size)
|
void QQuickGridLayoutBase::rearrange(const QSizeF &size)
|
||||||
{
|
{
|
||||||
Q_D(QQuickGridLayoutBase);
|
Q_D(QQuickGridLayoutBase);
|
||||||
if (!isReady())
|
if (!isReady() || !size.isValid())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
qCDebug(lcQuickLayouts) << "QQuickGridLayoutBase::rearrange" << d->m_recurRearrangeCounter << this;
|
qCDebug(lcQuickLayouts) << "QQuickGridLayoutBase::rearrange" << d->m_recurRearrangeCounter << this;
|
||||||
|
|
|
@ -385,12 +385,22 @@ void QQuickControlPrivate::resizeBackground()
|
||||||
bool changeHeight = false;
|
bool changeHeight = false;
|
||||||
if (((!p->widthValid() || !extra.isAllocated() || !extra->hasBackgroundWidth) && qFuzzyIsNull(background->x()))
|
if (((!p->widthValid() || !extra.isAllocated() || !extra->hasBackgroundWidth) && qFuzzyIsNull(background->x()))
|
||||||
|| (extra.isAllocated() && (extra->hasLeftInset || extra->hasRightInset))) {
|
|| (extra.isAllocated() && (extra->hasLeftInset || extra->hasRightInset))) {
|
||||||
background->setX(getLeftInset());
|
const auto leftInset = getLeftInset();
|
||||||
|
if (!qt_is_nan(leftInset) && p->x.valueBypassingBindings() != leftInset) {
|
||||||
|
// We bypass the binding here to prevent it from being removed
|
||||||
|
p->x.setValueBypassingBindings(leftInset);
|
||||||
|
p->dirty(DirtyType::Position);
|
||||||
|
}
|
||||||
changeWidth = !p->width.hasBinding();
|
changeWidth = !p->width.hasBinding();
|
||||||
}
|
}
|
||||||
if (((!p->heightValid() || !extra.isAllocated() || !extra->hasBackgroundHeight) && qFuzzyIsNull(background->y()))
|
if (((!p->heightValid() || !extra.isAllocated() || !extra->hasBackgroundHeight) && qFuzzyIsNull(background->y()))
|
||||||
|| (extra.isAllocated() && (extra->hasTopInset || extra->hasBottomInset))) {
|
|| (extra.isAllocated() && (extra->hasTopInset || extra->hasBottomInset))) {
|
||||||
background->setY(getTopInset());
|
const auto topInset = getTopInset();
|
||||||
|
if (!qt_is_nan(topInset) && p->y.valueBypassingBindings() != topInset) {
|
||||||
|
// We bypass the binding here to prevent it from being removed
|
||||||
|
p->y.setValueBypassingBindings(topInset);
|
||||||
|
p->dirty(DirtyType::Position);
|
||||||
|
}
|
||||||
changeHeight = !p->height.hasBinding();
|
changeHeight = !p->height.hasBinding();
|
||||||
}
|
}
|
||||||
if (changeHeight || changeWidth) {
|
if (changeHeight || changeWidth) {
|
||||||
|
|
|
@ -498,6 +498,13 @@ bool QQuickOverlay::childMouseEventFilter(QQuickItem *item, QEvent *event)
|
||||||
case QEvent::HoverEnter:
|
case QEvent::HoverEnter:
|
||||||
case QEvent::HoverMove:
|
case QEvent::HoverMove:
|
||||||
case QEvent::HoverLeave:
|
case QEvent::HoverLeave:
|
||||||
|
// If the control item has already been hovered, allow the hover leave event
|
||||||
|
// to be processed by the same item for resetting its internal hovered state
|
||||||
|
// instead of filtering it here.
|
||||||
|
if (auto *control = qobject_cast<QQuickControl *>(item)) {
|
||||||
|
if (control->isHovered() && event->type() == QEvent::HoverLeave)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
handled = d->handleHoverEvent(item, static_cast<QHoverEvent *>(event), popup);
|
handled = d->handleHoverEvent(item, static_cast<QHoverEvent *>(event), popup);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
|
@ -664,7 +664,24 @@ QQuickWidget::QQuickWidget(QWidget *parent)
|
||||||
{
|
{
|
||||||
setMouseTracking(true);
|
setMouseTracking(true);
|
||||||
setFocusPolicy(Qt::StrongFocus);
|
setFocusPolicy(Qt::StrongFocus);
|
||||||
|
#ifndef Q_OS_MACOS
|
||||||
|
/*
|
||||||
|
Usually, a QTouchEvent comes from a touchscreen, and we want those
|
||||||
|
touch events in Qt Quick. But on macOS, there are no touchscreens, and
|
||||||
|
WA_AcceptTouchEvents has a different meaning: QApplication::notify()
|
||||||
|
calls the native-integration function registertouchwindow() to change
|
||||||
|
NSView::allowedTouchTypes to include NSTouchTypeMaskIndirect when the
|
||||||
|
trackpad cursor enters the window, and removes that mask when the
|
||||||
|
cursor exits. In other words, WA_AcceptTouchEvents enables getting
|
||||||
|
discrete touchpoints from the trackpad. We rather prefer to get mouse,
|
||||||
|
wheel and native gesture events from the trackpad (because those
|
||||||
|
provide more of a "native feel"). The only exception is for
|
||||||
|
MultiPointTouchArea, and it takes care of that for itself. So don't
|
||||||
|
automatically set WA_AcceptTouchEvents on macOS. The user can still do
|
||||||
|
it, but we don't recommend it.
|
||||||
|
*/
|
||||||
setAttribute(Qt::WA_AcceptTouchEvents);
|
setAttribute(Qt::WA_AcceptTouchEvents);
|
||||||
|
#endif
|
||||||
d_func()->init();
|
d_func()->init();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -120,6 +120,7 @@ if(QT_FEATURE_private_tests)
|
||||||
add_subdirectory(qqmltablemodel)
|
add_subdirectory(qqmltablemodel)
|
||||||
add_subdirectory(qv4assembler)
|
add_subdirectory(qv4assembler)
|
||||||
add_subdirectory(qv4mm)
|
add_subdirectory(qv4mm)
|
||||||
|
add_subdirectory(qv4estable)
|
||||||
add_subdirectory(qv4identifiertable)
|
add_subdirectory(qv4identifiertable)
|
||||||
add_subdirectory(qv4regexp)
|
add_subdirectory(qv4regexp)
|
||||||
if(QT_FEATURE_process AND NOT QNX)
|
if(QT_FEATURE_process AND NOT QNX)
|
||||||
|
|
|
@ -293,6 +293,7 @@ private slots:
|
||||||
void spreadNoOverflow();
|
void spreadNoOverflow();
|
||||||
|
|
||||||
void deleteDefineCycle();
|
void deleteDefineCycle();
|
||||||
|
void deleteFromSparseArray();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Q_INVOKABLE QJSValue throwingCppMethod1();
|
Q_INVOKABLE QJSValue throwingCppMethod1();
|
||||||
|
@ -5837,6 +5838,26 @@ void tst_QJSEngine::deleteDefineCycle()
|
||||||
QVERIFY(stackTrace.isEmpty());
|
QVERIFY(stackTrace.isEmpty());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void tst_QJSEngine::deleteFromSparseArray()
|
||||||
|
{
|
||||||
|
QJSEngine engine;
|
||||||
|
|
||||||
|
// Should not crash
|
||||||
|
const QJSValue result = engine.evaluate(QLatin1String(R"((function() {
|
||||||
|
let o = [];
|
||||||
|
o[10000] = 10;
|
||||||
|
o[20000] = 20;
|
||||||
|
for (let k in o)
|
||||||
|
delete o[k];
|
||||||
|
return o;
|
||||||
|
})())"));
|
||||||
|
|
||||||
|
QVERIFY(result.isArray());
|
||||||
|
QCOMPARE(result.property("length").toNumber(), 20001);
|
||||||
|
QVERIFY(result.property(10000).isUndefined());
|
||||||
|
QVERIFY(result.property(20000).isUndefined());
|
||||||
|
}
|
||||||
|
|
||||||
QTEST_MAIN(tst_QJSEngine)
|
QTEST_MAIN(tst_QJSEngine)
|
||||||
|
|
||||||
#include "tst_qjsengine.moc"
|
#include "tst_qjsengine.moc"
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
import QtQml 2.15
|
||||||
|
|
||||||
|
SimpleWidget {
|
||||||
|
width: 20
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
import QtQuick 2.15
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: outer
|
||||||
|
|
||||||
|
property real innerWidth: 0
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: inner
|
||||||
|
width: style.width
|
||||||
|
onWidthChanged: outer.innerWidth = width
|
||||||
|
}
|
||||||
|
|
||||||
|
width: inner.width
|
||||||
|
|
||||||
|
onWidthChanged: {
|
||||||
|
if (width !== inner.width)
|
||||||
|
inner.width = width // overwrite binding
|
||||||
|
}
|
||||||
|
|
||||||
|
QtObject {
|
||||||
|
id: style
|
||||||
|
property int width: 50
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,26 @@
|
||||||
|
|
||||||
|
import QtQml
|
||||||
|
|
||||||
|
QtObject {
|
||||||
|
id: self
|
||||||
|
|
||||||
|
function doStuff(status: Binding.NotAnInlineComponent) : int {
|
||||||
|
return status
|
||||||
|
}
|
||||||
|
|
||||||
|
function doStuff2(status: InlineComponentBase.IC) : QtObject {
|
||||||
|
return status
|
||||||
|
}
|
||||||
|
|
||||||
|
function doStuff3(status: InlineComponentBase.NotIC) : QtObject {
|
||||||
|
return status
|
||||||
|
}
|
||||||
|
|
||||||
|
property InlineComponentBase.IC ic: InlineComponentBase.IC {}
|
||||||
|
|
||||||
|
property int a: doStuff(5)
|
||||||
|
property QtObject b: doStuff2(ic)
|
||||||
|
property QtObject c: doStuff3(ic)
|
||||||
|
property QtObject d: doStuff2(self)
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
import QtQml
|
||||||
|
|
||||||
|
QtObject {
|
||||||
|
property var b;
|
||||||
|
property Component c: QtObject {}
|
||||||
|
|
||||||
|
// In 6.5 and earlier we don't have heap-managed QQmlListProperty, yet.
|
||||||
|
property list<Component> ll;
|
||||||
|
|
||||||
|
function returnList(a: Component) : list<Component> { ll.push(a); return ll; }
|
||||||
|
|
||||||
|
Component.onCompleted: b = { b: returnList(c) }
|
||||||
|
}
|
|
@ -394,6 +394,11 @@ private slots:
|
||||||
void deepAliasOnICOrReadonly();
|
void deepAliasOnICOrReadonly();
|
||||||
|
|
||||||
void writeNumberToEnumAlias();
|
void writeNumberToEnumAlias();
|
||||||
|
void badInlineComponentAnnotation();
|
||||||
|
|
||||||
|
void typedObjectList();
|
||||||
|
|
||||||
|
void overrideInnerBinding();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QQmlEngine engine;
|
QQmlEngine engine;
|
||||||
|
@ -6747,6 +6752,52 @@ void tst_qqmllanguage::writeNumberToEnumAlias()
|
||||||
QCOMPARE(o->property("strokeStyle").toInt(), 1);
|
QCOMPARE(o->property("strokeStyle").toInt(), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void tst_qqmllanguage::badInlineComponentAnnotation()
|
||||||
|
{
|
||||||
|
QQmlEngine engine;
|
||||||
|
const QUrl url = testFileUrl("badICAnnotation.qml");
|
||||||
|
QQmlComponent c(&engine, testFileUrl("badICAnnotation.qml"));
|
||||||
|
QVERIFY2(c.isReady(), qPrintable(c.errorString()));
|
||||||
|
|
||||||
|
QScopedPointer<QObject> o(c.create());
|
||||||
|
QVERIFY(!o.isNull());
|
||||||
|
|
||||||
|
QCOMPARE(o->property("a").toInt(), 5);
|
||||||
|
|
||||||
|
QObject *ic = o->property("ic").value<QObject *>();
|
||||||
|
QVERIFY(ic);
|
||||||
|
|
||||||
|
QCOMPARE(o->property("b").value<QObject *>(), ic);
|
||||||
|
QCOMPARE(o->property("c").value<QObject *>(), ic);
|
||||||
|
}
|
||||||
|
|
||||||
|
void tst_qqmllanguage::typedObjectList()
|
||||||
|
{
|
||||||
|
QQmlEngine e;
|
||||||
|
QQmlComponent c(&e, testFileUrl("typedObjectList.qml"));
|
||||||
|
QVERIFY2(c.isReady(), qPrintable(c.errorString()));
|
||||||
|
QScopedPointer<QObject> o(c.create());
|
||||||
|
QVERIFY(!o.isNull());
|
||||||
|
|
||||||
|
QJSValue b = o->property("b").value<QJSValue>();
|
||||||
|
auto list = qjsvalue_cast<QQmlListProperty<QQmlComponent>>(b.property(QStringLiteral("b")));
|
||||||
|
|
||||||
|
QCOMPARE(list.count(&list), 1);
|
||||||
|
QVERIFY(list.at(&list, 0) != nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void tst_qqmllanguage::overrideInnerBinding()
|
||||||
|
{
|
||||||
|
QQmlEngine e;
|
||||||
|
QQmlComponent c(&e, testFileUrl("BindingOverrider.qml"));
|
||||||
|
QVERIFY2(c.isReady(), qPrintable(c.errorString()));
|
||||||
|
QScopedPointer<QObject> o(c.create());
|
||||||
|
QVERIFY(!o.isNull());
|
||||||
|
|
||||||
|
QCOMPARE(o->property("width").toReal(), 20.0);
|
||||||
|
QCOMPARE(o->property("innerWidth").toReal(), 20.0);
|
||||||
|
}
|
||||||
|
|
||||||
QTEST_MAIN(tst_qqmllanguage)
|
QTEST_MAIN(tst_qqmllanguage)
|
||||||
|
|
||||||
#include "tst_qqmllanguage.moc"
|
#include "tst_qqmllanguage.moc"
|
||||||
|
|
|
@ -0,0 +1,45 @@
|
||||||
|
import QtQml
|
||||||
|
|
||||||
|
QtObject {
|
||||||
|
function swapCorpses() {
|
||||||
|
const lhsData = getModelData(lhsButtonListModel);
|
||||||
|
const rhsData = getModelData(rhsButtonListModel);
|
||||||
|
|
||||||
|
lhsButtonListModel.clear();
|
||||||
|
rhsButtonListModel.clear();
|
||||||
|
|
||||||
|
addToModel(lhsButtonListModel, rhsData);
|
||||||
|
addToModel(rhsButtonListModel, lhsData);
|
||||||
|
}
|
||||||
|
|
||||||
|
property ListModel l1: ListModel {
|
||||||
|
id: lhsButtonListModel
|
||||||
|
}
|
||||||
|
|
||||||
|
property ListModel l2: ListModel {
|
||||||
|
id: rhsButtonListModel
|
||||||
|
}
|
||||||
|
|
||||||
|
Component.onCompleted: {
|
||||||
|
lhsButtonListModel.append({ "ident": 1, "buttonText": "B 1"});
|
||||||
|
lhsButtonListModel.append({ "ident": 2, "buttonText": "B 2"});
|
||||||
|
lhsButtonListModel.append({ "ident": 3, "buttonText": "B 3"});
|
||||||
|
|
||||||
|
rhsButtonListModel.append({ "ident": 4, "buttonText": "B 4"});
|
||||||
|
rhsButtonListModel.append({ "ident": 5, "buttonText": "B 5"});
|
||||||
|
rhsButtonListModel.append({ "ident": 6, "buttonText": "B 6"});
|
||||||
|
}
|
||||||
|
|
||||||
|
function getModelData(model) {
|
||||||
|
var dataList = []
|
||||||
|
for (var i = 0; i < model.count; ++i)
|
||||||
|
dataList.push(model.get(i));
|
||||||
|
|
||||||
|
return dataList;
|
||||||
|
}
|
||||||
|
|
||||||
|
function addToModel(model, buttonData) {
|
||||||
|
for (var i = 0; i < buttonData.length; ++i)
|
||||||
|
model.append(buttonData[i]);
|
||||||
|
}
|
||||||
|
}
|
|
@ -140,6 +140,7 @@ private slots:
|
||||||
void destroyComponentObject();
|
void destroyComponentObject();
|
||||||
void objectOwnershipFlip();
|
void objectOwnershipFlip();
|
||||||
void protectQObjectFromGC();
|
void protectQObjectFromGC();
|
||||||
|
void deadModelData();
|
||||||
};
|
};
|
||||||
|
|
||||||
bool tst_qqmllistmodel::compareVariantList(const QVariantList &testList, QVariant object)
|
bool tst_qqmllistmodel::compareVariantList(const QVariantList &testList, QVariant object)
|
||||||
|
@ -1940,6 +1941,67 @@ void tst_qqmllistmodel::protectQObjectFromGC()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void tst_qqmllistmodel::deadModelData()
|
||||||
|
{
|
||||||
|
QQmlEngine engine;
|
||||||
|
QQmlComponent component(&engine, testFileUrl("deadModelData.qml"));
|
||||||
|
QVERIFY2(component.isReady(), qPrintable(component.errorString()));
|
||||||
|
QScopedPointer<QObject> o(component.create());
|
||||||
|
QVERIFY(!o.isNull());
|
||||||
|
|
||||||
|
QQmlListModel *l1 = o->property("l1").value<QQmlListModel *>();
|
||||||
|
QVERIFY(l1);
|
||||||
|
QQmlListModel *l2 = o->property("l2").value<QQmlListModel *>();
|
||||||
|
QVERIFY(l2);
|
||||||
|
|
||||||
|
QCOMPARE(l1->count(), 3);
|
||||||
|
QCOMPARE(l2->count(), 3);
|
||||||
|
|
||||||
|
for (int i = 0; i < 3; ++i) {
|
||||||
|
QObject *i1 = qjsvalue_cast<QObject *>(l1->get(i));
|
||||||
|
QVERIFY(i1);
|
||||||
|
QCOMPARE(i1->property("ident").value<double>(), i + 1);
|
||||||
|
QCOMPARE(i1->property("buttonText").value<QString>(),
|
||||||
|
QLatin1String("B %1").arg(QLatin1Char('0' + i + 1)));
|
||||||
|
|
||||||
|
QObject *i2 = qjsvalue_cast<QObject *>(l2->get(i));
|
||||||
|
QVERIFY(i2);
|
||||||
|
QCOMPARE(i2->property("ident").value<double>(), i + 4);
|
||||||
|
QCOMPARE(i2->property("buttonText").value<QString>(),
|
||||||
|
QLatin1String("B %1").arg(QLatin1Char('0' + i + 4)));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < 6; ++i) {
|
||||||
|
QTest::ignoreMessage(
|
||||||
|
QtWarningMsg,
|
||||||
|
QRegularExpression(".*: ident is undefined. Adding an object with a undefined "
|
||||||
|
"member does not create a role for it."));
|
||||||
|
QTest::ignoreMessage(
|
||||||
|
QtWarningMsg,
|
||||||
|
QRegularExpression(".*: buttonText is undefined. Adding an object with a undefined "
|
||||||
|
"member does not create a role for it."));
|
||||||
|
}
|
||||||
|
|
||||||
|
QMetaObject::invokeMethod(o.data(), "swapCorpses");
|
||||||
|
|
||||||
|
// We get default-created values for all the roles now.
|
||||||
|
|
||||||
|
QCOMPARE(l1->count(), 3);
|
||||||
|
QCOMPARE(l2->count(), 3);
|
||||||
|
|
||||||
|
for (int i = 0; i < 3; ++i) {
|
||||||
|
QObject *i1 = qjsvalue_cast<QObject *>(l1->get(i));
|
||||||
|
QVERIFY(i1);
|
||||||
|
QCOMPARE(i1->property("ident").value<double>(), double());
|
||||||
|
QCOMPARE(i1->property("buttonText").value<QString>(), QString());
|
||||||
|
|
||||||
|
QObject *i2 = qjsvalue_cast<QObject *>(l2->get(i));
|
||||||
|
QVERIFY(i2);
|
||||||
|
QCOMPARE(i2->property("ident").value<double>(), double());
|
||||||
|
QCOMPARE(i2->property("buttonText").value<QString>(), QString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
QTEST_MAIN(tst_qqmllistmodel)
|
QTEST_MAIN(tst_qqmllistmodel)
|
||||||
|
|
||||||
#include "tst_qqmllistmodel.moc"
|
#include "tst_qqmllistmodel.moc"
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
# Copyright (C) 2024 The Qt Company Ltd.
|
||||||
|
# SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
|
||||||
|
#####################################################################
|
||||||
|
## tst_qv4estable Test:
|
||||||
|
#####################################################################
|
||||||
|
|
||||||
|
if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
|
||||||
|
cmake_minimum_required(VERSION 3.16)
|
||||||
|
project(tst_qv4estable LANGUAGES CXX)
|
||||||
|
find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
qt_internal_add_test(tst_qv4estable
|
||||||
|
SOURCES
|
||||||
|
tst_qv4estable.cpp
|
||||||
|
LIBRARIES
|
||||||
|
Qt::Gui
|
||||||
|
Qt::Qml
|
||||||
|
Qt::QmlPrivate
|
||||||
|
)
|
||||||
|
|
||||||
|
## Scopes:
|
||||||
|
#####################################################################
|
|
@ -0,0 +1,40 @@
|
||||||
|
// Copyright (C) 2024 The Qt Company Ltd.
|
||||||
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
|
||||||
|
|
||||||
|
#include <qtest.h>
|
||||||
|
#include <private/qv4estable_p.h>
|
||||||
|
|
||||||
|
class tst_qv4estable : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void checkRemoveAvoidsHeapBufferOverflow();
|
||||||
|
};
|
||||||
|
|
||||||
|
// QTBUG-123999
|
||||||
|
void tst_qv4estable::checkRemoveAvoidsHeapBufferOverflow()
|
||||||
|
{
|
||||||
|
QV4::ESTable estable;
|
||||||
|
|
||||||
|
// Fill the ESTable with values so it is at max capacity.
|
||||||
|
QCOMPARE(estable.m_capacity, 8u);
|
||||||
|
for (uint i = 0; i < estable.m_capacity; ++i) {
|
||||||
|
estable.set(QV4::Value::fromUInt32(i), QV4::Value::fromUInt32(i));
|
||||||
|
}
|
||||||
|
// Our |m_keys| array should now contain eight values.
|
||||||
|
// > [v0, v1, v2, v3, v4, v5, v6, v7]
|
||||||
|
for (uint i = 0; i < estable.m_capacity; ++i) {
|
||||||
|
QVERIFY(estable.m_keys[i].sameValueZero(QV4::Value::fromUInt32(i)));
|
||||||
|
}
|
||||||
|
QCOMPARE(estable.m_capacity, 8u);
|
||||||
|
QCOMPARE(estable.m_size, 8u);
|
||||||
|
|
||||||
|
// Remove the first item from the set to verify that asan does not trip.
|
||||||
|
// Relies on the CI platform propagating asan flag to all tests.
|
||||||
|
estable.remove(QV4::Value::fromUInt32(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
QTEST_MAIN(tst_qv4estable)
|
||||||
|
|
||||||
|
#include "tst_qv4estable.moc"
|
|
@ -119,6 +119,7 @@ private slots:
|
||||||
void cleanupWhenRenderThreadStops();
|
void cleanupWhenRenderThreadStops();
|
||||||
void infiniteLoopsWithoutFrom();
|
void infiniteLoopsWithoutFrom();
|
||||||
void targetsDeletedNotRemoved();
|
void targetsDeletedNotRemoved();
|
||||||
|
void alwaysRunToEndSetFalseRestartBug();
|
||||||
};
|
};
|
||||||
#define QTIMED_COMPARE(lhs, rhs) do { \
|
#define QTIMED_COMPARE(lhs, rhs) do { \
|
||||||
for (int ii = 0; ii < 5; ++ii) { \
|
for (int ii = 0; ii < 5; ++ii) { \
|
||||||
|
@ -2081,6 +2082,41 @@ void tst_qquickanimations::targetsDeletedNotRemoved()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//QTBUG-125224
|
||||||
|
void tst_qquickanimations::alwaysRunToEndSetFalseRestartBug()
|
||||||
|
{
|
||||||
|
QQuickRectangle rect;
|
||||||
|
QQuickSequentialAnimation sequential;
|
||||||
|
QQuickPropertyAnimation beginAnim;
|
||||||
|
QQuickPropertyAnimation endAnim;
|
||||||
|
|
||||||
|
beginAnim.setTargetObject(&rect);
|
||||||
|
beginAnim.setProperty("x");
|
||||||
|
beginAnim.setTo(200);
|
||||||
|
beginAnim.setDuration(1000);
|
||||||
|
|
||||||
|
endAnim.setTargetObject(&rect);
|
||||||
|
endAnim.setProperty("x");
|
||||||
|
endAnim.setFrom(200);
|
||||||
|
endAnim.setDuration(1000);
|
||||||
|
|
||||||
|
beginAnim.setGroup(&sequential);
|
||||||
|
endAnim.setGroup(&sequential);
|
||||||
|
|
||||||
|
sequential.setLoops(-1);
|
||||||
|
sequential.setAlwaysRunToEnd(true);
|
||||||
|
|
||||||
|
QCOMPARE(sequential.loops(), -1);
|
||||||
|
QVERIFY(sequential.alwaysRunToEnd());
|
||||||
|
sequential.start();
|
||||||
|
sequential.stop();
|
||||||
|
sequential.setAlwaysRunToEnd(false);
|
||||||
|
sequential.start();
|
||||||
|
QCOMPARE(sequential.isRunning(), true);
|
||||||
|
sequential.stop();
|
||||||
|
QCOMPARE(sequential.isRunning(), false);
|
||||||
|
}
|
||||||
|
|
||||||
QTEST_MAIN(tst_qquickanimations)
|
QTEST_MAIN(tst_qquickanimations)
|
||||||
|
|
||||||
#include "tst_qquickanimations.moc"
|
#include "tst_qquickanimations.moc"
|
||||||
|
|
|
@ -1308,6 +1308,53 @@ Item {
|
||||||
compare(rootRect.item1.width, 100)
|
compare(rootRect.item1.width, 100)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//---------------------------
|
||||||
|
// Layout with negative size
|
||||||
|
Component {
|
||||||
|
id: negativeSize_Component
|
||||||
|
Item {
|
||||||
|
id: rootItem
|
||||||
|
width: 0
|
||||||
|
height: 0
|
||||||
|
// default width x height: (0 x 0)
|
||||||
|
RowLayout {
|
||||||
|
spacing: 0
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.leftMargin: 1 // since parent size == (0 x 0), it causes layout size
|
||||||
|
anchors.bottomMargin: 1 // to become (-1, -1)
|
||||||
|
Item {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.fillHeight: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function test_negativeSize() {
|
||||||
|
let rootItem = createTemporaryObject(negativeSize_Component, container)
|
||||||
|
let rowLayout = rootItem.children[0]
|
||||||
|
let item = rowLayout.children[0]
|
||||||
|
|
||||||
|
// 1 doesn't work in 6.2 because that will make the layout of size 0x0
|
||||||
|
// Setting the geometry of a layout to 0x0 doesn't work because
|
||||||
|
// QQuickLayout::geometryChange() early returns if !newGeometry.isValid()
|
||||||
|
// This check has been later removed.
|
||||||
|
const arr = [7, /*1,*/ 7, 0]
|
||||||
|
arr.forEach((n) => {
|
||||||
|
rootItem.width = n
|
||||||
|
rootItem.height = n
|
||||||
|
|
||||||
|
// n === 0 is special: It will cause the layout to have a
|
||||||
|
// negative size. In this case it will simply not rearrange its
|
||||||
|
// child (and leave it at its previous size, 6)
|
||||||
|
const expectedItemExtent = n === 0 ? 6 : n - 1
|
||||||
|
|
||||||
|
compare(item.width, expectedItemExtent)
|
||||||
|
compare(item.height, expectedItemExtent)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//---------------------------
|
//---------------------------
|
||||||
Component {
|
Component {
|
||||||
id: rowlayoutWithTextItems_Component
|
id: rowlayoutWithTextItems_Component
|
||||||
|
|
|
@ -0,0 +1,52 @@
|
||||||
|
import QtQuick
|
||||||
|
|
||||||
|
ListView {
|
||||||
|
id: listView
|
||||||
|
width: 240
|
||||||
|
height: 300
|
||||||
|
|
||||||
|
model: ListModel {
|
||||||
|
ListElement { section: "section 1" }
|
||||||
|
ListElement { section: "section 1" }
|
||||||
|
ListElement { section: "section 1" }
|
||||||
|
ListElement { section: "section 2" }
|
||||||
|
ListElement { section: "section 2" }
|
||||||
|
ListElement { section: "section 2" }
|
||||||
|
ListElement { section: "section 3" }
|
||||||
|
ListElement { section: "section 3" }
|
||||||
|
ListElement { section: "section 3" }
|
||||||
|
ListElement { section: "section 4" }
|
||||||
|
ListElement { section: "section 4" }
|
||||||
|
ListElement { section: "section 4" }
|
||||||
|
ListElement { section: "section 5" }
|
||||||
|
ListElement { section: "section 5" }
|
||||||
|
ListElement { section: "section 5" }
|
||||||
|
}
|
||||||
|
|
||||||
|
section.property: "section"
|
||||||
|
section.labelPositioning: ViewSection.InlineLabels | ViewSection.CurrentLabelAtStart
|
||||||
|
section.delegate: Rectangle {
|
||||||
|
width: listView.width
|
||||||
|
height: 30
|
||||||
|
Text {
|
||||||
|
anchors.fill: parent
|
||||||
|
text: section
|
||||||
|
}
|
||||||
|
color: "lightblue"
|
||||||
|
}
|
||||||
|
|
||||||
|
snapMode: ListView.SnapToItem
|
||||||
|
|
||||||
|
delegate: Rectangle {
|
||||||
|
width: listView.width
|
||||||
|
height: 30
|
||||||
|
Text {
|
||||||
|
anchors.fill: parent
|
||||||
|
text: index
|
||||||
|
}
|
||||||
|
border {
|
||||||
|
width: 1
|
||||||
|
color: "black"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -193,6 +193,7 @@ private slots:
|
||||||
void headerSnapToItem_data();
|
void headerSnapToItem_data();
|
||||||
void headerSnapToItem();
|
void headerSnapToItem();
|
||||||
void snapToItemWithSpacing_QTBUG_59852();
|
void snapToItemWithSpacing_QTBUG_59852();
|
||||||
|
void snapToItemWithSectionAtStart();
|
||||||
void snapOneItemResize_QTBUG_43555();
|
void snapOneItemResize_QTBUG_43555();
|
||||||
void snapOneItem_data();
|
void snapOneItem_data();
|
||||||
void snapOneItem();
|
void snapOneItem();
|
||||||
|
@ -5407,6 +5408,27 @@ void tst_QQuickListView::snapToItemWithSpacing_QTBUG_59852()
|
||||||
releaseView(window);
|
releaseView(window);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void tst_QQuickListView::snapToItemWithSectionAtStart() // QTBUG-30768
|
||||||
|
{
|
||||||
|
QQuickView window;
|
||||||
|
QVERIFY(QQuickTest::showView(window, testFileUrl("snapToItemWithSectionAtStart.qml")));
|
||||||
|
QQuickListView *listView = qobject_cast<QQuickListView *>(window.rootObject());
|
||||||
|
QTRY_VERIFY(listView);
|
||||||
|
|
||||||
|
// Both sections and elements are 30px high. The list height is 300px, so
|
||||||
|
// it fits exactly 10 elements. We can do some random flicks, but the
|
||||||
|
// content position always MUST be divisible by 30.
|
||||||
|
for (int i = 0; i < 10; ++i) {
|
||||||
|
const bool even = (i % 2 == 0);
|
||||||
|
const QPoint start = even ? QPoint(20, 100 + i * 5) : QPoint(20, 20 + i * 3);
|
||||||
|
const QPoint end = even ? start - QPoint(0, 50 + i * 10) : start + QPoint(0, 50 + i * 5);
|
||||||
|
|
||||||
|
flick(&window, start, end, 180);
|
||||||
|
QTRY_COMPARE(listView->isMoving(), false); // wait until it stops
|
||||||
|
QCOMPARE(int(listView->contentY()) % 30, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void drag_helper(QWindow *window, QPoint *startPos, const QPoint &delta)
|
static void drag_helper(QWindow *window, QPoint *startPos, const QPoint &delta)
|
||||||
{
|
{
|
||||||
QPoint pos = *startPos;
|
QPoint pos = *startPos;
|
||||||
|
|
|
@ -4,3 +4,5 @@ ubuntu-22.04
|
||||||
[nested]
|
[nested]
|
||||||
ubuntu-20.04
|
ubuntu-20.04
|
||||||
ubuntu-22.04
|
ubuntu-22.04
|
||||||
|
[inFlickable]
|
||||||
|
* # QTBUG-127628
|
||||||
|
|
|
@ -185,6 +185,8 @@ private slots:
|
||||||
void checkSyncView_pageFlicking();
|
void checkSyncView_pageFlicking();
|
||||||
void checkSyncView_emptyModel();
|
void checkSyncView_emptyModel();
|
||||||
void checkSyncView_topLeftChanged();
|
void checkSyncView_topLeftChanged();
|
||||||
|
void checkSyncView_dontRelayoutWhileFlicking();
|
||||||
|
void checkSyncView_detectTopLeftPositionChanged();
|
||||||
void delegateWithRequiredProperties();
|
void delegateWithRequiredProperties();
|
||||||
void checkThatFetchMoreIsCalledWhenScrolledToTheEndOfTable();
|
void checkThatFetchMoreIsCalledWhenScrolledToTheEndOfTable();
|
||||||
void replaceModel();
|
void replaceModel();
|
||||||
|
@ -3108,6 +3110,85 @@ void tst_QQuickTableView::checkSyncView_topLeftChanged()
|
||||||
QCOMPARE(tableViewV->topRow(), tableView->topRow());
|
QCOMPARE(tableViewV->topRow(), tableView->topRow());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void tst_QQuickTableView::checkSyncView_dontRelayoutWhileFlicking()
|
||||||
|
{
|
||||||
|
// Check that we don't do a full relayout in a sync child when
|
||||||
|
// a new row or column is flicked into the view. Normal load
|
||||||
|
// and unload of edges should suffice, equal to how the main
|
||||||
|
// TableView (syncView) does it.
|
||||||
|
LOAD_TABLEVIEW("syncviewsimple.qml");
|
||||||
|
GET_QML_TABLEVIEW(tableViewHV);
|
||||||
|
|
||||||
|
auto model = TestModelAsVariant(100, 100);
|
||||||
|
tableView->setModel(model);
|
||||||
|
tableViewHV->setModel(model);
|
||||||
|
|
||||||
|
tableView->setColumnWidthProvider(QJSValue());
|
||||||
|
tableView->setRowHeightProvider(QJSValue());
|
||||||
|
view->rootObject()->setProperty("delegateWidth", 50);
|
||||||
|
view->rootObject()->setProperty("delegateHeight", 50);
|
||||||
|
|
||||||
|
WAIT_UNTIL_POLISHED;
|
||||||
|
|
||||||
|
// To check that we don't do a relayout when flicking horizontally, we use a "trick"
|
||||||
|
// where we check the rebuildOptions when we receive the rightColumnChanged
|
||||||
|
// signal. If this signal is emitted as a part of a relayout, rebuildOptions
|
||||||
|
// would still be different from RebuildOption::None at that point.
|
||||||
|
bool columnFlickedIn = false;
|
||||||
|
connect(tableViewHV, &QQuickTableView::rightColumnChanged, [&] {
|
||||||
|
columnFlickedIn = true;
|
||||||
|
QCOMPARE(tableViewHVPrivate->rebuildOptions, QQuickTableViewPrivate::RebuildOption::None);
|
||||||
|
});
|
||||||
|
|
||||||
|
// We do the same for vertical flicking
|
||||||
|
bool rowFlickedIn = false;
|
||||||
|
connect(tableViewHV, &QQuickTableView::bottomRowChanged, [&] {
|
||||||
|
rowFlickedIn = true;
|
||||||
|
QCOMPARE(tableViewHVPrivate->rebuildOptions, QQuickTableViewPrivate::RebuildOption::None);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Move the main tableview so that a new column is flicked in
|
||||||
|
tableView->setContentX(60);
|
||||||
|
QTRY_VERIFY(columnFlickedIn);
|
||||||
|
|
||||||
|
// Move the main tableview so that a new row is flicked in
|
||||||
|
tableView->setContentY(60);
|
||||||
|
QTRY_VERIFY(rowFlickedIn);
|
||||||
|
}
|
||||||
|
|
||||||
|
void tst_QQuickTableView::checkSyncView_detectTopLeftPositionChanged()
|
||||||
|
{
|
||||||
|
// It can happen that, during a resize of columns or rows from using a float-based
|
||||||
|
// slider, that the position of the top-left delegate item is shifted a bit left or
|
||||||
|
// right because of rounding issues. And this again can over time, as you flick, make
|
||||||
|
// the loadedTableOuterRect get slightly out of sync in the sync child compared to the
|
||||||
|
// sync view. TableView will detect if this happens (in syncSyncView), and correct for
|
||||||
|
// it. And this test will test that it works.
|
||||||
|
LOAD_TABLEVIEW("syncviewsimple.qml");
|
||||||
|
GET_QML_TABLEVIEW(tableViewHV);
|
||||||
|
|
||||||
|
auto model = TestModelAsVariant(100, 100);
|
||||||
|
tableView->setModel(model);
|
||||||
|
tableViewHV->setModel(model);
|
||||||
|
|
||||||
|
WAIT_UNTIL_POLISHED;
|
||||||
|
|
||||||
|
// Writing an auto test to trigger this rounding issue is very hard. So to keep it
|
||||||
|
// simple, we cheat by just moving the loadedTableOuterRect directly, and
|
||||||
|
// check that the syncView child detects it, and corrects it, upon doing a
|
||||||
|
// forceLayout()
|
||||||
|
tableViewPrivate->loadedTableOuterRect.moveLeft(20);
|
||||||
|
tableViewPrivate->loadedTableOuterRect.moveTop(30);
|
||||||
|
tableViewPrivate->relayoutTableItems();
|
||||||
|
tableViewHV->forceLayout();
|
||||||
|
|
||||||
|
QCOMPARE(tableViewPrivate->loadedTableOuterRect.left(), 20);
|
||||||
|
QCOMPARE(tableViewHVPrivate->loadedTableOuterRect.left(), 20);
|
||||||
|
|
||||||
|
QCOMPARE(tableViewPrivate->loadedTableOuterRect.top(), 30);
|
||||||
|
QCOMPARE(tableViewHVPrivate->loadedTableOuterRect.top(), 30);
|
||||||
|
}
|
||||||
|
|
||||||
void tst_QQuickTableView::checkThatFetchMoreIsCalledWhenScrolledToTheEndOfTable()
|
void tst_QQuickTableView::checkThatFetchMoreIsCalledWhenScrolledToTheEndOfTable()
|
||||||
{
|
{
|
||||||
LOAD_TABLEVIEW("plaintableview.qml");
|
LOAD_TABLEVIEW("plaintableview.qml");
|
||||||
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
import QtQuick
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: root
|
||||||
|
property bool ok: false
|
||||||
|
width: 640
|
||||||
|
height: 480
|
||||||
|
|
||||||
|
Text {
|
||||||
|
id: text
|
||||||
|
text: "This is a quite long text. Click me and i should remain visible!!! Sadly this doesn't happen"
|
||||||
|
elide: Text.ElideRight
|
||||||
|
anchors {
|
||||||
|
fill: parent
|
||||||
|
margins: 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Component.onCompleted: {
|
||||||
|
text.width = 300;
|
||||||
|
text.height = 0;
|
||||||
|
text.width = 0;
|
||||||
|
text.height = 30;
|
||||||
|
text.width = 300;
|
||||||
|
root.ok = text.paintedWidth > 0 && text.paintedHeight > 0
|
||||||
|
}
|
||||||
|
}
|
|
@ -69,6 +69,7 @@ private slots:
|
||||||
void wrap();
|
void wrap();
|
||||||
void elide();
|
void elide();
|
||||||
void elideParentChanged();
|
void elideParentChanged();
|
||||||
|
void elideRelayoutAfterZeroWidth_data();
|
||||||
void elideRelayoutAfterZeroWidth();
|
void elideRelayoutAfterZeroWidth();
|
||||||
void multilineElide_data();
|
void multilineElide_data();
|
||||||
void multilineElide();
|
void multilineElide();
|
||||||
|
@ -611,10 +612,19 @@ void tst_qquicktext::elideParentChanged()
|
||||||
QCOMPARE(actualItemImageGrab, expectedItemImageGrab);
|
QCOMPARE(actualItemImageGrab, expectedItemImageGrab);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void tst_qquicktext::elideRelayoutAfterZeroWidth_data()
|
||||||
|
{
|
||||||
|
QTest::addColumn<QByteArray>("fileName");
|
||||||
|
|
||||||
|
QTest::newRow("no_margins") << QByteArray("elideZeroWidth.qml");
|
||||||
|
QTest::newRow("with_margins") << QByteArray("elideZeroWidthWithMargins.qml");
|
||||||
|
}
|
||||||
|
|
||||||
void tst_qquicktext::elideRelayoutAfterZeroWidth()
|
void tst_qquicktext::elideRelayoutAfterZeroWidth()
|
||||||
{
|
{
|
||||||
|
QFETCH(const QByteArray, fileName);
|
||||||
QQmlEngine engine;
|
QQmlEngine engine;
|
||||||
QQmlComponent component(&engine, testFileUrl("elideZeroWidth.qml"));
|
QQmlComponent component(&engine, testFileUrl(fileName.constData()));
|
||||||
QScopedPointer<QObject> root(component.create());
|
QScopedPointer<QObject> root(component.create());
|
||||||
QVERIFY2(root, qPrintable(component.errorString()));
|
QVERIFY2(root, qPrintable(component.errorString()));
|
||||||
QVERIFY(root->property("ok").toBool());
|
QVERIFY(root->property("ok").toBool());
|
||||||
|
|
|
@ -502,6 +502,36 @@ TestCase {
|
||||||
verify(control.background.height !== control.height)
|
verify(control.background.height !== control.height)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Component {
|
||||||
|
id: backgroundTest2
|
||||||
|
Button {
|
||||||
|
id: btn
|
||||||
|
width: 100
|
||||||
|
height: 100
|
||||||
|
topInset: 0
|
||||||
|
objectName: ""
|
||||||
|
|
||||||
|
background: Rectangle {
|
||||||
|
id: bg
|
||||||
|
implicitHeight: 80
|
||||||
|
border.color: "red"
|
||||||
|
y: btn.objectName === "aaa" ? 20 : 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// QTBUG-120033: Make sure that the binding for y on the tab button's background doesn't get removed
|
||||||
|
function test_background2() {
|
||||||
|
let button = createTemporaryObject(backgroundTest2, testCase)
|
||||||
|
verify(button)
|
||||||
|
|
||||||
|
verify(button.background.y === 0)
|
||||||
|
button.objectName = "aaa"
|
||||||
|
verify(button.background.y === 20)
|
||||||
|
button.objectName = ""
|
||||||
|
verify(button.background.y === 0)
|
||||||
|
}
|
||||||
|
|
||||||
Component {
|
Component {
|
||||||
id: component2
|
id: component2
|
||||||
T.Control {
|
T.Control {
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Controls
|
||||||
|
|
||||||
|
ApplicationWindow {
|
||||||
|
id: root
|
||||||
|
width: 100
|
||||||
|
height: 100
|
||||||
|
property alias controlsPopup: _controlsPopup
|
||||||
|
property alias blockInputPopup: _blockInputPopup
|
||||||
|
Popup {
|
||||||
|
id: _controlsPopup
|
||||||
|
width: parent.width
|
||||||
|
height: parent.height
|
||||||
|
modal: true
|
||||||
|
Control {
|
||||||
|
id: controls
|
||||||
|
anchors.fill: parent
|
||||||
|
hoverEnabled: true
|
||||||
|
contentItem: Text { text: "Test Control" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Popup {
|
||||||
|
id: _blockInputPopup
|
||||||
|
width: parent.width
|
||||||
|
height: parent.height
|
||||||
|
modal: true
|
||||||
|
}
|
||||||
|
}
|
|
@ -121,6 +121,7 @@ private slots:
|
||||||
void shrinkPopupThatWasLargerThanWindow();
|
void shrinkPopupThatWasLargerThanWindow();
|
||||||
void mirroredCombobox();
|
void mirroredCombobox();
|
||||||
void rotatedCombobox();
|
void rotatedCombobox();
|
||||||
|
void resetHoveredStateForItemsWithinPopup();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static bool hasWindowActivation();
|
static bool hasWindowActivation();
|
||||||
|
@ -2038,6 +2039,40 @@ void tst_QQuickPopup::rotatedCombobox()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void tst_QQuickPopup::resetHoveredStateForItemsWithinPopup()
|
||||||
|
{
|
||||||
|
QQuickControlsApplicationHelper helper(this, "resetHoveredForItemsWithinOverlay.qml");
|
||||||
|
QVERIFY2(helper.ready, helper.failureMessage());
|
||||||
|
|
||||||
|
QQuickWindow *window = helper.window;
|
||||||
|
window->show();
|
||||||
|
QVERIFY(QTest::qWaitForWindowExposed(window));
|
||||||
|
|
||||||
|
QQuickPopup *controlsPopup = window->property("controlsPopup").value<QQuickPopup*>();
|
||||||
|
QVERIFY(controlsPopup);
|
||||||
|
|
||||||
|
QQuickPopup *blockInputPopup = window->property("blockInputPopup").value<QQuickPopup*>();
|
||||||
|
QVERIFY(controlsPopup);
|
||||||
|
|
||||||
|
controlsPopup->open();
|
||||||
|
QTRY_VERIFY(controlsPopup->isOpened());
|
||||||
|
|
||||||
|
QTest::mouseMove(window, QPoint(window->width() / 2 + 2, window->height() / 2 + 2));
|
||||||
|
QTest::mouseMove(window, QPoint(window->width() / 2, window->height() / 2));
|
||||||
|
|
||||||
|
auto *controlItem = qobject_cast<QQuickControl *>(controlsPopup->contentItem()->childItems().at(0));
|
||||||
|
QVERIFY(controlItem);
|
||||||
|
// Check hover enabled for the control item within the popup
|
||||||
|
QTRY_VERIFY(controlItem->isHovered());
|
||||||
|
|
||||||
|
// Open the modal popup window over the existing control item
|
||||||
|
blockInputPopup->open();
|
||||||
|
QTRY_VERIFY(blockInputPopup->isOpened());
|
||||||
|
|
||||||
|
// Control item hovered shall be disabled once we open the modal popup
|
||||||
|
QTRY_VERIFY(!controlItem->isHovered());
|
||||||
|
}
|
||||||
|
|
||||||
QTEST_QUICKCONTROLS_MAIN(tst_QQuickPopup)
|
QTEST_QUICKCONTROLS_MAIN(tst_QQuickPopup)
|
||||||
|
|
||||||
#include "tst_qquickpopup.moc"
|
#include "tst_qquickpopup.moc"
|
||||||
|
|
|
@ -711,6 +711,9 @@ void tst_qquickwidget::touchMultipleWidgets()
|
||||||
QWidget window;
|
QWidget window;
|
||||||
QQuickWidget *leftQuick = new QQuickWidget;
|
QQuickWidget *leftQuick = new QQuickWidget;
|
||||||
leftQuick->setSource(testFileUrl("button.qml"));
|
leftQuick->setSource(testFileUrl("button.qml"));
|
||||||
|
if (!leftQuick->testAttribute(Qt::WA_AcceptTouchEvents))
|
||||||
|
QSKIP("irrelevant on non-touch platforms");
|
||||||
|
|
||||||
QQuickWidget *rightQuick = new QQuickWidget;
|
QQuickWidget *rightQuick = new QQuickWidget;
|
||||||
rightQuick->setSource(testFileUrl("button.qml"));
|
rightQuick->setSource(testFileUrl("button.qml"));
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue