Merge lp:~unity-team/unity8/two_see_more_bugfix into lp:unity8

Proposed by Michał Sawicz
Status: Merged
Approved by: Andrea Cimitan
Approved revision: 1193
Merged at revision: 1272
Proposed branch: lp:~unity-team/unity8/two_see_more_bugfix
Merge into: lp:unity8
Diff against target: 738 lines (+322/-184)
10 files modified
plugins/Dash/listviewwithpageheader.cpp (+11/-1)
plugins/Dash/listviewwithpageheader.h (+2/-0)
qml/Dash/GenericScopeView.qml (+74/-29)
tests/mocks/Unity/fake_categories.cpp (+100/-141)
tests/mocks/Unity/fake_categories.h (+7/-12)
tests/mocks/Unity/fake_resultsmodel.cpp (+9/-0)
tests/mocks/Unity/fake_resultsmodel.h (+3/-0)
tests/mocks/Unity/fake_scope.cpp (+17/-0)
tests/mocks/Unity/fake_scope.h (+2/-0)
tests/qmltests/Dash/tst_GenericScopeView.qml (+97/-1)
To merge this branch: bzr merge lp:~unity-team/unity8/two_see_more_bugfix
Reviewer Review Type Date Requested Status
PS Jenkins bot (community) continuous-integration Needs Fixing
Andrea Cimitan (community) Approve
Albert Astals Cid (community) contains my code Abstain
Michael Zanetti (community) Needs Fixing
Review via email: mp+234340@code.launchpad.net

This proposal supersedes a proposal from 2014-08-19.

Commit message

Dash: Fix issue when expanding a category and collapsing another one at the same time.

We need to first run the shrink+grow animations in the two category items, and later, if needed run the maximizeVisibleArea in the one we expanded.

It does not fix *everything* related to seeAll growing/shrinking + maximization, it may need some rethinking/rearchitecture to fix all issues, so let's just get these in that fix some very broken behaviour

Description of the change

* Are there any related MPs required for this MP to build/function as expected?
No

* Did you perform an exploratory manual test run of your code change and any related functionality?
Yes

* Did you make sure that your branch does not contain spurious tags?
Yes

* If you changed the packaging (debian), did you subscribe the ubuntu-unity team to this MP?
N/A

* If you changed the UI, has there been a design review?
N/A

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Michael Zanetti (mzanetti) wrote :

Some minor things inline, seems to work fine.

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

Fixeded.

1188. By Michał Sawicz

Drop Q_PROPERTY

1189. By Michał Sawicz

We already have a seeAllButton property.

1190. By Michał Sawicz

I said we have it already.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Michael Zanetti (mzanetti) wrote :

seems to fail a test now :/

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

> seems to fail a test now :/

Yeah, and I can't reproduce locally. Albert, back to you...

Revision history for this message
Albert Astals Cid (aacid) :
review: Abstain (contains my code)
1191. By Albert Astals Cid

Try to make LVWPH to behave consistently

doubles are not fun

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Albert Astals Cid (aacid) wrote :
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Andrea Cimitan (cimi) wrote :

Minor things around spacing

A question more for the backend: is it possible to have same categoryId? (in case someone badly implements a scope) We are checking for the id string now, rather the obj

1192. By Albert Astals Cid

spacing and (C) year

Revision history for this message
Albert Astals Cid (aacid) wrote :

> A question more for the backend: is it possible to have same categoryId? (in
> case someone badly implements a scope) We are checking for the id string now,
> rather the obj

Yes, we used to check for id not too long ago, but was [wrongly] changed in r1212 http://bazaar.launchpad.net/~unity-team/unity8/trunk/revision/1212

I say wrognly changed because keeping the pointer to the delegate means that if you scroll a lot in the list and the delegate gets destroyed, when you come back it'll be a different delegate pointer.

1193. By Albert Astals Cid

Typo

Revision history for this message
Andrea Cimitan (cimi) wrote :

 * Did you perform an exploratory manual test run of the code change and any related functionality?
Tested this branch through other dependants, works fine
 * Did CI run pass? If not, please explain why.
Auto.. ehm. :)

review: Approve
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'plugins/Dash/listviewwithpageheader.cpp'
--- plugins/Dash/listviewwithpageheader.cpp 2014-09-01 10:45:25 +0000
+++ plugins/Dash/listviewwithpageheader.cpp 2014-09-18 10:05:43 +0000
@@ -409,6 +409,16 @@
409 }409 }
410}410}
411411
412int ListViewWithPageHeader::firstCreatedIndex() const
413{
414 return m_firstVisibleIndex;
415}
416
417int ListViewWithPageHeader::createdItemCount() const
418{
419 return m_visibleItems.count();
420}
421
412QQuickItem *ListViewWithPageHeader::item(int modelIndex) const422QQuickItem *ListViewWithPageHeader::item(int modelIndex) const
413{423{
414 ListItem *item = itemAtIndex(modelIndex);424 ListItem *item = itemAtIndex(modelIndex);
@@ -520,7 +530,7 @@
520 // (but the header was not shown by it's own position)530 // (but the header was not shown by it's own position)
521 // or the header is partially shown and we are not doing a maximizeVisibleArea either531 // or the header is partially shown and we are not doing a maximizeVisibleArea either
522 const bool scrolledUp = m_previousContentY > contentY();532 const bool scrolledUp = m_previousContentY > contentY();
523 const bool notRebounding = contentY() + height() < contentHeight();533 const bool notRebounding = qRound(contentY() + height()) < qRound(contentHeight());
524 const bool notShownByItsOwn = contentY() + diff >= m_headerItem->y() + m_headerItem->height();534 const bool notShownByItsOwn = contentY() + diff >= m_headerItem->y() + m_headerItem->height();
525 const bool maximizeVisibleAreaRunning = m_contentYAnimation->isRunning() && contentYAnimationType == ContentYAnimationMaximizeVisibleArea;535 const bool maximizeVisibleAreaRunning = m_contentYAnimation->isRunning() && contentYAnimationType == ContentYAnimationMaximizeVisibleArea;
526536
527537
=== modified file 'plugins/Dash/listviewwithpageheader.h'
--- plugins/Dash/listviewwithpageheader.h 2014-09-01 10:45:25 +0000
+++ plugins/Dash/listviewwithpageheader.h 2014-09-18 10:05:43 +0000
@@ -86,6 +86,8 @@
8686
87 Q_INVOKABLE void positionAtBeginning();87 Q_INVOKABLE void positionAtBeginning();
88 Q_INVOKABLE void showHeader();88 Q_INVOKABLE void showHeader();
89 Q_INVOKABLE int firstCreatedIndex() const;
90 Q_INVOKABLE int createdItemCount() const;
89 Q_INVOKABLE QQuickItem *item(int modelIndex) const;91 Q_INVOKABLE QQuickItem *item(int modelIndex) const;
9092
91 // The index has to be created for this to try to do something93 // The index has to be created for this to try to do something
9294
=== modified file 'qml/Dash/GenericScopeView.qml'
--- qml/Dash/GenericScopeView.qml 2014-09-08 14:15:01 +0000
+++ qml/Dash/GenericScopeView.qml 2014-09-18 10:05:43 +0000
@@ -47,6 +47,10 @@
4747
48 signal backClicked()48 signal backClicked()
4949
50 onScopeChanged: {
51 floatingSeeLess.companionBase = null;
52 }
53
50 function positionAtBeginning() {54 function positionAtBeginning() {
51 categoryView.positionAtBeginning()55 categoryView.positionAtBeginning()
52 }56 }
@@ -152,11 +156,54 @@
152 forceNoClip: subPageLoader.open156 forceNoClip: subPageLoader.open
153 pixelAligned: true157 pixelAligned: true
154158
155 property Item expandedCategoryItem: null159 property string expandedCategoryId: ""
160 property int runMaximizeAfterSizeChanges: 0
156161
157 readonly property bool pageHeaderTotallyVisible: scopeView.showPageHeader &&162 readonly property bool pageHeaderTotallyVisible: scopeView.showPageHeader &&
158 ((headerItemShownHeight == 0 && categoryView.contentY <= categoryView.originY) || (headerItemShownHeight == pageHeaderLoader.item.height))163 ((headerItemShownHeight == 0 && categoryView.contentY <= categoryView.originY) || (headerItemShownHeight == pageHeaderLoader.item.height))
159164
165 onExpandedCategoryIdChanged: {
166 var firstCreated = firstCreatedIndex();
167 var shrinkingAny = false;
168 var shrinkHeightDifference = 0;
169 for (var i = 0; i < createdItemCount(); ++i) {
170 var baseItem = item(firstCreated + i);
171 if (baseItem.expandable) {
172 var shouldExpand = baseItem.category === expandedCategoryId;
173 if (shouldExpand != baseItem.expanded) {
174 var animate = false;
175 if (!subPageLoader.open) {
176 var animateShrinking = !shouldExpand && baseItem.y + baseItem.item.collapsedHeight + baseItem.seeAllButton.height < categoryView.height;
177 var animateGrowing = shouldExpand && baseItem.y + baseItem.height < categoryView.height;
178 animate = shrinkingAny || animateShrinking || animateGrowing;
179 }
180
181 if (!shouldExpand) {
182 shrinkingAny = true;
183 shrinkHeightDifference = baseItem.item.expandedHeight - baseItem.item.collapsedHeight;
184 }
185
186 if (shouldExpand && !subPageLoader.open) {
187 if (!shrinkingAny) {
188 categoryView.maximizeVisibleArea(firstCreated + i, baseItem.item.expandedHeight + baseItem.seeAllButton.height);
189 } else {
190 // If the space that shrinking is smaller than the one we need to grow we'll call maximizeVisibleArea
191 // after the shrink/grow animation ends
192 var growHeightDifference = baseItem.item.expandedHeight - baseItem.item.collapsedHeight;
193 if (growHeightDifference > shrinkHeightDifference) {
194 runMaximizeAfterSizeChanges = 2;
195 } else {
196 runMaximizeAfterSizeChanges = 0;
197 }
198 }
199 }
200
201 baseItem.expand(shouldExpand, animate);
202 }
203 }
204 }
205 }
206
160 delegate: ListItems.Base {207 delegate: ListItems.Base {
161 id: baseItem208 id: baseItem
162 objectName: "dashCategory" + category209 objectName: "dashCategory" + category
@@ -194,7 +241,7 @@
194 // This can happen with the VJ that doesn't know how height it will be on creation241 // This can happen with the VJ that doesn't know how height it will be on creation
195 // so doesn't set expandable until a bit too late for onLoaded242 // so doesn't set expandable until a bit too late for onLoaded
196 if (expandable) {243 if (expandable) {
197 var shouldExpand = baseItem === categoryView.expandedCategoryItem;244 var shouldExpand = baseItem.category === categoryView.expandedCategoryId;
198 baseItem.expand(shouldExpand, false /*animate*/);245 baseItem.expand(shouldExpand, false /*animate*/);
199 }246 }
200 }247 }
@@ -215,9 +262,23 @@
215 id: heightBehaviour262 id: heightBehaviour
216 enabled: false263 enabled: false
217 animation: UbuntuNumberAnimation {264 animation: UbuntuNumberAnimation {
265 duration: UbuntuAnimation.FastDuration
218 onRunningChanged: {266 onRunningChanged: {
219 if (!running) {267 if (!running) {
220 heightBehaviour.enabled = false268 heightBehaviour.enabled = false
269 if (categoryView.runMaximizeAfterSizeChanges > 0) {
270 categoryView.runMaximizeAfterSizeChanges--;
271 if (categoryView.runMaximizeAfterSizeChanges == 0) {
272 var firstCreated = categoryView.firstCreatedIndex();
273 for (var i = 0; i < categoryView.createdItemCount(); ++i) {
274 var baseItem = categoryView.item(firstCreated + i);
275 if (baseItem.category === categoryView.expandedCategoryId) {
276 categoryView.maximizeVisibleArea(firstCreated + i, baseItem.item.expandedHeight + baseItem.seeAllButton.height);
277 break;
278 }
279 }
280 }
281 }
221 }282 }
222 }283 }
223 }284 }
@@ -245,7 +306,7 @@
245 item.objectName = Qt.binding(function() { return categoryId })306 item.objectName = Qt.binding(function() { return categoryId })
246 item.scopeStyle = scopeView.scopeStyle;307 item.scopeStyle = scopeView.scopeStyle;
247 if (baseItem.expandable) {308 if (baseItem.expandable) {
248 var shouldExpand = baseItem === categoryView.expandedCategoryItem;309 var shouldExpand = baseItem.category === categoryView.expandedCategoryId;
249 baseItem.expand(shouldExpand, false /*animate*/);310 baseItem.expand(shouldExpand, false /*animate*/);
250 }311 }
251 updateDelegateCreationRange();312 updateDelegateCreationRange();
@@ -282,27 +343,6 @@
282 }343 }
283 Connections {344 Connections {
284 target: categoryView345 target: categoryView
285 onExpandedCategoryItemChanged: {
286 collapseAllButExpandedCategory();
287 }
288 function collapseAllButExpandedCategory() {
289 var item = rendererLoader.item;
290 if (baseItem.expandable) {
291 var shouldExpand = baseItem === categoryView.expandedCategoryItem;
292 if (shouldExpand != baseItem.expanded) {
293 // If the filter animation will be seen start it, otherwise, just flip the switch
294 var shrinkingVisible = !shouldExpand && y + item.collapsedHeight + seeAll.height < categoryView.height;
295 var growingVisible = shouldExpand && y + height < categoryView.height;
296 if (!subPageLoader.open || shouldExpand) {
297 var animate = shrinkingVisible || growingVisible;
298 baseItem.expand(shouldExpand, animate)
299 if (shouldExpand && !subPageLoader.open) {
300 categoryView.maximizeVisibleArea(index, item.expandedHeight + seeAll.height);
301 }
302 }
303 }
304 }
305 }
306 onOriginYChanged: rendererLoader.updateDelegateCreationRange();346 onOriginYChanged: rendererLoader.updateDelegateCreationRange();
307 onContentYChanged: rendererLoader.updateDelegateCreationRange();347 onContentYChanged: rendererLoader.updateDelegateCreationRange();
308 onHeightChanged: rendererLoader.updateDelegateCreationRange();348 onHeightChanged: rendererLoader.updateDelegateCreationRange();
@@ -352,10 +392,11 @@
352 height: seeAllLabel.visible ? seeAllLabel.font.pixelSize + units.gu(4) : 0392 height: seeAllLabel.visible ? seeAllLabel.font.pixelSize + units.gu(4) : 0
353393
354 onClicked: {394 onClicked: {
355 if (categoryView.expandedCategoryItem !== baseItem) {395 if (categoryView.expandedCategoryId !== baseItem.category) {
356 categoryView.expandedCategoryItem = baseItem;396 categoryView.expandedCategoryId = baseItem.category;
397 floatingSeeLess.companionBase = baseItem;
357 } else {398 } else {
358 categoryView.expandedCategoryItem = null;399 categoryView.expandedCategoryId = "";
359 }400 }
360 }401 }
361402
@@ -455,7 +496,7 @@
455 objectName: "floatingSeeLess"496 objectName: "floatingSeeLess"
456497
457 property Item companionTo: companionBase ? companionBase.seeAllButton : null498 property Item companionTo: companionBase ? companionBase.seeAllButton : null
458 property Item companionBase: categoryView.expandedCategoryItem499 property Item companionBase: null
459 property bool showBecausePosition: false500 property bool showBecausePosition: false
460 property real yOffset: 0501 property real yOffset: 0
461502
@@ -467,7 +508,7 @@
467 height: seeLessLabel.font.pixelSize + units.gu(4)508 height: seeLessLabel.font.pixelSize + units.gu(4)
468 visible: companionTo && showBecausePosition509 visible: companionTo && showBecausePosition
469510
470 onClicked: categoryView.expandedCategoryItem = null;511 onClicked: categoryView.expandedCategoryId = "";
471512
472 function updateVisibility() {513 function updateVisibility() {
473 var companionPos = companionTo.mapToItem(floatingSeeLess, 0, 0);514 var companionPos = companionTo.mapToItem(floatingSeeLess, 0, 0);
@@ -476,6 +517,10 @@
476 var posToBase = floatingSeeLess.mapToItem(companionBase, 0, -yOffset).y;517 var posToBase = floatingSeeLess.mapToItem(companionBase, 0, -yOffset).y;
477 yOffset = Math.max(0, companionBase.item.collapsedHeight - posToBase);518 yOffset = Math.max(0, companionBase.item.collapsedHeight - posToBase);
478 yOffset = Math.min(yOffset, height);519 yOffset = Math.min(yOffset, height);
520
521 if (!showBecausePosition && categoryView.expandedCategoryId === "") {
522 companionBase = null;
523 }
479 }524 }
480525
481 Label {526 Label {
482527
=== modified file 'tests/mocks/Unity/fake_categories.cpp'
--- tests/mocks/Unity/fake_categories.cpp 2014-08-15 14:21:42 +0000
+++ tests/mocks/Unity/fake_categories.cpp 2014-09-18 10:05:43 +0000
@@ -29,25 +29,12 @@
2929
30int Categories::rowCount(const QModelIndex& /*parent*/) const30int Categories::rowCount(const QModelIndex& /*parent*/) const
31{31{
32 return m_category_count + m_specialCategories.count();32 return m_category_count;
33}33}
3434
35void Categories::addSpecialCategory(QString const& categoryId, QString const& name, QString const& icon, QString const& rawTemplate, QObject* countObject)35void Categories::addSpecialCategory(QString const& /*categoryId*/, QString const& /*name*/, QString const& /*icon*/, QString const& /*rawTemplate*/, QObject* /*countObject*/)
36{36{
37 CategoryData catData;37 qFatal("Using un-implemented Categories::addSpecialCategory");
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 }
51}38}
5239
53bool Categories::overrideCategoryJson(QString const& /* categoryId */, QString const& /* json */)40bool Categories::overrideCategoryJson(QString const& /* categoryId */, QString const& /* json */)
@@ -55,23 +42,6 @@
55 qFatal("Using un-implemented Categories::overrideCategoryJson");42 qFatal("Using un-implemented Categories::overrideCategoryJson");
56}43}
5744
58void 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
75QVariant45QVariant
76Categories::data(const QModelIndex& index, int role) const46Categories::data(const QModelIndex& index, int role) const
77{47{
@@ -79,115 +49,74 @@
79 return QVariant();49 return QVariant();
80 }50 }
8151
82 ResultsModel *resultsModel = m_resultsModels[index.row()];52 ResultsModel *resultsModel = resultModel(index.row());
83 if (!resultsModel) {53 switch (role) {
84 resultsModel = new ResultsModel(15, index.row());54 case RoleCategoryId:
85 m_resultsModels[index.row()] = resultsModel;55 return QString("%1").arg(index.row());
86 }56 case RoleName:
87 if (index.row() < m_specialCategories.count()) {57 return QString("Category %1").arg(index.row());
88 const CategoryData &catData = m_specialCategories.at(index.row());58 case RoleIcon:
89 switch (role) {59 return "gtk-apply";
90 case RoleCategoryId:60 case RoleRawRendererTemplate:
91 return catData.categoryId;61 qFatal("Using un-implemented RoleRawRendererTemplate Categories role");
92 case RoleName:62 return QVariant();
93 return catData.name;63 case RoleRenderer:
94 case RoleIcon:64 {
95 return catData.icon;65 QVariantMap map;
96 case RoleRawRendererTemplate:66 if (index.row() % 2 == 0) {
97 return catData.rawTemplate;67 map["category-layout"] = "grid";
98 case RoleRenderer:68 } else {
99 {69 map["category-layout"] = "carousel";
100 QVariantMap map;70 }
101 if (index.row() % 2 == 0) {71 if (index.row() == 18) {
102 map["category-layout"] = "grid";72 map["category-layout"] = "horizontal-list";
103 } else {73 }
104 map["category-layout"] = "carousel";74 if (index.row() == 19) {
105 map["overlay"] = true;75 map["category-layout"] = "grid";
106 }76 map["collapsed-rows"] = 0;
107 map["card-size"] = "small";77 }
108 return map;78 map["card-size"] = "small";
109 }79
110 case RoleComponents:80 map["category-layout"] = m_layouts.value(index.row(), map["category-layout"].toString());
111 {81
112 QVariantMap map, artMap, attributeMap;82 if (map["category-layout"] == "carousel") {
83 map["overlay"] = true;
84 }
85
86 return map;
87 }
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 {
113 artMap["aspect-ratio"] = "1.0";94 artMap["aspect-ratio"] = "1.0";
114 artMap["field"] = "art";95 }
115 map["art"] = artMap;96 artMap["field"] = "art";
116 map["title"] = "HOLA";97 map["art"] = artMap;
117 attributeMap["field"] = "attribute";98 map["title"] = "HOLA";
118 map["attributes"] = attributeMap;99 map["subtitle"] = "HOLA";
119 return map;100 attributeMap["field"] = "attribute";
120 }101 map["attributes"] = attributeMap;
121 case RoleHeaderLink:102 return map;
122 return QString();103 }
123 case RoleResults:104 case RoleHeaderLink:
124 return QVariant();105 {
125 case RoleCount:106 QString res;
126 return catData.countObject->property("count");107 if (index.row() == 1 || index.row() == 4) {
127 default:108 res = QString("scope://query/1");
128 qFatal("Using un-implemented Categories role");109 }
129 return QVariant();110 res = m_headerLinks.value(index.row(), res);
130 }111 return res;
131 } else {112 }
132 switch (role) {113 case RoleResults:
133 case RoleCategoryId:114 return QVariant::fromValue(resultsModel);
134 return QString("%1").arg(index.row());115 case RoleCount:
135 case RoleName:116 return resultsModel->rowCount();
136 return QString("Category %1").arg(index.row());117 default:
137 case RoleIcon:118 qFatal("Using un-implemented Categories role");
138 return "gtk-apply";119 return QVariant();
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;
161 }
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;
177 }
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();
190 }
191 }120 }
192}121}
193122
@@ -196,3 +125,33 @@
196{125{
197 return data(index(row, 0), role);126 return data(index(row, 0), role);
198}127}
128
129void 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
138ResultsModel* 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
149void Categories::setLayout(int row, const QString &layout)
150{
151 m_layouts[row] = layout;
152}
153
154void Categories::setHeaderLink(int row, const QString &headerLink)
155{
156 m_headerLinks[row] = headerLink;
157}
199158
=== modified file 'tests/mocks/Unity/fake_categories.h'
--- tests/mocks/Unity/fake_categories.h 2014-07-11 16:39:33 +0000
+++ tests/mocks/Unity/fake_categories.h 2014-09-18 10:05:43 +0000
@@ -39,22 +39,17 @@
3939
40 Q_INVOKABLE QVariant data(int row, int role) const;40 Q_INVOKABLE QVariant data(int row, int role) const;
4141
42private Q_SLOTS:42 // For testing purposes
43 void countChanged();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
45private:48private:
46 mutable QHash<int, ResultsModel*> m_resultsModels;49 mutable QHash<int, ResultsModel*> m_resultsModels;
50 QHash<int, QString> m_layouts;
51 QHash<int, QString> m_headerLinks;
47 int m_category_count;52 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;
58};53};
5954
60#endif // FAKE_CATEGORIES_H55#endif // FAKE_CATEGORIES_H
6156
=== modified file 'tests/mocks/Unity/fake_resultsmodel.cpp'
--- tests/mocks/Unity/fake_resultsmodel.cpp 2014-08-13 16:06:40 +0000
+++ tests/mocks/Unity/fake_resultsmodel.cpp 2014-09-18 10:05:43 +0000
@@ -44,6 +44,15 @@
44 qFatal("Calling un-implemented ResultsModel::setCategoryId");44 qFatal("Calling un-implemented ResultsModel::setCategoryId");
45}45}
4646
47void 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
47int ResultsModel::rowCount(const QModelIndex& parent) const56int ResultsModel::rowCount(const QModelIndex& parent) const
48{57{
49 Q_UNUSED(parent);58 Q_UNUSED(parent);
5059
=== modified file 'tests/mocks/Unity/fake_resultsmodel.h'
--- tests/mocks/Unity/fake_resultsmodel.h 2014-08-11 09:57:29 +0000
+++ tests/mocks/Unity/fake_resultsmodel.h 2014-09-18 10:05:43 +0000
@@ -41,6 +41,9 @@
41 /* setters */41 /* setters */
42 void setCategoryId(QString const& id) override;42 void setCategoryId(QString const& id) override;
4343
44 // For testing purposes
45 Q_INVOKABLE void setResultCount(int result_count);
46
44private:47private:
45 int m_result_count;48 int m_result_count;
46 int m_categoryId;49 int m_categoryId;
4750
=== modified file 'tests/mocks/Unity/fake_scope.cpp'
--- tests/mocks/Unity/fake_scope.cpp 2014-08-27 08:01:40 +0000
+++ tests/mocks/Unity/fake_scope.cpp 2014-09-18 10:05:43 +0000
@@ -145,6 +145,23 @@
145 Q_EMIT favoriteChanged();145 Q_EMIT favoriteChanged();
146 }146 }
147}147}
148
149void Scope::setId(const QString &id)
150{
151 if (id != m_id) {
152 m_id = id;
153 Q_EMIT idChanged();
154 }
155}
156
157void Scope::setName(const QString &name)
158{
159 if (name != m_name) {
160 m_name = name;
161 Q_EMIT nameChanged();
162 }
163}
164
148void Scope::setSearchInProgress(const bool inProg)165void Scope::setSearchInProgress(const bool inProg)
149{166{
150 if (inProg != m_searching) {167 if (inProg != m_searching) {
151168
=== modified file 'tests/mocks/Unity/fake_scope.h'
--- tests/mocks/Unity/fake_scope.h 2014-08-12 12:09:49 +0000
+++ tests/mocks/Unity/fake_scope.h 2014-09-18 10:05:43 +0000
@@ -56,6 +56,8 @@
56 void setFormFactor(const QString& form_factor) override;56 void setFormFactor(const QString& form_factor) override;
57 void setActive(const bool) override;57 void setActive(const bool) override;
58 void setFavorite(const bool) override;58 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
59 Q_INVOKABLE void setSearchInProgress(const bool inProg); // This is not invokable in the Interface, here for testing benefits61 Q_INVOKABLE void setSearchInProgress(const bool inProg); // This is not invokable in the Interface, here for testing benefits
6062
61 Q_INVOKABLE void activate(QVariant const& result) override;63 Q_INVOKABLE void activate(QVariant const& result) override;
6264
=== modified file 'tests/qmltests/Dash/tst_GenericScopeView.qml'
--- tests/qmltests/Dash/tst_GenericScopeView.qml 2014-08-26 19:25:41 +0000
+++ tests/qmltests/Dash/tst_GenericScopeView.qml 2014-09-18 10:05:43 +0000
@@ -1,5 +1,5 @@
1/*1/*
2 * Copyright 2013 Canonical Ltd.2 * Copyright 2014 Canonical Ltd.
3 *3 *
4 * This program is free software; you can redistribute it and/or modify4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by5 * it under the terms of the GNU General Public License as published by
@@ -43,6 +43,10 @@
43 onLoadedChanged: if (loaded) genericScopeView.scope = scopes.getScope(2);43 onLoadedChanged: if (loaded) genericScopeView.scope = scopes.getScope(2);
44 }44 }
4545
46 MockScope {
47 id: mockScope
48 }
49
46 SignalSpy {50 SignalSpy {
47 id: spy51 id: spy
48 }52 }
@@ -92,6 +96,17 @@
92 return findChild(genericScopeView, category);96 return findChild(genericScopeView, category);
93 }97 }
9498
99 function scrollToEnd()
100 {
101 var categoryListView = findChild(genericScopeView, "categoryListView");
102 waitForRendering(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 }
108 }
109
95 function test_isActive() {110 function test_isActive() {
96 tryCompare(genericScopeView.scope, "isActive", false)111 tryCompare(genericScopeView.scope, "isActive", false)
97 genericScopeView.isCurrent = true112 genericScopeView.isCurrent = true
@@ -426,6 +441,87 @@
426 compare(image.source, data.logo, "Title image has the wrong source");441 compare(image.source, data.logo, "Title image has the wrong source");
427 }442 }
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
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
429 function test_favorite_data() {525 function test_favorite_data() {
430 return [526 return [
431 { tag: "People", id: "MockScope1", favorite: true },527 { tag: "People", id: "MockScope1", favorite: true },

Subscribers

People subscribed via source and target branches