on xenial help sign in
Merge from greeter-ux-fixes
2d68048Michael Terry
cmake/modules/QmlTest.cmake+16−1
@@ -58,7 +58,15 @@ macro(add_manual_qml_test SUBPATH COMPONENT_NAME)
58
58
59endmacro(add_manual_qml_test)
59endmacro(add_manual_qml_test)
60
60
61+macro(add_qml_benchmark SUBPATH COMPONENT_NAME ITERATIONS)
62+ add_qml_test_internal(${SUBPATH} ${COMPONENT_NAME} ${ITERATIONS})
63+endmacro(add_qml_benchmark)
64+
61macro(add_qml_test SUBPATH COMPONENT_NAME)
65macro(add_qml_test SUBPATH COMPONENT_NAME)
66+ add_qml_test_internal(${SUBPATH} ${COMPONENT_NAME} 0)
67+endmacro(add_qml_test)
68+
69+macro(add_qml_test_internal SUBPATH COMPONENT_NAME ITERATIONS)
62 set(options NO_ADD_TEST NO_TARGETS)
70 set(options NO_ADD_TEST NO_TARGETS)
63 set(multi_value_keywords IMPORT_PATHS TARGETS PROPERTIES ENVIRONMENT)
71 set(multi_value_keywords IMPORT_PATHS TARGETS PROPERTIES ENVIRONMENT)
64
72
@@ -88,10 +96,17 @@ macro(add_qml_test SUBPATH COMPONENT_NAME)
88 set(function_ARGS "")
96 set(function_ARGS "")
89 endif()
97 endif()
90
98
99+ if (${ITERATIONS} GREATER 0)
100+ set(ITERATIONS_STRING "-iterations" ${ITERATIONS})
101+ else()
102+ set(ITERATIONS_STRING "")
103+ endif()
104+
91 set(qmltest_command
105 set(qmltest_command
92 env ${qmltest_ENVIRONMENT}
106 env ${qmltest_ENVIRONMENT}
93 ${qmltestrunner_exe} -input ${CMAKE_CURRENT_SOURCE_DIR}/${qmltest_FILE}.qml
107 ${qmltestrunner_exe} -input ${CMAKE_CURRENT_SOURCE_DIR}/${qmltest_FILE}.qml
94 ${qmltestrunner_imports}
108 ${qmltestrunner_imports}
109+ ${ITERATIONS_STRING}
95 -o ${CMAKE_BINARY_DIR}/${qmltest_TARGET}.xml,xunitxml
110 -o ${CMAKE_BINARY_DIR}/${qmltest_TARGET}.xml,xunitxml
96 -o -,txt
111 -o -,txt
97 ${function_ARGS}
112 ${function_ARGS}
@@ -114,7 +129,7 @@ macro(add_qml_test SUBPATH COMPONENT_NAME)
114 add_qmltest_target(${qmltest_TARGET} "${qmltest_command}" TRUE ${qmltest_NO_ADD_TEST})
129 add_qmltest_target(${qmltest_TARGET} "${qmltest_command}" TRUE ${qmltest_NO_ADD_TEST})
115 add_qmltest_target(${qmltest_xvfb_TARGET} "${qmltest_xvfb_command}" ${qmltest_NO_TARGETS} TRUE)
130 add_qmltest_target(${qmltest_xvfb_TARGET} "${qmltest_xvfb_command}" ${qmltest_NO_TARGETS} TRUE)
116 add_manual_qml_test(${SUBPATH} ${COMPONENT_NAME} ${ARGN})
131 add_manual_qml_test(${SUBPATH} ${COMPONENT_NAME} ${ARGN})
117−endmacro(add_qml_test)
132+endmacro(add_qml_test_internal)
118
133
119macro(add_binary_qml_test CLASS_NAME LD_PATH DEPS)
134macro(add_binary_qml_test CLASS_NAME LD_PATH DEPS)
120 set(testCommand
135 set(testCommand
data/unity8.conf+2−1
@@ -1,7 +1,7 @@
1description "Unity Shell v8"
1description "Unity Shell v8"
2author "Ricardo Mendoza <ricmm@ubuntu.com>"
2author "Ricardo Mendoza <ricmm@ubuntu.com>"
3
3
4−emits scope-ui-starting
4+emits scope-ui-starting indicator-services-start
5
5
6start on ((xsession SESSION=ubuntu-touch) or (xsession SESSION=ubuntu-touch-surfaceflinger)) and started dbus
6start on ((xsession SESSION=ubuntu-touch) or (xsession SESSION=ubuntu-touch-surfaceflinger)) and started dbus
7stop on desktop-end
7stop on desktop-end
@@ -42,6 +42,7 @@ pre-start script
42 fi
42 fi
43
43
44 initctl emit scope-ui-starting
44 initctl emit scope-ui-starting
45+ initctl emit indicator-services-start
45end script
46end script
46
47
47exec ${BINARY:-unity8} $ARGS
48exec ${BINARY:-unity8} $ARGS
debian/changelog+88
@@ -4,6 +4,94 @@ unity8 (7.86+14.04.20140306-0ubuntu1) UNRELEASED; urgency=medium
4
4
5 -- Michael Terry <mterry@ubuntu.com> Wed, 02 Apr 2014 14:39:45 -0400
5 -- Michael Terry <mterry@ubuntu.com> Wed, 02 Apr 2014 14:39:45 -0400
6
6
7+unity8 (7.85+14.04.20140416-0ubuntu1) trusty; urgency=low
8+
9+ [ Albert Astals ]
10+ * Fix last item X position Fixes clicking on the last item sometimes
11+ not working (LP: #1301871)
12+ * Use upstart in ./run Makes it so that you can use the lock button on
13+ the device without getting that nasty hwc crash
14+ * Remove AnimationControllerWithSignals.
15+ * Use the correct delegate base item for the Carousel test
16+ * Some simplification in DashContent Kill the ScopeDelegateMapper in
17+ favour of a simple if (that will eventually go away). Removal of all
18+ the fake scopes in the tests that added nothing of value to the
19+ tests. Removal of movementEnded signal that was unused. Removal of
20+ movementStarted and positionedAtBeginning signals that were being
21+ used as function calls. Rework DashContent tests so they what the
22+ function does what it is supposed to do instead of just making sure
23+ QML signals work .
24+ * Improve Card creation time by adding loaders that make sure only
25+ what's needed is loaded In my computer it goes from RESULT :
26+ qmltestrunner::benchmark_time:"cardTitleArtSubtitleMascotSummaryMode
27+ l": 3.217 msecs per iteration (total: 3,218, iterations: 1000)
28+ RESULT :
29+ qmltestrunner::benchmark_time:"cardTitleArtSubtitleMascotModel":
30+ 1.647 msecs per iteration (total: 1,648, iterations: 1000) RESULT :
31+ qmltestrunner::benchmark_time:"cardTitleArtSubtitleModel": 1.514
32+ msecs per iteration (total: 1,515, iterations: 1000) RESULT :
33+ qmltestrunner::benchmark_time:"cardTitleArtModel": 1.471 msecs per
34+ iteration (total: 1,471, iterations: 1000) RESULT :
35+ qmltestrunner::benchmark_time:"cardArtModel": 1.447 msecs per
36+ iteration (total: 1,448, iterations: 1000) RESULT :
37+ qmltestrunner::benchmark_time:"cardTitleModel": 1.276 msecs per
38+ iteration (total: 1,276, iterations: 1000) to RESULT :
39+ qmltestrunner::benchmark_time:"cardTitleArtSubtitleMascotSummaryMode
40+ l": 2.916 msecs per iteration (total: 2,917, iterations: 1000)
41+ RESULT :
42+ qmltestrunner::benchmark_time:"cardTitleArtSubtitleMascotModel":
43+ 1.504 msecs per iteration (total: 1,504, iterations: 1000) RESULT :
44+ qmltestrunner::benchmark_time:"cardTitleArtSubtitleModel": 1.060
45+ msecs per iteration (total: 1,061, iterations: 1000) RESULT :
46+ qmltestrunner::benchmark_time:"cardTitleArtModel": 1.052 msecs per
47+ iteration (total: 1,053, iterations: 1000) RESULT :
48+ qmltestrunner::benchmark_time:"cardArtModel": 0.727 msecs per
49+ iteration (total: 728, iterations: 1000) RESULT :
50+ qmltestrunner::benchmark_time:"cardTitleModel": 0.817 msecs per
51+ iteration (total: 818, iterations: 1000) (LP: #1297197)
52+
53+ [ Allan LeSage ]
54+ * DashApps emulator get_applications should return a list ordered by
55+ visible y, x.
56+
57+ [ Andrea Cimitan ]
58+ * Workaround for lp1301309 until fixes for palette in ui toolkit (LP:
59+ #1301309)
60+
61+ [ Leo Arias ]
62+ * Reverted the change that returns application cards instead of
63+ titles.
64+
65+ [ Nick Dedekind ]
66+ * Indicator services started by unity8 upstart configuration rather
67+ than manual emmision from indicator manager.
68+
69+ [ Mirco Müller ]
70+ * Fix notification ap-test assertions.
71+
72+ [ Michael Terry ]
73+ * Use new tablet and phone backgrounds from Design.
74+
75+ [ Michael Zanetti ]
76+ * workaround the QTestLogger assertion issue with make tryXyz and our
77+ custom uqmlscene
78+
79+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Wed, 16 Apr 2014 13:45:01 +0000
80+
81+unity8 (7.85+14.04.20140415.2-0ubuntu1) trusty; urgency=low
82+
83+ [ Michael Terry ]
84+ * When an application requests focus, handle it in Shell.qml by hiding
85+ the greeter and stopping any edge demo. (LP: #1227753)
86+
87+ [ Leo Arias ]
88+ * Use subprocess.check_call when caling url-dispatcher, so an error
89+ will be raised if it fails.
90+ * Test application life cycle with fake apps, instead of messaging and
91+ address book.
92+
93+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Tue, 15 Apr 2014 12:47:11 +0000
94+
7unity8 (7.85+14.04.20140410.1-0ubuntu1) trusty; urgency=medium
95unity8 (7.85+14.04.20140410.1-0ubuntu1) trusty; urgency=medium
8
96
9 [ Didier Roche ]
97 [ Didier Roche ]
debian/control−3
@@ -13,14 +13,11 @@ Build-Depends: cmake,
13 libgles2-mesa-dev[armhf],
13 libgles2-mesa-dev[armhf],
14 libgsettings-qt-dev,
14 libgsettings-qt-dev,
15 libhud-client2-dev,
15 libhud-client2-dev,
16− libnih-dbus-dev,
17− libnih-dev,
18 liblightdm-qt5-3-dev,
16 liblightdm-qt5-3-dev,
19 libpulse-dev,
17 libpulse-dev,
20 libqmenumodel-dev (>= 0.2.7),
18 libqmenumodel-dev (>= 0.2.7),
21 libunity-api-dev (>= 7.80.6),
19 libunity-api-dev (>= 7.80.6),
22 libunity-mir-dev,
20 libunity-mir-dev,
23− libupstart-dev,
24 libusermetricsoutput1-dev,
21 libusermetricsoutput1-dev,
25 libxcb1-dev,
22 libxcb1-dev,
26 libglib2.0-dev,
23 libglib2.0-dev,
plugins/Unity/Indicators/CMakeLists.txt−3
@@ -6,7 +6,6 @@ project(IndicatorsQml)
6pkg_check_modules(GLIB REQUIRED glib-2.0>=2.32)
6pkg_check_modules(GLIB REQUIRED glib-2.0>=2.32)
7pkg_check_modules(GIO REQUIRED gio-2.0>=2.32)
7pkg_check_modules(GIO REQUIRED gio-2.0>=2.32)
8pkg_check_modules(QMENUMODEL REQUIRED qmenumodel)
8pkg_check_modules(QMENUMODEL REQUIRED qmenumodel)
9−pkg_check_modules(LIBUPSTART REQUIRED libupstart libnih libnih-dbus dbus-1)
10
9
11find_package(Qt5Core REQUIRED)
10find_package(Qt5Core REQUIRED)
12find_package(Qt5Quick REQUIRED)
11find_package(Qt5Quick REQUIRED)
@@ -19,7 +18,6 @@ include_directories(
19 ${GLIB_INCLUDE_DIRS}
18 ${GLIB_INCLUDE_DIRS}
20 ${GIO_INCLUDE_DIRS}
19 ${GIO_INCLUDE_DIRS}
21 ${QMENUMODEL_INCLUDE_DIRS}
20 ${QMENUMODEL_INCLUDE_DIRS}
22− ${LIBUPSTART_INCLUDE_DIRS}
23)
21)
24
22
25set(IndicatorsQML_SOURCES
23set(IndicatorsQML_SOURCES
@@ -54,7 +52,6 @@ target_link_libraries(IndicatorsQml
54 ${GLIB_LIBRARIES}
52 ${GLIB_LIBRARIES}
55 ${GIO_LIBRARIES}
53 ${GIO_LIBRARIES}
56 ${QMENUMODEL_LDFLAGS}
54 ${QMENUMODEL_LDFLAGS}
57− ${LIBUPSTART_LIBRARIES}
58)
55)
59
56
60qt5_use_modules(IndicatorsQml Core Qml Quick)
57qt5_use_modules(IndicatorsQml Core Qml Quick)
plugins/Unity/Indicators/indicatorsmanager.cpp−33
@@ -21,9 +21,6 @@
21#include <QSettings>
21#include <QSettings>
22#include <QDebug>
22#include <QDebug>
23
23
24−#include <upstart.h>
25−#include <nih/alloc.h>
26−
27#include <paths.h>
24#include <paths.h>
28
25
29
26
@@ -216,36 +213,6 @@ void IndicatorsManager::setLoaded(bool loaded)
216 {
213 {
217 m_loaded = loaded;
214 m_loaded = loaded;
218 Q_EMIT loadedChanged(m_loaded);
215 Q_EMIT loadedChanged(m_loaded);
219−
220− auto upstartsession = qgetenv("UPSTART_SESSION");
221− NihDBusProxy * upstart = NULL;
222−
223− if (!upstartsession.isNull()) {
224− DBusConnection * conn = NULL;
225− conn = dbus_connection_open(upstartsession.constData(), NULL);
226− if (conn != NULL) {
227− upstart = nih_dbus_proxy_new(NULL, conn,
228− NULL,
229− DBUS_PATH_UPSTART,
230− NULL, NULL);
231− dbus_connection_unref(conn);
232− }
233− }
234−
235− if (upstart != NULL) {
236− int event_sent = 0;
237− if (m_loaded) {
238− event_sent = upstart_emit_event_sync(NULL, upstart, "indicator-services-start", NULL, 0);
239− } else {
240− event_sent = upstart_emit_event_sync(NULL, upstart, "indicator-services-end", NULL, 0);
241− }
242−
243− if (event_sent != 0) {
244− qWarning() << "Unable to send indicator event to Upstart";
245− }
246− nih_unref(upstart, NULL);
247− upstart = NULL;
248− }
249 }
216 }
250}
217}
251
218
plugins/Unity/Indicators/indicatorsmanager.h−2
@@ -28,8 +28,6 @@
28#include <QHash>
28#include <QHash>
29#include <QSharedPointer>
29#include <QSharedPointer>
30
30
31−typedef struct nih_dbus_proxy NihDBusProxy;
32−
33class UNITYINDICATORS_EXPORT IndicatorsManager : public QObject
31class UNITYINDICATORS_EXPORT IndicatorsManager : public QObject
34{
32{
35 Q_OBJECT
33 Q_OBJECT
po/br.ponew file+164
@@ -0,0 +1,164 @@
1+# Breton translation for unity8
2+# Copyright (c) 2014 Rosetta Contributors and Canonical Ltd 2014
3+# This file is distributed under the same license as the unity8 package.
4+# FIRST AUTHOR <EMAIL@ADDRESS>, 2014.
5+#
6+msgid ""
7+msgstr ""
8+"Project-Id-Version: unity8\n"
9+"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10+"POT-Creation-Date: 2014-03-25 16:48+0100\n"
11+"PO-Revision-Date: 2014-04-15 18:15+0000\n"
12+"Last-Translator: Rouxel <vincent.rouxel@mailoo.org>\n"
13+"Language-Team: Breton <br@li.org>\n"
14+"MIME-Version: 1.0\n"
15+"Content-Type: text/plain; charset=UTF-8\n"
16+"Content-Transfer-Encoding: 8bit\n"
17+"X-Launchpad-Export-Date: 2014-04-16 07:12+0000\n"
18+"X-Generator: Launchpad (build 16976)\n"
19+
20+#: plugins/Unity/Launcher/launcheritem.cpp:43
21+#: plugins/Unity/Launcher/launcheritem.cpp:73
22+msgid "Lock to Launcher"
23+msgstr ""
24+
25+#: plugins/Unity/Launcher/launcheritem.cpp:73
26+msgid "Unlock from Launcher"
27+msgstr ""
28+
29+#: qml/Components/EdgeDemoOverlay.qml:151
30+msgid "Skip intro"
31+msgstr ""
32+
33+#: qml/Components/EdgeDemo.qml:113
34+msgid "Right edge"
35+msgstr ""
36+
37+#: qml/Components/EdgeDemo.qml:114
38+msgid "Try swiping from the right edge to unlock the phone"
39+msgstr ""
40+
41+#: qml/Components/EdgeDemo.qml:145
42+msgid "Top edge"
43+msgstr ""
44+
45+#: qml/Components/EdgeDemo.qml:146
46+msgid "Try swiping from the top edge to access the indicators"
47+msgstr ""
48+
49+#: qml/Components/EdgeDemo.qml:171
50+msgid "Close"
51+msgstr "Serriñ"
52+
53+#: qml/Components/EdgeDemo.qml:172
54+msgid "Swipe up again to close the settings screen"
55+msgstr ""
56+
57+#: qml/Components/EdgeDemo.qml:199
58+msgid "Left edge"
59+msgstr ""
60+
61+#: qml/Components/EdgeDemo.qml:200
62+msgid "Swipe from the left to reveal the launcher for quick access to apps"
63+msgstr ""
64+
65+#: qml/Components/EdgeDemo.qml:227
66+msgid "Well done"
67+msgstr ""
68+
69+#: qml/Components/EdgeDemo.qml:228
70+msgid ""
71+"You have now mastered the edge gestures and can start using the "
72+"phone<br><br>Tap on the screen to start"
73+msgstr ""
74+
75+#: qml/Components/PageHeader.qml:365
76+msgid "Recent searches"
77+msgstr ""
78+
79+#: qml/Components/SeeMore.qml:35
80+msgid "See more"
81+msgstr ""
82+
83+#: qml/Components/SeeMore.qml:58
84+msgid "See less"
85+msgstr ""
86+
87+#: qml/Dash/DashApps.qml:38
88+msgid "Recent"
89+msgstr ""
90+
91+#: qml/Dash/PreviewListView.qml:52
92+#, qt-format
93+msgid "%1 Preview"
94+msgstr ""
95+
96+#: qml/Dash/Previews/PreviewActionCombo.qml:34
97+msgid "More..."
98+msgstr ""
99+
100+#: qml/Dash/Previews/PreviewActionCombo.qml:34
101+msgid "Less..."
102+msgstr ""
103+
104+#: qml/Dash/Previews/PreviewRatingInput.qml:81
105+msgid "Rate this"
106+msgstr ""
107+
108+#: qml/Dash/Previews/PreviewRatingInput.qml:126
109+msgid "Add a review"
110+msgstr ""
111+
112+#: qml/Dash/Previews/PreviewRatingInput.qml:166
113+msgid "Send"
114+msgstr ""
115+
116+#: qml/Greeter/Lockscreen.qml:149
117+msgid "Emergency Call"
118+msgstr ""
119+
120+#: qml/Greeter/PassphraseLockscreen.qml:59
121+#, qt-format
122+msgid "Hello %1"
123+msgstr ""
124+
125+#: qml/Greeter/PassphraseLockscreen.qml:59
126+msgid "Hello"
127+msgstr ""
128+
129+#: qml/Hud/HudParametrizedActionsPage.qml:132
130+msgid "Confirm"
131+msgstr ""
132+
133+#: qml/Hud/Hud.qml:61 qml/Hud/Hud.qml:99 qml/Hud/Hud.qml:372
134+msgid "Type or say a command"
135+msgstr ""
136+
137+#: qml/Hud/Hud.qml:84
138+msgid "Loading. Please Wait..."
139+msgstr ""
140+
141+#: qml/Hud/Hud.qml:89
142+msgid "Speak Now..."
143+msgstr ""
144+
145+#: qml/Hud/Hud.qml:94
146+msgid "Speaking..."
147+msgstr ""
148+
149+#: qml/Notifications/NotificationMenuItemFactory.qml:91
150+msgid "Show password"
151+msgstr ""
152+
153+#: qml/Notifications/NotificationMenuItemFactory.qml:103
154+msgid "Please enter SIM PIN"
155+msgstr ""
156+
157+#: qml/Panel/SearchIndicator.qml:27
158+msgid "Search"
159+msgstr ""
160+
161+#: qml/Shell.qml:417
162+#, qt-format
163+msgid "Please enter %1"
164+msgstr ""
po/ug.po+7−23
@@ -8,15 +8,14 @@ msgstr ""
8"Project-Id-Version: unity\n"
8"Project-Id-Version: unity\n"
9"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
9"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10"POT-Creation-Date: 2014-03-25 16:48+0100\n"
10"POT-Creation-Date: 2014-03-25 16:48+0100\n"
11−"PO-Revision-Date: 2014-02-15 12:09+0000\n"
11+"PO-Revision-Date: 2014-04-14 09:31+0000\n"
12−"Last-Translator: Gheyret T.Kenji <Unknown>\n"
12+"Last-Translator: volkhan <Unknown>\n"
13"Language-Team: Uyghur <ug@li.org>\n"
13"Language-Team: Uyghur <ug@li.org>\n"
14"MIME-Version: 1.0\n"
14"MIME-Version: 1.0\n"
15"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17−"Plural-Forms: nplurals=1; plural=0;\n"
18−"X-Launchpad-Export-Date: 2014-03-28 06:49+0000\n"
17+"X-Launchpad-Export-Date: 2014-04-15 07:57+0000\n"
19−"X-Generator: Launchpad (build 16967)\n"
18+"X-Generator: Launchpad (build 16976)\n"
20
19
21#: plugins/Unity/Launcher/launcheritem.cpp:43
20#: plugins/Unity/Launcher/launcheritem.cpp:43
22#: plugins/Unity/Launcher/launcheritem.cpp:73
21#: plugins/Unity/Launcher/launcheritem.cpp:73
@@ -89,7 +88,7 @@ msgstr "ئازراق كۆرۈش"
89
88
90#: qml/Dash/DashApps.qml:38
89#: qml/Dash/DashApps.qml:38
91msgid "Recent"
90msgid "Recent"
92−msgstr ""
91+msgstr "يېقىنقى"
93
92
94#: qml/Dash/PreviewListView.qml:52
93#: qml/Dash/PreviewListView.qml:52
95#, qt-format
94#, qt-format
@@ -98,11 +97,11 @@ msgstr ""
98
97
99#: qml/Dash/Previews/PreviewActionCombo.qml:34
98#: qml/Dash/Previews/PreviewActionCombo.qml:34
100msgid "More..."
99msgid "More..."
101−msgstr ""
100+msgstr "تېخىمۇ كۆپ…"
102
101
103#: qml/Dash/Previews/PreviewActionCombo.qml:34
102#: qml/Dash/Previews/PreviewActionCombo.qml:34
104msgid "Less..."
103msgid "Less..."
105−msgstr ""
104+msgstr "ئازراق..."
106
105
107#: qml/Dash/Previews/PreviewRatingInput.qml:81
106#: qml/Dash/Previews/PreviewRatingInput.qml:81
108msgid "Rate this"
107msgid "Rate this"
@@ -165,18 +164,3 @@ msgstr "ئىزدە"
165#, qt-format
164#, qt-format
166msgid "Please enter %1"
165msgid "Please enter %1"
167msgstr "%1 نى كىرگۈزۈڭ"
166msgstr "%1 نى كىرگۈزۈڭ"
168−
169−#, qt-format
170−#~ msgid "%1 review"
171−#~ msgid_plural "%1 reviews"
172−#~ msgstr[0] "%1 باھا"
173−
174−#, qt-format
175−#~ msgid "(%1)"
176−#~ msgstr "(%1)"
177−
178−#~ msgid "Comments:"
179−#~ msgstr "ئىنكاس:"
180−
181−#~ msgid "Review"
182−#~ msgstr "تەكشۈر"
qml/Components/AnimationControllerWithSignals.qmldeleted−64
@@ -1,64 +0,0 @@
1−/*
2− * Copyright (C) 2013 Canonical, Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− */
16−
17−import QtQuick 2.0
18−
19−AnimationController {
20− signal animationCompletedAtBeginning()
21− signal animationCompletedAtEnd()
22− readonly property bool completed: progress == 1.0 || progress == 0.0
23− property bool completing: false
24−
25− function __completeAtBeginning() {
26− completing = false;
27− animationCompletedAtBeginning();
28− }
29−
30− function __completeAtEnd() {
31− completing = false;
32− animationCompletedAtEnd();
33− }
34−
35− function completeToBeginningWithSignal() {
36− if (progress == 0.0) {
37− __completeAtBeginning()
38− } else {
39− completing = true;
40− completeToBeginning();
41− }
42− }
43−
44− function completeToEndWithSignal() {
45− if (progress == 1.0) {
46− __completeAtEnd()
47− } else {
48− completing = true;
49− completeToEnd();
50− }
51− }
52−
53− onProgressChanged: {
54− if (!completing) {
55− return;
56− }
57−
58− if (progress == 0.0) {
59− __completeAtBeginning()
60− } else if (progress == 1.0) {
61− __completeAtEnd()
62− }
63− }
64−}
qml/Components/Carousel.qml+13−19
@@ -75,6 +75,7 @@ Item {
75 The scaling of the items is controlled by the variable continuousIndex, described below. */
75 The scaling of the items is controlled by the variable continuousIndex, described below. */
76 ListView {
76 ListView {
77 id: listView
77 id: listView
78+ objectName: "listView"
78
79
79 property int highlightIndex: -1
80 property int highlightIndex: -1
80 property real minimumTileWidth: 0
81 property real minimumTileWidth: 0
@@ -148,15 +149,19 @@ Item {
148 maximumFlickVelocity: Math.max(2500 * Math.pow(realWidth / referenceWidth, 1.5), 2500) // 2500 is platform default
149 maximumFlickVelocity: Math.max(2500 * Math.pow(realWidth / referenceWidth, 1.5), 2500) // 2500 is platform default
149 orientation: ListView.Horizontal
150 orientation: ListView.Horizontal
150
151
151− function itemClicked(index, delegateItem) {
152+ function getXFromContinuousIndex(index) {
152− listView.currentIndex = index
153− var x = CarouselJS.getXFromContinuousIndex(index,
153+ return CarouselJS.getXFromContinuousIndex(index,
154 realWidth,
154 realWidth,
155− realContentWidth,
155+ footerItem.x,
156 tileWidth,
156 tileWidth,
157 gapToMiddlePhase,
157 gapToMiddlePhase,
158 gapToEndPhase,
158 gapToEndPhase,
159 carousel.drawBuffer)
159 carousel.drawBuffer)
160+ }
161+
162+ function itemClicked(index, delegateItem) {
163+ listView.currentIndex = index
164+ var x = getXFromContinuousIndex(index);
160
165
161 if (Math.abs(x - contentX) < 1 && delegateItem !== undefined) {
166 if (Math.abs(x - contentX) < 1 && delegateItem !== undefined) {
162 /* We're clicking the selected item and
167 /* We're clicking the selected item and
@@ -174,13 +179,7 @@ Item {
174 }
179 }
175
180
176 function itemPressAndHold(index, delegateItem) {
181 function itemPressAndHold(index, delegateItem) {
177− var x = CarouselJS.getXFromContinuousIndex(index,
182+ var x = getXFromContinuousIndex(index);
178− realWidth,
179− realContentWidth,
180− tileWidth,
181− gapToMiddlePhase,
182− gapToEndPhase,
183− carousel.drawBuffer);
184
183
185 if (Math.abs(x - contentX) < 1 && delegateItem !== undefined) {
184 if (Math.abs(x - contentX) < 1 && delegateItem !== undefined) {
186 /* We're pressAndHold the selected item and
185 /* We're pressAndHold the selected item and
@@ -209,22 +208,17 @@ Item {
209 newContentX = disabledNewContentX
208 newContentX = disabledNewContentX
210 }
209 }
211 onMovementEnded: {
210 onMovementEnded: {
212− if (realContentX > 0 && realContentX < realContentWidth - realWidth)
211+ if (realContentX > 0)
213 stepAnimation.start()
212 stepAnimation.start()
214 }
213 }
215
214
216 SmoothedAnimation {
215 SmoothedAnimation {
217 id: stepAnimation
216 id: stepAnimation
217+ objectName: "stepAnimation"
218
218
219 target: listView
219 target: listView
220 property: "contentX"
220 property: "contentX"
221− to: CarouselJS.getXFromContinuousIndex(listView.selectedIndex,
221+ to: listView.getXFromContinuousIndex(listView.selectedIndex)
222− listView.realWidth,
223− listView.realContentWidth,
224− listView.tileWidth,
225− listView.gapToMiddlePhase,
226− listView.gapToEndPhase,
227− carousel.drawBuffer)
228 duration: 450
222 duration: 450
229 velocity: 200
223 velocity: 200
230 easing.type: Easing.InOutQuad
224 easing.type: Easing.InOutQuad
qml/Dash/Card.qml+99−79
@@ -25,47 +25,53 @@ AbstractButton {
25 property var components
25 property var components
26 property var cardData
26 property var cardData
27
27
28− property alias fontScale: header.fontScale
28+ property real fontScale: 1.0
29− property alias headerAlignment: header.headerAlignment
29+ property int headerAlignment: Text.AlignLeft
30− property alias headerHeight: header.height
30+ readonly property int headerHeight: headerLoader.item ? headerLoader.item.height : 0
31+ property int fixedHeaderHeight: -1
31− readonly property alias title: header.title
32+ readonly property string title: cardData && cardData["title"] || ""
32
33
33 property bool showHeader: true
34 property bool showHeader: true
34
35
35 implicitWidth: childrenRect.width
36 implicitWidth: childrenRect.width
36− implicitHeight: summary.y + summary.height + (summary.text && background.visible ? units.gu(1) : 0)
37+ implicitHeight: summary.y + summary.height + (summary.text && backgroundLoader.active ? units.gu(1) : 0)
37
38
38− UbuntuShape {
39+ Loader {
39− id: background
40+ id: backgroundLoader
40− objectName: "background"
41+ objectName: "backgroundLoader"
41− radius: "medium"
42− visible: template["card-layout"] !== "horizontal" && (template["card-background"] || components["background"]
43− || artAndSummary)
44− property bool artAndSummary: components["art"]["field"] && components["summary"] || false
45− color: getColor(0) || "white"
46− gradientColor: getColor(1) || color
47− anchors.fill: parent
48− image: backgroundImage.source ? backgroundImage : null
49
42
50− property real luminance: 0.2126 * color.r + 0.7152 * color.g + 0.0722 * color.b
43+ readonly property bool artAndSummary: components["art"]["field"] && components["summary"] || false
44+ active: template["card-layout"] !== "horizontal" && (template["card-background"] || components["background"] || artAndSummary)
45+ anchors.fill: parent
51
46
47+ sourceComponent: UbuntuShape {
48+ objectName: "background"
49+ radius: "medium"
50+ color: getColor(0) || "white"
51+ gradientColor: getColor(1) || color
52+ anchors.fill: parent
53+ image: backgroundImage.source ? backgroundImage : null
54+
55+ property real luminance: 0.2126 * color.r + 0.7152 * color.g + 0.0722 * color.b
56+
52− property Image backgroundImage: Image {
57+ property Image backgroundImage: Image {
53− objectName: "backgroundImage"
58+ objectName: "backgroundImage"
54− source: {
59+ source: {
55− if (cardData && typeof cardData["background"] === "string") return cardData["background"]
60+ if (cardData && typeof cardData["background"] === "string") return cardData["background"]
56− else if (template && typeof template["card-background"] === "string") return template["card-background"]
61+ else if (template && typeof template["card-background"] === "string") return template["card-background"]
57− else return ""
62+ else return ""
63+ }
58 }
64 }
59− }
60
65
61− function getColor(index) {
66+ function getColor(index) {
62− if (cardData && typeof cardData["background"] === "object"
67+ if (cardData && typeof cardData["background"] === "object"
63− && (cardData["background"]["type"] === "color" || cardData["background"]["type"] === "gradient")) {
68+ && (cardData["background"]["type"] === "color" || cardData["background"]["type"] === "gradient")) {
64− return cardData["background"]["elements"][index];
69+ return cardData["background"]["elements"][index];
65− } else if (template && typeof template["card-background"] === "object"
70+ } else if (template && typeof template["card-background"] === "object"
66− && (template["card-background"]["type"] === "color" || template["card-background"]["type"] === "gradient")) {
71+ && (template["card-background"]["type"] === "color" || template["card-background"]["type"] === "gradient")) {
67− return template["card-background"]["elements"][index];
72+ return template["card-background"]["elements"][index];
68− } else return undefined;
73+ } else return undefined;
74+ }
69 }
75 }
70 }
76 }
71
77
@@ -111,7 +117,7 @@ AbstractButton {
111 function updateWidthHeightBindings() {
117 function updateWidthHeightBindings() {
112 if (isHorizontal) {
118 if (isHorizontal) {
113 width = Qt.binding(function() { return height * artShape.aspect });
119 width = Qt.binding(function() { return height * artShape.aspect });
114− height = Qt.binding(function() { return header.height });
120+ height = Qt.binding(function() { return root.headerHeight });
115 } else {
121 } else {
116 width = Qt.binding(function() { return root.width });
122 width = Qt.binding(function() { return root.width });
117 height = Qt.binding(function() { return width / artShape.aspect });
123 height = Qt.binding(function() { return width / artShape.aspect });
@@ -120,53 +126,58 @@ AbstractButton {
120 }
126 }
121 }
127 }
122
128
123− ShaderEffect {
129+ Loader {
124− id: overlay
130+ id: overlayLoader
125 anchors {
131 anchors {
126 left: artShape.left
132 left: artShape.left
127 right: artShape.right
133 right: artShape.right
128 bottom: artShape.bottom
134 bottom: artShape.bottom
129 }
135 }
136+ active: template && template["overlay"] && artShape.visible && artShape.image.status === Image.Ready || false
130
137
131− height: header.height
138+ sourceComponent: ShaderEffect {
132− opacity: header.opacity * 0.6
139+ id: overlay
133− visible: template && template["overlay"] && artShape.visible && artShape.image.status === Image.Ready || false
134
140
141+ height: headerLoader.item ? headerLoader.item.height : 0
142+ opacity: headerLoader.item ? headerLoader.item.opacity * 0.6 : 0
143+
135− property var source: ShaderEffectSource {
144+ property var source: ShaderEffectSource {
136− id: shaderSource
145+ id: shaderSource
137− sourceItem: artShape
146+ sourceItem: artShape
138− onVisibleChanged: if (visible) scheduleUpdate()
147+ onVisibleChanged: if (visible) scheduleUpdate()
139− live: false
148+ live: false
140− sourceRect: Qt.rect(0, artShape.height - overlay.height, artShape.width, overlay.height)
149+ sourceRect: Qt.rect(0, artShape.height - overlay.height, artShape.width, overlay.height)
141− }
150+ }
142
151
143− vertexShader: "
152+ vertexShader: "
144− uniform highp mat4 qt_Matrix;
153+ uniform highp mat4 qt_Matrix;
145− attribute highp vec4 qt_Vertex;
154+ attribute highp vec4 qt_Vertex;
146− attribute highp vec2 qt_MultiTexCoord0;
155+ attribute highp vec2 qt_MultiTexCoord0;
147− varying highp vec2 coord;
156+ varying highp vec2 coord;
148− void main() {
157+ void main() {
149− coord = qt_MultiTexCoord0;
158+ coord = qt_MultiTexCoord0;
150− gl_Position = qt_Matrix * qt_Vertex;
159+ gl_Position = qt_Matrix * qt_Vertex;
151− }"
160+ }"
152−
161+
153− fragmentShader: "
162+ fragmentShader: "
154− varying highp vec2 coord;
163+ varying highp vec2 coord;
155− uniform sampler2D source;
164+ uniform sampler2D source;
156− uniform lowp float qt_Opacity;
165+ uniform lowp float qt_Opacity;
157− void main() {
166+ void main() {
158− lowp vec4 tex = texture2D(source, coord);
167+ lowp vec4 tex = texture2D(source, coord);
159− gl_FragColor = vec4(0, 0, 0, tex.a) * qt_Opacity;
168+ gl_FragColor = vec4(0, 0, 0, tex.a) * qt_Opacity;
160− }"
169+ }"
170+ }
161 }
171 }
162
172
163− CardHeader {
173+ Loader {
164− id: header
174+ id: headerLoader
165− objectName: "cardHeader"
175+ objectName: "cardHeaderLoader"
176+
166 anchors {
177 anchors {
167 top: {
178 top: {
168 if (template) {
179 if (template) {
169− if (template["overlay"]) return overlay.top;
180+ if (template["overlay"]) return overlayLoader.top;
170 if (template["card-layout"] === "horizontal") return artShape.top;
181 if (template["card-layout"] === "horizontal") return artShape.top;
171 }
182 }
172 return artShape.bottom;
183 return artShape.bottom;
@@ -179,29 +190,38 @@ AbstractButton {
179 }
190 }
180 right: parent.right
191 right: parent.right
181 }
192 }
193+ active: cardData && cardData["title"] || cardData && cardData["mascot"] || false
194+
195+ sourceComponent: CardHeader {
196+ id: header
197+ objectName: "cardHeader"
182
198
183− mascot: cardData && cardData["mascot"] || ""
199+ mascot: cardData && cardData["mascot"] || ""
184− title: cardData && cardData["title"] || ""
200+ title: root.title
185− subtitle: cardData && cardData["subtitle"] || ""
201+ subtitle: cardData && cardData["subtitle"] || ""
186
202
187− titleWeight: components && components["subtitle"] ? Font.DemiBold : Font.Normal
203+ titleWeight: components && components["subtitle"] ? Font.DemiBold : Font.Normal
188
204
189− opacity: showHeader ? 1 : 0
205+ opacity: showHeader ? 1 : 0
190− inOverlay: root.template && root.template["overlay"] === true
206+ inOverlay: root.template && root.template["overlay"] === true
191− fontColor: inOverlay ? "white" : summary.color
207+ fontColor: inOverlay ? "white" : summary.color
192− useMascotShape: !background.visible && !inOverlay
208+ useMascotShape: !backgroundLoader.active && !inOverlay
209+ headerAlignment: root.headerAlignment
210+ height: root.fixedHeaderHeight != -1 ? root.fixedHeaderHeight : implicitHeight
211+ fontScale: root.fontScale
193
212
194− Behavior on opacity { NumberAnimation { duration: UbuntuAnimation.SnapDuration } }
213+ Behavior on opacity { NumberAnimation { duration: UbuntuAnimation.SnapDuration } }
214+ }
195 }
215 }
196
216
197 Label {
217 Label {
198 id: summary
218 id: summary
199 objectName: "summaryLabel"
219 objectName: "summaryLabel"
200 anchors {
220 anchors {
201− top: header.visible ? header.bottom : artShape.bottom
221+ top: headerLoader.active ? headerLoader.bottom : artShape.bottom
202 left: parent.left
222 left: parent.left
203 right: parent.right
223 right: parent.right
204− margins: background.visible ? units.gu(1) : 0
224+ margins: backgroundLoader.active ? units.gu(1) : 0
205 topMargin: 0
225 topMargin: 0
206 }
226 }
207 wrapMode: Text.Wrap
227 wrapMode: Text.Wrap
@@ -211,6 +231,6 @@ AbstractButton {
211 height: text ? implicitHeight : 0
231 height: text ? implicitHeight : 0
212 fontSize: "small"
232 fontSize: "small"
213 // TODO karni: Change "grey" to Ubuntu.Components.Palette color once updated.
233 // TODO karni: Change "grey" to Ubuntu.Components.Palette color once updated.
214− color: background.visible && background.luminance < 0.7 ? "white" : "grey"
234+ color: backgroundLoader.active && backgroundLoader.item.luminance < 0.7 ? "white" : "grey"
215 }
235 }
216}
236}
qml/Dash/CardCarousel.qml+1−1
@@ -52,7 +52,7 @@ DashRenderer {
52 itemComponent: Card {
52 itemComponent: Card {
53 id: card
53 id: card
54 objectName: "carouselDelegate" + index
54 objectName: "carouselDelegate" + index
55− headerHeight: carousel.headerHeight
55+ fixedHeaderHeight: carousel.headerHeight
56 cardData: model
56 cardData: model
57 template: cardTool.template
57 template: cardTool.template
58 components: cardTool.components
58 components: cardTool.components
qml/Dash/CardFilterGrid.qml+3−2
@@ -45,14 +45,15 @@ DashRenderer {
45 collapsedRowCount: Math.min(2, cardTool && cardTool.template && cardTool.template["collapsed-rows"] || 2)
45 collapsedRowCount: Math.min(2, cardTool && cardTool.template && cardTool.template["collapsed-rows"] || 2)
46 delegateCreationBegin: genericFilterGrid.delegateCreationBegin
46 delegateCreationBegin: genericFilterGrid.delegateCreationBegin
47 delegateCreationEnd: genericFilterGrid.delegateCreationEnd
47 delegateCreationEnd: genericFilterGrid.delegateCreationEnd
48− delegate: Item {
48+ delegate: Loader {
49+ asynchronous: true
49 width: filterGrid.cellWidth
50 width: filterGrid.cellWidth
50 height: filterGrid.cellHeight
51 height: filterGrid.cellHeight
51 Card {
52 Card {
52 id: card
53 id: card
53 width: cardTool.cardWidth
54 width: cardTool.cardWidth
54 height: cardTool.cardHeight
55 height: cardTool.cardHeight
55− headerHeight: cardTool.headerHeight
56+ fixedHeaderHeight: cardTool.headerHeight
56 anchors.horizontalCenter: parent.horizontalCenter
57 anchors.horizontalCenter: parent.horizontalCenter
57 objectName: "delegate" + index
58 objectName: "delegate" + index
58 cardData: model
59 cardData: model
qml/Dash/CardHeader.qml+41−31
@@ -19,9 +19,9 @@ import Ubuntu.Components 0.1
19
19
20Item {
20Item {
21 id: root
21 id: root
22− property alias mascot: mascotImage.source
22+ property url mascot: ""
23 property alias title: titleLabel.text
23 property alias title: titleLabel.text
24− property alias subtitle: subtitleLabel.text
24+ property var subtitle
25
25
26 property alias titleWeight: titleLabel.font.weight
26 property alias titleWeight: titleLabel.font.weight
27 property alias titleSize: titleLabel.fontSize
27 property alias titleSize: titleLabel.fontSize
@@ -35,8 +35,8 @@ Item {
35 property bool useMascotShape: true
35 property bool useMascotShape: true
36 property color fontColor: Theme.palette.selected.backgroundText
36 property color fontColor: Theme.palette.selected.backgroundText
37
37
38− visible: mascotImage.status === Image.Ready || title
38+ visible: mascot != "" || title
39− height: row.height > 0 ? row.height + row.margins * 2 : 0
39+ implicitHeight: row.height > 0 ? row.height + row.margins * 2 : 0
40
40
41 Row {
41 Row {
42 id: row
42 id: row
@@ -44,7 +44,7 @@ Item {
44
44
45 property real margins: units.gu(1)
45 property real margins: units.gu(1)
46
46
47− spacing: mascotShape.visible || mascotImage.visible || inOverlay ? margins : 0
47+ spacing: mascotShapeLoader.active || mascotImageLoader.active || inOverlay ? margins : 0
48 anchors {
48 anchors {
49 top: parent.top; left: parent.left; right: parent.right
49 top: parent.top; left: parent.left; right: parent.right
50 margins: margins
50 margins: margins
@@ -52,33 +52,40 @@ Item {
52 rightMargin: spacing
52 rightMargin: spacing
53 }
53 }
54
54
55− UbuntuShape {
55+ Loader {
56− id: mascotShape
56+ id: mascotShapeLoader
57− objectName: "mascotShape"
57+ objectName: "mascotShapeLoader"
58
58
59+ active: useMascotShape && mascotImageLoader.item && mascotImageLoader.item.status === Image.Ready
60+ visible: active
61+ anchors.verticalCenter: parent.verticalCenter
59 // TODO karni: Icon aspect-ratio is 8:7.5. Revisit these values to avoid fraction of pixels.
62 // TODO karni: Icon aspect-ratio is 8:7.5. Revisit these values to avoid fraction of pixels.
60 width: units.gu(6)
63 width: units.gu(6)
61 height: units.gu(5.625)
64 height: units.gu(5.625)
62− anchors.verticalCenter: parent.verticalCenter
63− visible: useMascotShape && image && image.status === Image.Ready
64 readonly property int maxSize: Math.max(width, height) * 4
65 readonly property int maxSize: Math.max(width, height) * 4
65
66
66− image: useMascotShape ? mascotImage : null
67+ sourceComponent: UbuntuShape {
68+ image: mascotImageLoader.item
69+ }
67 }
70 }
68
71
69− Image {
72+ Loader {
70− id: mascotImage
73+ id: mascotImageLoader
71− objectName: "mascotImage"
74+ active: root.mascot != ""
72−
75+ visible: active && !useMascotShape && item.status === Image.Ready
73− width: source ? mascotShape.width : 0
74− height: mascotShape.height
75 anchors.verticalCenter: parent.verticalCenter
76 anchors.verticalCenter: parent.verticalCenter
76− visible: !useMascotShape && status === Image.Ready
77+ sourceComponent: Image {
78+ objectName: "mascotImage"
79+
80+ source: root.mascot
81+ width: source ? mascotShapeLoader.width : 0
82+ height: mascotShapeLoader.height
77
83
78− sourceSize { width: mascotShape.maxSize; height: mascotShape.maxSize }
84+ sourceSize { width: mascotShapeLoader.maxSize; height: mascotShapeLoader.maxSize }
79− fillMode: Image.PreserveAspectCrop
85+ fillMode: Image.PreserveAspectCrop
80− horizontalAlignment: Image.AlignHCenter
86+ horizontalAlignment: Image.AlignHCenter
81− verticalAlignment: Image.AlignVCenter
87+ verticalAlignment: Image.AlignVCenter
88+ }
82 }
89 }
83
90
84 Column {
91 Column {
@@ -100,16 +107,19 @@ Item {
100 color: fontColor
107 color: fontColor
101 }
108 }
102
109
103− Label {
110+ Loader {
104− id: subtitleLabel
111+ active: titleLabel.text && root.subtitle
105− objectName: "subtitleLabel"
106 anchors { left: parent.left; right: parent.right }
112 anchors { left: parent.left; right: parent.right }
113+ sourceComponent: Label {
114+ id: subtitleLabel
115+ objectName: "subtitleLabel"
107− elide: Text.ElideRight
116+ elide: Text.ElideRight
108− fontSize: "small"
117+ fontSize: "small"
109− font.weight: Font.Light
118+ font.weight: Font.Light
110− visible: titleLabel.text && text
111− font.pixelSize: Math.round(FontUtils.sizeToPixels(fontSize) * fontScale)
119+ font.pixelSize: Math.round(FontUtils.sizeToPixels(fontSize) * fontScale)
112− color: fontColor
120+ color: fontColor
121+ text: root.subtitle
122+ }
113 }
123 }
114 }
124 }
115 }
125 }
qml/Dash/DashContent.qml+5−10
@@ -27,13 +27,9 @@ Item {
27 readonly property alias currentIndex: dashContentList.currentIndex
27 readonly property alias currentIndex: dashContentList.currentIndex
28 property alias previewOpen: previewListView.open
28 property alias previewOpen: previewListView.open
29
29
30− property ScopeDelegateMapper scopeMapper : ScopeDelegateMapper {}
31 property ListModel searchHistory
30 property ListModel searchHistory
32
31
33− signal movementStarted()
34− signal movementEnded()
35 signal scopeLoaded(string scopeId)
32 signal scopeLoaded(string scopeId)
36− signal positionedAtBeginning()
37 signal gotoScope(string scopeId)
33 signal gotoScope(string scopeId)
38 signal openScope(var scope)
34 signal openScope(var scope)
39
35
@@ -71,7 +67,7 @@ Item {
71 dashContentList.currentIndex = index
67 dashContentList.currentIndex = index
72
68
73 if (reset) {
69 if (reset) {
74− dashContent.positionedAtBeginning()
70+ dashContentList.currentItem.item.positionAtBeginning()
75 }
71 }
76 }
72 }
77
73
@@ -114,8 +110,7 @@ Item {
114 highlightRangeMode: ListView.StrictlyEnforceRange
110 highlightRangeMode: ListView.StrictlyEnforceRange
115 // TODO Investigate if we can switch to a smaller cache buffer when/if UbuntuShape gets more performant
111 // TODO Investigate if we can switch to a smaller cache buffer when/if UbuntuShape gets more performant
116 cacheBuffer: 1073741823
112 cacheBuffer: 1073741823
117− onMovementStarted: dashContent.movementStarted()
113+ onMovementStarted: currentItem.item.showHeader();
118− onMovementEnded: dashContent.movementEnded()
119 clip: parent.x != 0
114 clip: parent.x != 0
120
115
121 // If the number of items is less than the current index, then need to reset to another item.
116 // If the number of items is less than the current index, then need to reset to another item.
@@ -135,7 +130,9 @@ Item {
135 width: ListView.view.width
130 width: ListView.view.width
136 height: ListView.view.height
131 height: ListView.view.height
137 asynchronous: true
132 asynchronous: true
138− source: scopeMapper.map(scope.id)
133+ // TODO This if will eventually go away since we're killing DashApps.qml
134+ // once we move app closing to the spread
135+ source: (scope.id == "clickscope") ? "DashApps.qml" : "GenericScopeView.qml"
139 objectName: scope.id + " loader"
136 objectName: scope.id + " loader"
140
137
141 readonly property bool moving: item ? item.moving : false
138 readonly property bool moving: item ? item.moving : false
@@ -154,8 +151,6 @@ Item {
154 item.scope = Qt.binding(function() { return scope })
151 item.scope = Qt.binding(function() { return scope })
155 item.isCurrent = Qt.binding(function() { return visible && ListView.isCurrentItem })
152 item.isCurrent = Qt.binding(function() { return visible && ListView.isCurrentItem })
156 item.tabBarHeight = dashPageHeader.implicitHeight;
153 item.tabBarHeight = dashPageHeader.implicitHeight;
157− dashContentList.movementStarted.connect(item.movementStarted)
158− dashContent.positionedAtBeginning.connect(item.positionedAtBeginning)
159 dashContent.scopeLoaded(item.scope.id)
154 dashContent.scopeLoaded(item.scope.id)
160 }
155 }
161 Connections {
156 Connections {
qml/Dash/GenericScopeView.qml+9−8
@@ -33,9 +33,6 @@ FocusScope {
33 property PageHeader pageHeader: null
33 property PageHeader pageHeader: null
34 property Item previewListView: null
34 property Item previewListView: null
35
35
36− signal movementStarted
37− signal positionedAtBeginning
38−
39 property bool enableHeightBehaviorOnNextCreation: false
36 property bool enableHeightBehaviorOnNextCreation: false
40 property var categoryView: categoryView
37 property var categoryView: categoryView
41
38
@@ -49,6 +46,14 @@ FocusScope {
49 shell.activateApplication(appId);
46 shell.activateApplication(appId);
50 }
47 }
51
48
49+ function positionAtBeginning() {
50+ categoryView.positionAtBeginning()
51+ }
52+
53+ function showHeader() {
54+ categoryView.showHeader()
55+ }
56+
52 Binding {
57 Binding {
53 target: scope
58 target: scope
54 property: "isActive"
59 property: "isActive"
@@ -69,10 +74,6 @@ FocusScope {
69 previewListView.open = false;
74 previewListView.open = false;
70 }
75 }
71
76
72− onMovementStarted: categoryView.showHeader()
73−
74− onPositionedAtBeginning: categoryView.positionAtBeginning()
75−
76 Binding {
77 Binding {
77 target: scopeView.scope
78 target: scopeView.scope
78 property: "searchQuery"
79 property: "searchQuery"
@@ -241,7 +242,7 @@ FocusScope {
241 // to the stable position and delete/create items without any reason
242 // to the stable position and delete/create items without any reason
242 if (categoryView.contentY < categoryView.originY) {
243 if (categoryView.contentY < categoryView.originY) {
243 return;
244 return;
244− } else if (categoryView.contentY + categoryView.height > categoryView.contentHeight) {
245+ } else if (categoryView.contentHeight > categoryView.height && categoryView.contentY + categoryView.height > categoryView.contentHeight) {
245 return;
246 return;
246 }
247 }
247
248
qml/Dash/Previews/PreviewRatingDisplay.qml+4−2
@@ -71,7 +71,8 @@ PreviewWidget {
71 id: authorLabel
71 id: authorLabel
72 objectName: "authorLabel"
72 objectName: "authorLabel"
73 anchors { left: parent.left; right: parent.right }
73 anchors { left: parent.left; right: parent.right }
74+ // TODO cimi: Yet another fix requiring Palette update.
74− color: Theme.palette.selected.backgroundText
75+ color: "grey" //Theme.palette.selected.backgroundText
75 opacity: .8
76 opacity: .8
76 text: modelData["author"] || ""
77 text: modelData["author"] || ""
77 visible: text !== ""
78 visible: text !== ""
@@ -82,7 +83,8 @@ PreviewWidget {
82 id: reviewLabel
83 id: reviewLabel
83 objectName: "reviewLabel"
84 objectName: "reviewLabel"
84 anchors { left: parent.left; right: parent.right }
85 anchors { left: parent.left; right: parent.right }
86+ // TODO cimi: Yet another fix requiring Palette update.
85− color: Theme.palette.selected.backgroundText
87+ color: "grey" //Theme.palette.selected.backgroundText
86 opacity: .8
88 opacity: .8
87 text: modelData["review"] || ""
89 text: modelData["review"] || ""
88 visible: text !== ""
90 visible: text !== ""
qml/Dash/Previews/PreviewRatingInput.qml+4−2
@@ -76,7 +76,8 @@ PreviewWidget {
76 verticalCenter: parent.verticalCenter
76 verticalCenter: parent.verticalCenter
77 left: parent.left
77 left: parent.left
78 }
78 }
79+ // TODO cimi: Yet another fix requiring Palette update.
79− color: Theme.palette.selected.backgroundText
80+ color: "grey" //Theme.palette.selected.backgroundText
80 opacity: .8
81 opacity: .8
81 text: widgetData["rating-label"] || i18n.tr("Rate this")
82 text: widgetData["rating-label"] || i18n.tr("Rate this")
82 }
83 }
@@ -121,7 +122,8 @@ PreviewWidget {
121 left: parent.left
122 left: parent.left
122 right: parent.right
123 right: parent.right
123 }
124 }
125+ // TODO cimi: Yet another fix requiring Palette update.
124− color: Theme.palette.selected.backgroundText
126+ color: "grey" //Theme.palette.selected.backgroundText
125 opacity: .8
127 opacity: .8
126 text: widgetData["review-label"] || i18n.tr("Add a review")
128 text: widgetData["review-label"] || i18n.tr("Add a review")
127 }
129 }
qml/Dash/ScopeDelegateMapper.qmldeleted−30
@@ -1,30 +0,0 @@
1−/*
2− * Copyright (C) 2013 Canonical, Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− */
16−
17−import QtQuick 2.0
18−
19−QtObject {
20− property var scopeDelegateMapping: {"clickscope": "DashApps.qml"}
21− property string genericScope: "GenericScopeView.qml"
22−
23− function map(scopeId) {
24− var customScope = scopeDelegateMapping[scopeId]
25− if (customScope != undefined) {
26− return customScope
27− }
28− return genericScope
29− }
30−}
qml/Greeter/Greeter.qml+13−7
@@ -50,14 +50,20 @@ Showable {
50 signal tease()
50 signal tease()
51
51
52 function hideRight() {
52 function hideRight() {
53+ if (shown) {
53− hideAnimation = __rightHideAnimation
54+ hideAnimation = __rightHideAnimation
54− hide()
55+ hide()
56+ }
55 }
57 }
56
58
57− Connections {
59+ onRequiredChanged: {
58− target: __rightHideAnimation
59 // Reset hide animation to default once we're finished with it
60 // Reset hide animation to default once we're finished with it
61+ if (!required) {
62+ // Put back on left for reliable show direction and so that
63+ // if normal hide() is called, we don't animate from right.
64+ x = -width
60− onRunningChanged: if (!__rightHideAnimation.running) greeter.hideAnimation = __leftHideAnimation
65+ hideAnimation = __leftHideAnimation
66+ }
61 }
67 }
62
68
63 // Bi-directional revealer
69 // Bi-directional revealer
@@ -205,7 +211,7 @@ Showable {
205 anchors.left: parent.right
211 anchors.left: parent.right
206 anchors.top: parent.top
212 anchors.top: parent.top
207 anchors.bottom: parent.bottom
213 anchors.bottom: parent.bottom
208− visible: parent.visible
214+ visible: parent.required
209 fillMode: Image.Tile
215 fillMode: Image.Tile
210 source: "../graphics/dropshadow_right.png"
216 source: "../graphics/dropshadow_right.png"
211 }
217 }
@@ -215,7 +221,7 @@ Showable {
215 anchors.right: parent.left
221 anchors.right: parent.left
216 anchors.top: parent.top
222 anchors.top: parent.top
217 anchors.bottom: parent.bottom
223 anchors.bottom: parent.bottom
218− visible: parent.visible
224+ visible: parent.required
219 fillMode: Image.Tile
225 fillMode: Image.Tile
220 source: "../graphics/dropshadow_left.png"
226 source: "../graphics/dropshadow_left.png"
221 }
227 }
qml/Shell.qml+6−5
@@ -216,6 +216,8 @@ BasicShell {
216 function show(focusApp) {
216 function show(focusApp) {
217 shown = true;
217 shown = true;
218 panel.indicators.hide();
218 panel.indicators.hide();
219+ edgeDemo.stopDemo();
220+ greeter.hide();
219 if (!ApplicationManager.focusedApplicationId && ApplicationManager.count > 0 && focusApp) {
221 if (!ApplicationManager.focusedApplicationId && ApplicationManager.count > 0 && focusApp) {
220 ApplicationManager.focusApplication(ApplicationManager.get(0).appId);
222 ApplicationManager.focusApplication(ApplicationManager.get(0).appId);
221 }
223 }
@@ -409,6 +411,7 @@ BasicShell {
409 width: parent.width
411 width: parent.width
410 dragAreaWidth: shell.edgeSize
412 dragAreaWidth: shell.edgeSize
411 available: edgeDemo.launcherEnabled
413 available: edgeDemo.launcherEnabled
414+
412 onShowDashHome: {
415 onShowDashHome: {
413 if (edgeDemo.running)
416 if (edgeDemo.running)
414 return;
417 return;
@@ -425,11 +428,9 @@ BasicShell {
425 }
428 }
426 }
429 }
427 onDashSwipeChanged: if (dashSwipe && stages.shown) dash.setCurrentScope("clickscope", false, true)
430 onDashSwipeChanged: if (dashSwipe && stages.shown) dash.setCurrentScope("clickscope", false, true)
428− onLauncherApplicationSelected:{
431+ onLauncherApplicationSelected: {
429− if (edgeDemo.running)
432+ if (!edgeDemo.running)
430− return;
431−
432− shell.activateApplication(appId)
433+ shell.activateApplication(appId)
433 }
434 }
434 onShownChanged: {
435 onShownChanged: {
435 if (shown) {
436 if (shown) {
qml/graphics/phone_background.jpg

Binary file not shown.

qml/graphics/tablet_background.jpg

Binary file not shown.

run+15−1
@@ -70,8 +70,22 @@ if $MOUSE_TOUCH; then
70 QML_PHONE_SHELL_ARGS="$QML_PHONE_SHELL_ARGS -mousetouch"
70 QML_PHONE_SHELL_ARGS="$QML_PHONE_SHELL_ARGS -mousetouch"
71fi
71fi
72
72
73+control_c()
74+{
75+ /sbin/initctl stop unity8
76+ exit $?
77+}
78+
79+trap control_c INT
80+
73if $GDB; then
81if $GDB; then
74 gdb -ex run --args $QML_PHONE_SHELL_PATH $QML_PHONE_SHELL_ARGS $@
82 gdb -ex run --args $QML_PHONE_SHELL_PATH $QML_PHONE_SHELL_ARGS $@
75else
83else
84+ status=`/sbin/initctl status unity8`
85+ if [ "$status" != "unity8 stop/waiting" ]; then
86+ echo "Unity8 is already running, please stop it first"
87+ exit 1
88+ fi
76− $QML_PHONE_SHELL_PATH $QML_PHONE_SHELL_ARGS $@
89+ /sbin/initctl start unity8 BINARY="`readlink -f $QML_PHONE_SHELL_PATH` $QML_PHONE_SHELL_ARGS $@"
90+ tailf -n 0 ~/.cache/upstart/unity8.log
77fi
91fi
tests/autopilot/unity8/application_lifecycle/tests/__init__.py+47
@@ -0,0 +1,47 @@
1+# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
2+#
3+# Unity Autopilot Test Suite
4+# Copyright (C) 2014 Canonical
5+#
6+# This program is free software: you can redistribute it and/or modify
7+# it under the terms of the GNU General Public License as published by
8+# the Free Software Foundation, either version 3 of the License, or
9+# (at your option) any later version.
10+#
11+# This program is distributed in the hope that it will be useful,
12+# but WITHOUT ANY WARRANTY; without even the implied warranty of
13+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+# GNU General Public License for more details.
15+#
16+# You should have received a copy of the GNU General Public License
17+# along with this program. If not, see <http://www.gnu.org/licenses/>.
18+#
19+
20+from autopilot.matchers import Eventually
21+from testtools.matchers import Equals
22+from ubuntuuitoolkit import fixture_setup
23+
24+from unity8 import process_helpers
25+from unity8.shell import tests
26+
27+
28+class ApplicationLifeCycleTestCase(tests.UnityTestCase):
29+
30+ def setUp(self):
31+ super(ApplicationLifeCycleTestCase, self).setUp()
32+ self._qml_mock_enabled = False
33+ self._data_dirs_mock_enabled = False
34+
35+ def create_test_application(self):
36+ desktop_file_dict = fixture_setup.DEFAULT_DESKTOP_FILE_DICT
37+ desktop_file_dict.update({'X-Ubuntu-Single-Instance': 'true'})
38+ fake_application = fixture_setup.FakeApplication(
39+ desktop_file_dict=desktop_file_dict)
40+ self.useFixture(fake_application)
41+ return (
42+ fake_application.qml_file_path, fake_application.desktop_file_path)
43+
44+ def assert_current_focused_application(self, application_name):
45+ self.assertThat(
46+ self.main_window.get_current_focused_app_id,
47+ Eventually(Equals(application_name)))
tests/autopilot/unity8/application_lifecycle/tests/test_application_lifecycle.py+27−67
@@ -21,26 +21,24 @@
21
21
22from __future__ import absolute_import
22from __future__ import absolute_import
23
23
24−from unity8.shell import disable_qml_mocking
24+import logging
25−from unity8.shell.tests import UnityTestCase, _get_device_emulation_scenarios
25+import os
26
26
27−from autopilot.matchers import Eventually
28from autopilot.platform import model
27from autopilot.platform import model
29−from testtools.matchers import Equals, NotEquals
30
28
31−import logging
29+from unity8.application_lifecycle import tests
32
30
33−logger = logging.getLogger(__name__)
34
31
32+logger = logging.getLogger(__name__)
35
33
36−class ApplicationLifecycleTests(UnityTestCase):
37
34
38− scenarios = _get_device_emulation_scenarios()
35+class ApplicationLifecycleTests(tests.ApplicationLifeCycleTestCase):
39
36
40 def setUp(self):
37 def setUp(self):
38+ if model() == 'Desktop':
39+ self.skipTest('Test cannot be run on the desktop.')
41 super(ApplicationLifecycleTests, self).setUp()
40 super(ApplicationLifecycleTests, self).setUp()
42− if model() == "Desktop":
41+ self.launch_unity()
43− self.skipTest("Test cannot be run on the desktop.")
44
42
45 def swipe_screen_from_right(self):
43 def swipe_screen_from_right(self):
46 width = self.main_window.width
44 width = self.main_window.width
@@ -53,77 +51,39 @@ class ApplicationLifecycleTests(UnityTestCase):
53 logger.info("Swiping screen from the right edge")
51 logger.info("Swiping screen from the right edge")
54 self.touch.drag(start_x, start_y, end_x, end_y)
52 self.touch.drag(start_x, start_y, end_x, end_y)
55
53
56− def _launch_app(self, app_name):
54+ def launch_fake_app(self):
57− """Launches the application *app_name*
55+ _, desktop_file_path = self.create_test_application()
58−
56+ desktop_file_name = os.path.basename(desktop_file_path)
59− Assumes that the desktop file resides at:
57+ application_name, _ = os.path.splitext(desktop_file_name)
60− /usr/share/applications/{app_name}.desktop
58+ self.launch_upstart_application(application_name)
59+ return application_name
61
60
62− """
63− desktop_file = "--desktop_file_hint="\
64− "/usr/share/applications/{app_name}.desktop".format(
65− app_name=app_name
66− )
67− return self.launch_test_application(
68− app_name,
69− desktop_file,
70− "--stage_hint=main_stage",
71− app_type='qt'
72− )
73−
74− @disable_qml_mocking
75 def test_can_launch_application(self):
61 def test_can_launch_application(self):
76 """Must be able to launch an application."""
62 """Must be able to launch an application."""
77− self.launch_unity()
63+ application_name = self.launch_fake_app()
78−
64+ self.assert_current_focused_application(application_name)
79− app = self._launch_app("messaging-app")
80
65
81− self.assertThat(app, NotEquals(None))
82− self.assertThat(
83− self.main_window.get_current_focused_app_id(),
84− Eventually(Equals("messaging-app"))
85− )
86−
87− @disable_qml_mocking
88 def test_can_launch_multiple_applications(self):
66 def test_can_launch_multiple_applications(self):
89 """A second application launched must be focused."""
67 """A second application launched must be focused."""
90− self.launch_unity()
68+ application1_name = self.launch_fake_app()
69+ self.assert_current_focused_application(application1_name)
91
70
92− self._launch_app("messaging-app")
71+ application2_name = self.launch_fake_app()
93− self.assertThat(
72+ self.assertFalse(application1_name == application2_name)
94− self.main_window.get_current_focused_app_id(),
73+ self.assert_current_focused_application(application2_name)
95− Eventually(Equals("messaging-app"))
96− )
97
74
98− self._launch_app("address-book-app")
99− self.assertThat(
100− self.main_window.get_current_focused_app_id(),
101− Eventually(Equals("address-book-app"))
102− )
103−
104− @disable_qml_mocking
105 def test_app_moves_from_unfocused_to_focused(self):
75 def test_app_moves_from_unfocused_to_focused(self):
106 """An application that is in the unfocused state must be able to be
76 """An application that is in the unfocused state must be able to be
107 brought back to the focused state.
77 brought back to the focused state.
108
78
109 """
79 """
110− self.launch_unity()
80+ application1_name = self.launch_fake_app()
111−
81+ self.assert_current_focused_application(application1_name)
112− self._launch_app("messaging-app")
113− self.assertThat(
114− self.main_window.get_current_focused_app_id(),
115− Eventually(Equals("messaging-app"))
116− )
117
82
118− self._launch_app("address-book-app")
83+ application2_name = self.launch_fake_app()
119− self.assertThat(
84+ self.assertFalse(application1_name == application2_name)
120− self.main_window.get_current_focused_app_id(),
85+ self.assert_current_focused_application(application2_name)
121− Eventually(Equals("address-book-app"))
122− )
123
86
124 self.swipe_screen_from_right()
87 self.swipe_screen_from_right()
125
88
126− self.assertThat(
89+ self.assert_current_focused_application(application1_name)
127− self.main_window.get_current_focused_app_id(),
128− Eventually(Equals("messaging-app"))
129− )
tests/autopilot/unity8/application_lifecycle/tests/test_greeter.pynew file+59
@@ -0,0 +1,59 @@
1+# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
2+#
3+# Unity Autopilot Test Suite
4+# Copyright (C) 2013, 2014 Canonical
5+#
6+# This program is free software: you can redistribute it and/or modify
7+# it under the terms of the GNU General Public License as published by
8+# the Free Software Foundation, either version 3 of the License, or
9+# (at your option) any later version.
10+#
11+# This program is distributed in the hope that it will be useful,
12+# but WITHOUT ANY WARRANTY; without even the implied warranty of
13+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+# GNU General Public License for more details.
15+#
16+# You should have received a copy of the GNU General Public License
17+# along with this program. If not, see <http://www.gnu.org/licenses/>.
18+#
19+
20+"""Tests for the application lifecycle in the greeter."""
21+
22+from __future__ import absolute_import
23+
24+import logging
25+import os
26+import subprocess
27+
28+from autopilot.matchers import Eventually
29+from autopilot.platform import model
30+from testtools.matchers import Equals
31+
32+from unity8.application_lifecycle import tests
33+from unity8.shell import with_lightdm_mock
34+
35+
36+logger = logging.getLogger(__name__)
37+
38+
39+class GreeterApplicationLifecycleTests(tests.ApplicationLifeCycleTestCase):
40+
41+ def setUp(self):
42+ if model() == 'Desktop':
43+ self.skipTest('Test cannot be run on the desktop.')
44+ super(GreeterApplicationLifecycleTests, self).setUp()
45+ self.launch_greeter()
46+
47+ @with_lightdm_mock("single")
48+ def test_greeter_hides_on_url_dispatcher(self):
49+ """Greeter should hide when an app is opened"""
50+ greeter = self.main_window.get_greeter()
51+ self.assertThat(greeter.created, Eventually(Equals(True)))
52+
53+ _, desktop_file_path = self.create_test_application()
54+ desktop_file_name = os.path.basename(desktop_file_path)
55+ application_name, _ = os.path.splitext(desktop_file_name)
56+
57+ subprocess.check_call(
58+ ['url-dispatcher', 'application:///{}'.format(desktop_file_name)])
59+ self.assertThat(greeter.created, Eventually(Equals(False)))
tests/autopilot/unity8/application_lifecycle/tests/test_url_dispatcher.py+9−38
@@ -20,47 +20,20 @@
20"""Test the integration with the URL dispatcher service."""
20"""Test the integration with the URL dispatcher service."""
21
21
22import os
22import os
23+import subprocess
23
24
24from autopilot import platform
25from autopilot import platform
25−from autopilot.matchers import Eventually
26−from testtools.matchers import Equals
27−from ubuntuuitoolkit import fixture_setup
28
26
29−from unity8 import process_helpers
27+from unity8.application_lifecycle import tests
30−from unity8.shell import tests
31
28
32
29
33−class URLDispatcherTestCase(tests.UnityTestCase):
30+class URLDispatcherTestCase(tests.ApplicationLifeCycleTestCase):
34−
35− scenarios = tests._get_device_emulation_scenarios()
36−
37− test_qml = ("""
38−import QtQuick 2.0
39−import Ubuntu.Components 0.1
40−
41−MainView {
42− width: units.gu(48)
43− height: units.gu(60)
44−
45− Label {
46− text: 'Test application.'
47− }
48−}
49−""")
50
31
51 def setUp(self):
32 def setUp(self):
52 if platform.model() == 'Desktop':
33 if platform.model() == 'Desktop':
53 self.skipTest("URL dispatcher doesn't work on the desktop.")
34 self.skipTest("URL dispatcher doesn't work on the desktop.")
54 super(URLDispatcherTestCase, self).setUp()
35 super(URLDispatcherTestCase, self).setUp()
55− self._qml_mock_enabled = False
56− self._data_dirs_mock_enabled = False
57− unity_proxy = self.launch_unity()
36+ self.launch_unity()
58−
59− def create_test_application(self):
60− fake_application = fixture_setup.FakeApplication(self.test_qml)
61− self.useFixture(fake_application)
62− return (
63− fake_application.qml_file_path, fake_application.desktop_file_path)
64
37
65 def test_swipe_out_application_started_by_url_dispatcher(self):
38 def test_swipe_out_application_started_by_url_dispatcher(self):
66 _, desktop_file_path = self.create_test_application()
39 _, desktop_file_path = self.create_test_application()
@@ -69,12 +42,10 @@ MainView {
69
42
70 self.assertEqual('', self.main_window.get_current_focused_app_id())
43 self.assertEqual('', self.main_window.get_current_focused_app_id())
71 self.addCleanup(os.system, 'pkill qmlscene')
44 self.addCleanup(os.system, 'pkill qmlscene')
45+
46+ subprocess.check_call(
72− os.system('url-dispatcher application:///{}'.format(desktop_file_name))
47+ ['url-dispatcher', 'application:///{}'.format(desktop_file_name)])
73− self.assertThat(
48+ self.assert_current_focused_application(application_name)
74− self.main_window.get_current_focused_app_id,
75− Eventually(Equals(application_name)))
76
49
77 self.main_window.show_dash_swiping()
50 self.main_window.show_dash_swiping()
78− self.assertThat(
51+ self.assert_current_focused_application('')
79− self.main_window.get_current_focused_app_id,
80− Eventually(Equals('')))
tests/autopilot/unity8/process_helpers.py+17
@@ -32,6 +32,23 @@ logger = logging.getLogger(__name__)
32class CannotAccessUnity(Exception):
32class CannotAccessUnity(Exception):
33 pass
33 pass
34
34
35+
36+def lock_unity(unity_proxy_obj=None):
37+ """Helper function that attempts to lock the unity greeter."""
38+ import evdev, time
39+ uinput = evdev.UInput(name='unity8-autopilot-power-button',
40+ devnode='/dev/autopilot-uinput')
41+ # One press and release to turn screen off (locking unity)
42+ uinput.write(evdev.ecodes.EV_KEY, evdev.ecodes.KEY_POWER, 1)
43+ uinput.write(evdev.ecodes.EV_KEY, evdev.ecodes.KEY_POWER, 0)
44+ uinput.syn()
45+ time.sleep(1)
46+ # And another press and release to turn screen back on
47+ uinput.write(evdev.ecodes.EV_KEY, evdev.ecodes.KEY_POWER, 1)
48+ uinput.write(evdev.ecodes.EV_KEY, evdev.ecodes.KEY_POWER, 0)
49+ uinput.syn()
50+
51+
35def restart_unity_with_testability(*args):
52def restart_unity_with_testability(*args):
36 """Restarts (or starts) unity with testability enabled.
53 """Restarts (or starts) unity with testability enabled.
37
54
tests/autopilot/unity8/shell/emulators/dash.py+10−5
@@ -191,13 +191,18 @@ class DashApps(GenericScopeView):
191
191
192 """
192 """
193 category_element = self._get_category_element(category)
193 category_element = self._get_category_element(category)
194− application_tiles = category_element.select_many('Card')
194+ application_cards = category_element.select_many('Card')
195− # TODO return them on the same order they are displayed.
195+
196− # --elopio - 2014-1-15
196+ # sort by y, x
197+ application_cards = sorted(
198+ application_cards,
199+ key=lambda card: (card.globalRect.y, card.globalRect.x))
200+
197 result = []
201 result = []
198− for card in application_tiles:
202+ for card in application_cards:
199 if card.objectName != 'cardToolCard':
203 if card.objectName != 'cardToolCard':
204+ card_header = card.select_single('CardHeader')
200− result.append(card)
205+ result.append(card_header.title)
201 return result
206 return result
202
207
203
208
tests/autopilot/unity8/shell/tests/test_emulators.py+3−11
@@ -165,7 +165,7 @@ class DashAppsEmulatorTestCase(DashBaseTestCase):
165 available_applications = [
165 available_applications = [
166 'Title.2.0', 'Title.2.1', 'Title.2.2', 'Title.2.3', 'Title.2.4',
166 'Title.2.0', 'Title.2.1', 'Title.2.2', 'Title.2.3', 'Title.2.4',
167 'Title.2.5', 'Title.2.6', 'Title.2.7', 'Title.2.8', 'Title.2.9',
167 'Title.2.5', 'Title.2.6', 'Title.2.7', 'Title.2.8', 'Title.2.9',
168− 'Title.2.9', 'Title.2.10', 'Title.2.11']
168+ 'Title.2.10', 'Title.2.11', 'Title.2.12']
169
169
170 def setUp(self):
170 def setUp(self):
171 # Set up the fake scopes before launching unity.
171 # Set up the fake scopes before launching unity.
@@ -182,21 +182,13 @@ class DashAppsEmulatorTestCase(DashBaseTestCase):
182 self.assertEqual(
182 self.assertEqual(
183 'No category found with name unexisting category', str(exception))
183 'No category found with name unexisting category', str(exception))
184
184
185− def test_get_applications_should_return_list_with_names(self):
185+ def test_get_applications_should_return_correct_applications(self):
186 category = '2'
186 category = '2'
187 expected_apps_count = self._get_number_of_application_slots(category)
187 expected_apps_count = self._get_number_of_application_slots(category)
188 expected_applications = self.available_applications[
188 expected_applications = self.available_applications[
189 :expected_apps_count]
189 :expected_apps_count]
190−
191 applications = self.applications_scope.get_applications(category)
190 applications = self.applications_scope.get_applications(category)
192− applications_titles = []
193− for application in applications:
194− cardHeader = application.select_single('CardHeader')
195− applications_titles.append(cardHeader.title)
196−
197− self.assertThat(applications, HasLength(expected_apps_count))
198− for expected in expected_applications:
191+ self.assertEqual(expected_applications, applications)
199− self.assertThat(applications_titles, Contains(expected))
200
192
201 def _get_number_of_application_slots(self, category):
193 def _get_number_of_application_slots(self, category):
202 category_element = self.applications_scope._get_category_element(
194 category_element = self.applications_scope._get_category_element(
tests/autopilot/unity8/shell/tests/test_notifications.py+3−4
@@ -193,7 +193,7 @@ class InteractiveNotificationBase(NotificationsBase):
193 get_notification = lambda: notify_list.wait_select_single(
193 get_notification = lambda: notify_list.wait_select_single(
194 'Notification', objectName='notification1')
194 'Notification', objectName='notification1')
195 notification = get_notification()
195 notification = get_notification()
196− self._assert_notification(notification, None, None, True, True, 1.0)
196+ self._assert_notification(notification, summary, body, True, True, 1.0)
197 initial_height = notification.height
197 initial_height = notification.height
198 self.touch.tap_object(notification.select_single(objectName="button1"))
198 self.touch.tap_object(notification.select_single(objectName="button1"))
199 self.assertThat(
199 self.assertThat(
@@ -398,7 +398,6 @@ class EphemeralNotificationsTests(NotificationsBase):
398
398
399 notification = lambda: notify_list.wait_select_single(
399 notification = lambda: notify_list.wait_select_single(
400 'Notification', objectName='notification1')
400 'Notification', objectName='notification1')
401−
402 self._assert_notification(
401 self._assert_notification(
403 notification(),
402 notification(),
404 summary,
403 summary,
@@ -570,7 +569,7 @@ class EphemeralNotificationsTests(NotificationsBase):
570 icon_path = self._get_icon_path('avatars/amanda.png')
569 icon_path = self._get_icon_path('avatars/amanda.png')
571 notification.update(summary, body, icon_path)
570 notification.update(summary, body, icon_path)
572 notification.show()
571 notification.show()
573− self._assert_notification(get_notification(), summary, body)
572+ self._assert_notification(get_notification(), summary, body, True, False, 1.0)
574
573
575 def test_update_notification_layout_change(self):
574 def test_update_notification_layout_change(self):
576 """Notification must allow updating its contents and layout while
575 """Notification must allow updating its contents and layout while
@@ -616,7 +615,7 @@ class EphemeralNotificationsTests(NotificationsBase):
616 notification.show()
615 notification.show()
617
616
618 self.assertThat(get_notification, Eventually(NotEquals(None)))
617 self.assertThat(get_notification, Eventually(NotEquals(None)))
619− self._assert_notification(get_notification(), summary, body, False)
618+ self._assert_notification(get_notification(), summary, body, False, False, 1.0)
620
619
621 def test_append_hint(self):
620 def test_append_hint(self):
622 """Notification has to accumulate body-text using append-hint."""
621 """Notification has to accumulate body-text using append-hint."""
tests/qmltests/CMakeLists.txt+1−1
@@ -12,7 +12,6 @@ set(qmltest_DEFAULT_IMPORT_PATHS
12set(qmltest_DEFAULT_TARGETS qmlunittests)
12set(qmltest_DEFAULT_TARGETS qmlunittests)
13set(qmltest_DEFAULT_NO_ADD_TEST FALSE)
13set(qmltest_DEFAULT_NO_ADD_TEST FALSE)
14set(qmltest_DEFAULT_PROPERTIES ENVIRONMENT "QT_QPA_PLATFORM=minimal")
14set(qmltest_DEFAULT_PROPERTIES ENVIRONMENT "QT_QPA_PLATFORM=minimal")
15−add_qml_test(Components AnimationControllerWithSignals)
16add_qml_test(Panel IndicatorItem)
15add_qml_test(Panel IndicatorItem)
17add_qml_test(utils/Unity/Test UnityTest)
16add_qml_test(utils/Unity/Test UnityTest)
18
17
@@ -37,6 +36,7 @@ add_qml_test(Components PageHeaderLabel)
37add_qml_test(Dash Dash)
36add_qml_test(Dash Dash)
38add_qml_test(Dash DashContent)
37add_qml_test(Dash DashContent)
39add_qml_test(Dash Card)
38add_qml_test(Dash Card)
39+add_qml_benchmark(Dash CardBenchmark 1000)
40add_qml_test(Dash CardHeader)
40add_qml_test(Dash CardHeader)
41add_qml_test(Dash CardTool)
41add_qml_test(Dash CardTool)
42add_qml_test(Dash GenericScopeView)
42add_qml_test(Dash GenericScopeView)
tests/qmltests/Components/tst_AnimationControllerWithSignals.qmldeleted−142
@@ -1,142 +0,0 @@
1−/*
2− * Copyright 2013 Canonical Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− */
16−
17−import QtQuick 2.0
18−import QtTest 1.0
19−import "../../../qml/Components"
20−
21−TestCase {
22− id: testCase
23− name: "AnimationControllerWithSignals"
24−
25− property real someNumber: 0.0
26−
27− NumberAnimation {
28− id: someNumberAnimation
29− target: testCase
30− properties: "someNumber"
31− from: 1.0
32− to: 100.0
33− }
34−
35− Component {
36− id: testSubjectComponent
37− AnimationControllerWithSignals {}
38− }
39−
40− Loader {
41− id: loader
42− asynchronous: false
43− }
44−
45− SignalSpy {
46− id: signalSpy
47− }
48−
49− function test_completeToEndWithSignal() {
50− loader.sourceComponent = testSubjectComponent;
51− var testSubject = loader.item;
52−
53− testSubject.animation = someNumberAnimation;
54− testSubject.progress = 0;
55−
56− signalSpy.signalName = "animationCompletedAtEnd";
57− signalSpy.target = testSubject;
58− signalSpy.clear();
59−
60− compare(testSubject.completing, false)
61− compare(testSubject.completed, true)
62−
63− testSubject.completeToEndWithSignal();
64− compare(testSubject.completing, true)
65− compare(testSubject.completed, true)
66− compare(signalSpy.count, 0);
67−
68− testSubject.progress = 0.5;
69− compare(testSubject.completing, true)
70− compare(testSubject.completed, false)
71− compare(signalSpy.count, 0);
72−
73− testSubject.progress = 1.0;
74− compare(testSubject.completing, false)
75− compare(testSubject.completed, true)
76− compare(signalSpy.count, 1);
77−
78− testSubject.animation = null
79− loader.sourceComponent = undefined;
80− }
81−
82− function test_completeToBeginningWithSignal() {
83− loader.sourceComponent = testSubjectComponent;
84− var testSubject = loader.item;
85−
86− testSubject.animation = someNumberAnimation;
87− testSubject.progress = 1;
88−
89− signalSpy.signalName = "animationCompletedAtBeginning";
90− signalSpy.target = testSubject;
91− signalSpy.clear();
92−
93− compare(testSubject.completing, false)
94− compare(testSubject.completed, true)
95−
96− testSubject.completeToBeginningWithSignal();
97− compare(testSubject.completing, true)
98− compare(testSubject.completed, true)
99− compare(signalSpy.count, 0);
100−
101− testSubject.progress = 0.5;
102− compare(testSubject.completing, true)
103− compare(testSubject.completed, false)
104− compare(signalSpy.count, 0);
105−
106− testSubject.progress = 0;
107− compare(testSubject.completing, false)
108− compare(testSubject.completed, true)
109− compare(signalSpy.count, 1);
110−
111− testSubject.animation = null
112− loader.sourceComponent = undefined;
113− }
114−
115− function test_settingProgressWithoutCallingCompleteWithSignal() {
116− loader.sourceComponent = testSubjectComponent;
117− var testSubject = loader.item;
118−
119− testSubject.animation = someNumberAnimation;
120− testSubject.progress = 0;
121−
122− signalSpy.signalName = "animationCompletedAtEnd";
123− signalSpy.target = testSubject;
124− signalSpy.clear();
125−
126− compare(testSubject.completing, false)
127− compare(testSubject.completed, true)
128−
129− testSubject.progress = 0.5;
130− compare(testSubject.completing, false)
131− compare(testSubject.completed, false)
132− compare(signalSpy.count, 0);
133−
134− testSubject.progress = 1;
135− compare(testSubject.completing, false)
136− compare(testSubject.completed, true)
137− compare(signalSpy.count, 0);
138−
139− testSubject.animation = null
140− loader.sourceComponent = undefined;
141− }
142−}
tests/qmltests/Components/tst_Carousel.qml+34−7
@@ -18,6 +18,7 @@ import QtQuick 2.0
18import QtTest 1.0
18import QtTest 1.0
19import "../../../qml/Components/"
19import "../../../qml/Components/"
20import "../../../qml/Components/carousel.js" as Carousel
20import "../../../qml/Components/carousel.js" as Carousel
21+import Unity.Test 0.1 as UT
21
22
22Item {
23Item {
23 width: 700
24 width: 700
@@ -31,13 +32,17 @@ Item {
31 property int createdDelegates: 0
32 property int createdDelegates: 0
32 property int destroyedDelegates: 0
33 property int destroyedDelegates: 0
33
34
35+ itemComponent: BaseCarouselDelegate {
34− itemComponent: Rectangle {
36+ Rectangle {
37+ anchors.fill: parent
38+ border.color: "black"
35− color: "red"
39+ color: "red"
36− Component.onCompleted: carousel.createdDelegates++
40+ Component.onCompleted: carousel.createdDelegates++
37− Component.onDestruction: carousel.destroyedDelegates++
41+ Component.onDestruction: carousel.destroyedDelegates++
42+ }
38 }
43 }
39 }
44 }
40− TestCase {
45+ UT.UnityTestCase {
41 id: root
46 id: root
42 name: "Carousel"
47 name: "Carousel"
43 when: windowShown
48 when: windowShown
@@ -55,8 +60,11 @@ Item {
55 property real kGapEnd: kMiddleIndex * (1 - gapToEndPhase / gapToMiddlePhase)
60 property real kGapEnd: kMiddleIndex * (1 - gapToEndPhase / gapToMiddlePhase)
56 property real kXBeginningEnd: 1 / tileWidth + kMiddleIndex / gapToMiddlePhase
61 property real kXBeginningEnd: 1 / tileWidth + kMiddleIndex / gapToMiddlePhase
57
62
58− function test_onlyNeededItemsCreated() {
63+ // This test needs to run first since it tests a corner case condition
64+ // to where the carousel is just being created
65+ // That is why it has a 1 in the name
66+ function test_1onlyNeededItemsCreated() {
59− compare(carousel.createdDelegates, 10);
67+ tryCompare(carousel, "createdDelegates", 10);
60 compare(carousel.destroyedDelegates, 0);
68 compare(carousel.destroyedDelegates, 0);
61 }
69 }
62
70
@@ -216,5 +224,24 @@ Item {
216 data.maxTranslation)
224 data.maxTranslation)
217 compare(scale, data.result)
225 compare(scale, data.result)
218 }
226 }
227+
228+ function test_lastItemXPosition() {
229+ var carouselList = findChild(carousel, "listView");
230+ var stepAnimation = findInvisibleChild(carouselList, "stepAnimation");
231+ var stepDiff = 0;
232+ stepAnimation.onRunningChanged.connect(function() { if (stepAnimation.running) stepDiff = Math.abs(carouselList.contentX - stepAnimation.to); })
233+ var overshootOnce = false;
234+ while (!overshootOnce) {
235+ overshootOnce = carouselList.realContentX > carouselList.realContentWidth - carouselList.realWidth;
236+ mouseFlick(carousel, carousel.width - units.gu(1),
237+ carousel.height / 2,
238+ units.gu(2),
239+ carousel.height / 2);
240+ tryCompare(carouselList, "moving", false);
241+ }
242+ verify(stepDiff < 1);
243+ var x = carouselList.getXFromContinuousIndex(carousel.model - 1);
244+ verify(Math.abs(x - carouselList.contentX) < 1);
245+ }
219 }
246 }
220}
247}
tests/qmltests/Dash/qml/FakeScopeView.qmldeleted−45
@@ -1,45 +0,0 @@
1−/*
2− * Copyright 2013 Canonical Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− */
16−
17−import QtQuick 2.0
18−import Unity 0.2
19−
20−import "../../../../qml/Dash"
21−
22−GenericScopeView {
23− id: fakeScopeView
24−
25− property alias backColor : back.color
26− property var categoryView: null
27−
28− onMovementStarted: {
29− if (shell != undefined && shell.scopeStatus != undefined) {
30− shell.scopeStatus[scope.id].movementStarted++;
31− }
32− }
33− onPositionedAtBeginning: {
34− if (shell != undefined && shell.scopeStatus != undefined) {
35− shell.scopeStatus[scope.id].positionedAtBeginning++;
36− }
37− }
38−
39− Rectangle {
40− id: back
41− anchors.fill: parent
42− color: "grey"
43− z: -1
44− }
45−}
tests/qmltests/Dash/qml/fake_generic_scopeView.qmldeleted−24
@@ -1,24 +0,0 @@
1−/*
2− * Copyright 2013 Canonical Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− */
16−
17−import QtQuick 2.0
18−
19−FakeScopeView {
20− id: fake_generic_scopeView
21− objectName: "fake_generic_scopeView"
22−
23− backColor: "#D0D0D0"
24−}
tests/qmltests/Dash/qml/fake_scopeView1.qmldeleted−24
@@ -1,24 +0,0 @@
1−/*
2− * Copyright 2013 Canonical Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− */
16−
17−import QtQuick 2.0
18−
19−FakeScopeView {
20− id: fake_scopeView1
21− objectName: "fake_scopeView1"
22−
23− backColor: "#90E090"
24−}
tests/qmltests/Dash/qml/fake_scopeView2.qmldeleted−24
@@ -1,24 +0,0 @@
1−/*
2− * Copyright 2013 Canonical Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− */
16−
17−import QtQuick 2.0
18−
19−FakeScopeView {
20− id: fake_scopeView2
21− objectName: "fake_scopeView2"
22−
23− backColor: "#A0D0A0"
24−}
tests/qmltests/Dash/qml/fake_scopeView3.qmldeleted−24
@@ -1,24 +0,0 @@
1−/*
2− * Copyright 2013 Canonical Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− */
16−
17−import QtQuick 2.0
18−
19−FakeScopeView {
20− id: fake_scopeView3
21− objectName: "fake_scopeView3"
22−
23− backColor: "#B0C0B0"
24−}
tests/qmltests/Dash/qml/fake_scopeView4.qmldeleted−24
@@ -1,24 +0,0 @@
1−/*
2− * Copyright 2013 Canonical Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− */
16−
17−import QtQuick 2.0
18−
19−FakeScopeView {
20− id: fake_scopeView4
21− objectName: "fake_scopeView4"
22−
23− backColor: "#C0C0C0"
24−}
tests/qmltests/Dash/tst_Card.qml+12−10
@@ -182,11 +182,13 @@ Rectangle {
182 when: windowShown
182 when: windowShown
183
183
184 property Item header: findChild(card, "cardHeader")
184 property Item header: findChild(card, "cardHeader")
185+ property Item headerLoader: findChild(card, "cardHeaderLoader")
185 property Item title: findChild(header, "titleLabel")
186 property Item title: findChild(header, "titleLabel")
186 property Item art: findChild(card, "artShape")
187 property Item art: findChild(card, "artShape")
187 property Item artImage: findChild(card, "artImage")
188 property Item artImage: findChild(card, "artImage")
188 property Item summary: findChild(card, "summaryLabel")
189 property Item summary: findChild(card, "summaryLabel")
189 property Item background: findChild(card, "background")
190 property Item background: findChild(card, "background")
191+ property Item backgroundLoader: findChild(card, "backgroundLoader")
190 property Item backgroundImage: findChild(card, "backgroundImage")
192 property Item backgroundImage: findChild(card, "backgroundImage")
191
193
192 function initTestCase() {
194 function initTestCase() {
@@ -244,8 +246,8 @@ Rectangle {
244 { tag: "Wide", width: units.gu(18.5), aspect: 0.5, index: 0 },
246 { tag: "Wide", width: units.gu(18.5), aspect: 0.5, index: 0 },
245 { tag: "Horizontal", width: units.gu(38), index: 5 },
247 { tag: "Horizontal", width: units.gu(38), index: 5 },
246 // Make sure card ends with header when there's no summary
248 // Make sure card ends with header when there's no summary
247− { tag: "NoSummary", height: function() { return header.y + header.height }, index: 6 },
249+ { tag: "NoSummary", height: function() { return headerLoader.y + headerLoader.height }, index: 6 },
248− { tag: "HorizontalNoSummary", height: function() { return header.height }, card_layout: "horizontal", index: 6 },
250+ { tag: "HorizontalNoSummary", height: function() { return headerLoader.height }, card_layout: "horizontal", index: 6 },
249 ]
251 ]
250 }
252 }
251
253
@@ -288,7 +290,7 @@ Rectangle {
288 { tag: "Fit", height: units.gu(38), size: "large", width: units.gu(19), index: 4 },
290 { tag: "Fit", height: units.gu(38), size: "large", width: units.gu(19), index: 4 },
289 { tag: "VerticalWidth", width: function() { return header.width }, index: 0 },
291 { tag: "VerticalWidth", width: function() { return header.width }, index: 0 },
290 { tag: "HorizontalHeight", height: function() { return header.height }, index: 5 },
292 { tag: "HorizontalHeight", height: function() { return header.height }, index: 5 },
291− { tag: "HorizontalWidth", width: function() { return header.x }, index: 5 },
293+ { tag: "HorizontalWidth", width: function() { return headerLoader.x }, index: 5 },
292 ]
294 ]
293 }
295 }
294
296
@@ -332,7 +334,7 @@ Rectangle {
332 function test_art_layout(data) {
334 function test_art_layout(data) {
333 selector.selectedIndex = data.index;
335 selector.selectedIndex = data.index;
334
336
335− tryCompare(testCase.header, "x", data.left());
337+ tryCompare(testCase.headerLoader, "x", data.left());
336 }
338 }
337
339
338 function test_header_layout_data() {
340 function test_header_layout_data() {
@@ -349,13 +351,13 @@ Rectangle {
349 function test_header_layout(data) {
351 function test_header_layout(data) {
350 selector.selectedIndex = data.index;
352 selector.selectedIndex = data.index;
351
353
352− tryCompareFunction(function() { return testCase.header.y === data.top() }, true);
354+ tryCompareFunction(function() { return testCase.headerLoader.y === data.top() }, true);
353− tryCompareFunction(function() { return testCase.header.x === data.left() }, true);
355+ tryCompareFunction(function() { return testCase.headerLoader.x === data.left() }, true);
354 }
356 }
355
357
356 function test_summary_layout_data() {
358 function test_summary_layout_data() {
357 return [
359 return [
358− { tag: "With header", top: function() { return header.y + header.height }, index: 0 },
360+ { tag: "With header", top: function() { return headerLoader.y + headerLoader.height }, index: 0 },
359 { tag: "Without header", top: function() { return art.y + art.height }, index: 7 },
361 { tag: "Without header", top: function() { return art.y + art.height }, index: 7 },
360 ]
362 ]
361 }
363 }
@@ -400,7 +402,7 @@ Rectangle {
400
402
401 waitForRendering(card);
403 waitForRendering(card);
402
404
403− tryCompare(background, "visible", data.visible);
405+ tryCompare(backgroundLoader, "active", data.visible);
404
406
405 if (data.hasOwnProperty("color")) {
407 if (data.hasOwnProperty("color")) {
406 tryCompare(background, "color", data.color);
408 tryCompare(background, "color", data.color);
@@ -467,13 +469,13 @@ Rectangle {
467 function test_mascotShape(data) {
469 function test_mascotShape(data) {
468 selector.selectedIndex = data.index;
470 selector.selectedIndex = data.index;
469
471
470− var shape = findChild(card, "mascotShape");
472+ var shape = findChild(card, "mascotShapeLoader");
471 var image = findChild(card, "mascotImage");
473 var image = findChild(card, "mascotImage");
472
474
473 verify(shape, "Could not find shape.");
475 verify(shape, "Could not find shape.");
474 verify(image, "Could not find image.");
476 verify(image, "Could not find image.");
475
477
476− tryCompare(shape, "visible", data.shape);
478+ tryCompare(shape, "active", data.shape);
477 tryCompare(image, "visible", !data.shape);
479 tryCompare(image, "visible", !data.shape);
478 }
480 }
479 }
481 }
tests/qmltests/Dash/tst_CardBenchmark.qmlnew file+94
@@ -0,0 +1,94 @@
1+/*
2+ * Copyright (C) 2014 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+import QtQuick 2.0
18+import QtTest 1.0
19+import Ubuntu.Components 0.1
20+import Unity.Test 0.1 as UT
21+import "../../../qml/Dash"
22+import "CardHelpers.js" as Helpers
23+
24+Rectangle {
25+ id: root
26+ width: units.gu(80)
27+ height: units.gu(72)
28+ color: "#88FFFFFF"
29+
30+ property string cardData: '
31+ {
32+ "art": "../../tests/qmltests/Dash/artwork/music-player-design.png",
33+ "mascot": "../../tests/qmltests/Dash/artwork/avatar.png",
34+ "title": "foo",
35+ "subtitle": "bar",
36+ "summary": "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
37+ }'
38+
39+ property string currentModel: '{}'
40+ property string cardTitleArtSubtitleMascotSummaryModel: '{ "components": { "title": "title", "art": "art", "subtitle": "subtitle", "mascot": "mascot", "summary": "summary" } }'
41+ property string cardTitleArtSubtitleMascotModel: '{ "components": { "title": "title", "art": "art", "subtitle": "subtitle", "mascot": "mascot" } }'
42+ property string cardTitleArtSubtitleModel: '{ "components": { "title": "title", "art": "art", "subtitle": "subtitle" } }'
43+ property string cardTitleArtModel: '{ "components": { "title": "title", "art": "art" } }'
44+ property string cardArtModel: '{ "components": { "art": "art" } }'
45+ property string cardTitleModel: '{ "components": { "title": "title" } }'
46+
47+ CardTool {
48+ id: cardTool
49+ template: Helpers.update(JSON.parse(Helpers.defaultLayout), JSON.parse(currentModel))['template'];
50+ components: Helpers.update(JSON.parse(Helpers.defaultLayout), JSON.parse(currentModel))['components'];
51+ viewWidth: units.gu(48)
52+ }
53+
54+ Repeater {
55+ id: cardRepeater
56+ model: 0
57+ Card {
58+ width: cardTool.cardWidth || implicitWidth
59+ height: cardTool.cardHeight || implicitHeight
60+
61+ template: cardTool.template
62+ components: cardTool.components
63+ cardData: Helpers.mapData(root.cardData, components)
64+ }
65+ }
66+
67+ UT.UnityTestCase {
68+ id: testCase
69+ name: "CardBenchmark"
70+
71+ when: windowShown
72+
73+ function init() {
74+ wait(1);
75+ }
76+
77+ function benchmark_time_data() {
78+ return [
79+ { tag: "cardTitleArtSubtitleMascotSummaryModel", model: cardTitleArtSubtitleMascotSummaryModel },
80+ { tag: "cardTitleArtSubtitleMascotModel", model: cardTitleArtSubtitleMascotModel },
81+ { tag: "cardTitleArtSubtitleModel", model: cardTitleArtSubtitleModel },
82+ { tag: "cardTitleArtModel", model: cardTitleArtModel },
83+ { tag: "cardArtModel", model: cardArtModel },
84+ { tag: "cardTitleModel", model: cardTitleModel },
85+ ];
86+ }
87+
88+ function benchmark_time(data) {
89+ currentModel = data.model;
90+ cardRepeater.model = 1;
91+ cardRepeater.model = 0;
92+ }
93+ }
94+}
tests/qmltests/Dash/tst_CardHeader.qml+1−1
@@ -43,7 +43,7 @@ Rectangle {
43
43
44 when: windowShown
44 when: windowShown
45
45
46− property Item mascot: findChild(cardHeader, "mascotShape")
46+ property Item mascot: findChild(cardHeader, "mascotShapeLoader")
47 property Item titleLabel: findChild(cardHeader, "titleLabel")
47 property Item titleLabel: findChild(cardHeader, "titleLabel")
48 property Item subtitleLabel: findChild(cardHeader, "subtitleLabel")
48 property Item subtitleLabel: findChild(cardHeader, "subtitleLabel")
49 property Item oldPriceLabel: findChild(cardHeader, "oldPriceLabel")
49 property Item oldPriceLabel: findChild(cardHeader, "oldPriceLabel")
tests/qmltests/Dash/tst_Dash.qml−11
@@ -41,16 +41,6 @@ Item {
41 showScopeOnLoaded: "MockScope2"
41 showScopeOnLoaded: "MockScope2"
42 }
42 }
43
43
44− ScopeDelegateMapper {
45− id: scopeDelegateMapper
46− scopeDelegateMapping: {
47− "MockScope1": Qt.resolvedUrl("qml/fake_scopeView1.qml"),
48− "MockScope2": Qt.resolvedUrl("qml/fake_scopeView2.qml"),
49− "clickscope": Qt.resolvedUrl("qml/fake_scopeView3.qml")
50− }
51− genericScope: Qt.resolvedUrl("qml/fake_generic_scopeView.qml")
52− }
53−
54 UT.UnityTestCase {
44 UT.UnityTestCase {
55 name: "Dash"
45 name: "Dash"
56 when: windowShown
46 when: windowShown
@@ -59,7 +49,6 @@ Item {
59
49
60 Component.onCompleted: {
50 Component.onCompleted: {
61 var dashContent = findChild(dash, "dashContent");
51 var dashContent = findChild(dash, "dashContent");
62− dashContent.scopeMapper = scopeDelegateMapper;
63 scopes = dashContent.scopes;
52 scopes = dashContent.scopes;
64 }
53 }
65
54
tests/qmltests/Dash/tst_DashContent.qml+27−51
@@ -35,13 +35,6 @@ Item {
35 property var panel: null
35 property var panel: null
36 // BEGIN To reduce warnings
36 // BEGIN To reduce warnings
37
37
38− property var scopeStatus: {
39− 'MockScope1': { 'movementStarted': 0, 'positionedAtBeginning': 0 },
40− 'MockScope2': { 'movementStarted': 0, 'positionedAtBeginning': 0 },
41− 'clickscope': { 'movementStarted': 0, 'positionedAtBeginning': 0 },
42− 'MockScope5': { 'movementStarted': 0, 'positionedAtBeginning': 0 }
43− }
44−
45 Scopes {
38 Scopes {
46 id: scopesModel
39 id: scopesModel
47 }
40 }
@@ -55,34 +48,9 @@ Item {
55 }
48 }
56 scopes : scopesModel
49 scopes : scopesModel
57
50
58− scopeMapper : scopeDelegateMapper
59 searchHistory: SearchHistoryModel {}
51 searchHistory: SearchHistoryModel {}
60 }
52 }
61
53
62− ScopeDelegateMapper {
63− id: scopeDelegateMapper
64− scopeDelegateMapping: {
65− "MockScope1": Qt.resolvedUrl("qml/fake_scopeView1.qml"),
66− "MockScope2": Qt.resolvedUrl("qml/fake_scopeView2.qml"),
67− "clickscope": Qt.resolvedUrl("qml/fake_scopeView3.qml"),
68− }
69− genericScope: Qt.resolvedUrl("qml/fake_generic_scopeView.qml")
70− }
71−
72− function clear_scope_status() {
73− scopeStatus["MockScope1"].movementStarted = 0;
74− scopeStatus["MockScope1"].positionedAtBeginning = 0;
75−
76− scopeStatus["MockScope2"].movementStarted = 0;
77− scopeStatus["MockScope2"].positionedAtBeginning = 0;
78−
79− scopeStatus["clickscope"].movementStarted = 0;
80− scopeStatus["clickscope"].positionedAtBeginning = 0;
81−
82− scopeStatus["MockScope5"].movementStarted = 0;
83− scopeStatus["MockScope5"].positionedAtBeginning = 0;
84− }
85−
86 SignalSpy {
54 SignalSpy {
87 id: scopeLoadedSpy
55 id: scopeLoadedSpy
88 target: dashContent
56 target: dashContent
@@ -97,7 +65,7 @@ Item {
97
65
98 UT.UnityTestCase {
66 UT.UnityTestCase {
99 name: "DashContent"
67 name: "DashContent"
100− when: scopesModel.loaded
68+ when: scopesModel.loaded && windowShown
101
69
102 function init() {
70 function init() {
103 scopesModel.clear();
71 scopesModel.clear();
@@ -108,7 +76,6 @@ Item {
108
76
109 function cleanup() {
77 function cleanup() {
110 movementStartedSpy.clear();
78 movementStartedSpy.clear();
111− clear_scope_status();
112 dashContent.visible = true;
79 dashContent.visible = true;
113
80
114 var dashContentList = findChild(dashContent, "dashContentList");
81 var dashContentList = findChild(dashContent, "dashContentList");
@@ -149,29 +116,38 @@ Item {
149 verify(dashContentList.currentIndex >= 0 && dashContentList.currentIndex < 5);
116 verify(dashContentList.currentIndex >= 0 && dashContentList.currentIndex < 5);
150 }
117 }
151
118
152− function test_movement_started_signal() {
119+ function test_show_header_on_list_movement() {
153− dashContent.setCurrentScopeAtIndex(3, true, false);
154−
155 var dashContentList = findChild(dashContent, "dashContentList");
120 var dashContentList = findChild(dashContent, "dashContentList");
156− verify(dashContentList != undefined)
121+ verify(dashContentList != undefined);
122+ var categoryListView = findChild(dashContentList, "categoryListView");
123+ verify(categoryListView != undefined);
124+
125+ waitForRendering(categoryListView);
157
126
158− dashContentList.movementStarted();
127+ categoryListView.contentY = units.gu(11);
128+ console.log("contentY", categoryListView.contentY);
159
129
160− compare(movementStartedSpy.count, 1, "DashContent should have emitted movementStarted signal when content list did.");
130+ var startX = dashContentList.width/2;
161− compare(scopeStatus["MockScope1"].movementStarted, 1, "MockScope1 should have emitted movementStarted signal when content list did.");
131+ var startY = dashContentList.height/2;
162− compare(scopeStatus["MockScope2"].movementStarted, 1, "MockScope2 should have emitted movementStarted signal when content list did.");
132+ touchFlick(dashContentList, startX - units.gu(2), startY, startX, startY);
163− compare(scopeStatus["clickscope"].movementStarted, 1, "clickscope should have emitted movementStarted signal when content list did.");
133+ tryCompare(categoryListView, "contentY", units.gu(11) - categoryListView.pageHeader.height);
164− compare(scopeStatus["MockScope5"].movementStarted, 1, "MockScope5 should have emitted movementStarted signal when content list did.");
165 }
134 }
166
135
167− function test_positioned_at_beginning_signal() {
136+ function test_set_current_scope_reset() {
137+ var dashContentList = findChild(dashContent, "dashContentList");
138+ verify(dashContentList != undefined);
139+ var categoryListView = findChild(dashContentList, "categoryListView");
140+ verify(categoryListView != undefined);
141+
142+ categoryListView.contentY = units.gu(10);
143+
144+ compare(dashContentList.currentItem.item.objectName, "MockScope1")
145+ compare(categoryListView.contentY, units.gu(10));
146+
168− dashContent.setCurrentScopeAtIndex(3, true, false);
147+ dashContent.setCurrentScopeAtIndex(0, false, true);
169
148
170− dashContent.positionedAtBeginning();
149+ compare(dashContentList.currentItem.item.objectName, "MockScope1")
171− compare(scopeStatus["MockScope1"].positionedAtBeginning, 1, "MockScope1 should have emitted positionedAtBeginning signal when DashContent did.");
150+ compare(categoryListView.contentY, 0);
172− compare(scopeStatus["MockScope2"].positionedAtBeginning, 1, "MockScope2 should have emitted positionedAtBeginning signal when DashContent did.");
173− compare(scopeStatus["clickscope"].positionedAtBeginning, 1, "clickscope should have emitted positionedAtBeginning signal when DashContent did.");
174− compare(scopeStatus["MockScope5"].positionedAtBeginning, 1, "MockScope5 should have emitted positionedAtBeginning signal when DashContent did.");
175 }
151 }
176
152
177 // This tests that setting the current scope index will end up at the correct index even if
153 // This tests that setting the current scope index will end up at the correct index even if
tests/qmltests/Dash/tst_GenericScopeView.qml+1−1
@@ -64,7 +64,7 @@ Item {
64
64
65 UT.UnityTestCase {
65 UT.UnityTestCase {
66 name: "GenericScopeView"
66 name: "GenericScopeView"
67− when: scopes.loaded
67+ when: scopes.loaded && windowShown
68
68
69 function init() {
69 function init() {
70 genericScopeView.scope = scopes.get(2)
70 genericScopeView.scope = scopes.get(2)
tests/qmltests/Launcher/tst_Launcher.qml+1
@@ -66,6 +66,7 @@ Item {
66
66
67 UT.UnityTestCase {
67 UT.UnityTestCase {
68 id: revealer
68 id: revealer
69+ when: windowShown
69
70
70 function dragLauncherIntoView() {
71 function dragLauncherIntoView() {
71 var startX = launcher.dragAreaWidth/2;
72 var startX = launcher.dragAreaWidth/2;
tests/qmltests/Panel/Indicators/tst_MenuItemFactory.qml+1
@@ -44,6 +44,7 @@ Item {
44
44
45 UT.UnityTestCase {
45 UT.UnityTestCase {
46 name: "MenuItemFactory"
46 name: "MenuItemFactory"
47+ when: windowShown
47
48
48 property QtObject menuData: QtObject {
49 property QtObject menuData: QtObject {
49 property string label: "root"
50 property string label: "root"
tests/qmltests/Panel/Indicators/tst_MessageMenuItemFactory.qml+1
@@ -39,6 +39,7 @@ Item {
39
39
40 UT.UnityTestCase {
40 UT.UnityTestCase {
41 name: "MessageMenuItemFactory"
41 name: "MessageMenuItemFactory"
42+ when: windowShown
42
43
43 property QtObject menuData: QtObject {
44 property QtObject menuData: QtObject {
44 property string label: "root"
45 property string label: "root"
tests/qmltests/tst_Shell.qml+11
@@ -511,5 +511,16 @@ Item {
511
511
512 tryCompare(searchIndicator, "opacity", 0);
512 tryCompare(searchIndicator, "opacity", 0);
513 }
513 }
514+
515+ function test_focusRequestedHidesGreeter() {
516+ var greeter = findChild(shell, "greeter")
517+
518+ greeter.show()
519+ tryCompare(greeter, "showProgress", 1)
520+
521+ ApplicationManager.focusRequested("notes-app")
522+ tryCompare(greeter, "showProgress", 0)
523+ waitUntilApplicationWindowIsFullyVisible()
524+ }
514 }
525 }
515}
526}