on xenial help sign in
[ Andrea Cimitan ]
b2d436eYing-Chun Liu
@@ -167,10 +167,6 @@ NB: Manual test or interation doesn't make sense for all components or classes,
167particularly the non-graphical ones. In such cases no "tryFoo" make target is
167particularly the non-graphical ones. In such cases no "tryFoo" make target is
168provided.
168provided.
169
169
170−NB: The tests expect the locale to be the C locale, they may fail if run
171−under a different locale, if you get failures others can not reproduce
172−prepend 'LC_ALL=C' to the 'make test' command
173−
174Running autopilot tests
170Running autopilot tests
175=======================
171=======================
176
172
cmake/modules/QmlTest.cmake+16−3
@@ -58,7 +58,15 @@ macro(add_manual_qml_test SUBPATH COMPONENT_NAME)
58
58
59endmacro(add_manual_qml_test)
59endmacro(add_manual_qml_test)
60
60
61+macro(add_qml_benchmark SUBPATH COMPONENT_NAME ITERATIONS)
62+ add_qml_test_internal(${SUBPATH} ${COMPONENT_NAME} ${ITERATIONS} ${ARGN})
63+endmacro(add_qml_benchmark)
64+
61macro(add_qml_test SUBPATH COMPONENT_NAME)
65macro(add_qml_test SUBPATH COMPONENT_NAME)
66+ add_qml_test_internal(${SUBPATH} ${COMPONENT_NAME} 0 ${ARGN})
67+endmacro(add_qml_test)
68+
69+macro(add_qml_test_internal SUBPATH COMPONENT_NAME ITERATIONS)
62 set(options NO_ADD_TEST NO_TARGETS)
70 set(options NO_ADD_TEST NO_TARGETS)
63 set(multi_value_keywords IMPORT_PATHS TARGETS PROPERTIES ENVIRONMENT)
71 set(multi_value_keywords IMPORT_PATHS TARGETS PROPERTIES ENVIRONMENT)
64
72
@@ -88,10 +96,17 @@ macro(add_qml_test SUBPATH COMPONENT_NAME)
88 set(function_ARGS "")
96 set(function_ARGS "")
89 endif()
97 endif()
90
98
99+ if (${ITERATIONS} GREATER 0)
100+ set(ITERATIONS_STRING "-iterations" ${ITERATIONS})
101+ else()
102+ set(ITERATIONS_STRING "")
103+ endif()
104+
91 set(qmltest_command
105 set(qmltest_command
92 env ${qmltest_ENVIRONMENT}
106 env ${qmltest_ENVIRONMENT}
93 ${qmltestrunner_exe} -input ${CMAKE_CURRENT_SOURCE_DIR}/${qmltest_FILE}.qml
107 ${qmltestrunner_exe} -input ${CMAKE_CURRENT_SOURCE_DIR}/${qmltest_FILE}.qml
94 ${qmltestrunner_imports}
108 ${qmltestrunner_imports}
109+ ${ITERATIONS_STRING}
95 -o ${CMAKE_BINARY_DIR}/${qmltest_TARGET}.xml,xunitxml
110 -o ${CMAKE_BINARY_DIR}/${qmltest_TARGET}.xml,xunitxml
96 -o -,txt
111 -o -,txt
97 ${function_ARGS}
112 ${function_ARGS}
@@ -114,7 +129,7 @@ macro(add_qml_test SUBPATH COMPONENT_NAME)
114 add_qmltest_target(${qmltest_TARGET} "${qmltest_command}" TRUE ${qmltest_NO_ADD_TEST})
129 add_qmltest_target(${qmltest_TARGET} "${qmltest_command}" TRUE ${qmltest_NO_ADD_TEST})
115 add_qmltest_target(${qmltest_xvfb_TARGET} "${qmltest_xvfb_command}" ${qmltest_NO_TARGETS} TRUE)
130 add_qmltest_target(${qmltest_xvfb_TARGET} "${qmltest_xvfb_command}" ${qmltest_NO_TARGETS} TRUE)
116 add_manual_qml_test(${SUBPATH} ${COMPONENT_NAME} ${ARGN})
131 add_manual_qml_test(${SUBPATH} ${COMPONENT_NAME} ${ARGN})
117−endmacro(add_qml_test)
132+endmacro(add_qml_test_internal)
118
133
119macro(add_binary_qml_test CLASS_NAME LD_PATH DEPS)
134macro(add_binary_qml_test CLASS_NAME LD_PATH DEPS)
120 set(testCommand
135 set(testCommand
@@ -141,8 +156,6 @@ macro(add_binary_qml_test CLASS_NAME LD_PATH DEPS)
141
156
142 add_qmltest_target(xvfbtest${CLASS_NAME} "${xvfbtestCommand}" FALSE TRUE)
157 add_qmltest_target(xvfbtest${CLASS_NAME} "${xvfbtestCommand}" FALSE TRUE)
143 add_dependencies(qmluitests xvfbtest${CLASS_NAME})
158 add_dependencies(qmluitests xvfbtest${CLASS_NAME})
144−
145− add_manual_qml_test(. ${CLASS_NAME} IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins)
146endmacro(add_binary_qml_test)
159endmacro(add_binary_qml_test)
147
160
148macro(add_qmltest_target qmltest_TARGET qmltest_command qmltest_NO_TARGETS qmltest_NO_ADD_TEST)
161macro(add_qmltest_target qmltest_TARGET qmltest_command qmltest_NO_TARGETS qmltest_NO_ADD_TEST)
data/CMakeLists.txt+1−2
@@ -1,8 +1,7 @@
1# generate desktop file
1# generate desktop file
2configure_file(${SHELL_APP}.desktop.in ${CMAKE_CURRENT_BINARY_DIR}/${SHELL_APP}.desktop @ONLY)
2configure_file(${SHELL_APP}.desktop.in ${CMAKE_CURRENT_BINARY_DIR}/${SHELL_APP}.desktop @ONLY)
3−configure_file(${SCOPE_TOOL}.desktop.in ${CMAKE_CURRENT_BINARY_DIR}/${SCOPE_TOOL}.desktop @ONLY)
4
3
5# install desktop files
4# install desktop files
6−install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${SHELL_APP}.desktop ${CMAKE_CURRENT_BINARY_DIR}/${SCOPE_TOOL}.desktop
5+install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${SHELL_APP}.desktop
7 DESTINATION ${CMAKE_INSTALL_DATADIR}/applications
6 DESTINATION ${CMAKE_INSTALL_DATADIR}/applications
8 )
7 )
data/unity-scope-tool.desktop.indeleted−8
@@ -1,8 +0,0 @@
1−[Desktop Entry]
2−Type=Application
3−Name=Unity Scope Tool
4−Comment=Developer tool for Unity scopes.
5−Exec=@CMAKE_INSTALL_PREFIX@/@CMAKE_INSTALL_BINDIR@/unity-scope-tool
6−Terminal=false
7−Icon=unity-scope-tool
8−X-Ubuntu-Touch=true
data/unity8.conf+10−1
@@ -1,7 +1,7 @@
1description "Unity Shell v8"
1description "Unity Shell v8"
2author "Ricardo Mendoza <ricmm@ubuntu.com>"
2author "Ricardo Mendoza <ricmm@ubuntu.com>"
3
3
4−emits scope-ui-starting
4+emits scope-ui-starting indicator-services-start
5
5
6start on ((xsession SESSION=ubuntu-touch) or (xsession SESSION=ubuntu-touch-surfaceflinger)) and started dbus
6start on ((xsession SESSION=ubuntu-touch) or (xsession SESSION=ubuntu-touch-surfaceflinger)) and started dbus
7stop on desktop-end
7stop on desktop-end
@@ -12,6 +12,9 @@ respawn
12expect stop
12expect stop
13
13
14pre-start script
14pre-start script
15+ # Tell unity-mir to raise SIGSTOP after we start
16+ initctl set-env UNITY_MIR_EMITS_SIGSTOP=1
17+
15 if [ -n "$MIR_SOCKET" ]; then
18 if [ -n "$MIR_SOCKET" ]; then
16 if [ -z "$UNITY_MIR_SOCKET" ]; then
19 if [ -z "$UNITY_MIR_SOCKET" ]; then
17 # Save original value of MIR_SOCKET in case we are restarted,
20 # Save original value of MIR_SOCKET in case we are restarted,
@@ -42,6 +45,12 @@ pre-start script
42 fi
45 fi
43
46
44 initctl emit scope-ui-starting
47 initctl emit scope-ui-starting
48+ initctl emit --no-wait indicator-services-start
45end script
49end script
46
50
47exec ${BINARY:-unity8} $ARGS
51exec ${BINARY:-unity8} $ARGS
52+
53+post-stop script
54+ initctl set-env --global MIR_SOCKET=$UNITY_MIR_SOCKET
55+ initctl unset-env --global UNITY_MIR_SOCKET
56+end script
debian/changelog+121
@@ -1,3 +1,124 @@
1+unity8 (7.86+14.10.20140429.2-0ubuntu1) utopic; urgency=medium
2+
3+ [ Andrea Cimitan ]
4+ * Update upstart job to reflect latest unity-mir changes
5+ * Fix locale in qml tests and fixtimeformattertest (LP: #1301038)
6+ * Fix 1309135 (LP: #1309135)
7+
8+ [ Michał Sawicz ]
9+ * Split out unity8-common package
10+ * Don't wait for indicator services to start, and drop Scope Tool's
11+ .desktop file. (LP: #1310172)
12+
13+ [ Michael Terry ]
14+ * Stop clock from hiding when the 'show dash' button is pressed in
15+ greeter. (LP: #1308139)
16+ * Make swipe teases in the greeter more helpful and obvious (LP:
17+ #1267623)
18+
19+ [ Nick Dedekind ]
20+ * Fixed datetime indicator appointment colour (LP: #1307048)
21+
22+ [ Albert Astals ]
23+ * Improve Card creation time by adding loaders that make sure only
24+ what's needed is loaded (LP: #1297197)
25+ * CategoryDelegateRange: Fix condition for detecting overshooting
26+ * Make xvfbtests work in the DashView plugins
27+ * Fix binding loop in FilterGrid height
28+
29+ [ Victor R. Ruiz ]
30+ * Move autopilot notification code to a helper method.
31+
32+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Tue, 29 Apr 2014 15:21:33 +0000
33+
34+unity8 (7.85+14.04.20140416-0ubuntu1) trusty; urgency=low
35+
36+ [ Albert Astals ]
37+ * Fix last item X position Fixes clicking on the last item sometimes
38+ not working (LP: #1301871)
39+ * Use upstart in ./run Makes it so that you can use the lock button on
40+ the device without getting that nasty hwc crash
41+ * Remove AnimationControllerWithSignals.
42+ * Use the correct delegate base item for the Carousel test
43+ * Some simplification in DashContent Kill the ScopeDelegateMapper in
44+ favour of a simple if (that will eventually go away). Removal of all
45+ the fake scopes in the tests that added nothing of value to the
46+ tests. Removal of movementEnded signal that was unused. Removal of
47+ movementStarted and positionedAtBeginning signals that were being
48+ used as function calls. Rework DashContent tests so they what the
49+ function does what it is supposed to do instead of just making sure
50+ QML signals work .
51+ * Improve Card creation time by adding loaders that make sure only
52+ what's needed is loaded In my computer it goes from RESULT :
53+ qmltestrunner::benchmark_time:"cardTitleArtSubtitleMascotSummaryMode
54+ l": 3.217 msecs per iteration (total: 3,218, iterations: 1000)
55+ RESULT :
56+ qmltestrunner::benchmark_time:"cardTitleArtSubtitleMascotModel":
57+ 1.647 msecs per iteration (total: 1,648, iterations: 1000) RESULT :
58+ qmltestrunner::benchmark_time:"cardTitleArtSubtitleModel": 1.514
59+ msecs per iteration (total: 1,515, iterations: 1000) RESULT :
60+ qmltestrunner::benchmark_time:"cardTitleArtModel": 1.471 msecs per
61+ iteration (total: 1,471, iterations: 1000) RESULT :
62+ qmltestrunner::benchmark_time:"cardArtModel": 1.447 msecs per
63+ iteration (total: 1,448, iterations: 1000) RESULT :
64+ qmltestrunner::benchmark_time:"cardTitleModel": 1.276 msecs per
65+ iteration (total: 1,276, iterations: 1000) to RESULT :
66+ qmltestrunner::benchmark_time:"cardTitleArtSubtitleMascotSummaryMode
67+ l": 2.916 msecs per iteration (total: 2,917, iterations: 1000)
68+ RESULT :
69+ qmltestrunner::benchmark_time:"cardTitleArtSubtitleMascotModel":
70+ 1.504 msecs per iteration (total: 1,504, iterations: 1000) RESULT :
71+ qmltestrunner::benchmark_time:"cardTitleArtSubtitleModel": 1.060
72+ msecs per iteration (total: 1,061, iterations: 1000) RESULT :
73+ qmltestrunner::benchmark_time:"cardTitleArtModel": 1.052 msecs per
74+ iteration (total: 1,053, iterations: 1000) RESULT :
75+ qmltestrunner::benchmark_time:"cardArtModel": 0.727 msecs per
76+ iteration (total: 728, iterations: 1000) RESULT :
77+ qmltestrunner::benchmark_time:"cardTitleModel": 0.817 msecs per
78+ iteration (total: 818, iterations: 1000) (LP: #1297197)
79+
80+ [ Allan LeSage ]
81+ * DashApps emulator get_applications should return a list ordered by
82+ visible y, x.
83+
84+ [ Andrea Cimitan ]
85+ * Workaround for lp1301309 until fixes for palette in ui toolkit (LP:
86+ #1301309)
87+
88+ [ Leo Arias ]
89+ * Reverted the change that returns application cards instead of
90+ titles.
91+
92+ [ Nick Dedekind ]
93+ * Indicator services started by unity8 upstart configuration rather
94+ than manual emmision from indicator manager.
95+
96+ [ Mirco Müller ]
97+ * Fix notification ap-test assertions.
98+
99+ [ Michael Terry ]
100+ * Use new tablet and phone backgrounds from Design.
101+
102+ [ Michael Zanetti ]
103+ * workaround the QTestLogger assertion issue with make tryXyz and our
104+ custom uqmlscene
105+
106+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Wed, 16 Apr 2014 13:45:01 +0000
107+
108+unity8 (7.85+14.04.20140415.2-0ubuntu1) trusty; urgency=low
109+
110+ [ Michael Terry ]
111+ * When an application requests focus, handle it in Shell.qml by hiding
112+ the greeter and stopping any edge demo. (LP: #1227753)
113+
114+ [ Leo Arias ]
115+ * Use subprocess.check_call when caling url-dispatcher, so an error
116+ will be raised if it fails.
117+ * Test application life cycle with fake apps, instead of messaging and
118+ address book.
119+
120+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Tue, 15 Apr 2014 12:47:11 +0000
121+
1unity8 (7.85+14.04.20140410.1-0ubuntu1) trusty; urgency=medium
122unity8 (7.85+14.04.20140410.1-0ubuntu1) trusty; urgency=medium
2
123
3 [ Didier Roche ]
124 [ Didier Roche ]
debian/control+34−25
@@ -11,37 +11,34 @@ Build-Depends: cmake,
11 libgl1-mesa-dev[!armhf] | libgl-dev[!armhf],
11 libgl1-mesa-dev[!armhf] | libgl-dev[!armhf],
12 libgl1-mesa-dri,
12 libgl1-mesa-dri,
13 libgles2-mesa-dev[armhf],
13 libgles2-mesa-dev[armhf],
14+ libglib2.0-dev,
14 libgsettings-qt-dev,
15 libgsettings-qt-dev,
15 libhud-client2-dev,
16 libhud-client2-dev,
16− libnih-dbus-dev,
17− libnih-dev,
18 libpulse-dev,
17 libpulse-dev,
19 libqmenumodel-dev (>= 0.2.7),
18 libqmenumodel-dev (>= 0.2.7),
19+ libqt5xmlpatterns5-dev,
20 libunity-api-dev (>= 7.80.6),
20 libunity-api-dev (>= 7.80.6),
21 libunity-mir-dev,
21 libunity-mir-dev,
22− libupstart-dev,
23 libusermetricsoutput1-dev,
22 libusermetricsoutput1-dev,
24 libxcb1-dev,
23 libxcb1-dev,
25− libglib2.0-dev,
26 pkg-config,
24 pkg-config,
27− python:any (>= 2.7),
28 python-setuptools,
25 python-setuptools,
29 python3-all:any,
26 python3-all:any,
30 python3-setuptools,
27 python3-setuptools,
28+ python:any (>= 2.7),
31 qt5-default,
29 qt5-default,
32 qtbase5-dev,
30 qtbase5-dev,
33 qtbase5-dev-tools,
31 qtbase5-dev-tools,
34 qtbase5-private-dev,
32 qtbase5-private-dev,
35 qtdeclarative5-dev,
33 qtdeclarative5-dev,
36 qtdeclarative5-dev-tools,
34 qtdeclarative5-dev-tools,
37− qtdeclarative5-qtmultimedia-plugin,
38 qtdeclarative5-private-dev,
35 qtdeclarative5-private-dev,
36+ qtdeclarative5-qtmultimedia-plugin,
39 qtdeclarative5-qtquick2-plugin,
37 qtdeclarative5-qtquick2-plugin,
40 qtdeclarative5-test-plugin,
38 qtdeclarative5-test-plugin,
41 qtdeclarative5-ubuntu-settings-components,
39 qtdeclarative5-ubuntu-settings-components,
42 qtdeclarative5-ubuntu-ui-toolkit-plugin,
40 qtdeclarative5-ubuntu-ui-toolkit-plugin,
43 qtdeclarative5-xmllistmodel-plugin,
41 qtdeclarative5-xmllistmodel-plugin,
44− libqt5xmlpatterns5-dev,
45 ttf-ubuntu-font-family,
42 ttf-ubuntu-font-family,
46Standards-Version: 3.9.4
43Standards-Version: 3.9.4
47Homepage: http://launchpad.net/unity
44Homepage: http://launchpad.net/unity
@@ -63,7 +60,8 @@ Description: Indicators client test application
63
60
64Package: unity-scope-tool
61Package: unity-scope-tool
65Architecture: any
62Architecture: any
63+Depends: unity8-common (= ${source:Version}),
66−Depends: unity8 (= ${binary:Version}),
64+ unity8-private (= ${binary:Version}),
67 ${misc:Depends},
65 ${misc:Depends},
68 ${shlibs:Depends},
66 ${shlibs:Depends},
69Description: Development tool for Unity scopes
67Description: Development tool for Unity scopes
@@ -74,27 +72,18 @@ Package: unity8
74Architecture: any
72Architecture: any
75Provides: indicator-renderer,
73Provides: indicator-renderer,
76Depends: gsettings-desktop-schemas,
74Depends: gsettings-desktop-schemas,
75+ libcap2-bin,
77 libglib2.0-bin,
76 libglib2.0-bin,
78− libunity-mir1,
77+ libunity-mir1 (>= 0.4),
79 qmenumodel-qml (>= 0.2.7),
78 qmenumodel-qml (>= 0.2.7),
80 qtdeclarative5-dee-plugin,
79 qtdeclarative5-dee-plugin,
81 qtdeclarative5-gsettings1.0,
80 qtdeclarative5-gsettings1.0,
82 qtdeclarative5-ubuntu-settings-components,
81 qtdeclarative5-ubuntu-settings-components,
83− qtdeclarative5-ubuntu-thumbnailer0.1 | ubuntu-thumbnailer-impl,
84− ubuntu-thumbnailer-impl-0,
85− qtdeclarative5-ubuntu-ui-toolkit-plugin,
86− qtdeclarative5-unity-notifications-plugin | unity-notifications-impl,
87 qtdeclarative5-xmllistmodel-plugin,
82 qtdeclarative5-xmllistmodel-plugin,
88− unity-application-impl-2,
89 unity-launcher-impl-3,
83 unity-launcher-impl-3,
90− unity-notifications-impl-2,
84+ unity8-common (= ${source:Version}),
91− unity8-fake-env | unity-application-impl,
92 unity8-private (= ${binary:Version}),
85 unity8-private (= ${binary:Version}),
93 unity8-private | unity-launcher-impl,
86 unity8-private | unity-launcher-impl,
94− unity-plugin-scopes | unity-scopes-impl,
95− unity-scopes-impl-0,
96−# for setcap:
97− libcap2-bin,
98 ${misc:Depends},
87 ${misc:Depends},
99 ${shlibs:Depends},
88 ${shlibs:Depends},
100Recommends: unity-scope-click,
89Recommends: unity-scope-click,
@@ -102,10 +91,30 @@ Recommends: unity-scope-click,
102 unity-scope-scopes,
91 unity-scope-scopes,
103Breaks: indicator-network (<< 0.5.1),
92Breaks: indicator-network (<< 0.5.1),
104 ubuntu-touch-session (<< 0.107),
93 ubuntu-touch-session (<< 0.107),
105−Replaces: ubuntu-touch-session (<< 0.82~)
94+Replaces: ubuntu-touch-session (<< 0.82~),
106Description: Unity 8 shell
95Description: Unity 8 shell
107 The Unity 8 shell is the primary user interface for Ubuntu devices.
96 The Unity 8 shell is the primary user interface for Ubuntu devices.
108
97
98+Package: unity8-common
99+Architecture: all
100+Depends: qtdeclarative5-ubuntu-thumbnailer0.1 | ubuntu-thumbnailer-impl,
101+ qtdeclarative5-ubuntu-ui-toolkit-plugin,
102+ qtdeclarative5-unity-notifications-plugin | unity-notifications-impl,
103+ ubuntu-thumbnailer-impl-0,
104+ unity-application-impl-2,
105+ unity-notifications-impl-2,
106+ unity-plugin-scopes | unity-scopes-impl,
107+ unity-scopes-impl-0,
108+ unity8-fake-env | unity-application-impl,
109+ ${misc:Depends},
110+Breaks: unity8 (<< 7.86),
111+Replaces: unity8 (<< 7.86),
112+Description: Unity 8 shell (common files)
113+ The Unity 8 shell is the primary user interface for Ubuntu devices.
114+ .
115+ This package contains the QML, graphics and locale files shared between
116+ unity8 and unity-scope-tool.
117+
109Package: unity8-autopilot
118Package: unity8-autopilot
110Architecture: all
119Architecture: all
111Depends: gir1.2-glib-2.0,
120Depends: gir1.2-glib-2.0,
@@ -122,12 +131,12 @@ Depends: gir1.2-glib-2.0,
122 python3-fixtures,
131 python3-fixtures,
123 python3-gi,
132 python3-gi,
124 ubuntu-ui-toolkit-autopilot,
133 ubuntu-ui-toolkit-autopilot,
125− unity8 (>= ${source:Version}),
134+ unity8 (= ${source:Version}),
126− unity8-fake-env (>= ${source:Version}),
135+ unity8-fake-env (= ${source:Version}),
127 url-dispatcher-tools,
136 url-dispatcher-tools,
128 ${misc:Depends},
137 ${misc:Depends},
129− ${python:Depends},
130 ${python3:Depends},
138 ${python3:Depends},
139+ ${python:Depends},
131 ${shlibs:Depends},
140 ${shlibs:Depends},
132Description: Test package for Unity 8 shell
141Description: Test package for Unity 8 shell
133 Autopilot tests for the unity8 package
142 Autopilot tests for the unity8 package
@@ -149,9 +158,9 @@ Architecture: any
149Multi-Arch: same
158Multi-Arch: same
150Pre-Depends: ${misc:Pre-Depends},
159Pre-Depends: ${misc:Pre-Depends},
151Depends: gsettings-ubuntu-schemas,
160Depends: gsettings-ubuntu-schemas,
161+ libunity-core-6.0-9,
152 ${misc:Depends},
162 ${misc:Depends},
153 ${shlibs:Depends},
163 ${shlibs:Depends},
154− libunity-core-6.0-9,
155Provides: unity-launcher-impl,
164Provides: unity-launcher-impl,
156 unity-launcher-impl-3,
165 unity-launcher-impl-3,
157Description: Unity 8 private libs
166Description: Unity 8 private libs
debian/unity-scope-tool.install−1
@@ -1,3 +1,2 @@
1usr/bin/unity-scope-tool
1usr/bin/unity-scope-tool
2−usr/share/applications/unity-scope-tool.desktop
3usr/share/unity8/ScopeTool.qml
2usr/share/unity8/ScopeTool.qml
debian/unity8-common.installnew file+5
@@ -0,0 +1,5 @@
1+usr/share/locale
2+usr/share/unity8/Components
3+usr/share/unity8/Dash
4+usr/share/unity8/Notifications
5+usr/share/unity8/graphics
debian/unity8-fake-env.install+1−1
@@ -1,4 +1,4 @@
1−usr/lib/*/unity8/qml/nonmirplugins
2usr/lib/*/unity8/qml/mocks
1usr/lib/*/unity8/qml/mocks
2+usr/lib/*/unity8/qml/nonmirplugins
3usr/lib/*/unity8/qml/scopefakes
3usr/lib/*/unity8/qml/scopefakes
4usr/share/unity8/mocks
4usr/share/unity8/mocks
debian/unity8-private.install+1−1
@@ -1,7 +1,7 @@
1usr/lib/*/unity8/qml/AccountsService
1usr/lib/*/unity8/qml/AccountsService
2+usr/lib/*/unity8/qml/DashViews
2usr/lib/*/unity8/qml/HudClient
3usr/lib/*/unity8/qml/HudClient
3usr/lib/*/unity8/qml/LightDM
4usr/lib/*/unity8/qml/LightDM
4−usr/lib/*/unity8/qml/DashViews
5usr/lib/*/unity8/qml/Powerd
5usr/lib/*/unity8/qml/Powerd
6usr/lib/*/unity8/qml/SessionBroadcast
6usr/lib/*/unity8/qml/SessionBroadcast
7usr/lib/*/unity8/qml/Ubuntu
7usr/lib/*/unity8/qml/Ubuntu
debian/unity8.install+1−6
@@ -1,15 +1,10 @@
1+data/unity8.conf usr/share/upstart/sessions/
1usr/bin/unity8
2usr/bin/unity8
2usr/share/applications/unity8.desktop
3usr/share/applications/unity8.desktop
3−usr/share/locale
4usr/share/unity8/Bottombar
4usr/share/unity8/Bottombar
5−usr/share/unity8/Components
6−usr/share/unity8/Dash
7usr/share/unity8/Greeter
5usr/share/unity8/Greeter
8usr/share/unity8/Hud
6usr/share/unity8/Hud
9usr/share/unity8/Launcher
7usr/share/unity8/Launcher
10−usr/share/unity8/Notifications
11usr/share/unity8/Panel
8usr/share/unity8/Panel
12usr/share/unity8/Shell.qml
9usr/share/unity8/Shell.qml
13usr/share/unity8/Stages
10usr/share/unity8/Stages
14−usr/share/unity8/graphics
15−data/unity8.conf usr/share/upstart/sessions/
plugins/Unity/Indicators/CMakeLists.txt−3
@@ -6,7 +6,6 @@ project(IndicatorsQml)
6pkg_check_modules(GLIB REQUIRED glib-2.0>=2.32)
6pkg_check_modules(GLIB REQUIRED glib-2.0>=2.32)
7pkg_check_modules(GIO REQUIRED gio-2.0>=2.32)
7pkg_check_modules(GIO REQUIRED gio-2.0>=2.32)
8pkg_check_modules(QMENUMODEL REQUIRED qmenumodel)
8pkg_check_modules(QMENUMODEL REQUIRED qmenumodel)
9−pkg_check_modules(LIBUPSTART REQUIRED libupstart libnih libnih-dbus dbus-1)
10
9
11find_package(Qt5Core REQUIRED)
10find_package(Qt5Core REQUIRED)
12find_package(Qt5Quick REQUIRED)
11find_package(Qt5Quick REQUIRED)
@@ -19,7 +18,6 @@ include_directories(
19 ${GLIB_INCLUDE_DIRS}
18 ${GLIB_INCLUDE_DIRS}
20 ${GIO_INCLUDE_DIRS}
19 ${GIO_INCLUDE_DIRS}
21 ${QMENUMODEL_INCLUDE_DIRS}
20 ${QMENUMODEL_INCLUDE_DIRS}
22− ${LIBUPSTART_INCLUDE_DIRS}
23)
21)
24
22
25set(IndicatorsQML_SOURCES
23set(IndicatorsQML_SOURCES
@@ -54,7 +52,6 @@ target_link_libraries(IndicatorsQml
54 ${GLIB_LIBRARIES}
52 ${GLIB_LIBRARIES}
55 ${GIO_LIBRARIES}
53 ${GIO_LIBRARIES}
56 ${QMENUMODEL_LDFLAGS}
54 ${QMENUMODEL_LDFLAGS}
57− ${LIBUPSTART_LIBRARIES}
58)
55)
59
56
60qt5_use_modules(IndicatorsQml Core Qml Quick)
57qt5_use_modules(IndicatorsQml Core Qml Quick)
plugins/Unity/Indicators/indicatorsmanager.cpp−33
@@ -21,9 +21,6 @@
21#include <QSettings>
21#include <QSettings>
22#include <QDebug>
22#include <QDebug>
23
23
24−#include <upstart.h>
25−#include <nih/alloc.h>
26−
27#include <paths.h>
24#include <paths.h>
28
25
29
26
@@ -216,36 +213,6 @@ void IndicatorsManager::setLoaded(bool loaded)
216 {
213 {
217 m_loaded = loaded;
214 m_loaded = loaded;
218 Q_EMIT loadedChanged(m_loaded);
215 Q_EMIT loadedChanged(m_loaded);
219−
220− auto upstartsession = qgetenv("UPSTART_SESSION");
221− NihDBusProxy * upstart = NULL;
222−
223− if (!upstartsession.isNull()) {
224− DBusConnection * conn = NULL;
225− conn = dbus_connection_open(upstartsession.constData(), NULL);
226− if (conn != NULL) {
227− upstart = nih_dbus_proxy_new(NULL, conn,
228− NULL,
229− DBUS_PATH_UPSTART,
230− NULL, NULL);
231− dbus_connection_unref(conn);
232− }
233− }
234−
235− if (upstart != NULL) {
236− int event_sent = 0;
237− if (m_loaded) {
238− event_sent = upstart_emit_event_sync(NULL, upstart, "indicator-services-start", NULL, 0);
239− } else {
240− event_sent = upstart_emit_event_sync(NULL, upstart, "indicator-services-end", NULL, 0);
241− }
242−
243− if (event_sent != 0) {
244− qWarning() << "Unable to send indicator event to Upstart";
245− }
246− nih_unref(upstart, NULL);
247− upstart = NULL;
248− }
249 }
216 }
250}
217}
251
218
plugins/Unity/Indicators/indicatorsmanager.h−2
@@ -28,8 +28,6 @@
28#include <QHash>
28#include <QHash>
29#include <QSharedPointer>
29#include <QSharedPointer>
30
30
31−typedef struct nih_dbus_proxy NihDBusProxy;
32−
33class UNITYINDICATORS_EXPORT IndicatorsManager : public QObject
31class UNITYINDICATORS_EXPORT IndicatorsManager : public QObject
34{
32{
35 Q_OBJECT
33 Q_OBJECT
plugins/Unity/Indicators/qml/MenuItemFactory.qml+1−1
@@ -273,7 +273,7 @@ Item {
273 text: menuData && menuData.label || ""
273 text: menuData && menuData.label || ""
274 iconSource: menuData && menuData.icon || "image://theme/calendar"
274 iconSource: menuData && menuData.icon || "image://theme/calendar"
275 time: timeFormatter.timeString
275 time: timeFormatter.timeString
276− eventColor: menu && menu.ext.hasOwnProperty("xCanonicalColor") ? menu.ext.xCanonicalColor : Qt.rgba(0.0, 0.0, 0.0, 0.0)
276+ eventColor: getExtendedProperty(extendedData, "xCanonicalColor", Qt.rgba(0.0, 0.0, 0.0, 0.0))
277 enabled: menuData && menuData.sensitive || false
277 enabled: menuData && menuData.sensitive || false
278
278
279 onMenuModelChanged: {
279 onMenuModelChanged: {
po/br.ponew file+164
@@ -0,0 +1,164 @@
1+# Breton translation for unity8
2+# Copyright (c) 2014 Rosetta Contributors and Canonical Ltd 2014
3+# This file is distributed under the same license as the unity8 package.
4+# FIRST AUTHOR <EMAIL@ADDRESS>, 2014.
5+#
6+msgid ""
7+msgstr ""
8+"Project-Id-Version: unity8\n"
9+"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10+"POT-Creation-Date: 2014-03-25 16:48+0100\n"
11+"PO-Revision-Date: 2014-04-15 18:15+0000\n"
12+"Last-Translator: Rouxel <vincent.rouxel@mailoo.org>\n"
13+"Language-Team: Breton <br@li.org>\n"
14+"MIME-Version: 1.0\n"
15+"Content-Type: text/plain; charset=UTF-8\n"
16+"Content-Transfer-Encoding: 8bit\n"
17+"X-Launchpad-Export-Date: 2014-04-16 07:12+0000\n"
18+"X-Generator: Launchpad (build 16976)\n"
19+
20+#: plugins/Unity/Launcher/launcheritem.cpp:43
21+#: plugins/Unity/Launcher/launcheritem.cpp:73
22+msgid "Lock to Launcher"
23+msgstr ""
24+
25+#: plugins/Unity/Launcher/launcheritem.cpp:73
26+msgid "Unlock from Launcher"
27+msgstr ""
28+
29+#: qml/Components/EdgeDemoOverlay.qml:151
30+msgid "Skip intro"
31+msgstr ""
32+
33+#: qml/Components/EdgeDemo.qml:113
34+msgid "Right edge"
35+msgstr ""
36+
37+#: qml/Components/EdgeDemo.qml:114
38+msgid "Try swiping from the right edge to unlock the phone"
39+msgstr ""
40+
41+#: qml/Components/EdgeDemo.qml:145
42+msgid "Top edge"
43+msgstr ""
44+
45+#: qml/Components/EdgeDemo.qml:146
46+msgid "Try swiping from the top edge to access the indicators"
47+msgstr ""
48+
49+#: qml/Components/EdgeDemo.qml:171
50+msgid "Close"
51+msgstr "Serriñ"
52+
53+#: qml/Components/EdgeDemo.qml:172
54+msgid "Swipe up again to close the settings screen"
55+msgstr ""
56+
57+#: qml/Components/EdgeDemo.qml:199
58+msgid "Left edge"
59+msgstr ""
60+
61+#: qml/Components/EdgeDemo.qml:200
62+msgid "Swipe from the left to reveal the launcher for quick access to apps"
63+msgstr ""
64+
65+#: qml/Components/EdgeDemo.qml:227
66+msgid "Well done"
67+msgstr ""
68+
69+#: qml/Components/EdgeDemo.qml:228
70+msgid ""
71+"You have now mastered the edge gestures and can start using the "
72+"phone<br><br>Tap on the screen to start"
73+msgstr ""
74+
75+#: qml/Components/PageHeader.qml:365
76+msgid "Recent searches"
77+msgstr ""
78+
79+#: qml/Components/SeeMore.qml:35
80+msgid "See more"
81+msgstr ""
82+
83+#: qml/Components/SeeMore.qml:58
84+msgid "See less"
85+msgstr ""
86+
87+#: qml/Dash/DashApps.qml:38
88+msgid "Recent"
89+msgstr ""
90+
91+#: qml/Dash/PreviewListView.qml:52
92+#, qt-format
93+msgid "%1 Preview"
94+msgstr ""
95+
96+#: qml/Dash/Previews/PreviewActionCombo.qml:34
97+msgid "More..."
98+msgstr ""
99+
100+#: qml/Dash/Previews/PreviewActionCombo.qml:34
101+msgid "Less..."
102+msgstr ""
103+
104+#: qml/Dash/Previews/PreviewRatingInput.qml:81
105+msgid "Rate this"
106+msgstr ""
107+
108+#: qml/Dash/Previews/PreviewRatingInput.qml:126
109+msgid "Add a review"
110+msgstr ""
111+
112+#: qml/Dash/Previews/PreviewRatingInput.qml:166
113+msgid "Send"
114+msgstr ""
115+
116+#: qml/Greeter/Lockscreen.qml:149
117+msgid "Emergency Call"
118+msgstr ""
119+
120+#: qml/Greeter/PassphraseLockscreen.qml:59
121+#, qt-format
122+msgid "Hello %1"
123+msgstr ""
124+
125+#: qml/Greeter/PassphraseLockscreen.qml:59
126+msgid "Hello"
127+msgstr ""
128+
129+#: qml/Hud/HudParametrizedActionsPage.qml:132
130+msgid "Confirm"
131+msgstr ""
132+
133+#: qml/Hud/Hud.qml:61 qml/Hud/Hud.qml:99 qml/Hud/Hud.qml:372
134+msgid "Type or say a command"
135+msgstr ""
136+
137+#: qml/Hud/Hud.qml:84
138+msgid "Loading. Please Wait..."
139+msgstr ""
140+
141+#: qml/Hud/Hud.qml:89
142+msgid "Speak Now..."
143+msgstr ""
144+
145+#: qml/Hud/Hud.qml:94
146+msgid "Speaking..."
147+msgstr ""
148+
149+#: qml/Notifications/NotificationMenuItemFactory.qml:91
150+msgid "Show password"
151+msgstr ""
152+
153+#: qml/Notifications/NotificationMenuItemFactory.qml:103
154+msgid "Please enter SIM PIN"
155+msgstr ""
156+
157+#: qml/Panel/SearchIndicator.qml:27
158+msgid "Search"
159+msgstr ""
160+
161+#: qml/Shell.qml:417
162+#, qt-format
163+msgid "Please enter %1"
164+msgstr ""
po/ug.po+5−5
@@ -8,14 +8,14 @@ msgstr ""
8"Project-Id-Version: unity\n"
8"Project-Id-Version: unity\n"
9"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
9"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10"POT-Creation-Date: 2014-03-25 16:48+0100\n"
10"POT-Creation-Date: 2014-03-25 16:48+0100\n"
11−"PO-Revision-Date: 2014-04-14 09:31+0000\n"
11+"PO-Revision-Date: 2014-04-22 05:46+0000\n"
12−"Last-Translator: volkhan <Unknown>\n"
12+"Last-Translator: abdurahman <Unknown>\n"
13"Language-Team: Uyghur <ug@li.org>\n"
13"Language-Team: Uyghur <ug@li.org>\n"
14"MIME-Version: 1.0\n"
14"MIME-Version: 1.0\n"
15"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17−"X-Launchpad-Export-Date: 2014-04-15 07:57+0000\n"
17+"X-Launchpad-Export-Date: 2014-04-23 07:07+0000\n"
18−"X-Generator: Launchpad (build 16976)\n"
18+"X-Generator: Launchpad (build 16985)\n"
19
19
20#: plugins/Unity/Launcher/launcheritem.cpp:43
20#: plugins/Unity/Launcher/launcheritem.cpp:43
21#: plugins/Unity/Launcher/launcheritem.cpp:73
21#: plugins/Unity/Launcher/launcheritem.cpp:73
@@ -93,7 +93,7 @@ msgstr "يېقىنقى"
93#: qml/Dash/PreviewListView.qml:52
93#: qml/Dash/PreviewListView.qml:52
94#, qt-format
94#, qt-format
95msgid "%1 Preview"
95msgid "%1 Preview"
96−msgstr ""
96+msgstr "%1 ئالدىن كۆرۈپ بىقىش"
97
97
98#: qml/Dash/Previews/PreviewActionCombo.qml:34
98#: qml/Dash/Previews/PreviewActionCombo.qml:34
99msgid "More..."
99msgid "More..."
po/unity8.pot+7−3
@@ -8,7 +8,7 @@ msgid ""
8msgstr ""
8msgstr ""
9"Project-Id-Version: unity8\n"
9"Project-Id-Version: unity8\n"
10"Report-Msgid-Bugs-To: \n"
10"Report-Msgid-Bugs-To: \n"
11−"POT-Creation-Date: 2014-03-25 16:48+0100\n"
11+"POT-Creation-Date: 2014-04-10 11:13-0400\n"
12"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
12"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
13"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
13"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
14"Language-Team: LANGUAGE <LL@li.org>\n"
14"Language-Team: LANGUAGE <LL@li.org>\n"
@@ -84,7 +84,7 @@ msgstr ""
84msgid "See less"
84msgid "See less"
85msgstr ""
85msgstr ""
86
86
87−#: qml/Dash/DashApps.qml:38
87+#: qml/Dash/DashApps.qml:37
88msgid "Recent"
88msgid "Recent"
89msgstr ""
89msgstr ""
90
90
@@ -113,6 +113,10 @@ msgstr ""
113msgid "Send"
113msgid "Send"
114msgstr ""
114msgstr ""
115
115
116+#: qml/Greeter/Greeter.qml:151
117+msgid "Swipe to unlock"
118+msgstr ""
119+
116#: qml/Greeter/Lockscreen.qml:149
120#: qml/Greeter/Lockscreen.qml:149
117msgid "Emergency Call"
121msgid "Emergency Call"
118msgstr ""
122msgstr ""
@@ -158,7 +162,7 @@ msgstr ""
158msgid "Search"
162msgid "Search"
159msgstr ""
163msgstr ""
160
164
161−#: qml/Shell.qml:417
165+#: qml/Shell.qml:348
162#, qt-format
166#, qt-format
163msgid "Please enter %1"
167msgid "Please enter %1"
164msgstr ""
168msgstr ""
qml/Components/AnimationControllerWithSignals.qmldeleted−64
@@ -1,64 +0,0 @@
1−/*
2− * Copyright (C) 2013 Canonical, Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− */
16−
17−import QtQuick 2.0
18−
19−AnimationController {
20− signal animationCompletedAtBeginning()
21− signal animationCompletedAtEnd()
22− readonly property bool completed: progress == 1.0 || progress == 0.0
23− property bool completing: false
24−
25− function __completeAtBeginning() {
26− completing = false;
27− animationCompletedAtBeginning();
28− }
29−
30− function __completeAtEnd() {
31− completing = false;
32− animationCompletedAtEnd();
33− }
34−
35− function completeToBeginningWithSignal() {
36− if (progress == 0.0) {
37− __completeAtBeginning()
38− } else {
39− completing = true;
40− completeToBeginning();
41− }
42− }
43−
44− function completeToEndWithSignal() {
45− if (progress == 1.0) {
46− __completeAtEnd()
47− } else {
48− completing = true;
49− completeToEnd();
50− }
51− }
52−
53− onProgressChanged: {
54− if (!completing) {
55− return;
56− }
57−
58− if (progress == 0.0) {
59− __completeAtBeginning()
60− } else if (progress == 1.0) {
61− __completeAtEnd()
62− }
63− }
64−}
qml/Components/Carousel.qml+13−19
@@ -75,6 +75,7 @@ Item {
75 The scaling of the items is controlled by the variable continuousIndex, described below. */
75 The scaling of the items is controlled by the variable continuousIndex, described below. */
76 ListView {
76 ListView {
77 id: listView
77 id: listView
78+ objectName: "listView"
78
79
79 property int highlightIndex: -1
80 property int highlightIndex: -1
80 property real minimumTileWidth: 0
81 property real minimumTileWidth: 0
@@ -148,15 +149,19 @@ Item {
148 maximumFlickVelocity: Math.max(2500 * Math.pow(realWidth / referenceWidth, 1.5), 2500) // 2500 is platform default
149 maximumFlickVelocity: Math.max(2500 * Math.pow(realWidth / referenceWidth, 1.5), 2500) // 2500 is platform default
149 orientation: ListView.Horizontal
150 orientation: ListView.Horizontal
150
151
151− function itemClicked(index, delegateItem) {
152+ function getXFromContinuousIndex(index) {
152− listView.currentIndex = index
153− var x = CarouselJS.getXFromContinuousIndex(index,
153+ return CarouselJS.getXFromContinuousIndex(index,
154 realWidth,
154 realWidth,
155− realContentWidth,
155+ footerItem.x,
156 tileWidth,
156 tileWidth,
157 gapToMiddlePhase,
157 gapToMiddlePhase,
158 gapToEndPhase,
158 gapToEndPhase,
159 carousel.drawBuffer)
159 carousel.drawBuffer)
160+ }
161+
162+ function itemClicked(index, delegateItem) {
163+ listView.currentIndex = index
164+ var x = getXFromContinuousIndex(index);
160
165
161 if (Math.abs(x - contentX) < 1 && delegateItem !== undefined) {
166 if (Math.abs(x - contentX) < 1 && delegateItem !== undefined) {
162 /* We're clicking the selected item and
167 /* We're clicking the selected item and
@@ -174,13 +179,7 @@ Item {
174 }
179 }
175
180
176 function itemPressAndHold(index, delegateItem) {
181 function itemPressAndHold(index, delegateItem) {
177− var x = CarouselJS.getXFromContinuousIndex(index,
182+ var x = getXFromContinuousIndex(index);
178− realWidth,
179− realContentWidth,
180− tileWidth,
181− gapToMiddlePhase,
182− gapToEndPhase,
183− carousel.drawBuffer);
184
183
185 if (Math.abs(x - contentX) < 1 && delegateItem !== undefined) {
184 if (Math.abs(x - contentX) < 1 && delegateItem !== undefined) {
186 /* We're pressAndHold the selected item and
185 /* We're pressAndHold the selected item and
@@ -209,22 +208,17 @@ Item {
209 newContentX = disabledNewContentX
208 newContentX = disabledNewContentX
210 }
209 }
211 onMovementEnded: {
210 onMovementEnded: {
212− if (realContentX > 0 && realContentX < realContentWidth - realWidth)
211+ if (realContentX > 0)
213 stepAnimation.start()
212 stepAnimation.start()
214 }
213 }
215
214
216 SmoothedAnimation {
215 SmoothedAnimation {
217 id: stepAnimation
216 id: stepAnimation
217+ objectName: "stepAnimation"
218
218
219 target: listView
219 target: listView
220 property: "contentX"
220 property: "contentX"
221− to: CarouselJS.getXFromContinuousIndex(listView.selectedIndex,
221+ to: listView.getXFromContinuousIndex(listView.selectedIndex)
222− listView.realWidth,
223− listView.realContentWidth,
224− listView.tileWidth,
225− listView.gapToMiddlePhase,
226− listView.gapToEndPhase,
227− carousel.drawBuffer)
228 duration: 450
222 duration: 450
229 velocity: 200
223 velocity: 200
230 easing.type: Easing.InOutQuad
224 easing.type: Easing.InOutQuad
qml/Components/FilterGrid.qml+37−24
@@ -28,11 +28,6 @@ import "../Components"
28Item {
28Item {
29 id: root
29 id: root
30
30
31− /* If true, the number of elements displayed will be limited by collapsedRowCount.
32− If false, all elements will be displayed, effectively looking the same as a regular
33− ResponsiveGridView. */
34− property bool filter: true
35−
36 /* Whether, when collapsed, a button should be displayed enabling the user to expand
31 /* Whether, when collapsed, a button should be displayed enabling the user to expand
37 the grid to its full size. */
32 the grid to its full size. */
38 readonly property bool expandable: model.count > rowsWhenCollapsed * iconTileGrid.columns
33 readonly property bool expandable: model.count > rowsWhenCollapsed * iconTileGrid.columns
@@ -65,30 +60,48 @@ Item {
65 readonly property alias pressDelay: iconTileGrid.pressDelay
60 readonly property alias pressDelay: iconTileGrid.pressDelay
66 property alias highlightIndex: iconTileGrid.highlightIndex
61 property alias highlightIndex: iconTileGrid.highlightIndex
67 readonly property alias currentItem: iconTileGrid.currentItem
62 readonly property alias currentItem: iconTileGrid.currentItem
63+ readonly property alias filtered: d.filter
64+
65+ QtObject {
66+ id: d
67+ // We do have filter and collapsed properties because we need to decouple
68+ // the real filtering with the animation since the closing animation
69+ // i.e. setFilter(false. true) we still need to not be filtering until
70+ // the animation finishes otherwise we hide the items when the animation
71+ // is still running
72+ property bool filter: true
73+ property bool collapsed: true
74+ }
68
75
69− height: !filterAnimation.running ? childrenRect.height : height
76+ height: d.collapsed ? root.collapsedHeight : root.uncollapsedHeight
70 clip: filterAnimation.running
77 clip: filterAnimation.running
71
78
79+ Behavior on height {
80+ id: heightBehaviour
81+ enabled: false
72− NumberAnimation {
82+ NumberAnimation {
73− property bool filterEndValue
74− id: filterAnimation
83+ id: filterAnimation
75− target: root
76− property: "height"
77− to: filterEndValue ? root.collapsedHeight : root.uncollapsedHeight
78− // Duration and easing here match the ListViewWithPageHeader::m_contentYAnimation
84+ // Duration and easing here match the ListViewWithPageHeader::m_contentYAnimation
79− // otherwise since both animations can run at the same time you'll get
85+ // otherwise since both animations can run at the same time you'll get
80− // some visual weirdness.
86+ // some visual weirdness.
81− duration: 200
87+ duration: 200
82− easing.type: Easing.InOutQuad
88+ easing.type: Easing.InOutQuad
83− onStopped: {
89+ onRunningChanged: {
84− root.filter = filterEndValue;
90+ if (!running) {
91+ d.filter = d.collapsed;
92+ }
93+ heightBehaviour.enabled = false;
94+ }
85 }
95 }
86 }
96 }
87
97
88− function startFilterAnimation(filter) {
98+ function setFilter(filter, animate) {
89− filterAnimation.filterEndValue = filter
99+ heightBehaviour.enabled = animate;
90− filterAnimation.start();
100+ d.collapsed = filter;
101+ if (!animate || !filter) {
102+ d.filter = filter;
103+ }
91− }
104+ }
92
105
93 ResponsiveGridView {
106 ResponsiveGridView {
94 id: iconTileGrid
107 id: iconTileGrid
@@ -105,7 +118,7 @@ Item {
105
118
106 model: LimitProxyModel {
119 model: LimitProxyModel {
107 model: root.model
120 model: root.model
108− limit: (filter && !filterAnimation.running) ? rowsWhenCollapsed * iconTileGrid.columns : -1
121+ limit: d.filter ? rowsWhenCollapsed * iconTileGrid.columns : -1
109 }
122 }
110 }
123 }
111}
124}
qml/Dash/Card.qml+99−79
@@ -25,47 +25,53 @@ AbstractButton {
25 property var components
25 property var components
26 property var cardData
26 property var cardData
27
27
28− property alias fontScale: header.fontScale
28+ property real fontScale: 1.0
29− property alias headerAlignment: header.headerAlignment
29+ property int headerAlignment: Text.AlignLeft
30− property alias headerHeight: header.height
30+ readonly property int headerHeight: headerLoader.item ? headerLoader.item.height : 0
31+ property int fixedHeaderHeight: -1
31− readonly property alias title: header.title
32+ readonly property string title: cardData && cardData["title"] || ""
32
33
33 property bool showHeader: true
34 property bool showHeader: true
34
35
35 implicitWidth: childrenRect.width
36 implicitWidth: childrenRect.width
36− implicitHeight: summary.y + summary.height + (summary.text && background.visible ? units.gu(1) : 0)
37+ implicitHeight: summary.y + summary.height + (summary.text && backgroundLoader.active ? units.gu(1) : 0)
37
38
38− UbuntuShape {
39+ Loader {
39− id: background
40+ id: backgroundLoader
40− objectName: "background"
41+ objectName: "backgroundLoader"
41− radius: "medium"
42− visible: template["card-layout"] !== "horizontal" && (template["card-background"] || components["background"]
43− || artAndSummary)
44− property bool artAndSummary: components["art"]["field"] && components["summary"] || false
45− color: getColor(0) || "white"
46− gradientColor: getColor(1) || color
47− anchors.fill: parent
48− image: backgroundImage.source ? backgroundImage : null
49
42
50− property real luminance: 0.2126 * color.r + 0.7152 * color.g + 0.0722 * color.b
43+ readonly property bool artAndSummary: components["art"]["field"] && components["summary"] || false
44+ active: template["card-layout"] !== "horizontal" && (template["card-background"] || components["background"] || artAndSummary)
45+ anchors.fill: parent
51
46
47+ sourceComponent: UbuntuShape {
48+ objectName: "background"
49+ radius: "medium"
50+ color: getColor(0) || "white"
51+ gradientColor: getColor(1) || color
52+ anchors.fill: parent
53+ image: backgroundImage.source ? backgroundImage : null
54+
55+ property real luminance: 0.2126 * color.r + 0.7152 * color.g + 0.0722 * color.b
56+
52− property Image backgroundImage: Image {
57+ property Image backgroundImage: Image {
53− objectName: "backgroundImage"
58+ objectName: "backgroundImage"
54− source: {
59+ source: {
55− if (cardData && typeof cardData["background"] === "string") return cardData["background"]
60+ if (cardData && typeof cardData["background"] === "string") return cardData["background"]
56− else if (template && typeof template["card-background"] === "string") return template["card-background"]
61+ else if (template && typeof template["card-background"] === "string") return template["card-background"]
57− else return ""
62+ else return ""
63+ }
58 }
64 }
59− }
60
65
61− function getColor(index) {
66+ function getColor(index) {
62− if (cardData && typeof cardData["background"] === "object"
67+ if (cardData && typeof cardData["background"] === "object"
63− && (cardData["background"]["type"] === "color" || cardData["background"]["type"] === "gradient")) {
68+ && (cardData["background"]["type"] === "color" || cardData["background"]["type"] === "gradient")) {
64− return cardData["background"]["elements"][index];
69+ return cardData["background"]["elements"][index];
65− } else if (template && typeof template["card-background"] === "object"
70+ } else if (template && typeof template["card-background"] === "object"
66− && (template["card-background"]["type"] === "color" || template["card-background"]["type"] === "gradient")) {
71+ && (template["card-background"]["type"] === "color" || template["card-background"]["type"] === "gradient")) {
67− return template["card-background"]["elements"][index];
72+ return template["card-background"]["elements"][index];
68− } else return undefined;
73+ } else return undefined;
74+ }
69 }
75 }
70 }
76 }
71
77
@@ -111,7 +117,7 @@ AbstractButton {
111 function updateWidthHeightBindings() {
117 function updateWidthHeightBindings() {
112 if (isHorizontal) {
118 if (isHorizontal) {
113 width = Qt.binding(function() { return height * artShape.aspect });
119 width = Qt.binding(function() { return height * artShape.aspect });
114− height = Qt.binding(function() { return header.height });
120+ height = Qt.binding(function() { return root.headerHeight });
115 } else {
121 } else {
116 width = Qt.binding(function() { return root.width });
122 width = Qt.binding(function() { return root.width });
117 height = Qt.binding(function() { return width / artShape.aspect });
123 height = Qt.binding(function() { return width / artShape.aspect });
@@ -120,53 +126,58 @@ AbstractButton {
120 }
126 }
121 }
127 }
122
128
123− ShaderEffect {
129+ Loader {
124− id: overlay
130+ id: overlayLoader
125 anchors {
131 anchors {
126 left: artShape.left
132 left: artShape.left
127 right: artShape.right
133 right: artShape.right
128 bottom: artShape.bottom
134 bottom: artShape.bottom
129 }
135 }
136+ active: template && template["overlay"] && artShape.visible && artShape.image.status === Image.Ready || false
130
137
131− height: header.height
138+ sourceComponent: ShaderEffect {
132− opacity: header.opacity * 0.6
139+ id: overlay
133− visible: template && template["overlay"] && artShape.visible && artShape.image.status === Image.Ready || false
134
140
141+ height: headerLoader.item ? headerLoader.item.height : 0
142+ opacity: headerLoader.item ? headerLoader.item.opacity * 0.6 : 0
143+
135− property var source: ShaderEffectSource {
144+ property var source: ShaderEffectSource {
136− id: shaderSource
145+ id: shaderSource
137− sourceItem: artShape
146+ sourceItem: artShape
138− onVisibleChanged: if (visible) scheduleUpdate()
147+ onVisibleChanged: if (visible) scheduleUpdate()
139− live: false
148+ live: false
140− sourceRect: Qt.rect(0, artShape.height - overlay.height, artShape.width, overlay.height)
149+ sourceRect: Qt.rect(0, artShape.height - overlay.height, artShape.width, overlay.height)
141− }
150+ }
142
151
143− vertexShader: "
152+ vertexShader: "
144− uniform highp mat4 qt_Matrix;
153+ uniform highp mat4 qt_Matrix;
145− attribute highp vec4 qt_Vertex;
154+ attribute highp vec4 qt_Vertex;
146− attribute highp vec2 qt_MultiTexCoord0;
155+ attribute highp vec2 qt_MultiTexCoord0;
147− varying highp vec2 coord;
156+ varying highp vec2 coord;
148− void main() {
157+ void main() {
149− coord = qt_MultiTexCoord0;
158+ coord = qt_MultiTexCoord0;
150− gl_Position = qt_Matrix * qt_Vertex;
159+ gl_Position = qt_Matrix * qt_Vertex;
151− }"
160+ }"
152−
161+
153− fragmentShader: "
162+ fragmentShader: "
154− varying highp vec2 coord;
163+ varying highp vec2 coord;
155− uniform sampler2D source;
164+ uniform sampler2D source;
156− uniform lowp float qt_Opacity;
165+ uniform lowp float qt_Opacity;
157− void main() {
166+ void main() {
158− lowp vec4 tex = texture2D(source, coord);
167+ lowp vec4 tex = texture2D(source, coord);
159− gl_FragColor = vec4(0, 0, 0, tex.a) * qt_Opacity;
168+ gl_FragColor = vec4(0, 0, 0, tex.a) * qt_Opacity;
160− }"
169+ }"
170+ }
161 }
171 }
162
172
163− CardHeader {
173+ Loader {
164− id: header
174+ id: headerLoader
165− objectName: "cardHeader"
175+ objectName: "cardHeaderLoader"
176+
166 anchors {
177 anchors {
167 top: {
178 top: {
168 if (template) {
179 if (template) {
169− if (template["overlay"]) return overlay.top;
180+ if (template["overlay"]) return overlayLoader.top;
170 if (template["card-layout"] === "horizontal") return artShape.top;
181 if (template["card-layout"] === "horizontal") return artShape.top;
171 }
182 }
172 return artShape.bottom;
183 return artShape.bottom;
@@ -179,29 +190,38 @@ AbstractButton {
179 }
190 }
180 right: parent.right
191 right: parent.right
181 }
192 }
193+ active: cardData && cardData["title"] || cardData && cardData["mascot"] || false
194+
195+ sourceComponent: CardHeader {
196+ id: header
197+ objectName: "cardHeader"
182
198
183− mascot: cardData && cardData["mascot"] || ""
199+ mascot: cardData && cardData["mascot"] || ""
184− title: cardData && cardData["title"] || ""
200+ title: root.title
185− subtitle: cardData && cardData["subtitle"] || ""
201+ subtitle: cardData && cardData["subtitle"] || ""
186
202
187− titleWeight: components && components["subtitle"] ? Font.DemiBold : Font.Normal
203+ titleWeight: components && components["subtitle"] ? Font.DemiBold : Font.Normal
188
204
189− opacity: showHeader ? 1 : 0
205+ opacity: showHeader ? 1 : 0
190− inOverlay: root.template && root.template["overlay"] === true
206+ inOverlay: root.template && root.template["overlay"] === true
191− fontColor: inOverlay ? "white" : summary.color
207+ fontColor: inOverlay ? "white" : summary.color
192− useMascotShape: !background.visible && !inOverlay
208+ useMascotShape: !backgroundLoader.active && !inOverlay
209+ headerAlignment: root.headerAlignment
210+ height: root.fixedHeaderHeight != -1 ? root.fixedHeaderHeight : implicitHeight
211+ fontScale: root.fontScale
193
212
194− Behavior on opacity { NumberAnimation { duration: UbuntuAnimation.SnapDuration } }
213+ Behavior on opacity { NumberAnimation { duration: UbuntuAnimation.SnapDuration } }
214+ }
195 }
215 }
196
216
197 Label {
217 Label {
198 id: summary
218 id: summary
199 objectName: "summaryLabel"
219 objectName: "summaryLabel"
200 anchors {
220 anchors {
201− top: header.visible ? header.bottom : artShape.bottom
221+ top: headerLoader.active ? headerLoader.bottom : artShape.bottom
202 left: parent.left
222 left: parent.left
203 right: parent.right
223 right: parent.right
204− margins: background.visible ? units.gu(1) : 0
224+ margins: backgroundLoader.active ? units.gu(1) : 0
205 topMargin: 0
225 topMargin: 0
206 }
226 }
207 wrapMode: Text.Wrap
227 wrapMode: Text.Wrap
@@ -211,6 +231,6 @@ AbstractButton {
211 height: text ? implicitHeight : 0
231 height: text ? implicitHeight : 0
212 fontSize: "small"
232 fontSize: "small"
213 // TODO karni: Change "grey" to Ubuntu.Components.Palette color once updated.
233 // TODO karni: Change "grey" to Ubuntu.Components.Palette color once updated.
214− color: background.visible && background.luminance < 0.7 ? "white" : "grey"
234+ color: backgroundLoader.active && backgroundLoader.item.luminance < 0.7 ? "white" : "grey"
215 }
235 }
216}
236}
qml/Dash/CardCarousel.qml+1−1
@@ -52,7 +52,7 @@ DashRenderer {
52 itemComponent: Card {
52 itemComponent: Card {
53 id: card
53 id: card
54 objectName: "carouselDelegate" + index
54 objectName: "carouselDelegate" + index
55− headerHeight: carousel.headerHeight
55+ fixedHeaderHeight: carousel.headerHeight
56 cardData: model
56 cardData: model
57 template: cardTool.template
57 template: cardTool.template
58 components: cardTool.components
58 components: cardTool.components
qml/Dash/CardFilterGrid.qml+6−10
@@ -28,9 +28,10 @@ DashRenderer {
28 verticalSpacing: units.gu(1)
28 verticalSpacing: units.gu(1)
29 currentItem: filterGrid.currentItem
29 currentItem: filterGrid.currentItem
30 height: filterGrid.height
30 height: filterGrid.height
31+ filtered: filterGrid.filtered
31
32
32− function startFilterAnimation(filter) {
33+ function setFilter(filter, animate) {
33− filterGrid.startFilterAnimation(filter)
34+ filterGrid.setFilter(filter, animate)
34 }
35 }
35
36
36 FilterGrid {
37 FilterGrid {
@@ -41,18 +42,18 @@ DashRenderer {
41 delegateHeight: cardTool.cardHeight
42 delegateHeight: cardTool.cardHeight
42 verticalSpacing: genericFilterGrid.verticalSpacing
43 verticalSpacing: genericFilterGrid.verticalSpacing
43 model: genericFilterGrid.model
44 model: genericFilterGrid.model
44− filter: genericFilterGrid.filter
45 collapsedRowCount: Math.min(2, cardTool && cardTool.template && cardTool.template["collapsed-rows"] || 2)
45 collapsedRowCount: Math.min(2, cardTool && cardTool.template && cardTool.template["collapsed-rows"] || 2)
46 delegateCreationBegin: genericFilterGrid.delegateCreationBegin
46 delegateCreationBegin: genericFilterGrid.delegateCreationBegin
47 delegateCreationEnd: genericFilterGrid.delegateCreationEnd
47 delegateCreationEnd: genericFilterGrid.delegateCreationEnd
48− delegate: Item {
48+ delegate: Loader {
49+ asynchronous: true
49 width: filterGrid.cellWidth
50 width: filterGrid.cellWidth
50 height: filterGrid.cellHeight
51 height: filterGrid.cellHeight
51 Card {
52 Card {
52 id: card
53 id: card
53 width: cardTool.cardWidth
54 width: cardTool.cardWidth
54 height: cardTool.cardHeight
55 height: cardTool.cardHeight
55− headerHeight: cardTool.headerHeight
56+ fixedHeaderHeight: cardTool.headerHeight
56 anchors.horizontalCenter: parent.horizontalCenter
57 anchors.horizontalCenter: parent.horizontalCenter
57 objectName: "delegate" + index
58 objectName: "delegate" + index
58 cardData: model
59 cardData: model
@@ -65,10 +66,5 @@ DashRenderer {
65 onPressAndHold: genericFilterGrid.pressAndHold(index, card.y)
66 onPressAndHold: genericFilterGrid.pressAndHold(index, card.y)
66 }
67 }
67 }
68 }
68−
69− onFilterChanged: {
70− genericFilterGrid.filter = filter
71− filter = Qt.binding(function() { return genericFilterGrid.filter })
72− }
73 }
69 }
74}
70}
qml/Dash/CardHeader.qml+41−31
@@ -19,9 +19,9 @@ import Ubuntu.Components 0.1
19
19
20Item {
20Item {
21 id: root
21 id: root
22− property alias mascot: mascotImage.source
22+ property url mascot: ""
23 property alias title: titleLabel.text
23 property alias title: titleLabel.text
24− property alias subtitle: subtitleLabel.text
24+ property var subtitle
25
25
26 property alias titleWeight: titleLabel.font.weight
26 property alias titleWeight: titleLabel.font.weight
27 property alias titleSize: titleLabel.fontSize
27 property alias titleSize: titleLabel.fontSize
@@ -35,8 +35,8 @@ Item {
35 property bool useMascotShape: true
35 property bool useMascotShape: true
36 property color fontColor: Theme.palette.selected.backgroundText
36 property color fontColor: Theme.palette.selected.backgroundText
37
37
38− visible: mascotImage.status === Image.Ready || title
38+ visible: mascot != "" || title
39− height: row.height > 0 ? row.height + row.margins * 2 : 0
39+ implicitHeight: row.height > 0 ? row.height + row.margins * 2 : 0
40
40
41 Row {
41 Row {
42 id: row
42 id: row
@@ -44,7 +44,7 @@ Item {
44
44
45 property real margins: units.gu(1)
45 property real margins: units.gu(1)
46
46
47− spacing: mascotShape.visible || mascotImage.visible || inOverlay ? margins : 0
47+ spacing: mascotShapeLoader.active || mascotImageLoader.active || inOverlay ? margins : 0
48 anchors {
48 anchors {
49 top: parent.top; left: parent.left; right: parent.right
49 top: parent.top; left: parent.left; right: parent.right
50 margins: margins
50 margins: margins
@@ -52,33 +52,40 @@ Item {
52 rightMargin: spacing
52 rightMargin: spacing
53 }
53 }
54
54
55− UbuntuShape {
55+ Loader {
56− id: mascotShape
56+ id: mascotShapeLoader
57− objectName: "mascotShape"
57+ objectName: "mascotShapeLoader"
58
58
59+ active: useMascotShape && mascotImageLoader.item && mascotImageLoader.item.status === Image.Ready
60+ visible: active
61+ anchors.verticalCenter: parent.verticalCenter
59 // TODO karni: Icon aspect-ratio is 8:7.5. Revisit these values to avoid fraction of pixels.
62 // TODO karni: Icon aspect-ratio is 8:7.5. Revisit these values to avoid fraction of pixels.
60 width: units.gu(6)
63 width: units.gu(6)
61 height: units.gu(5.625)
64 height: units.gu(5.625)
62− anchors.verticalCenter: parent.verticalCenter
63− visible: useMascotShape && image && image.status === Image.Ready
64 readonly property int maxSize: Math.max(width, height) * 4
65 readonly property int maxSize: Math.max(width, height) * 4
65
66
66− image: useMascotShape ? mascotImage : null
67+ sourceComponent: UbuntuShape {
68+ image: mascotImageLoader.item
69+ }
67 }
70 }
68
71
69− Image {
72+ Loader {
70− id: mascotImage
73+ id: mascotImageLoader
71− objectName: "mascotImage"
74+ active: root.mascot != ""
72−
75+ visible: active && !useMascotShape && item.status === Image.Ready
73− width: source ? mascotShape.width : 0
74− height: mascotShape.height
75 anchors.verticalCenter: parent.verticalCenter
76 anchors.verticalCenter: parent.verticalCenter
76− visible: !useMascotShape && status === Image.Ready
77+ sourceComponent: Image {
78+ objectName: "mascotImage"
79+
80+ source: root.mascot
81+ width: source ? mascotShapeLoader.width : 0
82+ height: mascotShapeLoader.height
77
83
78− sourceSize { width: mascotShape.maxSize; height: mascotShape.maxSize }
84+ sourceSize { width: mascotShapeLoader.maxSize; height: mascotShapeLoader.maxSize }
79− fillMode: Image.PreserveAspectCrop
85+ fillMode: Image.PreserveAspectCrop
80− horizontalAlignment: Image.AlignHCenter
86+ horizontalAlignment: Image.AlignHCenter
81− verticalAlignment: Image.AlignVCenter
87+ verticalAlignment: Image.AlignVCenter
88+ }
82 }
89 }
83
90
84 Column {
91 Column {
@@ -100,16 +107,19 @@ Item {
100 color: fontColor
107 color: fontColor
101 }
108 }
102
109
103− Label {
110+ Loader {
104− id: subtitleLabel
111+ active: titleLabel.text && root.subtitle
105− objectName: "subtitleLabel"
106 anchors { left: parent.left; right: parent.right }
112 anchors { left: parent.left; right: parent.right }
113+ sourceComponent: Label {
114+ id: subtitleLabel
115+ objectName: "subtitleLabel"
107− elide: Text.ElideRight
116+ elide: Text.ElideRight
108− fontSize: "small"
117+ fontSize: "small"
109− font.weight: Font.Light
118+ font.weight: Font.Light
110− visible: titleLabel.text && text
111− font.pixelSize: Math.round(FontUtils.sizeToPixels(fontSize) * fontScale)
119+ font.pixelSize: Math.round(FontUtils.sizeToPixels(fontSize) * fontScale)
112− color: fontColor
120+ color: fontColor
121+ text: root.subtitle
122+ }
113 }
123 }
114 }
124 }
115 }
125 }
qml/Dash/DashContent.qml+5−10
@@ -27,13 +27,9 @@ Item {
27 readonly property alias currentIndex: dashContentList.currentIndex
27 readonly property alias currentIndex: dashContentList.currentIndex
28 property alias previewOpen: previewListView.open
28 property alias previewOpen: previewListView.open
29
29
30− property ScopeDelegateMapper scopeMapper : ScopeDelegateMapper {}
31 property ListModel searchHistory
30 property ListModel searchHistory
32
31
33− signal movementStarted()
34− signal movementEnded()
35 signal scopeLoaded(string scopeId)
32 signal scopeLoaded(string scopeId)
36− signal positionedAtBeginning()
37 signal gotoScope(string scopeId)
33 signal gotoScope(string scopeId)
38 signal openScope(var scope)
34 signal openScope(var scope)
39
35
@@ -71,7 +67,7 @@ Item {
71 dashContentList.currentIndex = index
67 dashContentList.currentIndex = index
72
68
73 if (reset) {
69 if (reset) {
74− dashContent.positionedAtBeginning()
70+ dashContentList.currentItem.item.positionAtBeginning()
75 }
71 }
76 }
72 }
77
73
@@ -114,8 +110,7 @@ Item {
114 highlightRangeMode: ListView.StrictlyEnforceRange
110 highlightRangeMode: ListView.StrictlyEnforceRange
115 // TODO Investigate if we can switch to a smaller cache buffer when/if UbuntuShape gets more performant
111 // TODO Investigate if we can switch to a smaller cache buffer when/if UbuntuShape gets more performant
116 cacheBuffer: 1073741823
112 cacheBuffer: 1073741823
117− onMovementStarted: dashContent.movementStarted()
113+ onMovementStarted: currentItem.item.showHeader();
118− onMovementEnded: dashContent.movementEnded()
119 clip: parent.x != 0
114 clip: parent.x != 0
120
115
121 // If the number of items is less than the current index, then need to reset to another item.
116 // If the number of items is less than the current index, then need to reset to another item.
@@ -135,7 +130,9 @@ Item {
135 width: ListView.view.width
130 width: ListView.view.width
136 height: ListView.view.height
131 height: ListView.view.height
137 asynchronous: true
132 asynchronous: true
138− source: scopeMapper.map(scope.id)
133+ // TODO This if will eventually go away since we're killing DashApps.qml
134+ // once we move app closing to the spread
135+ source: (scope.id == "clickscope") ? "DashApps.qml" : "GenericScopeView.qml"
139 objectName: scope.id + " loader"
136 objectName: scope.id + " loader"
140
137
141 readonly property bool moving: item ? item.moving : false
138 readonly property bool moving: item ? item.moving : false
@@ -154,8 +151,6 @@ Item {
154 item.scope = Qt.binding(function() { return scope })
151 item.scope = Qt.binding(function() { return scope })
155 item.isCurrent = Qt.binding(function() { return visible && ListView.isCurrentItem })
152 item.isCurrent = Qt.binding(function() { return visible && ListView.isCurrentItem })
156 item.tabBarHeight = dashPageHeader.implicitHeight;
153 item.tabBarHeight = dashPageHeader.implicitHeight;
157− dashContentList.movementStarted.connect(item.movementStarted)
158− dashContent.positionedAtBeginning.connect(item.positionedAtBeginning)
159 dashContent.scopeLoaded(item.scope.id)
154 dashContent.scopeLoaded(item.scope.id)
160 }
155 }
161 Connections {
156 Connections {
qml/Dash/DashRenderer.qml+3−3
@@ -20,8 +20,8 @@ Item {
20 // Can the item be expanded?
20 // Can the item be expanded?
21 property bool expandable: false
21 property bool expandable: false
22
22
23− // In case it can be expanded, should we filter it
23+ // In case it can be expanded, is it filtered
24− property bool filter: true
24+ property bool filtered: true
25
25
26 property int collapsedHeight: height
26 property int collapsedHeight: height
27
27
@@ -58,6 +58,6 @@ Item {
58 /// @param itemY is y of the held delegate
58 /// @param itemY is y of the held delegate
59 signal pressAndHold(int index, real itemY)
59 signal pressAndHold(int index, real itemY)
60
60
61− function startFilterAnimation(filter) {
61+ function setFilter(filter, animate) {
62 }
62 }
63}
63}
qml/Dash/GenericScopeView.qml+21−22
@@ -33,9 +33,6 @@ FocusScope {
33 property PageHeader pageHeader: null
33 property PageHeader pageHeader: null
34 property Item previewListView: null
34 property Item previewListView: null
35
35
36− signal movementStarted
37− signal positionedAtBeginning
38−
39 property bool enableHeightBehaviorOnNextCreation: false
36 property bool enableHeightBehaviorOnNextCreation: false
40 property var categoryView: categoryView
37 property var categoryView: categoryView
41
38
@@ -49,6 +46,14 @@ FocusScope {
49 shell.activateApplication(appId);
46 shell.activateApplication(appId);
50 }
47 }
51
48
49+ function positionAtBeginning() {
50+ categoryView.positionAtBeginning()
51+ }
52+
53+ function showHeader() {
54+ categoryView.showHeader()
55+ }
56+
52 Binding {
57 Binding {
53 target: scope
58 target: scope
54 property: "isActive"
59 property: "isActive"
@@ -69,10 +74,6 @@ FocusScope {
69 previewListView.open = false;
74 previewListView.open = false;
70 }
75 }
71
76
72− onMovementStarted: categoryView.showHeader()
73−
74− onPositionedAtBeginning: categoryView.positionAtBeginning()
75−
76 Binding {
77 Binding {
77 target: scopeView.scope
78 target: scopeView.scope
78 property: "searchQuery"
79 property: "searchQuery"
@@ -121,7 +122,7 @@ FocusScope {
121 showDivider: false
122 showDivider: false
122
123
123 readonly property bool expandable: rendererLoader.item ? rendererLoader.item.expandable : false
124 readonly property bool expandable: rendererLoader.item ? rendererLoader.item.expandable : false
124− readonly property bool filtered: rendererLoader.item ? rendererLoader.item.filter : true
125+ readonly property bool filtered: rendererLoader.item ? rendererLoader.item.filtered : true
125 readonly property string category: categoryId
126 readonly property string category: categoryId
126 readonly property var item: rendererLoader.item
127 readonly property var item: rendererLoader.item
127
128
@@ -167,9 +168,7 @@ FocusScope {
167 item.objectName = Qt.binding(function() { return categoryId })
168 item.objectName = Qt.binding(function() { return categoryId })
168 if (item.expandable) {
169 if (item.expandable) {
169 var shouldFilter = categoryId != categoryView.expandedCategoryId;
170 var shouldFilter = categoryId != categoryView.expandedCategoryId;
170− if (shouldFilter != item.filter) {
171+ item.setFilter(shouldFilter, false /*animate*/);
171− item.filter = shouldFilter;
172− }
173 }
172 }
174 updateDelegateCreationRange();
173 updateDelegateCreationRange();
175 item.cardTool = cardTool;
174 item.cardTool = cardTool;
@@ -218,11 +217,8 @@ FocusScope {
218 var shrinkingVisible = shouldFilter && y + item.collapsedHeight < categoryView.height;
217 var shrinkingVisible = shouldFilter && y + item.collapsedHeight < categoryView.height;
219 var growingVisible = !shouldFilter && y + height < categoryView.height;
218 var growingVisible = !shouldFilter && y + height < categoryView.height;
220 if (!previewListView.open || !shouldFilter) {
219 if (!previewListView.open || !shouldFilter) {
221− if (shrinkingVisible || growingVisible) {
220+ var animate = shrinkingVisible || growingVisible;
222− item.startFilterAnimation(shouldFilter)
221+ item.setFilter(shouldFilter, animate)
223− } else {
224− item.filter = shouldFilter;
225− }
226 if (!shouldFilter && !previewListView.open) {
222 if (!shouldFilter && !previewListView.open) {
227 categoryView.maximizeVisibleArea(index, item.uncollapsedHeight);
223 categoryView.maximizeVisibleArea(index, item.uncollapsedHeight);
228 }
224 }
@@ -237,12 +233,15 @@ FocusScope {
237 }
233 }
238
234
239 function updateDelegateCreationRange() {
235 function updateDelegateCreationRange() {
236+ if (categoryView.moving) {
240− // Do not update the range if we are overshooting up or down, since we'll come back
237+ // Do not update the range if we are overshooting up or down, since we'll come back
241− // to the stable position and delete/create items without any reason
238+ // to the stable position and delete/create items without any reason
242− if (categoryView.contentY < categoryView.originY) {
239+ if (categoryView.contentY < categoryView.originY) {
243− return;
240+ return;
241+ } else if (categoryView.contentHeight - categoryView.originY > categoryView.height &&
244− } else if (categoryView.contentY + categoryView.height > categoryView.contentHeight) {
242+ categoryView.contentY + categoryView.height > categoryView.contentHeight) {
245− return;
243+ return;
244+ }
246 }
245 }
247
246
248 if (item && item.hasOwnProperty("delegateCreationBegin")) {
247 if (item && item.hasOwnProperty("delegateCreationBegin")) {
qml/Dash/Previews/PreviewRatingDisplay.qml+4−2
@@ -71,7 +71,8 @@ PreviewWidget {
71 id: authorLabel
71 id: authorLabel
72 objectName: "authorLabel"
72 objectName: "authorLabel"
73 anchors { left: parent.left; right: parent.right }
73 anchors { left: parent.left; right: parent.right }
74+ // TODO cimi: Yet another fix requiring Palette update.
74− color: Theme.palette.selected.backgroundText
75+ color: "grey" //Theme.palette.selected.backgroundText
75 opacity: .8
76 opacity: .8
76 text: modelData["author"] || ""
77 text: modelData["author"] || ""
77 visible: text !== ""
78 visible: text !== ""
@@ -82,7 +83,8 @@ PreviewWidget {
82 id: reviewLabel
83 id: reviewLabel
83 objectName: "reviewLabel"
84 objectName: "reviewLabel"
84 anchors { left: parent.left; right: parent.right }
85 anchors { left: parent.left; right: parent.right }
86+ // TODO cimi: Yet another fix requiring Palette update.
85− color: Theme.palette.selected.backgroundText
87+ color: "grey" //Theme.palette.selected.backgroundText
86 opacity: .8
88 opacity: .8
87 text: modelData["review"] || ""
89 text: modelData["review"] || ""
88 visible: text !== ""
90 visible: text !== ""
qml/Dash/Previews/PreviewRatingInput.qml+6−4
@@ -76,7 +76,8 @@ PreviewWidget {
76 verticalCenter: parent.verticalCenter
76 verticalCenter: parent.verticalCenter
77 left: parent.left
77 left: parent.left
78 }
78 }
79+ // TODO cimi: Yet another fix requiring Palette update.
79− color: Theme.palette.selected.backgroundText
80+ color: "grey" //Theme.palette.selected.backgroundText
80 opacity: .8
81 opacity: .8
81 text: widgetData["rating-label"] || i18n.tr("Rate this")
82 text: widgetData["rating-label"] || i18n.tr("Rate this")
82 }
83 }
@@ -121,7 +122,8 @@ PreviewWidget {
121 left: parent.left
122 left: parent.left
122 right: parent.right
123 right: parent.right
123 }
124 }
125+ // TODO cimi: Yet another fix requiring Palette update.
124− color: Theme.palette.selected.backgroundText
126+ color: "grey" //Theme.palette.selected.backgroundText
125 opacity: .8
127 opacity: .8
126 text: widgetData["review-label"] || i18n.tr("Add a review")
128 text: widgetData["review-label"] || i18n.tr("Add a review")
127 }
129 }
@@ -153,8 +155,8 @@ PreviewWidget {
153 objectName: "submitButton"
155 objectName: "submitButton"
154
156
155 readonly property bool readyToSubmit: {
157 readonly property bool readyToSubmit: {
156− if (reviewTextArea.text === "" ||
157− (widgetData["visible"] === "both" && rating.value < 0)) return false;
158+ if ((widgetData["required"] !== "review" && rating.value < 0) ||
159+ (widgetData["required"] !== "rating" && reviewTextArea.text === "")) return false;
158 else return true;
160 else return true;
159 }
161 }
160
162
qml/Dash/ScopeDelegateMapper.qmldeleted−30
@@ -1,30 +0,0 @@
1−/*
2− * Copyright (C) 2013 Canonical, Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− */
16−
17−import QtQuick 2.0
18−
19−QtObject {
20− property var scopeDelegateMapping: {"clickscope": "DashApps.qml"}
21− property string genericScope: "GenericScopeView.qml"
22−
23− function map(scopeId) {
24− var customScope = scopeDelegateMapping[scopeId]
25− if (customScope != undefined) {
26− return customScope
27− }
28− return genericScope
29− }
30−}
qml/Greeter/Clock.qml+3−6
@@ -24,14 +24,11 @@ Item {
24 implicitWidth: childrenRect.width
24 implicitWidth: childrenRect.width
25 implicitHeight: childrenRect.height
25 implicitHeight: childrenRect.height
26
26
27− // Allows to set the current Date. Will be overwritten if active
27+ // Allows to set the current Date. Will be overwritten if visible
28 property date currentDate
28 property date currentDate
29
29
30− // If active, time will be updated through the indicators service
31− property bool active: clock.enabled && clock.visible
32−
33 Component.onCompleted: {
30 Component.onCompleted: {
34− if (active) {
31+ if (visible) {
35 currentDate = new Date()
32 currentDate = new Date()
36 }
33 }
37 }
34 }
@@ -42,7 +39,7 @@ Item {
42
39
43 busName: "com.canonical.indicator.datetime"
40 busName: "com.canonical.indicator.datetime"
44 actionsObjectPath: "/com/canonical/indicator/datetime"
41 actionsObjectPath: "/com/canonical/indicator/datetime"
45− menuObjectPath: clock.active ? "/com/canonical/indicator/datetime/phone" : ""
42+ menuObjectPath: clock.visible ? "/com/canonical/indicator/datetime/phone" : ""
46
43
47 Indicators.RootActionState {
44 Indicators.RootActionState {
48 menu: timeModel.model
45 menu: timeModel.model
qml/Greeter/Greeter.qml+115−42
@@ -28,10 +28,10 @@ Showable {
28 property url defaultBackground
28 property url defaultBackground
29
29
30 // 1 when fully shown and 0 when fully hidden
30 // 1 when fully shown and 0 when fully hidden
31− property real showProgress: MathUtils.clamp((width + x) / width, 0, 1)
31+ property real showProgress: MathUtils.clamp((width - Math.abs(x)) / width, 0, 1)
32
32
33 showAnimation: StandardAnimation { property: "x"; to: 0 }
33 showAnimation: StandardAnimation { property: "x"; to: 0 }
34− hideAnimation: StandardAnimation { property: "x"; to: -width }
34+ hideAnimation: __leftHideAnimation
35
35
36 property alias dragHandleWidth: dragHandle.width
36 property alias dragHandleWidth: dragHandle.width
37 property alias model: greeterContentLoader.model
37 property alias model: greeterContentLoader.model
@@ -40,19 +40,81 @@ Showable {
40 readonly property bool narrowMode: !multiUser && height > width
40 readonly property bool narrowMode: !multiUser && height > width
41 readonly property bool multiUser: LightDM.Users.count > 1
41 readonly property bool multiUser: LightDM.Users.count > 1
42
42
43− readonly property bool leftTeaserPressed: greeterContentLoader.status == Loader.Ready &&
44− greeterContentLoader.item.leftTeaserPressed
45− readonly property bool rightTeaserPressed: greeterContentLoader.status == Loader.Ready &&
46− greeterContentLoader.item.rightTeaserPressed
47−
48 readonly property int currentIndex: greeterContentLoader.currentIndex
43 readonly property int currentIndex: greeterContentLoader.currentIndex
49
44
45+ property var __leftHideAnimation: StandardAnimation { property: "x"; to: -width }
46+ property var __rightHideAnimation: StandardAnimation { property: "x"; to: width }
47+
50 signal selected(int uid)
48 signal selected(int uid)
51 signal unlocked(int uid)
49 signal unlocked(int uid)
50+ signal tease()
51+
52+ function hideRight() {
53+ if (shown) {
54+ hideAnimation = __rightHideAnimation
55+ hide()
56+ }
57+ }
58+
59+ onRequiredChanged: {
60+ // Reset hide animation to default once we're finished with it
61+ if (!required) {
62+ // Put back on left for reliable show direction and so that
63+ // if normal hide() is called, we don't animate from right.
64+ x = -width
65+ hideAnimation = __leftHideAnimation
66+ }
67+ }
68+
69+ // Bi-directional revealer
70+ DraggingArea {
71+ id: dragHandle
72+ anchors.fill: parent
73+ enabled: greeter.narrowMode || !greeter.locked
74+ orientation: Qt.Horizontal
75+ propagateComposedEvents: true
76+
77+ Component.onCompleted: {
78+ // set evaluators to baseline of dragValue == 0
79+ leftEvaluator.reset()
80+ rightEvaluator.reset()
81+ }
82+
83+ function maybeTease() {
84+ if (!greeter.locked || greeter.narrowMode)
85+ greeter.tease();
86+ }
87+
88+ onClicked: maybeTease()
89+ onDragStart: maybeTease()
90+ onPressAndHold: {} // eat event, but no need to tease, as drag will cover it
91+
92+ onDragEnd: {
93+ if (rightEvaluator.shouldAutoComplete())
94+ greeter.hideRight()
95+ else if (leftEvaluator.shouldAutoComplete())
96+ greeter.hide();
97+ else
98+ greeter.show(); // undo drag
99+ }
100+
101+ onDragValueChanged: {
102+ // dragValue is kept as a "step" value since we do this x adjusting on the fly
103+ greeter.x += dragValue
104+ }
105+
106+ EdgeDragEvaluator {
107+ id: rightEvaluator
108+ trackedPosition: dragHandle.dragValue + greeter.x
109+ maxDragDistance: parent.width
110+ direction: Direction.Rightwards
111+ }
52
112
53− onRightTeaserPressedChanged: {
113+ EdgeDragEvaluator {
54− if (rightTeaserPressed && (!locked || narrowMode) && x == 0) {
114+ id: leftEvaluator
55− teasingTimer.start();
115+ trackedPosition: dragHandle.dragValue + greeter.x
116+ maxDragDistance: parent.width
117+ direction: Direction.Leftwards
56 }
118 }
57 }
119 }
58
120
@@ -82,45 +144,56 @@ Showable {
82 }
144 }
83 }
145 }
84
146
85− Timer {
147+ onTease: showLabelAnimation.start()
86− id: teasingTimer
87− interval: 200
88− }
89
148
90− states: [
149+ Label {
91− State {
150+ id: swipeHint
92− name: "teasing"
151+ visible: greeter.shown
152+ property real baseOpacity: 0.5
153+ opacity: 0.0
154+ anchors.horizontalCenter: parent.horizontalCenter
155+ anchors.bottom: parent.bottom
156+ anchors.bottomMargin: units.gu(5)
157+ text: i18n.tr("Swipe to unlock")
158+ color: "white"
159+ font.weight: Font.Light
160+
161+ SequentialAnimation on opacity {
162+ id: showLabelAnimation
93− when: teasingTimer.running
163+ running: false
94− PropertyChanges {
164+ loops: 2
95− target: greeter
165+
96− x: -dragHandle.hintDisplacement
166+ StandardAnimation {
167+ from: 0.0
168+ to: swipeHint.baseOpacity
169+ duration: UbuntuAnimation.SleepyDuration
97 }
170 }
98− }
171+ PauseAnimation { duration: UbuntuAnimation.BriskDuration }
99− ]
172+ StandardAnimation {
100− transitions: [
173+ from: swipeHint.baseOpacity
101− Transition {
102− from: "*"
103− to: "*"
174+ to: 0.0
104− NumberAnimation {
175+ duration: UbuntuAnimation.SleepyDuration
105− target: greeter
106− property: "x"
107− duration: 300
108− easing.type: Easing.OutCubic
109 }
176 }
110 }
177 }
111− ]
178+ }
112−
113− DragHandle {
114− id: dragHandle
115
179
180+ // right side shadow
181+ Image {
182+ anchors.left: parent.right
116 anchors.top: parent.top
183 anchors.top: parent.top
117 anchors.bottom: parent.bottom
184 anchors.bottom: parent.bottom
118− anchors.right: parent.right
185+ visible: parent.required
119−
186+ fillMode: Image.Tile
120− hintDisplacement: units.gu(2)
187+ source: "../graphics/dropshadow_right.png"
121−
188+ }
122− enabled: greeter.narrowMode || !greeter.locked
123
189
124− direction: Direction.Leftwards
190+ // left side shadow
191+ Image {
192+ anchors.right: parent.left
193+ anchors.top: parent.top
194+ anchors.bottom: parent.bottom
195+ visible: parent.required
196+ fillMode: Image.Tile
197+ source: "../graphics/dropshadow_left.png"
125 }
198 }
126}
199}
qml/Greeter/GreeterContent.qml+1−10
@@ -20,15 +20,11 @@ import Ubuntu.Components 0.1
20import LightDM 0.1 as LightDM
20import LightDM 0.1 as LightDM
21import "../Components"
21import "../Components"
22
22
23−MouseArea {
23+Item {
24 id: root
24 id: root
25 anchors.fill: parent
25 anchors.fill: parent
26
26
27 property bool ready: background.source == "" || background.status == Image.Ready || background.status == Image.Error
27 property bool ready: background.source == "" || background.status == Image.Ready || background.status == Image.Error
28− property bool leftTeaserPressed: teasingMouseArea.pressed &&
29− teasingMouseArea.mouseX < teasingMouseArea.width / 2
30− property bool rightTeaserPressed: teasingMouseArea.pressed &&
31− teasingMouseArea.mouseX > teasingMouseArea.width / 2
32
28
33 signal selected(int uid)
29 signal selected(int uid)
34 signal unlocked(int uid)
30 signal unlocked(int uid)
@@ -74,11 +70,6 @@ MouseArea {
74 opacity: 0.4
70 opacity: 0.4
75 }
71 }
76
72
77− MouseArea {
78− id: teasingMouseArea
79− anchors.fill: parent
80− }
81−
82 Loader {
73 Loader {
83 id: loginLoader
74 id: loginLoader
84 objectName: "loginLoader"
75 objectName: "loginLoader"
qml/Greeter/Infographics.qml+3
@@ -457,5 +457,8 @@ Item {
457 !circleGrowAnimTimer.running)
457 !circleGrowAnimTimer.running)
458 infographic.model.nextDataSource()
458 infographic.model.nextDataSource()
459 }
459 }
460+
461+ onClicked: mouse.accepted = false
462+ onPressed: mouse.accepted = false
460 }
463 }
461}
464}
qml/Hud/Hud.qml+1−1
@@ -491,6 +491,6 @@ Item {
491 anchors.top: hudContentClipper.top
491 anchors.top: hudContentClipper.top
492 anchors.bottom: hudContentClipper.bottom
492 anchors.bottom: hudContentClipper.bottom
493 fillMode: Image.Tile
493 fillMode: Image.Tile
494− source: "graphics/dropshadow_right.png"
494+ source: "../graphics/dropshadow_right.png"
495 }
495 }
496}
496}
qml/Shell.qml+64−57
@@ -148,8 +148,8 @@ FocusScope {
148
148
149 available: !greeter.shown && !lockscreen.shown
149 available: !greeter.shown && !lockscreen.shown
150 hides: [stages, launcher, panel.indicators]
150 hides: [stages, launcher, panel.indicators]
151− shown: disappearingAnimationProgress !== 1.0
151+ shown: disappearingAnimationProgress !== 1.0 && greeterWrapper.showProgress !== 1.0
152− enabled: disappearingAnimationProgress === 0.0 && edgeDemo.dashEnabled
152+ enabled: disappearingAnimationProgress === 0.0 && greeterWrapper.showProgress === 0.0 && edgeDemo.dashEnabled
153
153
154 anchors {
154 anchors {
155 fill: parent
155 fill: parent
@@ -159,18 +159,14 @@ FocusScope {
159 contentScale: 1.0 - 0.2 * disappearingAnimationProgress
159 contentScale: 1.0 - 0.2 * disappearingAnimationProgress
160 opacity: 1.0 - disappearingAnimationProgress
160 opacity: 1.0 - disappearingAnimationProgress
161 property real disappearingAnimationProgress: {
161 property real disappearingAnimationProgress: {
162− if (greeter.shown) {
162+ if (stages.overlayMode) {
163− return greeter.showProgress;
163+ return 0;
164 } else {
164 } else {
165− if (stages.overlayMode) {
166− return 0;
167− }
168 return stages.showProgress
165 return stages.showProgress
169 }
166 }
170 }
167 }
171
168
172− // FIXME: only necessary because stages.showProgress and
169+ // FIXME: only necessary because stages.showProgress is not animated
173− // greeterRevealer.animatedProgress are not animated
174 Behavior on disappearingAnimationProgress { SmoothedAnimation { velocity: 5 }}
170 Behavior on disappearingAnimationProgress { SmoothedAnimation { velocity: 5 }}
175 }
171 }
176 }
172 }
@@ -240,6 +236,8 @@ FocusScope {
240 function show(focusApp) {
236 function show(focusApp) {
241 shown = true;
237 shown = true;
242 panel.indicators.hide();
238 panel.indicators.hide();
239+ edgeDemo.stopDemo();
240+ greeter.hide();
243 if (!ApplicationManager.focusedApplicationId && ApplicationManager.count > 0 && focusApp) {
241 if (!ApplicationManager.focusedApplicationId && ApplicationManager.count > 0 && focusApp) {
244 ApplicationManager.focusApplication(ApplicationManager.get(0).appId);
242 ApplicationManager.focusApplication(ApplicationManager.get(0).appId);
245 }
243 }
@@ -267,12 +265,6 @@ FocusScope {
267 stages.hide();
265 stages.hide();
268 }
266 }
269 }
267 }
270−
271− // If any app is focused when greeter is open, it's due to a user action
272− // like a snap decision (say, an incoming call).
273− // TODO: these should be protected to only unlock for certain applications / certain usecases
274− // potentially only in connection with a notification.
275− greeter.hide()
276 }
268 }
277
269
278 onApplicationAdded: {
270 onApplicationAdded: {
@@ -370,52 +362,66 @@ FocusScope {
370 }
362 }
371 }
363 }
372
364
373− Greeter {
365+ Rectangle {
374− id: greeter
366+ anchors.fill: parent
375− objectName: "greeter"
367+ color: "black"
376−
368+ opacity: greeterWrapper.showProgress * 0.8
377− available: true
369+ }
378− hides: [launcher, panel.indicators, hud]
379− shown: true
380−
381− defaultBackground: shell.background
382
370
371+ Item {
372+ // Just a tiny wrapper to adjust greeter's x without messing with its own dragging
373+ id: greeterWrapper
374+ x: launcher.progress
383 y: panel.panelHeight
375 y: panel.panelHeight
384 width: parent.width
376 width: parent.width
385 height: parent.height - panel.panelHeight
377 height: parent.height - panel.panelHeight
386
378
387− dragHandleWidth: shell.edgeSize
379+ Behavior on x {SmoothedAnimation{velocity: 600}}
388
380
381+ readonly property real showProgress: MathUtils.clamp((1 - x/width) + greeter.showProgress - 1, 0, 1)
382+
383+ Greeter {
384+ id: greeter
385+ objectName: "greeter"
386+
387+ available: true
388+ hides: [launcher, panel.indicators, hud]
389+ shown: true
390+
391+ defaultBackground: shell.background
392+
393+ width: parent.width
394+ height: parent.height
395+
396+ dragHandleWidth: shell.edgeSize
397+
389− onShownChanged: {
398+ onShownChanged: {
390− if (shown) {
399+ if (shown) {
391− lockscreen.reset();
400+ lockscreen.reset();
392− // If there is only one user, we start authenticating with that one here.
401+ // If there is only one user, we start authenticating with that one here.
393− // If there are more users, the Greeter will handle that
402+ // If there are more users, the Greeter will handle that
394− if (LightDM.Users.count == 1) {
403+ if (LightDM.Users.count == 1) {
395− LightDM.Greeter.authenticate(LightDM.Users.data(0, LightDM.UserRoles.NameRole));
404+ LightDM.Greeter.authenticate(LightDM.Users.data(0, LightDM.UserRoles.NameRole));
405+ }
406+ greeter.forceActiveFocus();
396 }
407 }
397− greeter.forceActiveFocus();
398 }
408 }
399− }
400
409
401− onUnlocked: greeter.hide()
410+ onUnlocked: greeter.hide()
402− onSelected: {
411+ onSelected: {
403− // Update launcher items for new user
412+ // Update launcher items for new user
404− var user = LightDM.Users.data(uid, LightDM.UserRoles.NameRole);
413+ var user = LightDM.Users.data(uid, LightDM.UserRoles.NameRole);
405− AccountsService.user = user;
414+ AccountsService.user = user;
406− LauncherModel.setUser(user);
415+ LauncherModel.setUser(user);
407− }
408−
409− onLeftTeaserPressedChanged: {
410− if (leftTeaserPressed) {
411− launcher.tease();
412 }
416 }
413− }
414
417
418+ onTease: launcher.tease()
419+
415− Binding {
420+ Binding {
416− target: ApplicationManager
421+ target: ApplicationManager
417− property: "suspended"
422+ property: "suspended"
418− value: greeter.shown && greeter.showProgress == 1
423+ value: greeter.shown && greeterWrapper.showProgress == 1
424+ }
419 }
425 }
420 }
426 }
421
427
@@ -546,7 +552,7 @@ FocusScope {
546 anchors.bottom: parent.bottom
552 anchors.bottom: parent.bottom
547 width: parent.width
553 width: parent.width
548 dragAreaWidth: shell.edgeSize
554 dragAreaWidth: shell.edgeSize
549− available: (!greeter.shown || greeter.narrowMode) && edgeDemo.launcherEnabled
555+ available: edgeDemo.launcherEnabled
550
556
551 onShowDashHome: {
557 onShowDashHome: {
552 if (edgeDemo.running)
558 if (edgeDemo.running)
@@ -561,14 +567,15 @@ FocusScope {
561 launcher.hide();
567 launcher.hide();
562 }
568 }
563 }
569 }
570+ if (greeter.shown) {
571+ greeter.hideRight();
572+ launcher.hide();
573+ }
564 }
574 }
565 onDashSwipeChanged: if (dashSwipe && stages.shown) dash.setCurrentScope("clickscope", false, true)
575 onDashSwipeChanged: if (dashSwipe && stages.shown) dash.setCurrentScope("clickscope", false, true)
566− onLauncherApplicationSelected:{
576+ onLauncherApplicationSelected: {
567− if (edgeDemo.running)
577+ if (!edgeDemo.running)
568− return;
569−
570− greeter.hide()
571− shell.activateApplication(appId)
578+ shell.activateApplication(appId)
572 }
579 }
573 onShownChanged: {
580 onShownChanged: {
574 if (shown) {
581 if (shown) {
qml/graphics/dropshadow_left@20.pngnew file

Binary file not shown.

qml/Hud/graphics/dropshadow_right@20.png → qml/graphics/dropshadow_right@20.pngrenamed

Binary file not shown.

qml/graphics/phone_background.jpg

Binary file not shown.

qml/graphics/tablet_background.jpg

Binary file not shown.

run+15−1
@@ -68,8 +68,22 @@ if $MOUSE_TOUCH; then
68 QML_PHONE_SHELL_ARGS="$QML_PHONE_SHELL_ARGS -mousetouch"
68 QML_PHONE_SHELL_ARGS="$QML_PHONE_SHELL_ARGS -mousetouch"
69fi
69fi
70
70
71+control_c()
72+{
73+ /sbin/initctl stop unity8
74+ exit $?
75+}
76+
77+trap control_c INT
78+
71if $GDB; then
79if $GDB; then
72 gdb -ex run --args $QML_PHONE_SHELL_PATH $QML_PHONE_SHELL_ARGS $@
80 gdb -ex run --args $QML_PHONE_SHELL_PATH $QML_PHONE_SHELL_ARGS $@
73else
81else
82+ status=`/sbin/initctl status unity8`
83+ if [ "$status" != "unity8 stop/waiting" ]; then
84+ echo "Unity8 is already running, please stop it first"
85+ exit 1
86+ fi
74− $QML_PHONE_SHELL_PATH $QML_PHONE_SHELL_ARGS $@
87+ /sbin/initctl start unity8 BINARY="`readlink -f $QML_PHONE_SHELL_PATH` $QML_PHONE_SHELL_ARGS $@"
88+ tailf -n 0 ~/.cache/upstart/unity8.log
75fi
89fi
tests/autopilot/unity8/application_lifecycle/tests/__init__.py+49
@@ -0,0 +1,49 @@
1+# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
2+#
3+# Unity Autopilot Test Suite
4+# Copyright (C) 2014 Canonical
5+#
6+# This program is free software: you can redistribute it and/or modify
7+# it under the terms of the GNU General Public License as published by
8+# the Free Software Foundation, either version 3 of the License, or
9+# (at your option) any later version.
10+#
11+# This program is distributed in the hope that it will be useful,
12+# but WITHOUT ANY WARRANTY; without even the implied warranty of
13+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+# GNU General Public License for more details.
15+#
16+# You should have received a copy of the GNU General Public License
17+# along with this program. If not, see <http://www.gnu.org/licenses/>.
18+#
19+
20+from autopilot.matchers import Eventually
21+from testtools.matchers import Equals
22+from ubuntuuitoolkit import fixture_setup
23+
24+from unity8 import process_helpers
25+from unity8.shell import tests
26+
27+
28+class ApplicationLifeCycleTestCase(tests.UnityTestCase):
29+
30+ def setUp(self):
31+ super(ApplicationLifeCycleTestCase, self).setUp()
32+ self._qml_mock_enabled = False
33+ self._data_dirs_mock_enabled = False
34+ unity_proxy = self.launch_unity()
35+ process_helpers.unlock_unity(unity_proxy)
36+
37+ def create_test_application(self):
38+ desktop_file_dict = fixture_setup.DEFAULT_DESKTOP_FILE_DICT
39+ desktop_file_dict.update({'X-Ubuntu-Single-Instance': 'true'})
40+ fake_application = fixture_setup.FakeApplication(
41+ desktop_file_dict=desktop_file_dict)
42+ self.useFixture(fake_application)
43+ return (
44+ fake_application.qml_file_path, fake_application.desktop_file_path)
45+
46+ def assert_current_focused_application(self, application_name):
47+ self.assertThat(
48+ self.main_window.get_current_focused_app_id,
49+ Eventually(Equals(application_name)))
tests/autopilot/unity8/application_lifecycle/tests/test_application_lifecycle.py+56−72
@@ -21,27 +21,26 @@
21
21
22from __future__ import absolute_import
22from __future__ import absolute_import
23
23
24−from unity8.process_helpers import unlock_unity
24+import logging
25−from unity8.shell import disable_qml_mocking
25+import os
26−from unity8.shell.tests import UnityTestCase, _get_device_emulation_scenarios
27
26
28from autopilot.matchers import Eventually
27from autopilot.matchers import Eventually
29from autopilot.platform import model
28from autopilot.platform import model
30−from testtools.matchers import Equals, NotEquals
29+from testtools.matchers import Equals
31
30
32−import logging
31+from unity8 import process_helpers
32+from unity8.application_lifecycle import tests
33
33
34−logger = logging.getLogger(__name__)
35
34
35+logger = logging.getLogger(__name__)
36
36
37−class ApplicationLifecycleTests(UnityTestCase):
38
37
39− scenarios = _get_device_emulation_scenarios()
38+class ApplicationLifecycleTests(tests.ApplicationLifeCycleTestCase):
40
39
41 def setUp(self):
40 def setUp(self):
41+ if model() == 'Desktop':
42+ self.skipTest('Test cannot be run on the desktop.')
42 super(ApplicationLifecycleTests, self).setUp()
43 super(ApplicationLifecycleTests, self).setUp()
43− if model() == "Desktop":
44− self.skipTest("Test cannot be run on the desktop.")
45
44
46 def swipe_screen_from_right(self):
45 def swipe_screen_from_right(self):
47 width = self.main_window.width
46 width = self.main_window.width
@@ -54,80 +53,65 @@ class ApplicationLifecycleTests(UnityTestCase):
54 logger.info("Swiping screen from the right edge")
53 logger.info("Swiping screen from the right edge")
55 self.touch.drag(start_x, start_y, end_x, end_y)
54 self.touch.drag(start_x, start_y, end_x, end_y)
56
55
57− def _launch_app(self, app_name):
56+ def launch_fake_app(self):
58− """Launches the application *app_name*
57+ _, desktop_file_path = self.create_test_application()
59−
58+ desktop_file_name = os.path.basename(desktop_file_path)
60− Assumes that the desktop file resides at:
59+ application_name, _ = os.path.splitext(desktop_file_name)
61− /usr/share/applications/{app_name}.desktop
60+ self.launch_upstart_application(application_name)
61+ return application_name
62
62
63− """
64− desktop_file = "--desktop_file_hint="\
65− "/usr/share/applications/{app_name}.desktop".format(
66− app_name=app_name
67− )
68− return self.launch_test_application(
69− app_name,
70− desktop_file,
71− "--stage_hint=main_stage",
72− app_type='qt'
73− )
74−
75− @disable_qml_mocking
76 def test_can_launch_application(self):
63 def test_can_launch_application(self):
77 """Must be able to launch an application."""
64 """Must be able to launch an application."""
78− unity_proxy = self.launch_unity()
65+ application_name = self.launch_fake_app()
79− unlock_unity(unity_proxy)
66+ self.assert_current_focused_application(application_name)
80−
81− app = self._launch_app("messaging-app")
82
67
83− self.assertThat(app, NotEquals(None))
84− self.assertThat(
85− self.main_window.get_current_focused_app_id(),
86− Eventually(Equals("messaging-app"))
87− )
88−
89− @disable_qml_mocking
90 def test_can_launch_multiple_applications(self):
68 def test_can_launch_multiple_applications(self):
91 """A second application launched must be focused."""
69 """A second application launched must be focused."""
92− unity_proxy = self.launch_unity()
70+ application1_name = self.launch_fake_app()
93− unlock_unity(unity_proxy)
71+ self.assert_current_focused_application(application1_name)
94−
72+
95− self._launch_app("messaging-app")
73+ application2_name = self.launch_fake_app()
96− self.assertThat(
74+ self.assertFalse(application1_name == application2_name)
97− self.main_window.get_current_focused_app_id(),
75+ self.assert_current_focused_application(application2_name)
98− Eventually(Equals("messaging-app"))
76+
99− )
100−
101− self._launch_app("address-book-app")
102− self.assertThat(
103− self.main_window.get_current_focused_app_id(),
104− Eventually(Equals("address-book-app"))
105− )
106−
107− @disable_qml_mocking
108 def test_app_moves_from_unfocused_to_focused(self):
77 def test_app_moves_from_unfocused_to_focused(self):
109 """An application that is in the unfocused state must be able to be
78 """An application that is in the unfocused state must be able to be
110 brought back to the focused state.
79 brought back to the focused state.
111
80
112 """
81 """
113− unity_proxy = self.launch_unity()
82+ application1_name = self.launch_fake_app()
114− unlock_unity(unity_proxy)
83+ self.assert_current_focused_application(application1_name)
115−
116− self._launch_app("messaging-app")
117− self.assertThat(
118− self.main_window.get_current_focused_app_id(),
119− Eventually(Equals("messaging-app"))
120− )
121
84
122− self._launch_app("address-book-app")
85+ application2_name = self.launch_fake_app()
123− self.assertThat(
86+ self.assertFalse(application1_name == application2_name)
124− self.main_window.get_current_focused_app_id(),
87+ self.assert_current_focused_application(application2_name)
125− Eventually(Equals("address-book-app"))
126− )
127
88
128 self.swipe_screen_from_right()
89 self.swipe_screen_from_right()
129
90
130− self.assertThat(
91+ self.assert_current_focused_application(application1_name)
92+
93+ def test_greeter_hides_on_app_open(self):
94+ """Greeter should hide when an app is opened"""
95+ process_helpers.lock_unity()
131− self.main_window.get_current_focused_app_id(),
96+ greeter = self.main_window.get_greeter()
97+ self.assertThat(greeter.created, Eventually(Equals(True)))
98+
99+ application_name = self.launch_fake_app()
132− Eventually(Equals("messaging-app"))
100+ self.assertThat(greeter.created, Eventually(Equals(False)))
133− )
101+ self.assert_current_focused_application(application_name)
102+
103+ def test_greeter_hides_on_app_focus(self):
104+ """Greeter should hide when an app is re-focused"""
105+ application_name = self.launch_fake_app()
106+ self.assert_current_focused_application(application_name)
107+
108+ self.main_window.show_dash_swiping()
109+ self.assert_current_focused_application('')
110+
111+ process_helpers.lock_unity()
112+ greeter = self.main_window.get_greeter()
113+ self.assertThat(greeter.created, Eventually(Equals(True)))
114+
115+ self.launch_upstart_application(application_name)
116+ self.assertThat(greeter.created, Eventually(Equals(False)))
117+ self.assert_current_focused_application(application_name)
tests/autopilot/unity8/application_lifecycle/tests/test_url_dispatcher.py+8−39
@@ -20,48 +20,19 @@
20"""Test the integration with the URL dispatcher service."""
20"""Test the integration with the URL dispatcher service."""
21
21
22import os
22import os
23+import subprocess
23
24
24from autopilot import platform
25from autopilot import platform
25−from autopilot.matchers import Eventually
26−from testtools.matchers import Equals
27−from ubuntuuitoolkit import fixture_setup
28
26
29−from unity8 import process_helpers
27+from unity8.application_lifecycle import tests
30−from unity8.shell import tests
31
28
32
29
33−class URLDispatcherTestCase(tests.UnityTestCase):
30+class URLDispatcherTestCase(tests.ApplicationLifeCycleTestCase):
34−
35− scenarios = tests._get_device_emulation_scenarios()
36−
37− test_qml = ("""
38−import QtQuick 2.0
39−import Ubuntu.Components 0.1
40−
41−MainView {
42− width: units.gu(48)
43− height: units.gu(60)
44−
45− Label {
46− text: 'Test application.'
47− }
48−}
49−""")
50
31
51 def setUp(self):
32 def setUp(self):
52 if platform.model() == 'Desktop':
33 if platform.model() == 'Desktop':
53 self.skipTest("URL dispatcher doesn't work on the desktop.")
34 self.skipTest("URL dispatcher doesn't work on the desktop.")
54 super(URLDispatcherTestCase, self).setUp()
35 super(URLDispatcherTestCase, self).setUp()
55− self._qml_mock_enabled = False
56− self._data_dirs_mock_enabled = False
57− unity_proxy = self.launch_unity()
58− process_helpers.unlock_unity(unity_proxy)
59−
60− def create_test_application(self):
61− fake_application = fixture_setup.FakeApplication(self.test_qml)
62− self.useFixture(fake_application)
63− return (
64− fake_application.qml_file_path, fake_application.desktop_file_path)
65
36
66 def test_swipe_out_application_started_by_url_dispatcher(self):
37 def test_swipe_out_application_started_by_url_dispatcher(self):
67 _, desktop_file_path = self.create_test_application()
38 _, desktop_file_path = self.create_test_application()
@@ -70,12 +41,10 @@ MainView {
70
41
71 self.assertEqual('', self.main_window.get_current_focused_app_id())
42 self.assertEqual('', self.main_window.get_current_focused_app_id())
72 self.addCleanup(os.system, 'pkill qmlscene')
43 self.addCleanup(os.system, 'pkill qmlscene')
44+
45+ subprocess.check_call(
73− os.system('url-dispatcher application:///{}'.format(desktop_file_name))
46+ ['url-dispatcher', 'application:///{}'.format(desktop_file_name)])
74− self.assertThat(
47+ self.assert_current_focused_application(application_name)
75− self.main_window.get_current_focused_app_id,
76− Eventually(Equals(application_name)))
77
48
78 self.main_window.show_dash_swiping()
49 self.main_window.show_dash_swiping()
79− self.assertThat(
50+ self.assert_current_focused_application('')
80− self.main_window.get_current_focused_app_id,
81− Eventually(Equals('')))
tests/autopilot/unity8/process_helpers.py+16
@@ -89,6 +89,22 @@ def unlock_unity(unity_proxy_obj=None):
89 break
89 break
90
90
91
91
92+def lock_unity(unity_proxy_obj=None):
93+ """Helper function that attempts to lock the unity greeter."""
94+ import evdev, time
95+ uinput = evdev.UInput(name='unity8-autopilot-power-button',
96+ devnode='/dev/autopilot-uinput')
97+ # One press and release to turn screen off (locking unity)
98+ uinput.write(evdev.ecodes.EV_KEY, evdev.ecodes.KEY_POWER, 1)
99+ uinput.write(evdev.ecodes.EV_KEY, evdev.ecodes.KEY_POWER, 0)
100+ uinput.syn()
101+ time.sleep(1)
102+ # And another press and release to turn screen back on
103+ uinput.write(evdev.ecodes.EV_KEY, evdev.ecodes.KEY_POWER, 1)
104+ uinput.write(evdev.ecodes.EV_KEY, evdev.ecodes.KEY_POWER, 0)
105+ uinput.syn()
106+
107+
92def restart_unity_with_testability(*args):
108def restart_unity_with_testability(*args):
93 """Restarts (or starts) unity with testability enabled.
109 """Restarts (or starts) unity with testability enabled.
94
110
tests/autopilot/unity8/shell/__init__.py+50−1
@@ -21,8 +21,9 @@
21
21
22from time import sleep
22from time import sleep
23from functools import wraps
23from functools import wraps
24−import logging
24+from gi.repository import Notify
25
25
26+import logging
26
27
27logger = logging.getLogger(__name__)
28logger = logging.getLogger(__name__)
28
29
@@ -48,6 +49,7 @@ def disable_qml_mocking(fn):
48 return fn(*args, **kwargs)
49 return fn(*args, **kwargs)
49 return wrapper
50 return wrapper
50
51
52+
51class DragMixin(object):
53class DragMixin(object):
52 def _drag(self, x1, y1, x2, y2):
54 def _drag(self, x1, y1, x2, y2):
53 # XXX This ugly code is here just temporarily, waiting for drag
55 # XXX This ugly code is here just temporarily, waiting for drag
@@ -69,3 +71,50 @@ class DragMixin(object):
69 self.touch._finger_move(int(x2), int(y2))
71 self.touch._finger_move(int(x2), int(y2))
70 except AttributeError:
72 except AttributeError:
71 self.touch._device.finger_move(int(x2), int(y2))
73 self.touch._device.finger_move(int(x2), int(y2))
74+
75+
76+def create_ephemeral_notification(
77+ summary='',
78+ body='',
79+ icon=None,
80+ hints=[],
81+ urgency='NORMAL'
82+):
83+ """Create an ephemeral (non-interactive) notification
84+
85+ :param summary: Summary text for the notification
86+ :param body: Body text to display in the notification
87+ :param icon: Path string to the icon to use
88+ :param hint_strings: List of tuples containing the 'name' and value
89+ for setting the hint strings for the notification
90+ :param urgency: Urgency string for the noticiation, either: 'LOW',
91+ 'NORMAL', 'CRITICAL'
92+ """
93+ Notify.init('Unity8')
94+
95+ logger.info(
96+ "Creating ephemeral: summary(%s), body(%s), urgency(%r) "
97+ "and Icon(%s)",
98+ summary,
99+ body,
100+ urgency,
101+ icon
102+ )
103+
104+ notification = Notify.Notification.new(summary, body, icon)
105+
106+ for hint in hints:
107+ key, value = hint
108+ notification.set_hint_string(key, value)
109+ logger.info("Adding hint to notification: (%s, %s)", key, value)
110+ notification.set_urgency(_get_urgency(urgency))
111+
112+ return notification
113+
114+
115+def _get_urgency(urgency):
116+ """Translates urgency string to enum."""
117+ _urgency_enums = {'LOW': Notify.Urgency.LOW,
118+ 'NORMAL': Notify.Urgency.NORMAL,
119+ 'CRITICAL': Notify.Urgency.CRITICAL}
120+ return _urgency_enums.get(urgency.upper())
tests/autopilot/unity8/shell/emulators/dash.py+10−5
@@ -191,13 +191,18 @@ class DashApps(GenericScopeView):
191
191
192 """
192 """
193 category_element = self._get_category_element(category)
193 category_element = self._get_category_element(category)
194− application_tiles = category_element.select_many('Card')
194+ application_cards = category_element.select_many('Card')
195− # TODO return them on the same order they are displayed.
195+
196− # --elopio - 2014-1-15
196+ # sort by y, x
197+ application_cards = sorted(
198+ application_cards,
199+ key=lambda card: (card.globalRect.y, card.globalRect.x))
200+
197 result = []
201 result = []
198− for card in application_tiles:
202+ for card in application_cards:
199 if card.objectName != 'cardToolCard':
203 if card.objectName != 'cardToolCard':
204+ card_header = card.select_single('CardHeader')
200− result.append(card)
205+ result.append(card_header.title)
201 return result
206 return result
202
207
203
208
tests/autopilot/unity8/shell/tests/test_emulators.py+4−12
@@ -166,7 +166,7 @@ class DashAppsEmulatorTestCase(DashBaseTestCase):
166 available_applications = [
166 available_applications = [
167 'Title.2.0', 'Title.2.1', 'Title.2.2', 'Title.2.3', 'Title.2.4',
167 'Title.2.0', 'Title.2.1', 'Title.2.2', 'Title.2.3', 'Title.2.4',
168 'Title.2.5', 'Title.2.6', 'Title.2.7', 'Title.2.8', 'Title.2.9',
168 'Title.2.5', 'Title.2.6', 'Title.2.7', 'Title.2.8', 'Title.2.9',
169− 'Title.2.9', 'Title.2.10', 'Title.2.11']
169+ 'Title.2.10', 'Title.2.11', 'Title.2.12']
170
170
171 def setUp(self):
171 def setUp(self):
172 # Set up the fake scopes before launching unity.
172 # Set up the fake scopes before launching unity.
@@ -183,28 +183,20 @@ class DashAppsEmulatorTestCase(DashBaseTestCase):
183 self.assertEqual(
183 self.assertEqual(
184 'No category found with name unexisting category', str(exception))
184 'No category found with name unexisting category', str(exception))
185
185
186− def test_get_applications_should_return_list_with_names(self):
186+ def test_get_applications_should_return_correct_applications(self):
187 category = '2'
187 category = '2'
188 expected_apps_count = self._get_number_of_application_slots(category)
188 expected_apps_count = self._get_number_of_application_slots(category)
189 expected_applications = self.available_applications[
189 expected_applications = self.available_applications[
190 :expected_apps_count]
190 :expected_apps_count]
191−
192 applications = self.applications_scope.get_applications(category)
191 applications = self.applications_scope.get_applications(category)
193− applications_titles = []
194− for application in applications:
195− cardHeader = application.select_single('CardHeader')
196− applications_titles.append(cardHeader.title)
197−
198− self.assertThat(applications, HasLength(expected_apps_count))
199− for expected in expected_applications:
192+ self.assertEqual(expected_applications, applications)
200− self.assertThat(applications_titles, Contains(expected))
201
193
202 def _get_number_of_application_slots(self, category):
194 def _get_number_of_application_slots(self, category):
203 category_element = self.applications_scope._get_category_element(
195 category_element = self.applications_scope._get_category_element(
204 category)
196 category)
205 grid = category_element.select_single('CardFilterGrid')
197 grid = category_element.select_single('CardFilterGrid')
206 filtergrid = grid.select_single('FilterGrid')
198 filtergrid = grid.select_single('FilterGrid')
207− if (grid.filter):
199+ if (grid.filtered):
208 return filtergrid.collapsedRowCount * filtergrid.columns
200 return filtergrid.collapsedRowCount * filtergrid.columns
209 else:
201 else:
210 return filtergrid.uncollapsedRowCount * filtergrid.columns
202 return filtergrid.uncollapsedRowCount * filtergrid.columns
tests/autopilot/unity8/shell/tests/test_notifications.py+17−61
@@ -21,6 +21,7 @@
21
21
22from __future__ import absolute_import
22from __future__ import absolute_import
23
23
24+from unity8 import shell
24from unity8.process_helpers import unlock_unity
25from unity8.process_helpers import unlock_unity
25from unity8.shell.tests import UnityTestCase, _get_device_emulation_scenarios
26from unity8.shell.tests import UnityTestCase, _get_device_emulation_scenarios
26
27
@@ -64,7 +65,8 @@ class NotificationsBase(UnityTestCase):
64 if os.path.abspath(__file__).startswith('/usr/'):
65 if os.path.abspath(__file__).startswith('/usr/'):
65 return '/usr/share/unity8/graphics/' + icon_name
66 return '/usr/share/unity8/graphics/' + icon_name
66 else:
67 else:
67− return os.path.dirname(__file__) + "/../../../../../qml/graphics/" + icon_name
68+ return os.path.dirname(__file__) + (
69+ "/../../../../../qml/graphics/" + icon_name)
68
70
69 def _get_notifications_list(self):
71 def _get_notifications_list(self):
70 return self.main_window.select_single(
72 return self.main_window.select_single(
@@ -196,7 +198,7 @@ class InteractiveNotificationBase(NotificationsBase):
196 get_notification = lambda: notify_list.wait_select_single(
198 get_notification = lambda: notify_list.wait_select_single(
197 'Notification', objectName='notification1')
199 'Notification', objectName='notification1')
198 notification = get_notification()
200 notification = get_notification()
199− self._assert_notification(notification, None, None, True, True, 1.0)
201+ self._assert_notification(notification, summary, body, True, True, 1.0)
200 initial_height = notification.height
202 initial_height = notification.height
201 self.touch.tap_object(notification.select_single(objectName="button1"))
203 self.touch.tap_object(notification.select_single(objectName="button1"))
202 self.assertThat(
204 self.assertThat(
@@ -354,7 +356,7 @@ class EphemeralNotificationsTests(NotificationsBase):
354 )
356 )
355 ]
357 ]
356
358
357− notification = self._create_ephemeral_notification(
359+ notification = shell.create_ephemeral_notification(
358 summary,
360 summary,
359 body,
361 body,
360 icon_path,
362 icon_path,
@@ -391,7 +393,7 @@ class EphemeralNotificationsTests(NotificationsBase):
391 )
393 )
392 ]
394 ]
393
395
394− notification = self._create_ephemeral_notification(
396+ notification = shell.create_ephemeral_notification(
395 summary,
397 summary,
396 None,
398 None,
397 None,
399 None,
@@ -403,7 +405,6 @@ class EphemeralNotificationsTests(NotificationsBase):
403
405
404 notification = lambda: notify_list.wait_select_single(
406 notification = lambda: notify_list.wait_select_single(
405 'Notification', objectName='notification1')
407 'Notification', objectName='notification1')
406−
407 self._assert_notification(
408 self._assert_notification(
408 notification(),
409 notification(),
409 summary,
410 summary,
@@ -434,7 +435,7 @@ class EphemeralNotificationsTests(NotificationsBase):
434 body_critical = 'Dude, this is so urgent you have no idea :)'
435 body_critical = 'Dude, this is so urgent you have no idea :)'
435 icon_path_critical = self._get_icon_path('avatars/anna_olsson.png')
436 icon_path_critical = self._get_icon_path('avatars/anna_olsson.png')
436
437
437− notification_normal = self._create_ephemeral_notification(
438+ notification_normal = shell.create_ephemeral_notification(
438 summary_normal,
439 summary_normal,
439 body_normal,
440 body_normal,
440 icon_path_normal,
441 icon_path_normal,
@@ -442,7 +443,7 @@ class EphemeralNotificationsTests(NotificationsBase):
442 )
443 )
443 notification_normal.show()
444 notification_normal.show()
444
445
445− notification_low = self._create_ephemeral_notification(
446+ notification_low = shell.create_ephemeral_notification(
446 summary_low,
447 summary_low,
447 body_low,
448 body_low,
448 icon_path_low,
449 icon_path_low,
@@ -450,7 +451,7 @@ class EphemeralNotificationsTests(NotificationsBase):
450 )
451 )
451 notification_low.show()
452 notification_low.show()
452
453
453− notification_critical = self._create_ephemeral_notification(
454+ notification_critical = shell.create_ephemeral_notification(
454 summary_critical,
455 summary_critical,
455 body_critical,
456 body_critical,
456 icon_path_critical,
457 icon_path_critical,
@@ -511,7 +512,7 @@ class EphemeralNotificationsTests(NotificationsBase):
511 summary = 'Summary-Body'
512 summary = 'Summary-Body'
512 body = 'This is a superfluous notification'
513 body = 'This is a superfluous notification'
513
514
514− notification = self._create_ephemeral_notification(summary, body)
515+ notification = shell.create_ephemeral_notification(summary, body)
515 notification.show()
516 notification.show()
516
517
517 notification = notify_list.wait_select_single(
518 notification = notify_list.wait_select_single(
@@ -535,7 +536,7 @@ class EphemeralNotificationsTests(NotificationsBase):
535
536
536 summary = 'Summary-Only'
537 summary = 'Summary-Only'
537
538
538− notification = self._create_ephemeral_notification(summary)
539+ notification = shell.create_ephemeral_notification(summary)
539 notification.show()
540 notification.show()
540
541
541 notification = notify_list.wait_select_single(
542 notification = notify_list.wait_select_single(
@@ -555,7 +556,7 @@ class EphemeralNotificationsTests(NotificationsBase):
555 body = 'This is the original content of this notification-bubble.'
556 body = 'This is the original content of this notification-bubble.'
556 icon_path = self._get_icon_path('avatars/funky.png')
557 icon_path = self._get_icon_path('avatars/funky.png')
557
558
558− notification = self._create_ephemeral_notification(
559+ notification = shell.create_ephemeral_notification(
559 summary,
560 summary,
560 body,
561 body,
561 icon_path
562 icon_path
@@ -579,7 +580,7 @@ class EphemeralNotificationsTests(NotificationsBase):
579 icon_path = self._get_icon_path('avatars/amanda.png')
580 icon_path = self._get_icon_path('avatars/amanda.png')
580 notification.update(summary, body, icon_path)
581 notification.update(summary, body, icon_path)
581 notification.show()
582 notification.show()
582− self._assert_notification(get_notification(), summary, body)
583+ self._assert_notification(get_notification(), summary, body, True, False, 1.0)
583
584
584 def test_update_notification_layout_change(self):
585 def test_update_notification_layout_change(self):
585 """Notification must allow updating its contents and layout while
586 """Notification must allow updating its contents and layout while
@@ -595,7 +596,7 @@ class EphemeralNotificationsTests(NotificationsBase):
595 icon_path = self._get_icon_path('avatars/anna_olsson.png')
596 icon_path = self._get_icon_path('avatars/anna_olsson.png')
596 hint_icon = self._get_icon_path('applicationIcons/phone-app.png')
597 hint_icon = self._get_icon_path('applicationIcons/phone-app.png')
597
598
598− notification = self._create_ephemeral_notification(
599+ notification = shell.create_ephemeral_notification(
599 summary,
600 summary,
600 body,
601 body,
601 icon_path
602 icon_path
@@ -626,7 +627,7 @@ class EphemeralNotificationsTests(NotificationsBase):
626 notification.show()
627 notification.show()
627
628
628 self.assertThat(get_notification, Eventually(NotEquals(None)))
629 self.assertThat(get_notification, Eventually(NotEquals(None)))
629− self._assert_notification(get_notification(), summary, body, False)
630+ self._assert_notification(get_notification(), summary, body, False, False, 1.0)
630
631
631 def test_append_hint(self):
632 def test_append_hint(self):
632 """Notification has to accumulate body-text using append-hint."""
633 """Notification has to accumulate body-text using append-hint."""
@@ -639,7 +640,7 @@ class EphemeralNotificationsTests(NotificationsBase):
639 body = 'Hey Bro Coly!'
640 body = 'Hey Bro Coly!'
640 icon_path = self._get_icon_path('avatars/amanda.png')
641 icon_path = self._get_icon_path('avatars/amanda.png')
641 body_sum = body
642 body_sum = body
642− notification = self._create_ephemeral_notification(
643+ notification = shell.create_ephemeral_notification(
643 summary,
644 summary,
644 body,
645 body,
645 icon_path,
646 icon_path,
@@ -675,7 +676,7 @@ class EphemeralNotificationsTests(NotificationsBase):
675 for new_body in bodies:
676 for new_body in bodies:
676 body = new_body
677 body = new_body
677 body_sum += '\n' + body
678 body_sum += '\n' + body
678− notification = self._create_ephemeral_notification(
679+ notification = shell.create_ephemeral_notification(
679 summary,
680 summary,
680 body,
681 body,
681 icon_path,
682 icon_path,
@@ -696,48 +697,3 @@ class EphemeralNotificationsTests(NotificationsBase):
696 False,
697 False,
697 1.0
698 1.0
698 )
699 )
699−
700− def _create_ephemeral_notification(
701− self,
702− summary="",
703− body="",
704− icon=None,
705− hints=[],
706− urgency="NORMAL"
707− ):
708− """Create an ephemeral (non-interactive) notification
709−
710− :param summary: Summary text for the notification
711− :param body: Body text to display in the notification
712− :param icon: Path string to the icon to use
713− :param hint_strings: List of tuples containing the 'name' and value
714− for setting the hint strings for the notification
715− :param urgency: Urgency string for the noticiation, either: 'LOW',
716− 'NORMAL', 'CRITICAL'
717−
718− """
719− logger.info(
720− "Creating ephemeral: summary(%s), body(%s), urgency(%r) "
721− "and Icon(%s)",
722− summary,
723− body,
724− urgency,
725− icon
726− )
727−
728− n = Notify.Notification.new(summary, body, icon)
729−
730− for hint in hints:
731− key, value = hint
732− n.set_hint_string(key, value)
733− logger.info("Adding hint to notification: (%s, %s)", key, value)
734− n.set_urgency(self._get_urgency(urgency))
735−
736− return n
737−
738− def _get_urgency(self, urgency):
739− """Translates urgency string to enum."""
740− _urgency_enums = {'LOW': Notify.Urgency.LOW,
741− 'NORMAL': Notify.Urgency.NORMAL,
742− 'CRITICAL': Notify.Urgency.CRITICAL}
743− return _urgency_enums.get(urgency.upper())
tests/autopilot/unity8/shell/tests/test_upstart.py+2−2
@@ -82,7 +82,7 @@ class UpstartIntegrationTests(UnityTestCase):
82 ))
82 ))
83
83
84 def test_no_sigstop(self):
84 def test_no_sigstop(self):
85− self.patch_environment("UPSTART_JOB", "foo")
85+ self.patch_environment("UNITY_MIR_EMITS_SIGSTOP", "")
86 self._launch_unity()
86 self._launch_unity()
87 self._set_proxy()
87 self._set_proxy()
88
88
@@ -91,7 +91,7 @@ class UpstartIntegrationTests(UnityTestCase):
91 logger.debug("Unity loaded and ready.")
91 logger.debug("Unity loaded and ready.")
92
92
93 def test_expect_sigstop(self):
93 def test_expect_sigstop(self):
94− self.patch_environment("UPSTART_JOB", "unity8")
94+ self.patch_environment("UNITY_MIR_EMITS_SIGSTOP", "1")
95 self._launch_unity()
95 self._launch_unity()
96 self.assertThat(lambda: os.WIFSTOPPED(self._get_status()), Eventually(Equals(True)), "Unity8 should raise SIGSTOP when ready")
96 self.assertThat(lambda: os.WIFSTOPPED(self._get_status()), Eventually(Equals(True)), "Unity8 should raise SIGSTOP when ready")
97
97
tests/plugins/DashViews/CMakeLists.txt+23−35
@@ -25,46 +25,41 @@ remove_definitions(-DQT_NO_KEYWORDS)
25add_definitions(-DDASHVIEWSTEST_FOLDER="${CMAKE_CURRENT_SOURCE_DIR}")
25add_definitions(-DDASHVIEWSTEST_FOLDER="${CMAKE_CURRENT_SOURCE_DIR}")
26add_definitions(-DBUILT_PLUGINS_DIR="${CMAKE_BINARY_DIR}/plugins")
26add_definitions(-DBUILT_PLUGINS_DIR="${CMAKE_BINARY_DIR}/plugins")
27
27
28+macro(add_lvwph_test FILENAME TESTNAME)
29+ add_executable(${TESTNAME}TestExec
30+ ${FILENAME}test.cpp
28−add_executable(listviewwithpageheadertestExec listviewwithpageheadertest.cpp ${CMAKE_CURRENT_SOURCE_DIR}/../../../plugins/DashViews/listviewwithpageheader.cpp)
31+ ${CMAKE_CURRENT_SOURCE_DIR}/../../../plugins/DashViews/listviewwithpageheader.cpp)
29−qt5_use_modules(listviewwithpageheadertestExec Test Core Qml)
32+ qt5_use_modules(${TESTNAME}TestExec Test Core Qml)
30−target_link_libraries(listviewwithpageheadertestExec ${Qt5Gui_LIBRARIES} ${Qt5Quick_LIBRARIES})
33+ target_link_libraries(${TESTNAME}TestExec ${Qt5Gui_LIBRARIES} ${Qt5Quick_LIBRARIES})
31−add_custom_target(testlistviewwithpageheader ${CMAKE_CURRENT_BINARY_DIR}/listviewwithpageheadertestExec -o ${CMAKE_BINARY_DIR}/testlistviewwithpageheader.xml,xunitxml -o -,txt)
32
34
33−add_executable(listviewwithpageheadertestsectionExec listviewwithpageheadertestsection.cpp ${CMAKE_CURRENT_SOURCE_DIR}/../../../plugins/DashViews/listviewwithpageheader.cpp)
35+ add_binary_qml_test(${TESTNAME} "" "DashViews-qml")
34−qt5_use_modules(listviewwithpageheadertestsectionExec Test Core Qml)
36+endmacro()
35−target_link_libraries(listviewwithpageheadertestsectionExec ${Qt5Gui_LIBRARIES} ${Qt5Quick_LIBRARIES})
36−add_custom_target(testlistviewwithpageheadersection ${CMAKE_CURRENT_BINARY_DIR}/listviewwithpageheadertestsectionExec -o ${CMAKE_BINARY_DIR}/testlistviewwithpageheadersection.xml,xunitxml -o -,txt)
37
37
38−add_executable(listviewwithpageheadertestsectionexternalmodelExec listviewwithpageheadertestsectionexternalmodel.cpp ${CMAKE_CURRENT_SOURCE_DIR}/../../../plugins/DashViews/listviewwithpageheader.cpp)
38+add_lvwph_test(listviewwithpageheader ListViewWithPageHeader)
39−qt5_use_modules(listviewwithpageheadertestsectionexternalmodelExec Test Core Qml)
39+add_lvwph_test(listviewwithpageheadersection ListViewWithPageHeaderSection)
40−target_link_libraries(listviewwithpageheadertestsectionexternalmodelExec ${Qt5Gui_LIBRARIES} ${Qt5Quick_LIBRARIES})
40+add_lvwph_test(listviewwithpageheadersectionexternalmodel ListViewWithPageHeaderSectionExternalModel)
41−add_custom_target(testlistviewwithpageheadersectionexternalmodel ${CMAKE_CURRENT_BINARY_DIR}/listviewwithpageheadertestsectionexternalmodelExec -o ${CMAKE_BINARY_DIR}/testlistviewwithpageheadersectionexternalmodel.xml,xunitxml -o -,txt)
42
41
43macro(add_dashview_try_test FILENAME TESTNAME)
42macro(add_dashview_try_test FILENAME TESTNAME)
44− add_executable(${FILENAME}testExec
43+ add_executable(${TESTNAME}TestExec
45 ${FILENAME}test.cpp
44 ${FILENAME}test.cpp
46 ${CMAKE_CURRENT_SOURCE_DIR}/../../../plugins/DashViews/${FILENAME}.cpp
45 ${CMAKE_CURRENT_SOURCE_DIR}/../../../plugins/DashViews/${FILENAME}.cpp
47 ${CMAKE_CURRENT_SOURCE_DIR}/../../../plugins/DashViews/abstractdashview.cpp
46 ${CMAKE_CURRENT_SOURCE_DIR}/../../../plugins/DashViews/abstractdashview.cpp
48 )
47 )
49− qt5_use_modules(${FILENAME}testExec Test Core Qml)
48+ qt5_use_modules(${TESTNAME}TestExec Test Core Qml)
50− target_link_libraries(${FILENAME}testExec ${Qt5Gui_LIBRARIES} ${Qt5Quick_LIBRARIES})
49+ target_link_libraries(${TESTNAME}TestExec ${Qt5Gui_LIBRARIES} ${Qt5Quick_LIBRARIES})
51− add_custom_target(test${TESTNAME}
52− ${CMAKE_CURRENT_BINARY_DIR}/${FILENAME}testExec
53− -o ${CMAKE_BINARY_DIR}/test${TESTNAME}.xml,xunitxml
54− -o -,txt
55− DEPENDS ${FILENAME}testExec DashViews-qml
56− )
57
50
51+ add_binary_qml_test(${TESTNAME} "" "DashViews-qml")
52+
58− add_executable(${FILENAME}tryExec
53+ add_executable(${TESTNAME}tryExec
59 ${FILENAME}try.cpp
54 ${FILENAME}try.cpp
60 ${CMAKE_CURRENT_SOURCE_DIR}/../../../plugins/DashViews/${FILENAME}.cpp
55 ${CMAKE_CURRENT_SOURCE_DIR}/../../../plugins/DashViews/${FILENAME}.cpp
61 ${CMAKE_CURRENT_SOURCE_DIR}/../../../plugins/DashViews/abstractdashview.cpp
56 ${CMAKE_CURRENT_SOURCE_DIR}/../../../plugins/DashViews/abstractdashview.cpp
62 )
57 )
63− qt5_use_modules(${FILENAME}tryExec Test Core Qml)
58+ qt5_use_modules(${TESTNAME}tryExec Test Core Qml)
64− target_link_libraries(${FILENAME}tryExec ${Qt5Gui_LIBRARIES} ${Qt5Quick_LIBRARIES})
59+ target_link_libraries(${TESTNAME}tryExec ${Qt5Gui_LIBRARIES} ${Qt5Quick_LIBRARIES})
65 add_custom_target(try${TESTNAME}
60 add_custom_target(try${TESTNAME}
66− ${CMAKE_CURRENT_BINARY_DIR}/${FILENAME}tryExec
61+ ${CMAKE_CURRENT_BINARY_DIR}/${TESTNAME}tryExec
67− DEPENDS ${FILENAME}tryExec DashViews-qml
62+ DEPENDS ${TESTNAME}tryExec DashViews-qml
68 )
63 )
69endmacro()
64endmacro()
70
65
@@ -72,13 +67,6 @@ add_dashview_try_test(verticaljournal VerticalJournal)
72add_dashview_try_test(horizontaljournal HorizontalJournal)
67add_dashview_try_test(horizontaljournal HorizontalJournal)
73add_dashview_try_test(organicgrid OrganicGrid)
68add_dashview_try_test(organicgrid OrganicGrid)
74
69
70+set(qmltest_DEFAULT_TARGETS qmluitests)
75set(qmltest_DEFAULT_NO_ADD_TEST TRUE)
71set(qmltest_DEFAULT_NO_ADD_TEST TRUE)
76−add_qml_test(. listviewwithpageheaderqml IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins)
72+add_qml_test(. ListViewWithPageHeaderQML IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins)
77−
78−add_dependencies(qmluitests testlistviewwithpageheader)
79−add_dependencies(qmluitests testlistviewwithpageheadersection)
80−add_dependencies(qmluitests testlistviewwithpageheadersectionexternalmodel)
81−add_dependencies(qmluitests testlistviewwithpageheaderqml)
82−add_dependencies(qmluitests testVerticalJournal)
83−add_dependencies(qmluitests testHorizontalJournal)
84−add_dependencies(qmluitests testOrganicGrid)
tests/plugins/DashViews/listviewwithpageheadertestsectionexternalmodel.cpp → tests/plugins/DashViews/listviewwithpageheadersectionexternalmodeltest.cpprenamed+1−1
@@ -248,4 +248,4 @@ private:
248
248
249QTEST_MAIN(ListViewWithPageHeaderTestSection)
249QTEST_MAIN(ListViewWithPageHeaderTestSection)
250
250
251−#include "listviewwithpageheadertestsectionexternalmodel.moc"
251+#include "listviewwithpageheadersectionexternalmodeltest.moc"
tests/plugins/DashViews/listviewwithpageheadertestsection.cpp → tests/plugins/DashViews/listviewwithpageheadersectiontest.cpprenamed+1−1
@@ -2166,4 +2166,4 @@ private:
2166
2166
2167QTEST_MAIN(ListViewWithPageHeaderTestSection)
2167QTEST_MAIN(ListViewWithPageHeaderTestSection)
2168
2168
2169−#include "listviewwithpageheadertestsection.moc"
2169+#include "listviewwithpageheadersectiontest.moc"
tests/plugins/DashViews/tst_listviewwithpageheaderqml.qml → tests/plugins/DashViews/tst_ListViewWithPageHeaderQML.qmlrenamed

The content is the same.

tests/plugins/Ubuntu/Gestures/CMakeLists.txt+1
@@ -20,6 +20,7 @@ macro(add_gesture_ui_test CLASSNAME)
20 target_link_libraries(${CLASSNAME}TestExec UbuntuGestureQml)
20 target_link_libraries(${CLASSNAME}TestExec UbuntuGestureQml)
21
21
22 add_binary_qml_test(${CLASSNAME} ${CMAKE_BINARY_DIR}/plugins/Ubuntu/Gestures UbuntuGesturesTestQmlFiles)
22 add_binary_qml_test(${CLASSNAME} ${CMAKE_BINARY_DIR}/plugins/Ubuntu/Gestures UbuntuGesturesTestQmlFiles)
23+ add_manual_qml_test(. ${CLASSNAME} IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins)
23endmacro(add_gesture_ui_test)
24endmacro(add_gesture_ui_test)
24
25
25macro(add_gesture_test CLASSNAME)
26macro(add_gesture_test CLASSNAME)
tests/plugins/Utils/CMakeLists.txt+2−1
@@ -11,7 +11,8 @@ macro(run_tests)
11 -o ${CMAKE_BINARY_DIR}/${_test}.xml,xunitxml
11 -o ${CMAKE_BINARY_DIR}/${_test}.xml,xunitxml
12 -o -,txt)
12 -o -,txt)
13 add_test(NAME ${_test} COMMAND ${testCommand})
13 add_test(NAME ${_test} COMMAND ${testCommand})
14+ set_tests_properties(${_test} PROPERTIES ENVIRONMENT "LC_ALL=C")
14− add_custom_target(${_test} ${testCommand})
15+ add_custom_target(${_test} env "LC_ALL=C" ${testCommand})
15 add_executable(${_test}Exec ${_test}.cpp modeltest.cpp)
16 add_executable(${_test}Exec ${_test}.cpp modeltest.cpp)
16 qt5_use_modules(${_test}Exec Test Core Qml)
17 qt5_use_modules(${_test}Exec Test Core Qml)
17 target_link_libraries(${_test}Exec
18 target_link_libraries(${_test}Exec
tests/qmltests/CMakeLists.txt+2−2
@@ -11,13 +11,12 @@ set(qmltest_DEFAULT_IMPORT_PATHS
11set(qmltest_DEFAULT_TARGETS qmlunittests)
11set(qmltest_DEFAULT_TARGETS qmlunittests)
12set(qmltest_DEFAULT_NO_ADD_TEST FALSE)
12set(qmltest_DEFAULT_NO_ADD_TEST FALSE)
13set(qmltest_DEFAULT_PROPERTIES ENVIRONMENT "QT_QPA_PLATFORM=minimal")
13set(qmltest_DEFAULT_PROPERTIES ENVIRONMENT "QT_QPA_PLATFORM=minimal")
14−add_qml_test(Components AnimationControllerWithSignals)
15add_qml_test(Panel IndicatorItem)
14add_qml_test(Panel IndicatorItem)
16add_qml_test(utils/Unity/Test UnityTest)
15add_qml_test(utils/Unity/Test UnityTest)
17
16
18set(qmltest_DEFAULT_TARGETS qmluitests)
17set(qmltest_DEFAULT_TARGETS qmluitests)
19set(qmltest_DEFAULT_NO_ADD_TEST TRUE)
18set(qmltest_DEFAULT_NO_ADD_TEST TRUE)
20−set(qmltest_DEFAULT_PROPERTIES "")
19+set(qmltest_DEFAULT_PROPERTIES ENVIRONMENT "LC_ALL=C")
21
20
22add_qml_test(. Shell IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins ${qmltest_DEFAULT_IMPORT_PATHS} ${CMAKE_BINARY_DIR}/tests/mocks
21add_qml_test(. Shell IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins ${qmltest_DEFAULT_IMPORT_PATHS} ${CMAKE_BINARY_DIR}/tests/mocks
23 ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/LightDM/single")
22 ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/LightDM/single")
@@ -36,6 +35,7 @@ add_qml_test(Components PageHeaderLabel)
36add_qml_test(Dash Dash IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins ${qmltest_DEFAULT_IMPORT_PATHS})
35add_qml_test(Dash Dash IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins ${qmltest_DEFAULT_IMPORT_PATHS})
37add_qml_test(Dash DashContent IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins ${qmltest_DEFAULT_IMPORT_PATHS})
36add_qml_test(Dash DashContent IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins ${qmltest_DEFAULT_IMPORT_PATHS})
38add_qml_test(Dash Card)
37add_qml_test(Dash Card)
38+add_qml_benchmark(Dash CardBenchmark 1000)
39add_qml_test(Dash CardHeader)
39add_qml_test(Dash CardHeader)
40add_qml_test(Dash CardTool)
40add_qml_test(Dash CardTool)
41add_qml_test(Dash GenericScopeView IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins ${qmltest_DEFAULT_IMPORT_PATHS})
41add_qml_test(Dash GenericScopeView IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins ${qmltest_DEFAULT_IMPORT_PATHS})
tests/qmltests/Components/CMakeLists.txt+1
@@ -11,6 +11,7 @@ qt5_use_modules(DragHandleTestExec Test Core Qml Gui Quick)
11target_link_libraries(DragHandleTestExec UbuntuGestureQml)
11target_link_libraries(DragHandleTestExec UbuntuGestureQml)
12
12
13add_binary_qml_test(DragHandle ${CMAKE_BINARY_DIR}/plugins/Ubuntu/Gestures "")
13add_binary_qml_test(DragHandle ${CMAKE_BINARY_DIR}/plugins/Ubuntu/Gestures "")
14+add_manual_qml_test(. DragHandle IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins)
14
15
15add_definitions(-DUBUNTU_GESTURES_PLUGIN_DIR="${CMAKE_BINARY_DIR}/plugins")
16add_definitions(-DUBUNTU_GESTURES_PLUGIN_DIR="${CMAKE_BINARY_DIR}/plugins")
16add_definitions(-DTEST_DIR="${CMAKE_CURRENT_LIST_DIR}")
17add_definitions(-DTEST_DIR="${CMAKE_CURRENT_LIST_DIR}")
tests/qmltests/Components/tst_AnimationControllerWithSignals.qmldeleted−142
@@ -1,142 +0,0 @@
1−/*
2− * Copyright 2013 Canonical Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− */
16−
17−import QtQuick 2.0
18−import QtTest 1.0
19−import "../../../qml/Components"
20−
21−TestCase {
22− id: testCase
23− name: "AnimationControllerWithSignals"
24−
25− property real someNumber: 0.0
26−
27− NumberAnimation {
28− id: someNumberAnimation
29− target: testCase
30− properties: "someNumber"
31− from: 1.0
32− to: 100.0
33− }
34−
35− Component {
36− id: testSubjectComponent
37− AnimationControllerWithSignals {}
38− }
39−
40− Loader {
41− id: loader
42− asynchronous: false
43− }
44−
45− SignalSpy {
46− id: signalSpy
47− }
48−
49− function test_completeToEndWithSignal() {
50− loader.sourceComponent = testSubjectComponent;
51− var testSubject = loader.item;
52−
53− testSubject.animation = someNumberAnimation;
54− testSubject.progress = 0;
55−
56− signalSpy.signalName = "animationCompletedAtEnd";
57− signalSpy.target = testSubject;
58− signalSpy.clear();
59−
60− compare(testSubject.completing, false)
61− compare(testSubject.completed, true)
62−
63− testSubject.completeToEndWithSignal();
64− compare(testSubject.completing, true)
65− compare(testSubject.completed, true)
66− compare(signalSpy.count, 0);
67−
68− testSubject.progress = 0.5;
69− compare(testSubject.completing, true)
70− compare(testSubject.completed, false)
71− compare(signalSpy.count, 0);
72−
73− testSubject.progress = 1.0;
74− compare(testSubject.completing, false)
75− compare(testSubject.completed, true)
76− compare(signalSpy.count, 1);
77−
78− testSubject.animation = null
79− loader.sourceComponent = undefined;
80− }
81−
82− function test_completeToBeginningWithSignal() {
83− loader.sourceComponent = testSubjectComponent;
84− var testSubject = loader.item;
85−
86− testSubject.animation = someNumberAnimation;
87− testSubject.progress = 1;
88−
89− signalSpy.signalName = "animationCompletedAtBeginning";
90− signalSpy.target = testSubject;
91− signalSpy.clear();
92−
93− compare(testSubject.completing, false)
94− compare(testSubject.completed, true)
95−
96− testSubject.completeToBeginningWithSignal();
97− compare(testSubject.completing, true)
98− compare(testSubject.completed, true)
99− compare(signalSpy.count, 0);
100−
101− testSubject.progress = 0.5;
102− compare(testSubject.completing, true)
103− compare(testSubject.completed, false)
104− compare(signalSpy.count, 0);
105−
106− testSubject.progress = 0;
107− compare(testSubject.completing, false)
108− compare(testSubject.completed, true)
109− compare(signalSpy.count, 1);
110−
111− testSubject.animation = null
112− loader.sourceComponent = undefined;
113− }
114−
115− function test_settingProgressWithoutCallingCompleteWithSignal() {
116− loader.sourceComponent = testSubjectComponent;
117− var testSubject = loader.item;
118−
119− testSubject.animation = someNumberAnimation;
120− testSubject.progress = 0;
121−
122− signalSpy.signalName = "animationCompletedAtEnd";
123− signalSpy.target = testSubject;
124− signalSpy.clear();
125−
126− compare(testSubject.completing, false)
127− compare(testSubject.completed, true)
128−
129− testSubject.progress = 0.5;
130− compare(testSubject.completing, false)
131− compare(testSubject.completed, false)
132− compare(signalSpy.count, 0);
133−
134− testSubject.progress = 1;
135− compare(testSubject.completing, false)
136− compare(testSubject.completed, true)
137− compare(signalSpy.count, 0);
138−
139− testSubject.animation = null
140− loader.sourceComponent = undefined;
141− }
142−}
tests/qmltests/Components/tst_Carousel.qml+34−7
@@ -18,6 +18,7 @@ import QtQuick 2.0
18import QtTest 1.0
18import QtTest 1.0
19import "../../../qml/Components/"
19import "../../../qml/Components/"
20import "../../../qml/Components/carousel.js" as Carousel
20import "../../../qml/Components/carousel.js" as Carousel
21+import Unity.Test 0.1 as UT
21
22
22Item {
23Item {
23 width: 700
24 width: 700
@@ -31,13 +32,17 @@ Item {
31 property int createdDelegates: 0
32 property int createdDelegates: 0
32 property int destroyedDelegates: 0
33 property int destroyedDelegates: 0
33
34
35+ itemComponent: BaseCarouselDelegate {
34− itemComponent: Rectangle {
36+ Rectangle {
37+ anchors.fill: parent
38+ border.color: "black"
35− color: "red"
39+ color: "red"
36− Component.onCompleted: carousel.createdDelegates++
40+ Component.onCompleted: carousel.createdDelegates++
37− Component.onDestruction: carousel.destroyedDelegates++
41+ Component.onDestruction: carousel.destroyedDelegates++
42+ }
38 }
43 }
39 }
44 }
40− TestCase {
45+ UT.UnityTestCase {
41 id: root
46 id: root
42 name: "Carousel"
47 name: "Carousel"
43 when: windowShown
48 when: windowShown
@@ -55,8 +60,11 @@ Item {
55 property real kGapEnd: kMiddleIndex * (1 - gapToEndPhase / gapToMiddlePhase)
60 property real kGapEnd: kMiddleIndex * (1 - gapToEndPhase / gapToMiddlePhase)
56 property real kXBeginningEnd: 1 / tileWidth + kMiddleIndex / gapToMiddlePhase
61 property real kXBeginningEnd: 1 / tileWidth + kMiddleIndex / gapToMiddlePhase
57
62
58− function test_onlyNeededItemsCreated() {
63+ // This test needs to run first since it tests a corner case condition
64+ // to where the carousel is just being created
65+ // That is why it has a 1 in the name
66+ function test_1onlyNeededItemsCreated() {
59− compare(carousel.createdDelegates, 10);
67+ tryCompare(carousel, "createdDelegates", 10);
60 compare(carousel.destroyedDelegates, 0);
68 compare(carousel.destroyedDelegates, 0);
61 }
69 }
62
70
@@ -216,5 +224,24 @@ Item {
216 data.maxTranslation)
224 data.maxTranslation)
217 compare(scale, data.result)
225 compare(scale, data.result)
218 }
226 }
227+
228+ function test_lastItemXPosition() {
229+ var carouselList = findChild(carousel, "listView");
230+ var stepAnimation = findInvisibleChild(carouselList, "stepAnimation");
231+ var stepDiff = 0;
232+ stepAnimation.onRunningChanged.connect(function() { if (stepAnimation.running) stepDiff = Math.abs(carouselList.contentX - stepAnimation.to); })
233+ var overshootOnce = false;
234+ while (!overshootOnce) {
235+ overshootOnce = carouselList.realContentX > carouselList.realContentWidth - carouselList.realWidth;
236+ mouseFlick(carousel, carousel.width - units.gu(1),
237+ carousel.height / 2,
238+ units.gu(2),
239+ carousel.height / 2);
240+ tryCompare(carouselList, "moving", false);
241+ }
242+ verify(stepDiff < 1);
243+ var x = carouselList.getXFromContinuousIndex(carousel.model - 1);
244+ verify(Math.abs(x - carouselList.contentX) < 1);
245+ }
219 }
246 }
220}
247}
tests/qmltests/Components/tst_FilterGrid.qml+1−1
@@ -50,6 +50,7 @@ Rectangle {
50 CheckBox {
50 CheckBox {
51 id: filterCheckBox
51 id: filterCheckBox
52 checked: true
52 checked: true
53+ onCheckedChanged: filterGrid.setFilter(checked, false /*animate*/)
53 }
54 }
54 }
55 }
55 }
56 }
@@ -99,7 +100,6 @@ Rectangle {
99 maximumNumberOfColumns: 3
100 maximumNumberOfColumns: 3
100 collapsedRowCount:
101 collapsedRowCount:
101 collapsedRowCountSelector.values[collapsedRowCountSelector.selectedIndex]
102 collapsedRowCountSelector.values[collapsedRowCountSelector.selectedIndex]
102− filter: filterCheckBox.checked
103 minimumHorizontalSpacing: units.gu(1)
103 minimumHorizontalSpacing: units.gu(1)
104 delegateWidth: units.gu(6)
104 delegateWidth: units.gu(6)
105 delegateHeight: units.gu(6)
105 delegateHeight: units.gu(6)
tests/qmltests/Dash/Previews/tst_PreviewRatingInput.qml+21−2
@@ -36,6 +36,8 @@ Rectangle {
36 property var triggeredDataReviewOnly: { "rating": invalidInputRating, "review": validInputText, "author": null }
36 property var triggeredDataReviewOnly: { "rating": invalidInputRating, "review": validInputText, "author": null }
37
37
38 property var widgetDataBoth: { "visible": "both", "required": "both" }
38 property var widgetDataBoth: { "visible": "both", "required": "both" }
39+ property var widgetDataBothRequireRating: { "visible": "both", "required": "rating" }
40+ property var widgetDataBothRequireReview: { "visible": "both", "required": "review" }
39 property var widgetDataRating: { "visible": "rating", "required": "rating" }
41 property var widgetDataRating: { "visible": "rating", "required": "rating" }
40 property var widgetDataRatingBroken: { "visible": "rating", "required": "review" }
42 property var widgetDataRatingBroken: { "visible": "rating", "required": "review" }
41 property var widgetDataReview: { "visible": "review", "required": "review" }
43 property var widgetDataReview: { "visible": "review", "required": "review" }
@@ -85,6 +87,14 @@ Rectangle {
85 {tag: "both, rating-only review", widgetData: widgetDataBoth, inputRating: validInputRating, inputText: invalidInputText, emitted: false},
87 {tag: "both, rating-only review", widgetData: widgetDataBoth, inputRating: validInputRating, inputText: invalidInputText, emitted: false},
86 {tag: "both, review-only review", widgetData: widgetDataBoth, inputRating: invalidInputRating, inputText: validInputText, emitted: false},
88 {tag: "both, review-only review", widgetData: widgetDataBoth, inputRating: invalidInputRating, inputText: validInputText, emitted: false},
87 {tag: "both, complete review", widgetData: widgetDataBoth, inputRating: validInputRating, inputText: validInputText, emitted: true},
89 {tag: "both, complete review", widgetData: widgetDataBoth, inputRating: validInputRating, inputText: validInputText, emitted: true},
90+ {tag: "both require rating, null review", widgetData: widgetDataBothRequireRating, inputRating: invalidInputRating, inputText: invalidInputText, emitted: false},
91+ {tag: "both require rating, rating-only review", widgetData: widgetDataBothRequireRating, inputRating: validInputRating, inputText: invalidInputText, emitted: true},
92+ {tag: "both require rating, review-only review", widgetData: widgetDataBothRequireRating, inputRating: invalidInputRating, inputText: validInputText, emitted: false},
93+ {tag: "both require rating, complete review", widgetData: widgetDataBothRequireRating, inputRating: validInputRating, inputText: validInputText, emitted: true},
94+ {tag: "both require review, null review", widgetData: widgetDataBothRequireReview, inputRating: invalidInputRating, inputText: invalidInputText, emitted: false},
95+ {tag: "both require review, rating-only review", widgetData: widgetDataBothRequireReview, inputRating: validInputRating, inputText: invalidInputText, emitted: false},
96+ {tag: "both require review, review-only review", widgetData: widgetDataBothRequireReview, inputRating: invalidInputRating, inputText: validInputText, emitted: true},
97+ {tag: "both require review, complete review", widgetData: widgetDataBothRequireReview, inputRating: validInputRating, inputText: validInputText, emitted: true},
88 {tag: "rating, null review", widgetData: widgetDataRating, inputRating: invalidInputRating, inputText: invalidInputText, emitted: false},
98 {tag: "rating, null review", widgetData: widgetDataRating, inputRating: invalidInputRating, inputText: invalidInputText, emitted: false},
89 {tag: "rating, rating-only review", widgetData: widgetDataRating, inputRating: validInputRating, inputText: invalidInputText, emitted: true},
99 {tag: "rating, rating-only review", widgetData: widgetDataRating, inputRating: validInputRating, inputText: invalidInputText, emitted: true},
90 {tag: "rating, review-only review", widgetData: widgetDataRating, inputRating: invalidInputRating, inputText: validInputText, emitted: false},
100 {tag: "rating, review-only review", widgetData: widgetDataRating, inputRating: invalidInputRating, inputText: validInputText, emitted: false},
@@ -114,7 +124,9 @@ Rectangle {
114 verify(rating.visible === true);
124 verify(rating.visible === true);
115
125
116 rating.value = data.inputRating;
126 rating.value = data.inputRating;
117− if (data.widgetData["required"] !== "rating" || data.inputRating < 0) {
127+ if (data.widgetData["required"] !== "rating" ||
128+ data.widgetData["visible"] !== "rating" ||
129+ data.inputRating < 0) {
118 compare(spy.count, 0);
130 compare(spy.count, 0);
119 } else {
131 } else {
120 compare(spy.count, 1);
132 compare(spy.count, 1);
@@ -129,7 +141,14 @@ Rectangle {
129 reviewTextArea.text = data.inputText;
141 reviewTextArea.text = data.inputText;
130 mouseClick(submitButton, submitButton.width / 2, submitButton.height / 2);
142 mouseClick(submitButton, submitButton.width / 2, submitButton.height / 2);
131 switch (data.widgetData["required"]) {
143 switch (data.widgetData["required"]) {
144+ case "rating": {
145+ if (rating.visible === false || data.inputRating < 0) {
132− case "rating": compare(spy.count, 0); break;
146+ compare(spy.count, 0);
147+ } else {
148+ compare(spy.count, 1);
149+ }
150+ break;
151+ }
133 case "both":
152 case "both":
134 default: {
153 default: {
135 if (data.inputRating < 0 || data.inputText === "") {
154 if (data.inputRating < 0 || data.inputText === "") {
tests/qmltests/Dash/qml/FakeScopeView.qmldeleted−45
@@ -1,45 +0,0 @@
1−/*
2− * Copyright 2013 Canonical Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− */
16−
17−import QtQuick 2.0
18−import Unity 0.2
19−
20−import "../../../../qml/Dash"
21−
22−GenericScopeView {
23− id: fakeScopeView
24−
25− property alias backColor : back.color
26− property var categoryView: null
27−
28− onMovementStarted: {
29− if (shell != undefined && shell.scopeStatus != undefined) {
30− shell.scopeStatus[scope.id].movementStarted++;
31− }
32− }
33− onPositionedAtBeginning: {
34− if (shell != undefined && shell.scopeStatus != undefined) {
35− shell.scopeStatus[scope.id].positionedAtBeginning++;
36− }
37− }
38−
39− Rectangle {
40− id: back
41− anchors.fill: parent
42− color: "grey"
43− z: -1
44− }
45−}
tests/qmltests/Dash/qml/fake_generic_scopeView.qmldeleted−24
@@ -1,24 +0,0 @@
1−/*
2− * Copyright 2013 Canonical Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− */
16−
17−import QtQuick 2.0
18−
19−FakeScopeView {
20− id: fake_generic_scopeView
21− objectName: "fake_generic_scopeView"
22−
23− backColor: "#D0D0D0"
24−}
tests/qmltests/Dash/qml/fake_scopeView1.qmldeleted−24
@@ -1,24 +0,0 @@
1−/*
2− * Copyright 2013 Canonical Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− */
16−
17−import QtQuick 2.0
18−
19−FakeScopeView {
20− id: fake_scopeView1
21− objectName: "fake_scopeView1"
22−
23− backColor: "#90E090"
24−}
tests/qmltests/Dash/qml/fake_scopeView2.qmldeleted−24
@@ -1,24 +0,0 @@
1−/*
2− * Copyright 2013 Canonical Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− */
16−
17−import QtQuick 2.0
18−
19−FakeScopeView {
20− id: fake_scopeView2
21− objectName: "fake_scopeView2"
22−
23− backColor: "#A0D0A0"
24−}
tests/qmltests/Dash/qml/fake_scopeView3.qmldeleted−24
@@ -1,24 +0,0 @@
1−/*
2− * Copyright 2013 Canonical Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− */
16−
17−import QtQuick 2.0
18−
19−FakeScopeView {
20− id: fake_scopeView3
21− objectName: "fake_scopeView3"
22−
23− backColor: "#B0C0B0"
24−}
tests/qmltests/Dash/qml/fake_scopeView4.qmldeleted−24
@@ -1,24 +0,0 @@
1−/*
2− * Copyright 2013 Canonical Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− */
16−
17−import QtQuick 2.0
18−
19−FakeScopeView {
20− id: fake_scopeView4
21− objectName: "fake_scopeView4"
22−
23− backColor: "#C0C0C0"
24−}
tests/qmltests/Dash/tst_Card.qml+12−10
@@ -182,11 +182,13 @@ Rectangle {
182 when: windowShown
182 when: windowShown
183
183
184 property Item header: findChild(card, "cardHeader")
184 property Item header: findChild(card, "cardHeader")
185+ property Item headerLoader: findChild(card, "cardHeaderLoader")
185 property Item title: findChild(header, "titleLabel")
186 property Item title: findChild(header, "titleLabel")
186 property Item art: findChild(card, "artShape")
187 property Item art: findChild(card, "artShape")
187 property Item artImage: findChild(card, "artImage")
188 property Item artImage: findChild(card, "artImage")
188 property Item summary: findChild(card, "summaryLabel")
189 property Item summary: findChild(card, "summaryLabel")
189 property Item background: findChild(card, "background")
190 property Item background: findChild(card, "background")
191+ property Item backgroundLoader: findChild(card, "backgroundLoader")
190 property Item backgroundImage: findChild(card, "backgroundImage")
192 property Item backgroundImage: findChild(card, "backgroundImage")
191
193
192 function initTestCase() {
194 function initTestCase() {
@@ -244,8 +246,8 @@ Rectangle {
244 { tag: "Wide", width: units.gu(18.5), aspect: 0.5, index: 0 },
246 { tag: "Wide", width: units.gu(18.5), aspect: 0.5, index: 0 },
245 { tag: "Horizontal", width: units.gu(38), index: 5 },
247 { tag: "Horizontal", width: units.gu(38), index: 5 },
246 // Make sure card ends with header when there's no summary
248 // Make sure card ends with header when there's no summary
247− { tag: "NoSummary", height: function() { return header.y + header.height }, index: 6 },
249+ { tag: "NoSummary", height: function() { return headerLoader.y + headerLoader.height }, index: 6 },
248− { tag: "HorizontalNoSummary", height: function() { return header.height }, card_layout: "horizontal", index: 6 },
250+ { tag: "HorizontalNoSummary", height: function() { return headerLoader.height }, card_layout: "horizontal", index: 6 },
249 ]
251 ]
250 }
252 }
251
253
@@ -288,7 +290,7 @@ Rectangle {
288 { tag: "Fit", height: units.gu(38), size: "large", width: units.gu(19), index: 4 },
290 { tag: "Fit", height: units.gu(38), size: "large", width: units.gu(19), index: 4 },
289 { tag: "VerticalWidth", width: function() { return header.width }, index: 0 },
291 { tag: "VerticalWidth", width: function() { return header.width }, index: 0 },
290 { tag: "HorizontalHeight", height: function() { return header.height }, index: 5 },
292 { tag: "HorizontalHeight", height: function() { return header.height }, index: 5 },
291− { tag: "HorizontalWidth", width: function() { return header.x }, index: 5 },
293+ { tag: "HorizontalWidth", width: function() { return headerLoader.x }, index: 5 },
292 ]
294 ]
293 }
295 }
294
296
@@ -332,7 +334,7 @@ Rectangle {
332 function test_art_layout(data) {
334 function test_art_layout(data) {
333 selector.selectedIndex = data.index;
335 selector.selectedIndex = data.index;
334
336
335− tryCompare(testCase.header, "x", data.left());
337+ tryCompare(testCase.headerLoader, "x", data.left());
336 }
338 }
337
339
338 function test_header_layout_data() {
340 function test_header_layout_data() {
@@ -349,13 +351,13 @@ Rectangle {
349 function test_header_layout(data) {
351 function test_header_layout(data) {
350 selector.selectedIndex = data.index;
352 selector.selectedIndex = data.index;
351
353
352− tryCompareFunction(function() { return testCase.header.y === data.top() }, true);
354+ tryCompareFunction(function() { return testCase.headerLoader.y === data.top() }, true);
353− tryCompareFunction(function() { return testCase.header.x === data.left() }, true);
355+ tryCompareFunction(function() { return testCase.headerLoader.x === data.left() }, true);
354 }
356 }
355
357
356 function test_summary_layout_data() {
358 function test_summary_layout_data() {
357 return [
359 return [
358− { tag: "With header", top: function() { return header.y + header.height }, index: 0 },
360+ { tag: "With header", top: function() { return headerLoader.y + headerLoader.height }, index: 0 },
359 { tag: "Without header", top: function() { return art.y + art.height }, index: 7 },
361 { tag: "Without header", top: function() { return art.y + art.height }, index: 7 },
360 ]
362 ]
361 }
363 }
@@ -400,7 +402,7 @@ Rectangle {
400
402
401 waitForRendering(card);
403 waitForRendering(card);
402
404
403− tryCompare(background, "visible", data.visible);
405+ tryCompare(backgroundLoader, "active", data.visible);
404
406
405 if (data.hasOwnProperty("color")) {
407 if (data.hasOwnProperty("color")) {
406 tryCompare(background, "color", data.color);
408 tryCompare(background, "color", data.color);
@@ -467,13 +469,13 @@ Rectangle {
467 function test_mascotShape(data) {
469 function test_mascotShape(data) {
468 selector.selectedIndex = data.index;
470 selector.selectedIndex = data.index;
469
471
470− var shape = findChild(card, "mascotShape");
472+ var shape = findChild(card, "mascotShapeLoader");
471 var image = findChild(card, "mascotImage");
473 var image = findChild(card, "mascotImage");
472
474
473 verify(shape, "Could not find shape.");
475 verify(shape, "Could not find shape.");
474 verify(image, "Could not find image.");
476 verify(image, "Could not find image.");
475
477
476− tryCompare(shape, "visible", data.shape);
478+ tryCompare(shape, "active", data.shape);
477 tryCompare(image, "visible", !data.shape);
479 tryCompare(image, "visible", !data.shape);
478 }
480 }
479 }
481 }
tests/qmltests/Dash/tst_CardBenchmark.qmlnew file+94
@@ -0,0 +1,94 @@
1+/*
2+ * Copyright (C) 2014 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+import QtQuick 2.0
18+import QtTest 1.0
19+import Ubuntu.Components 0.1
20+import Unity.Test 0.1 as UT
21+import "../../../qml/Dash"
22+import "CardHelpers.js" as Helpers
23+
24+Rectangle {
25+ id: root
26+ width: units.gu(80)
27+ height: units.gu(72)
28+ color: "#88FFFFFF"
29+
30+ property string cardData: '
31+ {
32+ "art": "../../tests/qmltests/Dash/artwork/music-player-design.png",
33+ "mascot": "../../tests/qmltests/Dash/artwork/avatar.png",
34+ "title": "foo",
35+ "subtitle": "bar",
36+ "summary": "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
37+ }'
38+
39+ property string currentModel: '{}'
40+ property string cardTitleArtSubtitleMascotSummaryModel: '{ "components": { "title": "title", "art": "art", "subtitle": "subtitle", "mascot": "mascot", "summary": "summary" } }'
41+ property string cardTitleArtSubtitleMascotModel: '{ "components": { "title": "title", "art": "art", "subtitle": "subtitle", "mascot": "mascot" } }'
42+ property string cardTitleArtSubtitleModel: '{ "components": { "title": "title", "art": "art", "subtitle": "subtitle" } }'
43+ property string cardTitleArtModel: '{ "components": { "title": "title", "art": "art" } }'
44+ property string cardArtModel: '{ "components": { "art": "art" } }'
45+ property string cardTitleModel: '{ "components": { "title": "title" } }'
46+
47+ CardTool {
48+ id: cardTool
49+ template: Helpers.update(JSON.parse(Helpers.defaultLayout), JSON.parse(currentModel))['template'];
50+ components: Helpers.update(JSON.parse(Helpers.defaultLayout), JSON.parse(currentModel))['components'];
51+ viewWidth: units.gu(48)
52+ }
53+
54+ Repeater {
55+ id: cardRepeater
56+ model: 0
57+ Card {
58+ width: cardTool.cardWidth || implicitWidth
59+ height: cardTool.cardHeight || implicitHeight
60+
61+ template: cardTool.template
62+ components: cardTool.components
63+ cardData: Helpers.mapData(root.cardData, components)
64+ }
65+ }
66+
67+ UT.UnityTestCase {
68+ id: testCase
69+ name: "CardBenchmark"
70+
71+ when: windowShown
72+
73+ function init() {
74+ wait(1);
75+ }
76+
77+ function benchmark_time_data() {
78+ return [
79+ { tag: "cardTitleArtSubtitleMascotSummaryModel", model: cardTitleArtSubtitleMascotSummaryModel },
80+ { tag: "cardTitleArtSubtitleMascotModel", model: cardTitleArtSubtitleMascotModel },
81+ { tag: "cardTitleArtSubtitleModel", model: cardTitleArtSubtitleModel },
82+ { tag: "cardTitleArtModel", model: cardTitleArtModel },
83+ { tag: "cardArtModel", model: cardArtModel },
84+ { tag: "cardTitleModel", model: cardTitleModel },
85+ ];
86+ }
87+
88+ function benchmark_time(data) {
89+ currentModel = data.model;
90+ cardRepeater.model = 1;
91+ cardRepeater.model = 0;
92+ }
93+ }
94+}
tests/qmltests/Dash/tst_CardHeader.qml+1−1
@@ -43,7 +43,7 @@ Rectangle {
43
43
44 when: windowShown
44 when: windowShown
45
45
46− property Item mascot: findChild(cardHeader, "mascotShape")
46+ property Item mascot: findChild(cardHeader, "mascotShapeLoader")
47 property Item titleLabel: findChild(cardHeader, "titleLabel")
47 property Item titleLabel: findChild(cardHeader, "titleLabel")
48 property Item subtitleLabel: findChild(cardHeader, "subtitleLabel")
48 property Item subtitleLabel: findChild(cardHeader, "subtitleLabel")
49 property Item oldPriceLabel: findChild(cardHeader, "oldPriceLabel")
49 property Item oldPriceLabel: findChild(cardHeader, "oldPriceLabel")
tests/qmltests/Dash/tst_Dash.qml−11
@@ -41,16 +41,6 @@ Item {
41 showScopeOnLoaded: "MockScope2"
41 showScopeOnLoaded: "MockScope2"
42 }
42 }
43
43
44− ScopeDelegateMapper {
45− id: scopeDelegateMapper
46− scopeDelegateMapping: {
47− "MockScope1": Qt.resolvedUrl("qml/fake_scopeView1.qml"),
48− "MockScope2": Qt.resolvedUrl("qml/fake_scopeView2.qml"),
49− "clickscope": Qt.resolvedUrl("qml/fake_scopeView3.qml")
50− }
51− genericScope: Qt.resolvedUrl("qml/fake_generic_scopeView.qml")
52− }
53−
54 UT.UnityTestCase {
44 UT.UnityTestCase {
55 name: "Dash"
45 name: "Dash"
56 when: windowShown
46 when: windowShown
@@ -59,7 +49,6 @@ Item {
59
49
60 Component.onCompleted: {
50 Component.onCompleted: {
61 var dashContent = findChild(dash, "dashContent");
51 var dashContent = findChild(dash, "dashContent");
62− dashContent.scopeMapper = scopeDelegateMapper;
63 scopes = dashContent.scopes;
52 scopes = dashContent.scopes;
64 }
53 }
65
54
tests/qmltests/Dash/tst_DashContent.qml+27−51
@@ -35,13 +35,6 @@ Item {
35 property var panel: null
35 property var panel: null
36 // BEGIN To reduce warnings
36 // BEGIN To reduce warnings
37
37
38− property var scopeStatus: {
39− 'MockScope1': { 'movementStarted': 0, 'positionedAtBeginning': 0 },
40− 'MockScope2': { 'movementStarted': 0, 'positionedAtBeginning': 0 },
41− 'clickscope': { 'movementStarted': 0, 'positionedAtBeginning': 0 },
42− 'MockScope5': { 'movementStarted': 0, 'positionedAtBeginning': 0 }
43− }
44−
45 Scopes {
38 Scopes {
46 id: scopesModel
39 id: scopesModel
47 }
40 }
@@ -55,34 +48,9 @@ Item {
55 }
48 }
56 scopes : scopesModel
49 scopes : scopesModel
57
50
58− scopeMapper : scopeDelegateMapper
59 searchHistory: SearchHistoryModel {}
51 searchHistory: SearchHistoryModel {}
60 }
52 }
61
53
62− ScopeDelegateMapper {
63− id: scopeDelegateMapper
64− scopeDelegateMapping: {
65− "MockScope1": Qt.resolvedUrl("qml/fake_scopeView1.qml"),
66− "MockScope2": Qt.resolvedUrl("qml/fake_scopeView2.qml"),
67− "clickscope": Qt.resolvedUrl("qml/fake_scopeView3.qml"),
68− }
69− genericScope: Qt.resolvedUrl("qml/fake_generic_scopeView.qml")
70− }
71−
72− function clear_scope_status() {
73− scopeStatus["MockScope1"].movementStarted = 0;
74− scopeStatus["MockScope1"].positionedAtBeginning = 0;
75−
76− scopeStatus["MockScope2"].movementStarted = 0;
77− scopeStatus["MockScope2"].positionedAtBeginning = 0;
78−
79− scopeStatus["clickscope"].movementStarted = 0;
80− scopeStatus["clickscope"].positionedAtBeginning = 0;
81−
82− scopeStatus["MockScope5"].movementStarted = 0;
83− scopeStatus["MockScope5"].positionedAtBeginning = 0;
84− }
85−
86 SignalSpy {
54 SignalSpy {
87 id: scopeLoadedSpy
55 id: scopeLoadedSpy
88 target: dashContent
56 target: dashContent
@@ -97,7 +65,7 @@ Item {
97
65
98 UT.UnityTestCase {
66 UT.UnityTestCase {
99 name: "DashContent"
67 name: "DashContent"
100− when: scopesModel.loaded
68+ when: scopesModel.loaded && windowShown
101
69
102 function init() {
70 function init() {
103 scopesModel.clear();
71 scopesModel.clear();
@@ -108,7 +76,6 @@ Item {
108
76
109 function cleanup() {
77 function cleanup() {
110 movementStartedSpy.clear();
78 movementStartedSpy.clear();
111− clear_scope_status();
112 dashContent.visible = true;
79 dashContent.visible = true;
113
80
114 var dashContentList = findChild(dashContent, "dashContentList");
81 var dashContentList = findChild(dashContent, "dashContentList");
@@ -149,29 +116,38 @@ Item {
149 verify(dashContentList.currentIndex >= 0 && dashContentList.currentIndex < 5);
116 verify(dashContentList.currentIndex >= 0 && dashContentList.currentIndex < 5);
150 }
117 }
151
118
152− function test_movement_started_signal() {
119+ function test_show_header_on_list_movement() {
153− dashContent.setCurrentScopeAtIndex(3, true, false);
154−
155 var dashContentList = findChild(dashContent, "dashContentList");
120 var dashContentList = findChild(dashContent, "dashContentList");
156− verify(dashContentList != undefined)
121+ verify(dashContentList != undefined);
122+ var categoryListView = findChild(dashContentList, "categoryListView");
123+ verify(categoryListView != undefined);
124+
125+ waitForRendering(categoryListView);
157
126
158− dashContentList.movementStarted();
127+ categoryListView.contentY = units.gu(11);
128+ console.log("contentY", categoryListView.contentY);
159
129
160− compare(movementStartedSpy.count, 1, "DashContent should have emitted movementStarted signal when content list did.");
130+ var startX = dashContentList.width/2;
161− compare(scopeStatus["MockScope1"].movementStarted, 1, "MockScope1 should have emitted movementStarted signal when content list did.");
131+ var startY = dashContentList.height/2;
162− compare(scopeStatus["MockScope2"].movementStarted, 1, "MockScope2 should have emitted movementStarted signal when content list did.");
132+ touchFlick(dashContentList, startX - units.gu(2), startY, startX, startY);
163− compare(scopeStatus["clickscope"].movementStarted, 1, "clickscope should have emitted movementStarted signal when content list did.");
133+ tryCompare(categoryListView, "contentY", units.gu(11) - categoryListView.pageHeader.height);
164− compare(scopeStatus["MockScope5"].movementStarted, 1, "MockScope5 should have emitted movementStarted signal when content list did.");
165 }
134 }
166
135
167− function test_positioned_at_beginning_signal() {
136+ function test_set_current_scope_reset() {
137+ var dashContentList = findChild(dashContent, "dashContentList");
138+ verify(dashContentList != undefined);
139+ var categoryListView = findChild(dashContentList, "categoryListView");
140+ verify(categoryListView != undefined);
141+
142+ categoryListView.contentY = units.gu(10);
143+
144+ compare(dashContentList.currentItem.item.objectName, "MockScope1")
145+ compare(categoryListView.contentY, units.gu(10));
146+
168− dashContent.setCurrentScopeAtIndex(3, true, false);
147+ dashContent.setCurrentScopeAtIndex(0, false, true);
169
148
170− dashContent.positionedAtBeginning();
149+ compare(dashContentList.currentItem.item.objectName, "MockScope1")
171− compare(scopeStatus["MockScope1"].positionedAtBeginning, 1, "MockScope1 should have emitted positionedAtBeginning signal when DashContent did.");
150+ compare(categoryListView.contentY, 0);
172− compare(scopeStatus["MockScope2"].positionedAtBeginning, 1, "MockScope2 should have emitted positionedAtBeginning signal when DashContent did.");
173− compare(scopeStatus["clickscope"].positionedAtBeginning, 1, "clickscope should have emitted positionedAtBeginning signal when DashContent did.");
174− compare(scopeStatus["MockScope5"].positionedAtBeginning, 1, "MockScope5 should have emitted positionedAtBeginning signal when DashContent did.");
175 }
151 }
176
152
177 // This tests that setting the current scope index will end up at the correct index even if
153 // This tests that setting the current scope index will end up at the correct index even if
tests/qmltests/Dash/tst_GenericScopeView.qml+4−4
@@ -64,7 +64,7 @@ Item {
64
64
65 UT.UnityTestCase {
65 UT.UnityTestCase {
66 name: "GenericScopeView"
66 name: "GenericScopeView"
67− when: scopes.loaded
67+ when: scopes.loaded && windowShown
68
68
69 function init() {
69 function init() {
70 genericScopeView.scope = scopes.get(2)
70 genericScopeView.scope = scopes.get(2)
@@ -140,7 +140,7 @@ Item {
140 mouseClick(header, header.width / 2, header.height / 2);
140 mouseClick(header, header.width / 2, header.height / 2);
141 tryCompareFunction(function() { middleHeight = category.height; return category.height > initialHeight; }, true);
141 tryCompareFunction(function() { middleHeight = category.height; return category.height > initialHeight; }, true);
142 tryCompare(category, "filtered", false);
142 tryCompare(category, "filtered", false);
143− verify(category.height > middleHeight);
143+ tryCompareFunction(function() { return category.height > middleHeight; }, true);
144
144
145 mouseClick(header, header.width / 2, header.height / 2);
145 mouseClick(header, header.width / 2, header.height / 2);
146 verify(category.expandable);
146 verify(category.expandable);
@@ -165,7 +165,7 @@ Item {
165
165
166 mouseClick(header2, header2.width / 2, header2.height / 2);
166 mouseClick(header2, header2.width / 2, header2.height / 2);
167 tryCompare(category2, "filtered", false);
167 tryCompare(category2, "filtered", false);
168− tryCompare(category2FilterGrid, "filter", false);
168+ tryCompare(category2FilterGrid, "filtered", false);
169
169
170 categoryListView.positionAtBeginning();
170 categoryListView.positionAtBeginning();
171
171
@@ -182,7 +182,7 @@ Item {
182 mouseClick(header0, header0.width / 2, header0.height / 2);
182 mouseClick(header0, header0.width / 2, header0.height / 2);
183 tryCompare(category0, "filtered", false);
183 tryCompare(category0, "filtered", false);
184 tryCompare(category2, "filtered", true);
184 tryCompare(category2, "filtered", true);
185− tryCompare(category2FilterGrid, "filter", true);
185+ tryCompare(category2FilterGrid, "filtered", true);
186 mouseClick(header0, header0.width / 2, header0.height / 2);
186 mouseClick(header0, header0.width / 2, header0.height / 2);
187 tryCompare(category0, "filtered", true);
187 tryCompare(category0, "filtered", true);
188 tryCompare(category2, "filtered", true);
188 tryCompare(category2, "filtered", true);
tests/qmltests/Greeter/tst_Clock.qml+3−3
@@ -71,10 +71,10 @@ Rectangle {
71 var dateString = Qt.formatDate(dateObj, Qt.DefaultLocaleLongDate)
71 var dateString = Qt.formatDate(dateObj, Qt.DefaultLocaleLongDate)
72 var timeString = Qt.formatTime(dateObj)
72 var timeString = Qt.formatTime(dateObj)
73
73
74− clock.enabled = false
74+ clock.visible = false
75 var timeModel = findInvisibleChild(clock, "timeModel")
75 var timeModel = findInvisibleChild(clock, "timeModel")
76
76
77− compare(timeModel.menuObjectPath, "", "Clock shouldn't be connected to Indicators when not active.")
77+ compare(timeModel.menuObjectPath, "", "Clock shouldn't be connected to Indicators when not visible.")
78
78
79 clock.currentDate = dateObj
79 clock.currentDate = dateObj
80
80
@@ -83,7 +83,7 @@ Rectangle {
83 var timeLabel = findChild(clock, "timeLabel")
83 var timeLabel = findChild(clock, "timeLabel")
84 compare(timeLabel.text, timeString, "Not the expected time")
84 compare(timeLabel.text, timeString, "Not the expected time")
85
85
86− clock.enabled = true
86+ clock.visible = true
87
87
88 verify(timeModel.menuObjectPath != "", "Should be connected to Indicators.")
88 verify(timeModel.menuObjectPath != "", "Should be connected to Indicators.")
89 }
89 }
tests/qmltests/Greeter/tst_Phone.qml+10−50
@@ -61,6 +61,12 @@ Item {
61 signalName: "unlocked"
61 signalName: "unlocked"
62 }
62 }
63
63
64+ SignalSpy {
65+ id: teaseSpy
66+ target: greeter
67+ signalName: "tease"
68+ }
69+
64 UT.UnityTestCase {
70 UT.UnityTestCase {
65 name: "Greeter"
71 name: "Greeter"
66 when: windowShown
72 when: windowShown
@@ -82,56 +88,10 @@ Item {
82 }
88 }
83
89
84 function test_teasingArea(data) {
90 function test_teasingArea(data) {
85− tryCompare(greeter, "leftTeaserPressed", false)
91+ teaseSpy.clear()
86− tryCompare(greeter, "rightTeaserPressed", false)
87− mousePress(greeter, data.posX, greeter.height - units.gu(1))
88− tryCompare(greeter, "leftTeaserPressed", data.leftPressed)
89− tryCompare(greeter, "rightTeaserPressed", data.rightPressed)
90− mouseRelease(greeter, data.posX, greeter.height - units.gu(1))
91− tryCompare(greeter, "leftTeaserPressed", false)
92− tryCompare(greeter, "rightTeaserPressed", false)
93− }
94−
95− function test_teaseLockedUnlocked_data() {
96− return [
97− {tag: "unlocked", locked: false, moved: false},
98− {tag: "locked", locked: true, moved: false},
99− {tag: "moved", locked: false, moved: true}
100− ];
101− }
102−
103− function test_teaseLockedUnlocked(data) {
104− tryCompare(greeter, "rightTeaserPressed", false);
105− tryCompare(greeter, "x", 0);
106− greeter.locked = data.locked;
107−
108− // simulate greeter being in the middle of a swipe
109− if (data.moved) {
110− greeter.x = -units.gu(4);
111− tryCompare(greeter, "x", -units.gu(4));
112− }
113−
114− mouseClick(greeter, greeter.width - units.gu(5), greeter.height - units.gu(1));
92+ mouseClick(greeter, data.posX, greeter.height - units.gu(1))
115− greeter.minX = 0; // This is needed because the transition actually makes x jump once before animating
116−
117− if (!data.moved) {
118− // Check if it has been moved over by 2 GUs. Give it a 2 pixel grace area
119− // because animation duration and teaseTimer are the same duration and
120− // might cause slight offsets
121− tryCompareFunction(function() { return greeter.minX <= -units.gu(2) + 2}, true);
122− } else {
123− // waiting 100ms to make sure nothing moves
124− wait(100);
93+ teaseSpy.wait()
125− compare(greeter.minX, 0, "Greeter teasing not disabled even though it's locked or moving.");
94+ tryCompare(teaseSpy, "count", 1)
126− }
127−
128− // Restore position in case we moved it for the test
129− if (data.moved) {
130− greeter.x = 0;
131− }
132−
133− // Wait until we're back to 0
134− tryCompareFunction(function() { return greeter.x;}, 0);
135 }
95 }
136
96
137 function test_statsWelcomeScreen() {
97 function test_statsWelcomeScreen() {
tests/qmltests/Greeter/tst_Tablet.qml+36−8
@@ -54,6 +54,12 @@ Item {
54 signalName: "selected"
54 signalName: "selected"
55 }
55 }
56
56
57+ SignalSpy {
58+ id: teaseSpy
59+ target: greeter
60+ signalName: "tease"
61+ }
62+
57 UT.UnityTestCase {
63 UT.UnityTestCase {
58 name: "Greeter"
64 name: "Greeter"
59 when: windowShown
65 when: windowShown
@@ -325,14 +331,36 @@ Item {
325 }
331 }
326
332
327 function test_teasingArea(data) {
333 function test_teasingArea(data) {
328− tryCompare(greeter, "leftTeaserPressed", false)
334+ teaseSpy.clear()
329− tryCompare(greeter, "rightTeaserPressed", false)
330− mousePress(greeter, data.posX, greeter.height - units.gu(1))
335+ mouseClick(greeter, data.posX, greeter.height - units.gu(1))
331− tryCompare(greeter, "leftTeaserPressed", data.leftPressed)
336+ teaseSpy.wait()
332− tryCompare(greeter, "rightTeaserPressed", data.rightPressed)
337+ tryCompare(teaseSpy, "count", 1)
338+ }
339+
340+ function test_teaseLockedUnlocked_data() {
341+ return [
342+ {tag: "unlocked", locked: false, narrow: false},
343+ {tag: "locked", locked: true, narrow: false},
344+ ];
345+ }
346+
347+ function test_teaseLockedUnlocked(data) {
348+ teaseSpy.clear()
349+ greeter.locked = data.locked;
350+
333− mouseRelease(greeter, data.posX, greeter.height - units.gu(1))
351+ mouseClick(greeter, greeter.width - units.gu(5), greeter.height - units.gu(1));
334− tryCompare(greeter, "leftTeaserPressed", false)
352+
335− tryCompare(greeter, "rightTeaserPressed", false)
353+ if (!data.locked || data.narrow) {
354+ teaseSpy.wait()
355+ tryCompare(teaseSpy, "count", 1);
356+ } else {
357+ // waiting 100ms to make sure nothing happens
358+ wait(100);
359+ compare(teaseSpy.count, 0, "Greeter teasing not disabled even though it's locked.");
360+ }
361+
362+ // Reset value
363+ greeter.locked = false;
336 }
364 }
337
365
338 function test_dbus_set_active_entry() {
366 function test_dbus_set_active_entry() {
tests/qmltests/Launcher/tst_Launcher.qml+1
@@ -66,6 +66,7 @@ Item {
66
66
67 UT.UnityTestCase {
67 UT.UnityTestCase {
68 id: revealer
68 id: revealer
69+ when: windowShown
69
70
70 function dragLauncherIntoView() {
71 function dragLauncherIntoView() {
71 var startX = launcher.dragAreaWidth/2;
72 var startX = launcher.dragAreaWidth/2;
tests/qmltests/Panel/Indicators/tst_MenuItemFactory.qml+30−4
@@ -19,6 +19,7 @@ import QtTest 1.0
19import Unity.Test 0.1 as UT
19import Unity.Test 0.1 as UT
20import QMenuModel 0.1
20import QMenuModel 0.1
21import Unity.Indicators 0.1 as Indicators
21import Unity.Indicators 0.1 as Indicators
22+import Utils 0.1 as Utils
22
23
23Item {
24Item {
24 id: testView
25 id: testView
@@ -42,8 +43,13 @@ Item {
42 }
43 }
43 }
44 }
44
45
46+ Utils.GDateTimeFormatter {
47+ id: timeFormatter
48+ }
49+
45 UT.UnityTestCase {
50 UT.UnityTestCase {
46 name: "MenuItemFactory"
51 name: "MenuItemFactory"
52+ when: windowShown
47
53
48 property QtObject menuData: QtObject {
54 property QtObject menuData: QtObject {
49 property string label: "root"
55 property string label: "root"
@@ -357,8 +363,10 @@ Item {
357
363
358 function test_create_alarmMenu_data() {
364 function test_create_alarmMenu_data() {
359 return [
365 return [
360− {label: "testLabel1", enabled: true, icon: "file:///testIcon1" },
366+ {label: "testLabel1", enabled: true, icon: "file:///testIcon1", color: Qt.rgba(0, 0, 0, 0),
367+ time: new Date(2014, 04, 14).getTime()*1000, timeFormat: "%a %d %b %l:%M %p"},
361− {label: "testLabel2", enabled: false, icon: "file:///testIcon2" },
368+ {label: "testLabel2", enabled: false, icon: "file:///testIcon2", color: Qt.rgba(1, 0, 0, 0),
369+ time: new Date(2015, 12, 31).getTime()*1000, timeFormat: "%A" },
362 ];
370 ];
363 }
371 }
364
372
@@ -367,6 +375,12 @@ Item {
367 menuData.label = data.label;
375 menuData.label = data.label;
368 menuData.sensitive = data.enabled;
376 menuData.sensitive = data.enabled;
369 menuData.icon = data.icon;
377 menuData.icon = data.icon;
378+ menuData.ext = {
379+ 'xCanonicalTime': data.time,
380+ 'xCanonicalTimeFormat': data.timeFormat
381+ };
382+ timeFormatter.format = data.timeFormat;
383+ timeFormatter.time = data.time;
370
384
371 loader.data = menuData;
385 loader.data = menuData;
372 loader.sourceComponent = factory.load(menuData);
386 loader.sourceComponent = factory.load(menuData);
@@ -375,13 +389,16 @@ Item {
375
389
376 compare(loader.item.text, data.label, "Label does not match data");
390 compare(loader.item.text, data.label, "Label does not match data");
377 compare(loader.item.iconSource, data.icon, "Icon does not match data");
391 compare(loader.item.iconSource, data.icon, "Icon does not match data");
392+ compare(loader.item.time, timeFormatter.timeString, "Time does not match data");
378 compare(loader.item.enabled, data.enabled, "Enabled does not match data");
393 compare(loader.item.enabled, data.enabled, "Enabled does not match data");
379 }
394 }
380
395
381 function test_create_appointmentMenu_data() {
396 function test_create_appointmentMenu_data() {
382 return [
397 return [
383− {label: "testLabel1", enabled: true, icon: "file:///testIcon1" },
398+ {label: "testLabel1", enabled: true, icon: "file:///testIcon1", color: Qt.rgba(0, 0, 0, 0),
399+ time: new Date(2014, 04, 14).getTime()*1000, timeFormat: "%a %d %b %l:%M %p"},
384− {label: "testLabel2", enabled: false, icon: "file:///testIcon2" },
400+ {label: "testLabel2", enabled: false, icon: "file:///testIcon2", color: Qt.rgba(1, 0, 0, 0),
401+ time: new Date(2015, 12, 31).getTime()*1000, timeFormat: "%A" },
385 ];
402 ];
386 }
403 }
387
404
@@ -390,6 +407,13 @@ Item {
390 menuData.label = data.label;
407 menuData.label = data.label;
391 menuData.sensitive = data.enabled;
408 menuData.sensitive = data.enabled;
392 menuData.icon = data.icon;
409 menuData.icon = data.icon;
410+ menuData.ext = {
411+ 'xCanonicalColor': data.colour,
412+ 'xCanonicalTime': data.time,
413+ 'xCanonicalTimeFormat': data.timeFormat
414+ };
415+ timeFormatter.format = data.timeFormat;
416+ timeFormatter.time = data.time;
393
417
394 loader.data = menuData;
418 loader.data = menuData;
395 loader.sourceComponent = factory.load(menuData);
419 loader.sourceComponent = factory.load(menuData);
@@ -398,6 +422,8 @@ Item {
398
422
399 compare(loader.item.text, data.label, "Label does not match data");
423 compare(loader.item.text, data.label, "Label does not match data");
400 compare(loader.item.iconSource, data.icon, "Icon does not match data");
424 compare(loader.item.iconSource, data.icon, "Icon does not match data");
425+ compare(loader.item.time, timeFormatter.timeString, "Time does not match data");
426+ compare(loader.item.eventColor, data.color, "Colour does not match data");
401 compare(loader.item.enabled, data.enabled, "Enabled does not match data");
427 compare(loader.item.enabled, data.enabled, "Enabled does not match data");
402 }
428 }
403
429
tests/qmltests/Panel/Indicators/tst_MessageMenuItemFactory.qml+1
@@ -39,6 +39,7 @@ Item {
39
39
40 UT.UnityTestCase {
40 UT.UnityTestCase {
41 name: "MessageMenuItemFactory"
41 name: "MessageMenuItemFactory"
42+ when: windowShown
42
43
43 property QtObject menuData: QtObject {
44 property QtObject menuData: QtObject {
44 property string label: "root"
45 property string label: "root"
tests/qmltests/tst_Shell.qml+11
@@ -554,5 +554,16 @@ Item {
554
554
555 tryCompare(searchIndicator, "opacity", 0);
555 tryCompare(searchIndicator, "opacity", 0);
556 }
556 }
557+
558+ function test_focusRequestedHidesGreeter() {
559+ var greeter = findChild(shell, "greeter")
560+
561+ greeter.show()
562+ tryCompare(greeter, "showProgress", 1)
563+
564+ ApplicationManager.focusRequested("notes-app")
565+ tryCompare(greeter, "showProgress", 0)
566+ waitUntilApplicationWindowIsFullyVisible()
567+ }
557 }
568 }
558}
569}