64.1.1
by Pawel Stolowski
First cut at scopes tutorial. |
1 |
/*!
|
163.98.11
by Pawel Stolowski
Mainpage uses notitle. |
2 |
\mainpage notitle
|
163.98.10
by Pawel Stolowski
Changed structure, make it appear on main page. |
3 |
|
4 |
\section overview What are scopes
|
|
5 |
||
6 |
\subsection intro Introduction
|
|
163.98.4
by Marcus Tomlinson
Added "Introduction" and "Local vs remote scopes" sections to tutorial.dox |
7 |
|
163.315.1
by Michi Henning
Lots of doc fixes and updates. |
8 |
One of Unity’s core features on the desktop is the Dash. The Dash allows users to search for and discover virtually anything,
|
9 |
from local files and applications to web content and other online data. The Dash achieves this by interfacing with one or more
|
|
10 |
search plug-ins called “scopes”, such as “Apps”, “Music”, “Videos”, “Amazon”, “Wikipedia”, and “Youtube”.
|
|
163.98.4
by Marcus Tomlinson
Added "Introduction" and "Local vs remote scopes" sections to tutorial.dox |
11 |
|
12 |
On the phone and tablet, scopes make up the central user interface, as they provide everything a user needs from an operating
|
|
13 |
system. Scopes enable users to locate and launch applications, access local files, play music and videos, search the web,
|
|
14 |
manage their favourite social network, keep up with the latest news, and much more.
|
|
15 |
||
163.315.1
by Michi Henning
Lots of doc fixes and updates. |
16 |
Each scope is a dedicated search engine for the category of data it represents. The data source could be a local database,
|
17 |
a web service, or even an aggregation of other scopes. (For example, the “Music” scope aggregates “Local Music” and “Online Music”
|
|
18 |
scopes). A scope is responsible for performing the actual search and returning the best possible results for each
|
|
163.98.4
by Marcus Tomlinson
Added "Introduction" and "Local vs remote scopes" sections to tutorial.dox |
19 |
query it receives.
|
20 |
||
163.315.1
by Michi Henning
Lots of doc fixes and updates. |
21 |
This document describes how to implement, test, and package your own scope using the Unity Scopes C++ API (unity-scopes-api).
|
163.98.4
by Marcus Tomlinson
Added "Introduction" and "Local vs remote scopes" sections to tutorial.dox |
22 |
|
163.146.1
by Pete Woods
Convert the remote scopes section to a conditional section |
23 |
\if RemoteScopes
|
163.98.10
by Pawel Stolowski
Changed structure, make it appear on main page. |
24 |
\subsection LvsR Local vs remote scopes
|
163.98.4
by Marcus Tomlinson
Added "Introduction" and "Local vs remote scopes" sections to tutorial.dox |
25 |
|
26 |
Local scopes are scopes that are located and run on the user’s device, while remote scopes (or “Smart Scopes”) are scopes that
|
|
27 |
are located and run remotely on the Ubuntu Smart Scopes Server (or “SSS”). (Note: Although local scopes execute as local
|
|
28 |
processes, they may still query online services in order to retrieve search results). A local scope usually requires local data,
|
|
29 |
and therefore, can only be run locally, while a remote scope can effectively be run both locally and remotely.
|
|
30 |
||
31 |
When deciding on whether to write a local or remote scope, keep the user’s privacy in mind. For security reasons, a scope should
|
|
32 |
not access the user’s personal data unless absolutely necessary (i.e. The scope requires account information or local data to
|
|
33 |
perform searches). It is only in these situations that a scope should be written to run locally. <b>By default, a scope should
|
|
163.98.13
by Pawel Stolowski
Typo fix. |
34 |
be written with the intention of running remotely on the Smart Scopes Server.</b>
|
163.98.4
by Marcus Tomlinson
Added "Introduction" and "Local vs remote scopes" sections to tutorial.dox |
35 |
|
36 |
(For more information on how to deploy your scope to the Smart Scopes Server, or how to implement a native remote scope using
|
|
163.113.28
by Marcus Tomlinson
Fixed warning in documentation. |
37 |
the SSS REST API see: <i>link_not_yet_available</i>)
|
163.146.1
by Pete Woods
Convert the remote scopes section to a conditional section |
38 |
\endif
|
163.98.1
by Pawel Stolowski
Minor additions to the tutorial. |
39 |
|
163.98.10
by Pawel Stolowski
Changed structure, make it appear on main page. |
40 |
\section develop Developing scopes
|
163.98.1
by Pawel Stolowski
Minor additions to the tutorial. |
41 |
|
163.98.10
by Pawel Stolowski
Changed structure, make it appear on main page. |
42 |
\subsection starting Getting started
|
163.98.1
by Pawel Stolowski
Minor additions to the tutorial. |
43 |
|
163.315.1
by Michi Henning
Lots of doc fixes and updates. |
44 |
A simple C++ scope template with a cmake build system is currently available as part of the Ubuntu SDK IDE. To use it, install the
|
163.154.1
by Pete Woods
Discuss the click packaging in the tutorial documentation |
45 |
packages required for scope development:
|
163.98.15
by Michal Hruby
Add some basic information on getting the template and deployment, to be completed |
46 |
|
47 |
\verbatim
|
|
48 |
sudo apt-get install libunity-scopes-dev
|
|
49 |
\endverbatim
|
|
50 |
||
163.315.1
by Michi Henning
Lots of doc fixes and updates. |
51 |
Now you are ready to explore and modify the sample code in the src/ directory.
|
163.98.1
by Pawel Stolowski
Minor additions to the tutorial. |
52 |
|
163.154.1
by Pete Woods
Discuss the click packaging in the tutorial documentation |
53 |
\subsection click Click packaging
|
54 |
||
55 |
To register your scope, you must use the "scope" click hook, and point it to a directory containing your .ini file and .so file.
|
|
163.315.1
by Michi Henning
Lots of doc fixes and updates. |
56 |
In the template, a manifest such as the following is used:
|
163.154.1
by Pete Woods
Discuss the click packaging in the tutorial documentation |
57 |
|
58 |
\code
|
|
59 |
{
|
|
60 |
"description": "Net scope description",
|
|
163.209.1
by Pete Woods
Incorrect click packaging documentation |
61 |
"framework": "ubuntu-sdk-14.10-dev1",
|
163.154.1
by Pete Woods
Discuss the click packaging in the tutorial documentation |
62 |
"hooks": {
|
63 |
"myscope": {
|
|
64 |
"scope": "myscope", <-- Point to directory in build tree with .ini and .so
|
|
65 |
"apparmor": "scope-security.json" <-- Point to AppArmor manifest in build tree
|
|
66 |
}
|
|
67 |
}
|
|
68 |
"maintainer": "Some Guy <some.guy@ubuntu.com>",
|
|
69 |
"name": "com.ubuntu.developer.username.net-scope",
|
|
70 |
"title": "Some scope",
|
|
71 |
"version": "0.1"
|
|
72 |
}
|
|
73 |
\endcode
|
|
74 |
||
163.387.2
by Michi Henning
Fixed a minor doc issue for scopes::Result: protected and private stuff was shown. |
75 |
\subsubsection multiarch_click Multi-arch click packages
|
163.378.3
by Pete Woods
Docs for multi-arch |
76 |
The search path for the shared library inside a click package is as follows:
|
77 |
||
78 |
<ul>
|
|
79 |
<li>${SCOPE_DIRECTORY}/${DEB_HOST_MULTIARCH}/lib${SCOPE_NAME}.so
|
|
80 |
<li>${SCOPE_DIRECTORY}/${DEB_HOST_MULTIARCH}/${SCOPE_NAME}.so
|
|
81 |
<li>${SCOPE_DIRECTORY}/${DEB_HOST_MULTIARCH}/scope.so
|
|
82 |
<li>${SCOPE_DIRECTORY}/lib${SCOPE_NAME}.so
|
|
83 |
<li>${SCOPE_DIRECTORY}/${SCOPE_NAME}.so
|
|
84 |
<li>${SCOPE_DIRECTORY}/scope.so
|
|
85 |
</ul>
|
|
86 |
||
87 |
Therefore click packges can be made multi-arch aware by compiling your targets for multiple architectures, and creating, e.g. the
|
|
88 |
following directory structure:
|
|
89 |
||
90 |
\code
|
|
91 |
├── testscopeA.ini
|
|
92 |
├── testscopeA-settings.ini
|
|
93 |
├── x86_64-linux-gnu
|
|
94 |
| └── libtestscopeA.so
|
|
95 |
└── arm-linux-gnueabihf
|
|
96 |
└── libtestscopeA.so
|
|
97 |
\endcode
|
|
98 |
||
163.378.5
by Pete Woods
Spelling |
99 |
You must also update the manifest file 'architecture' property to enumerate the included architectures, as follows:
|
163.378.3
by Pete Woods
Docs for multi-arch |
100 |
|
101 |
\code
|
|
102 |
"architecture": ["armhf", "amd64"]
|
|
103 |
\endcode
|
|
104 |
||
261.1.12
by Pete Woods
Fix mistakes in multi arch branch |
105 |
\subsubsection multiarch-scoperunner Multi-arch scope runner
|
163.378.4
by Pete Woods
Multi-arch scoperunner docs |
106 |
Similarly to the shared libraries, when a relative path is provided the search path for custom scope runners is as follows:
|
107 |
||
108 |
<ul>
|
|
109 |
<li>${SCOPE_DIRECTORY}/${DEB_HOST_MULTIARCH}/${CUSTOM_SCOPERUNNER}
|
|
110 |
<li>${SCOPE_DIRECTORY}/${CUSTOM_SCOPERUNNER}
|
|
111 |
</ul>
|
|
112 |
||
163.154.1
by Pete Woods
Discuss the click packaging in the tutorial documentation |
113 |
\subsubsection apparmor Apparmor manifest
|
114 |
||
163.223.2
by Pete Woods
Remove references to local-content scope |
115 |
Scopes that are packaged using click are inherently untrusted and must be confined. At present, there is only a single type of scope that can be defined:
|
163.154.1
by Pete Woods
Discuss the click packaging in the tutorial documentation |
116 |
<ul>
|
163.315.1
by Michi Henning
Lots of doc fixes and updates. |
117 |
<li>Network scope - can access the network / internet, but is not allowed to use APIs that provide access to the user's data.
|
163.154.1
by Pete Woods
Discuss the click packaging in the tutorial documentation |
118 |
</ul>
|
119 |
||
163.223.2
by Pete Woods
Remove references to local-content scope |
120 |
The security manifest for this type of scope should be as follows:
|
163.154.1
by Pete Woods
Discuss the click packaging in the tutorial documentation |
121 |
|
122 |
\code
|
|
123 |
{
|
|
124 |
"template": "ubuntu-scope-network",
|
|
163.223.1
by Pete Woods
Update the docs and examples to match the new confinement policy |
125 |
"policy_groups": [],
|
163.209.1
by Pete Woods
Incorrect click packaging documentation |
126 |
"policy_version": 1.2
|
163.154.1
by Pete Woods
Discuss the click packaging in the tutorial documentation |
127 |
}
|
128 |
\endcode
|
|
129 |
||
163.315.1
by Michi Henning
Lots of doc fixes and updates. |
130 |
\subsection impl Implementing a scope
|
163.98.1
by Pawel Stolowski
Minor additions to the tutorial. |
131 |
|
163.315.1
by Michi Henning
Lots of doc fixes and updates. |
132 |
This short tutorial covers the basic steps and building blocks needed to implement a scope in C++ with unity-scopes-api.
|
133 |
For complete examples of various scopes, see the `demo/scopes` subdirectory of the unity-scopes-api source project.
|
|
163.98.1
by Pawel Stolowski
Minor additions to the tutorial. |
134 |
|
163.98.2
by Pawel Stolowski
Fixes. |
135 |
A typical scope implementation needs to implement interfaces of the following classes from the Scopes API:
|
163.98.1
by Pawel Stolowski
Minor additions to the tutorial. |
136 |
<ul>
|
163.315.1
by Michi Henning
Lots of doc fixes and updates. |
137 |
<li>unity::scopes::ScopeBase - the main scope class and entry point for all incoming requests
|
138 |
<li>unity::scopes::SearchQueryBase - the handler for search requests
|
|
139 |
<li>unity::scopes::PreviewQueryBase - the handler for preview requests (only if handling previews)
|
|
140 |
<li>unity::scopes::ActivationQueryBase - the handler for activation and preview action requests (only if handling previews and activation)
|
|
141 |
<li>unity::scopes::SearchListenerBase - the handler for search replies (only in aggreagator scopes, to pull results from other scopes)
|
|
163.98.1
by Pawel Stolowski
Minor additions to the tutorial. |
142 |
</ul>
|
143 |
||
163.315.1
by Michi Henning
Lots of doc fixes and updates. |
144 |
The following sections show explaing these in more detail.
|
145 |
||
146 |
\subsubsection simplescope Case 1: A simple (non-aggregating) scope
|
|
147 |
||
148 |
This is the typical case: a scope that connects to a remote or local backend, such as a database,
|
|
149 |
and provides results in response to search queries coming from a
|
|
150 |
client (that is, the Unity Dash or another scope).
|
|
151 |
||
152 |
\paragraph scopebase Implementing ScopeBase
|
|
153 |
||
154 |
You must create a class that derives from \link unity::scopes::ScopeBase ScopeBase\endlink and
|
|
155 |
implement a few methods. As a minimum, you must provide implementations of the
|
|
156 |
\link unity::scopes::ScopeBase::search search()\endlink and \link unity::scopes::ScopeBase::preview preview()\endlink methods.
|
|
64.1.1
by Pawel Stolowski
First cut at scopes tutorial. |
157 |
|
158 |
\code{.cpp}
|
|
163.315.1
by Michi Henning
Lots of doc fixes and updates. |
159 |
using unity::scopes;
|
160 |
||
161 |
class MyScope : public ScopeBase
|
|
64.1.1
by Pawel Stolowski
First cut at scopes tutorial. |
162 |
{
|
163 |
public:
|
|
163.315.1
by Michi Henning
Lots of doc fixes and updates. |
164 |
virtual void start(std::string const& scope_id) override; // optional, dflt impl does nothing
|
165 |
virtual void stop() override; // optional, dflt impl does nothing
|
|
166 |
virtual void run() override; // optional, dflt impl does nothing
|
|
167 |
virtual SearchQueryBase::UPtr search(CannedQuery const& query,
|
|
168 |
SearchMetadata const& metadata) override;
|
|
169 |
virtual PreviewQueryBase::UPtr preview(Result const& result,
|
|
170 |
ActionMetadata const& metadata) override;
|
|
64.1.1
by Pawel Stolowski
First cut at scopes tutorial. |
171 |
}
|
172 |
\endcode
|
|
173 |
||
163.437.3
by Michi Henning
Doc fixes "run time" -> "runtime" for consistency. |
174 |
The scopes runtime calls \link unity::scopes::ScopeBase::start() start()\endlink once prior to
|
163.315.1
by Michi Henning
Lots of doc fixes and updates. |
175 |
sending any queries. You can use it to perform one-time initialization for your scope. Note that you should
|
176 |
not perform any lengthy operations in `start()`. Your implementation must return as quickly as possible
|
|
177 |
(in a fraction of the second), so do not, for example, make synchronous network requests as part of `start()`.
|
|
178 |
||
179 |
The scope ID passed to `start()` is taken from the name your scope's `.ini` configuration file.
|
|
180 |
||
163.437.3
by Michi Henning
Doc fixes "run time" -> "runtime" for consistency. |
181 |
The scopes runtime calls \link unity::scopes::ScopeBase::stop() stop()\endlink to inform your scope
|
163.315.1
by Michi Henning
Lots of doc fixes and updates. |
182 |
that it should shut down. You can use this method to perform any one-time clean-up.
|
183 |
||
163.437.3
by Michi Henning
Doc fixes "run time" -> "runtime" for consistency. |
184 |
Prior to sending any queries, the scopes runtime calls \link unity::scopes::ScopeBase::run() run()\endlink if your `start()` method
|
163.315.1
by Michi Henning
Lots of doc fixes and updates. |
185 |
completed successfully (did not throw an exception). The `run()` method
|
186 |
is called by a separate thread that you can use for your own purposes, for example, to run an event loop.
|
|
163.437.3
by Michi Henning
Doc fixes "run time" -> "runtime" for consistency. |
187 |
The scopes runtime has no further interest in this thread, but you must ensure that, if you do not return
|
163.315.1
by Michi Henning
Lots of doc fixes and updates. |
188 |
from `run()`, you must return from `run()` in response to a call to `stop()`.
|
189 |
||
190 |
For typical and simple cases, you can ignore `run()`.
|
|
64.1.1
by Pawel Stolowski
First cut at scopes tutorial. |
191 |
|
163.98.10
by Pawel Stolowski
Changed structure, make it appear on main page. |
192 |
\paragraph handlingsearch Handling search
|
163.83.2
by Pawel Stolowski
Described preview and activation handling. |
193 |
|
327.1.1
by Kyle Fazzari
Fix a couple typos in the tutorial. |
194 |
The unity::scopes::ScopeBase::search() method is called once for each query. Its purpose is to instantiate
|
163.315.1
by Michi Henning
Lots of doc fixes and updates. |
195 |
and return a new C++ instance that encapsulates the query, that is, `search()` is a factory method.
|
196 |
(Do not start execution of the query as part of `search()`; the query object has a separate method for this.)
|
|
197 |
||
198 |
`search()` must return an instance of an object that implements the unity::scopes::SearchQueryBase interface, for example:
|
|
64.1.1
by Pawel Stolowski
First cut at scopes tutorial. |
199 |
|
200 |
\code{.cpp}
|
|
163.315.1
by Michi Henning
Lots of doc fixes and updates. |
201 |
|
202 |
class MyQuery : public SearchQueryBase { ... };
|
|
203 |
||
163.83.5
by Pawel Stolowski
More tutorial updates. |
204 |
SearchQueryBase::UPtr MyScope::search(CannedQuery const& query, SearchMetadata const& metadata)
|
64.1.1
by Pawel Stolowski
First cut at scopes tutorial. |
205 |
{
|
163.213.7
by Pawel Stolowski
Updated tutorial and release notes. |
206 |
SearchQueryBase::UPtr q(new MyQuery(query, metadata));
|
64.1.1
by Pawel Stolowski
First cut at scopes tutorial. |
207 |
return q;
|
208 |
}
|
|
209 |
\endcode
|
|
210 |
||
163.315.1
by Michi Henning
Lots of doc fixes and updates. |
211 |
The search() method receives two arguments: a unity::scopes::CannedQuery query object that (among other information) carries the actual
|
212 |
query string, and
|
|
213 |
additional parameters for the search request, passed as unity::scopes::SearchMetadata. The metadata includes information such as
|
|
214 |
the current locale string, the form factor, and the query cardinality.
|
|
215 |
||
216 |
Cardinality is the maximum number of results expected from a query (a value of 0 indicates no limit). For optimal performance,
|
|
217 |
do not return more results than indicated by the cardinality. If you more than the requested number of results, you are
|
|
163.437.3
by Michi Henning
Doc fixes "run time" -> "runtime" for consistency. |
218 |
wasting resources. (The scopes runtime ignores the additional results.)
|
163.315.1
by Michi Henning
Lots of doc fixes and updates. |
219 |
|
163.402.1
by Marcus Tomlinson
Added "Handling aggregation" section |
220 |
\paragraph handlingaggregation Handling aggregation
|
221 |
||
222 |
As previously stated, SearchMetadata contains additional information about the search requests you receive, including
|
|
223 |
the methods:
|
|
224 |
||
225 |
<ul>
|
|
226 |
<li>\link unity::scopes::SearchMetadata::is_aggregated is_aggregated()\endlink - true if the request was initiated by
|
|
227 |
an aggregator,
|
|
228 |
<li>and \link unity::scopes::SearchMetadata::aggregated_keywords aggregated_keywords()\endlink - the list of keywords
|
|
229 |
used by the aggregator to find your scope.
|
|
230 |
</ul>
|
|
231 |
||
232 |
\note Please refer to the <a href="https://developer.ubuntu.com/en/scopes/tutorials/scope-keywords/">Scope Keywords</a>
|
|
233 |
tutorial document for more detail on using keywords in your scope.
|
|
234 |
||
235 |
You can use the is_aggregated() method from within
|
|
236 |
\link unity::scopes::SearchQueryBase::run SearchQueryBase::run()\endlink in order to ensure that an appropriate set of
|
|
237 |
results are returned when queried by an aggregator:
|
|
238 |
||
239 |
\code{.cpp}
|
|
240 |
void MyQuery::run(SearchReplyProxy const& reply)
|
|
241 |
{
|
|
242 |
if (metadata_.is_aggregated())
|
|
243 |
{
|
|
244 |
auto category = reply->register_category("agg_cat",
|
|
245 |
"MyScope Featured",
|
|
246 |
agg_icon);
|
|
247 |
do_aggregated_search(reply, category);
|
|
248 |
}
|
|
249 |
else
|
|
250 |
{
|
|
251 |
do_normal_search(reply);
|
|
252 |
}
|
|
253 |
}
|
|
254 |
\endcode
|
|
255 |
||
256 |
You may notice in the code snippet above that for each aggregated search we receive, we register a specific results
|
|
257 |
category. Although aggregators may be willing to accept more than one category from its child scopes, they are only
|
|
258 |
required to accept the first.
|
|
259 |
||
260 |
Thereafter, an aggregator may choose to ignore any additional categories the child scope registers. It is therefore
|
|
261 |
recommended that scope authors follow the above method of handling aggregated searches. It is also recommended that
|
|
262 |
your scope provide a decent category title (e.g. "MyScope Featured"). An aggregator is likely to display this category
|
|
263 |
title as is within its result set, so try to keep it clean and descriptive.
|
|
264 |
||
163.315.1
by Michi Henning
Lots of doc fixes and updates. |
265 |
\paragraph surfacingmode Surfacing mode
|
266 |
||
267 |
The query string may be the empty string. If so, the UI is asking your scope to produce default results
|
|
268 |
that are shown in what is known as _surfacing mode_. These are the results the UI displays if the user
|
|
269 |
navigates to your scope, but has not entered a query yet. What results to show here depends on how your
|
|
270 |
scope works. For example, for a music scope, the default results could be something like "Most Popular"
|
|
271 |
and "Recently Played"; similarly, for a weather scope, the default results could be for the weather
|
|
272 |
report for the current location. As the scope author, you need to decide what is most appropriate
|
|
273 |
to show in surfacing mode. In the interests of a good user experience, it is important to show _something_
|
|
163.350.3
by Michi Henning
Fixed typos in comments and doc. |
274 |
here (if at all possible), so the user gets to see at least some results (instead of being confronted with
|
163.315.1
by Michi Henning
Lots of doc fixes and updates. |
275 |
a blank screen).
|
276 |
||
163.384.3
by Michi Henning
Added cache read/write. Tests still missing. |
277 |
The runtime automatically saves the results of the most recent surfacing query. If a scope cannot produce
|
278 |
a result for a surfacing query (presumably, due to connectivity problems), calling
|
|
279 |
\link unity::scopes::SearchReply::push_surfacing_results_from_cache() push_surfacing_results_from_cache()\endlink
|
|
280 |
pushes the results that were produced by the most recent successful
|
|
281 |
surfacing query from the cache. If your scope cannot produce surfacing results, you can call this
|
|
282 |
method to "replay" the results of the previous surfacing query. In turn, this avoids the user
|
|
283 |
being presented with an empty screen if he/she swipes to the scope while the device does not have connectivity.
|
|
284 |
||
285 |
`push_surfacing_results_from_cache()` has an effect only if called for a surfacing query (that is, a query with an empty query string). If called for a non-empty query, it does nothing.
|
|
286 |
||
287 |
You must call this method before calling \link unity::scopes::Reply::finished finished()\endlink,
|
|
163.384.6
by Michi Henning
Fixed symbols file. Minor doc fix. |
288 |
otherwise no cached results will be pushed. (`push_surfacing_results_from_cache() implicitly calls `finished()`);
|
163.384.3
by Michi Henning
Added cache read/write. Tests still missing. |
289 |
|
163.315.1
by Michi Henning
Lots of doc fixes and updates. |
290 |
\paragraph querybase Implementing QueryBase
|
291 |
||
292 |
You must implement a class that derives from \link unity::scopes::SearchQueryBase SearchQueryBase\endlink and return
|
|
293 |
an instance of this class from `search()`.
|
|
163.437.3
by Michi Henning
Doc fixes "run time" -> "runtime" for consistency. |
294 |
Your class must implement a \link unity::scopes::SearchQueryBase::run run()\endlink method. The scopes runtime calls
|
163.315.1
by Michi Henning
Lots of doc fixes and updates. |
295 |
`run()` to execute the query.
|
296 |
||
297 |
The \link unity::scopes::SearchReplyProxy SearchReplyProxy\endlink that is passed to `run()` is an invocation
|
|
327.1.1
by Kyle Fazzari
Fix a couple typos in the tutorial. |
298 |
handle that allows you to push results for the query back towards the client. (`SearchReplyProxy` is a `shared_ptr`
|
163.315.1
by Michi Henning
Lots of doc fixes and updates. |
299 |
to a \link unity::scopes::SearchReply SearchReply\endlink object.)
|
300 |
||
301 |
Two important methods of `SerchReply` are \link unity::scopes::SearchReply::register_category register_category()\endlink
|
|
302 |
and \link unity::scopes::SearchReply::push push()\endlink.
|
|
303 |
||
304 |
`register_category()` is a factory method that registers new categories for the results of this query (see
|
|
163.350.1
by Michi Henning
Added Version attribute to Scope.ini and scope metadata. |
305 |
\link unity::scopes::Category\endlink). You can create new categories at any point during query processing.
|
306 |
Categories serve to visually group query results in some way;
|
|
307 |
when you push results for a query, you indicate which
|
|
163.315.1
by Michi Henning
Lots of doc fixes and updates. |
308 |
category each particular result belongs to, and the UI renders that result in the corresponding
|
163.350.1
by Michi Henning
Added Version attribute to Scope.ini and scope metadata. |
309 |
visual group. Categories are rendered in the order in which they are encountered by the UI
|
310 |
as you push your results. If you want to control the order in which categories are rendered
|
|
311 |
(for examples, such that a "Breaking News" category always appears first), you may need to
|
|
312 |
buffer the results you receive from your back-end data source until you get a result for that
|
|
313 |
category, and then push that result, plus any other buffered results.
|
|
163.315.1
by Michi Henning
Lots of doc fixes and updates. |
314 |
|
315 |
Pre-registering categories is the preferred approach because it allows the UI to reserve space
|
|
316 |
and perform layout chores before any query results arrive. (In turn, this permits the UI to
|
|
317 |
optimize its operation.) However, for some data sources, it may not be possible to determine
|
|
318 |
all of the possible categories in advance, in which case you have no choice but to create
|
|
319 |
new categories as they arrive in the data from your scope's data source.
|
|
320 |
||
321 |
Do _not_ wait for all results for a query to arrive in an attempt to buffer them and order
|
|
322 |
them by category. If you do, this prevents incremental rendering, and the user sees nothing
|
|
323 |
until your scope has processed _all_ results. To create a positive user experience,
|
|
324 |
your scope should push results as soon as possible.
|
|
325 |
||
163.443.1
by Michi Henning
Updated doc to clarify that unique category IDs are a bad idea. |
326 |
The UI uses categories to incrementally render the display after a refresh of search results. This relies
|
327 |
on categories staying the same from query to query. If your scope has, say, a "News" category, you need
|
|
328 |
to make sure that the category ID and name stay the same from query to query. In particular, do _not_
|
|
329 |
create category IDs that are artificially unique per query (such as by appending a sequence number).
|
|
330 |
||
163.315.1
by Michi Henning
Lots of doc fixes and updates. |
331 |
When you create a category, you can provide a \link unity::scopes::CategoryRenderer \endlink instance.
|
332 |
The category renderer determines the visual appearance of the results in that category (such as
|
|
333 |
display in a grid or in a carousel layout).
|
|
334 |
||
335 |
You must wrap each actual search result inside a \link unity::scopes::CategorisedResult CategorisedResult\endlink object and
|
|
336 |
pass the result instance to \link unity::scopes::SearchReply::push push\endlink.
|
|
337 |
||
338 |
A typical implementation of `run()` might look like this:
|
|
64.1.1
by Pawel Stolowski
First cut at scopes tutorial. |
339 |
|
340 |
\code{.cpp}
|
|
141.1.1
by Michal Hruby
Updated tutorial |
341 |
void MyQuery::run(SearchReplyProxy const& reply)
|
64.1.1
by Pawel Stolowski
First cut at scopes tutorial. |
342 |
{
|
163.315.1
by Michi Henning
Lots of doc fixes and updates. |
343 |
if (!valid())
|
344 |
{
|
|
345 |
return; // Query was cancelled
|
|
346 |
}
|
|
347 |
||
163.16.1
by Michal Hruby
More docs |
348 |
auto category = reply->register_category("recommended", "Recommended", icon);
|
64.1.1
by Pawel Stolowski
First cut at scopes tutorial. |
349 |
//... query a local or remote backend
|
350 |
||
163.315.1
by Michi Henning
Lots of doc fixes and updates. |
351 |
for (auto res : backend.get_results(query().query_string())) // for every result returned by a backend
|
64.1.1
by Pawel Stolowski
First cut at scopes tutorial. |
352 |
{
|
353 |
...
|
|
141.1.1
by Michal Hruby
Updated tutorial |
354 |
CategorisedResult result(category); // create a result item in "recommended" category
|
64.1.1
by Pawel Stolowski
First cut at scopes tutorial. |
355 |
result.set_uri(...);
|
356 |
result.set_title(...);
|
|
357 |
result.set_art(...);
|
|
358 |
result.set_dnd_uri(...);
|
|
141.1.1
by Michal Hruby
Updated tutorial |
359 |
result["my-custom-attribute"] = Variant(...); // add arbitrary data as needed
|
64.1.1
by Pawel Stolowski
First cut at scopes tutorial. |
360 |
|
163.83.2
by Pawel Stolowski
Described preview and activation handling. |
361 |
if (!reply->push(result)) // send result to the client
|
362 |
{
|
|
163.315.1
by Michi Henning
Lots of doc fixes and updates. |
363 |
break; // false from push() means that the search was cancelled
|
163.83.2
by Pawel Stolowski
Described preview and activation handling. |
364 |
}
|
365 |
}
|
|
366 |
}
|
|
367 |
\endcode
|
|
368 |
||
163.315.1
by Michi Henning
Lots of doc fixes and updates. |
369 |
As far as the UI is concerned, the query is complete when `run()` returns. (While the query can potentially
|
370 |
return more results, the UI shows a spinner or similar, to indicate that the query is not complete yet.)
|
|
371 |
||
372 |
It is possible for you to return from `run()` _without_ having the query complete automatically. The life time
|
|
373 |
of the query is controlled not only by `run()`, but also by the life time of the `SearchReplyProxy` that is passed
|
|
163.437.3
by Michi Henning
Doc fixes "run time" -> "runtime" for consistency. |
374 |
to `run()`. The scopes runtime monitors the reply proxy and informs the UI that the query is complete when
|
163.315.1
by Michi Henning
Lots of doc fixes and updates. |
375 |
_either_ `run()` returns _or_ the last reply proxy for the query goes out of scope. This allows you to, for example,
|
376 |
pass the reply proxy to a different thread that pushes results (as you might want to do if you need to run a
|
|
377 |
separate event loop). That thread can then also react to query cancellation. The important point is that, if
|
|
378 |
you keep copies of the reply proxy, the query will remain alive until you destroy all copies of the reply proxy
|
|
379 |
for that query (or explicitly call `finished()` on the reply proxy yourself, which explicitly ends the query).
|
|
380 |
||
381 |
\paragraph cancellation Query cancellation
|
|
382 |
||
383 |
It is possible for the UI to cancel a query before the query has completed and is still running in your scope, potentially
|
|
384 |
producing additional results.
|
|
385 |
Typically, this happens because the user has typed a few characters as the search term (which creates a query for
|
|
386 |
the string up to that point); shortly after this, the user might type another character or two, extending the search string.
|
|
387 |
After a short idle period, the UI cancels the original query and creates a new query for the extended search string.
|
|
388 |
However, the second query will not start until _after_ the previous query has completed.
|
|
389 |
||
390 |
\note _Query cancellation happens frequently, and it is important for your scope to react quickly to cancellation!_
|
|
391 |
||
163.437.3
by Michi Henning
Doc fixes "run time" -> "runtime" for consistency. |
392 |
The scopes runtime provides several ways for your implementation to react to cancellation:
|
163.315.1
by Michi Henning
Lots of doc fixes and updates. |
393 |
|
394 |
<ul>
|
|
395 |
<li>A `false` return value from `SearchReply::push`. If `push` returns `false`, there is no point in continuing to
|
|
396 |
provide more results.
|
|
397 |
<li>You can poll for cancellation by calling \link unity::scopes::QueryBase::valid QueryBase::valid()\endlink. `valid()`
|
|
398 |
returns `false` once a query is cancelled or has exceeded its cardinality limit.
|
|
399 |
<li>Your query implementation class must override the \link unity::scopes::QueryBase::cancelled QueryBase::cancelled()\endlink
|
|
163.437.3
by Michi Henning
Doc fixes "run time" -> "runtime" for consistency. |
400 |
method. The scopes runtime calls `cancelled()` if the UI has cancelled the query. (Note that calls to `cancelled()` are
|
163.315.1
by Michi Henning
Lots of doc fixes and updates. |
401 |
made by a separate thread.)
|
402 |
</ul>
|
|
403 |
||
404 |
Testing the return value from `push()` is reasonable only if you know that results for your scope will
|
|
405 |
arrive quickly (no more than 0.1 seconds apart). Otherwise, you should push results asynchronously from
|
|
406 |
a separate thread and arrange for the query to complete (return from `run()`) in response to the scopes
|
|
163.437.3
by Michi Henning
Doc fixes "run time" -> "runtime" for consistency. |
407 |
runtime calling `cancelled()`.
|
163.315.1
by Michi Henning
Lots of doc fixes and updates. |
408 |
|
163.437.3
by Michi Henning
Doc fixes "run time" -> "runtime" for consistency. |
409 |
Note that it is possible for a call to `cancelled()` to arrive before the scopes runtime has called `run()`
|
163.315.1
by Michi Henning
Lots of doc fixes and updates. |
410 |
(because `cancelled()` and `run()` are called by different threads and, therefore, can be dispatched out of order).
|
411 |
||
412 |
||
163.460.7
by Pawel Stolowski
Added filters section to the tutorial |
413 |
\paragraph filters Filters
|
414 |
||
415 |
Scopes API offers support for filter widgets, which provide means for filtering search results based on user input other than search query string
|
|
416 |
alone. Filter widgets need to be defined by creating appropriate filters inside the overriden SearchQueryBase::run() method, and then pushed
|
|
163.460.9
by Pawel Stolowski
Minor tutorial fixes |
417 |
to the UI. It is recommended to push filters early before search results are pushed for best user experience.
|
163.460.7
by Pawel Stolowski
Added filters section to the tutorial |
418 |
|
419 |
Here is an example of how filters can be created:
|
|
420 |
||
421 |
\code{.cpp}
|
|
422 |
void run(SearchReplyProxy const& reply)
|
|
423 |
{
|
|
424 |
OptionSelectorFilter::UPtr filter1 = OptionSelectorFilter::create("brand", "Brand");
|
|
425 |
filter1->add_option("audi", "Audi");
|
|
426 |
filter1->add_option("bmw", "BMW");
|
|
427 |
||
428 |
RangeInputFilter::SPtr filter2 = RangeInputFilter::create("price", Variant(0.0f), Variant::null(), "Min", "", "", "Max", "");
|
|
429 |
ValueSliderFilter::SPtr filter3 = ValueSliderFilter::create("horsepower", 1, 135, 50, ValueSliderLabels("Min", "Max"));
|
|
430 |
||
431 |
Filters filters;
|
|
432 |
filters.push_back(filter1);
|
|
433 |
filters.push_back(filter2);
|
|
434 |
filters.push_back(filter3);
|
|
435 |
||
436 |
reply->push(filters, query().filter_state());
|
|
437 |
||
438 |
// push search results here
|
|
439 |
\endcode
|
|
440 |
||
441 |
Scopes are free to change filters at any time - with every execution of search the scope can omit any of the previously visible filters or add new ones, if that
|
|
442 |
makes sense for particular use cases.
|
|
443 |
||
444 |
Filters act only as UI widgets - it is the responsibility of the scope to check their state and actually apply them to search results. The current value of a filter
|
|
445 |
becomes just another parameter of the search query that needs to be taken into account in the implementation of search handling inside run().
|
|
446 |
||
447 |
To examine current state of the filters, pass the instance of unity::scopes::FilterState received with search query to respective methods of
|
|
448 |
the filters. For example:
|
|
449 |
||
450 |
\code{.cpp}
|
|
451 |
void run(SearchReplyProxy const& reply)
|
|
452 |
{
|
|
453 |
// filter creation code omitted here
|
|
454 |
auto state = query().filter_state();
|
|
455 |
int search_start = 0;
|
|
456 |
int search_end = 1000;
|
|
457 |
if (rangefilter->has_start_value(state)) {
|
|
458 |
search_start = rangefilter->start_value(state);
|
|
459 |
}
|
|
460 |
if (rangefilter->has_end_value(state)) {
|
|
461 |
search_end = rangefilter->end_value(state);
|
|
462 |
}
|
|
463 |
||
464 |
// apply search_start and search_end to search logic
|
|
465 |
\endcode
|
|
466 |
||
467 |
The scope may nominate a single filter to act as "primary navigation". This is only possible if departments are not used at the same time (in which case departments
|
|
163.460.9
by Pawel Stolowski
Minor tutorial fixes |
468 |
become a primary navigation tool). An attempt to nominate a filter to be a "primary navigation" while departments are present is ignored by the UI and the
|
469 |
filter acts as a regular filter. Also, only a single-selection OptionSelectorFilter can currently be promoted to be primary navigation. To do this, set the display
|
|
163.460.7
by Pawel Stolowski
Added filters section to the tutorial |
470 |
hints to FilterBase::DisplayHints::Primary:
|
471 |
||
472 |
\code{.cpp}
|
|
473 |
OptionSelectorFilter::UPtr filter1 = OptionSelectorFilter::create("brand", "Brand");
|
|
474 |
filter1->set_display_hints(FilterBase::DisplayHints::Primary);
|
|
475 |
filter1->add_option("audi", "Audi");
|
|
476 |
\endcode
|
|
477 |
||
478 |
When a filter becomes a primary navigation filter, it gets displayed in the search box drop-down, below recent searches, so it's readily available for quick access.
|
|
479 |
Also, currently selected option is displayed as a "brick" in the search box, hinting the user about the context of current search. All the other filters can be
|
|
480 |
revealed via the filters panel icon.
|
|
481 |
||
163.98.10
by Pawel Stolowski
Changed structure, make it appear on main page. |
482 |
\paragraph handlingpreview Handling previews
|
163.83.2
by Pawel Stolowski
Described preview and activation handling. |
483 |
|
163.315.1
by Michi Henning
Lots of doc fixes and updates. |
484 |
Your scope is responsible for handling preview requests for results it has returned; you implement this by overriding
|
485 |
the unity::scopes::ScopeBase::preview() method:
|
|
163.83.2
by Pawel Stolowski
Described preview and activation handling. |
486 |
|
487 |
\code{.cpp}
|
|
163.315.1
by Michi Henning
Lots of doc fixes and updates. |
488 |
class MyScope : public unity::scopes::ScopeBase
|
163.83.2
by Pawel Stolowski
Described preview and activation handling. |
489 |
{
|
490 |
public:
|
|
491 |
...
|
|
163.315.1
by Michi Henning
Lots of doc fixes and updates. |
492 |
virtual PreviewQueryBase::UPtr preview(Result const& result, ActionMetadata const& metadata) override;
|
163.83.2
by Pawel Stolowski
Described preview and activation handling. |
493 |
...
|
494 |
}
|
|
495 |
\endcode
|
|
496 |
||
163.315.1
by Michi Henning
Lots of doc fixes and updates. |
497 |
This method must return an instance derived from unity::scopes::PreviewQueryBase. Like `search()`, `preview()` is a factory method;
|
163.437.3
by Michi Henning
Doc fixes "run time" -> "runtime" for consistency. |
498 |
the scopes runtime initiates the actual preview by calling \link unity::scopes::PreviewQueryBase::run run()\endlink on the instance you
|
163.315.1
by Michi Henning
Lots of doc fixes and updates. |
499 |
return. Your `run()` method is responsible for gathering preview data (from
|
500 |
local or remote sources) and passing it to the UI along with the definition of the visual appearance of the preview by calling
|
|
501 |
\link unity::scopes::PreviewReply::push push()\endlink on the reply proxy that is passed to `run()`. (This is analogous to returning
|
|
502 |
results from `search()`.)
|
|
503 |
||
504 |
A preview consists of one or more preview widgets. Preview widgets are the basic building blocks for previews, such as a header with a title and subtitle, an image, a
|
|
505 |
gallery with multiple images, a list of audio tracks, and so on.(See unity::scopes::PreviewWidget for a list of supported widget types.)
|
|
506 |
Your implementation of \link unity::scopes::PreviewQueryBase::run run()\endlink must create and populate one or more preview widgets
|
|
507 |
and push them to the UI.
|
|
508 |
||
509 |
Each preview widget has a unique identifier, a type name, and a set of attributes determined by the widget's type.
|
|
510 |
For example, a widget of "image" type expects two attributes: "source" (a URI that should point at an image),
|
|
511 |
and a "zoomable" flag that determines if the image should be zoomable.
|
|
512 |
You can specify the values of these attributes explicitly, or you can arrange for the values to be taken from a result
|
|
513 |
that the corresponding query returned earlier, by referencing the corresponding \link unity::scopes::Result Result\endlink instance.
|
|
514 |
You can also push the value for a referenced attribute separately as part of your implementation of `run()`.
|
|
515 |
||
516 |
You provide attributes explicitly by calling
|
|
517 |
\link unity::scopes::PreviewWidget::add_attribute_value PreviewWidget::add_attribute_value()\endlink:
|
|
518 |
||
519 |
\code{.cpp}
|
|
520 |
PreviewWidget image_widget("myimage", "image");
|
|
521 |
||
522 |
image_widget.add_attribute_value("source", Variant("file:///tmp/image.jpg"));
|
|
523 |
image_widget.add_attribute_value("zoomable", Variant(false));
|
|
524 |
\endcode
|
|
525 |
||
526 |
To reference values from results or arbitrary values that you push separately, use
|
|
527 |
\link unity::scopes::PreviewWidget::add_attribute_mapping PreviewWidget::add_attribute_mapping()\endlink:
|
|
528 |
||
529 |
\code{.cpp}
|
|
530 |
PreviewWidget image_widget("myimage", "image");
|
|
531 |
image_widget.add_attribute_mapping("source", "art"); // use 'art' attribute from the result
|
|
532 |
image_widget.add_attribute_mapping("zoomable", "myzoomable"); // 'myzoomable' not specified, but pushed below
|
|
533 |
reply->push("myzoomable", Variant(true));
|
|
534 |
\endcode
|
|
535 |
||
536 |
To push preview widgets to the client, use \link unity::scopes::PreviewReply::push PreviewReply::push()\endlink:
|
|
537 |
||
538 |
\code{.cpp}
|
|
539 |
PreviewWidget image_widget("myimage", "image");
|
|
540 |
PreviewWidget header_widget("myheader", "header");
|
|
541 |
// fill in widget attributes
|
|
542 |
...
|
|
543 |
PreviewWidgetList widgets { image_widget, header_widget };
|
|
544 |
reply->push(widgets);
|
|
163.83.2
by Pawel Stolowski
Described preview and activation handling. |
545 |
\endcode
|
546 |
||
163.98.1
by Pawel Stolowski
Minor additions to the tutorial. |
547 |
\paragraph previewactions Preview actions
|
163.83.2
by Pawel Stolowski
Described preview and activation handling. |
548 |
|
163.315.1
by Michi Henning
Lots of doc fixes and updates. |
549 |
Previews can have actions, such as buttons that the user can press. Actions are supported by a preview widget of type "actions".
|
550 |
An actions widget holds one or more action button definitions, where each definition has a unique identifier, a label,
|
|
551 |
and an optional icon. For example, a widget with two buttons, "Open" and "Download", can be defined as follows
|
|
552 |
(using the \link unity::scopes::VariantBuilder VariantBuilder\endlink helper class):
|
|
163.83.2
by Pawel Stolowski
Described preview and activation handling. |
553 |
|
554 |
\code{.cpp}
|
|
163.315.1
by Michi Henning
Lots of doc fixes and updates. |
555 |
|
556 |
PreviewWidget buttons("mybuttons", "actions");
|
|
557 |
||
558 |
VariantBuilder builder;
|
|
559 |
builder.add_tuple({
|
|
560 |
{"id", Variant("open")},
|
|
561 |
{"label", Variant("Open")}
|
|
562 |
});
|
|
563 |
builder.add_tuple({
|
|
564 |
{"id", Variant("download")},
|
|
565 |
{"label", Variant("Download")}
|
|
566 |
});
|
|
567 |
||
568 |
buttons.add_attribute_value("actions", builder.end());
|
|
163.83.2
by Pawel Stolowski
Described preview and activation handling. |
569 |
\endcode
|
570 |
||
163.315.1
by Michi Henning
Lots of doc fixes and updates. |
571 |
To respond to activation of preview actions, your scope must implement
|
572 |
\link unity::scopes::ScopeBase::perform_action ScopeBase::perform_action\endlink:
|
|
163.83.2
by Pawel Stolowski
Described preview and activation handling. |
573 |
|
574 |
\code{.cpp}
|
|
163.315.1
by Michi Henning
Lots of doc fixes and updates. |
575 |
class MyScope : public ScopeBase
|
163.83.2
by Pawel Stolowski
Described preview and activation handling. |
576 |
{
|
163.315.1
by Michi Henning
Lots of doc fixes and updates. |
577 |
...
|
578 |
virtual ActivationQueryBase::UPtr perform_action(Result const& result,
|
|
579 |
ActionMetadata const& metadata,
|
|
580 |
std::string const& widget_id,
|
|
581 |
std::string const& action_id) override
|
|
163.83.2
by Pawel Stolowski
Described preview and activation handling. |
582 |
...
|
583 |
}
|
|
584 |
\endcode
|
|
585 |
||
163.315.1
by Michi Henning
Lots of doc fixes and updates. |
586 |
Like `search()` and `preview()`, `perform_action()` is a factory method. It must return an
|
587 |
instance that derives from \link unity::scopes::ActivationQueryBase ActivationQueryBase\endlink.
|
|
588 |
Your derived class must implement the \link unity::scopes::ActivationQueryBase::activate activate()\endlink method,
|
|
589 |
whose job it is to respond to the activation (that is, the user pressing a button). `activate` must return
|
|
590 |
an \link unity::scopes::ActivationResponse ActivationResponse\endlink, which tells the UI how it should
|
|
591 |
behave in response to the activation. For example, your `activate()` could direct the UI to
|
|
592 |
run a new search as follows:
|
|
163.83.2
by Pawel Stolowski
Described preview and activation handling. |
593 |
|
594 |
\code{.cpp}
|
|
163.315.1
by Michi Henning
Lots of doc fixes and updates. |
595 |
class MyActivation : public ActivationQueryBase
|
163.83.2
by Pawel Stolowski
Described preview and activation handling. |
596 |
{
|
163.315.1
by Michi Henning
Lots of doc fixes and updates. |
597 |
MyActivation(Result const& result, unity::scopes::ActionMetadata const& metadata) :
|
163.213.7
by Pawel Stolowski
Updated tutorial and release notes. |
598 |
ActivationQueryBase(result, metadata)
|
599 |
{
|
|
600 |
}
|
|
601 |
||
163.315.1
by Michi Henning
Lots of doc fixes and updates. |
602 |
virtual ActivationResponse activate() override
|
163.83.2
by Pawel Stolowski
Described preview and activation handling. |
603 |
{
|
604 |
...
|
|
163.213.7
by Pawel Stolowski
Updated tutorial and release notes. |
605 |
if (action_id() == "search-grooveshark")
|
163.83.2
by Pawel Stolowski
Described preview and activation handling. |
606 |
{
|
163.98.8
by Michal Hruby
A few fixes to reflect latest API |
607 |
CannedQuery query("com.canonical.scopes.grooveshark");
|
163.83.2
by Pawel Stolowski
Described preview and activation handling. |
608 |
query.set_query_string("metal");
|
163.315.1
by Michi Henning
Lots of doc fixes and updates. |
609 |
return ActivationResponse(query);
|
163.83.2
by Pawel Stolowski
Described preview and activation handling. |
610 |
}
|
611 |
...
|
|
612 |
}
|
|
163.315.1
by Michi Henning
Lots of doc fixes and updates. |
613 |
};
|
163.83.2
by Pawel Stolowski
Described preview and activation handling. |
614 |
\endcode
|
615 |
||
163.98.10
by Pawel Stolowski
Changed structure, make it appear on main page. |
616 |
\paragraph handlingactivation Handling result activation
|
163.83.2
by Pawel Stolowski
Described preview and activation handling. |
617 |
|
163.315.1
by Michi Henning
Lots of doc fixes and updates. |
618 |
In many cases, the user can activate search results directly, by tapping on them, provided the result's schema (such as "http://")
|
619 |
has a handler in the system. If this is the case, you need not do anything for activation. However, if your scope uses
|
|
620 |
schemas without a handler, the shell will ignore the activation. (Nothing happens in response to a tap by the user.)
|
|
163.108.1
by Pawel Stolowski
Some more clarification on result activation handling doc. |
621 |
|
163.315.1
by Michi Henning
Lots of doc fixes and updates. |
622 |
If you want to intercept such activations (either for schemas without a handler, or to generally intercept result activation),
|
623 |
you must implement the \link unity::scopes::ScopeBase::activate ScopeBase::activate()\endlink method:
|
|
163.83.2
by Pawel Stolowski
Described preview and activation handling. |
624 |
|
625 |
\code{.cpp}
|
|
626 |
class MyScope : public ScopeBase
|
|
627 |
{
|
|
163.315.1
by Michi Henning
Lots of doc fixes and updates. |
628 |
virtual ActivationQueryBase::UPtr activate(Result const& result,
|
629 |
ActionMetadata const& metadata) override;
|
|
163.83.2
by Pawel Stolowski
Described preview and activation handling. |
630 |
...
|
631 |
}
|
|
632 |
\endcode
|
|
633 |
||
163.315.1
by Michi Henning
Lots of doc fixes and updates. |
634 |
In addition, you must call \link unity::scopes::Result::set_intercept_activation Result::set_intercept_activation()\endlink
|
635 |
for all results that should trigger a
|
|
636 |
call to your `activate()` method. Your implementation of `activate()` should follow the same guidelines as for
|
|
637 |
`perform_action()` (except that widget and action identifiers do not apply to result activation).
|
|
638 |
||
163.474.1
by Pawel Stolowski
Added section about in-card action activation |
639 |
\paragraph resultaction Handling result action activation
|
640 |
||
163.474.6
by Pawel Stolowski
Minor grammar fixes |
641 |
Search results can embed simple action buttons (icons) in their cards. When the user taps an action icon, the scope gets notified and can update
|
642 |
the affected result card to reflect the new state. A typical use case for this is to offer "social" actions, such as thumbs up/down buttons.
|
|
163.474.1
by Pawel Stolowski
Added section about in-card action activation |
643 |
|
644 |
The following snippet demonstrates how two actions can be added to a \link unity::scopes::CategorisedResult CategorisedResult\endlink:
|
|
645 |
||
646 |
\code
|
|
647 |
CategorisedResult res(cat);
|
|
648 |
res.set_uri("myuri");
|
|
649 |
res.set_title("My Title");
|
|
650 |
||
651 |
// Add result actions
|
|
652 |
VariantBuilder builder;
|
|
653 |
builder.add_tuple({
|
|
654 |
{"id", Variant("thumbsup")},
|
|
655 |
{"icon", Variant("thOff")},
|
|
656 |
{"temporaryIcon", Variant("thOn")},
|
|
657 |
{"label", Variant("I like it")},
|
|
658 |
});
|
|
659 |
builder.add_tuple({
|
|
660 |
{"id", Variant("flag")},
|
|
661 |
{"icon", Variant("flag")},
|
|
662 |
{"temporaryIcon", Variant("flagOn")},
|
|
663 |
{"label", Variant("Flag this result")},
|
|
664 |
});
|
|
163.474.3
by Pawel Stolowski
Renamed social_attributes to social-actions |
665 |
res["social-actions"] = builder.end();
|
163.474.1
by Pawel Stolowski
Added section about in-card action activation |
666 |
\endcode
|
667 |
||
668 |
The attributes of result actions are as follows:
|
|
669 |
<ul>
|
|
670 |
<li>id - unique action identifier that will be reported to the scope.
|
|
163.474.6
by Pawel Stolowski
Minor grammar fixes |
671 |
<li>icon - the icon for the action button.
|
672 |
<li>temporaryIcon (optional) - defines an icon that will be shown immediately when the user taps the button, before the scope reacts to the action.
|
|
673 |
<li>label - the text shown next to the icon.
|
|
163.474.1
by Pawel Stolowski
Added section about in-card action activation |
674 |
</ul>
|
675 |
||
676 |
To respond to activation of result actions, your scope must implement
|
|
677 |
\link unity::scopes::ScopeBase::activate_result_action ScopeBase::activate_result_action\endlink:
|
|
678 |
||
679 |
\code{.cpp}
|
|
680 |
class MyScope : public ScopeBase
|
|
681 |
{
|
|
682 |
...
|
|
683 |
ActivationQueryBase::UPtr activate_result_action(Result const& result,
|
|
684 |
ActionMetadata const& metadata,
|
|
685 |
std::string const& action_id) override;
|
|
686 |
...
|
|
687 |
}
|
|
688 |
\endcode
|
|
689 |
||
690 |
Like `search()` and `preview()`, `activate_result_action()` is a factory method. It must return an
|
|
691 |
instance that derives from \link unity::scopes::ActivationQueryBase ActivationQueryBase\endlink.
|
|
692 |
Your derived class must implement the \link unity::scopes::ActivationQueryBase::activate activate()\endlink method,
|
|
693 |
whose job it is to respond to the activation (that is, the user pressing action button). `activate` must return
|
|
694 |
an \link unity::scopes::ActivationResponse ActivationResponse\endlink, which tells the UI how it should
|
|
695 |
behave in response to the result action activation. For result actions the typical and recommended behavior is to update the card
|
|
696 |
for the result whose action was activated.
|
|
697 |
||
163.474.6
by Pawel Stolowski
Minor grammar fixes |
698 |
For example, here is how to update the actions of an affected card in response to a "thumbsup" action, so that tapping the "thumbsup" action button replaces that
|
163.474.1
by Pawel Stolowski
Added section about in-card action activation |
699 |
button with "thumbsdown":
|
700 |
||
701 |
\code{.cpp}
|
|
702 |
class MyActivation : public ActivationQueryBase
|
|
703 |
{
|
|
704 |
MyActivation(Result const& result, unity::scopes::ActionMetadata const& metadata, std::string const& action_id) :
|
|
705 |
ActivationQueryBase(result, metadata, action_id)
|
|
706 |
{
|
|
707 |
}
|
|
708 |
||
709 |
virtual ActivationResponse activate() override
|
|
710 |
{
|
|
711 |
if (action_id() == "thumbsup")
|
|
712 |
{
|
|
713 |
// ... update backend data for 'thumbs up' action ...
|
|
714 |
||
715 |
// get the affect result and update it
|
|
716 |
Result updatedRes(result());
|
|
717 |
VariantBuilder builder;
|
|
718 |
builder.add_tuple({
|
|
719 |
{"id", Variant("thumbsdown")},
|
|
720 |
{"icon", Variant("thOn")},
|
|
721 |
{"temporaryIcon", Variant("thOff")},
|
|
722 |
{"label", Variant("I don't like it")},
|
|
723 |
});
|
|
724 |
builder.add_tuple({ ... })
|
|
163.474.4
by Pawel Stolowski
Fix typo |
725 |
updatedRes["social-actions"] = builder.end();
|
163.474.1
by Pawel Stolowski
Added section about in-card action activation |
726 |
return ActivationResponse(updatedRes);
|
727 |
}
|
|
728 |
||
729 |
if (action_id() == "thumbsdown")
|
|
730 |
...
|
|
731 |
}
|
|
732 |
};
|
|
733 |
\endcode
|
|
734 |
||
163.315.1
by Michi Henning
Lots of doc fixes and updates. |
735 |
\paragraph export Exporting a scope
|
736 |
||
737 |
Your scope must be compiled into a `.so` shared library and, to be successfully
|
|
738 |
loaded at runtime, it must provide two C functions to create and destroy it.
|
|
739 |
A typical code snippet to do this looks as follows:
|
|
64.1.1
by Pawel Stolowski
First cut at scopes tutorial. |
740 |
|
741 |
\code{.cpp}
|
|
163.315.1
by Michi Henning
Lots of doc fixes and updates. |
742 |
extern "C"
|
743 |
{
|
|
744 |
unity::scopes::ScopeBase* UNITY_SCOPE_CREATE_FUNCTION()
|
|
64.1.1
by Pawel Stolowski
First cut at scopes tutorial. |
745 |
{
|
746 |
return new MyScope();
|
|
747 |
}
|
|
748 |
||
163.315.1
by Michi Henning
Lots of doc fixes and updates. |
749 |
void UNITY_SCOPE_DESTROY_FUNCTION(unity::scopes::ScopeBase* scope_base)
|
64.1.1
by Pawel Stolowski
First cut at scopes tutorial. |
750 |
{
|
751 |
delete scope_base;
|
|
752 |
}
|
|
753 |
}
|
|
754 |
\endcode
|
|
755 |
||
163.464.4
by Pawel Stolowski
Doc fixes |
756 |
\paragraph inlineplayback Inline music playback
|
757 |
||
758 |
Results which represent music (songs, albums etc.) can contain an extra data about audio content and can then be played directly from the Dash.
|
|
759 |
Such results have a "play" button overlaid on them. To create results that support this functionality two conditions must be met:
|
|
760 |
<ul>
|
|
761 |
<li>Category renderer definition must contain the "quick-preview-type" key with the value of "audio" in the "template" section;
|
|
762 |
<li>Results in the respective category must contain a "quick-preview-data" attribute, each of them is a dictionary with the extra playback data described
|
|
763 |
below.
|
|
764 |
</ul>
|
|
765 |
||
766 |
The data assigned to "quick-preview-data" attribute of a Result needs to contain the following keys:
|
|
767 |
<ul>
|
|
768 |
<li>uri - a playable uri of a media file (path of a local file, or http uri).
|
|
769 |
<li>duration - the duration of the media file, in seconds.
|
|
163.464.5
by Pawel Stolowski
-the |
770 |
<li>playlist - an array of uris of additional songs, e.g. songs from same album; they will be played in sequence when the main
|
163.464.4
by Pawel Stolowski
Doc fixes |
771 |
song denoted by 'uri' finishes.
|
772 |
</ul>
|
|
773 |
||
774 |
Here is an example of a category renderer for inline playback, which uses component mapping to map quick-preview-data to audio-data attribute of a result:
|
|
775 |
\code{.cpp}
|
|
776 |
static const char CATEGORY_RENDERER[] = R"(
|
|
777 |
{
|
|
778 |
"schema-version": 1,
|
|
779 |
"template": {
|
|
780 |
"category-layout": "grid",
|
|
781 |
"card-size": "large",
|
|
782 |
"card-layout" : "horizontal",
|
|
783 |
"quick-preview-type" : "audio"
|
|
784 |
},
|
|
785 |
"components": {
|
|
786 |
"title": "title",
|
|
787 |
"art": {
|
|
788 |
"field": "art"
|
|
789 |
},
|
|
790 |
"subtitle": "artist",
|
|
791 |
"quick-preview-data": {
|
|
792 |
"field": "audio-data"
|
|
793 |
}
|
|
794 |
}
|
|
795 |
}
|
|
796 |
)";
|
|
797 |
\endcode
|
|
798 |
||
799 |
A sample code that creates a result card representing a song and all songs from same album in a background playlist may look this way:
|
|
800 |
\code{.cpp}
|
|
801 |
||
802 |
CategorisedResult res(category);
|
|
803 |
res.set_uri(uri);
|
|
804 |
res.set_title(media.getTitle());
|
|
805 |
...
|
|
806 |
||
807 |
VariantMap inline_playback_data;
|
|
808 |
inline_playback_data["uri"] = uri;
|
|
809 |
inline_playback_data["duration"] = song_duration_in_seconds;
|
|
810 |
VariantArray playlist;
|
|
811 |
for (const std::string& song: album_songs)
|
|
812 |
{
|
|
813 |
playlist.push_back(Variant(song.getUri()));
|
|
814 |
}
|
|
815 |
inline_playback_data["playlist"] = playlist;
|
|
816 |
res["audio-data"] = inline_playback_data;
|
|
817 |
||
818 |
\endcode
|
|
819 |
||
163.315.1
by Michi Henning
Lots of doc fixes and updates. |
820 |
\subsubsection aggscope Case 2: An aggregating scope
|
821 |
||
822 |
Aggregating scopes are scopes that collect results from other scopes and possibly consolidate, modify, or re-categorise
|
|
823 |
the results in some way. In other words, for an aggregating scope, the data source(s) are other scopes rather than,
|
|
824 |
say, a remote web service.
|
|
825 |
||
826 |
To receive results from its child scopes, your scope must implement a class that derives from
|
|
827 |
\link unity::scopes::SearchListenerBase SearchListenerBase\endlink. You provide an instance
|
|
163.437.3
by Michi Henning
Doc fixes "run time" -> "runtime" for consistency. |
828 |
of this class to each sub-query; the scopes runtime invokes callback methods on this class
|
163.315.1
by Michi Henning
Lots of doc fixes and updates. |
829 |
to let you know when a new result or status update arrives, and when a query completes.
|
830 |
||
163.402.2
by Marcus Tomlinson
Updated "Finding child scopes" section to include the use of find_child_scopes() in aggregators |
831 |
\paragraph childscopes Finding child scopes
|
163.315.1
by Michi Henning
Lots of doc fixes and updates. |
832 |
|
163.437.3
by Michi Henning
Doc fixes "run time" -> "runtime" for consistency. |
833 |
To send queries to its child scopes, your scope must obtain a proxy for each child scope. The scopes runtime
|
163.315.1
by Michi Henning
Lots of doc fixes and updates. |
834 |
runs a registry process. The job of the registry (among other things) is to provide information about available
|
835 |
scopes (whether they are local scopes or remote scopes in the Smartscopes server).
|
|
836 |
||
837 |
You can obtain the proxy for a child scope by calling \link unity::scopes::Registry::get_metadata get_metadata()\endlink
|
|
838 |
on the registry, supplying the ID of the child scope. The return value is an instance of type
|
|
839 |
\link unity::scopes::ScopeMetadata ScopeMetadata\endlink that describes the scope and also provides access to the
|
|
840 |
proxy for the scope.
|
|
841 |
||
163.402.2
by Marcus Tomlinson
Updated "Finding child scopes" section to include the use of find_child_scopes() in aggregators |
842 |
You can also aggregate scopes indirectly via keyword(s). Keywords describe the type of content a scope provides (e.g.
|
843 |
a scope with the keyword "music" will return music results, the "video" keyword indicates video content, and so on).
|
|
844 |
You can obtain child scopes via keywords by calling \link unity::scopes::Registry::list_if list_if()\endlink on the
|
|
845 |
registry, supplying a predicate function. The return value is a map containing only those scopes for which the predicate
|
|
846 |
returns true. Therefore, your predicate function should return true for all scopes matching the keyword(s) you wish to
|
|
847 |
aggregate.
|
|
848 |
||
849 |
\note Please refer to the <a href="https://developer.ubuntu.com/en/scopes/tutorials/scope-keywords/">Scope Keywords</a>
|
|
850 |
tutorial document for a list of recommended keywords to use.
|
|
851 |
||
852 |
As an aggregator scope author you must provide an implementation of the virtual
|
|
853 |
\link unity::scopes::ScopeBase::find_child_scopes ScopeBase::find_child_scopes()\endlink method. All logic for finding
|
|
854 |
your aggregator's child scopes should be implemented within this method. The return value is of type
|
|
855 |
\link unity::scopes::ChildScopeList ChildScopeList\endlink and must contain an instance of
|
|
856 |
\link unity::scopes::ChildScope ChildScope\endlink for each scope your aggregator may collect results from.
|
|
857 |
||
858 |
Here is how you could implement find_child_scopes() to return all scopes in the registry that contain the keywords
|
|
859 |
"sports" and "news":
|
|
860 |
||
861 |
\code{.cpp}
|
|
862 |
ChildScopeList MyScope::find_child_scopes() const override
|
|
863 |
{
|
|
864 |
auto sportsnews_scopes = registry()->list_if([](ScopeMetadata const& item)
|
|
865 |
{
|
|
866 |
auto keywords = item.keywords();
|
|
867 |
return (keywords.find("sports") != keywords.end()) &&
|
|
868 |
(keywords.find("news") != keywords.end());
|
|
869 |
});
|
|
870 |
||
871 |
ChildScopeList list;
|
|
872 |
for (auto const& sportsnews_scope : sportsnews_scopes)
|
|
873 |
{
|
|
874 |
list.emplace_back(ChildScope{sportsnews_scope.first, // Child scope ID
|
|
875 |
sportsnews_scope.second, // Child scope metadata
|
|
876 |
true, // Default enabled state (when first discovered)
|
|
877 |
{"sports", "news"}}); // Keywords used to aggregate this scope
|
|
878 |
}
|
|
879 |
return list;
|
|
880 |
}
|
|
881 |
\endcode
|
|
882 |
||
163.315.1
by Michi Henning
Lots of doc fixes and updates. |
883 |
\paragraph subquery Sub-queries
|
884 |
||
163.366.9
by Pawel Stolowski
Updated tutorial. |
885 |
To send a query to another scope, use one of the `subsearch()` overloads of \link unity::scopes::SearchQueryBase\endlink
|
163.315.1
by Michi Henning
Lots of doc fixes and updates. |
886 |
inside your implementation of
|
887 |
\link unity::scopes::SearchQueryBase::run SearchQueryBase::run()\endlink.
|
|
163.402.3
by Marcus Tomlinson
Updated "Sub-queries" section to use find_child_scopes() and child_scopes() methods |
888 |
This method requires a handle to the child scope to query (either via proxy or ChildScope handle), the query details
|
889 |
(\link unity::scopes::CannedQuery CannedQuery\endlink), plus an instance of your `SearchListenerBase` implementation
|
|
890 |
that will receive the query results.
|
|
163.315.1
by Michi Henning
Lots of doc fixes and updates. |
891 |
|
892 |
\note `subsearch()` is identical to
|
|
163.437.3
by Michi Henning
Doc fixes "run time" -> "runtime" for consistency. |
893 |
\link unity::scopes::ScopeBase::search search()\endlink but, for `subsearch()`, the scopes runtime transparently
|
163.315.1
by Michi Henning
Lots of doc fixes and updates. |
894 |
forwards query cancellation to child scopes, so your implementation of \link unity::scopes::QueryBase::cancelled QueryBase::cancelled()\endlink
|
895 |
does not need to forward cancellation to its children.
|
|
896 |
(However, your query class still needs to react to cancellation and should terminate the current query
|
|
897 |
is quickly as possible in response to a cancelled message.)
|
|
898 |
||
163.402.3
by Marcus Tomlinson
Updated "Sub-queries" section to use find_child_scopes() and child_scopes() methods |
899 |
You should always call \link unity::scopes::ScopeBase::child_scopes ScopeBase::child_scopes()\endlink from within your
|
900 |
aggregator's \link unity::scopes::ScopeBase::search search()\endlink method in order to retrieve the latest child
|
|
901 |
scopes list containing the most recent "enabled" states. You can then pass this list into your instantiation of
|
|
902 |
SearchQueryBase for later use.
|
|
903 |
||
904 |
\note An aggregator must respect the "enabled" states of its child scopes, querying only the child scopes that are
|
|
905 |
enabled.
|
|
906 |
||
163.315.1
by Michi Henning
Lots of doc fixes and updates. |
907 |
Here is how you could implement an aggregating scope that passes a query to a single child scope "scope-A":
|
64.1.1
by Pawel Stolowski
First cut at scopes tutorial. |
908 |
|
909 |
\code{.cpp}
|
|
910 |
||
163.402.3
by Marcus Tomlinson
Updated "Sub-queries" section to use find_child_scopes() and child_scopes() methods |
911 |
ChildScopeList MyScope::find_child_scopes() const override
|
64.1.1
by Pawel Stolowski
First cut at scopes tutorial. |
912 |
{
|
163.315.1
by Michi Henning
Lots of doc fixes and updates. |
913 |
auto reg = registry(); // Up-call into base class
|
914 |
if (!reg)
|
|
915 |
{
|
|
916 |
throw ConfigException(scope_id + ": No registry available, cannot locate child scopes");
|
|
917 |
}
|
|
918 |
||
163.402.3
by Marcus Tomlinson
Updated "Sub-queries" section to use find_child_scopes() and child_scopes() methods |
919 |
ChildScopeList list;
|
64.1.1
by Pawel Stolowski
First cut at scopes tutorial. |
920 |
try
|
921 |
{
|
|
163.315.1
by Michi Henning
Lots of doc fixes and updates. |
922 |
auto meta = reg->get_metadata("scope-A");
|
163.402.3
by Marcus Tomlinson
Updated "Sub-queries" section to use find_child_scopes() and child_scopes() methods |
923 |
list.emplace_back(ChildScope{"scope-A", meta});
|
64.1.1
by Pawel Stolowski
First cut at scopes tutorial. |
924 |
}
|
925 |
catch (NotFoundException const& e)
|
|
926 |
{
|
|
927 |
...
|
|
928 |
}
|
|
163.402.3
by Marcus Tomlinson
Updated "Sub-queries" section to use find_child_scopes() and child_scopes() methods |
929 |
return list;
|
64.1.1
by Pawel Stolowski
First cut at scopes tutorial. |
930 |
}
|
931 |
||
163.315.1
by Michi Henning
Lots of doc fixes and updates. |
932 |
QueryBase::UPtr MyScope::search(CannedQuery const& query,
|
933 |
SearchMetadata const& metadata)
|
|
64.1.1
by Pawel Stolowski
First cut at scopes tutorial. |
934 |
{
|
163.402.3
by Marcus Tomlinson
Updated "Sub-queries" section to use find_child_scopes() and child_scopes() methods |
935 |
SearchQueryBase::UPtr q(new MyQuery(query, metadata, child_scopes()));
|
64.1.1
by Pawel Stolowski
First cut at scopes tutorial. |
936 |
return q;
|
937 |
}
|
|
938 |
||
939 |
...
|
|
940 |
||
163.315.1
by Michi Henning
Lots of doc fixes and updates. |
941 |
void MyQuery::run(SearchReplyProxy const& upstream_reply)
|
64.1.1
by Pawel Stolowski
First cut at scopes tutorial. |
942 |
{
|
163.402.3
by Marcus Tomlinson
Updated "Sub-queries" section to use find_child_scopes() and child_scopes() methods |
943 |
// Continue only if our child scope is installed AND enabled
|
944 |
if (!child_scopes_.empty() && child_scopes_.front().enabled)
|
|
945 |
{
|
|
946 |
auto category = reply->register_category("recommended", "Recommended", icon, "");
|
|
947 |
SearchListenerBase::SPtr reply(new MyReceiver(upstream_reply, category));
|
|
948 |
subsearch(child_scopes_.front(), query_, reply);
|
|
949 |
}
|
|
64.1.1
by Pawel Stolowski
First cut at scopes tutorial. |
950 |
}
|
951 |
\endcode
|
|
952 |
||
163.315.1
by Michi Henning
Lots of doc fixes and updates. |
953 |
Note that the `subsearch()` call is asynchronous and returns immediately. Despite this, your `MyQuery` instance is kept alive
|
163.437.3
by Michi Henning
Doc fixes "run time" -> "runtime" for consistency. |
954 |
because the scopes runtime does not delete it until the child query has completed. (The runtime tracks the `reply` proxy
|
163.315.1
by Michi Henning
Lots of doc fixes and updates. |
955 |
for the query and holds the query alive until it receives a finished message from the child scope.)
|
956 |
||
957 |
\paragraph receiver Receiving sub-query results
|
|
958 |
||
959 |
Here is a simple implementation of a receiver that passes all child categories and results through to
|
|
960 |
its parent without change. Of course, a more realistic aggregating scope will typically aggregate from
|
|
961 |
more than one child and probably de-duplicate, collate, or otherwise modify child results before passing
|
|
962 |
them upstream.
|
|
64.1.1
by Pawel Stolowski
First cut at scopes tutorial. |
963 |
|
964 |
\code{.cpp}
|
|
965 |
||
163.315.1
by Michi Henning
Lots of doc fixes and updates. |
966 |
class MyReceiver: public SearchListenerBase
|
967 |
{
|
|
968 |
public:
|
|
969 |
virtual void push(Category::SCPtr const& category) override
|
|
970 |
{
|
|
971 |
upstream_reply_->register_category(category);
|
|
972 |
}
|
|
973 |
||
974 |
virtual void push(CategorisedResult result) override
|
|
975 |
{
|
|
976 |
upstream_reply_->push(std::move(result));
|
|
977 |
}
|
|
978 |
||
979 |
MyReceiver(SearchReplyProxy const& upstream_reply) :
|
|
980 |
upstream_reply_(upstream_reply)
|
|
981 |
{
|
|
982 |
}
|
|
983 |
||
984 |
private:
|
|
985 |
SearchReplyProxy upstream_reply_;
|
|
986 |
};
|
|
64.1.1
by Pawel Stolowski
First cut at scopes tutorial. |
987 |
\endcode
|
988 |
||
163.366.12
by Michi Henning
Reworked documentation. |
989 |
\paragraph aggbuffering Controlling category order
|
990 |
||
991 |
Categories are displayed in the order their results are pushed. This can pose a challenge
|
|
992 |
for aggregator scopes because results from child scopes often arrive
|
|
993 |
in random order. To control the order in which categories are rendered,
|
|
994 |
the aggregator must buffer and potentially re-order results by
|
|
995 |
category before pushing them.
|
|
996 |
||
997 |
\link unity::scopes::utility::BufferedResultForwarder BufferedResultForwarder\endlink makes
|
|
998 |
it easier to do this.
|
|
999 |
To use the class, you create one instance for each child scope and chain the instances together
|
|
1000 |
in the desired order of categories. Each forwarder buffers results until its predecessor in
|
|
1001 |
the chain indicates that it has completed its category ordering, at which point it itself pushes
|
|
1002 |
any results it has buffered so far and indicates to its follower that it is ready.
|
|
1003 |
||
1004 |
By default, a forwarder indicates that it it is ready (has completed ordering) as soon as it has received
|
|
1005 |
a single result. This is useful if an aggregator has child scopes that produce results
|
|
1006 |
for a single category each. In this case, the order of the forwarders determines which
|
|
1007 |
category (the one used by child A or by child B) appears first when the results are rendered.
|
|
1008 |
||
1009 |
If an aggregator collates results from children that each produce results for more than
|
|
1010 |
one category, you can override the default implementation of
|
|
1011 |
\link unity::scopes::utility::BufferedResultForwarder::push push()\endlink to change
|
|
1012 |
categories for results from its child, and/or indicate
|
|
1013 |
that it is ready only once the child has provided results for all expected categories.
|
|
1014 |
(See \link unity::scopes::utility::BufferedResultForwarder BufferedResultForwarder\endlink
|
|
1015 |
for more details.)
|
|
163.366.9
by Pawel Stolowski
Updated tutorial. |
1016 |
|
163.315.1
by Michi Henning
Lots of doc fixes and updates. |
1017 |
\paragraph aggactiv Activation and preview
|
1018 |
||
1019 |
If an aggregator scope simply forwards the results it receives from other scopes (possibly changing their category),
|
|
1020 |
the aggregator need not do anything special for previews, preview actions, or result activation. In this case,
|
|
1021 |
previews, preview actions, and result activation are sent to the scope that produced the corresponding result.
|
|
1022 |
||
1023 |
If, however, an aggregator scope changes attributes of results (or creates completely new results that "replace"
|
|
1024 |
received results), you must take extra care:
|
|
163.83.5
by Pawel Stolowski
More tutorial updates. |
1025 |
<ul>
|
163.315.1
by Michi Henning
Lots of doc fixes and updates. |
1026 |
<li>If the original original scope should still handle preview (and activation) requests for a modified result, you must store
|
1027 |
a copy of the original result in the modified (or new) result by calling \link unity::scopes::Result::store Result::store()\endlink.
|
|
1028 |
Preview requests for such a result will automatically trigger the scope that created the innermost stored result.
|
|
1029 |
||
1030 |
\note Making changes to a receive result but failing to store the original result with the change can cause
|
|
1031 |
in unexpected behavior: a scope could receive a modified result and, depending the exact changes, may
|
|
1032 |
not be able to correctly deal with the result.
|
|
1033 |
||
1034 |
<li>If an aggregator creates a completely new result that replaces the original result but does not also store a copy of
|
|
1035 |
the original result, the aggregator _must_ handle preview and activation requests (if the intercept flag is set).
|
|
1036 |
The actions to take are the same as for a non-aggregating scope (see \ref handlingpreview and \ref handlingactivation).
|
|
163.83.5
by Pawel Stolowski
More tutorial updates. |
1037 |
</ul>
|
1038 |
||
163.315.1
by Michi Henning
Lots of doc fixes and updates. |
1039 |
Here is an example `push()` implementation that modifies a result and stores a copy, so the original scope
|
1040 |
can handle preview and activation:
|
|
163.83.5
by Pawel Stolowski
More tutorial updates. |
1041 |
|
1042 |
\code{.cpp}
|
|
1043 |
void MyReceiver::push(CategorisedResult original_result)
|
|
1044 |
{
|
|
163.315.1
by Michi Henning
Lots of doc fixes and updates. |
1045 |
// agg_category is a category that aggregates all results from other scopes
|
1046 |
CategorisedResult result(agg_category);
|
|
163.83.5
by Pawel Stolowski
More tutorial updates. |
1047 |
result.set_uri(original_result.uri());
|
163.315.1
by Michi Henning
Lots of doc fixes and updates. |
1048 |
result.set_title(original_result.title() + " (aggregated)");
|
163.83.5
by Pawel Stolowski
More tutorial updates. |
1049 |
result.set_art(original_result.art());
|
1050 |
result.store(original_result);
|
|
1051 |
||
1052 |
upstream_->push(std::move(result));
|
|
1053 |
}
|
|
1054 |
\endcode
|
|
163.83.3
by Pawel Stolowski
Fist cut at agg activation / preview doc. |
1055 |
|
163.437.1
by Michi Henning
Added doc about how method calls are partitioned onto threads. |
1056 |
\subsection threading Threading model
|
1057 |
||
1058 |
It is important to understand how the runtime uses threads to call methods on scopes and clients.
|
|
1059 |
The runtime maintains a number of threads that each call one or more methods. Methods in the same
|
|
1060 |
group are always called by the same thread. This means that methods in the same group do not run concurrently,
|
|
1061 |
but methods in different groups _do_ run concurrently. If you share state between methods in
|
|
1062 |
different groups, you _must_ synchronize access to that state, otherwise your code will suffer from
|
|
1063 |
race conditions.
|
|
1064 |
||
1065 |
The following lists shows how methods are grouped. Each group has a single dedicated dispatch thread.
|
|
1066 |
||
1067 |
<ul>
|
|
163.437.2
by Michi Henning
Added initialization methods to thread discussion. Minor rewording for clarity. |
1068 |
<li>\link UNITY_SCOPE_CREATE_FUNCTION()\endlink,
|
1069 |
\link unity::scopes::ScopeBase::start() ScopeBase::start()\endlink,
|
|
1070 |
\link unity::scopes::ScopeBase::stop() ScopeBase::stop()\endlink, and
|
|
163.437.5
by Michi Henning
Added missing parens to symbol in tutorial. |
1071 |
\link UNITY_SCOPE_DESTROY_FUNCTION()\endlink.
|
163.437.1
by Michi Henning
Added doc about how method calls are partitioned onto threads. |
1072 |
<li>\link unity::scopes::ScopeBase::search() ScopeBase::search()\endlink,
|
1073 |
\link unity::scopes::ScopeBase::preview() ScopeBase::preview()\endlink, and
|
|
1074 |
\link unity::scopes::ScopeBase::perform_action() ScopeBase::perform_action()\endlink.
|
|
1075 |
<li>\link unity::scopes::SearchQueryBase::run() SearchQueryBase::run()\endlink,
|
|
1076 |
\link unity::scopes::PreviewQueryBase::run() PreviewQueryBase::run()\endlink, and
|
|
1077 |
\link unity::scopes::ActivationQueryBase::activate() ActivationQueryBase::activate()\endlink.
|
|
1078 |
<li>\link unity::scopes::QueryBase::cancelled() QueryBase::cancelled()\endlink.
|
|
1079 |
<li>\link unity::scopes::SearchListenerBase::push() SearchListenerBase::push()\endlink,
|
|
1080 |
\link unity::scopes::PreviewListenerBase::push() PreviewListenerBase::push()\endlink,
|
|
1081 |
\link unity::scopes::ActivationListenerBase::activated() ActivationListenerBase::activated()\endlink,
|
|
1082 |
\link unity::scopes::ListenerBase::finished() ListenerBase::finished()\endlink,
|
|
1083 |
\link unity::scopes::ListenerBase::info() ListenerBase::info()\endlink.
|
|
1084 |
</ul>
|
|
1085 |
For your scope implementation, keep in mind that `cancelled()` is _not_ called by
|
|
1086 |
the same thread that called, for example, `search()` or `run()`. This means that any state you
|
|
1087 |
established in `search()` or `run()` must be synchronized if you use that state in `cancelled()`.
|
|
1088 |
||
1089 |
Similar considerations apply for aggregating scopes, which act as both client and server: you must
|
|
163.437.2
by Michi Henning
Added initialization methods to thread discussion. Minor rewording for clarity. |
1090 |
synchronize any state that is shared between the client side and the server side. For example,
|
1091 |
you must synchronize state established in `search()` and accessed from `push()` or `finished()`.
|
|
163.437.1
by Michi Henning
Added doc about how method calls are partitioned onto threads. |
1092 |
|
163.228.26
by Michi Henning
Added semantic check for duplicate setting ids. Added lots of doc to the tutorial. |
1093 |
\subsection scopesettings Settings
|
1094 |
||
1095 |
A scope can provide for simple customizations, such as allowing the user to configure an email address or
|
|
1096 |
select a distance unit as metric or imperial.
|
|
1097 |
||
163.315.1
by Michi Henning
Lots of doc fixes and updates. |
1098 |
\subsubsection settings_definitions Defining settings
|
163.228.26
by Michi Henning
Added semantic check for duplicate setting ids. Added lots of doc to the tutorial. |
1099 |
|
163.228.38
by Michi Henning
Changed settings schema to use .ini file instead, called <scope_id>-settings.ini. |
1100 |
You can define such settings in a configuration file.
|
163.228.26
by Michi Henning
Added semantic check for duplicate setting ids. Added lots of doc to the tutorial. |
1101 |
The file must be placed into the same directory as the scope's normal
|
163.228.38
by Michi Henning
Changed settings schema to use .ini file instead, called <scope_id>-settings.ini. |
1102 |
configuration file, with the name `<scope-name>-settings.ini`. For example, for a scope with ID `com.acme.myscope`,
|
163.228.26
by Michi Henning
Added semantic check for duplicate setting ids. Added lots of doc to the tutorial. |
1103 |
the normal configuration file is `com.acme.myscope.ini`, and the settings definition file is
|
163.228.38
by Michi Henning
Changed settings schema to use .ini file instead, called <scope_id>-settings.ini. |
1104 |
`com.acme.myscope-settings.ini`. Both files must be installed in the same directory (together with the scope's `.so` file).
|
163.228.26
by Michi Henning
Added semantic check for duplicate setting ids. Added lots of doc to the tutorial. |
1105 |
|
163.228.38
by Michi Henning
Changed settings schema to use .ini file instead, called <scope_id>-settings.ini. |
1106 |
The shell constructs a user interface from the settings definitions. The user can change settings via that UI.
|
1107 |
The scope can retrieve the actual setting values at run time (see \ref read_settings).
|
|
163.228.26
by Michi Henning
Added semantic check for duplicate setting ids. Added lots of doc to the tutorial. |
1108 |
|
1109 |
The following types are supported for settings:
|
|
1110 |
||
1111 |
<ul>
|
|
1112 |
<li>`string` - a string value
|
|
163.315.1
by Michi Henning
Lots of doc fixes and updates. |
1113 |
<li>`number` - a numeric value (integer or floating point)
|
163.228.26
by Michi Henning
Added semantic check for duplicate setting ids. Added lots of doc to the tutorial. |
1114 |
<li>`boolean` - `true` or `false`
|
1115 |
<li>`list` - a list of alternatives to choose from (single-choice)
|
|
1116 |
</ul>
|
|
1117 |
||
1118 |
It is possible to optionally define a default value for each setting.
|
|
1119 |
||
1120 |
Here are the contents of an example definition file:
|
|
1121 |
~~~
|
|
163.228.38
by Michi Henning
Changed settings schema to use .ini file instead, called <scope_id>-settings.ini. |
1122 |
[location]
|
1123 |
type = string
|
|
1124 |
defaultValue = London
|
|
1125 |
displayName = Location
|
|
1126 |
||
1127 |
[distanceUnit]
|
|
1128 |
type = list
|
|
1129 |
defaultValue = 1
|
|
1130 |
displayName = Distance Unit
|
|
1131 |
displayName[de] = Entfernungseinheit
|
|
1132 |
displayValues = Kilometers;Miles
|
|
1133 |
displayValues[de] = Kilometer;Meilen
|
|
1134 |
||
1135 |
[age]
|
|
1136 |
type = number
|
|
1137 |
defaultValue = 23
|
|
1138 |
displayName = Age
|
|
1139 |
||
1140 |
[enabled]
|
|
1141 |
type = boolean
|
|
1142 |
defaultValue = true
|
|
1143 |
displayName = Enabled
|
|
1144 |
||
1145 |
# Setting without a default value
|
|
1146 |
[color]
|
|
1147 |
type = string
|
|
1148 |
displayName = Color
|
|
163.228.26
by Michi Henning
Added semantic check for duplicate setting ids. Added lots of doc to the tutorial. |
1149 |
~~~
|
1150 |
||
163.228.38
by Michi Henning
Changed settings schema to use .ini file instead, called <scope_id>-settings.ini. |
1151 |
The file must contain a group for each setting.
|
1152 |
The order of the groups determines the display order for the user interface
|
|
1153 |
that is constructed by the shell. The group name is the ID of the corresponding setting.
|
|
163.228.26
by Michi Henning
Added semantic check for duplicate setting ids. Added lots of doc to the tutorial. |
1154 |
|
1155 |
Each setting definition must contain at least the following mandatory definitions:
|
|
1156 |
<ul>
|
|
1157 |
<li> `type` - Defines the type of the setting (`string`, `number`, `boolean`, or `list`).
|
|
163.228.38
by Michi Henning
Changed settings schema to use .ini file instead, called <scope_id>-settings.ini. |
1158 |
<li> `displayName` - Defines a display name that is shown for this setting by the shell.
|
163.228.26
by Michi Henning
Added semantic check for duplicate setting ids. Added lots of doc to the tutorial. |
1159 |
</ul>
|
1160 |
||
163.228.38
by Michi Henning
Changed settings schema to use .ini file instead, called <scope_id>-settings.ini. |
1161 |
The defaultValue field is optional. If present, it defines
|
163.228.26
by Michi Henning
Added semantic check for duplicate setting ids. Added lots of doc to the tutorial. |
1162 |
a default value that is provided to the scope if the user has not changed anything (or has never used the settings UI
|
163.228.38
by Michi Henning
Changed settings schema to use .ini file instead, called <scope_id>-settings.ini. |
1163 |
before using the scope).
|
1164 |
It is possible to test for settings that do not have a default value and
|
|
1165 |
were never set by the user (see \ref read_settings).
|
|
163.228.26
by Michi Henning
Added semantic check for duplicate setting ids. Added lots of doc to the tutorial. |
1166 |
|
163.228.38
by Michi Henning
Changed settings schema to use .ini file instead, called <scope_id>-settings.ini. |
1167 |
For settings of type `list`, the `displayValues` field is mandatory. It must contain an array
|
1168 |
that lists the available choices. If you provide a default value,
|
|
163.228.26
by Michi Henning
Added semantic check for duplicate setting ids. Added lots of doc to the tutorial. |
1169 |
it must be in the range `0..max-1` (where `max` is the number of choices).
|
1170 |
||
163.228.38
by Michi Henning
Changed settings schema to use .ini file instead, called <scope_id>-settings.ini. |
1171 |
The `displayName` and `displayValues` fields can be localized by appending a locale identifier
|
1172 |
in square brackets. If no entry can be found that matches the current locale, the non-localized value
|
|
1173 |
is used.
|
|
1174 |
||
163.315.1
by Michi Henning
Lots of doc fixes and updates. |
1175 |
\subsubsection read_settings Accessing settings
|
163.228.26
by Michi Henning
Added semantic check for duplicate setting ids. Added lots of doc to the tutorial. |
1176 |
|
1177 |
The settings that are currently in effect are available to a scope via the unity::scopes::ScopeBase::settings()
|
|
1178 |
and unity::scopes::QueryBase::settings() methods.
|
|
163.228.38
by Michi Henning
Changed settings schema to use .ini file instead, called <scope_id>-settings.ini. |
1179 |
These methods return a unity::scopes::VariantMap with one entry per setting. The map contains an entry for
|
1180 |
each setting (using the group name as the key). The lookup value is a unity::scopes::Variant that holds
|
|
1181 |
the current value of the setting.
|
|
1182 |
||
1183 |
If a setting has a value, the corresponding entry in the map contains a string (for settings of type `string`,
|
|
1184 |
a boolean (for settings of type `boolean`), or an integer (for settings of type `number` and `list`). (If the user
|
|
163.232.1
by Marcus Tomlinson
Missing the word "provide" |
1185 |
did not provide a particular value, but the settings definition provided a default value, the `Variant` contains the
|
1186 |
default value.
|
|
163.228.38
by Michi Henning
Changed settings schema to use .ini file instead, called <scope_id>-settings.ini. |
1187 |
|
1188 |
If a setting does not have a default value, and the user did not establish a value for the setting, the corresponding
|
|
1189 |
entry is absent from the map.
|
|
163.228.26
by Michi Henning
Added semantic check for duplicate setting ids. Added lots of doc to the tutorial. |
1190 |
|
1191 |
When you use settings in your scope implementation, do not cache the values and re-use them
|
|
1192 |
for a different query. If you do, any setting changes made by the user will not take effect until
|
|
163.437.3
by Michi Henning
Doc fixes "run time" -> "runtime" for consistency. |
1193 |
your scope is re-started by the runtime. (Because the user cannot know when that happens, this
|
163.228.26
by Michi Henning
Added semantic check for duplicate setting ids. Added lots of doc to the tutorial. |
1194 |
can be highly confusing.) Instead, call `settings()` each time you need to use the value
|
1195 |
of a setting. That way, your scope will react to any change made by the user as soon as it receives another
|
|
1196 |
query.
|
|
1197 |
||
163.228.38
by Michi Henning
Changed settings schema to use .ini file instead, called <scope_id>-settings.ini. |
1198 |
Here is an example of how to read the current settings values for the definition in \ref settings_definitions :
|
1199 |
||
1200 |
~~~
|
|
1201 |
// In your `ScopeBase` or `QueryBase` implementation:
|
|
1202 |
||
1203 |
unity::scopes::VariantMap s = settings(); // The settings method is provided by the base class
|
|
1204 |
||
1205 |
cout << s["location"].get_string(); // Prints "London" unless the user changed the value
|
|
1206 |
||
1207 |
auto it = s.find("color");
|
|
1208 |
if (it != s.end()) // Setting does not have a default value, need to test
|
|
1209 |
{
|
|
1210 |
cout << it->second.get_string(); // Prints the user-established value
|
|
1211 |
}
|
|
1212 |
~~~
|
|
163.228.26
by Michi Henning
Added semantic check for duplicate setting ids. Added lots of doc to the tutorial. |
1213 |
|
163.354.5
by Michi Henning
Updated doc and tutorial. |
1214 |
\subsection directories File system access
|
1215 |
||
1216 |
Scopes that are installed from click packages are subject to confinement and are not allowed
|
|
1217 |
to access most parts of the file system. However, a few locations are available to a scope.
|
|
1218 |
You can access these paths by calling methods on \link unity::scopes::ScopeBase ScopeBase\endlink.
|
|
1219 |
||
1220 |
\note Do not call these methods from the constructor of your `ScopeBase` implementation. If you
|
|
1221 |
do, these methods throw `LogicException`. Instead, call them from
|
|
1222 |
\link unity::scopes::ScopeBase::start() start()\endlink or any time thereafter.
|
|
1223 |
||
1224 |
\link unity::scopes::ScopeBase::scope_directory() scope_directory()\endlink returns the path of the installation
|
|
1225 |
directory of the scope. This directory contains the scope's `.so` and `.ini` files, plus whatever other
|
|
1226 |
files you decide to package with your scope. The scope has read-only permission for this directory.
|
|
1227 |
||
1228 |
\link unity::scopes::ScopeBase::cache_directory() cache_directory()\endlink returns the path of a
|
|
1229 |
directory that is (exclusively) writable for the scope. You can use this directory to store
|
|
1230 |
persistent information, such as a cache of results.
|
|
1231 |
||
1232 |
\link unity::scopes::ScopeBase::app_directory() app_directory()\endlink returns the path of a
|
|
1233 |
read-only directory. If the scope is packaged together with an app, the app has permission to write
|
|
1234 |
files in this location, that is, this directory can be used make information provided by the app
|
|
1235 |
available to the scope (but not vice versa).
|
|
1236 |
||
1237 |
\link unity::scopes::ScopeBase::tmp_directory() tmp_directory()\endlink returns the path of a
|
|
1238 |
read-only directory that is (exclusively) writable for the scope. This directory is periodically
|
|
1239 |
cleaned of unused files. The exact amount of time may vary, but is on the order of a few hours.
|
|
1240 |
The directory is also cleaned during reboot.
|
|
1241 |
||
163.316.14
by Marcus Tomlinson
Added "Online Accounts" section to tutorial.dox |
1242 |
\subsection online_accounts Online Accounts
|
1243 |
||
1244 |
A scope may require access to an online account in order to evaluate particular results, perform certain actions, or
|
|
1245 |
perhaps even operate at all. The following section describes how to use online account services from your scope.
|
|
1246 |
||
1247 |
\subsubsection oa_step1 Step 1: Update Apparmor manifest.
|
|
1248 |
||
1249 |
Firstly, in order for your scope to be granted access to the online accounts backend, the "accounts" policy group needs
|
|
1250 |
to be added to your Apparmor manifest file, as follows:
|
|
1251 |
||
1252 |
\paragraph oa_apparmor Example Apparmor manifest file:
|
|
1253 |
\code
|
|
1254 |
{
|
|
1255 |
"template": "ubuntu-scope-network",
|
|
1256 |
"policy_groups": [
|
|
1257 |
"accounts"
|
|
1258 |
],
|
|
1259 |
"policy_version": 1.2
|
|
1260 |
}
|
|
1261 |
\endcode
|
|
1262 |
||
1263 |
\subsubsection oa_step2 Step 2: Account service configuration.
|
|
1264 |
||
1265 |
Scopes access accounts at a service level (E.g. YouTube service under a Google account, Ubuntu Store service under an
|
|
1266 |
Ubuntu One account, etc.), therefore each scope must provide some config to specify its account service requirements.
|
|
1267 |
||
163.316.22
by Marcus Tomlinson
Create a desktop file for a scope when it is installed, and remove it when uninstalled |
1268 |
There are 2 additional files that a scope must supply:
|
163.316.14
by Marcus Tomlinson
Added "Online Accounts" section to tutorial.dox |
1269 |
1. A .service file to specify a method of accessing its particular account provider.
|
163.316.22
by Marcus Tomlinson
Create a desktop file for a scope when it is installed, and remove it when uninstalled |
1270 |
2. A .application file to link one or more services to your scope.
|
163.316.14
by Marcus Tomlinson
Added "Online Accounts" section to tutorial.dox |
1271 |
|
1272 |
\paragraph oa_service Example .service file:
|
|
1273 |
\code
|
|
1274 |
<?xml version="1.0" encoding="UTF-8"?>
|
|
1275 |
<service id="com.ubuntu.scopes.youtube_youtube">
|
|
1276 |
<type>sharing</type>
|
|
1277 |
<icon>youtube</icon>
|
|
1278 |
<name>YouTube</name>
|
|
1279 |
<provider>google</provider>
|
|
1280 |
<translations>unity-scope-youtube</translations>
|
|
1281 |
<template>
|
|
1282 |
<group name="auth">
|
|
1283 |
<setting name="method">oauth2</setting>
|
|
1284 |
<setting name="mechanism">web_server</setting>
|
|
1285 |
<group name="oauth2">
|
|
1286 |
<group name="web_server">
|
|
1287 |
<setting name="Host">accounts.google.com</setting>
|
|
1288 |
<setting name="AuthPath">o/oauth2/auth?access_type=offline</setting>
|
|
1289 |
<setting name="TokenPath">o/oauth2/token</setting>
|
|
1290 |
<setting name="RedirectUri">https://wiki.ubuntu.com/</setting>
|
|
1291 |
<setting name="ResponseType">code</setting>
|
|
1292 |
<setting type="as" name="Scope">['https://www.googleapis.com/auth/youtube.readonly']</setting>
|
|
1293 |
<setting name="ClientId">xxxx</setting>
|
|
1294 |
<setting name="ClientSecret">xxxx</setting>
|
|
1295 |
<setting type="as" name="AllowedSchemes">['https','http']</setting>
|
|
1296 |
</group>
|
|
1297 |
</group>
|
|
1298 |
</group>
|
|
1299 |
</template>
|
|
1300 |
</service>
|
|
1301 |
\endcode
|
|
1302 |
||
1303 |
\paragraph oa_application Example .application file:
|
|
1304 |
\code
|
|
1305 |
<?xml version="1.0" encoding="UTF-8"?>
|
|
1306 |
<application id="com.ubuntu.scopes.youtube_youtube">
|
|
1307 |
<description>YouTube</description>
|
|
163.316.22
by Marcus Tomlinson
Create a desktop file for a scope when it is installed, and remove it when uninstalled |
1308 |
<desktop-entry>com.ubuntu.scopes.youtube_youtube.desktop</desktop-entry>
|
163.316.14
by Marcus Tomlinson
Added "Online Accounts" section to tutorial.dox |
1309 |
<services>
|
1310 |
<service id="com.ubuntu.scopes.youtube_youtube">
|
|
1311 |
<description>Watch your favorite YouTube videos</description>
|
|
1312 |
</service>
|
|
1313 |
</services>
|
|
1314 |
</application>
|
|
1315 |
\endcode
|
|
1316 |
||
1317 |
\subsubsection oa_step3 Step 3: Update Click manifest.
|
|
1318 |
||
163.316.22
by Marcus Tomlinson
Create a desktop file for a scope when it is installed, and remove it when uninstalled |
1319 |
Now that we have added the new files from the previous step to our project, we need to update our click manifest file to include
|
163.316.14
by Marcus Tomlinson
Added "Online Accounts" section to tutorial.dox |
1320 |
them:
|
1321 |
||
1322 |
\paragraph oa_click Example Click manifest file:
|
|
1323 |
\code
|
|
1324 |
{
|
|
1325 |
"description": "YouTube scope",
|
|
1326 |
"framework": "ubuntu-sdk-14.10-dev2",
|
|
1327 |
"architecture": "armhf",
|
|
1328 |
"hooks": {
|
|
1329 |
"youtube": {
|
|
1330 |
"scope": "youtube",
|
|
1331 |
"apparmor": "apparmor.json",
|
|
1332 |
"account-application": "youtube.application",
|
|
163.316.22
by Marcus Tomlinson
Create a desktop file for a scope when it is installed, and remove it when uninstalled |
1333 |
"account-service": "youtube.service"
|
163.316.14
by Marcus Tomlinson
Added "Online Accounts" section to tutorial.dox |
1334 |
}
|
1335 |
},
|
|
1336 |
"icon": "youtube/icon.png",
|
|
1337 |
"maintainer": "Ubuntu Developers <ubuntu-devel-discuss@lists.ubuntu.com>",
|
|
1338 |
"name": "com.ubuntu.scopes.youtube",
|
|
1339 |
"title": "YouTube scope",
|
|
1340 |
"version": "1.0.12"
|
|
1341 |
}
|
|
1342 |
\endcode
|
|
1343 |
||
1344 |
\subsubsection oa_step4 Step 4: Utilize the OnlineAccountClient class.
|
|
1345 |
||
163.316.21
by Marcus Tomlinson
Some more tutorial.dox clean up |
1346 |
Finally, we can access online account services from within our scope implementation.
|
163.316.14
by Marcus Tomlinson
Added "Online Accounts" section to tutorial.dox |
1347 |
|
1348 |
The first thing we need to do is instantiate a unity::scopes::OnlineAccountClient object. On construction we must
|
|
1349 |
specify our account service name, service type, and provider name (These correspond to the values of the "service_id",
|
|
1350 |
"type", and "provider" entries in your .service file).
|
|
1351 |
||
359.2.2
by Alberto Mardegan
Tests, version and docs |
1352 |
The constructor accepts a fourth optional parameter which can be used to specify a dictionary of authentication data,
|
1353 |
whose contents will complement (or override) those authentication parameters specified in the `<template>` element of
|
|
1354 |
the \link oa_service `.service` file\endlink. It can be used in those rare cases where the authentication parameters are
|
|
1355 |
known only at runtime.
|
|
1356 |
||
163.316.14
by Marcus Tomlinson
Added "Online Accounts" section to tutorial.dox |
1357 |
Via this object we can get the statuses of all account services, set a callback for status updates, and register
|
163.316.21
by Marcus Tomlinson
Some more tutorial.dox clean up |
1358 |
results and widgets that require authorization (See: unity::scopes::OnlineAccountClient class documentation for more
|
163.316.14
by Marcus Tomlinson
Added "Online Accounts" section to tutorial.dox |
1359 |
detail).
|
1360 |
||
163.316.21
by Marcus Tomlinson
Some more tutorial.dox clean up |
1361 |
Here's a simple example of how one could return a "Log-in" result to the dash (Selecting this result from the dash will
|
1362 |
trigger an authorization request to the user before executing one of the 2 post-login actions):
|
|
163.316.14
by Marcus Tomlinson
Added "Online Accounts" section to tutorial.dox |
1363 |
|
163.316.21
by Marcus Tomlinson
Some more tutorial.dox clean up |
1364 |
\paragraph oa_usage Example OnlineAccountClient usage:
|
163.316.14
by Marcus Tomlinson
Added "Online Accounts" section to tutorial.dox |
1365 |
\code
|
1366 |
void Query::run(unity::scopes::SearchReplyProxy const& reply)
|
|
1367 |
{
|
|
163.316.21
by Marcus Tomlinson
Some more tutorial.dox clean up |
1368 |
// Instantiate a unity::scopes::OnlineAccountClient object
|
163.316.14
by Marcus Tomlinson
Added "Online Accounts" section to tutorial.dox |
1369 |
unity::scopes::OnlineAccountClient oa_client("com.ubuntu.scopes.youtube_youtube", "sharing", "google");
|
163.316.20
by Marcus Tomlinson
Updated tutorial.dox with more detail on example OnlineAccountClient usage |
1370 |
|
163.316.21
by Marcus Tomlinson
Some more tutorial.dox clean up |
1371 |
// Check if our service is authenticated under at least one account
|
163.316.20
by Marcus Tomlinson
Updated tutorial.dox with more detail on example OnlineAccountClient usage |
1372 |
bool service_authenticated = false;
|
1373 |
for (auto const& status : oa_client.get_service_statuses())
|
|
1374 |
{
|
|
1375 |
if (status.service_authenticated)
|
|
1376 |
{
|
|
1377 |
service_authenticated = true;
|
|
1378 |
break;
|
|
1379 |
}
|
|
1380 |
}
|
|
1381 |
||
1382 |
// If our service is not authenticated, return a "Log-in" result
|
|
1383 |
if (!service_authenticated)
|
|
1384 |
{
|
|
1385 |
auto cat = reply->register_category("youtube_login", "", "");
|
|
1386 |
unity::scopes::CategorisedResult res(cat);
|
|
1387 |
res.set_title("Log-in to YouTube");
|
|
1388 |
||
1389 |
oa_client.register_account_login_item(res,
|
|
1390 |
query(),
|
|
1391 |
unity::scopes::OnlineAccountClient::InvalidateResults,
|
|
1392 |
unity::scopes::OnlineAccountClient::DoNothing);
|
|
1393 |
reply->push(res);
|
|
1394 |
}
|
|
163.316.14
by Marcus Tomlinson
Added "Online Accounts" section to tutorial.dox |
1395 |
}
|
1396 |
\endcode
|
|
1397 |
||
163.98.1
by Pawel Stolowski
Minor additions to the tutorial. |
1398 |
\subsection scopetesting Testing
|
163.83.7
by Pawel Stolowski
Added testing section to the tutorial. |
1399 |
|
163.315.1
by Michi Henning
Lots of doc fixes and updates. |
1400 |
The Unity Scopes API provides testing helpers based on the well-known and established testing frameworks,
|
163.83.7
by Pawel Stolowski
Added testing section to the tutorial. |
1401 |
<a href="https://code.google.com/p/googletest/">googletest</a> and <a href="https://code.google.com/p/googlemock/">googlemock</a>.
|
163.315.1
by Michi Henning
Lots of doc fixes and updates. |
1402 |
Please see the respective documentation of these framework for general information on how to use them.
|
163.83.7
by Pawel Stolowski
Added testing section to the tutorial. |
1403 |
|
163.315.1
by Michi Henning
Lots of doc fixes and updates. |
1404 |
The testing helper classes are in the unity::scopes::testing namespace. The most important ones are:
|
163.83.7
by Pawel Stolowski
Added testing section to the tutorial. |
1405 |
<ul>
|
163.315.1
by Michi Henning
Lots of doc fixes and updates. |
1406 |
<li>unity::scopes::testing::TypedScopeFixture - A template class that takes your scope class name as a template argument
|
1407 |
and creates a test fixture that can be used in tests.
|
|
1408 |
<li>unity::scopes::testing::MockSearchReply - A mock of unity::scopes::SearchReply that makes it possible to intercept
|
|
1409 |
responses to search request sent from the scope to a client, so you can test if your scope returns the expected data.
|
|
1410 |
<li>unity::scopes::testing::MockPreviewReply - A mock of unity::scopes::PreviewReply that makes it possible to
|
|
1411 |
intercept and test responses to preview request sent from the scope to a client.
|
|
1412 |
<li>unity::scopes::testing::Result - A simple Result class derived from unity::scopes::Result that provides a default constructor,
|
|
1413 |
so you can create dummy results (without attributes) for testing purposes.
|
|
1414 |
<li>unity::scopes::testing::category - A simple class derived from unity::scopes::Category that makes it possible to create
|
|
1415 |
dummy categories (which otherwise would require an instance of \link unity::scopes::SearchReply SearchReply\endlink and a call to
|
|
1416 |
\link unity::scopes::SearchReply::register_category register_category()\endlink).
|
|
163.83.7
by Pawel Stolowski
Added testing section to the tutorial. |
1417 |
</ul>
|
1418 |
||
163.315.1
by Michi Henning
Lots of doc fixes and updates. |
1419 |
Here is a test that checks if `MyScope` calls appropriate methods of unity::scopes::SearchReply. Note
|
1420 |
that the test only checks that the correct methods are called and uses `_` matchers that match any value.
|
|
1421 |
For a proper test, you will need to substitute values appropriate for your scope.
|
|
1422 |
||
163.83.7
by Pawel Stolowski
Added testing section to the tutorial. |
1423 |
\code{.cpp}
|
163.258.1
by Michi Henning
Refactored scoperunner and ScopeLoader. ScopeLoader |
1424 |
typedef unity::scopes::testing::TypedScopeFixture<MyScope> TestScopeFixture;
|
163.83.7
by Pawel Stolowski
Added testing section to the tutorial. |
1425 |
using namespace ::testing;
|
1426 |
||
163.258.1
by Michi Henning
Refactored scoperunner and ScopeLoader. ScopeLoader |
1427 |
TEST_F(TestScopeFixture, search_results)
|
163.83.7
by Pawel Stolowski
Added testing section to the tutorial. |
1428 |
{
|
1429 |
const unity::scopes::CategoryRenderer renderer;
|
|
1430 |
||
1431 |
NiceMock<unity::scopes::testing::MockSearchReply> reply;
|
|
1432 |
EXPECT_CALL(reply, register_departments(_, _)).Times(1);
|
|
1433 |
EXPECT_CALL(reply, register_category(_, _, _, _))
|
|
1434 |
.Times(1)
|
|
1435 |
.WillOnce(
|
|
1436 |
Return(
|
|
1437 |
unity::scopes::Category::SCPtr(new unity::scopes::testing::Category("id", "title", "icon", renderer))
|
|
1438 |
)
|
|
1439 |
);
|
|
163.147.4
by Pawel Stolowski
Updated tutorial. |
1440 |
EXPECT_CALL(reply, push(Matcher<unity::scopes::Annotation const&>(_)))
|
163.83.7
by Pawel Stolowski
Added testing section to the tutorial. |
1441 |
.Times(1)
|
1442 |
.WillOnce(Return(true));
|
|
163.147.4
by Pawel Stolowski
Updated tutorial. |
1443 |
EXPECT_CALL(reply, push(Matcher<unity::scopes::CategorisedResult const&>(_)))
|
163.83.7
by Pawel Stolowski
Added testing section to the tutorial. |
1444 |
.Times(1)
|
1445 |
.WillOnce(Return(true));
|
|
1446 |
||
163.315.1
by Michi Henning
Lots of doc fixes and updates. |
1447 |
// note: this is a std::shared_ptr with empty deleter
|
1448 |
unity::scopes::SearchReplyProxy reply_proxy(&reply, [](unity::scopes::SearchReplyBase*) {});
|
|
163.83.7
by Pawel Stolowski
Added testing section to the tutorial. |
1449 |
|
1450 |
unity::scopes::CannedQuery query(scope_id, "", "");
|
|
1451 |
unity::scopes::SearchMetadata meta_data("en_EN", "phone");
|
|
1452 |
||
1453 |
auto search_query = scope->search(query, meta_data);
|
|
1454 |
ASSERT_NE(nullptr, search_query);
|
|
1455 |
search_query->run(reply_proxy);
|
|
1456 |
}
|
|
1457 |
\endcode
|
|
163.98.3
by Pawel Stolowski
Added stub section for deployment. |
1458 |
|
1459 |
\subsection deployment Deployment
|
|
1460 |
||
163.98.15
by Michal Hruby
Add some basic information on getting the template and deployment, to be completed |
1461 |
Installing a scope is as simple as running `make install` when using the scope
|
1462 |
template. You might need to restart the global scope registry when a new scope
|
|
163.98.18
by James Henstridge
Use a verbatim block for the restart command. |
1463 |
is installed by running:
|
1464 |
||
1465 |
\verbatim
|
|
1466 |
restart scope-registry
|
|
1467 |
\endverbatim
|
|
163.98.15
by Michal Hruby
Add some basic information on getting the template and deployment, to be completed |
1468 |
|
163.181.2
by Michi Henning
Updated doc for new library names. Minor style fixes in the doc. |
1469 |
Scopes are installed under one of the "scopes directories"
|
163.98.16
by James Henstridge
Flesh out the deployment section. |
1470 |
scanned by the scope registry. Currently these default to:
|
1471 |
||
163.98.17
by James Henstridge
Fix bullet list and comment out note about click package install |
1472 |
<ul>
|
1473 |
<li>/usr/lib/${arch}/unity-scopes</li>
|
|
1474 |
<li>/custom/lib/${arch}/unity-scopes</li>
|
|
163.181.2
by Michi Henning
Updated doc for new library names. Minor style fixes in the doc. |
1475 |
<li>$HOME/.local/share/unity-scopes</li>
|
163.98.17
by James Henstridge
Fix bullet list and comment out note about click package install |
1476 |
</ul>
|
163.98.16
by James Henstridge
Flesh out the deployment section. |
1477 |
|
163.181.2
by Michi Henning
Updated doc for new library names. Minor style fixes in the doc. |
1478 |
The `/usr/lib` directory is for scopes that are pre-installed by Canonical.
|
1479 |
The `/custom/lib` directory is for scopes that pre-installed by OEMs.
|
|
1480 |
The `$HOME/.local` directory is for scopes that are installed from click packages.
|
|
1481 |
||
1482 |
Individual scopes are installed into subdirectories of these
|
|
1483 |
installation directories. The name of the subdirectory containing
|
|
1484 |
a scope's `.ini` and `.so` files can be anything but, to avoid name clashes,
|
|
1485 |
we strongly suggest something that is unique, such as `com.canonical.scopes.scopename`.
|
|
1486 |
At a minimum, the directory structure must contain the following:
|
|
163.98.16
by James Henstridge
Flesh out the deployment section. |
1487 |
|
1488 |
-+- ${scopesdir}
|
|
163.181.2
by Michi Henning
Updated doc for new library names. Minor style fixes in the doc. |
1489 |
`-+- subdirectory
|
163.98.16
by James Henstridge
Flesh out the deployment section. |
1490 |
|--- scopename.ini
|
163.181.2
by Michi Henning
Updated doc for new library names. Minor style fixes in the doc. |
1491 |
`--- <library>.so
|
163.98.16
by James Henstridge
Flesh out the deployment section. |
1492 |
|
163.181.2
by Michi Henning
Updated doc for new library names. Minor style fixes in the doc. |
1493 |
That is, each subdirectory must contain a scope `.ini` file and a shared library containing the
|
163.315.1
by Michi Henning
Lots of doc fixes and updates. |
1494 |
scope code. You are free to ship additional data in this
|
1495 |
directory, such as a settings definition file (if your scope uses settings) or icon files
|
|
1496 |
and screenshots.
|
|
163.98.16
by James Henstridge
Flesh out the deployment section. |
1497 |
|
163.181.2
by Michi Henning
Updated doc for new library names. Minor style fixes in the doc. |
1498 |
The name of the scope's `.ini` file _must_ be a unique ID for the scope. We _strongly_
|
1499 |
suggest to use a unique identifier, such as `com.canonical.scopes.scopename`, to avoid
|
|
1500 |
clashes with scopes created by other developers.
|
|
1501 |
||
163.142.78
by Michal Hruby
Update tutorial |
1502 |
The name of of the scope's `.so` file can be `libscopename.so`, `scopename.so`, or simply `scope.so`. For example,
|
1503 |
for a scope named `Fred`, the names `libFred.so`, `Fred.so`, and `scope.so` are acceptable. (No other library
|
|
1504 |
names are valid.)
|
|
1505 |
||
163.181.2
by Michi Henning
Updated doc for new library names. Minor style fixes in the doc. |
1506 |
The scope `.ini` file uses the standard `.ini` file format, with the
|
163.98.16
by James Henstridge
Flesh out the deployment section. |
1507 |
following keys:
|
1508 |
||
1509 |
[ScopeConfig]
|
|
1510 |
DisplayName = human readable name of scope
|
|
1511 |
Description = description of scope
|
|
1512 |
Author = Author
|
|
163.350.1
by Michi Henning
Added Version attribute to Scope.ini and scope metadata. |
1513 |
Version = 1
|
163.98.16
by James Henstridge
Flesh out the deployment section. |
1514 |
Icon = path to icon representing the scope
|
1515 |
Art = path to screenshot of the scope
|
|
1516 |
SearchHint = hint text displayed to user when viewing scope
|
|
1517 |
HotKey =
|
|
163.181.2
by Michi Henning
Updated doc for new library names. Minor style fixes in the doc. |
1518 |
ResultsTtlType = None, Small, Medium, or Large
|
163.374.2
by Marcus Tomlinson
Renamed all occurrences of "tag" with "keyword" |
1519 |
Keywords =
|
163.414.2
by Michi Henning
Review comments from Marcus. |
1520 |
IsAggregator = true or false
|
275.2.1
by Michi Henning
Documented missing config items. |
1521 |
IdleTimeout = idle timeout in seconds
|
1522 |
LocationDataNeeded = true or false
|
|
1523 |
ScopeRunner = path_to_scope_runner args... %R %S
|
|
163.181.2
by Michi Henning
Updated doc for new library names. Minor style fixes in the doc. |
1524 |
|
1525 |
[Appearance]
|
|
163.142.78
by Michal Hruby
Update tutorial |
1526 |
ForegroundColor = default text color (defaults to theme-provided foreground color)
|
1527 |
BackgroundColor = color of scope background (default is transparent)
|
|
163.245.1
by Michal Hruby
Updated docs |
1528 |
ShapeImages = whether to use Ubuntu-shape for all cards and artwork (defaults to true)
|
1529 |
PreviewButtonColor = color of preview buttons (defaults to theme-provided color)
|
|
163.253.1
by Michal Hruby
Added one more appearance attribute |
1530 |
LogoOverlayColor = color for the overlay in scopes overview (defaults to semi-transparent black)
|
163.245.1
by Michal Hruby
Updated docs |
1531 |
PageHeader.Logo = image containing scope's logo
|
1532 |
PageHeader.ForegroundColor = default header text color (defaults to the overall foreground color)
|
|
1533 |
PageHeader.Background = background scheme of the header
|
|
1534 |
PageHeader.DividerColor = color of the header divider
|
|
1535 |
PageHeader.NavigationBackground = background scheme of the navigation bar
|
|
163.181.2
by Michi Henning
Updated doc for new library names. Minor style fixes in the doc. |
1536 |
|
275.2.1
by Michi Henning
Documented missing config items. |
1537 |
The `ScopeConfig` group is mandatory. The information in this group makes the scope known to the registry.
|
1538 |
In addition, this information controls how the scope appears in the "Scopes" scope.
|
|
1539 |
||
1540 |
The `ScopeConfig` group must contain settings for at least `DisplayName`, `Description`, and `Author`.
|
|
163.181.2
by Michi Henning
Updated doc for new library names. Minor style fixes in the doc. |
1541 |
`DisplayName` and `Description` can (and should) be localized. For example:
|
1542 |
||
163.258.3
by Michi Henning
Completed support for cache_directory() accessor. |
1543 |
`Description[de_DE] = Fußballergebnisse`
|
163.181.2
by Michi Henning
Updated doc for new library names. Minor style fixes in the doc. |
1544 |
|
163.350.1
by Michi Henning
Added Version attribute to Scope.ini and scope metadata. |
1545 |
The `Version` key is optional, but we strongly recommend that you set it.
|
1546 |
If the behavior of your scope changes in any way that is visible to the query source
|
|
1547 |
(such having added or removed a result attribute), you should increment the version number.
|
|
163.350.3
by Michi Henning
Fixed typos in comments and doc. |
1548 |
This allows an aggregating scope to adjust its behavior according to which version of
|
163.350.1
by Michi Henning
Added Version attribute to Scope.ini and scope metadata. |
1549 |
your scope is installed.
|
1550 |
If not set, the default value is 0. You can set the value to any integer >= 1.
|
|
1551 |
||
163.414.1
by Michi Henning
Updated doc for scope.ini keys. |
1552 |
The `SearchHint` key provides text that may be shown by the UI, such as "Enter a city name".
|
1553 |
||
1554 |
The `Keywords` key is optional, but we recommend that you use it. Keywords are used by aggregators
|
|
1555 |
to collect results from scopes of similar type (E.g. The Music scope will aggregate scopes with the
|
|
1556 |
keyword "music", and so on). The value of `Keywords` should specify a list of keywords your scope
|
|
1557 |
falls under. This value must be a semicolon separated list (E.g. `Keywords = music;video`).
|
|
1558 |
||
163.414.2
by Michi Henning
Review comments from Marcus. |
1559 |
The `IsAggregator` key must be set to `true` for aggregating scopes. The default value is `false`.
|
1560 |
||
275.2.1
by Michi Henning
Documented missing config items. |
1561 |
The `IdleTimeout` key controls how long a scope can remain idle before it is told to stop by the registry (or
|
1562 |
killed if it does not stop within 4 seconds). The default idle timeout is 40 seconds, meaning that a
|
|
163.480.1
by Marcus Tomlinson
Be much stricter on idle timeout (1s to 5min). Not only are scopes currently allowed to set very very large timeouts, we seem to allow disabling of the timeout entirely (a value of -1) :/ |
1563 |
scope will be told to stop if no query was sent to it for that amount of time. Only values in the range 1 to
|
1564 |
300 seconds are accepted.
|
|
275.2.1
by Michi Henning
Documented missing config items. |
1565 |
|
163.414.1
by Michi Henning
Updated doc for scope.ini keys. |
1566 |
`ResultTtl` determines how long results should be cached by the UI before they are considered "stale"
|
1567 |
and should be refreshed. `None` indicates that results remain valid indefinitely; `Small` indicates
|
|
1568 |
results are valid for around a minute; `Medium` indicates that results are valid for a few minutes;
|
|
1569 |
`Large` indicates that results remain valid for around an hour.
|
|
1570 |
||
275.2.1
by Michi Henning
Documented missing config items. |
1571 |
`LocationDataNeeded` should be set to `true` if the scope requires location data. In that case, the
|
1572 |
\link unity::scopes::SearchMetadata SearchMetadata\endlink provides access to
|
|
1573 |
\link unity::scopes::Location Location\endlink information
|
|
1574 |
(assuming the user has granted location permission to the scope). If not set, the default value is `false`.
|
|
1575 |
||
1576 |
The `Scoperunner` key defines a command line to be executed when the scope is started by the registry.
|
|
1577 |
Typically, scopes do not need to change this setting. It is provided mainly to allow scopes implemented
|
|
1578 |
in languages other than C++ to be started, as well as for debugging.
|
|
1579 |
For example, the following setting causes a scope to be run under `gdb`:
|
|
1580 |
||
1581 |
`ScopeRunner = /usr/bin/gdb --ex run --args /usr/lib/x86_64-linux-gnu/unity-scopes/scoperunner %R %S`
|
|
1582 |
||
1583 |
The `%R` expands to the path to the `Runtime.ini` config file, and `%S` expands to the scope's `.ini` file.
|
|
1584 |
||
1585 |
The `Appearance` group and all keys within it are optional and can be used to customize the look of the scope.
|
|
163.414.1
by Michi Henning
Updated doc for scope.ini keys. |
1586 |
Some of the `Appearance` keys (such as `PageHeader.Background`) require background scheme URIs.
|
1587 |
Valid URIs for these keys include:
|
|
163.245.1
by Michal Hruby
Updated docs |
1588 |
|
1589 |
<ul>
|
|
1590 |
<li>color:///\#aarrggbb</li>
|
|
1591 |
<li>color:///black</li>
|
|
1592 |
<li>gradient:///\#aarrggbb/\#aarrggbb</li>
|
|
1593 |
<li>/absolute/path/to/image</li>
|
|
1594 |
<li>http://remote-server.com/path/to/image</li>
|
|
1595 |
</ul>
|
|
163.98.6
by Michal Hruby
Added section on scope-tool |
1596 |
|
163.402.4
by Marcus Tomlinson
Add reference to keywords doc in scope config section as well |
1597 |
\note Please refer to the <a href="https://developer.ubuntu.com/en/scopes/tutorials/scope-keywords/">Scope Keywords</a>
|
1598 |
tutorial document for more detail on using keywords in your scope.
|
|
1599 |
||
163.315.1
by Michi Henning
Lots of doc fixes and updates. |
1600 |
\subsection scopetool The scope tool
|
1601 |
||
163.437.4
by Michi Henning
Fixed typos. |
1602 |
The Unity Scope Tool is a stand-alone rendering tool that allows you
|
163.315.1
by Michi Henning
Lots of doc fixes and updates. |
1603 |
to see how the dash will render your scope.
|
1604 |
||
1605 |
You can install the tool from the Ubuntu archive using:
|
|
163.98.14
by Pawel Stolowski
Use verbatim. |
1606 |
\verbatim
|
1607 |
sudo apt-get install unity-scope-tool
|
|
1608 |
\endverbatim
|
|
163.98.6
by Michal Hruby
Added section on scope-tool |
1609 |
|
163.181.2
by Michi Henning
Updated doc for new library names. Minor style fixes in the doc. |
1610 |
After installation, you can run the scope-tool with a parameter specifying the
|
1611 |
path to your scope configuration file (for example `unity-scope-tool ~/dev/myscope/build/myscope.ini`).
|
|
1612 |
If a binary for your scope can be found in the same
|
|
163.315.1
by Michi Henning
Lots of doc fixes and updates. |
1613 |
directory, the scope-tool
|
1614 |
displays surfacing and search results provided by your scope, and it allows you to
|
|
1615 |
perform searches, invoke previews, and perform actions within previews.
|
|
163.98.6
by Michal Hruby
Added section on scope-tool |
1616 |
|
163.181.2
by Michi Henning
Updated doc for new library names. Minor style fixes in the doc. |
1617 |
Note that the scope-tool uses the same rendering mechanism as Unity
|
1618 |
itself and, therefore, what you see in the scope-tool is what you get in Unity.
|
|
163.315.1
by Michi Henning
Lots of doc fixes and updates. |
1619 |
The tool can also be used to fine-tune category definitions, as it allows you
|
1620 |
to manipulate the definitions on the fly. Once you are satisfied with the result,
|
|
163.98.7
by Michal Hruby
A bit more |
1621 |
you can just copy the JSON definition back into your scope
|
1622 |
(see unity::scopes::CategoryRenderer::CategoryRenderer()).
|
|
163.98.6
by Michal Hruby
Added section on scope-tool |
1623 |
|
1624 |
The scope-tool supports a few command line arguments:
|
|
163.437.4
by Michi Henning
Fixed typos. |
1625 |
\arg By default (without any arguments) it will communicate with all scopes
|
163.98.6
by Michal Hruby
Added section on scope-tool |
1626 |
installed on the system and available on the smart scopes server.
|
1627 |
\arg When a path to a scope configuration file is provided, only that scope is
|
|
1628 |
initialized, but you can either pass multiple configuration files or
|
|
1629 |
the `--include-system-scopes` / `--include-server-scopes` option to allow
|
|
1630 |
development of aggregating scopes.
|
|
1631 |
||
64.1.1
by Pawel Stolowski
First cut at scopes tutorial. |
1632 |
*/
|