From 1eaebd0c3b7b21bb7483df9bbfe391823ecdc181 Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Thu, 18 May 2017 21:37:09 +0200 Subject: ScrollView: fix default Flickable content item creation Short version: do not emit contentItemChanged() while contentItem() is being called to avoid binding loops. Long version: ScrollView is a thin wrapper around Flickable, and when necessary, instantiates a Flickable behind the scenes. However, ScrollView cannot instantiate one unconditionally, because it has to work with existing Flickables, such as ListView and GridView, too. ScrollView { Item { } } // creates a Flickable ScrollView { Flickable { } } // does not create a Flickable ScrollView { contentItem: Flickable { } } // does not create a Flickable When a Flickable is created behind the scenes, it is assigned as the contentItem of the ScrollView. However, when the Flickable is created lazily as a result of ScrollView::contentItem being accessed, it must NOT emit contentItemChanged() while the contentItem() getter is being called, because that results to a binding loop. This problem was exposed by the recent attempts to enable QML caching at build time (QTBUG-58571). Change-Id: I712f2f30da454a6c22a722afe8a00ae240733571 Reviewed-by: Mitch Curtis --- src/quicktemplates2/qquickcontrol.cpp | 39 ++++++++++++++++++++++------------- 1 file changed, 25 insertions(+), 14 deletions(-) (limited to 'src/quicktemplates2/qquickcontrol.cpp') diff --git a/src/quicktemplates2/qquickcontrol.cpp b/src/quicktemplates2/qquickcontrol.cpp index c039253d..a2b16a10 100644 --- a/src/quicktemplates2/qquickcontrol.cpp +++ b/src/quicktemplates2/qquickcontrol.cpp @@ -281,6 +281,27 @@ QQuickItem *QQuickControlPrivate::getContentItem() return contentItem; } +void QQuickControlPrivate::setContentItem_helper(QQuickItem *item, bool notify) +{ + Q_Q(QQuickControl); + if (contentItem == item) + return; + + q->contentItemChange(item, contentItem); + destroyDelegate(contentItem, q); + contentItem = item; + + if (item) { + if (!item->parentItem()) + item->setParentItem(q); + if (componentComplete) + resizeContent(); + } + + if (notify) + emit q->contentItemChanged(); +} + #if QT_CONFIG(accessibility) void QQuickControlPrivate::accessibilityActiveChanged(bool active) { @@ -1243,25 +1264,15 @@ void QQuickControl::setBackground(QQuickItem *background) QQuickItem *QQuickControl::contentItem() const { QQuickControlPrivate *d = const_cast(d_func()); - return d->getContentItem(); + if (!d->contentItem) + d->setContentItem_helper(d->getContentItem(), false); + return d->contentItem; } void QQuickControl::setContentItem(QQuickItem *item) { Q_D(QQuickControl); - if (d->contentItem == item) - return; - - contentItemChange(item, d->contentItem); - QQuickControlPrivate::destroyDelegate(d->contentItem, this); - d->contentItem = item; - if (item) { - if (!item->parentItem()) - item->setParentItem(this); - if (isComponentComplete()) - d->resizeContent(); - } - emit contentItemChanged(); + d->setContentItem_helper(item, true); } void QQuickControl::classBegin() -- cgit v1.2.3