summaryrefslogtreecommitdiff
path: root/dev-qt/qtquickcontrols2/files/qtquickcontrols2-5.15.5-QTBUG-104983.patch
blob: f31e04d6ff4d44c4997c6121b7691e0254ed2563 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
From d0642867ab629daf36a1194274a74758111140be Mon Sep 17 00:00:00 2001
From: Mitch Curtis <mitch.curtis@qt.io>
Date: Mon, 18 Jul 2022 15:21:49 +0800
Subject: [PATCH] Fix scroll bars not showing up when binding to standalone
 contentItem

908aa77d16e00f2bccc0ddae0f8b61955c56a6a1 hid old scroll bars, but
didn't account for the situation where the old scroll bars would be put
back into place, and so they never showed up.

In the case of the linked bug report, since there was a binding to the
ScrollView's contentItem, a default Flickable would be created. After
that binding was evaluated, the contentItem was set, causing the scroll
bars to be hidden (as part of the process of disconnecting from the old
flickable). To fix the issue, we now do the reverse of hideOldItem when
a new contentItem is set.

Fixes: QTBUG-104983
Pick-to: 6.2 6.3 6.4
Change-Id: I910259cc3e8f6a6231ae6c87c7d4f0f652bd0545
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
Reviewed-by: Nate Graham

(cherry picked from qtdeclarative 58bae53237417f28eac6d772fa6ecab657f8a73f)
---
 src/quicktemplates2/qquickcontrol.cpp       | 30 +++++++++++++
 src/quicktemplates2/qquickcontrol_p_p.h     |  1 +
 src/quicktemplates2/qquickscrollbar.cpp     | 11 +++++
 tests/auto/controls/data/tst_scrollview.qml | 47 +++++++++++++++++++++
 4 files changed, 89 insertions(+)

diff --git a/src/quicktemplates2/qquickcontrol.cpp b/src/quicktemplates2/qquickcontrol.cpp
index bbbd0e622..1f4b47343 100644
--- a/src/quicktemplates2/qquickcontrol.cpp
+++ b/src/quicktemplates2/qquickcontrol.cpp
@@ -845,6 +845,13 @@ void QQuickControlPrivate::executeBackground(bool complete)
         quickCompleteDeferred(q, backgroundName(), background);
 }
 
+/*
+    \internal
+
+    Hides an item that was replaced by a newer one, rather than
+    deleting it, as the item is typically created in QML and hence
+    we don't own it.
+*/
 void QQuickControlPrivate::hideOldItem(QQuickItem *item)
 {
     if (!item)
@@ -863,6 +870,29 @@ void QQuickControlPrivate::hideOldItem(QQuickItem *item)
 #endif
 }
 
+/*
+    \internal
+
+    Named "unhide" because it's used for cases where an item
+    that was previously hidden by \l hideOldItem() wants to be
+    shown by a control again, such as a ScrollBar in ScrollView.
+*/
+void QQuickControlPrivate::unhideOldItem(QQuickControl *control, QQuickItem *item)
+{
+    Q_ASSERT(item);
+    qCDebug(lcItemManagement) << "unhiding old item" << item;
+
+    item->setVisible(true);
+    item->setParentItem(control);
+
+#if QT_CONFIG(accessibility)
+    // Add the item back in to the accessibility tree.
+    QQuickAccessibleAttached *accessible = accessibleAttached(item);
+    if (accessible)
+        accessible->setIgnored(false);
+#endif
+}
+
 void QQuickControlPrivate::updateBaselineOffset()
 {
     Q_Q(QQuickControl);
diff --git a/src/quicktemplates2/qquickcontrol_p_p.h b/src/quicktemplates2/qquickcontrol_p_p.h
index 8e979079e..a6e624c91 100644
--- a/src/quicktemplates2/qquickcontrol_p_p.h
+++ b/src/quicktemplates2/qquickcontrol_p_p.h
@@ -173,6 +173,7 @@ public:
     virtual void executeBackground(bool complete = false);
 
     static void hideOldItem(QQuickItem *item);
+    static void unhideOldItem(QQuickControl *control, QQuickItem *item);
 
     void updateBaselineOffset();
 
diff --git a/src/quicktemplates2/qquickscrollbar.cpp b/src/quicktemplates2/qquickscrollbar.cpp
index 4e2f509db..1c4b308cd 100644
--- a/src/quicktemplates2/qquickscrollbar.cpp
+++ b/src/quicktemplates2/qquickscrollbar.cpp
@@ -797,6 +797,14 @@ void QQuickScrollBarAttachedPrivate::initHorizontal()
     if (parent && parent == flickable->parentItem())
         horizontal->stackAfter(flickable);
 
+    // If a scroll bar was previously hidden (due to e.g. setting a new contentItem
+    // on a ScrollView), we need to make sure that we un-hide it.
+    // We don't bother checking if the item is actually the old one, because
+    // if it's not, all of the things the function does (setting parent, visibility, etc.)
+    // should be no-ops anyway.
+    if (auto control = qobject_cast<QQuickControl*>(q_ptr->parent()))
+        QQuickControlPrivate::unhideOldItem(control, horizontal);
+
     layoutHorizontal();
     horizontal->setSize(area->property("widthRatio").toReal());
     horizontal->setPosition(area->property("xPosition").toReal());
@@ -818,6 +826,9 @@ void QQuickScrollBarAttachedPrivate::initVertical()
     if (parent && parent == flickable->parentItem())
         vertical->stackAfter(flickable);
 
+    if (auto control = qobject_cast<QQuickControl*>(q_ptr->parent()))
+        QQuickControlPrivate::unhideOldItem(control, vertical);
+
     layoutVertical();
     vertical->setSize(area->property("heightRatio").toReal());
     vertical->setPosition(area->property("yPosition").toReal());
diff --git a/tests/auto/controls/data/tst_scrollview.qml b/tests/auto/controls/data/tst_scrollview.qml
index 0e8b08352..cd4931184 100644
--- a/tests/auto/controls/data/tst_scrollview.qml
+++ b/tests/auto/controls/data/tst_scrollview.qml
@@ -576,4 +576,51 @@ TestCase {
         verify(newHorizontalScrollBar.visible)
         verify(!oldHorizontalScrollBar.visible)
     }
+
+    Component {
+        id: bindingToContentItemAndStandaloneFlickable
+
+        Item {
+            width: 200
+            height: 200
+
+            property alias scrollView: scrollView
+
+            ScrollView {
+                id: scrollView
+                anchors.fill: parent
+                contentItem: listView
+
+                property Item someBinding: contentItem
+            }
+            ListView {
+                id: listView
+                model: 10
+                delegate: ItemDelegate {
+                    text: modelData
+                    width: listView.width
+                }
+            }
+        }
+    }
+
+    // Tests that scroll bars show up for a ScrollView where
+    // - its contentItem is declared as a standalone, separate item
+    // - there is a binding to contentItem (which causes a default Flickable to be created)
+    function test_bindingToContentItemAndStandaloneFlickable() {
+        let root = createTemporaryObject(bindingToContentItemAndStandaloneFlickable, testCase)
+        verify(root)
+
+        let control = root.scrollView
+        let verticalScrollBar = control.ScrollBar.vertical
+        let horizontalScrollBar = control.ScrollBar.horizontal
+        compare(verticalScrollBar.parent, control)
+        compare(horizontalScrollBar.parent, control)
+        verify(verticalScrollBar.visible)
+        verify(horizontalScrollBar.visible)
+
+        mouseDrag(verticalScrollBar, verticalScrollBar.width / 2, verticalScrollBar.height / 2, 0, 50)
+        verify(verticalScrollBar.active)
+        verify(horizontalScrollBar.active)
+    }
 }
-- 
GitLab