on xenial help sign in
Merge from trunk
49c02bdMichael Terry
cmake/modules/QmlTest.cmake+4−4
@@ -51,7 +51,7 @@ macro(add_manual_qml_test SUBPATH COMPONENT_NAME)
51
51
52 set(qmlscene_command
52 set(qmlscene_command
53 env ${qmltest_ENVIRONMENT}
53 env ${qmltest_ENVIRONMENT}
54− ${qmlscene_exe} ${CMAKE_CURRENT_SOURCE_DIR}/${qmltest_FILE}.qml
54+ ${qmlscene_exe} -qmljsdebugger=port:3768 ${CMAKE_CURRENT_SOURCE_DIR}/${qmltest_FILE}.qml
55 ${qmlscene_imports}
55 ${qmlscene_imports}
56 )
56 )
57 add_custom_target(${qmlscene_TARGET} ${qmlscene_command})
57 add_custom_target(${qmlscene_TARGET} ${qmlscene_command})
@@ -111,9 +111,9 @@ macro(add_qml_test_internal SUBPATH COMPONENT_NAME ITERATIONS)
111 -o -,txt
111 -o -,txt
112 ${function_ARGS}
112 ${function_ARGS}
113 )
113 )
114− find_program( HAVE_GCC gcc )
114+ find_program(DPKG dpkg-architecture)
115− if (NOT ${HAVE_GCC} STREQUAL "")
115+ if(DPKG)
116− exec_program( gcc ARGS "-dumpmachine" OUTPUT_VARIABLE ARCH_TRIPLET )
116+ exec_program(${DPKG} ARGS "-qDEB_BUILD_MULTIARCH" OUTPUT_VARIABLE ARCH_TRIPLET )
117 set(LD_PRELOAD_PATH "LD_PRELOAD=/usr/lib/${ARCH_TRIPLET}/mesa/libGL.so.1")
117 set(LD_PRELOAD_PATH "LD_PRELOAD=/usr/lib/${ARCH_TRIPLET}/mesa/libGL.so.1")
118 endif()
118 endif()
119 set(qmltest_xvfb_command
119 set(qmltest_xvfb_command
debian/changelog+41
@@ -4,6 +4,47 @@ unity8 (7.87+14.10.20140505-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.86+14.10.20140527-0ubuntu1) utopic; urgency=low
8+
9+ [ Andrea Cimitan ]
10+ * Passes to make tryCommand -qmljsdebugger=port:3768 to enable
11+ debug/profiling test apps
12+ * Fixes carousel shadow
13+
14+ [ Michał Sawicz ]
15+ * Use dpkg-architecture, not gcc, to determine the machine triplet.
16+
17+ [ Ying-Chun Liu ]
18+ * Fix ZoomableImage test failure. (LP: #1317254)
19+
20+ [ Albert Astals ]
21+ * We don't need iconutils in this mock
22+ * Don't reserve space for mascot if no mascot is specified (LP:
23+ #1319343)
24+ * CardHeader is no more, remove stale line in CMakeLists.txt
25+ * GenericScopeViewTest: Wait a bit more Otherwise sometimes we end
26+ getting up the wrong delegate (maybe one that will be garbage
27+ collected?) (LP: #1322279)
28+ * Fix crash in organicgridtest
29+
30+ [ Daniel d'Andrada ]
31+ * Remove Shell's underlay background image as it cannot be seen
32+ anymore Now that the Dash has its own, opaque, background, the
33+ underlay's background image can no longer be seen. So it's just a
34+ waste of resources to have it.
35+
36+ [ Michael Terry ]
37+ * Use the same animation when dismissing a greeter slide from the
38+ launcher as from a normal greeter drag. (LP: #1316513)
39+
40+ [ Michael Zanetti ]
41+ * enhance lockscreen add a retry indication label (e.g. 3 attempts
42+ left). add an additional label (e.g. phone number for multi sim).
43+ add a infoPopup (e.g. to display a warning for last retry). add min
44+ and max limit values. add tests for the above (LP: #1302050)
45+
46+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Tue, 27 May 2014 07:47:11 +0000
47+
7unity8 (7.86+14.10.20140522-0ubuntu1) utopic; urgency=low
48unity8 (7.86+14.10.20140522-0ubuntu1) utopic; urgency=low
8
49
9 [ Albert Astals ]
50 [ Albert Astals ]
plugins/Dash/CardCreator.js+3−3
@@ -70,10 +70,9 @@ var kArtShapeHolderCode = 'Item { \n\
70 radius: "medium"; \n\
70 radius: "medium"; \n\
71 readonly property real aspect: components !== undefined ? components["art"]["aspect-ratio"] : 1; \n\
71 readonly property real aspect: components !== undefined ? components["art"]["aspect-ratio"] : 1; \n\
72 readonly property bool aspectSmallerThanImageAspect: aspect < image.aspect; \n\
72 readonly property bool aspectSmallerThanImageAspect: aspect < image.aspect; \n\
73− Component.onCompleted: updateWidthHeightBindings(); \n\
73+ Component.onCompleted: { updateWidthHeightBindings(); if (artShapeBorderSource !== undefined) borderSource = artShapeBorderSource; } \n\
74 onAspectSmallerThanImageAspectChanged: updateWidthHeightBindings(); \n\
74 onAspectSmallerThanImageAspectChanged: updateWidthHeightBindings(); \n\
75 visible: image.status == Image.Ready; \n\
75 visible: image.status == Image.Ready; \n\
76− borderSource: artShapeBorderSource; \n\
77 function updateWidthHeightBindings() { \n\
76 function updateWidthHeightBindings() { \n\
78 if (aspectSmallerThanImageAspect) { \n\
77 if (aspectSmallerThanImageAspect) { \n\
79 width = Qt.binding(function() { return !visible ? 0 : image.width }); \n\
78 width = Qt.binding(function() { return !visible ? 0 : image.width }); \n\
@@ -281,7 +280,7 @@ function cardString(template, components) {
281 property var template; \n\
280 property var template; \n\
282 property var components; \n\
281 property var components; \n\
283 property var cardData; \n\
282 property var cardData; \n\
284− property var artShapeBorderSource; \n\
283+ property var artShapeBorderSource: undefined; \n\
285 property real fontScale: 1.0; \n\
284 property real fontScale: 1.0; \n\
286 property int headerAlignment: Text.AlignLeft; \n\
285 property int headerAlignment: Text.AlignLeft; \n\
287 property int fixedHeaderHeight: -1; \n\
286 property int fixedHeaderHeight: -1; \n\
@@ -307,6 +306,7 @@ function cardString(template, components) {
307 }
306 }
308
307
309 if (hasArt) {
308 if (hasArt) {
309+ code += 'onArtShapeBorderSourceChanged: { if (artShapeBorderSource !== undefined && artShapeLoader.item) artShapeLoader.item.borderSource = artShapeBorderSource; } \n';
310 code += 'readonly property size artShapeSize: artShapeLoader.item ? Qt.size(artShapeLoader.item.width, artShapeLoader.item.height) : Qt.size(-1, -1);\n';
310 code += 'readonly property size artShapeSize: artShapeLoader.item ? Qt.size(artShapeLoader.item.width, artShapeLoader.item.height) : Qt.size(-1, -1);\n';
311
311
312 var widthCode, heightCode;
312 var widthCode, heightCode;
plugins/Dash/abstractdashview.cpp+3
@@ -176,6 +176,9 @@ void AbstractDashView::refill()
176
176
177bool AbstractDashView::addVisibleItems(qreal fillFromY, qreal fillToY, bool asynchronous)
177bool AbstractDashView::addVisibleItems(qreal fillFromY, qreal fillToY, bool asynchronous)
178{
178{
179+ if (fillToY <= fillFromY)
180+ return false;
181+
179 if (!delegate())
182 if (!delegate())
180 return false;
183 return false;
181
184
po/de.po+5−3
@@ -8,13 +8,13 @@ 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-04-10 11:13-0400\n"
10"POT-Creation-Date: 2014-04-10 11:13-0400\n"
11−"PO-Revision-Date: 2014-05-20 13:45+0000\n"
11+"PO-Revision-Date: 2014-05-27 14:09+0000\n"
12−"Last-Translator: Tobias Bannert <Unknown>\n"
12+"Last-Translator: Phillip Sz <Unknown>\n"
13"Language-Team: German <de@li.org>\n"
13"Language-Team: German <de@li.org>\n"
14"MIME-Version: 1.0\n"
14"MIME-Version: 1.0\n"
15"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17−"X-Launchpad-Export-Date: 2014-05-22 06:49+0000\n"
17+"X-Launchpad-Export-Date: 2014-05-28 05:54+0000\n"
18"X-Generator: Launchpad (build 17017)\n"
18"X-Generator: Launchpad (build 17017)\n"
19
19
20#: plugins/Unity/Launcher/launcheritem.cpp:43
20#: plugins/Unity/Launcher/launcheritem.cpp:43
@@ -73,6 +73,8 @@ msgid ""
73"You have now mastered the edge gestures and can start using the "
73"You have now mastered the edge gestures and can start using the "
74"phone<br><br>Tap on the screen to start"
74"phone<br><br>Tap on the screen to start"
75msgstr ""
75msgstr ""
76+"Sie haben nun die Kantengesten erfolgreich erlernt und können das Telefon "
77+"nun nutzen<br><br>Zum Starten auf den Bildschirm tippen"
76
78
77#: qml/Components/PageHeader.qml:365
79#: qml/Components/PageHeader.qml:365
78msgid "Recent searches"
80msgid "Recent searches"
po/it.po+12−12
@@ -8,14 +8,14 @@ msgstr ""
8"Project-Id-Version: unity\n"
8"Project-Id-Version: unity\n"
9"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
9"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10"POT-Creation-Date: 2014-04-10 11:13-0400\n"
10"POT-Creation-Date: 2014-04-10 11:13-0400\n"
11−"PO-Revision-Date: 2014-01-22 09:15+0000\n"
11+"PO-Revision-Date: 2014-05-23 11:52+0000\n"
12−"Last-Translator: Domenico <domenico.verde125@live.it>\n"
12+"Last-Translator: Gio <gio.scino@gmail.com>\n"
13"Language-Team: Italian <it@li.org>\n"
13"Language-Team: Italian <it@li.org>\n"
14"MIME-Version: 1.0\n"
14"MIME-Version: 1.0\n"
15"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17−"X-Launchpad-Export-Date: 2014-05-01 06:43+0000\n"
17+"X-Launchpad-Export-Date: 2014-05-24 06:52+0000\n"
18−"X-Generator: Launchpad (build 16985)\n"
18+"X-Generator: Launchpad (build 17017)\n"
19
19
20#: plugins/Unity/Launcher/launcheritem.cpp:43
20#: plugins/Unity/Launcher/launcheritem.cpp:43
21#: plugins/Unity/Launcher/launcheritem.cpp:73
21#: plugins/Unity/Launcher/launcheritem.cpp:73
@@ -83,28 +83,28 @@ msgstr "Ricerche recenti"
83
83
84#: qml/Components/SeeMore.qml:35
84#: qml/Components/SeeMore.qml:35
85msgid "See more"
85msgid "See more"
86−msgstr ""
86+msgstr "Mostra di più"
87
87
88#: qml/Components/SeeMore.qml:58
88#: qml/Components/SeeMore.qml:58
89msgid "See less"
89msgid "See less"
90−msgstr ""
90+msgstr "Mostra meno"
91
91
92#: qml/Dash/DashApps.qml:37
92#: qml/Dash/DashApps.qml:37
93msgid "Recent"
93msgid "Recent"
94−msgstr ""
94+msgstr "Recenti"
95
95
96#: qml/Dash/PreviewListView.qml:52
96#: qml/Dash/PreviewListView.qml:52
97#, qt-format
97#, qt-format
98msgid "%1 Preview"
98msgid "%1 Preview"
99−msgstr ""
99+msgstr "Anteprime: %1"
100
100
101#: qml/Dash/Previews/PreviewActionCombo.qml:34
101#: qml/Dash/Previews/PreviewActionCombo.qml:34
102msgid "More..."
102msgid "More..."
103−msgstr ""
103+msgstr "Altro..."
104
104
105#: qml/Dash/Previews/PreviewActionCombo.qml:34
105#: qml/Dash/Previews/PreviewActionCombo.qml:34
106msgid "Less..."
106msgid "Less..."
107−msgstr ""
107+msgstr "Meno..."
108
108
109#: qml/Dash/Previews/PreviewRatingInput.qml:81
109#: qml/Dash/Previews/PreviewRatingInput.qml:81
110msgid "Rate this"
110msgid "Rate this"
@@ -120,7 +120,7 @@ msgstr "Invia"
120
120
121#: qml/Greeter/Greeter.qml:151
121#: qml/Greeter/Greeter.qml:151
122msgid "Swipe to unlock"
122msgid "Swipe to unlock"
123−msgstr ""
123+msgstr "Scorrere per sbloccare"
124
124
125#: qml/Greeter/Lockscreen.qml:149
125#: qml/Greeter/Lockscreen.qml:149
126msgid "Emergency Call"
126msgid "Emergency Call"
@@ -161,7 +161,7 @@ msgstr "Mostra password"
161
161
162#: qml/Notifications/NotificationMenuItemFactory.qml:103
162#: qml/Notifications/NotificationMenuItemFactory.qml:103
163msgid "Please enter SIM PIN"
163msgid "Please enter SIM PIN"
164−msgstr ""
164+msgstr "Inserire il codice PIN"
165
165
166#: qml/Panel/SearchIndicator.qml:27
166#: qml/Panel/SearchIndicator.qml:27
167msgid "Search"
167msgid "Search"
po/pl.po+14−12
@@ -8,14 +8,14 @@ msgstr ""
8"Project-Id-Version: unity\n"
8"Project-Id-Version: unity\n"
9"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
9"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10"POT-Creation-Date: 2014-04-10 11:13-0400\n"
10"POT-Creation-Date: 2014-04-10 11:13-0400\n"
11−"PO-Revision-Date: 2014-01-10 11:38+0000\n"
11+"PO-Revision-Date: 2014-05-27 15:20+0000\n"
12−"Last-Translator: Michał Sawicz <michal.sawicz@canonical.com>\n"
12+"Last-Translator: GTriderXC <gtriderxc@yahoo.com>\n"
13"Language-Team: Polish <pl@li.org>\n"
13"Language-Team: Polish <pl@li.org>\n"
14"MIME-Version: 1.0\n"
14"MIME-Version: 1.0\n"
15"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17−"X-Launchpad-Export-Date: 2014-05-01 06:44+0000\n"
17+"X-Launchpad-Export-Date: 2014-05-28 05:54+0000\n"
18−"X-Generator: Launchpad (build 16985)\n"
18+"X-Generator: Launchpad (build 17017)\n"
19
19
20#: plugins/Unity/Launcher/launcheritem.cpp:43
20#: plugins/Unity/Launcher/launcheritem.cpp:43
21#: plugins/Unity/Launcher/launcheritem.cpp:73
21#: plugins/Unity/Launcher/launcheritem.cpp:73
@@ -73,6 +73,8 @@ msgid ""
73"You have now mastered the edge gestures and can start using the "
73"You have now mastered the edge gestures and can start using the "
74"phone<br><br>Tap on the screen to start"
74"phone<br><br>Tap on the screen to start"
75msgstr ""
75msgstr ""
76+"Wydawanie poleceń krawędzi zostało opanowane. Urządzenie gotowe do "
77+"pracy.<br><br>Dotknij ekranu by rozpocząć"
76
78
77#: qml/Components/PageHeader.qml:365
79#: qml/Components/PageHeader.qml:365
78msgid "Recent searches"
80msgid "Recent searches"
@@ -80,28 +82,28 @@ msgstr "Ostatnie wyszukiwania"
80
82
81#: qml/Components/SeeMore.qml:35
83#: qml/Components/SeeMore.qml:35
82msgid "See more"
84msgid "See more"
83−msgstr ""
85+msgstr "Zobacz więcej"
84
86
85#: qml/Components/SeeMore.qml:58
87#: qml/Components/SeeMore.qml:58
86msgid "See less"
88msgid "See less"
87−msgstr ""
89+msgstr "Zobacz mniej"
88
90
89#: qml/Dash/DashApps.qml:37
91#: qml/Dash/DashApps.qml:37
90msgid "Recent"
92msgid "Recent"
91−msgstr ""
93+msgstr "Ostatnio używane"
92
94
93#: qml/Dash/PreviewListView.qml:52
95#: qml/Dash/PreviewListView.qml:52
94#, qt-format
96#, qt-format
95msgid "%1 Preview"
97msgid "%1 Preview"
96−msgstr ""
98+msgstr "%1 Podgląd"
97
99
98#: qml/Dash/Previews/PreviewActionCombo.qml:34
100#: qml/Dash/Previews/PreviewActionCombo.qml:34
99msgid "More..."
101msgid "More..."
100−msgstr ""
102+msgstr "Więcej..."
101
103
102#: qml/Dash/Previews/PreviewActionCombo.qml:34
104#: qml/Dash/Previews/PreviewActionCombo.qml:34
103msgid "Less..."
105msgid "Less..."
104−msgstr ""
106+msgstr "Mniej..."
105
107
106#: qml/Dash/Previews/PreviewRatingInput.qml:81
108#: qml/Dash/Previews/PreviewRatingInput.qml:81
107msgid "Rate this"
109msgid "Rate this"
@@ -117,7 +119,7 @@ msgstr "Wyślij"
117
119
118#: qml/Greeter/Greeter.qml:151
120#: qml/Greeter/Greeter.qml:151
119msgid "Swipe to unlock"
121msgid "Swipe to unlock"
120−msgstr ""
122+msgstr "Przeciągnij aby odblokować"
121
123
122#: qml/Greeter/Lockscreen.qml:149
124#: qml/Greeter/Lockscreen.qml:149
123msgid "Emergency Call"
125msgid "Emergency Call"
@@ -158,7 +160,7 @@ msgstr "Wyświetl hasło"
158
160
159#: qml/Notifications/NotificationMenuItemFactory.qml:103
161#: qml/Notifications/NotificationMenuItemFactory.qml:103
160msgid "Please enter SIM PIN"
162msgid "Please enter SIM PIN"
161−msgstr ""
163+msgstr "Wprowadź kod PIN karty SIM"
162
164
163#: qml/Panel/SearchIndicator.qml:27
165#: qml/Panel/SearchIndicator.qml:27
164msgid "Search"
166msgid "Search"
qml/Components/Lockscreen.qml+91−6
@@ -15,7 +15,8 @@
15 */
15 */
16
16
17import QtQuick 2.0
17import QtQuick 2.0
18−import Ubuntu.Components 0.1
18+import Ubuntu.Components 1.0
19+import Ubuntu.Components.Popups 1.0
19
20
20Showable {
21Showable {
21 id: root
22 id: root
@@ -25,17 +26,32 @@ Showable {
25
26
26 // Placeholder text
27 // Placeholder text
27 property string placeholderText: ""
28 property string placeholderText: ""
29+ // Placeholder text while shaking (e.g. Incorrect passprase)
30+ property string wrongPlaceholderText: ""
31+ // Retries text (e.g. 3 retries left)
32+ property string retryText: ""
33+
34+ // Informational text. (e.g. some text to tell which domain this is pin is entered for.
35+ property string infoText: ""
28
36
29 // In case the Lockscreen can show a greeter message, this is the username
37 // In case the Lockscreen can show a greeter message, this is the username
30 property string username: ""
38 property string username: ""
31
39
32− // Set this to a value greater 0 to enable auto-confirm behavior for the lockscreen.
40+ // Set those to a value greater 0 to restrict the pin length.
41+ // If both are unset, the Lockscreen will show a confirm button and allow typing any length of pin before
42+ // confirming. If minPinLength is set to a value > 0, the confirm button will only become active when the
43+ // entered pin is at least that long. If maxPinLength is set, the lockscreen won't allow entering any
44+ // more numbers than that. If both are set to the same value, the lockscreen will enter auto confirming
45+ // behavior, hiding the confirmation button and triggering that automatically when the entered pin reached
33− // This is ignored by the alphaNumeric lockscreen as that one is confirmed with pressing enter on the OSK.
46+ // that length. This is ignored by the alphaNumeric lockscreen as that one is always confirmed by pressing
47+ // enter on the OSK.
34− property int pinLength: -1
48+ property int minPinLength: -1
49+ property int maxPinLength: -1
35
50
36 signal entered(string passphrase)
51 signal entered(string passphrase)
37 signal cancel()
52 signal cancel()
38 signal emergencyCall()
53 signal emergencyCall()
54+ signal infoPopupConfirmed()
39
55
40 onRequiredChanged: {
56 onRequiredChanged: {
41 if (required && pinPadLoader.item) {
57 if (required && pinPadLoader.item) {
@@ -53,10 +69,51 @@ Showable {
53 pinPadLoader.item.clear(showAnimation);
69 pinPadLoader.item.clear(showAnimation);
54 }
70 }
55
71
72+ function showInfoPopup(title, text) {
73+ PopupUtils.open(infoPopupComponent, root, {title: title, text: text})
74+ }
75+
56 MouseArea {
76 MouseArea {
57 anchors.fill: root
77 anchors.fill: root
58 }
78 }
59
79
80+ Column {
81+ spacing: units.gu(2)
82+ anchors {
83+ left: parent.left
84+ right: parent.right
85+ bottom: pinPadLoader.top
86+ bottomMargin: units.gu(2)
87+ }
88+ Label {
89+ objectName: "retryCountLabel"
90+ anchors {
91+ left: parent.left
92+ right: parent.right
93+ }
94+ text: root.retryText
95+ horizontalAlignment: Text.AlignHCenter
96+ color: "#f3f3e7"
97+ opacity: 0.6
98+ visible: root.retryText.length > 0
99+ }
100+ Label {
101+ id: infoTextLabel
102+ objectName: "infoTextLabel"
103+ anchors {
104+ left: parent.left
105+ right: parent.right
106+ }
107+ text: root.infoText
108+ horizontalAlignment: Text.AlignHCenter
109+ color: "#f3f3e7"
110+ opacity: 0.6
111+ visible: root.infoText.length > 0
112+ }
113+ }
114+
115+
116+
60 Loader {
117 Loader {
61 id: pinPadLoader
118 id: pinPadLoader
62 objectName: "pinPadLoader"
119 objectName: "pinPadLoader"
@@ -84,14 +141,24 @@ Showable {
84
141
85 Binding {
142 Binding {
86 target: pinPadLoader.item
143 target: pinPadLoader.item
87− property: "pinLength"
144+ property: "minPinLength"
145+ value: root.minPinLength
146+ }
147+ Binding {
148+ target: pinPadLoader.item
149+ property: "maxPinLength"
88− value: root.pinLength
150+ value: root.maxPinLength
89 }
151 }
90 Binding {
152 Binding {
91 target: pinPadLoader.item
153 target: pinPadLoader.item
92 property: "placeholderText"
154 property: "placeholderText"
93 value: root.placeholderText
155 value: root.placeholderText
94 }
156 }
157+ Binding {
158+ target: pinPadLoader.item
159+ property: "wrongPlaceholderText"
160+ value: root.wrongPlaceholderText
161+ }
95 Binding {
162 Binding {
96 target: pinPadLoader.item
163 target: pinPadLoader.item
97 property: "username"
164 property: "username"
@@ -132,4 +199,22 @@ Showable {
132 anchors.horizontalCenter: parent.horizontalCenter
199 anchors.horizontalCenter: parent.horizontalCenter
133 }
200 }
134 }
201 }
202+
203+ Component {
204+ id: infoPopupComponent
205+ Dialog {
206+ id: dialog
207+ objectName: "infoPopup"
208+ modal: true
209+
210+ Button {
211+ objectName: "infoPopupOkButton"
212+ text: i18n.tr("OK")
213+ onClicked: {
214+ PopupUtils.close(dialog)
215+ root.infoPopupConfirmed();
216+ }
217+ }
218+ }
219+ }
135}
220}
qml/Components/PassphraseLockscreen.qml+6−2
@@ -22,7 +22,8 @@ Item {
22 id: root
22 id: root
23 height: highlightItem.height
23 height: highlightItem.height
24
24
25− property alias placeholderText: pinentryField.placeholderText
25+ property string placeholderText
26+ property string wrongPlaceholderText
26 property string username: ""
27 property string username: ""
27
28
28 signal entered(string passphrase)
29 signal entered(string passphrase)
@@ -73,9 +74,12 @@ Item {
73 echoMode: TextInput.Password
74 echoMode: TextInput.Password
74 opacity: 0.9
75 opacity: 0.9
75 hasClearButton: false
76 hasClearButton: false
77+ placeholderText: wrongPasswordAnimation.running ? root.wrongPlaceholderText : root.placeholderText
76
78
77 onAccepted: {
79 onAccepted: {
80+ if (pinentryField.text) {
78− root.entered(pinentryField.text);
81+ root.entered(pinentryField.text);
82+ }
79 }
83 }
80 }
84 }
81 }
85 }
qml/Components/PinLockscreen.qml+29−11
@@ -25,9 +25,11 @@ Column {
25 spacing: units.gu(3.5)
25 spacing: units.gu(3.5)
26
26
27 property alias placeholderText: pinentryField.placeholderText
27 property alias placeholderText: pinentryField.placeholderText
28+ property alias wrongPlaceholderText: pinentryField.wrongPlaceholderText
28 property int padWidth: units.gu(34)
29 property int padWidth: units.gu(34)
29 property int padHeight: units.gu(28)
30 property int padHeight: units.gu(28)
30− property int pinLength: -1
31+ property int minPinLength: -1
32+ property int maxPinLength: -1
31
33
32 signal entered(string passphrase)
34 signal entered(string passphrase)
33 signal cancel()
35 signal cancel()
@@ -41,6 +43,10 @@ Column {
41 }
43 }
42 }
44 }
43
45
46+ QtObject {
47+ id: priv
48+ property bool autoConfirm: root.minPinLength == root.maxPinLength && root.minPinLength != -1
49+ }
44
50
45 UbuntuShape {
51 UbuntuShape {
46 id: pinentryField
52 id: pinentryField
@@ -52,12 +58,20 @@ Column {
52 radius: "medium"
58 radius: "medium"
53 property string text: ""
59 property string text: ""
54 property string placeholderText: ""
60 property string placeholderText: ""
61+ property string wrongPlaceholderText: ""
62+
63+ function appendChar(character) {
64+ if (root.maxPinLength == -1 || pinentryField.text.length < root.maxPinLength) {
65+ pinentryField.text = pinentryField.text + character;
66+ }
67+ }
68+
55 onTextChanged: {
69 onTextChanged: {
56 pinentryFieldLabel.text = "";
70 pinentryFieldLabel.text = "";
57 for (var i = 0; i < text.length; ++i) {
71 for (var i = 0; i < text.length; ++i) {
58 pinentryFieldLabel.text += "•";
72 pinentryFieldLabel.text += "•";
59 }
73 }
60− if (text.length === root.pinLength) {
74+ if (priv.autoConfirm && text.length === root.maxPinLength) {
61 root.entered(text);
75 root.entered(text);
62 }
76 }
63 }
77 }
@@ -74,9 +88,11 @@ Column {
74 }
88 }
75 Label {
89 Label {
76 id: pinentryFieldPlaceHolder
90 id: pinentryFieldPlaceHolder
91+ objectName: "pinentryFieldPlaceHolder"
77 anchors.centerIn: parent
92 anchors.centerIn: parent
78− color: "grey"
93+ color: "#f3f3e7"
94+ opacity: 0.6
79− text: parent.placeholderText
95+ text: wrongPasswordAnimation.running ? parent.wrongPlaceholderText : parent.placeholderText
80 visible: pinentryFieldLabel.text.length == 0
96 visible: pinentryFieldLabel.text.length == 0
81 }
97 }
82
98
@@ -91,9 +107,11 @@ Column {
91 bottom: parent.bottom
107 bottom: parent.bottom
92 bottomMargin: units.gu(1)
108 bottomMargin: units.gu(1)
93 }
109 }
94− visible: root.pinLength == -1
110+ visible: !priv.autoConfirm
95 width: height
111 width: height
96 name: "erase"
112 name: "erase"
113+ color: "#f3f3e7"
114+ opacity: 0.6
97 MouseArea {
115 MouseArea {
98 anchors.fill: parent
116 anchors.fill: parent
99 onClicked: pinentryField.text = pinentryField.text.substring(0, pinentryField.text.length-1);
117 onClicked: pinentryField.text = pinentryField.text.substring(0, pinentryField.text.length-1);
@@ -168,7 +186,7 @@ Column {
168 enabled: entryEnabled
186 enabled: entryEnabled
169
187
170 onClicked: {
188 onClicked: {
171− pinentryField.text = pinentryField.text + text;
189+ pinentryField.appendChar(text);
172 }
190 }
173 }
191 }
174 }
192 }
@@ -186,7 +204,7 @@ Column {
186 width: root.padWidth / 3
204 width: root.padWidth / 3
187 height: root.padHeight / 4
205 height: root.padHeight / 4
188 text: "0"
206 text: "0"
189− onClicked: pinentryField.text = pinentryField.text + text
207+ onClicked: pinentryField.appendChar(text);
190 enabled: entryEnabled
208 enabled: entryEnabled
191 }
209 }
192
210
@@ -194,16 +212,16 @@ Column {
194 objectName: "pinPadButtonErase"
212 objectName: "pinPadButtonErase"
195 width: root.padWidth / 3
213 width: root.padWidth / 3
196 height: root.padHeight / 4
214 height: root.padHeight / 4
197− iconName: root.pinLength == -1 ? "" : "erase"
215+ iconName: priv.autoConfirm ? "erase" : ""
198− subText: root.pinLength == -1 ? "DONE" : ""
216+ subText: priv.autoConfirm ? "" : "DONE"
199 onClicked: {
217 onClicked: {
200− if (root.pinLength !== -1) {
218+ if (priv.autoConfirm) {
201 pinentryField.text = pinentryField.text.substring(0, pinentryField.text.length-1);
219 pinentryField.text = pinentryField.text.substring(0, pinentryField.text.length-1);
202 } else {
220 } else {
203 root.entered(pinentryField.text);
221 root.entered(pinentryField.text);
204 }
222 }
205 }
223 }
206− enabled: entryEnabled
224+ enabled: priv.autoConfirm ? entryEnabled : pinentryField.text.length >= root.minPinLength
207 }
225 }
208 }
226 }
209 }
227 }
qml/Components/PinPadButton.qml+2−1
@@ -19,6 +19,7 @@ import Ubuntu.Components 0.1
19
19
20Item {
20Item {
21 id: root
21 id: root
22+ opacity: enabled ? 1 : 0.6
22
23
23 property alias text: label.text
24 property alias text: label.text
24 property alias subText: subTextLabel.text
25 property alias subText: subTextLabel.text
@@ -62,7 +63,7 @@ Item {
62 Label {
63 Label {
63 id: subTextLabel
64 id: subTextLabel
64 fontSize: "small"
65 fontSize: "small"
65− color: "grey"
66+ color: "#f3f3e7"
66 anchors.horizontalCenter: parent.horizontalCenter
67 anchors.horizontalCenter: parent.horizontalCenter
67 visible: text.length > 0
68 visible: text.length > 0
68 }
69 }
qml/Dash/CardCarousel.qml+1−1
@@ -34,7 +34,7 @@ DashRenderer {
34 Carousel {
34 Carousel {
35 id: carousel
35 id: carousel
36 anchors.fill: parent
36 anchors.fill: parent
37− tileAspectRatio: cardCarousel.components && cardCarousel.components["art"]["aspect-ratio"] || 1.0
37+ tileAspectRatio: cardTool.components && cardTool.components["art"]["aspect-ratio"] || 1.0
38 // FIXME we need to "reverse" the carousel to make the selected item the size
38 // FIXME we need to "reverse" the carousel to make the selected item the size
39 // and push others back.
39 // and push others back.
40 minimumTileWidth: cardTool.cardWidth / selectedItemScaleFactor
40 minimumTileWidth: cardTool.cardWidth / selectedItemScaleFactor
qml/Dash/GenericScopeView.qml+1−1
@@ -128,7 +128,7 @@ FocusScope {
128
128
129 CardTool {
129 CardTool {
130 id: cardTool
130 id: cardTool
131−
131+ objectName: "cardTool"
132 count: results.count
132 count: results.count
133 template: model.renderer
133 template: model.renderer
134 components: model.components
134 components: model.components
qml/Dash/Previews/PreviewHeader.qml+3
@@ -56,6 +56,9 @@ PreviewWidget {
56
56
57 Loader {
57 Loader {
58 id: mascotShapeLoader
58 id: mascotShapeLoader
59+ objectName: "mascotShapeLoader"
60+ active: headerRoot.mascot != ""
61+ visible: active
59
62
60 anchors.verticalCenter: parent.verticalCenter
63 anchors.verticalCenter: parent.verticalCenter
61 // TODO karni: Icon aspect-ratio is 8:7.5. Revisit these values to avoid fraction of pixels.
64 // TODO karni: Icon aspect-ratio is 8:7.5. Revisit these values to avoid fraction of pixels.
qml/GreeterShell.qml+8−2
@@ -58,7 +58,8 @@ BasicShell {
58 x: required ? 0 : - width
58 x: required ? 0 : - width
59 width: parent.width
59 width: parent.width
60 height: parent.height - panel.panelHeight
60 height: parent.height - panel.panelHeight
61− pinLength: 4
61+ minPinLength: 4
62+ maxPinLength: 4
62
63
63 onEntered: LightDM.Greeter.respond(passphrase);
64 onEntered: LightDM.Greeter.respond(passphrase);
64 onCancel: greeter.show()
65 onCancel: greeter.show()
@@ -116,7 +117,10 @@ BasicShell {
116 width: parent.width
117 width: parent.width
117 height: parent.height
118 height: parent.height
118
119
119− Behavior on x {SmoothedAnimation{velocity: 600}}
120+ Behavior on x {
121+ enabled: !launcher.dashSwipe
122+ StandardAnimation {}
123+ }
120
124
121 readonly property real showProgress: MathUtils.clamp((1 - x/width) + greeter.showProgress - 1, 0, 1)
125 readonly property real showProgress: MathUtils.clamp((1 - x/width) + greeter.showProgress - 1, 0, 1)
122 onShowProgressChanged: if (LightDM.Greeter.promptless && showProgress === 0) greeter.login()
126 onShowProgressChanged: if (LightDM.Greeter.promptless && showProgress === 0) greeter.login()
@@ -189,6 +193,8 @@ BasicShell {
189 Launcher {
193 Launcher {
190 id: launcher
194 id: launcher
191
195
196+ readonly property bool dashSwipe: progress > 0
197+
192 anchors.top: parent.top
198 anchors.top: parent.top
193 anchors.bottom: parent.bottom
199 anchors.bottom: parent.bottom
194 width: parent.width
200 width: parent.width
qml/Shell.qml−9
@@ -98,15 +98,6 @@ BasicShell {
98 // through the translucent parts of the shell surface.
98 // through the translucent parts of the shell surface.
99 visible: !fullyCovered && !applicationSurfaceShouldBeSeen
99 visible: !fullyCovered && !applicationSurfaceShouldBeSeen
100
100
101− CrossFadeImage {
102− id: backgroundImage
103− objectName: "backgroundImage"
104−
105− anchors.fill: parent
106− source: shell.background
107− fillMode: Image.PreserveAspectCrop
108− }
109−
110 Rectangle {
101 Rectangle {
111 anchors.fill: parent
102 anchors.fill: parent
112 color: "black"
103 color: "black"
tests/autopilot/unity8/shell/emulators/main_window.py−4
@@ -114,10 +114,6 @@ class QQuickView(emulators.UnityEmulatorBase):
114 self.wait_select_single('Indicators', fullyOpened=True)
114 self.wait_select_single('Indicators', fullyOpened=True)
115 return self._get_indicator_page(indicator_name)
115 return self._get_indicator_page(indicator_name)
116
116
117− def get_shell_background(self):
118− return self.select_single(
119− "CrossFadeImage", objectName="backgroundImage")
120−
121 @autopilot_logging.log_action(logger.info)
117 @autopilot_logging.log_action(logger.info)
122 def show_dash_swiping(self):
118 def show_dash_swiping(self):
123 """Show the dash swiping from the left."""
119 """Show the dash swiping from the left."""
tests/mocks/Unity/CMakeLists.txt−1
@@ -19,7 +19,6 @@ include_directories(
19add_definitions(-DQT_NO_KEYWORDS)
19add_definitions(-DQT_NO_KEYWORDS)
20
20
21set(UnityQML_SOURCES
21set(UnityQML_SOURCES
22− iconutils.cpp
23 fake_scope.cpp
22 fake_scope.cpp
24 fake_scopes.cpp
23 fake_scopes.cpp
25 fake_categories.cpp
24 fake_categories.cpp
tests/mocks/Unity/fake_categories.cpp+5−1
@@ -152,7 +152,11 @@ Categories::data(const QModelIndex& index, int role) const
152 case RoleComponents:
152 case RoleComponents:
153 {
153 {
154 QVariantMap map, artMap;
154 QVariantMap map, artMap;
155+ if (index.row() % 2 != 0) {
155− artMap["aspect-ratio"] = "1.0";
156+ artMap["aspect-ratio"] = QString("1.%1").arg(index.row());
157+ } else {
158+ artMap["aspect-ratio"] = "1.0";
159+ }
156 artMap["field"] = "art";
160 artMap["field"] = "art";
157 map["art"] = artMap;
161 map["art"] = artMap;
158 map["title"] = "HOLA";
162 map["title"] = "HOLA";
tests/mocks/Unity/iconutils.cppdeleted−124
@@ -1,124 +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− * Authors:
17− * Michal Hruby <michal.hruby@canonical.com>
18− */
19−
20−#include "iconutils.h"
21−
22−#include <gio/gio.h>
23−
24−#include <QStringList>
25−#include <QUrl>
26−#include <QUrlQuery>
27−
28−#define BASE_THEME_ICON_URI "image://theme/"
29−#define BASE_THUMBNAILER_URI "image://thumbnailer/"
30−#define BASE_ALBUMART_URI "image://albumart/"
31−
32−QString gIconToDeclarativeImageProviderString(QString const &giconString)
33−{
34− if (giconString.isEmpty()) return giconString;
35−
36− if (giconString.startsWith('/') || giconString.startsWith(QLatin1String("http")) ||
37− giconString.startsWith(QLatin1String("file:")) || giconString.startsWith(QLatin1String("image:"))) {
38− return giconString;
39− }
40−
41− if (!giconString.startsWith(QLatin1String(". "))) {
42− // must be a themed icon
43− QString themedIcon(BASE_THEME_ICON_URI);
44− themedIcon.append(giconString);
45− return themedIcon;
46− }
47−
48− // special case annotated icon
49− if (giconString.startsWith(QLatin1String(". UnityProtocolAnnotatedIcon "))) {
50− QString annotatedIcon;
51− QString serializedData(QUrl::fromPercentEncoding(giconString.mid(29).toUtf8()));
52− GVariant *variant = g_variant_parse(G_VARIANT_TYPE_VARDICT, serializedData.toUtf8().constData(), NULL, NULL, NULL);
53− gchar *baseUri;
54− if (variant != NULL && g_variant_lookup(variant, "base-icon", "&s", &baseUri)) {
55− annotatedIcon = gIconToDeclarativeImageProviderString(QString(baseUri));
56− // FIXME: enclose in image://annotated/... once unity supports that
57− }
58− if (variant != NULL) g_variant_unref(variant);
59−
60− return annotatedIcon;
61− }
62−
63− // handle real gicon strings
64− QString result;
65− GError *error = NULL;
66− GIcon *icon = g_icon_new_for_string(giconString.toLocal8Bit().constData(), &error);
67− if (error != NULL || icon == NULL) {
68− qWarning("Unable to deserialize icon: %s", giconString.toLocal8Bit().constData());
69− g_clear_error(&error);
70− return result;
71− }
72−
73− if (G_IS_THEMED_ICON(icon)) {
74− QString themedIcon(BASE_THEME_ICON_URI);
75− QStringList list;
76− const char* const *iconNames = g_themed_icon_get_names(G_THEMED_ICON(icon));
77− if (iconNames != NULL) {
78− for (const char * const *iter = iconNames; *iter != NULL; ++iter) {
79− list << QLatin1String(*iter);
80− }
81− }
82− themedIcon.append(list.join(QString(",")));
83− result = themedIcon;
84− } else if (G_IS_FILE_ICON(icon)) {
85− GFile *file = g_file_icon_get_file(G_FILE_ICON(icon));
86− gchar *uri = g_file_get_uri(file);
87− QString iconUri(uri);
88− g_free(uri);
89− result = iconUri;
90− }
91−
92− g_object_unref(icon);
93−
94− return result;
95−}
96−
97−QString uriToThumbnailerProviderString(QString const &uri, QString const &mimetype, QVariantHash const &metadata)
98−{
99− if (uri.startsWith(QLatin1String("file:///"))) {
100− bool isAudio = mimetype.startsWith(QLatin1String("audio/"));
101− QString thumbnailerUri;
102− if (isAudio) {
103− thumbnailerUri = BASE_ALBUMART_URI;
104− if (metadata.contains("content")) {
105− QVariantHash contentHash = metadata["content"].toHash();
106− if (contentHash.contains("content")) { // nested content in Home?
107− contentHash = contentHash["content"].toHash();
108− }
109− if (contentHash.contains("album") && contentHash.contains("artist")) {
110− QUrlQuery query;
111− query.addQueryItem(QStringLiteral("artist"), contentHash["artist"].toString());
112− query.addQueryItem(QStringLiteral("album"), contentHash["album"].toString());
113− thumbnailerUri.append(query.toString());
114− }
115− }
116− } else {
117− thumbnailerUri = BASE_THUMBNAILER_URI;
118− thumbnailerUri.append(uri.midRef(7));
119− }
120− return thumbnailerUri;
121− }
122−
123− return QString::null;
124−}
tests/mocks/Unity/iconutils.hdeleted−29
@@ -1,29 +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− * Authors:
17− * Michal Hruby <michal.hruby@canonical.com>
18− */
19−
20−#ifndef ICONUTILS_H
21−#define ICONUTILS_H
22−
23−#include <QString>
24−#include <QVariant>
25−
26−QString gIconToDeclarativeImageProviderString(QString const &giconString);
27−QString uriToThumbnailerProviderString(QString const &uri, QString const &mimetype, QVariantHash const &metadata);
28−
29−#endif
tests/plugins/Dash/cardcreator/1.res+3−3
@@ -3,7 +3,7 @@ AbstractButton {
3 property var template;
3 property var template;
4 property var components;
4 property var components;
5 property var cardData;
5 property var cardData;
6− property var artShapeBorderSource;
6+ property var artShapeBorderSource: undefined;
7 property real fontScale: 1.0;
7 property real fontScale: 1.0;
8 property int headerAlignment: Text.AlignLeft;
8 property int headerAlignment: Text.AlignLeft;
9 property int fixedHeaderHeight: -1;
9 property int fixedHeaderHeight: -1;
@@ -12,6 +12,7 @@ AbstractButton {
12 property bool asynchronous: true;
12 property bool asynchronous: true;
13 property bool showHeader: true;
13 property bool showHeader: true;
14 implicitWidth: childrenRect.width;
14 implicitWidth: childrenRect.width;
15+onArtShapeBorderSourceChanged: { if (artShapeBorderSource !== undefined && artShapeLoader.item) artShapeLoader.item.borderSource = artShapeBorderSource; }
15readonly property size artShapeSize: artShapeLoader.item ? Qt.size(artShapeLoader.item.width, artShapeLoader.item.height) : Qt.size(-1, -1);
16readonly property size artShapeSize: artShapeLoader.item ? Qt.size(artShapeLoader.item.width, artShapeLoader.item.height) : Qt.size(-1, -1);
16Item {
17Item {
17 id: artShapeHolder;
18 id: artShapeHolder;
@@ -30,10 +31,9 @@ Item {
30 radius: "medium";
31 radius: "medium";
31 readonly property real aspect: components !== undefined ? components["art"]["aspect-ratio"] : 1;
32 readonly property real aspect: components !== undefined ? components["art"]["aspect-ratio"] : 1;
32 readonly property bool aspectSmallerThanImageAspect: aspect < image.aspect;
33 readonly property bool aspectSmallerThanImageAspect: aspect < image.aspect;
33− Component.onCompleted: updateWidthHeightBindings();
34+ Component.onCompleted: { updateWidthHeightBindings(); if (artShapeBorderSource !== undefined) borderSource = artShapeBorderSource; }
34 onAspectSmallerThanImageAspectChanged: updateWidthHeightBindings();
35 onAspectSmallerThanImageAspectChanged: updateWidthHeightBindings();
35 visible: image.status == Image.Ready;
36 visible: image.status == Image.Ready;
36− borderSource: artShapeBorderSource;
37 function updateWidthHeightBindings() {
37 function updateWidthHeightBindings() {
38 if (aspectSmallerThanImageAspect) {
38 if (aspectSmallerThanImageAspect) {
39 width = Qt.binding(function() { return !visible ? 0 : image.width });
39 width = Qt.binding(function() { return !visible ? 0 : image.width });
tests/plugins/Dash/cardcreator/2.res+1−1
@@ -3,7 +3,7 @@ AbstractButton {
3 property var template;
3 property var template;
4 property var components;
4 property var components;
5 property var cardData;
5 property var cardData;
6− property var artShapeBorderSource;
6+ property var artShapeBorderSource: undefined;
7 property real fontScale: 1.0;
7 property real fontScale: 1.0;
8 property int headerAlignment: Text.AlignLeft;
8 property int headerAlignment: Text.AlignLeft;
9 property int fixedHeaderHeight: -1;
9 property int fixedHeaderHeight: -1;
tests/plugins/Dash/cardcreator/3.res+3−3
@@ -3,7 +3,7 @@ AbstractButton {
3 property var template;
3 property var template;
4 property var components;
4 property var components;
5 property var cardData;
5 property var cardData;
6− property var artShapeBorderSource;
6+ property var artShapeBorderSource: undefined;
7 property real fontScale: 1.0;
7 property real fontScale: 1.0;
8 property int headerAlignment: Text.AlignLeft;
8 property int headerAlignment: Text.AlignLeft;
9 property int fixedHeaderHeight: -1;
9 property int fixedHeaderHeight: -1;
@@ -12,6 +12,7 @@ AbstractButton {
12 property bool asynchronous: true;
12 property bool asynchronous: true;
13 property bool showHeader: true;
13 property bool showHeader: true;
14 implicitWidth: childrenRect.width;
14 implicitWidth: childrenRect.width;
15+onArtShapeBorderSourceChanged: { if (artShapeBorderSource !== undefined && artShapeLoader.item) artShapeLoader.item.borderSource = artShapeBorderSource; }
15readonly property size artShapeSize: artShapeLoader.item ? Qt.size(artShapeLoader.item.width, artShapeLoader.item.height) : Qt.size(-1, -1);
16readonly property size artShapeSize: artShapeLoader.item ? Qt.size(artShapeLoader.item.width, artShapeLoader.item.height) : Qt.size(-1, -1);
16Item {
17Item {
17 id: artShapeHolder;
18 id: artShapeHolder;
@@ -30,10 +31,9 @@ Item {
30 radius: "medium";
31 radius: "medium";
31 readonly property real aspect: components !== undefined ? components["art"]["aspect-ratio"] : 1;
32 readonly property real aspect: components !== undefined ? components["art"]["aspect-ratio"] : 1;
32 readonly property bool aspectSmallerThanImageAspect: aspect < image.aspect;
33 readonly property bool aspectSmallerThanImageAspect: aspect < image.aspect;
33− Component.onCompleted: updateWidthHeightBindings();
34+ Component.onCompleted: { updateWidthHeightBindings(); if (artShapeBorderSource !== undefined) borderSource = artShapeBorderSource; }
34 onAspectSmallerThanImageAspectChanged: updateWidthHeightBindings();
35 onAspectSmallerThanImageAspectChanged: updateWidthHeightBindings();
35 visible: image.status == Image.Ready;
36 visible: image.status == Image.Ready;
36− borderSource: artShapeBorderSource;
37 function updateWidthHeightBindings() {
37 function updateWidthHeightBindings() {
38 if (aspectSmallerThanImageAspect) {
38 if (aspectSmallerThanImageAspect) {
39 width = Qt.binding(function() { return !visible ? 0 : image.width });
39 width = Qt.binding(function() { return !visible ? 0 : image.width });
tests/plugins/Dash/cardcreator/4.res+1−1
@@ -3,7 +3,7 @@ AbstractButton {
3 property var template;
3 property var template;
4 property var components;
4 property var components;
5 property var cardData;
5 property var cardData;
6− property var artShapeBorderSource;
6+ property var artShapeBorderSource: undefined;
7 property real fontScale: 1.0;
7 property real fontScale: 1.0;
8 property int headerAlignment: Text.AlignLeft;
8 property int headerAlignment: Text.AlignLeft;
9 property int fixedHeaderHeight: -1;
9 property int fixedHeaderHeight: -1;
tests/plugins/Dash/cardcreator/5.res+3−3
@@ -3,7 +3,7 @@ AbstractButton {
3 property var template;
3 property var template;
4 property var components;
4 property var components;
5 property var cardData;
5 property var cardData;
6− property var artShapeBorderSource;
6+ property var artShapeBorderSource: undefined;
7 property real fontScale: 1.0;
7 property real fontScale: 1.0;
8 property int headerAlignment: Text.AlignLeft;
8 property int headerAlignment: Text.AlignLeft;
9 property int fixedHeaderHeight: -1;
9 property int fixedHeaderHeight: -1;
@@ -12,6 +12,7 @@ AbstractButton {
12 property bool asynchronous: true;
12 property bool asynchronous: true;
13 property bool showHeader: true;
13 property bool showHeader: true;
14 implicitWidth: childrenRect.width;
14 implicitWidth: childrenRect.width;
15+onArtShapeBorderSourceChanged: { if (artShapeBorderSource !== undefined && artShapeLoader.item) artShapeLoader.item.borderSource = artShapeBorderSource; }
15readonly property size artShapeSize: artShapeLoader.item ? Qt.size(artShapeLoader.item.width, artShapeLoader.item.height) : Qt.size(-1, -1);
16readonly property size artShapeSize: artShapeLoader.item ? Qt.size(artShapeLoader.item.width, artShapeLoader.item.height) : Qt.size(-1, -1);
16Item {
17Item {
17 id: artShapeHolder;
18 id: artShapeHolder;
@@ -30,10 +31,9 @@ Item {
30 radius: "medium";
31 radius: "medium";
31 readonly property real aspect: components !== undefined ? components["art"]["aspect-ratio"] : 1;
32 readonly property real aspect: components !== undefined ? components["art"]["aspect-ratio"] : 1;
32 readonly property bool aspectSmallerThanImageAspect: aspect < image.aspect;
33 readonly property bool aspectSmallerThanImageAspect: aspect < image.aspect;
33− Component.onCompleted: updateWidthHeightBindings();
34+ Component.onCompleted: { updateWidthHeightBindings(); if (artShapeBorderSource !== undefined) borderSource = artShapeBorderSource; }
34 onAspectSmallerThanImageAspectChanged: updateWidthHeightBindings();
35 onAspectSmallerThanImageAspectChanged: updateWidthHeightBindings();
35 visible: image.status == Image.Ready;
36 visible: image.status == Image.Ready;
36− borderSource: artShapeBorderSource;
37 function updateWidthHeightBindings() {
37 function updateWidthHeightBindings() {
38 if (aspectSmallerThanImageAspect) {
38 if (aspectSmallerThanImageAspect) {
39 width = Qt.binding(function() { return !visible ? 0 : image.width });
39 width = Qt.binding(function() { return !visible ? 0 : image.width });
tests/plugins/Dash/organicgridtest.cpp+5
@@ -514,6 +514,11 @@ private Q_SLOTS:
514
514
515 model->setCount(21);
515 model->setCount(21);
516
516
517+ QTRY_COMPARE(grid->m_visibleItems.count(), 0);
518+
519+ grid->setDisplayMarginBeginning(0);
520+ grid->setDisplayMarginEnd(0);
521+
517 // This is exactly the same block as the first again
522 // This is exactly the same block as the first again
518 checkInitialPositions();
523 checkInitialPositions();
519 }
524 }
tests/qmltests/CMakeLists.txt−1
@@ -37,7 +37,6 @@ add_qml_test(Dash Dash)
37add_qml_test(Dash DashContent)
37add_qml_test(Dash DashContent)
38add_qml_test(Dash Card)
38add_qml_test(Dash Card)
39add_qml_benchmark(Dash CardBenchmark 1000)
39add_qml_benchmark(Dash CardBenchmark 1000)
40−add_qml_test(Dash CardHeader)
41add_qml_test(Dash CardTool)
40add_qml_test(Dash CardTool)
42add_qml_test(Dash GenericScopeView)
41add_qml_test(Dash GenericScopeView)
43add_qml_test(Dash/Apps RunningApplicationsGrid)
42add_qml_test(Dash/Apps RunningApplicationsGrid)
tests/qmltests/Components/tst_ZoomableImage.qml+21−19
@@ -98,22 +98,23 @@ Rectangle {
98 // move mouse to center
98 // move mouse to center
99 mouseMove(zoomableImage, zoomableImage.width / 2, zoomableImage.height / 2);
99 mouseMove(zoomableImage, zoomableImage.width / 2, zoomableImage.height / 2);
100
100
101+ var oldScale = image.scale;
101 // Test Zoom-in Zoom-out twice.
102 // Test Zoom-in Zoom-out twice.
102 for (var c=0; c<2; c++) {
103 for (var c=0; c<2; c++) {
103 // zoom in
104 // zoom in
104 for (var i=0; i<10; i++) {
105 for (var i=0; i<10; i++) {
105 mouseWheel(zoomableImage, zoomableImage.width / 2, zoomableImage.height / 2, 0, 10);
106 mouseWheel(zoomableImage, zoomableImage.width / 2, zoomableImage.height / 2, 0, 10);
106− tryCompare(image, "scale", 1.0 + (i + 1) * 0.1);
107+ tryCompare(image, "scale", oldScale + (i + 1) * 0.1);
107− compare(flickable.contentWidth, lazyImage.width * image.scale);
108+ compare(flickable.contentWidth, Math.max(lazyImage.width * image.scale, flickable.width));
108− compare(flickable.contentHeight, lazyImage.height * image.scale);
109+ compare(flickable.contentHeight, Math.max(lazyImage.height * image.scale, flickable.height));
109 }
110 }
110
111
111 // zoom out
112 // zoom out
112 for (var i=0; i<10; i++) {
113 for (var i=0; i<10; i++) {
113 mouseWheel(zoomableImage, zoomableImage.width / 2, zoomableImage.height / 2, 0, -10);
114 mouseWheel(zoomableImage, zoomableImage.width / 2, zoomableImage.height / 2, 0, -10);
114− tryCompare(image, "scale", 2.0 - (i + 1) * 0.1);
115+ tryCompare(image, "scale", oldScale + 1.0 - (i + 1) * 0.1);
115− compare(flickable.contentWidth, lazyImage.width * image.scale);
116+ compare(flickable.contentWidth, Math.max(lazyImage.width * image.scale, flickable.width));
116− compare(flickable.contentHeight, lazyImage.height * image.scale);
117+ compare(flickable.contentHeight, Math.max(lazyImage.height * image.scale, flickable.height));
117 }
118 }
118 }
119 }
119 }
120 }
@@ -123,16 +124,12 @@ Rectangle {
123 zoomable:false,
124 zoomable:false,
124 answer1: true,
125 answer1: true,
125 answer2: false,
126 answer2: false,
126− answer3: true,
127+ answer3: true },
127− answer4: 1.0,
128− answer5: 1.0 },
129 { source:widgetData2["source"],
128 { source:widgetData2["source"],
130 zoomable:true,
129 zoomable:true,
131 answer1: false,
130 answer1: false,
132 answer2: true,
131 answer2: true,
133− answer3: false,
132+ answer3: false }
134− answer4: 1.7740461882048026,
135− answer5: 1.0 }
136 ]
133 ]
137 }
134 }
138
135
@@ -163,7 +160,7 @@ Rectangle {
163 var y2End = zoomableImage.height * 5 / 6;
160 var y2End = zoomableImage.height * 5 / 6;
164
161
165 var oldScale = image.scale;
162 var oldScale = image.scale;
166−
163+ var newScale = -1;
167 // move mouse to center
164 // move mouse to center
168 mouseMove(zoomableImage, zoomableImage.width / 2, zoomableImage.height / 2);
165 mouseMove(zoomableImage, zoomableImage.width / 2, zoomableImage.height / 2);
169
166
@@ -172,20 +169,25 @@ Rectangle {
172 wait(3000); // have to delay between two consequent pinch event.
169 wait(3000); // have to delay between two consequent pinch event.
173 // pinch zoom-in
170 // pinch zoom-in
174 touchPinch(zoomableImage, x1Start, y1Start, x1End, y1End, x2Start, y2Start, x2End, y2End);
171 touchPinch(zoomableImage, x1Start, y1Start, x1End, y1End, x2Start, y2Start, x2End, y2End);
172+ waitForRendering(image);
175
173
176− tryCompare(image, "scale", data.answer4);
174+ if (newScale == -1) {
177− var newScale = image.scale;
175+ newScale = image.scale;
176+ }
177+ tryCompare(image, "scale", newScale);
178 compare(newScale == oldScale, data.answer1, "scale factor not equal: "+ oldScale + "=?" + newScale);
178 compare(newScale == oldScale, data.answer1, "scale factor not equal: "+ oldScale + "=?" + newScale);
179 compare(newScale > oldScale, data.answer2, "scale factor didn't changed");
179 compare(newScale > oldScale, data.answer2, "scale factor didn't changed");
180 compare(signalSpy.count == 0, data.answer3, "scale signal count error");
180 compare(signalSpy.count == 0, data.answer3, "scale signal count error");
181− compare(newScale, data.answer4, "scale factor error");
181+ compare(image.scale, newScale, "scale factor error");
182− compare(flickable.contentWidth, lazyImage.width * image.scale);
182+ compare(flickable.contentWidth, Math.max(lazyImage.width * image.scale, flickable.width));
183− compare(flickable.contentHeight, lazyImage.height * image.scale);
183+ compare(flickable.contentHeight, Math.max(lazyImage.height * image.scale, flickable.height));
184
184
185 wait(3000); // have to delay between two consequent pinch event.
185 wait(3000); // have to delay between two consequent pinch event.
186 // pinch zoom-out
186 // pinch zoom-out
187 touchPinch(zoomableImage, x1End, y1End, x1Start, y1Start, x2End, y2End, x2Start, y2Start);
187 touchPinch(zoomableImage, x1End, y1End, x1Start, y1Start, x2End, y2End, x2Start, y2Start);
188− tryCompare(image, "scale", data.answer5);
188+ tryCompare(image, "scale", oldScale);
189+ compare(flickable.contentWidth, Math.max(lazyImage.width * image.scale, flickable.width));
190+ compare(flickable.contentHeight, Math.max(lazyImage.height * image.scale, flickable.height));
189 }
191 }
190 }
192 }
191 }
193 }
tests/qmltests/Dash/Previews/tst_PreviewHeader.qml+12−7
@@ -53,12 +53,12 @@ Rectangle {
53 name: "PreviewHeaderTest"
53 name: "PreviewHeaderTest"
54 when: windowShown
54 when: windowShown
55
55
56− property Item mascot: findChild(previewHeader, "mascotShape")
56+ property Item mascotShapeLoader: findChild(previewHeader, "mascotShapeLoader")
57 property Item outerRow: findChild(previewHeader, "outerRow")
57 property Item outerRow: findChild(previewHeader, "outerRow")
58 property Item column: findChild(previewHeader, "column")
58 property Item column: findChild(previewHeader, "column")
59
59
60 function initTestCase() {
60 function initTestCase() {
61− verify(typeof testCase.mascot === "object", "Couldn't find mascot object.");
61+ verify(typeof testCase.mascotShapeLoader === "object", "Couldn't find mascot loader object.");
62 verify(typeof testCase.outerRow === "object", "Couldn't find outerRow object.");
62 verify(typeof testCase.outerRow === "object", "Couldn't find outerRow object.");
63 verify(typeof testCase.column === "object", "Couldn't find column object.");
63 verify(typeof testCase.column === "object", "Couldn't find column object.");
64
64
@@ -70,9 +70,9 @@ Rectangle {
70
70
71 function test_mascot_data() {
71 function test_mascot_data() {
72 return [
72 return [
73− { tag: "Empty", source: "", visible: false },
73+ { tag: "Empty", source: "", loaderVisible: false, visible: false },
74− { tag: "Invalid", source: "bad_path", visible: false },
74+ { tag: "Invalid", source: "bad_path", loaderVisible: true, visible: false },
75− { tag: "Valid", source: "../graphics/play_button.png", visible: true },
75+ { tag: "Valid", source: "../graphics/play_button.png", loaderVisible: true, visible: true },
76 ]
76 ]
77 }
77 }
78
78
@@ -80,12 +80,17 @@ Rectangle {
80 headerjson.mascot = data.source;
80 headerjson.mascot = data.source;
81 previewHeader.widgetData = headerjson;
81 previewHeader.widgetData = headerjson;
82
82
83+ tryCompare(testCase.mascotShapeLoader, "visible", data.loaderVisible);
84+ if (data.loaderVisible) {
85+ tryCompareFunction(function() { return findChild(previewHeader, "mascotShape") != null }, true);
86+ var mascot = findChild(previewHeader, "mascotShape")
83− tryCompare(testCase.mascot, "visible", data.visible);
87+ tryCompare(mascot, "visible", data.visible);
88+ }
84 }
89 }
85
90
86 function test_dimensions_data() {
91 function test_dimensions_data() {
87 return [
92 return [
88− { tag: "Column width with mascot", object: column, width: previewHeader.width - mascot.width - outerRow.margins * 3, mascot: "artwork/avatar.png" },
93+ { tag: "Column width with mascot", object: column, width: previewHeader.width - mascotShapeLoader.width - outerRow.margins * 3, mascot: "artwork/avatar.png" },
89 { tag: "Header height", object: previewHeader, height: function() { return outerRow.height + outerRow.margins * 2 } },
94 { tag: "Header height", object: previewHeader, height: function() { return outerRow.height + outerRow.margins * 2 } },
90 ]
95 ]
91 }
96 }
tests/qmltests/Dash/Previews/tst_PreviewZoomableImage.qml+7−5
@@ -26,12 +26,12 @@ Rectangle {
26 color: "lightgrey"
26 color: "lightgrey"
27
27
28 property var widgetData0: {
28 property var widgetData0: {
29− "source": ""
29+ "source": Qt.resolvedUrl("../artwork/checkers.png"),
30+ "zoomable": false
30 }
31 }
31
32
32 property var widgetData1: {
33 property var widgetData1: {
33− "source": Qt.resolvedUrl("../artwork/checkers.png"),
34+ "source": ""
34− "zoomable": false
35 }
35 }
36
36
37 PreviewZoomableImage {
37 PreviewZoomableImage {
@@ -49,11 +49,13 @@ Rectangle {
49
49
50 zoomableImage.widgetData = widgetData0;
50 zoomableImage.widgetData = widgetData0;
51 waitForRendering(zoomableImage);
51 waitForRendering(zoomableImage);
52+ waitForRendering(image);
52− tryCompare(image, "imageState", "default");
53+ tryCompare(image, "imageState", "ready");
53
54
54 zoomableImage.widgetData = widgetData1;
55 zoomableImage.widgetData = widgetData1;
55 waitForRendering(zoomableImage);
56 waitForRendering(zoomableImage);
57+ waitForRendering(image);
56− tryCompare(image, "imageState", "ready");
58+ tryCompare(image, "imageState", "default");
57 }
59 }
58 }
60 }
59}
61}
tests/qmltests/Dash/tst_DashContent.qml+29−14
@@ -67,13 +67,17 @@ Item {
67 name: "DashContent"
67 name: "DashContent"
68 when: scopesModel.loaded && windowShown
68 when: scopesModel.loaded && windowShown
69
69
70− function init() {
70+ function loadScopes() {
71− scopesModel.clear();
72 scopeLoadedSpy.clear();
71 scopeLoadedSpy.clear();
73 scopesModel.load();
72 scopesModel.load();
74 tryCompare(scopeLoadedSpy, "count", 4);
73 tryCompare(scopeLoadedSpy, "count", 4);
75 }
74 }
76
75
76+ function init() {
77+ scopesModel.clear();
78+ loadScopes();
79+ }
80+
77 function cleanup() {
81 function cleanup() {
78 movementStartedSpy.clear();
82 movementStartedSpy.clear();
79 dashContent.visible = true;
83 dashContent.visible = true;
@@ -93,9 +97,7 @@ Item {
93 compare(dashContentList.count, 0, "DashContent should have 0 items when it starts");
97 compare(dashContentList.count, 0, "DashContent should have 0 items when it starts");
94 tryCompare(dashContentList, "currentIndex", -1);
98 tryCompare(dashContentList, "currentIndex", -1);
95
99
96− scopeLoadedSpy.clear();
100+ loadScopes();
97− scopesModel.load();
98− tryCompare(scopeLoadedSpy, "count", 4);
99
101
100 verify(dashContentList.currentIndex >= 0);
102 verify(dashContentList.currentIndex >= 0);
101 }
103 }
@@ -109,9 +111,7 @@ Item {
109 // pretend we're running after a model reset
111 // pretend we're running after a model reset
110 dashContentList.currentIndex = 27;
112 dashContentList.currentIndex = 27;
111
113
112− scopeLoadedSpy.clear();
114+ loadScopes();
113− scopesModel.load();
114− tryCompare(scopeLoadedSpy, "count", 4);
115
115
116 verify(dashContentList.currentIndex >= 0 && dashContentList.currentIndex < 5);
116 verify(dashContentList.currentIndex >= 0 && dashContentList.currentIndex < 5);
117 }
117 }
@@ -326,8 +326,6 @@ Item {
326 }
326 }
327
327
328 function test_previewOpenClose() {
328 function test_previewOpenClose() {
329− tryCompare(scopeLoadedSpy, "count", 4);
330−
331 var previewListView = findChild(dashContent, "dashContentPreviewList");
329 var previewListView = findChild(dashContent, "dashContentPreviewList");
332 tryCompare(previewListView, "open", false);
330 tryCompare(previewListView, "open", false);
333
331
@@ -352,8 +350,6 @@ Item {
352 },
350 },
353 true);
351 true);
354
352
355− tryCompare(scopeLoadedSpy, "count", 4);
356−
357 var previewListView = findChild(dashContent, "dashContentPreviewList");
353 var previewListView = findChild(dashContent, "dashContentPreviewList");
358 tryCompare(previewListView, "open", false);
354 tryCompare(previewListView, "open", false);
359
355
@@ -368,8 +364,6 @@ Item {
368 }
364 }
369
365
370 function test_previewCycle() {
366 function test_previewCycle() {
371− tryCompare(scopeLoadedSpy, "count", 4);
372−
373 var categoryListView = findChild(dashContent, "categoryListView");
367 var categoryListView = findChild(dashContent, "categoryListView");
374 categoryListView.positionAtBeginning();
368 categoryListView.positionAtBeginning();
375
369
@@ -392,5 +386,26 @@ Item {
392 }
386 }
393 closePreview();
387 closePreview();
394 }
388 }
389+
390+ function test_carouselAspectRatio() {
391+ tryCompareFunction(function() {
392+ var scope = findChild(dashContent, "MockScope1 loader");
393+ if (scope != null) {
394+ var dashCategory1 = findChild(scope, "dashCategory1");
395+ if (dashCategory1 != null) {
396+ var tile = findChild(dashCategory1, "carouselDelegate1");
397+ return tile != null;
398+ }
399+ }
400+ return false;
401+ },
402+ true);
403+
404+ var scope = findChild(dashContent, "MockScope1 loader");
405+ var dashCategory1 = findChild(scope, "dashCategory1");
406+ var cardTool = findChild(dashCategory1, "cardTool");
407+ var carouselLV = findChild(dashCategory1, "listView");
408+ verify(carouselLV.tileWidth / carouselLV.tileHeight == cardTool.components["art"]["aspect-ratio"]);
409+ }
395 }
410 }
396}
411}
tests/qmltests/Dash/tst_GenericScopeView.qml+1
@@ -126,6 +126,7 @@ Item {
126
126
127 function test_filter_expand_collapse() {
127 function test_filter_expand_collapse() {
128 // wait for the item to be there
128 // wait for the item to be there
129+ waitForRendering(genericScopeView);
129 tryCompareFunction(function() { return findChild(genericScopeView, "dashSectionHeader0") != null; }, true);
130 tryCompareFunction(function() { return findChild(genericScopeView, "dashSectionHeader0") != null; }, true);
130
131
131 var header = findChild(genericScopeView, "dashSectionHeader0")
132 var header = findChild(genericScopeView, "dashSectionHeader0")
tests/qmltests/Greeter/tst_Lockscreen.qml+207−30
@@ -23,25 +23,33 @@ import LightDM 0.1 as LightDM
23import Unity.Test 0.1 as UT
23import Unity.Test 0.1 as UT
24
24
25Rectangle {
25Rectangle {
26+ id: root
26− width: units.gu(60)
27+ width: units.gu(80)
27 height: units.gu(80)
28 height: units.gu(80)
28 color: "orange"
29 color: "orange"
29
30
30 Lockscreen {
31 Lockscreen {
31 id: lockscreen
32 id: lockscreen
32 anchors.fill: parent
33 anchors.fill: parent
33− anchors.rightMargin: units.gu(18)
34+ anchors.rightMargin: units.gu(30)
34 placeholderText: "Please enter your PIN"
35 placeholderText: "Please enter your PIN"
36+ wrongPlaceholderText: "Incorrect PIN"
37+ retryText: retryCountTextField.text
35 alphaNumeric: pinPadCheckBox.checked
38 alphaNumeric: pinPadCheckBox.checked
36− pinLength: pinLengthTextField.text
39+ minPinLength: minPinLengthTextField.text
40+ maxPinLength: maxPinLengthTextField.text
37 username: "Lola"
41 username: "Lola"
42+ infoText: infoTextTextField.text
38 }
43 }
39
44
40 Connections {
45 Connections {
41 target: lockscreen
46 target: lockscreen
42
47
43 onEmergencyCall: emergencyCheckBox.checked = true
48 onEmergencyCall: emergencyCheckBox.checked = true
49+ onEntered: {
44− onEntered: enteredLabel.text = passphrase
50+ enteredLabel.text = passphrase
51+ lockscreen.clear(true)
52+ }
45 }
53 }
46
54
47 Connections {
55 Connections {
@@ -49,9 +57,9 @@ Rectangle {
49
57
50 onShowPrompt: {
58 onShowPrompt: {
51 if (text.indexOf("PIN") >= 0) {
59 if (text.indexOf("PIN") >= 0) {
52− lockscreen.alphaNumeric = false
60+ pinPadCheckBox.checked = false
53 } else {
61 } else {
54− lockscreen.alphaNumeric = true
62+ pinPadCheckBox.checked = true
55 }
63 }
56 lockscreen.placeholderText = text;
64 lockscreen.placeholderText = text;
57 }
65 }
@@ -65,6 +73,7 @@ Rectangle {
65 Column {
73 Column {
66 anchors.fill: parent
74 anchors.fill: parent
67 anchors.margins: units.gu(1)
75 anchors.margins: units.gu(1)
76+ spacing: units.gu(1)
68
77
69 Row {
78 Row {
70 CheckBox {
79 CheckBox {
@@ -86,12 +95,32 @@ Rectangle {
86 }
95 }
87 Row {
96 Row {
88 TextField {
97 TextField {
89− id: pinLengthTextField
98+ id: minPinLengthTextField
90 width: units.gu(7)
99 width: units.gu(7)
91 text: "4"
100 text: "4"
92 }
101 }
93 Label {
102 Label {
103+ text: "Min PIN length"
104+ }
105+ }
106+ Row {
107+ TextField {
108+ id: maxPinLengthTextField
109+ width: units.gu(7)
110+ text: "4"
111+ }
112+ Label {
94− text: "PIN length"
113+ text: "Max PIN length"
114+ }
115+ }
116+ Row {
117+ TextField {
118+ id: retryCountTextField
119+ width: units.gu(7)
120+ text: "3 retries left"
121+ }
122+ Label {
123+ text: "Retries left"
95 }
124 }
96 }
125 }
97 Label {
126 Label {
@@ -108,12 +137,40 @@ Rectangle {
108 }
137 }
109 Button {
138 Button {
110 text: "start auth (1234)"
139 text: "start auth (1234)"
140+ width: parent.width
111 onClicked: LightDM.Greeter.authenticate("has-pin")
141 onClicked: LightDM.Greeter.authenticate("has-pin")
112 }
142 }
113 Button {
143 Button {
114 text: "start auth (password)"
144 text: "start auth (password)"
145+ width: parent.width
115 onClicked: LightDM.Greeter.authenticate("has-password")
146 onClicked: LightDM.Greeter.authenticate("has-password")
116 }
147 }
148+
149+ TextField {
150+ id: infoTextTextField
151+ width: parent.width
152+ placeholderText: "Infotext"
153+ text: "+49 179 3253553"
154+ }
155+
156+ TextField {
157+ id: infoPopupTitleTextField
158+ width: parent.width
159+ placeholderText: "Popup title"
160+ text: "This will be the last attempt"
161+ }
162+
163+ TextArea {
164+ id: infoPopupTextArea
165+ width: parent.width
166+ text: "If the SIM PIN is entered incorrectly, your SIM will be blocked and would require the PUK code to unlock."
167+ }
168+
169+ Button {
170+ text: "open info popup"
171+ width: parent.width
172+ onClicked: lockscreen.showInfoPopup(infoPopupTitleTextField.text, infoPopupTextArea.text)
173+ }
117 }
174 }
118 }
175 }
119
176
@@ -121,6 +178,16 @@ Rectangle {
121 name: "Lockscreen"
178 name: "Lockscreen"
122 when: windowShown
179 when: windowShown
123
180
181+ function cleanup() {
182+ lockscreen.clear(false);
183+ }
184+
185+ function waitForLockscreenReady() {
186+ var pinPadLoader = findChild(lockscreen, "pinPadLoader");
187+ tryCompare(pinPadLoader, "status", Loader.Ready)
188+ waitForRendering(lockscreen)
189+ }
190+
124 function test_loading_data() {
191 function test_loading_data() {
125 return [
192 return [
126 {tag: "numeric", alphanumeric: false, pinPadAvailable: true },
193 {tag: "numeric", alphanumeric: false, pinPadAvailable: true },
@@ -129,8 +196,8 @@ Rectangle {
129 }
196 }
130
197
131 function test_loading(data) {
198 function test_loading(data) {
132− lockscreen.alphaNumeric = data.alphanumeric
199+ pinPadCheckBox.checked = data.alphanumeric
133− waitForRendering(lockscreen)
200+ waitForLockscreenReady();
134 if (data.pinPadAvailable) {
201 if (data.pinPadAvailable) {
135 compare(findChild(lockscreen, "pinPadButton8").text, "8", "Could not find number 8 on PinPad")
202 compare(findChild(lockscreen, "pinPadButton8").text, "8", "Could not find number 8 on PinPad")
136 } else {
203 } else {
@@ -147,8 +214,8 @@ Rectangle {
147
214
148 function test_emergency_call(data) {
215 function test_emergency_call(data) {
149 emergencyCheckBox.checked = false
216 emergencyCheckBox.checked = false
150− lockscreen.alphaNumeric = data.alphanumeric
217+ pinPadCheckBox.checked = data.alphanumeric
151− waitForRendering(lockscreen)
218+ waitForLockscreenReady();
152 var emergencyButton = findChild(lockscreen, "emergencyCallIcon")
219 var emergencyButton = findChild(lockscreen, "emergencyCallIcon")
153 mouseClick(emergencyButton, units.gu(1), units.gu(1))
220 mouseClick(emergencyButton, units.gu(1), units.gu(1))
154 tryCompare(emergencyCheckBox, "checked", true)
221 tryCompare(emergencyCheckBox, "checked", true)
@@ -163,9 +230,9 @@ Rectangle {
163 }
230 }
164
231
165 function test_labels(data) {
232 function test_labels(data) {
166− lockscreen.alphaNumeric = data.alphanumeric
233+ pinPadCheckBox.checked = data.alphanumeric
167 lockscreen.placeholderText = data.placeholderText
234 lockscreen.placeholderText = data.placeholderText
168− waitForRendering(lockscreen)
235+ waitForLockscreenReady();
169 compare(findChild(lockscreen, "pinentryField").placeholderText, data.placeholderText, "Placeholdertext is not what it should be")
236 compare(findChild(lockscreen, "pinentryField").placeholderText, data.placeholderText, "Placeholdertext is not what it should be")
170 if (data.alphanumeric) {
237 if (data.alphanumeric) {
171 compare(findChild(lockscreen, "greeterLabel").text, "Hello " + data.username, "Greeter is not set correctly")
238 compare(findChild(lockscreen, "greeterLabel").text, "Hello " + data.username, "Greeter is not set correctly")
@@ -175,23 +242,25 @@ Rectangle {
175
242
176 function test_unlock_data() {
243 function test_unlock_data() {
177 return [
244 return [
178− {tag: "numeric", alphanumeric: false, username: "has-pin", password: "1234", pinLength: 4},
245+ {tag: "numeric", alphanumeric: false, username: "has-pin", password: "1234", minPinLength: 4, maxPinLength: 4},
179− {tag: "alphanumeric", alphanumeric: true, username: "has-password", password: "password", pinLength: -1},
246+ {tag: "alphanumeric", alphanumeric: true, username: "has-password", password: "password", minPinLength: -1, maxPinLength: -1},
180− {tag: "numeric (wrong)", alphanumeric: false, username: "has-pin", password: "4321", pinLength: 4},
247+ {tag: "numeric (wrong)", alphanumeric: false, username: "has-pin", password: "4321", minPinLength: 4, maxPinLength: 4},
181− {tag: "alphanumeric (wrong)", alphanumeric: true, username: "has-password", password: "drowssap", pinLength: -1},
248+ {tag: "alphanumeric (wrong)", alphanumeric: true, username: "has-password", password: "drowssap", minPinLength: -1, maxPinLength: -1},
182− {tag: "flexible length", alphanumeric: false, username: "has-pin", password: "1234", pinLength: -1},
249+ {tag: "flexible length", alphanumeric: false, username: "has-pin", password: "1234", minPinLength: -1, maxPinLength: -1},
183 ]
250 ]
184 }
251 }
185
252
186 function test_unlock(data) {
253 function test_unlock(data) {
187 enteredLabel.text = ""
254 enteredLabel.text = ""
188− pinLengthTextField.text = data.pinLength
255+ minPinLengthTextField.text = data.minPinLength
256+ maxPinLengthTextField.text = data.maxPinLength
189 LightDM.Greeter.authenticate(data.username)
257 LightDM.Greeter.authenticate(data.username)
190− waitForRendering(lockscreen)
258+ waitForLockscreenReady();
191
259
192 var inputField = findChild(lockscreen, "pinentryField")
260 var inputField = findChild(lockscreen, "pinentryField")
193 if (data.alphanumeric) {
261 if (data.alphanumeric) {
194 mouseClick(inputField, units.gu(1), units.gu(1))
262 mouseClick(inputField, units.gu(1), units.gu(1))
263+ tryCompare(inputField, "focus", true);
195 typeString(data.password)
264 typeString(data.password)
196 keyClick(Qt.Key_Enter)
265 keyClick(Qt.Key_Enter)
197 } else {
266 } else {
@@ -200,7 +269,7 @@ Rectangle {
200 var button = findChild(lockscreen, "pinPadButton" + character)
269 var button = findChild(lockscreen, "pinPadButton" + character)
201 mouseClick(button, units.gu(1), units.gu(1))
270 mouseClick(button, units.gu(1), units.gu(1))
202 }
271 }
203− if (data.pinLength == -1) {
272+ if (data.minPinLength !== data.maxPinLength || data.minPinLength == -1) {
204 var pinPadButtonErase = findChild(lockscreen, "pinPadButtonErase");
273 var pinPadButtonErase = findChild(lockscreen, "pinPadButtonErase");
205 mouseClick(pinPadButtonErase, units.gu(1), units.gu(1));
274 mouseClick(pinPadButtonErase, units.gu(1), units.gu(1));
206 }
275 }
@@ -219,11 +288,12 @@ Rectangle {
219
288
220 function test_clear(data) {
289 function test_clear(data) {
221 pinPadCheckBox.checked = data.alphanumeric
290 pinPadCheckBox.checked = data.alphanumeric
222− waitForRendering(lockscreen)
291+ waitForLockscreenReady();
223
292
224 var inputField = findChild(lockscreen, "pinentryField")
293 var inputField = findChild(lockscreen, "pinentryField")
225 if (data.alphanumeric) {
294 if (data.alphanumeric) {
226 mouseClick(inputField, units.gu(1), units.gu(1))
295 mouseClick(inputField, units.gu(1), units.gu(1))
296+ tryCompare(inputField, "activeFocus", true);
227 typeString("1")
297 typeString("1")
228 } else {
298 } else {
229 var button = findChild(lockscreen, "pinPadButton1")
299 var button = findChild(lockscreen, "pinPadButton1")
@@ -239,6 +309,16 @@ Rectangle {
239
309
240 wait(0) // Trigger event loop to make sure the animation would start running
310 wait(0) // Trigger event loop to make sure the animation would start running
241 compare(animation.running, data.animation)
311 compare(animation.running, data.animation)
312+ if (data.animation) {
313+ if (data.alphanumeric) {
314+ tryCompare(inputField, "placeholderText", lockscreen.wrongPlaceholderText)
315+ tryCompare(inputField, "placeholderText", lockscreen.placeholderText)
316+ } else {
317+ var label = findChild(lockscreen, "pinentryFieldPlaceHolder");
318+ tryCompare(label, "text", lockscreen.wrongPlaceholderText)
319+ tryCompare(label, "text", lockscreen.placeholderText)
320+ }
321+ }
242
322
243 // wait for animation to finish to not disturb other tests
323 // wait for animation to finish to not disturb other tests
244 tryCompare(animation, "running", false)
324 tryCompare(animation, "running", false)
@@ -246,33 +326,130 @@ Rectangle {
246
326
247 function test_backspace_data() {
327 function test_backspace_data() {
248 return [
328 return [
249− {tag: "fixed length", pinLength: 4},
329+ {tag: "fixed length", minPinLength: 4, maxPinLength: 4},
250− {tag: "variable length", pinLength: -1}
330+ {tag: "variable undefined length", minPinLength: -1, maxPinLength: -1},
331+ {tag: "variable restricted length", minPinLength: 4, maxPinLength: 8}
251 ];
332 ];
252 }
333 }
253
334
254 function test_backspace(data) {
335 function test_backspace(data) {
255 pinPadCheckBox.checked = false
336 pinPadCheckBox.checked = false
256− pinLengthTextField.text = data.pinLength
337+ minPinLengthTextField.text = data.minPinLength
257− waitForRendering(lockscreen);
338+ maxPinLengthTextField.text = data.maxPinLength
339+ waitForLockscreenReady();
258
340
259 var pinPadButtonErase = findChild(lockscreen, "pinPadButtonErase");
341 var pinPadButtonErase = findChild(lockscreen, "pinPadButtonErase");
260 var backspaceIcon = findChild(lockscreen, "backspaceIcon");
342 var backspaceIcon = findChild(lockscreen, "backspaceIcon");
261 var pinEntryField = findChild(lockscreen, "pinentryField");
343 var pinEntryField = findChild(lockscreen, "pinentryField");
262
344
345+ var autoConfirmEnabled = data.minPinLength === data.maxPinLength && data.minPinLength !== -1;
263− compare(pinPadButtonErase.iconName, data.pinLength == -1 ? "" : "erase");
346+ compare(pinPadButtonErase.iconName, autoConfirmEnabled ? "erase" : "");
264− compare(backspaceIcon.visible, data.pinLength == -1);
347+ compare(backspaceIcon.visible, !autoConfirmEnabled);
265
348
266 var pinPadButton5 = findChild(lockscreen, "pinPadButton5");
349 var pinPadButton5 = findChild(lockscreen, "pinPadButton5");
267 mouseClick(pinPadButton5, units.gu(1), units.gu(1));
350 mouseClick(pinPadButton5, units.gu(1), units.gu(1));
268 compare(pinEntryField.text, "5");
351 compare(pinEntryField.text, "5");
269
352
270− if (data.pinLength == -1) {
353+ if (data.minPinLength !== data.maxPinLength) {
271 mouseClick(backspaceIcon, units.gu(1), units.gu(1));
354 mouseClick(backspaceIcon, units.gu(1), units.gu(1));
272 } else {
355 } else {
273 mouseClick(pinPadButtonErase, units.gu(1), units.gu(1));
356 mouseClick(pinPadButtonErase, units.gu(1), units.gu(1));
274 }
357 }
275 compare(pinEntryField.text, "");
358 compare(pinEntryField.text, "");
276 }
359 }
360+
361+ function test_minMaxLength_data() {
362+ return [
363+ {tag: "undefined", minPinLength: -1, maxPinLength: -1},
364+ {tag: "fixed", minPinLength: 4, maxPinLength: 4},
365+ {tag: "variable, limited", minPinLength: 4, maxPinLength: 8},
366+ ];
367+ }
368+
369+ function test_minMaxLength(data) {
370+ pinPadCheckBox.checked = false
371+ minPinLengthTextField.text = data.minPinLength
372+ maxPinLengthTextField.text = data.maxPinLength
373+ waitForLockscreenReady();
374+
375+ var pinPadButton5 = findChild(lockscreen, "pinPadButton5");
376+ var pinPadButtonErase = findChild(lockscreen, "pinPadButtonErase");
377+ var inputField = findChild(lockscreen, "pinentryField")
378+
379+ for (var i = 0; i < 10; i++) {
380+ mouseClick(pinPadButton5, units.gu(1), units.gu(1));
381+
382+ if (data.minPinLength == data.maxPinLength && data.minPinLength != -1) {
383+ // auto confirm mode...
384+ compare(inputField.text.length, (i+1) % data.minPinLength);
385+ } else {
386+ // manual confirm mode
387+ tryCompare(pinPadButtonErase, "enabled", (i+1) >= data.minPinLength)
388+ if (data.maxPinLength == -1) {
389+ compare(inputField.text.length, i+1);
390+ } else {
391+ compare(inputField.text.length, Math.min(data.maxPinLength, i+1));
392+ }
393+
394+ }
395+ }
396+ }
397+
398+ function test_retryDisplay_data() {
399+ return [
400+ {tag: "empty", retryText: "", shown: false},
401+ {tag: "3 retries left", retryText: "3 retries left", shown: true},
402+ ]
403+ }
404+
405+ function test_retryDisplay(data) {
406+ pinPadCheckBox.checked = false
407+ waitForLockscreenReady();
408+
409+ retryCountTextField.text = data.retryText;
410+ var label = findChild(lockscreen, "retryCountLabel")
411+ compare(label.visible, data.shown);
412+ }
413+
414+ function test_infoPopup() {
415+ verify(findChild(root, "infoPopup") === null);
416+ lockscreen.showInfoPopup("foo", "bar");
417+ tryCompareFunction(function() { return findChild(root, "infoPopup") !== null}, true);
418+
419+ var infoPopup = findChild(root, "infoPopup");
420+ compare(infoPopup.title, "foo");
421+ compare(infoPopup.text, "bar");
422+
423+ signalSpy.signalName = "infoPopupConfirmed"
424+ signalSpy.clear();
425+
426+ var okButton = findChild(root, "infoPopupOkButton");
427+ mouseClick(okButton, okButton.width / 2, okButton.height / 2);
428+
429+ tryCompareFunction(function() { return findChild(root, "infoPopup") === null}, true);
430+
431+ tryCompare(signalSpy, "count", 1);
432+ }
433+
434+ function test_infoTextDisplay_data() {
435+ return [
436+ {tag: "empty string", text: "", shown: false},
437+ {tag: "hello world", text: "hello world", shown: true},
438+ ]
439+ }
440+
441+ function test_infoTextDisplay(data) {
442+ pinPadCheckBox.checked = false
443+ waitForLockscreenReady();
444+
445+ infoTextTextField.text = data.text;
446+ var label = findChild(lockscreen, "infoTextLabel")
447+ compare(label.visible, data.shown);
448+ }
449+ }
450+
451+ SignalSpy {
452+ id: signalSpy
453+ target: lockscreen
277 }
454 }
278}
455}
tests/qmltests/tst_Shell.qml−9
@@ -451,15 +451,6 @@ Item {
451 } while (!isStill);
451 } while (!isStill);
452 }
452 }
453
453
454− function test_background_data() {
455− return [
456− {tag: "red", url: Qt.resolvedUrl("../data/unity/backgrounds/red.png"), expectedUrl: "tests/data/unity/backgrounds/red.png"},
457− {tag: "blue", url: Qt.resolvedUrl("../data/unity/backgrounds/blue.png"), expectedUrl: "tests/data/unity/backgrounds/blue.png"},
458− {tag: "invalid", url: "invalid", expectedUrl: shell.defaultBackground},
459− {tag: "empty", url: "", expectedUrl: shell.defaultBackground}
460− ]
461− }
462−
463 function test_DashShown_data() {
454 function test_DashShown_data() {
464 return [
455 return [
465 {tag: "in focus", app: false, launcher: false, indicators: false, expectedShown: true},
456 {tag: "in focus", app: false, launcher: false, indicators: false, expectedShown: true},