ListView: Do not create context for section if component is bound

ListView's section needs to inject a "section" property for
compatibility, unless a required property is used for this case.
So far, this made it impossible to use ComponentBehavior: Bound
with sections.
Remedy this by not creating a separate context if we detect that
required properties are used.
Adjust the check in QQuickListViewPrivate::setSectionHelper: If
we don't create a custom context, it might pick up the context
property from somewhere else; but we can then detect that the
used context is internal, and use that check to decide whether
we should call setContextProperyt or setProperty.

Fixes: QTBUG-111433
Pick-to: 6.5
Change-Id: Icd3c138d48f790db92d02c53613539f8f17f5c77
Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
This commit is contained in:
Fabian Kosmale 2023-02-23 11:14:57 +01:00
parent de4635e253
commit 471c909a68
3 changed files with 37 additions and 7 deletions

View File

@ -1062,16 +1062,20 @@ QQuickItem * QQuickListViewPrivate::getSectionItem(const QString &section)
QQmlContext *context = QQmlEngine::contextForObject(sectionItem)->parentContext();
setSectionHelper(context, sectionItem, section);
} else {
QQmlContext *creationContext = sectionCriteria->delegate()->creationContext();
QQmlContext *context = new QQmlContext(
creationContext ? creationContext : qmlContext(q));
QQmlComponent* delegate = sectionCriteria->delegate();
QQmlComponentPrivate* delegatePriv = QQmlComponentPrivate::get(delegate);
const bool reuseExistingContext = delegate->isBound();
auto delegatePriv = QQmlComponentPrivate::get(delegate);
QQmlPropertyCache::ConstPtr rootPropertyCache;
QQmlContext *creationContext = sectionCriteria->delegate()->creationContext();
auto baseContext = creationContext ? creationContext : qmlContext(q);
// if we need to insert a context property, we need a separate context
QQmlContext *context = reuseExistingContext ? baseContext : new QQmlContext(baseContext);
QObject *nobj = delegate->beginCreate(context);
if (nobj) {
if (delegatePriv->hadTopLevelRequiredProperties()) {
delegate->setInitialProperties(nobj, {{QLatin1String("section"), section}});
} else {
} else if (!reuseExistingContext) {
context->setContextProperty(QLatin1String("section"), section);
}
QQml_setParent_noEvent(context, nobj);
@ -1087,7 +1091,7 @@ QQuickItem * QQuickListViewPrivate::getSectionItem(const QString &section)
// sections are not controlled by FxListItemSG, so apply attached properties here
QQuickItemViewAttached *attached = static_cast<QQuickItemViewAttached*>(qmlAttachedPropertiesObject<QQuickListView>(sectionItem));
attached->setView(q);
} else {
} else if (!reuseExistingContext) {
delete context;
}
sectionCriteria->delegate()->completeCreate();
@ -1974,7 +1978,7 @@ bool QQuickListViewPrivate::flick(AxisData &data, qreal minExtent, qreal maxExte
void QQuickListViewPrivate::setSectionHelper(QQmlContext *context, QQuickItem *sectionItem, const QString &section)
{
if (context->contextProperty(QLatin1String("section")).isValid())
if (!QQmlContextData::get(context)->isInternal() && context->contextProperty(QLatin1String("section")).isValid())
context->setContextProperty(QLatin1String("section"), section);
else
sectionItem->setProperty("section", section);

View File

@ -0,0 +1,12 @@
pragma ComponentBehavior: Bound
import QtQuick
ListView {
id: view
model: ListModel {
ListElement { name: "foo"; age: 42 }
ListElement { name: "bar"; age: 13 }
}
delegate: Text { required property string name; text: name}
section.property: "age"
section.delegate: Rectangle { color: "gray"; width: view.width; height: 20; required property string section; Text {text: parent.section} }
}

View File

@ -52,6 +52,7 @@ private slots:
void pullbackSparseList();
void highlightWithBound();
void sectionIsCompatibleWithBoundComponents();
private:
void flickWithTouch(QQuickWindow *window, const QPoint &from, const QPoint &to);
@ -946,6 +947,19 @@ void tst_QQuickListView2::highlightWithBound()
QCOMPARE(highlight->objectName(), QStringLiteral("highlight"));
}
void tst_QQuickListView2::sectionIsCompatibleWithBoundComponents()
{
QTest::failOnWarning(".?");
QQmlEngine engine;
QQmlComponent c(&engine, testFileUrl("sectionBoundComponent.qml"));
QVERIFY2(c.isReady(), qPrintable(c.errorString()));
QScopedPointer<QObject> o(c.create());
QVERIFY(!o.isNull());
QQuickListView *listView = qobject_cast<QQuickListView *>(o.data());
QVERIFY(listView);
QTRY_COMPARE(listView->currentSection(), "42");
}
QTEST_MAIN(tst_QQuickListView2)
#include "tst_qquicklistview2.moc"