Merge lp:~unity-team/unity-scopes-shell/overview into lp:unity-scopes-shell

Proposed by Michal Hruby
Status: Merged
Approved by: Michal Hruby
Approved revision: 132
Merged at revision: 113
Proposed branch: lp:~unity-team/unity-scopes-shell/overview
Merge into: lp:unity-scopes-shell
Diff against target: 1668 lines (+1114/-52)
29 files modified
debian/changelog (+6/-0)
debian/control (+2/-1)
src/Unity/CMakeLists.txt (+4/-1)
src/Unity/categories.cpp (+20/-14)
src/Unity/categories.h (+3/-2)
src/Unity/overviewcategories.cpp (+144/-0)
src/Unity/overviewcategories.h (+62/-0)
src/Unity/overviewresults.cpp (+183/-0)
src/Unity/overviewresults.h (+62/-0)
src/Unity/overviewscope.cpp (+133/-0)
src/Unity/overviewscope.h (+52/-0)
src/Unity/previewstack.cpp (+3/-2)
src/Unity/resultsmodel.cpp (+20/-0)
src/Unity/resultsmodel.h (+6/-0)
src/Unity/scope.cpp (+34/-8)
src/Unity/scope.h (+11/-5)
src/Unity/scopes.cpp (+38/-1)
src/Unity/scopes.h (+6/-0)
tests/CMakeLists.txt (+5/-4)
tests/data/CMakeLists.txt (+1/-0)
tests/data/mock-scope-ttl/mock-scope-ttl.ini.in (+0/-3)
tests/data/mock-scope/mock-scope.cpp (+2/-2)
tests/data/scopes/CMakeLists.txt (+8/-0)
tests/data/scopes/scopes.cpp (+132/-0)
tests/data/scopes/scopes.ini.in (+8/-0)
tests/overviewtest.cpp (+148/-0)
tests/previewtest.cpp (+2/-2)
tests/resultstest.cpp (+13/-3)
tests/test-utils.h (+6/-4)
To merge this branch: bzr merge lp:~unity-team/unity-scopes-shell/overview
Reviewer Review Type Date Requested Status
PS Jenkins bot (community) continuous-integration Needs Fixing
Pete Woods (community) Approve
Albert Astals Cid (community) functional Approve
Review via email: mp+227745@code.launchpad.net

Commit message

Implement support for the scopes overview.

Description of the change

Implement support for the scopes overview.

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
124. By Michal Hruby

Added missing file

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
125. By Michal Hruby

Pretend we're the scopes scope, so server recommendations work

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
126. By Michal Hruby

Bump dep on libunity-api

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

Been using it with my unity8 branch and can't find nothing wrong.

review: Approve (functional)
Revision history for this message
Pete Woods (pete-woods) wrote :

The code changes look good to me.

review: Approve
127. By Michal Hruby

Merge trunk

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
128. By Michal Hruby

Fix tests

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
129. By Michal Hruby

Merge trunk

130. By Michal Hruby

Fix up things

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
131. By Michal Hruby

Fix tests

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
132. By Michal Hruby

Merge the catch branch

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

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'debian/changelog'
2--- debian/changelog 2014-07-28 15:27:16 +0000
3+++ debian/changelog 2014-07-31 13:04:48 +0000
4@@ -1,3 +1,9 @@
5+unity-scopes-shell (0.5.2-0ubuntu1) UNRELEASED; urgency=medium
6+
7+ * Specialized implementation of scopes overview
8+
9+ -- Michal Hruby <michal.hruby@canonical.com> Wed, 16 Jul 2014 18:18:08 +0100
10+
11 unity-scopes-shell (0.5.0+14.10.20140728.1-0ubuntu1) utopic; urgency=low
12
13 [ Pete Woods ]
14
15=== modified file 'debian/control'
16--- debian/control 2014-07-28 15:20:34 +0000
17+++ debian/control 2014-07-31 13:04:48 +0000
18@@ -3,7 +3,7 @@
19 Section: libs
20 Build-Depends: cmake,
21 debhelper (>= 9),
22- libunity-api-dev (>= 7.85),
23+ libunity-api-dev (>= 7.87),
24 libunity-scopes-dev (>= 0.5.3~),
25 libgsettings-qt-dev (>= 0.1),
26 libqtdbustest1-dev (>= 0.2),
27@@ -35,6 +35,7 @@
28 unity-scopes-impl-0,
29 unity-scopes-impl-1,
30 unity-scopes-impl-2,
31+ unity-scopes-impl-3,
32 Breaks: unity8-private (<< 7.84)
33 Replaces: unity8-private (<< 7.84)
34 Description: QML plugin for Scopes
35
36=== modified file 'src/Unity/CMakeLists.txt'
37--- src/Unity/CMakeLists.txt 2014-07-25 15:30:02 +0000
38+++ src/Unity/CMakeLists.txt 2014-07-31 13:04:48 +0000
39@@ -2,7 +2,7 @@
40 include(Plugins)
41
42 # Dependencies
43-pkg_check_modules(SCOPES_API REQUIRED unity-shell-scopes=2)
44+pkg_check_modules(SCOPES_API REQUIRED unity-shell-scopes=3)
45 pkg_check_modules(SCOPESLIB REQUIRED libunity-scopes>=0.5.3)
46 pkg_check_modules(GSETTINGSQT REQUIRED gsettings-qt)
47 pkg_check_modules(U1DB REQUIRED libu1db-qt5)
48@@ -24,6 +24,9 @@
49 departmentnode.cpp
50 geoip.cpp
51 locationservice.cpp
52+ overviewcategories.cpp
53+ overviewresults.cpp
54+ overviewscope.cpp
55 previewmodel.cpp
56 previewstack.cpp
57 previewwidgetmodel.cpp
58
59=== modified file 'src/Unity/categories.cpp'
60--- src/Unity/categories.cpp 2014-07-24 15:21:23 +0000
61+++ src/Unity/categories.cpp 2014-07-31 13:04:48 +0000
62@@ -39,7 +39,7 @@
63 namespace scopes_ng {
64
65 // FIXME: this should be in a common place
66-#define CATEGORY_JSON_DEFAULTS R"({"schema-version":1,"template": {"category-layout":"grid","card-layout":"vertical","card-size":"small","overlay-mode":null,"collapsed-rows":2}, "components": { "title":null, "art": { "aspect-ratio":1.0, "fill-mode":"crop" }, "subtitle":null, "mascot":null, "emblem":null, "summary":null, "attributes": { "max-count":2 }, "background":null }, "resources":{}})"
67+#define CATEGORY_JSON_DEFAULTS R"({"schema-version":1,"template": {"category-layout":"grid","card-layout":"vertical","card-size":"small","overlay-mode":null,"collapsed-rows":2}, "components": { "title":null, "art": { "aspect-ratio":1.0, "fill-mode":"crop" }, "subtitle":null, "mascot":null, "emblem":null, "summary":null, "attributes": { "max-count":2 }, "background":null, "overlay-color":null }, "resources":{}})"
68
69 class CategoryData
70 {
71@@ -219,19 +219,6 @@
72 return m_isSpecial;
73 }
74
75-private:
76- static QJsonValue* DEFAULTS;
77- scopes::Category::SCPtr m_category;
78- QString m_catId;
79- QString m_catTitle;
80- QString m_catIcon;
81- std::string m_rawTemplate;
82- QJsonValue m_rendererTemplate;
83- QJsonValue m_components;
84- ResultsModel* m_resultsModel;
85- QPointer<QObject> m_countObject;
86- bool m_isSpecial;
87-
88 static bool parseTemplate(std::string const& raw_template, QJsonValue* renderer, QJsonValue* components)
89 {
90 // lazy init of the defaults
91@@ -265,6 +252,19 @@
92 return true;
93 }
94
95+private:
96+ static QJsonValue* DEFAULTS;
97+ scopes::Category::SCPtr m_category;
98+ QString m_catId;
99+ QString m_catTitle;
100+ QString m_catIcon;
101+ std::string m_rawTemplate;
102+ QJsonValue m_rendererTemplate;
103+ QJsonValue m_components;
104+ ResultsModel* m_resultsModel;
105+ QPointer<QObject> m_countObject;
106+ bool m_isSpecial;
107+
108 static QJsonValue mergeOverrides(QJsonValue const& defaultVal, QJsonValue const& overrideVal)
109 {
110 if (overrideVal.isObject() && defaultVal.isObject()) {
111@@ -440,6 +440,12 @@
112 dataChanged(changeStart, changeEnd, roles);
113 }
114
115+
116+bool Categories::parseTemplate(std::string const& raw_template, QJsonValue* renderer, QJsonValue* components)
117+{
118+ return CategoryData::parseTemplate(raw_template, renderer, components);
119+}
120+
121 bool Categories::overrideCategoryJson(QString const& categoryId, QString const& json)
122 {
123 int idx = getCategoryIndex(categoryId);
124
125=== modified file 'src/Unity/categories.h'
126--- src/Unity/categories.h 2014-05-13 13:59:41 +0000
127+++ src/Unity/categories.h 2014-07-31 13:04:48 +0000
128@@ -24,9 +24,8 @@
129
130 #include <unity/shell/scopes/CategoriesInterface.h>
131
132-#include <QSet>
133-#include <QTimer>
134 #include <QSharedPointer>
135+#include <QJsonValue>
136
137 #include <unity/scopes/Category.h>
138
139@@ -55,6 +54,8 @@
140 void updateResultCount(ResultsModel* resultsModel);
141 void clearAll();
142
143+ static bool parseTemplate(std::string const& raw_template, QJsonValue* renderer, QJsonValue* components);
144+
145 private Q_SLOTS:
146 void countChanged();
147
148
149=== added file 'src/Unity/overviewcategories.cpp'
150--- src/Unity/overviewcategories.cpp 1970-01-01 00:00:00 +0000
151+++ src/Unity/overviewcategories.cpp 2014-07-31 13:04:48 +0000
152@@ -0,0 +1,144 @@
153+/*
154+ * Copyright (C) 2013 Canonical, Ltd.
155+ *
156+ * Authors:
157+ * Michał Sawicz <michal.sawicz@canonical.com>
158+ * Michal Hruby <michal.hruby@canonical.com>
159+ *
160+ * This program is free software; you can redistribute it and/or modify
161+ * it under the terms of the GNU General Public License as published by
162+ * the Free Software Foundation; version 3.
163+ *
164+ * This program is distributed in the hope that it will be useful,
165+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
166+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
167+ * GNU General Public License for more details.
168+ *
169+ * You should have received a copy of the GNU General Public License
170+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
171+ */
172+
173+// self
174+#include "overviewcategories.h"
175+
176+// local
177+#include "overviewresults.h"
178+#include "utils.h"
179+
180+namespace scopes_ng
181+{
182+
183+#define CATEGORY_JSON R"({"schema-version":1,"template": {"category-layout":"grid","card-size":"small","overlay":true}, "components": { "title":"title", "art": {"field":"art", "aspect-ratio": 0.5}, "overlay-color": "overlay-color"}})"
184+
185+struct ScopesCategoryData
186+{
187+ QString categoryId;
188+ QString rawTemplate;
189+ QVariant rendererVar;
190+ QVariant componentsVar;
191+
192+ ScopesCategoryData(QString const& id, QString const& jsonTemplate): categoryId(id), rawTemplate(jsonTemplate)
193+ {
194+ QJsonValue rendererTemplate;
195+ QJsonValue components;
196+
197+ Categories::parseTemplate(jsonTemplate.toStdString(), &rendererTemplate, &components);
198+ rendererVar = rendererTemplate.toVariant();
199+ componentsVar = components.toVariant();
200+ }
201+};
202+
203+OverviewCategories::OverviewCategories(QObject* parent)
204+ : scopes_ng::Categories(parent)
205+ , m_isSurfacing(true)
206+{
207+ m_allScopes.reset(new OverviewResultsModel(this));
208+ m_favouriteScopes.reset(new OverviewResultsModel(this));
209+
210+ m_surfaceCategories.append(QSharedPointer<ScopesCategoryData>(new ScopesCategoryData("favorites", CATEGORY_JSON)));
211+ m_surfaceCategories.append(QSharedPointer<ScopesCategoryData>(new ScopesCategoryData("all", CATEGORY_JSON)));
212+}
213+
214+OverviewCategories::~OverviewCategories()
215+{
216+}
217+
218+void OverviewCategories::setSurfacingMode(bool surfacingMode)
219+{
220+ if (m_isSurfacing != surfacingMode) {
221+ beginResetModel();
222+ m_isSurfacing = surfacingMode;
223+ endResetModel();
224+ }
225+}
226+
227+void OverviewCategories::setAllScopes(const QList<unity::scopes::ScopeMetadata::SPtr>& scopes)
228+{
229+ m_allScopes->setResults(scopes);
230+
231+ if (!m_isSurfacing) return;
232+
233+ QVector<int> roles;
234+ roles.append(RoleCount);
235+
236+ QModelIndex changedIndex(index(1));
237+ dataChanged(changedIndex, changedIndex, roles);
238+}
239+
240+void OverviewCategories::setFavouriteScopes(const QList<unity::scopes::ScopeMetadata::SPtr>& scopes)
241+{
242+ m_favouriteScopes->setResults(scopes);
243+
244+ if (!m_isSurfacing) return;
245+
246+ QVector<int> roles;
247+ roles.append(RoleCount);
248+
249+ QModelIndex changedIndex(index(0));
250+ dataChanged(changedIndex, changedIndex, roles);
251+}
252+
253+int OverviewCategories::rowCount(const QModelIndex& parent) const
254+{
255+ if (m_isSurfacing) {
256+ return m_surfaceCategories.size();
257+ } else {
258+ return Categories::rowCount(parent);
259+ }
260+}
261+
262+QVariant
263+OverviewCategories::data(const QModelIndex& index, int role) const
264+{
265+ if (!m_isSurfacing) {
266+ return Categories::data(index, role);
267+ }
268+
269+ ScopesCategoryData* catData = m_surfaceCategories.at(index.row()).data();
270+ OverviewResultsModel* results = index.row() == 0 ? m_favouriteScopes.data() : m_allScopes.data();
271+
272+ switch (role) {
273+ case RoleCategoryId:
274+ return catData->categoryId;
275+ case RoleName:
276+ return QVariant();
277+ case RoleIcon:
278+ return QVariant();
279+ case RoleRawRendererTemplate:
280+ return catData->rawTemplate;
281+ case RoleRenderer:
282+ return catData->rendererVar;
283+ case RoleComponents:
284+ return catData->componentsVar;
285+ case RoleHeaderLink:
286+ return QVariant();
287+ case RoleResults:
288+ return QVariant::fromValue(results);
289+ case RoleCount:
290+ return QVariant(results->rowCount());
291+ default:
292+ return QVariant();
293+ }
294+}
295+
296+} // namespace scopes_ng
297
298=== added file 'src/Unity/overviewcategories.h'
299--- src/Unity/overviewcategories.h 1970-01-01 00:00:00 +0000
300+++ src/Unity/overviewcategories.h 2014-07-31 13:04:48 +0000
301@@ -0,0 +1,62 @@
302+/*
303+ * Copyright (C) 2014 Canonical, Ltd.
304+ *
305+ * Authors:
306+ * Michal Hruby <michal.hruby@canonical.com>
307+ *
308+ * This program is free software; you can redistribute it and/or modify
309+ * it under the terms of the GNU General Public License as published by
310+ * the Free Software Foundation; version 3.
311+ *
312+ * This program is distributed in the hope that it will be useful,
313+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
314+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
315+ * GNU General Public License for more details.
316+ *
317+ * You should have received a copy of the GNU General Public License
318+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
319+ */
320+
321+
322+#ifndef NG_OVERVIEW_CATEGORIES_H
323+#define NG_OVERVIEW_CATEGORIES_H
324+
325+#include <unity/scopes/ScopeMetadata.h>
326+
327+#include "categories.h"
328+
329+namespace scopes_ng
330+{
331+
332+class ScopesCategoryData;
333+class OverviewResultsModel;
334+
335+class Q_DECL_EXPORT OverviewCategories : public scopes_ng::Categories
336+{
337+ Q_OBJECT
338+
339+public:
340+ explicit OverviewCategories(QObject* parent = 0);
341+ virtual ~OverviewCategories();
342+
343+ void setSurfacingMode(bool isSurfacing);
344+
345+ QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;
346+ int rowCount(const QModelIndex& parent = QModelIndex()) const override;
347+
348+ void setAllScopes(const QList<unity::scopes::ScopeMetadata::SPtr>& scopes);
349+ void setFavouriteScopes(const QList<unity::scopes::ScopeMetadata::SPtr>& scopes);
350+
351+private:
352+ bool m_isSurfacing;
353+
354+ QList<QSharedPointer<ScopesCategoryData>> m_surfaceCategories;
355+ QScopedPointer<OverviewResultsModel> m_allScopes;
356+ QScopedPointer<OverviewResultsModel> m_favouriteScopes;
357+};
358+
359+} // namespace scopes_ng
360+
361+Q_DECLARE_METATYPE(scopes_ng::OverviewCategories*)
362+
363+#endif // NG_OVERVIEW_CATEGORIES_H
364
365=== added file 'src/Unity/overviewresults.cpp'
366--- src/Unity/overviewresults.cpp 1970-01-01 00:00:00 +0000
367+++ src/Unity/overviewresults.cpp 2014-07-31 13:04:48 +0000
368@@ -0,0 +1,183 @@
369+/*
370+ * Copyright (C) 2014 Canonical, Ltd.
371+ *
372+ * Authors:
373+ * Michal Hruby <michal.hruby@canonical.com>
374+ *
375+ * This program is free software; you can redistribute it and/or modify
376+ * it under the terms of the GNU General Public License as published by
377+ * the Free Software Foundation; version 3.
378+ *
379+ * This program is distributed in the hope that it will be useful,
380+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
381+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
382+ * GNU General Public License for more details.
383+ *
384+ * You should have received a copy of the GNU General Public License
385+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
386+ */
387+
388+// self
389+#include "overviewresults.h"
390+
391+// local
392+#include "resultsmodel.h"
393+#include "utils.h"
394+
395+#include <unity/scopes/Result.h>
396+
397+namespace scopes_ng {
398+
399+using namespace unity;
400+
401+class FakeResult: public scopes::Result
402+{
403+public:
404+ FakeResult(scopes::ScopeMetadata const& metadata): Result(map_for_meta(metadata)) {}
405+
406+private:
407+ // HACK: we need to create a fake result understood by the scopes scope, so it can create a proper preview
408+ static scopes::VariantMap map_for_meta(scopes::ScopeMetadata const& metadata)
409+ {
410+ scopes::VariantMap map;
411+ scopes::VariantMap internal;
412+ scopes::VariantMap attrs;
413+
414+ internal["origin"] = "scopes";
415+ map["internal"] = internal;
416+
417+ attrs["title"] = metadata.display_name();
418+ try {
419+ attrs["art"] = metadata.art();
420+ } catch (...) {}
421+ try {
422+ attrs["icon"] = metadata.icon();
423+ } catch (...) {}
424+ attrs["description"] = metadata.description();
425+ attrs["uri"] = scopes::CannedQuery(metadata.scope_id()).to_uri();
426+ map["attrs"] = attrs;
427+
428+ return map;
429+ }
430+};
431+
432+OverviewResultsModel::OverviewResultsModel(QObject* parent)
433+ : unity::shell::scopes::ResultsModelInterface(parent)
434+{
435+}
436+
437+void OverviewResultsModel::setResults(const QList<unity::scopes::ScopeMetadata::SPtr>& results)
438+{
439+ beginResetModel();
440+ m_results = results;
441+ endResetModel();
442+}
443+
444+QString OverviewResultsModel::categoryId() const
445+{
446+ return QString();
447+}
448+
449+void OverviewResultsModel::setCategoryId(const QString& id)
450+{
451+ Q_UNUSED(id);
452+}
453+
454+int OverviewResultsModel::rowCount(const QModelIndex& parent) const
455+{
456+ Q_UNUSED(parent);
457+
458+ return m_results.count();
459+}
460+
461+int OverviewResultsModel::count() const
462+{
463+ return m_results.count();
464+}
465+
466+int OverviewResultsModel::scopeIndex(const QString& scopeId) const
467+{
468+ std::string id(scopeId.toStdString());
469+
470+ for (int i = 0; i < m_results.size(); i++) {
471+ if (m_results.at(i)->scope_id() == id) return i;
472+ }
473+
474+ return -1;
475+}
476+
477+QHash<int, QByteArray> OverviewResultsModel::roleNames() const
478+{
479+ QHash<int, QByteArray> roles(unity::shell::scopes::ResultsModelInterface::roleNames());
480+ roles.insert(ExtraRoles::RoleScopeId, "scopeId");
481+
482+ return roles;
483+}
484+
485+QVariant
486+OverviewResultsModel::data(const QModelIndex& index, int role) const
487+{
488+ scopes::ScopeMetadata* metadata = m_results.at(index.row()).get();
489+
490+ switch (role) {
491+ case RoleUri: {
492+ scopes::CannedQuery q(metadata->scope_id());
493+ return QString::fromStdString(q.to_uri());
494+ }
495+ case RoleCategoryId:
496+ return QVariant();
497+ case RoleDndUri:
498+ return data(index, RoleUri);
499+ case RoleResult: {
500+ scopes::Result::SPtr result(new FakeResult(*metadata));
501+ return QVariant::fromValue(result);
502+ }
503+ case RoleTitle:
504+ return QString::fromStdString(metadata->display_name());
505+ case RoleArt: {
506+ std::string art;
507+ try {
508+ art = metadata->icon();
509+ } catch (...) {
510+ try {
511+ art = metadata->art();
512+ } catch (...) {
513+ // no icon, oh well
514+ }
515+ }
516+ return QString::fromStdString(art);
517+ }
518+ case RoleSubtitle:
519+ return QVariant();
520+ case RoleMascot:
521+ return QVariant();
522+ case RoleEmblem:
523+ return QVariant();
524+ case RoleAttributes:
525+ return QVariant();
526+ case RoleSummary:
527+ return QVariant();
528+ case RoleBackground:
529+ return QVariant();
530+ case RoleOverlayColor: {
531+ try {
532+ std::string color;
533+ auto attrs = metadata->appearance_attributes();
534+ auto it = attrs.find("logo-overlay-color");
535+ if (it != attrs.end()) {
536+ color = it->second.get_string();
537+ return QString::fromStdString(color);
538+ }
539+ } catch (...) {
540+ // silently ignore
541+ }
542+ return QVariant();
543+ }
544+ case RoleScopeId:
545+ return QString::fromStdString(metadata->scope_id());
546+ default:
547+ return QVariant();
548+ }
549+}
550+
551+} // namespace scopes_ng
552
553=== added file 'src/Unity/overviewresults.h'
554--- src/Unity/overviewresults.h 1970-01-01 00:00:00 +0000
555+++ src/Unity/overviewresults.h 2014-07-31 13:04:48 +0000
556@@ -0,0 +1,62 @@
557+/*
558+ * Copyright (C) 2014 Canonical, Ltd.
559+ *
560+ * Authors:
561+ * Michal Hruby <michal.hruby@canonical.com>
562+ *
563+ * This program is free software; you can redistribute it and/or modify
564+ * it under the terms of the GNU General Public License as published by
565+ * the Free Software Foundation; version 3.
566+ *
567+ * This program is distributed in the hope that it will be useful,
568+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
569+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
570+ * GNU General Public License for more details.
571+ *
572+ * You should have received a copy of the GNU General Public License
573+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
574+ */
575+
576+
577+#ifndef NG_OVERVIEW_RESULTS_H
578+#define NG_OVERVIEW_RESULTS_H
579+
580+#include <unity/shell/scopes/ResultsModelInterface.h>
581+#include <unity/scopes/ScopeMetadata.h>
582+
583+#include <QHash>
584+
585+namespace scopes_ng {
586+
587+class Q_DECL_EXPORT OverviewResultsModel : public unity::shell::scopes::ResultsModelInterface
588+{
589+ Q_OBJECT
590+
591+public:
592+ enum ExtraRoles {
593+ RoleScopeId = unity::shell::scopes::ResultsModelInterface::Roles::RoleBackground + 100
594+ };
595+
596+ explicit OverviewResultsModel(QObject* parent = 0);
597+
598+ void setResults(const QList<unity::scopes::ScopeMetadata::SPtr>& results);
599+
600+ int rowCount(const QModelIndex& parent = QModelIndex()) const override;
601+ QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;
602+
603+ int count() const override;
604+
605+ QString categoryId() const override;
606+ void setCategoryId(QString const& id) override;
607+
608+ QHash<int, QByteArray> roleNames() const override;
609+
610+ Q_INVOKABLE int scopeIndex(const QString& scopeId) const;
611+
612+private:
613+ QList<unity::scopes::ScopeMetadata::SPtr> m_results;
614+};
615+
616+} // namespace scopes_ng
617+
618+#endif // NG_OVERVIEW_RESULTS_H
619
620=== added file 'src/Unity/overviewscope.cpp'
621--- src/Unity/overviewscope.cpp 1970-01-01 00:00:00 +0000
622+++ src/Unity/overviewscope.cpp 2014-07-31 13:04:48 +0000
623@@ -0,0 +1,133 @@
624+/*
625+ * Copyright (C) 2014 Canonical, Ltd.
626+ *
627+ * Authors:
628+ * Michal Hruby <michal.hruby@canonical.com>
629+ *
630+ * This program is free software; you can redistribute it and/or modify
631+ * it under the terms of the GNU General Public License as published by
632+ * the Free Software Foundation; version 3.
633+ *
634+ * This program is distributed in the hope that it will be useful,
635+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
636+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
637+ * GNU General Public License for more details.
638+ *
639+ * You should have received a copy of the GNU General Public License
640+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
641+ */
642+
643+// Self
644+#include "overviewscope.h"
645+
646+// local
647+#include "overviewcategories.h"
648+#include "scopes.h"
649+#include "utils.h"
650+
651+// Qt
652+#include <QScopedPointer>
653+
654+namespace scopes_ng
655+{
656+
657+using namespace unity;
658+
659+OverviewScope::OverviewScope(QObject *parent) : scopes_ng::Scope(parent)
660+{
661+ m_categories.reset(new OverviewCategories(this));
662+
663+ QObject::connect(m_scopesInstance.data(), &Scopes::metadataRefreshed, this, &OverviewScope::metadataChanged);
664+}
665+
666+OverviewScope::~OverviewScope()
667+{
668+}
669+
670+struct ScopeInfo {
671+ scopes::ScopeMetadata::SPtr data;
672+ QString name;
673+
674+ ScopeInfo(scopes::ScopeMetadata::SPtr const& data_):
675+ data(data_), name(QString::fromStdString(data->display_name())) {}
676+};
677+
678+bool operator<(ScopeInfo const& first, ScopeInfo const& second)
679+{
680+ return first.name.compare(second.name, Qt::CaseInsensitive) < 0;
681+}
682+
683+void OverviewScope::metadataChanged()
684+{
685+ OverviewCategories* categories = qobject_cast<OverviewCategories*>(m_categories.data());
686+ if (!categories) {
687+ qWarning("Unable to cast m_categories to OverviewCategories");
688+ return;
689+ }
690+
691+ QMap<QString, scopes::ScopeMetadata::SPtr> allMetadata = m_scopesInstance->getAllMetadata();
692+ QList<scopes::ScopeMetadata::SPtr> favourites;
693+ Q_FOREACH(QString id, m_scopesInstance->getFavoriteIds()) {
694+ auto it = allMetadata.find(id);
695+ if (it != allMetadata.end()) {
696+ favourites.append(it.value());
697+ }
698+ }
699+
700+ QList<ScopeInfo> scopes;
701+ Q_FOREACH(scopes::ScopeMetadata::SPtr const& metadata, allMetadata.values()) {
702+ if (metadata->invisible()) continue;
703+ scopes.append(ScopeInfo(metadata));
704+ }
705+ qSort(scopes.begin(), scopes.end());
706+
707+ QList<scopes::ScopeMetadata::SPtr> allScopes;
708+ Q_FOREACH(ScopeInfo const& info, scopes) {
709+ allScopes << info.data;
710+ }
711+
712+ // FIXME: filter invisible scopes?
713+ categories->setAllScopes(allScopes);
714+ categories->setFavouriteScopes(favourites);
715+}
716+
717+QString OverviewScope::id() const
718+{
719+ return QString("scopes");
720+}
721+
722+bool OverviewScope::visible() const
723+{
724+ return false;
725+}
726+
727+scopes::ScopeProxy OverviewScope::proxy_for_result(scopes::Result::SPtr const& result) const
728+{
729+ try {
730+ return result->target_scope_proxy();
731+ } catch (...) {
732+ // our fake results don't have a proxy associated, return the default one
733+ return proxy();
734+ }
735+}
736+
737+void OverviewScope::dispatchSearch()
738+{
739+ OverviewCategories* categories = qobject_cast<OverviewCategories*>(m_categories.data());
740+ if (!categories) {
741+ qWarning("Unable to cast m_categories to OverviewCategories");
742+ return;
743+ }
744+
745+ if (searchQuery().isEmpty()) {
746+ setSearchInProgress(true);
747+ invalidateLastSearch();
748+ categories->setSurfacingMode(true);
749+ setSearchInProgress(false);
750+ } else {
751+ categories->setSurfacingMode(false);
752+ Scope::dispatchSearch();
753+ }
754+}
755+
756+} // namespace scopes_ng
757
758=== added file 'src/Unity/overviewscope.h'
759--- src/Unity/overviewscope.h 1970-01-01 00:00:00 +0000
760+++ src/Unity/overviewscope.h 2014-07-31 13:04:48 +0000
761@@ -0,0 +1,52 @@
762+/*
763+ * Copyright (C) 2014 Canonical, Ltd.
764+ *
765+ * Authors:
766+ * Michal Hruby <michal.hruby@canonical.com>
767+ *
768+ * This program is free software; you can redistribute it and/or modify
769+ * it under the terms of the GNU General Public License as published by
770+ * the Free Software Foundation; version 3.
771+ *
772+ * This program is distributed in the hope that it will be useful,
773+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
774+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
775+ * GNU General Public License for more details.
776+ *
777+ * You should have received a copy of the GNU General Public License
778+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
779+ */
780+
781+#ifndef NG_OVERVIEW_SCOPE_H
782+#define NG_OVERVIEW_SCOPE_H
783+
784+#include "scope.h"
785+
786+namespace scopes_ng
787+{
788+
789+class Q_DECL_EXPORT OverviewScope : public scopes_ng::Scope
790+{
791+ Q_OBJECT
792+
793+public:
794+ explicit OverviewScope(QObject *parent = 0);
795+ virtual ~OverviewScope();
796+
797+ /* getters */
798+ QString id() const override;
799+ bool visible() const override;
800+
801+ void dispatchSearch() override;
802+
803+ unity::scopes::ScopeProxy proxy_for_result(unity::scopes::Result::SPtr const& result) const override;
804+
805+private Q_SLOTS:
806+ void metadataChanged();
807+};
808+
809+} // namespace scopes_ng
810+
811+Q_DECLARE_METATYPE(scopes_ng::OverviewScope*)
812+
813+#endif // NG_OVERVIEW_SCOPE_H
814
815=== modified file 'src/Unity/previewstack.cpp'
816--- src/Unity/previewstack.cpp 2014-05-19 09:58:14 +0000
817+++ src/Unity/previewstack.cpp 2014-07-31 13:04:48 +0000
818@@ -112,7 +112,7 @@
819 // TODO: figure out if the result can produce a preview without sending a request to the scope
820 // if (m_previewedResult->has_early_preview()) { ... }
821 try {
822- auto proxy = m_previewedResult->target_scope_proxy();
823+ auto proxy = m_associatedScope ? m_associatedScope->proxy_for_result(m_previewedResult) : m_previewedResult->target_scope_proxy();
824
825 QString formFactor(m_associatedScope ? m_associatedScope->formFactor() : "phone");
826 scopes::ActionMetadata metadata(QLocale::system().name().toStdString(), formFactor.toStdString());
827@@ -153,7 +153,8 @@
828 }
829
830 try {
831- auto proxy = m_previewedResult->target_scope_proxy();
832+ auto proxy = m_associatedScope ? m_associatedScope->proxy_for_result(m_previewedResult) : m_previewedResult->target_scope_proxy();
833+
834 QString formFactor(m_associatedScope ? m_associatedScope->formFactor() : "phone");
835 scopes::ActionMetadata metadata(QLocale::system().name().toStdString(), formFactor.toStdString());
836 metadata.set_scope_data(qVariantToScopeVariant(data));
837
838=== modified file 'src/Unity/resultsmodel.cpp'
839--- src/Unity/resultsmodel.cpp 2014-07-24 15:21:23 +0000
840+++ src/Unity/resultsmodel.cpp 2014-07-31 13:04:48 +0000
841@@ -167,6 +167,14 @@
842 return attributes;
843 }
844
845+QHash<int, QByteArray> ResultsModel::roleNames() const
846+{
847+ QHash<int, QByteArray> roles(unity::shell::scopes::ResultsModelInterface::roleNames());
848+ roles.insert(ExtraRoles::RoleScopeId, "scopeId");
849+
850+ return roles;
851+}
852+
853 QVariant
854 ResultsModel::data(const QModelIndex& index, int role) const
855 {
856@@ -217,6 +225,18 @@
857 }
858 return backgroundUriToVariant(backgroundVariant.toString());
859 }
860+ case RoleOverlayColor:
861+ return componentValue(result, "overlay-color");
862+ case RoleScopeId:
863+ if (result->uri().compare(0, 8, "scope://") == 0) {
864+ try {
865+ scopes::CannedQuery q(scopes::CannedQuery::from_uri(result->uri()));
866+ return QString::fromStdString(q.scope_id());
867+ } catch (...) {
868+ // silently ignore and return "undefined"
869+ }
870+ }
871+ return QVariant();
872 default:
873 return QVariant();
874 }
875
876=== modified file 'src/Unity/resultsmodel.h'
877--- src/Unity/resultsmodel.h 2014-07-24 15:21:23 +0000
878+++ src/Unity/resultsmodel.h 2014-07-31 13:04:48 +0000
879@@ -35,6 +35,10 @@
880 Q_OBJECT
881
882 public:
883+ enum ExtraRoles {
884+ RoleScopeId = unity::shell::scopes::ResultsModelInterface::Roles::RoleBackground + 100
885+ };
886+
887 explicit ResultsModel(QObject* parent = 0);
888
889 int rowCount(const QModelIndex& parent = QModelIndex()) const override;
890@@ -52,6 +56,8 @@
891 void setComponentsMapping(QHash<QString, QString> const& mapping);
892 void setMaxAtrributesCount(int count);
893
894+ QHash<int, QByteArray> roleNames() const override;
895+
896 private:
897 QVariant componentValue(unity::scopes::CategorisedResult const* result, std::string const& fieldName) const;
898 QVariant attributesValue(unity::scopes::CategorisedResult const* result) const;
899
900=== modified file 'src/Unity/scope.cpp'
901--- src/Unity/scope.cpp 2014-07-25 15:30:02 +0000
902+++ src/Unity/scope.cpp 2014-07-31 13:04:48 +0000
903@@ -74,7 +74,7 @@
904 , m_searchController(new CollectionController)
905 , m_activationController(new CollectionController)
906 {
907- m_categories = new Categories(this);
908+ m_categories.reset(new Categories(this));
909
910 m_settings = QGSettings::isSchemaInstalled("com.canonical.Unity.Lenses") ? new QGSettings("com.canonical.Unity.Lenses", QByteArray(), this) : nullptr;
911 QObject::connect(m_settings, &QGSettings::changed, this, &Scope::internetFlagChanged);
912@@ -216,13 +216,20 @@
913 QString scopeId(QString::fromStdString(query.scope_id()));
914 QString searchString(QString::fromStdString(query.query_string()));
915 QString departmentId(QString::fromStdString(query.department_id()));
916- // figure out if this scope is already favourited
917- Scope* scope = m_scopesInstance->getScopeById(scopeId);
918+
919+ Scope* scope = nullptr;
920+ if (scopeId == id()) {
921+ scope = this;
922+ } else {
923+ // figure out if this scope is already favourited
924+ scope = m_scopesInstance->getScopeById(scopeId);
925+ }
926+
927 if (scope != nullptr) {
928 // TODO: change filters?
929 scope->setCurrentDepartmentId(departmentId);
930 scope->setSearchQuery(searchString);
931- Q_EMIT gotoScope(scopeId);
932+ if (scope != this) Q_EMIT gotoScope(scopeId);
933 } else {
934 // create temp dash page
935 auto meta_sptr = m_scopesInstance->getCachedMetadata(scopeId);
936@@ -405,7 +412,7 @@
937 Q_FOREACH(scopes::Category::SCPtr const& category, categories) {
938 ResultsModel* category_model = m_categories->lookupCategory(category->id());
939 if (category_model == nullptr) {
940- category_model = new ResultsModel(m_categories);
941+ category_model = new ResultsModel(m_categories.data());
942 category_model->setCategoryId(QString::fromStdString(category->id()));
943 category_model->addResults(category_results[category->id()]);
944 m_categories->registerCategory(category, category_model);
945@@ -418,6 +425,16 @@
946 }
947 }
948
949+scopes::ScopeProxy Scope::proxy() const
950+{
951+ return m_proxy;
952+}
953+
954+scopes::ScopeProxy Scope::proxy_for_result(scopes::Result::SPtr const& result) const
955+{
956+ return result->target_scope_proxy();
957+}
958+
959 void Scope::invalidateLastSearch()
960 {
961 m_searchController->invalidate();
962@@ -608,7 +625,16 @@
963
964 QString Scope::searchHint() const
965 {
966- return QString::fromStdString(m_scopeMetadata ? m_scopeMetadata->search_hint() : "");
967+ std::string search_hint;
968+ try {
969+ if (m_scopeMetadata) {
970+ search_hint = m_scopeMetadata->search_hint();
971+ }
972+ } catch (...) {
973+ // throws if the value isn't set, safe to ignore
974+ }
975+
976+ return QString::fromStdString(search_hint);
977 }
978
979 bool Scope::searchInProgress() const
980@@ -638,7 +664,7 @@
981
982 unity::shell::scopes::CategoriesInterface* Scope::categories() const
983 {
984- return m_categories;
985+ return m_categories.data();
986 }
987
988 unity::shell::scopes::SettingsModelInterface* Scope::settings() const
989@@ -813,7 +839,7 @@
990 scopes::ActivationListenerBase::SPtr listener(new ActivationReceiver(this, result));
991 m_activationController->setListener(listener);
992
993- auto proxy = result->target_scope_proxy();
994+ auto proxy = proxy_for_result(result);
995 unity::scopes::ActionMetadata metadata(QLocale::system().name().toStdString(), m_formFactor.toStdString());
996 scopes::QueryCtrlProxy controller = proxy->activate(*(result.get()), metadata, listener);
997 m_activationController->setController(controller);
998
999=== modified file 'src/Unity/scope.h'
1000--- src/Unity/scope.h 2014-07-20 17:14:37 +0000
1001+++ src/Unity/scope.h 2014-07-31 13:04:48 +0000
1002@@ -148,6 +148,7 @@
1003 void activateUri(QString const& uri);
1004
1005 bool resultsDirty() const;
1006+ virtual unity::scopes::ScopeProxy proxy_for_result(unity::scopes::Result::SPtr const& result) const;
1007
1008 public Q_SLOTS:
1009 void invalidateResults();
1010@@ -161,17 +162,24 @@
1011 void internetFlagChanged(QString const& key);
1012 void departmentModelDestroyed(QObject* obj);
1013
1014+protected:
1015+ void setSearchInProgress(bool searchInProgress);
1016+ void invalidateLastSearch();
1017+ virtual void dispatchSearch();
1018+
1019+ unity::scopes::ScopeProxy proxy() const;
1020+
1021+ QScopedPointer<Categories> m_categories;
1022+ QPointer<Scopes> m_scopesInstance;
1023+
1024 private:
1025 void setScopesInstance(Scopes*);
1026 void startTtlTimer();
1027- void setSearchInProgress(bool searchInProgress);
1028 void setCurrentDepartmentId(QString const& id);
1029 void processSearchChunk(PushEvent* pushEvent);
1030 void executeCannedQuery(unity::scopes::CannedQuery const& query, bool allowDelayedActivation);
1031
1032 void processResultSet(QList<std::shared_ptr<unity::scopes::CategorisedResult>>& result_set);
1033- void dispatchSearch();
1034- void invalidateLastSearch();
1035
1036 static unity::scopes::Department::SCPtr findDepartmentById(unity::scopes::Department::SCPtr const& root, std::string const& id);
1037 static unity::scopes::Department::SCPtr findUpdateNode(DepartmentNode* node, unity::scopes::Department::SCPtr const& scopeNode);
1038@@ -195,7 +203,6 @@
1039 unity::scopes::Department::SCPtr m_rootDepartment;
1040 unity::scopes::Department::SCPtr m_lastRootDepartment;
1041 QGSettings* m_settings;
1042- Categories* m_categories;
1043 QScopedPointer<SettingsModel> m_settingsModel;
1044 QSharedPointer<DepartmentNode> m_departmentTree;
1045 QTimer m_aggregatorTimer;
1046@@ -205,7 +212,6 @@
1047 QSet<unity::shell::scopes::ScopeInterface*> m_tempScopes;
1048 QMultiMap<QString, Department*> m_departmentModels;
1049 QMap<Department*, QString> m_inverseDepartments;
1050- QPointer<Scopes> m_scopesInstance;
1051 QMetaObject::Connection m_metadataConnection;
1052 LocationService::Ptr m_locationService;
1053 };
1054
1055=== modified file 'src/Unity/scopes.cpp'
1056--- src/Unity/scopes.cpp 2014-07-24 13:17:30 +0000
1057+++ src/Unity/scopes.cpp 2014-07-31 13:04:48 +0000
1058@@ -22,6 +22,7 @@
1059
1060 // Local
1061 #include "scope.h"
1062+#include "overviewscope.h"
1063 #include "ubuntulocationservice.h"
1064
1065 // Qt
1066@@ -39,6 +40,8 @@
1067
1068 using namespace unity;
1069
1070+#define SCOPES_SCOPE_ID "scopes"
1071+
1072 void ScopeListWorker::run()
1073 {
1074 try
1075@@ -90,6 +93,7 @@
1076
1077 Scopes::Scopes(QObject *parent)
1078 : unity::shell::scopes::ScopesInterface(parent)
1079+ , m_overviewScope(nullptr)
1080 , m_listThread(nullptr)
1081 , m_loaded(false)
1082 , m_priv(new Priv())
1083@@ -107,6 +111,7 @@
1084
1085 QDBusConnection::sessionBus().connect(QString(), QString("/com/canonical/unity/scopes"), QString("com.canonical.unity.scopes"), QString("InvalidateResults"), this, SLOT(invalidateScopeResults(QString)));
1086
1087+ m_overviewScope = new OverviewScope(this);
1088 m_locationService.reset(new UbuntuLocationService());
1089 }
1090
1091@@ -147,7 +152,7 @@
1092 new core::ScopedConnection(
1093 m_scopesRuntime->registry()->set_list_update_callback(
1094 std::bind(&Scopes::Priv::safeInvalidateScopeResults,
1095- m_priv.get(), "scopes"))));
1096+ m_priv.get(), SCOPES_SCOPE_ID))));
1097
1098 // FIXME: use a dconf setting for this
1099 QByteArray enabledScopes = qgetenv("UNITY_SCOPES_LIST");
1100@@ -174,6 +179,16 @@
1101 }
1102 }
1103
1104+ // HACK! deal with the overview scope
1105+ {
1106+ auto it = scopes.find(SCOPES_SCOPE_ID);
1107+ if (it != scopes.end()) {
1108+ m_overviewScope->setScopeData(it->second);
1109+ } else {
1110+ qWarning("Unable to add overview scope, can't find with ID: \"%s\"", SCOPES_SCOPE_ID);
1111+ }
1112+ }
1113+
1114 // cache all the metadata
1115 for (auto it = scopes.begin(); it != scopes.end(); ++it) {
1116 m_cachedMetadata[QString::fromStdString(it->first)] = std::make_shared<unity::scopes::ScopeMetadata>(it->second);
1117@@ -183,6 +198,7 @@
1118
1119 m_loaded = true;
1120 Q_EMIT loadedChanged();
1121+ Q_EMIT overviewScopeChanged();
1122 Q_EMIT metadataRefreshed();
1123
1124 m_listThread = nullptr;
1125@@ -266,6 +282,22 @@
1126 return nullptr;
1127 }
1128
1129+QStringList Scopes::getFavoriteIds() const
1130+{
1131+ QStringList ids;
1132+
1133+ Q_FOREACH(Scope* scope, m_scopes) {
1134+ ids << scope->id();
1135+ }
1136+
1137+ return ids;
1138+}
1139+
1140+QMap<QString, unity::scopes::ScopeMetadata::SPtr> Scopes::getAllMetadata() const
1141+{
1142+ return m_cachedMetadata;
1143+}
1144+
1145 scopes::ScopeMetadata::SPtr Scopes::getCachedMetadata(QString const& scopeId) const
1146 {
1147 auto it = m_cachedMetadata.constFind(scopeId);
1148@@ -290,6 +322,11 @@
1149 }
1150 }
1151
1152+unity::shell::scopes::ScopeInterface* Scopes::overviewScope() const
1153+{
1154+ return m_loaded ? m_overviewScope : nullptr;
1155+}
1156+
1157 bool Scopes::loaded() const
1158 {
1159 return m_loaded;
1160
1161=== modified file 'src/Unity/scopes.h'
1162--- src/Unity/scopes.h 2014-07-16 15:32:25 +0000
1163+++ src/Unity/scopes.h 2014-07-31 13:04:48 +0000
1164@@ -27,6 +27,7 @@
1165 // Qt
1166 #include <QList>
1167 #include <QThread>
1168+#include <QStringList>
1169 #include <QSharedPointer>
1170
1171 #include <unity/scopes/Runtime.h>
1172@@ -55,9 +56,13 @@
1173
1174 Scope* getScopeById(QString const& scopeId) const;
1175 unity::scopes::ScopeMetadata::SPtr getCachedMetadata(QString const& scopeId) const;
1176+ QMap<QString, unity::scopes::ScopeMetadata::SPtr> getAllMetadata() const;
1177+ QStringList getFavoriteIds() const;
1178+
1179 void refreshScopeMetadata();
1180
1181 bool loaded() const override;
1182+ unity::shell::scopes::ScopeInterface* overviewScope() const override;
1183
1184 LocationService::Ptr locationService() const;
1185
1186@@ -76,6 +81,7 @@
1187
1188 QList<Scope*> m_scopes;
1189 QMap<QString, unity::scopes::ScopeMetadata::SPtr> m_cachedMetadata;
1190+ Scope* m_overviewScope;
1191 QThread* m_listThread;
1192 bool m_loaded;
1193
1194
1195=== modified file 'tests/CMakeLists.txt'
1196--- tests/CMakeLists.txt 2014-07-25 15:30:02 +0000
1197+++ tests/CMakeLists.txt 2014-07-31 13:04:48 +0000
1198@@ -1,4 +1,4 @@
1199-pkg_check_modules(SCOPES_API REQUIRED unity-shell-scopes=1)
1200+pkg_check_modules(SCOPES_API REQUIRED unity-shell-scopes=3)
1201 pkg_check_modules(SCOPESLIB REQUIRED libunity-scopes>=0.5.3)
1202 pkg_check_modules(GSETTINGSQT REQUIRED gsettings-qt)
1203 pkg_check_modules(QTDBUSTEST REQUIRED libqtdbustest-1>=0.2 REQUIRED)
1204@@ -57,11 +57,12 @@
1205
1206 run_tests(
1207 departmentstest
1208+ locationtest
1209+ overviewtest
1210+ previewtest
1211 resultstest
1212- previewtest
1213- locationtest
1214+ settingstest
1215 utilstest
1216- settingstest
1217 )
1218
1219 qt5_use_modules(settingstestExec Sql)
1220
1221=== modified file 'tests/data/CMakeLists.txt'
1222--- tests/data/CMakeLists.txt 2014-06-02 14:36:07 +0000
1223+++ tests/data/CMakeLists.txt 2014-07-31 13:04:48 +0000
1224@@ -1,6 +1,7 @@
1225 add_subdirectory(mock-scope)
1226 add_subdirectory(mock-scope-departments)
1227 add_subdirectory(mock-scope-ttl)
1228+add_subdirectory(scopes)
1229
1230 configure_file(Runtime.ini.in Runtime.ini @ONLY)
1231 configure_file(Registry.ini.in Registry.ini @ONLY)
1232
1233=== modified file 'tests/data/mock-scope-ttl/mock-scope-ttl.ini.in'
1234--- tests/data/mock-scope-ttl/mock-scope-ttl.ini.in 2014-05-15 08:21:45 +0000
1235+++ tests/data/mock-scope-ttl/mock-scope-ttl.ini.in 2014-07-31 13:04:48 +0000
1236@@ -1,9 +1,6 @@
1237 [ScopeConfig]
1238 DisplayName = mock-ttl.DisplayName
1239 Description = mock-ttl.Description
1240-Art = /mock-ttl.Art
1241 Icon = /mock-ttl.Icon
1242-SearchHint = mock-ttl.SearchHint
1243-HotKey = mock-ttl.HotKey
1244 Author = mock-ttl.Author
1245 ResultsTtlType = Small
1246
1247=== modified file 'tests/data/mock-scope/mock-scope.cpp'
1248--- tests/data/mock-scope/mock-scope.cpp 2014-07-24 15:21:23 +0000
1249+++ tests/data/mock-scope/mock-scope.cpp 2014-07-31 13:04:48 +0000
1250@@ -143,7 +143,7 @@
1251 CategorisedResult res(cat);
1252 res.set_uri("test:perform-query");
1253 res.set_title("result for: \"" + query_ + "\"");
1254- res["scope-id"] = "mock-scope";
1255+ res["scope-id"] = "mock-scope-ttl";
1256 res.set_intercept_activation();
1257 reply->push(res);
1258 }
1259@@ -163,7 +163,7 @@
1260 CategoryRenderer minimal_rndr(R"({"schema-version": 1, "components": {"title": "title"}})");
1261 auto cat = reply->register_category("cat1", "Category 1", "", minimal_rndr);
1262 CategorisedResult res(cat);
1263- res.set_uri("scope://mock-scope?q=next-scope-uri");
1264+ res.set_uri("scope://mock-scope?q=next-scope-query");
1265 res.set_title("result for: \"" + query_ + "\"");
1266 reply->push(res);
1267 }
1268
1269=== added directory 'tests/data/scopes'
1270=== added file 'tests/data/scopes/CMakeLists.txt'
1271--- tests/data/scopes/CMakeLists.txt 1970-01-01 00:00:00 +0000
1272+++ tests/data/scopes/CMakeLists.txt 2014-07-31 13:04:48 +0000
1273@@ -0,0 +1,8 @@
1274+pkg_check_modules(SCOPESLIB REQUIRED libunity-scopes>=0.5.0)
1275+
1276+include_directories(${SCOPESLIB_INCLUDE_DIRS})
1277+
1278+add_library(scopes MODULE scopes.cpp)
1279+target_link_libraries(scopes ${SCOPESLIB_LDFLAGS})
1280+
1281+configure_file(scopes.ini.in scopes.ini)
1282
1283=== added file 'tests/data/scopes/scopes.cpp'
1284--- tests/data/scopes/scopes.cpp 1970-01-01 00:00:00 +0000
1285+++ tests/data/scopes/scopes.cpp 2014-07-31 13:04:48 +0000
1286@@ -0,0 +1,132 @@
1287+/*
1288+ * Copyright (C) 2013 Canonical, Ltd.
1289+ *
1290+ * This program is free software; you can redistribute it and/or modify
1291+ * it under the terms of the GNU General Public License as published by
1292+ * the Free Software Foundation; version 3.
1293+ *
1294+ * This program is distributed in the hope that it will be useful,
1295+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1296+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1297+ * GNU General Public License for more details.
1298+ *
1299+ * You should have received a copy of the GNU General Public License
1300+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1301+ *
1302+ * Authors:
1303+ * Michal Hruby <michal.hruby@canonical.com>
1304+ */
1305+
1306+#include <unity-scopes.h>
1307+
1308+#include <iostream>
1309+
1310+#define EXPORT __attribute__ ((visibility ("default")))
1311+
1312+using namespace std;
1313+using namespace unity::scopes;
1314+
1315+// Example scope A: replies synchronously to a query. (Replies are returned before returning from the run() method.)
1316+
1317+class MyQuery : public SearchQueryBase
1318+{
1319+public:
1320+ MyQuery(CannedQuery const& query, SearchMetadata const& metadata) :
1321+ SearchQueryBase(query, metadata),
1322+ query_(query.query_string())
1323+ {
1324+ }
1325+
1326+ ~MyQuery() noexcept
1327+ {
1328+ }
1329+
1330+ virtual void cancelled() override
1331+ {
1332+ }
1333+
1334+ virtual void run(SearchReplyProxy const& reply) override
1335+ {
1336+ CategoryRenderer minimal_rndr(R"({"schema-version": 1, "components": {"title": "title"}})");
1337+ auto cat = reply->register_category("cat1", "Category 1", "", minimal_rndr);
1338+ CategorisedResult res(cat);
1339+ res.set_uri("test:uri");
1340+ res.set_title("result for: \"" + query_ + "\"");
1341+ res.set_art("art");
1342+ res.set_dnd_uri("test:dnd_uri");
1343+ reply->push(res);
1344+ }
1345+
1346+private:
1347+ string query_;
1348+};
1349+
1350+class MyPreview : public PreviewQueryBase
1351+{
1352+public:
1353+ MyPreview(Result const& result, ActionMetadata const& metadata) :
1354+ PreviewQueryBase(result, metadata),
1355+ scope_data_(metadata.scope_data())
1356+ {
1357+ }
1358+
1359+ ~MyPreview() noexcept
1360+ {
1361+ }
1362+
1363+ virtual void cancelled() override
1364+ {
1365+ }
1366+
1367+ virtual void run(PreviewReplyProxy const& reply) override
1368+ {
1369+ PreviewWidgetList widgets;
1370+ PreviewWidget w1(R"({"id": "hdr", "type": "header", "components": {"title": "title", "subtitle": "uri"}})");
1371+ PreviewWidget w2(R"({"id": "img", "type": "image", "components": {"source": "art"}, "zoomable": false})");
1372+ widgets.push_back(w1);
1373+ widgets.push_back(w2);
1374+ reply->push(widgets);
1375+ }
1376+
1377+private:
1378+ Variant scope_data_;
1379+};
1380+
1381+class MyScope : public ScopeBase
1382+{
1383+public:
1384+ virtual SearchQueryBase::UPtr search(CannedQuery const& q, SearchMetadata const& metadata) override
1385+ {
1386+ SearchQueryBase::UPtr query(new MyQuery(q, metadata));
1387+ cout << "scope-A: created query: \"" << q.query_string() << "\"" << endl;
1388+ return query;
1389+ }
1390+
1391+ virtual PreviewQueryBase::UPtr preview(Result const& result, ActionMetadata const& metadata) override
1392+ {
1393+ PreviewQueryBase::UPtr query(new MyPreview(result, metadata));
1394+ cout << "scope-A: created preview query: \"" << result.uri() << "\"" << endl;
1395+ return query;
1396+ }
1397+};
1398+
1399+extern "C"
1400+{
1401+
1402+ EXPORT
1403+ unity::scopes::ScopeBase*
1404+ // cppcheck-suppress unusedFunction
1405+ UNITY_SCOPE_CREATE_FUNCTION()
1406+ {
1407+ return new MyScope;
1408+ }
1409+
1410+ EXPORT
1411+ void
1412+ // cppcheck-suppress unusedFunction
1413+ UNITY_SCOPE_DESTROY_FUNCTION(unity::scopes::ScopeBase* scope_base)
1414+ {
1415+ delete scope_base;
1416+ }
1417+
1418+}
1419
1420=== added file 'tests/data/scopes/scopes.ini.in'
1421--- tests/data/scopes/scopes.ini.in 1970-01-01 00:00:00 +0000
1422+++ tests/data/scopes/scopes.ini.in 2014-07-31 13:04:48 +0000
1423@@ -0,0 +1,8 @@
1424+[ScopeConfig]
1425+DisplayName = mock.scopes.DisplayName
1426+Description = mock.scopes.Description
1427+Art = /mock.Art
1428+Icon = /mock.Icon
1429+SearchHint = mock.SearchHint
1430+HotKey = mock.HotKey
1431+Author = mock.Author
1432
1433=== added file 'tests/overviewtest.cpp'
1434--- tests/overviewtest.cpp 1970-01-01 00:00:00 +0000
1435+++ tests/overviewtest.cpp 2014-07-31 13:04:48 +0000
1436@@ -0,0 +1,148 @@
1437+/*
1438+ * Copyright (C) 2013-2014 Canonical, Ltd.
1439+ *
1440+ * This program is free software; you can redistribute it and/or modify
1441+ * it under the terms of the GNU General Public License as published by
1442+ * the Free Software Foundation; version 3.
1443+ *
1444+ * This program is distributed in the hope that it will be useful,
1445+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1446+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1447+ * GNU General Public License for more details.
1448+ *
1449+ * You should have received a copy of the GNU General Public License
1450+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1451+ *
1452+ * Authors:
1453+ * Michal Hruby <michal.hruby@canonical.com>
1454+ */
1455+
1456+#include <QObject>
1457+#include <QTest>
1458+#include <QJsonValue>
1459+#include <QJsonObject>
1460+#include <QThread>
1461+#include <QScopedPointer>
1462+#include <QSignalSpy>
1463+#include <QVariantList>
1464+
1465+#include <scopes.h>
1466+#include <scope.h>
1467+#include <categories.h>
1468+#include <overviewresults.h>
1469+#include <previewmodel.h>
1470+#include <previewstack.h>
1471+#include <previewwidgetmodel.h>
1472+
1473+#include "registry-spawner.h"
1474+#include "test-utils.h"
1475+
1476+using namespace scopes_ng;
1477+
1478+class OverviewTest : public QObject
1479+{
1480+ Q_OBJECT
1481+private:
1482+ QScopedPointer<Scopes> m_scopes;
1483+ Scope* m_scope;
1484+ QScopedPointer<RegistrySpawner> m_registry;
1485+
1486+private Q_SLOTS:
1487+ void initTestCase()
1488+ {
1489+ m_registry.reset(new RegistrySpawner);
1490+ }
1491+
1492+ void cleanupTestCase()
1493+ {
1494+ m_registry.reset();
1495+ }
1496+
1497+ void init()
1498+ {
1499+ m_scopes.reset(new Scopes(nullptr));
1500+ // no scopes on startup
1501+ QCOMPARE(m_scopes->rowCount(), 0);
1502+ QCOMPARE(m_scopes->loaded(), false);
1503+ QSignalSpy spy(m_scopes.data(), SIGNAL(loadedChanged()));
1504+ // wait till the registry spawns
1505+ QVERIFY(spy.wait());
1506+ QCOMPARE(m_scopes->loaded(), true);
1507+
1508+ // get scope proxy
1509+ m_scope = qobject_cast<scopes_ng::Scope*>(m_scopes->overviewScope());
1510+ QVERIFY(m_scope != nullptr);
1511+ m_scope->setActive(true);
1512+ }
1513+
1514+ void cleanup()
1515+ {
1516+ m_scopes.reset();
1517+ m_scope = nullptr;
1518+ }
1519+
1520+ void testScopeProperties()
1521+ {
1522+ QCOMPARE(m_scope->id(), QString("scopes"));
1523+ QCOMPARE(m_scope->name(), QString("mock.scopes.DisplayName"));
1524+ QCOMPARE(m_scope->iconHint(), QString("/mock.Icon"));
1525+ QCOMPARE(m_scope->description(), QString("mock.scopes.Description"));
1526+ QCOMPARE(m_scope->searchHint(), QString("mock.SearchHint"));
1527+ QCOMPARE(m_scope->shortcut(), QString("mock.HotKey"));
1528+ QCOMPARE(m_scope->searchQuery(), QString());
1529+
1530+ QCOMPARE(m_scope->isActive(), true);
1531+ m_scope->setActive(false);
1532+ QCOMPARE(m_scope->isActive(), false);
1533+ }
1534+
1535+ void testSurfacingQuery()
1536+ {
1537+ performSearch(m_scope, QString(""));
1538+
1539+ // ensure categories have > 0 rows
1540+ auto categories = m_scope->categories();
1541+ QVERIFY(categories->rowCount() > 0);
1542+ QCOMPARE(categories->data(categories->index(0), Categories::Roles::RoleCategoryId), QVariant(QString("favorites")));
1543+ QCOMPARE(categories->data(categories->index(1), Categories::Roles::RoleCategoryId), QVariant(QString("all")));
1544+
1545+ QVariant results_var = categories->data(categories->index(0), Categories::Roles::RoleResults);
1546+ QVERIFY(results_var.canConvert<OverviewResultsModel*>());
1547+ OverviewResultsModel* results = results_var.value<OverviewResultsModel*>();
1548+ QVERIFY(results->rowCount() > 0);
1549+ }
1550+
1551+ void testPreview()
1552+ {
1553+ performSearch(m_scope, QString(""));
1554+
1555+ // get a result from the model
1556+ auto categories = m_scope->categories();
1557+ QVERIFY(categories->rowCount() > 0);
1558+ QVariant results_var = categories->data(categories->index(0), Categories::Roles::RoleResults);
1559+ QVERIFY(results_var.canConvert<OverviewResultsModel*>());
1560+ OverviewResultsModel* results = results_var.value<OverviewResultsModel*>();
1561+ auto result_var = results->data(results->index(0), ResultsModel::RoleResult);
1562+ QCOMPARE(result_var.isNull(), false);
1563+ auto result = result_var.value<std::shared_ptr<unity::scopes::Result>>();
1564+ QVERIFY(result != nullptr);
1565+
1566+ // and try to preview it
1567+ QScopedPointer<PreviewStack> preview_stack(static_cast<PreviewStack*>(m_scope->preview(QVariant::fromValue(result))));
1568+ QCOMPARE(preview_stack->rowCount(), 1);
1569+ QCOMPARE(preview_stack->widgetColumnCount(), 1);
1570+ auto preview_var = preview_stack->data(preview_stack->index(0), PreviewStack::RolePreviewModel);
1571+ auto preview_model = preview_stack->getPreviewModel(0);
1572+ QCOMPARE(preview_model, preview_var.value<scopes_ng::PreviewModel*>());
1573+ QCOMPARE(preview_model->widgetColumnCount(), 1);
1574+ QTRY_COMPARE(preview_model->loaded(), true);
1575+
1576+ auto preview_widgets = preview_model->data(preview_model->index(0), PreviewModel::RoleColumnModel).value<scopes_ng::PreviewWidgetModel*>();
1577+ QVERIFY(!preview_widgets->roleNames().isEmpty());
1578+ QCOMPARE(preview_widgets->rowCount(), 2);
1579+ }
1580+
1581+};
1582+
1583+QTEST_GUILESS_MAIN(OverviewTest)
1584+#include <overviewtest.moc>
1585
1586=== modified file 'tests/previewtest.cpp'
1587--- tests/previewtest.cpp 2014-07-18 16:35:52 +0000
1588+++ tests/previewtest.cpp 2014-07-31 13:04:48 +0000
1589@@ -66,8 +66,8 @@
1590 // wait till the registry spawns
1591 QVERIFY(spy.wait());
1592 QCOMPARE(m_scopes->loaded(), true);
1593- // should have one scope now
1594- QCOMPARE(m_scopes->rowCount(), 3);
1595+ // should have at least one scope now
1596+ QCOMPARE(m_scopes->rowCount(), 4);
1597
1598 QVariant scope_var = m_scopes->data(m_scopes->index(0), Scopes::Roles::RoleScope);
1599 QVERIFY(scope_var.canConvert<Scope*>());
1600
1601=== modified file 'tests/resultstest.cpp'
1602--- tests/resultstest.cpp 2014-07-18 16:35:52 +0000
1603+++ tests/resultstest.cpp 2014-07-31 13:04:48 +0000
1604@@ -111,8 +111,8 @@
1605 // wait till the registry spawns
1606 QVERIFY(spy.wait());
1607 QCOMPARE(m_scopes->loaded(), true);
1608- // should have one scope now
1609- QCOMPARE(m_scopes->rowCount(), 3);
1610+ // should have at least one scope now
1611+ QCOMPARE(m_scopes->rowCount(), 4);
1612
1613 // get scope proxy
1614 m_scope = qobject_cast<scopes_ng::Scope*>(m_scopes->getScope(QString("mock-scope")));
1615@@ -192,6 +192,15 @@
1616 QCOMPARE(m_scope->isActive(), true);
1617 m_scope->setActive(false);
1618 QCOMPARE(m_scope->isActive(), false);
1619+
1620+ QCOMPARE(m_scope_ttl->id(), QString("mock-scope-ttl"));
1621+ QCOMPARE(m_scope_ttl->name(), QString("mock-ttl.DisplayName"));
1622+ QCOMPARE(m_scope_ttl->iconHint(), QString("/mock-ttl.Icon"));
1623+ QCOMPARE(m_scope_ttl->description(), QString("mock-ttl.Description"));
1624+ QCOMPARE(m_scope_ttl->searchHint(), QString());
1625+ QCOMPARE(m_scope_ttl->shortcut(), QString());
1626+ QCOMPARE(m_scope_ttl->visible(), true);
1627+ QCOMPARE(m_scope_ttl->searchQuery(), QString());
1628 }
1629
1630 void testCategoryQuery()
1631@@ -649,13 +658,14 @@
1632 unity::scopes::Result::SPtr result;
1633 QVERIFY(getFirstResult(m_scope, result));
1634
1635- QSignalSpy spy(m_scope, SIGNAL(gotoScope(QString)));
1636+ QSignalSpy spy(m_scope, SIGNAL(searchQueryChanged()));
1637 m_scope->activate(QVariant::fromValue(result));
1638 // this is likely to be invoked synchronously
1639 if (spy.count() == 0) {
1640 QVERIFY(spy.wait());
1641 }
1642 QVERIFY(spy.count() > 0);
1643+ QCOMPARE(m_scope->searchQuery(), QString("next-scope-query"));
1644 }
1645
1646 };
1647
1648=== modified file 'tests/test-utils.h'
1649--- tests/test-utils.h 2014-05-22 08:03:59 +0000
1650+++ tests/test-utils.h 2014-07-31 13:04:48 +0000
1651@@ -64,12 +64,14 @@
1652 void performSearch(Scope* scope, QString const& searchString)
1653 {
1654 QCOMPARE(scope->searchInProgress(), false);
1655+ QSignalSpy spy(scope, SIGNAL(searchInProgressChanged()));
1656 // perform a search
1657 scope->setSearchQuery(searchString);
1658- QCOMPARE(scope->searchInProgress(), true);
1659- // wait for the search to finish
1660- QSignalSpy spy(scope, SIGNAL(searchInProgressChanged()));
1661- QVERIFY(spy.wait());
1662+ QVERIFY(scope->searchInProgress() || spy.count() > 1);
1663+ if (scope->searchInProgress()) {
1664+ // wait for the search to finish
1665+ QVERIFY(spy.wait());
1666+ }
1667 QCOMPARE(scope->searchInProgress(), false);
1668 }
1669

Subscribers

People subscribed via source and target branches

to all changes: