on xenial help sign in
Merge lp:~unity-team/unity8/scopes_more_things_on_memory
commit2d8b2562aa603e35b6c85df8f4b22d23dddd8098 authorMichał Sawicz <michal.sawicz@canonical.com> dateThu 11 Sep 2014, 20:20 (12 years ago) parent430799488b240c
44 files changed+727−209
build.sh+1 cmake/modules/QmlTest.cmake+2−1 debian/control+1 plugins/Dash/CardCreator.js+5−2 plugins/Dash/listviewwithpageheader.cpp+28−7 plugins/Dash/listviewwithpageheader.h+8 qml/Dash/CardGrid.qml+1 qml/Dash/CardTool.qml+8−5 qml/Dash/CardVerticalJournal.qml+1 qml/Dash/DashContent.qml+1 qml/Dash/DashRenderer.qml+4 qml/Dash/GenericScopeView.qml+109−20 qml/Dash/ScopeListView.qml+1 qml/Dash/ScopesOverviewAll.qml+2 tests/autopilot/unity8/shell/emulators/dash.py+2−2 tests/mocks/Ubuntu/CMakeLists.txt+1 tests/mocks/Ubuntu/Connectivity/CMakeLists.txt+10 tests/mocks/Ubuntu/Connectivity/networking-status.cpp+65 tests/mocks/Ubuntu/Connectivity/networking-status.h+73 tests/mocks/Ubuntu/Connectivity/plugin.cpp+46 tests/mocks/Ubuntu/Connectivity/plugin.h+35 tests/mocks/Ubuntu/Connectivity/qmldir+2 tests/mocks/Unity/fake_categories.cpp+95−136 tests/mocks/Unity/fake_categories.h+7−12 tests/mocks/Unity/fake_resultsmodel.cpp+9 tests/mocks/Unity/fake_resultsmodel.h+3 tests/mocks/Unity/fake_scope.cpp+17 tests/mocks/Unity/fake_scope.h+2 tests/plugins/Dash/CMakeLists.txt+3−3 tests/plugins/Dash/cardcreator/1.res+2−1 tests/plugins/Dash/cardcreator/2.res+2−1 tests/plugins/Dash/cardcreator/3.res+3−2 tests/plugins/Dash/cardcreator/4.res+3−2 tests/plugins/Dash/cardcreator/5.res+3−2 tests/plugins/Dash/cardcreator/7.res+3−2 tests/plugins/Dash/listviewwithpageheadertest.cpp+39 tests/plugins/Dash/listviewwithpageheadertest.qml+1 tests/plugins/Dash/listviewwithpageheadertestsection.qml+1 tests/plugins/Dash/listviewwithpageheadertestsectionexternalmodel.qml+1 tests/plugins/Ubuntu/Gestures/CMakeLists.txt+1−1 tests/qmltests/Components/CMakeLists.txt+1−1 tests/qmltests/Dash/tst_Card.qml+21 tests/qmltests/Dash/tst_Dash.qml+1−2 tests/qmltests/Dash/tst_GenericScopeView.qml+103−7
build.sh+1
@@ -51,6 +51,7 @@ install_dependencies() {
5151 qtdeclarative5-ubuntu-settings-components \
5252 qtdeclarative5-ubuntu-telephony0.1 \
5353 qtdeclarative5-ubuntu-thumbnailer0.1 \
54+ qml-module-ubuntu-connectivity \
5455 unity-notifications-impl \
5556 ubuntu-mobile-icons \
5657 unity-scope-home \
cmake/modules/QmlTest.cmake+2−1
@@ -131,7 +131,7 @@ macro(add_qml_test_internal SUBPATH COMPONENT_NAME ITERATIONS)
131131 add_manual_qml_test(${SUBPATH} ${COMPONENT_NAME} ${ARGN})
132132endmacro(add_qml_test_internal)
133133
134−macro(add_binary_qml_test CLASS_NAME LD_PATH DEPS)
134+macro(add_binary_qml_test CLASS_NAME LD_PATH DEPS ENVVAR)
135135 set(testCommand
136136 LD_LIBRARY_PATH=${LD_PATH}
137137 ${CMAKE_CURRENT_BINARY_DIR}/${CLASS_NAME}TestExec
@@ -148,6 +148,7 @@ macro(add_binary_qml_test CLASS_NAME LD_PATH DEPS)
148148 endif()
149149 set(xvfbtestCommand
150150 ${LD_PRELOAD_PATH}
151+ ${ENVVAR}
151152 LD_LIBRARY_PATH=${LD_PATH}
152153 xvfb-run --server-args "-screen 0 1024x768x24" --auto-servernum
153154 ${CMAKE_CURRENT_BINARY_DIR}/${CLASS_NAME}TestExec
debian/control+1
@@ -173,6 +173,7 @@ Depends: accountsservice-ubuntu-schemas (>= 0.0.3),
173173 libhardware2,
174174 libunity-core-6.0-9,
175175 pay-service,
176+ qml-module-ubuntu-connectivity,
176177 ${misc:Depends},
177178 ${shlibs:Depends},
178179Provides: unity-launcher-impl,
plugins/Dash/CardCreator.js+5−2
@@ -84,7 +84,8 @@ var kArtShapeHolderCode = 'Item { \n\
8484 } \n\
8585 image: Image { \n\
8686 objectName: "artImage"; \n\
87− source: cardData && cardData["art"] || ""; \n\
87+ property bool doLoadSource: !NetworkingStatus.limitedBandwith; \n\
88+ source: { if (root.visible) doLoadSource = true; return doLoadSource && cardData && cardData["art"] || ""; } \n\
8889 cache: true; \n\
8990 asynchronous: root.asynchronous; \n\
9091 fillMode: Image.PreserveAspectCrop; \n\
@@ -195,7 +196,8 @@ var kMascotImageCode = 'Image { \n\
195196 objectName: "mascotImage"; \n\
196197 anchors { %1 } \n\
197198 readonly property int maxSize: Math.max(width, height) * 4; \n\
198− source: cardData && cardData["mascot"] || ""; \n\
199+ property bool doLoadSource: !NetworkingStatus.limitedBandwith; \n\
200+ source: { if (root.visible) doLoadSource = true; return doLoadSource && cardData && cardData["mascot"] || ""; } \n\
199201 width: units.gu(6); \n\
200202 height: units.gu(5.625); \n\
201203 sourceSize { width: maxSize; height: maxSize } \n\
@@ -654,6 +656,7 @@ function createCardComponent(parent, template, components) {
654656 var imports = 'import QtQuick 2.2; \n\
655657 import Ubuntu.Components 1.1; \n\
656658 import Ubuntu.Settings.Components 0.1; \n\
659+ import Ubuntu.Connectivity 1.0; \n\
657660 import Dash 0.1;\n\
658661 import Utils 0.1;\n';
659662 var card = cardString(template, components);
plugins/Dash/listviewwithpageheader.cpp+28−7
@@ -104,8 +104,6 @@
104104#pragma GCC diagnostic pop
105105// #include <private/qquickrectangle_p.h>
106106
107−static const qreal bufferRatio = 0.5;
108−
109107qreal ListViewWithPageHeader::ListItem::height() const
110108{
111109 return m_item->height() + (m_sectionItem ? m_sectionItem->height() : 0);
@@ -158,6 +156,7 @@ ListViewWithPageHeader::ListViewWithPageHeader()
158156 , m_forceNoClip(false)
159157 , m_inLayout(false)
160158 , m_inContentHeightKeepHeaderShown(false)
159+ , m_cacheBuffer(0)
161160{
162161 m_clipItem = new QQuickItem(contentItem());
163162// m_clipItem = new QQuickRectangle(contentItem());
@@ -335,6 +334,20 @@ qreal ListViewWithPageHeader::headerItemShownHeight() const
335334 return m_headerItemShownHeight;
336335}
337336
337+qreal ListViewWithPageHeader::cacheBuffer() const
338+{
339+ return m_cacheBuffer;
340+}
341+
342+void ListViewWithPageHeader::setCacheBuffer(qreal cacheBuffer)
343+{
344+ if (cacheBuffer != m_cacheBuffer) {
345+ m_cacheBuffer = cacheBuffer;
346+ Q_EMIT cacheBufferChanged();
347+ polish();
348+ }
349+}
350+
338351void ListViewWithPageHeader::positionAtBeginning()
339352{
340353 if (m_delegateModel->count() <= 0)
@@ -356,8 +369,7 @@ void ListViewWithPageHeader::positionAtBeginning()
356369 // Create the subsequent items
357370 int modelIndex = 1;
358371 qreal pos = item->y() + item->height();
359− const qreal buffer = height() * bufferRatio;
360− const qreal bufferTo = height() + buffer;
372+ const qreal bufferTo = height() + m_cacheBuffer;
361373 while (modelIndex < m_delegateModel->count() && pos <= bufferTo) {
362374 if (!(item = createItem(modelIndex, false)))
363375 break;
@@ -409,6 +421,16 @@ void ListViewWithPageHeader::showHeader()
409421 }
410422}
411423
424+Q_INVOKABLE int ListViewWithPageHeader::firstCreatedIndex() const
425+{
426+ return m_firstVisibleIndex;
427+}
428+
429+Q_INVOKABLE int ListViewWithPageHeader::createdItemCount() const
430+{
431+ return m_visibleItems.count();
432+}
433+
412434QQuickItem *ListViewWithPageHeader::item(int modelIndex) const
413435{
414436 ListItem *item = itemAtIndex(modelIndex);
@@ -593,11 +615,10 @@ void ListViewWithPageHeader::refill()
593615 return;
594616 }
595617
596− const qreal buffer = height() * bufferRatio;
597618 const qreal from = contentY();
598619 const qreal to = from + height();
599− const qreal bufferFrom = from - buffer;
600− const qreal bufferTo = to + buffer;
620+ const qreal bufferFrom = from - m_cacheBuffer;
621+ const qreal bufferTo = to + m_cacheBuffer;
601622
602623 bool added = addVisibleItems(from, to, false);
603624 bool removed = removeNonVisibleItems(bufferFrom, bufferTo);
plugins/Dash/listviewwithpageheader.h+8
@@ -54,6 +54,7 @@ class ListViewWithPageHeader : public QQuickFlickable, public QQuickItemChangeLi
5454 Q_PROPERTY(bool forceNoClip READ forceNoClip WRITE setForceNoClip NOTIFY forceNoClipChanged)
5555 Q_PROPERTY(int stickyHeaderHeight READ stickyHeaderHeight NOTIFY stickyHeaderHeightChanged)
5656 Q_PROPERTY(qreal headerItemShownHeight READ headerItemShownHeight NOTIFY headerItemShownHeightChanged)
57+ Q_PROPERTY(qreal cacheBuffer READ cacheBuffer WRITE setCacheBuffer NOTIFY cacheBufferChanged)
5758
5859 friend class ListViewWithPageHeaderTest;
5960 friend class ListViewWithPageHeaderTestSection;
@@ -84,8 +85,13 @@ public:
8485 int stickyHeaderHeight() const;
8586 qreal headerItemShownHeight() const;
8687
88+ qreal cacheBuffer() const;
89+ void setCacheBuffer(qreal cacheBuffer);
90+
8791 Q_INVOKABLE void positionAtBeginning();
8892 Q_INVOKABLE void showHeader();
93+ Q_INVOKABLE int firstCreatedIndex() const;
94+ Q_INVOKABLE int createdItemCount() const;
8995 Q_INVOKABLE QQuickItem *item(int modelIndex) const;
9096
9197 // The index has to be created for this to try to do something
@@ -103,6 +109,7 @@ Q_SIGNALS:
103109 void forceNoClipChanged();
104110 void stickyHeaderHeightChanged();
105111 void headerItemShownHeightChanged();
112+ void cacheBufferChanged();
106113
107114protected:
108115 void componentComplete() override;
@@ -197,6 +204,7 @@ private:
197204 bool m_forceNoClip;
198205 bool m_inLayout;
199206 bool m_inContentHeightKeepHeaderShown;
207+ qreal m_cacheBuffer;
200208
201209 // Qt 5.0 doesn't like releasing the items just after itemCreated
202210 // so we delay the releasing until the next updatePolish
qml/Dash/CardGrid.qml+1
@@ -55,6 +55,7 @@ DashRenderer {
5555 delegate: Item {
5656 width: grid.cellWidth
5757 height: grid.cellHeight
58+ visible: y + height >= root.visibleRangeBegin && y <= root.visibleRangeEnd
5859 Loader {
5960 id: loader
6061 sourceComponent: cardTool.cardComponent
qml/Dash/CardTool.qml+8−5
@@ -174,16 +174,19 @@ Item {
174174
175175 Item {
176176 id: attributesModel
177− property int numOfAttributes: {
177+ property int numOfAttributes: 0
178+ property var model: []
179+ property bool hasAttributes: {
178180 var attributes = components["attributes"];
179− if ((attributes != undefined) && attributes["field"]) {
181+ var hasAttributesFlag = (attributes != undefined) && attributes["field"];
182+
183+ if (hasAttributesFlag) {
180184 if (attributes["max-count"]) {
181− return attributes["max-count"];
185+ numOfAttributes = attributes["max-count"];
182186 }
183187 }
184− return 0;
188+ return hasAttributesFlag
185189 }
186− property var model: []
187190
188191 onNumOfAttributesChanged: {
189192 model = []
qml/Dash/CardVerticalJournal.qml+1
@@ -49,6 +49,7 @@ DashRenderer {
4949 id: loader
5050 sourceComponent: cardTool.cardComponent
5151 width: cardTool.cardWidth
52+ visible: y + height >= root.visibleRangeBegin && y <= root.visibleRangeEnd
5253 onLoaded: {
5354 item.objectName = "delegate" + index;
5455 item.fixedArtShapeSize = Qt.binding(function() { return cardTool.artShapeSize; });
qml/Dash/DashContent.qml+1
@@ -177,6 +177,7 @@ Item {
177177 dashContent.scopeLoaded(item.scope.id)
178178 item.paginationCount = Qt.binding(function() { return dashContentList.count } )
179179 item.paginationIndex = Qt.binding(function() { return dashContentList.currentIndex } )
180+ item.holdingList = dashContentList;
180181 }
181182 Connections {
182183 target: isCurrent ? scope : null
qml/Dash/DashRenderer.qml+4
@@ -27,6 +27,10 @@ Item {
2727
2828 property int displayMarginEnd: 0
2929
30+ property int visibleRangeBegin: 0
31+
32+ property int visibleRangeEnd: 0
33+
3034 property real originY: 0
3135
3236 // The model to renderer
qml/Dash/GenericScopeView.qml+109−20
@@ -38,6 +38,7 @@ FocusScope {
3838 property int paginationCount: 0
3939 property int paginationIndex: 0
4040 property alias pageHeaderTotallyVisible: categoryView.pageHeaderTotallyVisible
41+ property var holdingList: null
4142
4243 property var scopeStyle: ScopeStyle {
4344 style: scope ? scope.customizations : {}
@@ -47,6 +48,10 @@ FocusScope {
4748
4849 signal backClicked()
4950
51+ onScopeChanged: {
52+ floatingSeeLess.companionBase = null;
53+ }
54+
5055 function positionAtBeginning() {
5156 categoryView.positionAtBeginning()
5257 }
@@ -152,11 +157,55 @@ FocusScope {
152157 forceNoClip: subPageLoader.open
153158 pixelAligned: true
154159
155− property Item expandedCategoryItem: null
160+ property string expandedCategoryId: ""
161+ property int runMaximizeAfterSizeChanges: 0
156162
157163 readonly property bool pageHeaderTotallyVisible: scopeView.showPageHeader &&
158164 ((headerItemShownHeight == 0 && categoryView.contentY <= categoryView.originY) || (headerItemShownHeight == pageHeaderLoader.item.height))
159165
166+ onExpandedCategoryIdChanged: {
167+ var firstCreated = firstCreatedIndex();
168+ var shrinkingAny = false;
169+ var shrinkHeightDifference = 0;
170+ for (var i = 0; i < createdItemCount(); ++i) {
171+ var baseItem = item(firstCreated + i);
172+ if (baseItem.expandable) {
173+ var shouldExpand = baseItem.category === expandedCategoryId;
174+ if (shouldExpand != baseItem.expanded) {
175+
176+ var animate = false;
177+ if (!subPageLoader.open) {
178+ var animateShrinking = !shouldExpand && baseItem.y + baseItem.item.collapsedHeight + baseItem.seeAll.height < categoryView.height;
179+ var animateGrowing = shouldExpand && baseItem.y + baseItem.height < categoryView.height;
180+ animate = shrinkingAny || animateShrinking || animateGrowing;
181+ }
182+
183+ if (!shouldExpand) {
184+ shrinkingAny = true;
185+ shrinkHeightDifference = baseItem.item.expandedHeight - baseItem.item.collapsedHeight;
186+ }
187+
188+ if (shouldExpand && !subPageLoader.open) {
189+ if (!shrinkingAny) {
190+ categoryView.maximizeVisibleArea(firstCreated + i, baseItem.item.expandedHeight + baseItem.seeAll.height);
191+ } else {
192+ // If the space that shrkinking is smaller than the one we need to grow we'll call maximizeVisibleArea
193+ // after the shrink/grow animation ends
194+ var growHeightDifference = baseItem.item.expandedHeight - baseItem.item.collapsedHeight;
195+ if (growHeightDifference > shrinkHeightDifference) {
196+ runMaximizeAfterSizeChanges = 2;
197+ } else {
198+ runMaximizeAfterSizeChanges = 0;
199+ }
200+ }
201+ }
202+
203+ baseItem.expand(shouldExpand, animate);
204+ }
205+ }
206+ }
207+ }
208+
160209 delegate: ListItems.Base {
161210 id: baseItem
162211 objectName: "dashCategory" + category
@@ -175,6 +224,7 @@ FocusScope {
175224 readonly property string category: categoryId
176225 readonly property string headerLink: model.headerLink
177226 readonly property var item: rendererLoader.item
227+ readonly property var seeAll: seeAll
178228
179229 function expand(expand, animate) {
180230 heightBehaviour.enabled = animate;
@@ -194,13 +244,13 @@ FocusScope {
194244 // This can happen with the VJ that doesn't know how height it will be on creation
195245 // so doesn't set expandable until a bit too late for onLoaded
196246 if (expandable) {
197− var shouldExpand = baseItem === categoryView.expandedCategoryItem;
247+ var shouldExpand = baseItem.category === categoryView.expandedCategoryId;
198248 baseItem.expand(shouldExpand, false /*animate*/);
199249 }
200250 }
201251
202− onHeightChanged: rendererLoader.updateDelegateCreationRange();
203− onYChanged: rendererLoader.updateDelegateCreationRange();
252+ onHeightChanged: rendererLoader.updateRanges();
253+ onYChanged: rendererLoader.updateRanges();
204254
205255 Loader {
206256 id: rendererLoader
@@ -215,9 +265,23 @@ FocusScope {
215265 id: heightBehaviour
216266 enabled: false
217267 animation: UbuntuNumberAnimation {
268+ duration: UbuntuAnimation.FastDuration
218269 onRunningChanged: {
219270 if (!running) {
220271 heightBehaviour.enabled = false
272+ if (categoryView.runMaximizeAfterSizeChanges > 0) {
273+ categoryView.runMaximizeAfterSizeChanges--;
274+ if (categoryView.runMaximizeAfterSizeChanges == 0) {
275+ var firstCreated = categoryView.firstCreatedIndex();
276+ for (var i = 0; i < categoryView.createdItemCount(); ++i) {
277+ var baseItem = categoryView.item(firstCreated + i);
278+ if (baseItem.category === categoryView.expandedCategoryId) {
279+ categoryView.maximizeVisibleArea(firstCreated + i, baseItem.item.expandedHeight + baseItem.seeAll.height);
280+ break;
281+ }
282+ }
283+ }
284+ }
221285 }
222286 }
223287 }
@@ -245,10 +309,10 @@ FocusScope {
245309 item.objectName = Qt.binding(function() { return categoryId })
246310 item.scopeStyle = scopeView.scopeStyle;
247311 if (baseItem.expandable) {
248− var shouldExpand = baseItem === categoryView.expandedCategoryItem;
312+ var shouldExpand = baseItem.category === categoryView.expandedCategoryId;
249313 baseItem.expand(shouldExpand, false /*animate*/);
250314 }
251− updateDelegateCreationRange();
315+ updateRanges();
252316 if (scope && scope.id === "clickscope" && (categoryId === "predefined" || categoryId === "local")) {
253317 // Yeah, hackish :/
254318 cardTool.artShapeSize = Qt.size(units.gu(8), units.gu(7.5));
@@ -303,13 +367,25 @@ FocusScope {
303367 }
304368 }
305369 }
306− onOriginYChanged: rendererLoader.updateDelegateCreationRange();
307− onContentYChanged: rendererLoader.updateDelegateCreationRange();
308− onHeightChanged: rendererLoader.updateDelegateCreationRange();
309− onContentHeightChanged: rendererLoader.updateDelegateCreationRange();
370+ onOriginYChanged: rendererLoader.updateRanges();
371+ onContentYChanged: rendererLoader.updateRanges();
372+ onHeightChanged: rendererLoader.updateRanges();
373+ onContentHeightChanged: rendererLoader.updateRanges();
374+ }
375+ Connections {
376+ target: scopeView
377+ onIsCurrentChanged: rendererLoader.updateRanges();
378+ }
379+ Connections {
380+ target: holdingList
381+ onMovingChanged: if (!moving) rendererLoader.updateRanges();
310382 }
311383
312− function updateDelegateCreationRange() {
384+ function updateRanges() {
385+ if (holdingList && holdingList.moving) {
386+ return;
387+ }
388+
313389 if (categoryView.moving) {
314390 // Do not update the range if we are overshooting up or down, since we'll come back
315391 // to the stable position and delete/create items without any reason
@@ -321,10 +397,18 @@ FocusScope {
321397 }
322398 }
323399
400+ if (item && item.hasOwnProperty("visibleRangeBegin")) {
401+ item.visibleRangeBegin = Math.max(-baseItem.y, 0)
402+ item.visibleRangeEnd = item.visibleRangeBegin + Math.min(categoryView.height, rendererLoader.height)
403+ }
404+
324405 if (item && item.hasOwnProperty("displayMarginBeginning")) {
325406 // TODO do we need item.originY here, test 1300302 once we have a silo
326407 // and we can run it on the phone
327− if (baseItem.y + baseItem.height <= 0) {
408+ if (scopeView.isCurrent) {
409+ item.displayMarginBeginning = 1073741823;
410+ item.displayMarginEnd = 1073741823;
411+ } else if (baseItem.y + baseItem.height <= 0) {
328412 // Not visible (item at top of the list viewport)
329413 item.displayMarginBeginning = -baseItem.height;
330414 item.displayMarginEnd = 0;
@@ -333,9 +417,9 @@ FocusScope {
333417 item.displayMarginBeginning = 0;
334418 item.displayMarginEnd = -baseItem.height;
335419 } else {
336− item.displayMarginBeginning = -Math.max(-baseItem.y, 0);
337− item.displayMarginEnd = -Math.max(baseItem.height - seeAll.height
338− - categoryView.height + baseItem.y, 0)
420+ item.displayMarginBeginning = Math.round(-Math.max(-baseItem.y, 0));
421+ item.displayMarginEnd = -Math.round(Math.max(baseItem.height - seeAll.height
422+ - categoryView.height + baseItem.y, 0));
339423 }
340424 }
341425 }
@@ -352,10 +436,11 @@ FocusScope {
352436 height: seeAllLabel.visible ? seeAllLabel.font.pixelSize + units.gu(4) : 0
353437
354438 onClicked: {
355− if (categoryView.expandedCategoryItem !== baseItem) {
356− categoryView.expandedCategoryItem = baseItem;
439+ if (categoryView.expandedCategoryId !== baseItem.category) {
440+ categoryView.expandedCategoryId = baseItem.category;
441+ floatingSeeLess.companionBase = baseItem;
357442 } else {
358− categoryView.expandedCategoryItem = null;
443+ categoryView.expandedCategoryId = "";
359444 }
360445 }
361446
@@ -455,7 +540,7 @@ FocusScope {
455540 objectName: "floatingSeeLess"
456541
457542 property Item companionTo: companionBase ? companionBase.seeAllButton : null
458− property Item companionBase: categoryView.expandedCategoryItem
543+ property Item companionBase: null
459544 property bool showBecausePosition: false
460545 property real yOffset: 0
461546
@@ -467,7 +552,7 @@ FocusScope {
467552 height: seeLessLabel.font.pixelSize + units.gu(4)
468553 visible: companionTo && showBecausePosition
469554
470− onClicked: categoryView.expandedCategoryItem = null;
555+ onClicked: categoryView.expandedCategoryId = "";
471556
472557 function updateVisibility() {
473558 var companionPos = companionTo.mapToItem(floatingSeeLess, 0, 0);
@@ -476,6 +561,10 @@ FocusScope {
476561 var posToBase = floatingSeeLess.mapToItem(companionBase, 0, -yOffset).y;
477562 yOffset = Math.max(0, companionBase.item.collapsedHeight - posToBase);
478563 yOffset = Math.min(yOffset, height);
564+
565+ if (!showBecausePosition && categoryView.expandedCategoryId === "") {
566+ companionBase = null;
567+ }
479568 }
480569
481570 Label {
qml/Dash/ScopeListView.qml+1
@@ -20,4 +20,5 @@ import Dash 0.1
2020ListViewWithPageHeader {
2121 maximumFlickVelocity: height * 10
2222 flickDeceleration: height * 2
23+ cacheBuffer: Number.MAX_VALUE
2324}
qml/Dash/ScopesOverviewAll.qml+2
@@ -43,6 +43,8 @@ Flickable {
4343 id: cardGrid
4444 width: root.width
4545 height: parent.height
46+ visibleRangeBegin: root.contentY
47+ visibleRangeEnd: root.contentY + root.height
4648
4749 onClicked: {
4850 root.clicked(index, result, item, itemModel);
tests/autopilot/unity8/shell/emulators/dash.py+2−2
@@ -93,7 +93,7 @@ class Dash(emulators.UnityEmulatorBase):
9393 'No scope found with id {0}'.format(scope_id))
9494
9595 def _get_scope_from_loader(self, loader):
96− return loader.get_children()[0]
96+ return loader.wait_select_single('GenericScopeView');
9797
9898 def _open_scope_scrolling(self, scope_loader):
9999 scroll = self._get_scroll_direction(scope_loader)
@@ -102,8 +102,8 @@ class Dash(emulators.UnityEmulatorBase):
102102 scroll()
103103 self.dash_content_list.moving.wait_for(False)
104104
105+ scope_loader.isCurrent.wait_for(True)
105106 scope = self._get_scope_from_loader(scope_loader)
106− scope.isCurrent.wait_for(True)
107107 return scope
108108
109109 def _get_scroll_direction(self, scope_loader):
tests/mocks/Ubuntu/CMakeLists.txt+1
@@ -1,3 +1,4 @@
1+add_subdirectory(Connectivity)
12add_subdirectory(DownloadDaemonListener)
23add_subdirectory(Payments)
34add_subdirectory(SystemImage)
tests/mocks/Ubuntu/Connectivity/CMakeLists.txtnew file+10
@@ -0,0 +1,10 @@
1+add_library(connectivity-qml SHARED
2+ networking-status.cpp
3+ plugin.cpp
4+)
5+qt5_use_modules(connectivity-qml Qml)
6+
7+# copy qmldir file into build directory for shadow builds
8+file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/qmldir"
9+ DESTINATION ${CMAKE_CURRENT_BINARY_DIR}
10+ )
tests/mocks/Ubuntu/Connectivity/networking-status.cppnew file+65
@@ -0,0 +1,65 @@
1+/*
2+ * Copyright © 2013 Canonical Ltd.
3+ *
4+ * This program is free software: you can redistribute it and/or modify it
5+ * under the terms of the GNU Lesser General Public License version 3,
6+ * as published by the Free Software Foundation.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU Lesser General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU Lesser General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ *
16+ * Authors:
17+ * Antti Kaijanmäki <antti.kaijanmaki@canonical.com>
18+ */
19+
20+#include "networking-status.h"
21+
22+NetworkingStatus::NetworkingStatus(QObject *parent)
23+ : QObject(parent)
24+{
25+
26+ qRegisterMetaType<NetworkingStatus::Limitations>();
27+ qRegisterMetaType<QVector<NetworkingStatus::Limitations>>();
28+ qRegisterMetaType<NetworkingStatus::Status>();
29+}
30+
31+NetworkingStatus::~NetworkingStatus()
32+{}
33+
34+QVector<NetworkingStatus::Limitations>
35+NetworkingStatus::limitations() const
36+{
37+ return m_limitations;
38+}
39+
40+NetworkingStatus::Status
41+NetworkingStatus::status() const
42+{
43+ return Status::Online;
44+}
45+
46+bool
47+NetworkingStatus::online() const
48+{
49+ return status() == Status::Online;
50+}
51+
52+bool
53+NetworkingStatus::limitedBandwith() const
54+{
55+ return limitations().contains(Limitations::Bandwith);
56+}
57+
58+void NetworkingStatus::setLimitedBandwidth(bool limited)
59+{
60+ if (limited) {
61+ m_limitations << Limitations::Bandwith;
62+ } else if (limitedBandwith()) {
63+ m_limitations.remove(m_limitations.indexOf(Limitations::Bandwith));
64+ }
65+}
tests/mocks/Ubuntu/Connectivity/networking-status.hnew file+73
@@ -0,0 +1,73 @@
1+/*
2+ * Copyright © 2014 Canonical Ltd.
3+ *
4+ * This program is free software: you can redistribute it and/or modify it
5+ * under the terms of the GNU Lesser General Public License version 3,
6+ * as published by the Free Software Foundation.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU Lesser General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU Lesser General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ *
16+ */
17+
18+#ifndef FAKE_NETWORKING_STATUS_H
19+#define FAKE_NETWORKING_STATUS_H
20+
21+#include <QObject>
22+#include <QVector>
23+
24+class Q_DECL_EXPORT NetworkingStatus : public QObject
25+{
26+ Q_OBJECT
27+ Q_DISABLE_COPY(NetworkingStatus)
28+
29+ Q_ENUMS(Limitations)
30+ Q_ENUMS(Status)
31+
32+ Q_PROPERTY(QVector<Limitations> limitations READ limitations NOTIFY limitationsChanged)
33+ Q_PROPERTY(Status status READ status NOTIFY statusChanged)
34+ Q_PROPERTY(bool online READ online NOTIFY onlineChanged)
35+ Q_PROPERTY(bool limitedBandwith READ limitedBandwith WRITE setLimitedBandwidth NOTIFY limitedBandwithChanged)
36+
37+public:
38+ explicit NetworkingStatus(QObject *parent = 0);
39+ virtual ~NetworkingStatus();
40+
41+ enum Limitations {
42+ Bandwith
43+ };
44+
45+ enum Status {
46+ Offline,
47+ Connecting,
48+ Online
49+ };
50+
51+ QVector<Limitations> limitations() const;
52+ Status status() const;
53+ bool online() const;
54+ bool limitedBandwith() const;
55+
56+ // Only in the fake one
57+ void setLimitedBandwidth(bool limited);
58+
59+Q_SIGNALS:
60+ void limitationsChanged();
61+ void statusChanged(Status value);
62+ void onlineChanged(bool value);
63+ void limitedBandwithChanged(bool value);
64+
65+private:
66+ QVector<NetworkingStatus::Limitations> m_limitations;
67+};
68+
69+Q_DECLARE_METATYPE(NetworkingStatus::Limitations)
70+Q_DECLARE_METATYPE(QVector<NetworkingStatus::Limitations>)
71+Q_DECLARE_METATYPE(NetworkingStatus::Status)
72+
73+#endif // FAKE_NETWORKING_STATUS_H
tests/mocks/Ubuntu/Connectivity/plugin.cppnew file+46
@@ -0,0 +1,46 @@
1+/*
2+ * Copyright © 2014 Canonical Ltd.
3+ *
4+ * This program is free software: you can redistribute it and/or modify it
5+ * under the terms of the GNU Lesser General Public License version 3,
6+ * as published by the Free Software Foundation.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU Lesser General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU Lesser General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ *
16+ * Authors:
17+ * Antti Kaijanmäki <antti.kaijanmaki@canonical.com>
18+ */
19+
20+#include "plugin.h"
21+
22+#include <QtQml>
23+
24+#include "networking-status.h"
25+
26+static QObject *
27+networkingStatusSingletonProvider(QQmlEngine *engine, QJSEngine *scriptEngine)
28+{
29+ Q_UNUSED(scriptEngine)
30+
31+ return new NetworkingStatus(engine);
32+}
33+
34+void
35+QmlConnectivityNetworkingPlugin::registerTypes(const char *uri)
36+{
37+ // @uri Ubuntu.Connectivity
38+ qmlRegisterSingletonType<NetworkingStatus>(uri, 1, 0, "NetworkingStatus", networkingStatusSingletonProvider);
39+}
40+
41+void
42+QmlConnectivityNetworkingPlugin::initializeEngine(QQmlEngine *engine, const char *uri)
43+{
44+ Q_UNUSED(uri);
45+ Q_UNUSED(engine);
46+}
tests/mocks/Ubuntu/Connectivity/plugin.hnew file+35
@@ -0,0 +1,35 @@
1+/*
2+ * Copyright © 2014 Canonical Ltd.
3+ *
4+ * This program is free software: you can redistribute it and/or modify it
5+ * under the terms of the GNU Lesser General Public License version 3,
6+ * as published by the Free Software Foundation.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU Lesser General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU Lesser General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ *
16+ * Authors:
17+ * Antti Kaijanmäki <antti.kaijanmaki@canonical.com>
18+ */
19+
20+#ifndef QML_CONNECTIVITY_PLUGIN_H
21+#define QML_CONNECTIVITY_PLUGIN_H
22+
23+#include <QQmlExtensionPlugin>
24+
25+class QmlConnectivityNetworkingPlugin : public QQmlExtensionPlugin {
26+ Q_OBJECT
27+ Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
28+ Q_INTERFACES(QQmlExtensionInterface)
29+
30+public:
31+ void registerTypes(const char *uri);
32+ void initializeEngine(QQmlEngine *engine, const char *uri);
33+};
34+
35+#endif // QML_CONNECTIVITY_PLUGIN_H
tests/mocks/Ubuntu/Connectivity/qmldirnew file+2
@@ -0,0 +1,2 @@
1+module Ubuntu.Connectivity
2+plugin connectivity-qml
tests/mocks/Unity/fake_categories.cpp+95−136
@@ -29,25 +29,12 @@ Categories::Categories(int category_count, QObject* parent)
2929
3030int Categories::rowCount(const QModelIndex& /*parent*/) const
3131{
32− return m_category_count + m_specialCategories.count();
32+ return m_category_count;
3333}
3434
35−void Categories::addSpecialCategory(QString const& categoryId, QString const& name, QString const& icon, QString const& rawTemplate, QObject* countObject)
35+void Categories::addSpecialCategory(QString const& /*categoryId*/, QString const& /*name*/, QString const& /*icon*/, QString const& /*rawTemplate*/, QObject* /*countObject*/)
3636{
37− CategoryData catData;
38− catData.categoryId = categoryId;
39− catData.name = name;
40− catData.icon = icon;
41− catData.rawTemplate = rawTemplate;
42− catData.countObject = countObject;
43−
44− beginInsertRows(QModelIndex(), 0, 0);
45− m_specialCategories.prepend(catData);
46− endInsertRows();
47−
48− if (countObject) {
49− connect(countObject, SIGNAL(countChanged()), this, SLOT(countChanged()));
50− }
37+ qFatal("Using un-implemented Categories::addSpecialCategory");
5138}
5239
5340bool Categories::overrideCategoryJson(QString const& /* categoryId */, QString const& /* json */)
@@ -55,23 +42,6 @@ bool Categories::overrideCategoryJson(QString const& /* categoryId */, QString c
5542 qFatal("Using un-implemented Categories::overrideCategoryJson");
5643}
5744
58−void Categories::countChanged()
59−{
60− QObject* countObject = sender();
61−
62− for (int i = 0; i < m_specialCategories.count(); ++i) {
63− const CategoryData &catData = m_specialCategories.at(i);
64− if (catData.countObject == countObject) {
65− QVector<int> roles;
66− roles.append(RoleCount);
67−
68− QModelIndex changedIndex(index(i));
69− dataChanged(changedIndex, changedIndex, roles);
70− break;
71− }
72− }
73−}
74−
7545QVariant
7646Categories::data(const QModelIndex& index, int role) const
7747{
@@ -79,115 +49,74 @@ Categories::data(const QModelIndex& index, int role) const
7949 return QVariant();
8050 }
8151
82− ResultsModel *resultsModel = m_resultsModels[index.row()];
83− if (!resultsModel) {
84− resultsModel = new ResultsModel(15, index.row());
85− m_resultsModels[index.row()] = resultsModel;
86− }
87− if (index.row() < m_specialCategories.count()) {
88− const CategoryData &catData = m_specialCategories.at(index.row());
89− switch (role) {
90− case RoleCategoryId:
91− return catData.categoryId;
92− case RoleName:
93− return catData.name;
94− case RoleIcon:
95− return catData.icon;
96− case RoleRawRendererTemplate:
97− return catData.rawTemplate;
98− case RoleRenderer:
99− {
100− QVariantMap map;
101− if (index.row() % 2 == 0) {
102− map["category-layout"] = "grid";
103− } else {
104− map["category-layout"] = "carousel";
105− map["overlay"] = true;
106− }
107− map["card-size"] = "small";
108− return map;
52+ ResultsModel *resultsModel = resultModel(index.row());
53+ switch (role) {
54+ case RoleCategoryId:
55+ return QString("%1").arg(index.row());
56+ case RoleName:
57+ return QString("Category %1").arg(index.row());
58+ case RoleIcon:
59+ return "gtk-apply";
60+ case RoleRawRendererTemplate:
61+ qFatal("Using un-implemented RoleRawRendererTemplate Categories role");
62+ return QVariant();
63+ case RoleRenderer:
64+ {
65+ QVariantMap map;
66+ if (index.row() % 2 == 0) {
67+ map["category-layout"] = "grid";
68+ } else {
69+ map["category-layout"] = "carousel";
10970 }
110− case RoleComponents:
111− {
112− QVariantMap map, artMap, attributeMap;
113− artMap["aspect-ratio"] = "1.0";
114− artMap["field"] = "art";
115− map["art"] = artMap;
116− map["title"] = "HOLA";
117− attributeMap["field"] = "attribute";
118− map["attributes"] = attributeMap;
119− return map;
71+ if (index.row() == 18) {
72+ map["category-layout"] = "horizontal-list";
73+ }
74+ if (index.row() == 19) {
75+ map["category-layout"] = "grid";
76+ map["collapsed-rows"] = 0;
77+ }
78+ map["card-size"] = "small";
79+
80+ map["category-layout"] = m_layouts.value(index.row(), map["category-layout"].toString());
81+
82+ if (map["category-layout"] == "carousel") {
83+ map["overlay"] = true;
12084 }
121− case RoleHeaderLink:
122− return QString();
123− case RoleResults:
124− return QVariant();
125− case RoleCount:
126− return catData.countObject->property("count");
127− default:
128− qFatal("Using un-implemented Categories role");
129− return QVariant();
85+
86+ return map;
13087 }
131− } else {
132− switch (role) {
133− case RoleCategoryId:
134− return QString("%1").arg(index.row());
135− case RoleName:
136− return QString("Category %1").arg(index.row());
137− case RoleIcon:
138− return "gtk-apply";
139− case RoleRawRendererTemplate:
140− qFatal("Using un-implemented RoleRawRendererTemplate Categories role");
141− return QVariant();
142− case RoleRenderer:
143− {
144− QVariantMap map;
145− if (index.row() % 2 == 0) {
146− map["category-layout"] = "grid";
147− } else {
148− map["category-layout"] = "carousel";
149− map["card-size"] = "medium";
150− map["overlay"] = true;
151− }
152− if (index.row() == 18) {
153− map["category-layout"] = "horizontal-list";
154− }
155− if (index.row() == 19) {
156− map["category-layout"] = "grid";
157− map["collapsed-rows"] = 0;
158− }
159− map["card-size"] = "small";
160− return map;
88+ case RoleComponents:
89+ {
90+ QVariantMap map, artMap, attributeMap;
91+ if (index.row() % 2 != 0) {
92+ artMap["aspect-ratio"] = QString("1.%1").arg(index.row());
93+ } else {
94+ artMap["aspect-ratio"] = "1.0";
16195 }
162− case RoleComponents:
163− {
164− QVariantMap map, artMap, attributeMap;
165− if (index.row() % 2 != 0) {
166− artMap["aspect-ratio"] = QString("1.%1").arg(index.row());
167− } else {
168− artMap["aspect-ratio"] = "1.0";
169− }
170− artMap["field"] = "art";
171− map["art"] = artMap;
172− map["title"] = "HOLA";
173− map["subtitle"] = "HOLA";
174− attributeMap["field"] = "attribute";
175− map["attributes"] = attributeMap;
176− return map;
96+ artMap["field"] = "art";
97+ map["art"] = artMap;
98+ map["title"] = "HOLA";
99+ map["subtitle"] = "HOLA";
100+ attributeMap["field"] = "attribute";
101+ map["attributes"] = attributeMap;
102+ return map;
103+ }
104+ case RoleHeaderLink:
105+ {
106+ QString res;
107+ if (index.row() == 1 || index.row() == 4) {
108+ res = QString("scope://query/1");
177109 }
178− case RoleHeaderLink:
179− if (index.row() == 1 || index.row() == 4) {
180− return QString("scope://query/1");
181− }
182− return QString();
183− case RoleResults:
184− return QVariant::fromValue(resultsModel);
185− case RoleCount:
186− return resultsModel->rowCount();
187− default:
188− qFatal("Using un-implemented Categories role");
189− return QVariant();
110+ res = m_headerLinks.value(index.row(), res);
111+ return res;
190112 }
113+ case RoleResults:
114+ return QVariant::fromValue(resultsModel);
115+ case RoleCount:
116+ return resultsModel->rowCount();
117+ default:
118+ qFatal("Using un-implemented Categories role");
119+ return QVariant();
191120 }
192121}
193122
@@ -196,3 +125,33 @@ Categories::data(int row, int role) const
196125{
197126 return data(index(row, 0), role);
198127}
128+
129+void Categories::setCount(int count)
130+{
131+ if (m_category_count != count) {
132+ beginResetModel(); // This is just for test setup so we can be lazy and reset
133+ m_category_count = count;
134+ endResetModel();
135+ }
136+}
137+
138+ResultsModel* Categories::resultModel(int row) const
139+{
140+ ResultsModel *result = m_resultsModels[row];
141+ if (!result) {
142+ Categories *that = const_cast<Categories*>(this);
143+ result = new ResultsModel(15, row, that);
144+ m_resultsModels[row] = result;
145+ }
146+ return result;
147+}
148+
149+void Categories::setLayout(int row, const QString &layout)
150+{
151+ m_layouts[row] = layout;
152+}
153+
154+void Categories::setHeaderLink(int row, const QString &headerLink)
155+{
156+ m_headerLinks[row] = headerLink;
157+}
tests/mocks/Unity/fake_categories.h+7−12
@@ -39,22 +39,17 @@ public:
3939
4040 Q_INVOKABLE QVariant data(int row, int role) const;
4141
42−private Q_SLOTS:
43− void countChanged();
42+ // For testing purposes
43+ Q_INVOKABLE void setCount(int count);
44+ Q_INVOKABLE ResultsModel* resultModel(int row) const;
45+ Q_INVOKABLE void setLayout(int row, const QString &layout);
46+ Q_INVOKABLE void setHeaderLink(int row, const QString &headerLink);
4447
4548private:
4649 mutable QHash<int, ResultsModel*> m_resultsModels;
50+ QHash<int, QString> m_layouts;
51+ QHash<int, QString> m_headerLinks;
4752 int m_category_count;
48−
49− struct CategoryData {
50− QString categoryId;
51− QString name;
52− QString icon;
53− QString rawTemplate;
54− QObject* countObject;
55− };
56−
57− QList<CategoryData> m_specialCategories;
5853};
5954
6055#endif // FAKE_CATEGORIES_H
tests/mocks/Unity/fake_resultsmodel.cpp+9
@@ -44,6 +44,15 @@ void ResultsModel::setCategoryId(QString const& /*id*/)
4444 qFatal("Calling un-implemented ResultsModel::setCategoryId");
4545}
4646
47+void ResultsModel::setResultCount(int result_count)
48+{
49+ if (m_result_count != result_count) {
50+ beginResetModel(); // This is just for test setup so we can be lazy and reset
51+ m_result_count = result_count;
52+ endResetModel();
53+ }
54+}
55+
4756int ResultsModel::rowCount(const QModelIndex& parent) const
4857{
4958 Q_UNUSED(parent);
tests/mocks/Unity/fake_resultsmodel.h+3
@@ -41,6 +41,9 @@ public:
4141 /* setters */
4242 void setCategoryId(QString const& id) override;
4343
44+ // For testing purposes
45+ Q_INVOKABLE void setResultCount(int result_count);
46+
4447private:
4548 int m_result_count;
4649 int m_categoryId;
tests/mocks/Unity/fake_scope.cpp+17
@@ -145,6 +145,23 @@ void Scope::setFavorite(const bool favorite)
145145 Q_EMIT favoriteChanged();
146146 }
147147}
148+
149+void Scope::setId(const QString &id)
150+{
151+ if (id != m_id) {
152+ m_id = id;
153+ Q_EMIT idChanged();
154+ }
155+}
156+
157+void Scope::setName(const QString &name)
158+{
159+ if (name != m_name) {
160+ m_name = name;
161+ Q_EMIT nameChanged();
162+ }
163+}
164+
148165void Scope::setSearchInProgress(const bool inProg)
149166{
150167 if (inProg != m_searching) {
tests/mocks/Unity/fake_scope.h+2
@@ -56,6 +56,8 @@ public:
5656 void setFormFactor(const QString& form_factor) override;
5757 void setActive(const bool) override;
5858 void setFavorite(const bool) override;
59+ Q_INVOKABLE void setId(const QString &id); // This is not invokable in the Interface, here for testing benefits
60+ Q_INVOKABLE void setName(const QString &name); // This is not invokable in the Interface, here for testing benefits
5961 Q_INVOKABLE void setSearchInProgress(const bool inProg); // This is not invokable in the Interface, here for testing benefits
6062
6163 Q_INVOKABLE void activate(QVariant const& result) override;
tests/plugins/Dash/CMakeLists.txt+3−3
@@ -32,7 +32,7 @@ macro(add_lvwph_test FILENAME TESTNAME)
3232 qt5_use_modules(${TESTNAME}TestExec Test Core Qml)
3333 target_link_libraries(${TESTNAME}TestExec ${Qt5Gui_LIBRARIES} ${Qt5Quick_LIBRARIES})
3434
35− add_binary_qml_test(${TESTNAME} "" "Dash-qml")
35+ add_binary_qml_test(${TESTNAME} "" "Dash-qml" "")
3636endmacro()
3737
3838add_lvwph_test(listviewwithpageheader ListViewWithPageHeader)
@@ -48,7 +48,7 @@ macro(add_dashview_try_test FILENAME TESTNAME)
4848 qt5_use_modules(${TESTNAME}TestExec Test Core Qml)
4949 target_link_libraries(${TESTNAME}TestExec ${Qt5Gui_LIBRARIES} ${Qt5Quick_LIBRARIES})
5050
51− add_binary_qml_test(${TESTNAME} "" "Dash-qml")
51+ add_binary_qml_test(${TESTNAME} "" "Dash-qml" "")
5252
5353 add_executable(${TESTNAME}tryExec
5454 ${FILENAME}try.cpp
@@ -71,7 +71,7 @@ add_dashview_try_test(organicgrid OrganicGrid)
7171add_executable(CardCreatorTestExec cardcreatortest.cpp)
7272qt5_use_modules(CardCreatorTestExec Test Core Qml)
7373target_link_libraries(CardCreatorTestExec ${Qt5Gui_LIBRARIES} ${Qt5Quick_LIBRARIES})
74−add_binary_qml_test(CardCreator "" "Dash-qml")
74+add_binary_qml_test(CardCreator "" "Dash-qml" "QML2_IMPORT_PATH=${CMAKE_BINARY_DIR}/tests/mocks/")
7575
7676# plain qml test
7777set(qmltest_DEFAULT_TARGETS qmluitests)
tests/plugins/Dash/cardcreator/1.res+2−1
@@ -46,7 +46,8 @@ Item {
4646 }
4747 image: Image {
4848 objectName: "artImage";
49− source: cardData && cardData["art"] || "";
49+ property bool doLoadSource: !NetworkingStatus.limitedBandwith;
50+ source: { if (root.visible) doLoadSource = true; return doLoadSource && cardData && cardData["art"] || ""; }
5051 cache: true;
5152 asynchronous: root.asynchronous;
5253 fillMode: Image.PreserveAspectCrop;
tests/plugins/Dash/cardcreator/2.res+2−1
@@ -67,7 +67,8 @@ Image {
6767 objectName: "mascotImage";
6868 anchors { verticalCenter: parent.verticalCenter; }
6969 readonly property int maxSize: Math.max(width, height) * 4;
70− source: cardData && cardData["mascot"] || "";
70+ property bool doLoadSource: !NetworkingStatus.limitedBandwith;
71+ source: { if (root.visible) doLoadSource = true; return doLoadSource && cardData && cardData["mascot"] || ""; }
7172 width: units.gu(6);
7273 height: units.gu(5.625);
7374 sourceSize { width: maxSize; height: maxSize }
tests/plugins/Dash/cardcreator/3.res+3−2
@@ -46,8 +46,9 @@ Item {
4646 }
4747 image: Image {
4848 objectName: "artImage";
49− source: cardData && cardData["art"] || "";
50− cache: true;
49+ property bool doLoadSource: !NetworkingStatus.limitedBandwith;
50+ source: { if (root.visible) doLoadSource = true; return doLoadSource && cardData && cardData["art"] || ""; }
51+ cache: true;
5152 asynchronous: root.asynchronous;
5253 fillMode: Image.PreserveAspectCrop;
5354 width: root.width;
tests/plugins/Dash/cardcreator/4.res+3−2
@@ -46,8 +46,9 @@ Loader {
4646 objectName: "mascotImage";
4747 anchors { verticalCenter: parent.verticalCenter; }
4848 readonly property int maxSize: Math.max(width, height) * 4;
49− source: cardData && cardData["mascot"] || "";
50− width: units.gu(6);
49+ property bool doLoadSource: !NetworkingStatus.limitedBandwith;
50+ source: { if (root.visible) doLoadSource = true; return doLoadSource && cardData && cardData["mascot"] || ""; }
51+ width: units.gu(6);
5152 height: units.gu(5.625);
5253 sourceSize { width: maxSize; height: maxSize }
5354 fillMode: Image.PreserveAspectCrop;
tests/plugins/Dash/cardcreator/5.res+3−2
@@ -46,8 +46,9 @@ Item {
4646 }
4747 image: Image {
4848 objectName: "artImage";
49− source: cardData && cardData["art"] || "";
50− cache: true;
49+ property bool doLoadSource: !NetworkingStatus.limitedBandwith;
50+ source: { if (root.visible) doLoadSource = true; return doLoadSource && cardData && cardData["art"] || ""; }
51+ cache: true;
5152 asynchronous: root.asynchronous;
5253 fillMode: Image.PreserveAspectCrop;
5354 width: root.width;
tests/plugins/Dash/cardcreator/7.res+3−2
@@ -67,8 +67,9 @@ Image {
6767 objectName: "mascotImage";
6868 anchors { verticalCenter: parent.verticalCenter; }
6969 readonly property int maxSize: Math.max(width, height) * 4;
70− source: cardData && cardData["mascot"] || "";
71− width: units.gu(6);
70+ property bool doLoadSource: !NetworkingStatus.limitedBandwith;
71+ source: { if (root.visible) doLoadSource = true; return doLoadSource && cardData && cardData["mascot"] || ""; }
72+ width: units.gu(6);
7273 height: units.gu(5.625);
7374 sourceSize { width: maxSize; height: maxSize }
7475 fillMode: Image.PreserveAspectCrop;
tests/plugins/Dash/listviewwithpageheadertest.cpp+39
@@ -28,6 +28,8 @@
2828#include <private/qquickitem_p.h>
2929#pragma GCC diagnostic pop
3030
31+#include <limits>
32+
3133// TODO Think on how doing a test for lost items
3234// particullary making sure that lost items are culled
3335// and then removed in the next updatePolish cycle
@@ -1899,6 +1901,43 @@ private Q_SLOTS:
18991901 QTRY_COMPARE(lvwph->m_firstVisibleIndex, 0);
19001902 }
19011903
1904+ void testNoCacheBuffer()
1905+ {
1906+ lvwph->setCacheBuffer(0);
1907+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 3);
1908+ QCOMPARE(lvwph->m_firstVisibleIndex, 0);
1909+ verifyItem(0, 50., 150., false);
1910+ verifyItem(1, 200., 200., false);
1911+ verifyItem(2, 400., 350., false);
1912+ QCOMPARE(lvwph->m_minYExtent, 0.);
1913+ QCOMPARE(lvwph->m_clipItem->y(), 0.);
1914+ QCOMPARE(lvwph->m_clipItem->clip(), false);
1915+ QCOMPARE(lvwph->m_headerItem->y(), 0.);
1916+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
1917+ QCOMPARE(lvwph->contentY(), 0.);
1918+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
1919+ }
1920+
1921+ void testAllCacheBuffer()
1922+ {
1923+ lvwph->setCacheBuffer(std::numeric_limits<qreal>::max());
1924+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 6);
1925+ QCOMPARE(lvwph->m_firstVisibleIndex, 0);
1926+ verifyItem(0, 50., 150., false);
1927+ verifyItem(1, 200., 200., false);
1928+ verifyItem(2, 400., 350., false);
1929+ verifyItem(3, 750., 350., true);
1930+ verifyItem(4, 1100., 350., true);
1931+ verifyItem(5, 1450., 350., true);
1932+ QCOMPARE(lvwph->m_minYExtent, 0.);
1933+ QCOMPARE(lvwph->m_clipItem->y(), 0.);
1934+ QCOMPARE(lvwph->m_clipItem->clip(), false);
1935+ QCOMPARE(lvwph->m_headerItem->y(), 0.);
1936+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
1937+ QCOMPARE(lvwph->contentY(), 0.);
1938+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
1939+ }
1940+
19021941private:
19031942 QQuickView *view;
19041943 ListViewWithPageHeader *lvwph;
tests/plugins/Dash/listviewwithpageheadertest.qml+1
@@ -60,6 +60,7 @@ Rectangle {
6060 anchors.top: parent.top
6161 anchors.bottom: parent.bottom
6262 model: model
63+ cacheBuffer: height * 0.5
6364 delegate: Rectangle {
6465 property bool timerDone: false
6566 width: parent.width - 20
tests/plugins/Dash/listviewwithpageheadertestsection.qml+1
@@ -60,6 +60,7 @@ Rectangle {
6060 anchors.top: parent.top
6161 anchors.bottom: parent.bottom
6262 model: model
63+ cacheBuffer: height * 0.5
6364 delegate: Rectangle {
6465 property bool timerDone: false
6566 width: parent.width - 20
tests/plugins/Dash/listviewwithpageheadertestsectionexternalmodel.qml+1
@@ -28,6 +28,7 @@ Rectangle {
2828 anchors.top: parent.top
2929 anchors.bottom: parent.bottom
3030 model: model
31+ cacheBuffer: height * 0.5
3132 delegate: Rectangle {
3233 property bool timerDone: false
3334 width: parent.width - 20
tests/plugins/Ubuntu/Gestures/CMakeLists.txt+1−1
@@ -19,7 +19,7 @@ macro(add_gesture_ui_test CLASSNAME)
1919 qt5_use_modules(${CLASSNAME}TestExec Test Core Qml Gui Quick)
2020 target_link_libraries(${CLASSNAME}TestExec UbuntuGestureQml)
2121
22− add_binary_qml_test(${CLASSNAME} ${CMAKE_BINARY_DIR}/plugins/Ubuntu/Gestures UbuntuGesturesTestQmlFiles)
22+ add_binary_qml_test(${CLASSNAME} ${CMAKE_BINARY_DIR}/plugins/Ubuntu/Gestures UbuntuGesturesTestQmlFiles "")
2323 add_manual_qml_test(. ${CLASSNAME} IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins)
2424endmacro(add_gesture_ui_test)
2525
tests/qmltests/Components/CMakeLists.txt+1−1
@@ -10,7 +10,7 @@ add_executable(DragHandleTestExec tst_DragHandle.cpp)
1010qt5_use_modules(DragHandleTestExec Test Core Qml Gui Quick)
1111target_link_libraries(DragHandleTestExec UbuntuGestureQml)
1212
13−add_binary_qml_test(DragHandle ${CMAKE_BINARY_DIR}/plugins/Ubuntu/Gestures "")
13+add_binary_qml_test(DragHandle ${CMAKE_BINARY_DIR}/plugins/Ubuntu/Gestures "" "")
1414add_manual_qml_test(. DragHandle IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins)
1515
1616add_definitions(-DUBUNTU_GESTURES_PLUGIN_DIR="${CMAKE_BINARY_DIR}/plugins")
tests/qmltests/Dash/tst_Card.qml+21
@@ -17,6 +17,7 @@
1717import QtQuick 2.0
1818import QtTest 1.0
1919import Ubuntu.Components 0.1
20+import Ubuntu.Connectivity 1.0
2021import Unity.Test 0.1 as UT
2122import "../../../qml/Dash"
2223import "CardHelpers.js" as Helpers
@@ -566,5 +567,25 @@ Rectangle {
566567 verify((card.width - titleToCard.x - titleToCard.width) === units.gu(1));
567568 }
568569 }
570+
571+ function test_load_images_visibility_network_data() {
572+ return [
573+ { tag: "Visible, network", visible: true, limitedBandwith: false },
574+ { tag: "Visible, no network", visible: true, limitedBandwith: true },
575+ { tag: "Not Visible, network", visible: false, limitedBandwith: false },
576+ { tag: "Not Visible, no network", visible: false, limitedBandwith: true }
577+ ];
578+ }
579+
580+ function test_load_images_visibility_network(data) {
581+ loader.visible = data.visible;
582+ NetworkingStatus.limitedBandwith = data.limitedBandwith;
583+
584+ selector.selectedIndex = 0;
585+ waitForRendering(selector);
586+ waitForRendering(card);
587+
588+ verify(data.visible || !data.limitedBandwith || artImage.source == "");
589+ }
569590 }
570591}
tests/qmltests/Dash/tst_Dash.qml+1−2
@@ -249,8 +249,7 @@ Item {
249249 var categoryListView = findChild(dashContentList.currentItem, "categoryListView");
250250 var dashCategory2 = findChild(categoryListView, "dashCategory2");
251251 tryCompareFunction(function() {
252− var d = findChild(dashCategory2, "delegate2");
253− if (d) return true;
252+ if (dashCategory2.y < 200) return true;
254253 categoryListView.contentY += 100;
255254 return false;
256255 }, true);
tests/qmltests/Dash/tst_GenericScopeView.qml+103−7
@@ -1,5 +1,5 @@
11/*
2− * Copyright 2013 Canonical Ltd.
2+ * Copyright 2013, 2014 Canonical Ltd.
33 *
44 * This program is free software; you can redistribute it and/or modify
55 * it under the terms of the GNU General Public License as published by
@@ -43,6 +43,10 @@ Item {
4343 onLoadedChanged: if (loaded) genericScopeView.scope = scopes.getScope(2);
4444 }
4545
46+ MockScope {
47+ id: mockScope
48+ }
49+
4650 SignalSpy {
4751 id: spy
4852 }
@@ -78,18 +82,29 @@ Item {
7882 spy.signalName = "";
7983 }
8084
81− function scrollToCategory(category) {
85+ function scrollToCategory(categoryName) {
8286 var categoryListView = findChild(genericScopeView, "categoryListView");
8387 tryCompareFunction(function() {
84− if (findChild(genericScopeView, category)) return true;
88+ var category = findChild(genericScopeView, categoryName);
89+ if (category && category.y > 0 && category.y < genericScopeView.height) return true;
8590 mouseFlick(genericScopeView, genericScopeView.width/2, genericScopeView.height,
8691 genericScopeView.width/2, genericScopeView.y)
8792 tryCompare(categoryListView, "moving", false);
88− return findChild(genericScopeView, category) !== null;
93+ return false;
8994 }, true);
9095
9196 tryCompareFunction(function() { return findChild(genericScopeView, "delegate0") !== null; }, true);
92− return findChild(genericScopeView, category);
97+ return findChild(genericScopeView, categoryName);
98+ }
99+
100+ function scrollToEnd()
101+ {
102+ var categoryListView = findChild(genericScopeView, "categoryListView");
103+ while (!categoryListView.atYEnd) {
104+ mouseFlick(genericScopeView, genericScopeView.width/2, genericScopeView.height - units.gu(8),
105+ genericScopeView.width/2, genericScopeView.y)
106+ tryCompare(categoryListView, "moving", false);
107+ }
93108 }
94109
95110 function test_isActive() {
@@ -268,7 +283,7 @@ Item {
268283 if (category === undefined) category = 0;
269284 if (delegate === undefined) delegate = 0;
270285 tryCompareFunction(function() {
271− var cardGrid = findChild(genericScopeView, category);
286+ var cardGrid = findChild(genericScopeView, "dashCategory"+category);
272287 if (cardGrid != null) {
273288 var tile = findChild(cardGrid, "delegate"+delegate);
274289 return tile != null;
@@ -276,7 +291,7 @@ Item {
276291 return false;
277292 },
278293 true);
279− var tile = findChild(findChild(genericScopeView, category), "delegate"+delegate);
294+ var tile = findChild(findChild(genericScopeView, "dashCategory"+category), "delegate"+delegate);
280295 mouseClick(tile, tile.width / 2, tile.height / 2);
281296 tryCompare(testCase.subPageLoader, "open", true);
282297 tryCompare(testCase.subPageLoader, "x", 0);
@@ -426,6 +441,87 @@ Item {
426441 compare(image.source, data.logo, "Title image has the wrong source");
427442 }
428443
444+ function test_seeAllTwoCategoriesScenario1() {
445+ mockScope.setId("mockScope");
446+ mockScope.setName("Mock Scope");
447+ mockScope.categories.setCount(2);
448+ mockScope.categories.resultModel(0).setResultCount(50);
449+ mockScope.categories.resultModel(1).setResultCount(15);
450+ mockScope.categories.setLayout(0, "grid");
451+ mockScope.categories.setLayout(1, "grid");
452+ mockScope.categories.setHeaderLink(0, "");
453+ mockScope.categories.setHeaderLink(1, "");
454+ genericScopeView.scope = mockScope;
455+ waitForRendering(genericScopeView.categoryView);
456+
457+ var category0 = findChild(genericScopeView, "dashCategory0")
458+ var seeAll0 = findChild(category0, "seeAll")
459+
460+ waitForRendering(seeAll0);
461+ verify(category0.expandable);
462+ verify(!category0.expanded);
463+
464+ mouseClick(seeAll0, seeAll0.width / 2, seeAll0.height / 2);
465+ verify(category0.expanded);
466+ tryCompare(category0, "height", category0.item.expandedHeight + seeAll0.height);
467+ tryCompare(genericScopeView.categoryView, "contentY", units.gu(13.5));
468+
469+ scrollToEnd();
470+
471+ tryCompareFunction(function() { return findChild(genericScopeView, "dashCategory1") !== null; }, true);
472+ var category1 = findChild(genericScopeView, "dashCategory1")
473+ var seeAll1 = findChild(category1, "seeAll")
474+ verify(category1.expandable);
475+ verify(!category1.expanded);
476+
477+ mouseClick(seeAll1, seeAll1.width / 2, seeAll1.height / 2);
478+ verify(!category0.expanded);
479+ verify(category1.expanded);
480+ tryCompare(category1, "height", category1.item.expandedHeight + seeAll1.height);
481+ tryCompareFunction(function() {
482+ return genericScopeView.categoryView.contentY + category1.y + category1.height + genericScopeView.categoryView.pageHeader.height
483+ == genericScopeView.categoryView.contentHeight;}
484+ , true);
485+ }
486+
487+ function test_seeAllTwoCategoriesScenario2() {
488+ mockScope.setId("mockScope");
489+ mockScope.setName("Mock Scope");
490+ mockScope.categories.setCount(2);
491+ mockScope.categories.resultModel(0).setResultCount(15);
492+ mockScope.categories.resultModel(1).setResultCount(50);
493+ mockScope.categories.setLayout(0, "grid");
494+ mockScope.categories.setLayout(1, "grid");
495+ mockScope.categories.setHeaderLink(0, "");
496+ mockScope.categories.setHeaderLink(1, "");
497+ genericScopeView.scope = mockScope;
498+ waitForRendering(genericScopeView.categoryView);
499+
500+ var category0 = findChild(genericScopeView, "dashCategory0")
501+ var seeAll0 = findChild(category0, "seeAll")
502+
503+ waitForRendering(seeAll0);
504+ verify(category0.expandable);
505+ verify(!category0.expanded);
506+
507+ mouseClick(seeAll0, seeAll0.width / 2, seeAll0.height / 2);
508+ verify(category0.expanded);
509+ tryCompare(category0, "height", category0.item.expandedHeight + seeAll0.height);
510+
511+ scrollToEnd();
512+
513+ var category1 = findChild(genericScopeView, "dashCategory1")
514+ var seeAll1 = findChild(category1, "seeAll")
515+ verify(category1.expandable);
516+ verify(!category1.expanded);
517+
518+ mouseClick(seeAll1, seeAll1.width / 2, seeAll1.height / 2);
519+ verify(!category0.expanded);
520+ verify(category1.expanded);
521+ tryCompare(category1, "height", category1.item.expandedHeight + seeAll1.height);
522+ tryCompare(category1, "y", units.gu(5));
523+ }
524+
429525 function test_favorite_data() {
430526 return [
431527 { tag: "People", id: "MockScope1", favorite: true },