Merge lp:~unity-team/unity8/rtm-20150108 into lp:unity8/rtm-14.09

Proposed by Michał Sawicz
Status: Merged
Approved by: Michał Sawicz
Approved revision: 1416
Merged at revision: 1411
Proposed branch: lp:~unity-team/unity8/rtm-20150108
Merge into: lp:unity8/rtm-14.09
Diff against target: 1539 lines (+708/-143)
43 files modified
debian/changelog (+18/-0)
debian/control (+0/-1)
plugins/Dash/CMakeLists.txt (+3/-2)
plugins/Dash/CardCreator.js (+8/-10)
plugins/Dash/CroppedImageMinimumSourceSize.qml (+25/-19)
plugins/Dash/abstractdashview.cpp (+24/-5)
plugins/Dash/abstractdashview.h (+6/-0)
plugins/Dash/croppedimagesizer.cpp (+136/-0)
plugins/Dash/croppedimagesizer.h (+72/-0)
plugins/Dash/croppedimagesizerasyncworker.cpp (+74/-0)
plugins/Dash/croppedimagesizerasyncworker.h (+47/-0)
plugins/Dash/listviewwithpageheader.cpp (+7/-2)
plugins/Dash/listviewwithpageheader.h (+4/-4)
plugins/Dash/plugin.cpp (+2/-0)
qml/Components/ResponsiveVerticalJournal.qml (+1/-0)
qml/Dash/CardCarousel.qml (+1/-0)
qml/Dash/CardGrid.qml (+1/-2)
qml/Dash/CardHorizontalList.qml (+1/-0)
qml/Dash/CardVerticalJournal.qml (+1/-1)
qml/Dash/DashContent.qml (+2/-0)
qml/Dash/DashRenderer.qml (+2/-4)
qml/Dash/GenericScopeView.qml (+75/-24)
qml/Dash/Previews/PreviewZoomableImage.qml (+1/-0)
qml/Dash/ScopeListView.qml (+4/-2)
qml/Greeter/Infographics.qml (+9/-7)
qml/Shell.qml (+20/-2)
tests/autopilot/unity8/shell/emulators/dash.py (+1/-1)
tests/plugins/Dash/CMakeLists.txt (+1/-0)
tests/plugins/Dash/cardcreator/1.res (+4/-4)
tests/plugins/Dash/cardcreator/2.res (+2/-3)
tests/plugins/Dash/cardcreator/3.res (+10/-10)
tests/plugins/Dash/cardcreator/4.res (+3/-4)
tests/plugins/Dash/cardcreator/5.res (+10/-10)
tests/plugins/Dash/cardcreator/7.res (+2/-3)
tests/plugins/Dash/horizontaljournaltest.qml (+1/-0)
tests/plugins/Dash/listviewwithpageheadertest.cpp (+1/-1)
tests/plugins/Dash/organicgridtest.qml (+1/-0)
tests/plugins/Dash/tst_CroppedImageMinimumSourceSize.qml (+56/-0)
tests/plugins/Dash/verticaljournaltest.qml (+1/-0)
tests/qmltests/Dash/tst_Card.qml (+0/-22)
tests/qmltests/Dash/tst_DashContent.qml (+57/-0)
tests/qmltests/Dash/tst_GenericScopeView.qml (+2/-0)
tests/utils/modules/Unity/Test/UnityTestCase.qml (+12/-0)
To merge this branch: bzr merge lp:~unity-team/unity8/rtm-20150108
Reviewer Review Type Date Requested Status
Michał Sawicz Approve
Review via email: mp+245852@code.launchpad.net
To post a comment you must log in.
lp:~unity-team/unity8/rtm-20150108 updated
1414. By Albert Astals Cid

Rework how we set the ranges so we get some more asynchronousity from item views
Approved by: Andrea Cimitan

1415. By Michał Sawicz

Don't block handling power events on loading the greeter's qml and the background image.

During power button press, we call greeter.showNow(), which was taking so long to return that we couldn't handle the power button release for a few seconds. Which meant that the shutdown dialog thought it would be a good time to appear.

The easiest fix is to delay calling showNow until after we finish handling the event.
Approved by: Daniel d'Andrada, PS Jenkins bot

1416. By Michał Sawicz

Add changelog

Revision history for this message
Michał Sawicz (saviq) wrote :

As per the upstream changes.

review: Approve
lp:~unity-team/unity8/rtm-20150108 updated
1417. By Albert Astals Cid

Make sure changing a scope doesn't trigger creation/destruction of delegates until it's finished

1418. By Michał Sawicz

Update changelog

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'debian/changelog'
2--- debian/changelog 2015-01-07 09:49:10 +0000
3+++ debian/changelog 2015-01-13 15:16:16 +0000
4@@ -1,3 +1,21 @@
5+unity8 (8.02+15.04.20150108~rtm--0ubuntu1) UNRELEASED; urgency=medium
6+
7+ [ Albert Astals ]
8+ * Use QImageReader not to load the image into memory twice
9+ * Don't create the whole current scope delegates, just height * 3 (LP:
10+ #1384393)
11+ * Make CroppedImageSizer async
12+ * Rework how we set the ranges so we get some more asynchronousity
13+ from item views
14+ * Make sure changing a scope doesn't trigger creation/destruction of
15+ delegates until it's finished
16+
17+ [ Michael Terry ]
18+ * Don't block handling power events on loading the greeter's qml and the
19+ background image. (LP: #1383277)
20+
21+ -- Michał Sawicz <michal.sawicz@canonical.com> Thu, 08 Jan 2015 14:02:47 +0100
22+
23 unity8 (8.02+15.04.20150107~rtm-0ubuntu1) 14.09; urgency=low
24
25 [ Michael Zanetti ]
26
27=== modified file 'debian/control'
28--- debian/control 2014-12-12 13:08:13 +0000
29+++ debian/control 2015-01-13 15:16:16 +0000
30@@ -174,7 +174,6 @@
31 libhardware2,
32 unity-schemas (>= 7.3.1+14.10.20140915),
33 pay-service,
34- qml-module-ubuntu-connectivity,
35 ${misc:Depends},
36 ${shlibs:Depends},
37 Provides: unity-launcher-impl,
38
39=== modified file 'plugins/Dash/CMakeLists.txt'
40--- plugins/Dash/CMakeLists.txt 2014-05-14 10:11:14 +0000
41+++ plugins/Dash/CMakeLists.txt 2015-01-13 15:16:16 +0000
42@@ -11,7 +11,6 @@
43 ${CMAKE_CURRENT_SOURCE_DIR}
44 ${CMAKE_CURRENT_BINARY_DIR}
45 ${Qt5Qml_PRIVATE_INCLUDE_DIRS}
46- ${Qt5Quick_INCLUDE_DIRS}
47 ${Qt5Quick_PRIVATE_INCLUDE_DIRS}
48 ${Qt5V8_PRIVATE_INCLUDE_DIR}
49 )
50@@ -25,6 +24,8 @@
51 verticaljournal.cpp
52 horizontaljournal.cpp
53 organicgrid.cpp
54+ croppedimagesizer.cpp
55+ croppedimagesizerasyncworker.cpp
56 )
57
58 add_library(Dash-qml MODULE
59@@ -36,6 +37,6 @@
60 ${Qt5Quick_LIBRARIES}
61 )
62
63-qt5_use_modules(Dash-qml Qml Quick)
64+qt5_use_modules(Dash-qml Qml Quick Concurrent)
65
66 add_unity8_plugin(Dash 0.1 Dash TARGETS Dash-qml)
67
68=== modified file 'plugins/Dash/CardCreator.js'
69--- plugins/Dash/CardCreator.js 2014-10-20 20:51:10 +0000
70+++ plugins/Dash/CardCreator.js 2015-01-13 15:16:16 +0000
71@@ -82,16 +82,16 @@
72 height = Qt.binding(function() { return image.status !== Image.Ready ? 0 : image.height }); \n\
73 } \n\
74 } \n\
75- image: CroppedImageMinimumSourceSize { \n\
76+ CroppedImageMinimumSourceSize { \n\
77+ id: artImage; \n\
78 objectName: "artImage"; \n\
79- property bool doLoadSource: !NetworkingStatus.limitedBandwith; \n\
80- source: { if (root.visible) doLoadSource = true; return doLoadSource && cardData && cardData["art"] || ""; } \n\
81- cache: true; \n\
82+ source: cardData && cardData["art"] || ""; \n\
83 asynchronous: root.asynchronous; \n\
84 visible: false; \n\
85 width: %2; \n\
86 height: %3; \n\
87 } \n\
88+ image: artImage.image; \n\
89 } \n\
90 } \n\
91 }\n';
92@@ -181,11 +181,11 @@
93 id: mascotShapeLoader; \n\
94 objectName: "mascotShapeLoader"; \n\
95 asynchronous: root.asynchronous; \n\
96- active: mascotImage.status === Image.Ready; \n\
97+ active: mascotImage.image.status === Image.Ready; \n\
98 visible: showHeader && active && status == Loader.Ready; \n\
99 width: units.gu(6); \n\
100 height: units.gu(5.625); \n\
101- sourceComponent: UbuntuShape { image: mascotImage } \n\
102+ sourceComponent: UbuntuShape { image: mascotImage.image } \n\
103 anchors { %1 } \n\
104 }\n';
105
106@@ -195,8 +195,7 @@
107 id: mascotImage; \n\
108 objectName: "mascotImage"; \n\
109 anchors { %1 } \n\
110- property bool doLoadSource: !NetworkingStatus.limitedBandwith; \n\
111- source: { if (root.visible) doLoadSource = true; return doLoadSource && cardData && cardData["mascot"] || ""; } \n\
112+ source: cardData && cardData["mascot"] || ""; \n\
113 width: units.gu(6); \n\
114 height: units.gu(5.625); \n\
115 horizontalAlignment: Image.AlignHCenter; \n\
116@@ -435,7 +434,7 @@
117 mascotShapeCode = kMascotShapeLoaderCode.arg(mascotAnchors);
118 }
119
120- var mascotImageVisible = useMascotShape ? 'false' : 'showHeader && resized';
121+ var mascotImageVisible = useMascotShape ? 'false' : 'showHeader';
122 mascotCode = kMascotImageCode.arg(mascotAnchors).arg(mascotImageVisible);
123 }
124
125@@ -655,7 +654,6 @@
126 var imports = 'import QtQuick 2.2; \n\
127 import Ubuntu.Components 1.1; \n\
128 import Ubuntu.Settings.Components 0.1; \n\
129- import Ubuntu.Connectivity 1.0; \n\
130 import Dash 0.1;\n\
131 import Utils 0.1;\n';
132 var card = cardString(template, components);
133
134=== modified file 'plugins/Dash/CroppedImageMinimumSourceSize.qml'
135--- plugins/Dash/CroppedImageMinimumSourceSize.qml 2014-09-17 10:16:11 +0000
136+++ plugins/Dash/CroppedImageMinimumSourceSize.qml 2015-01-13 15:16:16 +0000
137@@ -15,24 +15,30 @@
138 */
139
140 import QtQuick 2.3
141-
142-Image {
143- property bool resized: false
144- property bool resizing: false
145- fillMode: Image.PreserveAspectCrop
146- visible: resized
147- onSourceSizeChanged: {
148- if (!resized && !resizing) {
149- resizing = true;
150- var ar = width / height;
151- var ssar = sourceSize.width / sourceSize.height;
152- if (ar > ssar) {
153- sourceSize = Qt.size(width, 0);
154- } else {
155- sourceSize = Qt.size(0, height);
156- }
157- resizing = false;
158- resized = true;
159- }
160+import Dash 0.1
161+
162+Item {
163+ id: root
164+
165+ property string source
166+ property alias image: innerImage
167+ property alias asynchronous: innerImage.asynchronous
168+ property alias verticalAlignment: innerImage.verticalAlignment
169+ property alias horizontalAlignment: innerImage.horizontalAlignment
170+ property alias fillMode: innerImage.fillMode
171+
172+ CroppedImageSizer {
173+ id: sizer
174+ source: root.source
175+ width: root.width
176+ height: root.height
177+ }
178+
179+ Image {
180+ id: innerImage
181+ anchors.fill: parent
182+ fillMode: Image.PreserveAspectCrop
183+ sourceSize: sizer.sourceSize.width == 0 && sizer.sourceSize.height == 0 ? undefined : sizer.sourceSize
184+ source: sizer.sourceSize.width == -1 && sizer.sourceSize.height == -1 ? "" : root.source
185 }
186 }
187
188=== modified file 'plugins/Dash/abstractdashview.cpp'
189--- plugins/Dash/abstractdashview.cpp 2014-05-22 13:37:05 +0000
190+++ plugins/Dash/abstractdashview.cpp 2015-01-13 15:16:16 +0000
191@@ -16,13 +16,12 @@
192
193 #include "abstractdashview.h"
194
195-static const qreal bufferRatio = 0.5;
196-
197 AbstractDashView::AbstractDashView()
198 : m_delegateModel(nullptr)
199 , m_asyncRequestedIndex(-1)
200 , m_columnSpacing(0)
201 , m_rowSpacing(0)
202+ , m_buffer(320) // Same value used in qquickitemview.cpp in Qt 5.4
203 , m_displayMarginBeginning(0)
204 , m_displayMarginEnd(0)
205 , m_needsRelayout(false)
206@@ -112,6 +111,27 @@
207 }
208 }
209
210+int AbstractDashView::cacheBuffer() const
211+{
212+ return m_buffer;
213+}
214+
215+void AbstractDashView::setCacheBuffer(int buffer)
216+{
217+ if (buffer < 0) {
218+ qmlInfo(this) << "Cannot set a negative cache buffer";
219+ return;
220+ }
221+
222+ if (m_buffer != buffer) {
223+ m_buffer = buffer;
224+ if (isComponentComplete()) {
225+ polish();
226+ }
227+ emit cacheBufferChanged();
228+ }
229+}
230+
231 qreal AbstractDashView::displayMarginBeginning() const
232 {
233 return m_displayMarginBeginning;
234@@ -160,9 +180,8 @@
235
236 const qreal from = -m_displayMarginBeginning;
237 const qreal to = height() + m_displayMarginEnd;
238- const qreal buffer = (to - from) * bufferRatio;
239- const qreal bufferFrom = from - buffer;
240- const qreal bufferTo = to + buffer;
241+ const qreal bufferFrom = from - m_buffer;
242+ const qreal bufferTo = to + m_buffer;
243
244 bool added = addVisibleItems(from, to, false);
245 bool removed = removeNonVisibleItems(bufferFrom, bufferTo);
246
247=== modified file 'plugins/Dash/abstractdashview.h'
248--- plugins/Dash/abstractdashview.h 2014-05-15 14:50:23 +0000
249+++ plugins/Dash/abstractdashview.h 2015-01-13 15:16:16 +0000
250@@ -35,6 +35,7 @@
251 Q_PROPERTY(QQmlComponent *delegate READ delegate WRITE setDelegate NOTIFY delegateChanged)
252 Q_PROPERTY(qreal columnSpacing READ columnSpacing WRITE setColumnSpacing NOTIFY columnSpacingChanged)
253 Q_PROPERTY(qreal rowSpacing READ rowSpacing WRITE setRowSpacing NOTIFY rowSpacingChanged)
254+ Q_PROPERTY(int cacheBuffer READ cacheBuffer WRITE setCacheBuffer NOTIFY cacheBufferChanged)
255 Q_PROPERTY(qreal displayMarginBeginning READ displayMarginBeginning
256 WRITE setDisplayMarginBeginning
257 NOTIFY displayMarginBeginningChanged)
258@@ -61,6 +62,9 @@
259 qreal rowSpacing() const;
260 void setRowSpacing(qreal rowSpacing);
261
262+ int cacheBuffer() const;
263+ void setCacheBuffer(int);
264+
265 qreal displayMarginBeginning() const;
266 void setDisplayMarginBeginning(qreal);
267
268@@ -72,6 +76,7 @@
269 void delegateChanged();
270 void columnSpacingChanged();
271 void rowSpacingChanged();
272+ void cacheBufferChanged();
273 void displayMarginBeginningChanged();
274 void displayMarginEndChanged();
275
276@@ -113,6 +118,7 @@
277
278 int m_columnSpacing;
279 int m_rowSpacing;
280+ int m_buffer;
281 qreal m_displayMarginBeginning;
282 qreal m_displayMarginEnd;
283 bool m_needsRelayout;
284
285=== added file 'plugins/Dash/croppedimagesizer.cpp'
286--- plugins/Dash/croppedimagesizer.cpp 1970-01-01 00:00:00 +0000
287+++ plugins/Dash/croppedimagesizer.cpp 2015-01-13 15:16:16 +0000
288@@ -0,0 +1,136 @@
289+/*
290+ * Copyright (C) 2014 Canonical, Ltd.
291+ *
292+ * This program is free software; you can redistribute it and/or modify
293+ * it under the terms of the GNU General Public License as published by
294+ * the Free Software Foundation; version 3.
295+ *
296+ * This program is distributed in the hope that it will be useful,
297+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
298+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
299+ * GNU General Public License for more details.
300+ *
301+ * You should have received a copy of the GNU General Public License
302+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
303+ */
304+
305+#include "croppedimagesizer.h"
306+
307+#include "croppedimagesizerasyncworker.h"
308+
309+#include <QNetworkAccessManager>
310+#include <QNetworkRequest>
311+#include <QQmlEngine>
312+#include <QQuickItem>
313+
314+CroppedImageSizer::CroppedImageSizer()
315+ : m_width(0),
316+ m_height(0),
317+ m_sourceSize(QSize(-1, -1)),
318+ m_worker(nullptr)
319+{
320+ connect(this, &CroppedImageSizer::inputParamsChanged, this, &CroppedImageSizer::calculateSourceSize);
321+ connect(this, &CroppedImageSizer::sourceChanged, this, &CroppedImageSizer::requestImage);
322+}
323+
324+CroppedImageSizer::~CroppedImageSizer()
325+{
326+ if (m_worker) {
327+ m_worker->abort();
328+ }
329+}
330+
331+QUrl CroppedImageSizer::source() const
332+{
333+ return m_source;
334+}
335+
336+void CroppedImageSizer::setSource(const QUrl &source)
337+{
338+ if (source != m_source) {
339+ m_source = source;
340+ Q_EMIT sourceChanged();
341+ }
342+}
343+
344+qreal CroppedImageSizer::width() const
345+{
346+ return m_width;
347+}
348+
349+void CroppedImageSizer::setWidth(qreal width)
350+{
351+ if (width != m_width) {
352+ m_width = width;
353+ Q_EMIT inputParamsChanged();
354+ }
355+}
356+
357+qreal CroppedImageSizer::height() const
358+{
359+ return m_height;
360+}
361+
362+void CroppedImageSizer::setHeight(qreal height)
363+{
364+ if (height != m_height) {
365+ m_height = height;
366+ Q_EMIT inputParamsChanged();
367+ }
368+}
369+
370+QSize CroppedImageSizer::sourceSize() const
371+{
372+ return m_sourceSize;
373+}
374+
375+void CroppedImageSizer::setSourceSize(const QSize &sourceSize)
376+{
377+ if (sourceSize != m_sourceSize) {
378+ m_sourceSize = sourceSize;
379+ Q_EMIT sourceSizeChanged();
380+ }
381+}
382+
383+void CroppedImageSizer::setImageSize(const QSize &imageSize)
384+{
385+ m_imageSize = imageSize;
386+ m_worker = nullptr;
387+ calculateSourceSize();
388+}
389+
390+void CroppedImageSizer::requestImage()
391+{
392+ if (m_worker) {
393+ m_worker->abort();
394+ m_worker = nullptr;
395+ }
396+
397+ if (m_source.isValid() && qmlEngine(this) && qmlEngine(this)->networkAccessManager()) {
398+ QNetworkRequest request(m_source);
399+ QNetworkReply *reply = qmlEngine(this)->networkAccessManager()->get(request);
400+ m_worker = new CroppedImageSizerAsyncWorker(this, reply);
401+ } else {
402+ setSourceSize(QSize(-1, -1));
403+ }
404+}
405+
406+void CroppedImageSizer::calculateSourceSize()
407+{
408+ if (m_source.isValid() && m_width > 0 && m_height > 0 && !m_worker) {
409+ if (!m_imageSize.isEmpty()) {
410+ const qreal ar = m_width / m_height;
411+ const qreal ssar = m_imageSize.width() / (qreal)m_imageSize.height();
412+ if (ar > ssar) {
413+ setSourceSize(QSize(m_width, 0));
414+ } else {
415+ setSourceSize(QSize(0, m_height));
416+ }
417+ } else {
418+ qWarning() << "Invalid size for " << m_source << m_imageSize;
419+ setSourceSize(QSize(0, 0));
420+ }
421+ } else {
422+ setSourceSize(QSize(-1, -1));
423+ }
424+}
425
426=== added file 'plugins/Dash/croppedimagesizer.h'
427--- plugins/Dash/croppedimagesizer.h 1970-01-01 00:00:00 +0000
428+++ plugins/Dash/croppedimagesizer.h 2015-01-13 15:16:16 +0000
429@@ -0,0 +1,72 @@
430+/*
431+ * Copyright (C) 2014 Canonical, Ltd.
432+ *
433+ * This program is free software; you can redistribute it and/or modify
434+ * it under the terms of the GNU General Public License as published by
435+ * the Free Software Foundation; version 3.
436+ *
437+ * This program is distributed in the hope that it will be useful,
438+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
439+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
440+ * GNU General Public License for more details.
441+ *
442+ * You should have received a copy of the GNU General Public License
443+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
444+ */
445+
446+#ifndef CROPPEDIMAGESIZER_H
447+#define CROPPEDIMAGESIZER_H
448+
449+#include <QImageReader>
450+#include <QObject>
451+#include <QSize>
452+#include <QUrl>
453+
454+class CroppedImageSizerAsyncWorker;
455+
456+class CroppedImageSizer : public QObject
457+{
458+ Q_OBJECT
459+
460+ Q_PROPERTY(QUrl source READ source WRITE setSource NOTIFY sourceChanged)
461+ Q_PROPERTY(qreal width READ width WRITE setWidth NOTIFY inputParamsChanged)
462+ Q_PROPERTY(qreal height READ height WRITE setHeight NOTIFY inputParamsChanged)
463+ Q_PROPERTY(QSize sourceSize READ sourceSize NOTIFY sourceSizeChanged)
464+
465+public:
466+ CroppedImageSizer();
467+ ~CroppedImageSizer();
468+
469+ QUrl source() const;
470+ void setSource(const QUrl &source);
471+
472+ qreal width() const;
473+ void setWidth(qreal width);
474+
475+ qreal height() const;
476+ void setHeight(qreal height);
477+
478+ QSize sourceSize() const;
479+ void setSourceSize(const QSize &sourceSize);
480+
481+ Q_INVOKABLE void setImageSize(const QSize &imageSize);
482+
483+Q_SIGNALS:
484+ void inputParamsChanged();
485+ void sourceChanged();
486+ void sourceSizeChanged();
487+
488+private Q_SLOT:
489+ void calculateSourceSize();
490+ void requestImage();
491+
492+private:
493+ QUrl m_source;
494+ qreal m_width;
495+ qreal m_height;
496+ QSize m_sourceSize;
497+ QSize m_imageSize;
498+ QPointer<CroppedImageSizerAsyncWorker> m_worker;
499+};
500+
501+#endif
502
503=== added file 'plugins/Dash/croppedimagesizerasyncworker.cpp'
504--- plugins/Dash/croppedimagesizerasyncworker.cpp 1970-01-01 00:00:00 +0000
505+++ plugins/Dash/croppedimagesizerasyncworker.cpp 2015-01-13 15:16:16 +0000
506@@ -0,0 +1,74 @@
507+/*
508+ * Copyright (C) 2014 Canonical, Ltd.
509+ *
510+ * This program is free software; you can redistribute it and/or modify
511+ * it under the terms of the GNU General Public License as published by
512+ * the Free Software Foundation; version 3.
513+ *
514+ * This program is distributed in the hope that it will be useful,
515+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
516+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
517+ * GNU General Public License for more details.
518+ *
519+ * You should have received a copy of the GNU General Public License
520+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
521+ */
522+
523+#include "croppedimagesizerasyncworker.h"
524+
525+#include "croppedimagesizer.h"
526+
527+#include <QNetworkReply>
528+#include <QtConcurrentRun>
529+
530+CroppedImageSizerAsyncWorker::CroppedImageSizerAsyncWorker(CroppedImageSizer *sizer, QNetworkReply *reply)
531+ : m_sizer(sizer),
532+ m_reply(reply),
533+ m_ignoreAbort(false)
534+{
535+ connect(m_reply, &QNetworkReply::finished, this, &CroppedImageSizerAsyncWorker::requestFinished);
536+}
537+
538+void CroppedImageSizerAsyncWorker::abort()
539+{
540+ // This runs on main thread
541+ QMutexLocker locker(&m_mutex);
542+ m_sizer = nullptr;
543+ // If we already started the future run we can't abort the reply
544+ // since we don't know at which stage the future is, just let it finish
545+ if (!m_ignoreAbort) {
546+ QMetaObject::invokeMethod(m_reply, "abort", Qt::QueuedConnection);
547+ }
548+}
549+
550+void CroppedImageSizerAsyncWorker::requestFinished()
551+{
552+ // This runs on main thread
553+ QMutexLocker locker(&m_mutex);
554+ if (m_sizer) {
555+ m_ignoreAbort = true;
556+ QtConcurrent::run(processRequestFinished, this);
557+ } else {
558+ // We were aborted delete ourselves
559+ m_reply->deleteLater();
560+ deleteLater();
561+ }
562+}
563+
564+void CroppedImageSizerAsyncWorker::processRequestFinished(CroppedImageSizerAsyncWorker *worker)
565+{
566+ // This runs on non main thread
567+ // m_reply has finished at this point and is protected against change by m_ignoreAbort
568+ QImageReader reader(worker->m_reply);
569+ const QSize imageSize = reader.size();
570+
571+ worker->m_mutex.lock();
572+ if (worker->m_sizer) {
573+ QMetaObject::invokeMethod(worker->m_sizer, "setImageSize", Qt::QueuedConnection, Q_ARG(QSize, imageSize));
574+ }
575+ worker->m_mutex.unlock();
576+
577+ // All work is done, delete ourselves
578+ worker->m_reply->deleteLater();
579+ worker->deleteLater();
580+}
581
582=== added file 'plugins/Dash/croppedimagesizerasyncworker.h'
583--- plugins/Dash/croppedimagesizerasyncworker.h 1970-01-01 00:00:00 +0000
584+++ plugins/Dash/croppedimagesizerasyncworker.h 2015-01-13 15:16:16 +0000
585@@ -0,0 +1,47 @@
586+/*
587+ * Copyright (C) 2014 Canonical, Ltd.
588+ *
589+ * This program is free software; you can redistribute it and/or modify
590+ * it under the terms of the GNU General Public License as published by
591+ * the Free Software Foundation; version 3.
592+ *
593+ * This program is distributed in the hope that it will be useful,
594+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
595+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
596+ * GNU General Public License for more details.
597+ *
598+ * You should have received a copy of the GNU General Public License
599+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
600+ */
601+
602+#ifndef CROPPEDIMAGESIZERASYNCWORKER_H
603+#define CROPPEDIMAGESIZERASYNCWORKER_H
604+
605+#include <QMutex>
606+#include <QObject>
607+
608+class CroppedImageSizer;
609+
610+class QNetworkReply;
611+
612+class CroppedImageSizerAsyncWorker : public QObject
613+{
614+ Q_OBJECT
615+public:
616+ CroppedImageSizerAsyncWorker(CroppedImageSizer *sizer, QNetworkReply *reply);
617+
618+ void abort();
619+
620+private Q_SLOTS:
621+ void requestFinished();
622+
623+private:
624+ static void processRequestFinished(CroppedImageSizerAsyncWorker *worker);
625+
626+ QMutex m_mutex;
627+ CroppedImageSizer *m_sizer;
628+ QNetworkReply *m_reply;
629+ bool m_ignoreAbort;
630+};
631+
632+#endif
633
634=== modified file 'plugins/Dash/listviewwithpageheader.cpp'
635--- plugins/Dash/listviewwithpageheader.cpp 2014-10-13 15:42:02 +0000
636+++ plugins/Dash/listviewwithpageheader.cpp 2015-01-13 15:16:16 +0000
637@@ -334,13 +334,18 @@
638 return m_headerItemShownHeight;
639 }
640
641-qreal ListViewWithPageHeader::cacheBuffer() const
642+int ListViewWithPageHeader::cacheBuffer() const
643 {
644 return m_cacheBuffer;
645 }
646
647-void ListViewWithPageHeader::setCacheBuffer(qreal cacheBuffer)
648+void ListViewWithPageHeader::setCacheBuffer(int cacheBuffer)
649 {
650+ if (cacheBuffer < 0) {
651+ qmlInfo(this) << "Cannot set a negative cache buffer";
652+ return;
653+ }
654+
655 if (cacheBuffer != m_cacheBuffer) {
656 m_cacheBuffer = cacheBuffer;
657 Q_EMIT cacheBufferChanged();
658
659=== modified file 'plugins/Dash/listviewwithpageheader.h'
660--- plugins/Dash/listviewwithpageheader.h 2014-10-10 11:13:26 +0000
661+++ plugins/Dash/listviewwithpageheader.h 2015-01-13 15:16:16 +0000
662@@ -54,7 +54,7 @@
663 Q_PROPERTY(bool forceNoClip READ forceNoClip WRITE setForceNoClip NOTIFY forceNoClipChanged)
664 Q_PROPERTY(int stickyHeaderHeight READ stickyHeaderHeight NOTIFY stickyHeaderHeightChanged)
665 Q_PROPERTY(qreal headerItemShownHeight READ headerItemShownHeight NOTIFY headerItemShownHeightChanged)
666- Q_PROPERTY(qreal cacheBuffer READ cacheBuffer WRITE setCacheBuffer NOTIFY cacheBufferChanged)
667+ Q_PROPERTY(int cacheBuffer READ cacheBuffer WRITE setCacheBuffer NOTIFY cacheBufferChanged)
668
669 friend class ListViewWithPageHeaderTest;
670 friend class ListViewWithPageHeaderTestSection;
671@@ -85,8 +85,8 @@
672 int stickyHeaderHeight() const;
673 qreal headerItemShownHeight() const;
674
675- qreal cacheBuffer() const;
676- void setCacheBuffer(qreal cacheBuffer);
677+ int cacheBuffer() const;
678+ void setCacheBuffer(int cacheBuffer);
679
680 Q_INVOKABLE void positionAtBeginning();
681 Q_INVOKABLE void showHeader();
682@@ -204,7 +204,7 @@
683 bool m_forceNoClip;
684 bool m_inLayout;
685 bool m_inContentHeightKeepHeaderShown;
686- qreal m_cacheBuffer;
687+ int m_cacheBuffer;
688
689 // Qt 5.0 doesn't like releasing the items just after itemCreated
690 // so we delay the releasing until the next updatePolish
691
692=== modified file 'plugins/Dash/plugin.cpp'
693--- plugins/Dash/plugin.cpp 2014-04-30 10:06:33 +0000
694+++ plugins/Dash/plugin.cpp 2015-01-13 15:16:16 +0000
695@@ -17,6 +17,7 @@
696
697 #include "plugin.h"
698
699+#include "croppedimagesizer.h"
700 #include "horizontaljournal.h"
701 #include "listviewwithpageheader.h"
702 #include "organicgrid.h"
703@@ -32,4 +33,5 @@
704 qmlRegisterType<ListViewWithPageHeader>(uri, 0, 1, "ListViewWithPageHeader");
705 qmlRegisterType<OrganicGrid>(uri, 0, 1, "OrganicGrid");
706 qmlRegisterType<VerticalJournal>(uri, 0, 1, "VerticalJournal");
707+ qmlRegisterType<CroppedImageSizer>(uri, 0, 1, "CroppedImageSizer");
708 }
709
710=== modified file 'qml/Components/ResponsiveVerticalJournal.qml'
711--- qml/Components/ResponsiveVerticalJournal.qml 2014-10-02 11:08:26 +0000
712+++ qml/Components/ResponsiveVerticalJournal.qml 2015-01-13 15:16:16 +0000
713@@ -45,6 +45,7 @@
714 property alias rowSpacing: verticalJournalView.rowSpacing
715 property alias model: verticalJournalView.model
716 property alias delegate: verticalJournalView.delegate
717+ property alias cacheBuffer: verticalJournalView.cacheBuffer
718 property alias displayMarginBeginning: verticalJournalView.displayMarginBeginning
719 property alias displayMarginEnd: verticalJournalView.displayMarginEnd
720
721
722=== modified file 'qml/Dash/CardCarousel.qml'
723--- qml/Dash/CardCarousel.qml 2014-09-12 09:31:56 +0000
724+++ qml/Dash/CardCarousel.qml 2015-01-13 15:16:16 +0000
725@@ -52,6 +52,7 @@
726 function pressAndHold() { cardCarousel.pressAndHold(index, model.result, model) }
727
728 sourceComponent: cardTool.cardComponent
729+ asynchronous: true
730 onLoaded: {
731 item.fixedHeaderHeight = Qt.binding(function() { return carousel.headerHeight; });
732 item.height = Qt.binding(function() { return cardTool.cardHeight; });
733
734=== modified file 'qml/Dash/CardGrid.qml'
735--- qml/Dash/CardGrid.qml 2014-09-30 09:23:23 +0000
736+++ qml/Dash/CardGrid.qml 2015-01-13 15:16:16 +0000
737@@ -50,12 +50,11 @@
738 model: root.model
739 displayMarginBeginning: root.displayMarginBeginning
740 displayMarginEnd: root.displayMarginEnd
741- cacheBuffer: 0
742+ cacheBuffer: root.cacheBuffer
743 interactive: false
744 delegate: Item {
745 width: grid.cellWidth
746 height: grid.cellHeight
747- visible: y + height >= root.visibleRangeBegin && y <= root.visibleRangeEnd
748 Loader {
749 id: loader
750 sourceComponent: cardTool.cardComponent
751
752=== modified file 'qml/Dash/CardHorizontalList.qml'
753--- qml/Dash/CardHorizontalList.qml 2014-10-23 11:59:22 +0000
754+++ qml/Dash/CardHorizontalList.qml 2015-01-13 15:16:16 +0000
755@@ -42,6 +42,7 @@
756 sourceComponent: cardTool.cardComponent
757 anchors { top: parent.top; bottom: parent.bottom }
758 width: cardTool.cardWidth
759+ asynchronous: true
760 onLoaded: {
761 item.objectName = "delegate" + index;
762 item.fixedArtShapeSize = Qt.binding(function() { return cardTool.artShapeSize; });
763
764=== modified file 'qml/Dash/CardVerticalJournal.qml'
765--- qml/Dash/CardVerticalJournal.qml 2014-10-15 15:03:51 +0000
766+++ qml/Dash/CardVerticalJournal.qml 2015-01-13 15:16:16 +0000
767@@ -59,6 +59,7 @@
768 rowSpacing: minimumColumnSpacing
769 columnWidth: cardTool.cardWidth
770
771+ cacheBuffer: root.cacheBuffer
772 displayMarginBeginning: root.displayMarginBeginning
773 displayMarginEnd: root.displayMarginEnd
774
775@@ -66,7 +67,6 @@
776 id: loader
777 sourceComponent: cardTool.cardComponent
778 width: cardTool.cardWidth
779- visible: y + height >= root.visibleRangeBegin && y <= root.visibleRangeEnd
780 onLoaded: {
781 item.objectName = "delegate" + index;
782 item.fixedArtShapeSize = Qt.binding(function() { return cardTool.artShapeSize; });
783
784=== modified file 'qml/Dash/DashContent.qml'
785--- qml/Dash/DashContent.qml 2014-12-12 11:25:10 +0000
786+++ qml/Dash/DashContent.qml 2015-01-13 15:16:16 +0000
787@@ -163,6 +163,7 @@
788
789 delegate:
790 Loader {
791+ id: loader
792 width: ListView.view.width
793 height: ListView.view.height
794 opacity: { // hide delegate if offscreen
795@@ -191,6 +192,7 @@
796 dashContent.scopeLoaded(item.scope.id)
797 item.paginationCount = Qt.binding(function() { return dashContentList.count } )
798 item.paginationIndex = Qt.binding(function() { return dashContentList.currentIndex } )
799+ item.visibleToParent = Qt.binding(function() { return loader.opacity != 0 });
800 item.holdingList = dashContentList;
801 item.forceNonInteractive = Qt.binding(function() { return dashContent.forceNonInteractive } )
802 }
803
804=== modified file 'qml/Dash/DashRenderer.qml'
805--- qml/Dash/DashRenderer.qml 2014-10-02 09:53:26 +0000
806+++ qml/Dash/DashRenderer.qml 2015-01-13 15:16:16 +0000
807@@ -23,14 +23,12 @@
808
809 property int collapsedItemCount: -1
810
811+ property int cacheBuffer: 0
812+
813 property int displayMarginBeginning: 0
814
815 property int displayMarginEnd: 0
816
817- property int visibleRangeBegin: 0
818-
819- property int visibleRangeEnd: 0
820-
821 property real originY: 0
822
823 // The model to renderer
824
825=== modified file 'qml/Dash/GenericScopeView.qml'
826--- qml/Dash/GenericScopeView.qml 2014-12-15 23:02:35 +0000
827+++ qml/Dash/GenericScopeView.qml 2015-01-13 15:16:16 +0000
828@@ -38,8 +38,10 @@
829 readonly property alias subPageShown: subPageLoader.subPageShown
830 property int paginationCount: 0
831 property int paginationIndex: 0
832+ property bool visibleToParent: false
833 property alias pageHeaderTotallyVisible: categoryView.pageHeaderTotallyVisible
834 property var holdingList: null
835+ property bool wasCurrentOnMoveStart: false
836
837 property var scopeStyle: ScopeStyle {
838 style: scope ? scope.customizations : {}
839@@ -115,6 +117,9 @@
840 }
841
842 onIsCurrentChanged: {
843+ if (!holdingList || !holdingList.moving) {
844+ wasCurrentOnMoveStart = scopeView.isCurrent;
845+ }
846 if (pageHeaderLoader.item && showPageHeader) {
847 pageHeaderLoader.item.resetSearch();
848 }
849@@ -141,6 +146,15 @@
850 onHideDash: subPageLoader.closeSubPage()
851 }
852
853+ Connections {
854+ target: holdingList
855+ onMovingChanged: {
856+ if (!moving) {
857+ wasCurrentOnMoveStart = scopeView.isCurrent;
858+ }
859+ }
860+ }
861+
862 Rectangle {
863 anchors.fill: parent
864 color: scopeView.scopeStyle ? scopeView.scopeStyle.background : "transparent"
865@@ -357,6 +371,7 @@
866 Connections {
867 target: scopeView
868 onIsCurrentChanged: rendererLoader.updateRanges();
869+ onVisibleToParentChanged: rendererLoader.updateRanges();
870 }
871 Connections {
872 target: holdingList
873@@ -364,7 +379,13 @@
874 }
875
876 function updateRanges() {
877- if (holdingList && holdingList.moving) {
878+ // Don't want to create stress by requesting more items during scope
879+ // changes so unless you're not part of the visible scopes just return.
880+ // For the visible scopes we need to do some work, the previously non visible
881+ // scope needs to adjust its ranges so that we define the new visible range,
882+ // that still means no creation/destruction of delegates, it's just about changing
883+ // the culling of the items so they are actually visible
884+ if (holdingList && holdingList.moving && !scopeView.visibleToParent) {
885 return;
886 }
887
888@@ -379,31 +400,61 @@
889 }
890 }
891
892- if (item && item.hasOwnProperty("visibleRangeBegin")) {
893- item.visibleRangeBegin = Math.max(-baseItem.y, 0)
894- item.visibleRangeEnd = item.visibleRangeBegin + Math.min(categoryView.height, rendererLoader.height)
895- }
896-
897 if (item && item.hasOwnProperty("displayMarginBeginning")) {
898- // TODO do we need item.originY here, test 1300302 once we have a silo
899- // and we can run it on the phone
900- if (scopeView.isCurrent) {
901- // 1073741823 is s^30 -1. A quite big number so that you have "infinite" display margin, but not so
902- // big so that if you add if with itself you're outside the 2^31 int range
903- item.displayMarginBeginning = 1073741823;
904- item.displayMarginEnd = 1073741823;
905- } else if (baseItem.y + baseItem.height <= 0) {
906- // Not visible (item at top of the list viewport)
907- item.displayMarginBeginning = -baseItem.height;
908- item.displayMarginEnd = 0;
909- } else if (baseItem.y >= categoryView.height) {
910- // Not visible (item at bottom of the list viewport)
911- item.displayMarginBeginning = 0;
912- item.displayMarginEnd = -baseItem.height;
913+ // A item view creates its delegates synchronously from
914+ // -displayMarginBeginning
915+ // to
916+ // height + displayMarginEnd
917+ // Around that area it adds the cacheBuffer area where delegates are created async
918+ //
919+ // We adjust displayMarginBeginning and displayMarginEnd so
920+ // * In non visible scopes nothing is considered visible and we set cacheBuffer
921+ // so that creates the items that would be in the viewport asynchronously
922+ // * For the current scope set the visible range to the viewport and then
923+ // use cacheBuffer to create extra items for categoryView.height * 1.5
924+ // to make scrolling nicer by mantaining a higher number of
925+ // cached items
926+ // * For non current but visible scopes (i.e. when the user changes from one scope
927+ // to the next, we set the visible range to the viewport so
928+ // items are not culled (invisible) but still use no cacheBuffer
929+ // (it will be set once the scope is the current one)
930+ var displayMarginBeginning = baseItem.y;
931+ displayMarginBeginning = -Math.max(-displayMarginBeginning, 0);
932+ displayMarginBeginning = -Math.min(-displayMarginBeginning, baseItem.height);
933+ displayMarginBeginning = Math.round(displayMarginBeginning);
934+ var displayMarginEnd = -baseItem.height + seeAll.height + categoryView.height - baseItem.y;
935+ displayMarginEnd = -Math.max(-displayMarginEnd, 0);
936+ displayMarginEnd = -Math.min(-displayMarginEnd, baseItem.height);
937+ displayMarginEnd = Math.round(displayMarginEnd);
938+ if (scopeView.isCurrent || scopeView.visibleToParent) {
939+ item.displayMarginBeginning = displayMarginBeginning;
940+ item.displayMarginEnd = displayMarginEnd;
941+ if (holdingList && holdingList.moving) {
942+ // If we are moving we need to reset the cache buffer of the
943+ // view that was not visible (i.e. !wasCurrentOnMoveStart) to 0 since
944+ // otherwise the cache buffer we had set to preload the items of the
945+ // visible range will trigger some item creations and we want move to
946+ // be as smooth as possible meaning no need creations
947+ if (!wasCurrentOnMoveStart) {
948+ item.cacheBuffer = 0;
949+ }
950+ } else {
951+ item.cacheBuffer = categoryView.height * 1.5;
952+ }
953 } else {
954- item.displayMarginBeginning = Math.round(-Math.max(-baseItem.y, 0));
955- item.displayMarginEnd = -Math.round(Math.max(baseItem.height - seeAll.height -
956- categoryView.height + baseItem.y, 0));
957+ var visibleRange = baseItem.height + displayMarginEnd + displayMarginBeginning;
958+ if (visibleRange < 0) {
959+ item.displayMarginBeginning = displayMarginBeginning;
960+ item.displayMarginEnd = displayMarginEnd;
961+ item.cacheBuffer = 0;
962+ } else {
963+ // This should be visibleRange/2 in each of the properties
964+ // but some item views still (like GridView) like creating sync delegates even if
965+ // the visible range is 0 so let's make sure the visible range is negative
966+ item.displayMarginBeginning = displayMarginBeginning - visibleRange;
967+ item.displayMarginEnd = displayMarginEnd - visibleRange;
968+ item.cacheBuffer = visibleRange;
969+ }
970 }
971 }
972 }
973
974=== modified file 'qml/Dash/Previews/PreviewZoomableImage.qml'
975--- qml/Dash/Previews/PreviewZoomableImage.qml 2014-10-22 17:35:15 +0000
976+++ qml/Dash/Previews/PreviewZoomableImage.qml 2015-01-13 15:16:16 +0000
977@@ -40,6 +40,7 @@
978 }
979 scaleTo: "height"
980 source: widgetData["source"]
981+ asynchronous: true
982
983 borderSource: mouseArea.pressed ? "radius_pressed.sci" : "radius_idle.sci"
984
985
986=== modified file 'qml/Dash/ScopeListView.qml'
987--- qml/Dash/ScopeListView.qml 2014-10-23 11:59:22 +0000
988+++ qml/Dash/ScopeListView.qml 2015-01-13 15:16:16 +0000
989@@ -1,5 +1,5 @@
990 /*
991- * Copyright (C) 2013 Canonical, Ltd.
992+ * Copyright (C) 2014 Canonical, Ltd.
993 *
994 * This program is free software; you can redistribute it and/or modify
995 * it under the terms of the GNU General Public License as published by
996@@ -20,5 +20,7 @@
997 ListViewWithPageHeader {
998 maximumFlickVelocity: height * 10
999 flickDeceleration: height * 2
1000- cacheBuffer: Number.MAX_VALUE
1001+ // 1073741823 is s^30 -1. A quite big number so that you have "infinite" cache, but not so
1002+ // big so that if you add if with itself you're outside the 2^31 int range
1003+ cacheBuffer: 1073741823
1004 }
1005
1006=== modified file 'qml/Greeter/Infographics.qml'
1007--- qml/Greeter/Infographics.qml 2014-11-05 00:19:41 +0000
1008+++ qml/Greeter/Infographics.qml 2015-01-13 15:16:16 +0000
1009@@ -127,7 +127,7 @@
1010
1011 index: model.index
1012 count: pastCircles.count
1013- radius: parent.width / 2
1014+ radius: dataCircle.width / 2
1015 halfSize: pastCircle.width / 2
1016 posOffset: 0.0
1017
1018@@ -187,7 +187,7 @@
1019
1020 index: model.index
1021 count: presentCircles.count
1022- radius: parent.width / 2
1023+ radius: dataCircle.width / 2
1024 halfSize: presentCircle.width / 2
1025 posOffset: 0.0
1026
1027@@ -255,14 +255,16 @@
1028 interval: animDuration * 0.5; running: false; repeat: true
1029 onTriggered: {
1030 if (dotCounter < dots.count) {
1031- var nextDot = dots.itemAt(dotCounter++)
1032- nextDot.unlockAnimation.start()
1033+ var nextDot = dots.itemAt(dotCounter);
1034+ if (nextDot) {
1035+ nextDot.unlockAnimation.start();
1036+ if (++dotCounter == Math.round(dots.count / 2)) {
1037+ circleChangeAnimTimer.startFromBeginning();
1038+ }
1039+ }
1040 } else {
1041 stop()
1042 }
1043- if (dotCounter == Math.round(dots.count / 2)) {
1044- circleChangeAnimTimer.startFromBeginning()
1045- }
1046 }
1047
1048 function startFromBeginning() {
1049
1050=== modified file 'qml/Shell.qml'
1051--- qml/Shell.qml 2014-12-05 16:27:27 +0000
1052+++ qml/Shell.qml 2015-01-13 15:16:16 +0000
1053@@ -353,7 +353,7 @@
1054
1055 function maybeShow() {
1056 if (!shell.forcedUnlock) {
1057- show()
1058+ showNow();
1059 }
1060 }
1061
1062@@ -557,6 +557,15 @@
1063 enabled = true;
1064 }
1065
1066+ Timer {
1067+ // See powerConnection for why this is useful
1068+ id: showGreeterDelayed
1069+ interval: 1
1070+ onTriggered: {
1071+ greeter.showNow();
1072+ }
1073+ }
1074+
1075 onShownChanged: {
1076 if (shown) {
1077 // Disable everything so that user can't swipe greeter or
1078@@ -622,7 +631,16 @@
1079 onStatusChanged: {
1080 if (Powerd.status === Powerd.Off && reason !== Powerd.Proximity &&
1081 !callManager.hasCalls && !edgeDemo.running) {
1082- greeter.showNow()
1083+ // We don't want to simply call greeter.showNow() here, because
1084+ // that will take too long. Qt will delay button event
1085+ // handling until the greeter is done loading and may think the
1086+ // user held down the power button the whole time, leading to a
1087+ // power dialog being shown. Instead, delay showing the
1088+ // greeter until we've finished handling the event. We could
1089+ // make the greeter load asynchronously instead, but that
1090+ // introduces a whole host of timing issues, especially with
1091+ // its animations. So this is simpler.
1092+ showGreeterDelayed.start();
1093 }
1094 }
1095 }
1096
1097=== renamed file 'qml/graphics/applicationIcons/dash@18.png' => 'qml/graphics/applicationIcons/dash.png'
1098=== modified file 'tests/autopilot/unity8/shell/emulators/dash.py'
1099--- tests/autopilot/unity8/shell/emulators/dash.py 2014-10-30 14:38:28 +0000
1100+++ tests/autopilot/unity8/shell/emulators/dash.py 2015-01-13 15:16:16 +0000
1101@@ -204,7 +204,7 @@
1102
1103 """
1104 category_element = self._get_category_element(category)
1105- icon = category_element.select_single('AbstractButton', title=title)
1106+ icon = category_element.wait_select_single('AbstractButton', title=title)
1107 self.pointing_device.click_object(icon)
1108
1109 def _get_category_element(self, category):
1110
1111=== modified file 'tests/plugins/Dash/CMakeLists.txt'
1112--- tests/plugins/Dash/CMakeLists.txt 2014-09-01 09:13:08 +0000
1113+++ tests/plugins/Dash/CMakeLists.txt 2015-01-13 15:16:16 +0000
1114@@ -80,3 +80,4 @@
1115 add_qml_test(. ScopeStyle IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins)
1116 add_qml_test(. ListViewWithPageHeaderQML IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins)
1117 add_qml_test(. CardAttributes IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins)
1118+add_qml_test(. CroppedImageMinimumSourceSize IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins)
1119
1120=== modified file 'tests/plugins/Dash/cardcreator/1.res'
1121--- tests/plugins/Dash/cardcreator/1.res 2014-10-20 20:51:10 +0000
1122+++ tests/plugins/Dash/cardcreator/1.res 2015-01-13 15:16:16 +0000
1123@@ -46,16 +46,16 @@
1124 height = Qt.binding(function() { return image.status !== Image.Ready ? 0 : image.height });
1125 }
1126 }
1127- image: CroppedImageMinimumSourceSize {
1128+ CroppedImageMinimumSourceSize {
1129+ id: artImage;
1130 objectName: "artImage";
1131- property bool doLoadSource: !NetworkingStatus.limitedBandwith;
1132- source: { if (root.visible) doLoadSource = true; return doLoadSource && cardData && cardData["art"] || ""; }
1133- cache: true;
1134+ source: cardData && cardData["art"] || "";
1135 asynchronous: root.asynchronous;
1136 visible: false;
1137 width: root.width;
1138 height: width / artShape.aspect;
1139 }
1140+ image: artImage.image;
1141 }
1142 }
1143 }
1144
1145=== modified file 'tests/plugins/Dash/cardcreator/2.res'
1146--- tests/plugins/Dash/cardcreator/2.res 2014-10-20 20:51:10 +0000
1147+++ tests/plugins/Dash/cardcreator/2.res 2015-01-13 15:16:16 +0000
1148@@ -68,13 +68,12 @@
1149 id: mascotImage;
1150 objectName: "mascotImage";
1151 anchors { verticalCenter: parent.verticalCenter; }
1152- property bool doLoadSource: !NetworkingStatus.limitedBandwith;
1153- source: { if (root.visible) doLoadSource = true; return doLoadSource && cardData && cardData["mascot"] || ""; }
1154+ source: cardData && cardData["mascot"] || "";
1155 width: units.gu(6);
1156 height: units.gu(5.625);
1157 horizontalAlignment: Image.AlignHCenter;
1158 verticalAlignment: Image.AlignVCenter;
1159- visible: showHeader && resized;
1160+ visible: showHeader;
1161 }
1162 ,Item {
1163 id: headerTitleContainer;
1164
1165=== modified file 'tests/plugins/Dash/cardcreator/3.res'
1166--- tests/plugins/Dash/cardcreator/3.res 2014-10-20 20:51:10 +0000
1167+++ tests/plugins/Dash/cardcreator/3.res 2015-01-13 15:16:16 +0000
1168@@ -46,16 +46,16 @@
1169 height = Qt.binding(function() { return image.status !== Image.Ready ? 0 : image.height });
1170 }
1171 }
1172- image: CroppedImageMinimumSourceSize {
1173- objectName: "artImage";
1174- property bool doLoadSource: !NetworkingStatus.limitedBandwith;
1175- source: { if (root.visible) doLoadSource = true; return doLoadSource && cardData && cardData["art"] || ""; }
1176- cache: true;
1177- asynchronous: root.asynchronous;
1178- visible: false;
1179- width: root.width;
1180- height: width / artShape.aspect;
1181- }
1182+ CroppedImageMinimumSourceSize {
1183+ id: artImage;
1184+ objectName: "artImage";
1185+ source: cardData && cardData["art"] || "";
1186+ asynchronous: root.asynchronous;
1187+ visible: false;
1188+ width: root.width;
1189+ height: width / artShape.aspect;
1190+ }
1191+ image: artImage.image;
1192 }
1193 }
1194 }
1195
1196=== modified file 'tests/plugins/Dash/cardcreator/4.res'
1197--- tests/plugins/Dash/cardcreator/4.res 2014-10-20 20:51:10 +0000
1198+++ tests/plugins/Dash/cardcreator/4.res 2015-01-13 15:16:16 +0000
1199@@ -35,11 +35,11 @@
1200 id: mascotShapeLoader;
1201 objectName: "mascotShapeLoader";
1202 asynchronous: root.asynchronous;
1203- active: mascotImage.status === Image.Ready;
1204+ active: mascotImage.image.status === Image.Ready;
1205 visible: showHeader && active && status == Loader.Ready;
1206 width: units.gu(6);
1207 height: units.gu(5.625);
1208- sourceComponent: UbuntuShape { image: mascotImage }
1209+ sourceComponent: UbuntuShape { image: mascotImage.image }
1210 anchors { verticalCenter: parent.verticalCenter; }
1211 }
1212
1213@@ -47,8 +47,7 @@
1214 id: mascotImage;
1215 objectName: "mascotImage";
1216 anchors { verticalCenter: parent.verticalCenter; }
1217- property bool doLoadSource: !NetworkingStatus.limitedBandwith;
1218- source: { if (root.visible) doLoadSource = true; return doLoadSource && cardData && cardData["mascot"] || ""; }
1219+ source: cardData && cardData["mascot"] || "";
1220 width: units.gu(6);
1221 height: units.gu(5.625);
1222 horizontalAlignment: Image.AlignHCenter;
1223
1224=== modified file 'tests/plugins/Dash/cardcreator/5.res'
1225--- tests/plugins/Dash/cardcreator/5.res 2014-10-20 20:51:10 +0000
1226+++ tests/plugins/Dash/cardcreator/5.res 2015-01-13 15:16:16 +0000
1227@@ -46,16 +46,16 @@
1228 height = Qt.binding(function() { return image.status !== Image.Ready ? 0 : image.height });
1229 }
1230 }
1231- image: CroppedImageMinimumSourceSize {
1232- objectName: "artImage";
1233- property bool doLoadSource: !NetworkingStatus.limitedBandwith;
1234- source: { if (root.visible) doLoadSource = true; return doLoadSource && cardData && cardData["art"] || ""; }
1235- cache: true;
1236- asynchronous: root.asynchronous;
1237- visible: false;
1238- width: root.width;
1239- height: width / artShape.aspect;
1240- }
1241+ CroppedImageMinimumSourceSize {
1242+ id: artImage;
1243+ objectName: "artImage";
1244+ source: cardData && cardData["art"] || "";
1245+ asynchronous: root.asynchronous;
1246+ visible: false;
1247+ width: root.width;
1248+ height: width / artShape.aspect;
1249+ }
1250+ image: artImage.image;
1251 }
1252 }
1253 }
1254
1255=== modified file 'tests/plugins/Dash/cardcreator/7.res'
1256--- tests/plugins/Dash/cardcreator/7.res 2014-10-20 20:51:10 +0000
1257+++ tests/plugins/Dash/cardcreator/7.res 2015-01-13 15:16:16 +0000
1258@@ -68,13 +68,12 @@
1259 id: mascotImage;
1260 objectName: "mascotImage";
1261 anchors { verticalCenter: parent.verticalCenter; }
1262- property bool doLoadSource: !NetworkingStatus.limitedBandwith;
1263- source: { if (root.visible) doLoadSource = true; return doLoadSource && cardData && cardData["mascot"] || ""; }
1264+ source: cardData && cardData["mascot"] || "";
1265 width: units.gu(6);
1266 height: units.gu(5.625);
1267 horizontalAlignment: Image.AlignHCenter;
1268 verticalAlignment: Image.AlignVCenter;
1269- visible: showHeader && resized;
1270+ visible: showHeader;
1271 }
1272
1273 ,Item {
1274
1275=== modified file 'tests/plugins/Dash/horizontaljournaltest.qml'
1276--- tests/plugins/Dash/horizontaljournaltest.qml 2014-04-30 10:06:33 +0000
1277+++ tests/plugins/Dash/horizontaljournaltest.qml 2015-01-13 15:16:16 +0000
1278@@ -25,6 +25,7 @@
1279 rowHeight: 150
1280 columnSpacing: 10
1281 rowSpacing: 10
1282+ cacheBuffer: Math.max(0, (height + displayMarginEnd + displayMarginBeginning) / 2)
1283
1284 delegate: Rectangle {
1285 property real randomValue: Math.random()
1286
1287=== modified file 'tests/plugins/Dash/listviewwithpageheadertest.cpp'
1288--- tests/plugins/Dash/listviewwithpageheadertest.cpp 2014-08-26 08:41:02 +0000
1289+++ tests/plugins/Dash/listviewwithpageheadertest.cpp 2015-01-13 15:16:16 +0000
1290@@ -1920,7 +1920,7 @@
1291
1292 void testAllCacheBuffer()
1293 {
1294- lvwph->setCacheBuffer(std::numeric_limits<qreal>::max());
1295+ lvwph->setCacheBuffer(std::numeric_limits<int>::max());
1296 QTRY_COMPARE(lvwph->m_visibleItems.count(), 6);
1297 QCOMPARE(lvwph->m_firstVisibleIndex, 0);
1298 verifyItem(0, 50., 150., false);
1299
1300=== modified file 'tests/plugins/Dash/organicgridtest.qml'
1301--- tests/plugins/Dash/organicgridtest.qml 2014-04-30 10:06:33 +0000
1302+++ tests/plugins/Dash/organicgridtest.qml 2015-01-13 15:16:16 +0000
1303@@ -27,6 +27,7 @@
1304 rowSpacing: 10
1305 smallDelegateSize: Qt.size(90, 90)
1306 bigDelegateSize: Qt.size(180, 180)
1307+ cacheBuffer: Math.max(0, (height + displayMarginEnd + displayMarginBeginning) / 2)
1308
1309 delegate: Rectangle {
1310 property real randomValue: Math.random()
1311
1312=== added file 'tests/plugins/Dash/tst_CroppedImageMinimumSourceSize.qml'
1313--- tests/plugins/Dash/tst_CroppedImageMinimumSourceSize.qml 1970-01-01 00:00:00 +0000
1314+++ tests/plugins/Dash/tst_CroppedImageMinimumSourceSize.qml 2015-01-13 15:16:16 +0000
1315@@ -0,0 +1,56 @@
1316+/*
1317+ * Copyright (C) 2014 Canonical, Ltd.
1318+ *
1319+ * This program is free software; you can redistribute it and/or modify
1320+ * it under the terms of the GNU General Public License as published by
1321+ * the Free Software Foundation; version 3.
1322+ *
1323+ * This program is distributed in the hope that it will be useful,
1324+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1325+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1326+ * GNU General Public License for more details.
1327+ *
1328+ * You should have received a copy of the GNU General Public License
1329+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1330+ */
1331+
1332+import QtQuick 2.3
1333+import QtTest 1.0
1334+import Ubuntu.Components 1.1
1335+import Dash 0.1
1336+
1337+Rectangle {
1338+ width: 500
1339+ height: 300
1340+
1341+ color: "red"
1342+
1343+ CroppedImageMinimumSourceSize {
1344+ id: cimss
1345+ x: 100
1346+ y: 100
1347+ width: 100
1348+ height: 100
1349+ source: Qt.resolvedUrl("../../qmltests/Dash/artwork/music-player-design.png")
1350+ asynchronous: true
1351+ }
1352+
1353+ TestCase {
1354+ id: testCase
1355+ name: "ScopeStyle"
1356+ when: windowShown
1357+
1358+ function test_croppedSource() {
1359+ tryCompare(cimss.image.sourceSize, "width", 100);
1360+ tryCompare(cimss.image.sourceSize, "height", 0);
1361+
1362+ cimss.width = 40;
1363+ tryCompare(cimss.image.sourceSize, "width", 0);
1364+ tryCompare(cimss.image.sourceSize, "height", 100);
1365+
1366+ cimss.width = 100;
1367+ tryCompare(cimss.image.sourceSize, "width", 100);
1368+ tryCompare(cimss.image.sourceSize, "height", 0);
1369+ }
1370+ }
1371+}
1372
1373=== modified file 'tests/plugins/Dash/verticaljournaltest.qml'
1374--- tests/plugins/Dash/verticaljournaltest.qml 2014-04-30 10:06:33 +0000
1375+++ tests/plugins/Dash/verticaljournaltest.qml 2015-01-13 15:16:16 +0000
1376@@ -26,6 +26,7 @@
1377 columnWidth: 150
1378 columnSpacing: 10
1379 rowSpacing: 10
1380+ cacheBuffer: Math.max(0, (height + displayMarginEnd + displayMarginBeginning) / 2)
1381
1382 delegate: Rectangle {
1383 property real randomValue: Math.random()
1384
1385=== modified file 'tests/qmltests/Dash/tst_Card.qml'
1386--- tests/qmltests/Dash/tst_Card.qml 2014-10-14 15:44:00 +0000
1387+++ tests/qmltests/Dash/tst_Card.qml 2015-01-13 15:16:16 +0000
1388@@ -17,7 +17,6 @@
1389 import QtQuick 2.0
1390 import QtTest 1.0
1391 import Ubuntu.Components 0.1
1392-import Ubuntu.Connectivity 1.0
1393 import Unity.Test 0.1 as UT
1394 import "../../../qml/Dash"
1395 import "CardHelpers.js" as Helpers
1396@@ -221,7 +220,6 @@
1397
1398 function init() {
1399 loader.visible = true;
1400- NetworkingStatus.limitedBandwith = false;
1401 }
1402
1403 function cleanup() {
1404@@ -585,25 +583,5 @@
1405 verify((card.width - titleToCard.x - titleToCard.width) === units.gu(1));
1406 }
1407 }
1408-
1409- function test_load_images_visibility_network_data() {
1410- return [
1411- { tag: "Visible, network", visible: true, limitedBandwith: false },
1412- { tag: "Visible, no network", visible: true, limitedBandwith: true },
1413- { tag: "Not Visible, network", visible: false, limitedBandwith: false },
1414- { tag: "Not Visible, no network", visible: false, limitedBandwith: true }
1415- ];
1416- }
1417-
1418- function test_load_images_visibility_network(data) {
1419- loader.visible = data.visible;
1420- NetworkingStatus.limitedBandwith = data.limitedBandwith;
1421-
1422- selector.selectedIndex = 0;
1423- waitForRendering(selector);
1424- waitForRendering(card);
1425-
1426- verify(data.visible || !data.limitedBandwith || artImage.source == "");
1427- }
1428 }
1429 }
1430
1431=== modified file 'tests/qmltests/Dash/tst_DashContent.qml'
1432--- tests/qmltests/Dash/tst_DashContent.qml 2014-12-16 18:29:37 +0000
1433+++ tests/qmltests/Dash/tst_DashContent.qml 2015-01-13 15:16:16 +0000
1434@@ -516,5 +516,62 @@
1435
1436 compare(categoryListView.pageHeader.item.searchHint, "Search People");
1437 }
1438+
1439+ function compareArrays(a, b) {
1440+ if (a.length != b.length) return false;
1441+ for (var i in a) {
1442+ if (a[i] != b[i]) return false;
1443+ }
1444+ return true;
1445+ }
1446+
1447+ function getSettledButtons() {
1448+ var buttons = findChildsByType(dashContent, "AbstractButton");
1449+ wait(2500);
1450+ var aux = findChildsByType(dashContent, "AbstractButton");
1451+ while (!compareArrays(aux, buttons)) {
1452+ buttons = aux;
1453+ wait(2500);
1454+ aux = findChildsByType(dashContent, "AbstractButton");
1455+ }
1456+ return buttons;
1457+ }
1458+
1459+ function test_noDelegateCreationDestructionOnMove() {
1460+ // Our cards are of type AbstractButton as defined in CardCreator.js
1461+ // This gives also other things that are not cards but for our purpose it
1462+ // does not matter
1463+
1464+ // Wait for the buttons to settle
1465+ var buttons = getSettledButtons();
1466+
1467+ // Move the scopes so that the item on the right is the current one
1468+ // without releasing the button
1469+ mouseFlick(dashContent, dashContent.width - units.gu(1), units.gu(1), units.gu(1), units.gu(1), true, false);
1470+
1471+ // Make sure we have changed to a new scope
1472+ compare(dashContent.currentIndex, 1);
1473+
1474+ // Wait for the buttons to settle
1475+ var buttons2 = getSettledButtons();
1476+
1477+ // Verify we have exactly the same buttons as before starting to move
1478+ verify(compareArrays(buttons2, buttons));
1479+
1480+ // Release the mouse
1481+ mouseRelease(dashContent, units.gu(1), units.gu(1));
1482+
1483+ // Wait for the scopes list to stop moving
1484+ var dashContentList = findChild(dashContent, "dashContentList");
1485+ tryCompare(dashContentList, "moving", false);
1486+ compare(dashContent.currentIndex, 1);
1487+
1488+ // Wait for the buttons to settle
1489+ var buttons3 = getSettledButtons();
1490+
1491+ // Verify we have a different set of buttons now
1492+ expectFail("", "There has to be new cards after releasing the list is not moving anymore");
1493+ verify(compareArrays(buttons3, buttons));
1494+ }
1495 }
1496 }
1497
1498=== modified file 'tests/qmltests/Dash/tst_GenericScopeView.qml'
1499--- tests/qmltests/Dash/tst_GenericScopeView.qml 2014-12-15 23:02:35 +0000
1500+++ tests/qmltests/Dash/tst_GenericScopeView.qml 2015-01-13 15:16:16 +0000
1501@@ -59,6 +59,7 @@
1502 GenericScopeView {
1503 id: genericScopeView
1504 anchors.fill: parent
1505+ visibleToParent: true
1506
1507 UT.UnityTestCase {
1508 id: testCase
1509@@ -293,6 +294,7 @@
1510 },
1511 true);
1512 var tile = findChild(findChild(genericScopeView, "dashCategory"+category), "delegate"+delegate);
1513+ waitForRendering(tile);
1514 mouseClick(tile, tile.width / 2, tile.height / 2);
1515 tryCompare(testCase.subPageLoader, "open", true);
1516 tryCompare(testCase.subPageLoader, "x", 0);
1517
1518=== modified file 'tests/utils/modules/Unity/Test/UnityTestCase.qml'
1519--- tests/utils/modules/Unity/Test/UnityTestCase.qml 2014-10-14 08:43:38 +0000
1520+++ tests/utils/modules/Unity/Test/UnityTestCase.qml 2015-01-13 15:16:16 +0000
1521@@ -109,6 +109,18 @@
1522 return null;
1523 }
1524
1525+ function findChildsByType(obj, typeName) {
1526+ var res = new Array(0);
1527+ for (var i in obj.children) {
1528+ var c = obj.children[i];
1529+ if (UT.Util.isInstanceOf(c, typeName)) {
1530+ res.push(c)
1531+ }
1532+ res = res.concat(findChildsByType(c, typeName));
1533+ }
1534+ return res;
1535+ }
1536+
1537 // Type a full string instead of keyClick letter by letter
1538 // TODO: this is not ugly, this is uber-ugly and does not support
1539 // any special character. Remove the keyMap once keyClick(obj, char)

Subscribers

People subscribed via source and target branches

to all changes: