Merge lp:~stolowski/unity-scope-home/direct-search into lp:unity-scope-home

Proposed by Paweł Stołowski
Status: Merged
Approved by: Michal Hruby
Approved revision: 93
Merged at revision: 84
Proposed branch: lp:~stolowski/unity-scope-home/direct-search
Merge into: lp:unity-scope-home
Diff against target: 670 lines (+254/-105)
6 files modified
src/filter-state.vala (+26/-10)
src/keyword-search.vala (+1/-1)
src/remote-scope-registry.vala (+15/-0)
src/scope.vala (+137/-69)
src/search-util.vala (+37/-25)
tests/unit/test-home-scope.vala (+38/-0)
To merge this branch: bzr merge lp:~stolowski/unity-scope-home/direct-search
Reviewer Review Type Date Requested Status
Michal Hruby (community) Approve
PS Jenkins bot (community) continuous-integration Approve
Review via email: mp+158385@code.launchpad.net

Commit message

Implemented direct search (keyword search) for server scopes, this also makes client-side keyword search actually work.
Various fixes regarding filters (interrelationships, lighting them up).
Limit updates of user's default view in dconf.

Description of the change

Implemented direct search (keyword search) for server scopes, this also makes client-side keyword search actually work.
Various fixes regarding filters (interrelationships, lighting them up).
Limit updates of user's default view in dconf.

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
93. By Paweł Stołowski

Added a comment.

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

Seems to work well, +1

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/filter-state.vala'
2--- src/filter-state.vala 2013-03-21 21:40:00 +0000
3+++ src/filter-state.vala 2013-04-11 17:02:21 +0000
4@@ -29,13 +29,10 @@
5 * highlights its subscopes, or deselecting last subscope deselects its master.
6 * This methods stores filter state in order to be able to detect what was selected/deselected.
7 */
8- public bool update_filter_relations (Unity.AggregatedScopeSearch scope_search)
9+ public bool update_filter_relations (string channel_id, Unity.OptionsFilter categories, Unity.OptionsFilter sources)
10 {
11 bool changed = false;
12
13- unowned Unity.OptionsFilter categories = scope_search.get_filter ("categories") as Unity.OptionsFilter;
14- unowned Unity.OptionsFilter sources = scope_search.get_filter ("sources") as Unity.OptionsFilter;
15-
16 if (categories == null || sources == null)
17 {
18 warning ("Categories or Sources filters missing");
19@@ -50,12 +47,24 @@
20 var current_state = new Gee.TreeSet<string> ();
21 get_selected_scopes (categories, current_state);
22 get_selected_scopes (sources, current_state);
23+
24 debug ("Scopes in current_state: %d", current_state.size);
25+ if (verbose_debug)
26+ {
27+ foreach (var scope_id in current_state)
28+ debug ("Current active: %s", scope_id);
29+ }
30
31- var previous_state = filter_state.lookup (scope_search.channel_id);
32+ var previous_state = filter_state.lookup (channel_id);
33
34 if (previous_state != null)
35 {
36+ if (verbose_debug)
37+ {
38+ foreach (var scope_id in previous_state)
39+ debug ("Previous active: %s", scope_id);
40+ }
41+
42 var selected = new Gee.TreeSet<string> ();
43 var unselected = new Gee.TreeSet<string> ();
44
45@@ -88,10 +97,20 @@
46 }
47 else // first search - no previous state
48 {
49+ debug ("No previous filter state");
50 changed = update_filters_for_selected (categories, sources, current_state);
51 }
52
53- filter_state[scope_search.channel_id] = current_state;
54+ var new_state = new Gee.TreeSet<string> ();
55+ get_selected_scopes (categories, new_state);
56+ get_selected_scopes (sources, new_state);
57+ if (verbose_debug)
58+ {
59+ foreach (var scope_id in new_state)
60+ debug ("New active: %s", scope_id);
61+ }
62+
63+ filter_state[channel_id] = new_state;
64
65 if (changed)
66 {
67@@ -250,11 +269,8 @@
68 return changed;
69 }
70
71- public static bool set_filters (Unity.AggregatedScopeSearch scope_search, string[] enabled_scopes)
72+ public static bool set_filters (Unity.OptionsFilter categories, Unity.OptionsFilter sources, string[] enabled_scopes)
73 {
74- unowned Unity.OptionsFilter categories = scope_search.get_filter ("categories") as Unity.OptionsFilter;
75- unowned Unity.OptionsFilter sources = scope_search.get_filter ("sources") as Unity.OptionsFilter;
76-
77 if (categories == null || sources == null)
78 {
79 warning ("Can't set filters, Categories or Sources filters missing");
80
81=== modified file 'src/keyword-search.vala'
82--- src/keyword-search.vala 2013-03-21 14:14:36 +0000
83+++ src/keyword-search.vala 2013-04-11 17:02:21 +0000
84@@ -46,7 +46,7 @@
85 }
86 }
87
88- private void index_keywords (string scope_id, GLib.SList<string> keywords)
89+ public void index_keywords (string scope_id, GLib.SList<string> keywords)
90 {
91 foreach (var kw in keywords)
92 {
93
94=== modified file 'src/remote-scope-registry.vala'
95--- src/remote-scope-registry.vala 2013-03-22 09:09:21 +0000
96+++ src/remote-scope-registry.vala 2013-04-11 17:02:21 +0000
97@@ -29,12 +29,22 @@
98
99 private Dee.Model scopes_model;
100 private SmartScopes.RemoteScopeInfo[] remote_scopes;
101+ private Gee.TreeSet<string> remote_scopes_lut = new Gee.TreeSet<string> ();
102
103 public RemoteScopeRegistry.for_scopes (SmartScopes.RemoteScopeInfo[] info)
104 {
105 Object ();
106
107 remote_scopes = info;
108+ foreach (var scope in remote_scopes)
109+ {
110+ remote_scopes_lut.add (scope.scope_id);
111+
112+ // also add a fake master scope id to the lookup
113+ var master_id = SearchUtil.get_master_id_from_scope_id (scope.scope_id);
114+ if (master_id != null)
115+ remote_scopes_lut.add (master_id);
116+ }
117 }
118
119 public Dee.Model create_model ()
120@@ -63,5 +73,10 @@
121 scopes_model = model;
122 return scopes_model;
123 }
124+
125+ public bool has_scope (string scope_id)
126+ {
127+ return remote_scopes_lut.contains (scope_id);
128+ }
129 }
130 }
131
132=== modified file 'src/scope.vala'
133--- src/scope.vala 2013-03-28 12:26:57 +0000
134+++ src/scope.vala 2013-04-11 17:02:21 +0000
135@@ -169,10 +169,23 @@
136 if (scopes != null)
137 {
138 debug ("Got %u remote scopes", scopes.length);
139- smart_scopes_ready = true;
140+ foreach (var remote_scope in scopes)
141+ {
142+ if (remote_scope.keywords.length > 0)
143+ {
144+ var kw = new GLib.SList<string> ();
145+ foreach (var k in remote_scope.keywords)
146+ {
147+ kw.append (k);
148+ }
149+ keywords_search.index_keywords (remote_scope.scope_id, kw);
150+ }
151+ }
152
153 remote_scope_registry = new RemoteScopeRegistry.for_scopes (scopes);
154 remote_scope_registry.create_model ();
155+
156+ smart_scopes_ready = true;
157 }
158 }
159 catch (Error e)
160@@ -442,8 +455,8 @@
161 bool wait_for_push = false;
162 bool wait_for_search = false;
163 bool sss_query_done = false;
164+ bool sss_query_started = false;
165 uint num_scopes = 0;
166- bool push_done = false;
167
168 // ids of scopes recommended by Smart Scope Service
169 var recommended_search_scopes = new List<SmartScopes.RecommendedScope?> ();
170@@ -523,12 +536,23 @@
171
172 bool empty_query = (scope_search.search_string.strip ().length == 0);
173
174+ // set if this search is a filter update only (e.g. search string is the same)
175+ bool filter_change_only = false;
176+ if (search_query_changed == SearchQueryChange.NOT_CHANGED)
177+ {
178+ filter_change_only = true;
179+ debug ("Filter change only");
180+ }
181+
182 // apply user filters only if search string is unchanged, the query is empty or smart scopes are disabled completly.
183 // this mean user set filters *after* entering a query and we apply them;
184 // otherwise smart scopes recommendations will take precedence.
185 // if search query is empty, then apply default user's filters.
186- if (search_query_changed == SearchQueryChange.NOT_CHANGED || empty_query || sss_client == null)
187+ if (filter_change_only || empty_query || sss_client == null)
188 {
189+ unowned Unity.OptionsFilter categories_filter = scope_search.get_filter ("categories") as Unity.OptionsFilter;
190+ unowned Unity.OptionsFilter sources_filter = scope_search.get_filter ("sources") as Unity.OptionsFilter;
191+
192 // if query is empty but it's not just a filter change (i.e. state is REMOVES_FROM_PREVIOUS_QUERY or NEW_QUERY),
193 // then apply default user filters.
194 if (empty_query && search_query_changed != SearchQueryChange.NOT_CHANGED)
195@@ -537,21 +561,27 @@
196 if (default_filters.length > 0)
197 {
198 debug ("Empty query, applying default filter view");
199- needs_filter_update |= FilterState.set_filters (scope_search, default_filters);
200+ needs_filter_update |= FilterState.set_filters (categories_filter, sources_filter, default_filters);
201 }
202 default_view = true;
203 }
204
205 debug ("Updating filter interrelationships");
206- needs_filter_update |= filter_state.update_filter_relations (scope_search);
207- debug ("Filter interrelationships changed: %s", needs_filter_update.to_string ());
208+ bool relations_changed = filter_state.update_filter_relations (scope_search.channel_id, categories_filter, sources_filter);
209+
210+ // caution: push_filter_settings may get cancelled if we ever yield before;
211+ // in such case internal filter state must be updated later (at the end of search).
212+ if (relations_changed)
213+ push_filters_update (scope_search);
214+ debug ("Filter interrelationships changed: %s", relations_changed.to_string ());
215
216 SearchUtil.scopes_to_query_from_filters (scope_search.get_filter ("sources") as Unity.OptionsFilter,
217 scope_search.get_filter ("categories") as Unity.OptionsFilter,
218 search_scopes);
219
220- // if this search request is a filter change only, then update user's default view in gsettings
221- if (search_query_changed == SearchQueryChange.NOT_CHANGED && empty_query)
222+ // if this search request is a filter change only and query is empty,
223+ // update user's default view in gsettings
224+ if (filter_change_only && empty_query && relations_changed)
225 {
226 default_view = true;
227 debug ("Updating user's default filter view");
228@@ -559,13 +589,29 @@
229 }
230 }
231
232+ // handle keywords (direct search)
233+ string? search_string = null;
234+ bool direct_search = false;
235+ unowned Gee.Set<string>? requested_scope_ids = keywords_search.process_query (
236+ scope_search.search_string, out search_string);
237+ if (requested_scope_ids != null && search_string != null)
238+ {
239+ debug ("Direct search query, search_string = '%s'", search_string);
240+ direct_search = SearchUtil.scopes_to_query_from_requested_ids (requested_scope_ids, search_scopes);
241+ }
242+
243+ if (search_string == null)
244+ search_string = scope_search.search_string;
245+ else
246+ empty_query = (search_string.strip ().length == 0);
247+
248 uint push_data_idle_src = 0;
249
250 // initiate Smart Scopes Search (if enabled and query not empty)
251 if (smart_scopes_ready)
252 {
253 if (empty_query)
254- {
255+ {
256 if (channel_id_map.has_session_id_for_channel (scope_search.channel_id))
257 {
258 debug ("Empty search, removing session mapping for channel %s", scope_search.channel_id);
259@@ -575,7 +621,7 @@
260 else // only sent the query to smart scopes if it's not empty
261 {
262 var session_id = get_session_id (search_query_changed, scope_search.channel_id);
263-
264+
265 AsyncReadyCallback sss_cb = (obj, res) =>
266 {
267 try
268@@ -592,43 +638,67 @@
269 search.callback ();
270 };
271
272- // apply filter to remote scopes query; since we don't really know remote scopes,
273- // we can only pass master scopes ids.
274-
275+ // apply filters to remote scopes query (either keyword-search filters or normal filters)
276 var reg = ScopeRegistry.instance ();
277 string[] remote_scopes_to_query = new string [0];
278- foreach (var scope_id in search_scopes.get_keys ())
279+ var iter = HashTableIter<string, Gee.Set<string>> (search_scopes);
280+ string scope_id;
281+ Gee.Set<string> subscopes;
282+ while (iter.next (out scope_id, out subscopes))
283 {
284- if (reg.is_master (scope_id)) //make sure it's really a master, we don't want 'applications.scope' etc.
285+ // this is to support virtual more_suggestions-* scopes and
286+ // effectively filter out applications.scope and alike.
287+ if (subscopes == null && remote_scope_registry.has_scope (scope_id))
288 remote_scopes_to_query += scope_id;
289- }
290-
291- // timeout to give cancellable a chance for update; it depends on query length (the longer the string, the shorter timeout);
292- // the formula is as follows:
293- // min_delay + (max_delay - min_delay) / query_length
294- // it gives the following values for lengths in 1..inf and min=50, max=100:
295- // 100, 75, 66, 62, 60, 58, 57, 56, 55, 55, 54, 54, 53, 53, 53, 53, 52, 52, 52, ... 50 ...
296- //
297- // note: query is guaranteed to be non-empty at this point, so we're never dividing by 0!
298- GLib.Timeout.add (SMART_SCOPES_QUERY_MIN_DELAY_MS +
299- (SMART_SCOPES_QUERY_MAX_DELAY_MS - SMART_SCOPES_QUERY_MIN_DELAY_MS) /
300- scope_search.search_string.length,
301- ()=>
302- {
303- if (wait_for_search == false && wait_for_push == false && wait_for_sss_query == false)
304- search.callback ();
305- return false;
306- });
307- yield;
308-
309- if (cancellable.is_cancelled ())
310- {
311- debug ("The search for '%s' on channel %s was cancelled", scope_search.search_string, scope_search.channel_id);
312- return;
313- }
314-
315- sss_client.search.begin (scope_search.search_string, session_id, remote_scopes_to_query, scope_mgr.disabled_scopes,
316- (scope_id, row) =>
317+
318+ if (subscopes != null)
319+ {
320+ foreach (var subscope_id in subscopes)
321+ {
322+ if (remote_scope_registry.has_scope (subscope_id))
323+ remote_scopes_to_query += subscope_id;
324+ }
325+ }
326+ };
327+
328+ // if specific scopes were requested via filters or direct search, then
329+ // only send the query to smart scopes server if
330+ // it has (some) of the requested scopes (will be passed via &scopes=)
331+ if ((direct_search || filter_change_only) && (remote_scopes_to_query == null || remote_scopes_to_query.length == 0))
332+ {
333+ debug ("No remote scopes to query based on keyword search or filters");
334+ }
335+ else
336+ {
337+ // timeout to give cancellable a chance for update; it depends on query length (the longer the string, the shorter timeout);
338+ // the formula is as follows:
339+ // min_delay + (max_delay - min_delay) / query_length
340+ // it gives the following values for lengths in 1..inf and min=50, max=100:
341+ // 100, 75, 66, 62, 60, 58, 57, 56, 55, 55, 54, 54, 53, 53, 53, 53, 52, 52, 52, ... 50 ...
342+ //
343+ // note: query is guaranteed to be non-empty at this point, so we're never dividing by 0!
344+ GLib.Timeout.add (SMART_SCOPES_QUERY_MIN_DELAY_MS +
345+ (SMART_SCOPES_QUERY_MAX_DELAY_MS - SMART_SCOPES_QUERY_MIN_DELAY_MS) /
346+ search_string.length,
347+ ()=>
348+ {
349+ if (wait_for_search == false
350+ && wait_for_push == false
351+ && wait_for_sss_query == false)
352+ search.callback ();
353+ return false;
354+ });
355+ yield;
356+
357+ if (cancellable.is_cancelled ())
358+ {
359+ debug ("The search for '%s' on channel %s was cancelled", scope_search.search_string, scope_search.channel_id);
360+ return;
361+ }
362+
363+ sss_query_started = true;
364+ sss_client.search.begin (search_string, session_id, remote_scopes_to_query, scope_mgr.disabled_scopes,
365+ (scope_id, row) =>
366 {
367 var pushed_model = push_data.lookup (scope_id);
368 if (pushed_model == null)
369@@ -650,17 +720,19 @@
370 (server_sid, recommendations) =>
371 {
372 if (server_sid != null)
373- {
374+ {
375 channel_id_map.map_server_sid (scope_search.channel_id, server_sid);
376 int rec_limit_count = 0;
377 foreach (var scope_rec in recommendations)
378 {
379- recommended_search_scopes.append (scope_rec);
380 if (scope_rec.scope_type == SmartScopes.ScopeType.ClientScope)
381 {
382- if (++rec_limit_count == SMART_SCOPES_RECOMMENDATIONS_CUTOFF)
383- break;
384+ if (rec_limit_count == SMART_SCOPES_RECOMMENDATIONS_CUTOFF)
385+ continue; // past cut off, ignore this client scope
386+ ++rec_limit_count;
387 }
388+ recommended_search_scopes.append (scope_rec);
389+ debug ("Got recommended scope: %s, %s", scope_rec.scope_id, scope_rec.scope_type.to_string ());
390 }
391 }
392 else
393@@ -668,6 +740,7 @@
394 warning ("server_sid is null");
395 }
396 }, cancellable, sss_cb);
397+ }
398 }
399 }
400 else
401@@ -683,22 +756,9 @@
402 SearchUtil.scopes_to_query_from_requested_ids (scope_mgr.get_always_run_scopes (), search_scopes);
403 }
404
405- // handle keywords
406- string search_string;
407- bool direct_search = false;
408- unowned Gee.Set<string>? requested_scope_ids = keywords_search.process_query (scope_search.search_string, out search_string);
409- if (requested_scope_ids != null && search_string != null)
410- {
411- debug ("Potential keyword-based query, search_string = '%s'", search_string);
412- direct_search = SearchUtil.scopes_to_query_from_requested_ids (requested_scope_ids, search_scopes);
413- }
414-
415 num_scopes = search_scopes.size ();
416 debug ("Dispatching search to %u scopes, home_channel=%s", num_scopes, scope_search.channel_id);
417
418- if (search_string == null)
419- search_string = scope_search.search_string;
420-
421 // iterate over master scopes, dispatch search query
422 foreach (var scope_id in search_scopes.get_keys ())
423 {
424@@ -716,7 +776,7 @@
425 if (smart_scopes_ready && !empty_query)
426 {
427 // wait for smart scopes service query to finish
428- if (!sss_query_done)
429+ if (sss_query_started && !sss_query_done)
430 {
431 debug ("Waiting for Smart Scopes query to finish");
432 wait_for_sss_query = true;
433@@ -740,15 +800,19 @@
434 debug ("Waiting for results pushing to finish");
435 wait_for_push = true;
436 yield;
437+ wait_for_push = false;
438 }
439 }
440 }
441+ catch (Error e)
442+ {
443+ debug ("The search for '%s' on channel %s was cancelled", scope_search.search_string, scope_search.channel_id);
444+ }
445 finally
446 {
447 if (push_data_idle_src > 0)
448 Source.remove (push_data_idle_src);
449 push_data_idle_src = 0;
450- debug ("The search for '%s' on channel %s was cancelled", scope_search.search_string, scope_search.channel_id);
451 }
452
453 debug ("Got %u recommended scopes from Smart Scope Service", recommended_search_scopes.length ());
454@@ -828,14 +892,10 @@
455
456 // update filter state again, but this time check result counts and send the update only if any of the highlighted masters has no results
457 if (!default_view)
458- needs_filter_update |= SearchUtil.update_filters (search_scopes, use_recommended_scopes ? recommended_search_scopes : null, scope_search, true);
459+ needs_filter_update |= SearchUtil.update_filters (search_scopes, use_recommended_scopes ? recommended_search_scopes : null, scope_search, filter_change_only == false);
460
461 if (needs_filter_update)
462- {
463- var filters = FilterState.create_filter_set (scope_search);
464- debug ("Sending updated filters");
465- scope_search.push_filter_settings (filters);
466- }
467+ push_filters_update (scope_search);
468
469 if (use_recommended_scopes)
470 {
471@@ -848,13 +908,21 @@
472 }
473
474 debug ("All search activities finished");
475+ search_cancel.remove (scope_search.channel_id);
476 }
477
478 public override int category_index_for_scope_id (string scope_id)
479 {
480 return CategoryManager.instance ().get_category_index (scope_id);
481 }
482-
483+
484+ private void push_filters_update (AggregatedScopeSearch scope_search)
485+ {
486+ var filters = FilterState.create_filter_set (scope_search);
487+ debug ("Sending updated filters");
488+ scope_search.push_filter_settings (filters);
489+ }
490+
491 private void signal_categories_order (AggregatedScopeSearch search, List<SmartScopes.RecommendedScope?> recommended_scopes)
492 {
493 var cats = CategoryManager.instance ().get_category_order (search.search_string, search.channel_id, search.results_model, recommended_scopes);
494
495=== modified file 'src/search-util.vala'
496--- src/search-util.vala 2013-03-21 21:51:40 +0000
497+++ src/search-util.vala 2013-04-11 17:02:21 +0000
498@@ -34,14 +34,14 @@
499 {
500 foreach (var scope in recommendations)
501 {
502- var parts = scope.scope_id.split ("-", 2);
503- string master_scope_id = "%s.scope".printf (parts[0]);
504+ string master_scope_id = get_master_id_from_scope_id (scope.scope_id);
505
506 rec_lookup.add (scope.scope_id);
507 rec_lookup.add (master_scope_id);
508 }
509 }
510
511+ var registry = ScopeRegistry.instance ();
512 search_scopes.foreach ((master, subscopes) =>
513 {
514 rec_lookup.add (master);
515@@ -50,6 +50,17 @@
516 foreach (var scope in subscopes)
517 rec_lookup.add (scope);
518 }
519+ else //no subscopes specified - assume all subscopes
520+ {
521+ var node = registry.get_master_scope_node (master);
522+ if (node != null)
523+ {
524+ foreach (var info in node.sub_scopes)
525+ {
526+ rec_lookup.add (info.id);
527+ }
528+ }
529+ }
530 });
531
532 var home_channel = scope_search.channel_id;
533@@ -63,18 +74,15 @@
534 {
535 int result_count = mgr.get_result_count (home_channel, opt.id);
536 debug ("Results for %s: %d", opt.id, result_count);
537+ bool value = false;
538 if (rec_lookup.contains (opt.id))
539- {
540- bool value = check_result_counts == false || result_count > 0;
541- if (opt.active != value)
542- {
543- opt.active = value;
544- changed = true;
545- }
546- }
547+ value = check_result_counts == false || result_count > 0;
548 else
549+ value = false;
550+ if (opt.active != value)
551 {
552- opt.active = false;
553+ opt.active = value;
554+ changed = true;
555 }
556 debug ("Setting category filter %s: %s", opt.id, opt.active.to_string ());
557 }
558@@ -88,23 +96,19 @@
559 {
560 foreach (var opt in sources.options)
561 {
562- var parts = opt.id.split ("-", 2);
563- string master_scope_id = "%s.scope".printf (parts[0]);
564+ string master_scope_id = get_master_id_from_scope_id (opt.id);
565
566- // we don't have result counts for specific scopes, so light them up if master has any results
567- int result_count = mgr.get_result_count (home_channel, master_scope_id);
568+ // light up subscope in sources filter if it has results
569+ int result_count = mgr.get_result_count (home_channel, opt.id);
570+ bool value = false;
571 if (rec_lookup.contains (opt.id))
572- {
573- bool value = check_result_counts == false || result_count > 0;
574- if (opt.active != value)
575- {
576- opt.active = value;
577- changed = true;
578- }
579- }
580+ value = check_result_counts == false || result_count > 0;
581 else
582+ value = false;
583+ if (opt.active != value)
584 {
585- opt.active = false;
586+ opt.active = value;
587+ changed = true;
588 }
589 debug ("Setting sources filter %s: %s", opt.id, opt.active.to_string ());
590 }
591@@ -197,6 +201,14 @@
592 return scopes;
593 }
594
595+ public string? get_master_id_from_scope_id (string scope_id)
596+ {
597+ var parts = scope_id.split ("-", 2);
598+ if (parts.length == 2)
599+ return "%s.scope".printf (parts[0]);
600+ return null;
601+ }
602+
603 public bool scopes_to_query_from_requested_ids (Gee.Set<string> requested_scope_ids, HashTable<string, Gee.Set<string>?> search_scopes)
604 {
605 bool found = false;
606@@ -215,7 +227,7 @@
607 }
608 else // user may have requested a subscope (not a master scope), we need to find a master that needs to receive the query
609 {
610- var master_id = registry.get_master_scope_id (req_scope_id);
611+ var master_id = get_master_id_from_scope_id (req_scope_id);
612 if (master_id != null)
613 {
614 if (!found)
615
616=== modified file 'tests/unit/test-home-scope.vala'
617--- tests/unit/test-home-scope.vala 2013-03-27 15:53:09 +0000
618+++ tests/unit/test-home-scope.vala 2013-04-11 17:02:21 +0000
619@@ -82,6 +82,9 @@
620 Test.add_data_func ("/Unit/SearchUtil/BuildSearchScopesList", Fixture.create<SearchUtilTester> (SearchUtilTester.test_build_search_scopes_list));
621 Test.add_data_func ("/Unit/SearchUtil/SetSubscopesFilterHint", Fixture.create<SearchUtilTester> (SearchUtilTester.test_set_subscopes_filter_hint));
622 Test.add_data_func ("/Unit/SearchUtil/ScopesToQueryFromRequestedIds", Fixture.create<SearchUtilTester> (SearchUtilTester.test_scopes_to_query_from_requested_ids));
623+ Test.add_data_func ("/Unit/SearchUtil/GetMasterScopeIdFromScopeId", Fixture.create<SearchUtilTester> (SearchUtilTester.test_get_master_id_from_scope_id));
624+
625+ Test.add_data_func ("/Unit/FilterState/SetFilters", Fixture.create<FilterStateTester> (FilterStateTester.test_set_filters));
626
627 Test.add_data_func ("/Unit/SmartScopes/Parse", Fixture.create<SmartScopesUtilTester> (SmartScopesUtilTester.test_smart_scopes_parse));
628 Test.add_data_func ("/Unit/SmartScopes/ParseErrors", Fixture.create<SmartScopesUtilTester> (SmartScopesUtilTester.test_smart_scopes_parse_errors));
629@@ -585,6 +588,41 @@
630 assert (subscopes.contains ("masterscope_b-subscope1.scope"));
631 assert (subscopes.contains ("masterscope_b-subscope2.scope"));
632 }
633+
634+ internal void test_get_master_id_from_scope_id ()
635+ {
636+ assert (SearchUtil.get_master_id_from_scope_id ("foo-bar.scope") == "foo.scope");
637+ assert (SearchUtil.get_master_id_from_scope_id ("foo.scope") == null);
638+ }
639+ }
640+
641+ class FilterStateTester: Object, Fixture
642+ {
643+ internal void test_set_filters ()
644+ {
645+ var categories = new Unity.OptionsFilter ();
646+ categories.add_option ("a.scope", "A");
647+
648+ var sources = new Unity.OptionsFilter ();
649+ sources.add_option ("a-b.scope", "A");
650+
651+ var enabled_scopes = new string [0];
652+ assert (FilterState.set_filters (categories, sources, enabled_scopes) == false);
653+ assert (categories.get_option ("a.scope").active == false);
654+ assert (sources.get_option ("a-b.scope").active == false);
655+
656+ enabled_scopes += "a.scope";
657+ assert (FilterState.set_filters (categories, sources, enabled_scopes) == true);
658+ assert (FilterState.set_filters (categories, sources, enabled_scopes) == false);
659+ assert (categories.get_option ("a.scope").active == true);
660+ assert (sources.get_option ("a-b.scope").active == false);
661+
662+ enabled_scopes += "a-b.scope";
663+ assert (FilterState.set_filters (categories, sources, enabled_scopes) == true);
664+ assert (FilterState.set_filters (categories, sources, enabled_scopes) == false);
665+ assert (categories.get_option ("a.scope").active == true);
666+ assert (sources.get_option ("a-b.scope").active == true);
667+ }
668 }
669
670 class SmartScopesUtilTester: Object, Fixture

Subscribers

People subscribed via source and target branches

to all changes: