Merge lp:~zsombi/ubuntu-ui-toolkit/focusing-improvements into lp:ubuntu-ui-toolkit/staging
- focusing-improvements
- Merge into staging
Status: | Merged |
---|---|
Approved by: | Zsombor Egri |
Approved revision: | 1229 |
Merged at revision: | 1228 |
Proposed branch: | lp:~zsombi/ubuntu-ui-toolkit/focusing-improvements |
Merge into: | lp:ubuntu-ui-toolkit/staging |
Diff against target: |
254 lines (+36/-111) 6 files modified
modules/Ubuntu/Components/AbstractButton.qml (+0/-1) modules/Ubuntu/Components/Pickers/Picker.qml (+0/-1) modules/Ubuntu/Components/plugin/ucstyleditembase.cpp (+22/-54) modules/Ubuntu/Components/plugin/ucstyleditembase.h (+1/-0) tests/unit_x11/tst_components/tst_focus.qml (+12/-0) tests/unit_x11/tst_components/tst_styleditem.qml (+1/-55) |
To merge this branch: | bzr merge lp:~zsombi/ubuntu-ui-toolkit/focusing-improvements |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
PS Jenkins bot | continuous-integration | Approve | |
Cris Dywan | Approve | ||
Review via email: mp+232972@code.launchpad.net |
Commit message
Focus should not be taken by a component if disabled. Complete child filtering properly.
Description of the change
Zsombor Egri (zsombi) wrote : | # |
Cris Dywan (kalikiana) wrote : | # |
This makes quite a bit of sense. I wonder how neither of us noticed before… looks sensible.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:1227
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Autolanding.
More details in the following jenkins job:
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
- 1228. By Zsombor Egri
-
remove unused d-pointer causing build warning
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:1228
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
- 1229. By Zsombor Egri
-
documentation fix
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:1229
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Preview Diff
1 | === modified file 'modules/Ubuntu/Components/AbstractButton.qml' | |||
2 | --- modules/Ubuntu/Components/AbstractButton.qml 2014-08-21 05:24:14 +0000 | |||
3 | +++ modules/Ubuntu/Components/AbstractButton.qml 2014-09-02 12:49:18 +0000 | |||
4 | @@ -103,7 +103,6 @@ | |||
5 | 103 | hoverEnabled: true | 103 | hoverEnabled: true |
6 | 104 | 104 | ||
7 | 105 | onClicked: { | 105 | onClicked: { |
8 | 106 | button.requestFocus(); | ||
9 | 107 | if (button.__acceptEvents) { | 106 | if (button.__acceptEvents) { |
10 | 108 | pressEffect.start() | 107 | pressEffect.start() |
11 | 109 | button.clicked() | 108 | button.clicked() |
12 | 110 | 109 | ||
13 | === modified file 'modules/Ubuntu/Components/Pickers/Picker.qml' | |||
14 | --- modules/Ubuntu/Components/Pickers/Picker.qml 2014-08-21 05:24:14 +0000 | |||
15 | +++ modules/Ubuntu/Components/Pickers/Picker.qml 2014-09-02 12:49:18 +0000 | |||
16 | @@ -294,7 +294,6 @@ | |||
17 | 294 | width: parent ? parent.width : 0 | 294 | width: parent ? parent.width : 0 |
18 | 295 | clip: true | 295 | clip: true |
19 | 296 | focus: true | 296 | focus: true |
20 | 297 | Mouse.onClicked: picker.requestFocus() | ||
21 | 298 | 297 | ||
22 | 299 | model: picker.model | 298 | model: picker.model |
23 | 300 | delegate: picker.delegate | 299 | delegate: picker.delegate |
24 | 301 | 300 | ||
25 | === modified file 'modules/Ubuntu/Components/plugin/ucstyleditembase.cpp' | |||
26 | --- modules/Ubuntu/Components/plugin/ucstyleditembase.cpp 2014-08-22 16:09:46 +0000 | |||
27 | +++ modules/Ubuntu/Components/plugin/ucstyleditembase.cpp 2014-09-02 12:49:18 +0000 | |||
28 | @@ -86,7 +86,7 @@ | |||
29 | 86 | } | 86 | } |
30 | 87 | 87 | ||
31 | 88 | /*! | 88 | /*! |
33 | 89 | * \qmlmethod void StyledItemBase::requestFocus() | 89 | * \qmlmethod void StyledItemBase::requestFocus(Qt::FocusReason reason) |
34 | 90 | * \since Ubuntu.Components 1.1 | 90 | * \since Ubuntu.Components 1.1 |
35 | 91 | * The function is similar to \c forceActiveFocus except that it sets focus only | 91 | * The function is similar to \c forceActiveFocus except that it sets focus only |
36 | 92 | * if all the ancestors have activeFocusOnPressed set. Returns true if the request | 92 | * if all the ancestors have activeFocusOnPressed set. Returns true if the request |
37 | @@ -96,7 +96,7 @@ | |||
38 | 96 | { | 96 | { |
39 | 97 | Q_D(UCStyledItemBase); | 97 | Q_D(UCStyledItemBase); |
40 | 98 | bool focusable = d->isParentFocusable(); | 98 | bool focusable = d->isParentFocusable(); |
42 | 99 | if (focusable) { | 99 | if (focusable && isEnabled()) { |
43 | 100 | QQuickItem::forceActiveFocus(reason); | 100 | QQuickItem::forceActiveFocus(reason); |
44 | 101 | } | 101 | } |
45 | 102 | return focusable; | 102 | return focusable; |
46 | @@ -151,57 +151,6 @@ | |||
47 | 151 | * } | 151 | * } |
48 | 152 | * \endqml | 152 | * \endqml |
49 | 153 | * | 153 | * |
50 | 154 | * StyledItem cannot gain focus automaically if there is a MouseArea or other | ||
51 | 155 | * component grabbing mouse events placed over it. In that case the focus must | ||
52 | 156 | * be grabbed by the overlapping area explicitly either by calling the \l requestFocus | ||
53 | 157 | * function or by forwarding mouse events to the covered StyledItem area. | ||
54 | 158 | * \qml | ||
55 | 159 | * import QtQuick 2.2 | ||
56 | 160 | * import Ubuntu.Components 1.1 | ||
57 | 161 | * | ||
58 | 162 | * Column { | ||
59 | 163 | * width: units.gu(50) | ||
60 | 164 | * height: units.gu(100) | ||
61 | 165 | * | ||
62 | 166 | * StyledItem { | ||
63 | 167 | * id: scope1 | ||
64 | 168 | * width: parent.width | ||
65 | 169 | * height: units.gu(30) | ||
66 | 170 | * activeFocusOnPress: false | ||
67 | 171 | * Rectangle { | ||
68 | 172 | * focus: true | ||
69 | 173 | * anchors { | ||
70 | 174 | * fill: parent | ||
71 | 175 | * margins: units.gu(1) | ||
72 | 176 | * } | ||
73 | 177 | * color: !activeFocus ? "red" : "green" | ||
74 | 178 | * MouseArea { | ||
75 | 179 | * anchors.fill: parent | ||
76 | 180 | * onClicked: scope1.requestFocus() | ||
77 | 181 | * } | ||
78 | 182 | * } | ||
79 | 183 | * } | ||
80 | 184 | * StyledItem { | ||
81 | 185 | * id: scope2 | ||
82 | 186 | * width: parent.width | ||
83 | 187 | * height: units.gu(30) | ||
84 | 188 | * activeFocusOnPress: false | ||
85 | 189 | * Rectangle { | ||
86 | 190 | * focus: true | ||
87 | 191 | * anchors { | ||
88 | 192 | * fill: parent | ||
89 | 193 | * margins: units.gu(1) | ||
90 | 194 | * } | ||
91 | 195 | * color: !activeFocus ? "red" : "green" | ||
92 | 196 | * MouseArea { | ||
93 | 197 | * anchors.fill: parent | ||
94 | 198 | * Mouse.forwardTo: [scope2] | ||
95 | 199 | * } | ||
96 | 200 | * } | ||
97 | 201 | * } | ||
98 | 202 | * } | ||
99 | 203 | * \endqml | ||
100 | 204 | * | ||
101 | 205 | * The default value is \c false. | 154 | * The default value is \c false. |
102 | 206 | */ | 155 | */ |
103 | 207 | bool UCStyledItemBase::activefocusOnPress() const | 156 | bool UCStyledItemBase::activefocusOnPress() const |
104 | @@ -223,8 +172,27 @@ | |||
105 | 223 | void UCStyledItemBase::mousePressEvent(QMouseEvent *event) | 172 | void UCStyledItemBase::mousePressEvent(QMouseEvent *event) |
106 | 224 | { | 173 | { |
107 | 225 | QQuickItem::mousePressEvent(event); | 174 | QQuickItem::mousePressEvent(event); |
108 | 226 | Q_D(UCStyledItemBase); | ||
109 | 227 | requestFocus(Qt::MouseFocusReason); | 175 | requestFocus(Qt::MouseFocusReason); |
110 | 228 | } | 176 | } |
111 | 229 | 177 | ||
112 | 178 | // filter children events as well, so we can catch mouse presses done over child | ||
113 | 179 | // MouseAreas or other mouse grabbers | ||
114 | 180 | bool UCStyledItemBase::childMouseEventFilter(QQuickItem *child, QEvent *event) | ||
115 | 181 | { | ||
116 | 182 | // only filter pressed events | ||
117 | 183 | if (event->type() == QEvent::MouseButtonPress) { | ||
118 | 184 | QMouseEvent *mouse = static_cast<QMouseEvent*>(event); | ||
119 | 185 | // the event may occur outside of the parent's boundaries if not clipped | ||
120 | 186 | // therefore must check containment | ||
121 | 187 | QPointF point = mapFromItem(child, mouse->localPos()); | ||
122 | 188 | if (contains(point)) { | ||
123 | 189 | QMouseEvent press(event->type(), point, mouse->windowPos(), mouse->screenPos(), | ||
124 | 190 | mouse->button(), mouse->buttons(), mouse->modifiers()); | ||
125 | 191 | mousePressEvent(&press); | ||
126 | 192 | } | ||
127 | 193 | } | ||
128 | 194 | // let the event be passed to children | ||
129 | 195 | return false; | ||
130 | 196 | } | ||
131 | 197 | |||
132 | 230 | #include "moc_ucstyleditembase.cpp" | 198 | #include "moc_ucstyleditembase.cpp" |
133 | 231 | 199 | ||
134 | === modified file 'modules/Ubuntu/Components/plugin/ucstyleditembase.h' | |||
135 | --- modules/Ubuntu/Components/plugin/ucstyleditembase.h 2014-08-20 12:56:51 +0000 | |||
136 | +++ modules/Ubuntu/Components/plugin/ucstyleditembase.h 2014-09-02 12:49:18 +0000 | |||
137 | @@ -44,6 +44,7 @@ | |||
138 | 44 | UCStyledItemBase(UCStyledItemBasePrivate &, QQuickItem *parent); | 44 | UCStyledItemBase(UCStyledItemBasePrivate &, QQuickItem *parent); |
139 | 45 | 45 | ||
140 | 46 | void mousePressEvent(QMouseEvent *event); | 46 | void mousePressEvent(QMouseEvent *event); |
141 | 47 | bool childMouseEventFilter(QQuickItem *child, QEvent *event); | ||
142 | 47 | 48 | ||
143 | 48 | private: | 49 | private: |
144 | 49 | Q_DECLARE_PRIVATE(UCStyledItemBase) | 50 | Q_DECLARE_PRIVATE(UCStyledItemBase) |
145 | 50 | 51 | ||
146 | === modified file 'tests/unit_x11/tst_components/tst_focus.qml' | |||
147 | --- tests/unit_x11/tst_components/tst_focus.qml 2014-08-18 16:02:33 +0000 | |||
148 | +++ tests/unit_x11/tst_components/tst_focus.qml 2014-09-02 12:49:18 +0000 | |||
149 | @@ -82,6 +82,12 @@ | |||
150 | 82 | Slider { | 82 | Slider { |
151 | 83 | id: slider | 83 | id: slider |
152 | 84 | } | 84 | } |
153 | 85 | StyledItem { | ||
154 | 86 | id: disabledButton | ||
155 | 87 | enabled: false | ||
156 | 88 | width: units.gu(20) | ||
157 | 89 | height: units.gu(6) | ||
158 | 90 | } | ||
159 | 85 | ComboButton { | 91 | ComboButton { |
160 | 86 | id: comboButton | 92 | id: comboButton |
161 | 87 | Rectangle { | 93 | Rectangle { |
162 | @@ -211,6 +217,7 @@ | |||
163 | 211 | compare(dropdownButton.focus, true, "Dropdown button hasn't got focused!"); | 217 | compare(dropdownButton.focus, true, "Dropdown button hasn't got focused!"); |
164 | 212 | compare(comboButton.focus, true, "ComboButton hasn't been focused!"); | 218 | compare(comboButton.focus, true, "ComboButton hasn't been focused!"); |
165 | 213 | comboButton.expanded = false; | 219 | comboButton.expanded = false; |
166 | 220 | waitForRendering(comboButton); | ||
167 | 214 | } | 221 | } |
168 | 215 | 222 | ||
169 | 216 | function test_popover_refocus_data() { | 223 | function test_popover_refocus_data() { |
170 | @@ -236,5 +243,10 @@ | |||
171 | 236 | popupCloseSpy.wait(); | 243 | popupCloseSpy.wait(); |
172 | 237 | verify(popoverTest.focus, "Button focus not restored."); | 244 | verify(popoverTest.focus, "Button focus not restored."); |
173 | 238 | } | 245 | } |
174 | 246 | |||
175 | 247 | function test_disabled_component_does_not_focus() { | ||
176 | 248 | mousePress(disabledButton, centerOf(disabledButton).x, centerOf(disabledButton).y); | ||
177 | 249 | compare(disabledButton.focus, false, "Disabled component shoudl not focus"); | ||
178 | 250 | } | ||
179 | 239 | } | 251 | } |
180 | 240 | } | 252 | } |
181 | 241 | 253 | ||
182 | === modified file 'tests/unit_x11/tst_components/tst_styleditem.qml' | |||
183 | --- tests/unit_x11/tst_components/tst_styleditem.qml 2014-08-20 12:40:19 +0000 | |||
184 | +++ tests/unit_x11/tst_components/tst_styleditem.qml 2014-09-02 12:49:18 +0000 | |||
185 | @@ -90,58 +90,6 @@ | |||
186 | 90 | } | 90 | } |
187 | 91 | } | 91 | } |
188 | 92 | } | 92 | } |
189 | 93 | StyledItem { | ||
190 | 94 | id: activeScope2 | ||
191 | 95 | objectName: "activeScope" | ||
192 | 96 | width: units.gu(50) | ||
193 | 97 | height: units.gu(20) | ||
194 | 98 | activeFocusOnPress: true | ||
195 | 99 | |||
196 | 100 | Rectangle { | ||
197 | 101 | width: height | ||
198 | 102 | height: units.gu(10) | ||
199 | 103 | color: "green" | ||
200 | 104 | anchors.centerIn: parent | ||
201 | 105 | |||
202 | 106 | StyledItem { | ||
203 | 107 | objectName: "in_active_scope" | ||
204 | 108 | activeFocusOnPress: true | ||
205 | 109 | anchors.fill: parent | ||
206 | 110 | MouseArea { | ||
207 | 111 | focus: true | ||
208 | 112 | objectName: "mouseArea" | ||
209 | 113 | anchors.fill: parent | ||
210 | 114 | onClicked: parent.requestFocus() | ||
211 | 115 | } | ||
212 | 116 | } | ||
213 | 117 | } | ||
214 | 118 | } | ||
215 | 119 | StyledItem { | ||
216 | 120 | id: activeScope3 | ||
217 | 121 | objectName: "activeScope" | ||
218 | 122 | width: units.gu(50) | ||
219 | 123 | height: units.gu(20) | ||
220 | 124 | activeFocusOnPress: true | ||
221 | 125 | |||
222 | 126 | Rectangle { | ||
223 | 127 | width: height | ||
224 | 128 | height: units.gu(10) | ||
225 | 129 | color: "green" | ||
226 | 130 | anchors.centerIn: parent | ||
227 | 131 | |||
228 | 132 | StyledItem { | ||
229 | 133 | objectName: "in_active_scope" | ||
230 | 134 | activeFocusOnPress: true | ||
231 | 135 | anchors.fill: parent | ||
232 | 136 | MouseArea { | ||
233 | 137 | focus: true | ||
234 | 138 | objectName: "mouseArea" | ||
235 | 139 | anchors.fill: parent | ||
236 | 140 | Mouse.forwardTo: [parent] | ||
237 | 141 | } | ||
238 | 142 | } | ||
239 | 143 | } | ||
240 | 144 | } | ||
241 | 145 | } | 93 | } |
242 | 146 | 94 | ||
243 | 147 | UbuntuTestCase { | 95 | UbuntuTestCase { |
244 | @@ -152,9 +100,7 @@ | |||
245 | 152 | return [ | 100 | return [ |
246 | 153 | {tag: "main scope is passive", mainScope: passiveScope, innerScope: "in_passive_scope", focusing: false}, | 101 | {tag: "main scope is passive", mainScope: passiveScope, innerScope: "in_passive_scope", focusing: false}, |
247 | 154 | {tag: "main scope is active", mainScope: activeScope, innerScope: "in_active_scope", focusing: true}, | 102 | {tag: "main scope is active", mainScope: activeScope, innerScope: "in_active_scope", focusing: true}, |
251 | 155 | {tag: "MouseArea as child, suppressing", mainScope: activeScope1, innerScope: "mouseArea", focusing: false}, | 103 | {tag: "MouseArea as child, gaining", mainScope: activeScope1, innerScope: "mouseArea", focusing: true}, |
249 | 156 | {tag: "MouseArea as child, gaining", mainScope: activeScope2, innerScope: "mouseArea", focusing: true}, | ||
250 | 157 | {tag: "MouseArea as child, forwarding", mainScope: activeScope3, innerScope: "mouseArea", focusing: true}, | ||
252 | 158 | ]; | 104 | ]; |
253 | 159 | } | 105 | } |
254 | 160 | function test_scope_focusing(data) { | 106 | function test_scope_focusing(data) { |
The child filtering wasn't completed in teh original MR :/ the setFiltersChild MouseEvents( ) call was there without having the childMouseEvent sFilter( ) being implemented. This caused us to have all sorts of workarounds for which QtQuick provides a solution. Mea culpa.