qquicklistview: support required properties in sectionDelegate

This changes the accessibile properties in the sectionDelegate:
If the sectionDelegate contains requiredProperties, "section" will not
be injected into a newly created parent scope.
Instead, the section property of the delegate will be set if it exists.

Change-Id: I34b04d08d2f80af7ea53fd722f08be0f9aea6e72
Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
This commit is contained in:
Fabian Kosmale 2019-08-13 17:11:48 +02:00
parent 6848770529
commit ba30971c7e
5 changed files with 117 additions and 7 deletions

View File

@ -345,6 +345,11 @@ RequiredProperties &QQmlComponentPrivate::requiredProperties()
return state.creator->requiredProperties();
}
bool QQmlComponentPrivate::hadRequiredProperties() const
{
return state.creator->componentHadRequiredProperties();
}
void QQmlComponentPrivate::clear()
{
if (typeData) {

View File

@ -108,6 +108,7 @@ public:
int start;
RequiredProperties& requiredProperties();
bool hadRequiredProperties() const;
QQmlRefPointer<QV4::ExecutableCompilationUnit> compilationUnit;
struct ConstructionState {

View File

@ -49,6 +49,7 @@
#include <QtCore/qmath.h>
#include <private/qquicksmoothedanimation_p_p.h>
#include <private/qqmlcomponent_p.h>
#include "qplatformdefs.h"
QT_BEGIN_NAMESPACE
@ -190,6 +191,8 @@ public:
}
friend class QQuickViewSection;
static void setSectionHelper(QQmlContext *context, QQuickItem *sectionItem, const QString &section);
};
//----------------------------------------------------------------------------
@ -992,14 +995,20 @@ QQuickItem * QQuickListViewPrivate::getSectionItem(const QString &section)
sectionCache[i] = nullptr;
sectionItem->setVisible(true);
QQmlContext *context = QQmlEngine::contextForObject(sectionItem)->parentContext();
context->setContextProperty(QLatin1String("section"), section);
setSectionHelper(context, sectionItem, section);
} else {
QQmlContext *creationContext = sectionCriteria->delegate()->creationContext();
QQmlContext *context = new QQmlContext(
creationContext ? creationContext : qmlContext(q));
context->setContextProperty(QLatin1String("section"), section);
QObject *nobj = sectionCriteria->delegate()->beginCreate(context);
QQmlComponent* delegate = sectionCriteria->delegate();
QQmlComponentPrivate* delegatePriv = QQmlComponentPrivate::get(delegate);
QObject *nobj = delegate->beginCreate(context);
if (nobj) {
if (delegatePriv->hadRequiredProperties()) {
delegate->setInitialProperties(nobj, {{"section", section}});
} else {
context->setContextProperty(QLatin1String("section"), section);
}
QQml_setParent_noEvent(context, nobj);
sectionItem = qobject_cast<QQuickItem *>(nobj);
if (!sectionItem) {
@ -1069,7 +1078,7 @@ void QQuickListViewPrivate::updateInlineSection(FxListItemSG *listItem)
listItem->setPosition(pos);
} else {
QQmlContext *context = QQmlEngine::contextForObject(listItem->section())->parentContext();
context->setContextProperty(QLatin1String("section"), listItem->attached->m_section);
setSectionHelper(context, listItem->section(), listItem->attached->m_section);
}
} else if (listItem->section()) {
qreal pos = listItem->position();
@ -1125,7 +1134,7 @@ void QQuickListViewPrivate::updateStickySections()
currentSectionItem = getSectionItem(currentSection);
} else if (QString::compare(currentStickySection, currentSection, Qt::CaseInsensitive)) {
QQmlContext *context = QQmlEngine::contextForObject(currentSectionItem)->parentContext();
context->setContextProperty(QLatin1String("section"), currentSection);
setSectionHelper(context, currentSectionItem, currentSection);
}
currentStickySection = currentSection;
if (!currentSectionItem)
@ -1159,7 +1168,7 @@ void QQuickListViewPrivate::updateStickySections()
nextSectionItem = getSectionItem(nextSection);
} else if (QString::compare(nextStickySection, nextSection, Qt::CaseInsensitive)) {
QQmlContext *context = QQmlEngine::contextForObject(nextSectionItem)->parentContext();
context->setContextProperty(QLatin1String("section"), nextSection);
setSectionHelper(context, nextSectionItem, nextSection);
}
nextStickySection = nextSection;
if (!nextSectionItem)
@ -1754,6 +1763,14 @@ 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())
context->setContextProperty(QLatin1String("section"), section);
else
sectionItem->setProperty("section", section);
}
//----------------------------------------------------------------------------
/*!

View File

@ -0,0 +1,77 @@
import QtQuick 2.0
Rectangle {
property string sectionProperty: "number"
property int sectionPositioning: ViewSection.InlineLabels
width: 240
height: 320
color: "#ffffff"
resources: [
Component {
id: myDelegate
Item {
id: wrapper
objectName: "wrapper"
property string section: ListView.section
property string nextSection: ListView.nextSection
property string prevSection: ListView.previousSection
height: 20;
width: 240
Rectangle {
height: 20
width: parent.width
color: wrapper.ListView.isCurrentItem ? "lightsteelblue" : "white"
Text {
text: index
}
Text {
x: 30
id: textName
objectName: "textName"
text: name
}
Text {
x: 100
id: textNumber
objectName: "textNumber"
text: number
}
Text {
objectName: "nextSection"
x: 150
text: wrapper.ListView.nextSection
}
Text {
x: 200
text: wrapper.y
}
}
ListView.onRemove: SequentialAnimation {
PropertyAction { target: wrapper; property: "ListView.delayRemove"; value: true }
NumberAnimation { target: wrapper; property: "height"; to: 0; duration: 100; easing.type: Easing.InOutQuad }
PropertyAction { target: wrapper; property: "ListView.delayRemove"; value: false }
}
}
}
]
ListView {
id: list
objectName: "list"
width: 240
height: 320
cacheBuffer: 60
model: testModel
delegate: myDelegate
section.property: sectionProperty
section.delegate: Rectangle {
id: myDelegate
required property string section
objectName: "sect_" + section
color: "#99bb99"
height: 20
width: list.width
Text { text: myDelegate.section + ", " + parent.y + ", " + parent.objectName }
}
section.labelPositioning: sectionPositioning
}
}

View File

@ -127,6 +127,7 @@ private slots:
void qAbstractItemModel_package_sections();
void qAbstractItemModel_sections();
void sectionsPositioning();
void sectionsDelegate_data();
void sectionsDelegate();
void sectionsDragOutsideBounds_data();
void sectionsDragOutsideBounds();
@ -2160,8 +2161,17 @@ void tst_QQuickListView::sections(const QUrl &source)
QTRY_COMPARE(item->height(), 40.0);
}
void tst_QQuickListView::sectionsDelegate_data()
{
QTest::addColumn<QUrl>("path");
QTest::addRow("implicit") << testFileUrl("listview-sections_delegate.qml");
QTest::addRow("required") << testFileUrl("listview-sections_delegate_required.qml");
}
void tst_QQuickListView::sectionsDelegate()
{
QFETCH(QUrl, path);
QScopedPointer<QQuickView> window(createView());
QaimModel model;
@ -2171,7 +2181,7 @@ void tst_QQuickListView::sectionsDelegate()
QQmlContext *ctxt = window->rootContext();
ctxt->setContextProperty("testModel", &model);
window->setSource(testFileUrl("listview-sections_delegate.qml"));
window->setSource(path);
window->show();
QVERIFY(QTest::qWaitForWindowExposed(window.data()));