Merge lp:~stolowski/unity-scope-click/header-apps into lp:unity-scope-click/devel

Proposed by Paweł Stołowski
Status: Merged
Approved by: dobey
Approved revision: 320
Merged at revision: 317
Proposed branch: lp:~stolowski/unity-scope-click/header-apps
Merge into: lp:unity-scope-click/devel
Diff against target: 981 lines (+509/-126)
17 files modified
CMakeLists.txt (+4/-3)
cmake/UseGSettings.cmake (+42/-0)
data/CMakeLists.txt (+2/-0)
data/com.canonical.unity.clickscope.gschema.xml (+10/-0)
debian/control (+1/-0)
debian/unity-scope-click.install (+1/-0)
libclickscope/click/CMakeLists.txt (+4/-0)
libclickscope/click/configuration.cpp (+37/-0)
libclickscope/click/configuration.h (+16/-0)
libclickscope/tests/test_configuration.cpp (+27/-0)
scope/clickapps/apps-query.cpp (+132/-61)
scope/clickapps/apps-query.h (+29/-6)
scope/clickapps/apps-scope.cpp (+2/-1)
scope/tests/CMakeLists.txt (+44/-0)
scope/tests/test_apps_query.cpp (+84/-0)
scope/tests/test_helpers.h (+71/-0)
scope/tests/test_query.cpp (+3/-55)
To merge this branch: bzr merge lp:~stolowski/unity-scope-click/header-apps
Reviewer Review Type Date Requested Status
PS Jenkins bot (community) continuous-integration Approve
Alejandro J. Cura (community) Approve
Review via email: mp+225844@code.launchpad.net

Commit message

Display preloaded core apps at the top in a dedicated headerless category. The list of apps to be displayed can be overriden with a dconf key.

Description of the change

Display preloaded core apps at the top in a dedicated headerless category. The list of apps to be displayed can be overriden with a dconf key.

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Alejandro J. Cura (alecu) wrote :

Code looks good; seems to be missing libgsettings-qt-dev in debian/control
Will test it on device after jenkins approves.

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

Tested on mako, looks wonderful.

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

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'CMakeLists.txt'
--- CMakeLists.txt 2014-06-23 15:00:28 +0000
+++ CMakeLists.txt 2014-07-08 07:23:41 +0000
@@ -20,6 +20,7 @@
20set(APPS_DATA_DIR ${CMAKE_INSTALL_FULL_DATADIR}/unity/scopes/clickapps/)20set(APPS_DATA_DIR ${CMAKE_INSTALL_FULL_DATADIR}/unity/scopes/clickapps/)
2121
22include(FindPkgConfig)22include(FindPkgConfig)
23include(UseGSettings)
2324
24pkg_check_modules(UNITY_SCOPES REQUIRED libunity-scopes>=0.5.0 libunity-api>=0.1.3)25pkg_check_modules(UNITY_SCOPES REQUIRED libunity-scopes>=0.5.0 libunity-api>=0.1.3)
25add_definitions(${UNITY_SCOPES_CFLAGS} ${UNITY_SCOPES_CFLAGS_OTHER})26add_definitions(${UNITY_SCOPES_CFLAGS} ${UNITY_SCOPES_CFLAGS_OTHER})
@@ -75,7 +76,7 @@
7576
76# Custom targets for the tests77# Custom targets for the tests
77add_custom_target (test78add_custom_target (test
78 DEPENDS test-click-scope test-libclickscope79 DEPENDS test-click-scope test-apps-scope test-libclickscope
79)80)
8081
81add_custom_target (test-disabled82add_custom_target (test-disabled
@@ -90,13 +91,13 @@
9091
91# Add a custom target for running the tests under valgrind.92# Add a custom target for running the tests under valgrind.
92add_custom_target (test-valgrind93add_custom_target (test-valgrind
93 DEPENDS test-click-scope-valgrind test-libclickscope-valgrind94 DEPENDS test-click-scope-valgrind test-apps-scope-valgrind test-libclickscope-valgrind
94)95)
9596
96# Add a custom target for running the tests under valgrind with the97# Add a custom target for running the tests under valgrind with the
97# full leak checks enabled.98# full leak checks enabled.
98add_custom_target (test-leaks99add_custom_target (test-leaks
99 DEPENDS test-click-scope-leaks test-libclickscope-leaks100 DEPENDS test-click-scope-leaks test-apps-scope-leaks test-libclickscope-leaks
100)101)
101102
102# Also let "make check" and partners work.103# Also let "make check" and partners work.
103104
=== added file 'cmake/UseGSettings.cmake'
--- cmake/UseGSettings.cmake 1970-01-01 00:00:00 +0000
+++ cmake/UseGSettings.cmake 2014-07-08 07:23:41 +0000
@@ -0,0 +1,42 @@
1# GSettings.cmake, CMake macros written for Marlin, feel free to re-use them.
2
3option (GSETTINGS_LOCALINSTALL "Install GSettings Schemas locally instead of to the GLib prefix" ${LOCAL_INSTALL})
4
5option (GSETTINGS_COMPILE "Compile GSettings Schemas after installation" ${GSETTINGS_LOCALINSTALL})
6
7if(GSETTINGS_LOCALINSTALL)
8 message(STATUS "GSettings schemas will be installed locally.")
9endif()
10
11if(GSETTINGS_COMPILE)
12 message(STATUS "GSettings shemas will be compiled.")
13endif()
14
15macro(add_schema SCHEMA_NAME)
16
17 set(PKG_CONFIG_EXECUTABLE pkg-config)
18 # Have an option to not install the schema into where GLib is
19 if (GSETTINGS_LOCALINSTALL)
20 SET (GSETTINGS_DIR "${CMAKE_INSTALL_PREFIX}/share/glib-2.0/schemas/")
21 else (GSETTINGS_LOCALINSTALL)
22 execute_process (COMMAND ${PKG_CONFIG_EXECUTABLE} glib-2.0 --variable prefix OUTPUT_VARIABLE _glib_prefix OUTPUT_STRIP_TRAILING_WHITESPACE)
23 SET (GSETTINGS_DIR "${_glib_prefix}/share/glib-2.0/schemas/")
24 endif (GSETTINGS_LOCALINSTALL)
25
26 # Run the validator and error if it fails
27 execute_process (COMMAND ${PKG_CONFIG_EXECUTABLE} gio-2.0 --variable glib_compile_schemas OUTPUT_VARIABLE _glib_comple_schemas OUTPUT_STRIP_TRAILING_WHITESPACE)
28 execute_process (COMMAND ${_glib_comple_schemas} --dry-run --schema-file=${CMAKE_CURRENT_SOURCE_DIR}/${SCHEMA_NAME} ERROR_VARIABLE _schemas_invalid OUTPUT_STRIP_TRAILING_WHITESPACE)
29
30 if (_schemas_invalid)
31 message (SEND_ERROR "Schema validation error: ${_schemas_invalid}")
32 endif (_schemas_invalid)
33
34 # Actually install and recomple schemas
35 message (STATUS "GSettings schemas will be installed into ${GSETTINGS_DIR}")
36 install (FILES ${CMAKE_CURRENT_SOURCE_DIR}/${SCHEMA_NAME} DESTINATION ${GSETTINGS_DIR} OPTIONAL)
37
38 if (GSETTINGS_COMPILE)
39 install (CODE "message (STATUS \"Compiling GSettings schemas\")")
40 install (CODE "execute_process (COMMAND ${_glib_comple_schemas} ${GSETTINGS_DIR})")
41 endif ()
42endmacro()
043
=== modified file 'data/CMakeLists.txt'
--- data/CMakeLists.txt 2014-06-30 21:50:00 +0000
+++ data/CMakeLists.txt 2014-07-08 07:23:41 +0000
@@ -2,6 +2,8 @@
2set(STORE_INI_TARGET com.canonical.scopes.clickstore.ini)2set(STORE_INI_TARGET com.canonical.scopes.clickstore.ini)
3set(APPS_INI_TARGET clickscope.ini)3set(APPS_INI_TARGET clickscope.ini)
44
5add_schema(com.canonical.unity.clickscope.gschema.xml)
6
5configure_file(7configure_file(
6 ${STORE_INI_TARGET}.in.in8 ${STORE_INI_TARGET}.in.in
7 ${STORE_INI_TARGET}.in9 ${STORE_INI_TARGET}.in
810
=== added file 'data/com.canonical.unity.clickscope.gschema.xml'
--- data/com.canonical.unity.clickscope.gschema.xml 1970-01-01 00:00:00 +0000
+++ data/com.canonical.unity.clickscope.gschema.xml 2014-07-08 07:23:41 +0000
@@ -0,0 +1,10 @@
1<?xml version="1.0" encoding="UTF-8"?>
2<schemalist>
3 <schema path="/com/canonical/unity/clickscope/" id="com.canonical.Unity.ClickScope" gettext-domain="unity-scope-click">
4 <key type="as" name="core-apps">
5 <default>[]</default>
6 <summary>Applications to display in the top category of the Apps scope</summary>
7 <description>List of application IDs that will be displayed in the upper area of the Applications scope for quick access.</description>
8 </key>
9 </schema>
10</schemalist>
011
=== modified file 'debian/control'
--- debian/control 2014-06-23 15:00:28 +0000
+++ debian/control 2014-07-08 07:23:41 +0000
@@ -14,6 +14,7 @@
14 libubuntuoneauth-2.0-dev,14 libubuntuoneauth-2.0-dev,
15 libunity-api-dev (>= 7.80.7),15 libunity-api-dev (>= 7.80.7),
16 libunity-scopes-dev (>= 0.5.0),16 libunity-scopes-dev (>= 0.5.0),
17 libgsettings-qt-dev,
17 pkg-config,18 pkg-config,
18 python3-all,19 python3-all,
19Maintainer: Ubuntu Developers <ubuntu-devel-discuss@lists.ubuntu.com>20Maintainer: Ubuntu Developers <ubuntu-devel-discuss@lists.ubuntu.com>
2021
=== modified file 'debian/unity-scope-click.install'
--- debian/unity-scope-click.install 2014-06-20 20:00:53 +0000
+++ debian/unity-scope-click.install 2014-07-08 07:23:41 +0000
@@ -1,4 +1,5 @@
1usr/lib/*/unity-scopes/*1usr/lib/*/unity-scopes/*
2usr/lib/unity-scope-click/*2usr/lib/unity-scope-click/*
3usr/share/unity/scopes/*3usr/share/unity/scopes/*
4usr/share/glib-2.0/schemas/*
4usr/share/locale/*/LC_MESSAGES/unity-scope-click.mo5usr/share/locale/*/LC_MESSAGES/unity-scope-click.mo
56
=== modified file 'libclickscope/click/CMakeLists.txt'
--- libclickscope/click/CMakeLists.txt 2014-06-23 15:00:28 +0000
+++ libclickscope/click/CMakeLists.txt 2014-07-08 07:23:41 +0000
@@ -2,11 +2,13 @@
2SET (CMAKE_AUTOMOC ON)2SET (CMAKE_AUTOMOC ON)
3find_package (Qt5Core REQUIRED)3find_package (Qt5Core REQUIRED)
4pkg_check_modules(JSON_CPP REQUIRED jsoncpp)4pkg_check_modules(JSON_CPP REQUIRED jsoncpp)
5pkg_check_modules(GSETTINGS_QT REQUIRED gsettings-qt)
56
6add_definitions(7add_definitions(
7 -DGETTEXT_PACKAGE=\"${PROJECT_NAME}\"8 -DGETTEXT_PACKAGE=\"${PROJECT_NAME}\"
8 -DGETTEXT_LOCALEDIR=\"${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LOCALEDIR}\"9 -DGETTEXT_LOCALEDIR=\"${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LOCALEDIR}\"
9 -DCLICK_INSTALL_HELPER=\"${CMAKE_INSTALL_PREFIX}/lib/unity-scope-click/install-helper\"10 -DCLICK_INSTALL_HELPER=\"${CMAKE_INSTALL_PREFIX}/lib/unity-scope-click/install-helper\"
11 ${GSETTINGS_QT_CFLAGS} ${GSETTINGS_QT_OTHER}
10)12)
1113
12add_library(${SCOPE_LIB_NAME} STATIC14add_library(${SCOPE_LIB_NAME} STATIC
@@ -32,6 +34,7 @@
3234
33include_directories(35include_directories(
34 ${JSON_CPP_INCLUDE_DIRS}36 ${JSON_CPP_INCLUDE_DIRS}
37 ${GSETTINGS_QT_INCLUDE_DIRS}
35 ${CMAKE_SOURCE_DIR}/libclickscope38 ${CMAKE_SOURCE_DIR}/libclickscope
36)39)
3740
@@ -41,5 +44,6 @@
41 ${UBUNTUONE_LDFLAGS}44 ${UBUNTUONE_LDFLAGS}
42 ${UBUNTU_DOWNLOAD_MANAGER_CLIENT_LDFLAGS}45 ${UBUNTU_DOWNLOAD_MANAGER_CLIENT_LDFLAGS}
43 ${UBUNTU_DOWNLOAD_MANAGER_COMMON_LDFLAGS}46 ${UBUNTU_DOWNLOAD_MANAGER_COMMON_LDFLAGS}
47 ${GSETTINGS_QT_LIBRARIES}
44 -lboost_locale48 -lboost_locale
45)49)
4650
=== modified file 'libclickscope/click/configuration.cpp'
--- libclickscope/click/configuration.cpp 2014-06-25 21:33:59 +0000
+++ libclickscope/click/configuration.cpp 2014-07-08 07:23:41 +0000
@@ -32,6 +32,11 @@
3232
33#include <QDir>33#include <QDir>
34#include <QProcess>34#include <QProcess>
35#include <QStringList>
36#include <QVariant>
37#include <QDebug>
38
39#include <qgsettings.h>
3540
36#include <boost/algorithm/string.hpp>41#include <boost/algorithm/string.hpp>
37#include <boost/algorithm/string/replace.hpp>42#include <boost/algorithm/string/replace.hpp>
@@ -141,4 +146,36 @@
141 != FULL_LANG_CODES.end();146 != FULL_LANG_CODES.end();
142}147}
143148
149const std::vector<std::string> Configuration::get_dconf_strings(const std::string& schema, const std::string& key) const
150{
151 if (!QGSettings::isSchemaInstalled(schema.c_str()))
152 {
153 qWarning() << "Schema" << QString::fromStdString(schema) << "is missing";
154 return std::vector<std::string>();
155 }
156 QGSettings qgs(schema.c_str());
157 std::vector<std::string> v;
158 if (qgs.keys().contains(QString::fromStdString(key)))
159 {
160 auto locations = qgs.get(QString::fromStdString(key)).toStringList();
161 for(const auto& l : locations) {
162 v.push_back(l.toStdString());
163 }
164 }
165 else
166 {
167 qWarning() << "No" << QString::fromStdString(key) << " key in schema" << QString::fromStdString(schema);
168 }
169 return v;
170}
171
172const std::vector<std::string> Configuration::get_core_apps() const
173{
174 auto apps = get_dconf_strings(Configuration::COREAPPS_SCHEMA, Configuration::COREAPPS_KEY);
175 if (apps.empty()) {
176 apps = get_default_core_apps();
177 }
178 return apps;
179}
180
144} // namespace click181} // namespace click
145182
=== modified file 'libclickscope/click/configuration.h'
--- libclickscope/click/configuration.h 2014-06-25 21:33:59 +0000
+++ libclickscope/click/configuration.h 2014-07-08 07:23:41 +0000
@@ -54,10 +54,26 @@
54 virtual std::string get_accept_languages();54 virtual std::string get_accept_languages();
55 static bool is_full_lang_code(const std::string& language);55 static bool is_full_lang_code(const std::string& language);
5656
57 constexpr static const char* COREAPPS_SCHEMA {"com.canonical.Unity.ClickScope"};
58 constexpr static const char* COREAPPS_KEY {"coreApps"};
59
60 virtual const std::vector<std::string> get_core_apps() const;
57 virtual ~Configuration() {}61 virtual ~Configuration() {}
58protected:62protected:
59 virtual std::vector<std::string> list_folder(const std::string &folder, const std::string &pattern);63 virtual std::vector<std::string> list_folder(const std::string &folder, const std::string &pattern);
60 virtual std::string architectureFromDpkg();64 virtual std::string architectureFromDpkg();
65 virtual const std::vector<std::string> get_dconf_strings(const std::string& schema, const std::string& key) const;
66 static const std::vector<std::string>& get_default_core_apps() {
67 static std::vector<std::string> default_apps {
68 "dialer-app",
69 "messaging-app",
70 "com.ubuntu.calculator",
71 "com.ubuntu.clock",
72 "com.ubuntu.camera",
73 "com.ubuntu.calendar"
74 };
75 return default_apps;
76 }
61};77};
6278
63} // namespace click79} // namespace click
6480
=== modified file 'libclickscope/tests/test_configuration.cpp'
--- libclickscope/tests/test_configuration.cpp 2014-06-25 21:33:59 +0000
+++ libclickscope/tests/test_configuration.cpp 2014-07-08 07:23:41 +0000
@@ -27,6 +27,8 @@
27 * files in the program, then also delete it here.27 * files in the program, then also delete it here.
28 */28 */
2929
30#include <QStringList>
31
30#include <gmock/gmock.h>32#include <gmock/gmock.h>
31#include <gtest/gtest.h>33#include <gtest/gtest.h>
3234
@@ -42,10 +44,35 @@
42public:44public:
43 MOCK_METHOD2(list_folder, std::vector<std::string>(45 MOCK_METHOD2(list_folder, std::vector<std::string>(
44 const std::string& folder, const std::string& pattern));46 const std::string& folder, const std::string& pattern));
47 MOCK_CONST_METHOD2(get_dconf_strings, const std::vector<std::string>(const std::string& schema, const std::string& key));
48 using Configuration::get_default_core_apps;
45};49};
4650
47}51}
4852
53TEST(Configuration, getCoreAppsFound)
54{
55 using namespace ::testing;
56 FakeConfiguration c;
57 EXPECT_CALL(c, get_dconf_strings(Configuration::COREAPPS_SCHEMA,
58 Configuration::COREAPPS_KEY))
59 .WillOnce(Return(std::vector<std::string>{"package1", "package2"}));
60 auto found_apps = c.get_core_apps();
61 auto expected_apps = std::vector<std::string>{"package1", "package2"};
62 ASSERT_EQ(found_apps, expected_apps);
63}
64
65TEST(Configuration, getCoreAppsEmpty)
66{
67 using namespace ::testing;
68 FakeConfiguration c;
69 EXPECT_CALL(c, get_dconf_strings(Configuration::COREAPPS_SCHEMA,
70 Configuration::COREAPPS_KEY))
71 .WillOnce(Return(std::vector<std::string>{}));
72 auto found_apps = c.get_core_apps();
73 auto expected_apps = c.get_default_core_apps();
74 ASSERT_EQ(found_apps, expected_apps);
75}
4976
50TEST(Configuration, getAvailableFrameworksUsesRightFolder)77TEST(Configuration, getAvailableFrameworksUsesRightFolder)
51{78{
5279
=== modified file 'scope/clickapps/apps-query.cpp'
--- scope/clickapps/apps-query.cpp 2014-06-30 20:06:33 +0000
+++ scope/clickapps/apps-query.cpp 2014-07-08 07:23:41 +0000
@@ -42,6 +42,7 @@
4242
43#include <click/click-i18n.h>43#include <click/click-i18n.h>
44#include "apps-query.h"44#include "apps-query.h"
45#include <QDebug>
4546
46namespace47namespace
47{48{
@@ -64,24 +65,6 @@
64 }65 }
65)";66)";
6667
67std::string CATEGORY_APPS_SEARCH = R"(
68 {
69 "schema-version" : 1,
70 "template" : {
71 "category-layout" : "grid",
72 "card-layout" : "horizontal",
73 "card-size": "large"
74 },
75 "components" : {
76 "title" : "title",
77 "mascot" : {
78 "field": "art"
79 },
80 "subtitle": "publisher"
81 }
82 }
83)";
84
85static const char CATEGORY_STORE[] = R"(68static const char CATEGORY_STORE[] = R"(
86{69{
87 "template": {70 "template": {
@@ -104,51 +87,138 @@
10487
105}88}
10689
107void click::Query::push_local_results(scopes::SearchReplyProxy const &replyProxy,90click::apps::ResultPusher::ResultPusher(const scopes::SearchReplyProxy &replyProxy, const std::vector<std::string>& core_apps)
108 std::vector<click::Application> const &apps,91 : replyProxy(replyProxy),
109 std::string &categoryTemplate)92 core_apps(core_apps),
110{93 top_apps_lookup(core_apps.begin(), core_apps.end())
111 scopes::CategoryRenderer rdr(categoryTemplate);94{
95}
96
97void click::apps::ResultPusher::push_result(scopes::Category::SCPtr& cat, const click::Application& a)
98{
99 scopes::CategorisedResult res(cat);
100 res.set_title(a.title);
101 res.set_art(a.icon_url);
102 res.set_uri(a.url);
103 res[click::apps::Query::ResultKeys::NAME] = a.name;
104 res[click::apps::Query::ResultKeys::DESCRIPTION] = a.description;
105 res[click::apps::Query::ResultKeys::MAIN_SCREENSHOT] = a.main_screenshot;
106 res[click::apps::Query::ResultKeys::INSTALLED] = true;
107 res[click::apps::Query::ResultKeys::VERSION] = a.version;
108 replyProxy->push(res);
109}
110
111//
112// Return an application identifier used to match applications against core-apps dconf key;
113// For click apps, it just returns application name (e.g. com.canonical.calculator).
114// For non-click apps, it return the desktop file name (without extension), taken from app uri.
115std::string click::apps::ResultPusher::get_app_identifier(const click::Application& app)
116{
117 static const std::string app_prefix("application:///");
118 if (!app.name.empty())
119 {
120 return app.name;
121 }
122 if (app.url.size() > app_prefix.size())
123 {
124 auto i = app.url.rfind('.');
125 if (i != std::string::npos)
126 {
127 return app.url.substr(app_prefix.size(), i - app_prefix.size());
128 }
129 }
130 throw std::runtime_error("Cannot determine application identifier for" + app.url);
131}
132
133void click::apps::ResultPusher::push_local_results(
134 const std::vector<click::Application> &apps,
135 const std::string &categoryTemplate)
136{
137 const scopes::CategoryRenderer rdr(categoryTemplate);
112 auto cat = replyProxy->register_category("local", _("My apps"), "", rdr);138 auto cat = replyProxy->register_category("local", _("My apps"), "", rdr);
113139
114 for(const auto & a: apps)140 for(const auto & a: apps)
115 {141 {
116 scopes::CategorisedResult res(cat);142 try
117 res.set_title(a.title);143 {
118 res.set_art(a.icon_url);144 if (top_apps_lookup.size() == 0 || top_apps_lookup.find(get_app_identifier(a)) == top_apps_lookup.end())
119 res.set_uri(a.url);145 {
120 res[click::Query::ResultKeys::NAME] = a.name;146 push_result(cat, a);
121 res[click::Query::ResultKeys::DESCRIPTION] = a.description;147 }
122 res[click::Query::ResultKeys::MAIN_SCREENSHOT] = a.main_screenshot;148 }
123 res[click::Query::ResultKeys::INSTALLED] = true;149 catch (const std::runtime_error &e)
124 res[click::Query::ResultKeys::VERSION] = a.version;150 {
125 replyProxy->push(res);151 qWarning() << QString::fromStdString(e.what());
126 }152 }
127}153 }
128154}
129struct click::Query::Private155
130{156void click::apps::ResultPusher::push_top_results(
131 Private(click::Index& index, const scopes::SearchMetadata& metadata)157 const std::vector<click::Application>& apps,
132 : index(index),158 const std::string& categoryTemplate)
133 meta(metadata)159{
134 {160 const scopes::CategoryRenderer rdr(categoryTemplate);
135 }161 auto cat = replyProxy->register_category("predefined", "", "", rdr);
136 click::Index& index;162
163 //
164 // iterate over all apps, insert those matching core apps into top_apps_to_push
165 std::map<std::string, click::Application> top_apps_to_push;
166 for (const auto& a: apps)
167 {
168 try
169 {
170 const auto id = get_app_identifier(a);
171 if (top_apps_lookup.find(id) != top_apps_lookup.end())
172 {
173 top_apps_to_push[id] = a;
174 if (core_apps.size() == top_apps_to_push.size())
175 {
176 // no need to iterate over remaining apps
177 break;
178 }
179 }
180 }
181 catch (const std::runtime_error &e)
182 {
183 qWarning() << QString::fromStdString(e.what());
184 }
185 }
186
187 //
188 // iterate over core apps and insert them based on top_apps_to_push;
189 // this way the order of core apps is preserved.
190 for (const auto &a: core_apps)
191 {
192 auto const it = top_apps_to_push.find(a);
193 if (it != top_apps_to_push.end())
194 {
195 push_result(cat, it->second);
196 }
197 }
198}
199
200struct click::apps::Query::Private
201{
202 Private(const scopes::SearchMetadata& metadata)
203 : meta(metadata)
204 {
205 }
137 scopes::SearchMetadata meta;206 scopes::SearchMetadata meta;
207 click::Configuration configuration;
138};208};
139209
140click::Query::Query(unity::scopes::CannedQuery const& query, click::Index& index, scopes::SearchMetadata const& metadata)210click::apps::Query::Query(unity::scopes::CannedQuery const& query, scopes::SearchMetadata const& metadata)
141 : unity::scopes::SearchQueryBase(query, metadata),211 : unity::scopes::SearchQueryBase(query, metadata),
142 impl(new Private(index, metadata))212 impl(new Private(metadata))
143{213{
144}214}
145215
146void click::Query::cancelled()216void click::apps::Query::cancelled()
147{217{
148 qDebug() << "cancelling search of" << QString::fromStdString(query().query_string());218 qDebug() << "cancelling search of" << QString::fromStdString(query().query_string());
149}219}
150220
151click::Query::~Query()221click::apps::Query::~Query()
152{222{
153 qDebug() << "destroying search";223 qDebug() << "destroying search";
154}224}
@@ -165,7 +235,7 @@
165235
166}236}
167237
168void click::Query::add_fake_store_app(scopes::SearchReplyProxy const& searchReply)238void click::apps::Query::add_fake_store_app(scopes::SearchReplyProxy const& searchReply)
169{239{
170 static const std::string title = _("Ubuntu Store");240 static const std::string title = _("Ubuntu Store");
171 static const std::string cat_title = _("Get more apps from the store");241 static const std::string cat_title = _("Get more apps from the store");
@@ -185,27 +255,28 @@
185 res.set_title(title);255 res.set_title(title);
186 res.set_art(STORE_DATA_DIR "/store-scope-icon.svg");256 res.set_art(STORE_DATA_DIR "/store-scope-icon.svg");
187 res.set_uri(store_scope.to_uri());257 res.set_uri(store_scope.to_uri());
188 res[click::Query::ResultKeys::NAME] = title;258 res[click::apps::Query::ResultKeys::NAME] = title;
189 res[click::Query::ResultKeys::DESCRIPTION] = "";259 res[click::apps::Query::ResultKeys::DESCRIPTION] = "";
190 res[click::Query::ResultKeys::MAIN_SCREENSHOT] = "";260 res[click::apps::Query::ResultKeys::MAIN_SCREENSHOT] = "";
191 res[click::Query::ResultKeys::INSTALLED] = true;261 res[click::apps::Query::ResultKeys::INSTALLED] = true;
192 res[click::Query::ResultKeys::VERSION] = "";262 res[click::apps::Query::ResultKeys::VERSION] = "";
193 searchReply->push(res);263 searchReply->push(res);
194 }264 }
195}265}
196266
197void click::Query::run(scopes::SearchReplyProxy const& searchReply)267void click::apps::Query::run(scopes::SearchReplyProxy const& searchReply)
198{268{
269 const std::string categoryTemplate = CATEGORY_APPS_DISPLAY;
199 auto querystr = query().query_string();270 auto querystr = query().query_string();
200 std::string categoryTemplate = CATEGORY_APPS_SEARCH;271
272 ResultPusher pusher(searchReply, querystr.empty() ? impl->configuration.get_core_apps() : std::vector<std::string>());
273 auto localResults = clickInterfaceInstance().find_installed_apps(querystr);
274
201 if (querystr.empty()) {275 if (querystr.empty()) {
202 categoryTemplate = CATEGORY_APPS_DISPLAY;276 pusher.push_top_results(localResults, categoryTemplate);
203 }277 }
204 auto localResults = clickInterfaceInstance().find_installed_apps(
205 querystr);
206278
207 push_local_results(279 pusher.push_local_results(
208 searchReply,
209 localResults,280 localResults,
210 categoryTemplate);281 categoryTemplate);
211282
212283
=== modified file 'scope/clickapps/apps-query.h'
--- scope/clickapps/apps-query.h 2014-05-28 14:27:28 +0000
+++ scope/clickapps/apps-query.h 2014-07-08 07:23:41 +0000
@@ -37,14 +37,19 @@
3737
38#include <QSharedPointer>38#include <QSharedPointer>
39#include <set>39#include <set>
40#include <unordered_set>
4041
4142
42namespace click43namespace click
43{44{
4445
45class Application;46class Application;
47class Configuration;
46class Index;48class Index;
4749
50namespace apps
51{
52
48class Query : public scopes::SearchQueryBase53class Query : public scopes::SearchQueryBase
49{54{
50public:55public:
@@ -60,7 +65,7 @@
60 constexpr static const char* VERSION{"version"};65 constexpr static const char* VERSION{"version"};
61 };66 };
6267
63 Query(unity::scopes::CannedQuery const& query, click::Index& index, scopes::SearchMetadata const& metadata);68 Query(unity::scopes::CannedQuery const& query, scopes::SearchMetadata const& metadata);
64 virtual ~Query();69 virtual ~Query();
6570
66 virtual void cancelled() override;71 virtual void cancelled() override;
@@ -69,14 +74,32 @@
6974
70protected:75protected:
71 virtual void add_fake_store_app(scopes::SearchReplyProxy const &replyProxy);76 virtual void add_fake_store_app(scopes::SearchReplyProxy const &replyProxy);
72 virtual void push_local_results(scopes::SearchReplyProxy const &replyProxy,
73 std::vector<click::Application> const &apps,
74 std::string& categoryTemplate);
75
76private:77private:
77 struct Private;78 struct Private;
78 QSharedPointer<Private> impl;79 QSharedPointer<Private> impl;
79};80};
80}81
82class ResultPusher
83{
84 const scopes::SearchReplyProxy &replyProxy;
85 std::vector<std::string> core_apps;
86 std::unordered_set<std::string> top_apps_lookup;
87
88public:
89 ResultPusher(const scopes::SearchReplyProxy &replyProxy, const std::vector<std::string>& core_apps);
90 virtual ~ResultPusher() = default;
91
92 virtual void push_local_results(const std::vector<click::Application> &apps,
93 const std::string& categoryTemplate);
94
95 virtual void push_top_results(
96 const std::vector<click::Application>& apps,
97 const std::string& categoryTemplate);
98protected:
99 virtual void push_result(scopes::Category::SCPtr& cat, const click::Application& a);
100 static std::string get_app_identifier(const click::Application& app);
101};
102} // namespace apps
103} // namespace query
81104
82#endif // CLICK_QUERY_H105#endif // CLICK_QUERY_H
83106
=== modified file 'scope/clickapps/apps-scope.cpp'
--- scope/clickapps/apps-scope.cpp 2014-06-18 16:23:50 +0000
+++ scope/clickapps/apps-scope.cpp 2014-07-08 07:23:41 +0000
@@ -42,6 +42,7 @@
42#include "apps-scope.h"42#include "apps-scope.h"
43#include "apps-query.h"43#include "apps-query.h"
4444
45using namespace click;
4546
46click::Scope::Scope()47click::Scope::Scope()
47{48{
@@ -78,7 +79,7 @@
7879
79scopes::SearchQueryBase::UPtr click::Scope::search(unity::scopes::CannedQuery const& q, scopes::SearchMetadata const& metadata)80scopes::SearchQueryBase::UPtr click::Scope::search(unity::scopes::CannedQuery const& q, scopes::SearchMetadata const& metadata)
80{81{
81 return scopes::SearchQueryBase::UPtr(new click::Query(q, *index, metadata));82 return scopes::SearchQueryBase::UPtr(new click::apps::Query(q, metadata));
82}83}
8384
8485
8586
=== modified file 'scope/tests/CMakeLists.txt'
--- scope/tests/CMakeLists.txt 2014-06-23 15:00:28 +0000
+++ scope/tests/CMakeLists.txt 2014-07-08 07:23:41 +0000
@@ -1,4 +1,5 @@
1set (CLICKSCOPE_TESTS_TARGET click-scope-tests)1set (CLICKSCOPE_TESTS_TARGET click-scope-tests)
2set (APPS_SCOPE_TESTS_TARGET apps-scope-tests)
2find_package(Threads)3find_package(Threads)
34
4# Qt5 bits5# Qt5 bits
@@ -19,7 +20,12 @@
19 test_query.cpp20 test_query.cpp
20)21)
2122
23add_executable (${APPS_SCOPE_TESTS_TARGET}
24 test_apps_query.cpp
25)
26
22qt5_use_modules(${CLICKSCOPE_TESTS_TARGET} Core DBus Network Test)27qt5_use_modules(${CLICKSCOPE_TESTS_TARGET} Core DBus Network Test)
28qt5_use_modules(${APPS_SCOPE_TESTS_TARGET} Core DBus Network Test)
2329
24target_link_libraries(${CLICKSCOPE_TESTS_TARGET}30target_link_libraries(${CLICKSCOPE_TESTS_TARGET}
25 ${STORE_LIB_UNVERSIONED}31 ${STORE_LIB_UNVERSIONED}
@@ -37,6 +43,22 @@
37 ${CMAKE_THREAD_LIBS_INIT}43 ${CMAKE_THREAD_LIBS_INIT}
38)44)
3945
46target_link_libraries(${APPS_SCOPE_TESTS_TARGET}
47 ${APPS_LIB_UNVERSIONED}
48 ${SCOPE_LIB_NAME}
49
50 ${UNITY_SCOPES_LDFLAGS}
51 ${UBUNTUONE_LDFLAGS}
52 ${UBUNTU_DOWNLOAD_MANAGER_CLIENT_LDFLAGS}
53 ${UBUNTU_DOWNLOAD_MANAGER_COMMON_LDFLAGS}
54 ${JSON_CPP_LDFLAGS}
55
56 gmock
57 gmock_main
58
59 ${CMAKE_THREAD_LIBS_INIT}
60)
61
40add_custom_target (test-click-scope62add_custom_target (test-click-scope
41 COMMAND ${CMAKE_CURRENT_BINARY_DIR}/${CLICKSCOPE_TESTS_TARGET}63 COMMAND ${CMAKE_CURRENT_BINARY_DIR}/${CLICKSCOPE_TESTS_TARGET}
42 DEPENDS ${CLICKSCOPE_TESTS_TARGET}64 DEPENDS ${CLICKSCOPE_TESTS_TARGET}
@@ -56,6 +78,28 @@
56 DEPENDS ${CLICKSCOPE_TESTS_TARGET}78 DEPENDS ${CLICKSCOPE_TESTS_TARGET}
57)79)
5880
81# ---
82
83add_custom_target (test-apps-scope
84 COMMAND ${CMAKE_CURRENT_BINARY_DIR}/${APPS_SCOPE_TESTS_TARGET}
85 DEPENDS ${APPS_SCOPE_TESTS_TARGET}
86)
87
88add_custom_target(test-apps-scope-valgrind
89 COMMAND valgrind --tool=memcheck ${CMAKE_CURRENT_BINARY_DIR}/${APPS_SCOPE_TESTS_TARGET}
90 DEPENDS ${APPS_SCOPE_TESTS_TARGET}
91)
92
93add_custom_target(test-apps-scope-leaks
94 COMMAND valgrind --tool=memcheck --track-origins=yes --num-callers=40 --leak-resolution=high --leak-check=full ${CMAKE_CURRENT_BINARY_DIR}/${APPS_SCOPE_TESTS_TARGET}
95 DEPENDS ${APPS_SCOPE_TESTS_TARGET}
96)
97add_custom_target (test-apps-scope-disabled
98 COMMAND GTEST_ALSO_RUN_DISABLED_TESTS=1 ${CMAKE_CURRENT_BINARY_DIR}/${APPS_SCOPE_TESTS_TARGET}
99 DEPENDS ${APPS_SCOPE_TESTS_TARGET}
100)
101
102
59add_subdirectory(integration)103add_subdirectory(integration)
60add_subdirectory(download_manager_tool)104add_subdirectory(download_manager_tool)
61add_subdirectory(click_interface_tool)105add_subdirectory(click_interface_tool)
62106
=== added file 'scope/tests/test_apps_query.cpp'
--- scope/tests/test_apps_query.cpp 1970-01-01 00:00:00 +0000
+++ scope/tests/test_apps_query.cpp 2014-07-08 07:23:41 +0000
@@ -0,0 +1,84 @@
1/*
2 * Copyright (C) 2014 Canonical Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 3, as published
6 * by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranties of
10 * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
11 * PURPOSE. See the GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License along
14 * with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * In addition, as a special exception, the copyright holders give
17 * permission to link the code of portions of this program with the
18 * OpenSSL library under certain conditions as described in each
19 * individual source file, and distribute linked combinations
20 * including the two.
21 * You must obey the GNU General Public License in all respects
22 * for all of the code used other than OpenSSL. If you modify
23 * file(s) with this exception, you may extend this exception to your
24 * version of the file(s), but you are not obligated to do so. If you
25 * do not wish to do so, delete this exception statement from your
26 * version. If you delete this exception statement from all source
27 * files in the program, then also delete it here.
28 */
29
30#include <string>
31#include <memory>
32
33#include <gtest/gtest.h>
34#include <gmock/gmock.h>
35
36#include <clickapps/apps-query.h>
37
38#include <unity/scopes/SearchReply.h>
39#include <unity/scopes/testing/MockSearchReply.h>
40
41#include "test_helpers.h"
42
43using namespace click::test::helpers;
44using namespace ::testing;
45
46class ResultPusherTest : public ::testing::Test
47{
48protected:
49 scopes::SearchReplyProxy reply;
50public:
51 ResultPusherTest()
52 {
53 reply.reset(new scopes::testing::MockSearchReply());
54 }
55};
56
57MATCHER_P(HasApplicationTitle, n, "") { return arg["title"].get_string() == n; }
58
59TEST_F(ResultPusherTest, testPushTopAndLocalResults)
60{
61 std::string categoryTemplate("{}");
62 std::vector<click::Application> apps {
63 {"app1", "App1", 0.0f, "icon", "url", "", "sshot"},
64 {"app2", "App2", 0.0f, "icon", "url", "", "sshot"},
65 {"app3", "App3", 0.0f, "icon", "url", "", "sshot"},
66 {"", "App4", 0.0f, "icon", "application:///app4.desktop", "", "sshot"} // a non-click app
67 };
68
69 click::apps::ResultPusher pusher(reply, {"app2", "app4"});
70 auto mockreply = (scopes::testing::MockSearchReply*)reply.get();
71
72 scopes::CategoryRenderer renderer("{}");
73 auto ptrCat = std::make_shared<FakeCategory>("id", "", "", renderer);
74
75 EXPECT_CALL(*mockreply, register_category(_, _, _, _)).WillRepeatedly(Return(ptrCat));
76 EXPECT_CALL(*mockreply, push(Matcher<unity::scopes::CategorisedResult const&>(HasApplicationTitle(std::string("App2")))));
77 EXPECT_CALL(*mockreply, push(Matcher<unity::scopes::CategorisedResult const&>(HasApplicationTitle(std::string("App4")))));
78
79 EXPECT_CALL(*mockreply, push(Matcher<unity::scopes::CategorisedResult const&>(HasApplicationTitle(std::string("App1")))));
80 EXPECT_CALL(*mockreply, push(Matcher<unity::scopes::CategorisedResult const&>(HasApplicationTitle(std::string("App3")))));
81 pusher.push_top_results(apps, categoryTemplate);
82 pusher.push_local_results(apps, categoryTemplate);
83}
84
085
=== added file 'scope/tests/test_helpers.h'
--- scope/tests/test_helpers.h 1970-01-01 00:00:00 +0000
+++ scope/tests/test_helpers.h 2014-07-08 07:23:41 +0000
@@ -0,0 +1,71 @@
1#ifndef TEST_HELPERS_H
2#define TEST_HELPERS_H
3
4#include <click/department-lookup.h>
5#include <click/highlights.h>
6#include "click/index.h"
7#include <click/interface.h>
8#include <click/package.h>
9
10namespace click
11{
12namespace test
13{
14namespace helpers
15{
16static const std::string FAKE_QUERY {"FAKE_QUERY"};
17static const std::string FAKE_CATEGORY_TEMPLATE {"{}"};
18
19
20class MockIndex : public click::Index {
21 click::Packages packages;
22 click::Packages recommends;
23 click::DepartmentList departments;
24 click::DepartmentList bootstrap_departments;
25 click::HighlightList bootstrap_highlights;
26public:
27 MockIndex(click::Packages packages = click::Packages(),
28 click::DepartmentList departments = click::DepartmentList(),
29 click::DepartmentList boot_departments = click::DepartmentList())
30 : Index(QSharedPointer<click::web::Client>()),
31 packages(packages),
32 departments(departments),
33 bootstrap_departments(boot_departments)
34 {
35
36 }
37
38 click::web::Cancellable search(const std::string &query, std::function<void (click::Packages, click::Packages)> callback) override
39 {
40 do_search(query, callback);
41 callback(packages, recommends);
42 return click::web::Cancellable();
43 }
44
45 click::web::Cancellable bootstrap(std::function<void(const click::DepartmentList&, const click::HighlightList&, Error, int)> callback) override
46 {
47 callback(bootstrap_departments, bootstrap_highlights, click::Index::Error::NoError, 0);
48 return click::web::Cancellable();
49 }
50
51 MOCK_METHOD2(do_search,
52 void(const std::string&,
53 std::function<void(click::Packages, click::Packages)>));
54};
55
56
57class FakeCategory : public scopes::Category
58{
59public:
60 FakeCategory(std::string const& id, std::string const& title,
61 std::string const& icon, scopes::CategoryRenderer const& renderer) :
62 scopes::Category(id, title, icon, renderer)
63 {
64 }
65
66};
67} // namespace helpers
68} // namespace test
69} // namespace click
70
71#endif // TEST_HELPERS_H
072
=== modified file 'scope/tests/test_query.cpp'
--- scope/tests/test_query.cpp 2014-06-24 17:18:53 +0000
+++ scope/tests/test_query.cpp 2014-07-08 07:23:41 +0000
@@ -35,8 +35,8 @@
3535
36#include "click/qtbridge.h"36#include "click/qtbridge.h"
37#include "clickstore/store-query.h"37#include "clickstore/store-query.h"
38#include "click/index.h"
39#include "click/application.h"38#include "click/application.h"
39#include "test_helpers.h"
4040
41#include <tests/mock_network_access_manager.h>41#include <tests/mock_network_access_manager.h>
4242
@@ -49,51 +49,10 @@
4949
50using namespace ::testing;50using namespace ::testing;
51using namespace click;51using namespace click;
52using namespace click::test::helpers;
5253
53namespace54namespace
54{55{
55static const std::string FAKE_QUERY {"FAKE_QUERY"};
56static const std::string FAKE_CATEGORY_TEMPLATE {"{}"};
57
58
59class MockIndex : public click::Index {
60 click::Packages packages;
61 click::Packages recommends;
62 click::DepartmentList departments;
63 click::DepartmentList bootstrap_departments;
64 click::HighlightList bootstrap_highlights;
65
66public:
67 MockIndex(click::Packages packages = click::Packages(),
68 click::DepartmentList departments = click::DepartmentList(),
69 click::DepartmentList boot_departments = click::DepartmentList())
70 : Index(QSharedPointer<click::web::Client>()),
71 packages(packages),
72 departments(departments),
73 bootstrap_departments(boot_departments)
74 {
75
76 }
77
78 click::web::Cancellable search(const std::string &query, std::function<void (click::Packages, click::Packages)> callback) override
79 {
80 do_search(query, callback);
81 callback(packages, recommends);
82 return click::web::Cancellable();
83 }
84
85
86 click::web::Cancellable bootstrap(std::function<void(const click::DepartmentList&, const click::HighlightList&, Error, int)> callback) override
87 {
88 callback(bootstrap_departments, bootstrap_highlights, click::Index::Error::NoError, 0);
89 return click::web::Cancellable();
90 }
91
92 MOCK_METHOD2(do_search,
93 void(const std::string&,
94 std::function<void(click::Packages, click::Packages)>));
95};
96
97class MockQueryBase : public click::Query {56class MockQueryBase : public click::Query {
98public:57public:
99 MockQueryBase(const unity::scopes::CannedQuery& query, click::Index& index,58 MockQueryBase(const unity::scopes::CannedQuery& query, click::Index& index,
@@ -140,7 +99,7 @@
140public:99public:
141 MockQueryRun(const unity::scopes::CannedQuery& query, click::Index& index,100 MockQueryRun(const unity::scopes::CannedQuery& query, click::Index& index,
142 click::DepartmentLookup& depts,101 click::DepartmentLookup& depts,
143 click::HighlightList& highlights, 102 click::HighlightList& highlights,
144 scopes::SearchMetadata const& metadata) : MockQueryBase(query, index, depts, highlights, metadata)103 scopes::SearchMetadata const& metadata) : MockQueryBase(query, index, depts, highlights, metadata)
145 {104 {
146105
@@ -154,17 +113,6 @@
154 std::string& categoryTemplate));113 std::string& categoryTemplate));
155 MOCK_METHOD0(get_installed_packages, PackageSet());114 MOCK_METHOD0(get_installed_packages, PackageSet());
156};115};
157
158class FakeCategory : public scopes::Category
159{
160public:
161 FakeCategory(std::string const& id, std::string const& title,
162 std::string const& icon, scopes::CategoryRenderer const& renderer) :
163 scopes::Category(id, title, icon, renderer)
164 {
165 }
166
167};
168} // namespace116} // namespace
169117
170TEST(QueryTest, testAddAvailableAppsCallsClickIndex)118TEST(QueryTest, testAddAvailableAppsCallsClickIndex)

Subscribers

People subscribed via source and target branches

to all changes: