Merge lp:~unity-team/unity8/two_see_more_bugfix into lp:unity8
- two_see_more_bugfix
- Merge into trunk
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 |
Related bugs: |
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/
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
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:1182
http://
Executed test runs:
FAILURE: http://
UNSTABLE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:1183
http://
Executed test runs:
FAILURE: http://
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:1183
http://
Executed test runs:
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:1184
http://
Executed test runs:
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:1185
http://
Executed test runs:
FAILURE: http://
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:1186
http://
Executed test runs:
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:1187
http://
Executed test runs:
FAILURE: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Michael Zanetti (mzanetti) wrote : | # |
Some minor things inline, seems to work fine.
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.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:1190
http://
Executed test runs:
FAILURE: http://
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Michael Zanetti (mzanetti) wrote : | # |
seems to fail a test now :/
Michał Sawicz (saviq) wrote : | # |
> seems to fail a test now :/
Yeah, and I can't reproduce locally. Albert, back to you...
Albert Astals Cid (aacid) : | # |
- 1191. By Albert Astals Cid
-
Try to make LVWPH to behave consistently
doubles are not fun
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:1191
http://
Executed test runs:
FAILURE: http://
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Albert Astals Cid (aacid) wrote : | # |
The crash in testDashContent is fixed by https:/
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:1191
http://
Executed test runs:
FAILURE: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
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
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://
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
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. :)
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:1192
http://
Executed test runs:
FAILURE: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Preview Diff
1 | === modified file 'plugins/Dash/listviewwithpageheader.cpp' |
2 | --- plugins/Dash/listviewwithpageheader.cpp 2014-09-01 10:45:25 +0000 |
3 | +++ plugins/Dash/listviewwithpageheader.cpp 2014-09-18 10:05:43 +0000 |
4 | @@ -409,6 +409,16 @@ |
5 | } |
6 | } |
7 | |
8 | +int ListViewWithPageHeader::firstCreatedIndex() const |
9 | +{ |
10 | + return m_firstVisibleIndex; |
11 | +} |
12 | + |
13 | +int ListViewWithPageHeader::createdItemCount() const |
14 | +{ |
15 | + return m_visibleItems.count(); |
16 | +} |
17 | + |
18 | QQuickItem *ListViewWithPageHeader::item(int modelIndex) const |
19 | { |
20 | ListItem *item = itemAtIndex(modelIndex); |
21 | @@ -520,7 +530,7 @@ |
22 | // (but the header was not shown by it's own position) |
23 | // or the header is partially shown and we are not doing a maximizeVisibleArea either |
24 | const bool scrolledUp = m_previousContentY > contentY(); |
25 | - const bool notRebounding = contentY() + height() < contentHeight(); |
26 | + const bool notRebounding = qRound(contentY() + height()) < qRound(contentHeight()); |
27 | const bool notShownByItsOwn = contentY() + diff >= m_headerItem->y() + m_headerItem->height(); |
28 | const bool maximizeVisibleAreaRunning = m_contentYAnimation->isRunning() && contentYAnimationType == ContentYAnimationMaximizeVisibleArea; |
29 | |
30 | |
31 | === modified file 'plugins/Dash/listviewwithpageheader.h' |
32 | --- plugins/Dash/listviewwithpageheader.h 2014-09-01 10:45:25 +0000 |
33 | +++ plugins/Dash/listviewwithpageheader.h 2014-09-18 10:05:43 +0000 |
34 | @@ -86,6 +86,8 @@ |
35 | |
36 | Q_INVOKABLE void positionAtBeginning(); |
37 | Q_INVOKABLE void showHeader(); |
38 | + Q_INVOKABLE int firstCreatedIndex() const; |
39 | + Q_INVOKABLE int createdItemCount() const; |
40 | Q_INVOKABLE QQuickItem *item(int modelIndex) const; |
41 | |
42 | // The index has to be created for this to try to do something |
43 | |
44 | === modified file 'qml/Dash/GenericScopeView.qml' |
45 | --- qml/Dash/GenericScopeView.qml 2014-09-08 14:15:01 +0000 |
46 | +++ qml/Dash/GenericScopeView.qml 2014-09-18 10:05:43 +0000 |
47 | @@ -47,6 +47,10 @@ |
48 | |
49 | signal backClicked() |
50 | |
51 | + onScopeChanged: { |
52 | + floatingSeeLess.companionBase = null; |
53 | + } |
54 | + |
55 | function positionAtBeginning() { |
56 | categoryView.positionAtBeginning() |
57 | } |
58 | @@ -152,11 +156,54 @@ |
59 | forceNoClip: subPageLoader.open |
60 | pixelAligned: true |
61 | |
62 | - property Item expandedCategoryItem: null |
63 | + property string expandedCategoryId: "" |
64 | + property int runMaximizeAfterSizeChanges: 0 |
65 | |
66 | readonly property bool pageHeaderTotallyVisible: scopeView.showPageHeader && |
67 | ((headerItemShownHeight == 0 && categoryView.contentY <= categoryView.originY) || (headerItemShownHeight == pageHeaderLoader.item.height)) |
68 | |
69 | + onExpandedCategoryIdChanged: { |
70 | + var firstCreated = firstCreatedIndex(); |
71 | + var shrinkingAny = false; |
72 | + var shrinkHeightDifference = 0; |
73 | + for (var i = 0; i < createdItemCount(); ++i) { |
74 | + var baseItem = item(firstCreated + i); |
75 | + if (baseItem.expandable) { |
76 | + var shouldExpand = baseItem.category === expandedCategoryId; |
77 | + if (shouldExpand != baseItem.expanded) { |
78 | + var animate = false; |
79 | + if (!subPageLoader.open) { |
80 | + var animateShrinking = !shouldExpand && baseItem.y + baseItem.item.collapsedHeight + baseItem.seeAllButton.height < categoryView.height; |
81 | + var animateGrowing = shouldExpand && baseItem.y + baseItem.height < categoryView.height; |
82 | + animate = shrinkingAny || animateShrinking || animateGrowing; |
83 | + } |
84 | + |
85 | + if (!shouldExpand) { |
86 | + shrinkingAny = true; |
87 | + shrinkHeightDifference = baseItem.item.expandedHeight - baseItem.item.collapsedHeight; |
88 | + } |
89 | + |
90 | + if (shouldExpand && !subPageLoader.open) { |
91 | + if (!shrinkingAny) { |
92 | + categoryView.maximizeVisibleArea(firstCreated + i, baseItem.item.expandedHeight + baseItem.seeAllButton.height); |
93 | + } else { |
94 | + // If the space that shrinking is smaller than the one we need to grow we'll call maximizeVisibleArea |
95 | + // after the shrink/grow animation ends |
96 | + var growHeightDifference = baseItem.item.expandedHeight - baseItem.item.collapsedHeight; |
97 | + if (growHeightDifference > shrinkHeightDifference) { |
98 | + runMaximizeAfterSizeChanges = 2; |
99 | + } else { |
100 | + runMaximizeAfterSizeChanges = 0; |
101 | + } |
102 | + } |
103 | + } |
104 | + |
105 | + baseItem.expand(shouldExpand, animate); |
106 | + } |
107 | + } |
108 | + } |
109 | + } |
110 | + |
111 | delegate: ListItems.Base { |
112 | id: baseItem |
113 | objectName: "dashCategory" + category |
114 | @@ -194,7 +241,7 @@ |
115 | // This can happen with the VJ that doesn't know how height it will be on creation |
116 | // so doesn't set expandable until a bit too late for onLoaded |
117 | if (expandable) { |
118 | - var shouldExpand = baseItem === categoryView.expandedCategoryItem; |
119 | + var shouldExpand = baseItem.category === categoryView.expandedCategoryId; |
120 | baseItem.expand(shouldExpand, false /*animate*/); |
121 | } |
122 | } |
123 | @@ -215,9 +262,23 @@ |
124 | id: heightBehaviour |
125 | enabled: false |
126 | animation: UbuntuNumberAnimation { |
127 | + duration: UbuntuAnimation.FastDuration |
128 | onRunningChanged: { |
129 | if (!running) { |
130 | heightBehaviour.enabled = false |
131 | + if (categoryView.runMaximizeAfterSizeChanges > 0) { |
132 | + categoryView.runMaximizeAfterSizeChanges--; |
133 | + if (categoryView.runMaximizeAfterSizeChanges == 0) { |
134 | + var firstCreated = categoryView.firstCreatedIndex(); |
135 | + for (var i = 0; i < categoryView.createdItemCount(); ++i) { |
136 | + var baseItem = categoryView.item(firstCreated + i); |
137 | + if (baseItem.category === categoryView.expandedCategoryId) { |
138 | + categoryView.maximizeVisibleArea(firstCreated + i, baseItem.item.expandedHeight + baseItem.seeAllButton.height); |
139 | + break; |
140 | + } |
141 | + } |
142 | + } |
143 | + } |
144 | } |
145 | } |
146 | } |
147 | @@ -245,7 +306,7 @@ |
148 | item.objectName = Qt.binding(function() { return categoryId }) |
149 | item.scopeStyle = scopeView.scopeStyle; |
150 | if (baseItem.expandable) { |
151 | - var shouldExpand = baseItem === categoryView.expandedCategoryItem; |
152 | + var shouldExpand = baseItem.category === categoryView.expandedCategoryId; |
153 | baseItem.expand(shouldExpand, false /*animate*/); |
154 | } |
155 | updateDelegateCreationRange(); |
156 | @@ -282,27 +343,6 @@ |
157 | } |
158 | Connections { |
159 | target: categoryView |
160 | - onExpandedCategoryItemChanged: { |
161 | - collapseAllButExpandedCategory(); |
162 | - } |
163 | - function collapseAllButExpandedCategory() { |
164 | - var item = rendererLoader.item; |
165 | - if (baseItem.expandable) { |
166 | - var shouldExpand = baseItem === categoryView.expandedCategoryItem; |
167 | - if (shouldExpand != baseItem.expanded) { |
168 | - // If the filter animation will be seen start it, otherwise, just flip the switch |
169 | - var shrinkingVisible = !shouldExpand && y + item.collapsedHeight + seeAll.height < categoryView.height; |
170 | - var growingVisible = shouldExpand && y + height < categoryView.height; |
171 | - if (!subPageLoader.open || shouldExpand) { |
172 | - var animate = shrinkingVisible || growingVisible; |
173 | - baseItem.expand(shouldExpand, animate) |
174 | - if (shouldExpand && !subPageLoader.open) { |
175 | - categoryView.maximizeVisibleArea(index, item.expandedHeight + seeAll.height); |
176 | - } |
177 | - } |
178 | - } |
179 | - } |
180 | - } |
181 | onOriginYChanged: rendererLoader.updateDelegateCreationRange(); |
182 | onContentYChanged: rendererLoader.updateDelegateCreationRange(); |
183 | onHeightChanged: rendererLoader.updateDelegateCreationRange(); |
184 | @@ -352,10 +392,11 @@ |
185 | height: seeAllLabel.visible ? seeAllLabel.font.pixelSize + units.gu(4) : 0 |
186 | |
187 | onClicked: { |
188 | - if (categoryView.expandedCategoryItem !== baseItem) { |
189 | - categoryView.expandedCategoryItem = baseItem; |
190 | + if (categoryView.expandedCategoryId !== baseItem.category) { |
191 | + categoryView.expandedCategoryId = baseItem.category; |
192 | + floatingSeeLess.companionBase = baseItem; |
193 | } else { |
194 | - categoryView.expandedCategoryItem = null; |
195 | + categoryView.expandedCategoryId = ""; |
196 | } |
197 | } |
198 | |
199 | @@ -455,7 +496,7 @@ |
200 | objectName: "floatingSeeLess" |
201 | |
202 | property Item companionTo: companionBase ? companionBase.seeAllButton : null |
203 | - property Item companionBase: categoryView.expandedCategoryItem |
204 | + property Item companionBase: null |
205 | property bool showBecausePosition: false |
206 | property real yOffset: 0 |
207 | |
208 | @@ -467,7 +508,7 @@ |
209 | height: seeLessLabel.font.pixelSize + units.gu(4) |
210 | visible: companionTo && showBecausePosition |
211 | |
212 | - onClicked: categoryView.expandedCategoryItem = null; |
213 | + onClicked: categoryView.expandedCategoryId = ""; |
214 | |
215 | function updateVisibility() { |
216 | var companionPos = companionTo.mapToItem(floatingSeeLess, 0, 0); |
217 | @@ -476,6 +517,10 @@ |
218 | var posToBase = floatingSeeLess.mapToItem(companionBase, 0, -yOffset).y; |
219 | yOffset = Math.max(0, companionBase.item.collapsedHeight - posToBase); |
220 | yOffset = Math.min(yOffset, height); |
221 | + |
222 | + if (!showBecausePosition && categoryView.expandedCategoryId === "") { |
223 | + companionBase = null; |
224 | + } |
225 | } |
226 | |
227 | Label { |
228 | |
229 | === modified file 'tests/mocks/Unity/fake_categories.cpp' |
230 | --- tests/mocks/Unity/fake_categories.cpp 2014-08-15 14:21:42 +0000 |
231 | +++ tests/mocks/Unity/fake_categories.cpp 2014-09-18 10:05:43 +0000 |
232 | @@ -29,25 +29,12 @@ |
233 | |
234 | int Categories::rowCount(const QModelIndex& /*parent*/) const |
235 | { |
236 | - return m_category_count + m_specialCategories.count(); |
237 | + return m_category_count; |
238 | } |
239 | |
240 | -void Categories::addSpecialCategory(QString const& categoryId, QString const& name, QString const& icon, QString const& rawTemplate, QObject* countObject) |
241 | +void Categories::addSpecialCategory(QString const& /*categoryId*/, QString const& /*name*/, QString const& /*icon*/, QString const& /*rawTemplate*/, QObject* /*countObject*/) |
242 | { |
243 | - CategoryData catData; |
244 | - catData.categoryId = categoryId; |
245 | - catData.name = name; |
246 | - catData.icon = icon; |
247 | - catData.rawTemplate = rawTemplate; |
248 | - catData.countObject = countObject; |
249 | - |
250 | - beginInsertRows(QModelIndex(), 0, 0); |
251 | - m_specialCategories.prepend(catData); |
252 | - endInsertRows(); |
253 | - |
254 | - if (countObject) { |
255 | - connect(countObject, SIGNAL(countChanged()), this, SLOT(countChanged())); |
256 | - } |
257 | + qFatal("Using un-implemented Categories::addSpecialCategory"); |
258 | } |
259 | |
260 | bool Categories::overrideCategoryJson(QString const& /* categoryId */, QString const& /* json */) |
261 | @@ -55,23 +42,6 @@ |
262 | qFatal("Using un-implemented Categories::overrideCategoryJson"); |
263 | } |
264 | |
265 | -void Categories::countChanged() |
266 | -{ |
267 | - QObject* countObject = sender(); |
268 | - |
269 | - for (int i = 0; i < m_specialCategories.count(); ++i) { |
270 | - const CategoryData &catData = m_specialCategories.at(i); |
271 | - if (catData.countObject == countObject) { |
272 | - QVector<int> roles; |
273 | - roles.append(RoleCount); |
274 | - |
275 | - QModelIndex changedIndex(index(i)); |
276 | - dataChanged(changedIndex, changedIndex, roles); |
277 | - break; |
278 | - } |
279 | - } |
280 | -} |
281 | - |
282 | QVariant |
283 | Categories::data(const QModelIndex& index, int role) const |
284 | { |
285 | @@ -79,115 +49,74 @@ |
286 | return QVariant(); |
287 | } |
288 | |
289 | - ResultsModel *resultsModel = m_resultsModels[index.row()]; |
290 | - if (!resultsModel) { |
291 | - resultsModel = new ResultsModel(15, index.row()); |
292 | - m_resultsModels[index.row()] = resultsModel; |
293 | - } |
294 | - if (index.row() < m_specialCategories.count()) { |
295 | - const CategoryData &catData = m_specialCategories.at(index.row()); |
296 | - switch (role) { |
297 | - case RoleCategoryId: |
298 | - return catData.categoryId; |
299 | - case RoleName: |
300 | - return catData.name; |
301 | - case RoleIcon: |
302 | - return catData.icon; |
303 | - case RoleRawRendererTemplate: |
304 | - return catData.rawTemplate; |
305 | - case RoleRenderer: |
306 | - { |
307 | - QVariantMap map; |
308 | - if (index.row() % 2 == 0) { |
309 | - map["category-layout"] = "grid"; |
310 | - } else { |
311 | - map["category-layout"] = "carousel"; |
312 | - map["overlay"] = true; |
313 | - } |
314 | - map["card-size"] = "small"; |
315 | - return map; |
316 | - } |
317 | - case RoleComponents: |
318 | - { |
319 | - QVariantMap map, artMap, attributeMap; |
320 | + ResultsModel *resultsModel = resultModel(index.row()); |
321 | + switch (role) { |
322 | + case RoleCategoryId: |
323 | + return QString("%1").arg(index.row()); |
324 | + case RoleName: |
325 | + return QString("Category %1").arg(index.row()); |
326 | + case RoleIcon: |
327 | + return "gtk-apply"; |
328 | + case RoleRawRendererTemplate: |
329 | + qFatal("Using un-implemented RoleRawRendererTemplate Categories role"); |
330 | + return QVariant(); |
331 | + case RoleRenderer: |
332 | + { |
333 | + QVariantMap map; |
334 | + if (index.row() % 2 == 0) { |
335 | + map["category-layout"] = "grid"; |
336 | + } else { |
337 | + map["category-layout"] = "carousel"; |
338 | + } |
339 | + if (index.row() == 18) { |
340 | + map["category-layout"] = "horizontal-list"; |
341 | + } |
342 | + if (index.row() == 19) { |
343 | + map["category-layout"] = "grid"; |
344 | + map["collapsed-rows"] = 0; |
345 | + } |
346 | + map["card-size"] = "small"; |
347 | + |
348 | + map["category-layout"] = m_layouts.value(index.row(), map["category-layout"].toString()); |
349 | + |
350 | + if (map["category-layout"] == "carousel") { |
351 | + map["overlay"] = true; |
352 | + } |
353 | + |
354 | + return map; |
355 | + } |
356 | + case RoleComponents: |
357 | + { |
358 | + QVariantMap map, artMap, attributeMap; |
359 | + if (index.row() % 2 != 0) { |
360 | + artMap["aspect-ratio"] = QString("1.%1").arg(index.row()); |
361 | + } else { |
362 | artMap["aspect-ratio"] = "1.0"; |
363 | - artMap["field"] = "art"; |
364 | - map["art"] = artMap; |
365 | - map["title"] = "HOLA"; |
366 | - attributeMap["field"] = "attribute"; |
367 | - map["attributes"] = attributeMap; |
368 | - return map; |
369 | - } |
370 | - case RoleHeaderLink: |
371 | - return QString(); |
372 | - case RoleResults: |
373 | - return QVariant(); |
374 | - case RoleCount: |
375 | - return catData.countObject->property("count"); |
376 | - default: |
377 | - qFatal("Using un-implemented Categories role"); |
378 | - return QVariant(); |
379 | - } |
380 | - } else { |
381 | - switch (role) { |
382 | - case RoleCategoryId: |
383 | - return QString("%1").arg(index.row()); |
384 | - case RoleName: |
385 | - return QString("Category %1").arg(index.row()); |
386 | - case RoleIcon: |
387 | - return "gtk-apply"; |
388 | - case RoleRawRendererTemplate: |
389 | - qFatal("Using un-implemented RoleRawRendererTemplate Categories role"); |
390 | - return QVariant(); |
391 | - case RoleRenderer: |
392 | - { |
393 | - QVariantMap map; |
394 | - if (index.row() % 2 == 0) { |
395 | - map["category-layout"] = "grid"; |
396 | - } else { |
397 | - map["category-layout"] = "carousel"; |
398 | - map["card-size"] = "medium"; |
399 | - map["overlay"] = true; |
400 | - } |
401 | - if (index.row() == 18) { |
402 | - map["category-layout"] = "horizontal-list"; |
403 | - } |
404 | - if (index.row() == 19) { |
405 | - map["category-layout"] = "grid"; |
406 | - map["collapsed-rows"] = 0; |
407 | - } |
408 | - map["card-size"] = "small"; |
409 | - return map; |
410 | - } |
411 | - case RoleComponents: |
412 | - { |
413 | - QVariantMap map, artMap, attributeMap; |
414 | - if (index.row() % 2 != 0) { |
415 | - artMap["aspect-ratio"] = QString("1.%1").arg(index.row()); |
416 | - } else { |
417 | - artMap["aspect-ratio"] = "1.0"; |
418 | - } |
419 | - artMap["field"] = "art"; |
420 | - map["art"] = artMap; |
421 | - map["title"] = "HOLA"; |
422 | - map["subtitle"] = "HOLA"; |
423 | - attributeMap["field"] = "attribute"; |
424 | - map["attributes"] = attributeMap; |
425 | - return map; |
426 | - } |
427 | - case RoleHeaderLink: |
428 | - if (index.row() == 1 || index.row() == 4) { |
429 | - return QString("scope://query/1"); |
430 | - } |
431 | - return QString(); |
432 | - case RoleResults: |
433 | - return QVariant::fromValue(resultsModel); |
434 | - case RoleCount: |
435 | - return resultsModel->rowCount(); |
436 | - default: |
437 | - qFatal("Using un-implemented Categories role"); |
438 | - return QVariant(); |
439 | - } |
440 | + } |
441 | + artMap["field"] = "art"; |
442 | + map["art"] = artMap; |
443 | + map["title"] = "HOLA"; |
444 | + map["subtitle"] = "HOLA"; |
445 | + attributeMap["field"] = "attribute"; |
446 | + map["attributes"] = attributeMap; |
447 | + return map; |
448 | + } |
449 | + case RoleHeaderLink: |
450 | + { |
451 | + QString res; |
452 | + if (index.row() == 1 || index.row() == 4) { |
453 | + res = QString("scope://query/1"); |
454 | + } |
455 | + res = m_headerLinks.value(index.row(), res); |
456 | + return res; |
457 | + } |
458 | + case RoleResults: |
459 | + return QVariant::fromValue(resultsModel); |
460 | + case RoleCount: |
461 | + return resultsModel->rowCount(); |
462 | + default: |
463 | + qFatal("Using un-implemented Categories role"); |
464 | + return QVariant(); |
465 | } |
466 | } |
467 | |
468 | @@ -196,3 +125,33 @@ |
469 | { |
470 | return data(index(row, 0), role); |
471 | } |
472 | + |
473 | +void Categories::setCount(int count) |
474 | +{ |
475 | + if (m_category_count != count) { |
476 | + beginResetModel(); // This is just for test setup so we can be lazy and reset |
477 | + m_category_count = count; |
478 | + endResetModel(); |
479 | + } |
480 | +} |
481 | + |
482 | +ResultsModel* Categories::resultModel(int row) const |
483 | +{ |
484 | + ResultsModel *result = m_resultsModels[row]; |
485 | + if (!result) { |
486 | + Categories *that = const_cast<Categories*>(this); |
487 | + result = new ResultsModel(15, row, that); |
488 | + m_resultsModels[row] = result; |
489 | + } |
490 | + return result; |
491 | +} |
492 | + |
493 | +void Categories::setLayout(int row, const QString &layout) |
494 | +{ |
495 | + m_layouts[row] = layout; |
496 | +} |
497 | + |
498 | +void Categories::setHeaderLink(int row, const QString &headerLink) |
499 | +{ |
500 | + m_headerLinks[row] = headerLink; |
501 | +} |
502 | |
503 | === modified file 'tests/mocks/Unity/fake_categories.h' |
504 | --- tests/mocks/Unity/fake_categories.h 2014-07-11 16:39:33 +0000 |
505 | +++ tests/mocks/Unity/fake_categories.h 2014-09-18 10:05:43 +0000 |
506 | @@ -39,22 +39,17 @@ |
507 | |
508 | Q_INVOKABLE QVariant data(int row, int role) const; |
509 | |
510 | -private Q_SLOTS: |
511 | - void countChanged(); |
512 | + // For testing purposes |
513 | + Q_INVOKABLE void setCount(int count); |
514 | + Q_INVOKABLE ResultsModel* resultModel(int row) const; |
515 | + Q_INVOKABLE void setLayout(int row, const QString &layout); |
516 | + Q_INVOKABLE void setHeaderLink(int row, const QString &headerLink); |
517 | |
518 | private: |
519 | mutable QHash<int, ResultsModel*> m_resultsModels; |
520 | + QHash<int, QString> m_layouts; |
521 | + QHash<int, QString> m_headerLinks; |
522 | int m_category_count; |
523 | - |
524 | - struct CategoryData { |
525 | - QString categoryId; |
526 | - QString name; |
527 | - QString icon; |
528 | - QString rawTemplate; |
529 | - QObject* countObject; |
530 | - }; |
531 | - |
532 | - QList<CategoryData> m_specialCategories; |
533 | }; |
534 | |
535 | #endif // FAKE_CATEGORIES_H |
536 | |
537 | === modified file 'tests/mocks/Unity/fake_resultsmodel.cpp' |
538 | --- tests/mocks/Unity/fake_resultsmodel.cpp 2014-08-13 16:06:40 +0000 |
539 | +++ tests/mocks/Unity/fake_resultsmodel.cpp 2014-09-18 10:05:43 +0000 |
540 | @@ -44,6 +44,15 @@ |
541 | qFatal("Calling un-implemented ResultsModel::setCategoryId"); |
542 | } |
543 | |
544 | +void ResultsModel::setResultCount(int result_count) |
545 | +{ |
546 | + if (m_result_count != result_count) { |
547 | + beginResetModel(); // This is just for test setup so we can be lazy and reset |
548 | + m_result_count = result_count; |
549 | + endResetModel(); |
550 | + } |
551 | +} |
552 | + |
553 | int ResultsModel::rowCount(const QModelIndex& parent) const |
554 | { |
555 | Q_UNUSED(parent); |
556 | |
557 | === modified file 'tests/mocks/Unity/fake_resultsmodel.h' |
558 | --- tests/mocks/Unity/fake_resultsmodel.h 2014-08-11 09:57:29 +0000 |
559 | +++ tests/mocks/Unity/fake_resultsmodel.h 2014-09-18 10:05:43 +0000 |
560 | @@ -41,6 +41,9 @@ |
561 | /* setters */ |
562 | void setCategoryId(QString const& id) override; |
563 | |
564 | + // For testing purposes |
565 | + Q_INVOKABLE void setResultCount(int result_count); |
566 | + |
567 | private: |
568 | int m_result_count; |
569 | int m_categoryId; |
570 | |
571 | === modified file 'tests/mocks/Unity/fake_scope.cpp' |
572 | --- tests/mocks/Unity/fake_scope.cpp 2014-08-27 08:01:40 +0000 |
573 | +++ tests/mocks/Unity/fake_scope.cpp 2014-09-18 10:05:43 +0000 |
574 | @@ -145,6 +145,23 @@ |
575 | Q_EMIT favoriteChanged(); |
576 | } |
577 | } |
578 | + |
579 | +void Scope::setId(const QString &id) |
580 | +{ |
581 | + if (id != m_id) { |
582 | + m_id = id; |
583 | + Q_EMIT idChanged(); |
584 | + } |
585 | +} |
586 | + |
587 | +void Scope::setName(const QString &name) |
588 | +{ |
589 | + if (name != m_name) { |
590 | + m_name = name; |
591 | + Q_EMIT nameChanged(); |
592 | + } |
593 | +} |
594 | + |
595 | void Scope::setSearchInProgress(const bool inProg) |
596 | { |
597 | if (inProg != m_searching) { |
598 | |
599 | === modified file 'tests/mocks/Unity/fake_scope.h' |
600 | --- tests/mocks/Unity/fake_scope.h 2014-08-12 12:09:49 +0000 |
601 | +++ tests/mocks/Unity/fake_scope.h 2014-09-18 10:05:43 +0000 |
602 | @@ -56,6 +56,8 @@ |
603 | void setFormFactor(const QString& form_factor) override; |
604 | void setActive(const bool) override; |
605 | void setFavorite(const bool) override; |
606 | + Q_INVOKABLE void setId(const QString &id); // This is not invokable in the Interface, here for testing benefits |
607 | + Q_INVOKABLE void setName(const QString &name); // This is not invokable in the Interface, here for testing benefits |
608 | Q_INVOKABLE void setSearchInProgress(const bool inProg); // This is not invokable in the Interface, here for testing benefits |
609 | |
610 | Q_INVOKABLE void activate(QVariant const& result) override; |
611 | |
612 | === modified file 'tests/qmltests/Dash/tst_GenericScopeView.qml' |
613 | --- tests/qmltests/Dash/tst_GenericScopeView.qml 2014-08-26 19:25:41 +0000 |
614 | +++ tests/qmltests/Dash/tst_GenericScopeView.qml 2014-09-18 10:05:43 +0000 |
615 | @@ -1,5 +1,5 @@ |
616 | /* |
617 | - * Copyright 2013 Canonical Ltd. |
618 | + * Copyright 2014 Canonical Ltd. |
619 | * |
620 | * This program is free software; you can redistribute it and/or modify |
621 | * it under the terms of the GNU General Public License as published by |
622 | @@ -43,6 +43,10 @@ |
623 | onLoadedChanged: if (loaded) genericScopeView.scope = scopes.getScope(2); |
624 | } |
625 | |
626 | + MockScope { |
627 | + id: mockScope |
628 | + } |
629 | + |
630 | SignalSpy { |
631 | id: spy |
632 | } |
633 | @@ -92,6 +96,17 @@ |
634 | return findChild(genericScopeView, category); |
635 | } |
636 | |
637 | + function scrollToEnd() |
638 | + { |
639 | + var categoryListView = findChild(genericScopeView, "categoryListView"); |
640 | + waitForRendering(categoryListView); |
641 | + while (!categoryListView.atYEnd) { |
642 | + mouseFlick(genericScopeView, genericScopeView.width/2, genericScopeView.height - units.gu(8), |
643 | + genericScopeView.width/2, genericScopeView.y) |
644 | + tryCompare(categoryListView, "moving", false); |
645 | + } |
646 | + } |
647 | + |
648 | function test_isActive() { |
649 | tryCompare(genericScopeView.scope, "isActive", false) |
650 | genericScopeView.isCurrent = true |
651 | @@ -426,6 +441,87 @@ |
652 | compare(image.source, data.logo, "Title image has the wrong source"); |
653 | } |
654 | |
655 | + function test_seeAllTwoCategoriesScenario1() { |
656 | + mockScope.setId("mockScope"); |
657 | + mockScope.setName("Mock Scope"); |
658 | + mockScope.categories.setCount(2); |
659 | + mockScope.categories.resultModel(0).setResultCount(50); |
660 | + mockScope.categories.resultModel(1).setResultCount(15); |
661 | + mockScope.categories.setLayout(0, "grid"); |
662 | + mockScope.categories.setLayout(1, "grid"); |
663 | + mockScope.categories.setHeaderLink(0, ""); |
664 | + mockScope.categories.setHeaderLink(1, ""); |
665 | + genericScopeView.scope = mockScope; |
666 | + waitForRendering(genericScopeView.categoryView); |
667 | + |
668 | + var category0 = findChild(genericScopeView, "dashCategory0") |
669 | + var seeAll0 = findChild(category0, "seeAll") |
670 | + |
671 | + waitForRendering(seeAll0); |
672 | + verify(category0.expandable); |
673 | + verify(!category0.expanded); |
674 | + |
675 | + mouseClick(seeAll0, seeAll0.width / 2, seeAll0.height / 2); |
676 | + verify(category0.expanded); |
677 | + tryCompare(category0, "height", category0.item.expandedHeight + seeAll0.height); |
678 | + tryCompare(genericScopeView.categoryView, "contentY", units.gu(13.5)); |
679 | + |
680 | + scrollToEnd(); |
681 | + |
682 | + tryCompareFunction(function() { return findChild(genericScopeView, "dashCategory1") !== null; }, true); |
683 | + var category1 = findChild(genericScopeView, "dashCategory1") |
684 | + var seeAll1 = findChild(category1, "seeAll") |
685 | + verify(category1.expandable); |
686 | + verify(!category1.expanded); |
687 | + |
688 | + mouseClick(seeAll1, seeAll1.width / 2, seeAll1.height / 2); |
689 | + verify(!category0.expanded); |
690 | + verify(category1.expanded); |
691 | + tryCompare(category1, "height", category1.item.expandedHeight + seeAll1.height); |
692 | + tryCompareFunction(function() { |
693 | + return genericScopeView.categoryView.contentY + category1.y + category1.height |
694 | + == genericScopeView.categoryView.contentHeight;} |
695 | + , true); |
696 | + } |
697 | + |
698 | + function test_seeAllTwoCategoriesScenario2() { |
699 | + mockScope.setId("mockScope"); |
700 | + mockScope.setName("Mock Scope"); |
701 | + mockScope.categories.setCount(2); |
702 | + mockScope.categories.resultModel(0).setResultCount(15); |
703 | + mockScope.categories.resultModel(1).setResultCount(50); |
704 | + mockScope.categories.setLayout(0, "grid"); |
705 | + mockScope.categories.setLayout(1, "grid"); |
706 | + mockScope.categories.setHeaderLink(0, ""); |
707 | + mockScope.categories.setHeaderLink(1, ""); |
708 | + genericScopeView.scope = mockScope; |
709 | + waitForRendering(genericScopeView.categoryView); |
710 | + |
711 | + var category0 = findChild(genericScopeView, "dashCategory0") |
712 | + var seeAll0 = findChild(category0, "seeAll") |
713 | + |
714 | + waitForRendering(seeAll0); |
715 | + verify(category0.expandable); |
716 | + verify(!category0.expanded); |
717 | + |
718 | + mouseClick(seeAll0, seeAll0.width / 2, seeAll0.height / 2); |
719 | + verify(category0.expanded); |
720 | + tryCompare(category0, "height", category0.item.expandedHeight + seeAll0.height); |
721 | + |
722 | + scrollToEnd(); |
723 | + |
724 | + var category1 = findChild(genericScopeView, "dashCategory1") |
725 | + var seeAll1 = findChild(category1, "seeAll") |
726 | + verify(category1.expandable); |
727 | + verify(!category1.expanded); |
728 | + |
729 | + mouseClick(seeAll1, seeAll1.width / 2, seeAll1.height / 2); |
730 | + verify(!category0.expanded); |
731 | + verify(category1.expanded); |
732 | + tryCompare(category1, "height", category1.item.expandedHeight + seeAll1.height); |
733 | + tryCompare(category1, "y", units.gu(5)); |
734 | + } |
735 | + |
736 | function test_favorite_data() { |
737 | return [ |
738 | { tag: "People", id: "MockScope1", favorite: true }, |
FAILED: Continuous integration, rev:1181 jenkins. qa.ubuntu. com/job/ unity8- ci/4035/ jenkins. qa.ubuntu. com/job/ generic- deb-autopilot- utopic- touch/3816 jenkins. qa.ubuntu. com/job/ unity-phablet- qmluitests- utopic/ 1036 jenkins. qa.ubuntu. com/job/ unity8- utopic- amd64-ci/ 1129 jenkins. qa.ubuntu. com/job/ unity8- utopic- i386-ci/ 1129 jenkins. qa.ubuntu. com/job/ generic- deb-autopilot- runner- mako/3681 jenkins. qa.ubuntu. com/job/ generic- mediumtests- builder- utopic- armhf/5063 jenkins. qa.ubuntu. com/job/ generic- mediumtests- builder- utopic- armhf/5063/ artifact/ work/output/ *zip*/output. zip s-jenkins. ubuntu- ci:8080/ job/touch- flash-device/ 11798
http://
Executed test runs:
UNSTABLE: http://
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild: s-jenkins. ubuntu- ci:8080/ job/unity8- ci/4035/ rebuild
http://