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 "")
|
||||
|
|
|
@ -5,4 +5,4 @@ DEFINES += QT_NO_JAVA_STYLE_ITERATORS
|
|||
|
||||
QQC2_SOURCE_TREE = $$PWD
|
||||
|
||||
MODULE_VERSION = 6.2.12
|
||||
MODULE_VERSION = 6.2.13
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
dependencies:
|
||||
../tqtc-qtbase:
|
||||
ref: 3a82051eade32b34c2f4f6f652a9d8ef0db96c71
|
||||
ref: a963a536e623499cc56b0231c35dc5790a4bbc29
|
||||
required: true
|
||||
../tqtc-qtimageformats:
|
||||
ref: 8dd102eea4bf0e6d683f9f8bdfe74c5d63a626c8
|
||||
ref: 282852e3eff8909bfa157d80d1ff7c72fd1662d6
|
||||
required: false
|
||||
../tqtc-qtshadertools:
|
||||
ref: ebe45c38bffcf8c3487949045f9ecf9c8a5f7e30
|
||||
ref: 4e8c28a3dc8d4dd6e237f7cc4235c078147385a2
|
||||
required: false
|
||||
../tqtc-qtsvg:
|
||||
ref: 2563e58640a7a85144ed64641f00c7e5edbabb68
|
||||
ref: 0463e412eeadba6dcf1b84b9c655550f93656e7d
|
||||
required: false
|
||||
|
|
|
@ -11,7 +11,7 @@ layout(location = 0) out vec4 fragColor;
|
|||
layout(std140, binding = 0) uniform buf {
|
||||
mat4 qt_Matrix;
|
||||
vec4 color;
|
||||
vec2 textureSize;
|
||||
vec2 texCoordScale;
|
||||
float qt_Opacity;
|
||||
};
|
||||
|
||||
|
|
Binary file not shown.
|
@ -9,7 +9,7 @@ layout(location = 1) out vec2 vShadeCoord;
|
|||
layout(std140, binding = 0) uniform buf {
|
||||
mat4 qt_Matrix;
|
||||
vec4 color;
|
||||
vec2 textureSize;
|
||||
vec2 texCoordScale;
|
||||
float qt_Opacity;
|
||||
};
|
||||
|
||||
|
@ -17,6 +17,6 @@ out gl_PerVertex { vec4 gl_Position; };
|
|||
|
||||
void main() {
|
||||
gl_Position = qt_Matrix * aVertex;
|
||||
vTexCoord = aVertex.xy * textureSize;
|
||||
vTexCoord = aVertex.xy * texCoordScale;
|
||||
vShadeCoord = aTexCoord;
|
||||
}
|
||||
|
|
Binary file not shown.
|
@ -42,5 +42,6 @@ import QML
|
|||
Member {
|
||||
property string alias
|
||||
property bool isFlag: false
|
||||
property bool isScoped: false
|
||||
property var values: []
|
||||
}
|
||||
|
|
|
@ -240,8 +240,7 @@ void QQuickParticleDataHeap::insertTimed(QQuickParticleData* data, int time)
|
|||
|
||||
int QQuickParticleDataHeap::top()
|
||||
{
|
||||
if (m_end == 0)
|
||||
return 1 << 30;
|
||||
Q_ASSERT(!isEmpty());
|
||||
return m_data[0].time;
|
||||
}
|
||||
|
||||
|
@ -391,7 +390,7 @@ bool QQuickParticleGroupData::recycle()
|
|||
{
|
||||
m_latestAliveParticles.clear();
|
||||
|
||||
while (dataHeap.top() <= m_system->timeInt) {
|
||||
while (!dataHeap.isEmpty() && dataHeap.top() <= m_system->timeInt) {
|
||||
for (QQuickParticleData *datum : dataHeap.pop()) {
|
||||
if (!datum->stillAlive(m_system)) {
|
||||
freeList.free(datum->index);
|
||||
|
|
|
@ -117,6 +117,8 @@ public:
|
|||
|
||||
int top();
|
||||
|
||||
bool isEmpty() const { return m_end == 0; }
|
||||
|
||||
QSet<QQuickParticleData*> pop();
|
||||
|
||||
void clear();
|
||||
|
|
|
@ -1334,14 +1334,14 @@ struct TypeReferenceMap : QHash<int, TypeReference>
|
|||
if (!formal->type.indexIsBuiltinType()) {
|
||||
TypeReference &r
|
||||
= this->add(formal->type.typeNameIndexOrBuiltinType(), it->location);
|
||||
r.errorWhenNotFound = true;
|
||||
r.errorWhenNotFound = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!it->returnType.indexIsBuiltinType()) {
|
||||
TypeReference &r
|
||||
= 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;
|
||||
}
|
||||
|
||||
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();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (metaType == QMetaType::fromType<QQmlListProperty<QObject>>()) {
|
||||
if (const QV4::QmlListWrapper *wrapper = value.as<QV4::QmlListWrapper>()) {
|
||||
*reinterpret_cast<QQmlListProperty<QObject> *>(data) = wrapper->d()->property();
|
||||
const auto wrapperPrivate = wrapper->d();
|
||||
if (QMetaType(wrapperPrivate->propertyType) == metaType) {
|
||||
*reinterpret_cast<QQmlListProperty<QObject> *>(data) = wrapperPrivate->property();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -147,21 +147,18 @@ ReturnedValue ESTable::get(const Value &key, bool *hasValue) const
|
|||
// Removes the given \a key from the table
|
||||
bool ESTable::remove(const Value &key)
|
||||
{
|
||||
bool found = false;
|
||||
uint idx = 0;
|
||||
for (; idx < m_size; ++idx) {
|
||||
if (m_keys[idx].sameValueZero(key)) {
|
||||
found = true;
|
||||
break;
|
||||
for (uint index = 0; index < m_size; ++index) {
|
||||
if (m_keys[index].sameValueZero(key)) {
|
||||
// Remove the element at |index| by moving all elements to the right
|
||||
// of |index| one place to the left.
|
||||
size_t count = (m_size - (index + 1)) * sizeof(Value);
|
||||
memmove(m_keys + index, m_keys + index + 1, count);
|
||||
memmove(m_values + index, m_values + index + 1, count);
|
||||
m_size--;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Returns the size of the table. Note that the size may not match the underlying allocation.
|
||||
|
|
|
@ -53,12 +53,13 @@
|
|||
|
||||
#include "qv4value_p.h"
|
||||
|
||||
class tst_qv4estable;
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
namespace QV4
|
||||
{
|
||||
namespace QV4 {
|
||||
|
||||
class ESTable
|
||||
class Q_AUTOTEST_EXPORT ESTable
|
||||
{
|
||||
public:
|
||||
ESTable();
|
||||
|
@ -76,13 +77,15 @@ public:
|
|||
void removeUnmarkedKeys();
|
||||
|
||||
private:
|
||||
friend class ::tst_qv4estable;
|
||||
|
||||
Value *m_keys = nullptr;
|
||||
Value *m_values = nullptr;
|
||||
uint m_size = 0;
|
||||
uint m_capacity = 0;
|
||||
};
|
||||
|
||||
}
|
||||
} // namespace QV4
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
|
|
|
@ -146,8 +146,8 @@ struct Q_QML_EXPORT SparseArray
|
|||
{
|
||||
SparseArray();
|
||||
~SparseArray() {
|
||||
if (root())
|
||||
freeTree(header.left, alignof(SparseArrayNode));
|
||||
if (SparseArrayNode *n = root())
|
||||
freeTree(n, alignof(SparseArrayNode));
|
||||
}
|
||||
|
||||
SparseArray(const SparseArray &other);
|
||||
|
@ -323,37 +323,45 @@ inline QList<int> SparseArray::keys() const
|
|||
|
||||
inline const SparseArrayNode *SparseArray::lowerBound(uint akey) const
|
||||
{
|
||||
const SparseArrayNode *lb = root()->lowerBound(akey);
|
||||
if (!lb)
|
||||
lb = end();
|
||||
return lb;
|
||||
if (SparseArrayNode *n = root()) {
|
||||
if (const SparseArrayNode *lb = n->lowerBound(akey))
|
||||
return lb;
|
||||
}
|
||||
|
||||
return end();
|
||||
}
|
||||
|
||||
|
||||
inline SparseArrayNode *SparseArray::lowerBound(uint akey)
|
||||
{
|
||||
SparseArrayNode *lb = root()->lowerBound(akey);
|
||||
if (!lb)
|
||||
lb = end();
|
||||
return lb;
|
||||
if (SparseArrayNode *n = root()) {
|
||||
if (SparseArrayNode *lb = n->lowerBound(akey))
|
||||
return lb;
|
||||
}
|
||||
|
||||
return end();
|
||||
}
|
||||
|
||||
|
||||
inline const SparseArrayNode *SparseArray::upperBound(uint akey) const
|
||||
{
|
||||
const SparseArrayNode *ub = root()->upperBound(akey);
|
||||
if (!ub)
|
||||
ub = end();
|
||||
return ub;
|
||||
if (SparseArrayNode *n = root()) {
|
||||
if (const SparseArrayNode *ub = n->upperBound(akey))
|
||||
return ub;
|
||||
}
|
||||
|
||||
return end();
|
||||
}
|
||||
|
||||
|
||||
inline SparseArrayNode *SparseArray::upperBound(uint akey)
|
||||
{
|
||||
SparseArrayNode *ub = root()->upperBound(akey);
|
||||
if (!ub)
|
||||
ub = end();
|
||||
return ub;
|
||||
if (SparseArrayNode *n = root()) {
|
||||
if (SparseArrayNode *ub = n->upperBound(akey))
|
||||
return ub;
|
||||
}
|
||||
|
||||
return end();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -251,7 +251,7 @@ struct QV4QPointer {
|
|||
|
||||
private:
|
||||
QtSharedPointer::ExternalRefCountData *d;
|
||||
QObject *qObject;
|
||||
T *qObject;
|
||||
};
|
||||
Q_STATIC_ASSERT(std::is_trivial< QV4QPointer<QObject> >::value);
|
||||
#endif
|
||||
|
|
|
@ -697,7 +697,13 @@ void qmlRegisterTypeAndRevisions<QQmlTypeNotAvailable, void>(
|
|||
|
||||
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
|
||||
|
@ -722,31 +728,23 @@ void AOTCompiledContext::setReturnValueUndefined() const
|
|||
|
||||
static void captureFallbackProperty(
|
||||
QObject *object, int coreIndex, int notifyIndex, bool isConstant,
|
||||
QQmlContextData *qmlContext)
|
||||
const AOTCompiledContext *aotContext)
|
||||
{
|
||||
if (!qmlContext || isConstant)
|
||||
if (isConstant)
|
||||
return;
|
||||
|
||||
QQmlEngine *engine = qmlContext->engine();
|
||||
Q_ASSERT(engine);
|
||||
QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine);
|
||||
Q_ASSERT(ep);
|
||||
if (QQmlPropertyCapture *capture = ep->propertyCapture)
|
||||
if (QQmlPropertyCapture *capture = propertyCapture(aotContext))
|
||||
capture->captureProperty(object, coreIndex, notifyIndex);
|
||||
}
|
||||
|
||||
static void captureObjectProperty(
|
||||
QObject *object, const QQmlPropertyCache *propertyCache,
|
||||
const QQmlPropertyData *property, QQmlContextData *qmlContext)
|
||||
const QQmlPropertyData *property, const AOTCompiledContext *aotContext)
|
||||
{
|
||||
if (!qmlContext || property->isConstant())
|
||||
if (property->isConstant())
|
||||
return;
|
||||
|
||||
QQmlEngine *engine = qmlContext->engine();
|
||||
Q_ASSERT(engine);
|
||||
QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine);
|
||||
Q_ASSERT(ep);
|
||||
if (QQmlPropertyCapture *capture = ep->propertyCapture)
|
||||
if (QQmlPropertyCapture *capture = propertyCapture(aotContext))
|
||||
capture->captureProperty(object, propertyCache, property);
|
||||
}
|
||||
|
||||
|
@ -762,7 +760,7 @@ static bool inherits(const QQmlPropertyCache *descendent, const QQmlPropertyCach
|
|||
enum class ObjectPropertyResult { OK, NeedsInit, Deleted };
|
||||
|
||||
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);
|
||||
if (!qmlData)
|
||||
|
@ -779,13 +777,13 @@ static ObjectPropertyResult loadObjectProperty(
|
|||
if (qmlData->hasPendingBindingBit(coreIndex))
|
||||
qmlData->flushPendingBinding(coreIndex);
|
||||
|
||||
captureObjectProperty(object, propertyCache, property, qmlContext);
|
||||
captureObjectProperty(object, propertyCache, property, aotContext);
|
||||
property->readProperty(object, target);
|
||||
return ObjectPropertyResult::OK;
|
||||
}
|
||||
|
||||
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);
|
||||
if (qmlData && qmlData->isQueuedForDeletion)
|
||||
|
@ -803,7 +801,7 @@ static ObjectPropertyResult loadFallbackProperty(
|
|||
qmlData->flushPendingBinding(coreIndex);
|
||||
|
||||
captureFallbackProperty(object, coreIndex, l->qobjectFallbackLookup.notifyIndex,
|
||||
l->qobjectFallbackLookup.isConstant, qmlContext);
|
||||
l->qobjectFallbackLookup.isConstant, aotContext);
|
||||
|
||||
void *a[] = { target, nullptr };
|
||||
metaObject->metacall(object, QMetaObject::ReadProperty, coreIndex, a);
|
||||
|
@ -984,7 +982,7 @@ bool AOTCompiledContext::captureLookup(uint index, QObject *object) const
|
|||
|| l->getter == QV4::Lookup::getterQObject) {
|
||||
const QQmlPropertyData *property = l->qobjectLookup.propertyData;
|
||||
QQmlData::flushPendingBinding(object, property->coreIndex());
|
||||
captureObjectProperty(object, l->qobjectLookup.propertyCache, property, qmlContext);
|
||||
captureObjectProperty(object, l->qobjectLookup.propertyCache, property, this);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -993,7 +991,7 @@ bool AOTCompiledContext::captureLookup(uint index, QObject *object) const
|
|||
QQmlData::flushPendingBinding(object, coreIndex);
|
||||
captureFallbackProperty(
|
||||
object, coreIndex, l->qobjectFallbackLookup.notifyIndex,
|
||||
l->qobjectFallbackLookup.isConstant, qmlContext);
|
||||
l->qobjectFallbackLookup.isConstant, this);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1007,7 +1005,7 @@ bool AOTCompiledContext::captureQmlContextPropertyLookup(uint index) const
|
|||
&& l->qmlContextPropertyGetter == QV4::QQmlContextWrapper::lookupContextObjectProperty) {
|
||||
const QQmlPropertyData *property = l->qobjectLookup.propertyData;
|
||||
QQmlData::flushPendingBinding(qmlScopeObject, property->coreIndex());
|
||||
captureObjectProperty(qmlScopeObject, l->qobjectLookup.propertyCache, property, qmlContext);
|
||||
captureObjectProperty(qmlScopeObject, l->qobjectLookup.propertyCache, property, this);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1015,7 +1013,7 @@ bool AOTCompiledContext::captureQmlContextPropertyLookup(uint index) const
|
|||
const int coreIndex = l->qobjectFallbackLookup.coreIndex;
|
||||
QQmlData::flushPendingBinding(qmlScopeObject, coreIndex);
|
||||
captureFallbackProperty(qmlScopeObject, coreIndex, l->qobjectFallbackLookup.notifyIndex,
|
||||
l->qobjectFallbackLookup.isConstant, qmlContext);
|
||||
l->qobjectFallbackLookup.isConstant, this);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1267,9 +1265,9 @@ bool AOTCompiledContext::loadScopeObjectPropertyLookup(uint index, void *target)
|
|||
|
||||
ObjectPropertyResult result = ObjectPropertyResult::NeedsInit;
|
||||
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)
|
||||
result = loadFallbackProperty(l, qmlScopeObject, target, qmlContext);
|
||||
result = loadFallbackProperty(l, qmlScopeObject, target, this);
|
||||
else
|
||||
return false;
|
||||
|
||||
|
@ -1405,9 +1403,9 @@ bool AOTCompiledContext::getObjectLookup(uint index, QObject *object, void *targ
|
|||
|
||||
ObjectPropertyResult result = ObjectPropertyResult::NeedsInit;
|
||||
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)
|
||||
result = loadFallbackProperty(l, object, target, qmlContext);
|
||||
result = loadFallbackProperty(l, object, target, this);
|
||||
else
|
||||
return false;
|
||||
|
||||
|
|
|
@ -812,17 +812,21 @@ static void removeOldBinding(QObject *object, QQmlPropertyIndex index, QQmlPrope
|
|||
oldBinding = data->bindings;
|
||||
|
||||
while (oldBinding && (oldBinding->targetPropertyIndex().coreIndex() != coreIndex ||
|
||||
oldBinding->targetPropertyIndex().hasValueTypeIndex()))
|
||||
oldBinding->targetPropertyIndex().hasValueTypeIndex())) {
|
||||
oldBinding = oldBinding->nextBinding();
|
||||
}
|
||||
|
||||
if (!oldBinding)
|
||||
return;
|
||||
|
||||
if (valueTypeIndex != -1 && oldBinding->isValueTypeProxy())
|
||||
if (valueTypeIndex != -1
|
||||
&& oldBinding
|
||||
&& oldBinding->isValueTypeProxy()) {
|
||||
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;
|
||||
}
|
||||
|
||||
if (!(flags & QQmlPropertyPrivate::DontEnable))
|
||||
oldBinding->setEnabled(false, {});
|
||||
|
|
|
@ -345,7 +345,9 @@ void QQmlTypeData::done()
|
|||
++it) {
|
||||
const TypeReference &type = *it;
|
||||
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 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
|
||||
|
@ -365,7 +367,7 @@ void QQmlTypeData::done()
|
|||
type.type.setInlineComponentObjectId(objectId);
|
||||
}
|
||||
}
|
||||
if (type.typeData && type.typeData->isError()) {
|
||||
if (type.errorWhenNotFound && type.typeData && type.typeData->isError()) {
|
||||
const QString typeName = stringAt(it.key());
|
||||
|
||||
QList<QQmlError> errors = type.typeData->errors();
|
||||
|
@ -887,6 +889,7 @@ void QQmlTypeData::resolveTypes()
|
|||
ref.version = version;
|
||||
ref.location = unresolvedRef->location;
|
||||
ref.needsCreation = unresolvedRef->needsCreation;
|
||||
ref.errorWhenNotFound = unresolvedRef->errorWhenNotFound;
|
||||
m_resolvedTypes.insert(unresolvedRef.key(), ref);
|
||||
}
|
||||
|
||||
|
@ -930,8 +933,12 @@ QQmlError QQmlTypeData::buildTypeResolutionCaches(
|
|||
} else {
|
||||
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);
|
||||
Q_ASSERT(ref->type().isInlineComponentType());
|
||||
}
|
||||
|
|
|
@ -62,16 +62,16 @@ class Q_AUTOTEST_EXPORT QQmlTypeData : public QQmlTypeLoader::Blob
|
|||
public:
|
||||
struct TypeReference
|
||||
{
|
||||
TypeReference() : version(QTypeRevision::zero()), needsCreation(true) {}
|
||||
|
||||
QV4::CompiledData::Location location;
|
||||
QQmlType type;
|
||||
QTypeRevision version;
|
||||
QTypeRevision version = QTypeRevision::zero();
|
||||
QQmlRefPointer<QQmlTypeData> typeData;
|
||||
bool selfReference = false;
|
||||
QString prefix; // used by CompositeSingleton types
|
||||
bool selfReference = false;
|
||||
bool needsCreation = true;
|
||||
bool errorWhenNotFound = true;
|
||||
|
||||
QString qualifiedName() const;
|
||||
bool needsCreation;
|
||||
};
|
||||
|
||||
struct ScriptReference
|
||||
|
|
|
@ -1340,6 +1340,7 @@ void QQmlJSImportVisitor::endVisit(UiArrayBinding *)
|
|||
bool QQmlJSImportVisitor::visit(QQmlJS::AST::UiEnumDeclaration *uied)
|
||||
{
|
||||
QQmlJSMetaEnum qmlEnum(uied->name.toString());
|
||||
qmlEnum.setIsQml(true);
|
||||
for (const auto *member = uied->members; member; member = member->next) {
|
||||
qmlEnum.addKey(member->member.toString());
|
||||
qmlEnum.addValue(int(member->value));
|
||||
|
|
|
@ -66,6 +66,8 @@ class QQmlJSMetaEnum
|
|||
QString m_alias;
|
||||
QSharedPointer<const QQmlJSScope> m_type;
|
||||
bool m_isFlag = false;
|
||||
bool m_isScoped = false;
|
||||
bool m_isQml = false;
|
||||
|
||||
public:
|
||||
QQmlJSMetaEnum() = default;
|
||||
|
@ -82,6 +84,12 @@ public:
|
|||
bool isFlag() const { return m_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); }
|
||||
QStringList keys() const { return m_keys; }
|
||||
|
||||
|
@ -102,7 +110,8 @@ public:
|
|||
&& a.m_name == b.m_name
|
||||
&& a.m_alias == b.m_alias
|
||||
&& 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)
|
||||
|
@ -112,7 +121,8 @@ public:
|
|||
|
||||
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));
|
||||
} else if (name == QLatin1String("values")) {
|
||||
readEnumValues(script, &metaEnum);
|
||||
} else if (name == QLatin1String("isScoped")) {
|
||||
metaEnum.setIsScoped(readBoolBinding(script));
|
||||
} else {
|
||||
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();
|
||||
const int elementIndex = that->d()->elementIndex();
|
||||
int roleIndex = that->d()->m_model->m_listModel->setExistingProperty(elementIndex, propName, value, eng);
|
||||
if (roleIndex != -1)
|
||||
that->d()->m_model->emitItemsChanged(elementIndex, 1, QVector<int>(1, roleIndex));
|
||||
if (QQmlListModel *model = that->d()->m_model) {
|
||||
const int 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());
|
||||
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);
|
||||
Scope scope(that);
|
||||
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)
|
||||
return QObjectWrapper::virtualGet(m, id, receiver, hasProperty);
|
||||
if (hasProperty)
|
||||
|
@ -1730,7 +1737,7 @@ ReturnedValue ModelObject::virtualGet(const Managed *m, PropertyKey id, const Va
|
|||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -1753,16 +1760,19 @@ PropertyKey ModelObjectOwnPropertyKeyIterator::next(const Object *o, Property *p
|
|||
const ModelObject *that = static_cast<const ModelObject *>(o);
|
||||
|
||||
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());
|
||||
const ListLayout::Role &role = that->listModel()->getExistingRole(roleNameIndex);
|
||||
const ListLayout::Role &role = listModel->getExistingRole(roleNameIndex);
|
||||
++roleNameIndex;
|
||||
ScopedString roleName(scope, v4->newString(role.name));
|
||||
if (attrs)
|
||||
*attrs = QV4::Attr_Data;
|
||||
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)) {
|
||||
auto size = recursiveListModel->count();
|
||||
auto array = ScopedArrayObject{scope, v4->newArrayObject(size)};
|
||||
|
|
|
@ -115,6 +115,8 @@ public:
|
|||
bool dynamicRoles() const { return m_dynamicRoles; }
|
||||
void setDynamicRoles(bool enableDynamicRoles);
|
||||
|
||||
ListModel *listModel() const { return m_listModel; }
|
||||
|
||||
Q_SIGNALS:
|
||||
void countChanged();
|
||||
|
||||
|
|
|
@ -161,13 +161,23 @@ struct ModelObject : public QObjectWrapper {
|
|||
{
|
||||
QObjectWrapper::init(object);
|
||||
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; }
|
||||
QQmlListModel *m_model;
|
||||
ModelNodeMetaObject *m_nodeModelMetaObject;
|
||||
|
||||
void destroy()
|
||||
{
|
||||
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_NEEDS_DESTROY
|
||||
|
||||
ListModel *listModel() const { return d()->m_model->m_listModel; }
|
||||
|
||||
protected:
|
||||
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);
|
||||
|
|
|
@ -118,15 +118,67 @@
|
|||
\snippet src_qmltest_qquicktest_snippet.cpp 1
|
||||
|
||||
Where "example" is the identifier to use to uniquely identify
|
||||
this set of tests. Finally, add \c{CONFIG += qmltestcase} to the project
|
||||
file:
|
||||
this set of tests.
|
||||
|
||||
\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
|
||||
TEMPLATE = app
|
||||
TARGET = tst_example
|
||||
CONFIG += warn_on qmltestcase
|
||||
SOURCES += tst_example.cpp
|
||||
IMPORTPATH += $$PWD/../imports/my_module1 $$PWD/../imports/my_module2
|
||||
\endcode
|
||||
\if defined(onlinedocs)
|
||||
\endtabcontent
|
||||
\endif
|
||||
|
||||
The test harness scans the specified source directory recursively
|
||||
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
|
||||
\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
|
||||
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();
|
||||
for (const QJsonValue classInfo : classInfos) {
|
||||
const QJsonObject obj = classInfo.toObject();
|
||||
if (obj[QStringLiteral("name")].toString() == QStringLiteral("DefaultProperty"))
|
||||
defaultProp = obj[QStringLiteral("value")].toString();
|
||||
if (obj[QStringLiteral("name")].toString() == QStringLiteral("ParentProperty"))
|
||||
parentProp = obj[QStringLiteral("value")].toString();
|
||||
const QString name = obj[QStringLiteral("name")].toString();
|
||||
const auto value = [&]() { return obj[QStringLiteral("value")].toString(); };
|
||||
if (name == QStringLiteral("DefaultProperty")) {
|
||||
defaultProp = value();
|
||||
} else if (name == QStringLiteral("ParentProperty")) {
|
||||
parentProp = value();
|
||||
} else if (name == QStringLiteral("RegisterEnumClassesUnscoped")
|
||||
&& value() == QStringLiteral("false")) {
|
||||
registerEnumClassesScoped = true;
|
||||
}
|
||||
}
|
||||
|
||||
collectInterfaces(classDef);
|
||||
|
@ -143,6 +149,9 @@ void QmlTypesClassDescription::collect(
|
|||
} else if (name == QLatin1String("ParentProperty")) {
|
||||
if (mode != RelatedType && parentProp.isEmpty())
|
||||
parentProp = value;
|
||||
} else if (name == QLatin1String("RegisterEnumClassesUnscoped")) {
|
||||
if (mode != RelatedType && value == QLatin1String("false"))
|
||||
registerEnumClassesScoped = true;
|
||||
} else if (name == QLatin1String("QML.AddedInVersion")) {
|
||||
const QTypeRevision revision = QTypeRevision::fromEncodedVersion(value.toInt());
|
||||
if (mode == TopLevel) {
|
||||
|
@ -192,10 +201,12 @@ void QmlTypesClassDescription::collect(
|
|||
if (const QJsonObject *other = findType(foreign, foreignTypeName)) {
|
||||
classDef = other;
|
||||
|
||||
// Default properties are always local.
|
||||
// Default properties and enum classes are always local.
|
||||
defaultProp.clear();
|
||||
registerEnumClassesScoped = false;
|
||||
|
||||
// Foreign type can have a default property or an attached types
|
||||
// or RegisterEnumClassesUnscoped classinfo.
|
||||
const auto classInfos = classDef->value(QLatin1String("classInfos")).toArray();
|
||||
for (const QJsonValue classInfo : classInfos) {
|
||||
const QJsonObject obj = classInfo.toObject();
|
||||
|
@ -205,6 +216,9 @@ void QmlTypesClassDescription::collect(
|
|||
defaultProp = foreignValue;
|
||||
} else if (parentProp.isEmpty() && foreignName == QLatin1String("ParentProperty")) {
|
||||
parentProp = foreignValue;
|
||||
} else if (foreignName == QLatin1String("RegisterEnumClassesUnscoped")) {
|
||||
if (foreignValue == QLatin1String("false"))
|
||||
registerEnumClassesScoped = true;
|
||||
} else if (foreignName == QLatin1String("QML.Attached")) {
|
||||
attachedType = foreignValue;
|
||||
collectRelated(foreignValue, types, foreign, defaultRevision);
|
||||
|
|
|
@ -55,6 +55,7 @@ struct QmlTypesClassDescription
|
|||
bool isSingleton = false;
|
||||
bool isRootClass = false;
|
||||
bool hasCustomParser = false;
|
||||
bool registerEnumClassesScoped = false;
|
||||
QStringList implementsInterfaces;
|
||||
|
||||
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) {
|
||||
const QJsonObject obj = item.toObject();
|
||||
|
@ -263,6 +264,13 @@ void QmlTypesCreator::writeEnums(const QJsonArray &enums)
|
|||
auto isFlag = obj.find(QLatin1String("isFlag"));
|
||||
if (isFlag != obj.end() && isFlag->toBool())
|
||||
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.writeEndObject();
|
||||
}
|
||||
|
@ -382,7 +390,11 @@ void QmlTypesCreator::writeComponents()
|
|||
writeClassProperties(collector);
|
||||
|
||||
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));
|
||||
|
||||
|
@ -411,7 +423,11 @@ void QmlTypesCreator::writeComponents()
|
|||
collector.collectLocalAnonymous(&component, m_ownTypes, m_foreignTypes, m_version);
|
||||
|
||||
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));
|
||||
|
||||
|
|
|
@ -53,7 +53,10 @@ private:
|
|||
void writeType(const QJsonObject &property, const QString &key);
|
||||
void writeProperties(const QJsonArray &properties);
|
||||
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();
|
||||
|
||||
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
|
||||
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}
|
||||
*/
|
||||
|
@ -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.
|
||||
|
||||
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
|
||||
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
|
||||
|
@ -394,6 +395,93 @@ void QQuickDragHandler::setActiveTranslation(const QVector2D &trans)
|
|||
\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
|
||||
|
||||
#include "moc_qquickdraghandler_p.cpp"
|
||||
|
|
|
@ -1404,9 +1404,53 @@ void QQuickGridView::setHighlightFollowsCurrentItem(bool autoHighlight)
|
|||
|
||||
/*!
|
||||
\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
|
||||
|
|
|
@ -1721,7 +1721,7 @@ void QQuickListViewPrivate::fixup(AxisData &data, qreal minExtent, qreal maxExte
|
|||
updateHighlight();
|
||||
bottomItem = currentItem;
|
||||
}
|
||||
qreal pos;
|
||||
qreal pos = 0;
|
||||
bool isInBounds = -position() > maxExtent && -position() <= minExtent;
|
||||
|
||||
if (header && !topItem && isInBounds) {
|
||||
|
@ -1802,6 +1802,19 @@ void QQuickListViewPrivate::fixup(AxisData &data, qreal minExtent, qreal maxExte
|
|||
QQuickItemViewPrivate::fixup(data, minExtent, maxExtent);
|
||||
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);
|
||||
|
||||
qreal dist = qAbs(data.move + pos);
|
||||
|
@ -2380,7 +2393,7 @@ QQuickListView::~QQuickListView()
|
|||
|
||||
/*!
|
||||
\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());
|
||||
updateContentWidth();
|
||||
|
||||
if (syncView->leftColumn() != q->leftColumn()) {
|
||||
// The left column is no longer the same as the left
|
||||
// column in syncView. This requires a rebuild.
|
||||
scheduledRebuildOptions |= QQuickTableViewPrivate::RebuildOption::CalculateNewTopLeftColumn;
|
||||
scheduledRebuildOptions.setFlag(RebuildOption::ViewportOnly);
|
||||
if (scheduledRebuildOptions & RebuildOption::LayoutOnly) {
|
||||
if (syncView->leftColumn() != q->leftColumn()
|
||||
|| syncView->d_func()->loadedTableOuterRect.left() != loadedTableOuterRect.left()) {
|
||||
// The left column is no longer the same, or at the same pos, as the left column in
|
||||
// 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());
|
||||
updateContentHeight();
|
||||
|
||||
if (syncView->topRow() != q->topRow()) {
|
||||
// The top row is no longer the same as the top
|
||||
// row in syncView. This requires a rebuild.
|
||||
scheduledRebuildOptions |= QQuickTableViewPrivate::RebuildOption::CalculateNewTopLeftRow;
|
||||
scheduledRebuildOptions.setFlag(RebuildOption::ViewportOnly);
|
||||
if (scheduledRebuildOptions & RebuildOption::LayoutOnly) {
|
||||
if (syncView->topRow() != q->topRow()
|
||||
|| syncView->d_func()->loadedTableOuterRect.top() != loadedTableOuterRect.top()) {
|
||||
// The top row is no longer the same, or at the same pos, as the top row in
|
||||
// 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) {
|
||||
if (!qFuzzyIsNull(oldGeometry.width())) {
|
||||
if (oldGeometry.width() > 0) {
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -190,7 +190,12 @@ void QSGDistanceFieldGlyphCache::update()
|
|||
distanceFields.reserve(pendingGlyphsSize);
|
||||
for (int i = 0; i < pendingGlyphsSize; ++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_doubleGlyphResolution));
|
||||
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();
|
||||
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;
|
||||
|
||||
// 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;
|
||||
} else {
|
||||
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
|
||||
// the root stack frame of the recursive calls to setRunning()
|
||||
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)
|
||||
{
|
||||
Q_D(QQuickGridLayoutBase);
|
||||
if (!isReady())
|
||||
if (!isReady() || !size.isValid())
|
||||
return;
|
||||
|
||||
qCDebug(lcQuickLayouts) << "QQuickGridLayoutBase::rearrange" << d->m_recurRearrangeCounter << this;
|
||||
|
|
|
@ -385,12 +385,22 @@ void QQuickControlPrivate::resizeBackground()
|
|||
bool changeHeight = false;
|
||||
if (((!p->widthValid() || !extra.isAllocated() || !extra->hasBackgroundWidth) && qFuzzyIsNull(background->x()))
|
||||
|| (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();
|
||||
}
|
||||
if (((!p->heightValid() || !extra.isAllocated() || !extra->hasBackgroundHeight) && qFuzzyIsNull(background->y()))
|
||||
|| (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();
|
||||
}
|
||||
if (changeHeight || changeWidth) {
|
||||
|
|
|
@ -498,6 +498,13 @@ bool QQuickOverlay::childMouseEventFilter(QQuickItem *item, QEvent *event)
|
|||
case QEvent::HoverEnter:
|
||||
case QEvent::HoverMove:
|
||||
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);
|
||||
break;
|
||||
|
||||
|
|
|
@ -664,7 +664,24 @@ QQuickWidget::QQuickWidget(QWidget *parent)
|
|||
{
|
||||
setMouseTracking(true);
|
||||
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);
|
||||
#endif
|
||||
d_func()->init();
|
||||
}
|
||||
|
||||
|
|
|
@ -120,6 +120,7 @@ if(QT_FEATURE_private_tests)
|
|||
add_subdirectory(qqmltablemodel)
|
||||
add_subdirectory(qv4assembler)
|
||||
add_subdirectory(qv4mm)
|
||||
add_subdirectory(qv4estable)
|
||||
add_subdirectory(qv4identifiertable)
|
||||
add_subdirectory(qv4regexp)
|
||||
if(QT_FEATURE_process AND NOT QNX)
|
||||
|
|
|
@ -293,6 +293,7 @@ private slots:
|
|||
void spreadNoOverflow();
|
||||
|
||||
void deleteDefineCycle();
|
||||
void deleteFromSparseArray();
|
||||
|
||||
public:
|
||||
Q_INVOKABLE QJSValue throwingCppMethod1();
|
||||
|
@ -5837,6 +5838,26 @@ void tst_QJSEngine::deleteDefineCycle()
|
|||
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)
|
||||
|
||||
#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 writeNumberToEnumAlias();
|
||||
void badInlineComponentAnnotation();
|
||||
|
||||
void typedObjectList();
|
||||
|
||||
void overrideInnerBinding();
|
||||
|
||||
private:
|
||||
QQmlEngine engine;
|
||||
|
@ -6747,6 +6752,52 @@ void tst_qqmllanguage::writeNumberToEnumAlias()
|
|||
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)
|
||||
|
||||
#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 objectOwnershipFlip();
|
||||
void protectQObjectFromGC();
|
||||
void deadModelData();
|
||||
};
|
||||
|
||||
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)
|
||||
|
||||
#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 infiniteLoopsWithoutFrom();
|
||||
void targetsDeletedNotRemoved();
|
||||
void alwaysRunToEndSetFalseRestartBug();
|
||||
};
|
||||
#define QTIMED_COMPARE(lhs, rhs) do { \
|
||||
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)
|
||||
|
||||
#include "tst_qquickanimations.moc"
|
||||
|
|
|
@ -1308,6 +1308,53 @@ Item {
|
|||
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 {
|
||||
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();
|
||||
void snapToItemWithSpacing_QTBUG_59852();
|
||||
void snapToItemWithSectionAtStart();
|
||||
void snapOneItemResize_QTBUG_43555();
|
||||
void snapOneItem_data();
|
||||
void snapOneItem();
|
||||
|
@ -5407,6 +5408,27 @@ void tst_QQuickListView::snapToItemWithSpacing_QTBUG_59852()
|
|||
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)
|
||||
{
|
||||
QPoint pos = *startPos;
|
||||
|
|
|
@ -4,3 +4,5 @@ ubuntu-22.04
|
|||
[nested]
|
||||
ubuntu-20.04
|
||||
ubuntu-22.04
|
||||
[inFlickable]
|
||||
* # QTBUG-127628
|
||||
|
|
|
@ -185,6 +185,8 @@ private slots:
|
|||
void checkSyncView_pageFlicking();
|
||||
void checkSyncView_emptyModel();
|
||||
void checkSyncView_topLeftChanged();
|
||||
void checkSyncView_dontRelayoutWhileFlicking();
|
||||
void checkSyncView_detectTopLeftPositionChanged();
|
||||
void delegateWithRequiredProperties();
|
||||
void checkThatFetchMoreIsCalledWhenScrolledToTheEndOfTable();
|
||||
void replaceModel();
|
||||
|
@ -3108,6 +3110,85 @@ void tst_QQuickTableView::checkSyncView_topLeftChanged()
|
|||
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()
|
||||
{
|
||||
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 elide();
|
||||
void elideParentChanged();
|
||||
void elideRelayoutAfterZeroWidth_data();
|
||||
void elideRelayoutAfterZeroWidth();
|
||||
void multilineElide_data();
|
||||
void multilineElide();
|
||||
|
@ -611,10 +612,19 @@ void tst_qquicktext::elideParentChanged()
|
|||
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()
|
||||
{
|
||||
QFETCH(const QByteArray, fileName);
|
||||
QQmlEngine engine;
|
||||
QQmlComponent component(&engine, testFileUrl("elideZeroWidth.qml"));
|
||||
QQmlComponent component(&engine, testFileUrl(fileName.constData()));
|
||||
QScopedPointer<QObject> root(component.create());
|
||||
QVERIFY2(root, qPrintable(component.errorString()));
|
||||
QVERIFY(root->property("ok").toBool());
|
||||
|
|
|
@ -502,6 +502,36 @@ TestCase {
|
|||
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 {
|
||||
id: component2
|
||||
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 mirroredCombobox();
|
||||
void rotatedCombobox();
|
||||
void resetHoveredStateForItemsWithinPopup();
|
||||
|
||||
private:
|
||||
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)
|
||||
|
||||
#include "tst_qquickpopup.moc"
|
||||
|
|
|
@ -711,6 +711,9 @@ void tst_qquickwidget::touchMultipleWidgets()
|
|||
QWidget window;
|
||||
QQuickWidget *leftQuick = new QQuickWidget;
|
||||
leftQuick->setSource(testFileUrl("button.qml"));
|
||||
if (!leftQuick->testAttribute(Qt::WA_AcceptTouchEvents))
|
||||
QSKIP("irrelevant on non-touch platforms");
|
||||
|
||||
QQuickWidget *rightQuick = new QQuickWidget;
|
||||
rightQuick->setSource(testFileUrl("button.qml"));
|
||||
|
||||
|
|
Loading…
Reference in New Issue