Merge lp:~jamesh/unity-lens-friends/use-scope-loader into lp:unity-lens-friends
- use-scope-loader
- Merge into trunk
Status: | Merged |
---|---|
Approved by: | Ken VanDine |
Approved revision: | 76 |
Merged at revision: | 66 |
Proposed branch: | lp:~jamesh/unity-lens-friends/use-scope-loader |
Merge into: | lp:unity-lens-friends |
Diff against target: |
848 lines (+260/-280) 8 files modified
configure.ac (+2/-1) data/Makefile.am (+9/-5) data/social.scope.in.in (+3/-0) data/unity-lens-friends.service.in (+1/-1) debian/rules (+1/-0) src/Makefile.am (+16/-13) src/daemon.vala (+210/-179) src/main.vala (+18/-81) |
To merge this branch: | bzr merge lp:~jamesh/unity-lens-friends/use-scope-loader |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Ken VanDine | Approve | ||
PS Jenkins bot (community) | continuous-integration | Approve | |
Michal Hruby (community) | Needs Fixing | ||
Review via email: mp+173878@code.launchpad.net |
Commit message
Convert the scope over to the new Unity.AbstractScope API, and run it through the new scope loader.
Description of the change
Switch scope over to using the new scope loader. This will allow the friends scope to be run in-process with other scopes.
To achieve this, I needed to port the scope over to the new Unity.AbstractScope API. In doing so, I've lost two features:
* no ability to toggle scope visibility.
* no ability to do live update of results.
(These are not available in the new API).
PS Jenkins bot (ps-jenkins) wrote : | # |
Ken VanDine (ken-vandine) wrote : | # |
You can go ahead and remove the commented out code for the features that aren't available in the API, assuming those features aren't planned in the near future. Please bump the libunity depends to reflect current the required version?
Michal Hruby (mhr3) wrote : | # |
Could you optimize the make_preview() method? It's currently linearly walking the entire model, and since we have extensible schema now it should be easy to save a key which will allow sub-linear search (afterall there's an in-memory model sorted by timestamp). Also it's reading fields from the model that are already present in the ScopeResult.
- 71. By James Henstridge
-
Remove commented out code that was incompatible with new scope API.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:71
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
James Henstridge (jamesh) wrote : | # |
mhr3: I had started on that method originally (as visible in the branch history).
I had difficulty making it work together with the handling of the "like"/"unlike" preview actions, where it responds by asking for a new preview. I found I couldn't rely on the state in the Unity.ScopeResult on repeated activations, so reverted back to the original preview logic.
- 72. By James Henstridge
-
Merge from trunk, fixing conflict
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:72
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Ken VanDine (ken-vandine) wrote : | # |
Is it still necessary to ask for a new preview to see the button state change? I always felt request a new preview just to change the text of the action to be a hack.
Ken VanDine (ken-vandine) wrote : | # |
the Module set in social.scope has the wrong path. The .so is getting installed in libdir (multiarch) but the Module path is set to /usr/lib/
Can you either update it to install the .so in the expected path or fix the .scope file to point to the correct location.
- 73. By James Henstridge
-
Reinstate result invalidation code now that it is suported by libunity's
new API. - 74. By James Henstridge
-
Substitute @libdir@ in the scope file, so the paths are correct when
configured with a custom library dir (e.g. for multi-arch).
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:74
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Ken VanDine (ken-vandine) wrote : | # |
It's not creating social.scope, I think you need:
-scope_DATA = $(scope_
+scope_DATA = $(scope_
Also it is installing the .la in the package as well.
- 75. By James Henstridge
-
Fix up definition of scope_DATA.
- 76. By James Henstridge
-
Don't include the .la file in the package.
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:76
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Ken VanDine (ken-vandine) wrote : | # |
Looks good, thanks!
Preview Diff
1 | === modified file 'configure.ac' |
2 | --- configure.ac 2013-07-11 16:35:41 +0000 |
3 | +++ configure.ac 2013-07-26 10:35:05 +0000 |
4 | @@ -2,6 +2,8 @@ |
5 | AM_INIT_AUTOMAKE |
6 | AC_CONFIG_HEADERS([config.h]) |
7 | |
8 | +LT_INIT |
9 | + |
10 | AM_PROG_VALAC([0.17]) |
11 | AC_PROG_CC |
12 | |
13 | @@ -55,7 +57,6 @@ |
14 | Makefile |
15 | src/Makefile |
16 | data/Makefile |
17 | - data/social.scope.in |
18 | data/icons/Makefile |
19 | data/icons/hicolor/Makefile |
20 | data/icons/hicolor/scalable/places/Makefile |
21 | |
22 | === modified file 'data/Makefile.am' |
23 | --- data/Makefile.am 2013-03-22 07:50:01 +0000 |
24 | +++ data/Makefile.am 2013-07-26 10:35:05 +0000 |
25 | @@ -6,11 +6,14 @@ |
26 | dbus_services_DATA = $(service_in_files:.service.in=.service) |
27 | |
28 | %.service: %.service.in |
29 | - sed -e "s|\@libexecdir\@|$(libexecdir)|" $< > $@ |
30 | + sed -e "s|\@bindir\@|$(bindir)|" $< > $@ |
31 | |
32 | -scope_in_files = social.scope.in |
33 | +scope_in_in_files = social.scope.in.in |
34 | scopedir = $(SCOPESDIR) |
35 | -scope_DATA = $(scope_in_files:.scope.in=.scope) |
36 | +scope_DATA = $(scope_in_in_files:.scope.in.in=.scope) |
37 | + |
38 | +%.scope.in: %.scope.in.in |
39 | + sed -e "s|\@prefix\@|$(prefix)|" -e "s|\@libdir\@|$(libdir)|" $< > $@ |
40 | |
41 | @INTLTOOL_SCOPE_RULE@ |
42 | |
43 | @@ -18,9 +21,10 @@ |
44 | |
45 | EXTRA_DIST = \ |
46 | $(scope_DATA) \ |
47 | - $(scope_in_files) \ |
48 | + $(scope_in_in_files) \ |
49 | $(service_in_files) |
50 | |
51 | CLEANFILES = \ |
52 | $(dbus_services_DATA) \ |
53 | - $(scope_DATA) |
54 | + $(scope_DATA) \ |
55 | + $(scope_in_in_files:.scope.in.in=.scope.in) |
56 | |
57 | === modified file 'data/social.scope.in.in' |
58 | --- data/social.scope.in.in 2013-05-28 13:51:14 +0000 |
59 | +++ data/social.scope.in.in 2013-07-26 10:35:05 +0000 |
60 | @@ -7,6 +7,9 @@ |
61 | _SearchHint=Search social network messages |
62 | Shortcut=g |
63 | Type=social |
64 | +RequiredMetadata=account_id[t];status_id[s] |
65 | +Module=@libdir@/unity/unity-scope-friends.so |
66 | +ModuleType=C |
67 | |
68 | # |
69 | # Make translation work with Ubuntu's special handling of keyfiles |
70 | |
71 | === modified file 'data/unity-lens-friends.service.in' |
72 | --- data/unity-lens-friends.service.in 2013-03-22 16:41:04 +0000 |
73 | +++ data/unity-lens-friends.service.in 2013-07-26 10:35:05 +0000 |
74 | @@ -1,3 +1,3 @@ |
75 | [D-BUS Service] |
76 | Name=com.canonical.Unity.Scope.Friends |
77 | -Exec=@libexecdir@/unity-lens-friends |
78 | +Exec=@bindir@/unity-scope-loader social.scope |
79 | |
80 | === modified file 'debian/rules' |
81 | --- debian/rules 2013-04-22 11:04:16 +0000 |
82 | +++ debian/rules 2013-07-26 10:35:05 +0000 |
83 | @@ -11,3 +11,4 @@ |
84 | |
85 | override_dh_install: |
86 | dh_install --fail-missing |
87 | + rm -f debian/unity-lens-friends/usr/lib/*/unity/*.la |
88 | |
89 | === modified file 'src/Makefile.am' |
90 | --- src/Makefile.am 2013-07-11 17:07:55 +0000 |
91 | +++ src/Makefile.am 2013-07-26 10:35:05 +0000 |
92 | @@ -4,10 +4,12 @@ |
93 | |
94 | DATADIR = $(datadir) |
95 | |
96 | -libexec_PROGRAMS = \ |
97 | - unity-lens-friends |
98 | - |
99 | -unity_lens_friends_CPPFLAGS = \ |
100 | +unitylibdir = $(libdir)/unity |
101 | + |
102 | +unitylib_LTLIBRARIES = \ |
103 | + unity-scope-friends.la |
104 | + |
105 | +AM_CPPFLAGS = \ |
106 | -DDATADIR=\"$(DATADIR)\" \ |
107 | -DPREFIX=\"$(PREFIX)\" \ |
108 | -DGETTEXT_PACKAGE=\"$(GETTEXT_PACKAGE)\" \ |
109 | @@ -15,7 +17,7 @@ |
110 | $(BASE_CFLAGS) \ |
111 | -I$(top_srcdir)/src |
112 | |
113 | -unity_lens_friends_VALAFLAGS = \ |
114 | +unity_scope_friends_la_VALAFLAGS = \ |
115 | -C \ |
116 | -X -I$(top_srcdir)/src \ |
117 | --vapidir $(top_srcdir)/vapi \ |
118 | @@ -29,31 +31,32 @@ |
119 | --basedir=. \ |
120 | $(MAINTAINER_VALAFLAGS) |
121 | |
122 | -unity_lens_friends_LDADD = \ |
123 | +unity_scope_friends_la_LDFLAGS = -shared -module -avoid-version -no-undefined |
124 | +unity_scope_friends_la_LIBADD = \ |
125 | $(BASE_LIBS) \ |
126 | $(NULL) |
127 | |
128 | -unity_lens_friends_VALASOURCES = \ |
129 | +unity_scope_friends_la_VALASOURCES = \ |
130 | daemon.vala \ |
131 | main.vala \ |
132 | schemas.vala \ |
133 | $(NULL) |
134 | |
135 | -unity_lens_friends_SOURCES = \ |
136 | - $(unity_lens_friends_VALASOURCES:.vala=.c) \ |
137 | +unity_scope_friends_la_SOURCES = \ |
138 | + $(unity_scope_friends_la_VALASOURCES:.vala=.c) \ |
139 | $(NULL) |
140 | |
141 | -BUILT_SOURCES += unity_lens_friends.vala.stamp \ |
142 | +BUILT_SOURCES += unity_scope_friends.vala.stamp \ |
143 | $(NULL) |
144 | |
145 | EXTRA_DIST += \ |
146 | - unity_lens_friends.vala.stamp \ |
147 | + unity_scope_friends.vala.stamp \ |
148 | $(unity_lens_friends_VALASOURCES) \ |
149 | $(BUILT_SOURCES) \ |
150 | $(NULL) |
151 | |
152 | -unity_lens_friends.vala.stamp: $(unity_lens_friends_VALASOURCES) |
153 | - $(AM_V_GEN) $(VALAC) $(unity_lens_friends_VALAFLAGS) $^ |
154 | +unity_scope_friends.vala.stamp: $(unity_scope_friends_la_VALASOURCES) |
155 | + $(AM_V_GEN) $(VALAC) $(unity_scope_friends_la_VALAFLAGS) $^ |
156 | touch unity_lens_friends.vala.stamp |
157 | |
158 | CLEANFILES += \ |
159 | |
160 | === modified file 'src/daemon.vala' |
161 | --- src/daemon.vala 2013-07-11 16:57:58 +0000 |
162 | +++ src/daemon.vala 2013-07-26 10:35:05 +0000 |
163 | @@ -1,5 +1,5 @@ |
164 | /* |
165 | - * Copyright (C) 2011 Canonical Ltd. |
166 | + * Copyright (C) 2011-13 Canonical Ltd. |
167 | * |
168 | * This program is free software: you can redistribute it and/or modify it |
169 | * under the terms of the GNU General Public License version 3, as published |
170 | @@ -30,14 +30,13 @@ |
171 | const string STRIP_LINKS = """</?a[^>]*>"""; |
172 | |
173 | /** |
174 | - * The Daemon class implements all of the logic for the place. |
175 | + * The Scope class implements all of the logic for the place. |
176 | * |
177 | */ |
178 | - public class Daemon : GLib.Object |
179 | + public class FriendsScope : Unity.AbstractScope |
180 | { |
181 | - private Unity.DeprecatedScope scope; |
182 | - private Unity.PreferencesManager preferences = Unity.PreferencesManager.get_default (); |
183 | - private unowned Dee.ResourceManager resources; |
184 | + private Unity.FilterSet? filters; |
185 | + |
186 | private Dee.Model? _model = null; |
187 | private Dee.SharedModel? _streams_model = null; |
188 | private Dee.Filter _sort_filter; |
189 | @@ -52,23 +51,9 @@ |
190 | private Ag.Manager _account_manager; |
191 | private bool _has_accounts = false; |
192 | private HashMap<string,Variant> featureMap; |
193 | - private Variant empty_asv; |
194 | |
195 | - construct |
196 | + public FriendsScope () |
197 | { |
198 | - empty_asv = new Variant.array (VariantType.VARDICT.element (), {}); |
199 | - scope = new Unity.DeprecatedScope("/com/canonical/unity/scope/friends", "friends.scope"); |
200 | - scope.search_in_global = false; |
201 | - scope.search_hint = _("Search social network messages"); |
202 | - scope.visible = false; |
203 | - try |
204 | - { |
205 | - scope.export (); |
206 | - } catch (GLib.IOError e) |
207 | - { |
208 | - warning ("failed to export lens: %s", e.message); |
209 | - } |
210 | - |
211 | featureMap = new HashMap<string,Variant> (); |
212 | |
213 | // Check for accounts |
214 | @@ -81,11 +66,10 @@ |
215 | if (accts.length () > 0 && !_has_accounts) |
216 | { |
217 | _has_accounts = true; |
218 | - setup (); |
219 | + setup_friends (); |
220 | } |
221 | else if (accts.length () == 0) |
222 | { |
223 | - scope.visible = false; |
224 | _has_accounts = false; |
225 | } |
226 | else |
227 | @@ -95,28 +79,14 @@ |
228 | }); |
229 | } |
230 | |
231 | - |
232 | - void setup () |
233 | - { |
234 | - setup_friends (); |
235 | - |
236 | - scope.visible = true; |
237 | - scope.preview_uri.connect (preview); |
238 | - |
239 | - /* Listen for filter changes */ |
240 | - scope.generate_search_key.connect ((lens_search) => |
241 | - { |
242 | - return lens_search.search_string.strip (); |
243 | - }); |
244 | - scope.search_changed.connect ((search, search_type, cancellable) => |
245 | - { |
246 | - dispatch_search.begin (search, search_type, cancellable); |
247 | - }); |
248 | - |
249 | - preferences.notify["remote-content-search"].connect ((obj, pspec) => |
250 | - { |
251 | - scope.queue_search_changed (SearchType.DEFAULT); |
252 | - }); |
253 | + public override string get_group_name () |
254 | + { |
255 | + return BUS_NAME; |
256 | + } |
257 | + |
258 | + public override string get_unique_name () |
259 | + { |
260 | + return "/com/canonical/unity/scope/friends"; |
261 | } |
262 | |
263 | private void map_account_features () |
264 | @@ -142,15 +112,12 @@ |
265 | if (accts.length() > 0) |
266 | { |
267 | _has_accounts = true; |
268 | - setup (); |
269 | + setup_friends (); |
270 | } |
271 | } |
272 | |
273 | private void setup_friends () |
274 | { |
275 | - populate_categories (); |
276 | - populate_filters (); |
277 | - |
278 | Intl.setlocale(LocaleCategory.COLLATE, "C"); |
279 | |
280 | _streams_model = new Dee.SharedModel ("com.canonical.Friends.Streams"); |
281 | @@ -159,13 +126,13 @@ |
282 | { |
283 | _streams_model.notify["synchronized"].connect (on_synchronized); |
284 | _streams_model.row_added.connect ((source) => { |
285 | - scope.queue_search_changed (SearchType.DEFAULT); |
286 | + results_invalidated (SearchType.DEFAULT); |
287 | }); |
288 | _streams_model.row_removed.connect ((source) => { |
289 | - scope.queue_search_changed (SearchType.DEFAULT); |
290 | + results_invalidated (SearchType.DEFAULT); |
291 | }); |
292 | _streams_model.row_changed.connect ((source) => { |
293 | - scope.queue_search_changed (SearchType.DEFAULT); |
294 | + results_invalidated (SearchType.DEFAULT); |
295 | }); |
296 | } |
297 | } |
298 | @@ -203,10 +170,12 @@ |
299 | _index = new Dee.TreeIndex (_model, _analyzer, reader); |
300 | } |
301 | |
302 | - private void populate_filters () |
303 | + public override Unity.FilterSet get_filters () |
304 | { |
305 | - var filters = new Unity.FilterSet (); |
306 | + if (filters != null) |
307 | + return filters; |
308 | |
309 | + filters = new Unity.FilterSet (); |
310 | /* Stream filter */ |
311 | { |
312 | var filter = new CheckOptionFilter ("stream", _("Stream")); |
313 | @@ -230,18 +199,17 @@ |
314 | filters.add (filter); |
315 | } |
316 | |
317 | - scope.filters = filters; |
318 | - |
319 | _account_manager.account_created.connect ((id) => { |
320 | debug ("ACCOUNT ADDED"); |
321 | var _acct = _account_manager.get_account ((Ag.AccountId)id); |
322 | - var filter = scope.filters.get_filter_by_id ("account_id") as CheckOptionFilter; |
323 | + var filter = filters.get_filter_by_id ("account_id") as CheckOptionFilter; |
324 | create_account_filter_option (filter, _acct); |
325 | map_account_features (); |
326 | }); |
327 | |
328 | /* FIXME: we need a way to remove an option or remove and re-add the |
329 | * filter on account deletion */ |
330 | + return filters; |
331 | } |
332 | |
333 | private Unity.CheckOptionFilter create_account_filter () |
334 | @@ -274,8 +242,7 @@ |
335 | filter.add_option (_acct.id.to_string(), _provider + "/" + _name, icon); |
336 | } |
337 | |
338 | - |
339 | - private void populate_categories () |
340 | + public override Unity.CategorySet get_categories () |
341 | { |
342 | var categories = new Unity.CategorySet (); |
343 | Icon icon; |
344 | @@ -315,51 +282,33 @@ |
345 | cat.content_type = CategoryContentType.SOCIAL; |
346 | categories.add (cat); |
347 | |
348 | - scope.categories = categories; |
349 | - } |
350 | - |
351 | - |
352 | - private bool is_empty_search (DeprecatedScopeSearch search) |
353 | - { |
354 | - return search.search_string.strip () == ""; |
355 | - } |
356 | - |
357 | - private async void dispatch_search (DeprecatedScopeSearch search, SearchType search_type, GLib.Cancellable cancellable) |
358 | - { |
359 | - /** |
360 | - * only perform the request if the user has not disabled |
361 | - * online/commercial suggestions. That will hide the category as well. |
362 | - */ |
363 | - if (preferences.remote_content_search != Unity.PreferencesManager.RemoteContent.ALL) |
364 | - { |
365 | - search.results_model.clear (); |
366 | - search.finished (); |
367 | - return; |
368 | - } |
369 | - |
370 | - // FIXME: no results for home screen of the dash? |
371 | - if (search_type == SearchType.GLOBAL && is_empty_search (search)) |
372 | - { |
373 | - search.finished (); |
374 | - return; |
375 | - } |
376 | - |
377 | - update_results_model (search, null); |
378 | - debug ("%u results", search.results_model.get_n_rows ()); |
379 | - search.finished (); |
380 | - } |
381 | - |
382 | - /* Generic method to update a results model. We do it like this to minimize |
383 | - * code dup between updating the global- and the entry results model */ |
384 | - private void update_results_model (DeprecatedScopeSearch search, |
385 | - Categories? category) |
386 | - { |
387 | - debug ("%u TOTAL ROWS", _model.get_n_rows ()); |
388 | + return categories; |
389 | + } |
390 | + |
391 | + public override Unity.Schema get_schema () |
392 | + { |
393 | + var schema = new Unity.Schema (); |
394 | + schema.add_field ("account_id", "t", Unity.Schema.FieldType.REQUIRED); |
395 | + schema.add_field ("status_id", "s", Unity.Schema.FieldType.REQUIRED); |
396 | + return schema; |
397 | + } |
398 | + |
399 | + public override string normalize_search_query (string search_query) |
400 | + { |
401 | + return search_query.strip (); |
402 | + } |
403 | + |
404 | + public override Unity.ScopeSearchBase create_search_for_query (Unity.SearchContext search_context) |
405 | + { |
406 | + return new FriendsSearch (this, search_context); |
407 | + } |
408 | + |
409 | + public void perform_search (Unity.SearchContext context) |
410 | + { |
411 | unowned Dee.ModelIter iter, end; |
412 | |
413 | - var results_model = search.results_model; |
414 | var stream_ids = new Gee.ArrayList<string> (); |
415 | - var filter = search.get_filter("stream") as CheckOptionFilter; |
416 | + var filter = context.filter_state.get_filter_by_id ("stream") as CheckOptionFilter; |
417 | if (filter.filtering) |
418 | { |
419 | foreach (Unity.FilterOption option in filter.options) |
420 | @@ -372,7 +321,7 @@ |
421 | } |
422 | |
423 | var account_ids = new Gee.ArrayList<string> (); |
424 | - filter = search.get_filter ("account_id") as CheckOptionFilter; |
425 | + filter = context.filter_state.get_filter_by_id ("account_id") as CheckOptionFilter; |
426 | if (filter.filtering) |
427 | { |
428 | foreach (Unity.FilterOption option in filter.options) |
429 | @@ -384,8 +333,6 @@ |
430 | } |
431 | } |
432 | |
433 | - results_model.clear (); |
434 | - |
435 | if (_model == null) |
436 | setup_friends (); |
437 | |
438 | @@ -397,7 +344,7 @@ |
439 | |
440 | var term_list = Object.new (typeof (Dee.TermList)) as Dee.TermList; |
441 | // search only the folded terms, FIXME: is that a good idea? |
442 | - _analyzer.tokenize (_ascii_filter.apply (search.search_string), term_list); |
443 | + _analyzer.tokenize (_ascii_filter.apply (context.search_query), term_list); |
444 | |
445 | var matches = new Sequence<Dee.ModelIter> (); |
446 | for (uint i = 0; i < term_list.num_terms (); i++) |
447 | @@ -438,7 +385,7 @@ |
448 | |
449 | if (matches_filters (_model, iter, stream_ids, account_ids)) |
450 | { |
451 | - add_result (_model, iter, results_model); |
452 | + add_result (_model, iter, context.result_set); |
453 | } |
454 | |
455 | match_iter = match_iter.next (); |
456 | @@ -451,7 +398,7 @@ |
457 | { |
458 | if (matches_filters (_model, iter, stream_ids, account_ids)) |
459 | { |
460 | - add_result (_model, iter, results_model); |
461 | + add_result (_model, iter, context.result_set); |
462 | } |
463 | iter = _model.next (iter); |
464 | } |
465 | @@ -484,51 +431,51 @@ |
466 | return account_match && stream_match; |
467 | } |
468 | |
469 | - private void add_result (Dee.Model model, Dee.ModelIter iter, Dee.Model results_model) |
470 | + private void add_result (Dee.Model model, Dee.ModelIter iter, Unity.ResultSet result_set) |
471 | { |
472 | - Categories group = Categories.MESSAGES; |
473 | - string _img_uri = null; |
474 | + var result = Unity.ScopeResult (); |
475 | |
476 | - unowned string stream_id = |
477 | + result.uri = model.get_string (iter, StreamModelColumn.URL); |
478 | + unowned string stream_id = |
479 | model.get_string (iter, StreamModelColumn.STREAM); |
480 | - switch (stream_id) |
481 | - { |
482 | - case "messages": group = Categories.MESSAGES; break; |
483 | - case "mentions": |
484 | - if (model.get_bool (iter, StreamModelColumn.FROM_ME)) |
485 | - group = Categories.MESSAGES; |
486 | - else |
487 | - group = Categories.REPLIES; |
488 | - break; |
489 | - case "images": group = Categories.IMAGES; break; |
490 | - case "videos": group = Categories.VIDEOS; break; |
491 | - case "links": group = Categories.LINKS; break; |
492 | - case "private": group = Categories.PRIVATE; break; |
493 | - case "public": group = Categories.PUBLIC; break; |
494 | - } |
495 | - |
496 | - string uri = model.get_string (iter, StreamModelColumn.URL); |
497 | string _icon_uri = model.get_string (iter, StreamModelColumn.ICON_URI); |
498 | if (stream_id == "images") |
499 | - _img_uri = model.get_string (iter, StreamModelColumn.LINK_PICTURE); |
500 | + result.icon_hint = model.get_string (iter, StreamModelColumn.LINK_PICTURE); |
501 | else if (stream_id == "videos") |
502 | { |
503 | - _img_uri = model.get_string (iter, StreamModelColumn.LINK_PICTURE); |
504 | - if (_img_uri.length < 1) |
505 | - _img_uri = get_avatar_path (_icon_uri); |
506 | + result.icon_hint = model.get_string (iter, StreamModelColumn.LINK_PICTURE); |
507 | + if (result.icon_hint.length < 1) |
508 | + result.icon_hint = get_avatar_path (_icon_uri); |
509 | } |
510 | else |
511 | - _img_uri = get_avatar_path (_icon_uri); |
512 | - |
513 | - results_model.append (uri, |
514 | - _img_uri, |
515 | - group, |
516 | - ResultType.PERSONAL, |
517 | - "text/html", |
518 | - GLib.Markup.escape_text (_model.get_string(iter, StreamModelColumn.SENDER)), |
519 | - sanitize_message (_model.get_string(iter, StreamModelColumn.MESSAGE)), |
520 | - uri, |
521 | - empty_asv); |
522 | + result.icon_hint = get_avatar_path (_icon_uri); |
523 | + |
524 | + result.category = Categories.MESSAGES; |
525 | + switch (stream_id) |
526 | + { |
527 | + case "messages": result.category = Categories.MESSAGES; break; |
528 | + case "mentions": |
529 | + if (model.get_bool (iter, StreamModelColumn.FROM_ME)) |
530 | + result.category = Categories.MESSAGES; |
531 | + else |
532 | + result.category = Categories.REPLIES; |
533 | + break; |
534 | + case "images": result.category = Categories.IMAGES; break; |
535 | + case "videos": result.category = Categories.VIDEOS; break; |
536 | + case "links": result.category = Categories.LINKS; break; |
537 | + case "private": result.category = Categories.PRIVATE; break; |
538 | + case "public": result.category = Categories.PUBLIC; break; |
539 | + } |
540 | + result.result_type = ResultType.PERSONAL; |
541 | + result.mimetype = "text/html"; |
542 | + result.title = GLib.Markup.escape_text (_model.get_string(iter, StreamModelColumn.SENDER)); |
543 | + result.comment = sanitize_message (_model.get_string(iter, StreamModelColumn.MESSAGE)); |
544 | + result.dnd_uri = result.uri; |
545 | + result.metadata = new HashTable<string,Variant> (str_hash, str_equal); |
546 | + result.metadata["account_id"] = new Variant.uint64 (model.get_uint64(iter, StreamModelColumn.ACCOUNT_ID)); |
547 | + result.metadata["status_id"] = new Variant.string (model.get_string (iter, StreamModelColumn.MESSAGE_ID)); |
548 | + |
549 | + result_set.add_result (result); |
550 | } |
551 | |
552 | private string get_avatar_path (string uri) |
553 | @@ -552,7 +499,12 @@ |
554 | return _avatar_cache_image; |
555 | } |
556 | |
557 | - public Unity.Preview preview (string uri) |
558 | + public override Unity.ResultPreviewer create_previewer (Unity.ScopeResult result, Unity.SearchMetadata metadata) |
559 | + { |
560 | + return new FriendsResultPreviewer (this, result, metadata); |
561 | + } |
562 | + |
563 | + public Unity.Preview make_preview (string uri) |
564 | { |
565 | debug ("Previewing: %s", uri); |
566 | Unity.SocialPreview preview = null; |
567 | @@ -632,21 +584,6 @@ |
568 | var view_action = new Unity.PreviewAction ("view", _("View"), icon); |
569 | preview.add_action (view_action); |
570 | |
571 | - view_action.activated.connect ((source) => { |
572 | - try |
573 | - { |
574 | - if (GLib.AppInfo.launch_default_for_uri (uri, null)) |
575 | - { |
576 | - return new Unity.ActivationResponse (Unity.HandledType.HIDE_DASH); |
577 | - } |
578 | - } |
579 | - catch (GLib.Error e) |
580 | - { |
581 | - warning ("Failed to launch default application for uri '%s': %s", uri, e.message); |
582 | - } |
583 | - return new Unity.ActivationResponse (Unity.HandledType.NOT_HANDLED); |
584 | - }); |
585 | - |
586 | if ("retweet" in _features) |
587 | { |
588 | if (_account_service == "twitter") |
589 | @@ -655,14 +592,6 @@ |
590 | retweet_str = _("Share"); |
591 | var retweet_action = new Unity.PreviewAction ("retweet", retweet_str, icon); |
592 | preview.add_action (retweet_action); |
593 | - retweet_action.activated.connect ((source) => { |
594 | - Idle.add (() => { |
595 | - var dispatcher = new Friends.Dispatcher (); |
596 | - dispatcher.retweet (_account_id, _status_id); |
597 | - return false; |
598 | - }); |
599 | - return new Unity.ActivationResponse (Unity.HandledType.SHOW_PREVIEW); |
600 | - }); |
601 | } |
602 | |
603 | bool from_me = model.get_bool (iter, StreamModelColumn.FROM_ME); |
604 | @@ -682,16 +611,6 @@ |
605 | like_str = liked ? _("Unlike") : _("Like"); |
606 | var like_action = new Unity.PreviewAction ("like", like_str, icon); |
607 | preview.add_action (like_action); |
608 | - like_action.activated.connect ((source) => { |
609 | - Idle.add (() => { |
610 | - var dispatcher = new Friends.Dispatcher (); |
611 | - var ret = liked ? dispatcher.unlike (_account_id, _status_id) : dispatcher.like (_account_id, _status_id); |
612 | - return false; |
613 | - }); |
614 | - model.set_value (iter, StreamModelColumn.LIKED, !liked); |
615 | - Unity.Preview new_preview = this.preview (uri); |
616 | - return new Unity.ActivationResponse.with_preview (new_preview); |
617 | - }); |
618 | } |
619 | |
620 | return preview; |
621 | @@ -739,6 +658,118 @@ |
622 | return null; |
623 | } |
624 | |
625 | - |
626 | - } /* End Daemon class */ |
627 | + public override Unity.ActivationResponse? activate (Unity.ScopeResult result, Unity.SearchMetadata metadata, string? action_id) |
628 | + { |
629 | + uint _account_id = (uint)result.metadata["account_id"].get_uint64(); |
630 | + var _status_id = result.metadata["status_id"].get_string(); |
631 | + if (action_id == "retweet") |
632 | + { |
633 | + Idle.add (() => { |
634 | + var dispatcher = new Friends.Dispatcher (); |
635 | + dispatcher.retweet (_account_id, _status_id); |
636 | + return false; |
637 | + }); |
638 | + return new Unity.ActivationResponse (Unity.HandledType.SHOW_PREVIEW); |
639 | + } |
640 | + else if (action_id == "like") |
641 | + { |
642 | + var old_liked = toggle_liked (result.uri); |
643 | + Idle.add (() => { |
644 | + var dispatcher = new Friends.Dispatcher (); |
645 | + if (old_liked) |
646 | + { |
647 | + dispatcher.unlike (_account_id, _status_id); |
648 | + } |
649 | + else |
650 | + { |
651 | + dispatcher.like (_account_id, _status_id); |
652 | + } |
653 | + return false; |
654 | + }); |
655 | + var new_preview = make_preview (result.uri); |
656 | + return new Unity.ActivationResponse.with_preview (new_preview); |
657 | + } |
658 | + else |
659 | + { |
660 | + // Default action, or "view" |
661 | + return new Unity.ActivationResponse (Unity.HandledType.NOT_HANDLED); |
662 | + } |
663 | + } |
664 | + |
665 | + public bool toggle_liked (string uri) |
666 | + { |
667 | + var model = _streams_model; |
668 | + var iter = model.get_first_iter (); |
669 | + var end = model.get_last_iter (); |
670 | + while (iter != end) |
671 | + { |
672 | + var row_uri = model.get_string (iter, StreamModelColumn.URL); |
673 | + if (row_uri == uri) |
674 | + { |
675 | + var liked = model.get_bool (iter, StreamModelColumn.LIKED); |
676 | + model.set_value (iter, StreamModelColumn.LIKED, !liked); |
677 | + return liked; |
678 | + } |
679 | + iter = model.next (iter); |
680 | + } |
681 | + return false; |
682 | + } |
683 | + } |
684 | + |
685 | + public class FriendsSearch : Unity.ScopeSearchBase |
686 | + { |
687 | + private FriendsScope scope; |
688 | + |
689 | + public FriendsSearch(FriendsScope scope, Unity.SearchContext search_context) |
690 | + { |
691 | + this.scope = scope; |
692 | + this.search_context = search_context; |
693 | + } |
694 | + |
695 | + public override void run () |
696 | + { |
697 | + // FIXME: no results for home screen of the dash? |
698 | + var context = this.search_context; |
699 | + if (context.search_type == SearchType.GLOBAL && |
700 | + context.search_query.strip () == "") |
701 | + { |
702 | + return; |
703 | + } |
704 | + |
705 | + this.scope.perform_search (context); |
706 | + } |
707 | + |
708 | + public override void run_async (Unity.ScopeSearchBaseCallback callback) |
709 | + { |
710 | + // Run the search in the main thread, to avoid |
711 | + // synchronisation problems. |
712 | + run (); |
713 | + callback (this); |
714 | + } |
715 | + } |
716 | + |
717 | + public class FriendsResultPreviewer : Unity.ResultPreviewer |
718 | + { |
719 | + private FriendsScope scope; |
720 | + |
721 | + public FriendsResultPreviewer (FriendsScope scope, Unity.ScopeResult result, Unity.SearchMetadata metadata) |
722 | + { |
723 | + this.scope = scope; |
724 | + set_scope_result (result); |
725 | + set_search_metadata (metadata); |
726 | + } |
727 | + |
728 | + public override Unity.AbstractPreview? run () |
729 | + { |
730 | + return scope.make_preview (result.uri); |
731 | + } |
732 | + |
733 | + public override void run_async (Unity.AbstractPreviewCallback callback) |
734 | + { |
735 | + // Build preview in the main thread, to avoid |
736 | + // synchronisation problems. |
737 | + var preview = run (); |
738 | + callback (this, preview); |
739 | + } |
740 | + } |
741 | } /* end Friends namespace */ |
742 | |
743 | === modified file 'src/main.vala' |
744 | --- src/main.vala 2013-03-20 08:37:09 +0000 |
745 | +++ src/main.vala 2013-07-26 10:35:05 +0000 |
746 | @@ -21,84 +21,21 @@ |
747 | using GLib; |
748 | using Config; |
749 | |
750 | -namespace UnityFriends { |
751 | - |
752 | - static Application? app = null; |
753 | - static Daemon? daemon = null; |
754 | - |
755 | - /* Check if a given well known DBus is owned. |
756 | - * WARNING: This does sync IO! */ |
757 | - public static bool dbus_name_has_owner (string name) |
758 | - { |
759 | - try { |
760 | - bool has_owner; |
761 | - DBusConnection bus = Bus.get_sync (BusType.SESSION); |
762 | - Variant result = bus.call_sync ("org.freedesktop.DBus", |
763 | - "/org/freedesktop/dbus", |
764 | - "org.freedesktop.DBus", |
765 | - "NameHasOwner", |
766 | - new Variant ("(s)", name), |
767 | - new VariantType ("(b)"), |
768 | - DBusCallFlags.NO_AUTO_START, |
769 | - -1); |
770 | - result.get ("(b)", out has_owner); |
771 | - return has_owner; |
772 | - } catch (Error e) { |
773 | - warning ("Unable to decide if '%s' is running: %s", name, e.message); |
774 | - } |
775 | - |
776 | - return false; |
777 | - } |
778 | - |
779 | - public static int main (string[] args) |
780 | - { |
781 | - /* Sort up locale to get translations but also sorting and |
782 | - * punctuation right */ |
783 | - GLib.Intl.textdomain (Config.PACKAGE); |
784 | - GLib.Intl.bindtextdomain (Config.PACKAGE, Config.LOCALE_DIR); |
785 | - GLib.Intl.bind_textdomain_codeset (Config.PACKAGE, "UTF-8"); |
786 | - GLib.Intl.setlocale (GLib.LocaleCategory.ALL, ""); |
787 | - |
788 | - /* Make sure the desktop appinfos are picked up correctly */ |
789 | - DesktopAppInfo.set_desktop_env ("GNOME"); |
790 | - |
791 | - /* Workaround for https://bugzilla.gnome.org/show_bug.cgi?id=640714 |
792 | - * GApplication.register() call owns our DBus name in a sync manner |
793 | - * making it race against GDBus' worker thread to export our |
794 | - * objects on the bus before/after owning our name and receiving |
795 | - * method calls on our objects (which may not yet be up!)*/ |
796 | - if (dbus_name_has_owner (BUS_NAME)) |
797 | - { |
798 | - print ("Another instance of the Unity Friends Daemon " + |
799 | - "already appears to be running.\nBailing out.\n"); |
800 | - return 2; |
801 | - } |
802 | - |
803 | - /* Now register our DBus objects *before* acquiring the name! |
804 | - * See above for reasons */ |
805 | - daemon = new Daemon (); |
806 | - |
807 | - /* Use GApplication directly for single instance app functionality */ |
808 | - app = new Application (BUS_NAME, ApplicationFlags.IS_SERVICE); |
809 | - try { |
810 | - app.register (); |
811 | - } catch (Error e) { |
812 | - /* FIXME: We get this error if another daemon is already running, |
813 | - * but it uses a generic error so we can't detect this reliably... */ |
814 | - print ("Failed to start files daemon: %s\n", e.message); |
815 | - return 1; |
816 | - } |
817 | - |
818 | - if (app.get_is_remote ()) |
819 | - { |
820 | - print ("Another instance of the Unity Friends Daemon " + |
821 | - "already appears to be running.\nBailing out.\n"); |
822 | - return 2; |
823 | - } |
824 | - |
825 | - /* Holding the app makes sure the GApplication doesn't exit */ |
826 | - app.hold(); |
827 | - return app.run (); |
828 | - } |
829 | - |
830 | -} /* namespace */ |
831 | +public int unity_scope_module_get_version () |
832 | +{ |
833 | + return Unity.SCOPE_API_VERSION; |
834 | +} |
835 | + |
836 | +public List<Unity.AbstractScope> unity_scope_module_load_scopes () throws Error |
837 | +{ |
838 | + /* Sort up locale to get translations but also sorting and |
839 | + * punctuation right */ |
840 | + GLib.Intl.bindtextdomain (Config.PACKAGE, Config.LOCALE_DIR); |
841 | + GLib.Intl.bind_textdomain_codeset (Config.PACKAGE, "UTF-8"); |
842 | + GLib.Intl.setlocale (GLib.LocaleCategory.ALL, ""); |
843 | + |
844 | + List<Unity.AbstractScope> scopes = null; |
845 | + var scope = new UnityFriends.FriendsScope (); |
846 | + scopes.append (scope); |
847 | + return scopes; |
848 | +} |
PASSED: Continuous integration, rev:70 jenkins. qa.ubuntu. com/job/ unity-lens- friends- ci/4/ jenkins. qa.ubuntu. com/job/ unity-lens- friends- saucy-amd64- ci/3 jenkins. qa.ubuntu. com/job/ unity-lens- friends- saucy-armhf- ci/3 jenkins. qa.ubuntu. com/job/ unity-lens- friends- saucy-i386- ci/3
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild: s-jenkins: 8080/job/ unity-lens- friends- ci/4/rebuild
http://