on xenial help sign in
Implement the API changes due to filters

Approved by: Andrea Cimitan, Michael Terry

commit8dae33557c2def7b9611c9d0bb6a9dccd582b9e6 authorAlbert Astals Cid <albert.astals@canonical.com> dateWed 23 Mar 2016, 09:50 (11 years ago) parentd388e17389724e
15 files changed+412−253
debian/control+1−1 qml/Dash/DashNavigation.qml+3−33 qml/Dash/DashNavigationButton.qml+6−16 qml/Dash/GenericScopeView.qml+35−48 tests/mocks/Unity/CMakeLists.txt+8−1 tests/mocks/Unity/fake_filters.cpp+56 tests/mocks/Unity/fake_filters.h+39 tests/mocks/Unity/fake_navigation.cpp+6−9 tests/mocks/Unity/fake_optionselectorfilter.cpp+59 tests/mocks/Unity/fake_optionselectorfilter.h+45 tests/mocks/Unity/fake_optionselectoroptions.cpp+65 tests/mocks/Unity/fake_optionselectoroptions.h+42 tests/mocks/Unity/fake_scope.cpp+33−30 tests/mocks/Unity/fake_scope.h+13−7 tests/qmltests/Dash/tst_DashContent.qml+1−108
debian/control+1−1
@@ -134,7 +134,7 @@ Depends: qml-module-qtquick-layouts,
134134 unity-application-impl-14,
135135 unity-notifications-impl-3,
136136 unity-plugin-scopes | unity-scopes-impl,
137− unity-scopes-impl-10,
137+ unity-scopes-impl-11,
138138 unity8-fake-env | unity-application-impl,
139139 ${misc:Depends},
140140Breaks: unity8 (<< 7.86),
qml/Dash/DashNavigation.qml+3−33
@@ -30,28 +30,24 @@ Item {
3030 property alias windowHeight: blackRect.height
3131 readonly property var openList: {
3232 if (navigationButton.showList) return navigationButton.listView;
33− if (altNavigationButton.showList) return altNavigationButton.listView;
3433 return null;
3534 }
3635 readonly property bool disableParentInteractive: {
37− return navigationButton.showList || altNavigationButton.showList ||
38− navigationButton.inverseMousePressed || altNavigationButton.inverseMousePressed;
36+ return navigationButton.showList || navigationButton.inverseMousePressed;
3937 }
4038
4139 // FIXME this is only here for highlight purposes (see Background.qml, too)
4240 readonly property var background: backgroundItem
4341
4442 visible: height != 0
45− height: navigationButton.currentNavigation || altNavigationButton.currentNavigation ? units.gu(5) : 0
43+ height: navigationButton.currentNavigation ? units.gu(5) : 0
4644
4745 QtObject {
4846 id: d
4947 readonly property color foregroundColor: root.scopeStyle
5048 ? root.scopeStyle.getTextColor(backgroundItem.luminance)
5149 : theme.palette.normal.baseText
52− readonly property bool bothVisible: altNavigationButton.visible && navigationButton.visible
5350 readonly property real navigationWidth: root.width >= units.gu(60) ? units.gu(40) : root.width
54− readonly property real buttonWidth: navigationWidth / (bothVisible ? 2 : 1)
5551 }
5652
5753 Rectangle {
@@ -76,27 +72,11 @@ Item {
7672 anchors { top: parent.bottom; left: parent.left; right: parent.right }
7773 }
7874
79− DashNavigationButton {
80− id: altNavigationButton
81− objectName: "altNavigationButton"
82− height: root.height
83− width: d.buttonWidth
84− scope: root.scope
85− scopeStyle: root.scopeStyle
86− foregroundColor: d.foregroundColor
87− listView.width: d.navigationWidth
88− isAltNavigation: true
89− showDivider: navigationButton.visible || root.width > d.navigationWidth
90− // needed so that InverseMouseArea is above navigationButton
91− z: listView.height > 0 ? 1 : 0
92− }
93−
9475 DashNavigationButton {
9576 id: navigationButton
9677 objectName: "navigationButton"
9778 height: root.height
98− width: altNavigationButton.visible ? d.buttonWidth : d.navigationWidth
99− x: altNavigationButton.visible ? d.buttonWidth : 0
79+ width: d.navigationWidth
10080 scope: root.scope
10181 scopeStyle: root.scopeStyle
10282 foregroundColor: d.foregroundColor
@@ -104,14 +84,4 @@ Item {
10484 listView.x: -x
10585 showDivider: root.width > d.navigationWidth
10686 }
107−
108− Image {
109− fillMode: Image.Stretch
110− source: backgroundItem.luminance > 0.7 ? "graphics/navigation_shadow.png" : "graphics/navigation_shadow_light.png"
111− x: navigationButton.listView.height > 0 ? altNavigationButton.x : navigationButton.x
112− width: d.buttonWidth
113− rotation: 180
114− anchors.bottom: parent.bottom
115− visible: d.bothVisible && (navigationButton.listView.height > 0 || altNavigationButton.listView.height > 0)
116− }
11787}
qml/Dash/DashNavigationButton.qml+6−16
@@ -25,11 +25,10 @@ AbstractButton {
2525 property var scope: null
2626 property var scopeStyle: null
2727 property color foregroundColor: theme.palette.normal.baseText
28− property bool isAltNavigation: false
2928 property bool showDivider: false
3029
3130 // Used by parent
32− readonly property var currentNavigation: scope && scope[hasNavigation] ? getNavigation(scope[currentNavigationId]) : null
31+ readonly property var currentNavigation: scope && scope.hasNavigation ? scope.getNavigation(scope.currentNavigationId) : null
3332 readonly property alias listView: navigationListView
3433 readonly property bool inverseMousePressed: inverseMouseArea.pressed
3534 property bool showList: false
@@ -37,15 +36,6 @@ AbstractButton {
3736 // Internal
3837 // Are we drilling down the tree or up?
3938 property bool isGoingBack: false
40− readonly property string hasNavigation: isAltNavigation ? "hasAltNavigation" : "hasNavigation"
41− readonly property string currentNavigationId: isAltNavigation ? "currentAltNavigationId" : "currentNavigationId"
42− function getNavigation(navId) {
43− if (isAltNavigation) {
44− return scope.getAltNavigation(navId);
45− } else {
46− return scope.getNavigation(navId);
47− }
48− }
4939
5040 visible: root.currentNavigation != null
5141
@@ -125,10 +115,10 @@ AbstractButton {
125115 }
126116 }
127117 height: desiredHeight
128− navigation: (nullifyNavigation || !scope) ? null : getNavigation(navigationId)
118+ navigation: (nullifyNavigation || !scope) ? null : scope.getNavigation(navigationId)
129119 currentNavigation: root.currentNavigation
130120 onEnterNavigation: {
131− scope.setNavigationState(newNavigationId, isAltNavigation);
121+ scope.setNavigationState(newNavigationId);
132122 // We only need to add a new item to the model
133123 // if we have children, otherwise just load it
134124 if (hasChildren) {
@@ -151,7 +141,7 @@ AbstractButton {
151141 navigationListView.highlightMoveDuration = aux;
152142 }
153143
154− scope.setNavigationState(navigation.parentNavigationId, isAltNavigation);
144+ scope.setNavigationState(navigation.parentNavigationId);
155145 isGoingBack = true;
156146 navigationModel.setProperty(navigationListView.currentIndex - 1, "nullifyNavigation", false);
157147 navigationListView.currentIndex--;
@@ -160,7 +150,7 @@ AbstractButton {
160150 showList = false;
161151 if (root.currentNavigation.parentNavigationId == navigation.navigationId) {
162152 // For leaves we have to go to the parent too
163− scope.setNavigationState(root.currentNavigation.parentNavigationId, isAltNavigation);
153+ scope.setNavigationState(root.currentNavigation.parentNavigationId);
164154 }
165155 }
166156 }
@@ -198,7 +188,7 @@ AbstractButton {
198188 if (isFirstLoad && currentNavigation && currentNavigation.loaded) {
199189 isFirstLoad = false;
200190 if (currentNavigation.count > 0) {
201− navigationModel.append({"navigationId": scope[currentNavigationId], "nullifyNavigation": false});
191+ navigationModel.append({"navigationId": scope.currentNavigationId, "nullifyNavigation": false});
202192 } else {
203193 navigationModel.append({"navigationId": currentNavigation.parentNavigationId, "nullifyNavigation": false});
204194 }
qml/Dash/GenericScopeView.qml+35−48
@@ -25,7 +25,7 @@ import "../Components/ListItems" as ListItems
2525FocusScope {
2626 id: scopeView
2727
28− readonly property bool navigationDisableParentInteractive: pageHeaderLoader.item ? pageHeaderLoader.item.bottomItem[0].disableParentInteractive : false
28+ readonly property bool navigationDisableParentInteractive: categoryView.pageHeader.bottomItem[0].disableParentInteractive
2929 property bool forceNonInteractive: false
3030 property var scope: null
3131 property UnitySortFilterProxyModel categories: categoryFilter
@@ -34,7 +34,6 @@ FocusScope {
3434 property bool hasBackAction: false
3535 property bool enableHeightBehaviorOnNextCreation: false
3636 property var categoryView: categoryView
37− property bool showPageHeader: true
3837 readonly property alias subPageShown: subPageLoader.subPageShown
3938 property int paginationCount: 0
4039 property int paginationIndex: 0
@@ -68,8 +67,7 @@ FocusScope {
6867 }
6968
7069 function resetSearch() {
71− if(pageHeaderLoader.item && showPageHeader)
72− pageHeaderLoader.item.resetSearch()
70+ categoryView.pageHeader.resetSearch()
7371 }
7472
7573 property var maybePreviewResult;
@@ -120,24 +118,22 @@ FocusScope {
120118 if (!holdingList || !holdingList.moving) {
121119 wasCurrentOnMoveStart = scopeView.isCurrent;
122120 }
123− if (pageHeaderLoader.item && showPageHeader) {
124− pageHeaderLoader.item.resetSearch();
125− }
121+ categoryView.pageHeader.resetSearch();
126122 subPageLoader.closeSubPage();
127123 }
128124
129125 Binding {
130126 target: scopeView.scope
131127 property: "searchQuery"
132− value: pageHeaderLoader.item ? pageHeaderLoader.item.searchQuery : ""
133− when: isCurrent && showPageHeader
128+ value: categoryView.pageHeader.searchQuery
129+ when: isCurrent
134130 }
135131
136132 Binding {
137− target: pageHeaderLoader.item
133+ target: categoryView.pageHeader
138134 property: "searchQuery"
139135 value: scopeView.scope ? scopeView.scope.searchQuery : ""
140− when: isCurrent && showPageHeader
136+ when: isCurrent
141137 }
142138
143139 Connections {
@@ -189,8 +185,8 @@ FocusScope {
189185 property string expandedCategoryId: ""
190186 property int runMaximizeAfterSizeChanges: 0
191187
192− readonly property bool pageHeaderTotallyVisible: scopeView.showPageHeader &&
193− ((headerItemShownHeight == 0 && categoryView.contentY <= categoryView.originY) || (headerItemShownHeight == pageHeaderLoader.item.height))
188+ readonly property bool pageHeaderTotallyVisible:
189+ ((headerItemShownHeight == 0 && categoryView.contentY <= categoryView.originY) || (headerItemShownHeight == categoryView.pageHeader.height))
194190
195191 onExpandedCategoryIdChanged: {
196192 var firstCreated = firstCreatedIndex();
@@ -615,41 +611,32 @@ FocusScope {
615611 }
616612 }
617613
618− pageHeader: scopeView.showPageHeader ? pageHeaderLoader : null
619− Loader {
620− id: pageHeaderLoader
614+ pageHeader: DashPageHeader {
615+ objectName: "scopePageHeader"
621616 width: parent.width
622− sourceComponent: scopeView.showPageHeader ? pageHeaderComponent : undefined
623− Component {
624− id: pageHeaderComponent
625− DashPageHeader {
626− objectName: "scopePageHeader"
627− width: parent.width
628− title: scopeView.scope ? scopeView.scope.name : ""
629− searchHint: scopeView.scope && scopeView.scope.searchHint || i18n.ctr("Label: Hint for dash search line edit", "Search")
630− showBackButton: scopeView.hasBackAction
631− searchEntryEnabled: true
632− settingsEnabled: scopeView.scope && scopeView.scope.settings && scopeView.scope.settings.count > 0 || false
633− favoriteEnabled: scopeView.scope && scopeView.scope.id !== "clickscope"
634− favorite: scopeView.scope && scopeView.scope.favorite
635− scopeStyle: scopeView.scopeStyle
636− paginationCount: scopeView.paginationCount
637− paginationIndex: scopeView.paginationIndex
638−
639− bottomItem: DashNavigation {
640− scope: scopeView.scope
641− anchors { left: parent.left; right: parent.right }
642− windowHeight: scopeView.height
643− windowWidth: scopeView.width
644− scopeStyle: scopeView.scopeStyle
645− }
646−
647− onBackClicked: scopeView.backClicked()
648− onSettingsClicked: subPageLoader.openSubPage("settings")
649− onFavoriteClicked: scopeView.scope.favorite = !scopeView.scope.favorite
650− onSearchTextFieldFocused: scopeView.showHeader()
651− }
617+ title: scopeView.scope ? scopeView.scope.name : ""
618+ searchHint: scopeView.scope && scopeView.scope.searchHint || i18n.ctr("Label: Hint for dash search line edit", "Search")
619+ showBackButton: scopeView.hasBackAction
620+ searchEntryEnabled: true
621+ settingsEnabled: scopeView.scope && scopeView.scope.settings && scopeView.scope.settings.count > 0 || false
622+ favoriteEnabled: scopeView.scope && scopeView.scope.id !== "clickscope"
623+ favorite: scopeView.scope && scopeView.scope.favorite
624+ scopeStyle: scopeView.scopeStyle
625+ paginationCount: scopeView.paginationCount
626+ paginationIndex: scopeView.paginationIndex
627+
628+ bottomItem: DashNavigation {
629+ scope: scopeView.scope
630+ anchors { left: parent.left; right: parent.right }
631+ windowHeight: scopeView.height
632+ windowWidth: scopeView.width
633+ scopeStyle: scopeView.scopeStyle
652634 }
635+
636+ onBackClicked: scopeView.backClicked()
637+ onSettingsClicked: subPageLoader.openSubPage("settings")
638+ onFavoriteClicked: scopeView.scope.favorite = !scopeView.scope.favorite
639+ onSearchTextFieldFocused: scopeView.showHeader()
653640 }
654641 }
655642
@@ -658,7 +645,7 @@ FocusScope {
658645 anchors.left: parent.left
659646 anchors.right: parent.right
660647 anchors.bottom: parent.bottom
661− height: parent.height - pullToRefresh.contentY + (pageHeaderLoader.item ? pageHeaderLoader.item.bottomItem[0].height - pageHeaderLoader.item.height : 0)
648+ height: parent.height - pullToRefresh.contentY + (categoryView.pageHeader.bottomItem[0].height - categoryView.pageHeader.height)
662649 clip: true
663650
664651 PullToRefresh {
@@ -793,7 +780,7 @@ FocusScope {
793780 open = true;
794781 }
795782
796− onOpenChanged: pageHeaderLoader.item.unfocus()
783+ onOpenChanged: categoryView.pageHeader.unfocus()
797784
798785 onVisibleChanged: if (!visible) subPage = ""
799786
tests/mocks/Unity/CMakeLists.txt+8−1
@@ -8,7 +8,7 @@ add_subdirectory(DashCommunicator)
88add_subdirectory(Screens)
99
1010pkg_search_module(GOBJECT gobject-2.0 REQUIRED)
11−pkg_check_modules(SCOPES_API REQUIRED unity-shell-scopes=10)
11+pkg_check_modules(SCOPES_API REQUIRED unity-shell-scopes=11)
1212
1313include_directories(
1414 ${CMAKE_CURRENT_BINARY_DIR}
@@ -29,9 +29,16 @@ set(UnityQML_SOURCES
2929 fake_resultsmodel.cpp
3030 fake_previewmodel.cpp
3131 fake_previewwidgetmodel.cpp
32+ fake_filters.cpp
33+ fake_optionselectorfilter.cpp
34+ fake_optionselectoroptions.cpp
3235 fake_unity_plugin.cpp
3336 ${SCOPES_API_INCLUDEDIR}/unity/shell/scopes/CategoriesInterface.h
37+ ${SCOPES_API_INCLUDEDIR}/unity/shell/scopes/FilterBaseInterface.h
38+ ${SCOPES_API_INCLUDEDIR}/unity/shell/scopes/FiltersInterface.h
3439 ${SCOPES_API_INCLUDEDIR}/unity/shell/scopes/NavigationInterface.h
40+ ${SCOPES_API_INCLUDEDIR}/unity/shell/scopes/OptionSelectorFilterInterface.h
41+ ${SCOPES_API_INCLUDEDIR}/unity/shell/scopes/OptionSelectorOptionsInterface.h
3542 ${SCOPES_API_INCLUDEDIR}/unity/shell/scopes/PreviewModelInterface.h
3643 ${SCOPES_API_INCLUDEDIR}/unity/shell/scopes/PreviewWidgetModelInterface.h
3744 ${SCOPES_API_INCLUDEDIR}/unity/shell/scopes/ResultsModelInterface.h
tests/mocks/Unity/fake_filters.cppnew file+56
@@ -0,0 +1,56 @@
1+/*
2+ * Copyright (C) 2015 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+#include "fake_filters.h"
18+
19+#include "fake_optionselectorfilter.h"
20+#include "fake_scope.h"
21+
22+Filters::Filters(Scope* parent)
23+ : unity::shell::scopes::FiltersInterface(parent)
24+{
25+ auto optionFilter1 = new FakeOptionSelectorFilter("OSF1", "Tag1", "Which Cake you like More", false, QStringList() << "cheese" << "carrot" << "chocolate", this);
26+ auto optionFilter2 = new FakeOptionSelectorFilter("OSF2", "Tag2", "Which Countries have you been to?", true, QStringList() << "Germany" << "UK" << "New Zealand", this);
27+ m_filters << optionFilter1 << optionFilter2;
28+}
29+
30+int Filters::rowCount(const QModelIndex &parent) const
31+{
32+ if (parent.isValid())
33+ return 0;
34+
35+ return m_filters.count();
36+}
37+
38+QVariant Filters::data(const QModelIndex &index, int role) const
39+{
40+ const int row = index.row();
41+ if (row < 0 || row >= m_filters.count())
42+ return QVariant();
43+
44+ unity::shell::scopes::FilterBaseInterface *filter = m_filters[row];
45+
46+ switch (role) {
47+ case RoleFilterId:
48+ return filter->filterId();
49+ case RoleFilterType:
50+ return filter->filterType();
51+ case RoleFilter:
52+ return QVariant::fromValue<unity::shell::scopes::FilterBaseInterface *>(filter);
53+ default:
54+ return QVariant();
55+ }
56+}
tests/mocks/Unity/fake_filters.hnew file+39
@@ -0,0 +1,39 @@
1+/*
2+ * Copyright (C) 2015 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+#ifndef FAKE_FILTERS_H
18+#define FAKE_FILTERS_H
19+
20+#include <unity/shell/scopes/FiltersInterface.h>
21+#include <unity/shell/scopes/FilterBaseInterface.h>
22+
23+class Scope;
24+
25+class Filters : public unity::shell::scopes::FiltersInterface
26+{
27+ Q_OBJECT
28+
29+public:
30+ Filters(Scope* parent);
31+
32+ int rowCount(const QModelIndex &parent) const override;
33+ QVariant data(const QModelIndex &index, int role) const override;
34+
35+private:
36+ QVector<unity::shell::scopes::FilterBaseInterface*> m_filters;
37+};
38+
39+#endif
tests/mocks/Unity/fake_navigation.cpp+6−9
@@ -32,7 +32,6 @@ Navigation::Navigation(const QString& navigationId, const QString& label, const
3232{
3333 QTimer::singleShot(1500, this, &Navigation::slotLoaded);
3434 connect(scope, &Scope::currentNavigationIdChanged, this, &Navigation::slotCurrentNavigationChanged);
35− connect(scope, &Scope::currentAltNavigationIdChanged, this, &Navigation::slotCurrentNavigationChanged);
3635}
3736
3837QString Navigation::navigationId() const
@@ -78,17 +77,17 @@ int Navigation::count() const
7877
7978bool Navigation::isRoot() const
8079{
81− return m_navigationId == "root" || m_navigationId == "altroot";
80+ return m_navigationId == "root";
8281}
8382
8483bool Navigation::hidden() const
8584{
86− return m_navigationId == "altroot";
85+ return false;
8786}
8887
8988int Navigation::rowCount(const QModelIndex & /*parent*/) const
9089{
91− if (!m_loaded || m_navigationId.startsWith("child") || m_navigationId.startsWith("altrootChild") || m_navigationId == "middle3")
90+ if (!m_loaded || m_navigationId.startsWith("child") || m_navigationId == "middle3")
9291 return 0;
9392 else
9493 return 8;
@@ -104,14 +103,12 @@ QVariant Navigation::data(const QModelIndex &index, int role) const
104103 return QString("child%1%2").arg(m_navigationId).arg(index.row());
105104 case RoleLabel:
106105 return QString("%1Child%2").arg(m_navigationId).arg(index.row());
106+ case RoleAllLabel:
107+ return QString("all%1Child%2").arg(m_navigationId).arg(index.row());
107108 case RoleHasChildren:
108109 return m_navigationId == "root" && index.row() != 3;
109110 case RoleIsActive:
110− if (m_navigationId.startsWith("alt")) {
111− return m_scope->currentAltNavigationId() == data(index, RoleNavigationId);
112− } else {
113− return m_scope->currentNavigationId() == data(index, RoleNavigationId);
114− }
111+ return m_scope->currentNavigationId() == data(index, RoleNavigationId);
115112 }
116113 return QVariant();
117114}
tests/mocks/Unity/fake_optionselectorfilter.cppnew file+59
@@ -0,0 +1,59 @@
1+/*
2+ * Copyright (C) 2015 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+#include "fake_optionselectorfilter.h"
18+
19+#include "fake_optionselectoroptions.h"
20+
21+FakeOptionSelectorFilter::FakeOptionSelectorFilter(const QString &id, const QString &tag, const QString &label, bool multiselect, const QStringList &optionLabels, QObject* parent)
22+ : unity::shell::scopes::OptionSelectorFilterInterface(parent),
23+ m_filterId(id),
24+ m_filterTag(tag),
25+ m_label(label),
26+ m_multiSelect(multiselect)
27+{
28+ m_options = new FakeOptionSelectorOptions(optionLabels, this);
29+}
30+
31+QString FakeOptionSelectorFilter::filterId() const
32+{
33+ return m_filterId;
34+}
35+
36+QString FakeOptionSelectorFilter::filterTag() const
37+{
38+ return m_filterTag;
39+}
40+
41+QString FakeOptionSelectorFilter::title() const
42+{
43+ return m_title;
44+}
45+
46+QString FakeOptionSelectorFilter::label() const
47+{
48+ return m_label;
49+}
50+
51+bool FakeOptionSelectorFilter::multiSelect() const
52+{
53+ return m_multiSelect;
54+}
55+
56+unity::shell::scopes::OptionSelectorOptionsInterface* FakeOptionSelectorFilter::options() const
57+{
58+ return m_options;
59+}
tests/mocks/Unity/fake_optionselectorfilter.hnew file+45
@@ -0,0 +1,45 @@
1+/*
2+ * Copyright (C) 2015 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+#ifndef FAKE_OPTIONSELECTORFILTER_H
18+#define FAKE_OPTIONSELECTORFILTER_H
19+
20+#include <unity/shell/scopes/OptionSelectorFilterInterface.h>
21+
22+class FakeOptionSelectorFilter : public unity::shell::scopes::OptionSelectorFilterInterface
23+{
24+ Q_OBJECT
25+
26+public:
27+ FakeOptionSelectorFilter(const QString &id, const QString &tag, const QString &label, bool multiselect, const QStringList &optionLabels, QObject* parent);
28+
29+ QString filterId() const override;
30+ QString filterTag() const override;
31+ QString title() const override;
32+ QString label() const override;
33+ bool multiSelect() const override;
34+ unity::shell::scopes::OptionSelectorOptionsInterface* options() const override;
35+
36+private:
37+ QString m_filterId;
38+ QString m_filterTag;
39+ QString m_title;
40+ QString m_label;
41+ bool m_multiSelect;
42+ unity::shell::scopes::OptionSelectorOptionsInterface* m_options;
43+};
44+
45+#endif
tests/mocks/Unity/fake_optionselectoroptions.cppnew file+65
@@ -0,0 +1,65 @@
1+/*
2+ * Copyright (C) 2015 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+#include "fake_optionselectoroptions.h"
18+
19+#include "fake_optionselectorfilter.h"
20+
21+FakeOptionSelectorOptions::FakeOptionSelectorOptions(const QStringList &optionLabels, FakeOptionSelectorFilter* parent)
22+ : unity::shell::scopes::OptionSelectorOptionsInterface(parent),
23+ m_optionLabels(optionLabels)
24+{
25+}
26+
27+int FakeOptionSelectorOptions::rowCount(const QModelIndex &parent) const
28+{
29+ if (parent.isValid())
30+ return 0;
31+
32+ return m_optionLabels.count();
33+}
34+
35+QVariant FakeOptionSelectorOptions::data(const QModelIndex &index, int role) const
36+{
37+ const int row = index.row();
38+ if (row < 0 || row >= m_optionLabels.count())
39+ return QVariant();
40+
41+ switch (role) {
42+ case RoleOptionId: {
43+ const QString id = static_cast<FakeOptionSelectorFilter*>(parent())->filterId() + QString::number(row);
44+ return id;
45+ }
46+ case RoleOptionLabel:
47+ return m_optionLabels[row];
48+ case RoleOptionChecked:
49+ return m_checkedIndexes.contains(row);
50+ default:
51+ return QVariant();
52+ }
53+
54+}
55+
56+void FakeOptionSelectorOptions::setChecked(int row, bool checked)
57+{
58+ if (checked) {
59+ m_checkedIndexes << row;
60+ } else {
61+ m_checkedIndexes.remove(row);
62+ }
63+ const QModelIndex idx = index(row, 0);
64+ Q_EMIT dataChanged(idx, idx, QVector<int>() << RoleOptionChecked);
65+}
tests/mocks/Unity/fake_optionselectoroptions.hnew file+42
@@ -0,0 +1,42 @@
1+/*
2+ * Copyright (C) 2015 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+#ifndef FAKE_OPTIONSELECTOROPTIONS_H
18+#define FAKE_OPTIONSELECTOROPTIONS_H
19+
20+#include <unity/shell/scopes/OptionSelectorFilterInterface.h>
21+
22+#include <QSet>
23+
24+class FakeOptionSelectorFilter;
25+
26+class FakeOptionSelectorOptions : public unity::shell::scopes::OptionSelectorOptionsInterface
27+{
28+ Q_OBJECT
29+
30+public:
31+ FakeOptionSelectorOptions(const QStringList &optionLabels, FakeOptionSelectorFilter* parent);
32+
33+ int rowCount(const QModelIndex &parent) const override;
34+ QVariant data(const QModelIndex &index, int role) const override;
35+ Q_INVOKABLE void setChecked(int index, bool checked) override;
36+
37+private:
38+ QStringList m_optionLabels;
39+ QSet<int> m_checkedIndexes;
40+};
41+
42+#endif
tests/mocks/Unity/fake_scope.cpp+33−30
@@ -1,5 +1,5 @@
11/*
2− * Copyright (C) 2013, 2014 Canonical, Ltd.
2+ * Copyright (C) 2013, 2014, 2015 Canonical, Ltd.
33 *
44 * This program is free software; you can redistribute it and/or modify
55 * it under the terms of the GNU General Public License as published by
@@ -19,6 +19,7 @@
1919
2020#include "fake_scope.h"
2121
22+#include "fake_filters.h"
2223#include "fake_navigation.h"
2324#include "fake_resultsmodel.h"
2425#include "fake_scopes.h"
@@ -38,11 +39,11 @@ Scope::Scope(QString const& id, QString const& name, bool favorite, Scopes* pare
3839 , m_favorite(favorite)
3940 , m_isActive(false)
4041 , m_currentNavigationId("root")
41− , m_currentAltNavigationId("altrootChild1")
4242 , m_previewRendererName("preview-generic")
4343 , m_categories(new Categories(categories, this))
4444 , m_openScope(nullptr)
4545 , m_settings(new SettingsModel(this))
46+ , m_filters(new Filters(this))
4647 , m_returnNullPreview(returnNullPreview)
4748{
4849}
@@ -232,16 +233,6 @@ bool Scope::hasNavigation() const
232233 return true;
233234}
234235
235−QString Scope::currentAltNavigationId() const
236−{
237− return m_currentAltNavigationId;
238−}
239−
240−bool Scope::hasAltNavigation() const
241−{
242− return true;
243−}
244−
245236Scope::Status Scope::status() const
246237{
247238 return Status::Okay;
@@ -276,6 +267,11 @@ void Scope::refresh()
276267 Q_EMIT refreshed();
277268}
278269
270+void Scope::resetFilters()
271+{
272+ qWarning() << "Scope::resetFilters is unimplemented";
273+}
274+
279275void Scope::activateAction(QVariant const& /*result*/, QString const& /*categoryId*/, QString const& /*actionId*/)
280276{
281277 qFatal("Using Scope::activateAction");
@@ -298,29 +294,36 @@ unity::shell::scopes::NavigationInterface* Scope::getNavigation(const QString& i
298294 return new Navigation(id, id, "all"+id, parentId, parentLabel, this);
299295}
300296
301−unity::shell::scopes::NavigationInterface* Scope::getAltNavigation(QString const& id)
297+void Scope::setNavigationState(const QString &navigationId)
302298{
303− if (id.isEmpty())
304− return nullptr;
299+ m_currentNavigationId = navigationId;
300+ Q_EMIT currentNavigationIdChanged();
301+}
305302
306− QString parentId;
307− QString parentLabel;
308− if (id != "altroot") {
309− parentId = "altroot";
310− parentLabel = "altroot";
311− }
312− return new Navigation(id, id, "all"+id, parentId, parentLabel, this);
303+unity::shell::scopes::FilterBaseInterface* Scope::primaryNavigationFilter() const
304+{
305+ return nullptr;
313306}
314307
315−void Scope::setNavigationState(const QString &navigationId, bool isAltNavigation)
308+unity::shell::scopes::FiltersInterface* Scope::filters() const
309+{
310+ return m_filters;
311+}
312+
313+QString Scope::primaryNavigationTag() const
314+{
315+ // TODO
316+ return QString();
317+}
318+
319+int Scope::activeFiltersCount() const
320+{
321+ // TODO
322+ return 0;
323+}
324+
325+void Scope::resetPrimaryNavigationTag()
316326{
317− if (isAltNavigation) {
318− m_currentAltNavigationId = navigationId;
319− Q_EMIT currentAltNavigationIdChanged();
320− } else {
321− m_currentNavigationId = navigationId;
322− Q_EMIT currentNavigationIdChanged();
323− }
324327}
325328
326329void Scope::performQuery(const QString& query)
tests/mocks/Unity/fake_scope.h+13−7
@@ -1,5 +1,5 @@
11/*
2− * Copyright (C) 2013, 2014 Canonical, Ltd.
2+ * Copyright (C) 2013, 2014, 2015 Canonical, Ltd.
33 *
44 * This program is free software; you can redistribute it and/or modify
55 * it under the terms of the GNU General Public License as published by
@@ -68,11 +68,15 @@ public:
6868
6969 QString currentNavigationId() const override;
7070 bool hasNavigation() const override;
71− QString currentAltNavigationId() const override;
72− bool hasAltNavigation() const override;
7371 Q_INVOKABLE unity::shell::scopes::NavigationInterface* getNavigation(QString const& navigationId) override;
74− Q_INVOKABLE unity::shell::scopes::NavigationInterface* getAltNavigation(QString const& altNavigationId) override;
75− Q_INVOKABLE void setNavigationState(const QString &navigationId, bool isAltNavigation) override;
72+ Q_INVOKABLE void setNavigationState(const QString &navigationId) override;
73+
74+ unity::shell::scopes::FilterBaseInterface* primaryNavigationFilter() const override;
75+ unity::shell::scopes::FiltersInterface* filters() const override;
76+ QString primaryNavigationTag() const override;
77+ int activeFiltersCount() const override;
78+ Q_INVOKABLE void resetPrimaryNavigationTag() override;
79+
7680 void performQuery(const QString& query) override;
7781
7882 Status status() const override;
@@ -80,7 +84,9 @@ public:
8084
8185 Q_INVOKABLE void refresh() override;
8286
83− Q_INVOKABLE virtual void activateAction(QVariant const& result, QString const& categoryId, QString const& actionId) override;
87+ Q_INVOKABLE void resetFilters() override;
88+
89+ Q_INVOKABLE void activateAction(QVariant const& result, QString const& categoryId, QString const& actionId) override;
8490
8591Q_SIGNALS:
8692 // These are not in the Interface, here for testing benefits
@@ -100,13 +106,13 @@ protected:
100106 bool m_favorite;
101107 bool m_isActive;
102108 QString m_currentNavigationId;
103− QString m_currentAltNavigationId;
104109
105110 QString m_previewRendererName;
106111
107112 unity::shell::scopes::CategoriesInterface* m_categories;
108113 unity::shell::scopes::ScopeInterface* m_openScope;
109114 unity::shell::scopes::SettingsModelInterface* m_settings;
115+ unity::shell::scopes::FiltersInterface* m_filters;
110116
111117 bool m_returnNullPreview;
112118};
tests/qmltests/Dash/tst_DashContent.qml+1−108
@@ -403,119 +403,12 @@ Item {
403403 tryCompare(dashNavigationButton.currentNavigation, "navigationId", "middle2");
404404 }
405405
406− function test_altNavigation() {
407− var dashContentList = findChild(dashContent, "dashContentList");
408− tryCompareFunction(function() { return findChild(dashContentList.currentItem, "dashNavigation") != null; }, true);
409− var dashNavigation = findChild(dashContentList.currentItem, "dashNavigation");
410− tryCompare(dashNavigation, "visible", true);
411− var dashNavigationButton = findChild(dashContentList.currentItem, "altNavigationButton");
412− verify(dashNavigationButton, "Can't find navigation button");
413−
414− compare(dashNavigationButton.showList, false);
415− waitForRendering(dashNavigationButton);
416− mouseClick(dashNavigationButton);
417− compare(dashNavigationButton.showList, true);
418−
419− var navigationListView = findChild(dashNavigationButton, "navigationListView");
420− tryCompareFunction(function() {
421− return navigationListView.currentItem &&
422− navigationListView.currentItem.navigation &&
423− navigationListView.currentItem.navigation.loaded; }, true);
424−
425− waitForRendering(navigationListView);
426− waitForRendering(navigationListView.currentItem);
427−
428− tryCompare(dashNavigationButton.currentNavigation, "navigationId", "altrootChild1");
429− tryCompare(navigationListView.currentItem.navigation, "navigationId", "altroot");
430−
431− var allButton = findChild(dashNavigationButton, "allButton");
432− compare(allButton.visible, false);
433− var backButton = findChild(navigationListView, "backButton");
434− compare(backButton.visible, false);
435−
436− var navigation = findChild(dashNavigationButton, "navigation0child3");
437− mouseClick(navigation);
438− compare(dashNavigationButton.showList, false);
439− tryCompare(dashNavigationButton.currentNavigation, "navigationId", "altrootChild3");
440− tryCompare(navigationListView.currentItem.navigation, "navigationId", "altroot");
441−
442− mouseClick(dashNavigationButton);
443− compare(dashNavigationButton.showList, true);
444− waitForRendering(navigationListView);
445− waitForRendering(navigationListView.currentItem);
446− compare(allButton.visible, false);
447−
448− navigation = findChild(dashNavigationButton, "navigation0child2");
449− mouseClick(navigation);
450− compare(dashNavigationButton.showList, false);
451− tryCompare(dashNavigationButton.currentNavigation, "navigationId", "altrootChild2");
452− tryCompare(navigationListView.currentItem.navigation, "navigationId", "altroot");
453−
454− mouseClick(dashNavigationButton);
455− compare(dashNavigationButton.showList, true);
456− waitForRendering(navigationListView);
457− waitForRendering(navigationListView.currentItem);
458− verify(!backButton.visible, "Back button should not be visible");
459−
460− compare(navigationListView.count, 1, "There should be no second-level navigation");
461−
462− mouseClick(dashNavigationButton);
463− compare(dashNavigationButton.showList, false);
464− }
465−
466− function test_navigationsClosing() {
467− var dashContentList = findChild(dashContent, "dashContentList");
468− tryCompareFunction(function() { return findChild(dashContentList.currentItem, "dashNavigation") != null; }, true);
469− var dashNavigation = findChild(dashContentList.currentItem, "dashNavigation");
470− tryCompare(dashNavigation, "visible", true);
471− var dashNavigationButton = findChild(dashContentList.currentItem, "navigationButton");
472− verify(dashNavigationButton, "Can't find navigation button");
473− var dashAltNavigationButton = findChild(dashContentList.currentItem, "altNavigationButton");
474− verify(dashAltNavigationButton, "Can't find alternative navigation button");
475−
476− waitForRendering(dashNavigationButton);
477− waitForRendering(dashAltNavigationButton);
478−
479− compare(dashNavigationButton.showList, false);
480− compare(dashAltNavigationButton.showList, false);
481−
482− mouseClick(dashAltNavigationButton);
483− compare(dashNavigationButton.showList, false);
484− compare(dashAltNavigationButton.showList, true);
485−
486− var navigationListView = findChild(dashAltNavigationButton, "navigationListView");
487− tryCompareFunction(function() {
488− return navigationListView.currentItem &&
489− navigationListView.currentItem.navigation &&
490− navigationListView.currentItem.navigation.loaded; }, true);
491−
492− var blackRect = findChild(dashNavigation, "blackRect");
493− tryCompare(blackRect, "opacity", 0.5);
494−
495− mouseClick(dashNavigationButton);
496− compare(dashNavigationButton.showList, false);
497− compare(dashAltNavigationButton.showList, false);
498−
499− tryCompare(navigationListView, "visible", false);
500−
501− mouseClick(dashNavigationButton);
502− compare(dashNavigationButton.showList, true);
503− compare(dashAltNavigationButton.showList, false);
504−
505− navigationListView = findChild(dashNavigationButton, "navigationListView");
506− tryCompare(navigationListView.currentItem.navigation, "loaded", true);
507−
508− mouseClick(dashAltNavigationButton);
509− compare(dashNavigationButton.showList, false);
510− compare(dashAltNavigationButton.showList, false);
511− }
512−
513406 function test_navigationsSwipeToNextScope() {
514407 var dashContentList = findChild(dashContent, "dashContentList");
515408 tryCompareFunction(function() { return findChild(dashContentList.currentItem, "dashNavigation") != null; }, true);
516409 var dashNavigation = findChild(dashContentList.currentItem, "dashNavigation");
517410 tryCompare(dashNavigation, "visible", true);
518− var dashNavigationButton = findChild(dashContentList.currentItem, "altNavigationButton");
411+ var dashNavigationButton = findChild(dashContentList.currentItem, "navigationButton");
519412 verify(dashNavigationButton, "Can't find navigation button");
520413
521414 compare(dashNavigationButton.showList, false);