on xenial help sign in
Drop FilterGrid and refactor height animations in GenericScopeView.

Also implement forced category expansion. Fixes: 1326470 Approved by: Michal Hruby, Michael Zanetti, Leo Arias, Albert Astals Cid

commitc7c13ef4d69deb85610b4c951cec3c257f00097a authorMichał Sawicz <michal.sawicz@canonical.com> dateThu 24 Jul 2014, 20:39 (12 years ago) parente92c697ea24351
18 files changed+176−447
qml/Components/FilterGrid.qml−124 qml/Components/ResponsiveGridView.qml+2−1 qml/Dash/CardCarousel.qml+2−7 qml/Dash/CardFilterGrid.qml → qml/Dash/CardGrid.qml+21−22 qml/Dash/CardVerticalJournal.qml+2−21 qml/Dash/DashRenderer.qml+2−11 qml/Dash/GenericScopeView.qml+53−27 tests/autopilot/unity8/shell/emulators/dash.py+9−3 tests/autopilot/unity8/shell/tests/test_emulators.py+15−5 tests/mocks/Unity/fake_categories.cpp+4−1 tests/mocks/Unity/fake_scope.cpp+2−2 tests/mocks/Unity/fake_scope.h+1−1 tests/mocks/Unity/fake_scopes.cpp+1 tests/qmltests/CMakeLists.txt−1 tests/qmltests/Components/tst_FilterGrid.qml−190 tests/qmltests/Dash/tst_Dash.qml+1−1 tests/qmltests/Dash/tst_DashContent.qml+15−6 tests/qmltests/Dash/tst_GenericScopeView.qml+46−24
qml/Components/FilterGrid.qmldeleted−124
@@ -1,124 +0,0 @@
1−/*
2− * Copyright (C) 2013 Canonical, Ltd.
3− *
4− * 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 by
6− * the Free Software Foundation; version 3.
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 General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− */
16−
17−import QtQuick 2.0
18−import Ubuntu.Components 0.1
19−import Utils 0.1
20−import "../Components"
21−
22−/*
23− A ResponsiveGridView that can optionally have the number of rows being displayed
24− reduced to collapsedRowCount, in which case a button saying "View all (123)"
25− will be shown at the bottom. If clicked, FilterGrid will them expand vertically
26− to display all rows.
27− */
28−Item {
29− id: root
30−
31− /* Whether, when collapsed, a button should be displayed enabling the user to expand
32− the grid to its full size. */
33− readonly property bool expandable: model.count > rowsWhenCollapsed * iconTileGrid.columns
34−
35− property var model: null
36−
37− /* Maximum number of rows to be show when filter=true. */
38− property int collapsedRowCount: 2
39− property int uncollapsedRowCount: Math.ceil(model.count / columns)
40− /* Never show more rows than model would fill up. */
41− readonly property int rowsWhenCollapsed: Math.min(collapsedRowCount, uncollapsedRowCount)
42− readonly property int collapsedHeight: iconTileGrid.contentHeightForRows(rowsWhenCollapsed)
43− readonly property int uncollapsedHeight: iconTileGrid.contentHeightForRows(uncollapsedRowCount)
44−
45− property alias minimumHorizontalSpacing: iconTileGrid.minimumHorizontalSpacing
46− property alias maximumNumberOfColumns: iconTileGrid.maximumNumberOfColumns
47− property alias columns: iconTileGrid.columns
48− property alias delegateWidth: iconTileGrid.delegateWidth
49− property alias delegateHeight: iconTileGrid.delegateHeight
50− property alias verticalSpacing: iconTileGrid.verticalSpacing
51− readonly property alias margins: iconTileGrid.margins
52− property alias delegate: iconTileGrid.delegate
53− property alias cellWidth: iconTileGrid.cellWidth
54− property alias cellHeight: iconTileGrid.cellHeight
55− property alias displayMarginBeginning: iconTileGrid.displayMarginBeginning
56− property alias displayMarginEnd: iconTileGrid.displayMarginEnd
57− readonly property alias originY: iconTileGrid.originY
58− readonly property alias flicking: iconTileGrid.flicking
59− readonly property alias moving: iconTileGrid.moving
60− readonly property alias pressDelay: iconTileGrid.pressDelay
61− property alias highlightIndex: iconTileGrid.highlightIndex
62− readonly property alias currentItem: iconTileGrid.currentItem
63− readonly property alias filtered: d.filter
64−
65− QtObject {
66− id: d
67− // We do have filter and collapsed properties because we need to decouple
68− // the real filtering with the animation since the closing animation
69− // i.e. setFilter(false. true) we still need to not be filtering until
70− // the animation finishes otherwise we hide the items when the animation
71− // is still running
72− property bool filter: true
73− property bool collapsed: true
74− }
75−
76− height: d.collapsed ? root.collapsedHeight : root.uncollapsedHeight
77− clip: filterAnimation.running
78−
79− Behavior on height {
80− id: heightBehaviour
81− enabled: false
82− NumberAnimation {
83− id: filterAnimation
84− // Duration and easing here match the ListViewWithPageHeader::m_contentYAnimation
85− // otherwise since both animations can run at the same time you'll get
86− // some visual weirdness.
87− duration: 200
88− easing.type: Easing.InOutQuad
89− onRunningChanged: {
90− if (!running) {
91− d.filter = d.collapsed;
92− }
93− heightBehaviour.enabled = false;
94− }
95− }
96− }
97−
98− function setFilter(filter, animate) {
99− heightBehaviour.enabled = animate;
100− d.collapsed = filter;
101− if (!animate || !filter) {
102− d.filter = filter;
103− }
104− }
105−
106− ResponsiveGridView {
107− id: iconTileGrid
108−
109− anchors { left: parent.left; right: parent.right }
110− height: totalContentHeight
111− interactive: false
112−
113− minimumHorizontalSpacing: units.gu(0.5)
114− maximumNumberOfColumns: 6
115− delegateWidth: units.gu(11)
116− delegateHeight: units.gu(9.5)
117− verticalSpacing: units.gu(2)
118−
119− model: LimitProxyModel {
120− model: root.model
121− limit: d.filter ? rowsWhenCollapsed * iconTileGrid.columns : -1
122− }
123− }
124−}
qml/Components/ResponsiveGridView.qml+2−1
@@ -44,10 +44,11 @@ Item {
4444 property alias displayMarginBeginning: gridView.displayMarginBeginning
4545 property alias displayMarginEnd: gridView.displayMarginEnd
4646 property alias highlightIndex: gridView.highlightIndex
47+ property alias cacheBuffer: gridView.cacheBuffer
4748 readonly property alias currentItem: gridView.currentItem
4849
4950 function contentHeightForRows(rows) {
50− return rows * cellHeight + verticalSpacing
51+ return rows * cellHeight;
5152 }
5253
5354 GridView {
qml/Dash/CardCarousel.qml+2−7
@@ -21,13 +21,8 @@ import "../Components"
2121DashRenderer {
2222 id: cardCarousel
2323
24− property alias cacheBuffer: carousel.cacheBuffer
25− property alias itemComponent: carousel.itemComponent
26− property alias minimumTileWidth: carousel.minimumTileWidth
27− property alias selectedItemScaleFactor: carousel.selectedItemScaleFactor
28− property alias tileAspectRatio: carousel.tileAspectRatio
29−
30− height: carousel.implicitHeight + units.gu(6)
24+ expandedHeight: carousel.implicitHeight + units.gu(6)
25+ collapsedHeight: expandedHeight
3126
3227 Carousel {
3328 id: carousel
qml/Dash/CardFilterGrid.qml → qml/Dash/CardGrid.qmlrenamed+21−22
@@ -18,33 +18,32 @@ import QtQuick 2.0
1818import "../Components"
1919
2020DashRenderer {
21− id: genericFilterGrid
21+ id: root
2222
23− expandable: filterGrid.expandable
24− collapsedHeight: filterGrid.collapsedHeight
25− uncollapsedHeight: filterGrid.uncollapsedHeight
26− originY: filterGrid.originY
27− height: filterGrid.height
28− filtered: filterGrid.filtered
29−
30− function setFilter(filter, animate) {
31− filterGrid.setFilter(filter, animate)
23+ readonly property int collapsedRows: {
24+ if (!cardTool || !cardTool.template || typeof cardTool.template["collapsed-rows"] != "number") return 2;
25+ return cardTool.template["collapsed-rows"];
3226 }
3327
34− FilterGrid {
35− id: filterGrid
36− width: genericFilterGrid.width
28+ expandedHeight: grid.totalContentHeight
29+ collapsedHeight: Math.min(grid.contentHeightForRows(collapsedRows), expandedHeight)
30+ originY: grid.originY
31+
32+ ResponsiveGridView {
33+ id: grid
34+ anchors.fill: parent
3735 minimumHorizontalSpacing: units.gu(1)
3836 delegateWidth: cardTool.cardWidth
3937 delegateHeight: cardTool.cardHeight
4038 verticalSpacing: units.gu(1)
41− model: genericFilterGrid.model
42− collapsedRowCount: Math.min(2, cardTool && cardTool.template && cardTool.template["collapsed-rows"] || 2)
43− displayMarginBeginning: genericFilterGrid.displayMarginBeginning
44− displayMarginEnd: genericFilterGrid.displayMarginEnd
39+ model: root.model
40+ displayMarginBeginning: root.displayMarginBeginning
41+ displayMarginEnd: root.displayMarginEnd
42+ cacheBuffer: 0
43+ interactive: false
4544 delegate: Item {
46− width: filterGrid.cellWidth
47− height: filterGrid.cellHeight
45+ width: grid.cellWidth
46+ height: grid.cellHeight
4847 Loader {
4948 id: loader
5049 sourceComponent: cardTool.cardComponent
@@ -58,12 +57,12 @@ DashRenderer {
5857 item.template = Qt.binding(function() { return cardTool.template; });
5958 item.components = Qt.binding(function() { return cardTool.components; });
6059 item.headerAlignment = Qt.binding(function() { return cardTool.headerAlignment; });
61− item.scopeStyle = genericFilterGrid.scopeStyle;
60+ item.scopeStyle = root.scopeStyle;
6261 }
6362 Connections {
6463 target: loader.item
65− onClicked: genericFilterGrid.clicked(index, result)
66− onPressAndHold: genericFilterGrid.pressAndHold(index)
64+ onClicked: root.clicked(index, result)
65+ onPressAndHold: root.pressAndHold(index)
6766 }
6867 }
6968 }
qml/Dash/CardVerticalJournal.qml+2−21
@@ -23,33 +23,14 @@ DashRenderer {
2323
2424 readonly property double collapseLimit: units.gu(35)
2525
26− uncollapsedHeight: cardVerticalJournal.implicitHeight
27− collapsedHeight: Math.min(collapseLimit, cardVerticalJournal.implicitHeight)
28− expandable: uncollapsedHeight > collapseLimit
26+ expandedHeight: Math.max(cardVerticalJournal.implicitHeight, minHeight)
27+ collapsedHeight: Math.max(Math.min(collapseLimit, cardVerticalJournal.implicitHeight), minHeight)
2928
3029 // This minHeight is used as bootstrapper for the height. Vertical Journal
3130 // is special by the fact that it doesn't know how to calculate its implicit height unless we give it
3231 // enough height that it can start creating its children so we make sure it has enough height for that
3332 // in case the model is non empty
3433 readonly property double minHeight: root.model.count >= 1 ? cardVerticalJournal.rowSpacing + 1 : 0
35− height: filtered ? Math.max(collapsedHeight, minHeight) : uncollapsedHeight
36−
37− Behavior on height {
38− id: heightBehaviour
39− enabled: false
40− animation: UbuntuNumberAnimation {
41− onRunningChanged: {
42− if (!running) {
43− heightBehaviour.enabled = false
44− }
45− }
46− }
47− }
48−
49− function setFilter(filter, animate) {
50− heightBehaviour.enabled = animate;
51− filtered = filter;
52− }
5334
5435 ResponsiveVerticalJournal {
5536 id: cardVerticalJournal
qml/Dash/DashRenderer.qml+2−11
@@ -17,15 +17,9 @@
1717import QtQuick 2.0
1818
1919Item {
20− // Can the item be expanded?
21− property bool expandable: false
20+ property int collapsedHeight
2221
23− // In case it can be expanded, is it filtered
24− property bool filtered: true
25−
26− property int collapsedHeight: height
27−
28− property int uncollapsedHeight: height
22+ property int expandedHeight
2923
3024 property int displayMarginBeginning: 0
3125
@@ -50,7 +44,4 @@ Item {
5044 /// Emitted when the user pressed and held on an item
5145 /// @param index is the index of the held item
5246 signal pressAndHold(int index)
53−
54− function setFilter(filter, animate) {
55− }
5647}
qml/Dash/GenericScopeView.qml+53−27
@@ -119,6 +119,7 @@ FocusScope {
119119
120120 model: scopeView.categories
121121 forceNoClip: previewListView.open
122+ pixelAligned: true
122123
123124 property string expandedCategoryId: ""
124125
@@ -128,11 +129,21 @@ FocusScope {
128129 highlightWhenPressed: false
129130 showDivider: false
130131
131− readonly property bool expandable: rendererLoader.item ? rendererLoader.item.expandable : false
132− readonly property bool filtered: rendererLoader.item ? rendererLoader.item.filtered : true
132+ readonly property bool expandable: {
133+ if (categoryView.model.count === 1) return false;
134+ if (cardTool.template && cardTool.template["collapsed-rows"] === 0) return false;
135+ if (item && item.expandedHeight > item.collapsedHeight) return true;
136+ return false;
137+ }
138+ property bool expanded: false
133139 readonly property string category: categoryId
134140 readonly property var item: rendererLoader.item
135141
142+ function expand(expand, animate) {
143+ heightBehaviour.enabled = animate;
144+ expanded = expand;
145+ }
146+
136147 CardTool {
137148 id: cardTool
138149 objectName: "cardTool"
@@ -142,6 +153,18 @@ FocusScope {
142153 viewWidth: parent.width
143154 }
144155
156+ onExpandableChanged: {
157+ // This can happen with the VJ that doesn't know how height it will be on creation
158+ // so doesn't set expandable until a bit too late for onLoaded
159+ if (expandable) {
160+ var shouldExpand = baseItem.category === categoryView.expandedCategoryId;
161+ baseItem.expand(shouldExpand, false /*animate*/);
162+ }
163+ }
164+
165+ onHeightChanged: rendererLoader.updateDelegateCreationRange();
166+ onYChanged: rendererLoader.updateDelegateCreationRange();
167+
145168 Loader {
146169 id: rendererLoader
147170 anchors {
@@ -151,13 +174,27 @@ FocusScope {
151174 topMargin: hasSectionHeader ? 0 : units.gu(2)
152175 }
153176
177+ Behavior on height {
178+ id: heightBehaviour
179+ enabled: false
180+ animation: UbuntuNumberAnimation {
181+ onRunningChanged: {
182+ if (!running) {
183+ heightBehaviour.enabled = false
184+ }
185+ }
186+ }
187+ }
188+
189+ height: baseItem.expandable && !baseItem.expanded ? item.collapsedHeight : item.expandedHeight
190+
154191 source: {
155192 switch (cardTool.categoryLayout) {
156193 case "carousel": return "CardCarousel.qml";
157194 case "vertical-journal": return "CardVerticalJournal.qml";
158195 case "running-apps": return "Apps/RunningApplicationsGrid.qml";
159196 case "grid":
160− default: return "CardFilterGrid.qml";
197+ default: return "CardGrid.qml";
161198 }
162199 }
163200
@@ -176,9 +213,9 @@ FocusScope {
176213 }
177214 item.objectName = Qt.binding(function() { return categoryId })
178215 item.scopeStyle = scopeView.scopeStyle;
179− if (item.expandable) {
180− var shouldFilter = categoryId != categoryView.expandedCategoryId;
181− item.setFilter(shouldFilter, false /*animate*/);
216+ if (baseItem.expandable) {
217+ var shouldExpand = categoryId === categoryView.expandedCategoryId;
218+ baseItem.expand(shouldExpand, false /*animate*/);
182219 }
183220 updateDelegateCreationRange();
184221 item.cardTool = cardTool;
@@ -211,14 +248,6 @@ FocusScope {
211248 previewListView.currentIndex = index;
212249 previewListView.open = true
213250 }
214− onExpandableChanged: {
215− // This can happen with the VJ that doesn't know how height it will be on creation
216− // so doesn't set expandable until a bit too late for onLoaded
217− if (rendererLoader.item.expandable) {
218− var shouldFilter = baseItem.category != categoryView.expandedCategoryId;
219− rendererLoader.item.setFilter(shouldFilter, false /*animate*/);
220− }
221− }
222251 }
223252 Connections {
224253 target: categoryView
@@ -227,17 +256,17 @@ FocusScope {
227256 }
228257 function collapseAllButExpandedCategory() {
229258 var item = rendererLoader.item;
230− if (item.expandable) {
231− var shouldFilter = categoryId != categoryView.expandedCategoryId;
232− if (shouldFilter != item.filter) {
259+ if (baseItem.expandable) {
260+ var shouldExpand = categoryId === categoryView.expandedCategoryId;
261+ if (shouldExpand != baseItem.expanded) {
233262 // If the filter animation will be seen start it, otherwise, just flip the switch
234− var shrinkingVisible = shouldFilter && y + item.collapsedHeight < categoryView.height;
235− var growingVisible = !shouldFilter && y + height < categoryView.height;
236− if (!previewListView.open || !shouldFilter) {
263+ var shrinkingVisible = !shouldExpand && y + item.collapsedHeight < categoryView.height;
264+ var growingVisible = shouldExpand && y + height < categoryView.height;
265+ if (!previewListView.open || shouldExpand) {
237266 var animate = shrinkingVisible || growingVisible;
238− item.setFilter(shouldFilter, animate)
239− if (!shouldFilter && !previewListView.open) {
240− categoryView.maximizeVisibleArea(index, item.uncollapsedHeight);
267+ baseItem.expand(shouldExpand, animate)
268+ if (shouldExpand && !previewListView.open) {
269+ categoryView.maximizeVisibleArea(index, item.expandedHeight);
241270 }
242271 }
243272 }
@@ -304,9 +333,6 @@ FocusScope {
304333 z: -1
305334 }
306335 }
307−
308− onHeightChanged: rendererLoader.updateDelegateCreationRange();
309− onYChanged: rendererLoader.updateDelegateCreationRange();
310336 }
311337
312338 sectionProperty: "name"
@@ -318,7 +344,7 @@ FocusScope {
318344 textColor: scopeStyle ? scopeStyle.foreground : "grey"
319345 image: {
320346 if (delegate && delegate.expandable)
321− return delegate.filtered ? "graphics/header_handlearrow.png" : "graphics/header_handlearrow2.png"
347+ return delegate.expanded ? "graphics/header_handlearrow2.png" : "graphics/header_handlearrow.png"
322348 return "";
323349 }
324350 onClicked: {
tests/autopilot/unity8/shell/emulators/dash.py+9−3
@@ -18,6 +18,7 @@
1818#
1919
2020import logging
21+import ubuntuuitoolkit
2122
2223from unity8.shell import emulators
2324
@@ -40,7 +41,7 @@ class Dash(emulators.UnityEmulatorBase):
4041
4142 def get_applications_grid(self):
4243 get_grid = self.get_scope('clickscope').wait_select_single(
43− 'CardFilterGrid', objectName='local')
44+ 'CardGrid', objectName='local')
4445 return get_grid
4546
4647 def get_application_icon(self, text):
@@ -151,6 +152,10 @@ class Dash(emulators.UnityEmulatorBase):
151152 return None
152153
153154
155+class ListViewWithPageHeader(ubuntuuitoolkit.QQuickFlickable):
156+ pass
157+
158+
154159class GenericScopeView(emulators.UnityEmulatorBase):
155160 """Autopilot emulator for generic scopes."""
156161
@@ -196,9 +201,10 @@ class DashApps(GenericScopeView):
196201 category_element = self._get_category_element(category)
197202 application_cards = category_element.select_many('AbstractButton')
198203
199− # sort by y, x
200204 application_cards = sorted(
201− application_cards,
205+ (card for card in application_cards
206+ if card.globalRect.y
207+ < category_element.globalRect.y + category_element.height),
202208 key=lambda card: (card.globalRect.y, card.globalRect.x))
203209
204210 result = []
tests/autopilot/unity8/shell/tests/test_emulators.py+15−5
@@ -16,6 +16,7 @@
1616# You should have received a copy of the GNU General Public License
1717# along with this program. If not, see <http://www.gnu.org/licenses/>.
1818#
19+from unity8.shell.emulators.dash import ListViewWithPageHeader
1920
2021"""Tests for the Dash autopilot emulators.
2122
@@ -182,18 +183,27 @@ class DashAppsEmulatorTestCase(DashBaseTestCase):
182183
183184 def test_get_applications_should_return_correct_applications(self):
184185 category = '2'
186+ category_element = self.applications_scope._get_category_element(
187+ category)
188+ list_view = self.dash.get_scope('clickscope')\
189+ .select_single(ListViewWithPageHeader)
185190 expected_apps_count = self._get_number_of_application_slots(category)
186191 expected_applications = self.available_applications[
187192 :expected_apps_count]
193+ x_center = list_view.globalRect.x + list_view.width / 2
194+ y_center = list_view.globalRect.y + list_view.height / 2
195+ y_diff = category_element.y - list_view.height + category_element.height
196+ list_view._slow_drag(x_center, x_center,
197+ y_center, y_center - y_diff)
188198 applications = self.applications_scope.get_applications(category)
189199 self.assertEqual(expected_applications, applications)
190200
191201 def _get_number_of_application_slots(self, category):
192202 category_element = self.applications_scope._get_category_element(
193203 category)
194− grid = category_element.select_single('CardFilterGrid')
195− filtergrid = grid.select_single('FilterGrid')
196− if (grid.filtered):
197− return filtergrid.collapsedRowCount * filtergrid.columns
204+ cardgrid = category_element.select_single('CardGrid')
205+ if (category_element.expanded):
206+ return cardgrid.select_single('QQuickGridView').count
198207 else:
199− return filtergrid.uncollapsedRowCount * filtergrid.columns
208+ return cardgrid.collapsedRows \
209+ * cardgrid.select_single('ResponsiveGridView').columns
tests/mocks/Unity/fake_categories.cpp+4−1
@@ -145,9 +145,12 @@ Categories::data(const QModelIndex& index, int role) const
145145 } else {
146146 map["category-layout"] = "carousel";
147147 map["card-size"] = "medium";
148− map["collapsed-rows"] = 2;
149148 map["overlay"] = true;
150149 }
150+ if (index.row() == 19) {
151+ map["category-layout"] = "grid";
152+ map["collapsed-rows"] = 0;
153+ }
151154 map["card-size"] = "small";
152155 return map;
153156 }
tests/mocks/Unity/fake_scope.cpp+2−2
@@ -24,7 +24,7 @@ Scope::Scope(QObject* parent) : Scope(QString(), QString(), false, parent)
2424{
2525}
2626
27−Scope::Scope(QString const& id, QString const& name, bool visible, QObject* parent)
27+Scope::Scope(QString const& id, QString const& name, bool visible, QObject* parent, int categories)
2828 : unity::shell::scopes::ScopeInterface(parent)
2929 , m_id(id)
3030 , m_name(name)
@@ -33,7 +33,7 @@ Scope::Scope(QString const& id, QString const& name, bool visible, QObject* pare
3333 , m_isActive(false)
3434 , m_currentDeparment("root")
3535 , m_previewRendererName("preview-generic")
36− , m_categories(new Categories(20, this))
36+ , m_categories(new Categories(categories, this))
3737{
3838}
3939
tests/mocks/Unity/fake_scope.h+1−1
@@ -30,7 +30,7 @@ class Scope : public unity::shell::scopes::ScopeInterface
3030
3131public:
3232 Scope(QObject* parent = 0);
33− Scope(QString const& id, QString const& name, bool visible, QObject* parent = 0);
33+ Scope(QString const& id, QString const& name, bool visible, QObject* parent = 0, int categories = 20);
3434
3535 /* getters */
3636 QString id() const override;
tests/mocks/Unity/fake_scopes.cpp+1
@@ -46,6 +46,7 @@ void Scopes::updateScopes()
4646 addScope(new Scope("MockScope2", "Music", false, this));
4747 addScope(new Scope("clickscope", "Apps", true, this));
4848 addScope(new Scope("MockScope5", "Videos", true, this));
49+ addScope(new Scope("SingleCategoryScope", "Single", true, this, 1));
4950
5051 if (!m_loaded) {
5152 m_loaded = true;
tests/qmltests/CMakeLists.txt−1
@@ -24,7 +24,6 @@ add_qml_test(. ShellWithPin ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tes
2424add_qml_test(Components Carousel)
2525add_qml_test(Components DraggingArea)
2626add_qml_test(Components EdgeDemoOverlay)
27−add_qml_test(Components FilterGrid)
2827add_qml_test(Components LazyImage)
2928add_qml_test(Components Rating)
3029add_qml_test(Components ResponsiveFlowView)
tests/qmltests/Components/tst_FilterGrid.qmldeleted−190
@@ -1,190 +0,0 @@
1−/*
2− * Copyright 2013 Canonical Ltd.
3− *
4− * 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 by
6− * the Free Software Foundation; version 3.
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 General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− */
16−
17−import QtQuick 2.0
18−import QtTest 1.0
19−import "../../../qml/Components"
20−import Ubuntu.Components.ListItems 0.1 as ListItem
21−import Ubuntu.Components 0.1
22−import Unity.Test 0.1 as UT
23−import Utils 0.1
24−
25−/*
26− You should see 6 green squares (from "A" to "F") and a button "View all (12)".
27− Once you press that button other 6 green squares (from "G" to "L") should show up.
28−*/
29−Rectangle {
30− width: gridRect.width + controls.width
31− height: units.gu(50)
32− color: "white"
33−
34− Column {
35− id: controls
36− width: units.gu(30)
37− height: parent.height
38− anchors.top: parent.top
39− anchors.right: parent.right
40− ListItem.ValueSelector {
41− id: collapsedRowCountSelector
42− text: "collapsedRowCount"
43− values: [1,2,3,4]
44− selectedIndex: 1
45− }
46− Row {
47− spacing: units.gu(1)
48− Label { anchors.verticalCenter: parent.verticalCenter
49− text: "Filter" }
50− CheckBox {
51− id: filterCheckBox
52− checked: true
53− onCheckedChanged: filterGrid.setFilter(checked, false /*animate*/)
54− }
55− }
56− }
57−
58− ListModel {
59− id: fakeModel
60− ListElement { name: "A" }
61− ListElement { name: "B" }
62− ListElement { name: "C" }
63− ListElement { name: "D" }
64− ListElement { name: "E" }
65− ListElement { name: "F" }
66− ListElement { name: "G" }
67− ListElement { name: "H" }
68− ListElement { name: "I" }
69− ListElement { name: "J" }
70− ListElement { name: "K" }
71− ListElement { name: "L" }
72− }
73−
74− ListModel {
75− id: fakeModelTwoItems
76− ListElement { name: "A" }
77− ListElement { name: "B" }
78− }
79−
80− ListModel {
81− id: fakeModelFourItems
82− ListElement { name: "A" }
83− ListElement { name: "B" }
84− ListElement { name: "C" }
85− ListElement { name: "D" }
86− }
87−
88− Rectangle {
89− id: gridRect
90− width: units.gu(30)
91− height: parent.height
92− color: "grey"
93− anchors.top: parent.top
94− anchors.left: parent.left
95−
96− FilterGrid {
97− id: filterGrid
98− anchors.fill: parent
99− model: fakeModel
100− maximumNumberOfColumns: 3
101− collapsedRowCount:
102− collapsedRowCountSelector.values[collapsedRowCountSelector.selectedIndex]
103− minimumHorizontalSpacing: units.gu(1)
104− delegateWidth: units.gu(6)
105− delegateHeight: units.gu(6)
106− verticalSpacing: units.gu(1)
107−
108− delegate: Rectangle {
109− // So that it can be identified by countVisibleDelegates()
110− property bool isGridDelegate: true
111−
112− color: "green"
113− width: units.gu(6)
114− height: units.gu(6)
115− Text {
116− anchors.centerIn: parent
117− text: name
118− }
119− }
120− }
121− }
122−
123− UT.UnityTestCase {
124− name: "FilterGrid"
125− when: windowShown
126−
127− function init() {
128− filterGrid.model = fakeModel
129− }
130−
131− function cleanup() {
132− filterCheckBox.checked = true
133− collapsedRowCountSelector.selectedIndex = 1
134− }
135−
136− function test_turningFilterOffShowsAllElements() {
137− tryCompareFunction(countVisibleDelegates, 6)
138−
139− filterCheckBox.checked = false
140−
141− tryCompareFunction(countVisibleDelegates, 12)
142− }
143−
144− function test_collapsedRowCount() {
145− for (var i = 0; i < 4; ++i) {
146− collapsedRowCountSelector.selectedIndex = i
147− // We have 3 elements per row.
148− // row count == index + 1
149− tryCompareFunction(countVisibleDelegates, 3*(i+1))
150− }
151− }
152−
153− function test_modelSizeAffectsCollapsedRowCount_data() {
154− return [
155− { tag: "2 items, collapsedRows 1", model: fakeModelTwoItems, collapsedRowCountIndex: 0,
156− rowsWhenCollapsed: 1, visibleDelegates: 2 },
157− { tag: "2 items, collapsedRows 2", model: fakeModelTwoItems, collapsedRowCountIndex: 1,
158− rowsWhenCollapsed: 1, visibleDelegates: 2 },
159− { tag: "4 items, collapsedRows 1", model: fakeModelFourItems, collapsedRowCountIndex: 0,
160− rowsWhenCollapsed: 1, visibleDelegates: 3 },
161− { tag: "4 items, collapsedRows 2", model: fakeModelFourItems, collapsedRowCountIndex: 1,
162− rowsWhenCollapsed: 2, visibleDelegates: 4 },
163− ]
164− }
165−
166− function test_modelSizeAffectsCollapsedRowCount(data) {
167− filterGrid.model = data.model
168− collapsedRowCountSelector.selectedIndex = data.collapsedRowCountIndex
169−
170− tryCompare(filterGrid, "rowsWhenCollapsed", data.rowsWhenCollapsed)
171− tryCompareFunction(countVisibleDelegates, data.visibleDelegates)
172− }
173−
174− function countVisibleDelegates() {
175− return __countVisibleDelegates(filterGrid.visibleChildren, 0)
176− }
177−
178− function __countVisibleDelegates(objList, total) {
179− for (var i = 0; i < objList.length; ++i) {
180− var child = objList[i];
181− if (child.isGridDelegate !== undefined) {
182− ++total;
183− } else {
184− total = __countVisibleDelegates(child.visibleChildren, total)
185− }
186− }
187− return total
188− }
189− }
190−}
tests/qmltests/Dash/tst_Dash.qml+1−1
@@ -86,7 +86,7 @@ Item {
8686 tryCompare(dashContentList, "count", 0);
8787 scopes.load();
8888 tryCompare(scopes, "loaded", true);
89− tryCompare(dashContentList, "count", 3);
89+ tryCompare(dashContentList, "count", 4);
9090
9191 verify(dashContentList != undefined);
9292 tryCompare(dashContentList, "currentIndex", data.visualIndex);
tests/qmltests/Dash/tst_DashContent.qml+15−6
@@ -61,6 +61,11 @@ Item {
6161 signalName: "movementStarted"
6262 }
6363
64+ SignalSpy {
65+ id: loadedSpy
66+ signalName: "loaded"
67+ }
68+
6469 UT.UnityTestCase {
6570 name: "DashContent"
6671 when: scopesModel.loaded && windowShown
@@ -78,6 +83,7 @@ Item {
7883
7984 function cleanup() {
8085 movementStartedSpy.clear();
86+ loadedSpy.clear();
8187 dashContent.visible = true;
8288
8389 var dashContentList = findChild(dashContent, "dashContentList");
@@ -116,10 +122,11 @@ Item {
116122
117123 function test_show_header_on_list_movement() {
118124 var dashContentList = findChild(dashContent, "dashContentList");
119− verify(dashContentList != undefined);
120− var categoryListView = findChild(dashContentList, "categoryListView");
121− verify(categoryListView != undefined);
125+ verify(dashContentList !== null);
126+ var scope = findChild(dashContent, "MockScope1 loader");
127+ waitForRendering(scope);
122128
129+ var categoryListView = findChild(scope, "categoryListView");
123130 waitForRendering(categoryListView);
124131
125132 categoryListView.contentY = units.gu(15);
@@ -133,10 +140,12 @@ Item {
133140
134141 function test_set_current_scope_reset() {
135142 var dashContentList = findChild(dashContent, "dashContentList");
136− verify(dashContentList != undefined);
137− var categoryListView = findChild(dashContentList, "categoryListView");
138− verify(categoryListView != undefined);
143+ verify(dashContentList, "Couldn't find dashContentList");
144+ var scope = findChild(dashContent, "MockScope1 loader");
139145
146+ tryCompare(scope, "status", Loader.Ready);
147+
148+ var categoryListView = findChild(dashContentList, "categoryListView");
140149 categoryListView.contentY = units.gu(10);
141150
142151 compare(dashContentList.currentItem.item.objectName, "MockScope1")
tests/qmltests/Dash/tst_GenericScopeView.qml+46−24
@@ -59,7 +59,7 @@ Item {
5959 genericScopeView.scope = scopes.getScope(1)
6060 shell.width = units.gu(120)
6161 genericScopeView.categoryView.positionAtBeginning();
62− tryCompare(genericScopeView.categoryView, "contentY", 0)
62+ waitForRendering(genericScopeView.categoryView);
6363 }
6464
6565 function test_isActive() {
@@ -105,8 +105,6 @@ Item {
105105 }
106106
107107 function test_filter_expand_collapse() {
108− // wait for the item to be there
109− waitForRendering(genericScopeView);
110108 tryCompareFunction(function() { return findChild(genericScopeView, "dashSectionHeader0") != null; }, true);
111109
112110 var header = findChild(genericScopeView, "dashSectionHeader0")
@@ -114,18 +112,18 @@ Item {
114112
115113 waitForRendering(header);
116114 verify(category.expandable);
117− verify(category.filtered);
115+ verify(!category.expanded);
118116
119117 var initialHeight = category.height;
120118 var middleHeight;
121119 mouseClick(header, header.width / 2, header.height / 2);
122120 tryCompareFunction(function() { middleHeight = category.height; return category.height > initialHeight; }, true);
123− tryCompare(category, "filtered", false);
121+ tryCompare(category, "expanded", true);
124122 tryCompareFunction(function() { return category.height > middleHeight; }, true);
125123
126124 mouseClick(header, header.width / 2, header.height / 2);
127125 verify(category.expandable);
128− tryCompare(category, "filtered", true);
126+ tryCompare(category, "expanded", false);
129127 }
130128
131129 function test_filter_expand_expand_collapse() {
@@ -137,51 +135,75 @@ Item {
137135
138136 var header2 = findChild(genericScopeView, "dashSectionHeader2")
139137 var category2 = findChild(genericScopeView, "dashCategory2")
140− var category2FilterGrid = category2.children[1].children[2];
141− verify(UT.Util.isInstanceOf(category2FilterGrid, "CardFilterGrid"));
142138
143139 waitForRendering(header2);
144140 verify(category2.expandable);
145− verify(category2.filtered);
141+ verify(!category2.expanded);
146142
147143 mouseClick(header2, header2.width / 2, header2.height / 2);
148− tryCompare(category2, "filtered", false);
149− tryCompare(category2FilterGrid, "filtered", false);
144+ tryCompare(category2, "expanded", true);
150145
151146 categoryListView.positionAtBeginning();
152147
153148 var header0 = findChild(genericScopeView, "dashSectionHeader0")
154149 var category0 = findChild(genericScopeView, "dashCategory0")
155150 mouseClick(header0, header0.width / 2, header0.height / 2);
156− tryCompare(category0, "filtered", false);
157− tryCompare(category2, "filtered", true);
158− tryCompare(category2FilterGrid, "filtered", true);
151+ tryCompare(category0, "expanded", true);
152+ tryCompare(category2, "expanded", false);
159153 mouseClick(header0, header0.width / 2, header0.height / 2);
160− tryCompare(category0, "filtered", true);
161− tryCompare(category2, "filtered", true);
154+ tryCompare(category0, "expanded", false);
155+ tryCompare(category2, "expanded", false);
162156 }
163157
164158 function test_narrow_delegate_ranges_expand() {
165− tryCompareFunction(function() { return findChild(genericScopeView, "dashCategory0") != undefined; }, true);
159+ tryCompareFunction(function() { return findChild(genericScopeView, "dashCategory0") !== null; }, true);
166160 var category = findChild(genericScopeView, "dashCategory0")
167− tryCompare(category, "filtered", true);
161+ tryCompare(category, "expanded", false);
168162
169163 shell.width = units.gu(20)
170164 var categoryListView = findChild(genericScopeView, "categoryListView");
171165 categoryListView.contentY = units.gu(20);
172166 var header0 = findChild(genericScopeView, "dashSectionHeader0")
173167 mouseClick(header0, header0.width / 2, header0.height / 2);
174− tryCompare(category, "filtered", false);
168+ tryCompare(category, "expanded", true);
175169 tryCompareFunction(function() { return category.item.height == genericScopeView.height - category.item.displayMarginBeginning - category.item.displayMarginEnd; }, true);
176170 mouseClick(header0, header0.width / 2, header0.height / 2);
177− tryCompare(category, "filtered", true);
171+ tryCompare(category, "expanded", false);
172+ }
173+
174+ function test_forced_category_expansion() {
175+ tryCompareFunction(function() {
176+ mouseFlick(genericScopeView, genericScopeView.width/2, genericScopeView.height,
177+ genericScopeView.width/2, genericScopeView.y)
178+ return findChild(genericScopeView, "dashCategory19") !== null;
179+ }, true);
180+ var category = findChild(genericScopeView, "dashCategory19")
181+ compare(category.expandable, false, "Category with collapsed-rows: 0 should not be expandable");
182+
183+ var grid = findChild(category, "19");
184+ verify(grid, "Could not find the category renderer.");
185+
186+ compare(grid.height, grid.expandedHeight, "Category with collapsed-rows: 0 should always be expanded.");
187+ }
188+
189+ function test_single_category_expansion() {
190+ genericScopeView.scope = scopes.getScope(4);
191+
192+ tryCompareFunction(function() { return findChild(genericScopeView, "dashCategory0") != undefined; }, true);
193+ var category = findChild(genericScopeView, "dashCategory0")
194+ compare(category.expandable, false, "Only category should not be expandable.");
195+
196+ var grid = findChild(category, "0");
197+ verify(grid, "Could not find the category renderer.");
198+
199+ compare(grid.height, grid.expandedHeight, "Only category should always be expanded");
178200 }
179201
180202 function openPreview() {
181203 tryCompareFunction(function() {
182− var filterGrid = findChild(genericScopeView, "0");
183− if (filterGrid != null) {
184− var tile = findChild(filterGrid, "delegate0");
204+ var cardGrid = findChild(genericScopeView, "0");
205+ if (cardGrid != null) {
206+ var tile = findChild(cardGrid, "delegate0");
185207 return tile != null;
186208 }
187209 return false;
@@ -257,7 +279,7 @@ Item {
257279 closePreview();
258280 }
259281
260− function test_haeder_logo() {
282+ function test_header_logo() {
261283 genericScopeView.scope = scopes.getScope(3);
262284
263285 var image = findChild(genericScopeView, "titleImage");