on xenial help sign in
Merge from trunk
1751096Michael Terry
CMakeLists.txt+2−2
@@ -64,13 +64,13 @@ if(SHELL_INSTALL_QML STREQUAL "")
64 message(FATAL_ERROR "Could not determine plugin installation dir.")
64 message(FATAL_ERROR "Could not determine plugin installation dir.")
65endif()
65endif()
66
66
67+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility=hidden")
68+
67execute_process(COMMAND ${PKG_CONFIG_EXECUTABLE} --variable=plugindir unity-shell-api OUTPUT_VARIABLE SHELL_PLUGINDIR OUTPUT_STRIP_TRAILING_WHITESPACE)
69execute_process(COMMAND ${PKG_CONFIG_EXECUTABLE} --variable=plugindir unity-shell-api OUTPUT_VARIABLE SHELL_PLUGINDIR OUTPUT_STRIP_TRAILING_WHITESPACE)
68if(SHELL_PLUGINDIR STREQUAL "")
70if(SHELL_PLUGINDIR STREQUAL "")
69 message(FATAL_ERROR "Could not determine plugin import dir.")
71 message(FATAL_ERROR "Could not determine plugin import dir.")
70endif()
72endif()
71
73
72−set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility=hidden")
73−
74set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -fno-permissive -pedantic -Wall -Wextra")
74set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -fno-permissive -pedantic -Wall -Wextra")
75
75
76if ("${CMAKE_BUILD_TYPE}" STREQUAL "release" OR "${CMAKE_BUILD_TYPE}" STREQUAL "relwithdebinfo")
76if ("${CMAKE_BUILD_TYPE}" STREQUAL "release" OR "${CMAKE_BUILD_TYPE}" STREQUAL "relwithdebinfo")
build.sh+1
@@ -51,6 +51,7 @@ install_dependencies() {
51 qtdeclarative5-ubuntu-settings-components \
51 qtdeclarative5-ubuntu-settings-components \
52 qtdeclarative5-ubuntu-telephony0.1 \
52 qtdeclarative5-ubuntu-telephony0.1 \
53 qtdeclarative5-ubuntu-thumbnailer0.1 \
53 qtdeclarative5-ubuntu-thumbnailer0.1 \
54+ qml-module-ubuntu-connectivity \
54 unity-notifications-impl \
55 unity-notifications-impl \
55 ubuntu-mobile-icons \
56 ubuntu-mobile-icons \
56 unity-scope-home \
57 unity-scope-home \
cmake/modules/QmlTest.cmake+2−1
@@ -151,7 +151,7 @@ macro(add_qml_test_internal SUBPATH COMPONENT_NAME ITERATIONS)
151 add_manual_qml_test(${SUBPATH} ${COMPONENT_NAME} ${ARGN})
151 add_manual_qml_test(${SUBPATH} ${COMPONENT_NAME} ${ARGN})
152endmacro(add_qml_test_internal)
152endmacro(add_qml_test_internal)
153
153
154−macro(add_binary_qml_test CLASS_NAME LD_PATH DEPS)
154+macro(add_binary_qml_test CLASS_NAME LD_PATH DEPS ENVVAR)
155 set(testCommand
155 set(testCommand
156 LD_LIBRARY_PATH=${LD_PATH}
156 LD_LIBRARY_PATH=${LD_PATH}
157 ${CMAKE_CURRENT_BINARY_DIR}/${CLASS_NAME}TestExec
157 ${CMAKE_CURRENT_BINARY_DIR}/${CLASS_NAME}TestExec
@@ -168,6 +168,7 @@ macro(add_binary_qml_test CLASS_NAME LD_PATH DEPS)
168 endif()
168 endif()
169 set(xvfbtestCommand
169 set(xvfbtestCommand
170 ${LD_PRELOAD_PATH}
170 ${LD_PRELOAD_PATH}
171+ ${ENVVAR}
171 LD_LIBRARY_PATH=${LD_PATH}
172 LD_LIBRARY_PATH=${LD_PATH}
172 xvfb-run --server-args "-screen 0 1024x768x24" --auto-servernum
173 xvfb-run --server-args "-screen 0 1024x768x24" --auto-servernum
173 ${CMAKE_CURRENT_BINARY_DIR}/${CLASS_NAME}TestExec
174 ${CMAKE_CURRENT_BINARY_DIR}/${CLASS_NAME}TestExec
debian/changelog+40
@@ -1,3 +1,43 @@
1+unity8 (8.00+14.10.20141006-0ubuntu1) utopic; urgency=low
2+
3+ [ Andrea Cimitan ]
4+ * Tweak card header to match the spec
5+ * Add preview image slideshow (LP: #1351537)
6+
7+ [ Michał Sawicz ]
8+ * Cache more things in memory, so flicking scopes should be faster
9+ (LP: #1336724)
10+ * Tweak card header to match the spec
11+ * Save texture memory by limiting sourceSize (LP: #1338430)
12+
13+ [ Ying-Chun Liu ]
14+ * Add attributes to Preview. (LP: #1282460)
15+
16+ [ Albert Astals ]
17+ * Update pot
18+ * Cache more things in memory, so flicking scopes should be faster
19+ (LP: #1336724)
20+ * Save texture memory by limiting sourceSize (LP: #1338430)
21+ * Clip the settings list
22+ * Fix unlocking from the left again
23+ * Add wait_ makes tests more reliable
24+
25+ [ Michael Zanetti ]
26+ * fix fading out the launcher instead of sliding it out on left-edge
27+ minimizing an app.
28+ * Make the DashCommunicator async and more flexible to handle a
29+ lifecycle-suspended dash (LP: #1339883)
30+
31+ [ Michael Terry ]
32+ * Retry unlock-device script if it fails, as there is always a risk of
33+ a small race with boot-up. (LP: #1370644)
34+ * Add pull-to-refresh functionality to scopes. (LP: #1368336)
35+
36+ [ CI bot ]
37+ * Resync trunk
38+
39+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Mon, 06 Oct 2014 08:03:23 +0000
40+
1unity8 (8.00+14.10.20140930.2-0ubuntu1) utopic; urgency=low
41unity8 (8.00+14.10.20140930.2-0ubuntu1) utopic; urgency=low
2
42
3 [ Alexandros Frantzis ]
43 [ Alexandros Frantzis ]
debian/control+2−1
@@ -25,7 +25,7 @@ Build-Depends: cmake,
25 libpulse-dev,
25 libpulse-dev,
26 libqmenumodel-dev (>= 0.2.8),
26 libqmenumodel-dev (>= 0.2.8),
27 libqt5xmlpatterns5-dev,
27 libqt5xmlpatterns5-dev,
28− libunity-api-dev (>= 7.91),
28+ libunity-api-dev (>= 7.92),
29 libusermetricsoutput1-dev,
29 libusermetricsoutput1-dev,
30 libxcb1-dev,
30 libxcb1-dev,
31 pkg-config,
31 pkg-config,
@@ -174,6 +174,7 @@ Depends: accountsservice-ubuntu-schemas (>= 0.0.3),
174 libhardware2,
174 libhardware2,
175 unity-schemas (>= 7.3.1+14.10.20140915),
175 unity-schemas (>= 7.3.1+14.10.20140915),
176 pay-service,
176 pay-service,
177+ qml-module-ubuntu-connectivity,
177 ${misc:Depends},
178 ${misc:Depends},
178 ${shlibs:Depends},
179 ${shlibs:Depends},
179Provides: unity-launcher-impl,
180Provides: unity-launcher-impl,
debian/unity8-private.install+1
@@ -1,3 +1,4 @@
1+usr/lib/*/libunity8-private.*
1usr/lib/*/unity8/qml/AccountsService
2usr/lib/*/unity8/qml/AccountsService
2usr/lib/*/unity8/qml/Dash
3usr/lib/*/unity8/qml/Dash
3usr/lib/*/unity8/qml/HudClient
4usr/lib/*/unity8/qml/HudClient
plugins/Dash/CardAttributes.qml+1−1
@@ -59,7 +59,7 @@ GridLayout {
59 text: "value" in modelData && modelData["value"] || "";
59 text: "value" in modelData && modelData["value"] || "";
60 elide: Text.ElideRight
60 elide: Text.ElideRight
61 maximumLineCount: 1
61 maximumLineCount: 1
62− font.weight: "style" in modelData && modelData["style"] == "highlighted" ? Font.DemiBold : Font.Light
62+ font.weight: "style" in modelData && modelData["style"] === "highlighted" ? Font.Bold : Font.Light
63 fontSize: "small"
63 fontSize: "small"
64 font.pixelSize: Math.round(FontUtils.sizeToPixels(fontSize) * fontScale)
64 font.pixelSize: Math.round(FontUtils.sizeToPixels(fontSize) * fontScale)
65 color: grid.color
65 color: grid.color
plugins/Dash/CardCreator.js+15−16
@@ -82,12 +82,13 @@ var kArtShapeHolderCode = 'Item { \n\
82 height = Qt.binding(function() { return image.status !== Image.Ready ? 0 : image.height }); \n\
82 height = Qt.binding(function() { return image.status !== Image.Ready ? 0 : image.height }); \n\
83 } \n\
83 } \n\
84 } \n\
84 } \n\
85− image: Image { \n\
85+ image: CroppedImageMinimumSourceSize { \n\
86 objectName: "artImage"; \n\
86 objectName: "artImage"; \n\
87+ property bool doLoadSource: !NetworkingStatus.limitedBandwith; \n\
87− source: cardData && cardData["art"] || ""; \n\
88+ source: { if (root.visible) doLoadSource = true; return doLoadSource && cardData && cardData["art"] || ""; } \n\
88 cache: true; \n\
89 cache: true; \n\
89 asynchronous: root.asynchronous; \n\
90 asynchronous: root.asynchronous; \n\
90− fillMode: Image.PreserveAspectCrop; \n\
91+ visible: false; \n\
91 width: %2; \n\
92 width: %2; \n\
92 height: %3; \n\
93 height: %3; \n\
93 } \n\
94 } \n\
@@ -190,16 +191,14 @@ var kMascotShapeLoaderCode = 'Loader { \n\
190
191
191// %1 is used as anchors of mascotImage
192// %1 is used as anchors of mascotImage
192// %2 is used as visible of mascotImage
193// %2 is used as visible of mascotImage
193−var kMascotImageCode = 'Image { \n\
194+var kMascotImageCode = 'CroppedImageMinimumSourceSize { \n\
194 id: mascotImage; \n\
195 id: mascotImage; \n\
195 objectName: "mascotImage"; \n\
196 objectName: "mascotImage"; \n\
196 anchors { %1 } \n\
197 anchors { %1 } \n\
197− readonly property int maxSize: Math.max(width, height) * 4; \n\
198+ property bool doLoadSource: !NetworkingStatus.limitedBandwith; \n\
198− source: cardData && cardData["mascot"] || ""; \n\
199+ source: { if (root.visible) doLoadSource = true; return doLoadSource && cardData && cardData["mascot"] || ""; } \n\
199 width: units.gu(6); \n\
200 width: units.gu(6); \n\
200 height: units.gu(5.625); \n\
201 height: units.gu(5.625); \n\
201− sourceSize { width: maxSize; height: maxSize } \n\
202− fillMode: Image.PreserveAspectCrop; \n\
203 horizontalAlignment: Image.AlignHCenter; \n\
202 horizontalAlignment: Image.AlignHCenter; \n\
204 verticalAlignment: Image.AlignVCenter; \n\
203 verticalAlignment: Image.AlignVCenter; \n\
205 visible: %2; \n\
204 visible: %2; \n\
@@ -220,13 +219,13 @@ var kTitleLabelCode = 'Label { \n\
220 color: %2; \n\
219 color: %2; \n\
221 visible: showHeader %3; \n\
220 visible: showHeader %3; \n\
222 text: root.title; \n\
221 text: root.title; \n\
223− font.weight: components && components["subtitle"] ? Font.DemiBold : Font.Normal; \n\
222+ font.weight: cardData && cardData["subtitle"] ? Font.DemiBold : Font.Normal; \n\
224− horizontalAlignment: root.headerAlignment; \n\
223+ horizontalAlignment: root.titleAlignment; \n\
225 }\n';
224 }\n';
226
225
227// %1 is used as extra anchors of emblemIcon
226// %1 is used as extra anchors of emblemIcon
228// %2 is used as color of emblemIcon
227// %2 is used as color of emblemIcon
229−var kEmblemIconCode = 'Icon { \n\
228+var kEmblemIconCode = 'StatusIcon { \n\
230 id: emblemIcon; \n\
229 id: emblemIcon; \n\
231 objectName: "emblemIcon"; \n\
230 objectName: "emblemIcon"; \n\
232 anchors { \n\
231 anchors { \n\
@@ -236,7 +235,6 @@ var kEmblemIconCode = 'Icon { \n\
236 } \n\
235 } \n\
237 source: cardData && cardData["emblem"] || ""; \n\
236 source: cardData && cardData["emblem"] || ""; \n\
238 color: %2; \n\
237 color: %2; \n\
239− width: height; \n\
240 height: source != "" ? titleLabel.font.pixelSize : 0; \n\
238 height: source != "" ? titleLabel.font.pixelSize : 0; \n\
241 }\n';
239 }\n';
242
240
@@ -258,13 +256,12 @@ var kSubtitleLabelCode = 'Label { \n\
258 anchors { %1 } \n\
256 anchors { %1 } \n\
259 anchors.topMargin: units.dp(2); \n\
257 anchors.topMargin: units.dp(2); \n\
260 elide: Text.ElideRight; \n\
258 elide: Text.ElideRight; \n\
261− fontSize: "small"; \n\
259+ fontSize: "x-small"; \n\
262 font.pixelSize: Math.round(FontUtils.sizeToPixels(fontSize) * fontScale); \n\
260 font.pixelSize: Math.round(FontUtils.sizeToPixels(fontSize) * fontScale); \n\
263 color: %2; \n\
261 color: %2; \n\
264 visible: titleLabel.visible && titleLabel.text; \n\
262 visible: titleLabel.visible && titleLabel.text; \n\
265 text: cardData && cardData["subtitle"] || ""; \n\
263 text: cardData && cardData["subtitle"] || ""; \n\
266 font.weight: Font.Light; \n\
264 font.weight: Font.Light; \n\
267− horizontalAlignment: root.headerAlignment; \n\
268 }\n';
265 }\n';
269
266
270// %1 is used as anchors of attributesRow
267// %1 is used as anchors of attributesRow
@@ -310,7 +307,7 @@ function cardString(template, components) {
310 property var artShapeBorderSource: undefined; \n\
307 property var artShapeBorderSource: undefined; \n\
311 property real fontScale: 1.0; \n\
308 property real fontScale: 1.0; \n\
312 property var scopeStyle: null; \n\
309 property var scopeStyle: null; \n\
313− property int headerAlignment: Text.AlignLeft; \n\
310+ property int titleAlignment: Text.AlignLeft; \n\
314 property int fixedHeaderHeight: -1; \n\
311 property int fixedHeaderHeight: -1; \n\
315 property size fixedArtShapeSize: Qt.size(-1, -1); \n\
312 property size fixedArtShapeSize: Qt.size(-1, -1); \n\
316 readonly property string title: cardData && cardData["title"] || ""; \n\
313 readonly property string title: cardData && cardData["title"] || ""; \n\
@@ -436,7 +433,7 @@ function cardString(template, components) {
436 mascotShapeCode = kMascotShapeLoaderCode.arg(mascotAnchors);
433 mascotShapeCode = kMascotShapeLoaderCode.arg(mascotAnchors);
437 }
434 }
438
435
439− var mascotImageVisible = useMascotShape ? 'false' : 'showHeader';
436+ var mascotImageVisible = useMascotShape ? 'false' : 'showHeader && resized';
440 mascotCode = kMascotImageCode.arg(mascotAnchors).arg(mascotImageVisible);
437 mascotCode = kMascotImageCode.arg(mascotAnchors).arg(mascotImageVisible);
441 }
438 }
442
439
@@ -655,6 +652,8 @@ function cardString(template, components) {
655function createCardComponent(parent, template, components) {
652function createCardComponent(parent, template, components) {
656 var imports = 'import QtQuick 2.2; \n\
653 var imports = 'import QtQuick 2.2; \n\
657 import Ubuntu.Components 1.1; \n\
654 import Ubuntu.Components 1.1; \n\
655+ import Ubuntu.Settings.Components 0.1; \n\
656+ import Ubuntu.Connectivity 1.0; \n\
658 import Dash 0.1;\n\
657 import Dash 0.1;\n\
659 import Utils 0.1;\n';
658 import Utils 0.1;\n';
660 var card = cardString(template, components);
659 var card = cardString(template, components);
plugins/Dash/CroppedImageMinimumSourceSize.qmlnew file+38
@@ -0,0 +1,38 @@
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.3
18+
19+Image {
20+ property bool resized: false
21+ property bool resizing: false
22+ fillMode: Image.PreserveAspectCrop
23+ visible: resized
24+ onSourceSizeChanged: {
25+ if (!resized && !resizing) {
26+ resizing = true;
27+ var ar = width / height;
28+ var ssar = sourceSize.width / sourceSize.height;
29+ if (ar > ssar) {
30+ sourceSize = Qt.size(width, 0);
31+ } else {
32+ sourceSize = Qt.size(0, height);
33+ }
34+ resizing = false;
35+ resized = true;
36+ }
37+ }
38+}
plugins/Dash/listviewwithpageheader.cpp+18−7
@@ -104,8 +104,6 @@
104#pragma GCC diagnostic pop
104#pragma GCC diagnostic pop
105// #include <private/qquickrectangle_p.h>
105// #include <private/qquickrectangle_p.h>
106
106
107−static const qreal bufferRatio = 0.5;
108−
109qreal ListViewWithPageHeader::ListItem::height() const
107qreal ListViewWithPageHeader::ListItem::height() const
110{
108{
111 return m_item->height() + (m_sectionItem ? m_sectionItem->height() : 0);
109 return m_item->height() + (m_sectionItem ? m_sectionItem->height() : 0);
@@ -158,6 +156,7 @@ ListViewWithPageHeader::ListViewWithPageHeader()
158 , m_forceNoClip(false)
156 , m_forceNoClip(false)
159 , m_inLayout(false)
157 , m_inLayout(false)
160 , m_inContentHeightKeepHeaderShown(false)
158 , m_inContentHeightKeepHeaderShown(false)
159+ , m_cacheBuffer(0)
161{
160{
162 m_clipItem = new QQuickItem(contentItem());
161 m_clipItem = new QQuickItem(contentItem());
163// m_clipItem = new QQuickRectangle(contentItem());
162// m_clipItem = new QQuickRectangle(contentItem());
@@ -335,6 +334,20 @@ qreal ListViewWithPageHeader::headerItemShownHeight() const
335 return m_headerItemShownHeight;
334 return m_headerItemShownHeight;
336}
335}
337
336
337+qreal ListViewWithPageHeader::cacheBuffer() const
338+{
339+ return m_cacheBuffer;
340+}
341+
342+void ListViewWithPageHeader::setCacheBuffer(qreal cacheBuffer)
343+{
344+ if (cacheBuffer != m_cacheBuffer) {
345+ m_cacheBuffer = cacheBuffer;
346+ Q_EMIT cacheBufferChanged();
347+ polish();
348+ }
349+}
350+
338void ListViewWithPageHeader::positionAtBeginning()
351void ListViewWithPageHeader::positionAtBeginning()
339{
352{
340 if (m_delegateModel->count() <= 0)
353 if (m_delegateModel->count() <= 0)
@@ -356,8 +369,7 @@ void ListViewWithPageHeader::positionAtBeginning()
356 // Create the subsequent items
369 // Create the subsequent items
357 int modelIndex = 1;
370 int modelIndex = 1;
358 qreal pos = item->y() + item->height();
371 qreal pos = item->y() + item->height();
359− const qreal buffer = height() * bufferRatio;
360− const qreal bufferTo = height() + buffer;
372+ const qreal bufferTo = height() + m_cacheBuffer;
361 while (modelIndex < m_delegateModel->count() && pos <= bufferTo) {
373 while (modelIndex < m_delegateModel->count() && pos <= bufferTo) {
362 if (!(item = createItem(modelIndex, false)))
374 if (!(item = createItem(modelIndex, false)))
363 break;
375 break;
@@ -603,11 +615,10 @@ void ListViewWithPageHeader::refill()
603 return;
615 return;
604 }
616 }
605
617
606− const qreal buffer = height() * bufferRatio;
607 const qreal from = contentY();
618 const qreal from = contentY();
608 const qreal to = from + height();
619 const qreal to = from + height();
609− const qreal bufferFrom = from - buffer;
620+ const qreal bufferFrom = from - m_cacheBuffer;
610− const qreal bufferTo = to + buffer;
621+ const qreal bufferTo = to + m_cacheBuffer;
611
622
612 bool added = addVisibleItems(from, to, false);
623 bool added = addVisibleItems(from, to, false);
613 bool removed = removeNonVisibleItems(bufferFrom, bufferTo);
624 bool removed = removeNonVisibleItems(bufferFrom, bufferTo);
plugins/Dash/listviewwithpageheader.h+6
@@ -54,6 +54,7 @@ class ListViewWithPageHeader : public QQuickFlickable, public QQuickItemChangeLi
54 Q_PROPERTY(bool forceNoClip READ forceNoClip WRITE setForceNoClip NOTIFY forceNoClipChanged)
54 Q_PROPERTY(bool forceNoClip READ forceNoClip WRITE setForceNoClip NOTIFY forceNoClipChanged)
55 Q_PROPERTY(int stickyHeaderHeight READ stickyHeaderHeight NOTIFY stickyHeaderHeightChanged)
55 Q_PROPERTY(int stickyHeaderHeight READ stickyHeaderHeight NOTIFY stickyHeaderHeightChanged)
56 Q_PROPERTY(qreal headerItemShownHeight READ headerItemShownHeight NOTIFY headerItemShownHeightChanged)
56 Q_PROPERTY(qreal headerItemShownHeight READ headerItemShownHeight NOTIFY headerItemShownHeightChanged)
57+ Q_PROPERTY(qreal cacheBuffer READ cacheBuffer WRITE setCacheBuffer NOTIFY cacheBufferChanged)
57
58
58 friend class ListViewWithPageHeaderTest;
59 friend class ListViewWithPageHeaderTest;
59 friend class ListViewWithPageHeaderTestSection;
60 friend class ListViewWithPageHeaderTestSection;
@@ -84,6 +85,9 @@ public:
84 int stickyHeaderHeight() const;
85 int stickyHeaderHeight() const;
85 qreal headerItemShownHeight() const;
86 qreal headerItemShownHeight() const;
86
87
88+ qreal cacheBuffer() const;
89+ void setCacheBuffer(qreal cacheBuffer);
90+
87 Q_INVOKABLE void positionAtBeginning();
91 Q_INVOKABLE void positionAtBeginning();
88 Q_INVOKABLE void showHeader();
92 Q_INVOKABLE void showHeader();
89 Q_INVOKABLE int firstCreatedIndex() const;
93 Q_INVOKABLE int firstCreatedIndex() const;
@@ -105,6 +109,7 @@ Q_SIGNALS:
105 void forceNoClipChanged();
109 void forceNoClipChanged();
106 void stickyHeaderHeightChanged();
110 void stickyHeaderHeightChanged();
107 void headerItemShownHeightChanged();
111 void headerItemShownHeightChanged();
112+ void cacheBufferChanged();
108
113
109protected:
114protected:
110 void componentComplete() override;
115 void componentComplete() override;
@@ -199,6 +204,7 @@ private:
199 bool m_forceNoClip;
204 bool m_forceNoClip;
200 bool m_inLayout;
205 bool m_inLayout;
201 bool m_inContentHeightKeepHeaderShown;
206 bool m_inContentHeightKeepHeaderShown;
207+ qreal m_cacheBuffer;
202
208
203 // Qt 5.0 doesn't like releasing the items just after itemCreated
209 // Qt 5.0 doesn't like releasing the items just after itemCreated
204 // so we delay the releasing until the next updatePolish
210 // so we delay the releasing until the next updatePolish
plugins/Dash/qmldir+2−1
@@ -3,4 +3,5 @@ plugin Dash-qml
3typeinfo Dash.qmltypes
3typeinfo Dash.qmltypes
4singleton CardCreatorCache 0.1 CardCreatorCache.qml
4singleton CardCreatorCache 0.1 CardCreatorCache.qml
5ScopeStyle 0.1 ScopeStyle.qml
5ScopeStyle 0.1 ScopeStyle.qml
6−CardAttributes 0.1 CardAttributes.qml
6+CardAttributes 0.1 CardAttributes.qml
7+CroppedImageMinimumSourceSize 0.1 CroppedImageMinimumSourceSize.qml
plugins/LightDM/DBusGreeter.h−1
@@ -21,7 +21,6 @@
21#include <QObject>
21#include <QObject>
22
22
23class Greeter;
23class Greeter;
24−class QDBusInterface;
25
24
26/** This is an internal class used to talk with the indicators.
25/** This is an internal class used to talk with the indicators.
27 */
26 */
plugins/LightDM/DBusGreeterList.h−1
@@ -21,7 +21,6 @@
21#include <QObject>
21#include <QObject>
22
22
23class Greeter;
23class Greeter;
24−class QDBusInterface;
25
24
26/** This is an internal class used to talk with the indicators.
25/** This is an internal class used to talk with the indicators.
27 */
26 */
plugins/Unity/DashCommunicator/CMakeLists.txt+8−2
@@ -1,5 +1,6 @@
1include_directories(
1include_directories(
2 ${CMAKE_CURRENT_SOURCE_DIR}
2 ${CMAKE_CURRENT_SOURCE_DIR}
3+ ${libunity8-private_SOURCE_DIR}
3)
4)
4
5
5set(QMLDASHCOMMUNICATORPLUGIN_SRC
6set(QMLDASHCOMMUNICATORPLUGIN_SRC
@@ -7,13 +8,18 @@ set(QMLDASHCOMMUNICATORPLUGIN_SRC
7 dbusdashcommunicatorservice.cpp
8 dbusdashcommunicatorservice.cpp
8 dashcommunicatorservice.cpp
9 dashcommunicatorservice.cpp
9 dashcommunicator.cpp
10 dashcommunicator.cpp
11+ dashconnection.cpp
10− )
12+)
11
13
12add_library(DashCommunicator-qml MODULE
14add_library(DashCommunicator-qml MODULE
13 ${QMLDASHCOMMUNICATORPLUGIN_SRC}
15 ${QMLDASHCOMMUNICATORPLUGIN_SRC}
14− )
16+)
15
17
16qt5_use_modules(DashCommunicator-qml DBus Qml)
18qt5_use_modules(DashCommunicator-qml DBus Qml)
17
19
20+target_link_libraries(DashCommunicator-qml
21+ unity8-private
22+)
23+
18# export the qmldir and qmltypes files
24# export the qmldir and qmltypes files
19add_unity8_plugin(Unity.DashCommunicator 0.1 Unity/DashCommunicator TARGETS DashCommunicator-qml)
25add_unity8_plugin(Unity.DashCommunicator 0.1 Unity/DashCommunicator TARGETS DashCommunicator-qml)
plugins/Unity/DashCommunicator/dashcommunicator.cpp+22−13
@@ -15,29 +15,38 @@
15 */
15 */
16
16
17#include "dashcommunicator.h"
17#include "dashcommunicator.h"
18+#include "dashconnection.h"
18
19
19#include <QObject>
20#include <QObject>
20−#include <QDBusConnection>
21−#include <QDBusInterface>
22−#include <QDebug>
23
21
24DashCommunicator::DashCommunicator(QObject *parent):
22DashCommunicator::DashCommunicator(QObject *parent):
25− QObject(parent)
23+ QThread(parent),
24+ m_dashConnection(nullptr),
25+ m_created(false)
26{
26{
27+ start();
27}
28}
28
29
29−DashCommunicator::~DashCommunicator()
30+void DashCommunicator::setCurrentScope(const QString &scopeId, bool animate, bool isSwipe)
30{
31{
32+ m_mutex.lock();
33+ if (m_created) {
34+ QMetaObject::invokeMethod(m_dashConnection, "setCurrentScope",
35+ Q_ARG(QString, scopeId),
36+ Q_ARG(bool, animate),
37+ Q_ARG(bool, isSwipe));
38+ }
39+ m_mutex.unlock();
31}
40}
32
41
33−
34−void DashCommunicator::setCurrentScope(const QString &scopeId, bool animate, bool isSwipe)
42+void DashCommunicator::run()
35{
43{
36− QDBusConnection connection = QDBusConnection::sessionBus();
37− QDBusInterface dashIface ("com.canonical.UnityDash",
44+ m_dashConnection = new DashConnection("com.canonical.UnityDash",
38− "/com/canonical/UnityDash",
45+ "/com/canonical/UnityDash",
39− "",
46+ "", this);
40− connection);
47+ m_mutex.lock();
48+ m_created = true;
49+ m_mutex.unlock();
41
50
42− dashIface.call("SetCurrentScope", scopeId, animate, isSwipe);
51+ exec();
43}
52}
plugins/Unity/DashCommunicator/dashcommunicator.h+16−6
@@ -17,19 +17,29 @@
17#ifndef DASHCOMMUNICATOR_H
17#ifndef DASHCOMMUNICATOR_H
18#define DASHCOMMUNICATOR_H
18#define DASHCOMMUNICATOR_H
19
19
20+// Qt
20−#include <QObject>
21+#include <QThread>
22+#include <QMutex>
21
23
24+class DashConnection;
25+
22−class DashCommunicator: public QObject
26+class DashCommunicator: public QThread
23{
27{
24 Q_OBJECT
28 Q_OBJECT
25− Q_CLASSINFO("D-Bus Interface", "com.canonical.Unity.DashCommunicator")
26−
27public:
29public:
28− DashCommunicator(QObject *parent = 0);
30+ explicit DashCommunicator(QObject *parent = 0);
29− ~DashCommunicator();
31+ ~DashCommunicator() = default;
30
32
31public Q_SLOTS:
33public Q_SLOTS:
32 void setCurrentScope(const QString &scopeId, bool animate, bool isSwipe);
34 void setCurrentScope(const QString &scopeId, bool animate, bool isSwipe);
35+
36+protected:
37+ void run() override;
38+
39+private:
40+ DashConnection *m_dashConnection;
41+ bool m_created;
42+ QMutex m_mutex;
33};
43};
34
44
35#endif
45#endif
plugins/Unity/DashCommunicator/dashconnection.cppnew file+33
@@ -0,0 +1,33 @@
1+/*
2+ * Copyright (C) 2014 Canonical, Ltd.
3+ *
4+ * This program is free software: you can redistribute it and/or modify it under
5+ * the terms of the GNU Lesser General Public License version 3, as published by
6+ * the Free Software Foundation.
7+ *
8+ * This program is distributed in the hope that it will be useful, but WITHOUT
9+ * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
10+ * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11+ * Lesser General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU Lesser General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+#include "dashconnection.h"
18+
19+#include <QDBusInterface>
20+#include <QDBusPendingCall>
21+
22+DashConnection::DashConnection(const QString &service, const QString &path, const QString &interface, QObject *parent):
23+ AbstractDBusServiceMonitor(service, path, interface, SessionBus, parent)
24+{
25+
26+}
27+
28+void DashConnection::setCurrentScope(const QString &scopeId, bool animate, bool isSwipe)
29+{
30+ if (dbusInterface()) {
31+ dbusInterface()->asyncCall("SetCurrentScope", scopeId, animate, isSwipe);
32+ }
33+}
plugins/Unity/DashCommunicator/dashconnection.hnew file+34
@@ -0,0 +1,34 @@
1+/*
2+ * Copyright (C) 2014 Canonical, Ltd.
3+ *
4+ * This program is free software: you can redistribute it and/or modify it under
5+ * the terms of the GNU Lesser General Public License version 3, as published by
6+ * the Free Software Foundation.
7+ *
8+ * This program is distributed in the hope that it will be useful, but WITHOUT
9+ * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
10+ * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11+ * Lesser General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU Lesser General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+#ifndef THREADEDDASHCONNECTION_H
18+#define THREADEDDASHCONNECTION_H
19+
20+// local
21+#include "abstractdbusservicemonitor.h"
22+
23+
24+class DashConnection: public AbstractDBusServiceMonitor
25+{
26+ Q_OBJECT
27+public:
28+ DashConnection(const QString &service, const QString &path, const QString &interface, QObject *parent = 0);
29+
30+public Q_SLOTS:
31+ void setCurrentScope(const QString &scopeId, bool animate, bool isSwipe);
32+};
33+
34+#endif
plugins/Unity/Launcher/CMakeLists.txt+1−1
@@ -1,6 +1,6 @@
1include(FindPkgConfig)
1include(FindPkgConfig)
2pkg_check_modules(LAUNCHER_API REQUIRED unity-shell-launcher=4)
2pkg_check_modules(LAUNCHER_API REQUIRED unity-shell-launcher=4)
3−pkg_check_modules(APPLICATION_API REQUIRED unity-shell-application=4)
3+pkg_check_modules(APPLICATION_API REQUIRED unity-shell-application=5)
4pkg_check_modules(GSETTINGS_QT REQUIRED gsettings-qt)
4pkg_check_modules(GSETTINGS_QT REQUIRED gsettings-qt)
5
5
6add_definitions(-DSM_BUSNAME=systemBus)
6add_definitions(-DSM_BUSNAME=systemBus)
po/es.po+5−3
@@ -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-10-02 10:35+0200\n"
10"POT-Creation-Date: 2014-10-02 10:35+0200\n"
11−"PO-Revision-Date: 2014-10-04 07:49+0000\n"
11+"PO-Revision-Date: 2014-10-05 08:50+0000\n"
12−"Last-Translator: Víctor R. Ruiz <Unknown>\n"
12+"Last-Translator: Paco Molinero <paco@byasl.com>\n"
13"Language-Team: Spanish <es@li.org>\n"
13"Language-Team: Spanish <es@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=2; plural=n != 1;\n"
17"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2014-10-05 06:38+0000\n"
18+"X-Launchpad-Export-Date: 2014-10-06 07:00+0000\n"
19"X-Generator: Launchpad (build 17196)\n"
19"X-Generator: Launchpad (build 17196)\n"
20
20
21#: plugins/LightDM/Greeter.cpp:130
21#: plugins/LightDM/Greeter.cpp:130
@@ -38,6 +38,8 @@ msgstr "Dispositivo bloqueado"
38#: qml/Components/DelayedLockscreen.qml:62
38#: qml/Components/DelayedLockscreen.qml:62
39msgid "You have been locked out due to too many failed passphrase attempts."
39msgid "You have been locked out due to too many failed passphrase attempts."
40msgstr ""
40msgstr ""
41+"Se ha proporcionado una contraseña errónea demasiadas veces. Se ha bloqueado "
42+"el dispositivo."
41
43
42#: qml/Components/DelayedLockscreen.qml:63
44#: qml/Components/DelayedLockscreen.qml:63
43msgid "You have been locked out due to too many failed passcode attempts."
45msgid "You have been locked out due to too many failed passcode attempts."
po/is.po+31−12
@@ -10,14 +10,14 @@ msgstr ""
10"Project-Id-Version: po_unity8-is\n"
10"Project-Id-Version: po_unity8-is\n"
11"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
11"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
12"POT-Creation-Date: 2014-10-02 10:35+0200\n"
12"POT-Creation-Date: 2014-10-02 10:35+0200\n"
13−"PO-Revision-Date: 2014-09-21 12:07+0000\n"
13+"PO-Revision-Date: 2014-10-05 08:44+0000\n"
14"Last-Translator: Sveinn í Felli <sv1@fellsnet.is>\n"
14"Last-Translator: Sveinn í Felli <sv1@fellsnet.is>\n"
15"Language-Team: Icelandic <translation-team-is@lists.sourceforge.net>\n"
15"Language-Team: Icelandic <translation-team-is@lists.sourceforge.net>\n"
16"MIME-Version: 1.0\n"
16"MIME-Version: 1.0\n"
17"Content-Type: text/plain; charset=UTF-8\n"
17"Content-Type: text/plain; charset=UTF-8\n"
18"Content-Transfer-Encoding: 8bit\n"
18"Content-Transfer-Encoding: 8bit\n"
19"Plural-Forms: nplurals=2; plural=n != 1;\n"
19"Plural-Forms: nplurals=2; plural=n != 1;\n"
20−"X-Launchpad-Export-Date: 2014-10-03 06:21+0000\n"
20+"X-Launchpad-Export-Date: 2014-10-06 07:00+0000\n"
21"X-Generator: Launchpad (build 17196)\n"
21"X-Generator: Launchpad (build 17196)\n"
22"Language: is\n"
22"Language: is\n"
23
23
@@ -59,7 +59,7 @@ msgstr "Útskráning"
59
59
60#: qml/Components/Dialogs.qml:71
60#: qml/Components/Dialogs.qml:71
61msgid "Are you sure you want to log out?"
61msgid "Are you sure you want to log out?"
62−msgstr ""
62+msgstr "Ertu viss um að þú viljir skrá þig út?"
63
63
64#: qml/Components/Dialogs.qml:73 qml/Components/Dialogs.qml:97
64#: qml/Components/Dialogs.qml:73 qml/Components/Dialogs.qml:97
65#: qml/Components/Dialogs.qml:122
65#: qml/Components/Dialogs.qml:122
@@ -77,7 +77,7 @@ msgstr "Slökkva á tölvunni"
77
77
78#: qml/Components/Dialogs.qml:95
78#: qml/Components/Dialogs.qml:95
79msgid "Are you sure you want to shut down?"
79msgid "Are you sure you want to shut down?"
80−msgstr ""
80+msgstr "Ertu viss um að þú viljir slökkva á símanum?"
81
81
82#: qml/Components/Dialogs.qml:119
82#: qml/Components/Dialogs.qml:119
83msgid "Reboot"
83msgid "Reboot"
@@ -85,7 +85,7 @@ msgstr "Endurræsa"
85
85
86#: qml/Components/Dialogs.qml:120
86#: qml/Components/Dialogs.qml:120
87msgid "Are you sure you want to reboot?"
87msgid "Are you sure you want to reboot?"
88−msgstr ""
88+msgstr "Ertu viss að þú viljir enduræsa?"
89
89
90#: qml/Components/Dialogs.qml:144
90#: qml/Components/Dialogs.qml:144
91msgid "Power"
91msgid "Power"
@@ -96,6 +96,8 @@ msgid ""
96"Are you sure you would like\n"
96"Are you sure you would like\n"
97"to power off?"
97"to power off?"
98msgstr ""
98msgstr ""
99+"Ertu viss um að þú viljir\n"
100+"slökkva á símanum?"
99
101
100#: qml/Components/Dialogs.qml:147
102#: qml/Components/Dialogs.qml:147
101msgid "Power off"
103msgid "Power off"
@@ -309,7 +311,7 @@ msgstr "Aflæsa SIM-korti"
309
311
310#: qml/Panel/Indicators/RoamingIndication.qml:27
312#: qml/Panel/Indicators/RoamingIndication.qml:27
311msgid "Roaming"
313msgid "Roaming"
312−msgstr ""
314+msgstr "Ráphamur"
313
315
314#: qml/Shell.qml:340
316#: qml/Shell.qml:340
315msgid "Enter passphrase"
317msgid "Enter passphrase"
@@ -317,7 +319,7 @@ msgstr ""
317
319
318#: qml/Shell.qml:321
320#: qml/Shell.qml:321
319msgid "Sorry, incorrect passphrase"
321msgid "Sorry, incorrect passphrase"
320−msgstr ""
322+msgstr "Því miður, rangt lykilorð"
321
323
322#: qml/Shell.qml:342
324#: qml/Shell.qml:342
323msgid "Please re-enter"
325msgid "Please re-enter"
@@ -329,7 +331,7 @@ msgstr ""
329
331
330#: qml/Shell.qml:324
332#: qml/Shell.qml:324
331msgid "Sorry, incorrect passcode"
333msgid "Sorry, incorrect passcode"
332−msgstr ""
334+msgstr "Því miður, rangur aðgangskóði"
333
335
334#: qml/Shell.qml:348
336#: qml/Shell.qml:348
335#, qt-format
337#, qt-format
@@ -339,31 +341,35 @@ msgstr ""
339#: qml/Shell.qml:328
341#: qml/Shell.qml:328
340#, qt-format
342#, qt-format
341msgid "Sorry, incorrect %1"
343msgid "Sorry, incorrect %1"
342−msgstr ""
344+msgstr "Því miður, rangt %1"
343
345
344#: qml/Shell.qml:363
346#: qml/Shell.qml:363
345msgid "Sorry, incorrect passphrase."
347msgid "Sorry, incorrect passphrase."
346−msgstr ""
348+msgstr "Því miður, rangt lykilorð."
347
349
348#: qml/Shell.qml:364
350#: qml/Shell.qml:364
349msgid "Sorry, incorrect passcode."
351msgid "Sorry, incorrect passcode."
350−msgstr ""
352+msgstr "Því miður, rangur aðgangskóði."
351
353
352#: qml/Shell.qml:365
354#: qml/Shell.qml:365
353msgid "This will be your last attempt."
355msgid "This will be your last attempt."
354−msgstr ""
356+msgstr "Þetta mun verða síðasta tilraunin þín."
355
357
356#: qml/Shell.qml:367
358#: qml/Shell.qml:367
357msgid ""
359msgid ""
358"If passphrase is entered incorrectly, your phone will conduct a factory "
360"If passphrase is entered incorrectly, your phone will conduct a factory "
359"reset and all personal data will be deleted."
361"reset and all personal data will be deleted."
360msgstr ""
362msgstr ""
363+"Ef lykilorð er rangt, mun síminn frumstilla allt á verksmiðjustillingar og "
364+"öllum einkagögnum verður eytt."
361
365
362#: qml/Shell.qml:368
366#: qml/Shell.qml:368
363msgid ""
367msgid ""
364"If passcode is entered incorrectly, your phone will conduct a factory reset "
368"If passcode is entered incorrectly, your phone will conduct a factory reset "
365"and all personal data will be deleted."
369"and all personal data will be deleted."
366msgstr ""
370msgstr ""
371+"Ef aðgangskóði er rangur, mun síminn frumstilla allt á verksmiðjustillingar "
372+"og öllum einkagögnum verður eytt."
367
373
368#, qt-format
374#, qt-format
369#~ msgid "Hello %1"
375#~ msgid "Hello %1"
@@ -377,3 +383,16 @@ msgstr ""
377
383
378#~ msgid "Please wait"
384#~ msgid "Please wait"
379#~ msgstr "Bíddu aðeins"
385#~ msgstr "Bíddu aðeins"
386+
387+#~ msgid "Too many incorrect attempts"
388+#~ msgstr "Of margar rangar tilraunir"
389+
390+#~ msgid "Enter your passphrase"
391+#~ msgstr "Sláðu inn lykilorðið þitt"
392+
393+#~ msgid "Enter your passcode"
394+#~ msgstr "Settu inn aðgangskóðann þinn"
395+
396+#, qt-format
397+#~ msgid "Enter your %1"
398+#~ msgstr "Settu inn %1"
po/ug.po+11−15
@@ -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-10-02 10:35+0200\n"
10"POT-Creation-Date: 2014-10-02 10:35+0200\n"
11−"PO-Revision-Date: 2014-09-29 00:52+0000\n"
11+"PO-Revision-Date: 2014-10-06 00:47+0000\n"
12"Last-Translator: Gheyret T.Kenji <Unknown>\n"
12"Last-Translator: Gheyret T.Kenji <Unknown>\n"
13"Language-Team: Uyghur Computer Science Association <UKIJ@yahoogroups.com>\n"
13"Language-Team: Uyghur Computer Science Association <UKIJ@yahoogroups.com>\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"
17"Plural-Forms: nplurals=1; plural=0;\n"
18−"X-Launchpad-Export-Date: 2014-10-03 06:22+0000\n"
18+"X-Launchpad-Export-Date: 2014-10-06 07:00+0000\n"
19"X-Generator: Launchpad (build 17196)\n"
19"X-Generator: Launchpad (build 17196)\n"
20
20
21#: plugins/LightDM/Greeter.cpp:130
21#: plugins/LightDM/Greeter.cpp:130
@@ -33,22 +33,21 @@ msgstr "تېزلەتمىنى ئېلىۋەت"
33
33
34#: qml/Components/DelayedLockscreen.qml:47
34#: qml/Components/DelayedLockscreen.qml:47
35msgid "Device Locked"
35msgid "Device Locked"
36−msgstr ""
36+msgstr "ئۈسكۈنە قۇلۇپلانغان"
37
37
38#: qml/Components/DelayedLockscreen.qml:62
38#: qml/Components/DelayedLockscreen.qml:62
39msgid "You have been locked out due to too many failed passphrase attempts."
39msgid "You have been locked out due to too many failed passphrase attempts."
40−msgstr ""
40+msgstr "خاتا ئىم جۈملىسى كۆپ قېتىم كىرگۈزۈلگەنلىكى ئۈچۈن قۇلۇپلاندى."
41
41
42#: qml/Components/DelayedLockscreen.qml:63
42#: qml/Components/DelayedLockscreen.qml:63
43msgid "You have been locked out due to too many failed passcode attempts."
43msgid "You have been locked out due to too many failed passcode attempts."
44−msgstr ""
44+msgstr "خاتا ئىم كودى(passcode) كۆپ قېتىم كىرگۈزۈلگەنلىكى ئۈچۈن قۇلۇپلاندى."
45
45
46#: qml/Components/DelayedLockscreen.qml:72
46#: qml/Components/DelayedLockscreen.qml:72
47#, qt-format
47#, qt-format
48msgid "Please wait %1 minute and then try again…"
48msgid "Please wait %1 minute and then try again…"
49msgid_plural "Please wait %1 minutes and then try again…"
49msgid_plural "Please wait %1 minutes and then try again…"
50−msgstr[0] ""
50+msgstr[0] "%1 مىنۇت كۈتۈپ ئاندىن قايتا سىناڭ…"
51−msgstr[1] ""
52
51
53#: qml/Components/Dialogs.qml:70
52#: qml/Components/Dialogs.qml:70
54msgid "Log out"
53msgid "Log out"
@@ -231,7 +230,7 @@ msgstr "ھەممىسى"
231
230
232#: qml/Greeter/Greeter.qml:157
231#: qml/Greeter/Greeter.qml:157
233msgid "Unlock"
232msgid "Unlock"
234−msgstr ""
233+msgstr "قۇلۇپسىزلا"
235
234
236#: qml/Hud/HudParametrizedActionsPage.qml:139
235#: qml/Hud/HudParametrizedActionsPage.qml:139
237msgid "Confirm"
236msgid "Confirm"
@@ -311,7 +310,7 @@ msgstr "كەزمە"
311
310
312#: qml/Shell.qml:340
311#: qml/Shell.qml:340
313msgid "Enter passphrase"
312msgid "Enter passphrase"
314−msgstr ""
313+msgstr "ئىم كىرگۈزۈڭ"
315
314
316#: qml/Shell.qml:321
315#: qml/Shell.qml:321
317msgid "Sorry, incorrect passphrase"
316msgid "Sorry, incorrect passphrase"
@@ -319,11 +318,11 @@ msgstr "كەچۈرۈڭ، ئىم توغرا ئەمەس"
319
318
320#: qml/Shell.qml:342
319#: qml/Shell.qml:342
321msgid "Please re-enter"
320msgid "Please re-enter"
322−msgstr ""
321+msgstr "قايتا كىرگۈزۈڭ"
323
322
324#: qml/Shell.qml:344
323#: qml/Shell.qml:344
325msgid "Enter passcode"
324msgid "Enter passcode"
326−msgstr ""
325+msgstr "ئىم كودى(passcode)نى كىرگۈزۈڭ"
327
326
328#: qml/Shell.qml:324
327#: qml/Shell.qml:324
329msgid "Sorry, incorrect passcode"
328msgid "Sorry, incorrect passcode"
@@ -332,7 +331,7 @@ msgstr "كەچۈرۈڭ، ئىم توغرا ئەمەس"
332#: qml/Shell.qml:348
331#: qml/Shell.qml:348
333#, qt-format
332#, qt-format
334msgid "Enter %1"
333msgid "Enter %1"
335−msgstr ""
334+msgstr "%1 نى كىرگۈزۈڭ"
336
335
337#: qml/Shell.qml:328
336#: qml/Shell.qml:328
338#, qt-format
337#, qt-format
@@ -380,9 +379,6 @@ msgstr ""
380#~ msgid "Please wait"
379#~ msgid "Please wait"
381#~ msgstr "سەل ساقلاڭ"
380#~ msgstr "سەل ساقلاڭ"
382
381
383−#~ msgid "Manage Dash"
384−#~ msgstr "باش تاختىنى باشقۇرۇش"
385−
386#~ msgid "Enter your passphrase"
382#~ msgid "Enter your passphrase"
387#~ msgstr "ئىمىڭىزنى كىرگۈزۈڭ"
383#~ msgstr "ئىمىڭىزنى كىرگۈزۈڭ"
388
384
po/unity8.pot+10−2
@@ -8,7 +8,7 @@ msgid ""
8msgstr ""
8msgstr ""
9"Project-Id-Version: unity8\n"
9"Project-Id-Version: unity8\n"
10"Report-Msgid-Bugs-To: \n"
10"Report-Msgid-Bugs-To: \n"
11−"POT-Creation-Date: 2014-10-02 10:35+0200\n"
11+"POT-Creation-Date: 2014-10-03 08:13-0400\n"
12"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
12"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
13"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
13"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
14"Language-Team: LANGUAGE <LL@li.org>\n"
14"Language-Team: LANGUAGE <LL@li.org>\n"
@@ -160,7 +160,7 @@ msgstr ""
160msgid "OK"
160msgid "OK"
161msgstr ""
161msgstr ""
162
162
163−#: qml/Dash/GenericScopeView.qml:411 qml/Dash/GenericScopeView.qml:533
163+#: qml/Dash/GenericScopeView.qml:411 qml/Dash/GenericScopeView.qml:568
164msgid "See less"
164msgid "See less"
165msgstr ""
165msgstr ""
166
166
@@ -205,6 +205,14 @@ msgstr ""
205msgid "Send"
205msgid "Send"
206msgstr ""
206msgstr ""
207
207
208+#: qml/Dash/PullToRefreshScopeStyle.qml:55
209+msgid "Pull to refresh…"
210+msgstr ""
211+
212+#: qml/Dash/PullToRefreshScopeStyle.qml:60
213+msgid "Release to refresh…"
214+msgstr ""
215+
208#: qml/Dash/ScopesOverview.qml:206
216#: qml/Dash/ScopesOverview.qml:206
209msgid "Manage Scopes"
217msgid "Manage Scopes"
210msgstr ""
218msgstr ""
qml/Components/LazyImage.qml+1
@@ -37,6 +37,7 @@ Item {
37 property alias horizontalAlignment: image.horizontalAlignment
37 property alias horizontalAlignment: image.horizontalAlignment
38 property alias verticalAlignment: image.verticalAlignment
38 property alias verticalAlignment: image.verticalAlignment
39 property alias sourceImage: image
39 property alias sourceImage: image
40+ property alias borderSource: shape.borderSource
40
41
41 state: "default"
42 state: "default"
42
43
qml/Components/ResponsiveGridView.qml+5−1
@@ -34,7 +34,11 @@ Item {
34 readonly property int cellWidth: gridView.cellWidth
34 readonly property int cellWidth: gridView.cellWidth
35 readonly property int cellHeight: gridView.cellHeight
35 readonly property int cellHeight: gridView.cellHeight
36 readonly property int totalContentHeight: {
36 readonly property int totalContentHeight: {
37+ if (gridView.model) {
37− return contentHeightForRows(Math.ceil(gridView.model.count / columns), cellHeight)
38+ return contentHeightForRows(Math.ceil(gridView.model.count / columns), cellHeight)
39+ } else {
40+ return 0;
41+ }
38 }
42 }
39 property alias interactive: gridView.interactive
43 property alias interactive: gridView.interactive
40 readonly property alias flicking: gridView.flicking
44 readonly property alias flicking: gridView.flicking
qml/Dash/CardGrid.qml+2−1
@@ -55,6 +55,7 @@ DashRenderer {
55 delegate: Item {
55 delegate: Item {
56 width: grid.cellWidth
56 width: grid.cellWidth
57 height: grid.cellHeight
57 height: grid.cellHeight
58+ visible: y + height >= root.visibleRangeBegin && y <= root.visibleRangeEnd
58 Loader {
59 Loader {
59 id: loader
60 id: loader
60 sourceComponent: cardTool.cardComponent
61 sourceComponent: cardTool.cardComponent
@@ -68,7 +69,7 @@ DashRenderer {
68 item.cardData = Qt.binding(function() { return model; });
69 item.cardData = Qt.binding(function() { return model; });
69 item.template = Qt.binding(function() { return cardTool.template; });
70 item.template = Qt.binding(function() { return cardTool.template; });
70 item.components = Qt.binding(function() { return cardTool.components; });
71 item.components = Qt.binding(function() { return cardTool.components; });
71− item.headerAlignment = Qt.binding(function() { return cardTool.headerAlignment; });
72+ item.titleAlignment = Qt.binding(function() { return cardTool.titleAlignment; });
72 item.scopeStyle = root.scopeStyle;
73 item.scopeStyle = root.scopeStyle;
73 }
74 }
74 Connections {
75 Connections {
qml/Dash/CardHorizontalList.qml+1−1
@@ -49,7 +49,7 @@ DashRenderer {
49 item.cardData = Qt.binding(function() { return model; });
49 item.cardData = Qt.binding(function() { return model; });
50 item.template = Qt.binding(function() { return cardTool.template; });
50 item.template = Qt.binding(function() { return cardTool.template; });
51 item.components = Qt.binding(function() { return cardTool.components; });
51 item.components = Qt.binding(function() { return cardTool.components; });
52− item.headerAlignment = Qt.binding(function() { return cardTool.headerAlignment; });
52+ item.titleAlignment = Qt.binding(function() { return cardTool.titleAlignment; });
53 item.scopeStyle = root.scopeStyle;
53 item.scopeStyle = root.scopeStyle;
54 }
54 }
55 Connections {
55 Connections {
qml/Dash/CardTool.qml+26−18
@@ -131,21 +131,26 @@ Item {
131 property size artShapeSize: cardLoader.item ? cardLoader.item.artShapeSize : 0
131 property size artShapeSize: cardLoader.item ? cardLoader.item.artShapeSize : 0
132
132
133 /*!
133 /*!
134− \brief Desired alignment of header components.
134+ \brief Desired alignment of title
135 */
135 */
136− readonly property int headerAlignment: {
136+ readonly property int titleAlignment: {
137− var subtitle = components["subtitle"];
137+ if (template["card-layout"] === "horizontal"
138− var price = components["price"];
138+ || (typeof components["title"] !== "object" &&
139− var summary = components["summary"];
139+ components["title"]["align"] !== "center")) return Text.AlignLeft;
140−
140+
141− var hasSubtitle = subtitle && (typeof subtitle === "string" || subtitle["field"])
141+ var keys = ["mascot", "emblem", "subtitle", "attributes", "summary"];
142− var hasPrice = price && (typeof price === "string" || subtitle["field"]);
142+
143− var hasSummary = summary && (typeof summary === "string" || summary["field"])
143+ for (var key in keys) {
144−
144+ key = keys[key];
145− var isOnlyTextComponent = !hasSubtitle && !hasPrice && !hasSummary;
145+ try {
146− if (!isOnlyTextComponent) return Text.AlignLeft;
146+ if (typeof components[key] === "string"
147+ || typeof components[key]["field"] === "string") return Text.AlignLeft;
148+ } catch (e) {
149+ continue;
150+ }
151+ }
147
152
148− return (template["card-layout"] === "horizontal") ? Text.AlignLeft : Text.AlignHCenter;
153+ return Text.AlignHCenter;
149 }
154 }
150
155
151 QtObject {
156 QtObject {
@@ -169,16 +174,19 @@ Item {
169
174
170 Item {
175 Item {
171 id: attributesModel
176 id: attributesModel
172− property int numOfAttributes: {
177+ property int numOfAttributes: 0
178+ property var model: []
179+ property bool hasAttributes: {
173 var attributes = components["attributes"];
180 var attributes = components["attributes"];
174− if ((attributes != undefined) && attributes["field"]) {
181+ var hasAttributesFlag = (attributes != undefined) && attributes["field"];
182+
183+ if (hasAttributesFlag) {
175 if (attributes["max-count"]) {
184 if (attributes["max-count"]) {
176− return attributes["max-count"];
185+ numOfAttributes = attributes["max-count"];
177 }
186 }
178 }
187 }
179− return 0;
188+ return hasAttributesFlag
180 }
189 }
181− property var model: []
182
190
183 onNumOfAttributesChanged: {
191 onNumOfAttributesChanged: {
184 model = []
192 model = []
qml/Dash/CardVerticalJournal.qml+2−1
@@ -49,6 +49,7 @@ DashRenderer {
49 id: loader
49 id: loader
50 sourceComponent: cardTool.cardComponent
50 sourceComponent: cardTool.cardComponent
51 width: cardTool.cardWidth
51 width: cardTool.cardWidth
52+ visible: y + height >= root.visibleRangeBegin && y <= root.visibleRangeEnd
52 onLoaded: {
53 onLoaded: {
53 item.objectName = "delegate" + index;
54 item.objectName = "delegate" + index;
54 item.fixedArtShapeSize = Qt.binding(function() { return cardTool.artShapeSize; });
55 item.fixedArtShapeSize = Qt.binding(function() { return cardTool.artShapeSize; });
@@ -56,7 +57,7 @@ DashRenderer {
56 item.cardData = Qt.binding(function() { return model; });
57 item.cardData = Qt.binding(function() { return model; });
57 item.template = Qt.binding(function() { return cardTool.template; });
58 item.template = Qt.binding(function() { return cardTool.template; });
58 item.components = Qt.binding(function() { return cardTool.components; });
59 item.components = Qt.binding(function() { return cardTool.components; });
59− item.headerAlignment = Qt.binding(function() { return cardTool.headerAlignment; });
60+ item.titleAlignment = Qt.binding(function() { return cardTool.titleAlignment; });
60 item.scopeStyle = root.scopeStyle;
61 item.scopeStyle = root.scopeStyle;
61 }
62 }
62 Connections {
63 Connections {
qml/Dash/DashContent.qml+3
@@ -111,6 +111,8 @@ Item {
111 highlightMoveDuration: 250
111 highlightMoveDuration: 250
112 highlightRangeMode: ListView.StrictlyEnforceRange
112 highlightRangeMode: ListView.StrictlyEnforceRange
113 // TODO Investigate if we can switch to a smaller cache buffer when/if UbuntuShape gets more performant
113 // TODO Investigate if we can switch to a smaller cache buffer when/if UbuntuShape gets more performant
114+ // 1073741823 is s^30 -1. A quite big number so that you have "infinite" cache, but not so
115+ // big so that if you add if with itself you're outside the 2^31 int range
114 cacheBuffer: 1073741823
116 cacheBuffer: 1073741823
115 onMovementStarted: currentItem.item.showHeader();
117 onMovementStarted: currentItem.item.showHeader();
116 clip: parent.x != 0
118 clip: parent.x != 0
@@ -177,6 +179,7 @@ Item {
177 dashContent.scopeLoaded(item.scope.id)
179 dashContent.scopeLoaded(item.scope.id)
178 item.paginationCount = Qt.binding(function() { return dashContentList.count } )
180 item.paginationCount = Qt.binding(function() { return dashContentList.count } )
179 item.paginationIndex = Qt.binding(function() { return dashContentList.currentIndex } )
181 item.paginationIndex = Qt.binding(function() { return dashContentList.currentIndex } )
182+ item.holdingList = dashContentList;
180 }
183 }
181 Connections {
184 Connections {
182 target: isCurrent ? scope : null
185 target: isCurrent ? scope : null
qml/Dash/DashNavigation.qml+1
@@ -52,6 +52,7 @@ Item {
52
52
53 Rectangle {
53 Rectangle {
54 id: blackRect
54 id: blackRect
55+ objectName: "blackRect"
55 color: "black"
56 color: "black"
56 opacity: openList && openList.currentItem && openList.currentItem.visible ? 0.5 : 0
57 opacity: openList && openList.currentItem && openList.currentItem.visible ? 0.5 : 0
57 Behavior on opacity { UbuntuNumberAnimation { duration: UbuntuAnimation.SnapDuration } }
58 Behavior on opacity { UbuntuNumberAnimation { duration: UbuntuAnimation.SnapDuration } }
qml/Dash/DashRenderer.qml+4
@@ -27,6 +27,10 @@ Item {
27
27
28 property int displayMarginEnd: 0
28 property int displayMarginEnd: 0
29
29
30+ property int visibleRangeBegin: 0
31+
32+ property int visibleRangeEnd: 0
33+
30 property real originY: 0
34 property real originY: 0
31
35
32 // The model to renderer
36 // The model to renderer
qml/Dash/GenericScopeView.qml+71−13
@@ -15,7 +15,7 @@
15 */
15 */
16
16
17import QtQuick 2.0
17import QtQuick 2.0
18−import Ubuntu.Components 0.1
18+import Ubuntu.Components 1.1
19import Utils 0.1
19import Utils 0.1
20import Unity 0.2
20import Unity 0.2
21import Dash 0.1
21import Dash 0.1
@@ -38,6 +38,7 @@ FocusScope {
38 property int paginationCount: 0
38 property int paginationCount: 0
39 property int paginationIndex: 0
39 property int paginationIndex: 0
40 property alias pageHeaderTotallyVisible: categoryView.pageHeaderTotallyVisible
40 property alias pageHeaderTotallyVisible: categoryView.pageHeaderTotallyVisible
41+ property var holdingList: null
41
42
42 property var scopeStyle: ScopeStyle {
43 property var scopeStyle: ScopeStyle {
43 style: scope ? scope.customizations : {}
44 style: scope ? scope.customizations : {}
@@ -251,8 +252,8 @@ FocusScope {
251 }
252 }
252 }
253 }
253
254
254− onHeightChanged: rendererLoader.updateDelegateCreationRange();
255+ onHeightChanged: rendererLoader.updateRanges();
255− onYChanged: rendererLoader.updateDelegateCreationRange();
256+ onYChanged: rendererLoader.updateRanges();
256
257
257 Loader {
258 Loader {
258 id: rendererLoader
259 id: rendererLoader
@@ -314,7 +315,7 @@ FocusScope {
314 var shouldExpand = baseItem.category === categoryView.expandedCategoryId;
315 var shouldExpand = baseItem.category === categoryView.expandedCategoryId;
315 baseItem.expand(shouldExpand, false /*animate*/);
316 baseItem.expand(shouldExpand, false /*animate*/);
316 }
317 }
317− updateDelegateCreationRange();
318+ updateRanges();
318 if (scope && scope.id === "clickscope" && (categoryId === "predefined" || categoryId === "local")) {
319 if (scope && scope.id === "clickscope" && (categoryId === "predefined" || categoryId === "local")) {
319 // Yeah, hackish :/
320 // Yeah, hackish :/
320 cardTool.artShapeSize = Qt.size(units.gu(8), units.gu(7.5));
321 cardTool.artShapeSize = Qt.size(units.gu(8), units.gu(7.5));
@@ -348,13 +349,25 @@ FocusScope {
348 }
349 }
349 Connections {
350 Connections {
350 target: categoryView
351 target: categoryView
351− onOriginYChanged: rendererLoader.updateDelegateCreationRange();
352+ onOriginYChanged: rendererLoader.updateRanges();
352− onContentYChanged: rendererLoader.updateDelegateCreationRange();
353+ onContentYChanged: rendererLoader.updateRanges();
353− onHeightChanged: rendererLoader.updateDelegateCreationRange();
354+ onHeightChanged: rendererLoader.updateRanges();
354− onContentHeightChanged: rendererLoader.updateDelegateCreationRange();
355+ onContentHeightChanged: rendererLoader.updateRanges();
356+ }
357+ Connections {
358+ target: scopeView
359+ onIsCurrentChanged: rendererLoader.updateRanges();
360+ }
361+ Connections {
362+ target: holdingList
363+ onMovingChanged: if (!moving) rendererLoader.updateRanges();
355 }
364 }
356
365
357− function updateDelegateCreationRange() {
366+ function updateRanges() {
367+ if (holdingList && holdingList.moving) {
368+ return;
369+ }
370+
358 if (categoryView.moving) {
371 if (categoryView.moving) {
359 // Do not update the range if we are overshooting up or down, since we'll come back
372 // Do not update the range if we are overshooting up or down, since we'll come back
360 // to the stable position and delete/create items without any reason
373 // to the stable position and delete/create items without any reason
@@ -366,10 +379,20 @@ FocusScope {
366 }
379 }
367 }
380 }
368
381
382+ if (item && item.hasOwnProperty("visibleRangeBegin")) {
383+ item.visibleRangeBegin = Math.max(-baseItem.y, 0)
384+ item.visibleRangeEnd = item.visibleRangeBegin + Math.min(categoryView.height, rendererLoader.height)
385+ }
386+
369 if (item && item.hasOwnProperty("displayMarginBeginning")) {
387 if (item && item.hasOwnProperty("displayMarginBeginning")) {
370 // TODO do we need item.originY here, test 1300302 once we have a silo
388 // TODO do we need item.originY here, test 1300302 once we have a silo
371 // and we can run it on the phone
389 // and we can run it on the phone
390+ if (scopeView.isCurrent) {
391+ // 1073741823 is s^30 -1. A quite big number so that you have "infinite" display margin, but not so
392+ // big so that if you add if with itself you're outside the 2^31 int range
393+ item.displayMarginBeginning = 1073741823;
394+ item.displayMarginEnd = 1073741823;
372− if (baseItem.y + baseItem.height <= 0) {
395+ } else if (baseItem.y + baseItem.height <= 0) {
373 // Not visible (item at top of the list viewport)
396 // Not visible (item at top of the list viewport)
374 item.displayMarginBeginning = -baseItem.height;
397 item.displayMarginBeginning = -baseItem.height;
375 item.displayMarginEnd = 0;
398 item.displayMarginEnd = 0;
@@ -378,9 +401,9 @@ FocusScope {
378 item.displayMarginBeginning = 0;
401 item.displayMarginBeginning = 0;
379 item.displayMarginEnd = -baseItem.height;
402 item.displayMarginEnd = -baseItem.height;
380 } else {
403 } else {
381− item.displayMarginBeginning = -Math.max(-baseItem.y, 0);
404+ item.displayMarginBeginning = Math.round(-Math.max(-baseItem.y, 0));
382− item.displayMarginEnd = -Math.max(baseItem.height - seeAll.height
405+ item.displayMarginEnd = -Math.round(Math.max(baseItem.height - seeAll.height -
383− - categoryView.height + baseItem.y, 0)
406+ categoryView.height + baseItem.y, 0));
384 }
407 }
385 }
408 }
386 }
409 }
@@ -496,6 +519,41 @@ FocusScope {
496 }
519 }
497 }
520 }
498
521
522+ Item {
523+ id: pullToRefreshClippingItem
524+ anchors.left: parent.left
525+ anchors.right: parent.right
526+ anchors.bottom: parent.bottom
527+ height: parent.height - pullToRefresh.contentY + (pageHeaderLoader.item ? pageHeaderLoader.item.bottomItem[0].height - pageHeaderLoader.item.height : 0)
528+ clip: true
529+
530+ PullToRefresh {
531+ id: pullToRefresh
532+ objectName: "pullToRefresh"
533+ target: categoryView
534+
535+ readonly property real contentY: categoryView.contentY - categoryView.originY
536+ y: -contentY - units.gu(5)
537+
538+ onRefresh: {
539+ refreshing = true
540+ scopeView.scope.refresh()
541+ }
542+ anchors.left: parent.left
543+ anchors.right: parent.right
544+
545+ Connections {
546+ target: scopeView
547+ onProcessingChanged: if (!scopeView.processing) pullToRefresh.refreshing = false
548+ }
549+
550+ style: PullToRefreshScopeStyle {
551+ anchors.fill: parent
552+ activationThreshold: units.gu(14)
553+ }
554+ }
555+ }
556+
499 AbstractButton {
557 AbstractButton {
500 id: floatingSeeLess
558 id: floatingSeeLess
501 objectName: "floatingSeeLess"
559 objectName: "floatingSeeLess"
qml/Dash/Previews/PreviewHeader.qml+13
@@ -16,12 +16,14 @@
16
16
17import QtQuick 2.0
17import QtQuick 2.0
18import Ubuntu.Components 0.1
18import Ubuntu.Components 0.1
19+import Dash 0.1
19import "../"
20import "../"
20
21
21/*! This preview widget shows a header
22/*! This preview widget shows a header
22 * The title comes in widgetData["title"]
23 * The title comes in widgetData["title"]
23 * The mascot comes in widgetData["mascot"]
24 * The mascot comes in widgetData["mascot"]
24 * The subtitle comes in widgetData["subtitle"]
25 * The subtitle comes in widgetData["subtitle"]
26+ * The attributes comes in widgetData["attributes"]
25 */
27 */
26
28
27PreviewWidget {
29PreviewWidget {
@@ -35,6 +37,7 @@ PreviewWidget {
35 readonly property url mascot: root.widgetData["mascot"] || ""
37 readonly property url mascot: root.widgetData["mascot"] || ""
36 readonly property string title: root.widgetData["title"] || ""
38 readonly property string title: root.widgetData["title"] || ""
37 readonly property string subtitle: root.widgetData["subtitle"] || ""
39 readonly property string subtitle: root.widgetData["subtitle"] || ""
40+ readonly property var attributes: root.widgetData["attributes"] || null
38 readonly property color fontColor: root.scopeStyle ? root.scopeStyle.foreground : Theme.palette.normal.baseText
41 readonly property color fontColor: root.scopeStyle ? root.scopeStyle.foreground : Theme.palette.normal.baseText
39
42
40 implicitHeight: row.height + row.margins * 2
43 implicitHeight: row.height + row.margins * 2
@@ -114,6 +117,16 @@ PreviewWidget {
114 text: headerRoot.subtitle
117 text: headerRoot.subtitle
115 }
118 }
116 }
119 }
120+
121+ Loader {
122+ active: titleLabel.text && headerRoot.attributes
123+ anchors { left: parent.left; right: parent.right }
124+ sourceComponent: CardAttributes {
125+ id: previewAttributes
126+ objectName: "previewAttributes"
127+ model: headerRoot.attributes
128+ }
129+ }
117 }
130 }
118 }
131 }
119 }
132 }
qml/Dash/Previews/PreviewImageGallery.qml+121−18
@@ -26,8 +26,11 @@ PreviewWidget {
26 id: root
26 id: root
27 implicitHeight: units.gu(22)
27 implicitHeight: units.gu(22)
28
28
29+ property Item rootItem: QuickUtils.rootItem(root)
30+
29 ListView {
31 ListView {
30 id: previewImageListView
32 id: previewImageListView
33+ objectName: "previewImageListView"
31 spacing: units.gu(1)
34 spacing: units.gu(1)
32 anchors.fill: parent
35 anchors.fill: parent
33 orientation: ListView.Horizontal
36 orientation: ListView.Horizontal
@@ -35,24 +38,6 @@ PreviewWidget {
35 model: root.widgetData["sources"]
38 model: root.widgetData["sources"]
36 clip: true
39 clip: true
37
40
38− // FIXME: Because of ListViews inside ListViews inside Flickables inside ListViews (and some more)
39− // we finally reached the point where this ListView doesn't correctly get swipe input any more but
40− // instead the parent ListView is the one that is swiped. This MouseArea sort of creates a blocking
41− // layer to make sure this ListView can be swiped, regardless of what's behind it.
42− MouseArea {
43− anchors.fill: parent
44− enabled: parent.contentWidth > parent.width
45− }
46−
47− // FIXME: Because of ListViews inside ListViews inside Flickables inside ListViews (and some more)
48− // we finally reached the point where this ListView doesn't correctly get swipe input any more but
49− // instead the parent ListView is the one that is swiped. This MouseArea sort of creates a blocking
50− // layer to make sure this ListView can be swiped, regardless of what's behind it.
51− MouseArea {
52− anchors.fill: parent
53− enabled: parent.contentWidth > parent.width
54− }
55−
56 LazyImage {
41 LazyImage {
57 objectName: "placeholderScreenshot"
42 objectName: "placeholderScreenshot"
58 anchors {
43 anchors {
@@ -66,6 +51,7 @@ PreviewWidget {
66 }
51 }
67
52
68 delegate: LazyImage {
53 delegate: LazyImage {
54+ objectName: "previewImage" + index
69 anchors {
55 anchors {
70 top: parent.top
56 top: parent.top
71 bottom: parent.bottom
57 bottom: parent.bottom
@@ -73,6 +59,123 @@ PreviewWidget {
73 source: modelData ? modelData : ""
59 source: modelData ? modelData : ""
74 scaleTo: "height"
60 scaleTo: "height"
75 initialWidth: units.gu(13)
61 initialWidth: units.gu(13)
62+ borderSource: mouseArea.pressed ? "radius_pressed.sci" : "radius_idle.sci"
63+
64+ MouseArea {
65+ id: mouseArea
66+ anchors.fill: parent
67+ onClicked: {
68+ slideShowListView.currentIndex = index;
69+ slideShow.initialX = rootItem.mapFromItem(parent, 0, 0).x
70+ slideShow.initialY = rootItem.mapFromItem(parent, 0, 0).y
71+ slideShow.visible = true;
72+ }
73+ }
74+ }
75+ }
76+
77+ Rectangle {
78+ id: slideShow
79+ objectName: "slideShow"
80+
81+ readonly property real initialScale: previewImageListView.height / rootItem.height
82+ readonly property real scaleProgress: (scale - initialScale) / (1.0 - initialScale)
83+ property real initialX: 0
84+ property real initialY: 0
85+
86+ parent: rootItem
87+ width: parent.width
88+ height: parent.height
89+ visible: false
90+ clip: visible && scale < 1.0
91+ scale: visible ? 1.0 : initialScale
92+ transformOrigin: Item.TopLeft
93+ transform: Translate {
94+ x: slideShow.initialX - slideShow.initialX * slideShow.scaleProgress
95+ y: slideShow.initialY - slideShow.initialY * slideShow.scaleProgress
96+ }
97+ color: "black"
98+ radius: units.gu(1) - units.gu(1) * slideShow.scaleProgress
99+
100+ Behavior on scale {
101+ enabled: !slideShow.visible
102+ UbuntuNumberAnimation { duration: UbuntuAnimation.FastDuration }
103+ }
104+
105+ ListView {
106+ id: slideShowListView
107+ objectName: "slideShowListView"
108+ anchors.fill: parent
109+ orientation: ListView.Horizontal
110+ highlightRangeMode: ListView.StrictlyEnforceRange
111+ highlightMoveDuration: 0
112+ snapMode: ListView.SnapOneItem
113+ boundsBehavior: Flickable.DragAndOvershootBounds
114+ model: root.widgetData["sources"]
115+
116+ delegate: Image {
117+ id: screenshot
118+ anchors {
119+ top: parent.top
120+ bottom: parent.bottom
121+ }
122+ width: slideShow.width
123+ source: modelData ? modelData : ""
124+ fillMode: Image.PreserveAspectFit
125+ sourceSize { width: screenshot.width; height: screenshot.height }
126+ }
127+
128+ MouseArea {
129+ anchors.fill: parent
130+ onClicked: slideShowHeader.shown = !slideShowHeader.shown
131+ }
132+ }
133+
134+ Rectangle {
135+ id: slideShowHeader
136+
137+ property bool shown: true
138+
139+ anchors {
140+ left: parent.left
141+ right: parent.right
142+ }
143+ height: units.gu(7)
144+ visible: opacity > 0
145+ opacity: slideShow.scaleProgress > 0.6 && shown ? 0.8 : 0
146+ color: "black"
147+
148+ Behavior on opacity {
149+ UbuntuNumberAnimation { duration: UbuntuAnimation.SnapDuration }
150+ }
151+
152+ AbstractButton {
153+ id: slideShowCloseButton
154+ objectName: "slideShowCloseButton"
155+ anchors {
156+ top: parent.top
157+ bottom: parent.bottom
158+ }
159+ width: units.gu(8)
160+ height: width
161+
162+ onClicked: slideShow.visible = false
163+
164+ Rectangle {
165+ anchors.fill: parent
166+ color: Qt.rgba(1.0, 1.0, 1.0, 0.3)
167+ visible: slideShowCloseButton.pressed
168+ }
169+
170+ Icon {
171+ id: icon
172+ anchors.centerIn: parent
173+ width: units.gu(2.5)
174+ height: width
175+ color: Theme.palette.normal.foregroundText
176+ name: "close"
177+ }
178+ }
76 }
179 }
77 }
180 }
78}
181}
qml/Dash/PullToRefreshScopeStyle.qmlnew file+82
@@ -0,0 +1,82 @@
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.3
18+import Ubuntu.Components 1.1
19+import Ubuntu.Components.Styles 1.1
20+
21+/**
22+ * TODO: Once the SDK version of PullToRefreshStyle doesn't have bug 1375799
23+ * (https://launchpad.net/bugs/1375799) anymore, we should switch to using a
24+ * a subclass of the Ambiance version with a hidden ActivityIndicator.
25+ */
26+PullToRefreshStyle {
27+ releaseToRefresh: styledItem.target.originY - styledItem.target.contentY > activationThreshold
28+
29+ Connections {
30+ property bool willRefresh: false
31+
32+ target: styledItem.target
33+ onDraggingChanged: {
34+ if (!styledItem.target.dragging && releaseToRefresh) {
35+ willRefresh = true
36+ }
37+ }
38+ onContentYChanged: {
39+ if (styledItem.target.originY - styledItem.target.contentY == 0 && willRefresh) {
40+ styledItem.refresh()
41+ willRefresh = false
42+ }
43+ }
44+ }
45+
46+ Label {
47+ id: pullLabel
48+ anchors.horizontalCenter: parent.horizontalCenter
49+ horizontalAlignment: Text.AlignHCenter
50+ verticalAlignment: Text.AlignVCenter
51+ states: [
52+ State {
53+ name: "pulling"
54+ when: styledItem.target.dragging && !releaseToRefresh
55+ PropertyChanges { target: pullLabel; text: i18n.tr("Pull to refresh…") }
56+ },
57+ State {
58+ name: "releasable"
59+ when: styledItem.target.dragging && releaseToRefresh
60+ PropertyChanges { target: pullLabel; text: i18n.tr("Release to refresh…") }
61+ }
62+ ]
63+ transitions: Transition {
64+ SequentialAnimation {
65+ UbuntuNumberAnimation {
66+ target: pullLabel
67+ property: "opacity"
68+ to: 0.0
69+ }
70+ PropertyAction {
71+ target: pullLabel
72+ property: "text"
73+ }
74+ UbuntuNumberAnimation {
75+ target: pullLabel
76+ property: "opacity"
77+ to: 1.0
78+ }
79+ }
80+ }
81+ }
82+}
qml/Dash/ScopeListView.qml+1
@@ -20,4 +20,5 @@ import Dash 0.1
20ListViewWithPageHeader {
20ListViewWithPageHeader {
21 maximumFlickVelocity: height * 10
21 maximumFlickVelocity: height * 10
22 flickDeceleration: height * 2
22 flickDeceleration: height * 2
23+ cacheBuffer: Number.MAX_VALUE
23}
24}
qml/Dash/ScopeSettingsPage.qml+1
@@ -49,6 +49,7 @@ Item {
49 right: parent.right
49 right: parent.right
50 }
50 }
51 model: root.scope ? root.scope.settings : null
51 model: root.scope ? root.scope.settings : null
52+ clip: true
52
53
53 delegate: ScopeSettingsWidgetFactory {
54 delegate: ScopeSettingsWidgetFactory {
54 objectName: "scopeSettingItem" + index
55 objectName: "scopeSettingItem" + index
qml/Dash/ScopesOverviewAll.qml+2
@@ -43,6 +43,8 @@ Flickable {
43 id: cardGrid
43 id: cardGrid
44 width: root.width
44 width: root.width
45 height: parent.height
45 height: parent.height
46+ visibleRangeBegin: root.contentY
47+ visibleRangeEnd: root.contentY + root.height
46
48
47 onClicked: {
49 onClicked: {
48 root.clicked(index, result, item, itemModel);
50 root.clicked(index, result, item, itemModel);
qml/Dash/ScopesOverviewFavorites.qml+1−1
@@ -61,7 +61,7 @@ Flickable {
61 item.cardData = Qt.binding(function() { return model; });
61 item.cardData = Qt.binding(function() { return model; });
62 item.template = Qt.binding(function() { return cardTool.template; });
62 item.template = Qt.binding(function() { return cardTool.template; });
63 item.components = Qt.binding(function() { return cardTool.components; });
63 item.components = Qt.binding(function() { return cardTool.components; });
64− item.headerAlignment = Qt.binding(function() { return cardTool.headerAlignment; });
64+ item.titleAlignment = Qt.binding(function() { return cardTool.titleAlignment; });
65 }
65 }
66
66
67 Connections {
67 Connections {
qml/Launcher/Launcher.qml+1
@@ -92,6 +92,7 @@ Item {
92 // machine and switch to the final state in the next event loop run
92 // machine and switch to the final state in the next event loop run
93 Timer {
93 Timer {
94 id: animateTimer
94 id: animateTimer
95+ objectName: "animateTimer"
95 interval: 1
96 interval: 1
96 property string nextState: ""
97 property string nextState: ""
97 onTriggered: {
98 onTriggered: {
qml/Shell.qml+7−1
@@ -128,6 +128,13 @@ Item {
128 objectName: "dashCommunicator"
128 objectName: "dashCommunicator"
129 }
129 }
130
130
131+ Binding {
132+ target: ApplicationManager
133+ property: "forceDashActive"
134+ value: launcher.shown || launcher.dashSwipe
135+ }
136+
137+
131 WindowKeysFilter {
138 WindowKeysFilter {
132 // Handle but do not filter out volume keys
139 // Handle but do not filter out volume keys
133 Keys.onVolumeUpPressed: { volumeControl.volumeUp(); event.accepted = false; }
140 Keys.onVolumeUpPressed: { volumeControl.volumeUp(); event.accepted = false; }
@@ -171,7 +178,6 @@ Item {
171 greeter.startUnlock()
178 greeter.startUnlock()
172 }
179 }
173 greeter.hide();
180 greeter.hide();
174− launcher.hide();
175 } else {
181 } else {
176 if (LightDM.Greeter.active) {
182 if (LightDM.Greeter.active) {
177 greeter.startUnlock()
183 greeter.startUnlock()
src/CMakeLists.txt+1
@@ -36,3 +36,4 @@ install(TARGETS ${SHELL_APP}
36
36
37add_subdirectory(Panel)
37add_subdirectory(Panel)
38add_subdirectory(Dash)
38add_subdirectory(Dash)
39+add_subdirectory(libunity8-private)
src/Dash/CMakeLists.txt+2
@@ -9,6 +9,8 @@ add_executable(unity8-dash ${DASH_SRCS})
9
9
10qt5_use_modules(unity8-dash Gui Qml Quick Test)
10qt5_use_modules(unity8-dash Gui Qml Quick Test)
11
11
12+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility=hidden")
13+
12# install binaries
14# install binaries
13install(TARGETS ${DASH_APP}
15install(TARGETS ${DASH_APP}
14 RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
16 RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
src/Panel/CMakeLists.txt+2
@@ -1 +1,3 @@
1add_subdirectory(Indicators)
1add_subdirectory(Indicators)
2+
3+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility=hidden")
src/libunity8-private/CMakeLists.txtnew file+25
@@ -0,0 +1,25 @@
1+set(LIB_NAME "unity8-private")
2+set(SOVERSION 0)
3+set(VERSION ${SOVERSION}.0.0)
4+
5+project(lib${LIB_NAME})
6+
7+set(lib${LIB_NAME}_SRCS
8+ abstractdbusservicemonitor.cpp
9+ )
10+
11+add_library(${LIB_NAME} SHARED
12+ ${lib${LIB_NAME}_SRCS}
13+ )
14+
15+set_target_properties(${LIB_NAME} PROPERTIES
16+ VERSION ${VERSION}
17+ SOVERSION ${SOVERSION}
18+ )
19+
20+qt5_use_modules(${LIB_NAME} DBus)
21+
22+# install library
23+install(TARGETS ${LIB_NAME}
24+ LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
25+ )
src/libunity8-private/abstractdbusservicemonitor.cppnew file+87
@@ -0,0 +1,87 @@
1+/*
2+ * Copyright (C) 2011-2014 Canonical, Ltd.
3+ *
4+ * Authors:
5+ * Ugo Riboni <ugo.riboni@canonical.com>
6+ *
7+ * This program is free software; you can redistribute it and/or modify
8+ * it under the terms of the GNU General Public License as published by
9+ * the Free Software Foundation; version 3.
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+#include "abstractdbusservicemonitor.h"
21+
22+#include <QDBusInterface>
23+#include <QDBusServiceWatcher>
24+#include <QDBusConnection>
25+#include <QDBusConnectionInterface>
26+#include <QDBusReply>
27+
28+AbstractDBusServiceMonitor::AbstractDBusServiceMonitor(const QString &service, const QString &path,
29+ const QString &interface, const Bus bus,
30+ QObject *parent)
31+ : QObject(parent)
32+ , m_service(service)
33+ , m_path(path)
34+ , m_interface(interface)
35+ , m_watcher(new QDBusServiceWatcher(service,
36+ (bus == SystemBus) ? QDBusConnection::systemBus()
37+ : QDBusConnection::sessionBus()))
38+ , m_dbusInterface(nullptr)
39+{
40+ connect(m_watcher, &QDBusServiceWatcher::serviceRegistered, this, &AbstractDBusServiceMonitor::createInterface);
41+ connect(m_watcher, &QDBusServiceWatcher::serviceUnregistered, this, &AbstractDBusServiceMonitor::destroyInterface);
42+
43+ // Connect to the service if it's up already
44+ QDBusConnectionInterface* sessionBus = QDBusConnection::sessionBus().interface();
45+ QDBusReply<bool> reply = sessionBus->isServiceRegistered(m_service);
46+ if (reply.isValid() && reply.value()) {
47+ createInterface(m_service);
48+ }
49+}
50+
51+AbstractDBusServiceMonitor::~AbstractDBusServiceMonitor()
52+{
53+ delete m_watcher;
54+ delete m_dbusInterface;
55+}
56+
57+void AbstractDBusServiceMonitor::createInterface(const QString &)
58+{
59+ if (m_dbusInterface != nullptr) {
60+ delete m_dbusInterface;
61+ m_dbusInterface = nullptr;
62+ }
63+
64+ m_dbusInterface = new QDBusInterface(m_service, m_path, m_interface,
65+ QDBusConnection::sessionBus());
66+ Q_EMIT serviceAvailableChanged(true);
67+}
68+
69+void AbstractDBusServiceMonitor::destroyInterface(const QString &)
70+{
71+ if (m_dbusInterface != nullptr) {
72+ delete m_dbusInterface;
73+ m_dbusInterface = nullptr;
74+ }
75+
76+ Q_EMIT serviceAvailableChanged(false);
77+}
78+
79+QDBusInterface* AbstractDBusServiceMonitor::dbusInterface() const
80+{
81+ return m_dbusInterface;
82+}
83+
84+bool AbstractDBusServiceMonitor::serviceAvailable() const
85+{
86+ return m_dbusInterface != nullptr;
87+}
src/libunity8-private/abstractdbusservicemonitor.hnew file+66
@@ -0,0 +1,66 @@
1+/*
2+ * Copyright (C) 2011-2014 Canonical, Ltd.
3+ *
4+ * Authors:
5+ * Ugo Riboni <ugo.riboni@canonical.com>
6+ *
7+ * This program is free software; you can redistribute it and/or modify
8+ * it under the terms of the GNU General Public License as published by
9+ * the Free Software Foundation; version 3.
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+#ifndef ABSTRACTDBUSSERVICEMONITOR_H
21+#define ABSTRACTDBUSSERVICEMONITOR_H
22+
23+#include <QObject>
24+#include <QString>
25+#include <QDBusConnection>
26+
27+class QDBusInterface;
28+class QDBusServiceWatcher;
29+
30+class Q_DECL_EXPORT AbstractDBusServiceMonitor : public QObject
31+{
32+ Q_OBJECT
33+ Q_ENUMS(Bus)
34+ Q_PROPERTY(bool serviceAvailable READ serviceAvailable NOTIFY serviceAvailableChanged)
35+
36+public:
37+ enum Bus {
38+ SessionBus,
39+ SystemBus,
40+ };
41+
42+ explicit AbstractDBusServiceMonitor(const QString &service, const QString &path, const QString &interface,
43+ const Bus bus = SessionBus,
44+ QObject *parent = 0);
45+ ~AbstractDBusServiceMonitor();
46+
47+ QDBusInterface* dbusInterface() const;
48+
49+ bool serviceAvailable() const;
50+
51+Q_SIGNALS:
52+ void serviceAvailableChanged(bool available);
53+
54+private Q_SLOTS:
55+ void createInterface(const QString &service);
56+ void destroyInterface(const QString &service);
57+
58+protected:
59+ const QString m_service;
60+ const QString m_path;
61+ const QString m_interface;
62+ QDBusServiceWatcher* m_watcher;
63+ QDBusInterface* m_dbusInterface;
64+};
65+
66+#endif // ABSTRACTDBUSSERVICEMONITOR_H
tests/autopilot/unity8/shell/emulators/dash.py+4−4
@@ -66,7 +66,7 @@ class Dash(emulators.UnityEmulatorBase):
66 return resp_grid.select_single('Tile', text=text)
66 return resp_grid.select_single('Tile', text=text)
67
67
68 def get_scope(self, scope_name='clickscope'):
68 def get_scope(self, scope_name='clickscope'):
69− return self.dash_content_list.select_single(
69+ return self.dash_content_list.wait_select_single(
70 'QQuickLoader', scopeId=scope_name)
70 'QQuickLoader', scopeId=scope_name)
71
71
72 @autopilot_logging.log_action(logger.info)
72 @autopilot_logging.log_action(logger.info)
@@ -86,14 +86,14 @@ class Dash(emulators.UnityEmulatorBase):
86
86
87 def _get_scope_loader(self, scope_id):
87 def _get_scope_loader(self, scope_id):
88 try:
88 try:
89− return self.dash_content_list.select_single(
89+ return self.dash_content_list.wait_select_single(
90 'QQuickLoader', scopeId=scope_id)
90 'QQuickLoader', scopeId=scope_id)
91 except dbus.StateNotFoundError:
91 except dbus.StateNotFoundError:
92 raise emulators.UnityEmulatorException(
92 raise emulators.UnityEmulatorException(
93 'No scope found with id {0}'.format(scope_id))
93 'No scope found with id {0}'.format(scope_id))
94
94
95 def _get_scope_from_loader(self, loader):
95 def _get_scope_from_loader(self, loader):
96− return loader.get_children()[0]
96+ return loader.wait_select_single('GenericScopeView');
97
97
98 def _open_scope_scrolling(self, scope_loader):
98 def _open_scope_scrolling(self, scope_loader):
99 scroll = self._get_scroll_direction(scope_loader)
99 scroll = self._get_scroll_direction(scope_loader)
@@ -102,8 +102,8 @@ class Dash(emulators.UnityEmulatorBase):
102 scroll()
102 scroll()
103 self.dash_content_list.moving.wait_for(False)
103 self.dash_content_list.moving.wait_for(False)
104
104
105+ scope_loader.isCurrent.wait_for(True)
105 scope = self._get_scope_from_loader(scope_loader)
106 scope = self._get_scope_from_loader(scope_loader)
106− scope.isCurrent.wait_for(True)
107 return scope
107 return scope
108
108
109 def _get_scroll_direction(self, scope_loader):
109 def _get_scroll_direction(self, scope_loader):
tests/mocks/Ubuntu/CMakeLists.txt+1
@@ -1,3 +1,4 @@
1+add_subdirectory(Connectivity)
1add_subdirectory(DownloadDaemonListener)
2add_subdirectory(DownloadDaemonListener)
2add_subdirectory(Payments)
3add_subdirectory(Payments)
3add_subdirectory(SystemImage)
4add_subdirectory(SystemImage)
tests/mocks/Ubuntu/Connectivity/CMakeLists.txtnew file+10
@@ -0,0 +1,10 @@
1+add_library(connectivity-qml SHARED
2+ networking-status.cpp
3+ plugin.cpp
4+)
5+qt5_use_modules(connectivity-qml Qml)
6+
7+# copy qmldir file into build directory for shadow builds
8+file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/qmldir"
9+ DESTINATION ${CMAKE_CURRENT_BINARY_DIR}
10+ )
tests/mocks/Ubuntu/Connectivity/networking-status.cppnew file+64
@@ -0,0 +1,64 @@
1+/*
2+ * Copyright © 2014 Canonical Ltd.
3+ *
4+ * This program is free software: you can redistribute it and/or modify it
5+ * under the terms of the GNU Lesser General Public License version 3,
6+ * as published by the Free Software Foundation.
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 Lesser General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU Lesser General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ *
16+ * Authors:
17+ * Antti Kaijanmäki <antti.kaijanmaki@canonical.com>
18+ */
19+
20+#include "networking-status.h"
21+
22+NetworkingStatus::NetworkingStatus(QObject *parent)
23+ : QObject(parent)
24+{
25+ qRegisterMetaType<NetworkingStatus::Limitations>();
26+ qRegisterMetaType<QVector<NetworkingStatus::Limitations>>();
27+ qRegisterMetaType<NetworkingStatus::Status>();
28+}
29+
30+NetworkingStatus::~NetworkingStatus()
31+{}
32+
33+QVector<NetworkingStatus::Limitations>
34+NetworkingStatus::limitations() const
35+{
36+ return m_limitations;
37+}
38+
39+NetworkingStatus::Status
40+NetworkingStatus::status() const
41+{
42+ return Status::Online;
43+}
44+
45+bool
46+NetworkingStatus::online() const
47+{
48+ return status() == Status::Online;
49+}
50+
51+bool
52+NetworkingStatus::limitedBandwith() const
53+{
54+ return limitations().contains(Limitations::Bandwith);
55+}
56+
57+void NetworkingStatus::setLimitedBandwidth(bool limited)
58+{
59+ if (limited) {
60+ m_limitations << Limitations::Bandwith;
61+ } else if (limitedBandwith()) {
62+ m_limitations.remove(m_limitations.indexOf(Limitations::Bandwith));
63+ }
64+}
tests/mocks/Ubuntu/Connectivity/networking-status.hnew file+73
@@ -0,0 +1,73 @@
1+/*
2+ * Copyright © 2014 Canonical Ltd.
3+ *
4+ * This program is free software: you can redistribute it and/or modify it
5+ * under the terms of the GNU Lesser General Public License version 3,
6+ * as published by the Free Software Foundation.
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 Lesser General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU Lesser General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ *
16+ */
17+
18+#ifndef FAKE_NETWORKING_STATUS_H
19+#define FAKE_NETWORKING_STATUS_H
20+
21+#include <QObject>
22+#include <QVector>
23+
24+class Q_DECL_EXPORT NetworkingStatus : public QObject
25+{
26+ Q_OBJECT
27+ Q_DISABLE_COPY(NetworkingStatus)
28+
29+ Q_ENUMS(Limitations)
30+ Q_ENUMS(Status)
31+
32+ Q_PROPERTY(QVector<Limitations> limitations READ limitations NOTIFY limitationsChanged)
33+ Q_PROPERTY(Status status READ status NOTIFY statusChanged)
34+ Q_PROPERTY(bool online READ online NOTIFY onlineChanged)
35+ Q_PROPERTY(bool limitedBandwith READ limitedBandwith WRITE setLimitedBandwidth NOTIFY limitedBandwithChanged)
36+
37+public:
38+ explicit NetworkingStatus(QObject *parent = 0);
39+ virtual ~NetworkingStatus();
40+
41+ enum Limitations {
42+ Bandwith
43+ };
44+
45+ enum Status {
46+ Offline,
47+ Connecting,
48+ Online
49+ };
50+
51+ QVector<Limitations> limitations() const;
52+ Status status() const;
53+ bool online() const;
54+ bool limitedBandwith() const;
55+
56+ // Only in the fake one
57+ void setLimitedBandwidth(bool limited);
58+
59+Q_SIGNALS:
60+ void limitationsChanged();
61+ void statusChanged(Status value);
62+ void onlineChanged(bool value);
63+ void limitedBandwithChanged(bool value);
64+
65+private:
66+ QVector<NetworkingStatus::Limitations> m_limitations;
67+};
68+
69+Q_DECLARE_METATYPE(NetworkingStatus::Limitations)
70+Q_DECLARE_METATYPE(QVector<NetworkingStatus::Limitations>)
71+Q_DECLARE_METATYPE(NetworkingStatus::Status)
72+
73+#endif // FAKE_NETWORKING_STATUS_H
tests/mocks/Ubuntu/Connectivity/plugin.cppnew file+46
@@ -0,0 +1,46 @@
1+/*
2+ * Copyright © 2014 Canonical Ltd.
3+ *
4+ * This program is free software: you can redistribute it and/or modify it
5+ * under the terms of the GNU Lesser General Public License version 3,
6+ * as published by the Free Software Foundation.
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 Lesser General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU Lesser General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ *
16+ * Authors:
17+ * Antti Kaijanmäki <antti.kaijanmaki@canonical.com>
18+ */
19+
20+#include "plugin.h"
21+
22+#include <QtQml>
23+
24+#include "networking-status.h"
25+
26+static QObject *
27+networkingStatusSingletonProvider(QQmlEngine *engine, QJSEngine *scriptEngine)
28+{
29+ Q_UNUSED(scriptEngine)
30+
31+ return new NetworkingStatus(engine);
32+}
33+
34+void
35+QmlConnectivityNetworkingPlugin::registerTypes(const char *uri)
36+{
37+ // @uri Ubuntu.Connectivity
38+ qmlRegisterSingletonType<NetworkingStatus>(uri, 1, 0, "NetworkingStatus", networkingStatusSingletonProvider);
39+}
40+
41+void
42+QmlConnectivityNetworkingPlugin::initializeEngine(QQmlEngine *engine, const char *uri)
43+{
44+ Q_UNUSED(uri);
45+ Q_UNUSED(engine);
46+}
tests/mocks/Ubuntu/Connectivity/plugin.hnew file+35
@@ -0,0 +1,35 @@
1+/*
2+ * Copyright © 2014 Canonical Ltd.
3+ *
4+ * This program is free software: you can redistribute it and/or modify it
5+ * under the terms of the GNU Lesser General Public License version 3,
6+ * as published by the Free Software Foundation.
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 Lesser General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU Lesser General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ *
16+ * Authors:
17+ * Antti Kaijanmäki <antti.kaijanmaki@canonical.com>
18+ */
19+
20+#ifndef QML_CONNECTIVITY_PLUGIN_H
21+#define QML_CONNECTIVITY_PLUGIN_H
22+
23+#include <QQmlExtensionPlugin>
24+
25+class QmlConnectivityNetworkingPlugin : public QQmlExtensionPlugin {
26+ Q_OBJECT
27+ Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
28+ Q_INTERFACES(QQmlExtensionInterface)
29+
30+public:
31+ void registerTypes(const char *uri);
32+ void initializeEngine(QQmlEngine *engine, const char *uri);
33+};
34+
35+#endif // QML_CONNECTIVITY_PLUGIN_H
tests/mocks/Ubuntu/Connectivity/qmldirnew file+2
@@ -0,0 +1,2 @@
1+module Ubuntu.Connectivity
2+plugin connectivity-qml
tests/mocks/Unity/Application/ApplicationManager.cpp+26
@@ -43,6 +43,7 @@ ApplicationManager *ApplicationManager::singleton()
43ApplicationManager::ApplicationManager(QObject *parent)
43ApplicationManager::ApplicationManager(QObject *parent)
44 : ApplicationManagerInterface(parent)
44 : ApplicationManagerInterface(parent)
45 , m_suspended(false)
45 , m_suspended(false)
46+ , m_forceDashActive(false)
46{
47{
47 m_roleNames.insert(RoleSession, "session");
48 m_roleNames.insert(RoleSession, "session");
48 m_roleNames.insert(RoleFullscreen, "fullscreen");
49 m_roleNames.insert(RoleFullscreen, "fullscreen");
@@ -292,6 +293,31 @@ void ApplicationManager::setSuspended(bool suspended)
292 Q_EMIT suspendedChanged();
293 Q_EMIT suspendedChanged();
293}
294}
294
295
296+bool ApplicationManager::forceDashActive() const
297+{
298+ return m_forceDashActive;
299+}
300+
301+void ApplicationManager::setForceDashActive(bool forceDashActive)
302+{
303+ if (m_forceDashActive == forceDashActive) {
304+ return;
305+ }
306+
307+ ApplicationInfo *dash = findApplication("unity8-dash");
308+ if (dash) {
309+ if (forceDashActive) {
310+ dash->setState(ApplicationInfo::Running);
311+ } else {
312+ if (!dash->focused()) {
313+ dash->setState(ApplicationInfo::Suspended);
314+ }
315+ }
316+ }
317+ m_forceDashActive = forceDashActive;
318+ Q_EMIT forceDashActiveChanged();
319+}
320+
295bool ApplicationManager::focusApplication(const QString &appId)
321bool ApplicationManager::focusApplication(const QString &appId)
296{
322{
297 ApplicationInfo *application = findApplication(appId);
323 ApplicationInfo *application = findApplication(appId);
tests/mocks/Unity/Application/ApplicationManager.h+6−2
@@ -99,8 +99,11 @@ class ApplicationManager : public ApplicationManagerInterface {
99 Q_INVOKABLE bool stopApplication(const QString &appId) override;
99 Q_INVOKABLE bool stopApplication(const QString &appId) override;
100
100
101 QString focusedApplicationId() const override;
101 QString focusedApplicationId() const override;
102− bool suspended() const;
102+ bool suspended() const override;
103− void setSuspended(bool suspended);
103+ void setSuspended(bool suspended) override;
104+
105+ bool forceDashActive() const override;
106+ void setForceDashActive(bool forceDashActive) override;
104
107
105 // Only for testing
108 // Only for testing
106 Q_INVOKABLE QStringList availableApplications();
109 Q_INVOKABLE QStringList availableApplications();
@@ -124,6 +127,7 @@ class ApplicationManager : public ApplicationManagerInterface {
124 void buildListOfAvailableApplications();
127 void buildListOfAvailableApplications();
125 void onWindowCreated();
128 void onWindowCreated();
126 bool m_suspended;
129 bool m_suspended;
130+ bool m_forceDashActive;
127 QList<ApplicationInfo*> m_runningApplications;
131 QList<ApplicationInfo*> m_runningApplications;
128 QList<ApplicationInfo*> m_availableApplications;
132 QList<ApplicationInfo*> m_availableApplications;
129 QTimer m_windowCreatedTimer;
133 QTimer m_windowCreatedTimer;
tests/mocks/Unity/Application/CMakeLists.txt+1−1
@@ -1,4 +1,4 @@
1−pkg_check_modules(APPLICATION_API REQUIRED unity-shell-application=4)
1+pkg_check_modules(APPLICATION_API REQUIRED unity-shell-application=5)
2
2
3set(FakeUnityApplicationQml_SOURCES
3set(FakeUnityApplicationQml_SOURCES
4 plugin.cpp
4 plugin.cpp
tests/mocks/Unity/fake_scope.cpp+1−1
@@ -266,7 +266,7 @@ QVariantMap Scope::customizations() const
266
266
267void Scope::refresh()
267void Scope::refresh()
268{
268{
269− qDebug() << "Scope::refresh is currently not implmented in the fake scopes plugin";
269+ Q_EMIT refreshed();
270}
270}
271
271
272unity::shell::scopes::NavigationInterface* Scope::getNavigation(const QString& id)
272unity::shell::scopes::NavigationInterface* Scope::getNavigation(const QString& id)
tests/mocks/Unity/fake_scope.h+3
@@ -79,6 +79,9 @@ public:
79
79
80 Q_INVOKABLE void refresh() override;
80 Q_INVOKABLE void refresh() override;
81
81
82+Q_SIGNALS:
83+ void refreshed(); // This is not in the Interface, here for testing benefits
84+
82protected:
85protected:
83
86
84 QString m_id;
87 QString m_id;
tests/plugins/Dash/CMakeLists.txt+3−3
@@ -32,7 +32,7 @@ macro(add_lvwph_test FILENAME TESTNAME)
32 qt5_use_modules(${TESTNAME}TestExec Test Core Qml)
32 qt5_use_modules(${TESTNAME}TestExec Test Core Qml)
33 target_link_libraries(${TESTNAME}TestExec ${Qt5Gui_LIBRARIES} ${Qt5Quick_LIBRARIES})
33 target_link_libraries(${TESTNAME}TestExec ${Qt5Gui_LIBRARIES} ${Qt5Quick_LIBRARIES})
34
34
35− add_binary_qml_test(${TESTNAME} "" "Dash-qml")
35+ add_binary_qml_test(${TESTNAME} "" "Dash-qml" "")
36endmacro()
36endmacro()
37
37
38add_lvwph_test(listviewwithpageheader ListViewWithPageHeader)
38add_lvwph_test(listviewwithpageheader ListViewWithPageHeader)
@@ -48,7 +48,7 @@ macro(add_dashview_try_test FILENAME TESTNAME)
48 qt5_use_modules(${TESTNAME}TestExec Test Core Qml)
48 qt5_use_modules(${TESTNAME}TestExec Test Core Qml)
49 target_link_libraries(${TESTNAME}TestExec ${Qt5Gui_LIBRARIES} ${Qt5Quick_LIBRARIES})
49 target_link_libraries(${TESTNAME}TestExec ${Qt5Gui_LIBRARIES} ${Qt5Quick_LIBRARIES})
50
50
51− add_binary_qml_test(${TESTNAME} "" "Dash-qml")
51+ add_binary_qml_test(${TESTNAME} "" "Dash-qml" "")
52
52
53 add_executable(${TESTNAME}tryExec
53 add_executable(${TESTNAME}tryExec
54 ${FILENAME}try.cpp
54 ${FILENAME}try.cpp
@@ -71,7 +71,7 @@ add_dashview_try_test(organicgrid OrganicGrid)
71add_executable(CardCreatorTestExec cardcreatortest.cpp)
71add_executable(CardCreatorTestExec cardcreatortest.cpp)
72qt5_use_modules(CardCreatorTestExec Test Core Qml)
72qt5_use_modules(CardCreatorTestExec Test Core Qml)
73target_link_libraries(CardCreatorTestExec ${Qt5Gui_LIBRARIES} ${Qt5Quick_LIBRARIES})
73target_link_libraries(CardCreatorTestExec ${Qt5Gui_LIBRARIES} ${Qt5Quick_LIBRARIES})
74−add_binary_qml_test(CardCreator "" "Dash-qml")
74+add_binary_qml_test(CardCreator "" "Dash-qml" "QML2_IMPORT_PATH=${CMAKE_BINARY_DIR}/tests/mocks/")
75
75
76# plain qml test
76# plain qml test
77set(qmltest_DEFAULT_TARGETS qmluitests)
77set(qmltest_DEFAULT_TARGETS qmluitests)
tests/plugins/Dash/cardcreator/1.res+7−6
@@ -6,7 +6,7 @@ AbstractButton {
6 property var artShapeBorderSource: undefined;
6 property var artShapeBorderSource: undefined;
7 property real fontScale: 1.0;
7 property real fontScale: 1.0;
8 property var scopeStyle: null;
8 property var scopeStyle: null;
9− property int headerAlignment: Text.AlignLeft;
9+ property int titleAlignment: Text.AlignLeft;
10 property int fixedHeaderHeight: -1;
10 property int fixedHeaderHeight: -1;
11 property size fixedArtShapeSize: Qt.size(-1, -1);
11 property size fixedArtShapeSize: Qt.size(-1, -1);
12 readonly property string title: cardData && cardData["title"] || "";
12 readonly property string title: cardData && cardData["title"] || "";
@@ -44,12 +44,13 @@ Item {
44 height = Qt.binding(function() { return image.status !== Image.Ready ? 0 : image.height });
44 height = Qt.binding(function() { return image.status !== Image.Ready ? 0 : image.height });
45 }
45 }
46 }
46 }
47− image: Image {
47+ image: CroppedImageMinimumSourceSize {
48 objectName: "artImage";
48 objectName: "artImage";
49+ property bool doLoadSource: !NetworkingStatus.limitedBandwith;
49− source: cardData && cardData["art"] || "";
50+ source: { if (root.visible) doLoadSource = true; return doLoadSource && cardData && cardData["art"] || ""; }
50 cache: true;
51 cache: true;
51 asynchronous: root.asynchronous;
52 asynchronous: root.asynchronous;
52− fillMode: Image.PreserveAspectCrop;
53+ visible: false;
53 width: root.width;
54 width: root.width;
54 height: width / artShape.aspect;
55 height: width / artShape.aspect;
55 }
56 }
@@ -73,8 +74,8 @@ Label {
73 color: root.scopeStyle ? root.scopeStyle.foreground : Theme.palette.normal.baseText;
74 color: root.scopeStyle ? root.scopeStyle.foreground : Theme.palette.normal.baseText;
74 visible: showHeader ;
75 visible: showHeader ;
75 text: root.title;
76 text: root.title;
76− font.weight: components && components["subtitle"] ? Font.DemiBold : Font.Normal;
77+ font.weight: cardData && cardData["subtitle"] ? Font.DemiBold : Font.Normal;
77− horizontalAlignment: root.headerAlignment;
78+ horizontalAlignment: root.titleAlignment;
78 }
79 }
79UbuntuShape {
80UbuntuShape {
80 id: touchdown;
81 id: touchdown;
tests/plugins/Dash/cardcreator/2.res+8−11
@@ -6,7 +6,7 @@ AbstractButton {
6 property var artShapeBorderSource: undefined;
6 property var artShapeBorderSource: undefined;
7 property real fontScale: 1.0;
7 property real fontScale: 1.0;
8 property var scopeStyle: null;
8 property var scopeStyle: null;
9− property int headerAlignment: Text.AlignLeft;
9+ property int titleAlignment: Text.AlignLeft;
10 property int fixedHeaderHeight: -1;
10 property int fixedHeaderHeight: -1;
11 property size fixedArtShapeSize: Qt.size(-1, -1);
11 property size fixedArtShapeSize: Qt.size(-1, -1);
12 readonly property string title: cardData && cardData["title"] || "";
12 readonly property string title: cardData && cardData["title"] || "";
@@ -62,19 +62,17 @@ Row {
62 anchors.margins: margins;
62 anchors.margins: margins;
63 anchors.rightMargin: 0;
63 anchors.rightMargin: 0;
64 data: [
64 data: [
65−Image {
65+CroppedImageMinimumSourceSize {
66 id: mascotImage;
66 id: mascotImage;
67 objectName: "mascotImage";
67 objectName: "mascotImage";
68 anchors { verticalCenter: parent.verticalCenter; }
68 anchors { verticalCenter: parent.verticalCenter; }
69− readonly property int maxSize: Math.max(width, height) * 4;
69+ property bool doLoadSource: !NetworkingStatus.limitedBandwith;
70− source: cardData && cardData["mascot"] || "";
70+ source: { if (root.visible) doLoadSource = true; return doLoadSource && cardData && cardData["mascot"] || ""; }
71 width: units.gu(6);
71 width: units.gu(6);
72 height: units.gu(5.625);
72 height: units.gu(5.625);
73− sourceSize { width: maxSize; height: maxSize }
74− fillMode: Image.PreserveAspectCrop;
75 horizontalAlignment: Image.AlignHCenter;
73 horizontalAlignment: Image.AlignHCenter;
76 verticalAlignment: Image.AlignVCenter;
74 verticalAlignment: Image.AlignVCenter;
77− visible: showHeader;
75+ visible: showHeader && resized;
78 }
76 }
79,Item {
77,Item {
80 id: headerTitleContainer;
78 id: headerTitleContainer;
@@ -97,8 +95,8 @@ Image {
97 color: backgroundLoader.active && backgroundLoader.item && root.scopeStyle ? root.scopeStyle.getTextColor(backgroundLoader.item.luminance) : (backgroundLoader.item && backgroundLoader.item.luminance > 0.7 ? Theme.palette.normal.baseText : "white");
95 color: backgroundLoader.active && backgroundLoader.item && root.scopeStyle ? root.scopeStyle.getTextColor(backgroundLoader.item.luminance) : (backgroundLoader.item && backgroundLoader.item.luminance > 0.7 ? Theme.palette.normal.baseText : "white");
98 visible: showHeader ;
96 visible: showHeader ;
99 text: root.title;
97 text: root.title;
100− font.weight: components && components["subtitle"] ? Font.DemiBold : Font.Normal;
98+ font.weight: cardData && cardData["subtitle"] ? Font.DemiBold : Font.Normal;
101− horizontalAlignment: root.headerAlignment;
99+ horizontalAlignment: root.titleAlignment;
102 }
100 }
103 ,Label {
101 ,Label {
104 id: subtitleLabel;
102 id: subtitleLabel;
@@ -110,13 +108,12 @@ Image {
110 }
108 }
111 anchors.topMargin: units.dp(2);
109 anchors.topMargin: units.dp(2);
112 elide: Text.ElideRight;
110 elide: Text.ElideRight;
113− fontSize: "small";
111+ fontSize: "x-small";
114 font.pixelSize: Math.round(FontUtils.sizeToPixels(fontSize) * fontScale);
112 font.pixelSize: Math.round(FontUtils.sizeToPixels(fontSize) * fontScale);
115 color: backgroundLoader.active && backgroundLoader.item && root.scopeStyle ? root.scopeStyle.getTextColor(backgroundLoader.item.luminance) : (backgroundLoader.item && backgroundLoader.item.luminance > 0.7 ? Theme.palette.normal.baseText : "white");
113 color: backgroundLoader.active && backgroundLoader.item && root.scopeStyle ? root.scopeStyle.getTextColor(backgroundLoader.item.luminance) : (backgroundLoader.item && backgroundLoader.item.luminance > 0.7 ? Theme.palette.normal.baseText : "white");
116 visible: titleLabel.visible && titleLabel.text;
114 visible: titleLabel.visible && titleLabel.text;
117 text: cardData && cardData["subtitle"] || "";
115 text: cardData && cardData["subtitle"] || "";
118 font.weight: Font.Light;
116 font.weight: Font.Light;
119− horizontalAlignment: root.headerAlignment;
120 }
117 }
121
118
122 ]
119 ]
tests/plugins/Dash/cardcreator/3.res+9−9
@@ -6,7 +6,7 @@ AbstractButton {
6 property var artShapeBorderSource: undefined;
6 property var artShapeBorderSource: undefined;
7 property real fontScale: 1.0;
7 property real fontScale: 1.0;
8 property var scopeStyle: null;
8 property var scopeStyle: null;
9− property int headerAlignment: Text.AlignLeft;
9+ property int titleAlignment: Text.AlignLeft;
10 property int fixedHeaderHeight: -1;
10 property int fixedHeaderHeight: -1;
11 property size fixedArtShapeSize: Qt.size(-1, -1);
11 property size fixedArtShapeSize: Qt.size(-1, -1);
12 readonly property string title: cardData && cardData["title"] || "";
12 readonly property string title: cardData && cardData["title"] || "";
@@ -44,12 +44,13 @@ Item {
44 height = Qt.binding(function() { return image.status !== Image.Ready ? 0 : image.height });
44 height = Qt.binding(function() { return image.status !== Image.Ready ? 0 : image.height });
45 }
45 }
46 }
46 }
47− image: Image {
47+ image: CroppedImageMinimumSourceSize {
48 objectName: "artImage";
48 objectName: "artImage";
49+ property bool doLoadSource: !NetworkingStatus.limitedBandwith;
49− source: cardData && cardData["art"] || "";
50+ source: { if (root.visible) doLoadSource = true; return doLoadSource && cardData && cardData["art"] || ""; }
50− cache: true;
51+ cache: true;
51 asynchronous: root.asynchronous;
52 asynchronous: root.asynchronous;
52− fillMode: Image.PreserveAspectCrop;
53+ visible: false;
53 width: root.width;
54 width: root.width;
54 height: width / artShape.aspect;
55 height: width / artShape.aspect;
55 }
56 }
@@ -73,8 +74,8 @@ Label {
73 color: root.scopeStyle ? root.scopeStyle.foreground : Theme.palette.normal.baseText;
74 color: root.scopeStyle ? root.scopeStyle.foreground : Theme.palette.normal.baseText;
74 visible: showHeader ;
75 visible: showHeader ;
75 text: root.title;
76 text: root.title;
76− font.weight: components && components["subtitle"] ? Font.DemiBold : Font.Normal;
77+ font.weight: cardData && cardData["subtitle"] ? Font.DemiBold : Font.Normal;
77− horizontalAlignment: root.headerAlignment;
78+ horizontalAlignment: root.titleAlignment;
78 }
79 }
79Label {
80Label {
80 id: subtitleLabel;
81 id: subtitleLabel;
@@ -86,13 +87,12 @@ Label {
86 }
87 }
87 anchors.topMargin: units.dp(2);
88 anchors.topMargin: units.dp(2);
88 elide: Text.ElideRight;
89 elide: Text.ElideRight;
89− fontSize: "small";
90+ fontSize: "x-small";
90 font.pixelSize: Math.round(FontUtils.sizeToPixels(fontSize) * fontScale);
91 font.pixelSize: Math.round(FontUtils.sizeToPixels(fontSize) * fontScale);
91 color: root.scopeStyle ? root.scopeStyle.foreground : Theme.palette.normal.baseText;
92 color: root.scopeStyle ? root.scopeStyle.foreground : Theme.palette.normal.baseText;
92 visible: titleLabel.visible && titleLabel.text;
93 visible: titleLabel.visible && titleLabel.text;
93 text: cardData && cardData["subtitle"] || "";
94 text: cardData && cardData["subtitle"] || "";
94 font.weight: Font.Light;
95 font.weight: Font.Light;
95− horizontalAlignment: root.headerAlignment;
96 }
96 }
97UbuntuShape {
97UbuntuShape {
98 id: touchdown;
98 id: touchdown;
tests/plugins/Dash/cardcreator/4.res+8−11
@@ -6,7 +6,7 @@ AbstractButton {
6 property var artShapeBorderSource: undefined;
6 property var artShapeBorderSource: undefined;
7 property real fontScale: 1.0;
7 property real fontScale: 1.0;
8 property var scopeStyle: null;
8 property var scopeStyle: null;
9− property int headerAlignment: Text.AlignLeft;
9+ property int titleAlignment: Text.AlignLeft;
10 property int fixedHeaderHeight: -1;
10 property int fixedHeaderHeight: -1;
11 property size fixedArtShapeSize: Qt.size(-1, -1);
11 property size fixedArtShapeSize: Qt.size(-1, -1);
12 readonly property string title: cardData && cardData["title"] || "";
12 readonly property string title: cardData && cardData["title"] || "";
@@ -41,16 +41,14 @@ Loader {
41 anchors { verticalCenter: parent.verticalCenter; }
41 anchors { verticalCenter: parent.verticalCenter; }
42 }
42 }
43
43
44−,Image {
44+,CroppedImageMinimumSourceSize {
45 id: mascotImage;
45 id: mascotImage;
46 objectName: "mascotImage";
46 objectName: "mascotImage";
47 anchors { verticalCenter: parent.verticalCenter; }
47 anchors { verticalCenter: parent.verticalCenter; }
48− readonly property int maxSize: Math.max(width, height) * 4;
48+ property bool doLoadSource: !NetworkingStatus.limitedBandwith;
49− source: cardData && cardData["mascot"] || "";
49+ source: { if (root.visible) doLoadSource = true; return doLoadSource && cardData && cardData["mascot"] || ""; }
50− width: units.gu(6);
50+ width: units.gu(6);
51 height: units.gu(5.625);
51 height: units.gu(5.625);
52− sourceSize { width: maxSize; height: maxSize }
53− fillMode: Image.PreserveAspectCrop;
54 horizontalAlignment: Image.AlignHCenter;
52 horizontalAlignment: Image.AlignHCenter;
55 verticalAlignment: Image.AlignVCenter;
53 verticalAlignment: Image.AlignVCenter;
56 visible: false;
54 visible: false;
@@ -77,8 +75,8 @@ Label {
77 color: root.scopeStyle ? root.scopeStyle.foreground : Theme.palette.normal.baseText;
75 color: root.scopeStyle ? root.scopeStyle.foreground : Theme.palette.normal.baseText;
78 visible: showHeader ;
76 visible: showHeader ;
79 text: root.title;
77 text: root.title;
80− font.weight: components && components["subtitle"] ? Font.DemiBold : Font.Normal;
78+ font.weight: cardData && cardData["subtitle"] ? Font.DemiBold : Font.Normal;
81− horizontalAlignment: root.headerAlignment;
79+ horizontalAlignment: root.titleAlignment;
82 }
80 }
83,Label {
81,Label {
84 id: subtitleLabel;
82 id: subtitleLabel;
@@ -90,13 +88,12 @@ Label {
90 }
88 }
91 anchors.topMargin: units.dp(2);
89 anchors.topMargin: units.dp(2);
92 elide: Text.ElideRight;
90 elide: Text.ElideRight;
93− fontSize: "small";
91+ fontSize: "x-small";
94 font.pixelSize: Math.round(FontUtils.sizeToPixels(fontSize) * fontScale);
92 font.pixelSize: Math.round(FontUtils.sizeToPixels(fontSize) * fontScale);
95 color: root.scopeStyle ? root.scopeStyle.foreground : Theme.palette.normal.baseText;
93 color: root.scopeStyle ? root.scopeStyle.foreground : Theme.palette.normal.baseText;
96 visible: titleLabel.visible && titleLabel.text;
94 visible: titleLabel.visible && titleLabel.text;
97 text: cardData && cardData["subtitle"] || "";
95 text: cardData && cardData["subtitle"] || "";
98 font.weight: Font.Light;
96 font.weight: Font.Light;
99− horizontalAlignment: root.headerAlignment;
100 }
97 }
101]
98]
102}
99}
tests/plugins/Dash/cardcreator/5.res+9−9
@@ -6,7 +6,7 @@ AbstractButton {
6 property var artShapeBorderSource: undefined;
6 property var artShapeBorderSource: undefined;
7 property real fontScale: 1.0;
7 property real fontScale: 1.0;
8 property var scopeStyle: null;
8 property var scopeStyle: null;
9− property int headerAlignment: Text.AlignLeft;
9+ property int titleAlignment: Text.AlignLeft;
10 property int fixedHeaderHeight: -1;
10 property int fixedHeaderHeight: -1;
11 property size fixedArtShapeSize: Qt.size(-1, -1);
11 property size fixedArtShapeSize: Qt.size(-1, -1);
12 readonly property string title: cardData && cardData["title"] || "";
12 readonly property string title: cardData && cardData["title"] || "";
@@ -44,12 +44,13 @@ Item {
44 height = Qt.binding(function() { return image.status !== Image.Ready ? 0 : image.height });
44 height = Qt.binding(function() { return image.status !== Image.Ready ? 0 : image.height });
45 }
45 }
46 }
46 }
47− image: Image {
47+ image: CroppedImageMinimumSourceSize {
48 objectName: "artImage";
48 objectName: "artImage";
49+ property bool doLoadSource: !NetworkingStatus.limitedBandwith;
49− source: cardData && cardData["art"] || "";
50+ source: { if (root.visible) doLoadSource = true; return doLoadSource && cardData && cardData["art"] || ""; }
50− cache: true;
51+ cache: true;
51 asynchronous: root.asynchronous;
52 asynchronous: root.asynchronous;
52− fillMode: Image.PreserveAspectCrop;
53+ visible: false;
53 width: root.width;
54 width: root.width;
54 height: width / artShape.aspect;
55 height: width / artShape.aspect;
55 }
56 }
@@ -117,8 +118,8 @@ Label {
117 color: root.scopeStyle && overlayLoader.item ? root.scopeStyle.getTextColor(overlayLoader.item.luminance) : (overlayLoader.item && overlayLoader.item.luminance > 0.7 ? Theme.palette.normal.baseText : "white");
118 color: root.scopeStyle && overlayLoader.item ? root.scopeStyle.getTextColor(overlayLoader.item.luminance) : (overlayLoader.item && overlayLoader.item.luminance > 0.7 ? Theme.palette.normal.baseText : "white");
118 visible: showHeader && overlayLoader.active;
119 visible: showHeader && overlayLoader.active;
119 text: root.title;
120 text: root.title;
120− font.weight: components && components["subtitle"] ? Font.DemiBold : Font.Normal;
121+ font.weight: cardData && cardData["subtitle"] ? Font.DemiBold : Font.Normal;
121− horizontalAlignment: root.headerAlignment;
122+ horizontalAlignment: root.titleAlignment;
122 }
123 }
123Label {
124Label {
124 id: subtitleLabel;
125 id: subtitleLabel;
@@ -131,13 +132,12 @@ Label {
131 }
132 }
132 anchors.topMargin: units.dp(2);
133 anchors.topMargin: units.dp(2);
133 elide: Text.ElideRight;
134 elide: Text.ElideRight;
134− fontSize: "small";
135+ fontSize: "x-small";
135 font.pixelSize: Math.round(FontUtils.sizeToPixels(fontSize) * fontScale);
136 font.pixelSize: Math.round(FontUtils.sizeToPixels(fontSize) * fontScale);
136 color: root.scopeStyle && overlayLoader.item ? root.scopeStyle.getTextColor(overlayLoader.item.luminance) : (overlayLoader.item && overlayLoader.item.luminance > 0.7 ? Theme.palette.normal.baseText : "white");
137 color: root.scopeStyle && overlayLoader.item ? root.scopeStyle.getTextColor(overlayLoader.item.luminance) : (overlayLoader.item && overlayLoader.item.luminance > 0.7 ? Theme.palette.normal.baseText : "white");
137 visible: titleLabel.visible && titleLabel.text;
138 visible: titleLabel.visible && titleLabel.text;
138 text: cardData && cardData["subtitle"] || "";
139 text: cardData && cardData["subtitle"] || "";
139 font.weight: Font.Light;
140 font.weight: Font.Light;
140− horizontalAlignment: root.headerAlignment;
141 }
141 }
142UbuntuShape {
142UbuntuShape {
143 id: touchdown;
143 id: touchdown;
tests/plugins/Dash/cardcreator/6.res+5−7
@@ -6,7 +6,7 @@ AbstractButton {
6 property var artShapeBorderSource: undefined;
6 property var artShapeBorderSource: undefined;
7 property real fontScale: 1.0;
7 property real fontScale: 1.0;
8 property var scopeStyle: null;
8 property var scopeStyle: null;
9− property int headerAlignment: Text.AlignLeft;
9+ property int titleAlignment: Text.AlignLeft;
10 property int fixedHeaderHeight: -1;
10 property int fixedHeaderHeight: -1;
11 property size fixedArtShapeSize: Qt.size(-1, -1);
11 property size fixedArtShapeSize: Qt.size(-1, -1);
12 readonly property string title: cardData && cardData["title"] || "";
12 readonly property string title: cardData && cardData["title"] || "";
@@ -73,8 +73,8 @@ Item {
73 color: backgroundLoader.active && backgroundLoader.item && root.scopeStyle ? root.scopeStyle.getTextColor(backgroundLoader.item.luminance) : (backgroundLoader.item && backgroundLoader.item.luminance > 0.7 ? Theme.palette.normal.baseText : "white");
73 color: backgroundLoader.active && backgroundLoader.item && root.scopeStyle ? root.scopeStyle.getTextColor(backgroundLoader.item.luminance) : (backgroundLoader.item && backgroundLoader.item.luminance > 0.7 ? Theme.palette.normal.baseText : "white");
74 visible: showHeader ;
74 visible: showHeader ;
75 text: root.title;
75 text: root.title;
76− font.weight: components && components["subtitle"] ? Font.DemiBold : Font.Normal;
76+ font.weight: cardData && cardData["subtitle"] ? Font.DemiBold : Font.Normal;
77− horizontalAlignment: root.headerAlignment;
77+ horizontalAlignment: root.titleAlignment;
78 }
78 }
79,Label {
79,Label {
80 id: subtitleLabel;
80 id: subtitleLabel;
@@ -86,15 +86,14 @@ Item {
86 }
86 }
87 anchors.topMargin: units.dp(2);
87 anchors.topMargin: units.dp(2);
88 elide: Text.ElideRight;
88 elide: Text.ElideRight;
89− fontSize: "small";
89+ fontSize: "x-small";
90 font.pixelSize: Math.round(FontUtils.sizeToPixels(fontSize) * fontScale);
90 font.pixelSize: Math.round(FontUtils.sizeToPixels(fontSize) * fontScale);
91 color: backgroundLoader.active && backgroundLoader.item && root.scopeStyle ? root.scopeStyle.getTextColor(backgroundLoader.item.luminance) : (backgroundLoader.item && backgroundLoader.item.luminance > 0.7 ? Theme.palette.normal.baseText : "white");
91 color: backgroundLoader.active && backgroundLoader.item && root.scopeStyle ? root.scopeStyle.getTextColor(backgroundLoader.item.luminance) : (backgroundLoader.item && backgroundLoader.item.luminance > 0.7 ? Theme.palette.normal.baseText : "white");
92 visible: titleLabel.visible && titleLabel.text;
92 visible: titleLabel.visible && titleLabel.text;
93 text: cardData && cardData["subtitle"] || "";
93 text: cardData && cardData["subtitle"] || "";
94 font.weight: Font.Light;
94 font.weight: Font.Light;
95− horizontalAlignment: root.headerAlignment;
96 }
95 }
97−,Icon {
96+,StatusIcon {
98 id: emblemIcon;
97 id: emblemIcon;
99 objectName: "emblemIcon";
98 objectName: "emblemIcon";
100 anchors {
99 anchors {
@@ -104,7 +103,6 @@ Item {
104 }
103 }
105 source: cardData && cardData["emblem"] || "";
104 source: cardData && cardData["emblem"] || "";
106 color: backgroundLoader.active && backgroundLoader.item && root.scopeStyle ? root.scopeStyle.getTextColor(backgroundLoader.item.luminance) : (backgroundLoader.item && backgroundLoader.item.luminance > 0.7 ? Theme.palette.normal.baseText : "white");
105 color: backgroundLoader.active && backgroundLoader.item && root.scopeStyle ? root.scopeStyle.getTextColor(backgroundLoader.item.luminance) : (backgroundLoader.item && backgroundLoader.item.luminance > 0.7 ? Theme.palette.normal.baseText : "white");
107− width: height;
108 height: source != "" ? titleLabel.font.pixelSize : 0;
106 height: source != "" ? titleLabel.font.pixelSize : 0;
109 }
107 }
110
108
tests/plugins/Dash/cardcreator/7.res+9−12
@@ -6,7 +6,7 @@ AbstractButton {
6 property var artShapeBorderSource: undefined;
6 property var artShapeBorderSource: undefined;
7 property real fontScale: 1.0;
7 property real fontScale: 1.0;
8 property var scopeStyle: null;
8 property var scopeStyle: null;
9− property int headerAlignment: Text.AlignLeft;
9+ property int titleAlignment: Text.AlignLeft;
10 property int fixedHeaderHeight: -1;
10 property int fixedHeaderHeight: -1;
11 property size fixedArtShapeSize: Qt.size(-1, -1);
11 property size fixedArtShapeSize: Qt.size(-1, -1);
12 readonly property string title: cardData && cardData["title"] || "";
12 readonly property string title: cardData && cardData["title"] || "";
@@ -62,19 +62,17 @@ Row {
62 anchors.margins: margins;
62 anchors.margins: margins;
63 anchors.rightMargin: 0;
63 anchors.rightMargin: 0;
64 data: [
64 data: [
65−Image {
65+CroppedImageMinimumSourceSize {
66 id: mascotImage;
66 id: mascotImage;
67 objectName: "mascotImage";
67 objectName: "mascotImage";
68 anchors { verticalCenter: parent.verticalCenter; }
68 anchors { verticalCenter: parent.verticalCenter; }
69− readonly property int maxSize: Math.max(width, height) * 4;
69+ property bool doLoadSource: !NetworkingStatus.limitedBandwith;
70− source: cardData && cardData["mascot"] || "";
70+ source: { if (root.visible) doLoadSource = true; return doLoadSource && cardData && cardData["mascot"] || ""; }
71− width: units.gu(6);
71+ width: units.gu(6);
72 height: units.gu(5.625);
72 height: units.gu(5.625);
73− sourceSize { width: maxSize; height: maxSize }
74− fillMode: Image.PreserveAspectCrop;
75 horizontalAlignment: Image.AlignHCenter;
73 horizontalAlignment: Image.AlignHCenter;
76 verticalAlignment: Image.AlignVCenter;
74 verticalAlignment: Image.AlignVCenter;
77− visible: showHeader;
75+ visible: showHeader && resized;
78 }
76 }
79
77
80,Item {
78,Item {
@@ -98,8 +96,8 @@ Image {
98 color: backgroundLoader.active && backgroundLoader.item && root.scopeStyle ? root.scopeStyle.getTextColor(backgroundLoader.item.luminance) : (backgroundLoader.item && backgroundLoader.item.luminance > 0.7 ? Theme.palette.normal.baseText : "white");
96 color: backgroundLoader.active && backgroundLoader.item && root.scopeStyle ? root.scopeStyle.getTextColor(backgroundLoader.item.luminance) : (backgroundLoader.item && backgroundLoader.item.luminance > 0.7 ? Theme.palette.normal.baseText : "white");
99 visible: showHeader ;
97 visible: showHeader ;
100 text: root.title;
98 text: root.title;
101− font.weight: components && components["subtitle"] ? Font.DemiBold : Font.Normal;
99+ font.weight: cardData && cardData["subtitle"] ? Font.DemiBold : Font.Normal;
102− horizontalAlignment: root.headerAlignment;
100+ horizontalAlignment: root.titleAlignment;
103 }
101 }
104,Label {
102,Label {
105 id: subtitleLabel;
103 id: subtitleLabel;
@@ -111,13 +109,12 @@ Image {
111 }
109 }
112 anchors.topMargin: units.dp(2);
110 anchors.topMargin: units.dp(2);
113 elide: Text.ElideRight;
111 elide: Text.ElideRight;
114− fontSize: "small";
112+ fontSize: "x-small";
115 font.pixelSize: Math.round(FontUtils.sizeToPixels(fontSize) * fontScale);
113 font.pixelSize: Math.round(FontUtils.sizeToPixels(fontSize) * fontScale);
116 color: backgroundLoader.active && backgroundLoader.item && root.scopeStyle ? root.scopeStyle.getTextColor(backgroundLoader.item.luminance) : (backgroundLoader.item && backgroundLoader.item.luminance > 0.7 ? Theme.palette.normal.baseText : "white");
114 color: backgroundLoader.active && backgroundLoader.item && root.scopeStyle ? root.scopeStyle.getTextColor(backgroundLoader.item.luminance) : (backgroundLoader.item && backgroundLoader.item.luminance > 0.7 ? Theme.palette.normal.baseText : "white");
117 visible: titleLabel.visible && titleLabel.text;
115 visible: titleLabel.visible && titleLabel.text;
118 text: cardData && cardData["subtitle"] || "";
116 text: cardData && cardData["subtitle"] || "";
119 font.weight: Font.Light;
117 font.weight: Font.Light;
120− horizontalAlignment: root.headerAlignment;
121 }
118 }
122,CardAttributes {
119,CardAttributes {
123 id: attributesRow;
120 id: attributesRow;
tests/plugins/Dash/listviewwithpageheadertest.cpp+39
@@ -28,6 +28,8 @@
28#include <private/qquickitem_p.h>
28#include <private/qquickitem_p.h>
29#pragma GCC diagnostic pop
29#pragma GCC diagnostic pop
30
30
31+#include <limits>
32+
31// TODO Think on how doing a test for lost items
33// TODO Think on how doing a test for lost items
32// particullary making sure that lost items are culled
34// particullary making sure that lost items are culled
33// and then removed in the next updatePolish cycle
35// and then removed in the next updatePolish cycle
@@ -1899,6 +1901,43 @@ private Q_SLOTS:
1899 QTRY_COMPARE(lvwph->m_firstVisibleIndex, 0);
1901 QTRY_COMPARE(lvwph->m_firstVisibleIndex, 0);
1900 }
1902 }
1901
1903
1904+ void testNoCacheBuffer()
1905+ {
1906+ lvwph->setCacheBuffer(0);
1907+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 3);
1908+ QCOMPARE(lvwph->m_firstVisibleIndex, 0);
1909+ verifyItem(0, 50., 150., false);
1910+ verifyItem(1, 200., 200., false);
1911+ verifyItem(2, 400., 350., false);
1912+ QCOMPARE(lvwph->m_minYExtent, 0.);
1913+ QCOMPARE(lvwph->m_clipItem->y(), 0.);
1914+ QCOMPARE(lvwph->m_clipItem->clip(), false);
1915+ QCOMPARE(lvwph->m_headerItem->y(), 0.);
1916+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
1917+ QCOMPARE(lvwph->contentY(), 0.);
1918+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
1919+ }
1920+
1921+ void testAllCacheBuffer()
1922+ {
1923+ lvwph->setCacheBuffer(std::numeric_limits<qreal>::max());
1924+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 6);
1925+ QCOMPARE(lvwph->m_firstVisibleIndex, 0);
1926+ verifyItem(0, 50., 150., false);
1927+ verifyItem(1, 200., 200., false);
1928+ verifyItem(2, 400., 350., false);
1929+ verifyItem(3, 750., 350., true);
1930+ verifyItem(4, 1100., 350., true);
1931+ verifyItem(5, 1450., 350., true);
1932+ QCOMPARE(lvwph->m_minYExtent, 0.);
1933+ QCOMPARE(lvwph->m_clipItem->y(), 0.);
1934+ QCOMPARE(lvwph->m_clipItem->clip(), false);
1935+ QCOMPARE(lvwph->m_headerItem->y(), 0.);
1936+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
1937+ QCOMPARE(lvwph->contentY(), 0.);
1938+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
1939+ }
1940+
1902private:
1941private:
1903 QQuickView *view;
1942 QQuickView *view;
1904 ListViewWithPageHeader *lvwph;
1943 ListViewWithPageHeader *lvwph;
tests/plugins/Dash/listviewwithpageheadertest.qml+1
@@ -60,6 +60,7 @@ Rectangle {
60 anchors.top: parent.top
60 anchors.top: parent.top
61 anchors.bottom: parent.bottom
61 anchors.bottom: parent.bottom
62 model: model
62 model: model
63+ cacheBuffer: height * 0.5
63 delegate: Rectangle {
64 delegate: Rectangle {
64 property bool timerDone: false
65 property bool timerDone: false
65 width: parent.width - 20
66 width: parent.width - 20
tests/plugins/Dash/listviewwithpageheadertestsection.qml+1
@@ -60,6 +60,7 @@ Rectangle {
60 anchors.top: parent.top
60 anchors.top: parent.top
61 anchors.bottom: parent.bottom
61 anchors.bottom: parent.bottom
62 model: model
62 model: model
63+ cacheBuffer: height * 0.5
63 delegate: Rectangle {
64 delegate: Rectangle {
64 property bool timerDone: false
65 property bool timerDone: false
65 width: parent.width - 20
66 width: parent.width - 20
tests/plugins/Dash/listviewwithpageheadertestsectionexternalmodel.qml+1
@@ -28,6 +28,7 @@ Rectangle {
28 anchors.top: parent.top
28 anchors.top: parent.top
29 anchors.bottom: parent.bottom
29 anchors.bottom: parent.bottom
30 model: model
30 model: model
31+ cacheBuffer: height * 0.5
31 delegate: Rectangle {
32 delegate: Rectangle {
32 property bool timerDone: false
33 property bool timerDone: false
33 width: parent.width - 20
34 width: parent.width - 20
tests/plugins/Ubuntu/Gestures/CMakeLists.txt+1−1
@@ -19,7 +19,7 @@ macro(add_gesture_ui_test CLASSNAME)
19 qt5_use_modules(${CLASSNAME}TestExec Test Core Qml Gui Quick)
19 qt5_use_modules(${CLASSNAME}TestExec Test Core Qml Gui Quick)
20 target_link_libraries(${CLASSNAME}TestExec UbuntuGestureQml)
20 target_link_libraries(${CLASSNAME}TestExec UbuntuGestureQml)
21
21
22− add_binary_qml_test(${CLASSNAME} ${CMAKE_BINARY_DIR}/plugins/Ubuntu/Gestures UbuntuGesturesTestQmlFiles)
22+ add_binary_qml_test(${CLASSNAME} ${CMAKE_BINARY_DIR}/plugins/Ubuntu/Gestures UbuntuGesturesTestQmlFiles "")
23 add_manual_qml_test(. ${CLASSNAME} IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins)
23 add_manual_qml_test(. ${CLASSNAME} IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins)
24endmacro(add_gesture_ui_test)
24endmacro(add_gesture_ui_test)
25
25
tests/plugins/Unity/Launcher/CMakeLists.txt+1−1
@@ -1,6 +1,6 @@
1pkg_check_modules(GSETTINGS_QT REQUIRED gsettings-qt)
1pkg_check_modules(GSETTINGS_QT REQUIRED gsettings-qt)
2pkg_check_modules(LAUNCHER_API REQUIRED unity-shell-launcher=4)
2pkg_check_modules(LAUNCHER_API REQUIRED unity-shell-launcher=4)
3−pkg_check_modules(APPLICATION_API REQUIRED unity-shell-application=4)
3+pkg_check_modules(APPLICATION_API REQUIRED unity-shell-application=5)
4
4
5include_directories(
5include_directories(
6 ${CMAKE_CURRENT_BINARY_DIR}
6 ${CMAKE_CURRENT_BINARY_DIR}
tests/plugins/Unity/Launcher/launchermodeltest.cpp+2
@@ -105,6 +105,8 @@ public:
105 bool requestFocusApplication(const QString &appId) { Q_UNUSED(appId); return true; }
105 bool requestFocusApplication(const QString &appId) { Q_UNUSED(appId); return true; }
106 bool suspended() const { return false; }
106 bool suspended() const { return false; }
107 void setSuspended(bool) {}
107 void setSuspended(bool) {}
108+ bool forceDashActive() const { return false; }
109+ void setForceDashActive(bool) {}
108
110
109private:
111private:
110 QList<MockApp*> m_list;
112 QList<MockApp*> m_list;
tests/qmltests/Components/CMakeLists.txt+1−1
@@ -10,7 +10,7 @@ add_executable(DragHandleTestExec tst_DragHandle.cpp)
10qt5_use_modules(DragHandleTestExec Test Core Qml Gui Quick)
10qt5_use_modules(DragHandleTestExec Test Core Qml Gui Quick)
11target_link_libraries(DragHandleTestExec UbuntuGestureQml)
11target_link_libraries(DragHandleTestExec UbuntuGestureQml)
12
12
13−add_binary_qml_test(DragHandle ${CMAKE_BINARY_DIR}/plugins/Ubuntu/Gestures "")
13+add_binary_qml_test(DragHandle ${CMAKE_BINARY_DIR}/plugins/Ubuntu/Gestures "" "")
14add_manual_qml_test(. DragHandle IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins)
14add_manual_qml_test(. DragHandle IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins)
15
15
16add_definitions(-DUBUNTU_GESTURES_PLUGIN_DIR="${CMAKE_BINARY_DIR}/plugins")
16add_definitions(-DUBUNTU_GESTURES_PLUGIN_DIR="${CMAKE_BINARY_DIR}/plugins")
tests/qmltests/Dash/CardHelpers.js+1−12
@@ -16,7 +16,7 @@
16
16
17.pragma library
17.pragma library
18
18
19−var components = ["title", "art", "subtitle", "mascot", "emblem", "old-price", "price", "alt-price", "rating", "alt-rating", "summary", "attributes", "overlayColor"]
19+var components = ["title", "art", "subtitle", "mascot", "emblem", "summary", "attributes", "overlayColor"]
20
20
21var defaultLayout = ' \
21var defaultLayout = ' \
22{ \
22{ \
@@ -37,17 +37,6 @@ var defaultLayout = ' \
37 "overlayColor": null, \
37 "overlayColor": null, \
38 "mascot": null, \
38 "mascot": null, \
39 "emblem": null, \
39 "emblem": null, \
40− "old-price": null, \
41− "price": null, \
42− "alt-price": null, \
43− "rating": { \
44− "type": "stars", \
45− "range": [0, 5], \
46− "full": "image://theme/rating-star-full", \
47− "half": "image://theme/rating-star-half", \
48− "empty": "image://theme/rating-star-empty" \
49− }, \
50− "alt-rating": null, \
51 "summary": null, \
40 "summary": null, \
52 "attributes": { "max-count": 2 } \
41 "attributes": { "max-count": 2 } \
53 }, \
42 }, \
tests/qmltests/Dash/Previews/tst_PreviewHeader.qml+4−2
@@ -27,13 +27,15 @@ Rectangle {
27 property var origHeaderjson: {
27 property var origHeaderjson: {
28 "title": "THE TITLE",
28 "title": "THE TITLE",
29 "subtitle": "Something catchy",
29 "subtitle": "Something catchy",
30− "mascot": "../graphics/play_button.png"
30+ "mascot": "../graphics/play_button.png",
31+ "attributes": [{"value":"text1","icon":"image://theme/ok"},{"value":"text2","icon":"image://theme/cancel"}]
31 }
32 }
32
33
33 property var headerjson: {
34 property var headerjson: {
34 "title": "THE TITLE",
35 "title": "THE TITLE",
35 "subtitle": "Something catchy",
36 "subtitle": "Something catchy",
36− "mascot": "../graphics/play_button.png"
37+ "mascot": "../graphics/play_button.png",
38+ "attributes": [{"value":"text1","icon":"image://theme/ok"},{"value":"text2","icon":"image://theme/cancel"}]
37 }
39 }
38
40
39 PreviewHeader {
41 PreviewHeader {
tests/qmltests/Dash/Previews/tst_PreviewImageGallery.qml+51−1
@@ -21,7 +21,7 @@ import Unity.Test 0.1 as UT
21
21
22Rectangle {
22Rectangle {
23 id: root
23 id: root
24− width: units.gu(60)
24+ width: units.gu(80)
25 height: units.gu(80)
25 height: units.gu(80)
26 color: "lightgrey"
26 color: "lightgrey"
27
27
@@ -44,13 +44,63 @@ Rectangle {
44 }
44 }
45
45
46 UT.UnityTestCase {
46 UT.UnityTestCase {
47+ id: testCase
47 name: "PreviewImageGalleryTest"
48 name: "PreviewImageGalleryTest"
48 when: windowShown
49 when: windowShown
49
50
51+ property Item slideShow: findChild(imageGallery.rootItem, "slideShow")
52+ property Item slideShowCloseButton: findChild(slideShow, "slideShowCloseButton")
53+ property Item slideShowListView: findChild(slideShow, "slideShowListView")
54+
55+ function cleanup() {
56+ slideShow.visible = false;
57+ imageGallery.widgetData = sourcesModel1;
58+ waitForRendering(imageGallery);
59+ }
60+
50 function test_changeEmptyModel() {
61 function test_changeEmptyModel() {
51 imageGallery.widgetData = sourcesModel0;
62 imageGallery.widgetData = sourcesModel0;
52 var placeholderScreenshot = findChild(imageGallery, "placeholderScreenshot");
63 var placeholderScreenshot = findChild(imageGallery, "placeholderScreenshot");
53 compare(placeholderScreenshot.visible, true);
64 compare(placeholderScreenshot.visible, true);
54 }
65 }
66+
67+ function test_slideShowOpenClose() {
68+ var image0 = findChild(imageGallery, "previewImage0");
69+ mouseClick(image0, image0.width / 2, image0.height / 2);
70+ tryCompare(slideShow, "visible", true);
71+ tryCompare(slideShow, "scale", 1.0);
72+ tryCompare(slideShowCloseButton, "visible", true);
73+ mouseClick(slideShowCloseButton, slideShowCloseButton.width / 2, slideShowCloseButton.height / 2);
74+ tryCompare(slideShow, "visible", false);
75+ }
76+
77+ function test_slideShowShowHideHeader() {
78+ var image0 = findChild(imageGallery, "previewImage0");
79+ mouseClick(image0, image0.width / 2, image0.height / 2);
80+ tryCompare(slideShow, "visible", true);
81+ tryCompare(slideShow, "scale", 1.0);
82+ tryCompare(slideShowCloseButton, "visible", true);
83+ mouseClick(slideShow, slideShow.width / 2, slideShow.height / 2);
84+ tryCompare(slideShowCloseButton, "visible", false);
85+ mouseClick(slideShow, slideShow.width / 2, slideShow.height / 2);
86+ tryCompare(slideShowCloseButton, "visible", true);
87+ }
88+
89+ function test_slideShowOpenCorrectImage_data() {
90+ return [
91+ { tag: "Image 0", index: 0 },
92+ { tag: "Image 1", index: 1 },
93+ { tag: "Image 2", index: 2 },
94+ ];
95+ }
96+
97+ function test_slideShowOpenCorrectImage(data) {
98+ var image = findChild(imageGallery, "previewImage" + data.index);
99+ mouseClick(image, image.width / 2, image.height / 2);
100+ tryCompare(slideShow, "visible", true);
101+ tryCompare(slideShow, "scale", 1.0);
102+ tryCompare(slideShowListView, "currentIndex", data.index);
103+ verify(image.source === slideShowListView.currentItem.source);
104+ }
55 }
105 }
56}
106}
tests/qmltests/Dash/tst_Card.qml+26
@@ -17,6 +17,7 @@
17import QtQuick 2.0
17import QtQuick 2.0
18import QtTest 1.0
18import QtTest 1.0
19import Ubuntu.Components 0.1
19import Ubuntu.Components 0.1
20+import Ubuntu.Connectivity 1.0
20import Unity.Test 0.1 as UT
21import Unity.Test 0.1 as UT
21import "../../../qml/Dash"
22import "../../../qml/Dash"
22import "CardHelpers.js" as Helpers
23import "CardHelpers.js" as Helpers
@@ -205,6 +206,11 @@ Rectangle {
205 property Item backgroundImage: findChild(card, "backgroundImage")
206 property Item backgroundImage: findChild(card, "backgroundImage")
206 property Item mascotImage: findChild(card, "mascotImage");
207 property Item mascotImage: findChild(card, "mascotImage");
207
208
209+ function init() {
210+ loader.visible = true;
211+ NetworkingStatus.limitedBandwith = false;
212+ }
213+
208 function cleanup() {
214 function cleanup() {
209 selector.selectedIndex = -1;
215 selector.selectedIndex = -1;
210 }
216 }
@@ -566,5 +572,25 @@ Rectangle {
566 verify((card.width - titleToCard.x - titleToCard.width) === units.gu(1));
572 verify((card.width - titleToCard.x - titleToCard.width) === units.gu(1));
567 }
573 }
568 }
574 }
575+
576+ function test_load_images_visibility_network_data() {
577+ return [
578+ { tag: "Visible, network", visible: true, limitedBandwith: false },
579+ { tag: "Visible, no network", visible: true, limitedBandwith: true },
580+ { tag: "Not Visible, network", visible: false, limitedBandwith: false },
581+ { tag: "Not Visible, no network", visible: false, limitedBandwith: true }
582+ ];
583+ }
584+
585+ function test_load_images_visibility_network(data) {
586+ loader.visible = data.visible;
587+ NetworkingStatus.limitedBandwith = data.limitedBandwith;
588+
589+ selector.selectedIndex = 0;
590+ waitForRendering(selector);
591+ waitForRendering(card);
592+
593+ verify(data.visible || !data.limitedBandwith || artImage.source == "");
594+ }
569 }
595 }
570}
596}
tests/qmltests/Dash/tst_CardTool.qml+28−20
@@ -85,8 +85,8 @@ Rectangle {
85 "layout": { "template": { "card-layout": "vertical" }, "components": { "title": "title", "subtitle": "subtitle" } }
85 "layout": { "template": { "card-layout": "vertical" }, "components": { "title": "title", "subtitle": "subtitle" } }
86 },
86 },
87 {
87 {
88− "name": "Title, price - horizontal",
88+ "name": "Title, attributes - horizontal",
89− "layout": { "template": { "card-layout": "horizontal" }, "components": { "title": "title", "price": "price" } }
89+ "layout": { "template": { "card-layout": "horizontal" }, "components": { "title": "title", "attributes": "attributes" } }
90 },
90 },
91 ]
91 ]
92
92
@@ -100,6 +100,7 @@ Rectangle {
100 }
100 }
101
101
102 Column {
102 Column {
103+ id: column
103 width: units.gu(38)
104 width: units.gu(38)
104 anchors { left: parent.left; top: parent.top; margins: units.gu(1) }
105 anchors { left: parent.left; top: parent.top; margins: units.gu(1) }
105
106
@@ -111,7 +112,7 @@ Rectangle {
111 ]
112 ]
112
113
113 delegate: Row {
114 delegate: Row {
114− anchors { left: parent.left; right: parent.right; margins: units.gu(3) }
115+ anchors { left: column.left; right: column.right; margins: units.gu(3) }
115
116
116 Label {
117 Label {
117 height: units.gu(5)
118 height: units.gu(5)
@@ -315,28 +316,35 @@ Rectangle {
315 }
316 }
316 }
317 }
317
318
318− function test_card_header_component_alignment_data() {
319+ function test_card_title_alignment_data() {
319 return [
320 return [
320− { tag: "Title - vertical", component: "titleLabel", property: "headerAlignment",
321+ { tag: "Art, header, summary", value: Text.AlignLeft, index: 0 },
322+ { tag: "Header, summary", value: Text.AlignLeft, index: 1 },
323+ { tag: "Art, header", value: Text.AlignLeft, index: 2 },
324+ { tag: "Header only", value: Text.AlignLeft, index: 3 },
325+ { tag: "Header title only", value: Text.AlignHCenter, index: 4 },
326+ { tag: "Header title and subtitle", value: Text.AlignLeft, index: 5 },
327+ { tag: "Header title and mascot", value: Text.AlignLeft, index: 6 },
328+ { tag: "Art, header, summary - small", value: Text.AlignLeft, index: 7 },
329+ { tag: "Art, header, summary - large", value: Text.AlignLeft, index: 8 },
330+ { tag: "Art, header, summary - horizontal", value: Text.AlignLeft, index: 9 },
331+ { tag: "Art, header - portrait", value: Text.AlignLeft, index: 10 },
321− value: Text.AlignHCenter, index: 11, layout_index: 0 },
332+ { tag: "Title - vertical", value: Text.AlignHCenter, index: 11 },
322− { tag: "Title - horizontal", component: "titleLabel", property: "headerAlignment",
323− value: Text.AlignLeft, index: 12, layout_index: 0},
333+ { tag: "Title - horizontal", value: Text.AlignLeft, index: 12 },
324− { tag: "Title, subtitle - vertical", component: "titleLabel", property: "headerAlignment",
325− value: Text.AlignLeft, index: 13, layout_index: 0},
334+ { tag: "Title, subtitle - vertical", value: Text.AlignLeft, index: 13 },
326− { tag: "Title, price - horizontal", component: "titleLabel", property: "headerAlignment",
327− value: Text.AlignLeft, index: 14, layout_index: 0},
335+ { tag: "Title, attributes - horizontal", value: Text.AlignLeft, index: 14 },
328− ]
336+ ];
329 }
337 }
330
338
331− function test_card_header_component_alignment(data) {
339+ function test_card_title_alignment(data) {
332 selector.selectedIndex = data.index;
340 selector.selectedIndex = data.index;
333− if (data.hasOwnProperty("layout_index")) {
334− layoutSelector.selectedIndex = data.layout_index;
335− }
336
341
337− if (data.hasOwnProperty("property")) {
342+ tryCompare(cardTool, "titleAlignment", Text.AlignLeft);
338− tryCompare(cardTool, data.property, data.value);
343+
339− }
344+ cardTool.components['title'] = { "field": "title", "align": "center" };
345+ cardTool.componentsChanged();
346+
347+ tryCompare(cardTool, "titleAlignment", data.value);
340 }
348 }
341
349
342 function test_categoryLayout_data() {
350 function test_categoryLayout_data() {
tests/qmltests/Dash/tst_Dash.qml+16−39
@@ -55,6 +55,16 @@ Item {
55 scopes.load();
55 scopes.load();
56 tryCompare(dashContentList, "currentIndex", 0);
56 tryCompare(dashContentList, "currentIndex", 0);
57 tryCompare(dashContentList, "count", 6);
57 tryCompare(dashContentList, "count", 6);
58+ tryCompare(scopes, "loaded", true);
59+ tryCompareFunction(function() {
60+ var mockScope1Loader = findChild(dash, "MockScope1 loader");
61+ return mockScope1Loader && mockScope1Loader.item != null; },
62+ true, 15000);
63+ tryCompareFunction(function() {
64+ var mockScope1Loader = findChild(dash, "MockScope1 loader");
65+ return mockScope1Loader && mockScope1Loader.status === Loader.Ready; },
66+ true, 15000);
67+ waitForRendering(findChild(dash, "MockScope1 loader").item);
58 }
68 }
59
69
60 function get_scope_data() {
70 function get_scope_data() {
@@ -92,15 +102,6 @@ Item {
92 }
102 }
93
103
94 function test_dash_overview_show_select_same_favorite() {
104 function test_dash_overview_show_select_same_favorite() {
95− // Wait for stuff to be loaded
96− tryCompare(scopes, "loaded", true);
97− var dashContentList = findChild(dash, "dashContentList");
98− tryCompare(dashContentList, "count", 6);
99− tryCompareFunction(function() {
100− var mockScope1Loader = findChild(dash, "MockScope1 loader");
101− return mockScope1Loader && mockScope1Loader.item != null; },
102− true);
103−
104 // Show the overview
105 // Show the overview
105 touchFlick(dash, dash.width / 2, dash.height - 1, dash.width / 2, dash.height - units.gu(18));
106 touchFlick(dash, dash.width / 2, dash.height - 1, dash.width / 2, dash.height - units.gu(18));
106 var overviewController = findInvisibleChild(dash, "overviewController");
107 var overviewController = findInvisibleChild(dash, "overviewController");
@@ -121,18 +122,12 @@ Item {
121
122
122 // Make sure animation went back
123 // Make sure animation went back
123 tryCompare(overviewController, "progress", 0);
124 tryCompare(overviewController, "progress", 0);
125+
126+ var dashContentList = findChild(dash, "dashContentList");
124 compare(dashContentList.currentIndex, 0);
127 compare(dashContentList.currentIndex, 0);
125 }
128 }
126
129
127 function test_dash_overview_show_select_different_favorite() {
130 function test_dash_overview_show_select_different_favorite() {
128− // Wait for stuff to be loaded
129− tryCompare(scopes, "loaded", true);
130− var dashContentList = findChild(dash, "dashContentList");
131− tryCompare(dashContentList, "count", 6);
132− tryCompareFunction(function() { return findChild(dash, "MockScope1 loader") != null; }, true);
133− var mockScope1Loader = findChild(dash, "MockScope1 loader");
134− tryCompare(mockScope1Loader, "status", Loader.Ready);
135−
136 // Show the overview
131 // Show the overview
137 touchFlick(dash, dash.width / 2, dash.height - 1, dash.width / 2, dash.height - units.gu(18));
132 touchFlick(dash, dash.width / 2, dash.height - 1, dash.width / 2, dash.height - units.gu(18));
138 var overviewController = findInvisibleChild(dash, "overviewController");
133 var overviewController = findInvisibleChild(dash, "overviewController");
@@ -153,19 +148,11 @@ Item {
153
148
154 // Make sure animation went back
149 // Make sure animation went back
155 tryCompare(overviewController, "progress", 0);
150 tryCompare(overviewController, "progress", 0);
151+ var dashContentList = findChild(dash, "dashContentList");
156 compare(dashContentList.currentIndex, 1);
152 compare(dashContentList.currentIndex, 1);
157 }
153 }
158
154
159 function test_dash_overview_all_temp_scope_done_from_all() {
155 function test_dash_overview_all_temp_scope_done_from_all() {
160− // Wait for stuff to be loaded
161− tryCompare(scopes, "loaded", true);
162− var dashContentList = findChild(dash, "dashContentList");
163− tryCompare(dashContentList, "count", 6);
164− tryCompareFunction(function() {
165− var mockScope1Loader = findChild(dash, "MockScope1 loader");
166− return mockScope1Loader && mockScope1Loader.item != null; },
167− true);
168−
169 // Show the overview
156 // Show the overview
170 touchFlick(dash, dash.width / 2, dash.height - 1, dash.width / 2, dash.height - units.gu(18));
157 touchFlick(dash, dash.width / 2, dash.height - 1, dash.width / 2, dash.height - units.gu(18));
171 var overviewController = findInvisibleChild(dash, "overviewController");
158 var overviewController = findInvisibleChild(dash, "overviewController");
@@ -227,20 +214,13 @@ Item {
227 tryCompare(overviewController, "progress", 0);
214 tryCompare(overviewController, "progress", 0);
228
215
229 // Original list is still on 0
216 // Original list is still on 0
217+ var dashContentList = findChild(dash, "dashContentList");
230 compare(dashContentList.currentIndex, 0);
218 compare(dashContentList.currentIndex, 0);
231 }
219 }
232
220
233 function test_temp_scope_dash_overview_all_search_temp_scope_favorite_from_all() {
221 function test_temp_scope_dash_overview_all_search_temp_scope_favorite_from_all() {
234− // Wait for stuff to be loaded
235− tryCompare(scopes, "loaded", true);
236− var dashContentList = findChild(dash, "dashContentList");
237− tryCompare(dashContentList, "count", 6);
238− tryCompareFunction(function() {
239− var mockScope1Loader = findChild(dash, "MockScope1 loader");
240− return mockScope1Loader && mockScope1Loader.item != null; },
241− true);
242−
243 // Swipe right to Apps scope
222 // Swipe right to Apps scope
223+ var dashContentList = findChild(dash, "dashContentList");
244 touchFlick(dash, dash.width - 1, units.gu(1), dash.width - units.gu(10), units.gu(1));
224 touchFlick(dash, dash.width - 1, units.gu(1), dash.width - units.gu(10), units.gu(1));
245 tryCompare(dashContentList, "contentX", dashContentList.width);
225 tryCompare(dashContentList, "contentX", dashContentList.width);
246 tryCompare(dashContentList, "currentIndex", 1);
226 tryCompare(dashContentList, "currentIndex", 1);
@@ -249,8 +229,7 @@ Item {
249 var categoryListView = findChild(dashContentList.currentItem, "categoryListView");
229 var categoryListView = findChild(dashContentList.currentItem, "categoryListView");
250 var dashCategory2 = findChild(categoryListView, "dashCategory2");
230 var dashCategory2 = findChild(categoryListView, "dashCategory2");
251 tryCompareFunction(function() {
231 tryCompareFunction(function() {
252− var d = findChild(dashCategory2, "delegate2");
253− if (d) return true;
232+ if (dashCategory2.y < 200) return true;
254 categoryListView.contentY += 100;
233 categoryListView.contentY += 100;
255 return false;
234 return false;
256 }, true);
235 }, true);
@@ -340,8 +319,6 @@ Item {
340 }
319 }
341
320
342 function test_processing_indicator() {
321 function test_processing_indicator() {
343− tryCompare(scopes, "loaded", true);
344−
345 var processingIndicator = findChild(dash, "processingIndicator");
322 var processingIndicator = findChild(dash, "processingIndicator");
346 verify(processingIndicator, "Can't find the processing indicator.");
323 verify(processingIndicator, "Can't find the processing indicator.");
347
324
tests/qmltests/Dash/tst_DashContent.qml+14−1
@@ -70,7 +70,17 @@ Item {
70 function loadScopes() {
70 function loadScopes() {
71 scopeLoadedSpy.clear();
71 scopeLoadedSpy.clear();
72 scopesModel.load();
72 scopesModel.load();
73− tryCompare(scopeLoadedSpy, "count", 6);
73+ tryCompare(scopeLoadedSpy, "count", 6, 15000);
74+ tryCompare(scopesModel, "loaded", true);
75+ tryCompareFunction(function() {
76+ var mockScope1Loader = findChild(shell, "MockScope1 loader");
77+ return mockScope1Loader && mockScope1Loader.item != null; },
78+ true, 15000);
79+ tryCompareFunction(function() {
80+ var mockScope1Loader = findChild(shell, "MockScope1 loader");
81+ return mockScope1Loader && mockScope1Loader.status === Loader.Ready; },
82+ true, 15000);
83+ waitForRendering(findChild(shell, "MockScope1 loader").item);
74 }
84 }
75
85
76 function init() {
86 function init() {
@@ -467,6 +477,9 @@ Item {
467 var navigationListView = findChild(dashAltNavigationButton, "navigationListView");
477 var navigationListView = findChild(dashAltNavigationButton, "navigationListView");
468 tryCompare(navigationListView.currentItem.navigation, "loaded", true);
478 tryCompare(navigationListView.currentItem.navigation, "loaded", true);
469
479
480+ var blackRect = findChild(dashNavigation, "blackRect");
481+ tryCompare(blackRect, "opacity", 0.5);
482+
470 mouseClick(dashNavigation, dashNavigationButton.x, 0);
483 mouseClick(dashNavigation, dashNavigationButton.x, 0);
471 compare(dashNavigationButton.showList, false);
484 compare(dashNavigationButton.showList, false);
472 compare(dashAltNavigationButton.showList, false);
485 compare(dashAltNavigationButton.showList, false);
tests/qmltests/Dash/tst_GenericScopeView.qml+28−6
@@ -82,18 +82,19 @@ Item {
82 spy.signalName = "";
82 spy.signalName = "";
83 }
83 }
84
84
85− function scrollToCategory(category) {
85+ function scrollToCategory(categoryName) {
86 var categoryListView = findChild(genericScopeView, "categoryListView");
86 var categoryListView = findChild(genericScopeView, "categoryListView");
87 tryCompareFunction(function() {
87 tryCompareFunction(function() {
88− if (findChild(genericScopeView, category)) return true;
88+ var category = findChild(genericScopeView, categoryName);
89+ if (category && category.y > 0 && category.y < genericScopeView.height) return true;
89 mouseFlick(genericScopeView, genericScopeView.width/2, genericScopeView.height,
90 mouseFlick(genericScopeView, genericScopeView.width/2, genericScopeView.height,
90 genericScopeView.width/2, genericScopeView.y)
91 genericScopeView.width/2, genericScopeView.y)
91 tryCompare(categoryListView, "moving", false);
92 tryCompare(categoryListView, "moving", false);
92− return findChild(genericScopeView, category) !== null;
93+ return false;
93 }, true);
94 }, true);
94
95
95 tryCompareFunction(function() { return findChild(genericScopeView, "delegate0") !== null; }, true);
96 tryCompareFunction(function() { return findChild(genericScopeView, "delegate0") !== null; }, true);
96− return findChild(genericScopeView, category);
97+ return findChild(genericScopeView, categoryName);
97 }
98 }
98
99
99 function scrollToEnd()
100 function scrollToEnd()
@@ -283,7 +284,7 @@ Item {
283 if (category === undefined) category = 0;
284 if (category === undefined) category = 0;
284 if (delegate === undefined) delegate = 0;
285 if (delegate === undefined) delegate = 0;
285 tryCompareFunction(function() {
286 tryCompareFunction(function() {
286− var cardGrid = findChild(genericScopeView, category);
287+ var cardGrid = findChild(genericScopeView, "dashCategory"+category);
287 if (cardGrid != null) {
288 if (cardGrid != null) {
288 var tile = findChild(cardGrid, "delegate"+delegate);
289 var tile = findChild(cardGrid, "delegate"+delegate);
289 return tile != null;
290 return tile != null;
@@ -291,7 +292,7 @@ Item {
291 return false;
292 return false;
292 },
293 },
293 true);
294 true);
294− var tile = findChild(findChild(genericScopeView, category), "delegate"+delegate);
295+ var tile = findChild(findChild(genericScopeView, "dashCategory"+category), "delegate"+delegate);
295 mouseClick(tile, tile.width / 2, tile.height / 2);
296 mouseClick(tile, tile.width / 2, tile.height / 2);
296 tryCompare(testCase.subPageLoader, "open", true);
297 tryCompare(testCase.subPageLoader, "open", true);
297 tryCompare(testCase.subPageLoader, "x", 0);
298 tryCompare(testCase.subPageLoader, "x", 0);
@@ -581,6 +582,27 @@ Item {
581
582
582 genericScopeView.scope = !genericScopeView.scope;
583 genericScopeView.scope = !genericScopeView.scope;
583 }
584 }
585+
586+ function test_pullToRefresh() {
587+ waitForRendering(genericScopeView)
588+
589+ mouseFlick(genericScopeView,
590+ genericScopeView.width/2, units.gu(10),
591+ genericScopeView.width/2, units.gu(80),
592+ true, false)
593+
594+ var pullToRefresh = findChild(genericScopeView, "pullToRefresh")
595+ tryCompare(pullToRefresh, "releaseToRefresh", true)
596+
597+ spy.target = genericScopeView.scope
598+ spy.signalName = "refreshed"
599+
600+ mouseRelease(genericScopeView)
601+ tryCompare(pullToRefresh, "releaseToRefresh", false)
602+
603+ spy.wait()
604+ compare(spy.count, 1)
605+ }
584 }
606 }
585 }
607 }
586}
608}
tests/qmltests/tst_Shell.qml+4
@@ -198,6 +198,10 @@ Row {
198
198
199 var launcher = findChild(shell, "launcherPanel");
199 var launcher = findChild(shell, "launcherPanel");
200 tryCompare(launcher, "x", data.launcherHides ? -launcher.width : 0)
200 tryCompare(launcher, "x", data.launcherHides ? -launcher.width : 0)
201+
202+ // Make sure the helper for sliding out the launcher wasn't touched. We want to fade it out here.
203+ var animateTimer = findInvisibleChild(shell, "animateTimer");
204+ compare(animateTimer.nextState, "visible");
201 }
205 }
202
206
203 function test_suspend() {
207 function test_suspend() {
tests/utils/modules/Unity/Test/UnityTestCase.qml+3−2
@@ -178,9 +178,10 @@ TestCase {
178 // Keeps executing a given parameter-less function until it returns the given
178 // Keeps executing a given parameter-less function until it returns the given
179 // expected result or the timemout is reached (in which case a test failure
179 // expected result or the timemout is reached (in which case a test failure
180 // is generated)
180 // is generated)
181− function tryCompareFunction(func, expectedResult) {
181+ function tryCompareFunction(func, expectedResult, timeout) {
182 var timeSpent = 0
182 var timeSpent = 0
183+ if (timeout === undefined)
183− var timeout = 5000
184+ timeout = 5000;
184 var success = false
185 var success = false
185 var actualResult
186 var actualResult
186 while (timeSpent < timeout && !success) {
187 while (timeSpent < timeout && !success) {
tools/unlock-device+14−13
@@ -4,7 +4,7 @@
4# Our goal here is to get an Ubuntu Touch device into a testable unlocked state.
4# Our goal here is to get an Ubuntu Touch device into a testable unlocked state.
5# This will include a reboot.
5# This will include a reboot.
6
6
7−WAIT_COMMAND="adb reboot; sleep 5; adb wait-for-device"
7+WAIT_COMMAND="adb reboot; sleep 5; adb wait-for-device; sleep 20"
8
8
9while getopts s:w: opt; do
9while getopts s:w: opt; do
10 case $opt in
10 case $opt in
@@ -19,16 +19,17 @@ done
19
19
20eval "$WAIT_COMMAND"
20eval "$WAIT_COMMAND"
21
21
22−# Force a sleep no matter what, since we may need to wait for unity8
22+for i in `seq 1 5`; do
23−# to finish coming up (it's hard to tell when the greeter is actually rendered)
23+ # We need to go through sudo to get a proper environment for dbus set up
24+ UNLOCK_OUTPUT=$(adb shell "gdbus call --session --dest com.canonical.UnityGreeter --object-path / --method com.canonical.UnityGreeter.HideGreeter && echo Greeter unlocked" 2>&1)
25+ if echo "$UNLOCK_OUTPUT" | grep 'Greeter unlocked' >/dev/null; then
26+ echo "I: Unlock passed"
27+ exit 0
28+ else
29+ echo "I: Unlock attempt $i failed, script output: '$UNLOCK_OUTPUT'"
24−sleep 30
30+ sleep 20
31+ fi
32+done
25
33
26−# We need to go through sudo to get a proper environment for dbus set up
34+echo "I: Too many unlock failures, giving up"
27−UNLOCK_OUTPUT=$(adb shell "gdbus call --session --dest com.canonical.UnityGreeter --object-path / --method com.canonical.UnityGreeter.HideGreeter && echo Greeter unlocked" 2>&1)
28−if echo "$UNLOCK_OUTPUT" | grep 'Greeter unlocked' >/dev/null; then
29− echo "I: Unlock passed"
30− exit 0
31−else
32− echo "I: Unlock failed, script output: '$UNLOCK_OUTPUT'"
33− exit 1
35+exit 1
34−fi