Merge lp:~knitzsche/scope-aggregator/refactor-handle-methods_add-login_remove-shared-category into lp:scope-aggregator
- refactor-handle-methods_add-login_remove-shared-category
- Merge into vivid-trunk
Status: | Merged |
---|---|
Approved by: | Kyle Nitzsche |
Approved revision: | 191 |
Merged at revision: | 174 |
Proposed branch: | lp:~knitzsche/scope-aggregator/refactor-handle-methods_add-login_remove-shared-category |
Merge into: | lp:scope-aggregator |
Diff against target: |
3725 lines (+1703/-1386) 15 files modified
DELETED_FEATURES.md (+1/-0) README.md (+270/-286) gtests/CMakeLists.txt (+4/-0) gtests/MockRegistry.h (+7/-0) gtests/scope_directory/login_1.json (+74/-0) gtests/scope_directory/login_2.json (+73/-0) gtests/scope_directory/login_3.json (+35/-0) gtests/scope_test.cpp (+110/-3) include/aggchildscope.h (+36/-1) include/query.h (+16/-9) src/CMakeLists.txt (+1/-0) src/aggchildscope.cpp (+34/-1) src/handle_results.cpp (+960/-0) src/query.cpp (+2/-9) src/utils.cpp (+80/-1077) |
To merge this branch: | bzr merge lp:~knitzsche/scope-aggregator/refactor-handle-methods_add-login_remove-shared-category |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Zhang Enwei (community) | Approve | ||
Gary.Wang | Pending | ||
Review via email: mp+307352@code.launchpad.net |
Commit message
Description of the change
For a proposed 4.13 release.
* Significant refactor of the three methods that handle results:
handle_
were simply too hard to debug and understand, and they had redundant code to
lookup and, if needed, to register Categories. Each of the three methods is
refactored as follows: define an enum that states the possible run types for
the method: get state variables, analyze state and set run type, switch on run
type to select code. Category lookup and registration is now moved to new
set_result_
link to child is needed. The three methods (and related) are moved to a new
file for clarity: handle_results.cpp.
* Added support for a "login_renderer" and
"login_
the updated README.md. I also added gtests for this.
* Removed "shared category" from "keywords". This feature is not used, I think.
I did not find it in all child_scopes.json files in clicks branch. It is mostly
redundant with a "category". That is, they both confine keywords to a Category
(although category type also can include scopes). We can reimplemented any
features that were supported only in keywords that are not supported in
categories if needed.
* Added Query::
Note: With this MP, an agg scope child_scopes.json file does not need a
"departments" object: it's absence is sufficient to signal no departments.
* Updated/rewrote README.md.
I tested this in Today, News, Nearby and Photos. It would be awesome if the .so
could be tested with our other aggregators!
Kyle Nitzsche (knitzsche) wrote : | # |
Zhang Enwei (zhangew401) wrote : | # |
LGTM except some typos.
I verified on food, films, china-dashboard, news-china and baidu aggregator scopes.
Kyle Nitzsche (knitzsche) wrote : | # |
thanks Enwei.
Preview Diff
1 | === added file 'DELETED_FEATURES.md' |
2 | --- DELETED_FEATURES.md 1970-01-01 00:00:00 +0000 |
3 | +++ DELETED_FEATURES.md 2016-09-30 19:17:35 +0000 |
4 | @@ -0,0 +1,1 @@ |
5 | +4.12: keyword object with shared_shared category: just use category. |
6 | |
7 | === modified file 'README.md' |
8 | --- README.md 2016-08-04 01:11:41 +0000 |
9 | +++ README.md 2016-09-30 19:17:35 +0000 |
10 | @@ -1,65 +1,90 @@ |
11 | -# Scope aggregator introduction |
12 | - |
13 | -This is a *declarative* aggregator scope template. You declare aggregated scopes and keywords for inclusion in json files. |
14 | - |
15 | -Consistent with release tag 1.5. |
16 | - |
17 | -## No compilation |
18 | +# Scope aggregator |
19 | + |
20 | +This is a *declarative* aggregator scope template. You declare aggregated scopes and keywords for inclusion in json files. |
21 | |
22 | You may combine the various text files and icons with the built scope-aggregator .so file into a click package, thus creating rich aggregator scopes with no c++ coding and compilation. |
23 | |
24 | -## Including scopes |
25 | - |
26 | -You may declare: |
27 | - |
28 | - * *scopes* to include (called "declared scopes") |
29 | - * *keywords* to aggregate scopes that advertise such keywords (called "declared keywords") |
30 | - * *categories* that contain specific declared scopes and declared keywords (called "declared categories") |
31 | - |
32 | -## Order |
33 | - |
34 | -You declare scopes, keywords and categories in a specific *order* that dictates the overall order of display at run time. |
35 | - |
36 | -When declaring keywords and not using `shared_category` (which keeps its results together in a single category), the order it not entirely determinant. Therefore `shared_category` is recommended. |
37 | - |
38 | -This order is used whether or not you also declared departments. (A department is treated as a section of the overall order, so even though you see only part of the overall order, the part you see still adheres to the order) |
39 | +Here are couple examples: |
40 | + |
41 | + * Today Scope: https://launchpad.net/today-scope |
42 | + * News Scope: https://launchpad.net/news-scope |
43 | + |
44 | +## Declaring scopes and the overall order |
45 | + |
46 | +You may declare one or more: |
47 | + |
48 | + * `scope`: includes a single scope |
49 | + * `category`: includes a set of scopes and keywords |
50 | + * `keyword`: includes child scopes that answer to the keywords |
51 | + |
52 | +These are declared directly inside the `order` json list element. The order of declaration determines the order of presentation in the aggregator scope, with the exception of `keyword` (explained below) |
53 | + |
54 | +The unity scope framework API provides Category objects. These are used to group together scope results. Scope-aggregator uses Categories as follows: |
55 | + |
56 | + * `scope`: A single Category is created for each `scope`. It contains all results from the scope. The Category displays in the declared order. |
57 | + * `category`: A single Category is created for each `category`. It contains all results from the internally declared set of scopes and from all present scopes that answer to the internally declared set of keywords. The Category displays in the declared order. |
58 | + * `keyword`: A Category is created for each scope that answers to the declared keyword. By default, the only guarantee relating to the overall order is that the first such child scope appears in the declared order. Categories for all other scopes that answer to the keyword display in an determinant order (but always after the first). You can use the additional `display_order` feature to set the order of child scopes answering to this keyword. |
59 | |
60 | ## Departments |
61 | |
62 | -You may declare departments. When doing so, every declared scope, declared keyword and declared category must be assigned to a department or it is not visible at run time. |
63 | +The unity scope framework provides Department objects. When used, these are selectable by tapping the magnifying glass, which displays a tappable list of Departments. |
64 | + |
65 | +You may declare departments. When doing so, every declared `scope`, `category` and `keyword` must be assigned to a department or it is not visible at run time. |
66 | + |
67 | +The declared order applies with declared departments. A department is treated as a sub-section of the overall order, so even though you see only part of the overall order, the part you see still adheres to the order. |
68 | + |
69 | +Each Department requires a title and a unique ID that you use to place each `scope`, `category` and `keyword` in a department. |
70 | + |
71 | +One department is declared as the default root department (it is the one displayed before the user selects any other department). |
72 | |
73 | ## Categories |
74 | |
75 | -A category is automatically created for each declared scope, declared category, and declared keyword (when using shared categories, see below). |
76 | - |
77 | -You can set various category items, including title, renderers, and, when a cagetegory contains a single child scope, whether tapping the category title switches focus to the child scope (called "link to child"). Note, enabling link to child on categories that contain multiple child scopes is not advisable because the category can only link to a single child but results from multiple child scopes are contained in the category. |
78 | +As noted, a Category is automatically created for each `scope`, `category`, and for each scope answering to a `keyword`. |
79 | + |
80 | +You can set various Category items, including title, renderers, and, whether tapping the category header (which displays the title) switches focus to another child scope (called "link to child"). |
81 | + |
82 | +By default, the link to child feature is enabled for `scope` and `keyword` categories. It can be disabled with `"link_to_child": "false"`. |
83 | + |
84 | +For `category` declaration, the link to child feature may or may not make sense. By default, there is no link to child for `category`. But, if the `category` always and only contains a single child scope, it usually makes sense. This is enabled with `"link_to_child_specified": "scope ID"`. |
85 | + |
86 | +But, when a `category` contains multiple child scopes, either when the `category` is declared with more than one child scope or when it is declared to include a keyword (which may result in multiple child scopes, link to child may not be appropriate because there may be no reasonable single child scope to link to. But even with multiple child scopes, link to child may still be appropriate: for example, the Today scope has a `category` that aggregates news headlines. It has a link to child that takes the user to the News scope |
87 | +Headlines department. |
88 | |
89 | ## Renderers |
90 | |
91 | -You can declare renderers to control display of results (of declared scopes, declared keywords and declared categories) for three cases: |
92 | - |
93 | - * surfacing: declare a `renderer` in place (or use a common renderer with `renderer_common_id`) to control result display for normal results |
94 | - * searching: declare a `search_renderer` in place (or use a common renderer with `search_renderer_common_id`) a to control result display for results when the user is searching |
95 | - * first result: declare a `first_result_renderer` in place (or use a common renderer with `first_result_renderer_common_id`) to provide a different display for the first result. For example, the first news result may have a large photo with overlay text and the rest may use a small photo. The rest of the results are displayed using the surfacing renderer. Note that there are cases where first result renderer is not supported, for example keyword scopes that do not use a shared category. |
96 | - |
97 | -In general, when no render is declared, the renderer is taken from the incoming result. |
98 | - |
99 | -For convenience, you may declare renderers once in `common_templates` and refer to them by id for reuse. |
100 | +The unity scope framework has the concept of a layout renderer that controls the display of results. The renderer dictates what the displayed result consists of, that is, its "components" (for example a title and an art, or a title, a subtitle, and a mascot). Each component consist of the key (which dictates the type of component) and the name of the property in the result that contains the value to be used. For example, "art": "image", which means each result has an "art" attribute whose value is derived from the result field named "image". |
101 | + |
102 | +The renderer also dictates the layout (for example, large card with grid layout, or vertical-journal, etc.). |
103 | + |
104 | +You can declare renderers to control display as follows: |
105 | + |
106 | + * Surfacing: declare a `renderer` in place (or use a common renderer with `renderer_common_id`) to control result display for normal results. |
107 | + * Login: declare a `login_renderer` with a `login_renderer_incoming_category_id` to control display of login results for the specified category_id. When declared, if the incoming result has the specified category, then ID the declared login renderer is used. This is not available for `keyword` declarations because one generally does not know the category ID for scopes that may answer to the keyword, and keyword scopes probably all use different category IDs for login results. |
108 | + * Searching: declare a `search_renderer` in place (or use a common renderer with `search_renderer_common_id`) a to control result display for results when the user is searching |
109 | + * First result: declare a `first_result_renderer` in place (or use a common renderer with `first_result_renderer_common_id`) to provide a different display for the first result. For example, the first news result may have a large photo with overlay text and the rest may use a small photo. The rest of the results are displayed using the surfacing renderer. This is only available for `category` declarations. |
110 | + |
111 | +In general, when no render is declared, the renderer is taken from the first incoming result in the Category. This works, but the layout and design is not in control of the aggregator scope developer, and there is no consistency in the layout and design among the multiple child scopes displayed. Therefore, designing and declaring renderers is a critical part or aggregator scope development. |
112 | + |
113 | +Typically you declare your renderers right inside your `scope`, `category` or `keyword` object. |
114 | + |
115 | +If you wish to declare renderers once and reuse them, you may declare each type of renderer (except for the login renderer) once in a `common_templates` object and include them by ID inside your `scope`, `category` or `keyword` object, as explained below. |
116 | |
117 | ## Cardinality |
118 | |
119 | -Cardinality means the number of results returned and displayed by any child scope instance whether included as a declared scope, a declared keyword, or a declared category. For example, if a child scope has two instances and the cardinality is 2, four results are displayed. |
120 | - |
121 | -There are two apporaches to cardinality: |
122 | - |
123 | - * user settings: in this case, the user may use settings to to set cardinality, and the default cardinality is obtained from settings. This approach requires setttings.ini and matching declarations in child_scopes.json. (if they do not match the scope may not function.) |
124 | - * declared for each declared scope, declared keyworrd and declared category. This approach only requires child_scopes.json. |
125 | - |
126 | -You may use botth approachest simultaneously. If so, declared cardinality for declared scopes, keywords and categories preempt user settings. |
127 | - |
128 | -### Cardinality by user settings |
129 | - |
130 | -Suppose you want the user to choose between cardinality of 1,2,4, and 8, and you want the defaul to be 2. Here is your settings.ini: |
131 | +Cardinality is the number of results returned and displayed by any single child scope instance. That is, the cardinality is sent to each child scope when asking for results to display, and the child scope follows this and returns no more than the requested number of result (it may return less). |
132 | + |
133 | +Note that in the case of a `category` that contains more than one scope, the overall maximum number of results displayed is the cardinality multiplied by the number of child scopes in the `categoory`. |
134 | + |
135 | +There are two approaches to implementing cardinality: |
136 | + |
137 | + * Scope settings: in this case, you implement the cardinality choices for scope settings, including the default. This allows user cardinality choice. This approach requires a settings.ini file and matching declarations in child_scopes.json. (if they do not match the scope may not function.) |
138 | + * Declared for each `scope`, `category` and `keyword`. |
139 | + |
140 | +You may use both approaches simultaneously. If so, declared cardinality for `scope`, `category` and `keyword` preempts settings. |
141 | + |
142 | +### Cardinality with scope settings |
143 | + |
144 | +Suppose you want the user to choose between cardinality of 1,2,4, and 8, and you want the default to be 2. Here is your settings.ini: |
145 | |
146 | [cardinality] |
147 | type = list |
148 | @@ -67,9 +92,9 @@ |
149 | displayValues = 1,2,4,8 |
150 | displayName = Results per source: |
151 | |
152 | -Note that the defaultValue is an *index*, thus a value of 0 would set the default to 1. |
153 | +Note that the defaultValue is an *index* starting at 0, thus a value of 1 would set the default to 2. |
154 | |
155 | -With this setttings.ini you *must* declare the same values in child_scopes.json as follows: |
156 | +With this settings.ini you *must* declare the same values in child_scopes.json as follows: |
157 | |
158 | "cardinality_settings": |
159 | [ |
160 | @@ -87,12 +112,10 @@ |
161 | } |
162 | ], |
163 | |
164 | -Note that the default value is set in settings.ini and is not mentioned elsewhere. |
165 | |
166 | ### Cardinality for any declared scope, keyword and category |
167 | |
168 | -When not using user settings for cardinality you can set cardinalities for any declared scope, keyword and category. Any not set use a default value. |
169 | - |
170 | +You can set cardinalities for any `scope`, `category` and `keyword`. This locally preempts any settings cardinality. |
171 | |
172 | "scope|keyword|category": |
173 | { |
174 | @@ -100,23 +123,70 @@ |
175 | "cardinality": 3, |
176 | |
177 | |
178 | -## Declared keyword shared categories |
179 | - |
180 | -When you declare a keyword, you can optinally set it to display all results from all matching child scopes in a *single* category. This is a called a "shared category". If you do not, each matching child scope's results appear in a category unique to the child scope and the overall order of child scopes is less determinant. Therefore, if you choose not to use a shared category, you might consider placing the keyword in a department that contains nothing else, thus keeping the categories together. |
181 | - |
182 | -## Keyword results should use common template |
183 | - |
184 | -All keyword sccopes that advertise a particular keyword should provide results using a the same template (for example, title, art and summary, or title, subtitle and mascot) because the aggregator generally assumes such a template provides a renderer to display it. If any aggregated scope does not use the expected template, its results may be missing expected template data at run time when aggregated. Note: This is a social convention: child scope developers who add a keyword to their scope should check what the expected template is for that keyword. |
185 | +## Fallbacks and Result Attribute Swaps |
186 | + |
187 | +Sometime child scopes provide results that contain the pieces of information the renderer needs, but they are not arranged as expected. |
188 | + |
189 | +For example, a scope might provide a news result with the url to the art in the "mascot" attribute, yet your aggegrator scope may expect the art to be in the "art" attribute. |
190 | + |
191 | +There are two methods for dealing with this: |
192 | + |
193 | + * Fallbacks |
194 | + * Attribute swaps |
195 | + |
196 | +### Fallbacks |
197 | + |
198 | +Fallbacks allows you to declare that for a given attribute in your renderer (for example "art"), you want to check a specified series of fields in the incoming result and use the first one that exists. For example, to get a value for your "art" field, you might want to check the "art" field, then the "mascot" field, and finally the "emblem" field of each incoming result. |
199 | + |
200 | +This is currently support using `common_templates`. Your template in common templates declares a `fallbacks` object. And of course, you declare a renderer to use the common template (instead of being declared in place). |
201 | + |
202 | +This example accomplishes the above goal: |
203 | + |
204 | + "common_templates": |
205 | + [ |
206 | + { |
207 | + "id" : "news-first", |
208 | + "fallbacks": |
209 | + [ |
210 | + { |
211 | + "key": "art", |
212 | + "fields": |
213 | + [ |
214 | + {"field": "art"}, |
215 | + {"field": "mascot"}, |
216 | + {"field": "emblem"} |
217 | + ] |
218 | + } |
219 | + ], |
220 | + "template": |
221 | + { |
222 | + [...] |
223 | + } |
224 | + }, |
225 | + [...] |
226 | + } |
227 | + |
228 | + |
229 | +### Result Attribute Swaps |
230 | + |
231 | +For `scope` types, you may also declare a specific attribute swaps to make on every incoming result. For example, if you know the child scope puts the art url in the mascot field, you can declare that the "art" attribute should be populated by the incoming "mascot" field. |
232 | + |
233 | +See `swap_result_attributes`. |
234 | |
235 | # Declarations in child_scopes.json |
236 | |
237 | -All declarations are made `data/child_scopes.json`. This json file is divided into the following objects: |
238 | +All declarations are made `child_scopes.json`. This json file is divided into the following objects: |
239 | |
240 | * `departments`: Here you declared your departments or declare you do not want departments |
241 | -* `order`: Here you declare your specific scopes, keywords and cagtegories for aggregation |
242 | -* `commmon_templates`: Here you declare category renderer tempalates you may use for multiple specified categories |
243 | - |
244 | -## `departments` (required) |
245 | +* `cardinality`: Here you declared cardinality options for use with scope settings. |
246 | +* `order`: Here you declare your specific scopes, keywords and categories for aggregation |
247 | +* `commmon_templates`: Here you declare category renderer templates you may use for multiple specified categories |
248 | + |
249 | +The order of these objects in the file has no affect. |
250 | + |
251 | +## `departments` (optional) |
252 | + |
253 | +When not present, departments are not used. |
254 | |
255 | Structure: |
256 | |
257 | @@ -146,7 +216,7 @@ |
258 | |
259 | Value: string. "true" or "false" |
260 | |
261 | -When this key is present and the value is "true" departments are not used (even if you separately declare departments). When not using departments, all current enabled scopes display in surfacing mode in the declared order. |
262 | +When this key is present and the value is "true" departments are not used (even if you separately declare departments). When not using departments, all current enabled scopes display in surfacing mode in the declared order. This is useful during development. As noted, when the `departments` object is not present, objects are not used. |
263 | |
264 | ### `declarations` (required) |
265 | |
266 | @@ -170,7 +240,7 @@ |
267 | |
268 | Value: string |
269 | |
270 | -The department title. If you include the value as a msgid in your po/mo files, the title displays localized as avaiable. |
271 | +The department title. If you include the value as a msgid in your po/mo files, the title displays localized as available. |
272 | |
273 | ### Examples |
274 | |
275 | @@ -212,7 +282,7 @@ |
276 | |
277 | ## `order` (required) |
278 | |
279 | -Here you declare scopes, keywords and categories, with options for each. The order of declaration determines the order of display at runtime, although not all scopes always display. (For example, if you are using departments, only the scopes in thee current department are displayed, but they still display in the declared order.) |
280 | +Here you declare `scope`s, `keywords` and `category` objects, with options for each. The order of declaration determines the order of display at runtime, as described above. |
281 | |
282 | { |
283 | [...] |
284 | @@ -281,13 +351,13 @@ |
285 | |
286 | The id is a fully qualified scope name. |
287 | |
288 | -If you include only this with no further declared customization the child scope is aggregrated as is with a tappable category navigation link to child. |
289 | +If you include only this with no further declared customization the child scope is aggregated as is with a tappable category navigation link to child. |
290 | |
291 | #### `local_id` key (required) |
292 | |
293 | Value: string |
294 | |
295 | -Must be unique in this file. This diffferentiates scopes and allows multiple instances of the same scope, for example to include the scope several times using `child_department` to pull different results from it. |
296 | +Must be unique in this file. This differentiates scopes and allows multiple instances of the same scope, for example to include the scope several times using `child_department` to pull different results from it. |
297 | |
298 | #### `department` (required when using departments) |
299 | |
300 | @@ -321,24 +391,6 @@ |
301 | |
302 | When this key exists, the category title is set from the first incoming child result that matches the various declared criteria. |
303 | |
304 | -#### `first_result_renderer_common_id` key (optional) |
305 | - |
306 | -Value: string |
307 | - |
308 | -The id must equal a template defined in `common_templates`. |
309 | - |
310 | -Creates a new category specifically for the first result using the refered to renderer. |
311 | - |
312 | -Only used if `_shared_category` present. |
313 | - |
314 | -#### `first_result_renderer` key (optional) |
315 | - |
316 | -Value: json defining a category renderer |
317 | - |
318 | -Only used if `_shared_category` present. |
319 | - |
320 | -Creates a new category specifically for the first result using the defined renderer. |
321 | - |
322 | #### `renderer_common_id` key (optional) |
323 | |
324 | Value: string |
325 | @@ -347,14 +399,10 @@ |
326 | |
327 | Uses the renderer referred to and defined in `common_templates` for all results (except for the first result if a renderer is provided for that). |
328 | |
329 | -Only used if `_shared_category` present. |
330 | - |
331 | #### `renderer` key (optional) |
332 | |
333 | Value: json defining a category renderer |
334 | |
335 | -Only used if `_shared_category` present. |
336 | - |
337 | This provides the CategoryRenderer template use for results in this category. When this is not present, the template used is taken from the first result of the keyword scopes. |
338 | |
339 | #### `search_renderer_common_id` key (optional) |
340 | @@ -365,48 +413,46 @@ |
341 | |
342 | Uses the renderer referred to and defined in `common_templates` for all results when searching. |
343 | |
344 | -Only used if `_shared_category` present. |
345 | - |
346 | #### `search_renderer` key (optional) |
347 | |
348 | Value: json defining a category renderer |
349 | |
350 | -Only used if `_shared_category` present. |
351 | - |
352 | This provides the CategoryRenderer to use when searching. |
353 | |
354 | #### `child_department` key (optional) |
355 | |
356 | +DEPRECATED. Use keywords in the child scope and here instead. There is no way to determine whether a child scope has a particular department at run time, and if you use this key and the specified department does not exists, there is an uncaught exception in the child scope that causes problems. |
357 | + |
358 | Value: string: a department id of the child scope. |
359 | |
360 | Displays only results from the specified child department. |
361 | |
362 | Note: To limit the number of results displayed when using `child_department`, use `cardinality`. |
363 | |
364 | -Note: Because scope user searches by design only return matching results onnly from the top level department, searches in the aggregator scope will not return results when this is used. |
365 | +Note: Because scope user searches by design return matching results only from the top level department, searches in the aggregator scope will not return results when this is used. |
366 | |
367 | #### `child_category` key (optional) DEPRECATED |
368 | |
369 | +DEPRECATED. Use keywords, a much more robust approach. |
370 | + |
371 | Value: string |
372 | |
373 | -When present, only child results from the specified child catagory are displayed, and you may also set the maximum number of child results using `child_category_max_results` key. |
374 | +When present, only child results from the specified child category are displayed, and you may also set the maximum number of child results using `child_category_max_results` key. |
375 | |
376 | Note: To limit the number of results displayed when using `child_category`, use `child_category_max_results`. |
377 | |
378 | -Note: If you also use `result_category_id_to_common_template`, results from that specified category *are* displayed (that is, they are not filterd out) using that specified common template (as documented). |
379 | - |
380 | -This is deprecated becuase keywords are a more robust approach. |
381 | +Note: If you also use `result_category_id_to_common_template`, results from that specified category *are* displayed (that is, they are not filtered out) using that specified common template (as documented). |
382 | |
383 | #### `child_category_max_results` key (optional) DEPRECATED |
384 | |
385 | +DEPRECATED along with `child_category`. |
386 | + |
387 | Value: number |
388 | |
389 | Only application when using `child_category`. (See `cardinality`.) |
390 | |
391 | Sets the maximum number of results to display. |
392 | |
393 | -Deprecated along with `child_category`. |
394 | - |
395 | #### `link_to_child` key (optional) |
396 | |
397 | Value: string: "false" |
398 | @@ -415,13 +461,13 @@ |
399 | |
400 | Note: When the category title is empty, this should not be set to "false" due to layout issues. |
401 | |
402 | -Note: When `"link_to_child": "true"` (either due to explicit declaration or when using the default value which is "true"), the scope framework does not currently support `"collapsed-rows": NUMBER` in the renderer template. When link_to_child is on, `"cardinality": NUMBER` may not appear to be respected if that number causes more results than display in the available vertical space for the child scope, although it is respected and does limit the number of results. |
403 | +Note: When `"link_to_child": "true"` (either due to explicit declaration or when using the default value which is "true"), the scope framework does not currently support `"collapsed-rows": NUMBER` in the renderer template. When link_to_child is on, `"cardinality": NUMBER` may not appear to be respected if that number causes more results than display in the available vertical space for the child scope, although it is respected and does limit the number of results. (Note: this needs to be tested) |
404 | |
405 | #### `swap_result_attributes` key (optional) |
406 | |
407 | Value: json list of objects. |
408 | |
409 | -This allows you to move values among attibutes in the result. |
410 | +This allows you to move values among attributes in the result. |
411 | |
412 | Example: |
413 | |
414 | @@ -459,9 +505,7 @@ |
415 | |
416 | Value: json list of objects. |
417 | |
418 | -Allows you to display results with a specified category using a CategoryRenderer declared in `common_templates`. Useful for child scopes requiring login to use the same design for all login results from all child scopes. |
419 | - |
420 | -Note: When also `child_category`, results using the specified category id(s) do display (are not filtered out), using the specified template. |
421 | +Allows you to display results with a specified category using a CategoryRenderer declared in `common_templates`. |
422 | |
423 | [...] |
424 | "result_category_id_to_common_template": |
425 | @@ -473,13 +517,15 @@ |
426 | ] |
427 | [...] |
428 | |
429 | +Note: This has often been used for a common layout for login results from different child scopes. As of scope aggregator release 4.12 you can use the new `login_renderer`/`login_renderer_incoming_category_id` pair of keys for directly declaring a renderer in your declared `scope`, or `category`. |
430 | + |
431 | #### `keyword_scope_ids` key (optional) |
432 | |
433 | Value: json list of objects. |
434 | |
435 | This key is only used on the special clickstore scope declared with "id": "com.canonical.scopes.clickstore". |
436 | |
437 | -This clickstore scope displays scopes that are not installed and allows the user to install them. |
438 | +This clickstore scope can display scopes that are declared but are not installed and allows the user to install them. |
439 | |
440 | By default, the clickstore scope (when declared) displays all child scopes declared in the child_scopes.json file by scope ID that are not currently installed. |
441 | |
442 | @@ -530,128 +576,21 @@ |
443 | } |
444 | [...] |
445 | |
446 | -### `keyword` (optional) |
447 | - |
448 | -Declare a specific keyword for aggregation. |
449 | - |
450 | -The first result of aggregated child scopes is placed in the declared order. To keep all results in this order, use `shared_category`, which confines the results into a single category. |
451 | - |
452 | -When not using `shared_category`, each aggregated keyword scope appears in its own category whose title is the child scope display name. |
453 | - |
454 | -When using departments, you may assign these to a department with `department`. Or, use `_departmentt_title` to auto create a department for them. |
455 | - |
456 | -#### `keyword` key (required) |
457 | - |
458 | -Value: a keyword whose advertising scopes will be aggreagated in this position in the order. |
459 | - |
460 | -Defining two `keyword`s with identical values is not supported at this time. |
461 | - |
462 | -#### `department` key (optional) |
463 | - |
464 | -Value: string |
465 | - |
466 | -If present, places the keyword aggegrateed scopes into the department. The department must be declared in `departments`. |
467 | - |
468 | -#### `_department_title` key DEPRECATED |
469 | - |
470 | -Value: string |
471 | - |
472 | -When you have not assigned the keyword to a department, you create a department for this keyword automatically by declaring this key. |
473 | - |
474 | -Do not declare this key when you have assigned the keyword to a department. |
475 | - |
476 | -**Note**: If the value is a msgid in your po files, the department title is localized according to po files. |
477 | - |
478 | -This is deprecated because it is easy to declare a department and assign the keyword to it. |
479 | - |
480 | -#### `shared_category` key (optional) |
481 | - |
482 | -Value: string, "true" or "false" |
483 | - |
484 | -When "true", all results from all scopes aggregated by this keyword are displayed in one category. |
485 | - |
486 | -#### `_shared_category_title` key (optional) |
487 | - |
488 | -Value: string |
489 | - |
490 | -Only used if `_shared_category_title` present. |
491 | - |
492 | -String that will be used (localized) for the category title. |
493 | - |
494 | -### Renderers |
495 | - |
496 | -These are identical to those described for `scope`. See that section. |
497 | - |
498 | -### Examples |
499 | - |
500 | -Place all "sports" scopes in a certain position in the order: |
501 | - |
502 | - { |
503 | - "order": |
504 | - [ |
505 | - [...] |
506 | - { |
507 | - "keyword": |
508 | - { |
509 | - "keyword": "sports" |
510 | - } |
511 | - }, |
512 | - [...] |
513 | - ] |
514 | - } |
515 | - |
516 | -Example. Place all "sports" scopes in a certain position in the order and in a specific department: |
517 | - |
518 | - { |
519 | - "order": |
520 | - [ |
521 | - [...] |
522 | - { |
523 | - "keyword": |
524 | - { |
525 | - "keyword": "sports", |
526 | - "department": "dept-sports" |
527 | - } |
528 | - }, |
529 | - [...] |
530 | - ] |
531 | - } |
532 | - |
533 | -Example: Place all "news" keyword scopes in a certain position in the order and in a deparmentt. Use a single shared category for all such results, providing the category title, and renderers (by reference to `common_templates` for first result, the result of the normal results, and search results: |
534 | - |
535 | - { |
536 | - "order": |
537 | - [ |
538 | - [...] |
539 | - { |
540 | - "keyword": |
541 | - { |
542 | - "keyword": "news", |
543 | - "department": "dept-news", |
544 | - "shared_category": "true", |
545 | - "_shared_category_title": "News Headlines", |
546 | - "first_result_renderer_common_id": "renderer-news-first-result", |
547 | - "category_renderer_common_id": "renderer-news", |
548 | - "search_renderer_common_id": "renderer-news-search", |
549 | - } |
550 | - }, |
551 | - [...] |
552 | - ] |
553 | - } |
554 | - |
555 | -### `category` |
556 | +### `category` (optional) |
557 | |
558 | You can declare a category that includes a specified set of scopes and keywords. All results from these child scopes are displayed in a single category. |
559 | |
560 | -You can place the category in a department and define the renderers for it (first result, normal, and search) in place or by referent to `common_templates`. |
561 | +You can place the category in a department and define the renderers for it (normal, first result, and search) in place or by reference to `common_templates`. |
562 | |
563 | -When not using user settings for cardinality, you can set it. |
564 | +You can declare cardinality that overrides scope settings for cardinality, if used. |
565 | |
566 | Each scope requires an `id` and a `local_id` (as described in `scope` material. It may optionally have a `child_department` that specifies to show only results from that. |
567 | |
568 | Each keyword also requires an `id` and a `local_id`. |
569 | |
570 | -Example using all currently supported keys: |
571 | +You may declare `"link_to_child_specified": "SCOPE_ID"` to provide a tappable link to the child scope on the Category header. |
572 | + |
573 | +Example: |
574 | |
575 | "order": |
576 | [ |
577 | @@ -697,13 +636,103 @@ |
578 | } |
579 | }, |
580 | |
581 | +### `keyword` (optional) |
582 | + |
583 | +Declare a specific keyword for aggregation. |
584 | + |
585 | +The category for the first child scope that answers under the specified keyword is always placed in declared position in the overall order. |
586 | + |
587 | +If multiple child scopes reply under the specified keyword, a category is created for each child scope whose title is taken from the first such incoming result. The order of the second scope and later child scopes is not determinant: they are positioned in the over all order in the order in which they are received. Therefore, `keyword` may be useful as the last item declared in the `order` as a catch-all to pick up additional relevant content without affecting the declared order that precedes it. order of |
588 | + |
589 | +Note: To keep all results from all child scopes that answer a specific keyword together in a single category (thus preserving the overall order), use `category` with `keywords` instead. |
590 | + |
591 | +You can place the keyword scopes in a department and define the renderers for it (normal, first result, and search - but not login) in place or by reference to `common_templates`. |
592 | + |
593 | +You can declare cardinality that overrides scope settings for cardinality, if used. |
594 | + |
595 | +#### `keyword` key (required) |
596 | + |
597 | +Value: a keyword whose advertising scopes will be aggregated in this position in the order. |
598 | + |
599 | +This is the unique ID with file scope. `Defining two `keyword`s with identical values is not supported. |
600 | + |
601 | +#### `department` key (optional) |
602 | + |
603 | +Value: string |
604 | + |
605 | +If present, places the keyword aggregated scopes into the department. The department must be declared in `departments`. |
606 | + |
607 | +#### Renderers |
608 | + |
609 | +These are identical to those described for `scope` except `login_renderer` is not supported. |
610 | + |
611 | +### `exclude_scopes` key (optional) |
612 | + |
613 | +Value: json list of objects. |
614 | + |
615 | +Suppose you want some scopes which supports one certain keywords not to display results, you can specify scope id in the exclude_scopes and scope aggregator will not display results of specified scopes. |
616 | + |
617 | +Note: This key is only supposed to be declared in a `keywords` json object. |
618 | +e.g. amazon supports 'books' keyword, but in most cases it returns something unrelated to 'books' keyword. we can get rid of its results in the way as following. |
619 | + "order": |
620 | + |
621 | + [ |
622 | + { |
623 | + "keyword": |
624 | + { |
625 | + "keyword": "books", |
626 | + "link_to_child" : "true", |
627 | + "exclude_scopes" :[ |
628 | + { |
629 | + "id": "com.canonical.scopes.amazon" |
630 | + } |
631 | + ] |
632 | + } |
633 | + } |
634 | + ] |
635 | + |
636 | + |
637 | +#### `display_order` key (optional) |
638 | + |
639 | +Value: json list of objects. |
640 | + |
641 | +display\_order allows developer to set child scopes display order of keyword scope. You can specify multiple scope id in the display\_order and scope aggregator will display child scopes according to the order you defined in display\_order.Installed keyword child scopes that are not listed in display_order are displayed after installed display_order scopes and in a indeterminate order. |
642 | + |
643 | +Note: `display_order` must be a direct child of a `keyword`. |
644 | +e.g. the following scopes support 'bollywood.movie' keyword, |
645 | + 1.Shemaroo |
646 | + 2.Eros |
647 | + 3.ZeeTV |
648 | + 4.Star-plus |
649 | + |
650 | +if we define display_order as following, shemaroo scope will be shown in the first place, then eros at 2nd place.And zeeTV and star-plus will be shown randomly |
651 | + "order": |
652 | + |
653 | + [ |
654 | + { |
655 | + "keyword": |
656 | + { |
657 | + "keyword": "bollywood.movie", |
658 | + "link_to_child" : "true", |
659 | + "display_order" :[ |
660 | + { |
661 | + "id": "com.canonical.scopes.shemaroo_shemaroo" |
662 | + }, |
663 | + { |
664 | + "id": "com.canonical.scopes.eros_eros" |
665 | + } |
666 | + ] |
667 | + } |
668 | + } |
669 | + ] |
670 | |
671 | ## `common_templates` key (optional) |
672 | |
673 | -Allows you to declare a category renderer once and use it multiple times. Useful for a common login result design. Each template requires a unique `id` and a `template`. |
674 | +Allows you to declare a renderer once and use it multiple times. Each template requires a unique `id` and a `template`. |
675 | + |
676 | + |
677 | |
678 | { |
679 | - [...] |
680 | "common_templates": |
681 | [ |
682 | { |
683 | @@ -715,13 +744,18 @@ |
684 | }, |
685 | { |
686 | "id" : "renderer-news-first-result", |
687 | + "fallbacks: |
688 | + { |
689 | + [...] |
690 | + } |
691 | "template": |
692 | { |
693 | [...] |
694 | } |
695 | } |
696 | ], |
697 | - ['...] |
698 | + "order": |
699 | + [...] |
700 | } |
701 | |
702 | ### `id` (required) |
703 | @@ -737,6 +771,9 @@ |
704 | The `template` is the categoryRenderer template to use for categories whose id matches `id`. |
705 | |
706 | { |
707 | + "departments": |
708 | + [...] |
709 | + "order": |
710 | [...] |
711 | "common_templates": |
712 | [ |
713 | @@ -762,21 +799,25 @@ |
714 | [...] |
715 | } |
716 | |
717 | - |
718 | -#### `default_query_string` key (optional) |
719 | +### `fallbacks` (optional) |
720 | + |
721 | +See Fallbacks discussion. |
722 | + |
723 | +## Other Features |
724 | + |
725 | +### `default_query_string` key (optional) |
726 | |
727 | Value: string: a query string passed to child scope |
728 | |
729 | The key is useful for developer to display results with specific query string by default instead of results fetched with empty query string. |
730 | |
731 | - |
732 | -#### `only_in_search` key (optional) |
733 | +### `only_in_search` key (optional) |
734 | |
735 | Value: string: "true" or "false", default value: "false" |
736 | |
737 | Displays only results of specified scope on search, not in surface. |
738 | |
739 | -Note:If aggregator has multiple departments, in order to display results in current departments, you need to declare the scope with different deparment and local_id separately. |
740 | +Note: If aggregator has multiple departments, in order to display results in current departments, you need to declare the scope with different department and local_id separately. |
741 | |
742 | { |
743 | "departments": |
744 | @@ -818,60 +859,3 @@ |
745 | ] |
746 | |
747 | |
748 | -#### `exclude_scopes` key (optional) |
749 | - |
750 | -Value: json list of objects. |
751 | - |
752 | -Suppose you want some scopes which supports one certain keywords not to display results, you can specify scope id in the exclude_scopes and scope aggregator will not display results of specified scopes. |
753 | - |
754 | -Note:This key is only supposed to be declared in a `keywords` json object, which doesn't not use a shared category. |
755 | -e.g. amazon supports 'books' keyword, but in most cases it returns something unrelated to 'books' keyword. we can get rid of its results in the way as following. |
756 | - "order": |
757 | - [ |
758 | - { |
759 | - "keyword": |
760 | - { |
761 | - "keyword": "books", |
762 | - "link_to_child" : "true", |
763 | - "exclude_scopes" :[ |
764 | - { |
765 | - "id": "com.canonical.scopes.amazon" |
766 | - } |
767 | - ] |
768 | - } |
769 | - } |
770 | - ] |
771 | - |
772 | - |
773 | -#### `display_order` key (optional) |
774 | - |
775 | -Value: json list of objects. |
776 | - |
777 | -display_order allows developer to set child scopes display order of keyword scope. You can specify multiple scope id in the display_order and scope aggregator will display child scopes according to the order you defined in display_order.Installed keyword child scopes that are not listed in display_order are displayed after installed display_order scopes and in a indeterminate order. |
778 | - |
779 | -Note: `display_order` must be a direct child of a `keyword`. |
780 | -e.g. the following scopes support 'bollywood.movie' keyword, |
781 | - 1.Shemaroo |
782 | - 2.Eros |
783 | - 3.ZeeTV |
784 | - 4.Star-plus |
785 | - |
786 | -if we define display_order as following, shemaroo scope will be shown in the first place, then eros at 2nd place.And zeeTV and star-plus will be shown randomly |
787 | - "order": |
788 | - [ |
789 | - { |
790 | - "keyword": |
791 | - { |
792 | - "keyword": "bollywood.movie", |
793 | - "link_to_child" : "true", |
794 | - "display_order" :[ |
795 | - { |
796 | - "id": "com.canonical.scopes.shemaroo_shemaroo" |
797 | - }, |
798 | - { |
799 | - "id": "com.canonical.scopes.eros_eros" |
800 | - } |
801 | - ] |
802 | - } |
803 | - } |
804 | - ] |
805 | |
806 | === modified file 'gtests/CMakeLists.txt' |
807 | --- gtests/CMakeLists.txt 2016-08-19 20:20:58 +0000 |
808 | +++ gtests/CMakeLists.txt 2016-09-30 19:17:35 +0000 |
809 | @@ -34,6 +34,7 @@ |
810 | ../src/resultforwarder.cpp |
811 | ../src/scope.cpp |
812 | ../src/utils.cpp |
813 | + ../src/handle_results.cpp |
814 | ../src/aggchildscope.cpp |
815 | ../src/listener.cpp |
816 | ../src/action.cpp |
817 | @@ -72,6 +73,9 @@ |
818 | COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/scope_directory/hints_local.json" "${CMAKE_CURRENT_BINARY_DIR}/scope_directory/hints_local.json" |
819 | COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/scope_directory/hints.json" "${CMAKE_CURRENT_BINARY_DIR}/scope_directory/hints.json" |
820 | COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/scope_directory/hints_remote.json" "${CMAKE_CURRENT_BINARY_DIR}/scope_directory/hints_remote.json" |
821 | + COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/scope_directory/login_1.json" "${CMAKE_CURRENT_BINARY_DIR}/scope_directory/login_1.json" |
822 | + COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/scope_directory/login_2.json" "${CMAKE_CURRENT_BINARY_DIR}/scope_directory/login_2.json" |
823 | + COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/scope_directory/login_3.json" "${CMAKE_CURRENT_BINARY_DIR}/scope_directory/login_3.json" |
824 | COMMAND ${CMAKE_COMMAND} -E make_directory "${CMAKE_CURRENT_BINARY_DIR}/cache_directory" |
825 | ) |
826 | |
827 | |
828 | === modified file 'gtests/MockRegistry.h' |
829 | --- gtests/MockRegistry.h 2016-08-17 16:17:03 +0000 |
830 | +++ gtests/MockRegistry.h 2016-09-30 19:17:35 +0000 |
831 | @@ -154,6 +154,13 @@ |
832 | { |
833 | mm.insert(pair<string, ScopeMetadata>("full_keyword_3", full_keyword_3)); |
834 | } |
835 | + |
836 | + set<string> keywords_login = {"login-test"}; |
837 | + auto login_metadata = build_scope_metadata("login-test", keywords_login); |
838 | + if (predicate(login_metadata)) |
839 | + { |
840 | + mm.insert(pair<string, ScopeMetadata>("login-test", login_metadata)); |
841 | + } |
842 | return mm; |
843 | } |
844 | }; |
845 | |
846 | === added file 'gtests/scope_directory/login_1.json' |
847 | --- gtests/scope_directory/login_1.json 1970-01-01 00:00:00 +0000 |
848 | +++ gtests/scope_directory/login_1.json 2016-09-30 19:17:35 +0000 |
849 | @@ -0,0 +1,74 @@ |
850 | +{ |
851 | + "common_templates": |
852 | + [ |
853 | + { |
854 | + "id" : "default-renderer", |
855 | + "template": |
856 | + { |
857 | + "components": |
858 | + { |
859 | + "art": "art", |
860 | + "title": "title", |
861 | + "subtitle": "subtitle", |
862 | + "summary": "summary", |
863 | + "emblem": "emblem" |
864 | + }, |
865 | + "schema-version": 1, |
866 | + "template": |
867 | + { |
868 | + "card-layout": "horizontal", |
869 | + "card-size": "large", |
870 | + "collapsed-rows": 0, |
871 | + "category-layout": "vertical-journal" |
872 | + } |
873 | + } |
874 | + } |
875 | + ], |
876 | + "order": |
877 | + [ |
878 | + { |
879 | + "scope": { |
880 | + "id": "scope_login", |
881 | + "local_id": "local_scope_2", |
882 | + "renderer_common_id": "fallbacks" |
883 | + } |
884 | + }, |
885 | + { |
886 | + "category": |
887 | + { |
888 | + "id": "headlines", |
889 | + "department": "dept-headlines", |
890 | + "_title": "Headlines", |
891 | + "renderer_common_id": "default-renderer", |
892 | + "login_renderer_incoming_category_id": "login-category", |
893 | + "login_renderer": |
894 | + { |
895 | + "components": |
896 | + { |
897 | + "mascot": "login-art", |
898 | + "title": "login-title" |
899 | + }, |
900 | + "schema-version": 1, |
901 | + "template": |
902 | + { |
903 | + "card-layout": "horizontal", |
904 | + "card-size": "small", |
905 | + "collapsed-rows": 1, |
906 | + "category-layout": "grid" |
907 | + } |
908 | + }, |
909 | + "scopes": |
910 | + [ |
911 | + ], |
912 | + "keywords": |
913 | + [ |
914 | + { |
915 | + "id": "login-test", |
916 | + "local_id": "login1-localid" |
917 | + } |
918 | + |
919 | + ] |
920 | + } |
921 | + } |
922 | + ] |
923 | +} |
924 | |
925 | === added file 'gtests/scope_directory/login_2.json' |
926 | --- gtests/scope_directory/login_2.json 1970-01-01 00:00:00 +0000 |
927 | +++ gtests/scope_directory/login_2.json 2016-09-30 19:17:35 +0000 |
928 | @@ -0,0 +1,73 @@ |
929 | +{ |
930 | + "common_templates": |
931 | + [ |
932 | + { |
933 | + "id" : "default-renderer", |
934 | + "template": |
935 | + { |
936 | + "components": |
937 | + { |
938 | + "art": "art", |
939 | + "title": "title", |
940 | + "subtitle": "subtitle", |
941 | + "summary": "summary", |
942 | + "emblem": "emblem" |
943 | + }, |
944 | + "schema-version": 1, |
945 | + "template": |
946 | + { |
947 | + "card-layout": "horizontal", |
948 | + "card-size": "large", |
949 | + "collapsed-rows": 0, |
950 | + "category-layout": "vertical-journal" |
951 | + } |
952 | + } |
953 | + } |
954 | + ], |
955 | + "order": |
956 | + [ |
957 | + { |
958 | + "scope": { |
959 | + "id": "scope_login", |
960 | + "local_id": "local_scope_2", |
961 | + "renderer_common_id": "fallbacks" |
962 | + } |
963 | + }, |
964 | + { |
965 | + "category": |
966 | + { |
967 | + "id": "headlines", |
968 | + "department": "dept-headlines", |
969 | + "_title": "Headlines", |
970 | + "renderer_common_id": "default-renderer", |
971 | + "login_renderer_incoming_category_id": "login-category", |
972 | + "login_renderer": |
973 | + { |
974 | + "components": |
975 | + { |
976 | + "mascot": "login-art", |
977 | + "title": "login-title" |
978 | + }, |
979 | + "schema-version": 1, |
980 | + "template": |
981 | + { |
982 | + "card-layout": "horizontal", |
983 | + "card-size": "small", |
984 | + "collapsed-rows": 1, |
985 | + "category-layout": "grid" |
986 | + } |
987 | + }, |
988 | + "scopes": |
989 | + [ |
990 | + { |
991 | + "id": "login-test", |
992 | + "local_id": "login1-localid" |
993 | + } |
994 | + ], |
995 | + "keywords": |
996 | + [ |
997 | + ] |
998 | + } |
999 | + } |
1000 | + ] |
1001 | +} |
1002 | |
1003 | === added file 'gtests/scope_directory/login_3.json' |
1004 | --- gtests/scope_directory/login_3.json 1970-01-01 00:00:00 +0000 |
1005 | +++ gtests/scope_directory/login_3.json 2016-09-30 19:17:35 +0000 |
1006 | @@ -0,0 +1,35 @@ |
1007 | +{ |
1008 | + "order": |
1009 | + [ |
1010 | + { |
1011 | + "scope": { |
1012 | + "_category_title": "Login Declared Scope Test", |
1013 | + "id": "login-test", |
1014 | + "local_id": "login1-localid", |
1015 | + "renderer": { |
1016 | + "components": { |
1017 | + "art": "art" |
1018 | + }, |
1019 | + "schema-version": 1, |
1020 | + "template": { |
1021 | + "card-size": "small", |
1022 | + "category-layout": "grid", |
1023 | + "collapsed-rows": 10 |
1024 | + } |
1025 | + }, |
1026 | + "login_renderer_incoming_category_id": "login-category", |
1027 | + "login_renderer": { |
1028 | + "components": { |
1029 | + "mascot": "mascot", |
1030 | + "title": "title" |
1031 | + }, |
1032 | + "schema-version": 1, |
1033 | + "template": { |
1034 | + "card-size": "large", |
1035 | + "category-layout": "grid" |
1036 | + } |
1037 | + } |
1038 | + } |
1039 | + } |
1040 | + ] |
1041 | +} |
1042 | |
1043 | === modified file 'gtests/scope_test.cpp' |
1044 | --- gtests/scope_test.cpp 2016-08-19 20:46:32 +0000 |
1045 | +++ gtests/scope_test.cpp 2016-09-30 19:17:35 +0000 |
1046 | @@ -81,6 +81,7 @@ |
1047 | QJsonArray depts_a = depts["declarations"].toArray(); |
1048 | ASSERT_EQ(depts_a.size(), 3); |
1049 | |
1050 | + |
1051 | NiceMock<unity::scopes::testing::MockSearchReply> reply; |
1052 | unity::scopes::SearchReplyProxy search_reply_proxy |
1053 | { |
1054 | @@ -97,6 +98,7 @@ |
1055 | |
1056 | Query * q = new Query(cq, smd, string("scope_directory"), string("cache_directory"), reg, scope_ptr); |
1057 | q->load_declarations(scope_ptr->child_root()); |
1058 | + ASSERT_TRUE(q->is_using_departments()); |
1059 | q->create_departments(search_reply_proxy); |
1060 | |
1061 | ASSERT_TRUE(child_root.contains("cardinality_settings")); |
1062 | @@ -105,8 +107,11 @@ |
1063 | ASSERT_TRUE(child_root.contains("common_templates")); |
1064 | ASSERT_TRUE(child_root.contains("order")); |
1065 | } |
1066 | + |
1067 | + |
1068 | /** |
1069 | * Verifies that no call to register_departments() made when no depts declared in json |
1070 | + * and that is_using_departments() returns false |
1071 | */ |
1072 | TEST_F(TestAggScope, verify_no_departments){ |
1073 | AggScope * scope_ptr; |
1074 | @@ -127,9 +132,6 @@ |
1075 | { |
1076 | &reply, [](unity::scopes::SearchReply*) {} |
1077 | }; |
1078 | - |
1079 | - //verify a call is made to register departments |
1080 | - //EXPECT_CALL(reply, register_departments(_)).Times(0); |
1081 | |
1082 | shared_ptr<MockRegistry> reg = make_shared<MockRegistry>(); |
1083 | SearchMetadata smd("en_US", "phone"); |
1084 | @@ -139,6 +141,7 @@ |
1085 | Query * q = new Query(cq, smd, string("scope_directory"), string("cache_directory"), reg, scope_ptr); |
1086 | q->load_declarations(scope_ptr->child_root()); |
1087 | q->create_departments(search_reply_proxy); |
1088 | + ASSERT_FALSE(q->is_using_departments()); |
1089 | } |
1090 | |
1091 | /** |
1092 | @@ -643,3 +646,107 @@ |
1093 | //tests that hints DOES iNOT display when hints_is_hidden file exists in cachee dir |
1094 | ASSERT_FALSE(q->assert_hints_display((proxy))); |
1095 | } |
1096 | + |
1097 | +/* |
1098 | + * Verifies that a category keyword defined to use a login renderer uses it. |
1099 | + * Particularly, the return value of Query::is_login_case() method is verified as true |
1100 | + * when the incoming result category id is the same as the declared one, and false otherwise. |
1101 | + * As with many tests, the MockRegistry is configured to have a scope that answers to |
1102 | + * the keyword defined in the login_1.json file used here. |
1103 | + */ |
1104 | +TEST_F(TestAggScope, is_login_case_category_keyword){ |
1105 | + AggScope * scope_ptr; |
1106 | + scope_ptr = &(*scope); |
1107 | + string fbj = "login_1.json"; |
1108 | + scope_ptr->set_child_scopes_json_filename(fbj); |
1109 | + ASSERT_EQ(scope_ptr->child_scopes_json_filename(), fbj); |
1110 | + QJsonObject child_root = scope_ptr->get_child_root(); |
1111 | + std::string path = scope_ptr->scope_directory() + "/" + scope_ptr->child_scopes_json_filename(); |
1112 | + ASSERT_TRUE(scope_ptr->load_json_file(child_root, path, scope_ptr->scope_id())) << "Problem with: " << path; |
1113 | + scope_ptr->set_child_root(child_root); |
1114 | + SearchMetadata smd("en_US", "phone"); |
1115 | + CannedQuery cq("not_an_id"); |
1116 | + shared_ptr<MockRegistry> reg = make_shared<MockRegistry>(); |
1117 | + Query * q = new Query(cq, smd, string("scope_directory"), string("cache_directory"), reg, scope_ptr); |
1118 | + q->load_declarations(scope_ptr->child_root()); |
1119 | + ChildScopeList csl = scope->find_child_scopes(); |
1120 | + ASSERT_EQ(csl.size(), 1); |
1121 | + ASSERT_EQ(csl.front().id, "login-test"); |
1122 | + q->current_child_scopes = csl; |
1123 | + q->make_categories(); |
1124 | + auto cat = q->categories[0]; |
1125 | + auto child = q->scopes_m["login-test:category=headlines:keyword=login-test"]; |
1126 | + bool login_case = q->is_login_case(child, "login-category"); |
1127 | + ASSERT_TRUE(login_case); |
1128 | + login_case = q->is_login_case(child, "NOT-login-category"); |
1129 | + ASSERT_FALSE(login_case); |
1130 | +} |
1131 | + |
1132 | +/* |
1133 | + * Verifies that a category scope defined to use a login renderer uses it. |
1134 | + * Particularly, the return value of Query::is_login_case() method is verified as true |
1135 | + * when the incoming result category id is the same as the declared one, and false otherwise. |
1136 | + * As with many tests, the MockRegistry is configured to have a scope with the id |
1137 | + * defined in login_2.json used here. |
1138 | + */ |
1139 | +TEST_F(TestAggScope, is_login_case_category_scope){ |
1140 | + AggScope * scope_ptr; |
1141 | + scope_ptr = &(*scope); |
1142 | + string fbj = "login_2.json"; |
1143 | + scope_ptr->set_child_scopes_json_filename(fbj); |
1144 | + ASSERT_EQ(scope_ptr->child_scopes_json_filename(), fbj); |
1145 | + QJsonObject child_root = scope_ptr->get_child_root(); |
1146 | + std::string path = scope_ptr->scope_directory() + "/" + scope_ptr->child_scopes_json_filename(); |
1147 | + ASSERT_TRUE(scope_ptr->load_json_file(child_root, path, scope_ptr->scope_id())) << "Problem with: " << path; |
1148 | + scope_ptr->set_child_root(child_root); |
1149 | + SearchMetadata smd("en_US", "phone"); |
1150 | + CannedQuery cq("not_an_id"); |
1151 | + shared_ptr<MockRegistry> reg = make_shared<MockRegistry>(); |
1152 | + Query * q = new Query(cq, smd, string("scope_directory"), string("cache_directory"), reg, scope_ptr); |
1153 | + q->load_declarations(scope_ptr->child_root()); |
1154 | + ChildScopeList csl = scope->find_child_scopes(); |
1155 | + ASSERT_EQ(csl.size(), 1); |
1156 | + ASSERT_EQ(csl.front().id, "login-test"); |
1157 | + q->current_child_scopes = csl; |
1158 | + q->make_categories(); |
1159 | + auto cat = q->categories[0]; |
1160 | + auto child = q->scopes_m["login1-localid"]; |
1161 | + bool login_case = q->is_login_case(child, "login-category"); |
1162 | + ASSERT_TRUE(login_case); |
1163 | + login_case = q->is_login_case(child, "NOT-login-category"); |
1164 | + ASSERT_FALSE(login_case); |
1165 | +} |
1166 | + |
1167 | +/* |
1168 | + * Verifies that a declared scope defined to use a login renderer uses it. |
1169 | + * Particularly, the return value of Query::is_login_case() method is verified as true |
1170 | + * when the incoming result category id is the same as the declared one, and false otherwise. |
1171 | + * As with many tests, the MockRegistry is configured to have a scope with the id |
1172 | + * defined in login_2.json used here. |
1173 | + */ |
1174 | +TEST_F(TestAggScope, is_login_case_declared_scope){ |
1175 | + AggScope * scope_ptr; |
1176 | + scope_ptr = &(*scope); |
1177 | + string fbj = "login_3.json"; |
1178 | + scope_ptr->set_child_scopes_json_filename(fbj); |
1179 | + ASSERT_EQ(scope_ptr->child_scopes_json_filename(), fbj); |
1180 | + QJsonObject child_root = scope_ptr->get_child_root(); |
1181 | + std::string path = scope_ptr->scope_directory() + "/" + scope_ptr->child_scopes_json_filename(); |
1182 | + ASSERT_TRUE(scope_ptr->load_json_file(child_root, path, scope_ptr->scope_id())) << "Problem with: " << path; |
1183 | + scope_ptr->set_child_root(child_root); |
1184 | + SearchMetadata smd("en_US", "phone"); |
1185 | + CannedQuery cq("not_an_id"); |
1186 | + shared_ptr<MockRegistry> reg = make_shared<MockRegistry>(); |
1187 | + Query * q = new Query(cq, smd, string("scope_directory"), string("cache_directory"), reg, scope_ptr); |
1188 | + q->load_declarations(scope_ptr->child_root()); |
1189 | + ChildScopeList csl = scope->find_child_scopes(); |
1190 | + ASSERT_EQ(csl.front().id, "login-test"); |
1191 | + q->current_child_scopes = csl; |
1192 | + ASSERT_EQ(csl.size(), 1); |
1193 | + q->make_declared_scopes(); |
1194 | + auto child = q->scopes_m["login1-localid"]; |
1195 | + bool login_case = q->is_login_case(child, "login-category"); |
1196 | + ASSERT_TRUE(login_case); |
1197 | + login_case = q->is_login_case(child, "NOT-login-category"); |
1198 | + ASSERT_FALSE(login_case); |
1199 | +} |
1200 | |
1201 | === modified file 'include/aggchildscope.h' |
1202 | --- include/aggchildscope.h 2016-06-29 10:29:37 +0000 |
1203 | +++ include/aggchildscope.h 2016-09-30 19:17:35 +0000 |
1204 | @@ -146,6 +146,37 @@ |
1205 | us::Category::SCPtr category(); |
1206 | |
1207 | /** |
1208 | + \brief Whether scope uses login renderer |
1209 | + \return Return whether scope uses login renderer |
1210 | + */ |
1211 | + bool using_login_renderer(); |
1212 | + |
1213 | + /** |
1214 | + \brief Enable using login renderer |
1215 | + */ |
1216 | + void enable_using_login_renderer(); |
1217 | + |
1218 | + /** |
1219 | + \brief Set the incoming category id which triggers use a the login_renderer |
1220 | + */ |
1221 | + void set_login_renderer_incoming_category_id(std::string const& cat_id); |
1222 | + |
1223 | + /** |
1224 | + \brief Get the incoming category id which triggers use a the login_renderer |
1225 | + */ |
1226 | + std::string login_renderer_incoming_category_id(); |
1227 | + |
1228 | + /** |
1229 | + \brief The json defining the CategoryRenderer json used when when incoming result has catgegory id == login_renderer_incoming_category_id. |
1230 | + */ |
1231 | + void set_login_template(std::string const& login_template); |
1232 | + |
1233 | + /** |
1234 | + \brief Return the json defining the CategoryRenderer template used for login when login_renderer_incoming_category_id set and current incoming result matches. |
1235 | + */ |
1236 | + const std::string & login_template() const; |
1237 | + |
1238 | + /** |
1239 | \brief The json defining the CategoryRenderer json used when surfacing the first result. You must also declare surface_template to handle the rest. |
1240 | */ |
1241 | void set_first_result_template(std::string const &first_result_template); |
1242 | @@ -154,8 +185,9 @@ |
1243 | \brief Return the json defining the CategoryRenderer template used when surfacing first result. |
1244 | */ |
1245 | const std::string & first_result_template() const; |
1246 | + |
1247 | /** |
1248 | - * |
1249 | + * |
1250 | \brief The json defining the CategoryRenderer template used when surfacing results. |
1251 | \param surface_template The json passed to the CategoryRenderer |
1252 | */ |
1253 | @@ -375,6 +407,8 @@ |
1254 | std::string id_; |
1255 | std::string local_id_; |
1256 | std::string cat_title = ""; |
1257 | + std::string login_renderer_incoming_category_id_; |
1258 | + bool using_login_renderer_ =false; |
1259 | bool using_category_link_to_child; |
1260 | bool using_category_title_incoming_ = false; |
1261 | bool using_category_title_display_name_ = false; |
1262 | @@ -396,6 +430,7 @@ |
1263 | us::Category::SCPtr cat; |
1264 | bool override_surface_template_ = true; |
1265 | bool override_search_template_ = true; |
1266 | + std::string template_login_; |
1267 | std::string TEMPLATE_NOT_LOGGED_IN; |
1268 | std::string template_first_result_; |
1269 | std::string first_common_template_id_; |
1270 | |
1271 | === modified file 'include/query.h' |
1272 | --- include/query.h 2016-08-19 17:04:10 +0000 |
1273 | +++ include/query.h 2016-09-30 19:17:35 +0000 |
1274 | @@ -44,6 +44,8 @@ |
1275 | std::string category_link_to_child_specified; |
1276 | std::string renderer; |
1277 | std::string search_renderer; |
1278 | + std::string login_renderer; |
1279 | + std::string login_renderer_incoming_category_id; |
1280 | std::vector<std::pair<std::string,std::string>> scopes; // id and local_id of scopes |
1281 | std::vector<std::string> keywords; // keywords in this cat |
1282 | std::vector<std::pair<std::string,std::string>> keyword_ids; // id and local id of keywords |
1283 | @@ -90,6 +92,8 @@ |
1284 | bool using_child_category_max_results = false;//NOT A JSON KEY |
1285 | bool overriding_surface_template = false;//NOT A JSON KEY |
1286 | bool overriding_search_template = false;//NOT A JSON KEY |
1287 | + std::string login_renderer; |
1288 | + std::string login_renderer_incoming_category_id; |
1289 | std::vector<std::shared_ptr<std::pair<std::string,std::string>>> swap_result_attributes; |
1290 | std::pair<std::string,std::string> if_category_use_template; |
1291 | std::map<std::string, std::string> result_category_id_to_common_template;//id is result category id. maps to id to use in common_templates |
1292 | @@ -110,7 +114,6 @@ |
1293 | |
1294 | virtual void run(unity::scopes::SearchReplyProxy const& upstream_reply) override; |
1295 | |
1296 | - bool using_departments = true; |
1297 | |
1298 | Client client; |
1299 | |
1300 | @@ -130,26 +133,32 @@ |
1301 | unity::scopes::CategorisedResult & res, |
1302 | std::string const& inc_res_cat_id, |
1303 | std::string const& inc_res_cat_title); |
1304 | + bool is_login_case(std::shared_ptr<AggChildScope> scope, std::string const& res_cat_id); |
1305 | + void make_categories(); |
1306 | + void make_declared_scopes(); |
1307 | + std::vector<std::shared_ptr<category>> categories; |
1308 | + us::ChildScopeList current_child_scopes; |
1309 | + std::map<std::string, std::shared_ptr<AggChildScope>> scopes_m;//key is local_id |
1310 | + bool is_using_departments(); |
1311 | + |
1312 | private: |
1313 | - void make_declared_scopes(); |
1314 | + bool using_departments = false; |
1315 | void make_keyword_scopes(); |
1316 | - void make_categories(); |
1317 | - |
1318 | void set_scope_order(); |
1319 | - |
1320 | void display_local_hints_quickstart(us::SearchReplyProxy const& upstream_reply_); |
1321 | void display_remote_hints_quickstart(us::SearchReplyProxy const& upstream_reply_); |
1322 | bool show_hints(us::SearchReplyProxy const& upstream_reply_); |
1323 | bool hints_exists(); |
1324 | bool hints_hidden(); |
1325 | void dismiss_hints_quickstart(); |
1326 | + us::Category::SCPtr set_result_catgory(us::SearchReplyProxy const& upstream_reply, us::CategorisedResult & res, std::string const& id, std::string const& title, std::string const& rdr, std::string const& link_to); |
1327 | + us::Category::SCPtr set_result_catgory(us::SearchReplyProxy const& upstream_reply, us::CategorisedResult & res, std::string const& id, std::string const& title, std::string const& rdr); |
1328 | |
1329 | - void handle_current_child_scopes(bool empty_search, us::SearchReplyProxy const& upstream_reply); |
1330 | + void complete_child_scopes(); |
1331 | void handle_child_scope_results(std::string const &query_string, bool empty_search, us::SearchReplyProxy const& upstream_reply); |
1332 | void noSources(unity::scopes::SearchReplyProxy const& reply); |
1333 | std::map<std::string,std::string> localId_defaultQryStr; |
1334 | std::map<std::string,std::string> scopeLocalId_childDept_m; // local_id of scope to scope's child department |
1335 | - std::vector<std::shared_ptr<category>> categories; |
1336 | std::map<std::string,std::shared_ptr<category>> id_category_m; |
1337 | std::map<std::string,std::string> categoryId_titleMsgid; |
1338 | std::vector<std::string> categoryIds; |
1339 | @@ -200,7 +209,6 @@ |
1340 | std::map<std::string,std::string> keyword_deptId; |
1341 | std::map<std::string,std::string> keyword_surfaceRdr; |
1342 | |
1343 | - us::ChildScopeList current_child_scopes; |
1344 | |
1345 | std::string first_result_owner; // set to first declaared keyword or scope that declared a first result renderer |
1346 | std::list<std::string> declared_keywords;// the declared list of keywords, in declared order |
1347 | @@ -217,7 +225,6 @@ |
1348 | std::map<std::string,bool> sharedcat_catregistered;//stores whether the shared cat's ctegory is registered yet |
1349 | |
1350 | std::vector<us::ScopeProxy> scopes; // will hold all enabled and present child scopes |
1351 | - std::map<std::string, std::shared_ptr<AggChildScope>> scopes_m;//key is local_id |
1352 | std::map<int,std::string> scopes_m_int_localId; |
1353 | std::string scope_dir_; |
1354 | std::string cache_dir_; |
1355 | |
1356 | === modified file 'src/CMakeLists.txt' |
1357 | --- src/CMakeLists.txt 2016-08-11 20:24:03 +0000 |
1358 | +++ src/CMakeLists.txt 2016-09-30 19:17:35 +0000 |
1359 | @@ -10,6 +10,7 @@ |
1360 | notify-strategy.cpp |
1361 | aggchildscope.cpp |
1362 | utils.cpp |
1363 | + handle_results.cpp |
1364 | action.cpp |
1365 | ) |
1366 | find_package(Qt5Core REQUIRED) |
1367 | |
1368 | === modified file 'src/aggchildscope.cpp' |
1369 | --- src/aggchildscope.cpp 2016-06-29 10:29:37 +0000 |
1370 | +++ src/aggchildscope.cpp 2016-09-30 19:17:35 +0000 |
1371 | @@ -71,12 +71,45 @@ |
1372 | using_category_title_display_name_ = b; |
1373 | } |
1374 | |
1375 | - |
1376 | us::Category::SCPtr AggChildScope::category() |
1377 | { |
1378 | return cat; |
1379 | } |
1380 | |
1381 | +bool AggChildScope::using_login_renderer() |
1382 | +{ |
1383 | + return using_login_renderer_; |
1384 | +} |
1385 | + |
1386 | +void AggChildScope::enable_using_login_renderer() |
1387 | +{ |
1388 | + using_login_renderer_ = true;; |
1389 | +} |
1390 | + |
1391 | +/* |
1392 | + * When login renderer is used, this required call defines the category id of the |
1393 | + * invoming result for which the login renderer is used. |
1394 | + */ |
1395 | +void AggChildScope::set_login_renderer_incoming_category_id(std::string const& cat_id) |
1396 | +{ |
1397 | + login_renderer_incoming_category_id_ = cat_id; |
1398 | +} |
1399 | + |
1400 | +std::string AggChildScope::login_renderer_incoming_category_id() |
1401 | +{ |
1402 | + return login_renderer_incoming_category_id_; |
1403 | +} |
1404 | + |
1405 | +void AggChildScope::set_login_template(std::string const& login_template) |
1406 | +{ |
1407 | + template_login_ = login_template; |
1408 | +} |
1409 | + |
1410 | +const std::string & AggChildScope::login_template() const |
1411 | +{ |
1412 | + return template_login_; |
1413 | +} |
1414 | + |
1415 | void AggChildScope::set_first_result_template(std::string const &first_result_template) |
1416 | { |
1417 | template_first_result_ = first_result_template; |
1418 | |
1419 | === added file 'src/handle_results.cpp' |
1420 | --- src/handle_results.cpp 1970-01-01 00:00:00 +0000 |
1421 | +++ src/handle_results.cpp 2016-09-30 19:17:35 +0000 |
1422 | @@ -0,0 +1,960 @@ |
1423 | +/* |
1424 | + * Copyright (C) 2016 Canonical Ltd |
1425 | + * |
1426 | + * This program is free software: you can redistribute it and/or modify |
1427 | + * it under the terms of the GNU General Public License version 3 as |
1428 | + * published by the Free Software Foundation. |
1429 | + * |
1430 | + * This program is distributed in the hope that it will be useful, |
1431 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1432 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1433 | + * GNU General Public License for more details. |
1434 | + * |
1435 | + * You should have received a copy of the GNU General Public License |
1436 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1437 | + * |
1438 | + * Authored by: Kyle Nitzsche <kyle.nitzsche@canonical.com> |
1439 | + * Scott Sweeny <scott.sweeny@canonical.com> |
1440 | + * |
1441 | + */ |
1442 | + |
1443 | +#include "query.h" |
1444 | +#include "aggchildscope.h" |
1445 | +#include "i18n.h" |
1446 | + |
1447 | +#include <unity/UnityExceptions.h> |
1448 | + |
1449 | +#include <QFile> |
1450 | +#include <QJsonParseError> |
1451 | +#include <QJsonDocument> |
1452 | +#include <QJsonObject> |
1453 | +#include <QJsonArray> |
1454 | +#include <QDateTime> |
1455 | +#include <iostream> |
1456 | +#include <fstream> |
1457 | +#include <sstream> |
1458 | + |
1459 | +using namespace unity::scopes; |
1460 | + |
1461 | +#define UNUSED(x) (void)(x); |
1462 | + |
1463 | +bool Query::is_login_case(std::shared_ptr<AggChildScope> scope, std::string const& res_cat_id) |
1464 | +{ |
1465 | + return scope->using_login_renderer() && |
1466 | + res_cat_id == scope->login_renderer_incoming_category_id(); |
1467 | + |
1468 | +} |
1469 | + |
1470 | +void Query::complete_child_scopes() |
1471 | +{ |
1472 | + // Cycle through child scopes (in current_scopes) and, if enabled in settings, complete set up |
1473 | + try |
1474 | + { |
1475 | + for (const std::string & local_id : current_scopes) |
1476 | + { |
1477 | + qDebug() << "==== CURRENT. local_id: " << client.qstr(local_id); |
1478 | + std::string id = localId_id_m[local_id]; |
1479 | + qDebug() << "==== CURRENT. id: " << client.qstr(id); |
1480 | + std::shared_ptr<AggChildScope> scope = scopes_m[local_id]; |
1481 | + |
1482 | + scope->set_proxy(registry_); |
1483 | + |
1484 | + if (!scope->exists()) { |
1485 | + std::string sep = query_store_ == "" ? "name:" : "+"; |
1486 | + std::string name = std::string(id, 0, id.find('_')); |
1487 | + query_store_.append(sep + name); |
1488 | + } |
1489 | + else |
1490 | + { |
1491 | + if (!scope->source_finder()) |
1492 | + has_one_source = true; |
1493 | + } |
1494 | + } |
1495 | + for (auto source : sources_for_clickstore) |
1496 | + { |
1497 | + AggChildScope scope(source); |
1498 | + scope.set_proxy(registry_); |
1499 | + if (!scope.exists()) { |
1500 | + std::string sep = query_store_ == "" ? "name:" : "+"; |
1501 | + std::string name = std::string(source, 0, source.find('_')); |
1502 | + query_store_.append(sep + name); |
1503 | + } |
1504 | + } |
1505 | + } |
1506 | + catch (unity::Exception const& e) |
1507 | + { |
1508 | + qWarning() << "NotFoundException: " << e.what(); |
1509 | + } |
1510 | +} |
1511 | + |
1512 | +void Query::noSources(unity::scopes::SearchReplyProxy const& reply) { |
1513 | + std::string MESS_GRID = R"( |
1514 | + { |
1515 | + "schema-version" : 1, |
1516 | + "template" : { |
1517 | + "category-layout" : "grid", |
1518 | + "card-layout": "horizontal", |
1519 | + "card-size": "small", |
1520 | + "non-interactive": true |
1521 | + }, |
1522 | + "components" : { |
1523 | + "title" : "title" |
1524 | + } |
1525 | + } |
1526 | + )"; |
1527 | + |
1528 | + CategoryRenderer emptyCat(MESS_GRID); |
1529 | + auto messGrid = reply->register_category("emptyMess", _("Welcome"), "", emptyCat); |
1530 | + CategorisedResult res(messGrid); |
1531 | + res.set_uri("http://ubuntu.com"); |
1532 | + res["title"]=_("To start using this scope please install sources from the list below"); |
1533 | + reply->push(res); |
1534 | +} |
1535 | + |
1536 | +bool Query::hints_exists() |
1537 | +{ |
1538 | + auto scopes = registry_->list(); |
1539 | + us::MetadataMap::const_iterator scope; |
1540 | + scope = scopes.find(HINTS_SCOPE_ID); |
1541 | + if (scope != scopes.end()) { |
1542 | + auto meta = registry_->get_metadata(HINTS_SCOPE_ID); |
1543 | + hints_scope = meta.proxy(); |
1544 | + return true; |
1545 | + } |
1546 | + return false; |
1547 | +} |
1548 | + |
1549 | +void Query::display_local_hints_quickstart(us::SearchReplyProxy const& upstream_reply_) |
1550 | +{ |
1551 | + if (!local_hints) |
1552 | + return; |
1553 | + if (!hints_local_json.contains(QStringLiteral("content"))) |
1554 | + return; |
1555 | + auto content = hints_local_json[QStringLiteral("content")].toObject(); |
1556 | + if (!content.contains(QStringLiteral("categories"))) |
1557 | + return; |
1558 | + |
1559 | + QJsonArray cats = content[QStringLiteral("categories")].toArray(); |
1560 | + for (const auto & cat_ : cats) |
1561 | + { |
1562 | + auto cat = cat_.toObject(); |
1563 | + |
1564 | + std::string id = client.sstr(cat[QStringLiteral("id")].toString()); |
1565 | + std::string title = _(client.sstr(cat[QStringLiteral("_title")].toString()).c_str()); |
1566 | + QJsonDocument layout_d(cat[QStringLiteral("layout")].toObject()); |
1567 | + std::string local_hints_template = client.sstr(layout_d.toJson()); |
1568 | + auto category = upstream_reply_->lookup_category(id); |
1569 | + if (!category) { |
1570 | + category = upstream_reply_->register_category(id, title, "", us::CategoryRenderer(local_hints_template)); |
1571 | + } |
1572 | + QJsonArray items = cat[QStringLiteral("items")].toArray(); |
1573 | + for (const auto & res__ : items) |
1574 | + { |
1575 | + auto res_ = res__.toObject(); |
1576 | + us::CategorisedResult res(category); |
1577 | + res.set_title(_(client.sstr(res_[QStringLiteral("_title")].toString()).c_str())); |
1578 | + res["subtitle"] = _(client.sstr(res_[QStringLiteral("_subtitle")].toString()).c_str()); |
1579 | + res["description"] = _(client.sstr(res_[QStringLiteral("_description")].toString()).c_str()); |
1580 | + std::string uri = "http://www.ubuntu.com"; |
1581 | + if (res_.contains(QStringLiteral("hide_in_locales"))) |
1582 | + { |
1583 | + QStringList hide_in_locales = res_[QStringLiteral("hide_in_locales")].toString().split(","); |
1584 | + std::string lcRaw = setlocale(LC_ALL, ""); |
1585 | + std::string lc_lang = lcRaw.size() > 5 ? lcRaw.substr(0, 2) : ""; |
1586 | + std::string lc_country = lcRaw.size() > 5 ? lcRaw.substr(3, 2) : ""; |
1587 | + std::string lc = lc_lang + "_" + lc_country; |
1588 | + if (hide_in_locales.contains(client.qstr(lc))) |
1589 | + { |
1590 | + continue; |
1591 | + } |
1592 | + } |
1593 | + if (res_.contains("uri")) |
1594 | + { |
1595 | + uri = client.sstr(res_["uri"].toString()); |
1596 | + } |
1597 | + if (res_.contains(QStringLiteral("action"))) |
1598 | + { |
1599 | + auto action = res_[QStringLiteral("action")].toObject(); |
1600 | + VariantBuilder builder; |
1601 | + builder.add_tuple({ |
1602 | + {"id", Variant("Open")}, |
1603 | + {"label", Variant(_(client.sstr(action[QStringLiteral("_name")].toString()).c_str()))}, |
1604 | + {"uri", Variant(client.sstr(action[QStringLiteral("uri")].toString()))} |
1605 | + }); |
1606 | + res["actions"]=builder.end(); |
1607 | + if (action.contains(QStringLiteral("uri"))) |
1608 | + { |
1609 | + uri = client.sstr(action[QStringLiteral("uri")].toString()); |
1610 | + } |
1611 | + } |
1612 | + if (res_.contains(QStringLiteral("oaccount"))) |
1613 | + { |
1614 | + auto oaccount = res_[QStringLiteral("oaccount")].toObject(); |
1615 | + auto queryScope = client.sstr(oaccount[QStringLiteral("QueryScope")].toString()); |
1616 | + |
1617 | + // before framework 15.0.4.4 the service name is the FQ scope id and contains one "_" |
1618 | + // with 15.04.4, it is FQ scope id += _PROVIDER |
1619 | + // we also want the fully qualified scope id to check with registry if it is installed. |
1620 | + // to support both cases: |
1621 | + QStringList parts = oaccount[QStringLiteral("ServiceName")].toString().split("_"); |
1622 | + QString provider = oaccount[QStringLiteral("ProviderName")].toString(); |
1623 | + QString sc_id = parts[0] + "_" + parts[1]; |
1624 | + QString id = sc_id; |
1625 | + if (parts.size() > 2) // framework 15.04.4 or higher |
1626 | + { |
1627 | + id += "_" + provider; |
1628 | + } |
1629 | + us::OnlineAccountClient oa_client(client.sstr(id), |
1630 | + client.sstr(oaccount[QStringLiteral("ServiceType")].toString()), |
1631 | + client.sstr(provider)); |
1632 | + bool alreadyLoggedIn = false; |
1633 | + oa_client.refresh_service_statuses(); |
1634 | + for (auto const& status : oa_client.get_service_statuses()) |
1635 | + { |
1636 | + if (status.service_enabled) |
1637 | + { |
1638 | + alreadyLoggedIn = true; |
1639 | + break; |
1640 | + } |
1641 | + } |
1642 | + // do not display quick start help for scopes that are not registered in the system |
1643 | + auto reg_scopes = registry_->list(); |
1644 | + us::MetadataMap::const_iterator scope_it; |
1645 | + scope_it = reg_scopes.find(client.sstr(sc_id)); |
1646 | + if (scope_it == reg_scopes.end()) { |
1647 | + qWarning () << QString("%1: OA scope is NOT REGISTERED, skipping for HINTS: %2").arg(oaccount[QStringLiteral("ServiceName")].toString()); |
1648 | + continue; |
1649 | + } |
1650 | + if (alreadyLoggedIn) { |
1651 | + //the hints code does this when the person is already logged in to the service. |
1652 | + //auto tmp = oaccount["_loggedin"].toString().toStdString(); |
1653 | + //res["title"] = std::string(_(tmp.c_str())); |
1654 | + // |
1655 | + //this continue statement means if the person is logged in, we do not show |
1656 | + //a result for the item |
1657 | + continue; |
1658 | + } |
1659 | + us::CannedQuery query(queryScope); |
1660 | + oa_client.register_account_login_item(res, |
1661 | + query, |
1662 | + OnlineAccountClient::InvalidateResults, |
1663 | + OnlineAccountClient::DoNothing); |
1664 | + |
1665 | + } |
1666 | + if (res_.contains(QStringLiteral("hide_hints"))) |
1667 | + { |
1668 | + qDebug() << "=== NHINTS. utils. hide hints found in json"; |
1669 | + res["action"] = "hide_hints"; |
1670 | + res.set_intercept_activation(); |
1671 | + } |
1672 | + res.set_uri(uri); |
1673 | + res.set_art(scope_dir_ + "/images/" + client.sstr(res_["art"].toString())); |
1674 | + upstream_reply_->push(res); |
1675 | + } |
1676 | + } |
1677 | +} |
1678 | + |
1679 | +void Query::display_remote_hints_quickstart(us::SearchReplyProxy const& upstream_reply_) |
1680 | +{ |
1681 | + qDebug() << "==== HINTS in display_remote_hints_quickstart()"; |
1682 | + Category::SCPtr hint_cat; |
1683 | + SearchMetadata metadata(search_metadata()); |
1684 | + auto reply = std::make_shared<ResultForwarder>(upstream_reply_, |
1685 | + [this, &hint_cat](CategorisedResult& res) -> bool { |
1686 | + UNUSED(res) |
1687 | + return true; |
1688 | + }); |
1689 | + |
1690 | + subsearch(hints_scope, "", HINTS_THIS_SCOPE, FilterState(), |
1691 | + metadata, reply); |
1692 | +} |
1693 | + |
1694 | +bool Query::hints_hidden() { |
1695 | + |
1696 | + auto filepath1 = QString::fromStdString(cache_dir_) +"/" + hints_file; |
1697 | + auto filepath2 = QString::fromStdString(cache_dir_) +"/" + firstboot; |
1698 | + if (QFile::exists(filepath1) || QFile::exists(filepath2)) |
1699 | + return true; |
1700 | + return false; //don't show hints as fall back |
1701 | +} |
1702 | + |
1703 | +void Query::dismiss_hints_quickstart() { |
1704 | + qDebug() << "==== HINTS in dismiss()"; |
1705 | + auto filepath= QString::fromStdString(cache_dir_) +"/" + hints_file; |
1706 | + QFile file(filepath); |
1707 | + file.open(QIODevice::WriteOnly); |
1708 | + QString msg = QString("Timestamp for %1 %2").arg(client.qstr(HINTS_THIS_SCOPE), QDateTime::currentDateTime().toString()); |
1709 | + file.write(client.sstr(msg).c_str(), client.sstr(msg).size()); |
1710 | + file.close(); |
1711 | +} |
1712 | + |
1713 | +void Query::handle_keyword_child(unity::scopes::SearchReplyProxy const& upstream_reply, |
1714 | + std::shared_ptr<AggChildScope> scope, |
1715 | + us::CategorisedResult & res){ |
1716 | + |
1717 | + //the supported cases |
1718 | + enum RunType { |
1719 | + Search, |
1720 | + SearchNoLink, |
1721 | + SearchNoRdr, |
1722 | + SearchNoRdrNoLink, |
1723 | + Surface, |
1724 | + SurfaceNoLink, |
1725 | + SurfaceNoRdr, |
1726 | + SurfaceNoRdrNoLink |
1727 | + }; |
1728 | + RunType runType; |
1729 | + |
1730 | + std::string keyword = scope->keyword(); |
1731 | + std::string scope_id = scope->id(); |
1732 | + std::string cat_id = keyword + ":" + scope_id; |
1733 | + std::string cat_title = registry_->get_metadata(scope->id()).display_name(); |
1734 | + std::string search_rdr = scope->search_template(); |
1735 | + std::string rdr = scope->surface_template(); |
1736 | + bool link = scope->category_link_to_child(); |
1737 | + |
1738 | + qDebug() << "==== KW scope cat_id prefix: " << client.qstr(rdr); |
1739 | + qDebug() << "==== KW scope: " << client.qstr(scope->id()) << " keyword: " << client.qstr(keyword);; |
1740 | + qDebug() << "==== KW scope shared cat name: " << client.qstr(scope->keyword_scope_shared_cat_name()); |
1741 | + qDebug() << "==== KW scope search rdr: " << client.qstr(search_rdr); |
1742 | + qDebug() << "==== KW scope rdr: " << client.qstr(rdr); |
1743 | + qDebug() << "==== KW scope link: " << QString::number(link); |
1744 | + |
1745 | + // Determine the current case based on state |
1746 | + if (!query().query_string().empty()) |
1747 | + {//search |
1748 | + if (!search_rdr.empty()) |
1749 | + {//rdr |
1750 | + if (link) |
1751 | + {//link |
1752 | + runType = Search; |
1753 | + } |
1754 | + else |
1755 | + {//no link |
1756 | + runType = SearchNoLink; |
1757 | + } |
1758 | + } |
1759 | + else |
1760 | + {//no rdr |
1761 | + if (link) |
1762 | + {//link |
1763 | + runType = SearchNoRdr; |
1764 | + } |
1765 | + else |
1766 | + {//link |
1767 | + runType = SearchNoRdrNoLink; |
1768 | + } |
1769 | + } |
1770 | + } |
1771 | + else |
1772 | + {//surface |
1773 | + if (!rdr.empty()) |
1774 | + { |
1775 | + if (link) |
1776 | + { |
1777 | + runType = Surface; |
1778 | + } |
1779 | + else |
1780 | + { |
1781 | + runType = SurfaceNoLink; |
1782 | + } |
1783 | + } |
1784 | + else |
1785 | + { |
1786 | + if (link) |
1787 | + { |
1788 | + runType = SurfaceNoRdr; |
1789 | + } |
1790 | + else |
1791 | + { |
1792 | + runType = SurfaceNoRdrNoLink; |
1793 | + } |
1794 | + } |
1795 | + } |
1796 | + |
1797 | + switch (runType) |
1798 | + { |
1799 | + case RunType::Search: |
1800 | + qDebug() << "=== run type: keyword Search"; |
1801 | + cat_id += ":keyword:search:rdr:" + cat_title; |
1802 | + set_result_catgory(upstream_reply, res, cat_id, cat_title, search_rdr, scope_id); |
1803 | + break; |
1804 | + case RunType::SearchNoLink: |
1805 | + qDebug() << "=== run type: keyword SearchNoLink"; |
1806 | + cat_id += ":keyword:search:rdrnolink:" + cat_title; |
1807 | + set_result_catgory(upstream_reply, res, cat_id, cat_title, search_rdr); |
1808 | + break; |
1809 | + case RunType::SearchNoRdr: |
1810 | + qDebug() << "=== run type: keyword SearchNoRdr"; |
1811 | + cat_id = ":keyword:search:nordr:" + cat_title; |
1812 | + rdr = res.category()->renderer_template().data(); |
1813 | + set_result_catgory(upstream_reply, res, cat_id, cat_title, rdr, scope_id); |
1814 | + break; |
1815 | + case RunType::SearchNoRdrNoLink: |
1816 | + qDebug() << "=== run type: keyword SearchNoRdrNoLink"; |
1817 | + cat_id = ":keyword:search:nordr:nolink:" + cat_title; |
1818 | + rdr = res.category()->renderer_template().data(); |
1819 | + set_result_catgory(upstream_reply, res, cat_id, cat_title, rdr); |
1820 | + break; |
1821 | + case RunType::Surface: |
1822 | + qDebug() << "=== run type: keyword Surface"; |
1823 | + cat_id += ":keyword:surface:rdr:" + cat_title; |
1824 | + set_result_catgory(upstream_reply, res, cat_id, cat_title, rdr, scope_id); |
1825 | + break; |
1826 | + case RunType::SurfaceNoLink: |
1827 | + qDebug() << "=== run type: keyword SurfaceNoLink"; |
1828 | + cat_id += ":keyword:surface:rdr:noLink::" + cat_title; |
1829 | + set_result_catgory(upstream_reply, res, cat_id, cat_title, rdr); |
1830 | + break; |
1831 | + case RunType::SurfaceNoRdr: |
1832 | + qDebug() << "=== run type: keyword SurfaceNoRdr"; |
1833 | + cat_id += ":keyword:surface:nordr:" + cat_title; |
1834 | + rdr = res.category()->renderer_template().data(); |
1835 | + set_result_catgory(upstream_reply, res, cat_id, cat_title, rdr, scope_id); |
1836 | + break; |
1837 | + case RunType::SurfaceNoRdrNoLink: |
1838 | + qDebug() << "=== run type: keyword SurfaceNoRdrNoLink"; |
1839 | + cat_id += ":keyword:surface:nordr:nolink:" + cat_title; |
1840 | + rdr = res.category()->renderer_template().data(); |
1841 | + set_result_catgory(upstream_reply, res, cat_id, cat_title, rdr); |
1842 | + break; |
1843 | + } |
1844 | +} |
1845 | + |
1846 | +us::Category::SCPtr Query::set_result_catgory(us::SearchReplyProxy const& upstream_reply, us::CategorisedResult & res, std::string const& id, std::string const& title, std::string const& rdr, std::string const& link_to) |
1847 | +{ |
1848 | + qDebug() << "=== category type in set result with child link"; |
1849 | + qDebug() << QString("=== in set_result_category() with link. id: %1, title: %2, link_to: %3, rdr: %4").arg(client.qstr(id), client.qstr(title), client.qstr(link_to), client.qstr(rdr)); |
1850 | + |
1851 | + us::Category::SCPtr cat = upstream_reply->lookup_category(id); |
1852 | + if (cat == nullptr) |
1853 | + { |
1854 | + qDebug() << QString("=== in set_result_category() with link. lookup_category() returns nullptr, so register it"); |
1855 | + cat = upstream_reply->register_category |
1856 | + ( |
1857 | + id, |
1858 | + title, |
1859 | + "", |
1860 | + us::CannedQuery(link_to), |
1861 | + us::CategoryRenderer(rdr) |
1862 | + ); |
1863 | + } |
1864 | + res.set_category(cat); |
1865 | + qDebug() << "=== in set_result_category() with link. here's the res category json: " << client.qstr(Variant(res.category()->query()->serialize()).serialize_json()); |
1866 | + return cat; |
1867 | +} |
1868 | + |
1869 | +us::Category::SCPtr Query::set_result_catgory(us::SearchReplyProxy const& upstream_reply, us::CategorisedResult & res, std::string const& id, std::string const& title, std::string const& rdr) |
1870 | +{ |
1871 | + qDebug() << "=== category type in set result no link"; |
1872 | + qDebug() << QString("=== in set_result_category() no link. id: %1, title: %2, rdr: %3").arg(client.qstr(id), client.qstr(title), client.qstr(rdr) ); |
1873 | + |
1874 | + us::Category::SCPtr cat = upstream_reply->lookup_category(id); |
1875 | + if (cat == nullptr) |
1876 | + { |
1877 | + qDebug() << QString("=== in set_result_category() no link. lookup_category() returns nullptr, so register it"); |
1878 | + cat = upstream_reply->register_category |
1879 | + ( |
1880 | + id, |
1881 | + title, |
1882 | + "", |
1883 | + us::CategoryRenderer(rdr) |
1884 | + ); |
1885 | + } |
1886 | + res.set_category(cat); |
1887 | + return cat; |
1888 | +} |
1889 | + |
1890 | +void Query::handle_category_child(unity::scopes::SearchReplyProxy const& upstream_reply, |
1891 | + std::shared_ptr<AggChildScope> scope, |
1892 | + us::CategorisedResult & res){ |
1893 | + |
1894 | + enum RunType { |
1895 | + Search, |
1896 | + SearchNoRdr, |
1897 | + SearchNoLink, |
1898 | + SearchNoLinkNoRdr, |
1899 | + Login, |
1900 | + LoginNoLink, |
1901 | + SurfaceUsesFirstIsFirst, |
1902 | + SurfaceUsesFirstIsFirstNoLink, |
1903 | + SurfaceUsesFirstNotFirst, |
1904 | + SurfaceUsesFirstNotFirstNoLink, |
1905 | + Surface, |
1906 | + SurfaceNoRdr, |
1907 | + SurfaceNoLink, |
1908 | + SurfaceNoLinkNoRdr |
1909 | + }; |
1910 | + RunType runType; |
1911 | + |
1912 | + //get state |
1913 | + bool login_case = is_login_case(scope, res.category()->id()); |
1914 | + bool uses_first_result_rdr = categoryId_first_result_renderers.find(scope->category_id()) != categoryId_first_result_renderers.end(); |
1915 | + bool is_first_result = categoryId_isFirstResult[scope->category_id()]; |
1916 | + bool not_first_result = categoryId_isSecondResult[scope->category_id()]; |
1917 | + bool link = false; |
1918 | + bool has_rdr = !scope->surface_template().empty(); |
1919 | + std::string category_id = scope->category_id(); |
1920 | + std::string link_to = categoryId_linkToChildSpecified[category_id]; |
1921 | + //qDebug() << "link: scope->category_id " << client.qstr(scope->category_id()); |
1922 | + |
1923 | + for (auto i : categoryId_linkToChildSpecified) |
1924 | + { |
1925 | + if ( i.first == scope->category_id()) |
1926 | + { |
1927 | + if ( !i.second.empty() ) |
1928 | + { |
1929 | + link = true; |
1930 | + } |
1931 | + } |
1932 | + } |
1933 | + |
1934 | + // Determine the current case based on state |
1935 | + if (!query().query_string().empty()) |
1936 | + { |
1937 | + if (!scope->search_template().empty()) |
1938 | + { |
1939 | + if (link) |
1940 | + { |
1941 | + runType = Search; |
1942 | + } |
1943 | + else |
1944 | + { |
1945 | + runType = SearchNoLink; |
1946 | + } |
1947 | + } |
1948 | + else |
1949 | + { |
1950 | + if (link) |
1951 | + { |
1952 | + runType = SearchNoRdr; |
1953 | + } |
1954 | + else |
1955 | + { |
1956 | + runType = SearchNoLinkNoRdr; |
1957 | + } |
1958 | + } |
1959 | + } |
1960 | + else if (login_case) |
1961 | + { |
1962 | + if (link) |
1963 | + { |
1964 | + runType = Login; |
1965 | + } |
1966 | + else |
1967 | + { |
1968 | + runType = LoginNoLink; |
1969 | + } |
1970 | + } |
1971 | + else |
1972 | + {//surface |
1973 | + if (uses_first_result_rdr) |
1974 | + {//uses first |
1975 | + if (is_first_result) |
1976 | + {//is first |
1977 | + if (link) |
1978 | + { |
1979 | + runType = SurfaceUsesFirstIsFirst; |
1980 | + } |
1981 | + else |
1982 | + { |
1983 | + runType = SurfaceUsesFirstIsFirstNoLink; |
1984 | + } |
1985 | + } |
1986 | + else if (not_first_result) |
1987 | + {// not first |
1988 | + if (link) |
1989 | + { |
1990 | + runType = SurfaceUsesFirstNotFirst; |
1991 | + } |
1992 | + else |
1993 | + { |
1994 | + runType = SurfaceUsesFirstNotFirstNoLink; |
1995 | + } |
1996 | + } |
1997 | + } |
1998 | + else {//not uses first |
1999 | + if (link) |
2000 | + { |
2001 | + if (has_rdr) |
2002 | + { |
2003 | + runType = Surface; |
2004 | + } |
2005 | + else |
2006 | + { |
2007 | + runType = SurfaceNoRdr; |
2008 | + } |
2009 | + } |
2010 | + else |
2011 | + { // no link |
2012 | + if (has_rdr) |
2013 | + { |
2014 | + runType = SurfaceNoLink; |
2015 | + } |
2016 | + else |
2017 | + { |
2018 | + runType = SurfaceNoLinkNoRdr; |
2019 | + } |
2020 | + } |
2021 | + } |
2022 | + } |
2023 | + |
2024 | + qDebug() << "=== login: using login renderer: " << QString::number(scope->using_login_renderer()); |
2025 | + qDebug() << "=== login: res cat id: " << client.qstr(res.category()->id()); |
2026 | + qDebug() << "=== login: login_renderer_incoming_category_id: " << client.qstr(scope->login_renderer_incoming_category_id()); |
2027 | + |
2028 | + // for use in category registration |
2029 | + std::string cat_id; |
2030 | + std::string cat_title; |
2031 | + std::string rdr; |
2032 | + |
2033 | + if (!categoryId_titleMsgid[category_id].empty()) |
2034 | + cat_title = _(categoryId_titleMsgid[category_id].c_str()); |
2035 | + else |
2036 | + cat_title = ""; |
2037 | + |
2038 | + switch (runType) |
2039 | + { |
2040 | + case RunType::Search: |
2041 | + qDebug() << "=== run type: category Search"; |
2042 | + cat_id = scope->local_id() + ":category:search-renderer:searching:" + cat_title; |
2043 | + rdr = scope->search_template(); |
2044 | + set_result_catgory(upstream_reply, res, cat_id, cat_title, rdr, link_to); |
2045 | + break; |
2046 | + case RunType::SearchNoLink: |
2047 | + qDebug() << "=== run type: category SearchNoLink"; |
2048 | + cat_id = scope->local_id() + ":category:search-renderer:no-link:searching:" + cat_title; |
2049 | + rdr = scope->search_template(); |
2050 | + set_result_catgory(upstream_reply, res, cat_id, cat_title, rdr); |
2051 | + break; |
2052 | + case RunType::SearchNoRdr: |
2053 | + qDebug() << "=== run type: category SearchNoRdr"; |
2054 | + cat_id = scope->local_id() + ":category:no-renderer:searching:" + cat_title; |
2055 | + rdr = res.category()->renderer_template().data(); |
2056 | + set_result_catgory(upstream_reply, res, cat_id, cat_title, rdr, link_to); |
2057 | + case RunType::SearchNoLinkNoRdr: |
2058 | + qDebug() << "=== run type: category SearchNoLinkNoRdr"; |
2059 | + cat_id = scope->local_id() + ":category:no-renderer:no-link:searching:" + cat_title; |
2060 | + rdr = res.category()->renderer_template().data(); |
2061 | + set_result_catgory(upstream_reply, res, cat_id, cat_title, rdr); |
2062 | + case RunType::Login: |
2063 | + qDebug() << "=== run type: category Login"; |
2064 | + cat_id = scope->local_id() + ":category:login-renderer:" + cat_title; |
2065 | + rdr = scope->login_template(); |
2066 | + set_result_catgory(upstream_reply, res, cat_id, cat_title, rdr, link_to); |
2067 | + break; |
2068 | + case RunType::LoginNoLink: |
2069 | + qDebug() << "=== run type: category LoginNoLink"; |
2070 | + cat_id = scope->local_id() + ":category:login-renderer:no-link" + cat_title; |
2071 | + rdr = scope->login_template(); |
2072 | + set_result_catgory(upstream_reply, res, cat_id, cat_title, rdr); |
2073 | + break; |
2074 | + case RunType::SurfaceUsesFirstIsFirst: |
2075 | + qDebug() << "=== run type: category SurfaceUsesFirstIsFirst"; |
2076 | + if ((first_result_owner.empty()) || (first_result_owner == category_id)) |
2077 | + { |
2078 | + qDebug() << "==== CATREG. uses FIRST result. FIRST result. NO LINK to child "; |
2079 | + first_result_owner = category_id; |
2080 | + cat_id = category_id + ":category:uses-first-result:is-first:surfacing"; |
2081 | + rdr = categoryId_first_result_renderers[category_id]; |
2082 | + categoryId_isFirstResult[category_id] = false; |
2083 | + categoryId_isSecondResult[category_id] = true; |
2084 | + catname_catptr[category_id] = set_result_catgory(upstream_reply, res, cat_id, cat_title, rdr, link_to); |
2085 | + scope->set_category(catname_catptr[category_id]); |
2086 | + } |
2087 | + break; |
2088 | + case RunType::SurfaceUsesFirstIsFirstNoLink: |
2089 | + qDebug() << "=== run type: category SurfaceUsesFirstIsFirstNoLink"; |
2090 | + if ((first_result_owner.empty()) || (first_result_owner == category_id)) |
2091 | + { |
2092 | + qDebug() << "==== CATREG. uses FIRST result. FIRST result. NO LINK to child "; |
2093 | + first_result_owner = category_id; |
2094 | + cat_id = category_id + ":category:uses-first-result:is-first:no-link:surfacing"; |
2095 | + rdr = categoryId_first_result_renderers[category_id]; |
2096 | + categoryId_isFirstResult[category_id] = false; |
2097 | + categoryId_isSecondResult[category_id] = true; |
2098 | + catname_catptr[category_id] = set_result_catgory(upstream_reply, res, cat_id, cat_title, rdr); |
2099 | + scope->set_category(catname_catptr[category_id]); |
2100 | + } |
2101 | + break; |
2102 | + case RunType::SurfaceUsesFirstNotFirst: |
2103 | + qDebug() << "=== run type: cateogry SurfaceUsesFirstNotFirst"; |
2104 | + cat_id = category_id + ":category:uses-first-result:not-first:surfacing:" + cat_title; |
2105 | + rdr = scope->surface_template(); |
2106 | + catname_catptr[category_id] = set_result_catgory(upstream_reply, res, cat_id, cat_title, rdr, link_to); |
2107 | + scope->set_category(catname_catptr[category_id]); |
2108 | + break; |
2109 | + case RunType::SurfaceUsesFirstNotFirstNoLink: |
2110 | + qDebug() << "=== run type: category SurfaceUsesFirstNotFirstNoLink"; |
2111 | + cat_id = category_id + ":category:uses-first-result:not-first:no-rdr:no-linksurfacing:" + cat_title; |
2112 | + rdr = scope->surface_template(); |
2113 | + catname_catptr[category_id] = set_result_catgory(upstream_reply, res, cat_id, cat_title, rdr); |
2114 | + scope->set_category(catname_catptr[category_id]); |
2115 | + break; |
2116 | + case RunType::Surface: |
2117 | + qDebug() << "=== run type: category Surface"; |
2118 | + cat_id = category_id + ":category:surface-rdr:surfacing:" + cat_title; |
2119 | + rdr = scope->surface_template(); |
2120 | + set_result_catgory(upstream_reply, res, cat_id, cat_title, rdr, link_to); |
2121 | + break; |
2122 | + case RunType::SurfaceNoRdr: |
2123 | + qDebug() << "=== run type: category SurfaceNoRdr"; |
2124 | + cat_id = category_id + ":category:no-rdr::surfacing:" + cat_title; |
2125 | + rdr = res.category()->renderer_template().data(); |
2126 | + set_result_catgory(upstream_reply, res, cat_id, cat_title, rdr, link_to); |
2127 | + break; |
2128 | + case RunType::SurfaceNoLink: |
2129 | + qDebug() << "=== run type: category SurfaceNoLink"; |
2130 | + cat_id = category_id + ":category:surface-rdr:no-link:surfacing:" + cat_title; |
2131 | + rdr = scope->surface_template(); |
2132 | + set_result_catgory(upstream_reply, res, cat_id, cat_title, rdr); |
2133 | + //qDebug() << "CQ json: " << client.qstr(Variant(catname_catptr[category_id]->query()->serialize()).serialize_json()); |
2134 | + break; |
2135 | + case RunType::SurfaceNoLinkNoRdr: |
2136 | + qDebug() << "=== run type: category SurfaceNoLinkNoRdr"; |
2137 | + cat_id = category_id + ":category:no-rdr:surfacing:" + cat_title; |
2138 | + rdr = res.category()->renderer_template().data(); |
2139 | + set_result_catgory(upstream_reply, res, cat_id, cat_title, rdr); |
2140 | + //qDebug() << "CQ json: " << client.qstr(Variant(upstream_reply->lookup_category(cat_id)->query()->serialize()).serialize_json()); |
2141 | + break; |
2142 | + } |
2143 | + |
2144 | + //TODO: put FALLBACK into method to avoid duplication needed by refactor |
2145 | + // perform res component fallback, as needed |
2146 | + if(!scope->surface_common_template_id().empty()) |
2147 | + { |
2148 | + std::string res_str = us::Variant(res.serialize()).serialize_json(); |
2149 | + auto change = this->client.check_result_fallbacks(res_str, |
2150 | + scope->surface_common_template_id(), |
2151 | + this->get_common_templates_fallbacks()); |
2152 | + if (!std::get<0>(change).empty()) |
2153 | + { |
2154 | + res[std::get<0>(change)] = std::get<1>(change); |
2155 | + } |
2156 | + } |
2157 | +} |
2158 | + |
2159 | +void Query::handle_declared_child(unity::scopes::SearchReplyProxy const& upstream_reply, |
2160 | + std::shared_ptr<AggChildScope> scope, |
2161 | + us::CategorisedResult & res, |
2162 | + std::string const& inc_res_cat_id, |
2163 | + std::string const& inc_res_cat_title) { |
2164 | + |
2165 | + //the supported cases |
2166 | + enum RunType { |
2167 | + Search, |
2168 | + SearchNoRdr, |
2169 | + SearchNoLink, |
2170 | + SearchNoLinkNoRdr, |
2171 | + Login, |
2172 | + LoginNoLink, |
2173 | + Surface, |
2174 | + SurfaceNoRdr, |
2175 | + SurfaceNoLink, |
2176 | + SurfaceNoLinkNoRdr |
2177 | + }; |
2178 | + RunType runType; |
2179 | + |
2180 | + //get state |
2181 | + bool login_case = is_login_case(scope, res.category()->id()); |
2182 | + qDebug() << "==== DECLARED. login_case: " << QString::number(login_case); |
2183 | + bool link = scope->category_link_to_child();//this means the category links, not that we get a specific child scope's category |
2184 | + std:: string link_to = scope->id(); |
2185 | + bool has_rdr = !scope->surface_template().empty(); |
2186 | + |
2187 | + // Determine the current case based on state |
2188 | + if (!query().query_string().empty()) |
2189 | + { |
2190 | + if (!scope->search_template().empty()) |
2191 | + { |
2192 | + if (link) |
2193 | + { |
2194 | + runType = Search; |
2195 | + } |
2196 | + else |
2197 | + { |
2198 | + runType = SearchNoLink; |
2199 | + } |
2200 | + } |
2201 | + else |
2202 | + { |
2203 | + if (link) |
2204 | + { |
2205 | + runType = SearchNoRdr; |
2206 | + } |
2207 | + else |
2208 | + { |
2209 | + runType = SearchNoLinkNoRdr; |
2210 | + } |
2211 | + } |
2212 | + } |
2213 | + else if (login_case) |
2214 | + { |
2215 | + if (link) |
2216 | + { |
2217 | + runType = Login; |
2218 | + } |
2219 | + else |
2220 | + { |
2221 | + runType = LoginNoLink; |
2222 | + } |
2223 | + } |
2224 | + else |
2225 | + {//surface |
2226 | + if (link) |
2227 | + { |
2228 | + if (has_rdr) |
2229 | + { |
2230 | + runType = Surface; |
2231 | + } |
2232 | + else |
2233 | + { |
2234 | + runType = SurfaceNoRdr; |
2235 | + } |
2236 | + } |
2237 | + else |
2238 | + { // no link |
2239 | + if (has_rdr) |
2240 | + { |
2241 | + runType = SurfaceNoLink; |
2242 | + } |
2243 | + else |
2244 | + { |
2245 | + runType = SurfaceNoLinkNoRdr; |
2246 | + } |
2247 | + } |
2248 | + } |
2249 | + |
2250 | + // for use in category registration |
2251 | + std::string cat_id; |
2252 | + std::string cat_title; |
2253 | + std::string rdr; |
2254 | + |
2255 | + qDebug() << "==== DECLARED. scope is declared: " << client.qstr(scope->local_id()); |
2256 | + |
2257 | + // set the category tiile |
2258 | + if (scope->using_category_title_incoming() ) |
2259 | + { |
2260 | + scope->set_category_title(inc_res_cat_title); |
2261 | + } |
2262 | + else if (scope->using_category_title_display_name() ) |
2263 | + { |
2264 | + scope->set_category_title(scope->metadata()->display_name()); |
2265 | + } |
2266 | + |
2267 | + cat_title = scope->category_title(); |
2268 | + |
2269 | + switch (runType) |
2270 | + { |
2271 | + case RunType::Login: |
2272 | + qDebug() << "=== run type: declared scope Login"; |
2273 | + cat_id = scope->local_id() + ":declared:login"; |
2274 | + rdr = scope->login_template(); |
2275 | + set_result_catgory(upstream_reply, res, cat_id, cat_title, rdr, link_to); |
2276 | + break; |
2277 | + case RunType::LoginNoLink: |
2278 | + qDebug() << "=== run type: declared scope LoginNoLink"; |
2279 | + cat_id = scope->local_id() + ":declared:login:no-link"; |
2280 | + rdr = scope->login_template(); |
2281 | + set_result_catgory(upstream_reply, res, cat_id, cat_title, rdr); |
2282 | + break; |
2283 | + case RunType::Search: |
2284 | + qDebug() << "=== run type: declared scope Search"; |
2285 | + cat_id = scope->local_id() + ":declared:search"; |
2286 | + rdr = scope->search_template(); |
2287 | + set_result_catgory(upstream_reply, res, cat_id, cat_title, rdr, link_to); |
2288 | + break; |
2289 | + case RunType::SearchNoRdr: |
2290 | + qDebug() << "=== run type: declared scope SearchNoRdr"; |
2291 | + cat_id = scope->local_id() + ":declared:no-rdr:search"; |
2292 | + rdr = res.category()->renderer_template().data(); |
2293 | + set_result_catgory(upstream_reply, res, cat_id, cat_title, rdr, link_to); |
2294 | + break; |
2295 | + case RunType::SearchNoLink: |
2296 | + qDebug() << "=== run type: declared scope Search"; |
2297 | + cat_id = scope->local_id() + ":declared:no-link:search"; |
2298 | + rdr = scope->search_template(); |
2299 | + set_result_catgory(upstream_reply, res, cat_id, cat_title, rdr); |
2300 | + break; |
2301 | + case RunType::SearchNoLinkNoRdr: |
2302 | + qDebug() << "=== run type: declared scope SearchNoRdr"; |
2303 | + cat_id = scope->local_id() + ":declared:no_rdr:no-link:search"; |
2304 | + rdr = res.category()->renderer_template().data(); |
2305 | + set_result_catgory(upstream_reply, res, cat_id, cat_title, rdr); |
2306 | + break; |
2307 | + case RunType::Surface: |
2308 | + qDebug() << "=== run type: declared scope Surface"; |
2309 | + cat_id = scope->local_id() + ":declared:rdr:surface"; |
2310 | + rdr = scope->surface_template(); |
2311 | + set_result_catgory(upstream_reply, res, cat_id, cat_title, rdr, link_to); |
2312 | + break; |
2313 | + case RunType::SurfaceNoRdr: |
2314 | + qDebug() << "=== run type: declared scope SurfaceNoRdr"; |
2315 | + cat_id = scope->local_id() + ":declared:no-rdr:surface"; |
2316 | + rdr = res.category()->renderer_template().data(); |
2317 | + set_result_catgory(upstream_reply, res, cat_id, cat_title, rdr, link_to); |
2318 | + break; |
2319 | + case RunType::SurfaceNoLink: |
2320 | + qDebug() << "=== run type: declared scope SurfaceNoLink"; |
2321 | + cat_id = scope->local_id() + ":declared:rdr:no-link:surface"; |
2322 | + rdr = scope->surface_template(); |
2323 | + set_result_catgory(upstream_reply, res, cat_id, cat_title, rdr); |
2324 | + break; |
2325 | + case RunType::SurfaceNoLinkNoRdr: |
2326 | + qDebug() << "=== run type: declared scope SurfaceNoLinkNoRdr"; |
2327 | + cat_id = scope->local_id() + ":declared:link:no-link:no-rdr:surface"; |
2328 | + rdr = res.category()->renderer_template().data(); |
2329 | + set_result_catgory(upstream_reply, res, cat_id, cat_title, rdr); |
2330 | + break; |
2331 | + } |
2332 | + |
2333 | + //TODO: put FALLBACK into method to avoid duplication needed by refactor |
2334 | + // perform res component fallback, as needed |
2335 | + if(!scope->surface_common_template_id().empty()) |
2336 | + { |
2337 | + std::string res_str = us::Variant(res.serialize()).serialize_json(); |
2338 | + auto change = this->client.check_result_fallbacks(res_str, |
2339 | + scope->surface_common_template_id(), |
2340 | + this->get_common_templates_fallbacks()); |
2341 | + if (!std::get<0>(change).empty()) |
2342 | + { |
2343 | + res[std::get<0>(change)] = std::get<1>(change); |
2344 | + } |
2345 | + } |
2346 | + |
2347 | + //for child scopes that declare attribute swaps, do them |
2348 | + for (std::shared_ptr<std::pair<std::string,std::string>> swap : this->child_scopes_m[scope->local_id()]->swap_result_attributes) |
2349 | + { |
2350 | + try |
2351 | + { |
2352 | + if (!res[swap->first].get_string().empty()) |
2353 | + { |
2354 | + res[swap->second] = res[swap->first]; |
2355 | + } |
2356 | + } |
2357 | + catch (unity::LogicException) |
2358 | + { |
2359 | + qWarning() << QString("Scope %1 swap: result does not contain attribute 2").arg(client.qstr(scope->local_id()), client.qstr(swap->second)); |
2360 | + } |
2361 | + } |
2362 | + |
2363 | + //TODO: deprecate child category as brittle. should use keywords instead. |
2364 | + // if child_category set, filter out other child categories by adding "dont_use" key to result |
2365 | + // also impose max category results if set |
2366 | + if (!scope->child_category().empty()) |
2367 | + { |
2368 | + if (client.qstr(inc_res_cat_id) != client.qstr(scope->child_category())) |
2369 | + { |
2370 | + res["dont_use"] = "true"; |
2371 | + } |
2372 | + else if (scope->using_child_category_max_results()) |
2373 | + { |
2374 | + scope->inc_result_idx(); // allows constraining num results to child_category_max_results declaration |
2375 | + if (scope->result_idx() > scope->child_category_max_results() ) |
2376 | + { |
2377 | + res["dont_use"] = "true"; |
2378 | + } |
2379 | + } |
2380 | + } |
2381 | + |
2382 | +} |
2383 | |
2384 | === modified file 'src/query.cpp' |
2385 | --- src/query.cpp 2016-08-19 20:23:21 +0000 |
2386 | +++ src/query.cpp 2016-09-30 19:17:35 +0000 |
2387 | @@ -312,8 +312,8 @@ |
2388 | // create child scope instances from keywords and scopes |
2389 | make_categories(); |
2390 | |
2391 | - // complete initializations inlcuding cutting child scopes to those present and enabled |
2392 | - handle_current_child_scopes(empty_search, upstream_reply); |
2393 | + // complete initializations including cutting child scopes to those present and enabled |
2394 | + complete_child_scopes(); |
2395 | |
2396 | // convert current_scopes into scope_order based on declared order |
2397 | set_scope_order(); |
2398 | @@ -546,11 +546,6 @@ |
2399 | |
2400 | qDebug() << "==== RESULT scope: " << client.qstr(scope->id()); |
2401 | |
2402 | - // for use in category registration |
2403 | - std::string cat_id; |
2404 | - std::string cat_title; |
2405 | - std::string rdr; |
2406 | - |
2407 | if (scope->keyword_scope()) |
2408 | { |
2409 | handle_keyword_child(upstream_reply, scope, res); |
2410 | @@ -670,7 +665,6 @@ |
2411 | { |
2412 | for (auto ch : current_child_scopes) |
2413 | { |
2414 | - |
2415 | if (ch.id == localId_id_m[locID]) |
2416 | { |
2417 | qDebug() << "=== subsearch non KEYWORD scope local_ id " << client.qstr(scope->local_id()); |
2418 | @@ -692,7 +686,6 @@ |
2419 | adj_qry = localId_defaultQryStr[locID]; |
2420 | else |
2421 | adj_qry = ""; |
2422 | - |
2423 | subsearch |
2424 | ( |
2425 | ch, |
2426 | |
2427 | === modified file 'src/utils.cpp' |
2428 | --- src/utils.cpp 2016-08-19 20:46:32 +0000 |
2429 | +++ src/utils.cpp 2016-09-30 19:17:35 +0000 |
2430 | @@ -155,6 +155,7 @@ |
2431 | |
2432 | if (cat_o.contains(QStringLiteral("link_to_child_specified"))) |
2433 | { |
2434 | + qDebug() << "=== CAT UTILs. id: link_to_child_specified FOUND for category: " << client.qstr(cat_ptr->id); |
2435 | categoryId_linkToChildSpecified[cat_ptr->id] = cat_o[QStringLiteral("link_to_child_specified")].toString().toStdString(); |
2436 | } |
2437 | int card = client.get_cardinality_setting(settings(), setting_cardinalities); |
2438 | @@ -221,7 +222,20 @@ |
2439 | QJsonDocument st_d(renderer_o); |
2440 | cat_ptr->search_renderer = client.sstr(st_d.toJson()); |
2441 | } |
2442 | - |
2443 | + if (cat_o.contains(QStringLiteral("login_renderer"))) |
2444 | + { |
2445 | + qDebug() << "==== UTILs. load. CATRES. login_renderer"; |
2446 | + QJsonObject renderer_o = cat_o[QStringLiteral("login_renderer")].toObject(); |
2447 | + QJsonDocument st_d(renderer_o); |
2448 | + cat_ptr->login_renderer = client.sstr(st_d.toJson()); |
2449 | + if (cat_o.contains(QStringLiteral("login_renderer_incoming_category_id"))) |
2450 | + { |
2451 | + qDebug() << "==== UTILs. load. CATRES. login_renderer_incoming_category_id"; |
2452 | + cat_ptr->login_renderer_incoming_category_id = cat_o[QStringLiteral("login_renderer_incoming_category_id")].toString().toStdString(); |
2453 | + } |
2454 | + } |
2455 | + qDebug() << "==== UTILs. load. CATRES. login_renderer: " << client.qstr(cat_ptr->login_renderer); |
2456 | + qDebug() << "==== UTILs. load. CATRES. login_renderer_incoming_category_id: " << client.qstr(cat_ptr->login_renderer_incoming_category_id); |
2457 | if (cat_o.contains(QStringLiteral("scopes"))) |
2458 | { |
2459 | QJsonArray scope_a = cat_o[QStringLiteral("scopes")].toArray(); |
2460 | @@ -298,6 +312,17 @@ |
2461 | if (scope_o.contains(QStringLiteral("department"))) |
2462 | cs->department = scope_o[QStringLiteral("department")].toString().toStdString(); |
2463 | |
2464 | + if (scope_o.contains(QStringLiteral("login_renderer"))) |
2465 | + { |
2466 | + QJsonObject renderer_o = scope_o[QStringLiteral("login_renderer")].toObject(); |
2467 | + QJsonDocument st_d(renderer_o); |
2468 | + cs->login_renderer = client.sstr(st_d.toJson()); |
2469 | + if (scope_o.contains(QStringLiteral("login_renderer_incoming_category_id"))) |
2470 | + { |
2471 | + cs->login_renderer_incoming_category_id = scope_o[QStringLiteral("login_renderer_incoming_category_id")].toString().toStdString(); |
2472 | + } |
2473 | + } |
2474 | + |
2475 | cs->link_to_child = true; |
2476 | if (scope_o.contains(QStringLiteral("link_to_child"))) |
2477 | { |
2478 | @@ -532,85 +557,32 @@ |
2479 | else if (dept_id_of_root_keywords_only.empty()) |
2480 | dept_id_of_root_keywords_only = keyword_id; |
2481 | } |
2482 | - std::string category; |
2483 | - if (keyword_o.contains(QStringLiteral("shared_category"))) |
2484 | - { |
2485 | - category = keyword_id; // note category is synomous with keyword and is therefore used even when not shared category |
2486 | - //note: removed support for shared_category value other than "true" |
2487 | - if (keyword_o[QStringLiteral("shared_category")] == TRUE) |
2488 | - { |
2489 | - std::string title_msgid = keyword_o[QStringLiteral("_shared_category_title")].toString().toStdString(); |
2490 | - shared_keyword_cat_titlemsgid[category] = title_msgid; |
2491 | - shared_keyword_cats[keyword_id] = category; |
2492 | - shared_keywords.emplace_back(keyword_id); |
2493 | - } |
2494 | - } |
2495 | - //we do not support first result with non shared category keyword scopes |
2496 | - if (category == keyword_id && keyword_o.contains(QStringLiteral("first_result_renderer_common_id"))) |
2497 | - { |
2498 | - std::string id = keyword_o[QStringLiteral("first_result_renderer_common_id")].toString().toStdString(); |
2499 | - keyword_catname_first_result_renderers[category] = common_templates[id]; |
2500 | - } |
2501 | - else if (category == keyword_id && keyword_o.contains(QStringLiteral("first_result_renderer"))) |
2502 | - { |
2503 | - QJsonObject template_o = keyword_o[QStringLiteral("first_result_renderer")].toObject(); |
2504 | - QJsonDocument t_d(template_o); |
2505 | - keyword_catname_first_result_renderers[category] = client.sstr(t_d.toJson()); |
2506 | - } |
2507 | - else if (category == keyword_id && keyword_o.contains(QStringLiteral("first_result_template"))) |
2508 | - { |
2509 | - //support deprecated for backwards compatibiliity |
2510 | - qWarning () << QString("%1: DEPRECATED use of 'first_result_template'. Switch to 'first_result_renderer'") |
2511 | - .arg(client.qstr(agg_scope_->scope_id())); |
2512 | - QJsonObject template_o = keyword_o[QStringLiteral("first_result_template")].toObject(); |
2513 | - QJsonDocument t_d(template_o); |
2514 | - keyword_catname_first_result_renderers[category] = client.sstr(t_d.toJson()); |
2515 | - } |
2516 | - //NOTE: README.md does not mention "category" renders. they exist for backwards compatibility. |
2517 | - //It says render declaration |
2518 | - //is the same as with a declared scope, which means "renderer_common_id", "renderer", |
2519 | - //"first_result_renderer_common_id", "first_result_renderer", "search_renderer_common_id", |
2520 | - //and "search_renderer" |
2521 | if (keyword_o.contains(QStringLiteral("renderer_common_id"))) |
2522 | { |
2523 | - qDebug() << "==== UTILs. load. KW CAT. renderer_common_id. keyword&category: " << client.qstr(category);; |
2524 | + qDebug() << "==== UTILs. load. KW CAT. renderer_common_id. keyword&category: " << client.qstr(keyword_id); |
2525 | std::string id = keyword_o[QStringLiteral("renderer_common_id")].toString().toStdString(); |
2526 | - keyword_catname_renderer[category] = common_templates[id]; |
2527 | + keyword_catname_renderer[keyword_id] = common_templates[id]; |
2528 | |
2529 | - qDebug() << "==== UTILs. load. KW CAT. renderer_common_id: "<< client.qstr(keyword_catname_renderer[category]).replace("\n", " "); |
2530 | + qDebug() << "==== UTILs. load. KW CAT. renderer_common_id: "<< client.qstr(keyword_catname_renderer[keyword_id]).replace("\n", " "); |
2531 | } |
2532 | else if (keyword_o.contains(QStringLiteral("renderer"))) |
2533 | { |
2534 | qDebug() << "==== UTILs. load. KW CAT. renderer"; |
2535 | QJsonObject renderer_o = keyword_o[QStringLiteral("renderer")].toObject(); |
2536 | QJsonDocument rdr_d(renderer_o); |
2537 | - keyword_catname_renderer[category] = client.sstr(rdr_d.toJson()); |
2538 | - |
2539 | - qDebug() << "==== UTILs. load. KW CAT. renderer:" << client.qstr(keyword_catname_renderer[category]).replace("\n", " "); |
2540 | - } |
2541 | - else if (keyword_o.contains(QStringLiteral("category_renderer_common_id"))) |
2542 | - { |
2543 | - qDebug() << "==== UTILs. load. KW SHARED CAT. category_renderer_common_id"; |
2544 | - std::string id = keyword_o[QStringLiteral("category_renderer_common_id")].toString().toStdString(); |
2545 | - keyword_catname_renderer[category] = common_templates[id]; |
2546 | - } |
2547 | - else if (keyword_o.contains(QStringLiteral("category_renderer"))) |
2548 | - { |
2549 | - qDebug() << "==== UTILs. load. KW CAT. category_renderer"; |
2550 | - QJsonObject renderer_o = keyword_o[QStringLiteral("category_renderer")].toObject(); |
2551 | - QJsonDocument rdr_d(renderer_o); |
2552 | - keyword_catname_renderer[category] = client.sstr(rdr_d.toJson()); |
2553 | + keyword_catname_renderer[keyword_id] = client.sstr(rdr_d.toJson()); |
2554 | + qDebug() << "==== UTILs. load. KW CAT. renderer:" << client.qstr(keyword_catname_renderer[keyword_id]).replace("\n", " "); |
2555 | } |
2556 | if (keyword_o.contains(QStringLiteral("search_renderer_common_id"))) |
2557 | { |
2558 | std::string id = keyword_o[QStringLiteral("search_renderer_common_id")].toString().toStdString(); |
2559 | - keyword_catname_search_renderer[category] = common_templates[id]; |
2560 | + keyword_catname_search_renderer[keyword_id] = common_templates[id]; |
2561 | } |
2562 | else if (keyword_o.contains(QStringLiteral("search_renderer"))) |
2563 | { |
2564 | QJsonObject renderer_o = keyword_o[QStringLiteral("search_renderer")].toObject(); |
2565 | QJsonDocument rdr_d(renderer_o); |
2566 | - keyword_catname_search_renderer[category] = client.sstr(rdr_d.toJson()); |
2567 | + keyword_catname_search_renderer[keyword_id] = client.sstr(rdr_d.toJson()); |
2568 | } |
2569 | if (keyword_o.contains(QStringLiteral("link_to_child")) |
2570 | && keyword_o[QStringLiteral("link_to_child")].toString() == TRUE) { |
2571 | @@ -643,8 +615,6 @@ |
2572 | id_keyword_map[keyword_id] = keyword_; |
2573 | } |
2574 | } |
2575 | - //for (auto str : declared_order) |
2576 | - // qDebug() << "==== ORDER. declared scope: " << client.qstr(str); |
2577 | } |
2578 | |
2579 | void Query::set_scope_order() |
2580 | @@ -800,6 +770,15 @@ |
2581 | ch_ptr->set_override_search_template(false); |
2582 | } |
2583 | |
2584 | + if (!child->login_renderer_incoming_category_id.empty() && |
2585 | + !child->login_renderer.empty()) |
2586 | + { |
2587 | + qDebug() << "==== SCOPE LOGIN"; |
2588 | + ch_ptr->enable_using_login_renderer(); |
2589 | + ch_ptr->set_login_template(child->login_renderer); |
2590 | + ch_ptr->set_login_renderer_incoming_category_id(child->login_renderer_incoming_category_id); |
2591 | + } |
2592 | + |
2593 | ch_ptr->set_only_in_search(child->only_in_search); |
2594 | |
2595 | ch_ptr->set_source_finder(child->source_finder); |
2596 | @@ -810,6 +789,10 @@ |
2597 | } |
2598 | } |
2599 | |
2600 | +bool Query::is_using_departments(){ |
2601 | + return using_departments; |
2602 | +} |
2603 | + |
2604 | void Query::create_departments(us::SearchReplyProxy const &reply_) |
2605 | { |
2606 | if (!using_departments) |
2607 | @@ -856,7 +839,6 @@ |
2608 | if (!keyword_child.enabled) |
2609 | continue; |
2610 | auto keych_ptr = std::make_shared<AggChildScope>(keyword_child.id); |
2611 | - QString time_str = QDateTime::currentDateTimeUtc().toString(); |
2612 | keych_ptr->set_keyword_scope(true); |
2613 | auto dept_ptr = std::make_shared<dept>(); |
2614 | dept_ptr->id = keyword_child.id; |
2615 | @@ -890,14 +872,22 @@ |
2616 | keych_ptr->set_department(kw); |
2617 | keych_ptr->set_keyword(kw); |
2618 | keych_ptr->set_category_link_to_child(id_keyword_map[kw]->link_to_child); |
2619 | + qDebug() << "===_ UTILs. KW. link to child: " << QString::number(keych_ptr->category_link_to_child()); |
2620 | + //get rdr if any |
2621 | if (!keyword_catname_renderer[kw].empty()) |
2622 | { |
2623 | - qDebug()<< "==== UTILs. adding renderer to: " << client.qstr(keyword_child.id); |
2624 | + qDebug()<< "==== UTILs. KW adding renderer to: " << client.qstr(keyword_child.id); |
2625 | keych_ptr->set_surface_template(keyword_catname_renderer[kw]);// this is overwritten below for shared cat scopes |
2626 | } |
2627 | else |
2628 | { |
2629 | - qDebug()<< "==== UTILs. renderer not declared: " << client.qstr(keyword_child.id); |
2630 | + qDebug()<< "==== UTILs. KW renderer not declared: " << client.qstr(keyword_child.id); |
2631 | + } |
2632 | + //get search rdr if any |
2633 | + if (!keyword_catname_search_renderer[kw].empty()) |
2634 | + { |
2635 | + qDebug()<< "==== UTILs. KW adding searchrenderer to: " << client.qstr(keyword_child.id); |
2636 | + keych_ptr->set_search_template(keyword_catname_search_renderer[kw]);// this is overwritten below for shared cat scopes |
2637 | } |
2638 | |
2639 | bool a_dup = false; |
2640 | @@ -946,7 +936,6 @@ |
2641 | depts[kw] = dept_ptr; |
2642 | } |
2643 | } |
2644 | - |
2645 | auto iter = find(shared_keywords.begin(), shared_keywords.end(), kw); |
2646 | if (iter != shared_keywords.end()) |
2647 | { |
2648 | @@ -954,18 +943,11 @@ |
2649 | qDebug() << QString("==== UTILs. set ky scope kw %1 as a a shared cat in kw: %2").arg(client.qstr(keych_ptr->id()), client.qstr(kw)); |
2650 | keych_ptr->set_keyword_scope_shared_cat_name(shared_keyword_cats[kw]); |
2651 | |
2652 | - //initially the category is set to false meaning there have been |
2653 | - //no results yet for it and it has not yet been registered |
2654 | - sharedcat_catregistered[shared_keyword_cats[kw]] = false; |
2655 | - // set more default values |
2656 | - keywordSharedCat_isFirstResult[kw] = true; |
2657 | qDebug() << "===== UTILs. kw: " << client.qstr(kw); |
2658 | qDebug() << "===== UTILs. keywordSharedCat_isFirstResult[kw] " << keywordSharedCat_isFirstResult[kw]; |
2659 | keywordSharedCat_isSecondResult[kw] = false; |
2660 | qDebug() << "===== UTILs. kw shared surface: " << client.qstr(keyword_catname_renderer[kw]).replace("\n"," "); |
2661 | keych_ptr->set_surface_template(keyword_catname_renderer[kw]); |
2662 | -// if (keyword_catname_first_result_renderers[kw].empty()) |
2663 | -// keych.set_first_resulte_template(keyword_catname_first_result_renderer[kw]); |
2664 | } |
2665 | found = true; |
2666 | //this break ensures the scope is associated with *first* decared keyword, thus |
2667 | @@ -1002,6 +984,19 @@ |
2668 | auto scope_ptr = std::make_shared<AggChildScope>(ids.first); |
2669 | scope_ptr->set_category_scope(true); |
2670 | scope_ptr->set_category_id(cat->id); |
2671 | + |
2672 | + if (!cat->login_renderer_incoming_category_id.empty() && |
2673 | + !cat->login_renderer.empty()) |
2674 | + { |
2675 | + scope_ptr->enable_using_login_renderer(); |
2676 | + scope_ptr->set_login_template(cat->login_renderer); |
2677 | + scope_ptr->set_login_renderer_incoming_category_id(cat->login_renderer_incoming_category_id); |
2678 | + } |
2679 | + |
2680 | + qDebug() << "==== MKCAT SCOPE cat->login_renderer CAT incoming_category_id: "<< QString::fromStdString(cat->login_renderer_incoming_category_id); |
2681 | + qDebug() << "==== MKCAT SCOPE cat->login_renderer: "<< QString::fromStdString(cat->login_renderer); |
2682 | + qDebug() << "==== MKCAT SCOPE login_renderer SCOPE incoming_category_id: "<< QString::fromStdString(scope_ptr->login_renderer_incoming_category_id()); |
2683 | + |
2684 | qDebug() << "==== MKCAT SCOPE cat card"<< QString::number(cat->cardinality); |
2685 | scope_ptr->set_cardinality(cat->cardinality); |
2686 | qDebug() << "==== MKCAT SCOPE get cat card"<< QString::number(scope_ptr->cardinality()); |
2687 | @@ -1058,6 +1053,7 @@ |
2688 | if (found_scopes.size() == 0 ) |
2689 | continue; |
2690 | |
2691 | + |
2692 | qDebug() << client.qstr("==== CATKW ID found: %1 %2").arg(client.qstr(kw),client.qstr(id)); |
2693 | auto keych_ptr = std::make_shared<AggChildScope>(id); |
2694 | std::string local_id = id + ":category=" + cat->id + ":keyword=" + kw; |
2695 | @@ -1066,6 +1062,7 @@ |
2696 | keych_ptr->set_category_scope(true); |
2697 | keych_ptr->set_category_id(cat->id); |
2698 | qDebug() << "==== CATKW adding id: " << client.qstr(id); |
2699 | + qDebug() << "==== CATKW adding. local_id: " << client.qstr(local_id); |
2700 | qDebug() << "==== CATKW adding kw: " << client.qstr(kw); |
2701 | type_ids_m[cat->id].emplace_back(keych_ptr->local_id()); |
2702 | keych_ptr->set_keyword(kw); |
2703 | @@ -1073,7 +1070,15 @@ |
2704 | keych_ptr->set_department(cat->dept_id); |
2705 | keych_ptr->set_department(cat->dept_id); |
2706 | keych_ptr->set_cardinality(cat->cardinality); |
2707 | - |
2708 | + //set up login renderer usage, if any |
2709 | + if (!cat->login_renderer_incoming_category_id.empty() && |
2710 | + !cat->login_renderer.empty()) |
2711 | + { |
2712 | + qDebug() << "==== CATKW: login renderer in use"; |
2713 | + keych_ptr->enable_using_login_renderer(); |
2714 | + keych_ptr->set_login_template(cat->login_renderer); |
2715 | + keych_ptr->set_login_renderer_incoming_category_id(cat->login_renderer_incoming_category_id); |
2716 | + } |
2717 | // set more default values |
2718 | categoryId_isFirstResult[kw] = true; |
2719 | categoryId_isSecondResult[kw] = false; |
2720 | @@ -1100,1005 +1105,3 @@ |
2721 | } |
2722 | } |
2723 | } |
2724 | - |
2725 | -void Query::handle_current_child_scopes(bool empty_search, us::SearchReplyProxy const& upstream_reply) |
2726 | -{ |
2727 | - UNUSED(empty_search) |
2728 | - UNUSED(upstream_reply) |
2729 | - // Cycle through child scopes (in current_scopes) and, if enabled in settings, complete set up |
2730 | - try |
2731 | - { |
2732 | - for (const std::string & local_id : current_scopes) |
2733 | - { |
2734 | - qDebug() << "==== CURRENT. local_id: " << client.qstr(local_id); |
2735 | - std::string id = localId_id_m[local_id]; |
2736 | - qDebug() << "==== CURRENT. id: " << client.qstr(id); |
2737 | - std::shared_ptr<AggChildScope> scope = scopes_m[local_id]; |
2738 | - |
2739 | - scope->set_proxy(registry_); |
2740 | - |
2741 | - if (!scope->exists()) { |
2742 | - std::string sep = query_store_ == "" ? "name:" : "+"; |
2743 | - std::string name = std::string(id, 0, id.find('_')); |
2744 | - query_store_.append(sep + name); |
2745 | - } |
2746 | - else |
2747 | - { |
2748 | - if (!scope->source_finder()) |
2749 | - has_one_source = true; |
2750 | - } |
2751 | - } |
2752 | - for (auto source : sources_for_clickstore) |
2753 | - { |
2754 | - AggChildScope scope(source); |
2755 | - scope.set_proxy(registry_); |
2756 | - if (!scope.exists()) { |
2757 | - std::string sep = query_store_ == "" ? "name:" : "+"; |
2758 | - std::string name = std::string(source, 0, source.find('_')); |
2759 | - query_store_.append(sep + name); |
2760 | - } |
2761 | - } |
2762 | - } |
2763 | - catch (unity::Exception const& e) |
2764 | - { |
2765 | - qWarning() << "NotFoundException: " << e.what(); |
2766 | - } |
2767 | -} |
2768 | - |
2769 | -void Query::noSources(unity::scopes::SearchReplyProxy const& reply) { |
2770 | - std::string MESS_GRID = R"( |
2771 | - { |
2772 | - "schema-version" : 1, |
2773 | - "template" : { |
2774 | - "category-layout" : "grid", |
2775 | - "card-layout": "horizontal", |
2776 | - "card-size": "small", |
2777 | - "non-interactive": true |
2778 | - }, |
2779 | - "components" : { |
2780 | - "title" : "title" |
2781 | - } |
2782 | - } |
2783 | - )"; |
2784 | - |
2785 | - CategoryRenderer emptyCat(MESS_GRID); |
2786 | - auto messGrid = reply->register_category("emptyMess", _("Welcome"), "", emptyCat); |
2787 | - CategorisedResult res(messGrid); |
2788 | - res.set_uri("http://ubuntu.com"); |
2789 | - res["title"]=_("To start using this scope please install sources from the list below"); |
2790 | - reply->push(res); |
2791 | -} |
2792 | - |
2793 | -bool Query::hints_exists() |
2794 | -{ |
2795 | - auto scopes = registry_->list(); |
2796 | - us::MetadataMap::const_iterator scope; |
2797 | - scope = scopes.find(HINTS_SCOPE_ID); |
2798 | - if (scope != scopes.end()) { |
2799 | - auto meta = registry_->get_metadata(HINTS_SCOPE_ID); |
2800 | - hints_scope = meta.proxy(); |
2801 | - return true; |
2802 | - } |
2803 | - return false; |
2804 | -} |
2805 | - |
2806 | -void Query::display_local_hints_quickstart(us::SearchReplyProxy const& upstream_reply_) |
2807 | -{ |
2808 | - if (!local_hints) |
2809 | - return; |
2810 | - if (!hints_local_json.contains(QStringLiteral("content"))) |
2811 | - return; |
2812 | - auto content = hints_local_json[QStringLiteral("content")].toObject(); |
2813 | - if (!content.contains(QStringLiteral("categories"))) |
2814 | - return; |
2815 | - |
2816 | - QJsonArray cats = content[QStringLiteral("categories")].toArray(); |
2817 | - for (const auto & cat_ : cats) |
2818 | - { |
2819 | - auto cat = cat_.toObject(); |
2820 | - |
2821 | - std::string id = client.sstr(cat[QStringLiteral("id")].toString()); |
2822 | - std::string title = _(client.sstr(cat[QStringLiteral("_title")].toString()).c_str()); |
2823 | - QJsonDocument layout_d(cat[QStringLiteral("layout")].toObject()); |
2824 | - std::string local_hints_template = client.sstr(layout_d.toJson()); |
2825 | - auto category = upstream_reply_->lookup_category(id); |
2826 | - if (!category) { |
2827 | - category = upstream_reply_->register_category(id, title, "", us::CategoryRenderer(local_hints_template)); |
2828 | - } |
2829 | - QJsonArray items = cat[QStringLiteral("items")].toArray(); |
2830 | - for (const auto & res__ : items) |
2831 | - { |
2832 | - auto res_ = res__.toObject(); |
2833 | - us::CategorisedResult res(category); |
2834 | - res.set_title(_(client.sstr(res_[QStringLiteral("_title")].toString()).c_str())); |
2835 | - res["subtitle"] = _(client.sstr(res_[QStringLiteral("_subtitle")].toString()).c_str()); |
2836 | - res["description"] = _(client.sstr(res_[QStringLiteral("_description")].toString()).c_str()); |
2837 | - std::string uri = "http://www.ubuntu.com"; |
2838 | - if (res_.contains(QStringLiteral("hide_in_locales"))) |
2839 | - { |
2840 | - QStringList hide_in_locales = res_[QStringLiteral("hide_in_locales")].toString().split(","); |
2841 | - std::string lcRaw = setlocale(LC_ALL, ""); |
2842 | - std::string lc_lang = lcRaw.size() > 5 ? lcRaw.substr(0, 2) : ""; |
2843 | - std::string lc_country = lcRaw.size() > 5 ? lcRaw.substr(3, 2) : ""; |
2844 | - std::string lc = lc_lang + "_" + lc_country; |
2845 | - if (hide_in_locales.contains(client.qstr(lc))) |
2846 | - { |
2847 | - continue; |
2848 | - } |
2849 | - } |
2850 | - if (res_.contains("uri")) |
2851 | - { |
2852 | - uri = client.sstr(res_["uri"].toString()); |
2853 | - } |
2854 | - if (res_.contains(QStringLiteral("action"))) |
2855 | - { |
2856 | - auto action = res_[QStringLiteral("action")].toObject(); |
2857 | - VariantBuilder builder; |
2858 | - builder.add_tuple({ |
2859 | - {"id", Variant("Open")}, |
2860 | - {"label", Variant(_(client.sstr(action[QStringLiteral("_name")].toString()).c_str()))}, |
2861 | - {"uri", Variant(client.sstr(action[QStringLiteral("uri")].toString()))} |
2862 | - }); |
2863 | - res["actions"]=builder.end(); |
2864 | - if (action.contains(QStringLiteral("uri"))) |
2865 | - { |
2866 | - uri = client.sstr(action[QStringLiteral("uri")].toString()); |
2867 | - } |
2868 | - } |
2869 | - if (res_.contains(QStringLiteral("oaccount"))) |
2870 | - { |
2871 | - auto oaccount = res_[QStringLiteral("oaccount")].toObject(); |
2872 | - auto queryScope = client.sstr(oaccount[QStringLiteral("QueryScope")].toString()); |
2873 | - |
2874 | - // before framework 15.0.4.4 the service name is the FQ scope id and contains one "_" |
2875 | - // with 15.04.4, it is FQ scope id += _PROVIDER |
2876 | - // we also want the fully qualified scope id to check with registry if it is installed. |
2877 | - // to support both cases: |
2878 | - QStringList parts = oaccount[QStringLiteral("ServiceName")].toString().split("_"); |
2879 | - QString provider = oaccount[QStringLiteral("ProviderName")].toString(); |
2880 | - QString sc_id = parts[0] + "_" + parts[1]; |
2881 | - QString id = sc_id; |
2882 | - if (parts.size() > 2) // framework 15.04.4 or higher |
2883 | - { |
2884 | - id += "_" + provider; |
2885 | - } |
2886 | - us::OnlineAccountClient oa_client(client.sstr(id), |
2887 | - client.sstr(oaccount[QStringLiteral("ServiceType")].toString()), |
2888 | - client.sstr(provider)); |
2889 | - bool alreadyLoggedIn = false; |
2890 | - oa_client.refresh_service_statuses(); |
2891 | - for (auto const& status : oa_client.get_service_statuses()) |
2892 | - { |
2893 | - if (status.service_enabled) |
2894 | - { |
2895 | - alreadyLoggedIn = true; |
2896 | - break; |
2897 | - } |
2898 | - } |
2899 | - // do not display quick start help for scopes that are not registered in the system |
2900 | - auto reg_scopes = registry_->list(); |
2901 | - us::MetadataMap::const_iterator scope_it; |
2902 | - scope_it = reg_scopes.find(client.sstr(sc_id)); |
2903 | - if (scope_it == reg_scopes.end()) { |
2904 | - qWarning () << QString("%1: OA scope is NOT REGISTERED, skipping for HINTS: %2").arg(oaccount[QStringLiteral("ServiceName")].toString()); |
2905 | - continue; |
2906 | - } |
2907 | - if (alreadyLoggedIn) { |
2908 | - //the hints code does this when the person is already logged in to the service. |
2909 | - //auto tmp = oaccount["_loggedin"].toString().toStdString(); |
2910 | - //res["title"] = std::string(_(tmp.c_str())); |
2911 | - // |
2912 | - //this continue statement means if the person is logged in, we do not show |
2913 | - //a result for the item |
2914 | - continue; |
2915 | - } |
2916 | - us::CannedQuery query(queryScope); |
2917 | - oa_client.register_account_login_item(res, |
2918 | - query, |
2919 | - OnlineAccountClient::InvalidateResults, |
2920 | - OnlineAccountClient::DoNothing); |
2921 | - |
2922 | - } |
2923 | - if (res_.contains(QStringLiteral("hide_hints"))) |
2924 | - { |
2925 | - qDebug() << "=== NHINTS. utils. hide hints found in json"; |
2926 | - res["action"] = "hide_hints"; |
2927 | - res.set_intercept_activation(); |
2928 | - } |
2929 | - res.set_uri(uri); |
2930 | - res.set_art(scope_dir_ + "/images/" + client.sstr(res_["art"].toString())); |
2931 | - upstream_reply_->push(res); |
2932 | - } |
2933 | - } |
2934 | -} |
2935 | - |
2936 | -void Query::display_remote_hints_quickstart(us::SearchReplyProxy const& upstream_reply_) |
2937 | -{ |
2938 | - qDebug() << "==== HINTS in display_remote_hints_quickstart()"; |
2939 | - Category::SCPtr hint_cat; |
2940 | - SearchMetadata metadata(search_metadata()); |
2941 | - auto reply = std::make_shared<ResultForwarder>(upstream_reply_, |
2942 | - [this, &hint_cat](CategorisedResult& res) -> bool { |
2943 | - UNUSED(res) |
2944 | - return true; |
2945 | - }); |
2946 | - |
2947 | - subsearch(hints_scope, "", HINTS_THIS_SCOPE, FilterState(), |
2948 | - metadata, reply); |
2949 | -} |
2950 | - |
2951 | -bool Query::hints_hidden() { |
2952 | - |
2953 | - auto filepath1 = QString::fromStdString(cache_dir_) +"/" + hints_file; |
2954 | - auto filepath2 = QString::fromStdString(cache_dir_) +"/" + firstboot; |
2955 | - if (QFile::exists(filepath1) || QFile::exists(filepath2)) |
2956 | - return true; |
2957 | - return false; //don't show hints as fall back |
2958 | -} |
2959 | - |
2960 | -void Query::dismiss_hints_quickstart() { |
2961 | - qDebug() << "==== HINTS in dismiss()"; |
2962 | - auto filepath= QString::fromStdString(cache_dir_) +"/" + hints_file; |
2963 | - QFile file(filepath); |
2964 | - file.open(QIODevice::WriteOnly); |
2965 | - QString msg = QString("Timestamp for %1 %2").arg(client.qstr(HINTS_THIS_SCOPE), QDateTime::currentDateTime().toString()); |
2966 | - file.write(client.sstr(msg).c_str(), client.sstr(msg).size()); |
2967 | - file.close(); |
2968 | -} |
2969 | - |
2970 | -void Query::handle_keyword_child(unity::scopes::SearchReplyProxy const& upstream_reply, |
2971 | - std::shared_ptr<AggChildScope> scope, |
2972 | - us::CategorisedResult & res){ |
2973 | - |
2974 | - // for use in category registration |
2975 | - std::string cat_id; |
2976 | - std::string cat_title; |
2977 | - std::string rdr; |
2978 | - |
2979 | - std::string keyword = scope->keyword(); |
2980 | - qDebug() << "==== KW scope: " << client.qstr(scope->id()) << " keyword: " << client.qstr(keyword);; |
2981 | - qDebug() << "==== KW scope shared cat name: " << client.qstr(scope->keyword_scope_shared_cat_name()); |
2982 | - |
2983 | - if (!query().query_string().empty()) |
2984 | - { |
2985 | - if (!keyword_catname_search_renderer[keyword].empty()) // keyword has declared cat search renderer |
2986 | - { |
2987 | - qDebug() << "==== KW SEARCH keyword using search renderer"; |
2988 | - cat_id = keyword + ":keyword:search_renderer:searching:" + cat_title; |
2989 | - rdr = keyword_catname_search_renderer[keyword]; |
2990 | - } |
2991 | - else |
2992 | - { |
2993 | - qDebug() << "==== KW SEARCH using incoming result renderer"; |
2994 | - cat_id = keyword + ":keyword:incoming_renderer:searching:" + cat_title; |
2995 | - rdr = res.category()->renderer_template().data(); |
2996 | - } |
2997 | - if (!upstream_reply->lookup_category(cat_id)) |
2998 | - { |
2999 | - catname_catptr[scope->keyword_scope_shared_cat_name()] = upstream_reply->register_category |
3000 | - ( |
3001 | - cat_id, |
3002 | - cat_title, |
3003 | - "", |
3004 | - us::CategoryRenderer(rdr) |
3005 | - ); |
3006 | - res.set_category(catname_catptr[scope->keyword_scope_shared_cat_name()]); |
3007 | - } |
3008 | - else |
3009 | - res.set_category(upstream_reply->lookup_category(cat_id)); |
3010 | - qDebug() << "==== KW SEARCH. cat_id: " << client.qstr(cat_id); |
3011 | - } |
3012 | - else if (!scope->keyword_scope_shared_cat_name().empty()) |
3013 | - {//uses shared category |
3014 | - cat_title = _(shared_keyword_cat_titlemsgid[keyword].c_str()); |
3015 | - qDebug() << "==== KW SHAREDCAT uses shared cat"; |
3016 | - if (!keyword_catname_first_result_renderers[keyword].empty()) // uses first result rdr |
3017 | - { |
3018 | - if ((first_result_owner.empty()) || (first_result_owner == keyword)) |
3019 | - { |
3020 | - qDebug() << "==== KW SHAREDCAT uses first result: " << client.qstr(scope->id()); |
3021 | - if (keywordSharedCat_isFirstResult[keyword]) |
3022 | - { |
3023 | - first_result_owner = keyword; |
3024 | - keywordSharedCat_isFirstResult[keyword] = false; |
3025 | - keywordSharedCat_isSecondResult[keyword] = true; |
3026 | - qDebug() << "==== KW SHAREDCAT is FIRST result: " << client.qstr(scope->keyword_scope_shared_cat_name()); |
3027 | - qDebug() << "==== KW SHAREDCAT claims FIRST result: " << client.qstr(scope->keyword_scope_shared_cat_name()); |
3028 | - cat_id = keyword + ":keyword:is_shared_category:is_first_result:" + cat_title; |
3029 | - rdr = keyword_catname_first_result_renderers[keyword]; |
3030 | - if (!upstream_reply->lookup_category(cat_id)) |
3031 | - { |
3032 | - catname_catptr[scope->keyword_scope_shared_cat_name()] = upstream_reply->register_category |
3033 | - ( |
3034 | - cat_id, |
3035 | - cat_title, |
3036 | - "", |
3037 | - us::CategoryRenderer(rdr) |
3038 | - ); |
3039 | - } |
3040 | - res.set_category(upstream_reply->lookup_category(cat_id)); |
3041 | - } |
3042 | - else if ( keywordSharedCat_isSecondResult[keyword] )// second result |
3043 | - { |
3044 | - //keywordSharedCat_isSecondResult[keyword] = false; |
3045 | - qDebug() << "==== KW SHAREDCAT uses FIRST result. is SECOND+ result: " << client.qstr(scope->keyword_scope_shared_cat_name()); |
3046 | - if (!keyword_catname_renderer[keyword].empty()) // keyword has declared cat renderer |
3047 | - { |
3048 | - qDebug() << "==== KW SHAREDCAT uses FIRST result. is SECOND+ result. NOT uses surface_template "; |
3049 | - cat_id = scope->keyword_scope_shared_cat_name() + ":keyword:is_shared_category:uses_first_result:second_result+:surface_template:surfacing:" + cat_title; |
3050 | - rdr = keyword_catname_renderer[keyword]; |
3051 | - } |
3052 | - else //no surface template found, use incoming result |
3053 | - { |
3054 | - qDebug() << "==== KW SHAREDCAT uses FIRST result. is SECOND+ result. NOT uses result template "; |
3055 | - cat_id = scope->keyword_scope_shared_cat_name() + ":keyword:is_shared_category:uses_first_result:second_result+:result_template:surfacing:" + cat_title; |
3056 | - rdr = res.category()->renderer_template().data(); |
3057 | - } |
3058 | - if (!upstream_reply->lookup_category(cat_id)) |
3059 | - { |
3060 | - catname_catptr[scope->keyword_scope_shared_cat_name()] = upstream_reply->register_category |
3061 | - ( |
3062 | - cat_id, |
3063 | - cat_title, |
3064 | - "", |
3065 | - us::CategoryRenderer(rdr) |
3066 | - ); |
3067 | - } |
3068 | - res.set_category(upstream_reply->lookup_category(cat_id)); |
3069 | - } |
3070 | - qDebug() << "==== KW SHAREDCAT uses FIRST result. cat_id: " << client.qstr(cat_id); |
3071 | - |
3072 | - } |
3073 | - } |
3074 | - else // not search and does not use declared first result rdr |
3075 | - { |
3076 | - if (!scope->surface_template().empty())// has a decared surface template |
3077 | - { |
3078 | - qDebug() << "==== KW SHAREDCAT not uses first result. uses surface template"; |
3079 | - cat_id = scope->keyword_scope_shared_cat_name() + ":keyword:is_shared_category:not_uses_first_result:surface_template:surfacing:" + cat_title; |
3080 | - rdr = scope->surface_template(); |
3081 | - qDebug() << "==== KW SHAREDCAT. rdr" << client.qstr(rdr).replace("\n", " "); |
3082 | - } |
3083 | - else // use result template |
3084 | - { |
3085 | - qDebug() << "==== KW SHAREDCAT not uses first result. NOT uses surface template"; |
3086 | - cat_id = scope->keyword_scope_shared_cat_name() + ":keyword:is_shared_category:not_uses_first_result:result_template:surfacing:" + cat_title; |
3087 | - rdr = res.category()->renderer_template().data(); |
3088 | - } |
3089 | - if (catname_catptr.find(scope->keyword_scope_shared_cat_name()) == catname_catptr.end()) |
3090 | - { |
3091 | - if (categoryId_linkToChildSpecified.find(scope->category_id()) != categoryId_linkToChildSpecified.end()) |
3092 | - { |
3093 | - if (!upstream_reply->lookup_category(cat_id)) |
3094 | - { |
3095 | - catname_catptr[scope->keyword_scope_shared_cat_name()] = upstream_reply->register_category |
3096 | - ( |
3097 | - cat_id, |
3098 | - cat_title, |
3099 | - "", |
3100 | - us::CannedQuery(categoryId_linkToChildSpecified[scope->category_id()]), |
3101 | - us::CategoryRenderer(rdr) |
3102 | - ); |
3103 | - } |
3104 | - else |
3105 | - { |
3106 | - res.set_category(upstream_reply->lookup_category(cat_id)); |
3107 | - } |
3108 | - } |
3109 | - else if (!upstream_reply->lookup_category(cat_id)) |
3110 | - { |
3111 | - catname_catptr[scope->keyword_scope_shared_cat_name()] = upstream_reply->register_category |
3112 | - ( |
3113 | - cat_id, |
3114 | - cat_title, |
3115 | - "", |
3116 | - us::CategoryRenderer(rdr) |
3117 | - ); |
3118 | - res.set_category(upstream_reply->lookup_category(cat_id)); |
3119 | - } |
3120 | - else |
3121 | - { |
3122 | - res.set_category(upstream_reply->lookup_category(cat_id)); |
3123 | - } |
3124 | - } |
3125 | - else |
3126 | - { |
3127 | - res.set_category(upstream_reply->lookup_category(cat_id)); |
3128 | - qDebug() << "==== KW SHAREDCAT not uses first result. cat_id: " << client.qstr(cat_id); |
3129 | - } |
3130 | - } |
3131 | - } |
3132 | - else // keyword scope does not use a shared category |
3133 | - { |
3134 | - qDebug() << "==== KW not SHAREDCAT"; |
3135 | - qDebug() << "==== KW not SHAREDCAT. first result for scope: " << client.qstr(scope->local_id()); |
3136 | - scope->set_is_first_result(false); |
3137 | - //cat_title = inc_res_cat_title; |
3138 | - //if (cat_title.empty()){ |
3139 | - cat_title = registry_->get_metadata(scope->id()).display_name(); |
3140 | - //} |
3141 | - qDebug() << "==== KW not SHAREDCAT. local_id: " << client.qstr(scope->local_id()); |
3142 | - qDebug() << "==== KW not SHAREDCAT. cat_ttile: " << client.qstr(cat_title); |
3143 | - //if (keyword_catname_renderer.find(keyword) != keyword_catname_renderer.end())// has a decared surface template |
3144 | - if (!keyword_catname_renderer[keyword].empty()) |
3145 | - { |
3146 | - qDebug() << "==== KW not SHAREDCAT. declared renderer "; |
3147 | - qDebug() << "==== KW not SHAREDCAR. keyword: " << client.qstr(scope->keyword()); |
3148 | - cat_id = scope->keyword() + ":keyword:not_shared_category:declared_renderer:surfacing:" + cat_title; |
3149 | - rdr = keyword_catname_renderer[keyword]; |
3150 | - } |
3151 | - else // use result template |
3152 | - { |
3153 | - qDebug() << "==== KW not SHAREDCAT. incoming renderer"; |
3154 | - cat_id = scope->keyword() + ":keyword:not_shared_category:incoming_renderer:surfacing:" + cat_title; |
3155 | - rdr = res.category()->renderer_template().data(); |
3156 | - } |
3157 | - qDebug() << "==== KW not SHAREDCAT. cat_id: " << client.qstr(cat_id); |
3158 | - if (scope->category_link_to_child()) |
3159 | - { |
3160 | - if (!upstream_reply->lookup_category(cat_id)) |
3161 | - { |
3162 | - upstream_reply->register_category |
3163 | - ( |
3164 | - cat_id, |
3165 | - cat_title, |
3166 | - "", |
3167 | - us::CannedQuery(scope->id(), query().query_string(), scope->child_department()), |
3168 | - us::CategoryRenderer(rdr) |
3169 | - ); |
3170 | - } |
3171 | - res.set_category(upstream_reply->lookup_category(cat_id)); |
3172 | - } |
3173 | - else |
3174 | - { |
3175 | - if (!upstream_reply->lookup_category(cat_id)) |
3176 | - { |
3177 | - upstream_reply->register_category |
3178 | - ( |
3179 | - cat_id, |
3180 | - cat_title, |
3181 | - "", |
3182 | - us::CategoryRenderer(rdr) |
3183 | - ); |
3184 | - } |
3185 | - res.set_category(upstream_reply->lookup_category(cat_id)); |
3186 | - } |
3187 | - } |
3188 | -} |
3189 | - |
3190 | -void Query::handle_category_child(unity::scopes::SearchReplyProxy const& upstream_reply, |
3191 | - std::shared_ptr<AggChildScope> scope, |
3192 | - us::CategorisedResult & res){ |
3193 | - |
3194 | - // for use in category registration |
3195 | - std::string cat_id; |
3196 | - std::string cat_title; |
3197 | - std::string rdr; |
3198 | - |
3199 | - std::string category_id = scope->category_id(); |
3200 | - qDebug() << "==== CATREG RESULT scope: " << client.qstr(scope->id()) << " title: " <<client.qstr(cat_title); |
3201 | - |
3202 | - if (!categoryId_titleMsgid[category_id].empty()) |
3203 | - cat_title = _(categoryId_titleMsgid[category_id].c_str()); |
3204 | - else |
3205 | - cat_title = ""; |
3206 | - |
3207 | - bool uses_first_result_rdr = categoryId_first_result_renderers.find(category_id) != categoryId_first_result_renderers.end(); |
3208 | - |
3209 | - if (!query().query_string().empty()) |
3210 | - { |
3211 | - qDebug()<<client.qstr("==== CATREG scope's (%1) search template: %2").arg(client.qstr(scope->local_id()), client.qstr(scope->search_template()).replace("\n", " ")); |
3212 | - qDebug() << "==== CATREG search renderer:" << client.qstr(scope->search_template()).replace("\n", ""); |
3213 | - if (!scope->search_template().empty()) |
3214 | - { |
3215 | - qDebug() << "==== CATREG using search renderer"; |
3216 | - cat_id = scope->local_id() + ":category:search-renderer:searching:" + cat_title; |
3217 | - rdr = scope->search_template(); |
3218 | - } |
3219 | - else |
3220 | - { |
3221 | - qDebug() << "==== CATREG using incoming eesult renderer"; |
3222 | - cat_id = scope->local_id() + ":category:incoming-renderer:searching:" + cat_title; |
3223 | - rdr = res.category()->renderer_template().data(); |
3224 | - } |
3225 | - if (!upstream_reply->lookup_category(cat_id)) |
3226 | - { |
3227 | - upstream_reply->register_category |
3228 | - ( |
3229 | - cat_id, |
3230 | - cat_title, |
3231 | - "", |
3232 | - us::CategoryRenderer(rdr) |
3233 | - ); |
3234 | - res.set_category(upstream_reply->lookup_category(cat_id)); |
3235 | - } |
3236 | - else |
3237 | - res.set_category(upstream_reply->lookup_category(cat_id)); |
3238 | - qDebug() << "==== CATREG search cat_id: " << client.qstr(cat_id); |
3239 | - } |
3240 | - else if (uses_first_result_rdr ) |
3241 | - { |
3242 | - qDebug() << "==== CATREG uses first result. scope category_id: " << client.qstr(category_id); |
3243 | - |
3244 | - if ((first_result_owner.empty()) || (first_result_owner == category_id)) |
3245 | - { |
3246 | - // perform fallbacks, if any |
3247 | - if(!scope->first_common_template_id().empty()) |
3248 | - { |
3249 | - qDebug() << "==== first check FALLB. scope->first_common_template_id():" << client.qstr(scope->first_common_template_id()); |
3250 | - std::string res_str = us::Variant(res.serialize()).serialize_json(); |
3251 | - auto change = this->client.check_result_fallbacks(res_str, |
3252 | - scope->first_common_template_id(), |
3253 | - this->get_common_templates_fallbacks()); |
3254 | - if (!std::get<0>(change).empty()) |
3255 | - { |
3256 | - res[std::get<0>(change)] = std::get<1>(change); |
3257 | - } |
3258 | - } |
3259 | - if (categoryId_isFirstResult[category_id]) |
3260 | - { |
3261 | - first_result_owner = category_id; |
3262 | - cat_id = category_id + ":category:uses-first-result:first-result-rdr:surfacing"; |
3263 | - qDebug() << "==== CATREG. uses FIRST result. FIRST result. cat_id: " << client.qstr(cat_id); |
3264 | - rdr = categoryId_first_result_renderers[category_id]; |
3265 | - categoryId_isFirstResult[category_id] = false; |
3266 | - categoryId_isSecondResult[category_id] = true; |
3267 | - if (categoryId_linkToChildSpecified.find(scope->category_id()) != categoryId_linkToChildSpecified.end()) |
3268 | - { |
3269 | - qDebug() << "==== CATREG. uses FIRST result. FIRST result. LINK to child "; |
3270 | - if (!upstream_reply->lookup_category(cat_id)) |
3271 | - { |
3272 | - catname_catptr[category_id] = upstream_reply->register_category |
3273 | - ( |
3274 | - cat_id, |
3275 | - cat_title, |
3276 | - "", |
3277 | - us::CannedQuery(categoryId_linkToChildSpecified[scope->category_id()]), |
3278 | - us::CategoryRenderer(rdr) |
3279 | - ); |
3280 | - scope->set_category(catname_catptr[category_id]); |
3281 | - } |
3282 | - res.set_category(upstream_reply->lookup_category(cat_id)); |
3283 | - } |
3284 | - else |
3285 | - { |
3286 | - qDebug() << "==== CATREG. uses FIRST result. FIRST result. NO LINK to child "; |
3287 | - if (!upstream_reply->lookup_category(cat_id)) |
3288 | - { |
3289 | - catname_catptr[category_id] = upstream_reply->register_category |
3290 | - ( |
3291 | - cat_id, |
3292 | - cat_title, |
3293 | - "", |
3294 | - us::CategoryRenderer(rdr) |
3295 | - ); |
3296 | - scope->set_category(catname_catptr[category_id]); |
3297 | - } |
3298 | - res.set_category(upstream_reply->lookup_category(cat_id)); |
3299 | - } |
3300 | - } |
3301 | - else if ( categoryId_isSecondResult[category_id] )// second result |
3302 | - { |
3303 | - //categoryId_isSecondResult[category_id] = false; |
3304 | - qDebug() << "==== CATREG RESULT uses FIRST result is SECOND result: " << client.qstr(category_id); |
3305 | - // perform fallbacks, if any |
3306 | - if(!scope->surface_common_template_id().empty()) |
3307 | - { |
3308 | - std::string res_str = us::Variant(res.serialize()).serialize_json(); |
3309 | - auto change = this->client.check_result_fallbacks(res_str, |
3310 | - scope->surface_common_template_id(), |
3311 | - this->get_common_templates_fallbacks()); |
3312 | - |
3313 | - if (!std::get<0>(change).empty()) |
3314 | - { |
3315 | - res[std::get<0>(change)] = std::get<1>(change); |
3316 | - } |
3317 | - } |
3318 | - if (!scope->surface_template().empty()) // keyword has declared cat renderer |
3319 | - { |
3320 | - qDebug() << "==== CATREG RESULT uses FIRST result. is SECOND result. uses surface_renderer "; |
3321 | - cat_id = category_id + ":category:uses-first-result:second-or-later-result:surface-rdr:surfacing:" + cat_title; |
3322 | - rdr = scope->surface_template(); |
3323 | - } |
3324 | - else // use result template |
3325 | - { |
3326 | - qDebug() << "==== CATREG RESULT uses FIRST result. is SECOND result. NOT uses surface_template "; |
3327 | - cat_id = category_id + ":category:uses-first-result:second-or-later-result:incoming-rdr:surfacing:" + cat_title; |
3328 | - rdr = res.category()->renderer_template().data(); |
3329 | - } |
3330 | - qDebug() << "==== CATREG. uses FIRST result. SECOND result. cat_id: " << client.qstr(cat_id); |
3331 | - if (!upstream_reply->lookup_category(cat_id)) |
3332 | - { |
3333 | - catname_catptr[category_id] = upstream_reply->register_category |
3334 | - ( |
3335 | - cat_id, |
3336 | - cat_title, |
3337 | - "", |
3338 | - us::CategoryRenderer(rdr) |
3339 | - ); |
3340 | - scope->set_category(catname_catptr[category_id]); |
3341 | - } |
3342 | - res.set_category(upstream_reply->lookup_category(cat_id)); |
3343 | - } |
3344 | - } |
3345 | - } |
3346 | - else // not search and does not use first result rdr |
3347 | - { |
3348 | - qDebug() << "==== CATREG RESULT not uses first result. res title: " << client.qstr(res["title"].get_string()); |
3349 | - // if uses common template, perform fallbacks, if any |
3350 | - qDebug () << "==== CATREG RESULT not uses first result: common id" << client.qstr(scope->surface_common_template_id()); |
3351 | - if(!scope->surface_common_template_id().empty()) |
3352 | - { |
3353 | - qDebug() << "==== surface check FALLB. scope->surface_common_template_id():" << client.qstr(scope->surface_common_template_id()); |
3354 | - std::string res_str = us::Variant(res.serialize()).serialize_json(); |
3355 | - auto change = this->client.check_result_fallbacks(res_str, |
3356 | - scope->surface_common_template_id(), |
3357 | - this->get_common_templates_fallbacks()); |
3358 | - if (!std::get<0>(change).empty()) |
3359 | - { |
3360 | - res[std::get<0>(change)] = std::get<1>(change); |
3361 | - } |
3362 | - } |
3363 | - if (!scope->surface_template().empty())// has a decared surface template |
3364 | - { |
3365 | - qDebug() << "==== CATREG RESULT not uses first result. uses surface template"; |
3366 | - cat_id = scope->category_id() + ":category:not-uses-first-result:surface-rdr:surfacing:" + cat_title; |
3367 | - rdr = scope->surface_template(); |
3368 | - } |
3369 | - else // use result template |
3370 | - { |
3371 | - qDebug() << "==== CATREG RESULT not uses first result. NOT uses result template"; |
3372 | - cat_id = scope->category_id() + ":category:not-uses-first-result:incoming-rdr:surfacing:" + cat_title; |
3373 | - rdr = res.category()->renderer_template().data(); |
3374 | - } |
3375 | - qDebug() << "== rdr: " << client.qstr(rdr); |
3376 | - if (catname_catptr.find(category_id) == catname_catptr.end()) |
3377 | - { |
3378 | - qDebug() << "==== CATREG RESULT not uses first result. category not found in catname_catptr"; |
3379 | - if (categoryId_linkToChildSpecified.find(scope->category_id()) != categoryId_linkToChildSpecified.end()) |
3380 | - { |
3381 | - qDebug() << "==== CATREG RESULT not uses first result. category not found in catname_catptr. is link to child"; |
3382 | - if (!upstream_reply->lookup_category(cat_id)) |
3383 | - { |
3384 | - qDebug() << "==== CATREG RESULT not uses first result. category not found in catname_catptr. is link to child. category not found on lookup"; |
3385 | - catname_catptr[category_id] = upstream_reply->register_category |
3386 | - ( |
3387 | - cat_id, |
3388 | - cat_title, |
3389 | - "", |
3390 | - us::CannedQuery(categoryId_linkToChildSpecified[scope->category_id()]), |
3391 | - us::CategoryRenderer(rdr) |
3392 | - ); |
3393 | - } |
3394 | - res.set_category(upstream_reply->lookup_category(cat_id)); |
3395 | - } |
3396 | - else |
3397 | - { |
3398 | - qDebug() << "==== CATREG RESULT not uses first result. category not found in catname_catptr. not link to child"; |
3399 | - if (!upstream_reply->lookup_category(cat_id)) |
3400 | - { |
3401 | - qDebug() << "==== CATREG RESULT not uses first result. category not found in catname_catptr. not link to child. category not found on lookup"; |
3402 | - catname_catptr[category_id] = upstream_reply->register_category |
3403 | - ( |
3404 | - cat_id, |
3405 | - cat_title, |
3406 | - "", |
3407 | - us::CategoryRenderer(rdr) |
3408 | - ); |
3409 | - } |
3410 | - res.set_category(upstream_reply->lookup_category(cat_id)); |
3411 | - } |
3412 | - } |
3413 | - else // category is found so use it |
3414 | - res.set_category(catname_catptr[category_id]); |
3415 | - qDebug() << "==== CATREG RESULT not uses first result. cat_id" << client.qstr(cat_id); |
3416 | - } |
3417 | -} |
3418 | - |
3419 | -void Query::handle_declared_child(unity::scopes::SearchReplyProxy const& upstream_reply, |
3420 | - std::shared_ptr<AggChildScope> scope, |
3421 | - us::CategorisedResult & res, |
3422 | - std::string const& inc_res_cat_id, |
3423 | - std::string const& inc_res_cat_title) { |
3424 | - |
3425 | - // for use in category registration |
3426 | - std::string cat_id; |
3427 | - std::string cat_title; |
3428 | - std::string rdr; |
3429 | - |
3430 | - qDebug() << "==== DECLARED. scope is declared: " << client.qstr(scope->local_id()); |
3431 | - bool set_declared_category = false; |
3432 | - |
3433 | - // if child_category set, filter out others by adding "dont_use" key to result |
3434 | - // also impose max category results if set |
3435 | - qDebug() << QString("=== DECLARED: child_categpry: %1").arg(client.qstr(scope->child_category())); |
3436 | - qDebug() << QString("=== DECLARED: inc_res_cat_id: %1").arg(client.qstr(inc_res_cat_id)); |
3437 | - if (!scope->child_category().empty()) |
3438 | - { |
3439 | - if (client.qstr(inc_res_cat_id) != client.qstr(scope->child_category())) |
3440 | - { |
3441 | - res["dont_use"] = "true"; |
3442 | - } |
3443 | - else if (scope->using_child_category_max_results()) |
3444 | - { |
3445 | - scope->inc_result_idx(); // allows constraining num results to child_category_max_results declaration |
3446 | - if (scope->result_idx() > scope->child_category_max_results() ) |
3447 | - { |
3448 | - res["dont_use"] = "true"; |
3449 | - } |
3450 | - } |
3451 | - } |
3452 | - |
3453 | - // set the category tiile |
3454 | - if (scope->using_category_title_incoming() ) |
3455 | - { |
3456 | - scope->set_category_title(inc_res_cat_title); |
3457 | - } |
3458 | - else if (scope->using_category_title_display_name() ) |
3459 | - { |
3460 | - scope->set_category_title(scope->metadata()->display_name()); |
3461 | - } |
3462 | - |
3463 | - cat_title = scope->category_title(); |
3464 | - |
3465 | - // dont search of incoming renderer when searching |
3466 | - if (!query().query_string().empty()) |
3467 | - { |
3468 | - set_declared_category = true; |
3469 | - if (!scope->search_template().empty()) |
3470 | - { |
3471 | - qDebug() << "==== DECLARED FIRST RESULT: SEARCH using search renderer"; |
3472 | - cat_id = scope->local_id() + ":declared:search-rdr:searching:" + cat_title; |
3473 | - rdr = scope->search_template(); |
3474 | - } |
3475 | - else |
3476 | - { |
3477 | - qDebug() << "==== DECLARED FIRST RESULT: SEARCH using incoming result renderer"; |
3478 | - cat_id = scope->local_id() + ":declared:incomiing_rdr:searching:" + cat_title; |
3479 | - rdr = res.category()->renderer_template().data(); |
3480 | - } |
3481 | - scope->set_category_id(cat_id); |
3482 | - } |
3483 | - else if (scope->is_first_result()) |
3484 | - { |
3485 | - qDebug() << "==== DECLARED FIRST RESULT for scope: " << client.qstr(scope->local_id()); |
3486 | - scope->set_is_first_result(false); |
3487 | - scope->set_is_second_result(true); |
3488 | - set_declared_category = true; |
3489 | - |
3490 | - cat_id = scope->id() + ":declared_default" + cat_title; |
3491 | - if (first_result_owner.empty() || first_result_owner == scope->id()) |
3492 | - { |
3493 | - first_result_owner = scope->id(); |
3494 | - if (!scope->first_result_template().empty()) |
3495 | - { |
3496 | - qDebug() << "==== DECLARED FIRST RESULT: using first result template"; |
3497 | - cat_id = scope->local_id() + ":declared:first-result:first-result-rdr:surfacing:" + cat_title; |
3498 | - rdr = scope->first_result_template(); |
3499 | - } |
3500 | - else if (!scope->surface_template().empty()) |
3501 | - { |
3502 | - cat_id = scope->local_id() + ":declared:first-result:surface-rdr:surfacing:" + cat_title; |
3503 | - rdr = scope->surface_template(); |
3504 | - qDebug() << "==== DECLARED FIRST RESULT: using surface template"; |
3505 | - } |
3506 | - else |
3507 | - { |
3508 | - cat_id = scope->local_id() + ":declared:first-result:incoming-rdr:surfacing:" + cat_title; |
3509 | - rdr = res.category()->renderer_template().data(); |
3510 | - qDebug() << "==== DECLARED FIRST RESULT: using incoming template"; |
3511 | - } |
3512 | - } |
3513 | - else if (!scope->surface_template().empty()) |
3514 | - { |
3515 | - cat_id = scope->local_id() + ":declared:first-result:first-result-owner:surface-rdr:surfacing:" + cat_title; |
3516 | - rdr = scope->surface_template(); |
3517 | - qDebug() << "==== DECLARED FIRST RESULT: first-result-ownwer. using surface template"; |
3518 | - } |
3519 | - else |
3520 | - { |
3521 | - cat_id = scope->local_id() + ":declared:first-result:first-result-owner:incoming-rdr:surfacing:" + cat_title; |
3522 | - rdr = res.category()->renderer_template().data(); |
3523 | - } |
3524 | - scope->set_category_id(cat_id); |
3525 | - } |
3526 | - else if( //second result but not using different renders for first result vs rest of the results |
3527 | - scope->is_second_result() |
3528 | - && scope->first_result_template().empty() |
3529 | - ) |
3530 | - { |
3531 | - qDebug() << "==== DECLARED SECOND RESULT (not using first/rest renderers) for scope: " << client.qstr(scope->local_id()); |
3532 | - scope->set_is_first_result(false); |
3533 | - scope->set_is_second_result(false); |
3534 | - set_declared_category = false; |
3535 | - } |
3536 | - else if( //second result and using different renderers for first result vs rest of the results |
3537 | - scope->is_second_result() |
3538 | - && !scope->first_result_template().empty() |
3539 | - ) |
3540 | - { |
3541 | - qDebug() << "==== DECLARED SECOND RESULT (using first/rest renderers) for scope: " << client.qstr(scope->local_id()); |
3542 | - scope->set_is_first_result(false); |
3543 | - scope->set_is_second_result(false); |
3544 | - set_declared_category = true; |
3545 | - |
3546 | - if (scope->using_category_title_incoming() ) |
3547 | - { |
3548 | - scope->set_category_title(inc_res_cat_title); |
3549 | - } |
3550 | - else if (scope->using_category_title_display_name() ) |
3551 | - { |
3552 | - scope->set_category_title(scope->metadata()->display_name()); |
3553 | - } |
3554 | - |
3555 | - cat_title = scope->category_title(); |
3556 | - |
3557 | - if (scope->category_link_to_child()) |
3558 | - { |
3559 | - if (query().query_string().empty()) // surfacing |
3560 | - { |
3561 | - if (scope->override_surface_template()) // use declared renderer |
3562 | - { |
3563 | - cat_id = scope->local_id() + ":declared:not-first-result:link:surface-rdr:surfacing:" + cat_title; |
3564 | - rdr = scope->surface_template(); |
3565 | - qDebug() << "=== rdr: " << QString::fromStdString(rdr); |
3566 | - } |
3567 | - else // use incoming renderer |
3568 | - { |
3569 | - cat_id = scope->local_id() + ":declared:not-first-result:link:incoming-rdr:surfacing:" + cat_title; |
3570 | - rdr = res.category()->renderer_template().data(); |
3571 | - } |
3572 | - } |
3573 | - else // user is searching |
3574 | - { |
3575 | - if (scope->override_search_template()) |
3576 | - { |
3577 | - cat_id = scope->local_id() + ":declared:not-first-result:link:search-rdr:searching:" + cat_title; |
3578 | - rdr = scope->search_template().data(); |
3579 | - } |
3580 | - else |
3581 | - { |
3582 | - cat_id = scope->local_id() + ":declared:not-first-result:link:incoming-rdr:searching:" + cat_title; |
3583 | - rdr = res.category()->renderer_template().data(); |
3584 | - } |
3585 | - } |
3586 | - } |
3587 | - else // no category link to child |
3588 | - { |
3589 | - if (query().query_string().empty()) |
3590 | - { |
3591 | - if (scope->override_surface_template()) |
3592 | - { |
3593 | - cat_id = scope->local_id() + ":declared:nolink:surface-rdr:surfacing:" + cat_title; |
3594 | - rdr = scope->surface_template().data(); |
3595 | - qDebug() << QString("=== rdr: %1").arg(client.qstr(rdr)); |
3596 | - } |
3597 | - else if (!scope->first_result_template().empty()) |
3598 | - { |
3599 | - cat_id = scope->local_id() + ":declared:nolink:incoming-rdr:surfacing:" + cat_title; |
3600 | - rdr = res.category()->renderer_template().data(); |
3601 | - } |
3602 | - } |
3603 | - else |
3604 | - { |
3605 | - if (scope->override_search_template()) |
3606 | - { |
3607 | - cat_id = scope->local_id() + "declared:nolink:search-rdr:searching:" + cat_title; |
3608 | - rdr = scope->search_template().data(); |
3609 | - } |
3610 | - else |
3611 | - { |
3612 | - cat_id = scope->local_id() + "declared:nolink:incoming-rdr:searching:" + cat_title; |
3613 | - rdr = res.category()->renderer_template().data(); |
3614 | - } |
3615 | - } |
3616 | - } |
3617 | - } |
3618 | - if (set_declared_category) |
3619 | - { //category needs to be registered |
3620 | - qDebug() << "==== DECLARED. set_declared_category"; |
3621 | - // if needed, get renderer from result_category_to_common_template |
3622 | - if (common_templates.find(child_scopes_m[scope->local_id()]->result_category_id_to_common_template[res.category()->id()]) != common_templates.end()) |
3623 | - { |
3624 | - qDebug() << "==== DECLARED. current category:" << client.qstr(res.category()->id()); |
3625 | - std::string common_template_id = child_scopes_m[scope->local_id()]->result_category_id_to_common_template[res.category()->id()]; |
3626 | - qDebug() << "==== DECLARED. using common_template_id: " << client.qstr(common_template_id); |
3627 | - std::string cat_id = common_template_id + ":" + scope->local_id() + cat_title; |
3628 | - |
3629 | - // if the common category has not yet been registered, register it |
3630 | - if (!upstream_reply->lookup_category(cat_id)) |
3631 | - { |
3632 | - std::string template_to_use = common_templates[child_scopes_m[scope->local_id()]->result_category_id_to_common_template[res.category()->id()]]; |
3633 | - std::string res_str = us::Variant(res.serialize()).serialize_json(); |
3634 | - auto change = this->client.check_result_fallbacks(res_str, |
3635 | - scope->surface_common_template_id(), |
3636 | - this->get_common_templates_fallbacks()); |
3637 | - if (!std::get<0>(change).empty()) |
3638 | - { |
3639 | - res[std::get<0>(change)] = std::get<1>(change); |
3640 | - } |
3641 | - if (scope->category_link_to_child()) |
3642 | - { |
3643 | - if (!upstream_reply->lookup_category(cat_id)) |
3644 | - { |
3645 | - registered_common_categories[cat_id] = upstream_reply->register_category(cat_id, scope->category_title(), "", |
3646 | - us::CannedQuery(scope->id(), query().query_string(), scope->child_department()), |
3647 | - us::CategoryRenderer(template_to_use)); |
3648 | - } |
3649 | - res.set_category(upstream_reply->lookup_category(cat_id)); |
3650 | - } |
3651 | - else |
3652 | - { |
3653 | - if (!upstream_reply->lookup_category(cat_id)) |
3654 | - { |
3655 | - registered_common_categories[cat_id] = upstream_reply->register_category(cat_id, scope->category_title(), "", us::CategoryRenderer(template_to_use)); |
3656 | - } |
3657 | - res.set_category(upstream_reply->lookup_category(cat_id)); |
3658 | - } |
3659 | - } |
3660 | - } |
3661 | - else |
3662 | - { |
3663 | - qDebug() << "=== DECLARED set_declared_category is TRUE. cat_id: " << client.qstr(cat_id); |
3664 | - if (!rdr.empty()) // should not ever be empty! |
3665 | - { |
3666 | - if (!upstream_reply->lookup_category(cat_id)) |
3667 | - { |
3668 | - qDebug() << "=== DECLARED set_declared_category is TRUE -- lookup cat not found: " << client.qstr(cat_id); |
3669 | - if (scope->category_link_to_child()) |
3670 | - { |
3671 | - qDebug() << "=== DECLARED set_declared_category is TRUE -- link to child "; |
3672 | - auto cat = upstream_reply->register_category |
3673 | - ( |
3674 | - cat_id, |
3675 | - cat_title, |
3676 | - "", |
3677 | - us::CannedQuery(scope->id(), query().query_string(), scope->child_department()), |
3678 | - us::CategoryRenderer(rdr) |
3679 | - ); |
3680 | - scope->set_category(cat); |
3681 | - scope->set_category_id(cat_id); |
3682 | - } |
3683 | - else |
3684 | - { |
3685 | - qDebug() << "=== DECLARED set_declared_category is TRUE -- NOT link to child . RDR:" << client.qstr(rdr); |
3686 | - auto cat = upstream_reply->register_category |
3687 | - ( |
3688 | - cat_id, |
3689 | - cat_title, |
3690 | - "", |
3691 | - us::CategoryRenderer(rdr) |
3692 | - ); |
3693 | - scope->set_category(cat); |
3694 | - scope->set_category_id(cat_id); |
3695 | - } |
3696 | - } |
3697 | - res.set_category(upstream_reply->lookup_category(cat_id)); |
3698 | - } |
3699 | - } |
3700 | - } |
3701 | - else // category already registered, so get it and set remember its id |
3702 | - { |
3703 | - res.set_category(upstream_reply->lookup_category(scope->category_id())); |
3704 | - scope->set_category_id(scope->category_id()); |
3705 | - } |
3706 | - |
3707 | - //for child scopes that declare attribute swaps, do them |
3708 | - for (std::shared_ptr<std::pair<std::string,std::string>> swap : this->child_scopes_m[scope->local_id()]->swap_result_attributes) |
3709 | - { |
3710 | - qDebug() << "==== trying to swap attributes"; |
3711 | - try |
3712 | - { |
3713 | - if (!res[swap->first].get_string().empty()) |
3714 | - { |
3715 | - qDebug() << "==== swap first: " << client.qstr(swap->first); |
3716 | - res[swap->second] = res[swap->first]; |
3717 | - } |
3718 | - } |
3719 | - catch (unity::LogicException) |
3720 | - { |
3721 | - qDebug() << "==== failed to swap attributes"; |
3722 | - qWarning() << QString("Scope %1 result does not contain attribute 2").arg(client.qstr(scope->local_id()), client.qstr(swap->second)); |
3723 | - } |
3724 | - } |
3725 | -} |
Note: I started doing this refactoring to help debug https:/ /bugs.launchpad .net/canonical- devices- system- image/+ bug/1622423. However, after the refactor that issue continues, and I suspect it may be a unity8 rendering issue (I am working with unity api team on this separately).