on xenial help sign in
merged with lp:~unity-team/unity8/installed-qmltests
eeb76c8Nick Dedekind
CMakeLists.txt+13−2
@@ -40,6 +40,19 @@ if(cmake_build_type_lower MATCHES coverage)
40 ENABLE_COVERAGE_REPORT(TARGETS ${SHELL_APP} FILTER /usr/include ${CMAKE_SOURCE_DIR}/tests/* ${CMAKE_BINARY_DIR}/*)
40 ENABLE_COVERAGE_REPORT(TARGETS ${SHELL_APP} FILTER /usr/include ${CMAKE_SOURCE_DIR}/tests/* ${CMAKE_BINARY_DIR}/*)
41endif()
41endif()
42
42
43+find_package (ECM 1.7.0 QUIET NO_MODULE)
44+if (ECM_FOUND)
45+ # Provides us with -DECM_ENABLE_SANITIZERS='X'
46+ # Where X can be address, thread, memory, leak, undefined
47+ include("${ECM_MODULE_DIR}/ECMEnableSanitizers.cmake")
48+endif()
49+
50+if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
51+ if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS "5.0.0")
52+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wsuggest-override" )
53+ endif()
54+endif()
55+
43# Make sure we have all the needed symbols
56# Make sure we have all the needed symbols
44set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,-z,defs")
57set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,-z,defs")
45set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} -Wl,-z,defs")
58set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} -Wl,-z,defs")
@@ -138,8 +151,6 @@ include_directories(
138 ${APPLICATION_API_INCLUDE_DIRS}
151 ${APPLICATION_API_INCLUDE_DIRS}
139)
152)
140
153
141−set(ARTIFACTS_DIR "" CACHE PATH "Store test artifacts in this directory.")
142−
143# Quiet logger
154# Quiet logger
144set(QUIET_LOGGER OFF CACHE BOOL "Disable test output on stdout.")
155set(QUIET_LOGGER OFF CACHE BOOL "Disable test output on stdout.")
145if(NOT QUIET_LOGGER)
156if(NOT QUIET_LOGGER)
cmake/modules/QmlTest.cmake+182−11
@@ -55,6 +55,55 @@ function(add_qml_test PATH COMPONENT_NAME)
55endfunction()
55endfunction()
56
56
57
57
58+# add_qml_test_data(path component_name
59+# [...]
60+# )
61+#
62+# Install file called ${component_name} (or ${component_name}.qml) under
63+# ${path}.
64+
65+function(add_qml_test_data PATH COMPONENT_NAME)
66+ cmake_parse_arguments(TEST "" "DESTINATION" "" ${ARGN})
67+
68+ set(filename "${CMAKE_CURRENT_SOURCE_DIR}/${PATH}/${COMPONENT_NAME}")
69+
70+ if (IS_DIRECTORY "${filename}")
71+ # As a convenience, allow specifying a directory and we will install
72+ # all files in the dir. We do it this way rather than passing
73+ # DIRECTORY to install() because we want to process any qml files.
74+ file(GLOB subfiles RELATIVE "${filename}" "${filename}/*")
75+ foreach(subfile ${subfiles})
76+ add_qml_test_data("${PATH}/${COMPONENT_NAME}" "${subfile}")
77+ endforeach()
78+ return()
79+ endif()
80+
81+ if (NOT EXISTS "${filename}")
82+ set(filename "${filename}.qml")
83+ set(COMPONENT_NAME "${COMPONENT_NAME}.qml")
84+ endif()
85+
86+ if ("${filename}" MATCHES "\\.qml$")
87+ file(READ "${filename}" contents)
88+ string(REGEX REPLACE "(\"[./]*)/qml(/|\")" "\\1\\2" contents "${contents}")
89+ # this is for (at least) cardcreatortest which pulls in an architecture-specific
90+ # import into the plugins directory (which is a 'qml' once installed).
91+ string(REGEX REPLACE "(import \"[./]*)/plugins(/|\")" "\\1/qml\\2" contents "${contents}")
92+ set(filename "${CMAKE_CURRENT_BINARY_DIR}/${PATH}/${COMPONENT_NAME}")
93+ file(WRITE "${filename}" "${contents}")
94+ endif()
95+
96+ if (TEST_DESTINATION)
97+ set(DESTINATION "${TEST_DESTINATION}")
98+ else()
99+ file(RELATIVE_PATH relcurpath "${CMAKE_SOURCE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}")
100+ set(DESTINATION "${SHELL_APP_DIR}/${relcurpath}/${PATH}")
101+ endif()
102+
103+ install(FILES "${filename}" DESTINATION "${DESTINATION}")
104+endfunction()
105+
106+
58# add_qml_unittest(path component_name
107# add_qml_unittest(path component_name
59# [...]
108# [...]
60# )
109# )
@@ -71,6 +120,10 @@ function(add_qml_unittest PATH COMPONENT_NAME)
71 ${ARGN}
120 ${ARGN}
72 ARGS -input ${CMAKE_CURRENT_SOURCE_DIR}/${PATH}/tst_${COMPONENT_NAME}.qml ${QMLTEST_ARGS}
121 ARGS -input ${CMAKE_CURRENT_SOURCE_DIR}/${PATH}/tst_${COMPONENT_NAME}.qml ${QMLTEST_ARGS}
73 )
122 )
123+
124+ if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${PATH}/tst_${COMPONENT_NAME}.qml")
125+ add_qml_test_data("${PATH}" "tst_${COMPONENT_NAME}.qml")
126+ endif()
74endfunction()
127endfunction()
75
128
76
129
@@ -91,6 +144,10 @@ function(add_manual_qml_test PATH COMPONENT_NAME)
91 ${ARGN}
144 ${ARGN}
92 ARGS ${CMAKE_CURRENT_SOURCE_DIR}/${PATH}/tst_${COMPONENT_NAME}.qml ${QMLTEST_ARGS}
145 ARGS ${CMAKE_CURRENT_SOURCE_DIR}/${PATH}/tst_${COMPONENT_NAME}.qml ${QMLTEST_ARGS}
93 )
146 )
147+
148+ if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${PATH}/tst_${COMPONENT_NAME}.qml")
149+ add_qml_test_data("${PATH}" "tst_${COMPONENT_NAME}.qml")
150+ endif()
94endfunction()
151endfunction()
95
152
96
153
@@ -108,8 +165,7 @@ endfunction()
108#
165#
109# Logging options in the standard form of "-o filename,format"
166# Logging options in the standard form of "-o filename,format"
110# will be appended to the arguments list, prefixed with ARG_PREFIX.
167# will be appended to the arguments list, prefixed with ARG_PREFIX.
111−# XUnitXML files will be stored in current binary dir or under
168+# XUnitXML files will be stored in current binary dir.
112−# ARTIFACTS_DIR, if set.
113#
169#
114# Three targets will be created:
170# Three targets will be created:
115# - test${component_name} - Runs the test
171# - test${component_name} - Runs the test
@@ -122,14 +178,8 @@ function(add_executable_test COMPONENT_NAME TARGET)
122 cmake_parse_arguments(QMLTEST "${QMLTEST_OPTIONS}" "${QMLTEST_SINGLE}" "${QMLTEST_MULTI}" ${ARGN})
178 cmake_parse_arguments(QMLTEST "${QMLTEST_OPTIONS}" "${QMLTEST_SINGLE}" "${QMLTEST_MULTI}" ${ARGN})
123 mangle_arguments()
179 mangle_arguments()
124
180
125− if(ARTIFACTS_DIR)
181+ file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
126− file(RELATIVE_PATH path ${CMAKE_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR})
127− file(MAKE_DIRECTORY ${ARTIFACTS_DIR}/${path})
128− set(file_logger -o ${ARTIFACTS_DIR}/${path}/test${COMPONENT_NAME}.xml,xunitxml)
129− else()
130− file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
131− set(file_logger -o ${CMAKE_CURRENT_BINARY_DIR}/test${COMPONENT_NAME}.xml,xunitxml)
182+ set(file_logger -o ${CMAKE_CURRENT_BINARY_DIR}/test${COMPONENT_NAME}.xml,xunitxml)
132− endif()
133
183
134 bake_arguments("${QMLTEST_ARG_PREFIX}" args ${iterations} ${file_logger} ${STDOUT_LOGGER})
184 bake_arguments("${QMLTEST_ARG_PREFIX}" args ${iterations} ${file_logger} ${STDOUT_LOGGER})
135
185
@@ -207,8 +257,124 @@ function(add_manual_test COMPONENT_NAME TARGET)
207endfunction()
257endfunction()
208
258
209
259
260+# add_meta_test(target)
261+#
262+# Adds a test target that will run one of our "meta" test targets, like
263+# xvfbuitests. This script will run the specified suite of tests on an
264+# installed system.
265+
266+function(add_meta_test TARGET_NAME)
267+ cmake_parse_arguments(TEST "" "" "DEPENDS" ${ARGN})
268+
269+ add_custom_target(${TARGET_NAME})
270+
271+ set(filename "${CMAKE_BINARY_DIR}/tests/scripts/${TARGET_NAME}.sh")
272+ file(WRITE "${filename}" "#!/usr/bin/parallel --shebang --no-notice\n\n")
273+
274+ add_meta_dependencies(${TARGET_NAME} DEPENDS ${TEST_DEPENDS})
275+ # else we will write the rest of the script as we add cmake targets
276+
277+ install(FILES "${filename}"
278+ PERMISSIONS OWNER_EXECUTE OWNER_READ OWNER_WRITE
279+ GROUP_EXECUTE GROUP_READ
280+ WORLD_EXECUTE WORLD_READ
281+ DESTINATION "${SHELL_PRIVATE_LIBDIR}/tests/scripts"
282+ )
283+endfunction()
284+
285+
210################### INTERNAL ####################
286################### INTERNAL ####################
211
287
288+function(install_test_script TARGET_NAME)
289+ cmake_parse_arguments(TEST "" "" "COMMAND;ENVIRONMENT" ${ARGN})
290+
291+ # Now write the above test into a shell script that we can run on an
292+ # installed system.
293+ set(script "#!/bin/sh\n\nset -x\n\n")
294+ foreach(ONE_ENV ${TEST_ENVIRONMENT})
295+ set(script "${script}export ${ONE_ENV}\n")
296+ endforeach()
297+ set(script "${script}export UNITY_TESTING_DATADIR=\"${CMAKE_INSTALL_PREFIX}/${SHELL_APP_DIR}\"\n")
298+ set(script "${script}export UNITY_TESTING_LIBDIR=\"${CMAKE_INSTALL_PREFIX}/${SHELL_PRIVATE_LIBDIR}\"\n")
299+ set(script "${script}\n")
300+ set(script "${script}XML_ARGS=\n")
301+ set(script "${script}if [ -n \"\$ARTIFACTS_DIR\" ]; then\n")
302+ set(script "${script} XML_ARGS=\"@XML_ARGS@\"\n")
303+ set(script "${script} mkdir -p \"@XML_DIR@\"\n")
304+ set(script "${script} touch \"@XML_FILE@\"\n")
305+ set(script "${script}fi\n")
306+ set(script "${script}\n")
307+ foreach(ONE_CMD ${TEST_COMMAND})
308+ set(script "${script}'${ONE_CMD}' ")
309+ endforeach()
310+
311+ set(filename "${CMAKE_BINARY_DIR}/tests/scripts/${TARGET_NAME}.sh")
312+
313+ # Generate script to file then read it back to resolve any generator
314+ # expressions before we try to replace paths.
315+ file(GENERATE
316+ OUTPUT "${filename}"
317+ CONTENT "${script}"
318+ )
319+
320+ # Do replacement at install time to save needless work and to make sure
321+ # we are modifying file after generate step above (which doesn't happen
322+ # immediately). We can't use a custom-defined function or macro here...
323+ # So instead we use a giant ugly code block.
324+
325+ # START OF CODE BLOCK --------------------------------------------------
326+ install(CODE "
327+ file(READ \"${filename}\" replacestr)
328+
329+ # Now some replacements...
330+ # tests like to write xml output to our builddir; we don't need that, but we do want them in ARTIFACTS_DIR
331+ string(REGEX MATCH \"( '--parameter')? '-o'( '--parameter')? '[^']*,xunitxml' \" xmlargs \"\${replacestr}\")
332+ string(REGEX REPLACE \"( '--parameter')? '-o'( '--parameter')? '[^']*,xunitxml' \" \" \\\$XML_ARGS \" replacestr \"\${replacestr}\")
333+ string(REGEX REPLACE \"'[^']*/tests/\" \"'\\\$ARTIFACTS_DIR/tests/\" xmlargs \"\${xmlargs}\")
334+ string(REGEX REPLACE \".*'([^']*),xunitxml'.*\" \"\\\\1\" xmlfile \"\${xmlargs}\")
335+ string(REGEX REPLACE \"(.*)/[^/]*\" \"\\\\1\" xmldir \"\${xmlfile}\")
336+ string(REGEX REPLACE \"'\" \"\" xmlargs \"\${xmlargs}\") # strip single quotes
337+ string(REGEX REPLACE \"@XML_ARGS@\" \"\${xmlargs}\" replacestr \"\${replacestr}\")
338+ string(REGEX REPLACE \"@XML_DIR@\" \"\${xmldir}\" replacestr \"\${replacestr}\")
339+ string(REGEX REPLACE \"@XML_FILE@\" \"\${xmlfile}\" replacestr \"\${replacestr}\")
340+ # replace build/source roots with their install paths
341+ string(REPLACE \"${CMAKE_BINARY_DIR}/libs\" \"${CMAKE_INSTALL_PREFIX}/${SHELL_PRIVATE_LIBDIR}\" replacestr \"\${replacestr}\")
342+ string(REPLACE \"${CMAKE_BINARY_DIR}/plugins\" \"${CMAKE_INSTALL_PREFIX}/${SHELL_INSTALL_QML}\" replacestr \"\${replacestr}\")
343+ string(REPLACE \"${CMAKE_BINARY_DIR}/tests/libs\" \"${CMAKE_INSTALL_PREFIX}/${SHELL_PRIVATE_LIBDIR}/tests/libs\" replacestr \"\${replacestr}\")
344+ string(REPLACE \"${CMAKE_BINARY_DIR}/tests/mocks\" \"${CMAKE_INSTALL_PREFIX}/${SHELL_INSTALL_QML}/mocks\" replacestr \"\${replacestr}\")
345+ string(REPLACE \"${CMAKE_BINARY_DIR}/tests/plugins\" \"${CMAKE_INSTALL_PREFIX}/${SHELL_PRIVATE_LIBDIR}/tests/plugins\" replacestr \"\${replacestr}\")
346+ string(REPLACE \"${CMAKE_BINARY_DIR}/tests/qmltests\" \"${CMAKE_INSTALL_PREFIX}/${SHELL_PRIVATE_LIBDIR}/tests/qmltests\" replacestr \"\${replacestr}\")
347+ string(REPLACE \"${CMAKE_BINARY_DIR}/tests/uqmlscene\" \"${CMAKE_INSTALL_PREFIX}/${SHELL_PRIVATE_LIBDIR}\" replacestr \"\${replacestr}\")
348+ string(REPLACE \"${CMAKE_BINARY_DIR}/tests/utils/modules\" \"${CMAKE_INSTALL_PREFIX}/${SHELL_INSTALL_QML}/utils\" replacestr \"\${replacestr}\")
349+ string(REPLACE \"${CMAKE_SOURCE_DIR}/tests/plugins\" \"${CMAKE_INSTALL_PREFIX}/${SHELL_APP_DIR}/tests/plugins\" replacestr \"\${replacestr}\")
350+ string(REPLACE \"${CMAKE_SOURCE_DIR}/tests/qmltests\" \"${CMAKE_INSTALL_PREFIX}/${SHELL_APP_DIR}/tests/qmltests\" replacestr \"\${replacestr}\")
351+
352+ file(WRITE \"${filename}\" \"\${replacestr}\")
353+ ")
354+ # END OF CODE BLOCK --------------------------------------------------
355+
356+ install(FILES "${filename}"
357+ PERMISSIONS OWNER_EXECUTE OWNER_READ OWNER_WRITE
358+ GROUP_EXECUTE GROUP_READ
359+ WORLD_EXECUTE WORLD_READ
360+ DESTINATION "${SHELL_PRIVATE_LIBDIR}/tests/scripts"
361+ )
362+endfunction()
363+
364+function(add_meta_dependencies UPSTREAM_TARGET)
365+ cmake_parse_arguments(TEST "" "" "DEPENDS" ${ARGN})
366+
367+ foreach(depend ${TEST_DEPENDS})
368+ add_dependencies(${UPSTREAM_TARGET} ${depend})
369+
370+ # add depend to the meta test script that we will install on system
371+ set(filename "${CMAKE_BINARY_DIR}/tests/scripts/${UPSTREAM_TARGET}.sh")
372+ if (EXISTS "${filename}")
373+ file(APPEND "${filename}" "${CMAKE_INSTALL_PREFIX}/${SHELL_PRIVATE_LIBDIR}/tests/scripts/${depend}.sh\n")
374+ endif()
375+ endforeach()
376+endfunction()
377+
212# add_qmltest_target(target_name target
378# add_qmltest_target(target_name target
213# COMMAND test_exe [arg1 [...]] # execute this test with arguments
379# COMMAND test_exe [arg1 [...]] # execute this test with arguments
214# [...] # see above for available arguments:
380# [...] # see above for available arguments:
@@ -231,6 +397,11 @@ function(add_qmltest_target TARGET_NAME TARGET)
231 DEPENDS ${TARGET} ${QMLTEST_DEPENDS}
397 DEPENDS ${TARGET} ${QMLTEST_DEPENDS}
232 )
398 )
233
399
400+ install_test_script(${TARGET_NAME}
401+ ENVIRONMENT ${QMLTEST_ENVIRONMENT}
402+ COMMAND ${QMLTEST_COMMAND}
403+ )
404+
234 if(QMLTEST_ADD_TEST)
405 if(QMLTEST_ADD_TEST)
235 add_test(
406 add_test(
236 NAME ${TARGET_NAME}
407 NAME ${TARGET_NAME}
@@ -248,7 +419,7 @@ function(add_qmltest_target TARGET_NAME TARGET)
248 endif()
419 endif()
249
420
250 foreach(UPSTREAM_TARGET ${QMLTEST_TARGETS})
421 foreach(UPSTREAM_TARGET ${QMLTEST_TARGETS})
251− add_dependencies(${UPSTREAM_TARGET} ${TARGET_NAME})
422+ add_meta_dependencies(${UPSTREAM_TARGET} DEPENDS ${TARGET_NAME})
252 endforeach()
423 endforeach()
253endfunction()
424endfunction()
254
425
data/com.canonical.Unity8.gschema.xml+2−2
@@ -12,7 +12,7 @@
12 <description>The usage mode chosen will affect the Window Management behaviour.</description>
12 <description>The usage mode chosen will affect the Window Management behaviour.</description>
13 </key>
13 </key>
14 <key type="y" name="edge-barrier-sensitivity">
14 <key type="y" name="edge-barrier-sensitivity">
15− <default>35</default>
15+ <default>50</default>
16 <range min="1" max="100"/>
16 <range min="1" max="100"/>
17 <summary>Sensitivity of screen edge barriers for the mouse pointer.</summary>
17 <summary>Sensitivity of screen edge barriers for the mouse pointer.</summary>
18 <description>Some UI actions like revealing the launcher or the applications spread are triggered by pushing the mouse pointer against a screen edge. This key defines how much you have to push in order to trigger the associated action.</description>
18 <description>Some UI actions like revealing the launcher or the applications spread are triggered by pushing the mouse pointer against a screen edge. This key defines how much you have to push in order to trigger the associated action.</description>
@@ -23,7 +23,7 @@
23 <description>How much you have to push (in grid units)the mouse against an edge barrier when sensibility is 100.</description>
23 <description>How much you have to push (in grid units)the mouse against an edge barrier when sensibility is 100.</description>
24 </key>
24 </key>
25 <key type="u" name="edge-barrier-max-push">
25 <key type="u" name="edge-barrier-max-push">
26− <default>60</default>
26+ <default>120</default>
27 <summary>Maximum push needed to overcome edge barrier</summary>
27 <summary>Maximum push needed to overcome edge barrier</summary>
28 <description>How much you have to push (in grid units) the mouse against an edge barrier when sensibility is 1.</description>
28 <description>How much you have to push (in grid units) the mouse against an edge barrier when sensibility is 1.</description>
29 </key>
29 </key>
debian/changelog+33
@@ -1,3 +1,36 @@
1+unity8 (8.15+17.04.20161207.1-0ubuntu1) zesty; urgency=medium
2+
3+ [ Albert Astals Cid ]
4+ * Add the Wsuggest-override flag to gcc
5+ * Add support for compiler sanitizers via ECM
6+ * Use timeStep as delay time (LP: #1642919)
7+ * Bring back fix for 1517830 (LP: #1517830)
8+ * Fix compile warnings in mocks
9+ * Do not hide panel when launching an application if the mouse is on
10+ the panel (LP: #1591311)
11+
12+ [ Daniel d'Andrada ]
13+ * Fix "make tryApplicationWindow"
14+ * Take save/restore functions out of WindowResizeArea
15+
16+ [ Josh Arenson ]
17+ * Enable the greeter to remember which session the user last logged
18+ into (LP: #1631365)
19+
20+ [ Lukáš Tinkl ]
21+ * Fix the Super key not invoking the dash scope home (LP: #1607427)
22+
23+ [ Michael Zanetti ]
24+ * Add the ApplicationDrawer
25+ * tune right edge push (LP: #1646094)
26+ * improve close button visiblity when hovering with the mouse
27+ * Update virtual touchpad visuals and add a tutorial. (LP: #1585220)
28+
29+ [ Pete Woods ]
30+ * MenuItemFactory: Add subtitle support to SwitchItem widget
31+
32+ -- Michał Sawicz <michal.sawicz@canonical.com> Wed, 07 Dec 2016 13:49:24 +0000
33+
1unity8 (8.15+17.04.20161129-0ubuntu1) zesty; urgency=medium
34unity8 (8.15+17.04.20161129-0ubuntu1) zesty; urgency=medium
2
35
3 [ Albert Astals Cid ]
36 [ Albert Astals Cid ]
debian/control+22−9
@@ -11,6 +11,7 @@ Build-Depends: cmake,
11# to g++ so we don't try to run arm g++
11# to g++ so we don't try to run arm g++
12# on an x86 CPU for example, when cross-compiling.
12# on an x86 CPU for example, when cross-compiling.
13 g++:native,
13 g++:native,
14+ gdb,
14 graphviz,
15 graphviz,
15 gsettings-ubuntu-schemas (>= 0.0.2+14.10.20140815),
16 gsettings-ubuntu-schemas (>= 0.0.2+14.10.20140815),
16 libandroid-properties-dev,
17 libandroid-properties-dev,
@@ -38,7 +39,7 @@ Build-Depends: cmake,
38 libubuntugestures5-private-dev (>= 1.3.2030),
39 libubuntugestures5-private-dev (>= 1.3.2030),
39 libudev-dev,
40 libudev-dev,
40 libudm-common-dev,
41 libudm-common-dev,
41− libunity-api-dev (>= 7.120),
42+ libunity-api-dev (>= 7.121),
42 libusermetricsoutput1-dev,
43 libusermetricsoutput1-dev,
43# Need those X11 libs touch emulation from mouse events in manual QML tests on a X11 desktop
44# Need those X11 libs touch emulation from mouse events in manual QML tests on a X11 desktop
44 libx11-dev[!arm64 !armhf],
45 libx11-dev[!arm64 !armhf],
@@ -49,6 +50,7 @@ Build-Depends: cmake,
49 python3-all:any,
50 python3-all:any,
50 python3-setuptools,
51 python3-setuptools,
51 qml-module-qt-labs-folderlistmodel,
52 qml-module-qt-labs-folderlistmodel,
53+ qml-module-qt-labs-settings,
52 qml-module-qtqml-statemachine,
54 qml-module-qtqml-statemachine,
53 qml-module-qtmultimedia (>= 5.4.1-1ubuntu19~overlay2),
55 qml-module-qtmultimedia (>= 5.4.1-1ubuntu19~overlay2),
54 qml-module-qtquick-layouts,
56 qml-module-qtquick-layouts,
@@ -68,6 +70,7 @@ Build-Depends: cmake,
68 qtdeclarative5-ubuntu-content1,
70 qtdeclarative5-ubuntu-content1,
69 qtdeclarative5-ubuntu-settings-components (>= 0.11),
71 qtdeclarative5-ubuntu-settings-components (>= 0.11),
70 ttf-ubuntu-font-family,
72 ttf-ubuntu-font-family,
73+ xvfb,
71Standards-Version: 3.9.4
74Standards-Version: 3.9.4
72Homepage: http://launchpad.net/unity
75Homepage: http://launchpad.net/unity
73# If you aren't a member of ~unity-team but need to upload
76# If you aren't a member of ~unity-team but need to upload
@@ -122,6 +125,7 @@ Depends: dmz-cursor-theme,
122 qmenumodel-qml (>= 0.2.10),
125 qmenumodel-qml (>= 0.2.10),
123 qml-module-biometryd,
126 qml-module-biometryd,
124 qml-module-qt-labs-folderlistmodel,
127 qml-module-qt-labs-folderlistmodel,
128+ qml-module-qt-labs-settings,
125 qml-module-qtqml-statemachine,
129 qml-module-qtqml-statemachine,
126 qml-module-qtquick-xmllistmodel,
130 qml-module-qtquick-xmllistmodel,
127 qml-module-qtsysteminfo,
131 qml-module-qtsysteminfo,
@@ -164,7 +168,7 @@ Depends: qml-module-qtquick-layouts,
164 unity-notifications-impl-3,
168 unity-notifications-impl-3,
165 unity-plugin-scopes | unity-scopes-impl,
169 unity-plugin-scopes | unity-scopes-impl,
166 unity-scopes-impl-12,
170 unity-scopes-impl-12,
167− unity8-fake-env | unity-application-impl,
171+ unity8-tests | unity-application-impl,
168 ${misc:Depends},
172 ${misc:Depends},
169Breaks: unity8 (<< 7.86),
173Breaks: unity8 (<< 7.86),
170Replaces: unity8 (<< 7.86),
174Replaces: unity8 (<< 7.86),
@@ -190,27 +194,36 @@ Depends: autopilot-qt5 (>= 1.4),
190 ubuntu-ui-toolkit-autopilot (>= 1.3.2030),
194 ubuntu-ui-toolkit-autopilot (>= 1.3.2030),
191 unity-scope-click,
195 unity-scope-click,
192 unity8 (= ${source:Version}),
196 unity8 (= ${source:Version}),
193− unity8-fake-env (= ${source:Version}),
197+ unity8-tests (= ${source:Version}),
194 url-dispatcher-tools,
198 url-dispatcher-tools,
195 xvfb,
199 xvfb,
196 ${misc:Depends},
200 ${misc:Depends},
197 ${python3:Depends},
201 ${python3:Depends},
198− ${shlibs:Depends},
199Description: Test package for Unity 8 shell
202Description: Test package for Unity 8 shell
200 Autopilot tests for the unity8 package
203 Autopilot tests for the unity8 package
201
204
202−Package: unity8-fake-env
205+Package: unity8-tests
203Architecture: any
206Architecture: any
204Multi-Arch: same
207Multi-Arch: same
205Pre-Depends: ${misc:Pre-Depends},
208Pre-Depends: ${misc:Pre-Depends},
209+Depends: dbus-test-runner,
210+ parallel,
211+ qt5-default,
212+ qtdeclarative5-dev-tools,
213+ unity8 (= ${source:Version}),
214+ xvfb,
206−Depends: ${misc:Depends},
215+ ${misc:Depends},
207 ${shlibs:Depends},
216 ${shlibs:Depends},
208Provides: unity-application-impl,
217Provides: unity-application-impl,
209 unity-application-impl-22,
218 unity-application-impl-22,
219+ unity8-fake-env,
210−Replaces: unity8-autopilot (<< 8.02+15.04.20150422-0ubuntu1)
220+Replaces: unity8-autopilot (<< 8.02+15.04.20150422-0ubuntu1),
221+ unity8-fake-env,
222+Conflicts: unity8-fake-env,
211−Description: Fake environment for running Unity 8 shell
223+Description: Scripts and mocks for running Unity 8 shell tests
212 Provides fake implementations of some QML modules used by Unity 8 shell
224 Provides fake implementations of some QML modules used by Unity 8 shell
213− (e.g Ubuntu.Application) so that you can run it in a sandboxed environment.
225+ (e.g Ubuntu.Application) so that you can run it in a sandboxed environment
226+ and scripts to run its test suite.
214
227
215Package: unity8-private
228Package: unity8-private
216Architecture: any
229Architecture: any
debian/rules+2−2
@@ -35,9 +35,9 @@ override_dh_installdeb:
35
35
36# use private lib directories
36# use private lib directories
37override_dh_makeshlibs:
37override_dh_makeshlibs:
38− dh_makeshlibs -Nunity8-private -Nunity8-fake-env
38+ dh_makeshlibs -Nunity8-private -Nunity8-tests
39
39
40override_dh_shlibdeps:
40override_dh_shlibdeps:
41 # Some mock libraries link against liblightdm-qt5-3.so which we want to
41 # Some mock libraries link against liblightdm-qt5-3.so which we want to
42 # avoid, since we only really link against our mock one, not the system one.
42 # avoid, since we only really link against our mock one, not the system one.
43− dh_shlibdeps -XlibMockLightDM-qml.so -XlibMockAccountsService-qml.so
43+ dh_shlibdeps -XlibMockLightDM-qml.so -XlibMockAccountsService-qml.so -Lunity8-private
debian/shlibs.localnew file+1
@@ -0,0 +1 @@
1+libunity8-private 0 unity8-private
debian/tests/control+2−3
@@ -1,8 +1,7 @@
1Tests: qmluitests.sh
1Tests: qmluitests.sh
2Restrictions: allow-stderr
2Restrictions: allow-stderr
3−Depends: @,
3+Depends: dpkg-dev,
4− @builddeps@,
4+ unity8-tests,
5− xvfb,
6
5
7Tests: autopilot.sh
6Tests: autopilot.sh
8Restrictions: allow-stderr,
7Restrictions: allow-stderr,
debian/tests/qmluitests.sh+4−14
@@ -1,21 +1,11 @@
1#!/bin/sh
1#!/bin/sh
2+# -*- Mode: sh; indent-tabs-mode: nil; tab-width: 4 -*-
2
3
3# log all commands and abort on error
4# log all commands and abort on error
4set -xe
5set -xe
5
6
6−SHELL_QML_PATH=$(pkg-config --variable=plugindir unity-shell-api)
7+DEB_HOST_MULTIARCH=$(dpkg-architecture -qDEB_HOST_MULTIARCH)
7−UNITY_SOURCE_DIR=$(readlink -f $(dirname $(readlink -f $0))/../..)
8
8
9−dh_auto_configure -- -DCMAKE_INSTALL_LOCALSTATEDIR="/var" \
10− -DARTIFACTS_DIR=${ADT_ARTIFACTS} \
9+export ARTIFACTS_DIR="${ADT_ARTIFACTS}"
11− -DUNITY_PLUGINPATH=${SHELL_QML_PATH} \
12− -DUNITY_MOCKPATH=${SHELL_QML_PATH}/mocks
13−dh_auto_build --parallel -- -C tests/mocks
14−dh_auto_build --parallel -- -C tests/plugins
15−dh_auto_build --parallel -- -C tests/qmltests
16−dh_auto_build --parallel -- -C tests/uqmlscene
17−dh_auto_build --parallel -- -C tests/utils
18
10
19−export UNITY_SOURCE_DIR
11+/usr/lib/$DEB_HOST_MULTIARCH/unity8/tests/scripts/xvfballtests.sh
20−
21−dh_auto_build --parallel -- -k xvfballtests
debian/unity8-fake-env.install → debian/unity8-tests.installrenamed+4
@@ -3,4 +3,8 @@ usr/bin/unity-mock-indicator-service
3usr/lib/*/unity8/qml/mocks
3usr/lib/*/unity8/qml/mocks
4usr/lib/*/unity8/qml/nonmirplugins
4usr/lib/*/unity8/qml/nonmirplugins
5usr/lib/*/unity8/qml/scopefakes
5usr/lib/*/unity8/qml/scopefakes
6+usr/lib/*/unity8/qml/utils
7+usr/lib/*/unity8/tests
8+usr/lib/*/unity8/uqmlscene
6usr/share/unity8/mocks
9usr/share/unity8/mocks
10+usr/share/unity8/tests
debian/unity8-tests.lintian-overridesnew file+1
@@ -0,0 +1 @@
1+unity8-tests: unusual-interpreter usr/lib/*/unity8/tests/scripts/*.sh #!/usr/bin/parallel
include/paths.h.in+26−1
@@ -41,7 +41,10 @@ inline QString installRoot() {
41}
41}
42
42
43inline bool isRunningInstalled() {
43inline bool isRunningInstalled() {
44+ // Tests don't use the normal binary, so we want to check binary *and*
45+ // the environment. Installed tests have UNITY_TESTING_DATADIR set.
46+ static bool installed_test_env = !qgetenv("UNITY_TESTING_DATADIR").isEmpty();
44− return !installRoot().isNull();
47+ return !installRoot().isNull() || installed_test_env;
45}
48}
46
49
47inline QString buildDirectory() {
50inline QString buildDirectory() {
@@ -62,6 +65,28 @@ inline QString translationDirectory() {
62 }
65 }
63}
66}
64
67
68+inline QString testDataDir() {
69+ // Can't use isRunningInstalled, since tests don't use the normal unity8
70+ // executable. $UNITY_TESTING_DATADIR is set by installed tests.
71+ QString datadir(qgetenv("UNITY_TESTING_DATADIR"));
72+ if (datadir.isEmpty()) {
73+ return sourceDirectory() + "/tests";
74+ } else {
75+ return datadir + "/tests";
76+ }
77+}
78+
79+inline QString testLibDir() {
80+ // Can't use isRunningInstalled, since tests don't use the normal unity8
81+ // executable. $UNITY_TESTING_DATADIR is set by installed tests.
82+ QString libdir(qgetenv("UNITY_TESTING_LIBDIR"));
83+ if (libdir.isEmpty()) {
84+ return buildDirectory() + "/tests";
85+ } else {
86+ return libdir + "/tests";
87+ }
88+}
89+
65inline QString qmlDirectory() {
90inline QString qmlDirectory() {
66 if (isRunningInstalled()) {
91 if (isRunningInstalled()) {
67 return installRoot() + QStringLiteral("@CMAKE_INSTALL_PREFIX@/@SHELL_APP_DIR@/");
92 return installRoot() + QStringLiteral("@CMAKE_INSTALL_PREFIX@/@SHELL_APP_DIR@/");
plugins/Greeter/Unity/Launcher/CMakeLists.txt+1−1
@@ -1,4 +1,4 @@
1−pkg_check_modules(LAUNCHER_API REQUIRED unity-shell-launcher=10)
1+pkg_check_modules(LAUNCHER_API REQUIRED unity-shell-launcher=11)
2pkg_check_modules(GSETTINGS_QT REQUIRED gsettings-qt)
2pkg_check_modules(GSETTINGS_QT REQUIRED gsettings-qt)
3
3
4add_definitions(-DSM_BUSNAME=systemBus)
4add_definitions(-DSM_BUSNAME=systemBus)
plugins/Greeter/Unity/Launcher/launcheritem.cpp+13
@@ -76,6 +76,19 @@ void LauncherItem::setIcon(const QString &icon)
76 }
76 }
77}
77}
78
78
79+QStringList LauncherItem::keywords() const
80+{
81+ return m_keywords;
82+}
83+
84+void LauncherItem::setKeywords(const QStringList &keywords)
85+{
86+ if (m_keywords != keywords) {
87+ m_keywords = keywords;
88+ Q_EMIT keywordsChanged(keywords);
89+ }
90+}
91+
79bool LauncherItem::pinned() const
92bool LauncherItem::pinned() const
80{
93{
81 return m_pinned;
94 return m_pinned;
plugins/Greeter/Unity/Launcher/launcheritem.h+3
@@ -34,6 +34,7 @@ public:
34 QString appId() const override;
34 QString appId() const override;
35 QString name() const override;
35 QString name() const override;
36 QString icon() const override;
36 QString icon() const override;
37+ QStringList keywords() const override;
37 bool pinned() const override;
38 bool pinned() const override;
38 bool running() const override;
39 bool running() const override;
39 bool recent() const override;
40 bool recent() const override;
@@ -49,6 +50,7 @@ public:
49private:
50private:
50 void setName(const QString &name);
51 void setName(const QString &name);
51 void setIcon(const QString &icon);
52 void setIcon(const QString &icon);
53+ void setKeywords(const QStringList &keywords);
52 void setPinned(bool pinned);
54 void setPinned(bool pinned);
53 void setRunning(bool running);
55 void setRunning(bool running);
54 void setRecent(bool recent);
56 void setRecent(bool recent);
@@ -63,6 +65,7 @@ private:
63 QString m_appId;
65 QString m_appId;
64 QString m_name;
66 QString m_name;
65 QString m_icon;
67 QString m_icon;
68+ QStringList m_keywords;
66 bool m_pinned;
69 bool m_pinned;
67 bool m_running;
70 bool m_running;
68 bool m_recent;
71 bool m_recent;
plugins/LightDM/FullLightDM/CMakeLists.txt+5−1
@@ -6,10 +6,14 @@ add_definitions(-DFULL_LIGHTDM)
6
6
7include_directories(
7include_directories(
8 ../
8 ../
9− ${LIBLIGHTDM_INCLUDE_DIRS}
10 ${CMAKE_CURRENT_BINARY_DIR}
9 ${CMAKE_CURRENT_BINARY_DIR}
11 )
10 )
12
11
12+include_directories(
13+ SYSTEM
14+ ${LIBLIGHTDM_INCLUDE_DIRS}
15+ )
16+
13foreach(source_file ${QMLPLUGIN_SRC})
17foreach(source_file ${QMLPLUGIN_SRC})
14 list(APPEND RELATIVE_QMLPLUGIN_SRC ../${source_file})
18 list(APPEND RELATIVE_QMLPLUGIN_SRC ../${source_file})
15endforeach()
19endforeach()
plugins/Ubuntu/Gestures/CMakeLists.txt+1−1
@@ -16,7 +16,7 @@ pkg_check_modules(UBUNTUGESTURES REQUIRED UbuntuGestures)
16
16
17add_definitions(-DUBUNTUGESTURESQML_LIBRARY)
17add_definitions(-DUBUNTUGESTURESQML_LIBRARY)
18
18
19−add_library(UbuntuGesturesQml MODULE ${UbuntuGesturesQml_SOURCES})
19+add_library(UbuntuGesturesQml SHARED ${UbuntuGesturesQml_SOURCES})
20target_link_libraries(UbuntuGesturesQml ${UBUNTUGESTURES_LIBRARIES})
20target_link_libraries(UbuntuGesturesQml ${UBUNTUGESTURES_LIBRARIES})
21
21
22qt5_use_modules(UbuntuGesturesQml Core Quick)
22qt5_use_modules(UbuntuGesturesQml Core Quick)
plugins/Unity/Indicators/CMakeLists.txt+3
@@ -11,6 +11,9 @@ include_directories(
11include_directories(
11include_directories(
12 SYSTEM
12 SYSTEM
13 ${GLIB_INCLUDE_DIRS}
13 ${GLIB_INCLUDE_DIRS}
14+)
15+include_directories(
16+ SYSTEM
14 ${GIO_INCLUDE_DIRS}
17 ${GIO_INCLUDE_DIRS}
15 ${QMENUMODEL_INCLUDE_DIRS}
18 ${QMENUMODEL_INCLUDE_DIRS}
16)
19)
plugins/Unity/Launcher/CMakeLists.txt+4−1
@@ -1,4 +1,4 @@
1−pkg_check_modules(LAUNCHER_API REQUIRED unity-shell-launcher=10)
1+pkg_check_modules(LAUNCHER_API REQUIRED unity-shell-launcher=11)
2pkg_check_modules(GSETTINGS_QT REQUIRED gsettings-qt)
2pkg_check_modules(GSETTINGS_QT REQUIRED gsettings-qt)
3
3
4add_definitions(-DSM_BUSNAME=systemBus)
4add_definitions(-DSM_BUSNAME=systemBus)
@@ -25,6 +25,8 @@ set(QMLLAUNCHERPLUGIN_SRC
25 dbusinterface.cpp
25 dbusinterface.cpp
26 gsettings.cpp
26 gsettings.cpp
27 asadapter.cpp
27 asadapter.cpp
28+ appdrawermodel.cpp
29+ ualwrapper.cpp
28 ${CMAKE_SOURCE_DIR}/plugins/AccountsService/AccountsServiceDBusAdaptor.cpp
30 ${CMAKE_SOURCE_DIR}/plugins/AccountsService/AccountsServiceDBusAdaptor.cpp
29 ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/ApplicationManagerInterface.h
31 ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/ApplicationManagerInterface.h
30 ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/ApplicationInfoInterface.h
32 ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/ApplicationInfoInterface.h
@@ -32,6 +34,7 @@ set(QMLLAUNCHERPLUGIN_SRC
32 ${LAUNCHER_API_INCLUDEDIR}/unity/shell/launcher/LauncherItemInterface.h
34 ${LAUNCHER_API_INCLUDEDIR}/unity/shell/launcher/LauncherItemInterface.h
33 ${LAUNCHER_API_INCLUDEDIR}/unity/shell/launcher/LauncherModelInterface.h
35 ${LAUNCHER_API_INCLUDEDIR}/unity/shell/launcher/LauncherModelInterface.h
34 ${LAUNCHER_API_INCLUDEDIR}/unity/shell/launcher/QuickListModelInterface.h
36 ${LAUNCHER_API_INCLUDEDIR}/unity/shell/launcher/QuickListModelInterface.h
37+ ${LAUNCHER_API_INCLUDEDIR}/unity/shell/launcher/AppDrawerModelInterface.h
35 )
38 )
36
39
37add_library(UnityLauncher-qml MODULE
40add_library(UnityLauncher-qml MODULE
plugins/Unity/Launcher/appdrawermodel.cppnew file+62
@@ -0,0 +1,62 @@
1+/*
2+ * Copyright (C) 2016 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+#include "appdrawermodel.h"
18+#include "ualwrapper.h"
19+
20+#include <QDebug>
21+#include <QDateTime>
22+
23+AppDrawerModel::AppDrawerModel(QObject *parent):
24+ AppDrawerModelInterface(parent)
25+{
26+ Q_FOREACH (const QString &appId, UalWrapper::installedApps()) {
27+ UalWrapper::AppInfo info = UalWrapper::getApplicationInfo(appId);
28+ if (!info.valid) {
29+ qWarning() << "Failed to get app info for app" << appId;
30+ continue;
31+ }
32+ m_list.append(new LauncherItem(appId, info.name, info.icon, this));
33+ m_list.last()->setKeywords(info.keywords);
34+ }
35+ qsrand(QDateTime::currentMSecsSinceEpoch() / 100);
36+}
37+
38+int AppDrawerModel::rowCount(const QModelIndex &parent) const
39+{
40+ Q_UNUSED(parent)
41+ return m_list.count();
42+}
43+
44+QVariant AppDrawerModel::data(const QModelIndex &index, int role) const
45+{
46+ switch (role) {
47+ case RoleAppId:
48+ return m_list.at(index.row())->appId();
49+ case RoleName:
50+ return m_list.at(index.row())->name();
51+ case RoleIcon:
52+ return m_list.at(index.row())->icon();
53+ case RoleKeywords:
54+ return m_list.at(index.row())->keywords();
55+ case RoleUsage:
56+ // FIXME: u-a-l needs to provide API for usage stats.
57+ // don't forget to drop the qsrand() call in the ctor when dropping this.
58+ return qrand();
59+ }
60+
61+ return QVariant();
62+}
plugins/Unity/Launcher/appdrawermodel.hnew file+33
@@ -0,0 +1,33 @@
1+/*
2+ * Copyright (C) 2016 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+
18+#include <unity/shell/launcher/AppDrawerModelInterface.h>
19+
20+#include "launcheritem.h"
21+
22+class AppDrawerModel: public AppDrawerModelInterface
23+{
24+ Q_OBJECT
25+public:
26+ AppDrawerModel(QObject* parent = nullptr);
27+
28+ int rowCount(const QModelIndex &parent) const override;
29+ QVariant data(const QModelIndex &index, int role) const override;
30+
31+private:
32+ QList<LauncherItem*> m_list;
33+};
plugins/Unity/Launcher/launcheritem.cpp+13
@@ -90,6 +90,19 @@ void LauncherItem::setIcon(const QString &icon)
90 }
90 }
91}
91}
92
92
93+QStringList LauncherItem::keywords() const
94+{
95+ return m_keywords;
96+}
97+
98+void LauncherItem::setKeywords(const QStringList &keywords)
99+{
100+ if (m_keywords != keywords) {
101+ m_keywords = keywords;
102+ Q_EMIT keywordsChanged(keywords);
103+ }
104+}
105+
93bool LauncherItem::pinned() const
106bool LauncherItem::pinned() const
94{
107{
95 return m_pinned;
108 return m_pinned;
plugins/Unity/Launcher/launcheritem.h+4
@@ -37,6 +37,7 @@ public:
37 QString appId() const override;
37 QString appId() const override;
38 QString name() const override;
38 QString name() const override;
39 QString icon() const override;
39 QString icon() const override;
40+ QStringList keywords() const override;
40 bool pinned() const override;
41 bool pinned() const override;
41 bool running() const override;
42 bool running() const override;
42 bool recent() const override;
43 bool recent() const override;
@@ -52,6 +53,7 @@ public:
52private:
53private:
53 void setName(const QString &name);
54 void setName(const QString &name);
54 void setIcon(const QString &icon);
55 void setIcon(const QString &icon);
56+ void setKeywords(const QStringList &keywords);
55 void setPinned(bool pinned);
57 void setPinned(bool pinned);
56 void setRunning(bool running);
58 void setRunning(bool running);
57 void setRecent(bool recent);
59 void setRecent(bool recent);
@@ -66,6 +68,7 @@ private:
66 QString m_appId;
68 QString m_appId;
67 QString m_name;
69 QString m_name;
68 QString m_icon;
70 QString m_icon;
71+ QStringList m_keywords;
69 bool m_pinned;
72 bool m_pinned;
70 bool m_running;
73 bool m_running;
71 bool m_recent;
74 bool m_recent;
@@ -79,6 +82,7 @@ private:
79 QuickListEntry m_quitAction;
82 QuickListEntry m_quitAction;
80
83
81 friend class LauncherModel;
84 friend class LauncherModel;
85+ friend class AppDrawerModel;
82};
86};
83
87
84#endif // LAUNCHERITEM_H
88#endif // LAUNCHERITEM_H
plugins/Unity/Launcher/launchermodel.cpp+6−37
@@ -19,18 +19,14 @@
19#include "gsettings.h"
19#include "gsettings.h"
20#include "dbusinterface.h"
20#include "dbusinterface.h"
21#include "asadapter.h"
21#include "asadapter.h"
22+#include "ualwrapper.h"
22
23
23−#include <ubuntu-app-launch/appid.h>
24−#include <ubuntu-app-launch/application.h>
25−#include <ubuntu-app-launch/registry.h>
26#include <unity/shell/application/ApplicationInfoInterface.h>
24#include <unity/shell/application/ApplicationInfoInterface.h>
27#include <unity/shell/application/MirSurfaceListInterface.h>
25#include <unity/shell/application/MirSurfaceListInterface.h>
28
26
29#include <QDesktopServices>
27#include <QDesktopServices>
30#include <QDebug>
28#include <QDebug>
31
29
32−namespace ual = ubuntu::app_launch;
33−
34using namespace unity::shell::application;
30using namespace unity::shell::application;
35
31
36LauncherModel::LauncherModel(QObject *parent):
32LauncherModel::LauncherModel(QObject *parent):
@@ -38,8 +34,7 @@ LauncherModel::LauncherModel(QObject *parent):
38 m_settings(new GSettings(this)),
34 m_settings(new GSettings(this)),
39 m_dbusIface(new DBusInterface(this)),
35 m_dbusIface(new DBusInterface(this)),
40 m_asAdapter(new ASAdapter()),
36 m_asAdapter(new ASAdapter()),
41− m_appManager(nullptr),
37+ m_appManager(nullptr)
42− m_ualRegistry(std::make_shared<ual::Registry>())
43{
38{
44 connect(m_dbusIface, &DBusInterface::countChanged, this, &LauncherModel::countChanged);
39 connect(m_dbusIface, &DBusInterface::countChanged, this, &LauncherModel::countChanged);
45 connect(m_dbusIface, &DBusInterface::countVisibleChanged, this, &LauncherModel::countVisibleChanged);
40 connect(m_dbusIface, &DBusInterface::countVisibleChanged, this, &LauncherModel::countVisibleChanged);
@@ -159,7 +154,7 @@ void LauncherModel::pin(const QString &appId, int index)
159 index = m_list.count();
154 index = m_list.count();
160 }
155 }
161
156
162− auto appInfo = getApplicationInfo(appId);
157+ UalWrapper::AppInfo appInfo = UalWrapper::getApplicationInfo(appId);
163 if (!appInfo.valid) {
158 if (!appInfo.valid) {
164 qWarning() << "Can't pin application, appId not found:" << appId;
159 qWarning() << "Can't pin application, appId not found:" << appId;
165 return;
160 return;
@@ -335,32 +330,6 @@ int LauncherModel::findApplication(const QString &appId)
335 return -1;
330 return -1;
336}
331}
337
332
338−LauncherModel::AppInfo LauncherModel::getApplicationInfo(const QString &appId)
339−{
340− AppInfo info;
341−
342− ual::AppID ualAppId = ual::AppID::find(m_ualRegistry, appId.toStdString());
343− if (ualAppId.empty()) {
344− return info;
345− }
346−
347− std::shared_ptr<ual::Application> ualApp;
348− try
349− {
350− ualApp = ual::Application::create(ualAppId, m_ualRegistry);
351− }
352− catch (std::runtime_error &e)
353− {
354− qWarning() << "Couldn't find application info for" << appId << "-" << e.what();
355− return info;
356− }
357−
358− info.valid = true;
359− info.name = QString::fromStdString(ualApp->info()->name());
360− info.icon = QString::fromStdString(ualApp->info()->iconPath());
361− return info;
362−}
363−
364void LauncherModel::progressChanged(const QString &appId, int progress)
333void LauncherModel::progressChanged(const QString &appId, int progress)
365{
334{
366 const int idx = findApplication(appId);
335 const int idx = findApplication(appId);
@@ -408,7 +377,7 @@ void LauncherModel::countVisibleChanged(const QString &appId, bool countVisible)
408 }
377 }
409 } else {
378 } else {
410 // Need to create a new LauncherItem and show the highlight
379 // Need to create a new LauncherItem and show the highlight
411− auto appInfo = getApplicationInfo(appId);
380+ UalWrapper::AppInfo appInfo = UalWrapper::getApplicationInfo(appId);
412 if (countVisible && appInfo.valid) {
381 if (countVisible && appInfo.valid) {
413 LauncherItem *item = new LauncherItem(appId,
382 LauncherItem *item = new LauncherItem(appId,
414 appInfo.name,
383 appInfo.name,
@@ -428,7 +397,7 @@ void LauncherModel::refresh()
428 // First walk through all the existing items and see if we need to remove something
397 // First walk through all the existing items and see if we need to remove something
429 QList<LauncherItem*> toBeRemoved;
398 QList<LauncherItem*> toBeRemoved;
430 Q_FOREACH (LauncherItem* item, m_list) {
399 Q_FOREACH (LauncherItem* item, m_list) {
431− auto appInfo = getApplicationInfo(item->appId());
400+ UalWrapper::AppInfo appInfo = UalWrapper::getApplicationInfo(item->appId());
432 if (!appInfo.valid) {
401 if (!appInfo.valid) {
433 // Application no longer available => drop it!
402 // Application no longer available => drop it!
434 toBeRemoved << item;
403 toBeRemoved << item;
@@ -480,7 +449,7 @@ void LauncherModel::refresh()
480 if (itemIndex == -1) {
449 if (itemIndex == -1) {
481 // Need to add it. Just add it into the addedIndex to keep same ordering as the list
450 // Need to add it. Just add it into the addedIndex to keep same ordering as the list
482 // in the settings.
451 // in the settings.
483− auto appInfo = getApplicationInfo(entry);
452+ UalWrapper::AppInfo appInfo = UalWrapper::getApplicationInfo(entry);
484 if (!appInfo.valid) {
453 if (!appInfo.valid) {
485 continue;
454 continue;
486 }
455 }
plugins/Unity/Launcher/launchermodel.h−14
@@ -27,12 +27,6 @@ class GSettings;
27class DBusInterface;
27class DBusInterface;
28class ASAdapter;
28class ASAdapter;
29
29
30−namespace ubuntu {
31− namespace app_launch {
32− class Registry;
33− }
34−}
35−
36using namespace unity::shell::launcher;
30using namespace unity::shell::launcher;
37using namespace unity::shell::application;
31using namespace unity::shell::application;
38
32
@@ -73,13 +67,6 @@ private:
73
67
74 void unpin(const QString &appId);
68 void unpin(const QString &appId);
75
69
76− struct AppInfo {
77− bool valid = false;
78− QString name;
79− QString icon;
80− };
81− AppInfo getApplicationInfo(const QString &appId);
82−
83private Q_SLOTS:
70private Q_SLOTS:
84 void countChanged(const QString &appId, int count);
71 void countChanged(const QString &appId, int count);
85 void countVisibleChanged(const QString &appId, bool count);
72 void countVisibleChanged(const QString &appId, bool count);
@@ -98,7 +85,6 @@ private:
98 ASAdapter *m_asAdapter;
85 ASAdapter *m_asAdapter;
99
86
100 ApplicationManagerInterface *m_appManager;
87 ApplicationManagerInterface *m_appManager;
101− std::shared_ptr<ubuntu::app_launch::Registry> m_ualRegistry;
102
88
103 friend class LauncherModelTest;
89 friend class LauncherModelTest;
104};
90};
plugins/Unity/Launcher/plugin.cpp+2−1
@@ -26,7 +26,7 @@
26// local
26// local
27#include "launchermodel.h"
27#include "launchermodel.h"
28#include "launcheritem.h"
28#include "launcheritem.h"
29−
29+#include "appdrawermodel.h"
30
30
31using namespace unity::shell::launcher;
31using namespace unity::shell::launcher;
32
32
@@ -46,4 +46,5 @@ void UnityLauncherPlugin::registerTypes(const char *uri)
46 qmlRegisterSingletonType<LauncherModel>(uri, 0, 1, "LauncherModel", modelProvider);
46 qmlRegisterSingletonType<LauncherModel>(uri, 0, 1, "LauncherModel", modelProvider);
47 qmlRegisterUncreatableType<LauncherItem>(uri, 0, 1, "LauncherItem", QStringLiteral("Can't create new Launcher Items in QML. Get them from the LauncherModel."));
47 qmlRegisterUncreatableType<LauncherItem>(uri, 0, 1, "LauncherItem", QStringLiteral("Can't create new Launcher Items in QML. Get them from the LauncherModel."));
48 qmlRegisterUncreatableType<QuickListModel>(uri, 0, 1, "QuickListModel", QStringLiteral("Can't create a QuickListModel in QML. Get them from the LauncherItems."));
48 qmlRegisterUncreatableType<QuickListModel>(uri, 0, 1, "QuickListModel", QStringLiteral("Can't create a QuickListModel in QML. Get them from the LauncherItems."));
49+ qmlRegisterType<AppDrawerModel>(uri, 0, 1, "AppDrawerModel");
49}
50}
plugins/Unity/Launcher/ualwrapper.cppnew file+73
@@ -0,0 +1,73 @@
1+/*
2+ * Copyright (C) 2016 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+#include <QDebug>
18+
19+#include "ualwrapper.h"
20+
21+#include <ubuntu-app-launch/registry.h>
22+using namespace ubuntu::app_launch;
23+
24+UalWrapper::UalWrapper(QObject *parent):
25+ QObject(parent)
26+{
27+
28+}
29+
30+QStringList UalWrapper::installedApps()
31+{
32+ QStringList appIds;
33+ try {
34+ for (const std::shared_ptr<Application> &app : Registry::installedApps()) {
35+ if (!app->appId().package.value().empty()) {
36+ appIds << QString::fromStdString(app->appId().package.value() + "_" + app->appId().appname.value());
37+ } else {
38+ appIds << QString::fromStdString(app->appId().appname);
39+ }
40+ }
41+ } catch (const std::runtime_error &e) {
42+ qWarning() << "ubuntu-all-launch threw an exception listing apps:" << e.what();
43+ }
44+
45+ return appIds;
46+}
47+
48+UalWrapper::AppInfo UalWrapper::getApplicationInfo(const QString &appId)
49+{
50+ AppInfo info;
51+
52+ try {
53+ AppID ualAppId = AppID::find(appId.toStdString());
54+ if (ualAppId.empty()) {
55+ qWarning() << "Empty ualAppId result for" << appId;
56+ return info;
57+ }
58+
59+ std::shared_ptr<Application> ualApp;
60+ ualApp = Application::create(ualAppId, Registry::getDefault());
61+
62+ info.name = QString::fromStdString(ualApp->info()->name());
63+ info.icon = QString::fromStdString(ualApp->info()->iconPath());
64+ for (const std::string &keyword : ualApp->info()->keywords().value()) {
65+ info.keywords << QString::fromStdString(keyword);
66+ }
67+ info.valid = true;
68+ } catch (const std::runtime_error &e) {
69+ qWarning() << "ubuntu-app-launch threw an exception getting app info for appId:" << appId << ":" << e.what();
70+ }
71+
72+ return info;
73+}
plugins/Unity/Launcher/ualwrapper.hnew file+35
@@ -0,0 +1,35 @@
1+/*
2+ * Copyright (C) 2016 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+#include <QObject>
18+
19+class UalWrapper: public QObject
20+{
21+ Q_OBJECT
22+public:
23+ struct AppInfo {
24+ bool valid = false;
25+ QString name;
26+ QString icon;
27+ QStringList keywords;
28+ };
29+
30+ UalWrapper(QObject* parent = nullptr);
31+
32+ static QStringList installedApps();
33+ static AppInfo getApplicationInfo(const QString &appId);
34+
35+};
plugins/Utils/CMakeLists.txt+4
@@ -15,6 +15,10 @@ set(QMLPLUGIN_SRC
15 ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/ApplicationManagerInterface.h
15 ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/ApplicationManagerInterface.h
16 ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/ApplicationInfoInterface.h
16 ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/ApplicationInfoInterface.h
17 applicationsfiltermodel.cpp
17 applicationsfiltermodel.cpp
18+ ${LAUNCHER_API_INCLUDEDIR}/unity/shell/launcher/AppDrawerModelInterface.h
19+ ${LAUNCHER_API_INCLUDEDIR}/unity/shell/launcher/LauncherItemInterface.h
20+ ${LAUNCHER_API_INCLUDEDIR}/unity/shell/launcher/LauncherModelInterface.h
21+ appdrawerproxymodel.cpp
18 constants.cpp
22 constants.cpp
19 WindowInputMonitor.cpp
23 WindowInputMonitor.cpp
20 inputwatcher.cpp
24 inputwatcher.cpp
plugins/Utils/ElapsedTimer.h+1−1
@@ -41,7 +41,7 @@ class ElapsedTimer : public AbstractElapsedTimer {
41public:
41public:
42 void start() override { m_timer.start(); }
42 void start() override { m_timer.start(); }
43 qint64 msecsSinceReference() const override { return m_timer.msecsSinceReference(); }
43 qint64 msecsSinceReference() const override { return m_timer.msecsSinceReference(); }
44− qint64 elapsed() const override { return m_timer.elapsed(); }
44+ qint64 elapsed() const override { return m_timer.isValid() ? m_timer.elapsed() : 0; }
45private:
45private:
46 QElapsedTimer m_timer;
46 QElapsedTimer m_timer;
47};
47};
plugins/Utils/Timer.cpp+5−2
@@ -37,13 +37,16 @@ void Timer::setInterval(int msecs)
37void Timer::start()
37void Timer::start()
38{
38{
39 m_timer.start();
39 m_timer.start();
40− AbstractTimer::start();
41}
40}
42
41
43void Timer::stop()
42void Timer::stop()
44{
43{
45 m_timer.stop();
44 m_timer.stop();
46− AbstractTimer::stop();
45+}
46+
47+bool Timer::isRunning() const
48+{
49+ return m_timer.isActive();
47}
50}
48
51
49bool Timer::isSingleShot() const
52bool Timer::isSingleShot() const
plugins/Utils/Timer.h+5−6
@@ -30,18 +30,16 @@ class AbstractTimer : public QObject
30{
30{
31 Q_OBJECT
31 Q_OBJECT
32public:
32public:
33− AbstractTimer(QObject *parent) : QObject(parent), m_isRunning(false) {}
33+ AbstractTimer(QObject *parent) : QObject(parent) {}
34 virtual int interval() const = 0;
34 virtual int interval() const = 0;
35 virtual void setInterval(int msecs) = 0;
35 virtual void setInterval(int msecs) = 0;
36− virtual void start() { m_isRunning = true; }
36+ virtual void start() = 0;
37− virtual void stop() { m_isRunning = false; }
37+ virtual void stop() = 0;
38− bool isRunning() const { return m_isRunning; }
38+ virtual bool isRunning() const = 0;
39 virtual bool isSingleShot() const = 0;
39 virtual bool isSingleShot() const = 0;
40 virtual void setSingleShot(bool value) = 0;
40 virtual void setSingleShot(bool value) = 0;
41Q_SIGNALS:
41Q_SIGNALS:
42 void timeout();
42 void timeout();
43−private:
44− bool m_isRunning;
45};
43};
46
44
47/** A QTimer wrapper */
45/** A QTimer wrapper */
@@ -55,6 +53,7 @@ public:
55 void setInterval(int msecs) override;
53 void setInterval(int msecs) override;
56 void start() override;
54 void start() override;
57 void stop() override;
55 void stop() override;
56+ bool isRunning() const override;
58 bool isSingleShot() const override;
57 bool isSingleShot() const override;
59 void setSingleShot(bool value) override;
58 void setSingleShot(bool value) override;
60private:
59private:
plugins/Utils/appdrawerproxymodel.cppnew file+189
@@ -0,0 +1,189 @@
1+/*
2+ * Copyright (C) 2016 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+#include "appdrawerproxymodel.h"
18+
19+#include <unity/shell/launcher/LauncherItemInterface.h>
20+
21+#include <QDebug>
22+
23+AppDrawerProxyModel::AppDrawerProxyModel(QObject *parent):
24+ QSortFilterProxyModel(parent)
25+{
26+ setSortRole(AppDrawerModelInterface::RoleName);
27+ setSortLocaleAware(true);
28+ sort(0);
29+
30+ connect(this, &QAbstractListModel::rowsInserted, this, &AppDrawerProxyModel::countChanged);
31+ connect(this, &QAbstractListModel::rowsRemoved, this, &AppDrawerProxyModel::countChanged);
32+ connect(this, &QAbstractListModel::layoutChanged, this, &AppDrawerProxyModel::countChanged);
33+}
34+
35+QAbstractItemModel *AppDrawerProxyModel::source() const
36+{
37+ return m_source;
38+}
39+
40+void AppDrawerProxyModel::setSource(QAbstractItemModel *source)
41+{
42+ if (m_source != source) {
43+ m_source = source;
44+ setSourceModel(m_source);
45+ setSortRole(m_sortBy == SortByAToZ ? AppDrawerModelInterface::RoleName : AppDrawerModelInterface::RoleUsage);
46+ connect(m_source, &QAbstractItemModel::rowsRemoved, this, &AppDrawerProxyModel::invalidateFilter);
47+ connect(m_source, &QAbstractItemModel::rowsInserted, this, &AppDrawerProxyModel::invalidateFilter);
48+ Q_EMIT sourceChanged();
49+ }
50+}
51+
52+AppDrawerProxyModel::GroupBy AppDrawerProxyModel::group() const
53+{
54+ return m_group;
55+}
56+
57+void AppDrawerProxyModel::setGroup(AppDrawerProxyModel::GroupBy group)
58+{
59+ if (m_group != group) {
60+ m_group = group;
61+ Q_EMIT groupChanged();
62+ invalidateFilter();
63+ }
64+}
65+
66+QString AppDrawerProxyModel::filterLetter() const
67+{
68+ return m_filterLetter;
69+}
70+
71+void AppDrawerProxyModel::setFilterLetter(const QString &filterLetter)
72+{
73+ if (m_filterLetter != filterLetter) {
74+ m_filterLetter = filterLetter;
75+ Q_EMIT filterLetterChanged();
76+ invalidateFilter();
77+ }
78+}
79+
80+QString AppDrawerProxyModel::filterString() const
81+{
82+ return m_filterString;
83+}
84+
85+void AppDrawerProxyModel::setFilterString(const QString &filterString)
86+{
87+ if (m_filterString != filterString) {
88+ m_filterString = filterString;
89+ Q_EMIT filterStringChanged();
90+ invalidateFilter();
91+ }
92+}
93+
94+AppDrawerProxyModel::SortBy AppDrawerProxyModel::sortBy() const
95+{
96+ return m_sortBy;
97+}
98+
99+void AppDrawerProxyModel::setSortBy(AppDrawerProxyModel::SortBy sortBy)
100+{
101+ if (m_sortBy != sortBy) {
102+ m_sortBy = sortBy;
103+ Q_EMIT sortByChanged();
104+ setSortRole(m_sortBy == SortByAToZ ? AppDrawerModelInterface::RoleName : AppDrawerModelInterface::RoleUsage);
105+ sort(0);
106+ }
107+}
108+
109+int AppDrawerProxyModel::count() const
110+{
111+ return rowCount();
112+}
113+
114+QVariant AppDrawerProxyModel::data(const QModelIndex &index, int role) const
115+{
116+ QModelIndex idx = mapToSource(index);
117+ if (role == Qt::UserRole) {
118+ QString name = m_source->data(idx, AppDrawerModelInterface::RoleName).toString();
119+ return name.length() > 0 ? QString(name.at(0)).toUpper() : QChar();
120+ }
121+ return m_source->data(idx, role);
122+}
123+
124+QHash<int, QByteArray> AppDrawerProxyModel::roleNames() const
125+{
126+ if (m_source) {
127+ QHash<int, QByteArray> roles = m_source->roleNames();
128+ roles.insert(Qt::UserRole, "letter");
129+ return roles;
130+ }
131+ return QHash<int, QByteArray>();
132+}
133+
134+bool AppDrawerProxyModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const
135+{
136+ Q_UNUSED(source_parent)
137+
138+ if (m_group == GroupByAToZ && source_row > 0) {
139+ QString currentName = m_source->data(m_source->index(source_row, 0), AppDrawerModelInterface::RoleName).toString();
140+ QChar currentLetter = currentName.length() > 0 ? currentName.at(0) : QChar();
141+ QString previousName = m_source->data(m_source->index(source_row - 1,0 ), AppDrawerModelInterface::RoleName).toString();
142+ QChar previousLetter = previousName.length() > 0 ? previousName.at(0) : QChar();
143+ if (currentLetter.toLower() == previousLetter.toLower()) {
144+ return false;
145+ }
146+ } else if(m_group == GroupByAll && source_row > 0) {
147+ return false;
148+ }
149+ if (!m_filterLetter.isEmpty()) {
150+ QString currentName = m_source->data(m_source->index(source_row, 0), AppDrawerModelInterface::RoleName).toString();
151+ QString currentLetter = currentName.length() > 0 ? QString(currentName.at(0)) : QString();
152+ if (currentLetter.toLower() != m_filterLetter.toLower()) {
153+ return false;
154+ }
155+ }
156+ if (!m_filterString.isEmpty()) {
157+ QStringList allWords = m_source->data(m_source->index(source_row, 0), AppDrawerModelInterface::RoleKeywords).toStringList();
158+ allWords.prepend(m_source->data(m_source->index(source_row, 0), AppDrawerModelInterface::RoleName).toString());
159+ bool found = false;
160+ Q_FOREACH (const QString currentWord, allWords) {
161+ if (currentWord.toLower().startsWith(m_filterString.toLower())) {
162+ found = true;
163+ break;
164+ }
165+ }
166+ if (!found) {
167+ return false;
168+ }
169+ }
170+ return true;
171+}
172+
173+QString AppDrawerProxyModel::appId(int index) const
174+{
175+ if (index >= 0 && index < rowCount()) {
176+ QModelIndex sourceIndex = mapToSource(this->index(index, 0));
177+
178+ AppDrawerModelInterface* adm = dynamic_cast<AppDrawerModelInterface*>(m_source);
179+ if (adm) {
180+ return adm->data(sourceIndex, AppDrawerModelInterface::RoleAppId).toString();
181+ }
182+
183+ AppDrawerProxyModel* adpm = qobject_cast<AppDrawerProxyModel*>(m_source);
184+ if (adpm) {
185+ return adpm->appId(sourceIndex.row());
186+ }
187+ }
188+ return nullptr;
189+}
plugins/Utils/appdrawerproxymodel.hnew file+87
@@ -0,0 +1,87 @@
1+/*
2+ * Copyright (C) 2016 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+#include <QSortFilterProxyModel>
18+
19+#include <unity/shell/launcher/AppDrawerModelInterface.h>
20+
21+using namespace unity::shell::launcher;
22+
23+class AppDrawerProxyModel: public QSortFilterProxyModel
24+{
25+ Q_OBJECT
26+ Q_ENUMS(GroupBy)
27+ Q_ENUMS(SortBy)
28+ Q_PROPERTY(QAbstractItemModel* source READ source WRITE setSource NOTIFY sourceChanged)
29+ Q_PROPERTY(GroupBy group READ group WRITE setGroup NOTIFY groupChanged)
30+ Q_PROPERTY(QString filterLetter READ filterLetter WRITE setFilterLetter NOTIFY filterLetterChanged)
31+ Q_PROPERTY(QString filterString READ filterString WRITE setFilterString NOTIFY filterStringChanged)
32+ Q_PROPERTY(SortBy sortBy READ sortBy WRITE setSortBy NOTIFY sortByChanged)
33+ Q_PROPERTY(int count READ count NOTIFY countChanged)
34+
35+public:
36+ enum GroupBy {
37+ GroupByNone,
38+ GroupByAll,
39+ GroupByAToZ
40+ };
41+ enum SortBy {
42+ SortByAToZ,
43+ SortByUsage
44+ };
45+
46+ AppDrawerProxyModel(QObject* parent = nullptr);
47+
48+ QAbstractItemModel* source() const;
49+ void setSource(QAbstractItemModel* source);
50+
51+ GroupBy group() const;
52+ void setGroup(GroupBy group);
53+
54+ QString filterLetter() const;
55+ void setFilterLetter(const QString &filterLetter);
56+
57+ QString filterString() const;
58+ void setFilterString(const QString &filterString);
59+
60+ SortBy sortBy() const;
61+ void setSortBy(SortBy sortBy);
62+
63+ int count() const;
64+
65+ QVariant data(const QModelIndex &index, int role) const override;
66+ QHash<int, QByteArray> roleNames() const override;
67+
68+ Q_INVOKABLE QString appId(int index) const;
69+
70+protected:
71+ bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const override;
72+
73+Q_SIGNALS:
74+ void sourceChanged();
75+ void groupChanged();
76+ void filterLetterChanged();
77+ void filterStringChanged();
78+ void sortByChanged();
79+ void countChanged();
80+
81+private:
82+ QAbstractItemModel* m_source = nullptr;
83+ GroupBy m_group = GroupByNone;
84+ QString m_filterLetter;
85+ QString m_filterString;
86+ SortBy m_sortBy = SortByAToZ;
87+};
plugins/Utils/globalfunctions.cpp+5
@@ -51,3 +51,8 @@ QQuickItem *GlobalFunctions::itemAt(QQuickItem* parent, int x, int y, QJSValue m
51 }
51 }
52 return nullptr;
52 return nullptr;
53}
53}
54+
55+bool GlobalFunctions::itemUnderMouse(QQuickItem* item)
56+{
57+ return item && item->isUnderMouse();
58+}
plugins/Utils/globalfunctions.h+2
@@ -37,6 +37,8 @@ public:
37 int x,
37 int x,
38 int y,
38 int y,
39 QJSValue matcher);
39 QJSValue matcher);
40+
41+ static Q_INVOKABLE bool itemUnderMouse(QQuickItem* item);
40};
42};
41
43
42#endif // GLOBALFUNCTIONS_H
44#endif // GLOBALFUNCTIONS_H
plugins/Utils/plugin.cpp+2
@@ -39,6 +39,7 @@
39#include "deviceconfigparser.h"
39#include "deviceconfigparser.h"
40#include "globalfunctions.h"
40#include "globalfunctions.h"
41#include "URLDispatcher.h"
41#include "URLDispatcher.h"
42+#include "appdrawerproxymodel.h"
42
43
43static QObject *createWindowStateStorage(QQmlEngine *engine, QJSEngine *scriptEngine)
44static QObject *createWindowStateStorage(QQmlEngine *engine, QJSEngine *scriptEngine)
44{
45{
@@ -82,4 +83,5 @@ void UtilsPlugin::registerTypes(const char *uri)
82 qmlRegisterType<DeviceConfigParser>(uri, 0, 1, "DeviceConfigParser");
83 qmlRegisterType<DeviceConfigParser>(uri, 0, 1, "DeviceConfigParser");
83 qmlRegisterSingletonType<GlobalFunctions>(uri, 0, 1, "Functions", createGlobalFunctions);
84 qmlRegisterSingletonType<GlobalFunctions>(uri, 0, 1, "Functions", createGlobalFunctions);
84 qmlRegisterType<URLDispatcher>(uri, 0, 1, "URLDispatcher");
85 qmlRegisterType<URLDispatcher>(uri, 0, 1, "URLDispatcher");
86+ qmlRegisterType<AppDrawerProxyModel>(uri, 0, 1, "AppDrawerProxyModel");
85}
87}
plugins/Wizard/PageList.cpp+3−1
@@ -46,7 +46,9 @@ PageList::PageList(QObject *parent)
46 QSet<QString> disabledPages;
46 QSet<QString> disabledPages;
47 QStringList dataDirs;
47 QStringList dataDirs;
48
48
49− if (!isRunningInstalled() && getenv("WIZARD_TESTING") == nullptr) {
49+ if (getenv("WIZARD_TESTING") != nullptr) {
50+ dataDirs = QStandardPaths::standardLocations(QStandardPaths::GenericDataLocation);
51+ } else if (!isRunningInstalled()) {
50 dataDirs << qmlDirectory();
52 dataDirs << qmlDirectory();
51 } else {
53 } else {
52 dataDirs = shellDataDirs();
54 dataDirs = shellDataDirs();
po/unity8.pot+80−43
@@ -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: 2016-11-29 09:43+0000\n"
11+"POT-Creation-Date: 2016-12-07 13:49+0000\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"
@@ -23,7 +23,7 @@ msgid "Password: "
23msgstr ""
23msgstr ""
24
24
25#: plugins/Unity/Launcher/launcheritem.cpp:50
25#: plugins/Unity/Launcher/launcheritem.cpp:50
26−#: plugins/Unity/Launcher/launcheritem.cpp:109
26+#: plugins/Unity/Launcher/launcheritem.cpp:122
27msgid "Pin shortcut"
27msgid "Pin shortcut"
28msgstr ""
28msgstr ""
29
29
@@ -31,7 +31,7 @@ msgstr ""
31msgid "Quit"
31msgid "Quit"
32msgstr ""
32msgstr ""
33
33
34−#: plugins/Unity/Launcher/launcheritem.cpp:109
34+#: plugins/Unity/Launcher/launcheritem.cpp:122
35msgid "Unpin shortcut"
35msgid "Unpin shortcut"
36msgstr ""
36msgstr ""
37
37
@@ -175,87 +175,95 @@ msgstr ""
175msgid "Same as clicking on a launcher icon."
175msgid "Same as clicking on a launcher icon."
176msgstr ""
176msgstr ""
177
177
178−#: qml/Components/KeyboardShortcutsOverlay.qml:181
178+#: qml/Components/KeyboardShortcutsOverlay.qml:177
179+msgid "Super + A"
180+msgstr ""
181+
182+#: qml/Components/KeyboardShortcutsOverlay.qml:182
183+msgid "Opens the Application Drawer."
184+msgstr ""
185+
186+#: qml/Components/KeyboardShortcutsOverlay.qml:194
179msgid "Scopes"
187msgid "Scopes"
180msgstr ""
188msgstr ""
181
189
182−#: qml/Components/KeyboardShortcutsOverlay.qml:188
190+#: qml/Components/KeyboardShortcutsOverlay.qml:201
183msgid "Super (Tap)"
191msgid "Super (Tap)"
184msgstr ""
192msgstr ""
185
193
186−#: qml/Components/KeyboardShortcutsOverlay.qml:193
194+#: qml/Components/KeyboardShortcutsOverlay.qml:206
187msgid "Opens the Scopes home."
195msgid "Opens the Scopes home."
188msgstr ""
196msgstr ""
189
197
190−#: qml/Components/KeyboardShortcutsOverlay.qml:209
198+#: qml/Components/KeyboardShortcutsOverlay.qml:222
191msgid "Switching"
199msgid "Switching"
192msgstr ""
200msgstr ""
193
201
194−#: qml/Components/KeyboardShortcutsOverlay.qml:216
202+#: qml/Components/KeyboardShortcutsOverlay.qml:229
195msgid "Alt + Tab"
203msgid "Alt + Tab"
196msgstr ""
204msgstr ""
197
205
198−#: qml/Components/KeyboardShortcutsOverlay.qml:221
206+#: qml/Components/KeyboardShortcutsOverlay.qml:234
199msgid "Switches between applications."
207msgid "Switches between applications."
200msgstr ""
208msgstr ""
201
209
202−#: qml/Components/KeyboardShortcutsOverlay.qml:229
210+#: qml/Components/KeyboardShortcutsOverlay.qml:242
203msgid "Super + W"
211msgid "Super + W"
204msgstr ""
212msgstr ""
205
213
206−#: qml/Components/KeyboardShortcutsOverlay.qml:234
214+#: qml/Components/KeyboardShortcutsOverlay.qml:247
207msgid "Opens the desktop spread."
215msgid "Opens the desktop spread."
208msgstr ""
216msgstr ""
209
217
210−#: qml/Components/KeyboardShortcutsOverlay.qml:242
218+#: qml/Components/KeyboardShortcutsOverlay.qml:255
211msgid "Cursor Left or Right"
219msgid "Cursor Left or Right"
212msgstr ""
220msgstr ""
213
221
214−#: qml/Components/KeyboardShortcutsOverlay.qml:247
222+#: qml/Components/KeyboardShortcutsOverlay.qml:260
215msgid "Moves the focus."
223msgid "Moves the focus."
216msgstr ""
224msgstr ""
217
225
218−#: qml/Components/KeyboardShortcutsOverlay.qml:259
226+#: qml/Components/KeyboardShortcutsOverlay.qml:272
219msgid "Windows"
227msgid "Windows"
220msgstr ""
228msgstr ""
221
229
222−#: qml/Components/KeyboardShortcutsOverlay.qml:266
230+#: qml/Components/KeyboardShortcutsOverlay.qml:279
223msgid "Ctrl + Super + D"
231msgid "Ctrl + Super + D"
224msgstr ""
232msgstr ""
225
233
226−#: qml/Components/KeyboardShortcutsOverlay.qml:271
234+#: qml/Components/KeyboardShortcutsOverlay.qml:284
227msgid "Minimizes all windows."
235msgid "Minimizes all windows."
228msgstr ""
236msgstr ""
229
237
230−#: qml/Components/KeyboardShortcutsOverlay.qml:279
238+#: qml/Components/KeyboardShortcutsOverlay.qml:292
231msgid "Ctrl + Super + Up"
239msgid "Ctrl + Super + Up"
232msgstr ""
240msgstr ""
233
241
234−#: qml/Components/KeyboardShortcutsOverlay.qml:284
242+#: qml/Components/KeyboardShortcutsOverlay.qml:297
235msgid "Maximizes the current window."
243msgid "Maximizes the current window."
236msgstr ""
244msgstr ""
237
245
238−#: qml/Components/KeyboardShortcutsOverlay.qml:292
246+#: qml/Components/KeyboardShortcutsOverlay.qml:305
239msgid "Ctrl + Super + Down"
247msgid "Ctrl + Super + Down"
240msgstr ""
248msgstr ""
241
249
242−#: qml/Components/KeyboardShortcutsOverlay.qml:297
250+#: qml/Components/KeyboardShortcutsOverlay.qml:310
243msgid "Minimizes or restores the current window."
251msgid "Minimizes or restores the current window."
244msgstr ""
252msgstr ""
245
253
246−#: qml/Components/KeyboardShortcutsOverlay.qml:305
254+#: qml/Components/KeyboardShortcutsOverlay.qml:318
247msgid "Ctrl + Super + Left or Right"
255msgid "Ctrl + Super + Left or Right"
248msgstr ""
256msgstr ""
249
257
250−#: qml/Components/KeyboardShortcutsOverlay.qml:310
258+#: qml/Components/KeyboardShortcutsOverlay.qml:323
251msgid "Semi-maximizes the current window."
259msgid "Semi-maximizes the current window."
252msgstr ""
260msgstr ""
253
261
254−#: qml/Components/KeyboardShortcutsOverlay.qml:318
262+#: qml/Components/KeyboardShortcutsOverlay.qml:331
255msgid "Alt + F4"
263msgid "Alt + F4"
256msgstr ""
264msgstr ""
257
265
258−#: qml/Components/KeyboardShortcutsOverlay.qml:323
266+#: qml/Components/KeyboardShortcutsOverlay.qml:336
259msgid "Closes the current window."
267msgid "Closes the current window."
260msgstr ""
268msgstr ""
261
269
@@ -311,6 +319,28 @@ msgstr ""
311msgid "Preview Share Item"
319msgid "Preview Share Item"
312msgstr ""
320msgstr ""
313
321
322+#: qml/Components/VirtualTouchPad.qml:317
323+msgid ""
324+"Your device is now connected to an external display. Use this screen as a "
325+"touch pad to interact with the pointer."
326+msgstr ""
327+
328+#: qml/Components/VirtualTouchPad.qml:327
329+msgid "Tap left button to click."
330+msgstr ""
331+
332+#: qml/Components/VirtualTouchPad.qml:339
333+msgid "Tap right button to right click."
334+msgstr ""
335+
336+#: qml/Components/VirtualTouchPad.qml:351
337+msgid "Swipe with two fingers to scroll."
338+msgstr ""
339+
340+#: qml/Components/VirtualTouchPad.qml:396
341+msgid "Find more settings in the system settings."
342+msgstr ""
343+
314#: qml/Dash/DashPageHeader.qml:361
344#: qml/Dash/DashPageHeader.qml:361
315msgctxt "Button: Open the Ubuntu Store"
345msgctxt "Button: Open the Ubuntu Store"
316msgid "Store"
346msgid "Store"
@@ -408,12 +438,6 @@ msgstr ""
408msgid "Also installed"
438msgid "Also installed"
409msgstr ""
439msgstr ""
410
440
411−#: qml/DisabledScreenNotice.qml:109
412−msgid ""
413−"Your device is now connected to an external display. Use this screen as a "
414−"touch pad to interact with the pointer."
415−msgstr ""
416−
417#: qml/Greeter/CoverPage.qml:127
441#: qml/Greeter/CoverPage.qml:127
418msgid "Unlock"
442msgid "Unlock"
419msgstr ""
443msgstr ""
@@ -437,7 +461,7 @@ msgid_plural "Please wait %1 minutes and then try again…"
437msgstr[0] ""
461msgstr[0] ""
438msgstr[1] ""
462msgstr[1] ""
439
463
440−#: qml/Greeter/Greeter.qml:596
464+#: qml/Greeter/Greeter.qml:592
441msgid "Try again"
465msgid "Try again"
442msgstr ""
466msgstr ""
443
467
@@ -465,6 +489,19 @@ msgstr ""
465msgid "Select desktop environment"
489msgid "Select desktop environment"
466msgstr ""
490msgstr ""
467
491
492+#: qml/Launcher/Drawer.qml:80
493+msgid "Search…"
494+msgstr ""
495+
496+#: qml/Launcher/Drawer.qml:101
497+msgctxt "Apps sorted alphabetically"
498+msgid "A-Z"
499+msgstr ""
500+
501+#: qml/Launcher/MoreAppsHeader.qml:32
502+msgid "More apps in the store"
503+msgstr ""
504+
468#: qml/Notifications/NotificationMenuItemFactory.qml:124
505#: qml/Notifications/NotificationMenuItemFactory.qml:124
469msgid "Show password"
506msgid "Show password"
470msgstr ""
507msgstr ""
@@ -477,62 +514,62 @@ msgstr ""
477msgid "Conference"
514msgid "Conference"
478msgstr ""
515msgstr ""
479
516
480−#: qml/Panel/Indicators/MenuItemFactory.qml:847
517+#: qml/Panel/Indicators/MenuItemFactory.qml:868
481msgid "Nothing is playing"
518msgid "Nothing is playing"
482msgstr ""
519msgstr ""
483
520
484−#: qml/Panel/Indicators/MenuItemFactory.qml:975
521+#: qml/Panel/Indicators/MenuItemFactory.qml:996
485#, qt-format
522#, qt-format
486msgid "%1 hour"
523msgid "%1 hour"
487msgid_plural "%1 hours"
524msgid_plural "%1 hours"
488msgstr[0] ""
525msgstr[0] ""
489msgstr[1] ""
526msgstr[1] ""
490
527
491−#: qml/Panel/Indicators/MenuItemFactory.qml:979
528+#: qml/Panel/Indicators/MenuItemFactory.qml:1000
492#, qt-format
529#, qt-format
493msgid "%1 minute"
530msgid "%1 minute"
494msgid_plural "%1 minutes"
531msgid_plural "%1 minutes"
495msgstr[0] ""
532msgstr[0] ""
496msgstr[1] ""
533msgstr[1] ""
497
534
498−#: qml/Panel/Indicators/MenuItemFactory.qml:984
535+#: qml/Panel/Indicators/MenuItemFactory.qml:1005
499#, qt-format
536#, qt-format
500msgid "%1 second"
537msgid "%1 second"
501msgid_plural "%1 seconds"
538msgid_plural "%1 seconds"
502msgstr[0] ""
539msgstr[0] ""
503msgstr[1] ""
540msgstr[1] ""
504
541
505−#: qml/Panel/Indicators/MenuItemFactory.qml:987
542+#: qml/Panel/Indicators/MenuItemFactory.qml:1008
506msgid "0 seconds"
543msgid "0 seconds"
507msgstr ""
544msgstr ""
508
545
509#. Translators: String like "1 hour, 2 minutes, 3 seconds remaining"
546#. Translators: String like "1 hour, 2 minutes, 3 seconds remaining"
510−#: qml/Panel/Indicators/MenuItemFactory.qml:989
547+#: qml/Panel/Indicators/MenuItemFactory.qml:1010
511#, qt-format
548#, qt-format
512msgid "%1 remaining"
549msgid "%1 remaining"
513msgstr ""
550msgstr ""
514
551
515−#: qml/Panel/Indicators/MenuItemFactory.qml:995
552+#: qml/Panel/Indicators/MenuItemFactory.qml:1016
516msgid "In queue…"
553msgid "In queue…"
517msgstr ""
554msgstr ""
518
555
519−#: qml/Panel/Indicators/MenuItemFactory.qml:999
556+#: qml/Panel/Indicators/MenuItemFactory.qml:1020
520msgid "Downloading"
557msgid "Downloading"
521msgstr ""
558msgstr ""
522
559
523−#: qml/Panel/Indicators/MenuItemFactory.qml:1001
560+#: qml/Panel/Indicators/MenuItemFactory.qml:1022
524msgid "Paused, tap to resume"
561msgid "Paused, tap to resume"
525msgstr ""
562msgstr ""
526
563
527−#: qml/Panel/Indicators/MenuItemFactory.qml:1003
564+#: qml/Panel/Indicators/MenuItemFactory.qml:1024
528msgid "Canceled"
565msgid "Canceled"
529msgstr ""
566msgstr ""
530
567
531−#: qml/Panel/Indicators/MenuItemFactory.qml:1005
568+#: qml/Panel/Indicators/MenuItemFactory.qml:1026
532msgid "Finished"
569msgid "Finished"
533msgstr ""
570msgstr ""
534
571
535−#: qml/Panel/Indicators/MenuItemFactory.qml:1007
572+#: qml/Panel/Indicators/MenuItemFactory.qml:1028
536msgid "Failed, tap to retry"
573msgid "Failed, tap to retry"
537msgstr ""
574msgstr ""
538
575
qml/Components/KeyboardShortcutsOverlay.qml+13
@@ -173,6 +173,19 @@ Rectangle {
173 Layout.maximumWidth: maxTextSize
173 Layout.maximumWidth: maxTextSize
174 }
174 }
175
175
176+ Label {
177+ text: i18n.tr("Super + A")
178+ fontSize: "small"
179+ font.weight: Font.Medium
180+ }
181+ Label {
182+ text: i18n.tr("Opens the Application Drawer.")
183+ fontSize: "small"
184+ font.weight: Font.Light
185+ wrapMode: Text.Wrap
186+ Layout.maximumWidth: maxTextSize
187+ }
188+
176
189
177 // Scopes section
190 // Scopes section
178 Item { Layout.columnSpan: 2; height: units.gu(2) }
191 Item { Layout.columnSpan: 2; height: units.gu(2) }
qml/Components/VirtualTouchPad.qml+269−1
@@ -15,20 +15,58 @@
15 */
15 */
16
16
17import QtQuick 2.4
17import QtQuick 2.4
18+import QtQuick.Layouts 1.1
18import Ubuntu.Components 1.3
19import Ubuntu.Components 1.3
20+import Qt.labs.settings 1.0
21+import Unity.Screens 0.1
19import UInput 0.1
22import UInput 0.1
23+import "../Components"
20
24
21Item {
25Item {
26+ id: root
22 property var uinput: UInput {
27 property var uinput: UInput {
23 Component.onCompleted: createMouse();
28 Component.onCompleted: createMouse();
24 Component.onDestruction: removeMouse();
29 Component.onDestruction: removeMouse();
25 }
30 }
26
31
32+ Component.onCompleted: {
33+ if (!settings.touchpadTutorialHasRun) {
34+ root.runTutorial()
35+ }
36+ }
37+
38+ function runTutorial() {
39+ // If the tutorial animation is started too early, e.g. in Component.onCompleted,
40+ // root width & height might be reported as 0x0 still. As animations read their
41+ // values at startup and won't update them, lets make sure to only start once
42+ // we have some actual size.
43+ if (root.width > 0 && root.height > 0) {
44+ tutorial.start();
45+ } else {
46+ tutorialTimer.start();
47+ }
48+ }
49+
50+ Timer {
51+ id: tutorialTimer
52+ interval: 50
53+ repeat: false
54+ running: false
55+ onTriggered: root.runTutorial();
56+ }
57+
27− readonly property bool pressed: point1.pressed || point2.pressed
58+ readonly property bool pressed: point1.pressed || point2.pressed || leftButton.pressed || rightButton.pressed
59+
60+ property var settings: Settings {
61+ objectName: "virtualTouchPadSettings"
62+ property bool touchpadTutorialHasRun: false
63+ property bool oskEnabled: true
64+ }
28
65
29 MultiPointTouchArea {
66 MultiPointTouchArea {
30 objectName: "touchPadArea"
67 objectName: "touchPadArea"
31 anchors.fill: parent
68 anchors.fill: parent
69+ enabled: !tutorial.running || tutorial.paused
32
70
33 // FIXME: Once we have Qt DPR support, this should be Qt.styleHints.startDragDistance
71 // FIXME: Once we have Qt DPR support, this should be Qt.styleHints.startDragDistance
34 readonly property int clickThreshold: internalGu * 1.5
72 readonly property int clickThreshold: internalGu * 1.5
@@ -37,6 +75,11 @@ Item {
37 property bool isDrag: false
75 property bool isDrag: false
38
76
39 onPressed: {
77 onPressed: {
78+ if (tutorial.paused) {
79+ tutorial.resume();
80+ return;
81+ }
82+
40 // If double-tapping *really* fast, it could happen that we end up having only point2 pressed
83 // If double-tapping *really* fast, it could happen that we end up having only point2 pressed
41 // Make sure we check for both combos, only point1 or only point2
84 // Make sure we check for both combos, only point1 or only point2
42 if (((point1.pressed && !point2.pressed) || (!point1.pressed && point2.pressed))
85 if (((point1.pressed && !point2.pressed) || (!point1.pressed && point2.pressed))
@@ -135,4 +178,229 @@ Item {
135 }
178 }
136 ]
179 ]
137 }
180 }
181+
182+ RowLayout {
183+ anchors { left: parent.left; right: parent.right; bottom: parent.bottom; margins: -internalGu * 1 }
184+ height: internalGu * 10
185+ spacing: internalGu * 1
186+
187+ MouseArea {
188+ id: leftButton
189+ objectName: "leftButton"
190+ Layout.fillWidth: true
191+ Layout.fillHeight: true
192+ onPressed: uinput.pressMouse(UInput.ButtonLeft);
193+ onReleased: uinput.releaseMouse(UInput.ButtonLeft);
194+ property bool highlight: false
195+ UbuntuShape {
196+ anchors.fill: parent
197+ backgroundColor: leftButton.highlight || leftButton.pressed ? UbuntuColors.ash : UbuntuColors.inkstone
198+ Behavior on backgroundColor { ColorAnimation { duration: UbuntuAnimation.FastDuration } }
199+ }
200+ }
201+
202+ MouseArea {
203+ id: rightButton
204+ objectName: "rightButton"
205+ Layout.fillWidth: true
206+ Layout.fillHeight: true
207+ onPressed: uinput.pressMouse(UInput.ButtonRight);
208+ onReleased: uinput.releaseMouse(UInput.ButtonRight);
209+ property bool highlight: false
210+ UbuntuShape {
211+ anchors.fill: parent
212+ backgroundColor: rightButton.highlight || rightButton.pressed ? UbuntuColors.ash : UbuntuColors.inkstone
213+ Behavior on backgroundColor { ColorAnimation { duration: UbuntuAnimation.FastDuration } }
214+ }
215+ }
216+ }
217+
218+ AbstractButton {
219+ id: oskButton
220+ objectName: "oskButton"
221+ anchors { right: parent.right; top: parent.top; margins: internalGu * 2 }
222+ height: internalGu * 6
223+ width: height
224+
225+ onClicked: {
226+ settings.oskEnabled = !settings.oskEnabled
227+ }
228+
229+ Rectangle {
230+ anchors.fill: parent
231+ radius: width / 2
232+ color: UbuntuColors.inkstone
233+ }
234+
235+ Icon {
236+ anchors.fill: parent
237+ anchors.margins: internalGu * 1.5
238+ name: "input-keyboard-symbolic"
239+ }
240+ }
241+
242+ Screens {
243+ id: screens
244+ }
245+
246+ InputMethod {
247+ id: inputMethod
248+ // Don't resize when there is only one screen to avoid resize clashing with the InputMethod in the Shell.
249+ enabled: screens.count > 1 && settings.oskEnabled && !tutorial.running
250+ objectName: "inputMethod"
251+ anchors.fill: parent
252+ }
253+
254+ Label {
255+ id: tutorialLabel
256+ objectName: "tutorialLabel"
257+ anchors { left: parent.left; top: parent.top; right: parent.right; margins: internalGu * 4; topMargin: internalGu * 10 }
258+ opacity: 0
259+ visible: opacity > 0
260+ font.pixelSize: 2 * internalGu
261+ color: "white"
262+ wrapMode: Text.WordWrap
263+ }
264+
265+ Icon {
266+ id: tutorialImage
267+ objectName: "tutorialImage"
268+ height: internalGu * 8
269+ width: height
270+ name: "input-touchpad-symbolic"
271+ color: "white"
272+ opacity: 0
273+ visible: opacity > 0
274+ anchors { top: tutorialLabel.bottom; horizontalCenter: parent.horizontalCenter; margins: internalGu * 2 }
275+ }
276+
277+ Item {
278+ id: tutorialFinger1
279+ objectName: "tutorialFinger1"
280+ width: internalGu * 5
281+ height: width
282+ property real scale: 1
283+ opacity: 0
284+ visible: opacity > 0
285+ Rectangle {
286+ width: parent.width * parent.scale
287+ height: width
288+ anchors.centerIn: parent
289+ radius: width / 2
290+ color: UbuntuColors.inkstone
291+ }
292+ }
293+
294+ Item {
295+ id: tutorialFinger2
296+ objectName: "tutorialFinger2"
297+ width: internalGu * 5
298+ height: width
299+ property real scale: 1
300+ opacity: 0
301+ visible: opacity > 0
302+ Rectangle {
303+ width: parent.width * parent.scale
304+ height: width
305+ anchors.centerIn: parent
306+ radius: width / 2
307+ color: UbuntuColors.inkstone
308+ }
309+ }
310+
311+ SequentialAnimation {
312+ id: tutorial
313+ objectName: "tutorialAnimation"
314+
315+ PropertyAction { targets: [leftButton, rightButton, oskButton]; property: "enabled"; value: false }
316+ PropertyAction { targets: [leftButton, rightButton, oskButton]; property: "opacity"; value: 0 }
317+ PropertyAction { target: tutorialLabel; property: "text"; value: i18n.tr("Your device is now connected to an external display. Use this screen as a touch pad to interact with the pointer.") }
318+ UbuntuNumberAnimation { targets: [tutorialLabel, tutorialImage]; property: "opacity"; to: 1; duration: UbuntuAnimation.FastDuration }
319+ PropertyAction { target: tutorial; property: "paused"; value: true }
320+ PauseAnimation { duration: 500 } // it takes a bit until pausing actually takes effect
321+ UbuntuNumberAnimation { targets: [tutorialLabel, tutorialImage]; property: "opacity"; to: 0; duration: UbuntuAnimation.FastDuration }
322+
323+ UbuntuNumberAnimation { target: leftButton; property: "opacity"; to: 1 }
324+ UbuntuNumberAnimation { target: rightButton; property: "opacity"; to: 1 }
325+
326+ PauseAnimation { duration: UbuntuAnimation.SleepyDuration }
327+ PropertyAction { target: tutorialLabel; property: "text"; value: i18n.tr("Tap left button to click.") }
328+ UbuntuNumberAnimation { target: tutorialLabel; property: "opacity"; to: 1; duration: UbuntuAnimation.FastDuration }
329+ SequentialAnimation {
330+ loops: 2
331+ PropertyAction { target: leftButton; property: "highlight"; value: true }
332+ PauseAnimation { duration: UbuntuAnimation.FastDuration }
333+ PropertyAction { target: leftButton; property: "highlight"; value: false }
334+ PauseAnimation { duration: UbuntuAnimation.SleepyDuration }
335+ }
336+ UbuntuNumberAnimation { target: tutorialLabel; property: "opacity"; to: 0; duration: UbuntuAnimation.FastDuration }
337+
338+ PauseAnimation { duration: UbuntuAnimation.SleepyDuration }
339+ PropertyAction { target: tutorialLabel; property: "text"; value: i18n.tr("Tap right button to right click.") }
340+ UbuntuNumberAnimation { target: tutorialLabel; property: "opacity"; to: 1; duration: UbuntuAnimation.FastDuration }
341+ SequentialAnimation {
342+ loops: 2
343+ PropertyAction { target: rightButton; property: "highlight"; value: true }
344+ PauseAnimation { duration: UbuntuAnimation.FastDuration }
345+ PropertyAction { target: rightButton; property: "highlight"; value: false }
346+ PauseAnimation { duration: UbuntuAnimation.SleepyDuration }
347+ }
348+ UbuntuNumberAnimation { target: tutorialLabel; property: "opacity"; to: 0; duration: UbuntuAnimation.FastDuration }
349+
350+ PauseAnimation { duration: UbuntuAnimation.SleepyDuration }
351+ PropertyAction { target: tutorialLabel; property: "text"; value: i18n.tr("Swipe with two fingers to scroll.") }
352+ UbuntuNumberAnimation { target: tutorialLabel; property: "opacity"; to: 1; duration: UbuntuAnimation.FastDuration }
353+ PropertyAction { target: tutorialFinger1; property: "x"; value: root.width / 2 - tutorialFinger1.width - internalGu * 1 }
354+ PropertyAction { target: tutorialFinger2; property: "x"; value: root.width / 2 + tutorialFinger1.width + internalGu * 1 - tutorialFinger2.width }
355+ PropertyAction { target: tutorialFinger1; property: "y"; value: root.height / 2 - internalGu * 10 }
356+ PropertyAction { target: tutorialFinger2; property: "y"; value: root.height / 2 - internalGu * 10 }
357+ SequentialAnimation {
358+ ParallelAnimation {
359+ UbuntuNumberAnimation { target: tutorialFinger1; property: "opacity"; to: 1; duration: UbuntuAnimation.FastDuration }
360+ UbuntuNumberAnimation { target: tutorialFinger2; property: "opacity"; to: 1; duration: UbuntuAnimation.FastDuration }
361+ UbuntuNumberAnimation { target: tutorialFinger1; property: "scale"; from: 0; to: 1; duration: UbuntuAnimation.FastDuration }
362+ UbuntuNumberAnimation { target: tutorialFinger2; property: "scale"; from: 0; to: 1; duration: UbuntuAnimation.FastDuration }
363+ }
364+ ParallelAnimation {
365+ UbuntuNumberAnimation { target: tutorialFinger1; property: "y"; to: root.height / 2 + internalGu * 10; duration: UbuntuAnimation.SleepyDuration }
366+ UbuntuNumberAnimation { target: tutorialFinger2; property: "y"; to: root.height / 2 + internalGu * 10; duration: UbuntuAnimation.SleepyDuration }
367+ }
368+ ParallelAnimation {
369+ UbuntuNumberAnimation { target: tutorialFinger1; property: "opacity"; to: 0; duration: UbuntuAnimation.FastDuration }
370+ UbuntuNumberAnimation { target: tutorialFinger2; property: "opacity"; to: 0; duration: UbuntuAnimation.FastDuration }
371+ UbuntuNumberAnimation { target: tutorialFinger1; property: "scale"; from: 1; to: 0; duration: UbuntuAnimation.FastDuration }
372+ UbuntuNumberAnimation { target: tutorialFinger2; property: "scale"; from: 1; to: 0; duration: UbuntuAnimation.FastDuration }
373+ }
374+ PauseAnimation { duration: UbuntuAnimation.SlowDuration }
375+ ParallelAnimation {
376+ UbuntuNumberAnimation { target: tutorialFinger1; property: "opacity"; to: 1; duration: UbuntuAnimation.FastDuration }
377+ UbuntuNumberAnimation { target: tutorialFinger2; property: "opacity"; to: 1; duration: UbuntuAnimation.FastDuration }
378+ UbuntuNumberAnimation { target: tutorialFinger1; property: "scale"; from: 0; to: 1; duration: UbuntuAnimation.FastDuration }
379+ UbuntuNumberAnimation { target: tutorialFinger2; property: "scale"; from: 0; to: 1; duration: UbuntuAnimation.FastDuration }
380+ }
381+ ParallelAnimation {
382+ UbuntuNumberAnimation { target: tutorialFinger1; property: "y"; to: root.height / 2 - internalGu * 10; duration: UbuntuAnimation.SleepyDuration }
383+ UbuntuNumberAnimation { target: tutorialFinger2; property: "y"; to: root.height / 2 - internalGu * 10; duration: UbuntuAnimation.SleepyDuration }
384+ }
385+ ParallelAnimation {
386+ UbuntuNumberAnimation { target: tutorialFinger1; property: "opacity"; to: 0; duration: UbuntuAnimation.FastDuration }
387+ UbuntuNumberAnimation { target: tutorialFinger2; property: "opacity"; to: 0; duration: UbuntuAnimation.FastDuration }
388+ UbuntuNumberAnimation { target: tutorialFinger1; property: "scale"; from: 1; to: 0; duration: UbuntuAnimation.FastDuration }
389+ UbuntuNumberAnimation { target: tutorialFinger2; property: "scale"; from: 1; to: 0; duration: UbuntuAnimation.FastDuration }
390+ }
391+ PauseAnimation { duration: UbuntuAnimation.SlowDuration }
392+ }
393+ UbuntuNumberAnimation { target: tutorialLabel; property: "opacity"; to: 0; duration: UbuntuAnimation.FastDuration }
394+
395+ PauseAnimation { duration: UbuntuAnimation.SleepyDuration }
396+ PropertyAction { target: tutorialLabel; property: "text"; value: i18n.tr("Find more settings in the system settings.") }
397+ UbuntuNumberAnimation { target: tutorialLabel; property: "opacity"; to: 1; duration: UbuntuAnimation.FastDuration }
398+ PauseAnimation { duration: 2000 }
399+ UbuntuNumberAnimation { target: tutorialLabel; property: "opacity"; to: 0; duration: UbuntuAnimation.FastDuration }
400+
401+ UbuntuNumberAnimation { target: oskButton; property: "opacity"; to: 1 }
402+ PropertyAction { targets: [leftButton, rightButton, oskButton]; property: "enabled"; value: true }
403+
404+ PropertyAction { target: settings; property: "touchpadTutorialHasRun"; value: true }
405+ }
138}
406}
qml/Dash/Previews/PreviewAudioPlayback.qml+1
@@ -70,6 +70,7 @@ PreviewWidget {
70 objectName: "playButton"
70 objectName: "playButton"
71 width: trackRow.column1Width
71 width: trackRow.column1Width
72 height: width
72 height: width
73+ activeFocusOnPress: false
73
74
74 onClicked: {
75 onClicked: {
75 if (trackItem.isPlayingItem) {
76 if (trackItem.isPlayingItem) {
qml/DisabledScreenNotice.qml+3−55
@@ -18,15 +18,12 @@ import QtQuick 2.4
18import QtQuick.Layouts 1.1
18import QtQuick.Layouts 1.1
19import Ubuntu.Components 1.3
19import Ubuntu.Components 1.3
20import Unity.Session 0.1
20import Unity.Session 0.1
21−import Unity.Screens 0.1
22import QtQuick.Window 2.2
21import QtQuick.Window 2.2
23import "Components"
22import "Components"
24
23
25Item {
24Item {
26 id: root
25 id: root
27
26
28− property bool infoNoteDisplayed: true
29−
30 // For testing
27 // For testing
31 property var screen: Screen
28 property var screen: Screen
32 property var orientationLock: OrientationLock
29 property var orientationLock: OrientationLock
@@ -36,10 +33,6 @@ Item {
36 name: applicationArguments.deviceName
33 name: applicationArguments.deviceName
37 }
34 }
38
35
39− Screens {
40− id: screens
41− }
42−
43 Item {
36 Item {
44 id: contentContainer
37 id: contentContainer
45 objectName: "contentContainer"
38 objectName: "contentContainer"
@@ -75,58 +68,13 @@ Item {
75 }
68 }
76 transformOrigin: Item.Center
69 transformOrigin: Item.Center
77
70
78− VirtualTouchPad {
79− anchors.fill: parent
80−
81− onPressedChanged: {
82− if (pressed && infoNoteDisplayed) {
83− infoNoteDisplayed = false;
84− }
85− }
86− }
87−
88 Rectangle {
71 Rectangle {
89 anchors.fill: parent
72 anchors.fill: parent
90− color: "#3b3b3b"
73+ color: UbuntuColors.jet
91 }
74 }
92
75
93− Item {
76+ VirtualTouchPad {
94− objectName: "infoNoticeArea"
95− anchors.fill: parent
96− opacity: infoNoteDisplayed ? 1 : 0
97− visible: opacity > 0
98− Behavior on opacity {
99− UbuntuNumberAnimation { }
100− }
101−
102− Column {
103− anchors.centerIn: parent
104− width: parent.width - (internalGu * 8)
105− spacing: internalGu * 4
106−
107− Label {
108− id: text
109− text: i18n.tr("Your device is now connected to an external display. Use this screen as a touch pad to interact with the pointer.")
110− color: "white"
111− width: parent.width
112− font.pixelSize: 2.5 * internalGu
113− wrapMode: Text.Wrap
114− }
115− Icon {
116− height: internalGu * 8
117− width: height
118− name: "input-touchpad-symbolic"
119− color: "white"
120− anchors.horizontalCenter: parent.horizontalCenter
121− }
122− }
123− }
124−
125− InputMethod {
126− id: inputMethod
127− // Don't resize when there is only one screen to avoid resize clashing with the InputMethod in the Shell.
128− enabled: screens.count > 1
129− objectName: "inputMethod"
77+ objectName: "virtualTouchPad"
130 anchors.fill: parent
78 anchors.fill: parent
131 }
79 }
132 }
80 }
qml/Greeter/Greeter.qml+1−5
@@ -145,11 +145,7 @@ Showable {
145 }
145 }
146 }
146 }
147
147
148− if (loader.item.sessionToStart === LightDMService.greeter.defaultSession) {
149− return LightDMService.greeter.defaultSession;
148+ return LightDMService.greeter.defaultSession;
150− } else {
151− return "ubuntu"; // The default / fallback
152− }
153 }
149 }
154
150
155 QtObject {
151 QtObject {
qml/Greeter/LoginList.qml+1−1
@@ -165,7 +165,7 @@ StyledItem {
165 }
165 }
166
166
167 delegate: Item {
167 delegate: Item {
168− width: parent.width
168+ width: userList.width
169 height: root.cellHeight
169 height: root.cellHeight
170
170
171 readonly property bool belowHighlight: (userList.currentIndex < 0 && index > 0) || (userList.currentIndex >= 0 && index > userList.currentIndex)
171 readonly property bool belowHighlight: (userList.currentIndex < 0 && index > 0) || (userList.currentIndex >= 0 && index > userList.currentIndex)
qml/Greeter/WideView.qml+7−2
@@ -125,6 +125,8 @@ FocusScope {
125 id: loginList
125 id: loginList
126 objectName: "loginList"
126 objectName: "loginList"
127
127
128+ property int selectedUserIndex: 0
129+
128 width: units.gu(40)
130 width: units.gu(40)
129 anchors {
131 anchors {
130 left: parent.left
132 left: parent.left
@@ -139,9 +141,12 @@ FocusScope {
139 Behavior on boxVerticalOffset { UbuntuNumberAnimation {} }
141 Behavior on boxVerticalOffset { UbuntuNumberAnimation {} }
140
142
141 model: root.userModel
143 model: root.userModel
142− currentSession: LightDMService.greeter.defaultSession
144+ currentSession: LightDMService.users.data(selectedUserIndex, LightDMService.userRoles.SessionRole);
143 onResponded: root.responded(response)
145 onResponded: root.responded(response)
146+ onSelected: {
144− onSelected: root.selected(index)
147+ root.selected(index)
148+ loginList.selectedUserIndex = index;
149+ }
145 onSessionChooserButtonClicked: parent.state = "SessionsList"
150 onSessionChooserButtonClicked: parent.state = "SessionsList"
146
151
147 Keys.forwardTo: [sessionChooserLoader.item]
152 Keys.forwardTo: [sessionChooserLoader.item]
qml/Launcher/BackgroundBlur.qmlnew file+81
@@ -0,0 +1,81 @@
1+/*
2+ * Copyright (C) 2016 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.4
18+import Ubuntu.Components 1.3
19+import QtGraphicalEffects 1.0
20+
21+Item {
22+ id: root
23+
24+ property int blurAmount: 32
25+ property Item sourceItem
26+ property rect blurRect: Qt.rect(0,0,0,0)
27+ property alias cached: fastBlur.cached
28+
29+ Rectangle {
30+ id: blurMask
31+ color: "yellow"
32+ x: blurRect.x
33+ y: blurRect.y
34+ width: blurRect.width
35+ height: blurRect.height
36+ }
37+
38+ ShaderEffect {
39+ id: maskedBlurEffect
40+ x: blurRect.x
41+ y: blurRect.y
42+ width: blurRect.width
43+ height: blurRect.height
44+
45+ property variant source: ShaderEffectSource {
46+ id: shaderEffectSource
47+ sourceItem: root.sourceItem
48+ hideSource: false
49+ sourceRect: root.blurRect
50+ }
51+
52+ property var mask: ShaderEffectSource {
53+ sourceItem: blurMask
54+ hideSource: true
55+ }
56+
57+ fragmentShader: "
58+ varying highp vec2 qt_TexCoord0;
59+ uniform sampler2D source;
60+ uniform sampler2D mask;
61+ void main(void)
62+ {
63+ highp vec4 sourceColor = texture2D(source, qt_TexCoord0);
64+ highp vec4 maskColor = texture2D(mask, qt_TexCoord0);
65+
66+ sourceColor *= maskColor.a;
67+
68+ gl_FragColor = sourceColor;
69+ }"
70+ }
71+
72+ FastBlur {
73+ id: fastBlur
74+ x: blurRect.x
75+ y: blurRect.y
76+ width: blurRect.width
77+ height: blurRect.height
78+ source: maskedBlurEffect
79+ radius: Math.min(blurAmount, 128)
80+ }
81+ }
qml/Launcher/Drawer.qmlnew file+306
@@ -0,0 +1,306 @@
1+/*
2+ * Copyright (C) 2016 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.4
18+import Ubuntu.Components 1.3
19+import Unity.Launcher 0.1
20+import Utils 0.1
21+import "../Components"
22+import Qt.labs.settings 1.0
23+
24+FocusScope {
25+ id: root
26+
27+ property int panelWidth: 0
28+ readonly property bool moving: listLoader.item && listLoader.item.moving
29+
30+ signal applicationSelected(string appId)
31+
32+ property bool draggingHorizontally: false
33+ property int dragDistance: 0
34+
35+ onFocusChanged: {
36+ if (focus) {
37+ searchField.selectAll();
38+ }
39+ }
40+
41+ function focusInput() {
42+ searchField.selectAll();
43+ searchField.focus = true;
44+ }
45+
46+ Settings {
47+ property alias selectedTab: sections.selectedIndex
48+ }
49+
50+ MouseArea {
51+ anchors.fill: parent
52+ hoverEnabled: true
53+ acceptedButtons: Qt.AllButtons
54+ onWheel: wheel.accepted = true
55+ }
56+
57+ Rectangle {
58+ anchors.fill: parent
59+ color: "#BF000000"
60+
61+ AppDrawerModel {
62+ id: appDrawerModel
63+ }
64+
65+ AppDrawerProxyModel {
66+ id: sortProxyModel
67+ source: appDrawerModel
68+ filterString: searchField.displayText
69+ sortBy: AppDrawerProxyModel.SortByAToZ
70+ }
71+
72+ Item {
73+ id: contentContainer
74+ anchors.fill: parent
75+ anchors.leftMargin: root.panelWidth
76+
77+ TextField {
78+ id: searchField
79+ anchors { left: parent.left; top: parent.top; right: parent.right; margins: units.gu(1) }
80+ placeholderText: i18n.tr("Search…")
81+ focus: true
82+ onAccepted: {
83+ if (searchField.displayText != "" && listLoader.item && listLoader.item.currentItem) {
84+ root.applicationSelected(listLoader.item.getFirstAppId());
85+ }
86+ }
87+ }
88+
89+ Item {
90+ id: sectionsContainer
91+ anchors { left: parent.left; top: searchField.bottom; right: parent.right; }
92+ height: sections.height
93+ clip: true
94+ z: 2
95+
96+ Sections {
97+ id: sections
98+ width: parent.width
99+ actions: [
100+ Action {
101+ text: i18n.ctr("Apps sorted alphabetically", "A-Z")
102+ // TODO: Disabling this for now as we don't get the right input from u-a-l yet.
103+// },
104+// Action {
105+// text: i18n.ctr("Most used apps", "Most used")
106+ }
107+ ]
108+
109+ Rectangle {
110+ anchors.bottom: parent.bottom
111+ height: units.dp(1)
112+ color: 'gray'
113+ width: contentContainer.width
114+ }
115+ }
116+ }
117+
118+ Loader {
119+ id: listLoader
120+ anchors { left: parent.left; top: sectionsContainer.bottom; right: parent.right; bottom: parent.bottom; leftMargin: units.gu(1); rightMargin: units.gu(1) }
121+ sourceComponent: {
122+ switch (sections.selectedIndex) {
123+ case 0: return aToZComponent;
124+ case 1: return mostUsedComponent;
125+ }
126+ }
127+ Binding {
128+ target: listLoader.item || null
129+ property: "objectName"
130+ value: "drawerItemList"
131+ }
132+ }
133+
134+ MouseArea {
135+ parent: listLoader.item ? listLoader.item : null
136+ anchors.fill: parent
137+ propagateComposedEvents: true
138+ property int oldX: 0
139+ onPressed: {
140+ oldX = mouseX;
141+ }
142+ onMouseXChanged: {
143+ var diff = oldX - mouseX;
144+ root.draggingHorizontally |= diff > units.gu(2);
145+ if (!root.draggingHorizontally) {
146+ return;
147+ }
148+ propagateComposedEvents = false;
149+ parent.interactive = false;
150+ root.dragDistance += diff;
151+ oldX = mouseX
152+ }
153+ onReleased: {
154+ if (root.draggingHorizontally) {
155+ root.draggingHorizontally = false;
156+ parent.interactive = true;
157+ }
158+ reactivateTimer.start();
159+ }
160+ Timer {
161+ id: reactivateTimer
162+ interval: 0
163+ onTriggered: parent.propagateComposedEvents = true;
164+ }
165+ }
166+
167+ Component {
168+ id: mostUsedComponent
169+ DrawerListView {
170+
171+ header: MoreAppsHeader {
172+ width: parent.width
173+ height: units.gu(6)
174+ }
175+
176+ model: AppDrawerProxyModel {
177+ source: sortProxyModel
178+ group: AppDrawerProxyModel.GroupByAll
179+ sortBy: AppDrawerProxyModel.SortByUsage
180+ }
181+
182+ delegate: UbuntuShape {
183+ width: parent.width
184+ color: "#20ffffff"
185+ aspect: UbuntuShape.Flat
186+ // NOTE: Cannot use gridView.rows here as it would evaluate to 0 at first and only update later,
187+ // which messes up the ListView.
188+ height: (Math.ceil(mostUsedGridView.model.count / mostUsedGridView.columns) * mostUsedGridView.delegateHeight) + units.gu(2)
189+
190+ readonly property string appId: model.appId
191+
192+ DrawerGridView {
193+ id: mostUsedGridView
194+ anchors.fill: parent
195+ topMargin: units.gu(1)
196+ bottomMargin: units.gu(1)
197+ clip: true
198+
199+ model: sortProxyModel
200+
201+ delegateWidth: units.gu(8)
202+ delegateHeight: units.gu(10)
203+ delegate: drawerDelegateComponent
204+ }
205+ }
206+ }
207+ }
208+
209+ Component {
210+ id: aToZComponent
211+ DrawerListView {
212+
213+ header: MoreAppsHeader {
214+ width: parent.width
215+ height: units.gu(6)
216+ }
217+
218+ model: AppDrawerProxyModel {
219+ source: sortProxyModel
220+ sortBy: AppDrawerProxyModel.SortByAToZ
221+ group: AppDrawerProxyModel.GroupByAToZ
222+ }
223+
224+ delegate: UbuntuShape {
225+ width: parent.width
226+ color: "#20ffffff"
227+ aspect: UbuntuShape.Flat
228+
229+ readonly property string appId: model.appId
230+
231+ // NOTE: Cannot use gridView.rows here as it would evaluate to 0 at first and only update later,
232+ // which messes up the ListView.
233+ height: (Math.ceil(gridView.model.count / gridView.columns) * gridView.delegateHeight) +
234+ categoryNameLabel.implicitHeight + units.gu(2)
235+
236+ Label {
237+ id: categoryNameLabel
238+ anchors { left: parent.left; top: parent.top; right: parent.right; margins: units.gu(1) }
239+ text: model.letter
240+ }
241+
242+ DrawerGridView {
243+ id: gridView
244+ anchors { left: parent.left; top: categoryNameLabel.bottom; right: parent.right; topMargin: units.gu(1) }
245+ height: rows * delegateHeight
246+
247+ interactive: false
248+
249+ model: AppDrawerProxyModel {
250+ id: categoryModel
251+ source: sortProxyModel
252+ filterLetter: model.letter
253+ }
254+ delegateWidth: units.gu(8)
255+ delegateHeight: units.gu(10)
256+ delegate: drawerDelegateComponent
257+ }
258+ }
259+ }
260+ }
261+ }
262+
263+ Component {
264+ id: drawerDelegateComponent
265+ AbstractButton {
266+ width: GridView.view.cellWidth
267+ height: units.gu(10)
268+ objectName: "drawerItem_" + model.appId
269+
270+ onClicked: root.applicationSelected(model.appId)
271+
272+ Column {
273+ width: units.gu(8)
274+ anchors.horizontalCenter: parent.horizontalCenter
275+ height: childrenRect.height
276+ spacing: units.gu(1)
277+
278+ UbuntuShape {
279+ id: appIcon
280+ width: units.gu(6)
281+ height: 7.5 / 8 * width
282+ anchors.horizontalCenter: parent.horizontalCenter
283+ backgroundMode: UbuntuShape.SolidColor
284+ backgroundColor: UbuntuColors.lightGrey
285+ radius: "medium"
286+ borderSource: 'undefined'
287+ source: Image {
288+ id: sourceImage
289+ sourceSize.width: appIcon.width
290+ source: model.icon
291+ }
292+ sourceFillMode: UbuntuShape.PreserveAspectCrop
293+ }
294+
295+ Label {
296+ text: model.name
297+ width: parent.width
298+ horizontalAlignment: Text.AlignHCenter
299+ fontSize: "small"
300+ elide: Text.ElideRight
301+ }
302+ }
303+ }
304+ }
305+ }
306+}
qml/Launcher/DrawerGridView.qmlnew file+47
@@ -0,0 +1,47 @@
1+/*
2+ * Copyright (C) 2016 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.4
18+import "../Components"
19+
20+Item {
21+ id: root
22+
23+ property int delegateWidth: units.gu(10)
24+ property int delegateHeight: units.gu(10)
25+ property alias delegate: gridView.delegate
26+ property alias model: gridView.model
27+ property alias interactive: gridView.interactive
28+
29+ property alias header: gridView.header
30+ property alias topMargin: gridView.topMargin
31+ property alias bottomMargin: gridView.bottomMargin
32+
33+ readonly property int columns: width / delegateWidth
34+ readonly property int rows: Math.ceil(gridView.model.count / root.columns)
35+
36+ GridView {
37+ id: gridView
38+ anchors.fill: parent
39+ leftMargin: spacing
40+
41+ readonly property int overflow: width - (root.columns * root.delegateWidth)
42+ readonly property real spacing: overflow / (root.columns)
43+
44+ cellWidth: root.delegateWidth + spacing
45+ cellHeight: root.delegateHeight
46+ }
47+}
qml/Launcher/DrawerListView.qmlnew file+32
@@ -0,0 +1,32 @@
1+/*
2+ * Copyright (C) 2016 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.4
18+import Ubuntu.Components 1.3
19+import "../Components"
20+
21+ListView {
22+ id: root
23+ anchors.fill: parent
24+ topMargin: units.gu(1)
25+ bottomMargin: units.gu(1)
26+ spacing: units.gu(1)
27+ clip: true
28+
29+ function getFirstAppId() {
30+ return model.appId(0);
31+ }
32+}
qml/Launcher/Launcher.qml+182−34
@@ -19,18 +19,23 @@ import "../Components"
19import Ubuntu.Components 1.3
19import Ubuntu.Components 1.3
20import Ubuntu.Gestures 0.1
20import Ubuntu.Gestures 0.1
21import Unity.Launcher 0.1
21import Unity.Launcher 0.1
22+import Utils 0.1 as Utils
22
23
23FocusScope {
24FocusScope {
24 id: root
25 id: root
25
26
27+ readonly property int ignoreHideIfMouseOverLauncher: 1
28+
26 property bool autohideEnabled: false
29 property bool autohideEnabled: false
27 property bool lockedVisible: false
30 property bool lockedVisible: false
28 property bool available: true // can be used to disable all interactions
31 property bool available: true // can be used to disable all interactions
29 property alias inverted: panel.inverted
32 property alias inverted: panel.inverted
33+ property Item blurSource: null
34+ property int topPanelHeight: 0
35+ property bool drawerEnabled: true
30
36
31 property int panelWidth: units.gu(10)
37 property int panelWidth: units.gu(10)
32 property int dragAreaWidth: units.gu(1)
38 property int dragAreaWidth: units.gu(1)
33− property int minimizeDistance: units.gu(26)
34 property real progress: dragArea.dragging && dragArea.touchPosition.x > panelWidth ?
39 property real progress: dragArea.dragging && dragArea.touchPosition.x > panelWidth ?
35 (width * (dragArea.touchPosition.x-panelWidth) / (width - panelWidth)) : 0
40 (width * (dragArea.touchPosition.x-panelWidth) / (width - panelWidth)) : 0
36
41
@@ -43,13 +48,11 @@ FocusScope {
43 readonly property alias shortcutHintsShown: panel.shortcutHintsShown
48 readonly property alias shortcutHintsShown: panel.shortcutHintsShown
44
49
45 readonly property bool shown: panel.x > -panel.width
50 readonly property bool shown: panel.x > -panel.width
51+ readonly property bool drawerShown: drawer.x == 0
46
52
47 // emitted when an application is selected
53 // emitted when an application is selected
48 signal launcherApplicationSelected(string appId)
54 signal launcherApplicationSelected(string appId)
49
55
50− // emitted when the apps dash should be shown because of a swipe gesture
51− signal dash()
52−
53 // emitted when the dash icon in the launcher has been tapped
56 // emitted when the dash icon in the launcher has been tapped
54 signal showDashHome()
57 signal showDashHome()
55
58
@@ -62,6 +65,9 @@ FocusScope {
62 }
65 }
63
66
64 onSuperPressedChanged: {
67 onSuperPressedChanged: {
68+ if (state == "drawer")
69+ return;
70+
65 if (superPressed) {
71 if (superPressed) {
66 superPressTimer.start();
72 superPressTimer.start();
67 superLongPressTimer.start();
73 superLongPressTimer.start();
@@ -102,7 +108,10 @@ FocusScope {
102 }
108 }
103 }
109 }
104
110
105− function hide() {
111+ function hide(flags) {
112+ if ((flags & ignoreHideIfMouseOverLauncher) && Utils.Functions.itemUnderMouse(panel)) {
113+ return;
114+ }
106 switchToNextState("")
115 switchToNextState("")
107 }
116 }
108
117
@@ -132,7 +141,7 @@ FocusScope {
132 }
141 }
133
142
134 function pushEdge(amount) {
143 function pushEdge(amount) {
135− if (root.state === "") {
144+ if (root.state === "" || root.state == "visible" || root.state == "visibleTemporary") {
136 edgeBarrier.push(amount);
145 edgeBarrier.push(amount);
137 }
146 }
138 }
147 }
@@ -143,6 +152,22 @@ FocusScope {
143 switchToNextState("visible")
152 switchToNextState("visible")
144 }
153 }
145
154
155+ function openDrawer(focusInputField) {
156+ if (!drawerEnabled) {
157+ return;
158+ }
159+
160+ panel.shortcutHintsShown = false;
161+ superPressTimer.stop();
162+ superLongPressTimer.stop();
163+ root.focus = true;
164+ drawer.focus = true;
165+ if (focusInputField) {
166+ drawer.focusInput();
167+ }
168+ switchToNextState("drawer")
169+ }
170+
146 Keys.onPressed: {
171 Keys.onPressed: {
147 switch (event.key) {
172 switch (event.key) {
148 case Qt.Key_Backtab:
173 case Qt.Key_Backtab:
@@ -278,7 +303,7 @@ FocusScope {
278 InverseMouseArea {
303 InverseMouseArea {
279 id: closeMouseArea
304 id: closeMouseArea
280 anchors.fill: panel
305 anchors.fill: panel
281− enabled: root.state == "visible" && (!root.lockedVisible || panel.highlightIndex >= -1)
306+ enabled: root.state == "visible" || root.state == "drawer"
282 visible: enabled
307 visible: enabled
283 onPressed: {
308 onPressed: {
284 mouse.accepted = false;
309 mouse.accepted = false;
@@ -307,23 +332,61 @@ FocusScope {
307 }
332 }
308 }
333 }
309
334
310− EdgeBarrier {
335+ BackgroundBlur {
311− id: edgeBarrier
336+ id: backgroundBlur
312− edge: Qt.LeftEdge
337+ anchors.fill: parent
338+ anchors.topMargin: root.inverted ? 0 : -root.topPanelHeight
339+ visible: root.blurSource && drawer.x > -drawer.width
340+ blurAmount: units.gu(6)
341+ sourceItem: root.blurSource
342+ blurRect: Qt.rect(panel.width,
343+ root.topPanelHeight,
344+ drawer.width + drawer.x - panel.width,
345+ height - root.topPanelHeight)
346+ cached: drawer.moving
347+ }
348+
349+ Drawer {
350+ id: drawer
351+ objectName: "drawer"
352+ anchors {
313− target: parent
353+ top: parent.top
314− enabled: root.available
354+ topMargin: root.inverted ? root.topPanelHeight : 0
355+ bottom: parent.bottom
356+ right: parent.left
357+ }
358+ width: Math.min(root.width, units.gu(90)) * .9
359+ panelWidth: panel.width
360+ visible: x > -width
361+
362+ Behavior on anchors.rightMargin {
363+ enabled: !dragArea.dragging && !launcherDragArea.drag.active && panel.animate && !drawer.draggingHorizontally
364+ NumberAnimation {
365+ duration: 300
366+ easing.type: Easing.OutCubic
367+ }
368+ }
369+
370+ onApplicationSelected: {
371+ root.hide();
372+ root.launcherApplicationSelected(appId)
373+ root.focus = false;
374+ }
375+
376+ Keys.onEscapePressed: {
315− onPassed: { root.switchToNextState("visibleTemporary"); }
377+ switchToNextState("");
316− material: Component {
378+ root.focus = false;
317− Item {
379+ }
318− Rectangle {
380+
319− width: parent.height
381+ onDragDistanceChanged: {
320− height: parent.width
382+ anchors.rightMargin = Math.max(-drawer.width, anchors.rightMargin + dragDistance);
321− rotation: -90
383+ }
322− anchors.centerIn: parent
384+ onDraggingHorizontallyChanged: {
323− gradient: Gradient {
385+ if (!draggingHorizontally) {
324− GradientStop { position: 0.0; color: Qt.rgba(panel.color.r, panel.color.g, panel.color.b, .5)}
386+ if (drawer.x < -units.gu(10)) {
325− GradientStop { position: 1.0; color: Qt.rgba(panel.color.r,panel.color.g,panel.color.b,0)}
387+ root.hide();
326− }
388+ } else {
389+ root.openDrawer();
327 }
390 }
328 }
391 }
329 }
392 }
@@ -332,7 +395,7 @@ FocusScope {
332 LauncherPanel {
395 LauncherPanel {
333 id: panel
396 id: panel
334 objectName: "launcherPanel"
397 objectName: "launcherPanel"
335− enabled: root.available && root.state == "visible" || root.state == "visibleTemporary"
398+ enabled: root.available && (root.state == "visible" || root.state == "visibleTemporary" || root.state == "drawer")
336 width: root.panelWidth
399 width: root.panelWidth
337 anchors {
400 anchors {
338 top: parent.top
401 top: parent.top
@@ -359,11 +422,11 @@ FocusScope {
359 property bool animate: true
422 property bool animate: true
360
423
361 onApplicationSelected: {
424 onApplicationSelected: {
362− root.hide();
425+ root.hide(ignoreHideIfMouseOverLauncher);
363 launcherApplicationSelected(appId)
426 launcherApplicationSelected(appId)
364 }
427 }
365 onShowDashHome: {
428 onShowDashHome: {
366− root.hide();
429+ root.hide(ignoreHideIfMouseOverLauncher);
367 root.showDashHome();
430 root.showDashHome();
368 }
431 }
369
432
@@ -394,6 +457,38 @@ FocusScope {
394 }
457 }
395 }
458 }
396
459
460+ EdgeBarrier {
461+ id: edgeBarrier
462+ edge: Qt.LeftEdge
463+ target: parent
464+ enabled: root.available
465+ onProgressChanged: {
466+ if (progress > .5 && root.state != "visibleTemporary" && root.state != "drawer" && root.state != "visible") {
467+ root.switchToNextState("visibleTemporary");
468+ }
469+ }
470+ onPassed: {
471+ if (root.drawerEnabled) {
472+ root.switchToNextState("drawer");
473+ }
474+ }
475+
476+ material: Component {
477+ Item {
478+ Rectangle {
479+ width: parent.height
480+ height: parent.width
481+ rotation: -90
482+ anchors.centerIn: parent
483+ gradient: Gradient {
484+ GradientStop { position: 0.0; color: Qt.rgba(panel.color.r, panel.color.g, panel.color.b, .5)}
485+ GradientStop { position: 1.0; color: Qt.rgba(panel.color.r,panel.color.g,panel.color.b,0)}
486+ }
487+ }
488+ }
489+ }
490+ }
491+
397 SwipeArea {
492 SwipeArea {
398 id: dragArea
493 id: dragArea
399 objectName: "launcherDragArea"
494 objectName: "launcherDragArea"
@@ -405,25 +500,62 @@ FocusScope {
405 width: root.dragAreaWidth
500 width: root.dragAreaWidth
406 height: root.height
501 height: root.height
407
502
503+ function easeInOutCubic(t) { return t<.5 ? 4*t*t*t : (t-1)*(2*t-2)*(2*t-2)+1 }
504+
505+ property var lastDragPoints: []
506+
507+ function dragDirection() {
508+ if (lastDragPoints.length < 5) {
509+ return "unknown";
510+ }
511+
512+ var toRight = true;
513+ var toLeft = true;
514+ for (var i = lastDragPoints.length - 5; i < lastDragPoints.length; i++) {
515+ if (toRight && lastDragPoints[i] < lastDragPoints[i-1]) {
516+ toRight = false;
517+ }
518+ if (toLeft && lastDragPoints[i] > lastDragPoints[i-1]) {
519+ toLeft = false;
520+ }
521+ }
522+ return toRight ? "right" : toLeft ? "left" : "unknown";
523+ }
524+
408 onDistanceChanged: {
525 onDistanceChanged: {
409− if (!dragging || launcher.state == "visible")
526+ if (dragging && launcher.state != "visible" && launcher.state != "drawer") {
410− return;
527+ panel.x = -panel.width + Math.min(Math.max(0, distance), panel.width);
528+ }
411
529
530+ if (root.drawerEnabled && dragging && launcher.state != "drawer") {
531+ lastDragPoints.push(distance)
532+ var drawerHintDistance = panel.width + units.gu(1)
533+ if (distance < drawerHintDistance) {
534+ drawer.anchors.rightMargin = -Math.min(Math.max(0, distance), drawer.width);
535+ } else {
412− panel.x = -panel.width + Math.min(Math.max(0, distance), panel.width);
536+ var linearDrawerX = Math.min(Math.max(0, distance - drawerHintDistance), drawer.width);
537+ var linearDrawerProgress = linearDrawerX / (drawer.width)
538+ var easedDrawerProgress = easeInOutCubic(linearDrawerProgress);
539+ drawer.anchors.rightMargin = -(drawerHintDistance + easedDrawerProgress * (drawer.width - drawerHintDistance));
540+ }
541+ }
413 }
542 }
414
543
415 onDraggingChanged: {
544 onDraggingChanged: {
416 if (!dragging) {
545 if (!dragging) {
417 if (distance > panel.width / 2) {
546 if (distance > panel.width / 2) {
418− root.switchToNextState("visible")
547+ if (root.drawerEnabled && distance > panel.width * 3 && dragDirection() !== "left") {
419− if (distance > minimizeDistance) {
548+ root.switchToNextState("drawer");
420− root.dash();
549+ root.focus = true;
550+ } else {
551+ root.switchToNextState("visible");
421 }
552 }
422 } else if (root.state === "") {
553 } else if (root.state === "") {
423 // didn't drag far enough. rollback
554 // didn't drag far enough. rollback
424− root.switchToNextState("")
555+ root.switchToNextState("");
425 }
556 }
426 }
557 }
558+ lastDragPoints = [];
427 }
559 }
428 }
560 }
429
561
@@ -434,6 +566,10 @@ FocusScope {
434 target: panel
566 target: panel
435 x: -root.panelWidth
567 x: -root.panelWidth
436 }
568 }
569+ PropertyChanges {
570+ target: drawer
571+ anchors.rightMargin: 0
572+ }
437 },
573 },
438 State {
574 State {
439 name: "visible"
575 name: "visible"
@@ -441,6 +577,18 @@ FocusScope {
441 target: panel
577 target: panel
442 x: -root.x // so we never go past panelWidth, even when teased by tutorial
578 x: -root.x // so we never go past panelWidth, even when teased by tutorial
443 }
579 }
580+ PropertyChanges {
581+ target: drawer
582+ anchors.rightMargin: 0
583+ }
584+ },
585+ State {
586+ name: "drawer"
587+ extend: "visible"
588+ PropertyChanges {
589+ target: drawer
590+ anchors.rightMargin: -drawer.width + root.x // so we never go past panelWidth, even when teased by tutorial
591+ }
444 },
592 },
445 State {
593 State {
446 name: "visibleTemporary"
594 name: "visibleTemporary"
qml/Launcher/MoreAppsHeader.qmlnew file+46
@@ -0,0 +1,46 @@
1+import QtQuick 2.4
2+import Ubuntu.Components 1.3
3+
4+AbstractButton {
5+ id: root
6+
7+ onClicked: {
8+ // TODO: Make this point to the snappy store as soon as we stop landing to vivid
9+ Qt.openUrlExternally("scope://com.canonical.scopes.clickstore")
10+ }
11+
12+ UbuntuShape {
13+ width: parent.width
14+ height: parent.height - units.gu(1)
15+ color: "#20ffffff"
16+ aspect: UbuntuShape.Flat
17+
18+ Row {
19+ anchors.fill: parent
20+ anchors.margins: units.gu(1)
21+ spacing: units.gu(1)
22+
23+ Icon {
24+ height: units.gu(2.2)
25+ width: height
26+ name: "stock_application"
27+ anchors.verticalCenter: parent.verticalCenter
28+ color: "white"
29+ }
30+
31+ Label {
32+ text: i18n.tr("More apps in the store")
33+ anchors.verticalCenter: parent.verticalCenter
34+ fontSize: "small"
35+ }
36+
37+ Icon {
38+ height: units.gu(2.5)
39+ width: height
40+ anchors.verticalCenter: parent.verticalCenter
41+ name: "go-next"
42+ color: "white"
43+ }
44+ }
45+ }
46+}
qml/Panel/Indicators/MenuItemFactory.qml+22−1
@@ -106,7 +106,7 @@ Item {
106 }
106 }
107
107
108 if (component === undefined) {
108 if (component === undefined) {
109− console.debug("Don't know how to make " + modelData.type + " for " + indicator);
109+ console.debug("Don't know how to make " + type + " for " + indicator);
110 }
110 }
111
111
112 return component
112 return component
@@ -398,7 +398,9 @@ Item {
398 id: switchItem
398 id: switchItem
399 objectName: "switchMenu"
399 objectName: "switchMenu"
400 property QtObject menuData: null
400 property QtObject menuData: null
401+ property var menuModel: menuFactory.menuModel
401 property int menuIndex: -1
402 property int menuIndex: -1
403+ property var extendedData: menuData && menuData.ext || undefined
402 property bool serverChecked: menuData && menuData.isToggled || false
404 property bool serverChecked: menuData && menuData.isToggled || false
403
405
404 text: menuData && menuData.label || ""
406 text: menuData && menuData.label || ""
@@ -407,6 +409,25 @@ Item {
407 checked: serverChecked
409 checked: serverChecked
408 highlightWhenPressed: false
410 highlightWhenPressed: false
409
411
412+ property var subtitleAction: UnityMenuAction {
413+ model: menuModel
414+ index: menuIndex
415+ name: getExtendedProperty(extendedData, "xCanonicalSubtitleAction", "")
416+ }
417+ subtitle.text: subtitleAction.valid ? subtitleAction.state : ""
418+
419+ onMenuModelChanged: {
420+ loadAttributes();
421+ }
422+ onMenuIndexChanged: {
423+ loadAttributes();
424+ }
425+
426+ function loadAttributes() {
427+ if (!menuModel || menuIndex == -1) return;
428+ menuModel.loadExtendedAttributes(menuIndex, {'x-canonical-subtitle-action': 'string'});
429+ }
430+
410 ServerPropertySynchroniser {
431 ServerPropertySynchroniser {
411 objectName: "sync"
432 objectName: "sync"
412 syncTimeout: Utils.Constants.indicatorValueTimeout
433 syncTimeout: Utils.Constants.indicatorValueTimeout
qml/Shell.qml+11−35
@@ -124,7 +124,7 @@ StyledItem {
124 greeter.notifyAppFocusRequested(appId);
124 greeter.notifyAppFocusRequested(appId);
125
125
126 panel.indicators.hide();
126 panel.indicators.hide();
127− launcher.hide();
127+ launcher.hide(launcher.ignoreHideIfMouseOverLauncher);
128 }
128 }
129
129
130 // For autopilot consumption
130 // For autopilot consumption
@@ -278,8 +278,6 @@ StyledItem {
278
278
279 dragAreaWidth: shell.edgeSize
279 dragAreaWidth: shell.edgeSize
280 background: wallpaperResolver.background
280 background: wallpaperResolver.background
281− leftEdgeDragProgress: !greeter || greeter.locked || !tutorial.launcherLongSwipeEnabled ? 0 :
282− Math.max(0, (launcher.dragDistance * (stage.width - launcher.panelWidth) / stage.width) - launcher.panelWidth)
283
281
284 applicationManager: ApplicationManager
282 applicationManager: ApplicationManager
285 topLevelSurfaceList: topLevelSurfaceList
283 topLevelSurfaceList: topLevelSurfaceList
@@ -301,14 +299,12 @@ StyledItem {
301
299
302 interactive: (!greeter || !greeter.shown)
300 interactive: (!greeter || !greeter.shown)
303 && panel.indicators.fullyClosed
301 && panel.indicators.fullyClosed
304− && launcher.progress == 0
305 && !notifications.useModal
302 && !notifications.useModal
306
303
307 onInteractiveChanged: { if (interactive) { focus = true; } }
304 onInteractiveChanged: { if (interactive) { focus = true; } }
308
305
309 leftMargin: shell.usageScenario == "desktop" && !settings.autohideLauncher ? launcher.panelWidth: 0
306 leftMargin: shell.usageScenario == "desktop" && !settings.autohideLauncher ? launcher.panelWidth: 0
310 suspended: greeter.shown
307 suspended: greeter.shown
311− keepDashRunning: launcher.shown || launcher.dashSwipe
312 altTabPressed: physicalKeysMapper.altTabPressed
308 altTabPressed: physicalKeysMapper.altTabPressed
313 oskEnabled: shell.oskEnabled
309 oskEnabled: shell.oskEnabled
314 spreadEnabled: tutorial.spreadEnabled && (!greeter || (!greeter.hasLockedApp && !greeter.shown))
310 spreadEnabled: tutorial.spreadEnabled && (!greeter || (!greeter.hasLockedApp && !greeter.shown))
@@ -323,7 +319,7 @@ StyledItem {
323 topMargin: panel.panelHeight
319 topMargin: panel.panelHeight
324 leftMargin: launcher.lockedVisible ? launcher.panelWidth : 0
320 leftMargin: launcher.lockedVisible ? launcher.panelWidth : 0
325 }
321 }
326− z: notifications.useModal || panel.indicators.shown || wizard.active || tutorial.running ? overlay.z + 1 : overlay.z - 1
322+ z: notifications.useModal || panel.indicators.shown || wizard.active || tutorial.running || launcher.drawerShown ? overlay.z + 1 : overlay.z - 1
327 }
323 }
328
324
329 Loader {
325 Loader {
@@ -345,7 +341,6 @@ StyledItem {
345 enabled: panel.indicators.fullyClosed // hides OSK when panel is open
341 enabled: panel.indicators.fullyClosed // hides OSK when panel is open
346 hides: [launcher, panel.indicators]
342 hides: [launcher, panel.indicators]
347 tabletMode: shell.usageScenario != "phone"
343 tabletMode: shell.usageScenario != "phone"
348− launcherOffset: launcher.progress
349 forcedUnlock: wizard.active || shell.mode === "full-shell"
344 forcedUnlock: wizard.active || shell.mode === "full-shell"
350 background: wallpaperResolver.cachedBackground
345 background: wallpaperResolver.cachedBackground
351 hasCustomBackground: wallpaperResolver.hasCustomBackground
346 hasCustomBackground: wallpaperResolver.hasCustomBackground
@@ -434,19 +429,6 @@ StyledItem {
434 }
429 }
435 }
430 }
436
431
437− function showDash() {
438− if (greeter.notifyShowingDashFromDrag()) {
439− launcher.fadeOut();
440− }
441−
442− if (!greeter.locked && tutorial.launcherLongSwipeEnabled
443− && (ApplicationManager.focusedApplicationId != "unity8-dash" || stage.spreadShown)) {
444− ApplicationManager.requestFocusApplication("unity8-dash")
445− launcher.fadeOut();
446− stage.closeSpread();
447− }
448− }
449−
450 Item {
432 Item {
451 id: overlay
433 id: overlay
452 z: 10
434 z: 10
@@ -497,15 +479,6 @@ StyledItem {
497 id: launcher
479 id: launcher
498 objectName: "launcher"
480 objectName: "launcher"
499
481
500− /*
501− * Since the Dash doesn't have the same controll over surfaces that the
502− * Shell does, it can't slowly move the scope out of the way, as the shell
503− * does with apps, and the dash is show instantly. This allows for some
504− * leeway and prevents accidental home swipes.
505− */
506− readonly property real offset: shell.focusedApplicationId == "unity8-dash" ? units.gu(12) : 0
507− readonly property bool dashSwipe: progress > offset
508−
509 anchors.top: parent.top
482 anchors.top: parent.top
510 anchors.topMargin: inverted ? 0 : panel.panelHeight
483 anchors.topMargin: inverted ? 0 : panel.panelHeight
511 anchors.bottom: parent.bottom
484 anchors.bottom: parent.bottom
@@ -521,14 +494,11 @@ StyledItem {
521 superTabPressed: physicalKeysMapper.superTabPressed
494 superTabPressed: physicalKeysMapper.superTabPressed
522 panelWidth: units.gu(settings.launcherWidth)
495 panelWidth: units.gu(settings.launcherWidth)
523 lockedVisible: shell.usageScenario == "desktop" && !settings.autohideLauncher && !panel.fullscreenMode
496 lockedVisible: shell.usageScenario == "desktop" && !settings.autohideLauncher && !panel.fullscreenMode
497+ blurSource: greeter.shown ? greeter : stages
498+ topPanelHeight: panel.panelHeight
499+ drawerEnabled: !greeter.shown
524
500
525 onShowDashHome: showHome()
501 onShowDashHome: showHome()
526− onDash: showDash()
527− onDashSwipeChanged: {
528− if (dashSwipe) {
529− dash.setCurrentScope(0, false, true)
530− }
531− }
532 onLauncherApplicationSelected: {
502 onLauncherApplicationSelected: {
533 greeter.notifyUserRequestedApp();
503 greeter.notifyUserRequestedApp();
534 shell.activateApplication(appId);
504 shell.activateApplication(appId);
@@ -544,6 +514,12 @@ StyledItem {
544 }
514 }
545 }
515 }
546
516
517+ GlobalShortcut {
518+ shortcut: Qt.MetaModifier | Qt.Key_A
519+ onTriggered: {
520+ launcher.openDrawer(true);
521+ }
522+ }
547 GlobalShortcut {
523 GlobalShortcut {
548 shortcut: Qt.AltModifier | Qt.Key_F1
524 shortcut: Qt.AltModifier | Qt.Key_F1
549 onTriggered: {
525 onTriggered: {
qml/Stage/MoveHandler.qml+2−2
@@ -90,8 +90,8 @@ QtObject {
90 if (target.anyMaximized) {
90 if (target.anyMaximized) {
91 // keep distanceX relative to the normal window width minus the window control buttons (+spacing)
91 // keep distanceX relative to the normal window width minus the window control buttons (+spacing)
92 // so that dragging it back doesn't make the window jump around to weird positions, away from the mouse pointer
92 // so that dragging it back doesn't make the window jump around to weird positions, away from the mouse pointer
93− priv.distanceX = MathUtils.clampAndProject(pos.x, 0, target.width, buttonsWidth, target.resizeArea.normalWidth);
93+ priv.distanceX = MathUtils.clampAndProject(pos.x, 0, target.width, buttonsWidth, target.normalWidth);
94− priv.distanceY = MathUtils.clampAndProject(pos.y, 0, target.height, 0, target.resizeArea.normalHeight);
94+ priv.distanceY = MathUtils.clampAndProject(pos.y, 0, target.height, 0, target.normalHeight);
95 } else {
95 } else {
96 priv.distanceX = pos.x;
96 priv.distanceX = pos.x;
97 priv.distanceY = pos.y;
97 priv.distanceY = pos.y;
qml/Stage/Spread/WindowedRightEdgeMaths.qml+19−4
@@ -25,21 +25,31 @@ QtObject {
25 // Input
25 // Input
26 property int itemIndex: 0
26 property int itemIndex: 0
27 property int normalZ: 0
27 property int normalZ: 0
28− property real progress: 0
29 property int startWidth: 0
28 property int startWidth: 0
30 property int startHeight: 0
29 property int startHeight: 0
31 property int startX: 0
30 property int startX: 0
32 property int targetX: 0
31 property int targetX: 0
33 property int startY: 0
32 property int startY: 0
34 property int targetY: 0
33 property int targetY: 0
35−// property real startAngle: 40
36 property real targetAngle: 0
34 property real targetAngle: 0
37 property int targetHeight: 0
35 property int targetHeight: 0
38 property real targetScale: 0
36 property real targetScale: 0
37+ property real swipeProgress: 0
38+ property real pushProgress: 0
39
39
40 // Config
40 // Config
41 property real breakPoint: 0.4
41 property real breakPoint: 0.4
42
42
43+ // internal
44+ readonly property real progress: {
45+ if (pushProgress > 0) {
46+ // we don't do the full animation when pushing, just a little bit
47+ return MathUtils.linearAnimation(0, 1, 0, breakPoint + .1, pushProgress)
48+ } else {
49+ return swipeProgress;
50+ }
51+ }
52+
43 // Output
53 // Output
44
54
45 readonly property real scaleToPreviewProgress: {
55 readonly property real scaleToPreviewProgress: {
@@ -68,12 +78,17 @@ QtObject {
68
78
69 readonly property int animatedZ: {
79 readonly property int animatedZ: {
70 if (progress < breakPoint + (1 - breakPoint) / 2) {
80 if (progress < breakPoint + (1 - breakPoint) / 2) {
81+ if (swipeProgress > 0) {
71− return itemIndex == 1 ? normalZ + 2 : normalZ
82+ return itemIndex == 1 ? normalZ + 2 : normalZ
83+ }
84+ if (pushProgress > 0) {
85+ return normalZ;
86+ }
72 }
87 }
73 return itemIndex
88 return itemIndex
74 }
89 }
75
90
76− readonly property real opacityMask: itemIndex == 1 ? MathUtils.linearAnimation(0, breakPoint, 0, 1, progress) : 1
91+ readonly property real opacityMask: (swipeProgress > 0 && itemIndex == 1) ? MathUtils.linearAnimation(0, breakPoint, 0, 1, progress) : 1
77
92
78 readonly property real animatedScale: progress < breakPoint ? 1 : MathUtils.linearAnimation(breakPoint, 1, 1, targetScale, progress)
93 readonly property real animatedScale: progress < breakPoint ? 1 : MathUtils.linearAnimation(breakPoint, 1, 1, targetScale, progress)
79
94
qml/Stage/Stage.qml+66−38
@@ -36,7 +36,6 @@ FocusScope {
36 property url background
36 property url background
37 property int dragAreaWidth
37 property int dragAreaWidth
38 property bool interactive
38 property bool interactive
39− property bool keepDashRunning: true
40 property real nativeHeight
39 property real nativeHeight
41 property real nativeWidth
40 property real nativeWidth
42 property QtObject orientations
41 property QtObject orientations
@@ -50,7 +49,6 @@ FocusScope {
50
49
51 // Configuration
50 // Configuration
52 property string mode: "staged"
51 property string mode: "staged"
53− property real leftEdgeDragProgress: 0
54
52
55 // Used by the tutorial code
53 // Used by the tutorial code
56 readonly property real rightEdgeDragProgress: rightEdgeDragArea.dragging ? rightEdgeDragArea.progress : 0 // How far left the stage has been dragged
54 readonly property real rightEdgeDragProgress: rightEdgeDragArea.dragging ? rightEdgeDragArea.progress : 0 // How far left the stage has been dragged
@@ -415,7 +413,7 @@ FocusScope {
415 // in staged mode, when it switches to Windowed mode it will suddenly
413 // in staged mode, when it switches to Windowed mode it will suddenly
416 // resume all those apps at once. We might want to avoid that.
414 // resume all those apps at once. We might want to avoid that.
417 value: root.mode === "windowed"
415 value: root.mode === "windowed"
418− || (isDash && root.keepDashRunning)
416+ || isDash
419 || (!root.suspended && model.application && priv.focusedAppDelegate &&
417 || (!root.suspended && model.application && priv.focusedAppDelegate &&
420 (priv.focusedAppDelegate.appId === model.application.appId ||
418 (priv.focusedAppDelegate.appId === model.application.appId ||
421 priv.mainStageAppId === model.application.appId ||
419 priv.mainStageAppId === model.application.appId ||
@@ -478,7 +476,7 @@ FocusScope {
478 visible: true
476 visible: true
479 blurRadius: 32
477 blurRadius: 32
480 brightness: .65
478 brightness: .65
481− opacity: MathUtils.linearAnimation(spreadItem.rightEdgeBreakPoint, 1, 0, 1, Math.max(rightEdgeDragArea.progress, edgeBarrier.progress))
479+ opacity: MathUtils.linearAnimation(spreadItem.rightEdgeBreakPoint, 1, 0, 1, Math.max(rightEdgeDragArea.dragging ? rightEdgeDragArea.progress : 0, edgeBarrier.progress))
482 }
480 }
483 },
481 },
484 State {
482 State {
@@ -712,6 +710,29 @@ FocusScope {
712 property real restoredX
710 property real restoredX
713 property real restoredY
711 property real restoredY
714
712
713+ // Keeps track of the window geometry while in normal or restored state
714+ // Useful when returning from some maxmized state or when saving the geometry while maximized
715+ // FIXME: find a better solution
716+ property real normalX: 0
717+ property real normalY: 0
718+ property real normalWidth: 0
719+ property real normalHeight: 0
720+ function updateNormalGeometry() {
721+ if (appDelegate.state == "normal" || appDelegate.state == "restored") {
722+ normalX = appDelegate.requestedX;
723+ normalY = appDelegate.requestedY;
724+ normalWidth = appDelegate.width;
725+ normalHeight = appDelegate.height;
726+ }
727+ }
728+ Connections {
729+ target: appDelegate
730+ onXChanged: appDelegate.updateNormalGeometry();
731+ onYChanged: appDelegate.updateNormalGeometry();
732+ onWidthChanged: appDelegate.updateNormalGeometry();
733+ onHeightChanged: appDelegate.updateNormalGeometry();
734+ }
735+
715 Binding {
736 Binding {
716 target: appDelegate
737 target: appDelegate
717 property: "y"
738 property: "y"
@@ -852,6 +873,16 @@ FocusScope {
852 MirFocusController.focusedSurface = null;
873 MirFocusController.focusedSurface = null;
853 }
874 }
854 }
875 }
876+
877+ WindowStateSaver {
878+ id: windowStateSaver
879+ target: appDelegate
880+ screenWidth: appContainer.width
881+ screenHeight: appContainer.height
882+ leftMargin: root.leftMargin
883+ minimumY: PanelState.panelHeight
884+ }
885+
855 Component.onCompleted: {
886 Component.onCompleted: {
856 if (application && application.rotatesWindowContents) {
887 if (application && application.rotatesWindowContents) {
857 decoratedWindow.surfaceOrientationAngle = shellOrientationAngle;
888 decoratedWindow.surfaceOrientationAngle = shellOrientationAngle;
@@ -863,7 +894,7 @@ FocusScope {
863 windowedX = priv.focusedAppDelegate ? priv.focusedAppDelegate.windowedX + units.gu(3) : (normalZ - 1) * units.gu(3)
894 windowedX = priv.focusedAppDelegate ? priv.focusedAppDelegate.windowedX + units.gu(3) : (normalZ - 1) * units.gu(3)
864 windowedY = priv.focusedAppDelegate ? priv.focusedAppDelegate.windowedY + units.gu(3) : normalZ * units.gu(3)
895 windowedY = priv.focusedAppDelegate ? priv.focusedAppDelegate.windowedY + units.gu(3) : normalZ * units.gu(3)
865 // Now load any saved state. This needs to happen *after* the cascading!
896 // Now load any saved state. This needs to happen *after* the cascading!
866− resizeArea.loadWindowState();
897+ windowStateSaver.load();
867
898
868 // NB: We're differentiating if this delegate was created in response to a new entry in the model
899 // NB: We're differentiating if this delegate was created in response to a new entry in the model
869 // or if the Repeater is just populating itself with delegates to match the model it received.
900 // or if the Repeater is just populating itself with delegates to match the model it received.
@@ -880,6 +911,8 @@ FocusScope {
880 _constructing = false;
911 _constructing = false;
881 }
912 }
882 Component.onDestruction: {
913 Component.onDestruction: {
914+ windowStateSaver.save();
915+
883 if (!root.parent) {
916 if (!root.parent) {
884 // This stage is about to be destroyed. Don't mess up with the model at this point
917 // This stage is about to be destroyed. Don't mess up with the model at this point
885 return;
918 return;
@@ -1061,7 +1094,6 @@ FocusScope {
1061 sideStageX: sideStage.x
1094 sideStageX: sideStage.x
1062 itemIndex: appDelegate.itemIndex
1095 itemIndex: appDelegate.itemIndex
1063 nextInStack: priv.nextInStack
1096 nextInStack: priv.nextInStack
1064− leftEdgeDragProgress: root.leftEdgeDragProgress
1065 }
1097 }
1066
1098
1067 StagedRightEdgeMaths {
1099 StagedRightEdgeMaths {
@@ -1164,7 +1196,8 @@ FocusScope {
1164 when: root.mode == "windowed" && (root.state == "windowedRightEdge" || rightEdgeFocusAnimation.running || hidingAnimation.running || edgeBarrier.progress > 0)
1196 when: root.mode == "windowed" && (root.state == "windowedRightEdge" || rightEdgeFocusAnimation.running || hidingAnimation.running || edgeBarrier.progress > 0)
1165 PropertyChanges {
1197 PropertyChanges {
1166 target: windowedRightEdgeMaths
1198 target: windowedRightEdgeMaths
1199+ swipeProgress: rightEdgeDragArea.dragging ? rightEdgeDragArea.progress : 0
1167− progress: Math.max(rightEdgeDragArea.progress, edgeBarrier.progress)
1200+ pushProgress: edgeBarrier.progress
1168 }
1201 }
1169 PropertyChanges {
1202 PropertyChanges {
1170 target: appDelegate
1203 target: appDelegate
@@ -1482,27 +1515,22 @@ FocusScope {
1482 id: resizeArea
1515 id: resizeArea
1483 objectName: "windowResizeArea"
1516 objectName: "windowResizeArea"
1484
1517
1518+ anchors.fill: appDelegate
1519+
1485 // workaround so that it chooses the correct resize borders when you drag from a corner ResizeGrip
1520 // workaround so that it chooses the correct resize borders when you drag from a corner ResizeGrip
1486 anchors.margins: touchControls.overlayShown ? borderThickness/2 : -borderThickness
1521 anchors.margins: touchControls.overlayShown ? borderThickness/2 : -borderThickness
1487
1522
1488 target: appDelegate
1523 target: appDelegate
1524+ minimumY: PanelState.panelHeight // disallow resizing up past Panel
1489 minWidth: units.gu(10)
1525 minWidth: units.gu(10)
1490 minHeight: units.gu(10)
1526 minHeight: units.gu(10)
1491 borderThickness: units.gu(2)
1527 borderThickness: units.gu(2)
1492− windowId: model.application.appId // FIXME: Change this to point to windowId once we have such a thing
1493− screenWidth: appContainer.width
1494− screenHeight: appContainer.height
1495− leftMargin: root.leftMargin
1496 enabled: false
1528 enabled: false
1497 visible: enabled
1529 visible: enabled
1498
1530
1499 onPressed: {
1531 onPressed: {
1500 appDelegate.focus = true;
1532 appDelegate.focus = true;
1501 }
1533 }
1502−
1503− Component.onDestruction: {
1504− saveWindowState();
1505− }
1506 }
1534 }
1507
1535
1508 DecoratedWindow {
1536 DecoratedWindow {
@@ -1652,10 +1680,10 @@ FocusScope {
1652 }
1680 }
1653 }
1681 }
1654
1682
1655− Image {
1683+ MouseArea {
1656− id: closeImage
1684+ id: closeMouseArea
1685+ objectName: "closeMouseArea"
1657 anchors { left: parent.left; top: parent.top; leftMargin: -height / 2; topMargin: -height / 2 + spreadMaths.closeIconOffset }
1686 anchors { left: parent.left; top: parent.top; leftMargin: -height / 2; topMargin: -height / 2 + spreadMaths.closeIconOffset }
1658− source: "graphics/window-close.svg"
1659 readonly property var mousePos: hoverMouseArea.mapToItem(appDelegate, hoverMouseArea.mouseX, hoverMouseArea.mouseY)
1687 readonly property var mousePos: hoverMouseArea.mapToItem(appDelegate, hoverMouseArea.mouseX, hoverMouseArea.mouseY)
1660 visible: !appDelegate.isDash && dragArea.distance == 0
1688 visible: !appDelegate.isDash && dragArea.distance == 0
1661 && index == spreadItem.highlightedIndex
1689 && index == spreadItem.highlightedIndex
@@ -1663,20 +1691,20 @@ FocusScope {
1663 && mousePos.y > -units.gu(4)
1691 && mousePos.y > -units.gu(4)
1664 && mousePos.x > -units.gu(4)
1692 && mousePos.x > -units.gu(4)
1665 && mousePos.x < (decoratedWindow.width * 2 / 3)
1693 && mousePos.x < (decoratedWindow.width * 2 / 3)
1666− height: units.gu(2)
1694+ height: units.gu(6)
1667 width: height
1695 width: height
1668− sourceSize.width: width
1696+
1669− sourceSize.height: height
1670−
1671− MouseArea {
1672− id: closeMouseArea
1673− objectName: "closeMouseArea"
1674− anchors.fill: closeImage
1675− anchors.margins: -units.gu(2)
1676− onClicked: {
1697+ onClicked: {
1677− priv.closingIndex = index;
1698+ priv.closingIndex = index;
1678− appDelegate.close();
1699+ appDelegate.close();
1679− }
1700+ }
1701+ Image {
1702+ id: closeImage
1703+ source: "graphics/window-close.svg"
1704+ anchors.fill: closeMouseArea
1705+ anchors.margins: units.gu(2)
1706+ sourceSize.width: width
1707+ sourceSize.height: height
1680 }
1708 }
1681 }
1709 }
1682 }
1710 }
@@ -1735,13 +1763,13 @@ FocusScope {
1735 }
1763 }
1736
1764
1737 // Find the hovered item and mark it active
1765 // Find the hovered item and mark it active
1738− var mapped = mapToItem(appContainer, hoverMouseArea.mouseX, hoverMouseArea.mouseY)
1766+ for (var i = appRepeater.count - 1; i >= 0; i--) {
1739− var itemUnder = appContainer.childAt(mapped.x, mapped.y)
1767+ var appDelegate = appRepeater.itemAt(i);
1740− if (itemUnder) {
1741− mapped = mapToItem(itemUnder, hoverMouseArea.mouseX, hoverMouseArea.mouseY)
1768+ var mapped = mapToItem(appDelegate, hoverMouseArea.mouseX, hoverMouseArea.mouseY)
1742− var delegateChild = itemUnder.childAt(mapped.x, mapped.y)
1769+ var itemUnder = appDelegate.childAt(mapped.x, mapped.y);
1743− if (delegateChild && (delegateChild.objectName === "dragArea" || delegateChild.objectName === "windowInfoItem")) {
1770+ if (itemUnder && (itemUnder.objectName === "dragArea" || itemUnder.objectName === "windowInfoItem" || itemUnder.objectName == "closeMouseArea")) {
1744− spreadItem.highlightedIndex = appRepeater.indexOf(itemUnder)
1771+ spreadItem.highlightedIndex = i;
1772+ break;
1745 }
1773 }
1746 }
1774 }
1747
1775
qml/Stage/StageMaths.qml+2−7
@@ -12,7 +12,6 @@ QtObject {
12 property int sideStageWidth: 0
12 property int sideStageWidth: 0
13 property int sideStageX: sceneWidth
13 property int sideStageX: sceneWidth
14 property bool animateX: false
14 property bool animateX: false
15− property int leftEdgeDragProgress: 0
16
15
17 property int stage: ApplicationInfoInterface.MainStage
16 property int stage: ApplicationInfoInterface.MainStage
18 property var thisDelegate: null
17 property var thisDelegate: null
@@ -26,10 +25,6 @@ QtObject {
26 // of the last focused order.
25 // of the last focused order.
27 readonly property int itemZ: {
26 readonly property int itemZ: {
28 // only shuffle when we've got a main and side stage
27 // only shuffle when we've got a main and side stage
29− if (thisDelegate.isDash && thisDelegate != mainStageDelegate && leftEdgeDragProgress > 0) {
30− return -1; // Keep the dash behind all other apps for the left edge gesture
31− }
32−
33 if (!sideStageDelegate) return itemIndex;
28 if (!sideStageDelegate) return itemIndex;
34
29
35 // don't shuffle indexes greater than "actives or next"
30 // don't shuffle indexes greater than "actives or next"
@@ -64,12 +59,12 @@ QtObject {
64
59
65 property int itemX: {
60 property int itemX: {
66 if (mainStageDelegate == thisDelegate) {
61 if (mainStageDelegate == thisDelegate) {
67− return thisDelegate.isDash ? 0 : leftEdgeDragProgress;
62+ return 0
68 }
63 }
69 if (sideStageDelegate == thisDelegate) {
64 if (sideStageDelegate == thisDelegate) {
70 return sideStageX;
65 return sideStageX;
71 }
66 }
72− return thisDelegate.isDash && leftEdgeDragProgress > 0 ? 0 : sceneWidth;
67+ return sceneWidth;
73 }
68 }
74 Behavior on itemX { enabled: root.animateX; UbuntuNumberAnimation {} }
69 Behavior on itemX { enabled: root.animateX; UbuntuNumberAnimation {} }
75
70
qml/Stage/WindowResizeArea.qml+2−70
@@ -18,91 +18,23 @@ import QtQuick 2.4
18import Ubuntu.Components 1.3
18import Ubuntu.Components 1.3
19import Utils 0.1
19import Utils 0.1
20import Unity.Application 0.1 // for Mir.cursorName
20import Unity.Application 0.1 // for Mir.cursorName
21−import "../Components/PanelState"
22
21
23MouseArea {
22MouseArea {
24 id: root
23 id: root
25
24
26− anchors.fill: target
27 anchors.margins: -borderThickness
25 anchors.margins: -borderThickness
28
26
29 hoverEnabled: target && !target.maximized // don't grab the resize under the panel
27 hoverEnabled: target && !target.maximized // don't grab the resize under the panel
30
28
31− property var windowStateStorage: WindowStateStorage
32 readonly property alias dragging: d.dragging
29 readonly property alias dragging: d.dragging
33− readonly property alias normalWidth: priv.normalWidth
34− readonly property alias normalHeight: priv.normalHeight
35
30
36 // The target item managed by this. Must be a parent or a sibling
31 // The target item managed by this. Must be a parent or a sibling
37 // The area will anchor to it and manage resize events
32 // The area will anchor to it and manage resize events
38 property Item target: null
33 property Item target: null
39− property string windowId: ""
40 property int borderThickness: 0
34 property int borderThickness: 0
35+ property real minimumY: -100000000 // By default, impose no limit
41 property int minWidth: 0
36 property int minWidth: 0
42 property int minHeight: 0
37 property int minHeight: 0
43− property int defaultWidth: units.gu(60)
44− property int defaultHeight: units.gu(50)
45− property int screenWidth: 0
46− property int screenHeight: 0
47− property int leftMargin: 0
48−
49− QtObject {
50− id: priv
51− objectName: "priv"
52−
53− property int normalX: 0
54− property int normalY: 0
55− property int normalWidth: 0
56− property int normalHeight: 0
57−
58− function updateNormalGeometry() {
59− if (root.target.state == "normal" || root.target.state == "restored") {
60− normalX = root.target.requestedX
61− normalY = root.target.requestedY
62− normalWidth = root.target.width
63− normalHeight = root.target.height
64− }
65− }
66− }
67−
68− Connections {
69− target: root.target
70− onXChanged: priv.updateNormalGeometry();
71− onYChanged: priv.updateNormalGeometry();
72− onWidthChanged: priv.updateNormalGeometry();
73− onHeightChanged: priv.updateNormalGeometry();
74− }
75−
76− function loadWindowState() {
77− var windowGeometry = windowStateStorage.getGeometry(root.windowId,
78− Qt.rect(target.windowedX, target.windowedY, defaultWidth, defaultHeight));
79−
80−
81− target.windowedWidth = Qt.binding(function() { return Math.min(Math.max(windowGeometry.width, d.minimumWidth), screenWidth - root.leftMargin); });
82− target.windowedHeight = Qt.binding(function() { return Math.min(Math.max(windowGeometry.height, d.minimumHeight),
83− root.screenHeight - (target.fullscreen ? 0 : PanelState.panelHeight)); });
84− target.windowedX = Qt.binding(function() { return Math.max(Math.min(windowGeometry.x, root.screenWidth - root.leftMargin - target.windowedWidth),
85− (target.fullscreen ? 0 : root.leftMargin)); });
86− target.windowedY = Qt.binding(function() { return Math.max(Math.min(windowGeometry.y, root.screenHeight - target.windowedHeight), PanelState.panelHeight); });
87−
88− var windowState = windowStateStorage.getState(root.windowId, WindowStateStorage.WindowStateNormal)
89− target.restore(false /* animated */, windowState);
90−
91− priv.updateNormalGeometry();
92−
93− // initialize the x/y to restore to
94− target.restoredX = priv.normalX;
95− target.restoredY = priv.normalY;
96− }
97−
98− function saveWindowState() {
99− var state = target.windowState;
100− if (state === WindowStateStorage.WindowStateRestored) {
101− state = WindowStateStorage.WindowStateNormal;
102− }
103− windowStateStorage.saveState(root.windowId, state & ~WindowStateStorage.WindowStateMinimized); // clear the minimized bit when saving
104− windowStateStorage.saveGeometry(root.windowId, Qt.rect(priv.normalX, priv.normalY, priv.normalWidth, priv.normalHeight));
105− }
106
38
107 QtObject {
39 QtObject {
108 id: d
40 id: d
@@ -311,7 +243,7 @@ MouseArea {
311 }
243 }
312
244
313 if (d.topBorder) {
245 if (d.topBorder) {
314− var newTargetY = Math.max(d.startY + deltaY, PanelState.panelHeight); // disallow resizing up past Panel
246+ var newTargetY = Math.max(d.startY + deltaY, root.minimumY);
315 var bottomBorderY = target.windowedY + target.height;
247 var bottomBorderY = target.windowedY + target.height;
316 if (bottomBorderY > newTargetY + d.minimumHeight) {
248 if (bottomBorderY > newTargetY + d.minimumHeight) {
317 if (bottomBorderY < newTargetY + d.maximumHeight) {
249 if (bottomBorderY < newTargetY + d.maximumHeight) {
qml/Stage/WindowStateSaver.qmlnew file+63
@@ -0,0 +1,63 @@
1+/*
2+ * Copyright (C) 2016 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.4
18+import Ubuntu.Components 1.3
19+import Utils 0.1
20+
21+QtObject {
22+ id: root
23+
24+ // set from outside
25+ property var target
26+ property int screenWidth: 0
27+ property int screenHeight: 0
28+ property int leftMargin: 0
29+ property int minimumY: 0
30+
31+ function load() {
32+ var defaultWidth = units.gu(60);
33+ var defaultHeight = units.gu(50);
34+ var windowGeometry = WindowStateStorage.getGeometry(target.appId,
35+ Qt.rect(target.windowedX, target.windowedY, defaultWidth, defaultHeight));
36+
37+ target.windowedWidth = Qt.binding(function() { return Math.min(Math.max(windowGeometry.width, target.minimumWidth), screenWidth - root.leftMargin); });
38+ target.windowedHeight = Qt.binding(function() { return Math.min(Math.max(windowGeometry.height, target.minimumHeight),
39+ screenHeight - (target.fullscreen ? 0 : minimumY)); });
40+ target.windowedX = Qt.binding(function() { return Math.max(Math.min(windowGeometry.x, screenWidth - root.leftMargin - target.windowedWidth),
41+ (target.fullscreen ? 0 : root.leftMargin)); });
42+ target.windowedY = Qt.binding(function() { return Math.max(Math.min(windowGeometry.y, screenHeight - target.windowedHeight), minimumY); });
43+
44+ var windowState = WindowStateStorage.getState(target.appId, WindowStateStorage.WindowStateNormal)
45+ target.restore(false /* animated */, windowState);
46+
47+ target.updateNormalGeometry();
48+
49+ // initialize the x/y to restore to
50+ target.restoredX = target.normalX;
51+ target.restoredY = target.normalY;
52+ }
53+
54+ function save() {
55+ var state = target.windowState;
56+ if (state === WindowStateStorage.WindowStateRestored) {
57+ state = WindowStateStorage.WindowStateNormal;
58+ }
59+
60+ WindowStateStorage.saveState(target.appId, state & ~WindowStateStorage.WindowStateMinimized); // clear the minimized bit when saving
61+ WindowStateStorage.saveGeometry(target.appId, Qt.rect(target.normalX, target.normalY, target.normalWidth, target.normalHeight));
62+ }
63+}
qml/Tutorial/TutorialLeftLong.qml+1−1
@@ -25,7 +25,7 @@ TutorialPage {
25
25
26 // Unlike other tutorials, this one can't be skipped before we show it, so
26 // Unlike other tutorials, this one can't be skipped before we show it, so
27 // only set opacityOverride if we're already shown.
27 // only set opacityOverride if we're already shown.
28− opacityOverride: shown ? 1 - launcher.dragDistance / launcher.minimizeDistance : 1
28+ opacityOverride: shown ? 1 - launcher.dragDistance / (launcher.panelWidth * 3) : 1
29
29
30 mouseArea {
30 mouseArea {
31 anchors.leftMargin: launcher.dragAreaWidth
31 anchors.leftMargin: launcher.dragAreaWidth
src/ShellApplication.cpp+1
@@ -36,6 +36,7 @@ ShellApplication::ShellApplication(int & argc, char ** argv, bool isMirServer)
36{
36{
37
37
38 setApplicationName(QStringLiteral("unity8"));
38 setApplicationName(QStringLiteral("unity8"));
39+ setOrganizationName(QStringLiteral("Canonical"));
39
40
40 connect(this, &QGuiApplication::screenAdded, this, &ShellApplication::onScreenAdded);
41 connect(this, &QGuiApplication::screenAdded, this, &ShellApplication::onScreenAdded);
41
42
tests/CMakeLists.txt+16−8
@@ -1,17 +1,14 @@
1include(QmlTest)
1include(QmlTest)
2
2
3# QML tests that do not require graphical capabilities.
3# QML tests that do not require graphical capabilities.
4−add_custom_target(unittests)
4+add_meta_test(unittests)
5
5
6# QML tests that require graphical capabilities.
6# QML tests that require graphical capabilities.
7−add_custom_target(uitests)
7+add_meta_test(uitests)
8−add_custom_target(xvfbuitests)
8+add_meta_test(xvfbuitests)
9
9
10−add_custom_target(alltests)
11−add_dependencies(alltests unittests uitests)
10+add_meta_test(alltests DEPENDS unittests uitests)
12−
13−add_custom_target(xvfballtests)
14−add_dependencies(xvfballtests unittests xvfbuitests)
11+add_meta_test(xvfballtests DEPENDS unittests xvfbuitests)
15
12
16# Support libraries and plugins
13# Support libraries and plugins
17add_subdirectory(mocks)
14add_subdirectory(mocks)
@@ -121,6 +118,11 @@ function(add_unity8_qmlbenchmark PATH COMPONENT_NAME ITERATIONS)
121 add_unity8_qmltest(${PATH} ${COMPONENT_NAME} ITERATIONS ${ITERATIONS} ${ARGN})
118 add_unity8_qmltest(${PATH} ${COMPONENT_NAME} ITERATIONS ${ITERATIONS} ${ARGN})
122endfunction()
119endfunction()
123
120
121+# add files needed for qml tests, just here for better alignment with add_unity8_qmltest
122+function(add_unity8_qmltest_data PATH COMPONENT_NAME)
123+ add_qml_test_data("${PATH}" "${COMPONENT_NAME}")
124+endfunction()
125+
124# used to make dbus adaptor classes from xml to mock system services
126# used to make dbus adaptor classes from xml to mock system services
125if(DEFINED ENV{DEB_BUILD_MULTIARCH})
127if(DEFINED ENV{DEB_BUILD_MULTIARCH})
126 set(QDBUSXML2CPP_EXECUTABLE "/usr/lib/$ENV{DEB_BUILD_MULTIARCH}/qt5/bin/qdbusxml2cpp")
128 set(QDBUSXML2CPP_EXECUTABLE "/usr/lib/$ENV{DEB_BUILD_MULTIARCH}/qt5/bin/qdbusxml2cpp")
@@ -128,6 +130,12 @@ else()
128 FIND_PROGRAM(QDBUSXML2CPP_EXECUTABLE qdbusxml2cpp)
130 FIND_PROGRAM(QDBUSXML2CPP_EXECUTABLE qdbusxml2cpp)
129endif()
131endif()
130
132
133+
134+install(DIRECTORY data graphics
135+ DESTINATION "${SHELL_APP_DIR}/tests"
136+)
137+
138+
131# Actual test definitions
139# Actual test definitions
132add_subdirectory(plugins)
140add_subdirectory(plugins)
133add_subdirectory(qmltests)
141add_subdirectory(qmltests)
tests/graphics/screenshots/gallery@12.pngnew file

Binary file not shown.

tests/mocks/AccountsService/CMakeLists.txt−1
@@ -20,6 +20,5 @@ target_link_libraries(MockAccountsService-qml
20 )
20 )
21
21
22add_unity8_mock(AccountsService 0.1 AccountsService
22add_unity8_mock(AccountsService 0.1 AccountsService
23− PREFIX mocks
24 TARGETS MockAccountsService-qml
23 TARGETS MockAccountsService-qml
25 )
24 )
tests/mocks/CMakeLists.txt+13−14
@@ -11,21 +11,20 @@ macro(add_unity8_mock PLUGIN VERSION PATH)
11 set(single PREFIX)
11 set(single PREFIX)
12 cmake_parse_arguments(MOCK "" "${single}" "" ${ARGN})
12 cmake_parse_arguments(MOCK "" "${single}" "" ${ARGN})
13
13
14− if(MOCK_PREFIX)
15− export_qmlfiles(${PLUGIN} ${PATH}
16− DESTINATION ${SHELL_INSTALL_QML}/${MOCK_PREFIX}
17− TARGET_PREFIX ${MOCK_PREFIX}-Mock
14+ if (NOT MOCK_PREFIX)
18− ${MOCK_UNPARSED_ARGUMENTS}
19− )
20− export_qmlplugin(${PLUGIN} ${VERSION} ${PATH}
21− DESTINATION ${SHELL_INSTALL_QML}/${MOCK_PREFIX}
22− TARGET_PREFIX ${MOCK_PREFIX}-Mock
15+ set(MOCK_PREFIX mocks)
23− ${MOCK_UNPARSED_ARGUMENTS}
24− )
25− else()
26− export_qmlfiles(${PLUGIN} ${PATH} TARGET_PREFIX Mock ${MOCK_UNPARSED_ARGUMENTS})
27− export_qmlplugin(${PLUGIN} ${VERSION} ${PATH} TARGET_PREFIX Mock ${MOCK_UNPARSED_ARGUMENTS})
28 endif()
16 endif()
17+
18+ export_qmlfiles(${PLUGIN} ${PATH}
19+ DESTINATION ${SHELL_INSTALL_QML}/${MOCK_PREFIX}
20+ TARGET_PREFIX ${MOCK_PREFIX}-Mock
21+ ${MOCK_UNPARSED_ARGUMENTS}
22+ )
23+ export_qmlplugin(${PLUGIN} ${VERSION} ${PATH}
24+ DESTINATION ${SHELL_INSTALL_QML}/${MOCK_PREFIX}
25+ TARGET_PREFIX ${MOCK_PREFIX}-Mock
26+ ${MOCK_UNPARSED_ARGUMENTS}
27+ )
29endmacro()
28endmacro()
30
29
31add_subdirectory(AccountsService)
30add_subdirectory(AccountsService)
tests/mocks/Cursor/CMakeLists.txt+1−1
@@ -1 +1 @@
1−add_unity8_mock(Cursor 1.1 Cursor PREFIX mocks)
1+add_unity8_mock(Cursor 1.1 Cursor)
tests/mocks/LightDM/IntegratedLightDM/CMakeLists.txt−1
@@ -45,7 +45,6 @@ target_link_libraries(MockLightDM-qml
45qt5_use_modules(MockLightDM-qml DBus Gui Qml)
45qt5_use_modules(MockLightDM-qml DBus Gui Qml)
46
46
47add_unity8_mock(LightDM.IntegratedLightDM 0.1 LightDM/IntegratedLightDM
47add_unity8_mock(LightDM.IntegratedLightDM 0.1 LightDM/IntegratedLightDM
48− PREFIX mocks
49 TARGETS MockLightDM-qml
48 TARGETS MockLightDM-qml
50 ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_CURRENT_BINARY_DIR}/liblightdm"
49 ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_CURRENT_BINARY_DIR}/liblightdm"
51)
50)
tests/mocks/LightDM/IntegratedLightDM/liblightdm/CMakeLists.txt+2−1
@@ -13,7 +13,8 @@ add_library(MockLightDM SHARED ${LibLightDM_SOURCES})
13qt5_use_modules(MockLightDM Gui)
13qt5_use_modules(MockLightDM Gui)
14
14
15set_target_properties(MockLightDM PROPERTIES
15set_target_properties(MockLightDM PROPERTIES
16− OUTPUT_NAME lightdm-qt5-3)
16+ OUTPUT_NAME lightdm-qt5-3
17+ SOVERSION 0)
17
18
18install(TARGETS MockLightDM
19install(TARGETS MockLightDM
19 DESTINATION ${SHELL_INSTALL_QML}/mocks/LightDM/IntegratedLightDM/liblightdm
20 DESTINATION ${SHELL_INSTALL_QML}/mocks/LightDM/IntegratedLightDM/liblightdm
tests/mocks/LightDM/IntegratedLightDM/liblightdm/SessionsModelPrivate.cpp+1−1
@@ -22,6 +22,7 @@ namespace QLightDM
22
22
23SessionsModelPrivate::SessionsModelPrivate(SessionsModel* parent)
23SessionsModelPrivate::SessionsModelPrivate(SessionsModel* parent)
24 : testScenario("singleSession")
24 : testScenario("singleSession")
25+ , q_ptr(parent)
25 , m_availableSessions(
26 , m_availableSessions(
26 {
27 {
27 {"ubuntu", "", "Ubuntu", ""},
28 {"ubuntu", "", "Ubuntu", ""},
@@ -36,7 +37,6 @@ SessionsModelPrivate::SessionsModelPrivate(SessionsModel* parent)
36 {"xterm", "", "Recovery Console", ""},
37 {"xterm", "", "Recovery Console", ""},
37 {"", "", "Unknown?", ""}
38 {"", "", "Unknown?", ""}
38 })
39 })
39− , q_ptr(parent)
40{
40{
41 numSessions = numAvailableSessions();
41 numSessions = numAvailableSessions();
42 resetEntries();
42 resetEntries();
tests/mocks/LightDM/IntegratedLightDM/liblightdm/UsersModelPrivate.cpp+23−23
@@ -73,7 +73,7 @@ void UsersModelPrivate::resetEntries_single()
73{
73{
74 entries =
74 entries =
75 {
75 {
76− { "single", "Single User", 0, 0, false, false, "ubuntu", 0 },
76+ { "single", "Single User", 0, 0, false, false, "ubuntu", 0, 0 },
77 };
77 };
78}
78}
79
79
@@ -81,7 +81,7 @@ void UsersModelPrivate::resetEntries_singlePassphrase()
81{
81{
82 entries =
82 entries =
83 {
83 {
84− { "single", "Single User", 0, 0, false, false, "ubuntu", 0 },
84+ { "single", "Single User", 0, 0, false, false, "ubuntu", 0, 0 },
85 };
85 };
86}
86}
87
87
@@ -89,7 +89,7 @@ void UsersModelPrivate::resetEntries_singlePin()
89{
89{
90 entries =
90 entries =
91 {
91 {
92− { "has-pin", "Has PIN", 0, 0, false, false, "ubuntu", 0 },
92+ { "has-pin", "Has PIN", 0, 0, false, false, "ubuntu", 0, 0 },
93 };
93 };
94}
94}
95
95
@@ -97,27 +97,27 @@ void UsersModelPrivate::resetEntries_full()
97{
97{
98 entries =
98 entries =
99 {
99 {
100− { "has-password", "Has Password", 0, 0, false, false, "ubuntu", 0 },
100+ { "has-password", "Has Password", 0, 0, false, false, "ubuntu", 0, 0 },
101− { "has-pin", "Has PIN", 0, 0, false, false, "ubuntu", 0 },
101+ { "has-pin", "Has PIN", 0, 0, false, false, "ubuntu", 0, 0 },
102− { "different-prompt", "Different Prompt", 0, 0, false, false, "ubuntu", 0 },
102+ { "different-prompt", "Different Prompt", 0, 0, false, false, "ubuntu", 0, 0 },
103− { "no-password", "No Password", 0, 0, false, false, "ubuntu", 0 },
103+ { "no-password", "No Password", 0, 0, false, false, "ubuntu", 0, 0 },
104− { "auth-error", "Auth Error", 0, 0, false, false, "ubuntu", 0 },
104+ { "auth-error", "Auth Error", 0, 0, false, false, "ubuntu", 0, 0 },
105− { "two-factor", "Two Factor", 0, 0, false, false, "ubuntu", 0 },
105+ { "two-factor", "Two Factor", 0, 0, false, false, "ubuntu", 0, 0 },
106− { "info-prompt", "Info Prompt", 0, 0, false, false, "ubuntu", 0 },
106+ { "info-prompt", "Info Prompt", 0, 0, false, false, "ubuntu", 0, 0 },
107− { "html-info-prompt", "HTML Info Prompt", 0, 0, false, false, "ubuntu", 0 },
107+ { "html-info-prompt", "HTML Info Prompt", 0, 0, false, false, "ubuntu", 0, 0 },
108− { "long-info-prompt", "Long Info Prompt", 0, 0, false, false, "ubuntu", 0 },
108+ { "long-info-prompt", "Long Info Prompt", 0, 0, false, false, "ubuntu", 0, 0 },
109− { "wide-info-prompt", "Wide Info Prompt", 0, 0, false, false, "ubuntu", 0 },
109+ { "wide-info-prompt", "Wide Info Prompt", 0, 0, false, false, "ubuntu", 0, 0 },
110− { "multi-info-prompt", "Multi Info Prompt", 0, 0, false, false, "ubuntu", 0 },
110+ { "multi-info-prompt", "Multi Info Prompt", 0, 0, false, false, "ubuntu", 0, 0 },
111− { "long-name", "Long name (far far too long to fit, seriously this would never fit on the screen, you will never see this part of the name)", 0, 0, false, false, "ubuntu", 0 },
111+ { "long-name", "Long name (far far too long to fit, seriously this would never fit on the screen, you will never see this part of the name)", 0, 0, false, false, "ubuntu", 0, 0 },
112− { "color-background", "Color Background", "#E95420", 0, false, false, "ubuntu", 0 },
112+ { "color-background", "Color Background", "#E95420", 0, false, false, "ubuntu", 0, 0 },
113 // white and black are a bit redundant, but useful for manually testing if UI is still readable
113 // white and black are a bit redundant, but useful for manually testing if UI is still readable
114− { "white-background", "White Background", "#ffffff", 0, false, false, "ubuntu", 0 },
114+ { "white-background", "White Background", "#ffffff", 0, false, false, "ubuntu", 0, 0 },
115− { "black-background", "Black Background", "#000000", 0, false, false, "ubuntu", 0 },
115+ { "black-background", "Black Background", "#000000", 0, false, false, "ubuntu", 0, 0 },
116− { "no-background", "No Background", "", 0, false, false, "ubuntu", 0 },
116+ { "no-background", "No Background", "", 0, false, false, "ubuntu", 0, 0 },
117− { "unicode", "가나다라마", 0, 0, false, false, "ubuntu", 0 },
117+ { "unicode", "가나다라마", 0, 0, false, false, "ubuntu", 0, 0 },
118− { "no-response", "No Response", 0, 0, false, false, "ubuntu", 0 },
118+ { "no-response", "No Response", 0, 0, false, false, "ubuntu", 0, 0 },
119− { "empty-name", "", 0, 0, false, false, "ubuntu", 0 },
119+ { "empty-name", "", 0, 0, false, false, "ubuntu", 0, 0 },
120− { "active", "Active Account", 0, 0, true, false, "ubuntu", 0 },
120+ { "active", "Active Account", 0, 0, true, false, "ubuntu", 0, 0 },
121 };
121 };
122}
122}
123
123
tests/mocks/QtMultimedia/videooutput.h+1−1
@@ -31,7 +31,7 @@ public:
31 QObject *source() const { return m_source.data(); }
31 QObject *source() const { return m_source.data(); }
32 void setSource(QObject *source);
32 void setSource(QObject *source);
33
33
34− void itemChange(ItemChange change, const ItemChangeData & value);
34+ void itemChange(ItemChange change, const ItemChangeData & value) override;
35
35
36Q_SIGNALS:
36Q_SIGNALS:
37 void sourceChanged();
37 void sourceChanged();
tests/mocks/Ubuntu/SystemSettings/SecurityPrivacy/CMakeLists.txt+1−1
@@ -7,4 +7,4 @@ add_library(MockSecurityPrivacy MODULE ${MOCK_SECURITYPRIVACY_SOURCES})
7
7
8qt5_use_modules(MockSecurityPrivacy Qml Quick Core)
8qt5_use_modules(MockSecurityPrivacy Qml Quick Core)
9
9
10−add_unity8_mock(Ubuntu.SystemSettings.SecurityPrivacy 1.0 Ubuntu/SystemSettings/SecurityPrivacy PREFIX mocks TARGETS MockSecurityPrivacy)
10+add_unity8_mock(Ubuntu.SystemSettings.SecurityPrivacy 1.0 Ubuntu/SystemSettings/SecurityPrivacy TARGETS MockSecurityPrivacy)
tests/mocks/Unity/Application/ApplicationInfo.cpp+1−2
@@ -138,8 +138,7 @@ void ApplicationInfo::createSurface()
138
138
139void ApplicationInfo::setIconId(const QString &iconId)
139void ApplicationInfo::setIconId(const QString &iconId)
140{
140{
141− setIcon(QString(sourceDirectory() + "/tests/graphics/applicationIcons/%2@18.png")
141+ setIcon(QUrl(testDataDir() + "/graphics/applicationIcons/" + iconId + "@18.png"));
142− .arg(iconId));
143}
142}
144
143
145void ApplicationInfo::setScreenshotId(const QString &screenshotId)
144void ApplicationInfo::setScreenshotId(const QString &screenshotId)
tests/mocks/Unity/Application/CMakeLists.txt+1−1
@@ -27,7 +27,7 @@ set_target_properties(NonMirUnityApplicationQml PROPERTIES OUTPUT_NAME FakeUnity
27qt5_use_modules(FakeUnityApplicationQml Core Quick DBus)
27qt5_use_modules(FakeUnityApplicationQml Core Quick DBus)
28qt5_use_modules(NonMirUnityApplicationQml Core Quick DBus)
28qt5_use_modules(NonMirUnityApplicationQml Core Quick DBus)
29
29
30−add_unity8_mock(Unity.Application 0.1 Unity/Application PREFIX mocks TARGETS FakeUnityApplicationQml)
30+add_unity8_mock(Unity.Application 0.1 Unity/Application TARGETS FakeUnityApplicationQml)
31add_unity8_mock(Unity.Application 0.1 Unity/Application
31add_unity8_mock(Unity.Application 0.1 Unity/Application
32 PREFIX nonmirplugins
32 PREFIX nonmirplugins
33 TARGETS NonMirUnityApplicationQml
33 TARGETS NonMirUnityApplicationQml
tests/mocks/Unity/CMakeLists.txt+3
@@ -68,4 +68,7 @@ target_link_libraries(FakeUnityQml
68
68
69qt5_use_modules(FakeUnityQml Qml)
69qt5_use_modules(FakeUnityQml Qml)
70
70
71+add_unity8_mock(Unity 0.2 Unity TARGETS FakeUnityQml)
72+
73+# and one copy in a separate directory for autopilot
71add_unity8_mock(Unity 0.2 Unity PREFIX scopefakes TARGETS FakeUnityQml)
74add_unity8_mock(Unity 0.2 Unity PREFIX scopefakes TARGETS FakeUnityQml)
tests/mocks/Unity/Indicators/CMakeLists.txt+4
@@ -31,6 +31,10 @@ target_link_libraries(IndicatorsFakeQml
31 QMenuModelQml
31 QMenuModelQml
32)
32)
33
33
34+set_target_properties(IndicatorsFakeQml PROPERTIES
35+ INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/${SHELL_INSTALL_QML}/mocks/QMenuModel"
36+)
37+
34qt5_use_modules(IndicatorsFakeQml Core Qml Quick)
38qt5_use_modules(IndicatorsFakeQml Core Qml Quick)
35
39
36add_unity8_mock(Unity.Indicators 0.1 Unity/Indicators TARGETS IndicatorsFakeQml)
40add_unity8_mock(Unity.Indicators 0.1 Unity/Indicators TARGETS IndicatorsFakeQml)
tests/mocks/Unity/Launcher/CMakeLists.txt+5−1
@@ -1,7 +1,8 @@
1−pkg_check_modules(LAUNCHER_API REQUIRED unity-shell-launcher=10)
1+pkg_check_modules(LAUNCHER_API REQUIRED unity-shell-launcher=11)
2
2
3include_directories(
3include_directories(
4 ${CMAKE_CURRENT_SOURCE_DIR}
4 ${CMAKE_CURRENT_SOURCE_DIR}
5+ ${CMAKE_SOURCE_DIR}/plugins/Unity/Launcher/
5)
6)
6
7
7set(MockLauncherModel_SOURCES
8set(MockLauncherModel_SOURCES
@@ -9,10 +10,13 @@ set(MockLauncherModel_SOURCES
9 ${LAUNCHER_API_INCLUDEDIR}/unity/shell/launcher/LauncherItemInterface.h
10 ${LAUNCHER_API_INCLUDEDIR}/unity/shell/launcher/LauncherItemInterface.h
10 ${LAUNCHER_API_INCLUDEDIR}/unity/shell/launcher/LauncherModelInterface.h
11 ${LAUNCHER_API_INCLUDEDIR}/unity/shell/launcher/LauncherModelInterface.h
11 ${LAUNCHER_API_INCLUDEDIR}/unity/shell/launcher/QuickListModelInterface.h
12 ${LAUNCHER_API_INCLUDEDIR}/unity/shell/launcher/QuickListModelInterface.h
13+ ${LAUNCHER_API_INCLUDEDIR}/unity/shell/launcher/AppDrawerModelInterface.h
12 plugin.cpp
14 plugin.cpp
13 MockLauncherModel.cpp
15 MockLauncherModel.cpp
14 MockLauncherItem.cpp
16 MockLauncherItem.cpp
15 MockQuickListModel.cpp
17 MockQuickListModel.cpp
18+ MockAppDrawerModel.cpp
19+ ${CMAKE_SOURCE_DIR}/plugins/Utils/applicationsfiltermodel.cpp
16)
20)
17
21
18add_library(MockLauncherPlugin MODULE ${MockLauncherModel_SOURCES})
22add_library(MockLauncherPlugin MODULE ${MockLauncherModel_SOURCES})
tests/mocks/Unity/Launcher/MockAppDrawerModel.cppnew file+75
@@ -0,0 +1,75 @@
1+/*
2+ * Copyright (C) 2016 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+#include "MockAppDrawerModel.h"
18+
19+#include <QDebug>
20+#include <QDateTime>
21+
22+MockAppDrawerModel::MockAppDrawerModel(QObject *parent):
23+ AppDrawerModelInterface(parent)
24+{
25+ MockLauncherItem *item = new MockLauncherItem("dialer-app", "/usr/share/applications/dialer-app.desktop", "Dialer", "dialer-app", this);
26+ m_list.append(item);
27+ item = new MockLauncherItem("camera-app", "/usr/share/applications/camera-app.desktop", "Camera", "camera", this);
28+ m_list.append(item);
29+ item = new MockLauncherItem("camera-app2", "/usr/share/applications/camera-app2.desktop", "Camera2", "camera", this);
30+ m_list.append(item);
31+ item = new MockLauncherItem("gallery-app", "/usr/share/applications/gallery-app.desktop", "Gallery", "gallery", this);
32+ m_list.append(item);
33+ item = new MockLauncherItem("music-app", "/usr/share/applications/music-app.desktop", "Music", "soundcloud", this);
34+ m_list.append(item);
35+ item = new MockLauncherItem("facebook-webapp", "/usr/share/applications/facebook-webapp.desktop", "Facebook", "facebook", this);
36+ m_list.append(item);
37+ item = new MockLauncherItem("webbrowser-app", "/usr/share/applications/webbrowser-app.desktop", "Browser", "browser", this);
38+ m_list.append(item);
39+ item = new MockLauncherItem("twitter-webapp", "/usr/share/applications/twitter-webapp.desktop", "Twitter", "twitter", this);
40+ m_list.append(item);
41+ item = new MockLauncherItem("gmail-webapp", "/usr/share/applications/gmail-webapp.desktop", "GMail", "gmail", this);
42+ m_list.append(item);
43+ item = new MockLauncherItem("ubuntu-weather-app", "/usr/share/applications/ubuntu-weather-app.desktop", "Weather", "weather", this);
44+ m_list.append(item);
45+ item = new MockLauncherItem("notes-app", "/usr/share/applications/notes-app.desktop", "Notepad", "notepad", this);
46+ m_list.append(item);
47+ item = new MockLauncherItem("calendar-app", "/usr/share/applications/calendar-app.desktop","Calendar", "calendar", this);
48+ m_list.append(item);
49+ item = new MockLauncherItem("libreoffice", "/usr/share/applications/libreoffice.desktop","Libre Office", "libreoffice", this);
50+ m_list.append(item);
51+ qDebug() << "mock model created";
52+
53+ qsrand(QDateTime::currentMSecsSinceEpoch() / 1000);
54+}
55+
56+int MockAppDrawerModel::rowCount(const QModelIndex &parent) const
57+{
58+ return m_list.count();
59+}
60+
61+QVariant MockAppDrawerModel::data(const QModelIndex &index, int role) const
62+{
63+ switch (role) {
64+ case RoleAppId:
65+ return m_list.at(index.row())->appId();
66+ case RoleName:
67+ return m_list.at(index.row())->name();
68+ case RoleIcon:
69+ return m_list.at(index.row())->icon();
70+ case RoleUsage:
71+ return qrand();
72+ }
73+
74+ return QVariant();
75+}
tests/mocks/Unity/Launcher/MockAppDrawerModel.hnew file+32
@@ -0,0 +1,32 @@
1+/*
2+ * Copyright (C) 2016 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+#include <unity/shell/launcher/AppDrawerModelInterface.h>
18+
19+#include "MockLauncherItem.h"
20+
21+class MockAppDrawerModel: public AppDrawerModelInterface
22+{
23+ Q_OBJECT
24+public:
25+ MockAppDrawerModel(QObject* parent = nullptr);
26+
27+ int rowCount(const QModelIndex &parent) const override;
28+ QVariant data(const QModelIndex &index, int role) const override;
29+
30+private:
31+ QList<MockLauncherItem*> m_list;
32+};
tests/mocks/Unity/Launcher/MockLauncherItem.cpp+14−1
@@ -29,7 +29,7 @@ MockLauncherItem::MockLauncherItem(const QString &appId, const QString& desktopF
29 m_appId(appId),
29 m_appId(appId),
30 m_desktopFile(desktopFile),
30 m_desktopFile(desktopFile),
31 m_name(name),
31 m_name(name),
32− m_icon("../../tests/graphics/applicationIcons/" + icon + ".png"),
32+ m_icon(testDataDir() + "/graphics/applicationIcons/" + icon + ".png"),
33 m_pinned(false),
33 m_pinned(false),
34 m_running(false),
34 m_running(false),
35 m_recent(false),
35 m_recent(false),
@@ -67,6 +67,11 @@ QString MockLauncherItem::icon() const
67 return m_icon;
67 return m_icon;
68}
68}
69
69
70+QStringList MockLauncherItem::keywords() const
71+{
72+ return m_keywords;
73+}
74+
70bool MockLauncherItem::pinned() const
75bool MockLauncherItem::pinned() const
71{
76{
72 return m_pinned;
77 return m_pinned;
@@ -200,3 +205,11 @@ unity::shell::launcher::QuickListModelInterface *MockLauncherItem::quickList() c
200{
205{
201 return m_quickList;
206 return m_quickList;
202}
207}
208+
209+void MockLauncherItem::setKeywords(const QStringList &keywords)
210+{
211+ if (m_keywords != keywords) {
212+ m_keywords = keywords;
213+ Q_EMIT keywordsChanged(keywords);
214+ }
215+}
tests/mocks/Unity/Launcher/MockLauncherItem.h+6
@@ -22,6 +22,8 @@
22
22
23#include <unity/shell/launcher/LauncherItemInterface.h>
23#include <unity/shell/launcher/LauncherItemInterface.h>
24
24
25+#include <QStringList>
26+
25class MockQuickListModel;
27class MockQuickListModel;
26
28
27using namespace unity::shell::launcher;
29using namespace unity::shell::launcher;
@@ -37,6 +39,7 @@ public:
37 QString desktopFile() const;
39 QString desktopFile() const;
38 QString name() const override;
40 QString name() const override;
39 QString icon() const override;
41 QString icon() const override;
42+ QStringList keywords() const override;
40
43
41 bool pinned() const override;
44 bool pinned() const override;
42 bool running() const override;
45 bool running() const override;
@@ -51,6 +54,7 @@ public:
51 unity::shell::launcher::QuickListModelInterface *quickList() const override;
54 unity::shell::launcher::QuickListModelInterface *quickList() const override;
52
55
53private:
56private:
57+ void setKeywords(const QStringList &keywords);
54 void setPinned(bool pinned);
58 void setPinned(bool pinned);
55 void setRunning(bool running);
59 void setRunning(bool running);
56 void setRecent(bool recent);
60 void setRecent(bool recent);
@@ -65,6 +69,7 @@ private:
65 QString m_desktopFile;
69 QString m_desktopFile;
66 QString m_name;
70 QString m_name;
67 QString m_icon;
71 QString m_icon;
72+ QStringList m_keywords;
68 bool m_pinned;
73 bool m_pinned;
69 bool m_running;
74 bool m_running;
70 bool m_recent;
75 bool m_recent;
@@ -77,6 +82,7 @@ private:
77 MockQuickListModel *m_quickList;
82 MockQuickListModel *m_quickList;
78
83
79 friend class MockLauncherModel;
84 friend class MockLauncherModel;
85+ friend class MockAppDrawerModel;
80};
86};
81
87
82#endif // MOCKLAUNCHERITEM_H
88#endif // MOCKLAUNCHERITEM_H
tests/mocks/Unity/Launcher/MockLauncherModel.cpp+3
@@ -36,6 +36,9 @@ MockLauncherModel::MockLauncherModel(QObject* parent): LauncherModelInterface(pa
36 item = new MockLauncherItem("camera-app2", "/usr/share/applications/camera-app2.desktop", "Camera2", "camera", this);
36 item = new MockLauncherItem("camera-app2", "/usr/share/applications/camera-app2.desktop", "Camera2", "camera", this);
37 item->setPinned(true);
37 item->setPinned(true);
38 m_list.append(item);
38 m_list.append(item);
39+ item = new MockLauncherItem("camera-app3", "/usr/share/applications/camera-app2.desktop", "Camera2", "camera", this);
40+ item->setPinned(true);
41+ m_list.append(item);
39 item = new MockLauncherItem("gallery-app", "/usr/share/applications/gallery-app.desktop", "Gallery", "gallery", this);
42 item = new MockLauncherItem("gallery-app", "/usr/share/applications/gallery-app.desktop", "Gallery", "gallery", this);
40 item->setProgress(50);
43 item->setProgress(50);
41 item->setCountVisible(true);
44 item->setCountVisible(true);
tests/mocks/Unity/Launcher/plugin.cpp+4
@@ -21,9 +21,11 @@
21#include "MockLauncherModel.h"
21#include "MockLauncherModel.h"
22#include "MockLauncherItem.h"
22#include "MockLauncherItem.h"
23#include "MockQuickListModel.h"
23#include "MockQuickListModel.h"
24+#include "MockAppDrawerModel.h"
24
25
25#include <unity/shell/launcher/LauncherModelInterface.h>
26#include <unity/shell/launcher/LauncherModelInterface.h>
26#include <unity/shell/launcher/LauncherItemInterface.h>
27#include <unity/shell/launcher/LauncherItemInterface.h>
28+#include <unity/shell/launcher/AppDrawerModelInterface.h>
27
29
28#include <QtQml/qqml.h>
30#include <QtQml/qqml.h>
29
31
@@ -41,8 +43,10 @@ void TestLauncherPlugin::registerTypes(const char* uri)
41 qmlRegisterUncreatableType<LauncherModelInterface>(uri, 0, 1, "LauncherModelInterface", "Abstract Interface. Cannot be instantiated.");
43 qmlRegisterUncreatableType<LauncherModelInterface>(uri, 0, 1, "LauncherModelInterface", "Abstract Interface. Cannot be instantiated.");
42 qmlRegisterUncreatableType<LauncherItemInterface>(uri, 0, 1, "LauncherItemInterface", "Abstract Interface. Cannot be instantiated.");
44 qmlRegisterUncreatableType<LauncherItemInterface>(uri, 0, 1, "LauncherItemInterface", "Abstract Interface. Cannot be instantiated.");
43 qmlRegisterUncreatableType<QuickListModelInterface>(uri, 0, 1, "QuickListModelInterface", "Abstract Interface. Cannot be instantiated.");
45 qmlRegisterUncreatableType<QuickListModelInterface>(uri, 0, 1, "QuickListModelInterface", "Abstract Interface. Cannot be instantiated.");
46+ qmlRegisterUncreatableType<AppDrawerModelInterface>(uri, 0, 1, "AppDrawerModelInterface", "Abstract Interface. Cannot be instantiated.");
44
47
45 qmlRegisterSingletonType<MockLauncherModel>(uri, 0, 1, "LauncherModel", modelProvider);
48 qmlRegisterSingletonType<MockLauncherModel>(uri, 0, 1, "LauncherModel", modelProvider);
46 qmlRegisterUncreatableType<MockLauncherItem>(uri, 0, 1, "LauncherItem", "Can't create LauncherItems in QML. Get them from the LauncherModel");
49 qmlRegisterUncreatableType<MockLauncherItem>(uri, 0, 1, "LauncherItem", "Can't create LauncherItems in QML. Get them from the LauncherModel");
47 qmlRegisterUncreatableType<MockQuickListModel>(uri, 0, 1, "QuickListModel", "Can't create QuickLists in QML. Get them from the LauncherItems");
50 qmlRegisterUncreatableType<MockQuickListModel>(uri, 0, 1, "QuickListModel", "Can't create QuickLists in QML. Get them from the LauncherItems");
51+ qmlRegisterType<MockAppDrawerModel>(uri, 0, 1, "AppDrawerModel");
48}
52}
tests/mocks/Unity/fake_scope.cpp+2−2
@@ -266,11 +266,11 @@ QVariantMap Scope::customizations() const
266 m["foreground-color"] = "blue";
266 m["foreground-color"] = "blue";
267 m["page-header"] = h;
267 m["page-header"] = h;
268 } else if (m_id == "MockScope4") {
268 } else if (m_id == "MockScope4") {
269− h["navigation-background"] = QUrl(sourceDirectory() + "/tests/qmltests/Dash/artwork/background.png");
269+ h["navigation-background"] = QUrl(testDataDir() + "/qmltests/Dash/artwork/background.png");
270 m["page-header"] = h;
270 m["page-header"] = h;
271 } else if (m_id == "MockScope5") {
271 } else if (m_id == "MockScope5") {
272 h["background"] = "gradient:///lightgrey/grey";
272 h["background"] = "gradient:///lightgrey/grey";
273− h["logo"] = QUrl(sourceDirectory() + "/tests/qmltests/Dash/tst_PageHeader/logo-ubuntu-orange.svg");
273+ h["logo"] = QUrl(testDataDir() + "/qmltests/Dash/tst_PageHeader/logo-ubuntu-orange.svg");
274 h["divider-color"] = "red";
274 h["divider-color"] = "red";
275 h["navigation-background"] = "color:///black";
275 h["navigation-background"] = "color:///black";
276 m["page-header"] = h;
276 m["page-header"] = h;
tests/mocks/Utils/CMakeLists.txt+4
@@ -24,11 +24,15 @@ set(QMLPLUGIN_SRC
24 ${CMAKE_SOURCE_DIR}/plugins/Utils/inputeventgenerator.cpp
24 ${CMAKE_SOURCE_DIR}/plugins/Utils/inputeventgenerator.cpp
25 ${CMAKE_SOURCE_DIR}/plugins/Utils/deviceconfigparser.cpp
25 ${CMAKE_SOURCE_DIR}/plugins/Utils/deviceconfigparser.cpp
26 ${CMAKE_SOURCE_DIR}/plugins/Utils/globalfunctions.cpp
26 ${CMAKE_SOURCE_DIR}/plugins/Utils/globalfunctions.cpp
27+ ${CMAKE_SOURCE_DIR}/plugins/Utils/appdrawerproxymodel.cpp
27 ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/ApplicationManagerInterface.h
28 ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/ApplicationManagerInterface.h
28 ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/ApplicationInfoInterface.h
29 ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/ApplicationInfoInterface.h
29 ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/MirSurfaceInterface.h
30 ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/MirSurfaceInterface.h
30 ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/MirSurfaceListInterface.h
31 ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/MirSurfaceListInterface.h
31 ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/Mir.h
32 ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/Mir.h
33+ ${LAUNCHER_API_INCLUDEDIR}/unity/shell/launcher/AppDrawerModelInterface.h
34+ ${LAUNCHER_API_INCLUDEDIR}/unity/shell/launcher/LauncherModelInterface.h
35+ ${LAUNCHER_API_INCLUDEDIR}/unity/shell/launcher/LauncherItemInterface.h
32 constants.cpp
36 constants.cpp
33 plugin.cpp
37 plugin.cpp
34 windowstatestorage.cpp
38 windowstatestorage.cpp
tests/mocks/Utils/plugin.cpp+2
@@ -40,6 +40,7 @@
40#include <inputeventgenerator.h>
40#include <inputeventgenerator.h>
41#include <deviceconfigparser.h>
41#include <deviceconfigparser.h>
42#include <globalfunctions.h>
42#include <globalfunctions.h>
43+#include <appdrawerproxymodel.h>
43
44
44static QObject *createWindowStateStorage(QQmlEngine *engine, QJSEngine *scriptEngine)
45static QObject *createWindowStateStorage(QQmlEngine *engine, QJSEngine *scriptEngine)
45{
46{
@@ -82,4 +83,5 @@ void FakeUtilsPlugin::registerTypes(const char *uri)
82 qmlRegisterType<DeviceConfigParser>(uri, 0, 1, "DeviceConfigParser");
83 qmlRegisterType<DeviceConfigParser>(uri, 0, 1, "DeviceConfigParser");
83 qmlRegisterSingletonType<GlobalFunctions>(uri, 0, 1, "Functions", createGlobalFunctions);
84 qmlRegisterSingletonType<GlobalFunctions>(uri, 0, 1, "Functions", createGlobalFunctions);
84 qmlRegisterType<URLDispatcher>(uri, 0, 1, "URLDispatcher");
85 qmlRegisterType<URLDispatcher>(uri, 0, 1, "URLDispatcher");
86+ qmlRegisterType<AppDrawerProxyModel>(uri, 0, 1, "AppDrawerProxyModel");
85}
87}
tests/plugins/AccountsService/CMakeLists.txt+6
@@ -41,6 +41,9 @@ add_executable(mock-server
41 UscServer.cpp
41 UscServer.cpp
42 )
42 )
43qt5_use_modules(mock-server Core DBus)
43qt5_use_modules(mock-server Core DBus)
44+install(TARGETS mock-server
45+ DESTINATION "${SHELL_PRIVATE_LIBDIR}/tests/plugins/AccountsService"
46+)
44
47
45add_executable(test-accountsservice
48add_executable(test-accountsservice
46 ${CMAKE_SOURCE_DIR}/plugins/AccountsService/AccountsService.cpp
49 ${CMAKE_SOURCE_DIR}/plugins/AccountsService/AccountsService.cpp
@@ -48,6 +51,9 @@ add_executable(test-accountsservice
48 client.cpp
51 client.cpp
49 )
52 )
50qt5_use_modules(test-accountsservice Core DBus Test)
53qt5_use_modules(test-accountsservice Core DBus Test)
54+install(TARGETS test-accountsservice
55+ DESTINATION "${SHELL_PRIVATE_LIBDIR}/tests/plugins/AccountsService"
56+)
51
57
52add_unity8_unittest(AccountsService dbus-test-runner
58add_unity8_unittest(AccountsService dbus-test-runner
53 ARG_PREFIX "--parameter"
59 ARG_PREFIX "--parameter"
tests/plugins/Dash/CMakeLists.txt+26−1
@@ -26,7 +26,7 @@ include_directories(
26
26
27remove_definitions(-DQT_NO_KEYWORDS)
27remove_definitions(-DQT_NO_KEYWORDS)
28
28
29−add_definitions(-DDASHVIEWSTEST_FOLDER="${CMAKE_CURRENT_SOURCE_DIR}")
29+add_definitions(-DTEST_DIR="plugins/Dash")
30
30
31macro(add_lvwph_test FILENAME TESTNAME)
31macro(add_lvwph_test FILENAME TESTNAME)
32 add_executable(${TESTNAME}TestExec
32 add_executable(${TESTNAME}TestExec
@@ -34,6 +34,9 @@ macro(add_lvwph_test FILENAME TESTNAME)
34 ${CMAKE_CURRENT_SOURCE_DIR}/../../../plugins/Dash/listviewwithpageheader.cpp)
34 ${CMAKE_CURRENT_SOURCE_DIR}/../../../plugins/Dash/listviewwithpageheader.cpp)
35 qt5_use_modules(${TESTNAME}TestExec Test Core Qml)
35 qt5_use_modules(${TESTNAME}TestExec Test Core Qml)
36 target_link_libraries(${TESTNAME}TestExec ${Qt5Gui_LIBRARIES} ${Qt5Quick_LIBRARIES})
36 target_link_libraries(${TESTNAME}TestExec ${Qt5Gui_LIBRARIES} ${Qt5Quick_LIBRARIES})
37+ install(TARGETS ${TESTNAME}TestExec
38+ DESTINATION "${SHELL_PRIVATE_LIBDIR}/tests/plugins/Dash"
39+ )
37
40
38 add_unity8_uitest(${TESTNAME} ${TESTNAME}TestExec DEPENDS Dash-qml)
41 add_unity8_uitest(${TESTNAME} ${TESTNAME}TestExec DEPENDS Dash-qml)
39endmacro()
42endmacro()
@@ -50,6 +53,9 @@ macro(add_dashview_try_test FILENAME TESTNAME)
50 )
53 )
51 qt5_use_modules(${TESTNAME}TestExec Test Core Qml)
54 qt5_use_modules(${TESTNAME}TestExec Test Core Qml)
52 target_link_libraries(${TESTNAME}TestExec ${Qt5Gui_LIBRARIES} ${Qt5Quick_LIBRARIES})
55 target_link_libraries(${TESTNAME}TestExec ${Qt5Gui_LIBRARIES} ${Qt5Quick_LIBRARIES})
56+ install(TARGETS ${TESTNAME}TestExec
57+ DESTINATION "${SHELL_PRIVATE_LIBDIR}/tests/plugins/Dash"
58+ )
53
59
54 add_unity8_uitest(${TESTNAME} ${TESTNAME}TestExec DEPENDS Dash-qml)
60 add_unity8_uitest(${TESTNAME} ${TESTNAME}TestExec DEPENDS Dash-qml)
55
61
@@ -60,6 +66,9 @@ macro(add_dashview_try_test FILENAME TESTNAME)
60 )
66 )
61 qt5_use_modules(${TESTNAME}TryExec Test Core Qml)
67 qt5_use_modules(${TESTNAME}TryExec Test Core Qml)
62 target_link_libraries(${TESTNAME}TryExec ${Qt5Gui_LIBRARIES} ${Qt5Quick_LIBRARIES})
68 target_link_libraries(${TESTNAME}TryExec ${Qt5Gui_LIBRARIES} ${Qt5Quick_LIBRARIES})
69+ install(TARGETS ${TESTNAME}TryExec
70+ DESTINATION "${SHELL_PRIVATE_LIBDIR}/tests/plugins/Dash"
71+ )
63 add_manual_test(${TESTNAME} ${TESTNAME}TryExec DEPENDS Dash-qml)
72 add_manual_test(${TESTNAME} ${TESTNAME}TryExec DEPENDS Dash-qml)
64endmacro()
73endmacro()
65
74
@@ -67,11 +76,27 @@ add_dashview_try_test(verticaljournal VerticalJournal)
67add_dashview_try_test(horizontaljournal HorizontalJournal)
76add_dashview_try_test(horizontaljournal HorizontalJournal)
68add_dashview_try_test(organicgrid OrganicGrid)
77add_dashview_try_test(organicgrid OrganicGrid)
69
78
79+# Install data files needed for tests
80+file(GLOB qml_files RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" *.qml)
81+foreach(qml_file ${qml_files})
82+ add_qml_test_data(. "${qml_file}")
83+endforeach()
84+
70# CardCreator test
85# CardCreator test
71add_executable(CardCreatorTestExec cardcreatortest.cpp)
86add_executable(CardCreatorTestExec cardcreatortest.cpp)
72qt5_use_modules(CardCreatorTestExec Test Core Qml)
87qt5_use_modules(CardCreatorTestExec Test Core Qml)
73target_link_libraries(CardCreatorTestExec ${Qt5Gui_LIBRARIES} ${Qt5Quick_LIBRARIES})
88target_link_libraries(CardCreatorTestExec ${Qt5Gui_LIBRARIES} ${Qt5Quick_LIBRARIES})
89+install(TARGETS CardCreatorTestExec
90+ DESTINATION "${SHELL_PRIVATE_LIBDIR}/tests/plugins/Dash"
91+)
74add_unity8_uitest(CardCreator CardCreatorTestExec DEPENDS Dash-qml)
92add_unity8_uitest(CardCreator CardCreatorTestExec DEPENDS Dash-qml)
93+add_qml_test_data(. cardcreator)
94+
95+# This one qml file imports a file in an arch-specific directory, so to make its
96+# import line relative, we install it into an arch-specific directory too.
97+add_qml_test_data(. cardcreatortest.qml
98+ DESTINATION "${SHELL_PRIVATE_LIBDIR}/tests/plugins/Dash"
99+)
75
100
76# plain qml test
101# plain qml test
77foreach(dash_test ScopeStyle ListViewWithPageHeaderQML CardAttributes CroppedImageMinimumSourceSize)
102foreach(dash_test ScopeStyle ListViewWithPageHeaderQML CardAttributes CroppedImageMinimumSourceSize)
tests/plugins/Dash/cardcreatortest.cpp+7−2
@@ -22,6 +22,8 @@
22#include <QDebug>
22#include <QDebug>
23#include <QTemporaryFile>
23#include <QTemporaryFile>
24
24
25+#include <paths.h>
26+
25class CardCreatorTest : public QObject
27class CardCreatorTest : public QObject
26{
28{
27 Q_OBJECT
29 Q_OBJECT
@@ -35,7 +37,10 @@ private Q_SLOTS:
35 void init()
37 void init()
36 {
38 {
37 view = new QQuickView();
39 view = new QQuickView();
40+ if (isRunningInstalled())
38− view->setSource(QUrl::fromLocalFile(DASHVIEWSTEST_FOLDER "/cardcreatortest.qml"));
41+ view->setSource(QUrl::fromLocalFile(testLibDir() + "/" TEST_DIR "/cardcreatortest.qml"));
42+ else
43+ view->setSource(QUrl::fromLocalFile(testDataDir() + "/" TEST_DIR "/cardcreatortest.qml"));
39 view->show();
44 view->show();
40 QTest::qWaitForWindowExposed(view);
45 QTest::qWaitForWindowExposed(view);
41 }
46 }
@@ -76,7 +81,7 @@ private Q_SLOTS:
76 const QString artShapeStyleString("artShapeStyle: ");
81 const QString artShapeStyleString("artShapeStyle: ");
77 const QString resultString("result: ");
82 const QString resultString("result: ");
78
83
79− const QString testDirPath = DASHVIEWSTEST_FOLDER "/cardcreator/";
84+ const QString testDirPath = testDataDir() + "/" TEST_DIR "/cardcreator/";
80 QDir d(testDirPath);
85 QDir d(testDirPath);
81 const QStringList testFiles = d.entryList(QStringList() << "*.tst");
86 const QStringList testFiles = d.entryList(QStringList() << "*.tst");
82 foreach(const QString &testFileName, testFiles) {
87 foreach(const QString &testFileName, testFiles) {
tests/plugins/Dash/horizontaljournaltest.cpp+3−1
@@ -27,6 +27,8 @@
27
27
28#include "horizontaljournal.h"
28#include "horizontaljournal.h"
29
29
30+#include <paths.h>
31+
30class WidthModel : public QAbstractListModel {
32class WidthModel : public QAbstractListModel {
31public:
33public:
32 QHash<int, QByteArray> roleNames() const override
34 QHash<int, QByteArray> roleNames() const override
@@ -126,7 +128,7 @@ private Q_SLOTS:
126 widthList << "100" << "50" << "125" << "10" << "40" << "70" << "200" << "110" << "160" << "20" << "20" << "65" << "80" << "200" << "300" << "130" << "400" << "300" << "500" << "10";
128 widthList << "100" << "50" << "125" << "10" << "40" << "70" << "200" << "110" << "160" << "20" << "20" << "65" << "80" << "200" << "300" << "130" << "400" << "300" << "500" << "10";
127 model->setStringList(widthList);
129 model->setStringList(widthList);
128
130
129− view->setSource(QUrl::fromLocalFile(DASHVIEWSTEST_FOLDER "/horizontaljournaltest.qml"));
131+ view->setSource(QUrl::fromLocalFile(testDataDir() + "/" TEST_DIR "/horizontaljournaltest.qml"));
130
132
131 view->show();
133 view->show();
132 view->resize(470, 400);
134 view->resize(470, 400);
tests/plugins/Dash/horizontaljournaltry.cpp+3−1
@@ -26,6 +26,8 @@
26
26
27#include "horizontaljournal.h"
27#include "horizontaljournal.h"
28
28
29+#include <paths.h>
30+
29class QWidthModela : public QStringListModel {
31class QWidthModela : public QStringListModel {
30 Q_OBJECT
32 Q_OBJECT
31public:
33public:
@@ -75,7 +77,7 @@ int main(int argc, char *argv[])
75 view->rootContext()->setContextProperty("listModel", &listModel);
77 view->rootContext()->setContextProperty("listModel", &listModel);
76 view->rootContext()->setContextProperty("vjModel", &model);
78 view->rootContext()->setContextProperty("vjModel", &model);
77
79
78− view->setSource(QUrl::fromLocalFile(DASHVIEWSTEST_FOLDER "/horizontaljournaltry.qml"));
80+ view->setSource(QUrl::fromLocalFile(testDataDir() + "/" TEST_DIR "/horizontaljournaltry.qml"));
79
81
80 view->show();
82 view->show();
81 view->resize(530, 400);
83 view->resize(530, 400);
tests/plugins/Dash/listviewwithpageheadersectionexternalmodeltest.cpp+3−1
@@ -26,6 +26,8 @@
26#include <private/qquickanimation_p.h>
26#include <private/qquickanimation_p.h>
27#include <private/qquickitem_p.h>
27#include <private/qquickitem_p.h>
28
28
29+#include <paths.h>
30+
29class StringListModel : public QAbstractListModel
31class StringListModel : public QAbstractListModel
30{
32{
31public:
33public:
@@ -165,7 +167,7 @@ private Q_SLOTS:
165 void init()
167 void init()
166 {
168 {
167 view = new QQuickView();
169 view = new QQuickView();
168− view->setSource(QUrl::fromLocalFile(DASHVIEWSTEST_FOLDER "/listviewwithpageheadertestsectionexternalmodel.qml"));
170+ view->setSource(QUrl::fromLocalFile(testDataDir() + "/" TEST_DIR "/listviewwithpageheadertestsectionexternalmodel.qml"));
169 lvwph = static_cast<ListViewWithPageHeader*>(view->rootObject()->findChild<QQuickFlickable*>());
171 lvwph = static_cast<ListViewWithPageHeader*>(view->rootObject()->findChild<QQuickFlickable*>());
170 QVERIFY(lvwph);
172 QVERIFY(lvwph);
171 view->show();
173 view->show();
tests/plugins/Dash/listviewwithpageheadersectiontest.cpp+3−1
@@ -25,6 +25,8 @@
25#include <private/qquickanimation_p.h>
25#include <private/qquickanimation_p.h>
26#include <private/qquickitem_p.h>
26#include <private/qquickitem_p.h>
27
27
28+#include <paths.h>
29+
28class ListViewWithPageHeaderTestSection : public QObject
30class ListViewWithPageHeaderTestSection : public QObject
29{
31{
30 Q_OBJECT
32 Q_OBJECT
@@ -130,7 +132,7 @@ private Q_SLOTS:
130 void init()
132 void init()
131 {
133 {
132 view = new QQuickView();
134 view = new QQuickView();
133− view->setSource(QUrl::fromLocalFile(DASHVIEWSTEST_FOLDER "/listviewwithpageheadertestsection.qml"));
135+ view->setSource(QUrl::fromLocalFile(testDataDir() + "/" TEST_DIR "/listviewwithpageheadertestsection.qml"));
134 lvwph = static_cast<ListViewWithPageHeader*>(view->rootObject()->findChild<QQuickFlickable*>());
136 lvwph = static_cast<ListViewWithPageHeader*>(view->rootObject()->findChild<QQuickFlickable*>());
135 model = view->rootObject()->findChild<QQmlListModel*>();
137 model = view->rootObject()->findChild<QQmlListModel*>();
136 otherDelegate = view->rootObject()->findChild<QQmlComponent*>();
138 otherDelegate = view->rootObject()->findChild<QQmlComponent*>();
tests/plugins/Dash/listviewwithpageheadertest.cpp+3−1
@@ -27,6 +27,8 @@
27
27
28#include <limits>
28#include <limits>
29
29
30+#include <paths.h>
31+
30// TODO Think on how doing a test for lost items
32// TODO Think on how doing a test for lost items
31// particullary making sure that lost items are culled
33// particullary making sure that lost items are culled
32// and then removed in the next updatePolish cycle
34// and then removed in the next updatePolish cycle
@@ -121,7 +123,7 @@ private Q_SLOTS:
121 void init()
123 void init()
122 {
124 {
123 view = new QQuickView();
125 view = new QQuickView();
124− view->setSource(QUrl::fromLocalFile(DASHVIEWSTEST_FOLDER "/listviewwithpageheadertest.qml"));
126+ view->setSource(QUrl::fromLocalFile(testDataDir() + "/" TEST_DIR "/listviewwithpageheadertest.qml"));
125 lvwph = static_cast<ListViewWithPageHeader*>(view->rootObject()->findChild<QQuickFlickable*>());
127 lvwph = static_cast<ListViewWithPageHeader*>(view->rootObject()->findChild<QQuickFlickable*>());
126 model = view->rootObject()->findChild<QQmlListModel*>();
128 model = view->rootObject()->findChild<QQmlListModel*>();
127 otherDelegate = view->rootObject()->findChild<QQmlComponent*>();
129 otherDelegate = view->rootObject()->findChild<QQmlComponent*>();
tests/plugins/Dash/organicgridtest.cpp+3−1
@@ -27,6 +27,8 @@
27
27
28#include "organicgrid.h"
28#include "organicgrid.h"
29
29
30+#include <paths.h>
31+
30class DummyModel : public QAbstractListModel {
32class DummyModel : public QAbstractListModel {
31public:
33public:
32 DummyModel() : m_count(0) {}
34 DummyModel() : m_count(0) {}
@@ -127,7 +129,7 @@ private Q_SLOTS:
127 model = new DummyModel();
129 model = new DummyModel();
128 model->setCount(21);
130 model->setCount(21);
129
131
130− view->setSource(QUrl::fromLocalFile(DASHVIEWSTEST_FOLDER "/organicgridtest.qml"));
132+ view->setSource(QUrl::fromLocalFile(testDataDir() + "/" TEST_DIR "/organicgridtest.qml"));
131
133
132 view->show();
134 view->show();
133 QTest::qWaitForWindowExposed(view);
135 QTest::qWaitForWindowExposed(view);
tests/plugins/Dash/organicgridtry.cpp+3−1
@@ -26,6 +26,8 @@
26
26
27#include "verticaljournal.h"
27#include "verticaljournal.h"
28
28
29+#include <paths.h>
30+
29class DummyModel : public QAbstractListModel {
31class DummyModel : public QAbstractListModel {
30 Q_OBJECT
32 Q_OBJECT
31public:
33public:
@@ -83,7 +85,7 @@ int main(int argc, char *argv[])
83 view->rootContext()->setContextProperty("listModel", &listModel);
85 view->rootContext()->setContextProperty("listModel", &listModel);
84 view->rootContext()->setContextProperty("gridModel", &model);
86 view->rootContext()->setContextProperty("gridModel", &model);
85
87
86− view->setSource(QUrl::fromLocalFile(DASHVIEWSTEST_FOLDER "/organicgridtry.qml"));
88+ view->setSource(QUrl::fromLocalFile(testDataDir() + "/" TEST_DIR "/organicgridtry.qml"));
87
89
88 view->show();
90 view->show();
89 view->resize(530, 400);
91 view->resize(530, 400);
tests/plugins/Dash/verticaljournaltest.cpp+3−1
@@ -27,6 +27,8 @@
27
27
28#include "verticaljournal.h"
28#include "verticaljournal.h"
29
29
30+#include <paths.h>
31+
30class HeightModel : public QAbstractListModel {
32class HeightModel : public QAbstractListModel {
31public:
33public:
32 QHash<int, QByteArray> roleNames() const override
34 QHash<int, QByteArray> roleNames() const override
@@ -142,7 +144,7 @@ private Q_SLOTS:
142 heightList << "100" << "50" << "125" << "10" << "40" << "70" << "200" << "110" << "160" << "20" << "20" << "65" << "80" << "200" << "300" << "130" << "400" << "300" << "500" << "10";
144 heightList << "100" << "50" << "125" << "10" << "40" << "70" << "200" << "110" << "160" << "20" << "20" << "65" << "80" << "200" << "300" << "130" << "400" << "300" << "500" << "10";
143 model->setStringList(heightList);
145 model->setStringList(heightList);
144
146
145− view->setSource(QUrl::fromLocalFile(DASHVIEWSTEST_FOLDER "/verticaljournaltest.qml"));
147+ view->setSource(QUrl::fromLocalFile(testDataDir() + "/" TEST_DIR "/verticaljournaltest.qml"));
146
148
147 view->show();
149 view->show();
148 QTest::qWaitForWindowExposed(view);
150 QTest::qWaitForWindowExposed(view);
tests/plugins/Dash/verticaljournaltry.cpp+3−1
@@ -26,6 +26,8 @@
26
26
27#include "verticaljournal.h"
27#include "verticaljournal.h"
28
28
29+#include <paths.h>
30+
29class QHeightModel : public QStringListModel {
31class QHeightModel : public QStringListModel {
30 Q_OBJECT
32 Q_OBJECT
31public:
33public:
@@ -75,7 +77,7 @@ int main(int argc, char *argv[])
75 view->rootContext()->setContextProperty("listModel", &listModel);
77 view->rootContext()->setContextProperty("listModel", &listModel);
76 view->rootContext()->setContextProperty("vjModel", &model);
78 view->rootContext()->setContextProperty("vjModel", &model);
77
79
78− view->setSource(QUrl::fromLocalFile(DASHVIEWSTEST_FOLDER "/verticaljournaltry.qml"));
80+ view->setSource(QUrl::fromLocalFile(testDataDir() + "/" TEST_DIR "/verticaljournaltry.qml"));
79
81
80 view->show();
82 view->show();
81 view->resize(530, 400);
83 view->resize(530, 400);
tests/plugins/GlobalShortcut/CMakeLists.txt+11−5
@@ -3,12 +3,18 @@ include_directories(
3 ${CMAKE_CURRENT_BINARY_DIR}
3 ${CMAKE_CURRENT_BINARY_DIR}
4 )
4 )
5
5
6−add_definitions(
6+add_definitions(-DTEST_DIR="plugins/GlobalShortcut")
7− -DCURRENT_SOURCE_DIR="${CMAKE_CURRENT_SOURCE_DIR}"
8− )
9−add_definitions(-DBUILT_PLUGINS_DIR="${CMAKE_BINARY_DIR}/plugins")
10
7
11add_executable(GlobalShortcutTestExec GlobalShortcutTest.cpp ${CMAKE_SOURCE_DIR}/plugins/GlobalShortcut/globalshortcut.cpp)
8add_executable(GlobalShortcutTestExec GlobalShortcutTest.cpp ${CMAKE_SOURCE_DIR}/plugins/GlobalShortcut/globalshortcut.cpp)
12qt5_use_modules(GlobalShortcutTestExec Test Quick)
9qt5_use_modules(GlobalShortcutTestExec Test Quick)
13target_link_libraries(GlobalShortcutTestExec ${Qt5Quick_LIBRARIES} GlobalShortcut-qml)
10target_link_libraries(GlobalShortcutTestExec ${Qt5Quick_LIBRARIES} GlobalShortcut-qml)
11+install(TARGETS GlobalShortcutTestExec
12+ DESTINATION "${SHELL_PRIVATE_LIBDIR}/tests/plugins/GlobalShortcut"
13+)
14+install(FILES shortcut.qml
15+ DESTINATION "${SHELL_APP_DIR}/tests/plugins/GlobalShortcut"
16+)
14−add_unity8_uitest(GlobalShortcut GlobalShortcutTestExec DEPENDS GlobalShortcut-qml)
17+add_unity8_uitest(GlobalShortcut GlobalShortcutTestExec
18+ DEPENDS GlobalShortcut-qml
19+ ENVIRONMENT LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/plugins/GlobalShortcut
20+)
tests/plugins/GlobalShortcut/GlobalShortcutTest.cpp+3−2
@@ -21,6 +21,8 @@
21#include <QtQuick/QQuickItem>
21#include <QtQuick/QQuickItem>
22#include <QQmlEngine>
22#include <QQmlEngine>
23
23
24+#include <paths.h>
25+
24class GlobalShortcutTest: public QObject
26class GlobalShortcutTest: public QObject
25{
27{
26 Q_OBJECT
28 Q_OBJECT
@@ -30,8 +32,7 @@ private Q_SLOTS:
30 void initTestCase()
32 void initTestCase()
31 {
33 {
32 m_view = new QQuickView();
34 m_view = new QQuickView();
33− m_view->engine()->addImportPath(BUILT_PLUGINS_DIR);
34− m_view->setSource(QUrl::fromLocalFile(CURRENT_SOURCE_DIR "/shortcut.qml"));
35+ m_view->setSource(QUrl::fromLocalFile(testDataDir() + "/" TEST_DIR "/shortcut.qml"));
35 m_shortcut = dynamic_cast<GlobalShortcut*>(m_view->rootObject()->property("shortcut").value<QObject*>());
36 m_shortcut = dynamic_cast<GlobalShortcut*>(m_view->rootObject()->property("shortcut").value<QObject*>());
36 QVERIFY(m_shortcut);
37 QVERIFY(m_shortcut);
37 m_inactiveShortcut = dynamic_cast<GlobalShortcut*>(m_view->rootObject()->property("inactiveShortcut").value<QObject*>());
38 m_inactiveShortcut = dynamic_cast<GlobalShortcut*>(m_view->rootObject()->property("inactiveShortcut").value<QObject*>());
tests/plugins/Greeter/Unity/Launcher/CMakeLists.txt+6−21
@@ -1,4 +1,4 @@
1−pkg_check_modules(LAUNCHER_API REQUIRED unity-shell-launcher=10)
1+pkg_check_modules(LAUNCHER_API REQUIRED unity-shell-launcher=11)
2
2
3include_directories(
3include_directories(
4 ${CMAKE_CURRENT_SOURCE_DIR}
4 ${CMAKE_CURRENT_SOURCE_DIR}
@@ -9,7 +9,7 @@ include_directories(
9 )
9 )
10
10
11add_definitions(-DSM_BUSNAME=sessionBus)
11add_definitions(-DSM_BUSNAME=sessionBus)
12−add_definitions(-DSRCDIR="${CMAKE_CURRENT_SOURCE_DIR}")
12+add_definitions(-DTEST_DIR="plugins/Greeter/Unity/Launcher")
13
13
14### LauncherModelASTest
14### LauncherModelASTest
15add_executable(launchermodelastestExec
15add_executable(launchermodelastestExec
@@ -30,7 +30,10 @@ target_link_libraries(launchermodelastestExec
30 ${GSETTINGS_QT_LDFLAGS}
30 ${GSETTINGS_QT_LDFLAGS}
31 )
31 )
32add_dependencies(launchermodelastestExec mock-server)
32add_dependencies(launchermodelastestExec mock-server)
33−qt5_use_modules(launchermodelastestExec Test Core DBus Gui)
33+qt5_use_modules(launchermodelastestExec Test Core DBus Gui Qml)
34+install(TARGETS launchermodelastestExec
35+ DESTINATION "${SHELL_PRIVATE_LIBDIR}/tests/plugins/Greeter/Unity/Launcher"
36+)
34add_unity8_unittest(LauncherModelAS dbus-test-runner
37add_unity8_unittest(LauncherModelAS dbus-test-runner
35 ARG_PREFIX "--parameter"
38 ARG_PREFIX "--parameter"
36 ARGS
39 ARGS
@@ -39,21 +42,3 @@ add_unity8_unittest(LauncherModelAS dbus-test-runner
39 --task $<TARGET_FILE:launchermodelastestExec>
42 --task $<TARGET_FILE:launchermodelastestExec>
40 --wait-for org.freedesktop.Accounts
43 --wait-for org.freedesktop.Accounts
41)
44)
42−
43−# copy .desktop files into build directory for shadow builds
44−file(GLOB DESKTOP_FILES *.desktop)
45−
46−foreach(DESKTOP_FILE ${DESKTOP_FILES})
47− file(COPY "${DESKTOP_FILE}"
48− DESTINATION ${CMAKE_CURRENT_BINARY_DIR}
49− )
50−endforeach()
51−
52−# copy .svg files into build directory for shadow builds
53−file(GLOB DESKTOP_FILES *.svg)
54−
55−foreach(DESKTOP_FILE ${DESKTOP_FILES})
56− file(COPY "${DESKTOP_FILE}"
57− DESTINATION ${CMAKE_CURRENT_BINARY_DIR}
58− )
59−endforeach()
tests/plugins/Greeter/Unity/Launcher/launchermodelastest.cpp+4
@@ -28,6 +28,7 @@
28#include <QSignalSpy>
28#include <QSignalSpy>
29#include <QtTest>
29#include <QtTest>
30
30
31+#include <paths.h>
31
32
32class LauncherModelASTest : public QObject
33class LauncherModelASTest : public QObject
33{
34{
@@ -45,6 +46,9 @@ private Q_SLOTS:
45 }
46 }
46
47
47 void init() {
48 void init() {
49+ // Launcher will look in current dir in testing mode for data
50+ QDir::setCurrent(testDataDir() + "/" TEST_DIR);
51+
48 // Prepare some fake list
52 // Prepare some fake list
49 QList<QVariantMap> list;
53 QList<QVariantMap> list;
50 QVariantMap item;
54 QVariantMap item;
tests/plugins/ImageCache/CMakeLists.txt+10
@@ -8,6 +8,7 @@ include_directories(
8 )
8 )
9
9
10add_definitions(-DCURRENT_SOURCE_DIR="${CMAKE_CURRENT_SOURCE_DIR}")
10add_definitions(-DCURRENT_SOURCE_DIR="${CMAKE_CURRENT_SOURCE_DIR}")
11+add_definitions(-DTEST_DIR="plugins/ImageCache")
11remove_definitions(-DQT_NO_KEYWORDS)
12remove_definitions(-DQT_NO_KEYWORDS)
12
13
13add_executable(ImageCacheTestExec
14add_executable(ImageCacheTestExec
@@ -18,3 +19,12 @@ add_unity8_uitest(ImageCache ImageCacheTestExec
18 DEPENDS ImageCache-qml
19 DEPENDS ImageCache-qml
19 IMPORT_PATHS ${UNITY_PLUGINPATH}
20 IMPORT_PATHS ${UNITY_PLUGINPATH}
20 )
21 )
22+install(TARGETS ImageCacheTestExec
23+ DESTINATION "${SHELL_PRIVATE_LIBDIR}/tests/plugins/ImageCache"
24+)
25+install(FILES test.qml
26+ DESTINATION "${SHELL_APP_DIR}/tests/plugins/ImageCache"
27+)
28+install(DIRECTORY graphics
29+ DESTINATION "${SHELL_APP_DIR}/tests/plugins/ImageCache"
30+)
tests/plugins/ImageCache/test.cpp+4−2
@@ -24,6 +24,8 @@
24#include <time.h>
24#include <time.h>
25#include <utime.h>
25#include <utime.h>
26
26
27+#include <paths.h>
28+
27Q_DECLARE_METATYPE(QQuickImage::Status)
29Q_DECLARE_METATYPE(QQuickImage::Status)
28
30
29class ImageCacheTest : public QObject
31class ImageCacheTest : public QObject
@@ -52,7 +54,7 @@ private:
52
54
53 QString sourceFile(const QString &name)
55 QString sourceFile(const QString &name)
54 {
56 {
55− return CURRENT_SOURCE_DIR "/graphics/" + name;
57+ return testDataDir() + "/" TEST_DIR "/graphics/" + name;
56 }
58 }
57
59
58 QString cachedFile(bool isPath, const QString &name)
60 QString cachedFile(bool isPath, const QString &name)
@@ -93,7 +95,7 @@ private Q_SLOTS:
93 qputenv("HOME", home->path().toUtf8());
95 qputenv("HOME", home->path().toUtf8());
94
96
95 view = new QQuickView();
97 view = new QQuickView();
96− view->setSource(QUrl::fromLocalFile(CURRENT_SOURCE_DIR "/test.qml"));
98+ view->setSource(QUrl::fromLocalFile(testDataDir() + "/" TEST_DIR "/test.qml"));
97 image = view->rootObject();
99 image = view->rootObject();
98
100
99 view->show();
101 view->show();
tests/plugins/LightDM/IntegratedLightDM/CMakeLists.txt+21−5
@@ -1,6 +1,3 @@
1−add_definitions(
2− -DCURRENT_SOURCE_DIR="${CMAKE_CURRENT_SOURCE_DIR}"
3− )
4include_directories(
1include_directories(
5 ${GLIB_INCLUDE_DIRS}
2 ${GLIB_INCLUDE_DIRS}
6 ${CMAKE_CURRENT_BINARY_DIR}
3 ${CMAKE_CURRENT_BINARY_DIR}
@@ -21,11 +18,17 @@ target_include_directories(GreeterDBusTestExec PUBLIC
21 ${CMAKE_SOURCE_DIR}/plugins/LightDM
18 ${CMAKE_SOURCE_DIR}/plugins/LightDM
22 ${CMAKE_SOURCE_DIR}/tests/mocks/LightDM/IntegratedLightDM
19 ${CMAKE_SOURCE_DIR}/tests/mocks/LightDM/IntegratedLightDM
23 )
20 )
21+set_target_properties(GreeterDBusTestExec PROPERTIES INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/${SHELL_INSTALL_QML}/mocks/IntegratedLightDM/liblightdm")
22+install(TARGETS GreeterDBusTestExec
23+ DESTINATION "${SHELL_PRIVATE_LIBDIR}/tests/plugins/LightDM/IntegratedLightDM"
24+ )
25+install(FILES greeter.qml
26+ DESTINATION "${SHELL_APP_DIR}/tests/plugins/LightDM/IntegratedLightDM"
27+ )
24add_unity8_uitest(GreeterDBus dbus-test-runner
28add_unity8_uitest(GreeterDBus dbus-test-runner
25 ARG_PREFIX "--parameter"
29 ARG_PREFIX "--parameter"
26 ARGS --task $<TARGET_FILE:GreeterDBusTestExec>
30 ARGS --task $<TARGET_FILE:GreeterDBusTestExec>
27− DEPENDS MockLightDM
31+ DEPENDS MockLightDM MockLightDM-qml
28− IMPORT_PATHS ${UNITY_MOCKPATH}
29 )
32 )
30
33
31add_executable(GreeterPamTestExec
34add_executable(GreeterPamTestExec
@@ -41,6 +44,9 @@ target_include_directories(GreeterPamTestExec PUBLIC
41 ${CMAKE_SOURCE_DIR}/plugins/LightDM/IntegratedLightDM
44 ${CMAKE_SOURCE_DIR}/plugins/LightDM/IntegratedLightDM
42 ${CMAKE_SOURCE_DIR}/plugins/LightDM/IntegratedLightDM/liblightdm
45 ${CMAKE_SOURCE_DIR}/plugins/LightDM/IntegratedLightDM/liblightdm
43 )
46 )
47+install(TARGETS GreeterPamTestExec
48+ DESTINATION "${SHELL_PRIVATE_LIBDIR}/tests/plugins/LightDM/IntegratedLightDM"
49+ )
44add_qmltest_target(testGreeterPam GreeterPamTestExec COMMAND $<TARGET_FILE:GreeterPamTestExec>)
50add_qmltest_target(testGreeterPam GreeterPamTestExec COMMAND $<TARGET_FILE:GreeterPamTestExec>)
45
51
46# SessionsModelTest
52# SessionsModelTest
@@ -59,6 +65,9 @@ target_include_directories(GreeterSessionsModelTestExec PUBLIC
59 ${CMAKE_SOURCE_DIR}/plugins/Utils
65 ${CMAKE_SOURCE_DIR}/plugins/Utils
60 ${CMAKE_SOURCE_DIR}/tests/mocks/LightDM/IntegratedLightDM
66 ${CMAKE_SOURCE_DIR}/tests/mocks/LightDM/IntegratedLightDM
61 )
67 )
68+install(TARGETS GreeterSessionsModelTestExec
69+ DESTINATION "${SHELL_PRIVATE_LIBDIR}/tests/plugins/LightDM/IntegratedLightDM"
70+ )
62add_unity8_uitest(GreeterSessions GreeterSessionsModelTestExec
71add_unity8_uitest(GreeterSessions GreeterSessionsModelTestExec
63 ENVIRONMENT LIBLIGHTDM_MOCK_MODE=full
72 ENVIRONMENT LIBLIGHTDM_MOCK_MODE=full
64 DEPENDS MockLightDM
73 DEPENDS MockLightDM
@@ -82,6 +91,10 @@ target_include_directories(GreeterUsersModelTestExec PUBLIC
82 ${CMAKE_SOURCE_DIR}/plugins/Utils
91 ${CMAKE_SOURCE_DIR}/plugins/Utils
83 ${CMAKE_SOURCE_DIR}/tests/mocks/LightDM/IntegratedLightDM
92 ${CMAKE_SOURCE_DIR}/tests/mocks/LightDM/IntegratedLightDM
84 )
93 )
94+set_target_properties(GreeterUsersModelTestExec PROPERTIES INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/${SHELL_INSTALL_QML}/mocks/IntegratedLightDM/liblightdm")
95+install(TARGETS GreeterUsersModelTestExec
96+ DESTINATION "${SHELL_PRIVATE_LIBDIR}/tests/plugins/LightDM/IntegratedLightDM"
97+ )
85add_unity8_uitest(GreeterUsers GreeterUsersModelTestExec
98add_unity8_uitest(GreeterUsers GreeterUsersModelTestExec
86 ENVIRONMENT LIBLIGHTDM_MOCK_MODE=full
99 ENVIRONMENT LIBLIGHTDM_MOCK_MODE=full
87 DEPENDS MockLightDM
100 DEPENDS MockLightDM
@@ -99,6 +112,9 @@ target_include_directories(GreeterIntegratedTestExec PUBLIC
99 ${GLIB_INCLUDE_DIRS}
112 ${GLIB_INCLUDE_DIRS}
100 ${CMAKE_SOURCE_DIR}/plugins/LightDM/IntegratedLightDM/liblightdm
113 ${CMAKE_SOURCE_DIR}/plugins/LightDM/IntegratedLightDM/liblightdm
101 )
114 )
115+install(TARGETS GreeterIntegratedTestExec
116+ DESTINATION "${SHELL_PRIVATE_LIBDIR}/tests/plugins/LightDM/IntegratedLightDM"
117+ )
102add_unity8_unittest(GreeterIntegrated dbus-test-runner
118add_unity8_unittest(GreeterIntegrated dbus-test-runner
103 ENVIRONMENT LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/plugins/IntegratedLightDM/liblightdm/
119 ENVIRONMENT LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/plugins/IntegratedLightDM/liblightdm/
104 ARG_PREFIX "--parameter"
120 ARG_PREFIX "--parameter"
tests/plugins/LightDM/IntegratedLightDM/dbus.cpp+2−1
@@ -23,6 +23,7 @@
23#include <QQuickItem>
23#include <QQuickItem>
24#include <QQuickView>
24#include <QQuickView>
25#include <QtTestGui>
25#include <QtTestGui>
26+#include <paths.h>
26
27
27class GreeterDBusTest : public QObject
28class GreeterDBusTest : public QObject
28{
29{
@@ -58,7 +59,7 @@ private Q_SLOTS:
58 void init()
59 void init()
59 {
60 {
60 view = new QQuickView();
61 view = new QQuickView();
61− view->setSource(QUrl::fromLocalFile(CURRENT_SOURCE_DIR "/greeter.qml"));
62+ view->setSource(QUrl::fromLocalFile(testDataDir() + "/plugins/LightDM/IntegratedLightDM/greeter.qml"));
62 greeter = dynamic_cast<Greeter*>(view->rootObject()->property("greeter").value<QObject*>());
63 greeter = dynamic_cast<Greeter*>(view->rootObject()->property("greeter").value<QObject*>());
63 QVERIFY(greeter);
64 QVERIFY(greeter);
64 QVERIFY(greeter->authenticationUser() == "");
65 QVERIFY(greeter->authenticationUser() == "");
tests/plugins/SessionBroadcast/CMakeLists.txt+6
@@ -25,6 +25,9 @@ add_executable(MockBroadcastServer
25 BroadcastServer.cpp
25 BroadcastServer.cpp
26)
26)
27qt5_use_modules(MockBroadcastServer Core DBus)
27qt5_use_modules(MockBroadcastServer Core DBus)
28+install(TARGETS MockBroadcastServer
29+ DESTINATION "${SHELL_PRIVATE_LIBDIR}/tests/plugins/SessionBroadcast"
30+)
28
31
29### SessionBroadcastTest
32### SessionBroadcastTest
30add_executable(sessionbroadcasttestExec
33add_executable(sessionbroadcasttestExec
@@ -32,6 +35,9 @@ add_executable(sessionbroadcasttestExec
32 sessionbroadcasttest.cpp
35 sessionbroadcasttest.cpp
33)
36)
34qt5_use_modules(sessionbroadcasttestExec Test Core Qml DBus)
37qt5_use_modules(sessionbroadcasttestExec Test Core Qml DBus)
38+install(TARGETS sessionbroadcasttestExec
39+ DESTINATION "${SHELL_PRIVATE_LIBDIR}/tests/plugins/SessionBroadcast"
40+)
35
41
36add_unity8_unittest(SessionBroadcast dbus-test-runner
42add_unity8_unittest(SessionBroadcast dbus-test-runner
37 ARG_PREFIX "--parameter"
43 ARG_PREFIX "--parameter"
tests/plugins/Ubuntu/Gestures/CMakeLists.txt+8−4
@@ -16,12 +16,15 @@ include_directories(
16 ${CMAKE_CURRENT_BINARY_DIR}
16 ${CMAKE_CURRENT_BINARY_DIR}
17 )
17 )
18
18
19−export_qmlfiles(UbuntuGesturesTest .)
20−
21macro(build_gesture_test CLASSNAME)
19macro(build_gesture_test CLASSNAME)
22 add_executable(${CLASSNAME}TestExec tst_${CLASSNAME}.cpp GestureTest.cpp TestItem.cpp)
20 add_executable(${CLASSNAME}TestExec tst_${CLASSNAME}.cpp GestureTest.cpp TestItem.cpp)
23 qt5_use_modules(${CLASSNAME}TestExec Test Core Qml Gui Quick)
21 qt5_use_modules(${CLASSNAME}TestExec Test Core Qml Gui Quick)
24 target_link_libraries(${CLASSNAME}TestExec UbuntuGesturesQml ${UBUNTUGESTURES_LIBRARIES})
22 target_link_libraries(${CLASSNAME}TestExec UbuntuGesturesQml ${UBUNTUGESTURES_LIBRARIES})
23+ install(TARGETS ${CLASSNAME}TestExec
24+ DESTINATION "${SHELL_PRIVATE_LIBDIR}/tests/plugins/Ubuntu/Gestures"
25+ )
26+ # To find libUbuntuGestures.so
27+ set_target_properties(${CLASSNAME}TestExec PROPERTIES INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/${SHELL_PRIVATE_LIBDIR}")
25endmacro()
28endmacro()
26
29
27set(UNITY_IMPORT_PATHS
30set(UNITY_IMPORT_PATHS
@@ -33,7 +36,6 @@ macro(add_gesture_unit_test CLASSNAME)
33 build_gesture_test(${CLASSNAME})
36 build_gesture_test(${CLASSNAME})
34 add_unity8_unittest(${CLASSNAME} ${CLASSNAME}TestExec
37 add_unity8_unittest(${CLASSNAME} ${CLASSNAME}TestExec
35 ENVIRONMENT LD_LIBRARY_PATH=${UNITY_PLUGINPATH}/Ubuntu/Gestures
38 ENVIRONMENT LD_LIBRARY_PATH=${UNITY_PLUGINPATH}/Ubuntu/Gestures
36− DEPENDS UbuntuGesturesTest-qmlfiles
37 ${ARGN}
39 ${ARGN}
38 )
40 )
39endmacro()
41endmacro()
@@ -42,12 +44,14 @@ macro(add_gesture_ui_test CLASSNAME)
42 build_gesture_test(${CLASSNAME})
44 build_gesture_test(${CLASSNAME})
43 add_unity8_uitest(${CLASSNAME} ${CLASSNAME}TestExec
45 add_unity8_uitest(${CLASSNAME} ${CLASSNAME}TestExec
44 ENVIRONMENT LD_LIBRARY_PATH=${UNITY_PLUGINPATH}/Ubuntu/Gestures
46 ENVIRONMENT LD_LIBRARY_PATH=${UNITY_PLUGINPATH}/Ubuntu/Gestures
45− DEPENDS UbuntuGesturesTest-qmlfiles
46 ${ARGN}
47 ${ARGN}
47 )
48 )
48 add_manual_qml_test(. ${CLASSNAME} IMPORT_PATHS ${UNITY_IMPORT_PATHS})
49 add_manual_qml_test(. ${CLASSNAME} IMPORT_PATHS ${UNITY_IMPORT_PATHS})
49endmacro()
50endmacro()
50
51
52+add_qml_test_data(. empty.qml)
53+add_qml_test_data(. touchGateExample.qml)
54+
51add_gesture_ui_test(FloatingFlickable)
55add_gesture_ui_test(FloatingFlickable)
52add_gesture_ui_test(PressedOutsideNotifier)
56add_gesture_ui_test(PressedOutsideNotifier)
53add_gesture_ui_test(TouchDispatcher)
57add_gesture_ui_test(TouchDispatcher)
tests/plugins/Ubuntu/Gestures/GestureTest.cpp+2−1
@@ -24,6 +24,7 @@
24
24
25#include <UbuntuGestures/private/timer_p.h>
25#include <UbuntuGestures/private/timer_p.h>
26#include <UbuntuGestures/private/touchregistry_p.h>
26#include <UbuntuGestures/private/touchregistry_p.h>
27+#include <paths.h>
27
28
28UG_USE_NAMESPACE
29UG_USE_NAMESPACE
29
30
@@ -45,7 +46,7 @@ void GestureTest::init()
45{
46{
46 m_view = new QQuickView;
47 m_view = new QQuickView;
47 m_view->setResizeMode(QQuickView::SizeRootObjectToView);
48 m_view->setResizeMode(QQuickView::SizeRootObjectToView);
48− m_view->setSource(QUrl::fromLocalFile(m_qmlFilename));
49+ m_view->setSource(QUrl::fromLocalFile(testDataDir() + "/plugins/Ubuntu/Gestures/" + m_qmlFilename));
49 m_view->show();
50 m_view->show();
50 QVERIFY(QTest::qWaitForWindowExposed(m_view));
51 QVERIFY(QTest::qWaitForWindowExposed(m_view));
51 QVERIFY(m_view->rootObject() != 0);
52 QVERIFY(m_view->rootObject() != 0);
tests/plugins/Ubuntu/Gestures/tst_FloatingFlickable.qml+1−1
@@ -18,7 +18,7 @@ import QtQuick 2.4
18import Ubuntu.Components 1.3
18import Ubuntu.Components 1.3
19import Ubuntu.Gestures 0.1
19import Ubuntu.Gestures 0.1
20import Unity.Test 0.1
20import Unity.Test 0.1
21−import "../../../../../qml/Components"
21+import "../../../../qml/Components"
22
22
23Rectangle {
23Rectangle {
24 id: root
24 id: root
tests/plugins/Ubuntu/Gestures/tst_TouchGate.cpp+3−1
@@ -29,6 +29,8 @@
29
29
30#include "TestItem.h"
30#include "TestItem.h"
31
31
32+#include <paths.h>
33+
32UG_USE_NAMESPACE
34UG_USE_NAMESPACE
33
35
34class CandidateItem : public QQuickItem
36class CandidateItem : public QQuickItem
@@ -98,7 +100,7 @@ void tst_TouchGate::init()
98 touchRegistry = TouchRegistry::instance();
100 touchRegistry = TouchRegistry::instance();
99
101
100 view = createView();
102 view = createView();
101− view->setSource(QUrl::fromLocalFile("touchGateExample.qml"));
103+ view->setSource(QUrl::fromLocalFile(testDataDir() + "/plugins/Ubuntu/Gestures/touchGateExample.qml"));
102 view->show();
104 view->show();
103 QVERIFY(QTest::qWaitForWindowExposed(view));
105 QVERIFY(QTest::qWaitForWindowExposed(view));
104 QVERIFY(view->rootObject() != 0);
106 QVERIFY(view->rootObject() != 0);
tests/plugins/Unity/Indicators/CMakeLists.txt+11−1
@@ -24,8 +24,18 @@ macro(indicator_test TEST)
24 ${GIO_LIBRARIES}
24 ${GIO_LIBRARIES}
25 ${QMENUMODEL_LDFLAGS}
25 ${QMENUMODEL_LDFLAGS}
26 )
26 )
27+ install(TARGETS ${TEST}Exec
28+ DESTINATION "${SHELL_PRIVATE_LIBDIR}/tests/plugins/Unity/Indicators"
29+ )
30+
31+ set(ldpath "")
32+ foreach(lib ${test_ADDITIONAL_LIBS})
33+ set(ldpath "$<TARGET_FILE_DIR:${lib}>:")
34+ endforeach(lib)
27
35
28− add_unity8_unittest(${TEST} ${TEST}Exec)
36+ add_unity8_unittest(${TEST} ${TEST}Exec
37+ ENVIRONMENT "LD_LIBRARY_PATH=${ldpath}"
38+ )
29endmacro(indicator_test)
39endmacro(indicator_test)
30
40
31indicator_test(IndicatorsManager ADDITIONAL_LIBS IndicatorsQml)
41indicator_test(IndicatorsManager ADDITIONAL_LIBS IndicatorsQml)
tests/plugins/Unity/Indicators/IndicatorsManagerTest.cpp+1−1
@@ -31,7 +31,7 @@ private Q_SLOTS:
31
31
32 void initTestCase()
32 void initTestCase()
33 {
33 {
34− setenv("XDG_DATA_DIRS", (sourceDirectory() + "/tests/data").toLatin1().data(), 1);
34+ setenv("XDG_DATA_DIRS", (testDataDir() + "/data").toLatin1().data(), 1);
35 }
35 }
36
36
37 void cleanupTestCase()
37 void cleanupTestCase()
tests/plugins/Unity/Indicators/IndicatorsModelTest.cpp+1−1
@@ -32,7 +32,7 @@ private Q_SLOTS:
32
32
33 void initTestCase()
33 void initTestCase()
34 {
34 {
35− setenv("XDG_DATA_DIRS", (sourceDirectory() + "/tests/data").toLatin1().data(), 1);
35+ setenv("XDG_DATA_DIRS", (testDataDir() + "/data").toLatin1().data(), 1);
36 }
36 }
37
37
38 void cleanupTestCase()
38 void cleanupTestCase()
tests/plugins/Unity/Launcher/CMakeLists.txt+11−4
@@ -1,5 +1,5 @@
1pkg_check_modules(GSETTINGS_QT REQUIRED gsettings-qt)
1pkg_check_modules(GSETTINGS_QT REQUIRED gsettings-qt)
2−pkg_check_modules(LAUNCHER_API REQUIRED unity-shell-launcher=10)
2+pkg_check_modules(LAUNCHER_API REQUIRED unity-shell-launcher=11)
3
3
4include_directories(
4include_directories(
5 ${CMAKE_CURRENT_SOURCE_DIR}
5 ${CMAKE_CURRENT_SOURCE_DIR}
@@ -17,7 +17,7 @@ include_directories(
17 )
17 )
18
18
19add_definitions(-DSM_BUSNAME=sessionBus)
19add_definitions(-DSM_BUSNAME=sessionBus)
20−add_definitions(-DSRCDIR="${CMAKE_CURRENT_SOURCE_DIR}")
20+add_definitions(-DTEST_DIR="plugins/Unity/Launcher")
21
21
22### LauncherModelTest
22### LauncherModelTest
23add_executable(launchermodeltestExec
23add_executable(launchermodeltestExec
@@ -30,6 +30,7 @@ add_executable(launchermodeltestExec
30 ${CMAKE_SOURCE_DIR}/plugins/Unity/Launcher/quicklistmodel.cpp
30 ${CMAKE_SOURCE_DIR}/plugins/Unity/Launcher/quicklistmodel.cpp
31 ${CMAKE_SOURCE_DIR}/plugins/Unity/Launcher/dbusinterface.cpp
31 ${CMAKE_SOURCE_DIR}/plugins/Unity/Launcher/dbusinterface.cpp
32 ${CMAKE_SOURCE_DIR}/plugins/Unity/Launcher/quicklistentry.cpp
32 ${CMAKE_SOURCE_DIR}/plugins/Unity/Launcher/quicklistentry.cpp
33+ ${CMAKE_SOURCE_DIR}/plugins/Unity/Launcher/ualwrapper.cpp
33 ${LAUNCHER_API_INCLUDEDIR}/unity/shell/launcher/LauncherItemInterface.h
34 ${LAUNCHER_API_INCLUDEDIR}/unity/shell/launcher/LauncherItemInterface.h
34 ${LAUNCHER_API_INCLUDEDIR}/unity/shell/launcher/LauncherModelInterface.h
35 ${LAUNCHER_API_INCLUDEDIR}/unity/shell/launcher/LauncherModelInterface.h
35 ${LAUNCHER_API_INCLUDEDIR}/unity/shell/launcher/QuickListModelInterface.h
36 ${LAUNCHER_API_INCLUDEDIR}/unity/shell/launcher/QuickListModelInterface.h
@@ -43,10 +44,13 @@ target_link_libraries(launchermodeltestExec
43 ${UAL_LIBRARIES}
44 ${UAL_LIBRARIES}
44 )
45 )
45add_dependencies(launchermodeltestExec mock-server)
46add_dependencies(launchermodeltestExec mock-server)
46−qt5_use_modules(launchermodeltestExec Test Core DBus Xml Gui)
47+qt5_use_modules(launchermodeltestExec Test Core DBus Xml Gui Qml)
48+install(TARGETS launchermodeltestExec
49+ DESTINATION "${SHELL_PRIVATE_LIBDIR}/tests/plugins/Unity/Launcher"
50+ )
47
51
48add_unity8_unittest(LauncherModel dbus-test-runner
52add_unity8_unittest(LauncherModel dbus-test-runner
49− ENVIRONMENT "XDG_DATA_HOME=${CMAKE_CURRENT_BINARY_DIR}"
53+ ENVIRONMENT "APPDIR=${CMAKE_CURRENT_BINARY_DIR}/applications"
50 ARG_PREFIX "--parameter"
54 ARG_PREFIX "--parameter"
51 ARGS
55 ARGS
52 --task $<TARGET_FILE:mock-server>
56 --task $<TARGET_FILE:mock-server>
@@ -59,3 +63,6 @@ add_unity8_unittest(LauncherModel dbus-test-runner
59file(COPY applications
63file(COPY applications
60 DESTINATION ${CMAKE_CURRENT_BINARY_DIR}
64 DESTINATION ${CMAKE_CURRENT_BINARY_DIR}
61 )
65 )
66+install(DIRECTORY applications
67+ DESTINATION "${SHELL_PRIVATE_LIBDIR}/tests/plugins/Unity/Launcher"
68+ )
tests/plugins/Unity/Launcher/launchermodeltest.cpp+17
@@ -32,6 +32,7 @@
32#include <QDomDocument>
32#include <QDomDocument>
33
33
34#include <glib.h>
34#include <glib.h>
35+#include <paths.h>
35
36
36// This is a mock, specifically to test the LauncherModel
37// This is a mock, specifically to test the LauncherModel
37class MockApp: public unity::shell::application::ApplicationInfoInterface
38class MockApp: public unity::shell::application::ApplicationInfoInterface
@@ -139,6 +140,7 @@ class LauncherModelTest : public QObject
139private:
140private:
140 LauncherModel *launcherModel;
141 LauncherModel *launcherModel;
141 MockAppManager *appManager;
142 MockAppManager *appManager;
143+ QTemporaryDir tmpDir;
142
144
143 QList<QVariantMap> getASConfig() {
145 QList<QVariantMap> getASConfig() {
144 AccountsServiceDBusAdaptor *as = launcherModel->m_asAdapter->m_accounts;
146 AccountsServiceDBusAdaptor *as = launcherModel->m_asAdapter->m_accounts;
@@ -148,11 +150,23 @@ private:
148 return qdbus_cast<QList<QVariantMap>>(reply.value().value<QDBusArgument>());
150 return qdbus_cast<QList<QVariantMap>>(reply.value().value<QDBusArgument>());
149 }
151 }
150
152
153+ // Link our app data from a tempdir & tell glib/UAL to look there.
154+ // We do this because we want to be able to delete the applications dir
155+ // during testing, but that dir may be read-only (installed on system).
156+ void setUpAppDir() {
157+ QFile appDir(qgetenv("APPDIR"));
158+ appDir.link(tmpDir.path() + "/applications");
159+
160+ qputenv("XDG_DATA_HOME", tmpDir.path().toUtf8());
161+ }
162+
151private Q_SLOTS:
163private Q_SLOTS:
152
164
153 void initTestCase() {
165 void initTestCase() {
154 qDBusRegisterMetaType<QList<QVariantMap>>();
166 qDBusRegisterMetaType<QList<QVariantMap>>();
155
167
168+ setUpAppDir();
169+
156 launcherModel = new LauncherModel(this);
170 launcherModel = new LauncherModel(this);
157 QCoreApplication::processEvents(); // to let the model register on DBus
171 QCoreApplication::processEvents(); // to let the model register on DBus
158 QCOMPARE(launcherModel->rowCount(QModelIndex()), 0);
172 QCOMPARE(launcherModel->rowCount(QModelIndex()), 0);
@@ -163,6 +177,9 @@ private Q_SLOTS:
163
177
164 // Adding 2 apps to the mock appmanager. Both should appear in the launcher.
178 // Adding 2 apps to the mock appmanager. Both should appear in the launcher.
165 void init() {
179 void init() {
180+ // Switching to tmpDir makes manipulating our appdir symlink easier.
181+ QDir::setCurrent(tmpDir.path());
182+
166 QDBusInterface accountsInterface(QStringLiteral("org.freedesktop.Accounts"),
183 QDBusInterface accountsInterface(QStringLiteral("org.freedesktop.Accounts"),
167 QStringLiteral("/org/freedesktop/Accounts"),
184 QStringLiteral("/org/freedesktop/Accounts"),
168 QStringLiteral("org.freedesktop.Accounts"));
185 QStringLiteral("org.freedesktop.Accounts"));
tests/plugins/Unity/Session/CMakeLists.txt+6
@@ -29,6 +29,9 @@ add_executable(LightDMServer
29 server.cpp
29 server.cpp
30)
30)
31qt5_use_modules(LightDMServer Core DBus)
31qt5_use_modules(LightDMServer Core DBus)
32+install(TARGETS LightDMServer
33+ DESTINATION "${SHELL_PRIVATE_LIBDIR}/tests/plugins/Unity/Session"
34+ )
32
35
33### SessionBackendTest
36### SessionBackendTest
34add_executable(sessionbackendtestExec
37add_executable(sessionbackendtestExec
@@ -40,6 +43,9 @@ target_link_libraries(sessionbackendtestExec
40 ${GLIB_LIBRARIES}
43 ${GLIB_LIBRARIES}
41 )
44 )
42qt5_use_modules(sessionbackendtestExec Test Core Qml DBus)
45qt5_use_modules(sessionbackendtestExec Test Core Qml DBus)
46+install(TARGETS sessionbackendtestExec
47+ DESTINATION "${SHELL_PRIVATE_LIBDIR}/tests/plugins/Unity/Session"
48+)
43
49
44add_unity8_unittest(SessionBackend dbus-test-runner
50add_unity8_unittest(SessionBackend dbus-test-runner
45 ENVIRONMENT XDG_SESSION_PATH=/session
51 ENVIRONMENT XDG_SESSION_PATH=/session
tests/plugins/Utils/CMakeLists.txt+8−1
@@ -15,8 +15,11 @@ foreach(util_test
15 add_executable(${util_test}TestExec ${util_test}Test.cpp ModelTest.cpp)
15 add_executable(${util_test}TestExec ${util_test}Test.cpp ModelTest.cpp)
16 qt5_use_modules(${util_test}TestExec Test Core Qml)
16 qt5_use_modules(${util_test}TestExec Test Core Qml)
17 target_link_libraries(${util_test}TestExec Utils-qml)
17 target_link_libraries(${util_test}TestExec Utils-qml)
18+ install(TARGETS ${util_test}TestExec
19+ DESTINATION "${SHELL_PRIVATE_LIBDIR}/tests/plugins/Utils"
20+ )
18 add_unity8_unittest(${util_test} ${util_test}TestExec ADD_TEST
21 add_unity8_unittest(${util_test} ${util_test}TestExec ADD_TEST
19− ENVIRONMENT XDG_CONFIG_HOME=${CMAKE_CURRENT_BINARY_DIR}
22+ ENVIRONMENT LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/plugins/Utils
20 )
23 )
21
24
22endforeach()
25endforeach()
@@ -28,7 +31,11 @@ add_unity8_qmlunittest(. UtilsStyle)
28add_executable(URLDispatcherTestExec URLDispatcherTest.cpp)
31add_executable(URLDispatcherTestExec URLDispatcherTest.cpp)
29qt5_use_modules(URLDispatcherTestExec Test Core Qml)
32qt5_use_modules(URLDispatcherTestExec Test Core Qml)
30target_link_libraries(URLDispatcherTestExec Utils-qml)
33target_link_libraries(URLDispatcherTestExec Utils-qml)
34+install(TARGETS URLDispatcherTestExec
35+ DESTINATION "${SHELL_PRIVATE_LIBDIR}/tests/plugins/Utils"
36+)
31add_unity8_unittest(URLDispatcher dbus-test-runner
37add_unity8_unittest(URLDispatcher dbus-test-runner
32 ARG_PREFIX "--parameter"
38 ARG_PREFIX "--parameter"
33 ARGS --task $<TARGET_FILE:URLDispatcherTestExec>
39 ARGS --task $<TARGET_FILE:URLDispatcherTestExec>
40+ ENVIRONMENT LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/plugins/Utils
34)
41)
tests/plugins/Utils/DeviceConfigParserTest.cpp+4−1
@@ -21,6 +21,7 @@
21#include <QTest>
21#include <QTest>
22#include <QDebug>
22#include <QDebug>
23#include <QSettings>
23#include <QSettings>
24+#include <QTemporaryDir>
24
25
25class DeviceConfigParserTest : public QObject
26class DeviceConfigParserTest : public QObject
26{
27{
@@ -45,13 +46,15 @@ private Q_SLOTS:
45 }
46 }
46
47
47 void testCustomFile() {
48 void testCustomFile() {
49+ QTemporaryDir dir;
48− QSettings s("./devices.conf", QSettings::IniFormat);
50+ QSettings s(dir.path() + "/devices.conf", QSettings::IniFormat);
49 s.beginGroup("fakedevice");
51 s.beginGroup("fakedevice");
50
52
51 s.setValue("SupportedOrientations", QStringList() << "Portrait" << "Landscape" << "InvertedLandscape");
53 s.setValue("SupportedOrientations", QStringList() << "Portrait" << "Landscape" << "InvertedLandscape");
52 s.setValue("PrimaryOrientation", "InvertedLandscape");
54 s.setValue("PrimaryOrientation", "InvertedLandscape");
53 s.sync();
55 s.sync();
54
56
57+ qputenv("XDG_CONFIG_HOME", dir.path().toUtf8());
55 DeviceConfigParser p;
58 DeviceConfigParser p;
56 p.setName("fakedevice");
59 p.setName("fakedevice");
57
60
tests/plugins/Utils/WindowInputMonitorTest.cpp+76−9
@@ -25,14 +25,15 @@ class FakeElapsedTimer : public AbstractElapsedTimer {
25public:
25public:
26 static qint64 msecsSinceEpoch;
26 static qint64 msecsSinceEpoch;
27
27
28− FakeElapsedTimer() { start(); }
28+ FakeElapsedTimer() {}
29
29
30− void start() override { m_msecsSinceReference = msecsSinceEpoch; }
30+ void start() override { m_msecsSinceReference = msecsSinceEpoch; m_valid = true; }
31 qint64 msecsSinceReference() const override { return m_msecsSinceReference; }
31 qint64 msecsSinceReference() const override { return m_msecsSinceReference; }
32− qint64 elapsed() const override { return msecsSinceEpoch - m_msecsSinceReference; }
32+ qint64 elapsed() const override { return m_valid ? msecsSinceEpoch - m_msecsSinceReference : qrand(); }
33
33
34private:
34private:
35 qint64 m_msecsSinceReference;
35 qint64 m_msecsSinceReference;
36+ bool m_valid{false};
36};
37};
37qint64 FakeElapsedTimer::msecsSinceEpoch = 0;
38qint64 FakeElapsedTimer::msecsSinceEpoch = 0;
38
39
@@ -48,11 +49,14 @@ public:
48 int interval() const override;
49 int interval() const override;
49 void setInterval(int msecs) override;
50 void setInterval(int msecs) override;
50 void start() override;
51 void start() override;
52+ void stop() override;
53+ bool isRunning() const override;
51 bool isSingleShot() const override;
54 bool isSingleShot() const override;
52 void setSingleShot(bool value) override;
55 void setSingleShot(bool value) override;
53private:
56private:
54 int m_interval;
57 int m_interval;
55 bool m_singleShot;
58 bool m_singleShot;
59+ bool m_isRunning;
56 qint64 m_nextTimeoutTime;
60 qint64 m_nextTimeoutTime;
57};
61};
58
62
@@ -85,6 +89,8 @@ private Q_SLOTS:
85 void tapWhileTouching();
89 void tapWhileTouching();
86 void multipleHomeKeys();
90 void multipleHomeKeys();
87
91
92+ void repeatedSuperPress();
93+
88private:
94private:
89 void passTime(qint64 timeSpanMs);
95 void passTime(qint64 timeSpanMs);
90
96
@@ -98,11 +104,10 @@ void WindowInputMonitorTest::init()
98
104
99void WindowInputMonitorTest::cleanup()
105void WindowInputMonitorTest::cleanup()
100{
106{
101− delete m_fakeTimerFactory;
107+ delete m_fakeTimerFactory;
102 m_fakeTimerFactory = nullptr;
108 m_fakeTimerFactory = nullptr;
103}
109}
104
110
105−
106void WindowInputMonitorTest::passTime(qint64 timeSpanMs)
111void WindowInputMonitorTest::passTime(qint64 timeSpanMs)
107{
112{
108 qint64 finalTime = FakeElapsedTimer::msecsSinceEpoch + timeSpanMs;
113 qint64 finalTime = FakeElapsedTimer::msecsSinceEpoch + timeSpanMs;
@@ -133,7 +138,7 @@ void WindowInputMonitorTest::touchTapTouch()
133 QFETCH(int, silenceAfterTap);
138 QFETCH(int, silenceAfterTap);
134 QFETCH(int, expectedActivatedCount);
139 QFETCH(int, expectedActivatedCount);
135 QFETCH(Qt::Key, key);
140 QFETCH(Qt::Key, key);
136− WindowInputMonitor homeKeyWatcher(m_fakeTimerFactory->create(), new FakeElapsedTimer);
141+ WindowInputMonitor homeKeyWatcher(m_fakeTimerFactory->create(this), new FakeElapsedTimer);
137 QSignalSpy activatedSpy(&homeKeyWatcher, &WindowInputMonitor::homeKeyActivated);
142 QSignalSpy activatedSpy(&homeKeyWatcher, &WindowInputMonitor::homeKeyActivated);
138 QVERIFY(activatedSpy.isValid());
143 QVERIFY(activatedSpy.isValid());
139
144
@@ -194,7 +199,7 @@ void WindowInputMonitorTest::touchTapTouch()
194
199
195void WindowInputMonitorTest::tapWhileTouching()
200void WindowInputMonitorTest::tapWhileTouching()
196{
201{
197− WindowInputMonitor homeKeyWatcher(m_fakeTimerFactory->create(), new FakeElapsedTimer);
202+ WindowInputMonitor homeKeyWatcher(m_fakeTimerFactory->create(this), new FakeElapsedTimer);
198 QSignalSpy activatedSpy(&homeKeyWatcher, &WindowInputMonitor::homeKeyActivated);
203 QSignalSpy activatedSpy(&homeKeyWatcher, &WindowInputMonitor::homeKeyActivated);
199 QVERIFY(activatedSpy.isValid());
204 QVERIFY(activatedSpy.isValid());
200
205
@@ -229,7 +234,7 @@ void WindowInputMonitorTest::tapWhileTouching()
229 */
234 */
230void WindowInputMonitorTest::multipleHomeKeys()
235void WindowInputMonitorTest::multipleHomeKeys()
231{
236{
232− WindowInputMonitor homeKeyWatcher(m_fakeTimerFactory->create(), new FakeElapsedTimer);
237+ WindowInputMonitor homeKeyWatcher(m_fakeTimerFactory->create(this), new FakeElapsedTimer);
233 QSignalSpy activatedSpy(&homeKeyWatcher, &WindowInputMonitor::homeKeyActivated);
238 QSignalSpy activatedSpy(&homeKeyWatcher, &WindowInputMonitor::homeKeyActivated);
234 QVERIFY(activatedSpy.isValid());
239 QVERIFY(activatedSpy.isValid());
235
240
@@ -258,12 +263,64 @@ void WindowInputMonitorTest::multipleHomeKeys()
258 QCOMPARE(activatedSpy.count(), 1);
263 QCOMPARE(activatedSpy.count(), 1);
259}
264}
260
265
266+// regression test for lp:1607427
267+void WindowInputMonitorTest::repeatedSuperPress()
268+{
269+ WindowInputMonitor homeKeyWatcher(m_fakeTimerFactory->create(this), new FakeElapsedTimer);
270+ QSignalSpy activatedSpy(&homeKeyWatcher, &WindowInputMonitor::homeKeyActivated);
271+ QVERIFY(activatedSpy.isValid());
272+
273+ // 1st try
274+ passTime(1000);
275+ {
276+ QKeyEvent keyEvent(QEvent::KeyPress, Qt::Key_Super_L, Qt::NoModifier);
277+ homeKeyWatcher.update(&keyEvent);
278+ }
279+ passTime(50);
280+ {
281+ QKeyEvent keyEvent(QEvent::KeyRelease, Qt::Key_Super_L, Qt::NoModifier);
282+ homeKeyWatcher.update(&keyEvent);
283+ }
284+ passTime(1000);
285+ QCOMPARE(activatedSpy.count(), 1);
286+
287+ // a touch event in between
288+ {
289+ QTouchEvent touchEvent(QEvent::TouchBegin);
290+ homeKeyWatcher.update(&touchEvent);
291+ }
292+ {
293+ QTouchEvent touchEvent(QEvent::TouchUpdate);
294+ homeKeyWatcher.update(&touchEvent);
295+ }
296+ {
297+ QTouchEvent touchEvent(QEvent::TouchEnd);
298+ homeKeyWatcher.update(&touchEvent);
299+ }
300+
301+ passTime(1000);
302+ // 2nd try
303+ activatedSpy.clear();
304+ {
305+ QKeyEvent keyEvent(QEvent::KeyPress, Qt::Key_Super_L, Qt::NoModifier);
306+ homeKeyWatcher.update(&keyEvent);
307+ }
308+ passTime(50);
309+ {
310+ QKeyEvent keyEvent(QEvent::KeyRelease, Qt::Key_Super_L, Qt::NoModifier);
311+ homeKeyWatcher.update(&keyEvent);
312+ }
313+ passTime(1000);
314+ QCOMPARE(activatedSpy.count(), 1);
315+}
316+
261/////////////////////////////////// FakeTimer //////////////////////////////////
317/////////////////////////////////// FakeTimer //////////////////////////////////
262
318
263FakeTimer::FakeTimer(QObject *parent)
319FakeTimer::FakeTimer(QObject *parent)
264 : UnityUtil::AbstractTimer(parent)
320 : UnityUtil::AbstractTimer(parent)
265 , m_interval(0)
321 , m_interval(0)
266 , m_singleShot(true)
322 , m_singleShot(true)
323+ , m_isRunning(false)
267{
324{
268}
325}
269
326
@@ -285,10 +342,20 @@ void FakeTimer::update()
285
342
286void FakeTimer::start()
343void FakeTimer::start()
287{
344{
288− AbstractTimer::start();
345+ m_isRunning = true;
289 m_nextTimeoutTime = FakeElapsedTimer::msecsSinceEpoch + (qint64)interval();
346 m_nextTimeoutTime = FakeElapsedTimer::msecsSinceEpoch + (qint64)interval();
290}
347}
291
348
349+void FakeTimer::stop()
350+{
351+ m_isRunning = false;
352+}
353+
354+bool FakeTimer::isRunning() const
355+{
356+ return m_isRunning;
357+}
358+
292int FakeTimer::interval() const
359int FakeTimer::interval() const
293{
360{
294 return m_interval;
361 return m_interval;
tests/plugins/Wizard/CMakeLists.txt+6
@@ -8,6 +8,9 @@ add_executable(tst-wizard-pagelist
8 ${CMAKE_SOURCE_DIR}/plugins/Wizard/PageList.cpp
8 ${CMAKE_SOURCE_DIR}/plugins/Wizard/PageList.cpp
9)
9)
10qt5_use_modules(tst-wizard-pagelist Core Qml Test)
10qt5_use_modules(tst-wizard-pagelist Core Qml Test)
11+install(TARGETS tst-wizard-pagelist
12+ DESTINATION "${SHELL_PRIVATE_LIBDIR}/tests/plugins/Wizard"
13+)
11add_unity8_unittest(WizardPageList tst-wizard-pagelist ENVIRONMENT WIZARD_TESTING=1)
14add_unity8_unittest(WizardPageList tst-wizard-pagelist ENVIRONMENT WIZARD_TESTING=1)
12
15
13add_executable(tst-wizard-system
16add_executable(tst-wizard-system
@@ -15,4 +18,7 @@ add_executable(tst-wizard-system
15 ${CMAKE_SOURCE_DIR}/plugins/Wizard/System.cpp
18 ${CMAKE_SOURCE_DIR}/plugins/Wizard/System.cpp
16)
19)
17qt5_use_modules(tst-wizard-system Core DBus Qml Test)
20qt5_use_modules(tst-wizard-system Core DBus Qml Test)
21+install(TARGETS tst-wizard-system
22+ DESTINATION "${SHELL_PRIVATE_LIBDIR}/tests/plugins/Wizard"
23+)
18add_unity8_unittest(WizardSystem tst-wizard-system)
24add_unity8_unittest(WizardSystem tst-wizard-system)
tests/qmltests/CMakeLists.txt+18
@@ -6,11 +6,13 @@ add_unity8_qmltest(. DisabledScreenNotice)
6add_unity8_qmltest(. Shell)
6add_unity8_qmltest(. Shell)
7add_unity8_qmltest(. ShellWithPin)
7add_unity8_qmltest(. ShellWithPin)
8add_unity8_qmltest(. DeviceConfiguration)
8add_unity8_qmltest(. DeviceConfiguration)
9+add_unity8_qmltest_data(. EdgeBarrierControls)
9add_unity8_qmltest(Components Background)
10add_unity8_qmltest(Components Background)
10add_unity8_qmltest(Components Carousel)
11add_unity8_qmltest(Components Carousel)
11add_unity8_qmltest(Components Dialogs)
12add_unity8_qmltest(Components Dialogs)
12add_unity8_qmltest(Components DraggingArea)
13add_unity8_qmltest(Components DraggingArea)
13add_unity8_qmltest(Components LazyImage)
14add_unity8_qmltest(Components LazyImage)
15+add_unity8_qmltest_data(Components tst_LazyImage)
14add_unity8_qmltest(Components Lockscreen)
16add_unity8_qmltest(Components Lockscreen)
15add_unity8_qmltest(Components MediaServices)
17add_unity8_qmltest(Components MediaServices)
16add_unity8_qmltest(Components ModeSwitchWarningDialog)
18add_unity8_qmltest(Components ModeSwitchWarningDialog)
@@ -33,6 +35,9 @@ add_unity8_qmltest(Dash CardTool)
33add_unity8_qmltest(Dash GenericScopeView)
35add_unity8_qmltest(Dash GenericScopeView)
34add_unity8_qmltest(Dash DashPageHeader)
36add_unity8_qmltest(Dash DashPageHeader)
35add_unity8_qmltest(Dash PreviewView)
37add_unity8_qmltest(Dash PreviewView)
38+add_unity8_qmltest_data(Dash artwork)
39+add_unity8_qmltest_data(Dash CardHelpers.js)
40+add_unity8_qmltest_data(Dash tst_PageHeader)
36add_unity8_qmltest(Dash/Previews Preview)
41add_unity8_qmltest(Dash/Previews Preview)
37add_unity8_qmltest(Dash/Previews PreviewActions)
42add_unity8_qmltest(Dash/Previews PreviewActions)
38add_unity8_qmltest(Dash/Previews PreviewAudioPlayback)
43add_unity8_qmltest(Dash/Previews PreviewAudioPlayback)
@@ -55,6 +60,7 @@ add_unity8_qmltest(Dash/Previews PreviewTextSummary)
55add_unity8_qmltest(Dash/Previews PreviewVideoPlayback)
60add_unity8_qmltest(Dash/Previews PreviewVideoPlayback)
56add_unity8_qmltest(Dash/Previews PreviewWidgetFactory)
61add_unity8_qmltest(Dash/Previews PreviewWidgetFactory)
57add_unity8_qmltest(Dash/Previews PreviewZoomableImage)
62add_unity8_qmltest(Dash/Previews PreviewZoomableImage)
63+add_unity8_qmltest_data(Dash/Previews MockPreviewWidget)
58add_unity8_qmltest(Dash/Filters FilterOptionSelector)
64add_unity8_qmltest(Dash/Filters FilterOptionSelector)
59add_unity8_qmltest(Dash/Filters FilterRangeInput)
65add_unity8_qmltest(Dash/Filters FilterRangeInput)
60add_unity8_qmltest(Dash/Filters FilterValueSlider)
66add_unity8_qmltest(Dash/Filters FilterValueSlider)
@@ -70,11 +76,14 @@ add_unity8_qmltest(Greeter Greeter)
70add_unity8_qmltest(Greeter Infographics)
76add_unity8_qmltest(Greeter Infographics)
71add_unity8_qmltest(Greeter NarrowView)
77add_unity8_qmltest(Greeter NarrowView)
72add_unity8_qmltest(Greeter WideView)
78add_unity8_qmltest(Greeter WideView)
79+add_unity8_qmltest_data(Greeter TestView)
73add_unity8_qmltest(Launcher Launcher)
80add_unity8_qmltest(Launcher Launcher)
81+add_unity8_qmltest(Launcher Drawer)
74add_unity8_qmltest(Notifications Notifications)
82add_unity8_qmltest(Notifications Notifications)
75add_unity8_qmltest(Notifications VisualSnapDecisionsQueue)
83add_unity8_qmltest(Notifications VisualSnapDecisionsQueue)
76add_unity8_qmltest(Notifications OptionToggle)
84add_unity8_qmltest(Notifications OptionToggle)
77add_unity8_qmltest(Notifications SwipeToAct)
85add_unity8_qmltest(Notifications SwipeToAct)
86+add_unity8_qmltest_data(Notifications Notification)
78add_unity8_qmltest(Panel ActiveCallHint)
87add_unity8_qmltest(Panel ActiveCallHint)
79add_unity8_qmltest(Panel IndicatorItem)
88add_unity8_qmltest(Panel IndicatorItem)
80add_unity8_qmltest(Panel IndicatorItemRow)
89add_unity8_qmltest(Panel IndicatorItemRow)
@@ -83,6 +92,7 @@ add_unity8_qmltest(Panel IndicatorsBar)
83add_unity8_qmltest(Panel IndicatorsMenu)
92add_unity8_qmltest(Panel IndicatorsMenu)
84add_unity8_qmltest(Panel MenuContent)
93add_unity8_qmltest(Panel MenuContent)
85add_unity8_qmltest(Panel Panel)
94add_unity8_qmltest(Panel Panel)
95+add_unity8_qmltest_data(Panel IndicatorTest)
86add_unity8_qmltest(Panel/Indicators IndicatorsLight)
96add_unity8_qmltest(Panel/Indicators IndicatorsLight)
87add_unity8_qmltest(Panel/Indicators MenuItemFactory)
97add_unity8_qmltest(Panel/Indicators MenuItemFactory)
88add_unity8_qmltest(Panel/Indicators MessageMenuItemFactory)
98add_unity8_qmltest(Panel/Indicators MessageMenuItemFactory)
@@ -94,6 +104,14 @@ add_unity8_qmltest(Stage TabletStage)
94add_unity8_qmltest(Stage WindowResizeArea)
104add_unity8_qmltest(Stage WindowResizeArea)
95add_unity8_qmltest(Stage Splash)
105add_unity8_qmltest(Stage Splash)
96add_unity8_qmltest(Stage DecoratedWindow)
106add_unity8_qmltest(Stage DecoratedWindow)
107+add_unity8_qmltest_data(Stage ApplicationCheckBox)
108+add_unity8_qmltest_data(Stage SizeHintField)
109+add_unity8_qmltest_data(Stage SurfaceManagerControls)
110+add_unity8_qmltest_data(Stage SurfaceManagerField)
97add_unity8_qmltest(Tutorial Tutorial)
111add_unity8_qmltest(Tutorial Tutorial)
98add_unity8_qmltest(Wizard Wizard ENVIRONMENT "OXIDE_NO_SANDBOX=1")
112add_unity8_qmltest(Wizard Wizard ENVIRONMENT "OXIDE_NO_SANDBOX=1")
113+add_unity8_qmltest_data(Wizard licenses)
114+add_unity8_qmltest_data(Wizard nolicenses)
99add_unity8_qmltest(utils/Unity/Test UnityTest)
115add_unity8_qmltest(utils/Unity/Test UnityTest)
116+add_unity8_qmltest_data(utils/Unity/Test MockObjectForInstanceOfTest)
117+add_unity8_qmltest_data(utils/Unity/Test MockObjectForInstanceOfTestChild)
tests/qmltests/Components/CMakeLists.txt+18−3
@@ -1,4 +1,4 @@
1−add_definitions(-DTEST_DIR="${CMAKE_CURRENT_LIST_DIR}")
1+add_definitions(-DTEST_DIR="qmltests/Components")
2
2
3pkg_check_modules(UBUNTUGESTURES REQUIRED UbuntuGestures)
3pkg_check_modules(UBUNTUGESTURES REQUIRED UbuntuGestures)
4
4
@@ -20,13 +20,28 @@ include_directories(
20add_executable(DragHandleTestExec tst_DragHandle.cpp)
20add_executable(DragHandleTestExec tst_DragHandle.cpp)
21qt5_use_modules(DragHandleTestExec Test Core Qml Gui Quick)
21qt5_use_modules(DragHandleTestExec Test Core Qml Gui Quick)
22target_link_libraries(DragHandleTestExec UbuntuGesturesQml ${UBUNTUGESTURES_LIBRARIES})
22target_link_libraries(DragHandleTestExec UbuntuGesturesQml ${UBUNTUGESTURES_LIBRARIES})
23+install(TARGETS DragHandleTestExec
24+ DESTINATION "${SHELL_PRIVATE_LIBDIR}/tests/qmltests/Components"
25+ )
26+set_target_properties(DragHandleTestExec PROPERTIES
27+ INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/${SHELL_INSTALL_QML}/Ubuntu/Gestures:${CMAKE_INSTALL_PREFIX}/${SHELL_PRIVATE_LIBDIR}"
28+ )
23
29
24−add_unity8_uitest(DragHandle DragHandleTestExec ENVIRONMENT LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/plugins/Ubuntu/Gestures)
30+add_unity8_uitest(DragHandle DragHandleTestExec)
25add_manual_qml_test(. DragHandle IMPORT_PATHS ${UNITY_IMPORT_PATHS})
31add_manual_qml_test(. DragHandle IMPORT_PATHS ${UNITY_IMPORT_PATHS})
32+add_unity8_qmltest_data(. tst_DragHandle.qml)
33+add_unity8_qmltest_data(. tst_DragHandle)
26
34
27########## tst_EdgeDragEvaluator
35########## tst_EdgeDragEvaluator
28add_executable(EdgeDragEvaluatorTestExec tst_EdgeDragEvaluator.cpp)
36add_executable(EdgeDragEvaluatorTestExec tst_EdgeDragEvaluator.cpp)
29qt5_use_modules(EdgeDragEvaluatorTestExec Test Core Qml Gui Quick)
37qt5_use_modules(EdgeDragEvaluatorTestExec Test Core Qml Gui Quick)
30target_link_libraries(EdgeDragEvaluatorTestExec UbuntuGesturesQml ${UBUNTUGESTURES_LIBRARIES})
38target_link_libraries(EdgeDragEvaluatorTestExec UbuntuGesturesQml ${UBUNTUGESTURES_LIBRARIES})
39+install(TARGETS EdgeDragEvaluatorTestExec
40+ DESTINATION "${SHELL_PRIVATE_LIBDIR}/tests/qmltests/Components"
41+ )
42+set_target_properties(EdgeDragEvaluatorTestExec PROPERTIES
43+ INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/${SHELL_INSTALL_QML}/Ubuntu/Gestures:${CMAKE_INSTALL_PREFIX}/${SHELL_PRIVATE_LIBDIR}"
44+ )
31
45
32−add_unity8_uitest(EdgeDragEvaluator EdgeDragEvaluatorTestExec ENVIRONMENT LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/plugins/Ubuntu/Gestures)
46+add_unity8_uitest(EdgeDragEvaluator EdgeDragEvaluatorTestExec)
47+add_unity8_qmltest_data(. tst_EdgeDragEvaluator.qml)
tests/qmltests/Components/tst_DragHandle.cpp+4−2
@@ -27,6 +27,8 @@
27#include <UbuntuGestures/private/timer_p.h>
27#include <UbuntuGestures/private/timer_p.h>
28#include "Direction.h"
28#include "Direction.h"
29
29
30+#include <paths.h>
31+
30UG_USE_NAMESPACE
32UG_USE_NAMESPACE
31
33
32class tst_DragHandle: public QObject
34class tst_DragHandle: public QObject
@@ -84,7 +86,7 @@ void tst_DragHandle::cleanupTestCase()
84void tst_DragHandle::init()
86void tst_DragHandle::init()
85{
87{
86 m_view = createView();
88 m_view = createView();
87− m_view->setSource(QUrl::fromLocalFile(TEST_DIR"/tst_DragHandle.qml"));
89+ m_view->setSource(QUrl::fromLocalFile(testDataDir() + "/" TEST_DIR "/tst_DragHandle.qml"));
88 m_view->show();
90 m_view->show();
89 QVERIFY(QTest::qWaitForWindowExposed(m_view));
91 QVERIFY(QTest::qWaitForWindowExposed(m_view));
90 QVERIFY(m_view->rootObject() != 0);
92 QVERIFY(m_view->rootObject() != 0);
@@ -113,7 +115,7 @@ QQuickView *tst_DragHandle::createView()
113{
115{
114 QQuickView *window = new QQuickView(0);
116 QQuickView *window = new QQuickView(0);
115 window->setResizeMode(QQuickView::SizeRootObjectToView);
117 window->setResizeMode(QQuickView::SizeRootObjectToView);
116− window->engine()->addImportPath(QLatin1String(TEST_DIR));
118+ window->engine()->addImportPath(testDataDir() + "/" TEST_DIR);
117
119
118 return window;
120 return window;
119}
121}
tests/qmltests/Components/tst_EdgeDragEvaluator.cpp+4−2
@@ -26,6 +26,8 @@
26#include <Direction.h>
26#include <Direction.h>
27#include <UbuntuGestures/private/timer_p.h>
27#include <UbuntuGestures/private/timer_p.h>
28
28
29+#include <paths.h>
30+
29UG_USE_NAMESPACE
31UG_USE_NAMESPACE
30
32
31class tst_EdgeDragEvaluator: public QObject
33class tst_EdgeDragEvaluator: public QObject
@@ -67,7 +69,7 @@ void tst_EdgeDragEvaluator::init()
67{
69{
68
70
69 m_view = createView();
71 m_view = createView();
70− m_view->setSource(QUrl::fromLocalFile(TEST_DIR"/tst_EdgeDragEvaluator.qml"));
72+ m_view->setSource(QUrl::fromLocalFile(testDataDir() + "/" TEST_DIR "/tst_EdgeDragEvaluator.qml"));
71 m_view->show();
73 m_view->show();
72 QVERIFY(QTest::qWaitForWindowExposed(m_view));
74 QVERIFY(QTest::qWaitForWindowExposed(m_view));
73 QVERIFY(m_view->rootObject() != 0);
75 QVERIFY(m_view->rootObject() != 0);
@@ -99,7 +101,7 @@ QQuickView *tst_EdgeDragEvaluator::createView()
99{
101{
100 QQuickView *window = new QQuickView(0);
102 QQuickView *window = new QQuickView(0);
101 window->setResizeMode(QQuickView::SizeRootObjectToView);
103 window->setResizeMode(QQuickView::SizeRootObjectToView);
102− window->engine()->addImportPath(QLatin1String(TEST_DIR));
104+ window->engine()->addImportPath(testDataDir() + "/" TEST_DIR);
103
105
104 return window;
106 return window;
105}
107}
tests/qmltests/Components/tst_VirtualTouchPad.qml+55−1
@@ -21,14 +21,20 @@ import UInput 0.1
21import "../../../qml/Components"
21import "../../../qml/Components"
22
22
23
23
24−Item {
24+Rectangle {
25 id: root
25 id: root
26 width: units.gu(70)
26 width: units.gu(70)
27 height: units.gu(70)
27 height: units.gu(70)
28+ color: "black"
28
29
29 VirtualTouchPad {
30 VirtualTouchPad {
30 id: touchScreenPad
31 id: touchScreenPad
31 anchors.fill: parent
32 anchors.fill: parent
33+ property int internalGu: units.gu(1)
34+ settings: QtObject {
35+ property bool touchpadTutorialHasRun: true
36+ property bool oskEnabled: true
37+ }
32 }
38 }
33
39
34 SignalSpy {
40 SignalSpy {
@@ -139,5 +145,53 @@ Item {
139 event.release(1, startX2, startY + units.gu(11));
145 event.release(1, startX2, startY + units.gu(11));
140 event.commit();
146 event.commit();
141 }
147 }
148+
149+ function test_tutorial() {
150+ var oskButton = findChild(touchScreenPad, "oskButton");
151+ var leftButton = findChild(touchScreenPad, "leftButton");
152+ var rightButton = findChild(touchScreenPad, "rightButton");
153+ var touchPad = findChild(touchScreenPad, "virtualTouchPad")
154+ var tutorial = findInvisibleChild(touchScreenPad, "tutorialAnimation")
155+ var tutorialFinger1 = findChild(touchScreenPad, "tutorialFinger1");
156+ var tutorialFinger2 = findChild(touchScreenPad, "tutorialFinger2");
157+ var tutorialLabel = findChild(touchScreenPad, "tutorialLabel");
158+ var tutorialImage = findChild(touchScreenPad, "tutorialImage");
159+
160+ mouseEventSpy1.signalName = "mousePressed"
161+ mouseEventSpy2.signalName = "mouseReleased"
162+
163+ mouseEventSpy1.clear();
164+ mouseEventSpy2.clear();
165+
166+ // run the tutorial
167+ touchScreenPad.runTutorial();
168+ tryCompare(tutorial, "running", true)
169+
170+ // Wait for it to pause
171+ tryCompare(tutorial, "paused", true)
172+
173+ // Click somewhere to make it continue
174+ mouseClick(root, root.width / 2, root.height /2)
175+ tryCompare(tutorial, "paused", false)
176+
177+ // Verify that the touchpad does NOT accept input while the tutorial is running
178+ mouseClick(root, root.width / 2, root.height /2)
179+ compare(mouseEventSpy1.count, 0)
180+ compare(mouseEventSpy2.count, 0)
181+
182+ // Wait for it to finish
183+ tryCompare(tutorial, "running", false, 60000)
184+
185+ // Make sure after the tutorial, all the visible states are proper
186+ tryCompare(oskButton, "visible", true)
187+ tryCompare(leftButton, "visible", true)
188+ tryCompare(rightButton, "visible", true)
189+
190+ tryCompare(tutorialFinger1, "visible", false)
191+ tryCompare(tutorialFinger2, "visible", false)
192+ tryCompare(tutorialImage, "visible", false)
193+ tryCompare(tutorialLabel, "visible", false)
194+ }
195+
142 }
196 }
143}
197}
tests/qmltests/Components/tst_ZoomableImage.qml+1−1
@@ -36,7 +36,7 @@ Rectangle {
36 }
36 }
37
37
38 property var widgetData2: {
38 property var widgetData2: {
39− "source": "../../mocks/Unity/Application/resources/screenshots/gallery@12.png",
39+ "source": Qt.resolvedUrl("../../graphics/screenshots/gallery@12.png"),
40 "zoomable": true
40 "zoomable": true
41 }
41 }
42
42
tests/qmltests/Dash/Previews/tst_Preview.qml+63
@@ -37,6 +37,51 @@ Rectangle {
37 id: mockPreviewModel
37 id: mockPreviewModel
38 }
38 }
39
39
40+ ListModel {
41+ id: tracksModel
42+ Component.onCompleted:
43+ {
44+ tracksModel.append( { "type" : "audio1",
45+ "widgetId" : "audiopw1",
46+ "properties" : { "tracks" : [
47+ { title: "Some track name", length: "30", source: "/not/existinga/path/testsound1" }
48+ ]
49+ }
50+ }
51+ );
52+ tracksModel.append(
53+ { "type" : "audio",
54+ "widgetId" : "audiopw",
55+ "properties" : { "tracks" : [
56+ { title: "Some track name", length: "30", source: "/not/existing/path/testsound1" },
57+ { title: "Some other track name", subtitle: "Subtitle", length: "83", source: "/not/existing/path/testsound2" },
58+ { title: "And another one", length: "7425", source: "/not/existing/path/testsound3" },
59+ { title: "And another one", length: "7425", source: "/not/existing/path/testsound4" },
60+ { title: "And another one", length: "7425", source: "/not/existing/path/testsound5" },
61+ { title: "And another one", length: "7425", source: "/not/existing/path/testsound6" },
62+ { title: "And another one", length: "7425", source: "/not/existing/path/testsound7" },
63+ { title: "And another one", length: "7425", source: "/not/existing/path/testsound8" },
64+ { title: "And another one", length: "7425", source: "/not/existing/path/testsound9" },
65+ { title: "And another one", length: "7425", source: "/not/existing/path/testsound10" },
66+ { title: "And another one", length: "7425", source: "/not/existing/path/testsound11" },
67+ { title: "And another one", length: "7425", source: "/not/existing/path/testsound12" },
68+ { title: "And another one", length: "7425", source: "/not/existing/path/testsound13" },
69+ { title: "And another one", length: "7425", source: "/not/existing/path/testsound14" },
70+ { title: "And another one", length: "7425", source: "/not/existing/path/testsound15" },
71+ { title: "And another one", length: "7425", source: "/not/existing/path/testsound16" },
72+ { title: "And another one", length: "7425", source: "/not/existing/path/testsound17" }
73+ ]
74+ }
75+ } );
76+ }
77+ }
78+
79+ QtObject {
80+ id: audiosModel
81+ property int widgetColumnCount: 1
82+ property var columnModel: { tracksModel }
83+ }
84+
40 Preview {
85 Preview {
41 id: preview
86 id: preview
42 anchors.fill: parent
87 anchors.fill: parent
@@ -57,6 +102,7 @@ Rectangle {
57 function init() {
102 function init() {
58 var widget = findChild(preview, "previewListRow0");
103 var widget = findChild(preview, "previewListRow0");
59 widget.positionViewAtBeginning();
104 widget.positionViewAtBeginning();
105+ preview.previewModel = mockPreviewModel;
60 }
106 }
61
107
62 function test_triggered() {
108 function test_triggered() {
@@ -147,5 +193,22 @@ Rectangle {
147 skip("preview %1 or widget %2 have been destroyed, thus we can't safely continue this test".arg(preview_str).arg(widget_str))
193 skip("preview %1 or widget %2 have been destroyed, thus we can't safely continue this test".arg(preview_str).arg(widget_str))
148 }
194 }
149 }
195 }
196+
197+ function test_audios() {
198+ preview.previewModel = audiosModel;
199+ waitForRendering(preview);
200+
201+ // Scroll down
202+ var previewListRow0 = findChild(preview, "previewListRow0");
203+ flickToYEnd(previewListRow0);
204+
205+ var previewsContentY = previewListRow0.contentY;
206+
207+ var trackItem = findChild(preview, "trackItem16");
208+ mouseClick(findChild(trackItem, "playButton"));
209+
210+ expectFail("", "Clicking on a track should not change contentY.");
211+ tryCompareFunction(function () { return previewsContentY != previewListRow0.contentY; }, true);
212+ }
150 }
213 }
151}
214}
tests/qmltests/Dash/Previews/tst_PreviewImageGallery.qml+13−13
@@ -31,31 +31,31 @@ Rectangle {
31
31
32 property var sourcesModel1: {
32 property var sourcesModel1: {
33 "sources": [
33 "sources": [
34− "../../../tests/graphics/avatars/amanda@12.png",
34+ Qt.resolvedUrl("../../../graphics/avatars/amanda@12.png"),
35− "../../../tests/graphics/avatars/funky@12.png",
35+ Qt.resolvedUrl("../../../graphics/avatars/funky@12.png"),
36− "../../../tests/graphics/clock@18.png",
36+ Qt.resolvedUrl("../../../graphics/clock@18.png"),
37− "../../graphics/borked"
37+ Qt.resolvedUrl("../../../../qml/graphics/borked")
38 ]
38 ]
39 }
39 }
40
40
41 property var sourcesModel1WithFallback: {
41 property var sourcesModel1WithFallback: {
42 "sources": [
42 "sources": [
43− "../../../tests/graphics/avatars/amanda@12.png",
43+ Qt.resolvedUrl("../../../graphics/avatars/amanda@12.png"),
44− "../../../tests/graphics/avatars/funky@12.png",
44+ Qt.resolvedUrl("../../../graphics/avatars/funky@12.png"),
45− "../../../tests/graphics/clock@18.png",
45+ Qt.resolvedUrl("../../../graphics/clock@18.png"),
46− "../../graphics/borked"
46+ Qt.resolvedUrl("../../../../qml/graphics/borked")
47 ]
47 ]
48− , "fallback": "../../../tests/graphics/clock@18.png"
48+ , "fallback": Qt.resolvedUrl("../../../graphics/clock@18.png")
49 }
49 }
50
50
51 property var sourcesModelEmptyWithFallback: {
51 property var sourcesModelEmptyWithFallback: {
52 "sources": [
52 "sources": [
53− "../../../tests/graphics/avatars/amanda@12.png",
53+ Qt.resolvedUrl("../../../graphics/avatars/amanda@12.png"),
54− "../../../tests/graphics/avatars/funky@12.png",
54+ Qt.resolvedUrl("../../../graphics/avatars/funky@12.png"),
55− "../../../tests/graphics/clock@18.png",
55+ Qt.resolvedUrl("../../../graphics/clock@18.png"),
56 ""
56 ""
57 ]
57 ]
58− , "fallback": "../../../tests/graphics/clock@18.png"
58+ , "fallback": Qt.resolvedUrl("../../../graphics/clock@18.png")
59 }
59 }
60
60
61 PreviewImageGallery {
61 PreviewImageGallery {
tests/qmltests/Dash/Previews/tst_PreviewZoomableImage.qml+5−5
@@ -26,7 +26,7 @@ Rectangle {
26 color: "lightgrey"
26 color: "lightgrey"
27
27
28 property var widgetData0: {
28 property var widgetData0: {
29− "source": "../../../tests/graphics/avatars/amanda@12.png",
29+ "source": Qt.resolvedUrl("../../../graphics/avatars/amanda@12.png"),
30 "zoomable": false
30 "zoomable": false
31 }
31 }
32
32
@@ -36,17 +36,17 @@ Rectangle {
36
36
37 property var widgetData2: {
37 property var widgetData2: {
38 "source": "fadsasf",
38 "source": "fadsasf",
39− "fallback": "../../../tests/graphics/avatars/amanda@12.png"
39+ "fallback": Qt.resolvedUrl("../../../graphics/avatars/amanda@12.png")
40 }
40 }
41
41
42 property var widgetData3: {
42 property var widgetData3: {
43 "source": "",
43 "source": "",
44− "fallback": "../../../tests/graphics/avatars/amanda@12.png"
44+ "fallback": Qt.resolvedUrl("../../../graphics/avatars/amanda@12.png")
45 }
45 }
46
46
47 property var widgetData4: {
47 property var widgetData4: {
48 "source": "fadsasf",
48 "source": "fadsasf",
49− "fallback": "../../../tests/graphics/avatars/amanda@12.png"
49+ "fallback": Qt.resolvedUrl("../../../graphics/avatars/amanda@12.png")
50 }
50 }
51
51
52 Loader {
52 Loader {
@@ -129,7 +129,7 @@ Rectangle {
129 waitForRendering(lazyImage);
129 waitForRendering(lazyImage);
130 tryCompare(lazyImage, "state", "ready");
130 tryCompare(lazyImage, "state", "ready");
131 verify(lazyImage.sourceImage.source.toString().indexOf("amanda") > -1);
131 verify(lazyImage.sourceImage.source.toString().indexOf("amanda") > -1);
132− zoomableImage.widgetData["source"] = "../../../tests/graphics/avatars/funky@12.png"
132+ zoomableImage.widgetData["source"] = Qt.resolvedUrl("../../../graphics/avatars/funky@12.png")
133 zoomableImage.widgetDataChanged();
133 zoomableImage.widgetDataChanged();
134 tryCompare(lazyImage, "state", "ready");
134 tryCompare(lazyImage, "state", "ready");
135 verify(lazyImage.sourceImage.source.toString().indexOf("funky") > -1);
135 verify(lazyImage.sourceImage.source.toString().indexOf("funky") > -1);
tests/qmltests/Dash/tst_Dash.qml+4−3
@@ -310,8 +310,9 @@ Item {
310 var stopX = units.gu(1)
310 var stopX = units.gu(1)
311 var stopY = startY;
311 var stopY = startY;
312 waitForRendering(dashContentList)
312 waitForRendering(dashContentList)
313− mouseFlick(dash, startX, startY, stopX, stopY);
313+ mouseFlick(dash, startX, startY, stopX, stopY, true, true, units.gu(200));
314+ compare(dashContentList.currentIndex, 1, "Could not flick to scope id 1");
314− mouseFlick(dash, startX, startY, stopX, stopY);
315+ mouseFlick(dash, startX, startY, stopX, stopY, units.gu(200));
315 compare(dashContentList.currentIndex, 2, "Could not flick to scope id 2");
316 compare(dashContentList.currentIndex, 2, "Could not flick to scope id 2");
316 var dashCommunicatorService = findInvisibleChild(dash, "dashCommunicatorService");
317 var dashCommunicatorService = findInvisibleChild(dash, "dashCommunicatorService");
317 dashCommunicatorService.mockSetCurrentScope(0, true, false);
318 dashCommunicatorService.mockSetCurrentScope(0, true, false);
@@ -411,7 +412,7 @@ Item {
411 compare(dashContentList.currentItem.scopeId, "clickscope");
412 compare(dashContentList.currentItem.scopeId, "clickscope");
412
413
413 // Move to second scope
414 // Move to second scope
414− mouseFlick(dash, dash.width / 2, units.gu(2), dash.width / 5, units.gu(2));
415+ mouseFlick(dash, dash.width / 2, units.gu(2), dash.width / 5, units.gu(2), true, true, units.gu(20));
415 tryCompare(dashContentList, "currentIndex", 1);
416 tryCompare(dashContentList, "currentIndex", 1);
416 compare(dashContentList.currentItem.scopeId, "MockScope1");
417 compare(dashContentList.currentItem.scopeId, "MockScope1");
417 }
418 }
tests/qmltests/Dash/tst_DashShell.qml−29
@@ -112,34 +112,5 @@ Item {
112 mouseClick(buttonShowDashHome);
112 mouseClick(buttonShowDashHome);
113 tryCompare(dashContentList, "currentIndex", 0);
113 tryCompare(dashContentList, "currentIndex", 0);
114 }
114 }
115−
116− function test_setShortLauncherMoveResetNonActiveDash() {
117− var dashContentList = findChild(dash, "dashContentList");
118− var startX = dash.width - units.gu(1);
119− var startY = dash.height / 2;
120− var stopX = units.gu(1)
121− var stopY = startY;
122− waitForRendering(dashContentList);
123− touchFlick(dash, startX, startY, stopX, stopY);
124− touchFlick(dash, startX, startY, stopX, stopY);
125− compare(dashContentList.currentIndex, 2, "Could not flick to scope id 2");
126−
127− // Pretend the dash is not active
128− dash.windowActive = false;
129−
130− // Flick the greeter away
131− var startX = shell.width - units.gu(1);
132− var startY = shell.height / 2;
133− var stopX = units.gu(1)
134− var stopY = startY;
135− touchFlick(shell, startX, startY, stopX, stopY);
136−
137− var greeter = findChild(shell, "greeter");
138− tryCompare(greeter, "shown", false);
139−
140− // Now do a small launcher movement
141− touchFlick(shell, stopX, startY, startX, stopY);
142− compare(dashContentList.currentIndex, 0, "Small launcher move did not reset dash on non active window");
143− }
144 }
115 }
145}
116}
tests/qmltests/Dash/tst_GenericScopeView.qml+1−1
@@ -463,7 +463,7 @@ Item {
463 { tag: "Default", index: 0, foreground: UbuntuColors.darkGrey, background: "color:///#ffffff", logo: "" },
463 { tag: "Default", index: 0, foreground: UbuntuColors.darkGrey, background: "color:///#ffffff", logo: "" },
464 { tag: "Foreground", index: 1, foreground: "yellow", background: "color:///#ffffff", logo: "" },
464 { tag: "Foreground", index: 1, foreground: "yellow", background: "color:///#ffffff", logo: "" },
465 { tag: "Logo+Background", index: 2, foreground: UbuntuColors.darkGrey, background: "gradient:///lightgrey/grey",
465 { tag: "Logo+Background", index: 2, foreground: UbuntuColors.darkGrey, background: "gradient:///lightgrey/grey",
466− logo: Qt.resolvedUrl("../Dash/tst_PageHeader/logo-ubuntu-orange.svg") },
466+ logo: Qt.resolvedUrl("tst_PageHeader/logo-ubuntu-orange.svg") },
467 ];
467 ];
468 }
468 }
469
469
tests/qmltests/Launcher/tst_Drawer.qmlnew file+264
@@ -0,0 +1,264 @@
1+/*
2+ * Copyright 2013-2016 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.4
18+import QtQuick.Layouts 1.1
19+import Ubuntu.Components 1.3
20+import ".."
21+import "../../../qml/Launcher"
22+import Unity.Launcher 0.1
23+import Utils 0.1 // For EdgeBarrierSettings
24+import Unity.Test 0.1
25+
26+StyledItem {
27+ id: root
28+ theme.name: "Ubuntu.Components.Themes.SuruDark"
29+
30+ width: units.gu(140)
31+ height: units.gu(70)
32+ Rectangle {
33+ anchors.fill: parent
34+ color: UbuntuColors.graphite // something neither white nor black
35+ }
36+
37+ Launcher {
38+ id: launcher
39+ x: 0
40+ y: 0
41+ width: units.gu(40)
42+ height: root.height
43+
44+ lockedVisible: lockedVisibleCheckBox.checked
45+
46+ property string lastSelectedApplication
47+ onLauncherApplicationSelected: {
48+ lastSelectedApplication = appId
49+ }
50+
51+ Component.onCompleted: {
52+ launcher.focus = true
53+ edgeBarrierControls.target = testCase.findChild(this, "edgeBarrierController");
54+ }
55+ }
56+
57+ ColumnLayout {
58+ anchors { bottom: parent.bottom; right: parent.right; margins: units.gu(1) }
59+ spacing: units.gu(1)
60+ width: childrenRect.width
61+
62+ RowLayout {
63+ CheckBox {
64+ id: lockedVisibleCheckBox
65+ checked: false
66+ }
67+ Label {
68+ text: "Launcher always visible"
69+ }
70+ }
71+
72+ Slider {
73+ id: widthSlider
74+ Layout.fillWidth: true
75+ minimumValue: 6
76+ maximumValue: 12
77+ value: 10
78+ }
79+
80+ MouseTouchEmulationCheckbox {}
81+
82+ EdgeBarrierControls {
83+ id: edgeBarrierControls
84+ text: "Drag here to pull out launcher"
85+ onDragged: { launcher.pushEdge(amount); }
86+ }
87+ }
88+
89+ UnityTestCase {
90+ id: testCase
91+ when: windowShown
92+ name: "Drawer"
93+
94+ function dragDrawerIntoView() {
95+ var startX = launcher.dragAreaWidth/2;
96+ var startY = launcher.height/2;
97+ touchFlick(launcher,
98+ startX, startY,
99+ startX+units.gu(35), startY);
100+
101+ var drawer = findChild(launcher, "drawer");
102+ verify(!!drawer);
103+
104+ // wait until it gets fully extended
105+ // a tryCompare doesn't work since
106+ // compare(-0.000005917593600024418, 0);
107+ // is true and in this case we want exactly 0 or will have pain later on
108+ tryCompareFunction( function(){ return drawer.x === 0; }, true );
109+ tryCompare(launcher, "state", "drawer");
110+ tryCompare(launcher, "drawerShown", true);
111+ }
112+
113+ function revealByEdgePush() {
114+ // Place the mouse against the window/screen edge and push beyond the barrier threshold
115+ // If the mouse did not move between two revealByEdgePush(), we need it to move out the
116+ // area to make sure we're not just accumulating to the previous push
117+ mouseMove(root, root.width, root.height / 2);
118+ mouseMove(root, 1, root.height / 2);
119+
120+ launcher.pushEdge(EdgeBarrierSettings.pushThreshold * 1.1);
121+
122+ var drawer = findChild(launcher, "drawer");
123+ verify(!!drawer);
124+
125+ // wait until it gets fully extended
126+ tryCompare(drawer, "x", 0);
127+ tryCompare(launcher, "state", "drawer");
128+ tryCompare(launcher, "drawerShown", true);
129+ }
130+
131+ function init() {
132+ launcher.lastSelectedApplication = "";
133+ launcher.lockedVisible = false;
134+ launcher.hide();
135+ var drawer = findChild(launcher, "drawer");
136+ tryCompare(drawer, "x", -drawer.width);
137+ }
138+
139+ function test_revealByEdgeDrag() {
140+ dragDrawerIntoView();
141+ }
142+
143+ function test_revealByEdgePush_data() {
144+ return [
145+ { tag: "autohide launcher", autohide: true },
146+ { tag: "locked launcher", autohide: false }
147+ ]
148+ }
149+
150+ function test_revealByEdgePush(data) {
151+ launcher.lockedVisible = !data.autohide;
152+
153+ var panel = findChild(launcher, "launcherPanel");
154+ tryCompare(panel, "x", data.autohide ? -panel.width : 0);
155+ tryCompare(launcher, "state", data.autohide ? "" : "visible");
156+ waitForRendering(launcher)
157+
158+ revealByEdgePush();
159+ }
160+
161+ function test_hideByDraggingDrawer_data() {
162+ return [
163+ {tag: "autohide", autohide: true, endState: ""},
164+ {tag: "locked", autohide: false, endState: "visible"}
165+ ]
166+ }
167+
168+ function test_hideByDraggingDrawer(data) {
169+ launcher.lockedVisible = !data.autohide;
170+
171+ dragDrawerIntoView();
172+ waitForRendering(launcher);
173+
174+ var drawer = findChild(launcher, "drawer");
175+
176+ mouseFlick(root, drawer.width - units.gu(1), drawer.height / 2, units.gu(2), drawer.height / 2, true, true);
177+
178+ tryCompare(drawer.anchors, "rightMargin", 0);
179+ tryCompare(launcher, "state", data.endState);
180+ launcher.lockedVisible = false;
181+ }
182+
183+ function test_hideByClickingOutside() {
184+ dragDrawerIntoView();
185+
186+ var drawer = findChild(launcher, "drawer");
187+
188+ mouseClick(root, drawer.width + units.gu(1), root.height / 2);
189+
190+ tryCompare(launcher, "state", "");
191+ }
192+
193+ function test_launchAppFromDrawer() {
194+ dragDrawerIntoView();
195+
196+ var drawerList = findChild(launcher, "drawerItemList");
197+ var dialerApp = findChild(drawerList, "drawerItem_dialer-app");
198+ mouseClick(dialerApp, dialerApp.width / 2, dialerApp.height / 2);
199+
200+ tryCompare(launcher, "lastSelectedApplication", "dialer-app");
201+
202+ tryCompare(launcher, "state", "");
203+ }
204+
205+ function test_launcherGivesUpFocusAfterLaunchingFromDrawer() {
206+ dragDrawerIntoView();
207+
208+ tryCompare(launcher, "focus", true);
209+
210+ var drawerList = findChild(launcher, "drawerItemList");
211+ var dialerApp = findChild(drawerList, "drawerItem_dialer-app");
212+ mouseClick(dialerApp, dialerApp.width / 2, dialerApp.height / 2);
213+
214+ tryCompare(launcher, "focus", false);
215+ }
216+
217+ function test_drawerDisabled() {
218+ launcher.drawerEnabled = false;
219+
220+ var startX = launcher.dragAreaWidth/2;
221+ var startY = launcher.height/2;
222+ touchFlick(launcher,
223+ startX, startY,
224+ startX+units.gu(35), startY);
225+
226+ var drawer = findChild(launcher, "drawer");
227+ verify(!!drawer);
228+
229+ tryCompare(launcher, "state", "visible");
230+ tryCompare(launcher, "drawerShown", false);
231+
232+ launcher.drawerEnabled = true;
233+ }
234+
235+ function test_search() {
236+ compare(launcher.lastSelectedApplication, "");
237+
238+ launcher.openDrawer(true)
239+ typeString("cam");
240+ keyClick(Qt.Key_Enter);
241+
242+ compare(launcher.lastSelectedApplication, "camera-app");
243+ }
244+
245+ function test_dragDirectionOnLeftEdgeDrag_data() {
246+ return [
247+ { tag: "reveal", direction: "right", endState: "drawer" },
248+ { tag: "cancel", direction: "left", endState: "visible" },
249+ ]
250+ }
251+
252+ function test_dragDirectionOnLeftEdgeDrag(data) {
253+ var startX = launcher.dragAreaWidth/2;
254+ var startY = launcher.height/2;
255+ var stopX = startX + units.gu(35);
256+ var endX = stopX + (units.gu(4) * (data.direction === "left" ? -1 : 1))
257+
258+ touchFlick(launcher, startX, startY, stopX, startY, true, false);
259+ touchFlick(launcher, stopX, startY, endX, startY, false, true);
260+
261+ tryCompare(launcher, "state", data.endState)
262+ }
263+ }
264+}
tests/qmltests/Launcher/tst_Launcher.qml+4−4
@@ -322,7 +322,7 @@ Rectangle {
322 function revealByEdgePush() {
322 function revealByEdgePush() {
323 // Place the mouse against the window/screen edge and push beyond the barrier threshold
323 // Place the mouse against the window/screen edge and push beyond the barrier threshold
324 mouseMove(root, 1, root.height / 2);
324 mouseMove(root, 1, root.height / 2);
325− launcher.pushEdge(EdgeBarrierSettings.pushThreshold * 1.1);
325+ launcher.pushEdge(EdgeBarrierSettings.pushThreshold * .6);
326
326
327 var panel = findChild(launcher, "launcherPanel");
327 var panel = findChild(launcher, "launcherPanel");
328 verify(!!panel);
328 verify(!!panel);
@@ -824,7 +824,7 @@ Rectangle {
824
824
825 // Dragging a bit (> 1.5 gu)
825 // Dragging a bit (> 1.5 gu)
826 newMouseX -= units.gu(2)
826 newMouseX -= units.gu(2)
827− mouseFlick(launcher, currentMouseX, currentMouseY, newMouseX, newMouseY, false, false, 100)
827+ mouseFlick(launcher, currentMouseX, currentMouseY, newMouseX, newMouseY, false, false)
828 currentMouseX = newMouseX
828 currentMouseX = newMouseX
829
829
830 // Other items need to expand and become 0.6 opaque
830 // Other items need to expand and become 0.6 opaque
@@ -832,8 +832,8 @@ Rectangle {
832 tryCompare(item0, "itemOpacity", 0.6)
832 tryCompare(item0, "itemOpacity", 0.6)
833
833
834 // Dragging a bit more
834 // Dragging a bit more
835− newMouseY += initialItemHeight * 1.5
835+ newMouseY += initialItemHeight * 1.25
836− mouseFlick(launcher, currentMouseX, currentMouseY, newMouseX, newMouseY, false, false, 100)
836+ mouseFlick(launcher, currentMouseX, currentMouseY, newMouseX, newMouseY, false, false)
837 currentMouseY = newMouseY
837 currentMouseY = newMouseY
838
838
839 tryCompare(findChild(draggedItem, "dropIndicator"), "opacity", 1)
839 tryCompare(findChild(draggedItem, "dropIndicator"), "opacity", 1)
tests/qmltests/Notifications/tst_Notifications.qml+11−11
@@ -61,8 +61,8 @@ Item {
61 "hints": {},
61 "hints": {},
62 "summary": "Cole Raby",
62 "summary": "Cole Raby",
63 "body": "I did not expect it to be <b>that</b> late.",
63 "body": "I did not expect it to be <b>that</b> late.",
64− "icon": "../../tests/graphics/avatars/amanda.png",
64+ "icon": Qt.resolvedUrl("../../graphics/avatars/amanda.png"),
65− "secondaryIcon": "../../tests/graphics/applicationIcons/facebook.png",
65+ "secondaryIcon": Qt.resolvedUrl("../../graphics/applicationIcons/facebook.png"),
66 "rawActions": ["reply_id", "Dummy"]})
66 "rawActions": ["reply_id", "Dummy"]})
67 n.completed.connect(mockModel.onCompleted)
67 n.completed.connect(mockModel.onCompleted)
68 mockModel.append(n)
68 mockModel.append(n)
@@ -75,7 +75,7 @@ Item {
75 "hints": {"x-canonical-non-shaped-icon": "true"},
75 "hints": {"x-canonical-non-shaped-icon": "true"},
76 "summary": "Contacts",
76 "summary": "Contacts",
77 "body": "Synchronised contacts-database &amp; cloud-storage.",
77 "body": "Synchronised contacts-database &amp; cloud-storage.",
78− "icon": "../../tests/graphics/applicationIcons/contacts-app.png",
78+ "icon": Qt.resolvedUrl("../../graphics/applicationIcons/contacts-app.png"),
79 "secondaryIcon": "",
79 "secondaryIcon": "",
80 "rawActions": ["reply_id", "Dummy"]})
80 "rawActions": ["reply_id", "Dummy"]})
81 n.completed.connect(mockModel.onCompleted)
81 n.completed.connect(mockModel.onCompleted)
@@ -89,7 +89,7 @@ Item {
89 "hints": {"x-canonical-non-shaped-icon": "false"},
89 "hints": {"x-canonical-non-shaped-icon": "false"},
90 "summary": "Photo upload completed",
90 "summary": "Photo upload completed",
91 "body": "",
91 "body": "",
92− "icon": "../../tests/graphics/applicationIcons/facebook.png",
92+ "icon": Qt.resolvedUrl("../../graphics/applicationIcons/facebook.png"),
93 "secondaryIcon": "",
93 "secondaryIcon": "",
94 "rawActions": ["reply_id", "Dummy"]})
94 "rawActions": ["reply_id", "Dummy"]})
95 n.completed.connect(mockModel.onCompleted)
95 n.completed.connect(mockModel.onCompleted)
@@ -103,7 +103,7 @@ Item {
103 "hints": {},
103 "hints": {},
104 "summary": "Interactive notification",
104 "summary": "Interactive notification",
105 "body": "This is a notification that can be clicked",
105 "body": "This is a notification that can be clicked",
106− "icon": "../../tests/graphics/avatars/anna_olsson.png",
106+ "icon": Qt.resolvedUrl("../../graphics/avatars/anna_olsson.png"),
107 "secondaryIcon": "",
107 "secondaryIcon": "",
108 "rawActions": ["reply_id", "Dummy"]})
108 "rawActions": ["reply_id", "Dummy"]})
109 n.completed.connect(mockModel.onCompleted)
109 n.completed.connect(mockModel.onCompleted)
@@ -287,7 +287,7 @@ Item {
287 type: Notification.Ephemeral
287 type: Notification.Ephemeral
288 summary: "Photo upload completed"
288 summary: "Photo upload completed"
289 body: ""
289 body: ""
290− icon: "../../tests/graphics/applicationIcons/facebook.png"
290+ icon: Qt.resolvedUrl("../../graphics/applicationIcons/facebook.png")
291 secondaryIcon: ""
291 secondaryIcon: ""
292 value: 0
292 value: 0
293 rawActions: []
293 rawActions: []
@@ -301,7 +301,7 @@ Item {
301 summary: "New comment successfully published"
301 summary: "New comment successfully published"
302 body: ""
302 body: ""
303 icon: ""
303 icon: ""
304− secondaryIcon: "../../tests/graphics/applicationIcons/facebook.png"
304+ secondaryIcon: Qt.resolvedUrl("../../graphics/applicationIcons/facebook.png")
305 value: 0
305 value: 0
306 rawActions: []
306 rawActions: []
307 },
307 },
@@ -312,7 +312,7 @@ Item {
312 "sound-file": "dummy.ogg"}
312 "sound-file": "dummy.ogg"}
313 summary: "Interactive notification"
313 summary: "Interactive notification"
314 body: "This is a notification that can be clicked"
314 body: "This is a notification that can be clicked"
315− icon: "../../tests/graphics/avatars/amanda.png"
315+ icon: Qt.resolvedUrl("../../graphics/avatars/amanda.png")
316 secondaryIcon: ""
316 secondaryIcon: ""
317 value: 0
317 value: 0
318 rawActions: ["reply_id", "Dummy"]
318 rawActions: ["reply_id", "Dummy"]
@@ -324,7 +324,7 @@ Item {
324 "sound-file": "dummy.ogg"}
324 "sound-file": "dummy.ogg"}
325 summary: "Bro Coly"
325 summary: "Bro Coly"
326 body: "At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet."
326 body: "At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet."
327− icon: "../../tests/graphics/avatars/anna_olsson.png"
327+ icon: Qt.resolvedUrl("../../graphics/avatars/anna_olsson.png")
328 secondaryIcon: ""
328 secondaryIcon: ""
329 value: 0
329 value: 0
330 rawActions: ["accept_id", "Accept",
330 rawActions: ["accept_id", "Accept",
@@ -337,8 +337,8 @@ Item {
337 "sound-file": "dummy.ogg"}
337 "sound-file": "dummy.ogg"}
338 summary: "Cole Raby"
338 summary: "Cole Raby"
339 body: "I did not expect it to be that late."
339 body: "I did not expect it to be that late."
340− icon: "../../tests/graphics/avatars/funky.png"
340+ icon: Qt.resolvedUrl("../../graphics/avatars/funky.png")
341− secondaryIcon: "../../tests/graphics/applicationIcons/facebook.png"
341+ secondaryIcon: Qt.resolvedUrl("../../graphics/applicationIcons/facebook.png")
342 value: 0
342 value: 0
343 rawActions: []
343 rawActions: []
344 },
344 },
tests/qmltests/Notifications/tst_SwipeToAct.qml+5−5
@@ -61,7 +61,7 @@ Item {
61 hints: {"x-canonical-snap-decisions-swipe": "true"},
61 hints: {"x-canonical-snap-decisions-swipe": "true"},
62 summary: "Incoming call",
62 summary: "Incoming call",
63 body: "Frank Zappa\n+44 (0)7736 027340",
63 body: "Frank Zappa\n+44 (0)7736 027340",
64− icon: "../../tests/graphics/avatars/amanda.png",
64+ icon: Qt.resolvedUrl("../../graphics/avatars/amanda.png"),
65 secondaryIcon: "image://theme/incoming-call",
65 secondaryIcon: "image://theme/incoming-call",
66 actions: [{ id: "ok_id", label: "Ok"},
66 actions: [{ id: "ok_id", label: "Ok"},
67 { id: "cancel_id", label: "Cancel"},
67 { id: "cancel_id", label: "Cancel"},
@@ -177,8 +177,8 @@ Item {
177 hints: {"x-canonical-snap-decisions-swipe": "true"},
177 hints: {"x-canonical-snap-decisions-swipe": "true"},
178 summary: "Incoming call",
178 summary: "Incoming call",
179 body: "Frank Zappa\n+44 (0)7736 027340",
179 body: "Frank Zappa\n+44 (0)7736 027340",
180− icon: "../../tests/graphics/avatars/amanda.png",
180+ icon: Qt.resolvedUrl("../../graphics/avatars/amanda.png"),
181− secondaryIcon: "../../tests/graphics/applicationIcons/facebook.png",
181+ secondaryIcon: Qt.resolvedUrl("../../graphics/applicationIcons/facebook.png"),
182 actions: myActionModel,
182 actions: myActionModel,
183 summaryVisible: true,
183 summaryVisible: true,
184 bodyVisible: true,
184 bodyVisible: true,
@@ -196,8 +196,8 @@ Item {
196 hints: {"x-canonical-snap-decisions-swipe": "true"},
196 hints: {"x-canonical-snap-decisions-swipe": "true"},
197 summary: "Incoming call",
197 summary: "Incoming call",
198 body: "Bro Coly\n+49 (0)221 426973",
198 body: "Bro Coly\n+49 (0)221 426973",
199− icon: "../../tests/graphics/avatars/funky.png",
199+ icon: Qt.resolvedUrl("../../graphics/avatars/funky.png"),
200− secondaryIcon: "../../tests/graphics/applicationIcons/facebook.png",
200+ secondaryIcon: Qt.resolvedUrl("../../graphics/applicationIcons/facebook.png"),
201 actions: myActionModel,
201 actions: myActionModel,
202 summaryVisible: true,
202 summaryVisible: true,
203 bodyVisible: true,
203 bodyVisible: true,
tests/qmltests/Panel/Indicators/tst_MenuItemFactory.qml+6−1
@@ -370,7 +370,8 @@ Item {
370 function test_create_switchMenu_data() {
370 function test_create_switchMenu_data() {
371 return [
371 return [
372 {label: "testLabel1", enabled: true, checked: false, icon: "file:///testIcon1" },
372 {label: "testLabel1", enabled: true, checked: false, icon: "file:///testIcon1" },
373− {label: "testLabel2", enabled: false, checked: true, icon: "file:///testIcon2" },
373+ {label: "testLabel2", enabled: false, checked: true, icon: "file:///testIcon2", subtitleAction: "action::subtitle1" },
374+ {label: "testLabel2", enabled: false, checked: true, icon: "file:///testIcon3", subtitleAction: "action::subtitle2" },
374 ];
375 ];
375 }
376 }
376
377
@@ -380,6 +381,9 @@ Item {
380 menuData.sensitive = data.enabled;
381 menuData.sensitive = data.enabled;
381 menuData.icon = data.icon;
382 menuData.icon = data.icon;
382 menuData.isToggled = data.checked;
383 menuData.isToggled = data.checked;
384+ menuData.ext = {
385+ 'xCanonicalSubtitleAction': data.subtitleAction,
386+ };
383
387
384 loader.data = menuData;
388 loader.data = menuData;
385 loader.sourceComponent = factory.load(menuData);
389 loader.sourceComponent = factory.load(menuData);
@@ -390,6 +394,7 @@ Item {
390 compare(loader.item.iconSource, data.icon, "Icon does not match data");
394 compare(loader.item.iconSource, data.icon, "Icon does not match data");
391 compare(loader.item.checked, data.checked, "Checked does not match data");
395 compare(loader.item.checked, data.checked, "Checked does not match data");
392 compare(loader.item.enabled, data.enabled, "Enabled does not match data");
396 compare(loader.item.enabled, data.enabled, "Enabled does not match data");
397+ compare(loader.item.subtitleAction.name, data.subtitleAction === undefined ? "" : data.subtitleAction, "Subtitle action does not match data");
393 }
398 }
394
399
395 function test_create_alarmMenu_data() {
400 function test_create_alarmMenu_data() {
tests/qmltests/Stage/tst_ApplicationWindow.qml+2−20
@@ -53,6 +53,8 @@ Rectangle {
53 surfaceOrientationAngle: 0
53 surfaceOrientationAngle: 0
54 interactive: true
54 interactive: true
55 focus: true
55 focus: true
56+ requestedWidth: width
57+ requestedHeight: height
56 Component.onDestruction: {
58 Component.onDestruction: {
57 applicationWindowLoader.itemDestroyed = true;
59 applicationWindowLoader.itemDestroyed = true;
58 }
60 }
@@ -150,26 +152,6 @@ Rectangle {
150 }
152 }
151 }
153 }
152 }
154 }
153−
154− Button {
155− anchors { left: parent.left; right: parent.right }
156− activeFocusOnPress: false
157− text: "Rotate device \u27F3"
158− onClicked: {
159− var orientation = applicationWindowLoader.item.orientation
160− if (orientation == Qt.PortraitOrientation) {
161− orientation = Qt.LandscapeOrientation;
162− } else if (orientation == Qt.LandscapeOrientation) {
163− orientation = Qt.InvertedPortraitOrientation;
164− } else if (orientation == Qt.InvertedPortraitOrientation) {
165− orientation = Qt.InvertedLandscapeOrientation;
166− } else {
167− orientation = Qt.PortraitOrientation;
168− }
169− applicationWindowLoader.item.orientation = orientation;
170− }
171− }
172−
173 }
155 }
174 }
156 }
175
157
tests/qmltests/Stage/tst_DesktopStage.qml+71
@@ -790,6 +790,77 @@ Item {
790 tryCompare(dialerAppDelegate, "state", "maximized");
790 tryCompare(dialerAppDelegate, "state", "maximized");
791 }
791 }
792
792
793+ function test_saveRestoreSize() {
794+ var originalWindowCount = topSurfaceList.count;
795+ var appDelegate = startApplication("dialer-app");
796+ compare(topSurfaceList.count, originalWindowCount + 1);
797+
798+ var initialWindowX = appDelegate.windowedX;
799+ var initialWindowY = appDelegate.windowedY;
800+ var initialWindowWidth = appDelegate.width
801+ var initialWindowHeight = appDelegate.height
802+
803+ var resizeDelta = units.gu(5)
804+ var startDragX = initialWindowX + initialWindowWidth + 1
805+ var startDragY = initialWindowY + initialWindowHeight + 1
806+ mouseFlick(root, startDragX, startDragY, startDragX + resizeDelta, startDragY + resizeDelta, true, true, units.gu(.5), 10);
807+
808+ tryCompare(appDelegate, "width", initialWindowWidth + resizeDelta);
809+ tryCompare(appDelegate, "height", initialWindowHeight + resizeDelta);
810+
811+ // Close the window and restart the application
812+ var closeButton = findChild(appDelegate, "closeWindowButton");
813+ appDelegate = null;
814+ verify(closeButton);
815+ mouseClick(closeButton);
816+ tryCompare(topSurfaceList, "count", originalWindowCount);
817+ wait(100); // plus some spare room
818+ appDelegate = startApplication("dialer-app");
819+
820+ // Make sure its size is again the same as before
821+ tryCompare(appDelegate, "width", initialWindowWidth + resizeDelta);
822+ tryCompare(appDelegate, "height", initialWindowHeight + resizeDelta);
823+ }
824+
825+ function test_saveRestoreMaximized() {
826+ var originalWindowCount = topSurfaceList.count;
827+ var appDelegate = startApplication("dialer-app");
828+ compare(topSurfaceList.count, originalWindowCount + 1);
829+
830+ var initialWindowX = appDelegate.windowedX;
831+ var initialWindowY = appDelegate.windowedY;
832+
833+ var moveDelta = units.gu(5);
834+
835+ appDelegate.windowedX = initialWindowX + moveDelta
836+ appDelegate.windowedY = initialWindowY + moveDelta
837+
838+ // Now change the state to maximized. The window should not keep updating the stored values
839+ maximizeAppDelegate(appDelegate);
840+
841+ // Close the window and restart the application
842+ var closeButton = findChild(appDelegate, "closeWindowButton");
843+ appDelegate = null;
844+ verify(closeButton);
845+ mouseClick(closeButton);
846+ closeButton = null;
847+ tryCompare(topSurfaceList, "count", originalWindowCount);
848+ wait(100); // plus some spare room
849+ appDelegate = startApplication("dialer-app");
850+
851+ // Make sure it's again where we left it in normal state before destroying
852+ tryCompare(appDelegate, "windowedX", initialWindowX + moveDelta)
853+ tryCompare(appDelegate, "windowedY", initialWindowY + moveDelta)
854+
855+ // Make sure maximize() has been called after restoring
856+ tryCompare(appDelegate, "state", "maximized")
857+
858+ // clean up
859+ // click on restore button (same one as maximize)
860+ var maximizeButton = findChild(appDelegate, "maximizeWindowButton");
861+ mouseClick(maximizeButton);
862+ }
863+
793 function test_grabbingCursorOnDecorationPress() {
864 function test_grabbingCursorOnDecorationPress() {
794 var appDelegate = startApplication("dialer-app");
865 var appDelegate = startApplication("dialer-app");
795 verify(appDelegate);
866 verify(appDelegate);
tests/qmltests/Stage/tst_PhoneStage.qml−26
@@ -334,32 +334,6 @@ Item {
334 tryCompare(firstApp, "focused", true);
334 tryCompare(firstApp, "focused", true);
335 }
335 }
336
336
337− function test_leftEdge_data() {
338− return [
339− { tag: "normal", inSpread: false, leftEdgeDragWidth: units.gu(20), shouldMoveApp: true },
340− { tag: "inSpread", inSpread: true, leftEdgeDragWidth: units.gu(5), shouldMoveApp: false }
341− ]
342− }
343−
344− function test_leftEdge(data) {
345− addApps(2);
346−
347− if (data.inSpread) {
348− performEdgeSwipeToShowAppSpread();
349− }
350−
351− var focusedDelegate = findChild(stage, "appDelegate_" + topLevelSurfaceList.idAt(0));
352− var currentX = focusedDelegate.x;
353−
354− stage.leftEdgeDragProgress = data.leftEdgeDragWidth;
355−
356− tryCompare(focusedDelegate, "x", data.shouldMoveApp ? data.leftEdgeDragWidth : currentX);
357−
358− stage.leftEdgeDragProgress = 0;
359−
360− tryCompare(focusedDelegate, "x", currentX);
361− }
362−
363 function test_focusedAppIsTheOnlyRunningApp() {
337 function test_focusedAppIsTheOnlyRunningApp() {
364 addApps(2);
338 addApps(2);
365
339
tests/qmltests/Stage/tst_WindowResizeArea.qml+1−66
@@ -88,22 +88,11 @@ Item {
88
88
89 WindowResizeArea {
89 WindowResizeArea {
90 id: windowResizeArea
90 id: windowResizeArea
91+ anchors.fill: parent
91 target: fakeWindow
92 target: fakeWindow
92 borderThickness: units.gu(2)
93 borderThickness: units.gu(2)
93 minWidth: units.gu(15)
94 minWidth: units.gu(15)
94 minHeight: units.gu(10)
95 minHeight: units.gu(10)
95− defaultWidth: units.gu(20)
96− defaultHeight: units.gu(20)
97− windowId: "test-window-id"
98− screenWidth: root.width
99− screenHeight: root.height
100−
101− Component.onCompleted: {
102− loadWindowState();
103− }
104− Component.onDestruction: {
105− saveWindowState();
106− }
107 }
96 }
108
97
109 Rectangle {
98 Rectangle {
@@ -312,30 +301,6 @@ Item {
312 compare(fakeWindow.requestedY, Math.min(initialWindowY + data.dy, initialWindowY + maxMoveY));
301 compare(fakeWindow.requestedY, Math.min(initialWindowY + data.dy, initialWindowY + maxMoveY));
313 }
302 }
314
303
315− function test_saveRestoreSize() {
316− var initialWindowX = fakeWindow.windowedX;
317− var initialWindowY = fakeWindow.windowedY;
318− var initialWindowWidth = fakeWindow.width
319− var initialWindowHeight = fakeWindow.height
320−
321− var resizeDelta = units.gu(5)
322− var startDragX = initialWindowX + initialWindowWidth + 1
323− var startDragY = initialWindowY + initialWindowHeight + 1
324− mouseFlick(root, startDragX, startDragY, startDragX + resizeDelta, startDragY + resizeDelta, true, true, units.gu(.5), 10);
325−
326− tryCompare(fakeWindow, "width", Math.max(initialWindowWidth + resizeDelta, fakeWindow.resizeAreaMinWidth));
327− tryCompare(fakeWindow, "height", Math.max(initialWindowHeight + resizeDelta, fakeWindow.resizeAreaMinHeight));
328−
329− // This will destroy the window and recreate it
330− windowLoader.active = false;
331− waitForRendering(root);
332− windowLoader.active = true;
333−
334− // Make sure its size is again the same as before
335− tryCompare(fakeWindow, "width", Math.max(initialWindowWidth + resizeDelta, fakeWindow.resizeAreaMinWidth));
336− tryCompare(fakeWindow, "height", Math.max(initialWindowHeight + resizeDelta, fakeWindow.resizeAreaMinHeight));
337− }
338−
339 // This tests if dragging smaller than minSize and then larger again, will keep the edge sticking
304 // This tests if dragging smaller than minSize and then larger again, will keep the edge sticking
340 // to the mouse, instead of immediately making the window grow again when switching direction
305 // to the mouse, instead of immediately making the window grow again when switching direction
341 function test_resizeSmallerAndLarger_data() {
306 function test_resizeSmallerAndLarger_data() {
@@ -361,36 +326,6 @@ Item {
361 tryCompare(fakeWindow, "height", initialWindowHeight);
326 tryCompare(fakeWindow, "height", initialWindowHeight);
362 }
327 }
363
328
364− function test_saveRestoreMaximized() {
365− var initialWindowX = fakeWindow.windowedX;
366− var initialWindowY = fakeWindow.windowedY;
367−
368− var moveDelta = units.gu(5);
369−
370− fakeWindow.windowedX = initialWindowX + moveDelta
371− fakeWindow.windowedY = initialWindowY + moveDelta
372−
373− // Now change the state to maximized. The window should not keep updating the stored values
374− fakeWindow.maximize()
375− fakeWindow.windowedX = 31415 // 0 is too risky to pass the test even when broken
376− fakeWindow.windowedY = 31415
377−
378− // This will destroy the window and recreate it
379− windowLoader.active = false;
380− waitForRendering(root);
381− windowLoader.active = true;
382−
383− // Make sure it's again where we left it in normal state before destroying
384− tryCompare(fakeWindow, "x", initialWindowX + moveDelta)
385− tryCompare(fakeWindow, "y", initialWindowX + moveDelta)
386−
387− // Make sure maximize() has been called after restoring
388− tryCompare(fakeWindow, "state", "maximized")
389−
390− // clean up
391− fakeWindow.restoreFromMaximized()
392− }
393−
394 function test_restoreMovesIntoBounds_data() {
329 function test_restoreMovesIntoBounds_data() {
395 return [
330 return [
396 {tag: "left off", x: -units.gu(5), y: units.gu(5), w: units.gu(10), h: units.gu(10)},
331 {tag: "left off", x: -units.gu(5), y: units.gu(5), w: units.gu(10), h: units.gu(10)},
tests/qmltests/tst_DisabledScreenNotice.qml+23−9
@@ -32,6 +32,12 @@ Item {
32 anchors.fill: parent
32 anchors.fill: parent
33 anchors.rightMargin: units.gu(40)
33 anchors.rightMargin: units.gu(40)
34
34
35+ // Mock some things here
36+ property int internalGu: units.gu(1)
37+ property var applicationArguments: QtObject {
38+ property string deviceName: "mako"
39+ }
40+
35 screen: QtObject {
41 screen: QtObject {
36 property int orientation: {
42 property int orientation: {
37 switch (orientationSelector.selectedIndex) {
43 switch (orientationSelector.selectedIndex) {
@@ -52,8 +58,9 @@ Item {
52 }
58 }
53
59
54 Column {
60 Column {
55− anchors.fill: parent
61+ anchors { top: parent.top; right: parent.right; bottom: parent.bottom }
56− anchors.leftMargin: units.gu(40)
62+ width: units.gu(40)
63+ spacing: units.gu(1)
57
64
58 ItemSelector {
65 ItemSelector {
59 id: orientationSelector
66 id: orientationSelector
@@ -71,6 +78,20 @@ Item {
71 Layout.fillWidth: true
78 Layout.fillWidth: true
72 }
79 }
73 }
80 }
81+ Button {
82+ text: "Reset first run settings"
83+ onClicked: {
84+ var settings = testCase.findInvisibleChild(touchScreenPad, "virtualTouchPadSettings");
85+ settings.touchpadTutorialHasRun = false;
86+ }
87+ }
88+ Button {
89+ text: "Run tutorial now"
90+ onClicked: {
91+ var touchPad = testCase.findChild(touchScreenPad, "virtualTouchPad")
92+ touchPad.runTutorial();
93+ }
94+ }
74 }
95 }
75
96
76 UnityTestCase {
97 UnityTestCase {
@@ -78,13 +99,6 @@ Item {
78 name: "DisabledScreenNotice"
99 name: "DisabledScreenNotice"
79 when: windowShown
100 when: windowShown
80
101
81− function test_mouseAreaHidesOnFirstTap() {
82− var noticeArea = findChild(touchScreenPad, "infoNoticeArea")
83− compare(noticeArea.visible, true)
84− tap(root)
85− tryCompare(noticeArea, "visible", false)
86− }
87−
88 function test_rotation_data() {
102 function test_rotation_data() {
89 return [
103 return [
90 {tag: "portrait", selectedOrientation: 0, expectedAngle: 0},
104 {tag: "portrait", selectedOrientation: 0, expectedAngle: 0},
tests/qmltests/tst_OrientedShell.qml+1−13
@@ -999,7 +999,7 @@ Rectangle {
999 var rotationStates = findInvisibleChild(orientedShell, "rotationStates");
999 var rotationStates = findInvisibleChild(orientedShell, "rotationStates");
1000 waitUntilTransitionsEnd(rotationStates);
1000 waitUntilTransitionsEnd(rotationStates);
1001
1001
1002− performLeftEdgeSwipeToSwitchToDash();
1002+ ApplicationManager.requestFocusApplication("unity8-dash");
1003
1003
1004 // Should be back to portrait
1004 // Should be back to portrait
1005 tryCompare(shell, "transformRotationAngle", 0);
1005 tryCompare(shell, "transformRotationAngle", 0);
@@ -1391,18 +1391,6 @@ Rectangle {
1391 waitUntilTransitionsEnd(rotationStates);
1391 waitUntilTransitionsEnd(rotationStates);
1392 }
1392 }
1393
1393
1394− function performLeftEdgeSwipeToSwitchToDash() {
1395− var swipeLength = shell.width * 0.7;
1396−
1397− var touchStartX = 1;
1398− var touchStartY = shell.height / 2;
1399− touchFlick(shell,
1400− touchStartX, touchStartY,
1401− touchStartX + swipeLength, touchStartY);
1402−
1403− tryCompare(ApplicationManager, "focusedApplicationId", "unity8-dash");
1404− }
1405−
1406 function performEdgeSwipeToSwitchToPreviousApp() {
1394 function performEdgeSwipeToSwitchToPreviousApp() {
1407 // swipe just enough to ensure an app switch action.
1395 // swipe just enough to ensure an app switch action.
1408 // If we swipe too much we will trigger the spread mode
1396 // If we swipe too much we will trigger the spread mode
tests/qmltests/tst_Shell.qml+8−152
@@ -605,38 +605,6 @@ Rectangle {
605 compare(ApplicationManager.get(0).appId, "unity8-dash");
605 compare(ApplicationManager.get(0).appId, "unity8-dash");
606 }
606 }
607
607
608− function test_phoneLeftEdgeDrag_data() {
609− return [
610− {tag: "without launcher",
611− revealLauncher: false, swipeLength: units.gu(30), appHides: true, focusedApp: "dialer-app",
612− launcherHides: true, greeterShown: false},
613−
614− {tag: "with launcher",
615− revealLauncher: true, swipeLength: units.gu(30), appHides: true, focusedApp: "dialer-app",
616− launcherHides: true, greeterShown: false},
617−
618− {tag: "small swipe",
619− revealLauncher: false, swipeLength: units.gu(25), appHides: false, focusedApp: "dialer-app",
620− launcherHides: false, greeterShown: false},
621−
622− {tag: "long swipe",
623− revealLauncher: false, swipeLength: units.gu(30), appHides: true, focusedApp: "dialer-app",
624− launcherHides: true, greeterShown: false},
625−
626− {tag: "small swipe with greeter",
627− revealLauncher: false, swipeLength: units.gu(25), appHides: false, focusedApp: "dialer-app",
628− launcherHides: false, greeterShown: true},
629−
630− {tag: "long swipe with greeter",
631− revealLauncher: false, swipeLength: units.gu(30), appHides: true, focusedApp: "dialer-app",
632− launcherHides: true, greeterShown: true},
633−
634− {tag: "swipe over dash",
635− revealLauncher: false, swipeLength: units.gu(30), appHides: true, focusedApp: "unity8-dash",
636− launcherHides: false, greeterShown: false},
637− ];
638− }
639−
640 function test_snapDecisionDismissalReturnsFocus() {
608 function test_snapDecisionDismissalReturnsFocus() {
641 loadShell("phone");
609 loadShell("phone");
642 swipeAwayGreeter();
610 swipeAwayGreeter();
@@ -689,8 +657,8 @@ Rectangle {
689 hints: {"x-canonical-private-affirmative-tint": "true"},
657 hints: {"x-canonical-private-affirmative-tint": "true"},
690 summary: "Tom Ato",
658 summary: "Tom Ato",
691 body: "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.",
659 body: "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.",
692− icon: "../../tests/graphics/avatars/funky.png",
660+ icon: Qt.resolvedUrl("../graphics/avatars/funky.png"),
693− secondaryIcon: "../../tests/graphics/applicationIcons/facebook.png",
661+ secondaryIcon: Qt.resolvedUrl("../graphics/applicationIcons/facebook.png"),
694 actions: [{ id: "ok_id", label: "Ok"},
662 actions: [{ id: "ok_id", label: "Ok"},
695 { id: "cancel_id", label: "Cancel"},
663 { id: "cancel_id", label: "Cancel"},
696 { id: "notreally_id", label: "Not really"},
664 { id: "notreally_id", label: "Not really"},
@@ -701,80 +669,6 @@ Rectangle {
701 mockNotificationsModel.append(n)
669 mockNotificationsModel.append(n)
702 }
670 }
703
671
704− function test_phoneLeftEdgeDrag(data) {
705− loadShell("phone");
706− swipeAwayGreeter();
707− dragLauncherIntoView();
708− var appSurfaceId = topLevelSurfaceList.nextId;
709− tapOnAppIconInLauncher();
710− waitUntilAppWindowIsFullyLoaded(appSurfaceId);
711−
712− var greeter = findChild(shell, "greeter");
713− if (data.greeterShown) {
714− showGreeter();
715− }
716−
717− if (data.revealLauncher) {
718− dragLauncherIntoView();
719− }
720−
721− swipeFromLeftEdge(data.swipeLength);
722− if (data.appHides) {
723− waitUntilDashIsFocused();
724− tryCompare(greeter, "shown", false);
725− } else {
726− tryCompare(greeter, "fullyShown", data.greeterShown);
727− }
728−
729− var launcher = findChild(shell, "launcherPanel");
730− tryCompare(launcher, "x", data.launcherHides ? -launcher.width : 0)
731−
732− //FIXME: This check fails. Don't understand the rationale behind it.
733− /*
734− // Make sure the helper for sliding out the launcher wasn't touched. We want to fade it out here.
735− var animateTimer = findInvisibleChild(shell, "animateTimer");
736− compare(animateTimer.nextState, "visible");
737− */
738− }
739−
740− function test_tabletLeftEdgeDrag_data() {
741− return [
742− {tag: "without password", user: "no-password", loggedIn: true},
743− {tag: "with password", user: "has-password", loggedIn: false},
744− ]
745− }
746−
747− function test_tabletLeftEdgeDrag(data) {
748− setLightDMMockMode("full");
749− loadShell("tablet");
750−
751− selectUser(data.user)
752−
753− swipeFromLeftEdge(shell.width * 0.75)
754− wait(500) // to give time to handle dash() signal from Launcher
755− confirmLoggedIn(data.loggedIn)
756− }
757−
758− function test_longLeftEdgeSwipeTakesToAppsAndResetSearchString() {
759− loadShell("phone");
760− swipeAwayGreeter();
761− dragLauncherIntoView();
762− dashCommunicatorSpy.clear();
763−
764− var appSurfaceId = topLevelSurfaceList.nextId;
765− tapOnAppIconInLauncher();
766− waitUntilAppWindowIsFullyLoaded(appSurfaceId);
767−
768− tryCompareFunction(function() { return ApplicationManager.focusedApplicationId !== "unity8-dash"; }, true);
769−
770− //Long left swipe
771− swipeFromLeftEdge(units.gu(30));
772−
773− tryCompare(ApplicationManager, "focusedApplicationId", "unity8-dash");
774−
775− compare(dashCommunicatorSpy.count, 1);
776− }
777−
778 function test_ClickUbuntuIconInLauncherTakesToAppsAndResetSearchString() {
672 function test_ClickUbuntuIconInLauncherTakesToAppsAndResetSearchString() {
779 loadShell("phone");
673 loadShell("phone");
780 swipeAwayGreeter();
674 swipeAwayGreeter();
@@ -913,39 +807,6 @@ Rectangle {
913 LightDM.Users.mockMode = mode;
807 LightDM.Users.mockMode = mode;
914 }
808 }
915
809
916− /*
917− Regression test for bug https://bugs.launchpad.net/touch-preview-images/+bug/1193419
918−
919− When the user minimizes an application (left-edge swipe) he should always end up in the
920− "Applications" scope view.
921−
922− Steps:
923− - reveal launcher and launch an app that covers the dash
924− - perform long left edge swipe to go minimize the app and go back to the dash.
925− - verify the setCurrentScope() D-Bus call to the dash has been called for the correct scope id.
926− */
927− function test_minimizingAppTakesToDashApps() {
928− loadShell("phone");
929− swipeAwayGreeter();
930− dragLauncherIntoView();
931−
932− // Launch an app from the launcher
933− var appSurfaceId = topLevelSurfaceList.nextId;
934− tapOnAppIconInLauncher();
935− waitUntilAppWindowIsFullyLoaded(appSurfaceId);
936−
937− verify(ApplicationManager.focusedApplicationId !== "unity8-dash")
938−
939− dashCommunicatorSpy.clear();
940− // Minimize the application we just launched
941− swipeFromLeftEdge(shell.width * 0.75);
942−
943− tryCompare(ApplicationManager, "focusedApplicationId", "unity8-dash");
944−
945− compare(dashCommunicatorSpy.count, 1);
946− compare(dashCommunicatorSpy.signalArguments[0][0], 0);
947− }
948−
949 function test_showInputMethod() {
810 function test_showInputMethod() {
950 loadShell("phone");
811 loadShell("phone");
951 swipeAwayGreeter();
812 swipeAwayGreeter();
@@ -1166,7 +1027,7 @@ Rectangle {
1166
1027
1167 // Place the mouse against the window/screen edge and push beyond the barrier threshold
1028 // Place the mouse against the window/screen edge and push beyond the barrier threshold
1168 mouseMove(shell, 0, shell.height / 2);
1029 mouseMove(shell, 0, shell.height / 2);
1169− launcher.pushEdge(EdgeBarrierSettings.pushThreshold * 1.1);
1030+ launcher.pushEdge(EdgeBarrierSettings.pushThreshold * .8);
1170
1031
1171 var panel = findChild(launcher, "launcherPanel");
1032 var panel = findChild(launcher, "launcherPanel");
1172 verify(panel);
1033 verify(panel);
@@ -1186,9 +1047,7 @@ Rectangle {
1186 waitUntilAppWindowIsFullyLoaded(appSurfaceId);
1047 waitUntilAppWindowIsFullyLoaded(appSurfaceId);
1187
1048
1188 // Minimize the application we just launched
1049 // Minimize the application we just launched
1189− swipeFromLeftEdge(shell.width * 0.75);
1050+ swipeFromLeftEdge(units.gu(15));
1190−
1191− waitUntilDashIsFocused();
1192
1051
1193 showGreeter();
1052 showGreeter();
1194
1053
@@ -1998,14 +1857,11 @@ Rectangle {
1998 var appRepeater = findChild(shell, "appRepeater");
1857 var appRepeater = findChild(shell, "appRepeater");
1999 var appDelegate = appRepeater.itemAt(0);
1858 var appDelegate = appRepeater.itemAt(0);
2000
1859
2001− var resizeArea = findChild(appDelegate, "windowResizeArea");
2002− var priv = findInvisibleChild(resizeArea, "priv");
2003−
2004 // Make sure windows are at 0,0 or greater and they have a size that's > 0
1860 // Make sure windows are at 0,0 or greater and they have a size that's > 0
2005− compare(priv.normalX >= 0, true)
1861+ compare(appDelegate.normalX >= 0, true)
2006− compare(priv.normalY >= 0, true)
1862+ compare(appDelegate.normalY >= 0, true)
2007− compare(priv.normalWidth > 0, true)
1863+ compare(appDelegate.normalWidth > 0, true)
2008− compare(priv.normalHeight > 0, true)
1864+ compare(appDelegate.normalHeight > 0, true)
2009 }
1865 }
2010
1866
2011 // bug http://pad.lv/1431566
1867 // bug http://pad.lv/1431566
tests/qmltests/tst_ShellWithPin.qml−66
@@ -547,71 +547,5 @@ Item {
547 var lockscreen = findChild(shell, "lockscreen");
547 var lockscreen = findChild(shell, "lockscreen");
548 verify(lockscreen.shown);
548 verify(lockscreen.shown);
549 }
549 }
550−
551− /*
552− Regression test for https://bugs.launchpad.net/ubuntu/+source/unity8/+bug/1393447
553−
554− Do a left edge drag that is long enough to start displacing the greeter
555− but short engough so that the greeter comes back into place once the
556− finger is lifted.
557−
558− In this situation the launcher should remaing fully shown and hide itself
559− only after its idle timeout is triggered.
560− */
561− function test_shortLeftEdgeSwipeMakesLauncherStayVisible() {
562− showGreeter();
563−
564− var launcher = testCase.findChild(shell, "launcher")
565− var launcherPanel = testCase.findChild(launcher, "launcherPanel");
566−
567− var toX = shell.width * 0.45;
568− touchFlick(shell,
569− 1 /* fromX */, shell.height * 0.5 /* fromY */,
570− toX /* toX */, shell.height * 0.5 /* toY */,
571− true /* beginTouch */, false /* endTouch */,
572− 50, 100);
573−
574− // Launcher must be fully shown by now
575− tryCompare(launcherPanel, "x", 0);
576−
577− // Greeter should be displaced
578− var coverPage = findChild(shell, "coverPage");
579− tryCompareFunction(function() { return coverPage.mapToItem(shell, 0, 0).x > shell.width*0.2; }, true);
580−
581− touchRelease(shell, toX, shell.height * 0.5);
582−
583− // Upon release the greeter should have slid back into full view
584− tryCompareFunction(function() { return coverPage.mapToItem(shell, 0, 0).x === 0; }, true);
585−
586− // And the launcher should stay fully shown
587− for (var i = 0; i < 10; ++i) {
588− wait(50);
589− compare(launcherPanel.x, 0);
590− }
591− }
592−
593− function test_longLeftEdgeDrags() {
594− var coverPage = findChild(shell, "coverPage");
595− var lockscreen = findChild(shell, "lockscreen");
596− var launcher = findChild(shell, "launcherPanel");
597− var galleryApp = ApplicationManager.startApplication("gallery-app");
598− tryCompare(shell, "mainApp", galleryApp);
599−
600− // Show greeter
601− showGreeter();
602−
603− // Swipe cover page away
604− touchFlick(shell, 2, shell.height / 2, units.gu(30), shell.height / 2);
605− tryCompare(launcher, "x", -launcher.width);
606− tryCompare(coverPage, "showProgress", 0);
607− compare(lockscreen.shown, true);
608− tryCompare(shell, "mainApp", galleryApp);
609−
610− // Now attempt a swipe on lockscreen
611− touchFlick(shell, 2, shell.height / 2, units.gu(30), shell.height / 2);
612− tryCompare(launcher, "x", 0);
613− compare(lockscreen.shown, true);
614− tryCompare(shell, "mainApp", galleryApp);
615− }
616 }
550 }
617}
551}
tests/uqmlscene/CMakeLists.txt+9−1
@@ -9,10 +9,14 @@ pkg_check_modules(XCB REQUIRED xcb)
9include_directories(
9include_directories(
10 ${CMAKE_CURRENT_BINARY_DIR}
10 ${CMAKE_CURRENT_BINARY_DIR}
11 ${CMAKE_SOURCE_DIR}/src
11 ${CMAKE_SOURCE_DIR}/src
12− ${Qt5Gui_PRIVATE_INCLUDE_DIRS}
13 ${CMAKE_SOURCE_DIR}/libs/UbuntuGestures
12 ${CMAKE_SOURCE_DIR}/libs/UbuntuGestures
14)
13)
15
14
15+include_directories(
16+ SYSTEM
17+ ${Qt5Gui_PRIVATE_INCLUDE_DIRS}
18+)
19+
16if (NOT "${XCB_INCLUDE_DIRS}" STREQUAL "")
20if (NOT "${XCB_INCLUDE_DIRS}" STREQUAL "")
17 set_target_properties(uqmlscene PROPERTIES INCLUDE_DIRECTORIES ${XCB_INCLUDE_DIRS})
21 set_target_properties(uqmlscene PROPERTIES INCLUDE_DIRECTORIES ${XCB_INCLUDE_DIRS})
18endif()
22endif()
@@ -23,3 +27,7 @@ target_link_libraries(uqmlscene
23 ${XCB_LDFLAGS}
27 ${XCB_LDFLAGS}
24 UbuntuGestures
28 UbuntuGestures
25 )
29 )
30+
31+install(TARGETS uqmlscene
32+ RUNTIME DESTINATION ${SHELL_PRIVATE_LIBDIR}
33+ )
tests/utils/modules/Unity/Test/CMakeLists.txt+4−2
@@ -33,7 +33,9 @@ if (ENABLE_TOUCH_EMULATION)
33 target_link_libraries(UnityTestQml ${MOUSETOUCHADAPTOR_LIBS_LDFLAGS})
33 target_link_libraries(UnityTestQml ${MOUSETOUCHADAPTOR_LIBS_LDFLAGS})
34endif()
34endif()
35
35
36+# To find libUbuntuGestures.so
37+set_target_properties(UnityTestQml PROPERTIES INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/${SHELL_PRIVATE_LIBDIR}")
38+
36qt5_use_modules(UnityTestQml Core Quick Test)
39qt5_use_modules(UnityTestQml Core Quick Test)
37
40
38−export_qmlfiles(Unity.Test Unity/Test)
39−export_qmlplugin(Unity.Test 0.1 Unity/Test TARGETS UnityTestQml)
41+add_unity8_mock(Unity.Test 0.1 Unity/Test PREFIX utils TARGETS UnityTestQml)
tests/utils/modules/Unity/Test/UnityTestCase.qml+4−4
@@ -163,9 +163,9 @@ TestCase {
163 if (i === iterations - 1) {
163 if (i === iterations - 1) {
164 // Avoid any rounding errors by making the last move be at precisely
164 // Avoid any rounding errors by making the last move be at precisely
165 // the point specified
165 // the point specified
166− mouseMove(item, toX, toY, iterations / speed)
166+ mouseMove(item, toX, toY, timeStep)
167 } else {
167 } else {
168− mouseMove(item, x + (i + 1) * diffX, y + (i + 1) * diffY, iterations / speed)
168+ mouseMove(item, x + (i + 1) * diffX, y + (i + 1) * diffY, timeStep)
169 }
169 }
170 }
170 }
171 if (releaseMouse) {
171 if (releaseMouse) {
@@ -346,12 +346,12 @@ TestCase {
346 if (i === iterations - 1) {
346 if (i === iterations - 1) {
347 // Avoid any rounding errors by making the last move be at precisely
347 // Avoid any rounding errors by making the last move be at precisely
348 // the point specified
348 // the point specified
349− wait(iterations / speed)
349+ wait(timeStep)
350 var event = touchEvent(item)
350 var event = touchEvent(item)
351 event.move(0 /* touchId */, rootTo.x, rootTo.y)
351 event.move(0 /* touchId */, rootTo.x, rootTo.y)
352 event.commit()
352 event.commit()
353 } else {
353 } else {
354− wait(iterations / speed)
354+ wait(timeStep)
355 var event = touchEvent(item)
355 var event = touchEvent(item)
356 event.move(0 /* touchId */, rootFrom.x + (i + 1) * diffX, rootFrom.y + (i + 1) * diffY)
356 event.move(0 /* touchId */, rootFrom.x + (i + 1) * diffX, rootFrom.y + (i + 1) * diffY)
357 event.commit()
357 event.commit()