Merge lp:~unity-team/unity8/rtm-20150108 into lp:unity8/rtm-14.09
- rtm-20150108
- Merge into 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 | ||||||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Michał Sawicz | Approve | ||
Review via email:
|
Commit message
Description of the change
To post a comment you must log in.
- 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
- 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) |
As per the upstream changes.