Merge lp:~bzoltan/ubuntu-ui-toolkit/OTA11-landing-2016-04-08 into lp:ubuntu-ui-toolkit

Proposed by Zoltan Balogh on 2016-04-08
Status: Merged
Approved by: Zoltan Balogh on 2016-04-08
Approved revision: 1928
Merged at revision: 1297
Proposed branch: lp:~bzoltan/ubuntu-ui-toolkit/OTA11-landing-2016-04-08
Merge into: lp:ubuntu-ui-toolkit
Diff against target: 3040 lines (+1342/-600)
49 files modified
.bazaar/plugins/packaging_sorting.py (+46/-0)
components.api (+4/-0)
debian/bileto_convert_to_gles (+1/-1)
debian/changelog (+43/-0)
debian/control (+3/-0)
debian/control.gles (+1/-0)
debian/libubuntutoolkit5-dev.install (+2/-0)
examples/ubuntu-ui-toolkit-gallery/MainPage.qml (+2/-0)
export_qml_dir.sh (+2/-0)
features/ubuntu_qml_plugin.prf (+6/-3)
src/Ubuntu/Components/1.3/InputHandler.qml (+20/-20)
src/Ubuntu/Components/1.3/Page.qml (+1/-4)
src/Ubuntu/Components/1.3/PageHeader.qml (+19/-3)
src/Ubuntu/Components/1.3/PageStack.qml (+1/-2)
src/Ubuntu/Components/Styles/1.3/PageHeaderStyle.qml (+16/-1)
src/Ubuntu/Components/Themes/Ambiance/1.3/OverflowPanel.qml (+10/-5)
src/Ubuntu/Components/Themes/Ambiance/1.3/PageHeaderStyle.qml (+96/-28)
src/Ubuntu/Components/plugin/ucheader.cpp (+63/-22)
src/Ubuntu/Components/plugin/ucheader.h (+2/-2)
src/Ubuntu/Components/plugin/ucmousefilters.cpp (+2/-1)
src/Ubuntu/Test/plugin/plugin.pri (+3/-5)
src/Ubuntu/Test/plugin/testplugin.cpp (+3/-11)
src/Ubuntu/Test/plugin/uctestextras.cpp (+7/-23)
src/Ubuntu/Test/plugin/uctestextras.h (+0/-1)
src/Ubuntu/UbuntuToolkit/UbuntuToolkit.pro (+13/-3)
src/Ubuntu/UbuntuToolkit/mousetouchadaptor.cpp (+71/-131)
src/Ubuntu/UbuntuToolkit/mousetouchadaptor.h (+27/-24)
src/Ubuntu/UbuntuToolkit/mousetouchadaptor_p.h (+77/-0)
src/Ubuntu/UbuntuToolkit/mousetouchadaptor_x11.cpp (+350/-0)
tests/autopilot/ubuntuuitoolkit/tests/test_touchadaptor.py (+38/-0)
tests/autopilot/ubuntuuitoolkit/tests/test_touchadaptor.qml (+51/-0)
tests/checkresults.sh (+41/-15)
tests/qmlapicheck.sh (+3/-3)
tests/uitk_test_plan.sh (+5/-5)
tests/unit/runtest.sh (+64/-21)
tests/unit_x11/tst_components/tst_adaptivepagelayout.qml (+1/-0)
tests/unit_x11/tst_components/tst_header.qml (+63/-4)
tests/unit_x11/tst_components/tst_page_with_header.qml (+11/-13)
tests/unit_x11/tst_components/tst_pageheader.qml (+11/-1)
tests/unit_x11/tst_components/tst_pagestack.qml (+40/-6)
tests/unit_x11/tst_components/tst_scrollbar_header.qml (+5/-13)
tests/unit_x11/tst_layouts/tst_layouts.cpp (+6/-2)
tests/unit_x11/tst_mousefilters/EnteredExitedOnMouseMove.qml (+32/-0)
tests/unit_x11/tst_mousefilters/tst_mousefilterstest.cpp (+70/-0)
ubuntu-sdk.pro (+4/-1)
ubuntu-ui-toolkit-launcher/MouseTouchAdaptor.cpp (+0/-159)
ubuntu-ui-toolkit-launcher/MouseTouchAdaptor.h (+0/-50)
ubuntu-ui-toolkit-launcher/launcher.cpp (+3/-12)
ubuntu-ui-toolkit-launcher/ubuntu-ui-toolkit-launcher.pro (+3/-5)
To merge this branch: bzr merge lp:~bzoltan/ubuntu-ui-toolkit/OTA11-landing-2016-04-08
Reviewer Review Type Date Requested Status
PS Jenkins bot continuous-integration Needs Fixing on 2016-04-08
Ubuntu SDK team 2016-04-08 Pending
Review via email: mp+291398@code.launchpad.net

Commit Message

OTA11-landing-2016-04-08

Description of the Change

OTA11-landing-2016-04-08

To post a comment you must log in.
1929. By Zoltan Balogh on 2016-04-08

Merged in the gles files from trunk

1930. By Zoltan Balogh on 2016-04-11

Sync with staging

1931. By Zoltan Balogh on 2016-04-11

Update changelog

1932. By Zoltan Balogh on 2016-04-11

Sync with staging

1933. By Zoltan Balogh on 2016-04-12

Sync with staging

1934. By Zoltan Balogh on 2016-04-12

make test plan executable

1935. By Zoltan Balogh on 2016-04-12

Sync with staging

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added file '.bazaar/plugins/packaging_sorting.py'
2--- .bazaar/plugins/packaging_sorting.py 1970-01-01 00:00:00 +0000
3+++ .bazaar/plugins/packaging_sorting.py 2016-04-12 11:09:51 +0000
4@@ -0,0 +1,46 @@
5+#!/usr/bin/python
6+# Copyright 2016 Canonical Ltd.
7+#
8+# This program is free software; you can redistribute it and/or modify
9+# it under the terms of the GNU Lesser General Public License as published by
10+# the Free Software Foundation; version 3.
11+#
12+# This program is distributed in the hope that it will be useful,
13+# but WITHOUT ANY WARRANTY; without even the implied warranty of
14+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+# GNU Lesser General Public License for more details.
16+#
17+# You should have received a copy of the GNU Lesser General Public License
18+# along with this program. If not, see <http://www.gnu.org/licenses/>.
19+#
20+# Author: Timo Jyrinki <timo.jyrinki@canonical.com>
21+
22+from bzrlib import branch
23+from bzrlib import errors
24+import os
25+import subprocess
26+
27+def pre_commit_hook(local, master, old_revno, old_revid, future_revno,
28+ future_revid, tree_delta, future_tree):
29+ """Ensure packaging has gone through wrap-and-sort command"""
30+
31+ if (master.get_parent().find("ubuntu-ui-toolkit") == -1):
32+ return
33+
34+ if not os.path.exists("/usr/bin/wrap-and-sort"):
35+ raise errors.BzrError("Please install 'devscripts' package.")
36+ return
37+
38+ subprocess.call(["cp", "-a", "debian", "debian-packaging-wraptest-temporary"])
39+
40+ subprocess.call(["wrap-and-sort", "-a", "-t"])
41+
42+ returncode = subprocess.call(["diff", "-urN",
43+ "debian-packaging-wraptest-temporary", "debian"])
44+ if returncode == 1:
45+ subprocess.call(["rm", "-rf", "debian-packaging-wraptest-temporary"])
46+ raise errors.BzrError("Please run wrap-and-sort -a -t to clean up packaging.")
47+
48+ subprocess.call(["rm", "-rf", "debian-packaging-wraptest-temporary"])
49+
50+branch.Branch.hooks.install_named_hook("pre_commit", pre_commit_hook, "Check packaging sorting")
51
52=== modified file 'components.api'
53--- components.api 2016-03-30 13:42:32 +0000
54+++ components.api 2016-04-12 11:09:51 +0000
55@@ -826,14 +826,18 @@
56 readonly property ActionBar leadingActionBar
57 property list<Action> navigationActions
58 readonly property Sections sections
59+ property string subtitle
60 property string title
61 readonly property ActionBar trailingActionBar
62 Ubuntu.Components.Styles.PageHeaderStyle 1.3: Item
63 property color backgroundColor
64 property double contentHeight
65 property Component defaultActionDelegate
66+ property color disabledForegroundColor
67 property color dividerColor
68 property color foregroundColor
69+ property color subtitleColor
70+ property Component subtitleComponent
71 property Component titleComponent
72 Ubuntu.Components.PageStack 1.0 0.1: PageTreeNode
73 property Item currentPage
74
75=== modified file 'debian/bileto_convert_to_gles'
76--- debian/bileto_convert_to_gles 2016-04-06 20:16:20 +0000
77+++ debian/bileto_convert_to_gles 2016-04-12 11:09:51 +0000
78@@ -12,6 +12,6 @@
79
80 sed --in-place 's/^ubuntu-ui-toolkit /ubuntu-ui-toolkit-gles /g' debian/changelog
81
82-for gles in libubuntutoolkit5-gles-dev.install libubuntugestures5-gles-dev.install libubuntugestures5-gles.install libubuntutoolkit5-gles.install qml-module-ubuntu-components-gles.install qml-module-ubuntu-components-gles.lintian-overrides; do
83+for gles in libubuntugestures5-gles.install libubuntugestures5-gles-dev.install libubuntutoolkit5-gles.install libubuntutoolkit5-gles-dev.install qml-module-ubuntu-components-gles.install qml-module-ubuntu-components-gles.lintian-overrides qml-module-ubuntu-performancemetrics-gles.install ; do
84 mv --verbose debian/"$(echo $gles | sed 's/-gles//')" debian/$gles
85 done
86
87=== modified file 'debian/changelog'
88--- debian/changelog 2016-04-08 15:23:50 +0000
89+++ debian/changelog 2016-04-12 11:09:51 +0000
90@@ -1,3 +1,46 @@
91+ubuntu-ui-toolkit (1.3.1938+16.04) UNRELEASED; urgency=medium
92+
93+ [ Tim Peeters ]
94+ * Hide the PageStack back button when depth == 1. Fixes LP: #1565811
95+ * Add header subtitle. Fixes LP: #1399289
96+ * Reveal the header in gallery when changing the layout to two columns.
97+ Fixes LP: #1556860
98+ * Set correct colors for disabled actions in the header.
99+ Fixes LP: #1393485
100+ * Disable tst_datepicker.qml to unblock the staging.Fixes LP: #1567840
101+ * Prevent invisible header from setting the flickable topMargin.
102+ Fixes LP: #1560419, LP: #1560458, LP: #1566231.
103+
104+ [ Zsombor Egri ]
105+ * Move MouseTouchAdaptor into UbuntuToolkit library. Fix adaptor code for
106+ Xenial. Fixes LP: #1561436
107+
108+ [ Christian Dywan ]
109+ * Don't use a separate argument to distinguish touch events. If it's touch,
110+ it has our overloaded methods. Fixes LP: #1530802
111+ * Use export_qml_dir.sh in qmlapicheck and runtest Also add Usage to runtest.
112+ Fixes LP: #1567286.
113+ * Summary style error results with sections. Fixes LP: #1568804
114+
115+ [ Andrea Bernabei ]
116+ * Mouse filter: check if mouse is inside the area on mouse moves and
117+ setHovered accordingly. Fixes LP: #1566378.
118+
119+ [ Timo Jyrinki ]
120+ * Add latest changes for GLES.
121+ * Add back Provides: qtdeclarative5-ubuntu-ui-toolkit-plugin to resolve
122+ upgrade issue. Fixes LP: #1568817
123+ * Fix wrapper script auto-generated by Qt that incorrectly tries to execute
124+ itself. Fixes LP: #1560000
125+ * bileto_convert_to_gles: sort and add
126+ qml-module-ubuntu-performancemetrics-gles.install. Fixes LP: #1569217
127+
128+
129+ [ Zolán Balogh ]
130+ * Fix the UITK test plan script.
131+
132+ -- Zoltán Balogh <zoltan@bakter.hu> Fri, 08 Apr 2016 20:28:19 +0300
133+
134 ubuntu-ui-toolkit (1.3.1918+16.04.20160404-0ubuntu1) xenial; urgency=medium
135
136 [ Benjamin Zeller ]
137
138=== modified file 'debian/control'
139--- debian/control 2016-04-08 14:07:07 +0000
140+++ debian/control 2016-04-12 11:09:51 +0000
141@@ -22,6 +22,9 @@
142 libqt5sql5-sqlite,
143 libqt5svg5-dev,
144 libudev-dev,
145+ libx11-dev[!armhf],
146+ libxcb1-dev[!armhf],
147+ libxi-dev[!armhf],
148 libxkbcommon-dev,
149 libxrender-dev,
150 locales,
151
152=== modified file 'debian/control.gles'
153--- debian/control.gles 2016-04-08 18:12:17 +0000
154+++ debian/control.gles 2016-04-12 11:09:51 +0000
155@@ -87,6 +87,7 @@
156 qtdeclarative5-ubuntu-ui-toolkit-plugin,
157 qtdeclarative5-ubuntu-ui-toolkit-plugin-gles (<< ${source:Version}),
158 Provides: qml-module-ubuntu-components,
159+ qtdeclarative5-ubuntu-ui-toolkit-plugin,
160 Multi-Arch: same
161 Pre-Depends: dpkg (>= 1.15.6~),
162 ${misc:Pre-Depends},
163
164=== modified file 'debian/libubuntutoolkit5-dev.install'
165--- debian/libubuntutoolkit5-dev.install 2016-03-04 11:58:12 +0000
166+++ debian/libubuntutoolkit5-dev.install 2016-04-12 11:09:51 +0000
167@@ -1,11 +1,13 @@
168 usr/include/*/qt5/UbuntuToolkit/AsyncLoader
169 usr/include/*/qt5/UbuntuToolkit/ColorUtils
170+usr/include/*/qt5/UbuntuToolkit/MouseTouchAdaptor
171 usr/include/*/qt5/UbuntuToolkit/Tree
172 usr/include/*/qt5/UbuntuToolkit/UbuntuToolkit
173 usr/include/*/qt5/UbuntuToolkit/UbuntuToolkitDepends
174 usr/include/*/qt5/UbuntuToolkit/UbuntuToolkitVersion
175 usr/include/*/qt5/UbuntuToolkit/asyncloader.h
176 usr/include/*/qt5/UbuntuToolkit/colorutils.h
177+usr/include/*/qt5/UbuntuToolkit/mousetouchadaptor.h
178 usr/include/*/qt5/UbuntuToolkit/tree.h
179 usr/include/*/qt5/UbuntuToolkit/ubuntutoolkitglobal.h
180 usr/include/*/qt5/UbuntuToolkit/ubuntutoolkitversion.h
181
182=== modified file 'examples/ubuntu-ui-toolkit-gallery/MainPage.qml'
183--- examples/ubuntu-ui-toolkit-gallery/MainPage.qml 2016-02-29 16:09:02 +0000
184+++ examples/ubuntu-ui-toolkit-gallery/MainPage.qml 2016-04-12 11:09:51 +0000
185@@ -24,6 +24,8 @@
186 header: PageHeader {
187 title: mainPage.title
188 flickable: layout.columns === 1 ? widgetList : null
189+ // avoid header staying hidden when resizing back to two columns, bug #1556860
190+ onFlickableChanged: exposed = true
191 trailingActionBar.actions: [
192 Action {
193 text: i18n.tr('Right to Left')
194
195=== modified file 'export_qml_dir.sh'
196--- export_qml_dir.sh 2016-03-21 17:51:44 +0000
197+++ export_qml_dir.sh 2016-04-12 11:09:51 +0000
198@@ -26,6 +26,8 @@
199 UBUNTU_QML_ROOT=$BUILD_DIR/qml/Ubuntu
200 UBUNTU_QML_DIRS=$UBUNTU_QML_ROOT/Components:$UBUNTU_QML_ROOT/Test:$UBUNTU_QML_ROOT/Layouts:$UBUNTU_QML_ROOT/PerformanceMetrics
201 export LD_LIBRARY_PATH=$BUILD_DIR/lib:$UBUNTU_QML_DIRS$LD_LIBRARY_PATH
202+# Build machines may not have initctl and don't need it
203+test -f /sbin/initctl || return 0
204 /sbin/initctl set-env --global QML_IMPORT_PATH=$BUILD_DIR/qml
205 /sbin/initctl set-env --global QML2_IMPORT_PATH=$BUILD_DIR/qml
206 /sbin/initctl set-env --global UBUNTU_UI_TOOLKIT_THEMES_PATH=$BUILD_DIR/qml
207
208=== modified file 'features/ubuntu_qml_plugin.prf'
209--- features/ubuntu_qml_plugin.prf 2016-01-12 13:48:53 +0000
210+++ features/ubuntu_qml_plugin.prf 2016-04-12 11:09:51 +0000
211@@ -46,9 +46,12 @@
212 ld_lib_path.value += $$shell_path($$ROOT_BUILD_DIR/lib)
213 ld_lib_path.value = $$unique(ld_lib_path.value)
214
215- qtAddToolEnv(QMLPLUGINDUMP, importpath)
216- qtAddToolEnv(QMLPLUGINDUMP, membackend)
217- qtAddToolEnv(QMLPLUGINDUMP, ld_lib_path)
218+
219+ QMLPLUGINDUMP_ENV_VARS = importpath \
220+ membackend \
221+ ld_lib_path
222+
223+ qtAddToolEnv(QMLPLUGINDUMP, $$QMLPLUGINDUMP_ENV_VARS)
224
225 TARGETPATHBASE = $$replace(TARGETPATH, \\.\\d+\$, )
226
227
228=== modified file 'src/Ubuntu/Components/1.3/InputHandler.qml'
229--- src/Ubuntu/Components/1.3/InputHandler.qml 2015-11-20 15:18:50 +0000
230+++ src/Ubuntu/Components/1.3/InputHandler.qml 2016-04-12 11:09:51 +0000
231@@ -147,7 +147,7 @@
232 return p;
233 }
234 // focuses the input if not yet focused, and shows the context menu
235- function openContextMenu(mouse, noAutoselect, fromTouch) {
236+ function openContextMenu(mouse, noAutoselect) {
237 var pos = mousePosition(mouse);
238 if (!main.focus || !mouseInSelection(mouse)) {
239 activateInput();
240@@ -157,7 +157,7 @@
241 }
242 }
243 // open context menu at the cursor position
244- inputHandler.pressAndHold(input.cursorPosition, fromTouch);
245+ inputHandler.pressAndHold(input.cursorPosition, mouse.touch);
246 // if opened with left press (touch falls into this criteria as well), we need to set state to inactive
247 // so the mouse moves won't result in selected text loss/change
248 if (mouse.button === Qt.LeftButton) {
249@@ -341,8 +341,8 @@
250 }
251
252 // touch and mous handling
253- function handlePressed(event, touch) {
254- if (touch) {
255+ function handlePressed(event) {
256+ if (event.touch) {
257 // we do not have longTap or double tap, therefore we need to generate those
258 event.touch();
259 } else {
260@@ -352,8 +352,8 @@
261 // remember pressed position as we need it when entering into selection state
262 pressedPosition = mousePosition(event);
263 }
264- function handleReleased(event, touch) {
265- if (touch) {
266+ function handleReleased(event) {
267+ if (event.touch) {
268 event.untouch();
269 }
270 if ((!main.focus && !main.activeFocusOnPress) || suppressReleaseEvent === true) {
271@@ -362,7 +362,7 @@
272 }
273
274 activateInput();
275- if (state === "" || touch) {
276+ if (state === "" || event.touch) {
277 input.cursorPosition = mousePosition(event);
278 }
279 moveStarts = moveEnds = -1;
280@@ -370,21 +370,21 @@
281 // check if we get right-click from the frame or the area that has no text
282 if (event.button === Qt.RightButton) {
283 // open the popover
284- inputHandler.pressAndHold(input.cursorPosition, touch);
285+ inputHandler.pressAndHold(input.cursorPosition, event.touch);
286 } else {
287 inputHandler.tap(input.cursorPosition);
288 }
289 }
290- function handleMove(event, touch ) {
291+ function handleMove(event) {
292 // leave if not focus, not the left button or not in select state
293- if (!input.activeFocus || (!touch && event.button !== Qt.LeftButton) || !main.selectByMouse) {
294+ if (!input.activeFocus || (!event.touch && event.button !== Qt.LeftButton) || !main.selectByMouse) {
295 return;
296 }
297 selectText(event);
298 }
299- function handleDblClick(event, touch) {
300+ function handleDblClick(event) {
301 if (main.selectByMouse) {
302- openContextMenu(event, false, touch);
303+ openContextMenu(event, false);
304 // turn selection state temporarily so the selection is not cleared on release
305 state = "selection";
306 suppressReleaseEvent = true;
307@@ -393,17 +393,17 @@
308
309 // Mouse handling
310 Mouse.forwardTo: [main]
311- Mouse.onPressed: handlePressed(mouse, false)
312- Mouse.onReleased: handleReleased(mouse, false)
313- Mouse.onPositionChanged: handleMove(mouse, false)
314- Mouse.onDoubleClicked: handleDblClick(mouse, false)
315+ Mouse.onPressed: handlePressed(mouse)
316+ Mouse.onReleased: handleReleased(mouse)
317+ Mouse.onPositionChanged: handleMove(mouse)
318+ Mouse.onDoubleClicked: handleDblClick(mouse)
319
320 // right button handling
321 MouseArea {
322 anchors.fill: parent
323 acceptedButtons: Qt.RightButton
324 // trigger pressAndHold
325- onReleased: openContextMenu(mouse, true, false)
326+ onReleased: openContextMenu(mouse, true)
327 cursorShape: Qt.IBeamCursor
328 }
329 Keys.onMenuPressed: inputHandler.pressAndHold(input.cursorPosition, false);
330@@ -442,7 +442,7 @@
331 if (touchPoint.startY - touchPoint.y < -units.gu(2))
332 return;
333
334- openContextMenu(touchPoint, false, true);
335+ openContextMenu(touchPoint, false);
336 suppressReleaseEvent = true;
337 }
338 }
339@@ -456,8 +456,8 @@
340 tapCount = running;
341 }
342 }
343- onPressed: handlePressed(touchPoints[0], true)
344- onReleased: handleReleased(touchPoints[0], true)
345+ onPressed: handlePressed(touchPoints[0])
346+ onReleased: handleReleased(touchPoints[0])
347
348 property Item cursorPositionCursor: null
349 property Item selectionStartCursor: null
350
351=== modified file 'src/Ubuntu/Components/1.3/Page.qml'
352--- src/Ubuntu/Components/1.3/Page.qml 2016-02-15 14:17:32 +0000
353+++ src/Ubuntu/Components/1.3/Page.qml 2016-04-12 11:09:51 +0000
354@@ -162,19 +162,16 @@
355 }
356
357 property Item previousHeader: null
358- property Item previousHeaderParent: null
359 function updateHeader() {
360 internal.showDeprecationWarning = false;
361 if (internal.previousHeader) {
362- internal.previousHeader.parent = internal.previousHeaderParent;
363+ internal.previousHeader.parent = null;
364 }
365 if (page.header) {
366- internal.previousHeaderParent = page.header.parent;
367 internal.previousHeader = page.header;
368 page.header.parent = page;
369 } else {
370 internal.previousHeader = null;
371- internal.previousHeaderParent = null;
372 }
373 }
374
375
376=== modified file 'src/Ubuntu/Components/1.3/PageHeader.qml'
377--- src/Ubuntu/Components/1.3/PageHeader.qml 2016-02-02 13:49:50 +0000
378+++ src/Ubuntu/Components/1.3/PageHeader.qml 2016-04-12 11:09:51 +0000
379@@ -54,9 +54,14 @@
380 property string title
381
382 /*!
383- The contents item to display in the header. By default the contents
384- is undefined, and setting it will disable showing of the title in
385- the header.
386+ Displayed under the title.
387+ Hidden when the \l contents Item is set.
388+ */
389+ property string subtitle
390+
391+ /*!
392+ The contents item to display in the header. By default the contents is
393+ undefined, and setting it will disable showing of the title and subtitle.
394
395 Example:
396 \qml
397@@ -79,6 +84,7 @@
398
399 Component.onCompleted: contentsHolder.updateContents()
400 onContentsChanged: contentsHolder.updateContents()
401+ onSubtitleChanged: contentsHolder.updateContents()
402
403 Item {
404 id: contentsHolder
405@@ -94,6 +100,11 @@
406 id: titleLoader
407 anchors.fill: parent
408 }
409+ Loader {
410+ id: subtitleLoader
411+ anchors.fill: parent
412+ }
413+
414 property Item previousContents: null
415 property Item previousContentsParent: null
416
417@@ -110,6 +121,11 @@
418 previousContents = null;
419 previousContentsParent = null;
420 titleLoader.sourceComponent = __styleInstance.titleComponent;
421+ if (!subtitle) {
422+ subtitleLoader.sourceComponent = null;
423+ } else {
424+ subtitleLoader.sourceComponent = __styleInstance.subtitleComponent;
425+ }
426 }
427 }
428
429
430=== modified file 'src/Ubuntu/Components/1.3/PageStack.qml'
431--- src/Ubuntu/Components/1.3/PageStack.qml 2016-02-08 13:55:17 +0000
432+++ src/Ubuntu/Components/1.3/PageStack.qml 2016-04-12 11:09:51 +0000
433@@ -218,14 +218,13 @@
434 Action {
435 // used when the Page has a Page.header property set.
436 id: backAction
437- visible: pageStack.depth > 0
438+ visible: pageStack.depth > 1
439 iconName: "back"
440 text: "Back"
441 onTriggered: pageStack.pop()
442 objectName: "pagestack_back_action"
443 }
444
445-
446 Component {
447 id: pageWrapperComponent
448 PageWrapper{
449
450=== modified file 'src/Ubuntu/Components/Styles/1.3/PageHeaderStyle.qml'
451--- src/Ubuntu/Components/Styles/1.3/PageHeaderStyle.qml 2015-11-27 14:59:03 +0000
452+++ src/Ubuntu/Components/Styles/1.3/PageHeaderStyle.qml 2016-04-12 11:09:51 +0000
453@@ -1,5 +1,5 @@
454 /*
455- * Copyright 2015 Canonical Ltd.
456+ * Copyright 2016 Canonical Ltd.
457 *
458 * This program is free software; you can redistribute it and/or modify
459 * it under the terms of the GNU Lesser General Public License as published by
460@@ -30,6 +30,16 @@
461 property color foregroundColor
462
463 /*!
464+ The color of disabled action buttons in the header.
465+ */
466+ property color disabledForegroundColor
467+
468+ /*!
469+ The color of the (optional) subtitle.
470+ */
471+ property color subtitleColor
472+
473+ /*!
474 The color of the background of the header.
475 */
476 property color backgroundColor
477@@ -51,6 +61,11 @@
478 property Component titleComponent
479
480 /*!
481+ The default component to display the subtitle.
482+ */
483+ property Component subtitleComponent
484+
485+ /*!
486 The height of the header excluding the divider and extension.
487 */
488 property real contentHeight
489
490=== modified file 'src/Ubuntu/Components/Themes/Ambiance/1.3/OverflowPanel.qml'
491--- src/Ubuntu/Components/Themes/Ambiance/1.3/OverflowPanel.qml 2016-01-27 16:42:47 +0000
492+++ src/Ubuntu/Components/Themes/Ambiance/1.3/OverflowPanel.qml 2016-04-12 11:09:51 +0000
493@@ -42,9 +42,12 @@
494 /*!
495 The foreground color (icon and text) of actions in the panel.
496 */
497- property color foregroundColor: styledItem.enabled
498- ? theme.palette.normal.backgroundText
499- : theme.palette.disabled.backgroundText
500+ property color foregroundColor: theme.palette.normal.backgroundText
501+
502+ /*!
503+ The foreground color (icon and text) of disabled actions in the panel.
504+ */
505+ property color disabledForegroundColor: theme.palette.disabled.backgroundText
506
507 property bool square: true
508 callerMargin: -units.gu(1) + units.dp(4)
509@@ -83,7 +86,8 @@
510 id: actionIcon
511 visible: "" != action.iconSource
512 source: action.iconSource
513- color: overflow.foregroundColor
514+ color: enabled ? overflow.foregroundColor
515+ : overflow.disabledForegroundColor
516 anchors {
517 verticalCenter: parent.verticalCenter
518 verticalCenterOffset: units.dp(-1)
519@@ -107,7 +111,8 @@
520 textSize: actionIcon.visible ? Label.Small : Label.Medium
521 elide: Text.ElideRight
522 text: action.text
523- color: overflow.foregroundColor
524+ color: enabled ? overflow.foregroundColor
525+ : overflow.disabledForegroundColor
526 }
527
528 // The value of showDivider is automatically set by ActionSelectionPopover.
529
530=== modified file 'src/Ubuntu/Components/Themes/Ambiance/1.3/PageHeaderStyle.qml'
531--- src/Ubuntu/Components/Themes/Ambiance/1.3/PageHeaderStyle.qml 2016-02-29 16:02:50 +0000
532+++ src/Ubuntu/Components/Themes/Ambiance/1.3/PageHeaderStyle.qml 2016-04-12 11:09:51 +0000
533@@ -22,51 +22,119 @@
534 id: pageHeaderStyle
535
536 foregroundColor: theme.palette.normal.backgroundText
537+ disabledForegroundColor: theme.palette.disabled.backgroundText
538+ subtitleColor: theme.palette.normal.backgroundTertiaryText
539 backgroundColor: theme.palette.normal.background
540 dividerColor: theme.palette.normal.base
541+
542+ // Font weight for the title and subtitle
543 property int fontWeight: Font.Light
544+
545+ // Text size for title
546 property int textSize: Label.Large
547
548- // reduced content height on a phone in landscape mode
549- contentHeight: Screen.height > units.gu(50) ? units.gu(6) : units.gu(5)
550+ // Text size for subtitle
551+ property int subTextSize: internal.landscape ? Label.Small : Label.Medium
552+
553+ contentHeight: internal.titleAreaHeight + internal.titleBottomSpacing
554 implicitHeight: contentHeight + divider.height + internal.extensionHeight
555
556+ Component.onCompleted: internal.updateHeights()
557 Object {
558 id: internal
559- property real extensionHeight: styledItem.extension ?
560- styledItem.extension.height
561+ property real extensionHeight: styledItem.extension
562+ ? styledItem.extension.height
563 : styledItem.sections.height
564+
565+ property bool landscape: Screen.height <= units.gu(50)
566+ property bool hasSubtitle: styledItem.subtitle && !styledItem.contents
567+ property bool hasExtension: styledItem.extension
568+
569+ // The height of the area in which the title and icons are vertically centered
570+ property real titleAreaHeight
571+ // Add to the content height for additional space under the title
572+ property real titleBottomSpacing
573+
574+ onLandscapeChanged: updateHeights()
575+ onHasSubtitleChanged: updateHeights()
576+ onHasExtensionChanged: updateHeights()
577+
578+ function updateHeights() {
579+ if (landscape) {
580+ if (hasSubtitle) {
581+ // with subtitle, and with or without extension
582+ titleAreaHeight = units.gu(4);
583+ titleBottomSpacing = units.gu(2);
584+ } else if (hasExtension) {
585+ titleAreaHeight = units.gu(4);
586+ titleBottomSpacing = units.gu(1);
587+ } else {
588+ titleAreaHeight = units.gu(5)
589+ titleBottomSpacing = 0;
590+ }
591+ } else { // portrait
592+ titleAreaHeight = units.gu(6);
593+ if (hasSubtitle) {
594+ titleBottomSpacing = units.gu(1);
595+ } else {
596+ titleBottomSpacing = 0;
597+ }
598+ }
599+ }
600 }
601
602 defaultActionDelegate: AbstractButton {
603 style: IconButtonStyle { }
604 objectName: action.objectName + "_button"
605- height: parent ? parent.height : undefined
606+ height: internal.titleAreaHeight
607 action: modelData
608 StyleHints {
609- // FIXME: introduce inactiveForegroundColor to PageHeaderStyle
610- foregroundColor: pageHeaderStyle.foregroundColor
611- }
612- }
613-
614- titleComponent: Item {
615- // The wrapping inside the extra Item is needed to
616- // be able to position the Label vertically. Without it,
617- // the Loader resizes the Label to span the full height.
618- Label {
619- id: titleLabel
620- objectName: "header_title_label"
621- text: styledItem.title
622-
623- anchors {
624- left: parent.left
625- right: parent.right
626- verticalCenter: parent.verticalCenter
627- }
628- color: pageHeaderStyle.foregroundColor
629- font.weight: pageHeaderStyle.fontWeight
630- textSize: pageHeaderStyle.textSize
631- elide: Text.ElideRight
632+ foregroundColor: enabled ? pageHeaderStyle.foregroundColor
633+ : pageHeaderStyle.disabledForegroundColor
634+ }
635+ }
636+
637+ titleComponent: Component {
638+ Item {
639+ // The wrapping inside the extra Item is needed to
640+ // be able to position the Label vertically. Without it,
641+ // the Loader resizes the Label to span the full height.
642+ Label {
643+ id: titleLabel
644+ objectName: "header_title_label"
645+ text: styledItem.title
646+
647+ anchors {
648+ left: parent.left
649+ right: parent.right
650+ verticalCenter: parent.verticalCenter
651+ verticalCenterOffset: -internal.titleBottomSpacing/2
652+ }
653+ color: pageHeaderStyle.foregroundColor
654+ font.weight: pageHeaderStyle.fontWeight
655+ textSize: pageHeaderStyle.textSize
656+ elide: Text.ElideRight
657+ }
658+ }
659+ }
660+
661+ subtitleComponent: Component {
662+ Item {
663+ // Item fills the contents height
664+ Label {
665+ anchors {
666+ left: parent.left
667+ right: parent.right
668+ baseline: parent.bottom
669+ baselineOffset: -units.gu(1)
670+ }
671+ objectName: "header_subtitle_label"
672+ text: styledItem.subtitle
673+ color: pageHeaderStyle.subtitleColor
674+ visible: text != ""
675+ textSize: pageHeaderStyle.subTextSize
676+ font.weight: pageHeaderStyle.fontWeight
677+ }
678 }
679 }
680
681
682=== modified file 'src/Ubuntu/Components/plugin/ucheader.cpp'
683--- src/Ubuntu/Components/plugin/ucheader.cpp 2016-02-15 13:19:05 +0000
684+++ src/Ubuntu/Components/plugin/ucheader.cpp 2016-04-12 11:09:51 +0000
685@@ -21,8 +21,6 @@
686 #include <QtQuick/private/qquickanimation_p.h>
687 #include "ucubuntuanimation.h"
688 #include "ucunits.h"
689-#include "propertychange_p.h"
690-
691
692 /*!
693 \qmltype Header
694@@ -79,8 +77,8 @@
695 : UCStyledItemBase(parent)
696 , m_flickable(Q_NULLPTR)
697 , m_showHideAnimation(new QQuickNumberAnimation)
698- , m_flickableTopMarginBackup(Q_NULLPTR)
699 , m_previous_contentY(0)
700+ , m_previous_header_height(0)
701 , m_exposed(true)
702 , m_moving(false)
703 {
704@@ -97,8 +95,7 @@
705
706 UCHeader::~UCHeader() {
707 if (m_flickable != Q_NULLPTR) {
708- Q_ASSERT(m_flickableTopMarginBackup != Q_NULLPTR);
709- delete m_flickableTopMarginBackup;
710+ m_flickable->setTopMargin(m_flickable->topMargin() - m_previous_header_height);
711 }
712 }
713
714@@ -116,6 +113,13 @@
715 }
716 }
717
718+void UCHeader::itemChange(ItemChange change, const ItemChangeData &value) {
719+ if (change == ItemVisibleHasChanged || change == ItemParentHasChanged) {
720+ updateFlickableMargins();
721+ }
722+ UCStyledItemBase::itemChange(change, value);
723+}
724+
725 /*!
726 * \qmlproperty Flickable Header::flickable
727 *
728@@ -127,10 +131,45 @@
729 *
730 * When flickable is null, the header can be exposed or
731 * hidden by setting the \l exposed property.
732+ * Note that \l exposed is not automatically updated when the value of flickable
733+ * changes, so if the header must be exposed when the flickable changes
734+ * (or is set to null), this must be done explicitly. Example:
735+ * \qml
736+ * import QtQuick 2.4
737+ * import Ubuntu.Components 1.3
738+ *
739+ * MainView {
740+ * width: units.gu(60)
741+ * height: units.gu(80)
742+ *
743+ * AdaptivePageLayout {
744+ * id: layout
745+ * anchors.fill: parent
746+ * primaryPage: Page {
747+ * id: page
748+ * Flickable {
749+ * id: contentFlick
750+ * anchors.fill: parent
751+ * topMargin: page.header.flickable ? 0 : page.header.height
752+ * contentHeight: units.gu(200)
753+ * // Scrolling here can hide the header.
754+ * }
755+ * header: PageHeader {
756+ * title: i18n.tr("Navigation")
757+ * flickable: layout.columns === 1 ? contentFlick : null
758+ * // Show header when it gets locked in a two-column layout:
759+ * onFlickableChanged: exposed = true
760+ * }
761+ * }
762+ * }
763+ * }
764+ * \endqml
765 *
766 * The topMargin of the flickable will automatically be updated to always match
767 * the height of the header. When changing the flickable, the topMargin of the previous
768- * flickable is set to 0.
769+ * flickable is set to 0. When the header is invisible because its visible property is
770+ * false, or the header has no parent, the flickable topMargin does not reflect the
771+ * header height.
772 *
773 * It is permitted to use a ListView as the value of flickable, but this works
774 * well only if the ListView.header property is not set. Alternatively,
775@@ -146,8 +185,6 @@
776 return;
777 }
778 if (!m_flickable.isNull()) {
779- Q_ASSERT(m_flickableTopMarginBackup != Q_NULLPTR);
780-
781 // Finish the current header movement in case the current
782 // flickable is disconnected while scrolling.
783 if (m_exposed) {
784@@ -157,23 +194,24 @@
785 }
786 m_flickable->disconnect(this);
787
788- qreal oldMargin = m_flickable->topMargin();
789- // store contentY to compensate for Flickable updating the position due to margin change.
790- qreal oldContentY = m_flickable->contentY();
791- delete m_flickableTopMarginBackup; // Restores previous value/binding for topMargin.
792- m_flickableTopMarginBackup = Q_NULLPTR;
793+ // store the current sum of the topMargin and contentY so that we
794+ // can add the change in topMargin+contentY to the new contentY after
795+ // updating the topMargin so that the user will still see the same
796+ // flickable contents at the top of the view after the header height changed.
797+ qreal delta = m_flickable->topMargin() + m_flickable->contentY();
798+ m_flickable->setTopMargin(m_flickable->topMargin() - m_previous_header_height);
799+ m_previous_header_height = 0;
800+ delta -= m_flickable->topMargin() + m_flickable->contentY();
801
802- qreal delta = m_flickable->topMargin() - oldMargin + m_flickable->contentY() - oldContentY;
803 // revert the flickable content Y.
804- m_flickable->setContentY(m_flickable->contentY() - delta);
805+ m_flickable->setContentY(m_flickable->contentY() + delta);
806 }
807
808 m_flickable = flickable;
809 Q_EMIT flickableChanged();
810
811- Q_ASSERT(m_flickableTopMarginBackup == Q_NULLPTR);
812+ Q_ASSERT(m_previous_header_height == 0);
813 if (!m_flickable.isNull()) {
814- m_flickableTopMarginBackup = new PropertyChange(m_flickable, "topMargin");
815 updateFlickableMargins();
816 connect(m_flickable, SIGNAL(contentYChanged()),
817 this, SLOT(_q_scrolledContents()));
818@@ -192,14 +230,17 @@
819 if (m_flickable.isNull()) {
820 return;
821 }
822- qreal headerHeight = height();
823- qreal previousHeaderHeight = m_flickable->topMargin();
824- if (headerHeight != previousHeaderHeight) {
825+ qreal headerHeight = 0.0;
826+ if (isVisible() && parentItem()) {
827+ headerHeight = height();
828+ } // else: header is not visible, so do not add to the topMargin.
829+ if (headerHeight != m_previous_header_height) {
830 qreal previousContentY = m_flickable->contentY();
831- PropertyChange::setValue(m_flickableTopMarginBackup, headerHeight);
832+ m_flickable->setTopMargin(m_flickable->topMargin() + headerHeight - m_previous_header_height);
833 // Push down contents when header grows,
834 // pull up contents when header shrinks.
835- m_flickable->setContentY(previousContentY - headerHeight + previousHeaderHeight);
836+ m_flickable->setContentY(previousContentY - headerHeight + m_previous_header_height);
837+ m_previous_header_height = headerHeight;
838 }
839 }
840
841
842=== modified file 'src/Ubuntu/Components/plugin/ucheader.h'
843--- src/Ubuntu/Components/plugin/ucheader.h 2016-02-02 12:17:58 +0000
844+++ src/Ubuntu/Components/plugin/ucheader.h 2016-04-12 11:09:51 +0000
845@@ -23,7 +23,6 @@
846 class QQuickFlickable;
847 class QQuickNumberAnimation;
848 class UCUbuntuAnimation;
849-class PropertyChange;
850
851 class UCHeader : public UCStyledItemBase
852 {
853@@ -49,6 +48,7 @@
854 protected:
855 virtual void show(bool animate);
856 virtual void hide(bool animate);
857+ virtual void itemChange(ItemChange change, const ItemChangeData &value);
858
859 private Q_SLOTS:
860 void _q_scrolledContents();
861@@ -61,9 +61,9 @@
862 private:
863 QPointer<QQuickFlickable> m_flickable;
864 QQuickNumberAnimation* m_showHideAnimation;
865- PropertyChange* m_flickableTopMarginBackup;
866
867 qreal m_previous_contentY;
868+ qreal m_previous_header_height;
869 bool m_exposed:1;
870 bool m_moving:1;
871
872
873=== modified file 'src/Ubuntu/Components/plugin/ucmousefilters.cpp'
874--- src/Ubuntu/Components/plugin/ucmousefilters.cpp 2016-01-30 12:03:31 +0000
875+++ src/Ubuntu/Components/plugin/ucmousefilters.cpp 2016-04-12 11:09:51 +0000
876@@ -608,7 +608,8 @@
877 m_pressAndHoldTimer.stop();
878 }
879
880- setHovered(true, 0);
881+ setHovered(m_owner->contains(m_lastPos), Q_NULLPTR);
882+
883 m_moved = true;
884 m_doubleClicked = false;
885 QQuickMouseEvent mev(m_lastPos.x(), m_lastPos.y(), m_lastButton, m_lastButtons, m_lastModifiers,
886
887=== modified file 'src/Ubuntu/Test/plugin/plugin.pri'
888--- src/Ubuntu/Test/plugin/plugin.pri 2016-02-25 02:29:05 +0000
889+++ src/Ubuntu/Test/plugin/plugin.pri 2016-04-12 11:09:51 +0000
890@@ -1,4 +1,4 @@
891-QT *= core-private qml qml-private quick quick-private gui-private testlib UbuntuGestures
892+QT *= core-private qml qml-private quick quick-private gui-private testlib UbuntuGestures UbuntuToolkit
893
894 equals(QT_MAJOR_VERSION, 5):lessThan(QT_MINOR_VERSION, 2) {
895 QT *= v8-private
896@@ -15,11 +15,9 @@
897 HEADERS += \
898 $$PWD/uctestcase.h \
899 $$PWD/testplugin.h \
900- $$PWD/uctestextras.h \
901- $$PWD/ucmousetouchadaptor.h \
902+ $$PWD/uctestextras.h
903
904 SOURCES += \
905 $$PWD/uctestcase.cpp \
906 $$PWD/testplugin.cpp \
907- $$PWD/uctestextras.cpp \
908- $$PWD/ucmousetouchadaptor.cpp \
909+ $$PWD/uctestextras.cpp
910
911=== modified file 'src/Ubuntu/Test/plugin/testplugin.cpp'
912--- src/Ubuntu/Test/plugin/testplugin.cpp 2015-10-21 08:33:21 +0000
913+++ src/Ubuntu/Test/plugin/testplugin.cpp 2016-04-12 11:09:51 +0000
914@@ -1,5 +1,5 @@
915 /*
916- * Copyright 2014 Canonical Ltd.
917+ * Copyright 2016 Canonical Ltd.
918 *
919 * This program is free software; you can redistribute it and/or modify
920 * it under the terms of the GNU Lesser General Public License as published by
921@@ -17,7 +17,7 @@
922 #include "testplugin.h"
923 #include <QtQml>
924 #include "uctestextras.h"
925-#include "ucmousetouchadaptor.h"
926+#include <MouseTouchAdaptor>
927
928 static QObject *registerExtras(QQmlEngine *engine, QJSEngine *scriptEngine)
929 {
930@@ -27,16 +27,8 @@
931 return new UCTestExtras;
932 }
933
934-static QObject *registerAdaptor(QQmlEngine *engine, QJSEngine *scriptEngine)
935-{
936- Q_UNUSED(engine)
937- Q_UNUSED(scriptEngine)
938-
939- return new UCMouseTouchAdaptor;
940-}
941-
942 void TestPlugin::registerTypes(const char *uri)
943 {
944 qmlRegisterSingletonType<UCTestExtras>(uri, 1, 0, "TestExtras", registerExtras);
945- qmlRegisterSingletonType<UCMouseTouchAdaptor>(uri, 1, 0, "MouseTouchAdaptor", registerAdaptor);
946+ qmlRegisterSingletonType<UbuntuToolkit::MouseTouchAdaptor>(uri, 1, 0, "MouseTouchAdaptor", UbuntuToolkit::MouseTouchAdaptor::registerQmlSingleton);
947 }
948
949=== modified file 'src/Ubuntu/Test/plugin/uctestextras.cpp'
950--- src/Ubuntu/Test/plugin/uctestextras.cpp 2015-12-17 15:23:26 +0000
951+++ src/Ubuntu/Test/plugin/uctestextras.cpp 2016-04-12 11:09:51 +0000
952@@ -1,5 +1,5 @@
953 /*
954- * Copyright 2014 Canonical Ltd.
955+ * Copyright 2016 Canonical Ltd.
956 *
957 * This program is free software; you can redistribute it and/or modify
958 * it under the terms of the GNU Lesser General Public License as published by
959@@ -23,6 +23,7 @@
960 #include <qpa/qwindowsysteminterface.h>
961 #include <private/qobject_p.h>
962 #include <QSysInfo>
963+#include <MouseTouchAdaptor>
964
965 const char *DEVICE_MISSING_MSG = "No touch device registered. Register one using registerTouchDevice() before using %1";
966
967@@ -40,7 +41,6 @@
968 return; \
969 }
970
971-QTouchDevice *UCTestExtras::m_touchDevice = 0;
972 UCTestExtras *UCTestExtras::m_testExtras = 0;
973
974 /*!
975@@ -118,24 +118,8 @@
976 */
977 void UCTestExtras::registerTouchDevice()
978 {
979- // check if there is any touch device registered in the system
980- if (!m_touchDevice) {
981- QList<const QTouchDevice*> touchDevices = QTouchDevice::devices();
982- Q_FOREACH(const QTouchDevice *device, touchDevices) {
983- if (device->type() == QTouchDevice::TouchScreen) {
984- m_touchDevice = const_cast<QTouchDevice*>(device);
985- break;
986- }
987- }
988- }
989- // if none, register one
990- if (!m_touchDevice) {
991- m_touchDevice = new QTouchDevice;
992- m_touchDevice->setType(QTouchDevice::TouchScreen);
993- QWindowSystemInterface::registerTouchDevice(m_touchDevice);
994- if (m_testExtras) {
995- Q_EMIT m_testExtras->touchDevicePresentChanged();
996- }
997+ if (UbuntuToolkit::MouseTouchAdaptor::registerTouchDevice() && m_testExtras) {
998+ Q_EMIT m_testExtras->touchDevicePresentChanged();
999 }
1000 }
1001
1002@@ -148,7 +132,7 @@
1003 void UCTestExtras::touchPress(int touchId, QQuickItem *item, const QPoint &point)
1004 {
1005 CHECK_TOUCH_DEVICE(touchId, item);
1006- QTest::touchEvent(item->window(), m_touchDevice).press(touchId, item->mapToScene(point).toPoint(), item->window());
1007+ QTest::touchEvent(item->window(), UbuntuToolkit::MouseTouchAdaptor::touchDevice()).press(touchId, item->mapToScene(point).toPoint(), item->window());
1008 }
1009 /*!
1010 * \qmlmethod TestExtras::touchRelease(touchId, item, point)
1011@@ -158,7 +142,7 @@
1012 void UCTestExtras::touchRelease(int touchId, QQuickItem *item, const QPoint &point)
1013 {
1014 CHECK_TOUCH_DEVICE(touchId, item);
1015- QTest::touchEvent(item->window(), m_touchDevice).release(touchId, item->mapToScene(point).toPoint(), item->window());
1016+ QTest::touchEvent(item->window(), UbuntuToolkit::MouseTouchAdaptor::touchDevice()).release(touchId, item->mapToScene(point).toPoint(), item->window());
1017 }
1018 /*!
1019 * \qmlmethod TestExtras::touchClick(touchId, item, point)
1020@@ -207,7 +191,7 @@
1021 void UCTestExtras::touchMove(int touchId, QQuickItem *item, const QPoint &point)
1022 {
1023 CHECK_TOUCH_DEVICE(touchId, item);
1024- QTest::touchEvent(item->window(), m_touchDevice).move(touchId, item->mapToScene(point).toPoint(), item->window());
1025+ QTest::touchEvent(item->window(), UbuntuToolkit::MouseTouchAdaptor::touchDevice()).move(touchId, item->mapToScene(point).toPoint(), item->window());
1026 }
1027 /*!
1028 * \qmlmethod TestExtras::touchDrag(touchId, item, from, delta, steps = 5)
1029
1030=== modified file 'src/Ubuntu/Test/plugin/uctestextras.h'
1031--- src/Ubuntu/Test/plugin/uctestextras.h 2015-12-17 14:42:40 +0000
1032+++ src/Ubuntu/Test/plugin/uctestextras.h 2016-04-12 11:09:51 +0000
1033@@ -53,7 +53,6 @@
1034 static void mouseDragWithPoints(QQuickItem *item, QList<QPoint> points, Qt::MouseButton button, Qt::KeyboardModifiers stateKey = 0, int delay = -1);
1035
1036 private:
1037- static QTouchDevice *m_touchDevice;
1038 static UCTestExtras *m_testExtras;
1039
1040 friend class UCMouseTouchAdaptor;
1041
1042=== modified file 'src/Ubuntu/UbuntuToolkit/UbuntuToolkit.pro'
1043--- src/Ubuntu/UbuntuToolkit/UbuntuToolkit.pro 2016-02-25 14:35:59 +0000
1044+++ src/Ubuntu/UbuntuToolkit/UbuntuToolkit.pro 2016-04-12 11:09:51 +0000
1045@@ -1,7 +1,14 @@
1046 TEMPLATE=lib
1047 TARGET=UbuntuToolkit
1048
1049-QT *= core-private gui-private qml qml-private quick quick-private
1050+QT *= core-private gui-private qml qml-private quick quick-private testlib
1051+
1052+!contains(QT_ARCH, arm) {
1053+ DEFINES += UBUNTUTOOLKIT_ENABLE_X11_TOUCH_EMULATION
1054+ LIBS += -lX11 -lxcb -lXi
1055+
1056+ SOURCES += mousetouchadaptor_x11.cpp
1057+}
1058
1059 CONFIG += dll no_keywords c++11
1060
1061@@ -17,9 +24,12 @@
1062 ubuntutoolkitglobal.h \
1063 tree.h \
1064 asyncloader.h \
1065- asyncloader_p.h
1066+ asyncloader_p.h \
1067+ mousetouchadaptor.h \
1068+ mousetouchadaptor_p.h
1069
1070 SOURCES += \
1071 colorutils.cpp \
1072 tree.cpp \
1073- asyncloader.cpp
1074+ asyncloader.cpp \
1075+ mousetouchadaptor.cpp
1076
1077=== renamed file 'src/Ubuntu/Test/plugin/ucmousetouchadaptor.cpp' => 'src/Ubuntu/UbuntuToolkit/mousetouchadaptor.cpp'
1078--- src/Ubuntu/Test/plugin/ucmousetouchadaptor.cpp 2015-11-10 14:42:20 +0000
1079+++ src/Ubuntu/UbuntuToolkit/mousetouchadaptor.cpp 2016-04-12 11:09:51 +0000
1080@@ -1,5 +1,5 @@
1081 /*
1082- * Copyright (C) 2013,2015 Canonical, Ltd.
1083+ * Copyright (C) 2013,2016 Canonical, Ltd.
1084 *
1085 * This program is free software; you can redistribute it and/or modify
1086 * it under the terms of the GNU General Public License as published by
1087@@ -14,36 +14,34 @@
1088 * along with this program. If not, see <http://www.gnu.org/licenses/>.
1089 *
1090 * Authored by: Daniel d'Andrada <daniel.dandrada@canonical.com>
1091+ * Zsombor Egri <zsomboir.egri@canonical.com>
1092 */
1093
1094-#include "ucmousetouchadaptor.h"
1095-#include "uctestextras.h"
1096+#include "mousetouchadaptor_p.h"
1097
1098+#include <qpa/qplatformnativeinterface.h>
1099 #include <qpa/qwindowsysteminterface.h>
1100
1101 #include <QCoreApplication>
1102 #include <QMouseEvent>
1103 #include <QTest>
1104
1105-using QTest::QTouchEventSequence;
1106-
1107-namespace {
1108-
1109-Qt::MouseButton translateMouseButton(xcb_button_t detail)
1110+#ifdef UBUNTUTOOLKIT_ENABLE_X11_TOUCH_EMULATION
1111+ #define ENABLE_TOUCH_EMULATION
1112+#endif
1113+
1114+namespace UbuntuToolkit {
1115+
1116+QTouchDevice *MouseTouchAdaptor::m_touchDevice = nullptr;
1117+
1118+MouseTouchAdaptorPrivate::~MouseTouchAdaptorPrivate()
1119 {
1120- switch (detail) {
1121- case 1: return Qt::LeftButton;
1122- case 2: return Qt::MidButton;
1123- case 3: return Qt::RightButton;
1124- // Button values 4-7 are Wheel events
1125- default: return Qt::NoButton;
1126- }
1127+ QCoreApplication::instance()->removeNativeEventFilter(this);
1128 }
1129-} // end of anonymous namespace
1130
1131 /*!
1132 * \qmltype MouseTouchAdaptor
1133- * \instantiates UCMouseTouchAdaptor
1134+ * \instantiates MouseTouchAdaptor
1135 * \inqmlmodule Ubuntu.Test 1.0
1136 * \ingroup ubuntu-test
1137 * \brief Singleton type turning mouse events into single finger touch events.
1138@@ -60,109 +58,49 @@
1139 * \endqml
1140 *
1141 */
1142-UCMouseTouchAdaptor::UCMouseTouchAdaptor()
1143- : QObject(nullptr)
1144- , m_leftButtonIsPressed(false)
1145- , m_enabled(true)
1146-{
1147- QCoreApplication::instance()->installNativeEventFilter(this);
1148-
1149- UCTestExtras::registerTouchDevice();
1150- m_touchDevice = UCTestExtras::m_touchDevice;
1151-}
1152-
1153-bool UCMouseTouchAdaptor::nativeEventFilter(const QByteArray & eventType,
1154- void * message, long * /*result*/)
1155-{
1156- if (!m_enabled) {
1157- return false;
1158- }
1159-
1160- if (eventType != "xcb_generic_event_t") {
1161- // wrong backend.
1162- qWarning("MouseTouchAdaptor: XCB backend not in use. Adaptor inoperative!");
1163- return false;
1164- }
1165-
1166- xcb_generic_event_t *xcbEvent = static_cast<xcb_generic_event_t *>(message);
1167-
1168- switch (xcbEvent->response_type & ~0x80) {
1169- case XCB_BUTTON_PRESS:
1170- return handleButtonPress(reinterpret_cast<xcb_button_press_event_t *>(xcbEvent));
1171- break;
1172- case XCB_BUTTON_RELEASE:
1173- return handleButtonRelease(reinterpret_cast<xcb_button_release_event_t *>(xcbEvent));
1174- break;
1175- case XCB_MOTION_NOTIFY:
1176- return handleMotionNotify(reinterpret_cast<xcb_motion_notify_event_t *>(xcbEvent));
1177- break;
1178- default:
1179- return false;
1180- break;
1181- };
1182-}
1183-
1184-bool UCMouseTouchAdaptor::handleButtonPress(xcb_button_press_event_t *pressEvent)
1185-{
1186- Qt::MouseButton button = translateMouseButton(pressEvent->detail);
1187-
1188- // Just eat the event if it wasn't a left mouse press
1189- if (button != Qt::LeftButton)
1190- return true;
1191-
1192- QWindow *targetWindow = findQWindowWithXWindowID(static_cast<WId>(pressEvent->event));
1193-
1194- QPoint windowPos(pressEvent->event_x / targetWindow->devicePixelRatio(), pressEvent->event_y / targetWindow->devicePixelRatio());
1195-
1196- QTouchEventSequence touchEvent = QTest::touchEvent(targetWindow, m_touchDevice,
1197- false /* autoCommit */);
1198- touchEvent.press(0 /* touchId */, windowPos);
1199- touchEvent.commit(false /* processEvents */);
1200-
1201- m_leftButtonIsPressed = true;
1202- return true;
1203-}
1204-
1205-bool UCMouseTouchAdaptor::handleButtonRelease(xcb_button_release_event_t *releaseEvent)
1206-{
1207- Qt::MouseButton button = translateMouseButton(releaseEvent->detail);
1208-
1209- // Just eat the event if it wasn't a left mouse release
1210- if (button != Qt::LeftButton)
1211- return true;
1212-
1213- QWindow *targetWindow = findQWindowWithXWindowID(static_cast<WId>(releaseEvent->event));
1214-
1215- QPoint windowPos(releaseEvent->event_x / targetWindow->devicePixelRatio(), releaseEvent->event_y / targetWindow->devicePixelRatio());
1216-
1217- QTouchEventSequence touchEvent = QTest::touchEvent(targetWindow, m_touchDevice,
1218- false /* autoCommit */);
1219- touchEvent.release(0 /* touchId */, windowPos);
1220- touchEvent.commit(false /* processEvents */);
1221-
1222- m_leftButtonIsPressed = false;
1223- return true;
1224-}
1225-
1226-bool UCMouseTouchAdaptor::handleMotionNotify(xcb_motion_notify_event_t *event)
1227-{
1228- if (!m_leftButtonIsPressed) {
1229- return true;
1230- }
1231-
1232- QWindow *targetWindow = findQWindowWithXWindowID(static_cast<WId>(event->event));
1233-
1234- QPoint windowPos(event->event_x / targetWindow->devicePixelRatio(), event->event_y / targetWindow->devicePixelRatio());
1235-
1236- QTouchEventSequence touchEvent = QTest::touchEvent(targetWindow, m_touchDevice,
1237- false /* autoCommit */);
1238- touchEvent.move(0 /* touchId */, windowPos);
1239- touchEvent.commit(false /* processEvents */);
1240-
1241- return true;
1242-}
1243-
1244-QWindow *UCMouseTouchAdaptor::findQWindowWithXWindowID(WId windowId)
1245+MouseTouchAdaptor::MouseTouchAdaptor(QObject *parent)
1246+ :
1247+#ifdef UBUNTUTOOLKIT_ENABLE_X11_TOUCH_EMULATION
1248+ QObject(*(new X11MouseTouchAdaptorPrivate), parent)
1249+#else
1250+ QObject(*(new MouseTouchAdaptorPrivate), parent)
1251+#endif
1252+{
1253+#ifdef ENABLE_TOUCH_EMULATION
1254+ registerTouchDevice();
1255+#else
1256+ qWarning() << "MouseTouchAdaptor not available on this architecture.";
1257+#endif
1258+ Q_D(MouseTouchAdaptor);
1259+ d->init();
1260+}
1261+
1262+// registers a test touch device, returns true if a device was found/registered
1263+bool MouseTouchAdaptor::registerTouchDevice()
1264+{
1265+ // check if there is any touch device registered in the system
1266+ if (!m_touchDevice) {
1267+ QList<const QTouchDevice*> touchDevices = QTouchDevice::devices();
1268+ Q_FOREACH(const QTouchDevice *device, touchDevices) {
1269+ if (device->type() == QTouchDevice::TouchScreen) {
1270+ m_touchDevice = const_cast<QTouchDevice*>(device);
1271+ return true;
1272+ }
1273+ }
1274+ }
1275+ // if none, register one
1276+#ifdef ENABLE_TOUCH_EMULATION
1277+ if (!m_touchDevice) {
1278+ m_touchDevice = new QTouchDevice;
1279+ m_touchDevice->setType(QTouchDevice::TouchScreen);
1280+ QWindowSystemInterface::registerTouchDevice(m_touchDevice);
1281+ return true;
1282+ }
1283+#endif
1284+ return false;
1285+}
1286+
1287+QWindow *MouseTouchAdaptorPrivate::findQWindowWithXWindowID(WId windowId)
1288 {
1289 QWindowList windowList = QGuiApplication::topLevelWindows();
1290 QWindow *foundWindow = nullptr;
1291@@ -185,14 +123,16 @@
1292 * \qmlproperty bool MouseTouchAdaptor::enabled
1293 * Enables the mouse to touch conversion functionality. Defaults to true.
1294 */
1295-bool UCMouseTouchAdaptor::enabled() const
1296-{
1297- return m_enabled;
1298-}
1299-void UCMouseTouchAdaptor::setEnabled(bool value)
1300-{
1301- if (value != m_enabled) {
1302- m_enabled = value;
1303- Q_EMIT enabledChanged(value);
1304- }
1305-}
1306+bool MouseTouchAdaptorPrivate::isEnabled() const
1307+{
1308+ return enabled;
1309+}
1310+void MouseTouchAdaptorPrivate::setEnabled(bool value)
1311+{
1312+ Q_UNUSED(value);
1313+ qWarning() << "MouseTouchAdaptor not available on this architecture, thus cannot be enabled.";
1314+}
1315+
1316+} // namespace UbuntuToolkit
1317+
1318+#include "moc_mousetouchadaptor.cpp"
1319
1320=== renamed file 'src/Ubuntu/Test/plugin/ucmousetouchadaptor.h' => 'src/Ubuntu/UbuntuToolkit/mousetouchadaptor.h'
1321--- src/Ubuntu/Test/plugin/ucmousetouchadaptor.h 2015-10-21 08:33:21 +0000
1322+++ src/Ubuntu/UbuntuToolkit/mousetouchadaptor.h 2016-04-12 11:09:51 +0000
1323@@ -1,5 +1,5 @@
1324 /*
1325- * Copyright (C) 2013,2015 Canonical, Ltd.
1326+ * Copyright (C) 2013,2016 Canonical, Ltd.
1327 *
1328 * This program is free software; you can redistribute it and/or modify
1329 * it under the terms of the GNU General Public License as published by
1330@@ -14,47 +14,50 @@
1331 * along with this program. If not, see <http://www.gnu.org/licenses/>.
1332 *
1333 * Authored by: Daniel d'Andrada <daniel.dandrada@canonical.com>
1334+ * Zsombor Egri <zsomboir.egri@canonical.com>
1335 */
1336
1337 #ifndef MOUSE_TOUCH_ADAPTOR_H
1338 #define MOUSE_TOUCH_ADAPTOR_H
1339
1340-#include <QtCore/QAbstractNativeEventFilter>
1341-#include <QWindow>
1342-#include <xcb/xcb.h>
1343+#include "ubuntutoolkitglobal.h"
1344+
1345+#include <QtCore/QObject>
1346
1347 class QMouseEvent;
1348 class QTouchDevice;
1349+class QQmlEngine;
1350+class QJSEngine;
1351+
1352+namespace UbuntuToolkit {
1353
1354 // Transforms QMouseEvents into single-finger QTouchEvents.
1355-class UCMouseTouchAdaptor : public QObject, public QAbstractNativeEventFilter
1356+class MouseTouchAdaptorPrivate;
1357+class UBUNTUTOOLKIT_EXPORT MouseTouchAdaptor : public QObject
1358 {
1359 Q_OBJECT
1360+ Q_PRIVATE_PROPERTY(MouseTouchAdaptor::d_func(), bool enabled READ isEnabled WRITE setEnabled NOTIFY enabledChanged)
1361 public:
1362- UCMouseTouchAdaptor();
1363-
1364- // Filters mouse events and posts the equivalent QTouchEvents.
1365- bool nativeEventFilter(const QByteArray & eventType, void *message, long *result) override;
1366-
1367- Q_PROPERTY(bool enabled READ enabled WRITE setEnabled NOTIFY enabledChanged)
1368-
1369- bool enabled() const;
1370- void setEnabled(bool value);
1371+ explicit MouseTouchAdaptor(QObject *parent = Q_NULLPTR);
1372+
1373+ static bool registerTouchDevice();
1374+ inline static QTouchDevice *touchDevice()
1375+ {
1376+ return m_touchDevice;
1377+ }
1378+ static QObject *registerQmlSingleton(QQmlEngine*, QJSEngine*)
1379+ {
1380+ return new MouseTouchAdaptor;
1381+ }
1382
1383 Q_SIGNALS:
1384 void enabledChanged(bool value);
1385
1386 private:
1387-
1388- bool handleButtonPress(xcb_button_press_event_t *pressEvent);
1389- bool handleButtonRelease(xcb_button_release_event_t *releaseEvent);
1390- bool handleMotionNotify(xcb_motion_notify_event_t *event);
1391- QWindow *findQWindowWithXWindowID(WId windowId);
1392-
1393- QTouchDevice *m_touchDevice;
1394- bool m_leftButtonIsPressed;
1395-
1396- bool m_enabled;
1397+ Q_DECLARE_PRIVATE(MouseTouchAdaptor)
1398+ static QTouchDevice *m_touchDevice;
1399 };
1400
1401+} // namespace UbuntuToolkit
1402+
1403 #endif // MOUSE_TOUCH_ADAPTOR_H
1404
1405=== added file 'src/Ubuntu/UbuntuToolkit/mousetouchadaptor_p.h'
1406--- src/Ubuntu/UbuntuToolkit/mousetouchadaptor_p.h 1970-01-01 00:00:00 +0000
1407+++ src/Ubuntu/UbuntuToolkit/mousetouchadaptor_p.h 2016-04-12 11:09:51 +0000
1408@@ -0,0 +1,77 @@
1409+/*
1410+ * Copyright (C) 2016 Canonical, Ltd.
1411+ *
1412+ * This program is free software; you can redistribute it and/or modify
1413+ * it under the terms of the GNU General Public License as published by
1414+ * the Free Software Foundation; version 3.
1415+ *
1416+ * This program is distributed in the hope that it will be useful,
1417+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1418+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1419+ * GNU General Public License for more details.
1420+ *
1421+ * You should have received a copy of the GNU General Public License
1422+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1423+ *
1424+ * Authored by: Zsombor Egri <zsombor.egri@canonical.com>
1425+ */
1426+
1427+#ifndef MOUSETOUCHADAPTOR_P
1428+#define MOUSETOUCHADAPTOR_P
1429+
1430+#include "mousetouchadaptor.h"
1431+#include <QtCore/private/qobject_p.h>
1432+#include <QtCore/QAbstractNativeEventFilter>
1433+#include <QWindow>
1434+#include <xcb/xcb.h>
1435+
1436+namespace UbuntuToolkit {
1437+
1438+class MouseTouchAdaptorPrivate : public QObjectPrivate, public QAbstractNativeEventFilter
1439+{
1440+ Q_DECLARE_PUBLIC(MouseTouchAdaptor)
1441+public:
1442+ MouseTouchAdaptorPrivate() : QObjectPrivate() {}
1443+ ~MouseTouchAdaptorPrivate();
1444+
1445+ virtual void init() {}
1446+ virtual bool nativeEventFilter(const QByteArray & eventType, void *message, long *result)
1447+ { Q_UNUSED(eventType); Q_UNUSED(message); Q_UNUSED(result); return false; }
1448+ bool isEnabled() const;
1449+ virtual void setEnabled(bool enabled);
1450+
1451+ QWindow *findQWindowWithXWindowID(WId windowId);
1452+
1453+ // fields
1454+ bool enabled{false};
1455+};
1456+
1457+#ifdef UBUNTUTOOLKIT_ENABLE_X11_TOUCH_EMULATION
1458+class X11MouseTouchAdaptorPrivate : public MouseTouchAdaptorPrivate
1459+{
1460+ Q_DECLARE_PUBLIC(MouseTouchAdaptor)
1461+public:
1462+ X11MouseTouchAdaptorPrivate();
1463+
1464+ void init() Q_DECL_OVERRIDE;
1465+ bool nativeEventFilter(const QByteArray & eventType, void *message, long *result) Q_DECL_OVERRIDE;
1466+ void setEnabled(bool value);
1467+
1468+ bool xi2HandleEvent(xcb_ge_event_t *event);
1469+ bool handleButtonPress(WId windowId, uint32_t detail, uint32_t modifiers, int x, int y);
1470+ bool handleButtonRelease(WId windowId, uint32_t detail, uint32_t modifiers, int x, int y);
1471+ bool handleMotionNotify(WId windowId, uint32_t modifiers, int x, int y);
1472+
1473+ bool m_leftButtonIsPressed;
1474+ bool m_triPressModifier;
1475+
1476+ bool m_xi2Enabled{false};
1477+ int m_xi2Minor{-1};
1478+ int m_xiOpCode, m_xiEventBase, m_xiErrorBase;
1479+};
1480+#endif
1481+
1482+} // namespace UbuntuToolkit
1483+
1484+#endif // MOUSETOUCHADAPTOR_P
1485+
1486
1487=== added file 'src/Ubuntu/UbuntuToolkit/mousetouchadaptor_x11.cpp'
1488--- src/Ubuntu/UbuntuToolkit/mousetouchadaptor_x11.cpp 1970-01-01 00:00:00 +0000
1489+++ src/Ubuntu/UbuntuToolkit/mousetouchadaptor_x11.cpp 2016-04-12 11:09:51 +0000
1490@@ -0,0 +1,350 @@
1491+/*
1492+ * Copyright (C) 2016 Canonical, Ltd.
1493+ *
1494+ * This program is free software; you can redistribute it and/or modify
1495+ * it under the terms of the GNU General Public License as published by
1496+ * the Free Software Foundation; version 3.
1497+ *
1498+ * This program is distributed in the hope that it will be useful,
1499+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1500+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1501+ * GNU General Public License for more details.
1502+ *
1503+ * You should have received a copy of the GNU General Public License
1504+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1505+ *
1506+ * Authored by: Zsombor Egri <zsombor.egri@canonical.com>
1507+ */
1508+
1509+/* Some parts of the code were copied from the XCB platform plugin of the Qt Toolkit,
1510+ * which is under the following license:
1511+ */
1512+
1513+/****************************************************************************
1514+**
1515+** Copyright (C) 2015 The Qt Company Ltd.
1516+** Contact: http://www.qt.io/licensing/
1517+**
1518+** This file is part of the .
1519+**
1520+** $QT_BEGIN_LICENSE:LGPL21$
1521+** Commercial License Usage
1522+** Licensees holding valid commercial Qt licenses may use this file in
1523+** accordance with the commercial license agreement provided with the
1524+** Software or, alternatively, in accordance with the terms contained in
1525+** a written agreement between you and The Qt Company. For licensing terms
1526+** and conditions see http://www.qt.io/terms-conditions. For further
1527+** information use the contact form at http://www.qt.io/contact-us.
1528+**
1529+** GNU Lesser General Public License Usage
1530+** Alternatively, this file may be used under the terms of the GNU Lesser
1531+** General Public License version 2.1 or version 3 as published by the Free
1532+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
1533+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
1534+** following information to ensure the GNU Lesser General Public License
1535+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
1536+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
1537+**
1538+** As a special exception, The Qt Company gives you certain additional
1539+** rights. These rights are described in The Qt Company LGPL Exception
1540+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
1541+**
1542+** $QT_END_LICENSE$
1543+**
1544+****************************************************************************/
1545+
1546+#include "mousetouchadaptor_p.h"
1547+
1548+#include <qpa/qplatformnativeinterface.h>
1549+
1550+#include <QCoreApplication>
1551+#include <QMouseEvent>
1552+#include <QTest>
1553+
1554+#include <X11/extensions/XInput2.h>
1555+#include <X11/extensions/XI2proto.h>
1556+
1557+using QTest::QTouchEventSequence;
1558+
1559+namespace {
1560+
1561+const Qt::KeyboardModifiers TRI_PRESS_MODIFIER = Qt::ShiftModifier|Qt::ControlModifier|Qt::AltModifier;
1562+
1563+Qt::MouseButton translateMouseButton(xcb_button_t detail)
1564+{
1565+ switch (detail) {
1566+ case 1: return Qt::LeftButton;
1567+ case 2: return Qt::MidButton;
1568+ case 3: return Qt::RightButton;
1569+ // Button values 4-7 are Wheel events
1570+ default: return Qt::NoButton;
1571+ }
1572+}
1573+
1574+Qt::KeyboardModifiers translateMofidier(uint32_t mod)
1575+{
1576+ Qt::KeyboardModifiers qtMod = Qt::NoModifier;
1577+
1578+ if (mod & 0x01) qtMod |= Qt::ShiftModifier;
1579+ if (mod & 0x04) qtMod |= Qt::ControlModifier;
1580+ if (mod & 0x08) qtMod |= Qt::AltModifier;
1581+ if (mod & 0x80) qtMod |= Qt::MetaModifier;
1582+
1583+ return qtMod;
1584+}
1585+
1586+} // end of anonymous namespace
1587+
1588+
1589+namespace UbuntuToolkit {
1590+
1591+X11MouseTouchAdaptorPrivate::X11MouseTouchAdaptorPrivate()
1592+ : m_leftButtonIsPressed(false)
1593+ , m_triPressModifier(false)
1594+{
1595+ enabled = true;
1596+}
1597+
1598+void X11MouseTouchAdaptorPrivate::init()
1599+{
1600+ QPlatformNativeInterface *nativeInterface = qGuiApp->platformNativeInterface();
1601+ Display *xDisplay = static_cast<Display*>(nativeInterface->nativeResourceForIntegration("Display"));
1602+ if (xDisplay && XQueryExtension(xDisplay, "XInputExtension", &m_xiOpCode, &m_xiEventBase, &m_xiErrorBase)) {
1603+ int xiMajor = 2;
1604+ m_xi2Minor = 2; // try 2.2 first, needed for TouchBegin/Update/End
1605+ if (XIQueryVersion(xDisplay, &xiMajor, &m_xi2Minor) == BadRequest) {
1606+ m_xi2Minor = 1; // for smooth scrolling 2.1 is enough
1607+ if (XIQueryVersion(xDisplay, &xiMajor, &m_xi2Minor) == BadRequest) {
1608+ m_xi2Minor = 0; // for tablet support 2.0 is enough
1609+ m_xi2Enabled = XIQueryVersion(xDisplay, &xiMajor, &m_xi2Minor) != BadRequest;
1610+ } else
1611+ m_xi2Enabled = true;
1612+ } else {
1613+ m_xi2Enabled = true;
1614+ }
1615+ }
1616+
1617+ QCoreApplication::instance()->installNativeEventFilter(this);
1618+}
1619+
1620+void X11MouseTouchAdaptorPrivate::setEnabled(bool value)
1621+{
1622+ if (value != enabled) {
1623+ enabled = value;
1624+ Q_EMIT q_func()->enabledChanged(value);
1625+ }
1626+}
1627+
1628+// Starting from the xcb version 1.9.3 struct xcb_ge_event_t has changed:
1629+// - "pad0" became "extension"
1630+// - "pad1" and "pad" became "pad0"
1631+// New and old version of this struct share the following fields:
1632+// NOTE: API might change again in the next release of xcb in which case this comment will
1633+// need to be updated to reflect the reality.
1634+typedef struct qt_xcb_ge_event_t {
1635+ uint8_t response_type;
1636+ uint8_t extension;
1637+ uint16_t sequence;
1638+ uint32_t length;
1639+ uint16_t event_type;
1640+} qt_xcb_ge_event_t;
1641+
1642+bool xi2PrepareXIGenericDeviceEvent(xcb_ge_event_t *ev, int opCode)
1643+{
1644+ qt_xcb_ge_event_t *event = (qt_xcb_ge_event_t *)ev;
1645+ // xGenericEvent has "extension" on the second byte, the same is true for xcb_ge_event_t starting from
1646+ // the xcb version 1.9.3, prior to that it was called "pad0".
1647+ if (event->extension == opCode) {
1648+ // xcb event structs contain stuff that wasn't on the wire, the full_sequence field
1649+ // adds an extra 4 bytes and generic events cookie data is on the wire right after the standard 32 bytes.
1650+ // Move this data back to have the same layout in memory as it was on the wire
1651+ // and allow casting, overwriting the full_sequence field.
1652+ memmove((char*) event + 32, (char*) event + 36, event->length * 4);
1653+ return true;
1654+ }
1655+ return false;
1656+}
1657+
1658+static inline qreal fixed1616ToReal(FP1616 val)
1659+{
1660+ return qreal(val) / 0x10000;
1661+}
1662+
1663+bool X11MouseTouchAdaptorPrivate::xi2HandleEvent(xcb_ge_event_t *event)
1664+{
1665+ if (!xi2PrepareXIGenericDeviceEvent(event, m_xiOpCode)) {
1666+ return false;
1667+ }
1668+
1669+ xXIGenericDeviceEvent *xiEvent = reinterpret_cast<xXIGenericDeviceEvent *>(event);
1670+ xXIDeviceEvent *xiDeviceEvent = 0;
1671+
1672+ switch (xiEvent->evtype) {
1673+ case XI_ButtonPress:
1674+ case XI_ButtonRelease:
1675+ case XI_Motion:
1676+ xiDeviceEvent = reinterpret_cast<xXIDeviceEvent *>(event);
1677+ break;
1678+ default:
1679+ break;
1680+ }
1681+
1682+ if (!xiDeviceEvent) {
1683+ return false;
1684+ }
1685+
1686+ switch (xiDeviceEvent->evtype) {
1687+ case XI_ButtonPress:
1688+ return handleButtonPress(
1689+ static_cast<WId>(xiDeviceEvent->event),
1690+ xiDeviceEvent->detail,
1691+ xiDeviceEvent->mods.base_mods,
1692+ fixed1616ToReal(xiDeviceEvent->event_x),
1693+ fixed1616ToReal(xiDeviceEvent->event_y));
1694+ case XI_ButtonRelease:
1695+ return handleButtonRelease(
1696+ static_cast<WId>(xiDeviceEvent->event),
1697+ xiDeviceEvent->detail,
1698+ xiDeviceEvent->mods.base_mods,
1699+ fixed1616ToReal(xiDeviceEvent->event_x),
1700+ fixed1616ToReal(xiDeviceEvent->event_y));
1701+ case XI_Motion:
1702+ return handleMotionNotify(
1703+ static_cast<WId>(xiDeviceEvent->event),
1704+ xiDeviceEvent->mods.base_mods,
1705+ fixed1616ToReal(xiDeviceEvent->event_x),
1706+ fixed1616ToReal(xiDeviceEvent->event_y));
1707+ return true;
1708+ default:
1709+ return false;
1710+ }
1711+}
1712+
1713+bool X11MouseTouchAdaptorPrivate::nativeEventFilter(const QByteArray &eventType, void *message, long *result)
1714+{
1715+ Q_UNUSED(result);
1716+ static int eventCount = 0;
1717+ eventCount++;
1718+ if (!enabled) {
1719+ return false;
1720+ }
1721+
1722+ if (eventType != "xcb_generic_event_t") {
1723+ // wrong backend.
1724+ qWarning("MouseTouchAdaptor: XCB backend not in use. Adaptor inoperative!");
1725+ return false;
1726+ }
1727+
1728+ xcb_generic_event_t *xcbEvent = static_cast<xcb_generic_event_t *>(message);
1729+
1730+ switch (xcbEvent->response_type & ~0x80) {
1731+ case XCB_BUTTON_PRESS: {
1732+ auto pressEvent = reinterpret_cast<xcb_button_press_event_t *>(xcbEvent);
1733+ return handleButtonPress(static_cast<WId>(pressEvent->event), pressEvent->detail, 0,
1734+ pressEvent->event_x, pressEvent->event_y);
1735+ }
1736+ case XCB_BUTTON_RELEASE: {
1737+ auto releaseEvent = reinterpret_cast<xcb_button_release_event_t *>(xcbEvent);
1738+ return handleButtonRelease(static_cast<WId>(releaseEvent->event), releaseEvent->detail, 0,
1739+ releaseEvent->event_x, releaseEvent->event_y);
1740+ }
1741+ case XCB_MOTION_NOTIFY: {
1742+ auto motionEvent = reinterpret_cast<xcb_motion_notify_event_t *>(xcbEvent);
1743+ return handleMotionNotify(static_cast<WId>(motionEvent->event), 0,
1744+ motionEvent->event_x, motionEvent->event_y);
1745+ }
1746+ case XCB_GE_GENERIC:
1747+ if (m_xi2Enabled) {
1748+ return xi2HandleEvent(reinterpret_cast<xcb_ge_event_t *>(xcbEvent));
1749+ } else {
1750+ return false;
1751+ }
1752+ default:
1753+ return false;
1754+ };
1755+}
1756+
1757+bool X11MouseTouchAdaptorPrivate::handleButtonPress(WId windowId, uint32_t detail, uint32_t modifiers, int x, int y)
1758+{
1759+ Qt::MouseButton button = translateMouseButton(detail);
1760+ Qt::KeyboardModifiers qtMod = translateMofidier(modifiers);
1761+
1762+ // Just eat the event if it wasn't a left mouse press
1763+ if (button != Qt::LeftButton)
1764+ return true;
1765+
1766+ QWindow *targetWindow = findQWindowWithXWindowID(windowId);
1767+
1768+ QPoint windowPos(x / targetWindow->devicePixelRatio(), y / targetWindow->devicePixelRatio());
1769+
1770+ QTouchEventSequence touchEvent = QTest::touchEvent(targetWindow, MouseTouchAdaptor::touchDevice(),
1771+ false /* autoCommit */);
1772+ touchEvent.press(0 /* touchId */, windowPos);
1773+ if (qtMod == TRI_PRESS_MODIFIER) {
1774+ touchEvent.press(1, windowPos);
1775+ touchEvent.press(2, windowPos);
1776+ m_triPressModifier = true;
1777+ }
1778+ touchEvent.commit(false /* processEvents */);
1779+
1780+ m_leftButtonIsPressed = true;
1781+ return true;
1782+}
1783+
1784+bool X11MouseTouchAdaptorPrivate::handleButtonRelease(WId windowId, uint32_t detail, uint32_t, int x, int y)
1785+{
1786+ Qt::MouseButton button = translateMouseButton(detail);
1787+
1788+ // Don't eat the event if it wasn't a left mouse press
1789+ if (button != Qt::LeftButton)
1790+ return false;
1791+
1792+ QWindow *targetWindow = findQWindowWithXWindowID(windowId);
1793+
1794+ QPoint windowPos(x / targetWindow->devicePixelRatio(), y / targetWindow->devicePixelRatio());
1795+
1796+ QTouchEventSequence touchEvent = QTest::touchEvent(targetWindow, MouseTouchAdaptor::touchDevice(),
1797+ false /* autoCommit */);
1798+ touchEvent.release(0 /* touchId */, windowPos);
1799+ if (m_triPressModifier) {
1800+ touchEvent.release(1, windowPos);
1801+ touchEvent.release(2, windowPos);
1802+ }
1803+ touchEvent.commit(false /* processEvents */);
1804+
1805+ m_leftButtonIsPressed = false;
1806+ m_triPressModifier = false;
1807+ return true;
1808+}
1809+
1810+bool X11MouseTouchAdaptorPrivate::handleMotionNotify(WId windowId, uint32_t modifiers, int x, int y)
1811+{
1812+ if (!m_leftButtonIsPressed) {
1813+ return true;
1814+ }
1815+ Qt::KeyboardModifiers qtMod = translateMofidier(modifiers);
1816+
1817+ QWindow *targetWindow = findQWindowWithXWindowID(windowId);
1818+
1819+ QPoint windowPos(x / targetWindow->devicePixelRatio(), y / targetWindow->devicePixelRatio());
1820+
1821+ QTouchEventSequence touchEvent = QTest::touchEvent(targetWindow, MouseTouchAdaptor::touchDevice(),
1822+ false /* autoCommit */);
1823+ touchEvent.move(0 /* touchId */, windowPos);
1824+ if (m_triPressModifier) {
1825+ if (qtMod == TRI_PRESS_MODIFIER) {
1826+ touchEvent.move(1, windowPos);
1827+ touchEvent.move(2, windowPos);
1828+ } else {
1829+ // released modifiers
1830+ touchEvent.release(1, windowPos);
1831+ touchEvent.release(2, windowPos);
1832+ m_triPressModifier = false;
1833+ }
1834+ }
1835+ touchEvent.commit(false /* processEvents */);
1836+
1837+ return true;
1838+}
1839+
1840+} // namespace UbuntuToolkit
1841
1842=== added file 'tests/autopilot/ubuntuuitoolkit/tests/test_touchadaptor.py'
1843--- tests/autopilot/ubuntuuitoolkit/tests/test_touchadaptor.py 1970-01-01 00:00:00 +0000
1844+++ tests/autopilot/ubuntuuitoolkit/tests/test_touchadaptor.py 2016-04-12 11:09:51 +0000
1845@@ -0,0 +1,38 @@
1846+# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
1847+#
1848+# Copyright (C) 2016 Canonical Ltd.
1849+#
1850+# This program is free software; you can redistribute it and/or modify
1851+# it under the terms of the GNU Lesser General Public License as published by
1852+# the Free Software Foundation; version 3.
1853+#
1854+# This program is distributed in the hope that it will be useful,
1855+# but WITHOUT ANY WARRANTY; without even the implied warranty of
1856+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1857+# GNU Lesser General Public License for more details.
1858+#
1859+# You should have received a copy of the GNU Lesser General Public License
1860+# along with this program. If not, see <http://www.gnu.org/licenses/>.
1861+
1862+import os
1863+from testtools.matchers import Equals
1864+from autopilot.matchers import Eventually
1865+from ubuntuuitoolkit import tests
1866+
1867+
1868+class TouchAdaptorTestCase(tests.QMLFileAppTestCase):
1869+ path = os.path.abspath(__file__)
1870+ dir_path = os.path.dirname(path)
1871+ test_qml_file_path = os.path.join(
1872+ dir_path, 'test_touchadaptor.qml')
1873+
1874+ def get_command_line(self, command_line):
1875+ command_line.append('-touch')
1876+ return command_line
1877+
1878+ def test_apparent_touch_screen(self):
1879+ touchArea = self.main_view.select_single(objectName="touchArea")
1880+ label = self.main_view.select_single(objectName="label")
1881+ # Trigger handlers as a courtesy to a watching person
1882+ self.pointing_device.click_object(touchArea)
1883+ self.assertThat(label.text, Eventually(Equals("Touched")))
1884
1885=== added file 'tests/autopilot/ubuntuuitoolkit/tests/test_touchadaptor.qml'
1886--- tests/autopilot/ubuntuuitoolkit/tests/test_touchadaptor.qml 1970-01-01 00:00:00 +0000
1887+++ tests/autopilot/ubuntuuitoolkit/tests/test_touchadaptor.qml 2016-04-12 11:09:51 +0000
1888@@ -0,0 +1,51 @@
1889+/*
1890+ * Copyright 2016 Canonical Ltd.
1891+ *
1892+ * This program is free software; you can redistribute it and/or modify
1893+ * it under the terms of the GNU Lesser General Public License as published by
1894+ * the Free Software Foundation; version 3.
1895+ *
1896+ * This program is distributed in the hope that it will be useful,
1897+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1898+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1899+ * GNU Lesser General Public License for more details.
1900+ *
1901+ * You should have received a copy of the GNU Lesser General Public License
1902+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1903+ */
1904+
1905+import QtQuick 2.4
1906+import Ubuntu.Components 1.3
1907+
1908+MainView {
1909+ width: units.gu(48)
1910+ height: units.gu(60)
1911+ objectName: "mainView"
1912+
1913+ Page {
1914+ title: "TouchAdaptor"
1915+
1916+ MultiPointTouchArea {
1917+ id: mpa
1918+ property bool touched: false
1919+ anchors.fill: parent
1920+ mouseEnabled: false
1921+ objectName: "touchArea"
1922+ touchPoints: TouchPoint {
1923+ id: point1
1924+ onPressedChanged: {
1925+ if (pressed) {
1926+ label.text = "Touched";
1927+ }
1928+ }
1929+ }
1930+
1931+ Label {
1932+ id: label
1933+ objectName: "label"
1934+ anchors.centerIn: parent
1935+ text: "Not touched"
1936+ }
1937+ }
1938+ }
1939+}
1940
1941=== modified file 'tests/checkresults.sh'
1942--- tests/checkresults.sh 2016-02-03 16:43:02 +0000
1943+++ tests/checkresults.sh 2016-04-12 11:09:51 +0000
1944@@ -17,9 +17,13 @@
1945 # Author: Christian Dywan <christian.dywan@canonical.com>
1946 ################################################################################
1947
1948+WARNINGS_PATTERN='message="(.*)" type="qwarn"'
1949+ERRORS_PATTERN='<failure'
1950+
1951 FAILURES=0
1952-for i in $*; do
1953- _XML=$i
1954+FATAL_WARNINGS=0
1955+EXCEPTED=0
1956+for _XML in $*; do
1957 _TESTNAME=$(basename $_XML | sed -r 's@test_(.+)\.xml@\1@' -)
1958
1959 if [ ! -f $_XML ]; then
1960@@ -30,6 +34,8 @@
1961 EXCEPTIONS='tst_components_benchmark \
1962 tst_tabbar.qml \
1963 tst_datepicker.qml \
1964+ tst_datepicker13.qml \
1965+ tst_swipearea \
1966 tst_qquick_image_extension \
1967 tst_page.qml \
1968 tst_toolbar.qml \
1969@@ -48,26 +54,46 @@
1970 tst_inversemousearea \
1971 '
1972
1973- WARNINGS=$(grep -c -e 'qwarn' $_XML)
1974- ERRORS=$(grep -c -e '<failure' $_XML)
1975+ WARNINGS=$(grep -c -P "$WARNINGS_PATTERN" $_XML)
1976+ ERRORS=$(grep -c -P "$ERRORS_PATTERN" $_XML)
1977 if [ $ERRORS -ne 0 ]; then
1978- echo "Error: $ERRORS errors in $_TESTNAME ($WARNINGS warnings)"
1979+ FAILURES_FILES="${FAILURES_FILES} ${_TESTNAME}\n"
1980 ((FAILURES+=$ERRORS))
1981- ((FAILURES+=$WARNINGS))
1982 elif [ $WARNINGS -ne 0 ]; then
1983 if [[ $EXCEPTIONS == *$_TESTNAME* ]]; then
1984- echo "FIXME: $WARNINGS warnings in $_TESTNAME - Known problematic test"
1985+ EXCEPTED_FILES="${EXCEPTED_FILES} ${_TESTNAME}\n"
1986+ ((EXCEPTED+=$WARNINGS))
1987 else
1988- echo "Error: $WARNINGS warnings in $_TESTNAME"
1989- # FIXME: ((FAILURES+=$WARNINGS))
1990+ FATAL_WARNINGS_FILES="${FATAL_WARNINGS_FILES} ${_TESTNAME}\n"
1991+ ((FATAL_WARNINGS+=$WARNINGS))
1992 fi
1993 elif [[ $EXCEPTIONS == *$_TESTNAME* ]]; then
1994- echo Woot! Known problematic test $_TESTNAME did pass afterall!
1995- echo ' ' Consider removing $_TESTNAME from EXCEPTIONS in ${0#$(pwd)/}
1996+ WOOT_FILES="${WOOT_FILES} ${_TESTNAME}\n"
1997 fi
1998 done
1999
2000-if [ $FAILURES -ne 0 ]; then
2001- echo Found $FAILURES failures including warnings.
2002- exit $FAILURES
2003-fi
2004+TOTAL=0
2005+if [ -n "$FAILURES_FILES" ]; then
2006+ ((TOTAL+=$FAILURES))
2007+ echo $FAILURES failures which MUST be fixed:
2008+ echo -e "$FAILURES_FILES"
2009+fi
2010+
2011+if [ -n "$FATAL_WARNINGS_FILES" ]; then
2012+ ((TOTAL+=FATAL_WARNINGS))
2013+ echo $FATAL_WARNINGS fatal warnings which MUST be fixed:
2014+ echo -e "$FATAL_WARNINGS_FILES"
2015+fi
2016+
2017+if [ -n "$EXCEPTED_FILES" ]; then
2018+ echo The following tests issued $EXCEPTED expected warnings:
2019+ echo -e "$EXCEPTED_FILES"
2020+fi
2021+
2022+if [ -n "$WOOT_FILES" ]; then
2023+ echo Woot! Known problematic tests passed!
2024+ echo Consider removing these from EXCEPTIONS in ${0#$(pwd)/}!
2025+ echo -e "$WOOT_FILES"
2026+fi
2027+
2028+exit $TOTAL
2029
2030=== modified file 'tests/qmlapicheck.sh'
2031--- tests/qmlapicheck.sh 2015-11-30 15:39:52 +0000
2032+++ tests/qmlapicheck.sh 2016-04-12 11:09:51 +0000
2033@@ -1,4 +1,4 @@
2034-#!/usr/bin/env sh
2035+#!/bin/bash
2036 #
2037 # Copyright 2013 Canonical Ltd.
2038 #
2039@@ -16,7 +16,7 @@
2040 #
2041 ################################################################################
2042
2043-. `dirname $0`/../build_paths.inc
2044+source `dirname $0`/../export_qml_dir.sh || exit 1
2045
2046 if [ ! -e $BUILD_DIR/qml/Ubuntu/Layouts/libUbuntuLayouts.so ]; then
2047 echo You need to build UITK before you can dump QML API!
2048@@ -26,7 +26,7 @@
2049 CPP="Ubuntu.Components Ubuntu.Components.ListItems Ubuntu.Components.Popups Ubuntu.Components.Pickers Ubuntu.Components.Styles Ubuntu.Components.Themes Ubuntu.Layouts Ubuntu.PerformanceMetrics Ubuntu.Test"
2050 echo Dumping QML API of C++ components
2051 test -s $BUILD_DIR/components.api.new && rm $BUILD_DIR/components.api.new
2052-env ALARM_BACKEND=memory QML2_IMPORT_PATH=$BUILD_DIR/qml LD_LIBRARY_PATH=$BUILD_DIR/lib \
2053+env ALARM_BACKEND=memory \
2054 $BUILD_DIR/apicheck/apicheck \
2055 --qml $CPP 1>> $BUILD_DIR/components.api.new &&
2056 echo Verifying the diff between existing and generated API
2057
2058=== modified file 'tests/uitk_test_plan.sh' (properties changed: -x to +x)
2059--- tests/uitk_test_plan.sh 2016-04-04 04:41:23 +0000
2060+++ tests/uitk_test_plan.sh 2016-04-12 11:09:51 +0000
2061@@ -203,7 +203,7 @@
2062 function device_comission {
2063 if [ ${COMISSION_BOOTSTRAP} == true ]; then
2064 # bootstrap the device with the latest image
2065- ubuntu-device-flash --revision=399 touch --channel=${CHANNEL} --wipe --bootstrap --developer-mode --password=0000a
2066+ ubuntu-device-flash touch --serial=${SERIALNUMBER} --channel=${CHANNEL} --wipe --bootstrap --developer-mode --password=0000
2067 elif [ ${COMISSION_FLASH} == true ]; then
2068 adb -s ${SERIALNUMBER} wait-for-device
2069 # Avoid https://bugs.launchpad.net/gallery-app/+bug/1363190
2070@@ -393,7 +393,7 @@
2071 RTM=false
2072 CHANNEL="ubuntu-touch/devel-proposed/ubuntu"
2073 DISTRO="ubuntu"
2074- SERIES="wily"
2075+ SERIES="xenial"
2076 ;;
2077 w)
2078 DISTUPGRADE=true
2079@@ -423,7 +423,7 @@
2080 echo -e "\t-p : Source PPA for the UITK. Default $PPA. Use -p archive to test stock image or -p [0-9]* to set a silo."
2081 echo -e "\t-f : Filter for the test suite. Default $FILTER"
2082 echo -e "\t-a : Start the test suite from the given test."
2083- echo -e "\t-u : Provision the Development release of Ubuntu, Wily. Default is vivid-overlay (formerly RTM)."
2084+ echo -e "\t-u : Provision the Development release of Ubuntu, Xenial. Default is vivid-overlay (formerly RTM)."
2085 echo -e "\t-w : dist-upgrade to the whole PPA instead of just Ubuntu UI Toolkit. Default is only UITK."
2086 echo -e "\t-q : Provision the device for normal use with the ${PPA} enabled"
2087 echo ""
2088@@ -442,13 +442,13 @@
2089 echo "Validate the UITK from teh archive on an vivid-overlay image"
2090 echo -e "\t$ ./uitk_test_plan.sh -c -p archive"
2091 echo ""
2092- echo "Validate the UITK from a specific CI silo on an Ubuntu Wily image"
2093+ echo "Validate the UITK from a specific CI silo on an Ubuntu Xenial image"
2094 echo -e "\t$ ./uitk_test_plan.sh -c -p 001 -u"
2095 echo ""
2096 echo "Provision the device for manual testing with the latest vivid-overlay image"
2097 echo -e "\t$ ./uitk_test_plan.sh -c -p archive -n"
2098 echo ""
2099- echo "Provision the device for manual testing with the latest Ubuntu Wily image"
2100+ echo "Provision the device for manual testing with the latest Ubuntu Xenial image"
2101 echo -e "\t$ ./uitk_test_plan.sh -c -p archive -u -n"
2102 echo ""
2103 echo "Run the test plan on an already provisioned device"
2104
2105=== modified file 'tests/unit/runtest.sh'
2106--- tests/unit/runtest.sh 2016-04-04 04:47:11 +0000
2107+++ tests/unit/runtest.sh 2016-04-12 11:09:51 +0000
2108@@ -17,23 +17,62 @@
2109 # Author: Juhapekka Piiroinen <juhapekka.piiroinen@canonical.com>
2110 ################################################################################
2111
2112-. `dirname $0`/../../build_paths.inc
2113+set -e
2114+
2115+source `dirname $0`/../../export_qml_dir.sh
2116
2117 _CMD=""
2118 _TARGETPATH=$1
2119 _TESTFILEPATH=$2
2120 _MINIMAL=$3
2121
2122-_TARGET=$(basename $1)
2123-_TESTFILE=$(basename $2)
2124-_LIB_PATH="${BUILD_DIR}/lib:${BUILD_DIR}/qml/Ubuntu/Components:${BUILD_DIR}/qml/Ubuntu/Test:$LD_LIBRARY_PATH"
2125-_IMPORT_PATH="${BUILD_DIR}/qml:$QML2_IMPORT_PATH"
2126-_THEMES_PATH="${BUILD_DIR}/qml"
2127+relpath() {
2128+ python -c 'import os, sys; print(os.path.relpath(*sys.argv[1:]))' $*
2129+}
2130+
2131+if [ -z $_TESTFILEPATH ]; then
2132+ _TESTFILEPATH=$_TARGETPATH
2133+elif [[ 'minimal custom' == *$_TESTFILEPATH* ]]; then
2134+ _MINIMAL=$_TESTFILEPATH
2135+ _TESTFILEPATH=$_TARGETPATH
2136+fi
2137+test -z $_MINIMAL && _MINIMAL=default
2138+
2139+if [ -z $_TARGETPATH ]; then
2140+ echo Usage:
2141+ echo " $0 TEST_EXECUTABLE [QML_FILE] [QT_QPA_PLATFORM]"
2142+ echo ''
2143+ echo 'Examples:'
2144+ echo " $0 $(relpath ${BUILD_DIR}/tests/unit/tst_components/tst_components) tst_label13.qml minimal"
2145+ echo ''
2146+ echo " cd $(relpath ${BUILD_DIR}/tests/unit/tst_mainview)"
2147+ echo " ../$(basename $0) tst_mainview minimal"
2148+ echo " cd ../../.."
2149+ echo ''
2150+ echo " cd $(relpath ${BUILD_DIR}/tests/unit_x11/tst_components)"
2151+ echo " ../../xvfb.sh ../../unit/$(basename $0) tst_components tst_listitem13.qml"
2152+ echo " cd ../../.."
2153+ echo ''
2154+ echo " $(relpath ${BUILD_DIR}/tests/xvfb.sh) $0 $(relpath ${BUILD_DIR}/tests/unit_x11/tst_bottomedge/tst_bottomedge)"
2155+ exit 1
2156+fi
2157+
2158+_TARGET=$(basename $_TARGETPATH)
2159+_TESTFILE=$(basename $_TESTFILEPATH)
2160 _XML="${BUILD_DIR}/tests/test_$_TARGET_$_TESTFILE.xml"
2161
2162 _ARGS="-p -o -p $_XML,xunitxml -p -o -p -,txt"
2163
2164-set +e
2165+function create_fallback_xml {
2166+ cat << EOF > $_XML
2167+<?xml version="1.0" encoding="UTF-8" ?>
2168+<testsuite errors="1" failures="1" tests="1" name="$_TESTFILE">
2169+ <testcase result="fail" name="${_TESTFILE}_Execution">
2170+ <failure message="$1" result="fail"/>
2171+ </testcase>
2172+</testsuite>
2173+EOF
2174+}
2175
2176 function create_test_cmd {
2177 if [[ "$_TARGETPATH" = /* ]]; then
2178@@ -41,23 +80,21 @@
2179 else
2180 EXE=./$_TARGETPATH
2181 fi
2182- _CMD="-n $_TESTFILE -m 300"
2183+ _CMD="-n $_TESTFILE -m 500"
2184
2185 DEB_HOST_ARCH=$(dpkg-architecture -qDEB_HOST_ARCH)
2186 if [[ ${DEB_HOST_ARCH} =~ 'arm' ]]; then
2187- _CMD="dbus-test-runner --task $EXE $_CMD"
2188+ _CMD="dbus-test-runner --task $(readlink -f $EXE) $_CMD"
2189 else
2190 _CMD="dbus-test-runner --task gdb -p --quiet $_CMD"
2191- _CMD="$_CMD -p --batch -p -ex -p 'set print thread-events off' -p -ex -p run -p -ex -p bt -p --return-child-result -p --args -p $EXE"
2192- fi
2193-
2194- if [ "$_MINIMAL" = "minimal" ]; then
2195- _CMD="$_CMD -p -platform -p minimal"
2196- elif [ "$_MINIMAL" = "custom" ]; then
2197- _CMD="$_CMD -p -platform -p custom"
2198- fi
2199-
2200- if [ $_TARGETPATH != $_TESTFILEPATH ]; then
2201+ _CMD="$_CMD -p --batch -p -ex -p 'set print thread-events off' -p -ex -p run -p -ex -p bt -p --return-child-result -p --args -p $(readlink -f $EXE)"
2202+ fi
2203+
2204+ if [[ 'minimal custom' == *$_MINIMAL* ]]; then
2205+ _CMD="$_CMD -p -platform -p $_MINIMAL"
2206+ fi
2207+
2208+ if [[ $_TESTFILEPATH == *\.qml* ]]; then
2209 _CMD="$_CMD -p -input -p $_TESTFILEPATH"
2210 fi
2211 _CMD="$_CMD -p -maxwarnings -p 100"
2212@@ -70,14 +107,18 @@
2213 echo "Error: $_TARGET wasn't built!"
2214 RESULT=2
2215 elif [ $DISPLAY ]; then
2216+ cd $(dirname $_TARGETPATH)
2217+
2218 # https://bugs.launchpad.net/ubuntu-ui-toolkit/+bug/1256999
2219 # https://bugreports.qt-project.org/browse/QTBUG-36243
2220
2221- QML2_IMPORT_PATH=${_IMPORT_PATH} UBUNTU_UI_TOOLKIT_THEMES_PATH=${_THEMES_PATH} \
2222- LD_LIBRARY_PATH=${_LIB_PATH} \
2223 ALARM_BACKEND=memory SUPPRESS_DEPRECATED_NOTE=no \
2224 QT_LOGGING_RULES="[PERFORMANCE].warning=false" \
2225 $_CMD $_ARGS 2>&1 | grep -v 'QFontDatabase: Cannot find font directory'
2226+ if [ ! -s $_XML ]; then
2227+ # Write fallback in case it crashed and the file is empty
2228+ create_fallback_xml "Test results corrupted (crash)"
2229+ fi
2230 if [ "x$UITK_TEST_KEEP_RUNNING" != "x1" ]; then
2231 ${BUILD_DIR}/tests/checkresults.sh $_XML
2232 RESULT=$?
2233@@ -98,6 +139,8 @@
2234 return $RESULT
2235 }
2236
2237+# Always create XML in case the test can't be run, eg. .so file missing
2238+create_fallback_xml "Test couldn't be run"
2239 create_test_cmd
2240 execute_test_cmd
2241 RESULT=$?
2242
2243=== modified file 'tests/unit_x11/tst_components/tst_adaptivepagelayout.qml'
2244--- tests/unit_x11/tst_components/tst_adaptivepagelayout.qml 2016-03-07 06:19:27 +0000
2245+++ tests/unit_x11/tst_components/tst_adaptivepagelayout.qml 2016-04-12 11:09:51 +0000
2246@@ -314,6 +314,7 @@
2247 ];
2248 }
2249 function test_forced_synchronous_loading_bug1540449(data) {
2250+ layout.asynchronous = false;
2251 layout[data.func](layout.primaryPage, data.page);
2252 waitForRendering(layout, 400);
2253
2254
2255=== renamed file 'tests/unit_x11/tst_components/tst_datepicker.qml' => 'tests/unit_x11/tst_components/tst_datepicker12.qml.SEGFAULT.bug1567840'
2256=== renamed file 'tests/unit_x11/tst_components/tst_datepicker13.qml' => 'tests/unit_x11/tst_components/tst_datepicker13.SEGFAULT.bug1567840'
2257=== modified file 'tests/unit_x11/tst_components/tst_header.qml'
2258--- tests/unit_x11/tst_components/tst_header.qml 2016-02-01 21:50:28 +0000
2259+++ tests/unit_x11/tst_components/tst_header.qml 2016-04-12 11:09:51 +0000
2260@@ -28,8 +28,8 @@
2261 Header {
2262 id: header
2263 flickable: flickable
2264- z:1
2265- width: parent.width
2266+ z: 1
2267+ width: parent ? parent.width : 234
2268 height: root.initialHeaderHeight
2269
2270 Rectangle {
2271@@ -196,6 +196,7 @@
2272 }
2273
2274 function init() {
2275+ header.flickable = flickable;
2276 flickable.contentHeight = 2*flickable.height;
2277 flickable.interactive = true;
2278 flickable.contentY = -header.height;
2279@@ -343,14 +344,72 @@
2280
2281 compare(otherFlickable.topMargin, otherFlickable.initialTopMargin, "Flickable top margin is not initialized properly.");
2282 header.flickable = otherFlickable;
2283- compare(otherFlickable.topMargin, header.height, "Setting flickable does not update flickable top margin.");
2284- compare(flickable.topMargin, 0, "Changing the flickable does not reset the previous flickable top margin to 0.");
2285+ compare(otherFlickable.topMargin, header.height + otherFlickable.initialTopMargin,
2286+ "Setting flickable does not update flickable top margin.");
2287+ compare(flickable.topMargin, 0,
2288+ "Changing the flickable does not reset the previous flickable top margin to 0.");
2289
2290 header.flickable = flickable;
2291 compare(otherFlickable.topMargin, otherFlickable.initialTopMargin, "Reverting flickable does not restore the other flickable top margin.");
2292 compare(flickable.topMargin, header.height, "Reverting flickable breaks flickable top margin.");
2293 }
2294
2295+ function test_flickable_margins_invisible_header_bug1560458_bug1560419_data() {
2296+ return [
2297+ { tag: "Inititial topMargin = 0",
2298+ flickable: flickable,
2299+ initialTopMargin: 0
2300+ },
2301+ { tag: "Initial topMargin > 0",
2302+ flickable: otherFlickable,
2303+ initialTopMargin: otherFlickable.initialTopMargin
2304+ }
2305+ ];
2306+ }
2307+
2308+ function test_flickable_margins_invisible_header_bug1560458_bug1560419(data) {
2309+ var h = header.height;
2310+ var fl = data.flickable;
2311+ // the original margin before the flickable is connected to the header
2312+ var fmargin = data.initialTopMargin;
2313+ if (header.flickable !== fl) {
2314+ compare(fl.topMargin, fmargin,
2315+ "Incorrect initial topMargin for flickable.");
2316+ header.flickable = fl;
2317+ }
2318+
2319+ compare(fl.topMargin, h + fmargin,
2320+ "Flickable top margin does not match header height.");
2321+ header.visible = false;
2322+ compare(fl.topMargin, fmargin,
2323+ "Invisible header sets flickable.topMargin.");
2324+ header.visible = true;
2325+ compare(fl.topMargin, h + fmargin,
2326+ "Making flickable visible does not set flickable.topMargin.");
2327+ header.height = 0;
2328+ compare(fl.topMargin, fmargin,
2329+ "Header with height = 0 sets flickable.topMargin.");
2330+ header.height = h;
2331+ compare(fl.topMargin, h + fmargin,
2332+ "Setting header height does not set flickable.topMargin.");
2333+
2334+ // Setting opacity to 0 should not change flickable.topMargin.
2335+ // This allows opacity animations.
2336+ header.opacity = 0.0;
2337+ compare(fl.topMargin, h + fmargin,
2338+ "Setting header opacity to 0 changes flickable.topMargin.");
2339+ header.opacity = 1.0;
2340+ compare(fl.topMargin, h + fmargin,
2341+ "Setting header opacity to 1 changes flickable.topMargin.");
2342+
2343+ header.parent = null;
2344+ compare(fl.topMargin, fmargin,
2345+ "Header with no parent sets flickable.topMargin.");
2346+ header.parent = root;
2347+ compare(fl.topMargin, h + fmargin,
2348+ "Header with parent does not set flickable.topMargin.");
2349+ }
2350+
2351 function test_flickable_contentHeight_bug1156573() {
2352 var old_height = flickable.contentHeight;
2353 header.exposed = false;
2354
2355=== modified file 'tests/unit_x11/tst_components/tst_page_with_header.qml'
2356--- tests/unit_x11/tst_components/tst_page_with_header.qml 2015-10-14 12:07:15 +0000
2357+++ tests/unit_x11/tst_components/tst_page_with_header.qml 2016-04-12 11:09:51 +0000
2358@@ -1,5 +1,5 @@
2359 /*
2360- * Copyright (C) 2015 Canonical Ltd.
2361+ * Copyright (C) 2016 Canonical Ltd.
2362 *
2363 * This program is free software; you can redistribute it and/or modify
2364 * it under the terms of the GNU Lesser General Public License as published by
2365@@ -31,10 +31,10 @@
2366 objectName: "my_rectangle"
2367 id: myRectangle
2368 anchors {
2369- left: parent.left
2370- right: parent.right
2371+ left: parent ? parent.left : undefined
2372+ right: parent ? parent.right : undefined
2373 }
2374- height: units.gu(6)
2375+ height: myPageHeader.height
2376 color: UbuntuColors.red
2377 }
2378
2379@@ -64,7 +64,7 @@
2380 anchors {
2381 left: parent.left
2382 right: parent.right
2383- top: parent.top
2384+ top: page.header ? page.header.bottom : parent.top
2385 topMargin: units.gu(10)
2386 leftMargin: units.gu(10)
2387 rightMargin: units.gu(10)
2388@@ -126,26 +126,24 @@
2389
2390 function test_page_with_no_header() {
2391 page.header = null;
2392- compare(myPageHeader.parent, invisible,
2393- "Header parent is not correctly reverted when unsetting Page.header.");
2394- compare(myPageHeader.visible, false,
2395- "My PageHeader is still visible after re-parenting it to an invisible Item.");
2396+ compare(myPageHeader.parent, null,
2397+ "Header parent is not wet to null when unsetting Page.header.");
2398 compare(appHeader.visible, true,
2399 "AppHeader does not become visible when Page.header is null.");
2400 }
2401
2402 function test_page_with_alternative_header() {
2403 page.header = myRectangle;
2404- compare(myPageHeader.parent, invisible,
2405- "Header parent not correctly reverted when setting a different Page.header.");
2406+ compare(myPageHeader.parent, null,
2407+ "Header parent not null after setting a different Page.header.");
2408 compare(myRectangle.parent, page,
2409 "Rectangle parent is not correctly set to page after setting it as Page.header.");
2410 compare(appHeader.visible, false,
2411 "Setting a different Page.header Item shows the AppHeader.");
2412
2413 page.header = myPageHeader;
2414- compare(myRectangle.parent, invisible,
2415- "Rectangle parent is not correctly reverted after unsetting it as Page.header.");
2416+ compare(myRectangle.parent, null,
2417+ "Rectangle parent is not set to null after unsetting it as Page.header.");
2418 // myPageHeader parent is checked in cleanup().
2419 }
2420 }
2421
2422=== modified file 'tests/unit_x11/tst_components/tst_pageheader.qml'
2423--- tests/unit_x11/tst_components/tst_pageheader.qml 2015-12-21 13:44:54 +0000
2424+++ tests/unit_x11/tst_components/tst_pageheader.qml 2016-04-12 11:09:51 +0000
2425@@ -89,6 +89,7 @@
2426 iconName: "attachment"
2427 text: "Attach"
2428 objectName: "five"
2429+ enabled: false
2430 },
2431 Action {
2432 iconName: "contact"
2433@@ -130,6 +131,7 @@
2434 z:1
2435
2436 title: "Default title"
2437+ subtitle: subtitleSwitch.checked ? "This is amaaaaaazing" : ""
2438 contents: contentsSwitch.checked ? alternativeContents : null
2439 sections.actions: sectionsSwitch.checked ? root.sectionActions : []
2440 trailingActionBar.actions: trailingActionsSwitch.checked ?
2441@@ -231,7 +233,15 @@
2442 checked: false
2443 }
2444 Label {
2445- text: "Resize with window"
2446+ text: "resize with window"
2447+ }
2448+
2449+ Switch {
2450+ id: subtitleSwitch
2451+ checked: false
2452+ }
2453+ Label {
2454+ text: "subtitle"
2455 }
2456 }
2457
2458
2459=== modified file 'tests/unit_x11/tst_components/tst_pagestack.qml'
2460--- tests/unit_x11/tst_components/tst_pagestack.qml 2016-01-07 14:55:33 +0000
2461+++ tests/unit_x11/tst_components/tst_pagestack.qml 2016-04-12 11:09:51 +0000
2462@@ -34,6 +34,41 @@
2463 id: pageInStack
2464 }
2465 }
2466+
2467+ Column {
2468+ // for manual testing
2469+ visible: pageStack.depth === 0
2470+ anchors {
2471+ left: parent.left
2472+ right: parent.right
2473+ top: parent.top
2474+ margins: units.gu(1)
2475+ }
2476+ Button {
2477+ text: "page1"
2478+ onClicked: pageStack.push(page1)
2479+ }
2480+ Button {
2481+ text: "page2"
2482+ onClicked: pageStack.push(page2)
2483+ }
2484+ Button {
2485+ text: "pageWithPage"
2486+ onClicked: pageStack.push(pageWithPage)
2487+ }
2488+ Button {
2489+ text: "tabs"
2490+ onClicked: pageStack.push(tabs)
2491+ }
2492+ Button {
2493+ text: "pageWithHeader"
2494+ onClicked: pageStack.push(pageWithHeader)
2495+ }
2496+ Button {
2497+ text: "pageComponent"
2498+ onClicked: pageStack.push(pageComponent)
2499+ }
2500+ }
2501 }
2502 Page {
2503 id: page1
2504@@ -238,19 +273,18 @@
2505 "PageStack.push() returns Page created from QML file");
2506 }
2507
2508- function test_page_header_back_button() {
2509+ function test_page_header_back_button_bug1565811() {
2510 pageStack.push(pageWithHeader);
2511- var backButton = findChild(pageWithHeader.header, "pagestack_back_action_button");
2512- // FIXME TIM: when visibleActions is fixed, only check for backButton, null.
2513- compare(backButton == null || !backButton.visible, true,
2514+ var backButton = findChild(pageWithHeader.header.leadingActionBar,
2515+ "pagestack_back_action_button");
2516+ compare(backButton, null,
2517 "Page header shows back button with only one page on the stack.");
2518-
2519 pageStack.pop();
2520 pageStack.push(page1);
2521 pageStack.push(pageWithHeader);
2522 waitForHeaderAnimation(mainView);
2523 backButton = findChild(pageWithHeader.header, "pagestack_back_action_button");
2524- compare(backButton.visible, true,
2525+ compare(backButton && backButton.visible, true,
2526 "Page header has no back button with two pages on the stack.");
2527 }
2528 }
2529
2530=== modified file 'tests/unit_x11/tst_components/tst_scrollbar_header.qml'
2531--- tests/unit_x11/tst_components/tst_scrollbar_header.qml 2016-03-30 15:14:32 +0000
2532+++ tests/unit_x11/tst_components/tst_scrollbar_header.qml 2016-04-12 11:09:51 +0000
2533@@ -124,7 +124,8 @@
2534
2535 PageHeader {
2536 id: standardHeaderItem
2537- visible: pageItem.header === standardHeaderItem
2538+ // hide the header until it is used by the page
2539+ parent: null
2540 title: "Default title"
2541 flickable: flickable_movingHeaderTest
2542 trailingActionBar.actions: [
2543@@ -137,7 +138,8 @@
2544 }
2545 PageHeader {
2546 id: editHeaderItem
2547- visible: pageItem.header === editHeaderItem
2548+ // hide the header until it is used by the page
2549+ parent: null
2550 flickable: flickable_movingHeaderTest
2551 property Component delegate: Component {
2552 AbstractButton {
2553@@ -241,14 +243,7 @@
2554 function test_handlingOfMovingHeader(data) {
2555 var page = pageItem
2556 var header = data.header
2557-
2558 page.header = header
2559- console.log(page.header, header.flickable)
2560-
2561- //make sure the currently tested header is the one driving the flickable changes
2562- //FIXME: this should not be needed after #1560458 is fixed
2563- header.flickable = null
2564- header.flickable = flickable_movingHeaderTest
2565
2566 compare(page.header, header, "Handling of moving header: wrong header.")
2567 compare(scrollbar_movingHeaderTest.__styleInstance.isVertical, true, "Scrollbar is not vertical.")
2568@@ -260,9 +255,8 @@
2569 checkScrollbarPositionRelativeToPage(scrollbar_movingHeaderTest, page, page.head.contents.height, data.tag)
2570 return
2571 } else {
2572- header.flickable = flickable_movingHeaderTest
2573 compare(header.flickable, flickable_movingHeaderTest, "Wrong PageHeader flickable.")
2574- checkScrollbarPositionRelativeToPage(scrollbar_movingHeaderTest, page, page.header.height, data.tag)
2575+ checkScrollbarPositionRelativeToPage(scrollbar_movingHeaderTest, page, page.header.height, data.tag + ", at initialization.")
2576 }
2577
2578 var tmpHeaderHeight = header.height
2579@@ -279,7 +273,6 @@
2580 //should cover the scrollbar)
2581 header.flickable = null
2582 compare(header.flickable, null, "Wrong PageHeader flickable.")
2583- expectFailContinue("Standard header", "Waiting on Header bug #1560458")
2584 checkScrollbarPositionRelativeToPage(scrollbar_movingHeaderTest, page, 0, data.tag)
2585
2586 //reassign the correct flickable and check again
2587@@ -289,7 +282,6 @@
2588
2589 header.visible = false
2590 compare(header.visible, false, "Header visibility did not change, should have been false.")
2591- expectFailContinue("", "Waiting on Header bug #1560458")
2592 checkScrollbarPositionRelativeToPage(scrollbar_movingHeaderTest, page, 0, data.tag + ", invisible header")
2593
2594 header.visible = true
2595
2596=== modified file 'tests/unit_x11/tst_layouts/tst_layouts.cpp'
2597--- tests/unit_x11/tst_layouts/tst_layouts.cpp 2016-01-30 10:51:22 +0000
2598+++ tests/unit_x11/tst_layouts/tst_layouts.cpp 2016-04-12 11:09:51 +0000
2599@@ -29,6 +29,7 @@
2600 #include "ullayouts.h"
2601 #include "ucunits.h"
2602 #include "uctestcase.h"
2603+#include "uctheme.h"
2604 #include <QtQuick/private/qquickanchors_p.h>
2605 #include <QtQuick/private/qquickanchors_p_p.h>
2606
2607@@ -95,10 +96,12 @@
2608 private Q_SLOTS:
2609 void initTestCase()
2610 {
2611+ qputenv("SUPPRESS_DEPRECATED_NOTE", "yes");
2612 }
2613
2614- void cleanupTestCase()
2615+ void cleanup()
2616 {
2617+ UCTheme::previousVersion = 0;
2618 }
2619
2620 void testCase_NoLayouts()
2621@@ -289,7 +292,8 @@
2622
2623 void testCase_NestedLayouts_ExtraLarge()
2624 {
2625- QTest::ignoreMessage(QtWarningMsg, "\"There are still \"1\" items in the process of being created at engine destruction.\"");
2626+ QRegularExpression expression(".+ items in the process of being created at engine destruction.+");
2627+ QTest::ignoreMessage(QtWarningMsg, expression);
2628 QScopedPointer<QQuickView> view(loadTest("NestedLayouts.qml"));
2629 QVERIFY(view);
2630 QQuickItem *root = view->rootObject();
2631
2632=== added file 'tests/unit_x11/tst_mousefilters/EnteredExitedOnMouseMove.qml'
2633--- tests/unit_x11/tst_mousefilters/EnteredExitedOnMouseMove.qml 1970-01-01 00:00:00 +0000
2634+++ tests/unit_x11/tst_mousefilters/EnteredExitedOnMouseMove.qml 2016-04-12 11:09:51 +0000
2635@@ -0,0 +1,32 @@
2636+/*
2637+ * Copyright 2016 Canonical Ltd.
2638+ *
2639+ * This program is free software; you can redistribute it and/or modify
2640+ * it under the terms of the GNU Lesser General Public License as published by
2641+ * the Free Software Foundation; version 3.
2642+ *
2643+ * This program is distributed in the hope that it will be useful,
2644+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2645+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2646+ * GNU Lesser General Public License for more details.
2647+ *
2648+ * You should have received a copy of the GNU Lesser General Public License
2649+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
2650+ */
2651+
2652+import QtQuick 2.4
2653+import Ubuntu.Components 1.3
2654+
2655+Rectangle {
2656+ width: units.gu(50)
2657+ height: units.gu(40)
2658+
2659+ MouseArea {
2660+ anchors.fill: parent
2661+ anchors.margins: units.gu(10)
2662+
2663+ objectName: "FilterOwner"
2664+ hoverEnabled: true
2665+ Mouse.enabled: true
2666+ }
2667+}
2668\ No newline at end of file
2669
2670=== modified file 'tests/unit_x11/tst_mousefilters/tst_mousefilterstest.cpp'
2671--- tests/unit_x11/tst_mousefilters/tst_mousefilterstest.cpp 2016-02-09 13:15:19 +0000
2672+++ tests/unit_x11/tst_mousefilters/tst_mousefilterstest.cpp 2016-04-12 11:09:51 +0000
2673@@ -981,6 +981,76 @@
2674 QTest::mouseRelease(view.data(), Qt::LeftButton, 0, QPoint(x, i));
2675 }
2676
2677+ //This is to test that entered/exited events are fired as a consequence of a mouse move.
2678+ //When mouse is PRESSED, in fact, you won't get hover events. Mouse moves have to update
2679+ //the hovered state (and that will trigger entered()/exited()). This fixes lp:1566378
2680+ void testCase_enteredExitedOnMouseMove_lp1566378() {
2681+ QScopedPointer<QQuickView> view(loadTest("EnteredExitedOnMouseMove.qml"));
2682+ QVERIFY(view);
2683+ UCMouse *filter = attachedFilter<UCMouse>(view->rootObject(), "FilterOwner");
2684+ QVERIFY(filter);
2685+ QSignalSpy pressed(filter, SIGNAL(pressed(QQuickMouseEvent*, QQuickItem*)));
2686+ QSignalSpy positionChanged(filter, SIGNAL(positionChanged(QQuickMouseEvent*, QQuickItem*)));
2687+ QSignalSpy entered(filter, SIGNAL(entered(QQuickMouseEvent*, QQuickItem*)));
2688+ QSignalSpy exited(filter, SIGNAL(exited(QQuickMouseEvent*, QQuickItem*)));
2689+
2690+ QObject::connect(filter, SIGNAL(pressed(QQuickMouseEvent*, QQuickItem*)), this, SLOT(onMouseEvent(QQuickMouseEvent*, QQuickItem*)));
2691+ QObject::connect(filter, SIGNAL(positionChanged(QQuickMouseEvent*, QQuickItem*)), this, SLOT(onMouseEvent2(QQuickMouseEvent*, QQuickItem*)));
2692+ QObject::connect(filter, SIGNAL(entered(QQuickMouseEvent*, QQuickItem*)), this, SLOT(onMouseEvent3(QQuickMouseEvent*, QQuickItem*)));
2693+ QObject::connect(filter, SIGNAL(exited(QQuickMouseEvent*, QQuickItem*)), this, SLOT(onMouseEvent3(QQuickMouseEvent*, QQuickItem*)));
2694+
2695+ preventDblClick();
2696+
2697+ //don't use guPoint(0,0) as it's the same as not passing any point, i.e. it sends mouseMove to the
2698+ //center of the view
2699+ QTest::mouseMove(view.data(), guPoint(1, 1));
2700+ QTest::mouseMove(view.data(), guPoint(15, 15));
2701+ QTest::waitForEvents();
2702+
2703+ QCOMPARE(entered.count(), 1);
2704+ QCOMPARE(mouseEvent3Params.handler, QString("EVENT4"));
2705+ QCOMPARE(mouseEvent3Params.pressedButton, Qt::NoButton);
2706+
2707+ QTest::mousePress(view.data(), Qt::LeftButton, 0, guPoint(15, 15));
2708+ QTest::waitForEvents();
2709+ QCOMPARE(mouseEventParams.handler, QString("EVENT1"));
2710+ QCOMPARE(mouseEventParams.pressedButton, Qt::LeftButton);
2711+
2712+ QTest::mouseMove(view.data(), guPoint(25, 15));
2713+
2714+ //go out of the mousearea on the right
2715+ QTest::mouseMove(view.data(), guPoint(45, 15));
2716+ QTest::waitForEvents();
2717+ QCOMPARE(mouseEvent2Params.handler, QString("EVENT2"));
2718+ QCOMPARE(mouseEvent2Params.pressedButton, Qt::LeftButton);
2719+ QCOMPARE(exited.count(), 1);
2720+ QCOMPARE(mouseEvent3Params.handler, QString("EVENT4"));
2721+ QCOMPARE(mouseEvent3Params.pressedButton, Qt::LeftButton);
2722+
2723+ //move back in
2724+ QTest::mouseMove(view.data(), guPoint(25, 15));
2725+ QTest::waitForEvents();
2726+ QCOMPARE(mouseEvent2Params.handler, QString("EVENT2"));
2727+ QCOMPARE(mouseEvent2Params.pressedButton, Qt::LeftButton);
2728+ QCOMPARE(entered.count(), 2);
2729+ QCOMPARE(mouseEvent3Params.handler, QString("EVENT4"));
2730+ QCOMPARE(mouseEvent3Params.pressedButton, Qt::LeftButton);
2731+
2732+ //and out again
2733+ QTest::mouseMove(view.data(), guPoint(45, 15));
2734+ QTest::waitForEvents();
2735+ QCOMPARE(mouseEvent2Params.handler, QString("EVENT2"));
2736+ QCOMPARE(mouseEvent2Params.pressedButton, Qt::LeftButton);
2737+ QCOMPARE(exited.count(), 2);
2738+ QCOMPARE(mouseEvent3Params.handler, QString("EVENT4"));
2739+ QCOMPARE(mouseEvent3Params.pressedButton, Qt::LeftButton);
2740+
2741+ QTest::mouseRelease(view.data(), Qt::LeftButton, 0, guPoint(45, 15));
2742+ QTest::waitForEvents();
2743+
2744+ QCOMPARE(positionChanged.count(), 4);
2745+ }
2746+
2747 void testCase_hoverEvents() {
2748 QScopedPointer<QQuickView> view(loadTest("HoverEvent.qml"));
2749 QVERIFY(view);
2750
2751=== modified file 'ubuntu-sdk.pro'
2752--- ubuntu-sdk.pro 2015-12-11 13:35:10 +0000
2753+++ ubuntu-sdk.pro 2016-04-12 11:09:51 +0000
2754@@ -8,7 +8,10 @@
2755 requires(qtHaveModule(quick))
2756 load(qt_parts)
2757
2758-SUBDIRS += po documentation app-launch-profiler ubuntu-ui-toolkit-launcher apicheck
2759+src_uitk_launcher.subdir = ubuntu-ui-toolkit-launcher
2760+src_uitk_launcher.depends = sub-src
2761+
2762+SUBDIRS += po documentation app-launch-profiler src_uitk_launcher apicheck
2763
2764 sub_tests.CONFIG -= no_default_target
2765 sub_tests.CONFIG -= no_default_install
2766
2767=== removed file 'ubuntu-ui-toolkit-launcher/MouseTouchAdaptor.cpp'
2768--- ubuntu-ui-toolkit-launcher/MouseTouchAdaptor.cpp 2014-06-16 09:50:56 +0000
2769+++ ubuntu-ui-toolkit-launcher/MouseTouchAdaptor.cpp 1970-01-01 00:00:00 +0000
2770@@ -1,159 +0,0 @@
2771-/*
2772- * Copyright 2014 Canonical Ltd.
2773- *
2774- * This program is free software; you can redistribute it and/or modify
2775- * it under the terms of the GNU Lesser General Public License as published by
2776- * the Free Software Foundation; version 3.
2777- *
2778- * This program is distributed in the hope that it will be useful,
2779- * but WITHOUT ANY WARRANTY; without even the implied warranty of
2780- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2781- * GNU Lesser General Public License for more details.
2782- *
2783- * You should have received a copy of the GNU Lesser General Public License
2784- * along with this program. If not, see <http://www.gnu.org/licenses/>.
2785- *
2786- * Authored by: Daniel d'Andrada <daniel.dandrada@canonical.com>
2787- *
2788- */
2789-
2790-#include "MouseTouchAdaptor.h"
2791-
2792-#include <qpa/qwindowsysteminterface.h>
2793-
2794-#include <QtGui/QMouseEvent>
2795-#include <QtTest/QTest>
2796-
2797-using QTest::QTouchEventSequence;
2798-
2799-namespace {
2800-Qt::MouseButton translateMouseButton(xcb_button_t detail)
2801-{
2802- switch (detail) {
2803- case 1: return Qt::LeftButton;
2804- case 2: return Qt::MidButton;
2805- case 3: return Qt::RightButton;
2806- // Button values 4-7 are Wheel events
2807- default: return Qt::NoButton;
2808- }
2809-}
2810-} // end of anonymous namespace
2811-
2812-MouseTouchAdaptor::MouseTouchAdaptor()
2813- : m_leftButtonIsPressed(false)
2814-{
2815- m_touchDevice = new QTouchDevice;
2816- m_touchDevice->setType(QTouchDevice::TouchScreen);
2817- QWindowSystemInterface::registerTouchDevice(m_touchDevice);
2818-}
2819-
2820-bool MouseTouchAdaptor::nativeEventFilter(const QByteArray & eventType,
2821- void * message, long * /*result*/)
2822-{
2823- if (eventType != "xcb_generic_event_t") {
2824- // wrong backend.
2825- qWarning("MouseTouchAdaptor: XCB backend not in use. Adaptor inoperative!");
2826- return false;
2827- }
2828-
2829- xcb_generic_event_t *xcbEvent = static_cast<xcb_generic_event_t *>(message);
2830-
2831- switch (xcbEvent->response_type & ~0x80) {
2832- case XCB_BUTTON_PRESS:
2833- return handleButtonPress(reinterpret_cast<xcb_button_press_event_t *>(xcbEvent));
2834- break;
2835- case XCB_BUTTON_RELEASE:
2836- return handleButtonRelease(reinterpret_cast<xcb_button_release_event_t *>(xcbEvent));
2837- break;
2838- case XCB_MOTION_NOTIFY:
2839- return handleMotionNotify(reinterpret_cast<xcb_motion_notify_event_t *>(xcbEvent));
2840- break;
2841- default:
2842- return false;
2843- break;
2844- };
2845-}
2846-
2847-bool MouseTouchAdaptor::handleButtonPress(xcb_button_press_event_t *pressEvent)
2848-{
2849- Qt::MouseButton button = translateMouseButton(pressEvent->detail);
2850-
2851- // Skip the event if it wasn't a left mouse press
2852- if (button != Qt::LeftButton) {
2853- return false;
2854- }
2855-
2856- QPoint windowPos(pressEvent->event_x, pressEvent->event_y);
2857-
2858- QWindow *targetWindow = findQWindowWithXWindowID(static_cast<WId>(pressEvent->event));
2859-
2860- // no autoCommit
2861- QTouchEventSequence touchEvent = QTest::touchEvent(targetWindow, m_touchDevice, false);
2862- touchEvent.press(0, windowPos);
2863- // do not process events when committed, let the events be processed with next event loop
2864- touchEvent.commit(false);
2865-
2866- m_leftButtonIsPressed = true;
2867- return true;
2868-}
2869-
2870-bool MouseTouchAdaptor::handleButtonRelease(xcb_button_release_event_t *releaseEvent)
2871-{
2872- Qt::MouseButton button = translateMouseButton(releaseEvent->detail);
2873-
2874- // Skip the event if it wasn't a left mouse release
2875- if (button != Qt::LeftButton) {
2876- return false;
2877- }
2878-
2879- QPoint windowPos(releaseEvent->event_x, releaseEvent->event_y);
2880-
2881- QWindow *targetWindow = findQWindowWithXWindowID(static_cast<WId>(releaseEvent->event));
2882-
2883- // no autoCommit
2884- QTouchEventSequence touchEvent = QTest::touchEvent(targetWindow, m_touchDevice, false);
2885- touchEvent.release(0, windowPos);
2886- // do not process events when committed, let the events be processed with next event loop
2887- touchEvent.commit(false);
2888-
2889- m_leftButtonIsPressed = false;
2890- return true;
2891-}
2892-
2893-bool MouseTouchAdaptor::handleMotionNotify(xcb_motion_notify_event_t *event)
2894-{
2895- if (!m_leftButtonIsPressed) {
2896- return false;
2897- }
2898-
2899- QPoint windowPos(event->event_x, event->event_y);
2900-
2901- QWindow *targetWindow = findQWindowWithXWindowID(static_cast<WId>(event->event));
2902-
2903- // no autoCommit
2904- QTouchEventSequence touchEvent = QTest::touchEvent(targetWindow, m_touchDevice, false);
2905- touchEvent.move(0, windowPos);
2906- // do not process events when committed, let the events be processed with next event loop
2907- touchEvent.commit(false);
2908-
2909- return true;
2910-}
2911-
2912-QWindow *MouseTouchAdaptor::findQWindowWithXWindowID(WId windowId)
2913-{
2914- QWindowList windowList = QGuiApplication::topLevelWindows();
2915- QWindow *foundWindow = 0;
2916-
2917- int i = 0;
2918- while (!foundWindow && i < windowList.count()) {
2919- QWindow *window = windowList[i];
2920- if (window->winId() == windowId) {
2921- foundWindow = window;
2922- } else {
2923- ++i;
2924- }
2925- }
2926-
2927- Q_ASSERT(foundWindow);
2928- return foundWindow;
2929-}
2930
2931=== removed file 'ubuntu-ui-toolkit-launcher/MouseTouchAdaptor.h'
2932--- ubuntu-ui-toolkit-launcher/MouseTouchAdaptor.h 2014-06-16 09:50:56 +0000
2933+++ ubuntu-ui-toolkit-launcher/MouseTouchAdaptor.h 1970-01-01 00:00:00 +0000
2934@@ -1,50 +0,0 @@
2935-/*
2936- * Copyright 2014 Canonical Ltd.
2937- *
2938- * This program is free software; you can redistribute it and/or modify
2939- * it under the terms of the GNU Lesser General Public License as published by
2940- * the Free Software Foundation; version 3.
2941- *
2942- * This program is distributed in the hope that it will be useful,
2943- * but WITHOUT ANY WARRANTY; without even the implied warranty of
2944- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2945- * GNU Lesser General Public License for more details.
2946- *
2947- * You should have received a copy of the GNU Lesser General Public License
2948- * along with this program. If not, see <http://www.gnu.org/licenses/>.
2949- *
2950- * Authored by: Daniel d'Andrada <daniel.dandrada@canonical.com>
2951- *
2952- */
2953-
2954-#ifndef MOUSE_TOUCH_ADAPTOR_H
2955-#define MOUSE_TOUCH_ADAPTOR_H
2956-
2957-#include <QtCore/QAbstractNativeEventFilter>
2958-#include <QWindow>
2959-#include <xcb/xcb.h>
2960-
2961-class QMouseEvent;
2962-class QTouchDevice;
2963-
2964-// Transforms QMouseEvents into single-finger QTouchEvents.
2965-class MouseTouchAdaptor : public QAbstractNativeEventFilter {
2966-
2967-public:
2968- MouseTouchAdaptor();
2969-
2970- // Filters mouse events and posts the equivalent QTouchEvents.
2971- virtual bool nativeEventFilter(const QByteArray & eventType, void *message, long *result);
2972-
2973-private:
2974-
2975- bool handleButtonPress(xcb_button_press_event_t *pressEvent);
2976- bool handleButtonRelease(xcb_button_release_event_t *releaseEvent);
2977- bool handleMotionNotify(xcb_motion_notify_event_t *event);
2978- QWindow *findQWindowWithXWindowID(WId windowId);
2979-
2980- QTouchDevice *m_touchDevice;
2981- bool m_leftButtonIsPressed;
2982-};
2983-
2984-#endif // MOUSE_TOUCH_ADAPTOR_H
2985
2986=== modified file 'ubuntu-ui-toolkit-launcher/launcher.cpp'
2987--- ubuntu-ui-toolkit-launcher/launcher.cpp 2015-11-13 09:29:40 +0000
2988+++ ubuntu-ui-toolkit-launcher/launcher.cpp 2016-04-12 11:09:51 +0000
2989@@ -32,19 +32,10 @@
2990 #include <QtQuick/private/qsgcontext_p.h>
2991 #include <QtCore/QCommandLineParser>
2992 #include <QtCore/QCommandLineOption>
2993-#include "MouseTouchAdaptor.h"
2994+#include <MouseTouchAdaptor>
2995 #include <QtGui/QTouchDevice>
2996 #include <QtQml/qqml.h>
2997
2998-bool touchDevicePresent()
2999-{
3000- Q_FOREACH(const QTouchDevice *device, QTouchDevice::devices()) {
3001- if (device->type() == QTouchDevice::TouchScreen)
3002- return true;
3003- }
3004- return false;
3005-}
3006-
3007 static QObject *s_testRootObject = 0;
3008 static QObject *testRootObject(QQmlEngine *engine, QJSEngine *jsEngine)
3009 {
3010@@ -151,9 +142,9 @@
3011 view->setFlags(Qt::FramelessWindowHint);
3012 }
3013
3014- if (args.isSet(_enableTouch) && !touchDevicePresent()) {
3015+ if (args.isSet(_enableTouch)) {
3016 // has no effect if we have touch screen
3017- application.installNativeEventFilter(new MouseTouchAdaptor);
3018+ new UbuntuToolkit::MouseTouchAdaptor(&application);
3019 }
3020
3021 QUrl source(QUrl::fromLocalFile(filename));
3022
3023=== modified file 'ubuntu-ui-toolkit-launcher/ubuntu-ui-toolkit-launcher.pro'
3024--- ubuntu-ui-toolkit-launcher/ubuntu-ui-toolkit-launcher.pro 2015-11-19 08:45:15 +0000
3025+++ ubuntu-ui-toolkit-launcher/ubuntu-ui-toolkit-launcher.pro 2016-04-12 11:09:51 +0000
3026@@ -1,11 +1,9 @@
3027 TEMPLATE = app
3028 QT += qml quick
3029 # For setSharedOpenGLContext
3030-QT += core-private gui-private testlib quick-private
3031-CONFIG += no_keywords
3032-HEADERS += MouseTouchAdaptor.h
3033-SOURCES += launcher.cpp \
3034- MouseTouchAdaptor.cpp
3035+QT += core-private gui-private testlib quick-private UbuntuToolkit
3036+CONFIG += no_keywords c++11
3037+SOURCES += launcher.cpp
3038 installPath = $$[QT_INSTALL_PREFIX]/bin
3039 launcher.path = $$installPath
3040 launcher.files = ubuntu-ui-toolkit-launcher

Subscribers

People subscribed via source and target branches

to status/vote changes: