Merge lp:~stolowski/unity-lens-applications/merge-smartscopes2 into lp:unity-lens-applications
- merge-smartscopes2
- Merge into trunk
Status: | Merged |
---|---|
Approved by: | Łukasz Zemczak |
Approved revision: | 343 |
Merged at revision: | 338 |
Proposed branch: | lp:~stolowski/unity-lens-applications/merge-smartscopes2 |
Merge into: | lp:unity-lens-applications |
Diff against target: |
2525 lines (+1036/-436) 24 files modified
Makefile.am (+6/-11) applications.lens.in.in (+0/-12) applications.scope.in.in (+13/-0) commands.scope.in.in (+6/-4) configure.ac (+14/-7) data/Makefile.am (+2/-2) data/unity-scope-applications.service.in (+1/-1) debian/changelog (+6/-0) debian/control (+2/-2) po/POTFILES.in (+2/-2) src/Makefile.am (+2/-1) src/config.vala.in (+3/-1) src/daemon.vala (+617/-256) src/main.vala (+4/-4) src/runner.vala (+99/-112) src/schemas.vala (+10/-0) src/unity-package-search.cc (+127/-7) src/unity-package-search.h (+7/-2) src/utils.vala (+93/-0) src/xapian-utils.vala (+7/-5) tests/unit/Makefile.am (+2/-0) tests/unit/test-xapian-utils.vala (+7/-7) vapi/unity-package-search.deps (+1/-0) vapi/unity-package-search.vapi (+5/-0) |
To merge this branch: | bzr merge lp:~stolowski/unity-lens-applications/merge-smartscopes2 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Łukasz Zemczak | Approve | ||
PS Jenkins bot (community) | continuous-integration | Approve | |
Review via email: mp+164230@code.launchpad.net |
Commit message
Merge new scope API changes (100 scopes feature).
Description of the change
Merge new scope API changes (100 scopes feature).
Note: needs libunity 7.0.0 to land (should happen very soon).
- 341. By Paweł Stołowski
-
Fixed required versions of libunity-dev and unity.
PS Jenkins bot (ps-jenkins) wrote : | # |
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:341
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
- 342. By Paweł Stołowski
-
Bumped version once more and updated changelog.
- 343. By Paweł Stołowski
-
Version should actually change 7.0.0...
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:342
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:343
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Łukasz Zemczak (sil2100) wrote : | # |
Looks good, but it's late, soo... Anyway, approved!
Preview Diff
1 | === modified file 'Makefile.am' |
2 | --- Makefile.am 2013-02-15 10:11:07 +0000 |
3 | +++ Makefile.am 2013-05-16 21:22:23 +0000 |
4 | @@ -4,18 +4,14 @@ |
5 | # |
6 | # Install the applications.lens file |
7 | # |
8 | -lens_in_files = applications.lens.in |
9 | -lensdir = $(datadir)/unity/lenses/applications |
10 | -lens_DATA = $(lens_in_files:.lens.in=.lens) |
11 | - |
12 | -cmdlens_in_files = commands.lens.in |
13 | -cmdlensdir = $(datadir)/unity/lenses/commands |
14 | -cmdlens_DATA = $(cmdlens_in_files:.lens.in=.lens) |
15 | +scope_in_files = applications.scope.in commands.scope.in |
16 | +scopedir = $(datadir)/unity/scopes |
17 | +scope_DATA = $(scope_in_files:.scope.in=.scope) |
18 | |
19 | icondir = $(datadir)/unity/themes |
20 | icon_DATA = applications.png |
21 | |
22 | -@INTLTOOL_LENS_RULE@ |
23 | +@INTLTOOL_SCOPE_RULE@ |
24 | |
25 | DISTCHECK_CONFIGURE_FLAGS = --enable-localinstall |
26 | |
27 | @@ -37,7 +33,7 @@ |
28 | EXTRA_DIST = \ |
29 | applications.png \ |
30 | autogen.sh \ |
31 | - $(lens_in_files) \ |
32 | + $(scope_in_files) \ |
33 | AUTHORS \ |
34 | COPYING \ |
35 | HACKING \ |
36 | @@ -50,8 +46,7 @@ |
37 | $(NULL) |
38 | |
39 | CLEANFILES = \ |
40 | - $(lens_DATA) \ |
41 | - $(cmdlens_DATA) \ |
42 | + $(scope_DATA) \ |
43 | $(NULL) |
44 | |
45 | include $(top_srcdir)/Makefile.am.coverage |
46 | |
47 | === removed file 'applications.lens.in.in' |
48 | --- applications.lens.in.in 2012-07-04 16:05:38 +0000 |
49 | +++ applications.lens.in.in 1970-01-01 00:00:00 +0000 |
50 | @@ -1,12 +0,0 @@ |
51 | -[Lens] |
52 | -DBusName=com.canonical.Unity.Lens.Applications |
53 | -DBusPath=/com/canonical/unity/lens/applications |
54 | -_Name=Applications |
55 | -Icon=@prefix@/share/unity/6/lens-nav-app.svg |
56 | -Description= |
57 | -_SearchHint=Search Applications |
58 | -Shortcut=a |
59 | - |
60 | -[Desktop Entry] |
61 | -X-Ubuntu-Gettext-Domain=unity-lens-applications |
62 | - |
63 | |
64 | === added file 'applications.scope.in.in' |
65 | --- applications.scope.in.in 1970-01-01 00:00:00 +0000 |
66 | +++ applications.scope.in.in 2013-05-16 21:22:23 +0000 |
67 | @@ -0,0 +1,13 @@ |
68 | +[Scope] |
69 | +DBusName=com.canonical.Unity.Scope.Applications |
70 | +DBusPath=/com/canonical/unity/scope/applications |
71 | +Icon=@prefix@/share/unity/icons/lens-nav-app.svg |
72 | +_Name=Applications |
73 | +_Description=This is an Ubuntu search plugin that enables information from local applications to be searched and displayed in the Dash underneath the Applications header. If you do not wish to search this content source, you can disable this search plugin. |
74 | +Type=applications |
75 | +_SearchHint=Search Applications |
76 | +Shortcut=a |
77 | + |
78 | +[Desktop Entry] |
79 | +X-Ubuntu-Gettext-Domain=unity-lens-applications |
80 | + |
81 | |
82 | === renamed file 'commands.lens.in.in' => 'commands.scope.in.in' |
83 | --- commands.lens.in.in 2011-08-08 22:05:14 +0000 |
84 | +++ commands.scope.in.in 2013-05-16 21:22:23 +0000 |
85 | @@ -1,8 +1,10 @@ |
86 | -[Lens] |
87 | -DBusName=com.canonical.Unity.Lens.Applications |
88 | -DBusPath=/com/canonical/unity/lens/commands |
89 | +[Scope] |
90 | +DBusName=com.canonical.Unity.Scope.Applications |
91 | +DBusPath=/com/canonical/unity/scope/commands |
92 | _Name=Commands |
93 | -Icon=@prefix@/share/unity/themes/applications.png |
94 | +_Description=This is an Ubuntu search plugin that enables information from local binaries to be searched and displayed in the Dash. If you do not wish to search this content source, you can disable this search plugin. |
95 | +Icon= |
96 | +Type=commands |
97 | _SearchHint=Run a command |
98 | Visible=false |
99 | |
100 | |
101 | === modified file 'configure.ac' |
102 | --- configure.ac 2013-03-01 15:11:29 +0000 |
103 | +++ configure.ac 2013-05-16 21:22:23 +0000 |
104 | @@ -1,4 +1,4 @@ |
105 | -AC_INIT(unity-lens-applications, 6.8.0, https://launchpad.net/unity-lens-applications) |
106 | +AC_INIT(unity-lens-applications, 7.0.0, https://launchpad.net/unity-lens-applications) |
107 | AC_COPYRIGHT([Copyright 2010-2012 Canonical]) |
108 | AM_INIT_AUTOMAKE([1.11]) |
109 | |
110 | @@ -47,10 +47,10 @@ |
111 | AC_DEFINE_UNQUOTED(PREFIXDIR, "${PREFIX}",[Prefix directory]) |
112 | |
113 | ###################################################### |
114 | -# intltool rule for generating translated .lens file |
115 | +# intltool rule for generating translated .scope file |
116 | ###################################################### |
117 | -INTLTOOL_LENS_RULE='%.lens: %.lens.in $(INTLTOOL_MERGE) $(wildcard $(top_srcdir)/po/*.po) ; LC_ALL=C $(INTLTOOL_MERGE) -d -u -c $(top_builddir)/po/.intltool-merge-cache $(top_srcdir)/po $< [$]@' |
118 | -AC_SUBST(INTLTOOL_LENS_RULE) |
119 | +INTLTOOL_SCOPE_RULE='%.scope: %.scope.in $(INTLTOOL_MERGE) $(wildcard $(top_srcdir)/po/*.po) ; LC_ALL=C $(INTLTOOL_MERGE) -d -u -c $(top_builddir)/po/.intltool-merge-cache $(top_srcdir)/po $< [$]@' |
120 | +AC_SUBST(INTLTOOL_SCOPE_RULE) |
121 | |
122 | ########################### |
123 | # gcov coverage reporting |
124 | @@ -76,7 +76,8 @@ |
125 | dee-1.0 >= 0.5.16 |
126 | zeitgeist-1.0 >= 0.3.8 |
127 | libcolumbus0 >= 0.4.0 |
128 | - unity >= 6.7.0 |
129 | + unity >= 7.0.0 |
130 | + unity-protocol-private |
131 | libgnome-menu-3.0 >= 3.6.0) |
132 | |
133 | AC_SUBST(LENS_DAEMON_CFLAGS) |
134 | @@ -138,6 +139,12 @@ |
135 | AS_AC_EXPAND(DATADIR, $datarootdir) |
136 | AC_SUBST(DATADIR) |
137 | |
138 | +##################################################### |
139 | +# Look for protocol-private lib dir |
140 | +##################################################### |
141 | +PROTOCOLPRIVATELIBDIR="`$PKG_CONFIG --variable=libdir unity-protocol-private`/libunity" |
142 | +AC_SUBST(PROTOCOLPRIVATELIBDIR) |
143 | + |
144 | ############################################# |
145 | # look for dbus service dir |
146 | ############################################# |
147 | @@ -159,8 +166,8 @@ |
148 | ############################################# |
149 | AC_CONFIG_FILES([ |
150 | Makefile |
151 | - applications.lens.in |
152 | - commands.lens.in |
153 | + applications.scope.in |
154 | + commands.scope.in |
155 | data/com.canonical.Unity.AppsLens.gschema.xml.in |
156 | data/Makefile |
157 | data/X-Unity-All-Applications.directory |
158 | |
159 | === modified file 'data/Makefile.am' |
160 | --- data/Makefile.am 2012-11-08 04:49:06 +0000 |
161 | +++ data/Makefile.am 2013-05-16 21:22:23 +0000 |
162 | @@ -2,7 +2,7 @@ |
163 | # DBus service files |
164 | ############################################################# |
165 | dbus_servicesdir = $(DBUSSERVICEDIR) |
166 | -service_in_files = unity-lens-applications.service.in |
167 | +service_in_files = unity-scope-applications.service.in |
168 | dbus_services_DATA = $(service_in_files:.service.in=.service) |
169 | |
170 | %.service: %.service.in |
171 | @@ -39,6 +39,6 @@ |
172 | $(menu_in_files) |
173 | |
174 | CLEANFILES = \ |
175 | - unity-lens-applications.service \ |
176 | + unity-scope-applications.service \ |
177 | $(gsettings_SCHEMAS) |
178 | |
179 | |
180 | === renamed file 'data/unity-lens-applications.service.in' => 'data/unity-scope-applications.service.in' |
181 | --- data/unity-lens-applications.service.in 2012-11-08 04:49:06 +0000 |
182 | +++ data/unity-scope-applications.service.in 2013-05-16 21:22:23 +0000 |
183 | @@ -1,3 +1,3 @@ |
184 | [D-BUS Service] |
185 | -Name=com.canonical.Unity.Lens.Applications |
186 | +Name=com.canonical.Unity.Scope.Applications |
187 | Exec=@pkglibexecdir@/unity-applications-daemon |
188 | |
189 | === modified file 'debian/changelog' |
190 | --- debian/changelog 2013-05-01 21:58:08 +0000 |
191 | +++ debian/changelog 2013-05-16 21:22:23 +0000 |
192 | @@ -1,3 +1,9 @@ |
193 | +unity-lens-applications (7.0.0-0ubuntu1) UNRELEASED; urgency=low |
194 | + |
195 | + * New upstream release. |
196 | + |
197 | + -- Pawel Stolowski <pawel.stolowski@ubuntu.com> Thu, 16 May 2013 23:12:47 +0200 |
198 | + |
199 | unity-lens-applications (6.10.0daily13.05.01.1ubuntu.unity.next-0ubuntu1) raring; urgency=low |
200 | |
201 | [ Sebastien Bacher ] |
202 | |
203 | === modified file 'debian/control' |
204 | --- debian/control 2013-04-12 12:21:04 +0000 |
205 | +++ debian/control 2013-05-16 21:22:23 +0000 |
206 | @@ -11,7 +11,7 @@ |
207 | libgee-dev, |
208 | libdee-dev (>= 0.5.16), |
209 | libzeitgeist-dev (>= 0.3.8), |
210 | - libunity-dev (>= 6.8.0), |
211 | + libunity-dev (>= 7.0.0), |
212 | libgnome-menu-3-dev, |
213 | dh-autoreconf, |
214 | libxapian-dev, |
215 | @@ -28,7 +28,7 @@ |
216 | Architecture: any |
217 | Depends: ${shlibs:Depends}, |
218 | ${misc:Depends}, |
219 | - unity-common (>= 4.4.0) |
220 | + unity-common (>= 7.0.0) |
221 | Breaks: unity (<< 6.0.0), |
222 | Description: Application lens for unity |
223 | This package contains the "application" lens which can be used |
224 | |
225 | === modified file 'po/POTFILES.in' |
226 | --- po/POTFILES.in 2011-08-04 10:07:39 +0000 |
227 | +++ po/POTFILES.in 2013-05-16 21:22:23 +0000 |
228 | @@ -4,5 +4,5 @@ |
229 | src/utils.vala |
230 | src/main.vala |
231 | data/X-Unity-All-Applications.directory.in |
232 | -[type: gettext/ini]applications.lens.in.in |
233 | -[type: gettext/ini]commands.lens.in.in |
234 | +[type: gettext/ini]applications.scope.in.in |
235 | +[type: gettext/ini]commands.scope.in.in |
236 | |
237 | === modified file 'src/Makefile.am' |
238 | --- src/Makefile.am 2013-02-22 12:05:05 +0000 |
239 | +++ src/Makefile.am 2013-05-16 21:22:23 +0000 |
240 | @@ -35,6 +35,7 @@ |
241 | --pkg dee-1.0 \ |
242 | --pkg zeitgeist-1.0 \ |
243 | --pkg unity \ |
244 | + --pkg unity-protocol \ |
245 | --pkg gee-1.0 \ |
246 | --pkg libgnome-menu-3.0 \ |
247 | --pkg unity-package-search \ |
248 | @@ -54,7 +55,7 @@ |
249 | unity-ratings-db.o \ |
250 | $(NULL) |
251 | |
252 | -unity_applications_daemon_LDFLAGS = $(COVERAGE_LDFLAGS) |
253 | +unity_applications_daemon_LDFLAGS = -rpath $(PROTOCOLPRIVATELIBDIR) $(COVERAGE_LDFLAGS) |
254 | |
255 | unity_applications_daemon_VALASOURCES = \ |
256 | app-watcher.vala \ |
257 | |
258 | === modified file 'src/config.vala.in' |
259 | --- src/config.vala.in 2010-06-22 07:36:19 +0000 |
260 | +++ src/config.vala.in 2013-05-16 21:22:23 +0000 |
261 | @@ -4,6 +4,8 @@ |
262 | |
263 | const string DATADIR = "@DATADIR@"; |
264 | |
265 | + const string PKGDATADIR = "@DATADIR@/unity"; |
266 | + |
267 | const string BINDIR = "@prefix@/bin"; |
268 | |
269 | const string LOCALEDIR = "@DATADIR@/locale"; |
270 | @@ -11,4 +13,4 @@ |
271 | const string PACKAGE = "@PACKAGE@"; |
272 | |
273 | const string VERSION = "@VERSION@"; |
274 | -} |
275 | \ No newline at end of file |
276 | +} |
277 | |
278 | === modified file 'src/daemon.vala' |
279 | --- src/daemon.vala 2013-04-22 17:45:49 +0000 |
280 | +++ src/daemon.vala 2013-05-16 21:22:23 +0000 |
281 | @@ -42,9 +42,13 @@ |
282 | |
283 | const string ICON_PATH = Config.DATADIR + "/icons/unity-icon-theme/places/svg/"; |
284 | const string GENERIC_APP_ICON = "applications-other"; |
285 | + const string GENERIC_SCOPE_ICON = ICON_PATH + "service-generic.svg"; |
286 | + |
287 | + const string LIBUNITY_SCHEMA = "com.canonical.Unity.Lenses"; |
288 | |
289 | public class Daemon : GLib.Object |
290 | { |
291 | + private Variant empty_asv; |
292 | private Zeitgeist.Log log; |
293 | private Zeitgeist.Index zg_index; |
294 | private Zeitgeist.Monitor monitor; |
295 | @@ -55,14 +59,14 @@ |
296 | /* The searcher for online material may be null if it fails to load |
297 | * the Xapian index from the Software Center */ |
298 | private Unity.Package.Searcher? pkgsearcher; |
299 | + private Unity.Package.Searcher? scopesearcher; |
300 | public Unity.Package.Searcher appsearcher; |
301 | |
302 | /* Read the app ratings dumped by the Software Center */ |
303 | private bool ratings_db_initialized = false; |
304 | private Unity.Ratings.Database? ratings = null; |
305 | |
306 | - private Unity.Lens lens; |
307 | - private Unity.Scope scope; |
308 | + private Unity.DeprecatedScope scope; |
309 | |
310 | /* Support aptd dbus interface; created when application install/remove was requested by preview action */ |
311 | private AptdProxy aptdclient; |
312 | @@ -107,6 +111,7 @@ |
313 | private Regex mountable_regex; |
314 | |
315 | private Settings gp_settings; |
316 | + private HashTable<unowned string, unowned string> disabled_scope_ids; |
317 | |
318 | private const string DISPLAY_RECENT_APPS_KEY = "display-recent-apps"; |
319 | private const string DISPLAY_AVAILABLE_APPS_KEY = "display-available-apps"; |
320 | @@ -116,6 +121,9 @@ |
321 | public bool force_small_icons_for_suggestions { get; set; default = true; } |
322 | |
323 | private PurchaseInfoHelper purchase_info = null; |
324 | + private Dee.Model remote_scopes_model; |
325 | + private Dee.Index scopes_index; |
326 | + private Dee.Analyzer analyzer; |
327 | |
328 | construct |
329 | { |
330 | @@ -123,6 +131,7 @@ |
331 | |
332 | log = new Zeitgeist.Log(); |
333 | zg_index = new Zeitgeist.Index(); |
334 | + empty_asv = new Variant.array (new VariantType ("{sv}"), {}); |
335 | monitor = new Zeitgeist.Monitor (new Zeitgeist.TimeRange.from_now (), |
336 | zg_templates); |
337 | monitor.events_inserted.connect (mark_dirty); |
338 | @@ -159,14 +168,17 @@ |
339 | image_extensions.add ("jpg"); |
340 | |
341 | build_app_menu_index (); |
342 | + build_scope_index.begin (); |
343 | |
344 | file_icon_cache = new HashTable<string,Icon>(str_hash, str_equal); |
345 | sc_mangler = new SoftwareCenterUtils.MangledDesktopFileLookup (); |
346 | |
347 | - scope = new Unity.Scope ("/com/canonical/unity/scope/applications"); |
348 | - scope.provides_personal_content = true; |
349 | - //scope.icon = @"$(Config.PREFIX)/share/unity/themes/applications.png"; |
350 | + scope = new Unity.DeprecatedScope ("/com/canonical/unity/scope/applications", |
351 | + "applications"); |
352 | |
353 | + scope.search_hint = _("Search Applications"); |
354 | + scope.search_in_global = true; |
355 | + // scope.sources_display_name = _("Sources"); |
356 | // TRANSLATORS: Please make sure this string is short enough to fit |
357 | // into the filter button |
358 | local_apps_option = scope.sources.add_option ("local", _("Local Apps")); |
359 | @@ -177,6 +189,10 @@ |
360 | usc_apps_option = scope.sources.add_option ("usc", _("Software Center")); |
361 | } |
362 | |
363 | + populate_categories (); |
364 | + populate_filters(); |
365 | + //scope.icon = @"$(Config.PREFIX)/share/unity/themes/applications.png"; |
366 | + |
367 | scope.generate_search_key.connect ((lens_search) => |
368 | { |
369 | return lens_search.search_string.strip (); |
370 | @@ -184,16 +200,10 @@ |
371 | /* Listen for changes to the lens scope search */ |
372 | scope.search_changed.connect ((lens_search, search_type, cancellable) => |
373 | { |
374 | - dispatch_search (lens_search, search_type, cancellable); |
375 | - }); |
376 | - |
377 | - /* Re-do the search if the filters changed */ |
378 | - scope.filters_changed.connect (() => |
379 | - { |
380 | - scope.queue_search_changed (SearchType.DEFAULT); |
381 | - }); |
382 | - |
383 | - /* And also if the sources change */ |
384 | + dispatch_search.begin (lens_search, search_type, cancellable); |
385 | + }); |
386 | + |
387 | + /* Re-do the search if the sources change */ |
388 | scope.active_sources_changed.connect (() => |
389 | { |
390 | scope.queue_search_changed (SearchType.DEFAULT); |
391 | @@ -225,15 +235,35 @@ |
392 | aptdclient = new AptdProxy (); |
393 | launcherservice = new LauncherProxy (); |
394 | |
395 | - lens = new Unity.Lens ("/com/canonical/unity/lens/applications", "applications"); |
396 | - lens.search_hint = _("Search Applications"); |
397 | - lens.visible = true; |
398 | - lens.search_in_global = true; |
399 | - lens.sources_display_name = _("Sources"); |
400 | - populate_categories (); |
401 | - populate_filters(); |
402 | - lens.add_local_scope (scope); |
403 | - lens.export (); |
404 | + scope.export (); |
405 | + |
406 | + remote_scopes_model = new Dee.SharedModel ("com.canonical.Unity.SmartScopes.RemoteScopesModel"); |
407 | + remote_scopes_model.set_schema ("s", "s", "s", "s", "s", "as"); |
408 | + |
409 | + scopes_index = Utils.prepare_index (remote_scopes_model, |
410 | + RemoteScopesColumn.NAME, |
411 | + (model, iter) => |
412 | + { |
413 | + unowned string name = model.get_string (iter, RemoteScopesColumn.NAME); |
414 | + return "%s\n%s".printf (_("scope"), name); |
415 | + }, out analyzer); |
416 | + |
417 | + disabled_scope_ids = new HashTable<unowned string, unowned string> (str_hash, str_equal); |
418 | + update_disabled_scopes_hash (); |
419 | + |
420 | + var pref_man = PreferencesManager.get_default (); |
421 | + pref_man.notify["disabled-scopes"].connect (update_disabled_scopes_hash); |
422 | + } |
423 | + |
424 | + private void update_disabled_scopes_hash () |
425 | + { |
426 | + disabled_scope_ids.remove_all (); |
427 | + var pref_man = PreferencesManager.get_default (); |
428 | + foreach (unowned string scope_id in pref_man.disabled_scopes) |
429 | + { |
430 | + // using HashTable as a set (optimized in glib when done like this) |
431 | + disabled_scope_ids[scope_id] = scope_id; |
432 | + } |
433 | } |
434 | |
435 | private void init_ratings_db () |
436 | @@ -251,9 +281,9 @@ |
437 | ratings_db_initialized = true; |
438 | } |
439 | |
440 | - private async void dispatch_search (LensSearch lens_search, |
441 | + private async void dispatch_search (DeprecatedScopeSearch search, |
442 | SearchType search_type, |
443 | - Cancellable cancellable) |
444 | + GLib.Cancellable cancellable) |
445 | { |
446 | if (popularities_dirty) |
447 | { |
448 | @@ -265,43 +295,45 @@ |
449 | } |
450 | |
451 | if (search_type == SearchType.DEFAULT) |
452 | - yield update_scope_search (lens_search, cancellable); |
453 | + yield update_scope_search (search, cancellable); |
454 | else |
455 | - yield update_global_search (lens_search, cancellable); |
456 | + yield update_global_search (search, cancellable); |
457 | + |
458 | + search.finished (); |
459 | } |
460 | |
461 | private void populate_categories () |
462 | { |
463 | - GLib.List<Unity.Category> categories = new GLib.List<Unity.Category> (); |
464 | + Unity.CategorySet categories = new Unity.CategorySet (); |
465 | File icon_dir = File.new_for_path (ICON_PATH); |
466 | |
467 | - var cat = new Unity.Category (_("Applications"), |
468 | + var cat = new Unity.Category ("apps", _("Applications"), |
469 | new FileIcon (icon_dir.get_child ("group-apps.svg"))); |
470 | - categories.append (cat); |
471 | + categories.add (cat); |
472 | |
473 | - cat = new Unity.Category (_("Recently Used"), |
474 | + cat = new Unity.Category ("recently-used", _("Recently Used"), |
475 | new FileIcon (icon_dir.get_child ("group-recent.svg"))); |
476 | - categories.append (cat); |
477 | + categories.add (cat); |
478 | |
479 | - cat = new Unity.Category (_("Recent Apps"), |
480 | + cat = new Unity.Category ("recent", _("Recent Apps"), |
481 | new FileIcon (icon_dir.get_child ("group-apps.svg"))); |
482 | - categories.append (cat); |
483 | + categories.add (cat); |
484 | |
485 | - cat = new Unity.Category (_("Installed"), |
486 | + cat = new Unity.Category ("installed", _("Installed"), |
487 | new FileIcon (icon_dir.get_child ("group-installed.svg"))); |
488 | - categories.append (cat); |
489 | + categories.add (cat); |
490 | |
491 | - cat = new Unity.Category (_("More suggestions"), |
492 | + cat = new Unity.Category ("more", _("More suggestions"), |
493 | new FileIcon (icon_dir.get_child ("group-treat-yourself.svg")), |
494 | Unity.CategoryRenderer.FLOW); |
495 | - categories.append (cat); |
496 | + categories.add (cat); |
497 | |
498 | - lens.categories = categories; |
499 | + scope.categories = categories; |
500 | } |
501 | |
502 | private void populate_filters() |
503 | { |
504 | - GLib.List<Unity.Filter> filters = new GLib.List<Unity.Filter> (); |
505 | + Unity.FilterSet filters = new Unity.FilterSet (); |
506 | |
507 | /* Type filter */ |
508 | { |
509 | @@ -320,25 +352,28 @@ |
510 | filter.add_option ("accessibility", _("Accessibility")); |
511 | filter.add_option ("developer", _("Developer")); |
512 | filter.add_option ("science-and-engineering", _("Science & Engineering")); |
513 | + filter.add_option ("scopes", _("Search plugins")); |
514 | filter.add_option ("system", _("System")); |
515 | |
516 | - filters.append (filter); |
517 | + filters.add (filter); |
518 | } |
519 | |
520 | - lens.filters = filters; |
521 | + scope.filters = filters; |
522 | } |
523 | |
524 | - private bool local_apps_active () |
525 | + private bool local_apps_active (DeprecatedScopeSearch search) |
526 | { |
527 | - if (scope.sources.filtering && local_apps_option != null) |
528 | - return local_apps_option.active; |
529 | + var filter = search.get_filter (scope.sources.id) as Unity.OptionsFilter; |
530 | + if (filter.filtering && local_apps_option != null) |
531 | + return filter.get_option (local_apps_option.id).active; |
532 | return true; |
533 | } |
534 | |
535 | - private bool usc_apps_active () |
536 | + private bool usc_apps_active (DeprecatedScopeSearch search) |
537 | { |
538 | - if (scope.sources.filtering && usc_apps_option != null) |
539 | - return usc_apps_option.active; |
540 | + var filter = search.get_filter (scope.sources.id) as Unity.OptionsFilter; |
541 | + if (filter.filtering && usc_apps_option != null) |
542 | + return filter.get_option (usc_apps_option.id).active; |
543 | return true; |
544 | } |
545 | |
546 | @@ -401,6 +436,15 @@ |
547 | return false; |
548 | } |
549 | |
550 | + private async void build_scope_index () |
551 | + { |
552 | + var scope_registry = yield Unity.Protocol.ScopeRegistry.find_scopes ( |
553 | + Config.PKGDATADIR + "/scopes"); |
554 | + |
555 | + debug ("Indexing scopes"); |
556 | + scopesearcher = new Unity.Package.Searcher.for_scopes (scope_registry); |
557 | + } |
558 | + |
559 | private void populate_zg_templates () |
560 | { |
561 | /* Create a template that activation of applications */ |
562 | @@ -430,7 +474,7 @@ |
563 | zg_templates, |
564 | StorageState.ANY, |
565 | 256, |
566 | - ResultType.MOST_POPULAR_SUBJECTS, |
567 | + Zeitgeist.ResultType.MOST_POPULAR_SUBJECTS, |
568 | null); |
569 | |
570 | // most popular apps must have high value, so unknown apps (where |
571 | @@ -461,21 +505,22 @@ |
572 | return app == null; |
573 | } |
574 | |
575 | - private async void update_scope_search (Unity.LensSearch search, |
576 | - Cancellable cancellable) |
577 | + private async void update_scope_search (DeprecatedScopeSearch search, |
578 | + GLib.Cancellable cancellable) |
579 | { |
580 | var model = search.results_model; |
581 | /* We'll clear the model once we finish waiting for the dbus-call |
582 | * to finish, to prevent flicker. */ |
583 | |
584 | - debug ("Searching for: %s", search.search_string); |
585 | - |
586 | - var filter = scope.get_filter ("type") as OptionsFilter; |
587 | - |
588 | - string pkg_search_string = XapianUtils.prepare_pkg_search_string (search.search_string, filter); |
589 | - |
590 | - bool has_filter = (filter != null && filter.filtering); |
591 | - bool has_search = !Utils.is_search_empty (search.search_string); |
592 | + var search_string = search.search_string.strip (); |
593 | + debug ("Searching for: %s", search_string); |
594 | + |
595 | + var type_filter = search.get_filter ("type") as OptionsFilter; |
596 | + |
597 | + string pkg_search_string = XapianUtils.prepare_pkg_search_string (search_string, type_filter); |
598 | + |
599 | + bool has_filter = (type_filter != null && type_filter.filtering); |
600 | + bool has_search = !Utils.is_search_empty (search_string); |
601 | |
602 | Timer timer = new Timer (); |
603 | |
604 | @@ -494,7 +539,7 @@ |
605 | has_search ? |
606 | Unity.Package.Sort.BY_RELEVANCY : |
607 | Unity.Package.Sort.BY_NAME); |
608 | - if (local_apps_active ()) |
609 | + if (local_apps_active (search)) |
610 | { |
611 | if (has_search) resort_pkg_search_results (appresults); |
612 | add_pkg_search_result (appresults, installed_uris, available_uris, |
613 | @@ -505,7 +550,7 @@ |
614 | debug ("Entry search listed %i Installed apps in %fms for query: %s", |
615 | appresults.num_hits, timer.elapsed ()*1000, pkg_search_string); |
616 | |
617 | - if (local_apps_active () && display_recent_apps) |
618 | + if (local_apps_active (search) && display_recent_apps) |
619 | { |
620 | try |
621 | { |
622 | @@ -513,7 +558,7 @@ |
623 | /* Ignore the search string, we want to keep displaying the same apps |
624 | * in the recent category and just filter out those that don't match |
625 | * the search query */ |
626 | - var zg_search_string = XapianUtils.prepare_zg_search_string ("", filter); |
627 | + var zg_search_string = XapianUtils.prepare_zg_search_string ("", type_filter); |
628 | |
629 | var results = yield zg_index.search (zg_search_string, |
630 | new Zeitgeist.TimeRange.anytime(), |
631 | @@ -535,16 +580,23 @@ |
632 | // no need to bother |
633 | return; |
634 | } catch (GLib.Error e) { |
635 | - warning ("Error performing search '%s': %s", search.search_string, e.message); |
636 | + warning ("Error performing search '%s': %s", search_string, e.message); |
637 | } |
638 | } |
639 | |
640 | transaction.commit (); |
641 | |
642 | + // add scopes (if filter is active) |
643 | + if (!has_filter || type_filter.get_option ("scopes").active) |
644 | + { |
645 | + add_local_scopes_results (search_string, model, installed_uris); |
646 | + add_remote_scopes_results (search_string, model); |
647 | + } |
648 | + |
649 | purchase_info = new PurchaseInfoHelper (); |
650 | |
651 | /* If we don't have a search we display 6 random apps */ |
652 | - if (usc_apps_active () && display_available_apps && pkgsearcher != null) |
653 | + if (usc_apps_active (search) && display_available_apps && pkgsearcher != null) |
654 | { |
655 | if (has_search) |
656 | { |
657 | @@ -561,7 +613,7 @@ |
658 | else if (has_filter) /* Empty search string + active filters should get lots of results from selected categories */ |
659 | { |
660 | timer.start (); |
661 | - string? filter_query = XapianUtils.prepare_pkg_search_string (search.search_string, filter); |
662 | + string? filter_query = XapianUtils.prepare_pkg_search_string (search_string, type_filter); |
663 | |
664 | var pkgresults = pkgsearcher.get_apps (filter_query, MAX_APP_FOR_DOWNLOAD_FOR_EMPTY_QUERY, filter_cb); |
665 | purchase_info.from_pkgresults (pkgresults); |
666 | @@ -610,19 +662,18 @@ |
667 | search.set_reply_hint ("no-results-hint", |
668 | _("Sorry, there are no applications that match your search.")); |
669 | } |
670 | - |
671 | - search.finished (); |
672 | } |
673 | |
674 | - private async void update_global_search (Unity.LensSearch search, |
675 | - Cancellable cancellable) |
676 | + private async void update_global_search (DeprecatedScopeSearch search, |
677 | + GLib.Cancellable cancellable) |
678 | { |
679 | /* |
680 | * In global search, with a non-empty search string, we collate all |
681 | * hits under one Applications category |
682 | */ |
683 | + var search_string = search.search_string.strip (); |
684 | |
685 | - if (Utils.is_search_empty (search.search_string)) |
686 | + if (Utils.is_search_empty (search_string)) |
687 | { |
688 | yield update_global_without_search (search, cancellable); |
689 | return; |
690 | @@ -632,11 +683,11 @@ |
691 | |
692 | model.clear (); |
693 | |
694 | - var search_string = XapianUtils.prepare_pkg_search_string (search.search_string, null); |
695 | + var pkg_search_string = XapianUtils.prepare_pkg_search_string (search_string, null); |
696 | Set<string> installed_uris = new HashSet<string> (); |
697 | Set<string> available_uris = new HashSet<string> (); |
698 | var timer = new Timer (); |
699 | - var appresults = appsearcher.search (search_string, 0, |
700 | + var appresults = appsearcher.search (pkg_search_string, 0, |
701 | Unity.Package.SearchType.PREFIX, |
702 | Unity.Package.Sort.BY_RELEVANCY); |
703 | resort_pkg_search_results (appresults); |
704 | @@ -645,17 +696,11 @@ |
705 | |
706 | timer.stop (); |
707 | debug ("Global search listed %i Installed apps in %fms for query: %s", |
708 | - appresults.num_hits, timer.elapsed ()*1000, search_string); |
709 | - |
710 | - /* Allow new searches once we enter an idle again. |
711 | - * We don't do it directly from here as that could mean we start |
712 | - * changing the model even before we had flushed out current changes |
713 | - */ |
714 | - search.finished (); |
715 | + appresults.num_hits, timer.elapsed ()*1000, pkg_search_string); |
716 | } |
717 | |
718 | - private async void update_global_without_search (Unity.LensSearch search, |
719 | - Cancellable cancellable) |
720 | + private async void update_global_without_search (DeprecatedScopeSearch search, |
721 | + GLib.Cancellable cancellable) |
722 | { |
723 | /* |
724 | * In global search, with an empty search string, we show just Recent Apps |
725 | @@ -665,12 +710,12 @@ |
726 | |
727 | Timer timer = new Timer (); |
728 | |
729 | - if (local_apps_active () && display_recent_apps) |
730 | + if (local_apps_active (search) && display_recent_apps) |
731 | { |
732 | try |
733 | { |
734 | - var zg_search_string = XapianUtils.prepare_zg_search_string (search.search_string, |
735 | - null); |
736 | + var zg_search_string = XapianUtils.prepare_zg_search_string ("", |
737 | + null); |
738 | |
739 | var time_range = new Zeitgeist.TimeRange.anytime (); |
740 | var results = yield log.find_events (time_range, |
741 | @@ -697,8 +742,6 @@ |
742 | search.search_string, e.message); |
743 | } |
744 | } |
745 | - |
746 | - search.finished (); |
747 | } |
748 | |
749 | public Icon find_pkg_icon (string? desktop_file, string icon_name) |
750 | @@ -871,10 +914,12 @@ |
751 | |
752 | model.append (uri, icon_obj, |
753 | category, |
754 | + pinfo != null && pinfo.paid ? Unity.ResultType.PERSONAL : Unity.ResultType.DEFAULT, |
755 | "application/x-desktop", |
756 | app.application_name, |
757 | "", //comment |
758 | - "file://" + app.desktop_file); |
759 | + "file://" + app.desktop_file, |
760 | + empty_asv); |
761 | duplicates_lookup.add (uri); |
762 | i++; |
763 | if (i == max_results) |
764 | @@ -968,11 +1013,16 @@ |
765 | icon_str = icon.to_string (); |
766 | } |
767 | |
768 | + var result_type = (category != Category.AVAILABLE && !results.fuzzy_search) ? |
769 | + Unity.ResultType.PERSONAL : Unity.ResultType.DEFAULT; |
770 | model.append (uri, icon_str, |
771 | - category,"application/x-desktop", |
772 | + category, |
773 | + result_type, |
774 | + "application/x-desktop", |
775 | display_name != null ? display_name : "", |
776 | comment != null ? comment : "", |
777 | - full_path != null ? "file://" + full_path : ""); |
778 | + full_path != null ? "file://" + full_path : "", |
779 | + empty_asv); |
780 | |
781 | /* Stop if we added the number of items requested */ |
782 | n_added++; |
783 | @@ -981,6 +1031,124 @@ |
784 | } |
785 | } |
786 | |
787 | + private static Icon? get_default_scope_icon () |
788 | + { |
789 | + try |
790 | + { |
791 | + return Icon.new_for_string (GENERIC_SCOPE_ICON); |
792 | + } |
793 | + catch (Error err) |
794 | + { |
795 | + warning ("%s", err.message); |
796 | + } |
797 | + return null; |
798 | + } |
799 | + |
800 | + private void add_local_scopes_results (string search_string, |
801 | + Dee.Model model, |
802 | + Set<string> installed_uris) |
803 | + { |
804 | + // If the local scopes Xapian index hasn't been built, return. |
805 | + if (scopesearcher == null) |
806 | + return; |
807 | + |
808 | + bool has_search = !Utils.is_search_empty (search_string); |
809 | + var pkg_search_string = XapianUtils.prepare_pkg_search_string ( |
810 | + search_string, null); |
811 | + |
812 | + var results = scopesearcher.search (pkg_search_string, 0, |
813 | + Unity.Package.SearchType.PREFIX, |
814 | + has_search ? |
815 | + Unity.Package.Sort.BY_RELEVANCY : |
816 | + Unity.Package.Sort.BY_NAME); |
817 | + |
818 | + foreach (unowned Unity.Package.PackageInfo info in results.results) |
819 | + { |
820 | + /* De-dupe by "application://foo.scope", since that is what is |
821 | + * used for software-center results. */ |
822 | + string dedup_key = @"application://$(info.desktop_file)"; |
823 | + if (dedup_key in installed_uris) |
824 | + continue; |
825 | + installed_uris.add(dedup_key); |
826 | + |
827 | + /* Don't include master scopes in the search results. This is |
828 | + * performed after deduping so the master scopes don't just |
829 | + * move to hte "available" category. */ |
830 | + if (info.is_master_scope) |
831 | + continue; |
832 | + |
833 | + var uri = @"scope://$(info.desktop_file)"; |
834 | + var name = info.application_name; |
835 | + var icon_hint = info.icon; |
836 | + var category = info.desktop_file in disabled_scope_ids ? |
837 | + Category.AVAILABLE : Category.INSTALLED; |
838 | + |
839 | + try |
840 | + { |
841 | + Icon base_icon = icon_hint == null || icon_hint == "" ? |
842 | + get_default_scope_icon () : Icon.new_for_string (icon_hint); |
843 | + var anno_icon = new AnnotatedIcon (base_icon); |
844 | + anno_icon.size_hint = IconSizeHint.SMALL; |
845 | + icon_hint = anno_icon.to_string (); |
846 | + } |
847 | + catch (Error err) |
848 | + { |
849 | + icon_hint = ""; |
850 | + } |
851 | + |
852 | + model.append (uri, |
853 | + icon_hint, |
854 | + category, |
855 | + ResultType.DEFAULT, |
856 | + "application/x-unity-scope", |
857 | + name != "" ? name : uri, |
858 | + "", |
859 | + "", // dnd_uri ?! |
860 | + empty_asv); |
861 | + } |
862 | + } |
863 | + |
864 | + private void add_remote_scopes_results (string search_string, |
865 | + Dee.Model model) |
866 | + { |
867 | + var results = Utils.search_index (scopes_index, analyzer, search_string); |
868 | + foreach (var iter in results) |
869 | + { |
870 | + unowned string scope_id = |
871 | + remote_scopes_model.get_string (iter, RemoteScopesColumn.SCOPE_ID); |
872 | + var uri = @"scope://$(scope_id)"; |
873 | + var name = |
874 | + remote_scopes_model.get_string (iter, RemoteScopesColumn.NAME); |
875 | + var icon_hint = |
876 | + remote_scopes_model.get_string (iter, RemoteScopesColumn.ICON_HINT); |
877 | + |
878 | + try |
879 | + { |
880 | + Icon base_icon = icon_hint == null || icon_hint == "" ? |
881 | + get_default_scope_icon () : Icon.new_for_string (icon_hint); |
882 | + var anno_icon = new AnnotatedIcon (base_icon); |
883 | + anno_icon.size_hint = IconSizeHint.SMALL; |
884 | + icon_hint = anno_icon.to_string (); |
885 | + } |
886 | + catch (Error err) |
887 | + { |
888 | + icon_hint = ""; |
889 | + } |
890 | + |
891 | + var category = scope_id in disabled_scope_ids ? |
892 | + Category.AVAILABLE : Category.INSTALLED; |
893 | + |
894 | + model.append (uri, |
895 | + icon_hint, |
896 | + category, |
897 | + ResultType.DEFAULT, |
898 | + "application/x-unity-scope", |
899 | + name != "" ? name : uri, |
900 | + "", |
901 | + "", // dnd_uri ?! |
902 | + empty_asv); |
903 | + } |
904 | + } |
905 | private async void call_install_packages (string package_name, out string tid) throws IOError |
906 | { |
907 | tid = yield aptdclient.install_packages ({package_name}); |
908 | @@ -1141,181 +1309,371 @@ |
909 | |
910 | public Unity.Preview preview (string uri) |
911 | { |
912 | + Unity.Preview? preview = null; |
913 | + bool installed = uri.has_prefix ("application://"); |
914 | + bool is_scope = uri.has_prefix ("scope://"); |
915 | + |
916 | + if (installed || uri.has_prefix ("unity-install://")) |
917 | + { |
918 | + preview = make_app_preview (uri, installed); |
919 | + } |
920 | + else if (is_scope) |
921 | + { |
922 | + preview = make_scope_preview (uri); |
923 | + } |
924 | + return preview; |
925 | + } |
926 | + |
927 | + private SoftwareCenterData.AppDetailsData get_app_details (string appname, string pkgname) throws Error |
928 | + { |
929 | + if (sc_data_provider == null) |
930 | + { |
931 | + sc_data_provider = new SoftwareCenterDataCache (TOP_RATED_ITEMS_CACHE_LIFETIME); |
932 | + sc_data_provider.connect_to (); |
933 | + } |
934 | + |
935 | + debug ("Requesting pkg info: %s, %s\n", pkgname, appname); |
936 | + return sc_data_provider.get_app_details (appname, pkgname); |
937 | + } |
938 | + |
939 | + private Unity.Preview make_app_preview (string uri, bool installed) |
940 | + { |
941 | Unity.ApplicationPreview? preview = null; |
942 | - |
943 | + string desktopfile = null; |
944 | string pkgname = ""; |
945 | string appname = ""; |
946 | - bool installed = uri.has_prefix ("application://"); |
947 | - |
948 | - if (installed || uri.has_prefix ("unity-install://")) |
949 | - { |
950 | - string desktopfile = null; |
951 | - if (installed) |
952 | - { |
953 | - desktopfile = uri.substring (14); //remove "application://" prefix |
954 | - |
955 | - // de-mangle desktop file names back to what S-C expects |
956 | - if (sc_mangler.contains (desktopfile)) |
957 | - { |
958 | - desktopfile = sc_mangler.get (desktopfile); |
959 | - } |
960 | - |
961 | - Unity.Package.PackageInfo pkginfo = pkgsearcher.get_by_desktop_file (desktopfile); |
962 | - if (pkginfo != null) |
963 | - { |
964 | - appname = pkginfo.application_name; |
965 | - pkgname = pkginfo.package_name; |
966 | - } |
967 | - } |
968 | - else // unity-install |
969 | - { |
970 | - string app = uri.substring (16); //remove "unity-install://" prefix |
971 | - string[] parts = app.split ("/"); |
972 | - if (parts.length > 1) |
973 | - { |
974 | - pkgname = parts[0]; |
975 | - appname = parts[1]; |
976 | - } |
977 | - } |
978 | - |
979 | - if (pkgname != "") |
980 | - { |
981 | + |
982 | + if (installed) |
983 | + { |
984 | + desktopfile = uri.substring (14); //remove "application://" prefix |
985 | + |
986 | + // de-mangle desktop file names back to what S-C expects |
987 | + if (sc_mangler.contains (desktopfile)) |
988 | + { |
989 | + desktopfile = sc_mangler.get (desktopfile); |
990 | + } |
991 | + |
992 | + Unity.Package.PackageInfo pkginfo = pkgsearcher.get_by_desktop_file (desktopfile); |
993 | + if (pkginfo != null) |
994 | + { |
995 | + appname = pkginfo.application_name; |
996 | + pkgname = pkginfo.package_name; |
997 | + } |
998 | + } |
999 | + else // unity-install |
1000 | + { |
1001 | + string app = uri.substring (16); //remove "unity-install://" prefix |
1002 | + string[] parts = app.split ("/"); |
1003 | + if (parts.length > 1) |
1004 | + { |
1005 | + pkgname = parts[0]; |
1006 | + appname = parts[1]; |
1007 | + } |
1008 | + } |
1009 | + |
1010 | + if (pkgname != "") |
1011 | + { |
1012 | + try { |
1013 | + var details = get_app_details (appname, pkgname); |
1014 | + |
1015 | + Icon? icon = null; |
1016 | + if (installed) |
1017 | + icon = new GLib.ThemedIcon (details.icon); |
1018 | + else |
1019 | + { |
1020 | + icon = find_pkg_icon (null, details.icon); |
1021 | + if (icon.to_string () == GENERIC_APP_ICON && details.icon_url != null && details.icon_url != "") |
1022 | + { |
1023 | + icon = new GLib.FileIcon (File.new_for_uri (details.icon_url)); |
1024 | + } |
1025 | + } |
1026 | + |
1027 | + Icon? screenshot = null; |
1028 | + |
1029 | + if (details.screenshot != null) |
1030 | + { |
1031 | + File scr_file = File.new_for_uri (details.screenshot); |
1032 | + screenshot = new FileIcon (scr_file); |
1033 | + } |
1034 | + |
1035 | + string subtitle = ""; |
1036 | + if (details.version != "") |
1037 | + subtitle = _("Version %s").printf (details.version); |
1038 | + if (details.size > 0) |
1039 | + { |
1040 | + if (subtitle != "") |
1041 | + subtitle += ", "; |
1042 | + subtitle += (_("Size %s")).printf (GLib.format_size (details.size)); |
1043 | + } |
1044 | + preview = new Unity.ApplicationPreview (details.name, subtitle, details.description, icon, screenshot); |
1045 | + preview.license = details.license; |
1046 | + |
1047 | + init_ratings_db (); |
1048 | + if (ratings != null) |
1049 | + { |
1050 | + Unity.Ratings.Result result; |
1051 | + ratings.query (pkgname, out result); |
1052 | + preview.set_rating (result.average_rating / 5.0f, result.total_rating); |
1053 | + } |
1054 | + |
1055 | + if (details.hardware_requirements != "") |
1056 | + preview.add_info (new InfoHint ("hardware-requirements", _("Hardware requirements"), null, details.hardware_requirements)); |
1057 | + |
1058 | + if (uri.has_prefix ("unity-install://")) // application needs to be purchased/installed |
1059 | + { |
1060 | + // uninstalled and not purchased before |
1061 | + if (details.pkg_state == SoftwareCenterData.PackageState.NEEDS_PURCHASE) |
1062 | + { |
1063 | + var buy_action = new Unity.PreviewAction ("buy", _("Buy"), null); |
1064 | + if (details.price != null && details.price != "") |
1065 | + { |
1066 | + buy_action.extra_text = details.price; |
1067 | + } |
1068 | + |
1069 | + buy_action.activated.connect (start_software_center); |
1070 | + preview.add_action (buy_action); |
1071 | + } |
1072 | + else // uninstalled, purchased before |
1073 | + { |
1074 | + |
1075 | + Unity.PreviewAction install_action = null; |
1076 | + if (details.raw_price == null || details.raw_price == "") |
1077 | + { |
1078 | + install_action = new Unity.PreviewAction ("install", _("Free Download"), null); |
1079 | + install_action.activated.connect (app_preview_install); |
1080 | + } |
1081 | + else |
1082 | + { |
1083 | + install_action = new Unity.PreviewAction ("install", _("Install"), null); |
1084 | + install_action.activated.connect (start_software_center); |
1085 | + } |
1086 | + preview.add_action (install_action); |
1087 | + } |
1088 | + |
1089 | + if (details.website != null && details.website != "") |
1090 | + { |
1091 | + preview_developer_website = details.website; |
1092 | + var website_action = new Unity.PreviewAction ("website", _("Developer Site"), null); |
1093 | + website_action.activated.connect (app_preview_website); |
1094 | + preview.add_action (website_action); |
1095 | + } |
1096 | + } |
1097 | + else // application is already installed |
1098 | + { |
1099 | + preview.add_info (new InfoHint ("date-installed", _("Installed on"), null, details.installation_date)); |
1100 | + var launch_action = new Unity.PreviewAction ("launch", _("Launch"), null); |
1101 | + preview.add_action (launch_action); |
1102 | + if (!details.is_desktop_dependency) |
1103 | + { |
1104 | + var uninstall_action = new Unity.PreviewAction ("uninstall", _("Uninstall"), null); |
1105 | + uninstall_action.activated.connect (app_preview_uninstall); |
1106 | + preview.add_action (uninstall_action); |
1107 | + } |
1108 | + } |
1109 | + |
1110 | + preview_installable_desktop_file = details.desktop_file; |
1111 | + preview_installable_icon_file = details.icon; |
1112 | + } |
1113 | + catch (Error e) |
1114 | + { |
1115 | + warning ("Failed to get package details for '%s': %s", uri, e.message); |
1116 | + preview = null; |
1117 | + } |
1118 | + } |
1119 | + |
1120 | + // xapian db doesn't know this .desktop file or S-C dbus data provider fails, |
1121 | + // fallback to DesktopAppInfo (based on installed .desktop file) if available |
1122 | + if (preview == null && desktopfile != null) |
1123 | + { |
1124 | + var app_info = new DesktopAppInfo (desktopfile); |
1125 | + if (app_info != null) |
1126 | + { |
1127 | + preview = new Unity.ApplicationPreview (app_info.get_display_name (), "", app_info.get_description () ?? "", app_info.get_icon (), null); |
1128 | + var launch_action = new Unity.PreviewAction ("launch", _("Launch"), null); |
1129 | + preview.add_action (launch_action); |
1130 | + } |
1131 | + } |
1132 | + |
1133 | + if (preview == null) |
1134 | + { |
1135 | + warning ("No pksearcher nor desktop app info for '%s'", uri); |
1136 | + } |
1137 | + return preview; |
1138 | + } |
1139 | + |
1140 | + private Unity.Preview make_scope_preview(string uri) |
1141 | + { |
1142 | + Unity.ApplicationPreview? preview = null; |
1143 | + var scope_id = uri.substring (8); |
1144 | + bool scope_disabled = scope_id in disabled_scope_ids; |
1145 | + |
1146 | + // figure out if the scope is remote |
1147 | + bool is_remote_scope = false; |
1148 | + var info = scopesearcher.get_by_desktop_file (scope_id); |
1149 | + |
1150 | + Dee.ModelIter found_iter = null; |
1151 | + if (info == null) |
1152 | + { |
1153 | + var iter = remote_scopes_model.get_first_iter (); |
1154 | + var end_iter = remote_scopes_model.get_last_iter (); |
1155 | + while (iter != end_iter) |
1156 | + { |
1157 | + if (remote_scopes_model.get_string (iter, 0) == scope_id) |
1158 | + { |
1159 | + is_remote_scope = true; |
1160 | + found_iter = iter; |
1161 | + break; |
1162 | + } |
1163 | + iter = remote_scopes_model.next (iter); |
1164 | + } |
1165 | + } |
1166 | + |
1167 | + if (is_remote_scope) |
1168 | + { |
1169 | + var name = remote_scopes_model.get_string (found_iter, 1); |
1170 | + if (name == null || name == "") |
1171 | + name = remote_scopes_model.get_string (found_iter, 0); |
1172 | + var description = remote_scopes_model.get_string (found_iter, 2); |
1173 | + if (description != null) |
1174 | + description = Markup.escape_text(description); |
1175 | + Icon? icon = null; |
1176 | + Icon? screenshot = null; |
1177 | + var icon_hint = remote_scopes_model.get_string (found_iter, 3); |
1178 | + var screenshot_url = remote_scopes_model.get_string (found_iter, 4); |
1179 | + try |
1180 | + { |
1181 | + if (icon_hint != "") icon = Icon.new_for_string (icon_hint); |
1182 | + if (screenshot_url != "") screenshot = Icon.new_for_string (screenshot_url); |
1183 | + } |
1184 | + catch (Error err) |
1185 | + { |
1186 | + warning ("%s", err.message); |
1187 | + } |
1188 | + |
1189 | + if (icon == null) icon = get_default_scope_icon (); |
1190 | + |
1191 | + preview = new Unity.ApplicationPreview (name, |
1192 | + "", |
1193 | + description, |
1194 | + icon, |
1195 | + screenshot); |
1196 | + } |
1197 | + else if (info != null) |
1198 | + { |
1199 | + var name = info.application_name; |
1200 | + if (name == null || name == "") |
1201 | + name = info.desktop_file; |
1202 | + var subtitle = ""; |
1203 | + var description = info.description; |
1204 | + if (description != null) |
1205 | + description = Markup.escape_text(description); |
1206 | + Icon? icon = null; |
1207 | + Icon? screenshot = null; |
1208 | + try |
1209 | + { |
1210 | + if (info.icon != null && info.icon != "") |
1211 | + icon = Icon.new_for_string (info.icon); |
1212 | + } |
1213 | + catch (Error err) |
1214 | + { |
1215 | + warning ("%s", err.message); |
1216 | + } |
1217 | + if (icon == null) |
1218 | + icon = get_default_scope_icon (); |
1219 | + |
1220 | + // de-mangle desktop file names back to what S-C expects |
1221 | + string mangled_id; |
1222 | + if (sc_mangler.contains (scope_id)) |
1223 | + { |
1224 | + mangled_id = sc_mangler.get (scope_id); |
1225 | + } |
1226 | + else |
1227 | + { |
1228 | + mangled_id = scope_id; |
1229 | + } |
1230 | + |
1231 | + Unity.Package.PackageInfo pkginfo = pkgsearcher.get_by_desktop_file (mangled_id); |
1232 | + if (pkginfo != null) |
1233 | + { |
1234 | + SoftwareCenterData.AppDetailsData? details; |
1235 | try { |
1236 | - if (sc_data_provider == null) |
1237 | - { |
1238 | - sc_data_provider = new SoftwareCenterDataCache (TOP_RATED_ITEMS_CACHE_LIFETIME); |
1239 | - sc_data_provider.connect_to (); |
1240 | - } |
1241 | - |
1242 | - debug ("Requesting pkg info: %s, %s\n", pkgname, appname); |
1243 | - var details = sc_data_provider.get_app_details (appname, pkgname); |
1244 | - |
1245 | - Icon? icon = null; |
1246 | - if (installed) |
1247 | - icon = new GLib.ThemedIcon (details.icon); |
1248 | - else |
1249 | - { |
1250 | - icon = find_pkg_icon (null, details.icon); |
1251 | - if (icon.to_string () == GENERIC_APP_ICON && details.icon_url != null && details.icon_url != "") |
1252 | - { |
1253 | - icon = new GLib.FileIcon (File.new_for_uri (details.icon_url)); |
1254 | - } |
1255 | - } |
1256 | - |
1257 | - Icon? screenshot = null; |
1258 | - |
1259 | + details = get_app_details(pkginfo.application_name, |
1260 | + pkginfo.package_name); |
1261 | + } catch (Error e) { |
1262 | + details = null; |
1263 | + } |
1264 | + if (details != null) { |
1265 | + if (details.version != "") |
1266 | + subtitle = _("Version %s").printf (details.version); |
1267 | if (details.screenshot != null) |
1268 | { |
1269 | File scr_file = File.new_for_uri (details.screenshot); |
1270 | screenshot = new FileIcon (scr_file); |
1271 | } |
1272 | - |
1273 | - string subtitle = ""; |
1274 | - if (details.version != "") |
1275 | - subtitle = _("Version %s").printf (details.version); |
1276 | - if (details.size > 0) |
1277 | - { |
1278 | - if (subtitle != "") |
1279 | - subtitle += ", "; |
1280 | - subtitle += (_("Size %s")).printf (GLib.format_size (details.size)); |
1281 | - } |
1282 | - preview = new Unity.ApplicationPreview (details.name, subtitle, details.description, icon, screenshot); |
1283 | - preview.license = details.license; |
1284 | - |
1285 | - init_ratings_db (); |
1286 | - if (ratings != null) |
1287 | - { |
1288 | - Unity.Ratings.Result result; |
1289 | - ratings.query (pkgname, out result); |
1290 | - preview.set_rating (result.average_rating / 5.0f, result.total_rating); |
1291 | - } |
1292 | - |
1293 | - if (details.hardware_requirements != "") |
1294 | - preview.add_info (new InfoHint ("hardware-requirements", _("Hardware requirements"), null, details.hardware_requirements)); |
1295 | - |
1296 | - if (uri.has_prefix ("unity-install://")) // application needs to be purchased/installed |
1297 | - { |
1298 | - // uninstalled and not purchased before |
1299 | - if (details.pkg_state == SoftwareCenterData.PackageState.NEEDS_PURCHASE) |
1300 | - { |
1301 | - var buy_action = new Unity.PreviewAction ("buy", _("Buy"), null); |
1302 | - if (details.price != null && details.price != "") |
1303 | - { |
1304 | - buy_action.extra_text = details.price; |
1305 | - } |
1306 | - |
1307 | - buy_action.activated.connect (start_software_center); |
1308 | - preview.add_action (buy_action); |
1309 | - } |
1310 | - else // uninstalled, purchased before |
1311 | - { |
1312 | - |
1313 | - Unity.PreviewAction install_action = null; |
1314 | - if (details.raw_price == null || details.raw_price == "") |
1315 | - { |
1316 | - install_action = new Unity.PreviewAction ("install", _("Free Download"), null); |
1317 | - install_action.activated.connect (app_preview_install); |
1318 | - } |
1319 | - else |
1320 | - { |
1321 | - install_action = new Unity.PreviewAction ("install", _("Install"), null); |
1322 | - install_action.activated.connect (start_software_center); |
1323 | - } |
1324 | - preview.add_action (install_action); |
1325 | - } |
1326 | - |
1327 | - if (details.website != null && details.website != "") |
1328 | - { |
1329 | - preview_developer_website = details.website; |
1330 | - var website_action = new Unity.PreviewAction ("website", _("Developer Site"), null); |
1331 | - website_action.activated.connect (app_preview_website); |
1332 | - preview.add_action (website_action); |
1333 | - } |
1334 | - } |
1335 | - else // application is already installed |
1336 | - { |
1337 | - preview.add_info (new InfoHint ("date-installed", _("Installed on"), null, details.installation_date)); |
1338 | - var launch_action = new Unity.PreviewAction ("launch", _("Launch"), null); |
1339 | - preview.add_action (launch_action); |
1340 | - if (!details.is_desktop_dependency) |
1341 | - { |
1342 | - var uninstall_action = new Unity.PreviewAction ("uninstall", _("Uninstall"), null); |
1343 | - uninstall_action.activated.connect (app_preview_uninstall); |
1344 | - preview.add_action (uninstall_action); |
1345 | - } |
1346 | - } |
1347 | - |
1348 | - preview_installable_desktop_file = details.desktop_file; |
1349 | - preview_installable_icon_file = details.icon; |
1350 | - } |
1351 | - catch (Error e) |
1352 | - { |
1353 | - warning ("Failed to get package details for '%s': %s", uri, e.message); |
1354 | - preview = null; |
1355 | - } |
1356 | - } |
1357 | - |
1358 | - // xapian db doesn't know this .desktop file or S-C dbus data provider fails, |
1359 | - // fallback to DesktopAppInfo (based on installed .desktop file) if available |
1360 | - if (preview == null && desktopfile != null) |
1361 | - { |
1362 | - var app_info = new DesktopAppInfo (desktopfile); |
1363 | - if (app_info != null) |
1364 | - { |
1365 | - preview = new Unity.ApplicationPreview (app_info.get_display_name (), "", app_info.get_description () ?? "", app_info.get_icon (), null); |
1366 | - var launch_action = new Unity.PreviewAction ("launch", _("Launch"), null); |
1367 | - preview.add_action (launch_action); |
1368 | - } |
1369 | - } |
1370 | - |
1371 | - if (preview == null) |
1372 | - { |
1373 | - warning ("No pksearcher nor desktop app info for '%s'", uri); |
1374 | - } |
1375 | + } |
1376 | + } |
1377 | + |
1378 | + preview = new Unity.ApplicationPreview (name, |
1379 | + subtitle, |
1380 | + description, |
1381 | + icon, |
1382 | + screenshot); |
1383 | + } |
1384 | + if (preview != null && scope_id != "home.scope" && |
1385 | + scope_id != "applications.scope") |
1386 | + { |
1387 | + PreviewAction action; |
1388 | + preview.set_rating(-1.0f, 0); |
1389 | + if (scope_disabled) |
1390 | + { |
1391 | + action = new Unity.PreviewAction ("enable-scope", _("Enable"), null); |
1392 | + action.activated.connect (() => |
1393 | + { |
1394 | + enable_scope (scope_id); |
1395 | + return new ActivationResponse.with_preview (this.preview (uri)); |
1396 | + }); |
1397 | + } |
1398 | + else |
1399 | + { |
1400 | + action = new Unity.PreviewAction ("disable-scope", _("Disable"), null); |
1401 | + action.activated.connect (() => |
1402 | + { |
1403 | + disable_scope (scope_id); |
1404 | + return new ActivationResponse.with_preview (this.preview (uri)); |
1405 | + }); |
1406 | + } |
1407 | + preview.add_action (action); |
1408 | } |
1409 | return preview; |
1410 | } |
1411 | |
1412 | + private void disable_scope (string scope_id) |
1413 | + { |
1414 | + if (scope_id in disabled_scope_ids) return; |
1415 | + |
1416 | + var pref_man = PreferencesManager.get_default (); |
1417 | + var disabled_scopes = pref_man.disabled_scopes; |
1418 | + disabled_scopes += scope_id; |
1419 | + |
1420 | + var settings = new Settings (LIBUNITY_SCHEMA); |
1421 | + settings.set_strv ("disabled-scopes", disabled_scopes); |
1422 | + } |
1423 | + |
1424 | + private void enable_scope (string scope_id) |
1425 | + { |
1426 | + if (!(scope_id in disabled_scope_ids)) return; |
1427 | + |
1428 | + var pref_man = PreferencesManager.get_default (); |
1429 | + string[] disabled_scopes = {}; |
1430 | + foreach (unowned string disabled_scope_id in pref_man.disabled_scopes) |
1431 | + { |
1432 | + if (disabled_scope_id != scope_id) |
1433 | + disabled_scopes += disabled_scope_id; |
1434 | + } |
1435 | + |
1436 | + var settings = new Settings (LIBUNITY_SCHEMA); |
1437 | + settings.set_strv ("disabled-scopes", disabled_scopes); |
1438 | + } |
1439 | /** |
1440 | * Override of the default activation handler. The apps lens daemon |
1441 | * can handle activation of installable apps using the Software Center |
1442 | @@ -1324,7 +1682,7 @@ |
1443 | { |
1444 | string[] args; |
1445 | string exec_or_dir = null; |
1446 | - if (uri.has_prefix ("unity-install://")) |
1447 | + if (uri.has_prefix ("unity-install://") || uri.has_prefix ("scope://")) |
1448 | { |
1449 | var prv = preview (uri); |
1450 | if (prv != null) |
1451 | @@ -1334,7 +1692,7 @@ |
1452 | else |
1453 | { |
1454 | warning ("Failed to generate preview for %s", uri); |
1455 | - return new Unity.ActivationResponse(Unity.HandledType.NOT_HANDLED); |
1456 | + return new Unity.ActivationResponse (Unity.HandledType.NOT_HANDLED); |
1457 | } |
1458 | } |
1459 | else if (uri.has_prefix ("unity-runner://")) |
1460 | @@ -1462,9 +1820,12 @@ |
1461 | string full_path = appmanager.get_path (desktop_id); |
1462 | string full_uri = full_path != null ? "file://" + full_path : app_uri; |
1463 | |
1464 | - results.append (app_uri, app.get_icon().to_string(), category_id, |
1465 | + results.append (app_uri, app.get_icon().to_string(), |
1466 | + category_id, Unity.ResultType.DEFAULT, |
1467 | "application/x-desktop", app.get_display_name (), |
1468 | - sanitize_binary_name (app.get_executable ()), full_uri); |
1469 | + sanitize_binary_name (app.get_executable ()), |
1470 | + full_uri, |
1471 | + empty_asv); |
1472 | } |
1473 | } |
1474 | |
1475 | |
1476 | === modified file 'src/main.vala' |
1477 | --- src/main.vala 2011-10-06 12:25:59 +0000 |
1478 | +++ src/main.vala 2013-05-16 21:22:23 +0000 |
1479 | @@ -22,6 +22,7 @@ |
1480 | |
1481 | namespace Unity.ApplicationsLens { |
1482 | |
1483 | + const string DBUS_NAME = "com.canonical.Unity.Scope.Applications"; |
1484 | static Application? app = null; |
1485 | static Daemon? daemon = null; |
1486 | |
1487 | @@ -71,7 +72,7 @@ |
1488 | * making it race against GDBus' worker thread to export our |
1489 | * objects on the bus before/after owning our name and receiving |
1490 | * method calls on our objects (which may not yet be up!)*/ |
1491 | - if (dbus_name_has_owner ("com.canonical.Unity.Lens.Applications")) |
1492 | + if (dbus_name_has_owner (DBUS_NAME)) |
1493 | { |
1494 | print ("Another instance of the Unity Applications Daemon " + |
1495 | "already appears to be running.\nBailing out.\n"); |
1496 | @@ -83,8 +84,7 @@ |
1497 | daemon = new Daemon (); |
1498 | |
1499 | /* Use GApplication directly for single instance app functionality */ |
1500 | - app = new Application ("com.canonical.Unity.Lens.Applications", |
1501 | - ApplicationFlags.IS_SERVICE); |
1502 | + app = new Application (DBUS_NAME, ApplicationFlags.IS_SERVICE); |
1503 | try { |
1504 | app.register (); |
1505 | } catch (Error e) { |
1506 | @@ -93,7 +93,7 @@ |
1507 | print ("Failed to start applications daemon: %s\n", e.message); |
1508 | return 1; |
1509 | } |
1510 | - |
1511 | + |
1512 | if (app.get_is_remote ()) |
1513 | { |
1514 | print ("Another instance of the Unity Applications Daemon " + |
1515 | |
1516 | === modified file 'src/runner.vala' |
1517 | --- src/runner.vala 2012-11-05 19:18:41 +0000 |
1518 | +++ src/runner.vala 2013-05-16 21:22:23 +0000 |
1519 | @@ -27,7 +27,7 @@ |
1520 | public string name; |
1521 | public string exec; |
1522 | public Icon icon; |
1523 | - |
1524 | + |
1525 | public AboutEntry (string name, string exec, Icon icon) |
1526 | { |
1527 | this.name = name; |
1528 | @@ -37,30 +37,33 @@ |
1529 | } |
1530 | |
1531 | public class Runner: GLib.Object |
1532 | - { |
1533 | - |
1534 | - private Unity.ApplicationsLens.Daemon daemon; |
1535 | + { |
1536 | + |
1537 | + private Unity.ApplicationsLens.Daemon daemon; |
1538 | private const string BUS_NAME_PREFIX = "com.canonical.Unity.ApplicationsLens.Runner"; |
1539 | - |
1540 | + |
1541 | /* for now, load the same keys as gnome-panel */ |
1542 | private const string HISTORY_KEY = "history"; |
1543 | private const int MAX_HISTORY = 10; |
1544 | - |
1545 | - public Unity.Lens lens; |
1546 | - public Unity.Scope scope; |
1547 | + |
1548 | + public Unity.DeprecatedScope scope; |
1549 | |
1550 | private Gee.HashMap<string,AboutEntry> about_entries; |
1551 | private Gee.List<string> history; |
1552 | private ExecSearcher exec_searcher = new ExecSearcher (); |
1553 | |
1554 | private Settings gp_settings; |
1555 | - |
1556 | + |
1557 | public Runner (Unity.ApplicationsLens.Daemon daemon) |
1558 | { |
1559 | /* First create scope */ |
1560 | - scope = new Unity.Scope ("/com/canonical/unity/scope/commands"); |
1561 | + scope = new Unity.DeprecatedScope ("/com/canonical/unity/scope/commands", |
1562 | + "commands"); |
1563 | scope.search_in_global = false; |
1564 | - |
1565 | + scope.search_hint = _("Run a command"); |
1566 | + scope.visible = false; |
1567 | + populate_categories (); |
1568 | + |
1569 | /* Listen for changes to the lens scope search */ |
1570 | scope.search_changed.connect ((lens_search, search_type, cancellable) => |
1571 | { |
1572 | @@ -73,56 +76,53 @@ |
1573 | return lens_search.search_string.strip (); |
1574 | }); |
1575 | |
1576 | - // Listen for when the lens is hidden/shown by the Unity Shell |
1577 | - scope.notify["active"].connect(() => |
1578 | - { |
1579 | - if (scope.active) |
1580 | - { |
1581 | - scope.queue_search_changed (SearchType.DEFAULT); |
1582 | - } |
1583 | - }); |
1584 | - |
1585 | scope.activate_uri.connect (daemon.activate); |
1586 | |
1587 | - /* Now create Lens */ |
1588 | - lens = new Unity.Lens ("/com/canonical/unity/lens/commands", "commands"); |
1589 | - lens.search_hint = _("Run a command"); |
1590 | - lens.visible = false; |
1591 | - lens.search_in_global = false; |
1592 | - populate_categories (); |
1593 | - //populate_filters(); |
1594 | - lens.add_local_scope (scope); |
1595 | - lens.export (); |
1596 | - |
1597 | /* create the private about entries */ |
1598 | about_entries = new Gee.HashMap<string,AboutEntry> (); |
1599 | load_about_entries (); |
1600 | - |
1601 | + |
1602 | this.gp_settings = new Settings ("com.canonical.Unity.Runner"); |
1603 | history = new Gee.ArrayList<string> (); |
1604 | load_history (); |
1605 | - |
1606 | + |
1607 | this.daemon = daemon; |
1608 | - |
1609 | + |
1610 | + scope.export (); |
1611 | } |
1612 | |
1613 | private void populate_categories () |
1614 | { |
1615 | - var categories = new GLib.List<Unity.Category> (); |
1616 | + var categories = new Unity.CategorySet (); |
1617 | var icon_dir = File.new_for_path (ICON_PATH); |
1618 | - var cat = new Unity.Category (_("Results"), |
1619 | + var cat = new Unity.Category ("results", _("Results"), |
1620 | new FileIcon (icon_dir.get_child ("group-installed.svg"))); |
1621 | - categories.append (cat); |
1622 | + categories.add (cat); |
1623 | |
1624 | - cat = new Unity.Category (_("History"), |
1625 | + cat = new Unity.Category ("history", _("History"), |
1626 | new FileIcon (icon_dir.get_child ("group-available.svg"))); |
1627 | |
1628 | - categories.append (cat); |
1629 | - |
1630 | - lens.categories = categories; |
1631 | - } |
1632 | - |
1633 | - private async void update_search (LensSearch search) |
1634 | + categories.add (cat); |
1635 | + |
1636 | + scope.categories = categories; |
1637 | + } |
1638 | + |
1639 | + private void add_result (Dee.Model model, string uri, string icon_hint, |
1640 | + uint category_id, string mimetype, string title) |
1641 | + { |
1642 | + Variant row_data[9]; |
1643 | + model.append_row ( |
1644 | + model.build_named_row_static (row_data, "uri", uri, |
1645 | + "icon_hint", icon_hint, |
1646 | + "category", category_id, |
1647 | + "result_type", ResultType.DEFAULT, |
1648 | + "mimetype", mimetype, |
1649 | + "title", title, |
1650 | + "comment", "", |
1651 | + "dnd_uri", uri)); |
1652 | + } |
1653 | + |
1654 | + private async void update_search (DeprecatedScopeSearch search) |
1655 | { |
1656 | var model = search.results_model; |
1657 | var executables_match = new Gee.ArrayList<string> (); |
1658 | @@ -132,19 +132,17 @@ |
1659 | var search_string = search.search_string; |
1660 | bool has_search = !Utils.is_search_empty (search.search_string); |
1661 | |
1662 | - string uri; |
1663 | + string uri; |
1664 | Icon icon; |
1665 | string mimetype; |
1666 | string display_name; |
1667 | var category_id = RunnerCategory.HISTORY; |
1668 | |
1669 | foreach (var command in this.history) |
1670 | - { |
1671 | - display_name = get_icon_uri_and_mimetype (command, out icon, out uri, out mimetype); |
1672 | - model.append (uri, icon.to_string (), |
1673 | - category_id, mimetype, |
1674 | - display_name, |
1675 | - null); |
1676 | + { |
1677 | + display_name = get_icon_uri_and_mimetype (command, out icon, out uri, out mimetype); |
1678 | + add_result (model, uri, icon.to_string (), category_id, mimetype, |
1679 | + display_name); |
1680 | } |
1681 | |
1682 | if (!has_search) |
1683 | @@ -154,34 +152,30 @@ |
1684 | } |
1685 | |
1686 | Timer timer = new Timer (); |
1687 | - |
1688 | + |
1689 | /* no easter egg in unity */ |
1690 | if (search_string == "free the fish") |
1691 | { |
1692 | - uri = "no-easter-egg"; |
1693 | + uri = "about:blank"; |
1694 | string commenteaster = _("There is no easter egg in Unity"); |
1695 | icon = new ThemedIcon ("gnome-panel-fish"); |
1696 | - model.append (uri, icon.to_string (), |
1697 | - 0, "no-mime", |
1698 | - commenteaster, |
1699 | - null); |
1700 | + add_result (model, uri, icon.to_string (), 0, "text/plain", |
1701 | + commenteaster); |
1702 | search.finished (); |
1703 | return; |
1704 | } |
1705 | else if (search_string == "gegls from outer space") |
1706 | { |
1707 | - uri = "really-no-easter-egg"; |
1708 | + uri = "about:blank"; |
1709 | string commentnoeaster = _("Still no easter egg in Unity"); |
1710 | icon = new ThemedIcon ("gnome-panel-fish"); |
1711 | - model.append (uri, icon.to_string (), |
1712 | - 0, "no-mime", |
1713 | - commentnoeaster, |
1714 | - null); |
1715 | + add_result (model, uri, icon.to_string (), 0, "text/plain", |
1716 | + commentnoeaster); |
1717 | search.finished (); |
1718 | return; |
1719 | - |
1720 | + |
1721 | } |
1722 | - |
1723 | + |
1724 | /* manual seek with directory and executables result */ |
1725 | if (search_string.has_prefix ("/") || search_string.has_prefix ("~")) |
1726 | { |
1727 | @@ -189,7 +183,7 @@ |
1728 | var search_dirname = Path.get_dirname (search_string); |
1729 | var directory = File.new_for_path (search_dirname); |
1730 | var search_dirname_in_path = false; |
1731 | - |
1732 | + |
1733 | /* strip path_directory if in executable in path */ |
1734 | foreach (var path_directory in Environment.get_variable ("PATH").split(":")) |
1735 | { |
1736 | @@ -208,7 +202,7 @@ |
1737 | var subelem_info = iterator.next_file (); |
1738 | if (subelem_info == null) |
1739 | break; |
1740 | - |
1741 | + |
1742 | var complete_path = Path.build_filename (search_dirname, subelem_info.get_name ()); |
1743 | if (complete_path.has_prefix (search_string)) |
1744 | { |
1745 | @@ -241,10 +235,10 @@ |
1746 | executables_match.add (matching_exec); |
1747 | } |
1748 | } |
1749 | - |
1750 | + |
1751 | executables_match.sort (); |
1752 | dirs_match.sort (); |
1753 | - |
1754 | + |
1755 | category_id = RunnerCategory.RESULTS; |
1756 | |
1757 | // populate results |
1758 | @@ -252,45 +246,38 @@ |
1759 | if ((executables_match.size == 0) && (dirs_match.size == 0)) |
1760 | { |
1761 | display_name = get_icon_uri_and_mimetype (search_string, out icon, out uri, out mimetype); |
1762 | - model.append (uri.strip (), icon.to_string (), |
1763 | - category_id, mimetype, |
1764 | - display_name, |
1765 | - null); |
1766 | + add_result (model, uri.strip (), icon.to_string (), |
1767 | + category_id, mimetype, display_name); |
1768 | } |
1769 | - |
1770 | + |
1771 | // 2. add possible directories (we don't store them) |
1772 | mimetype = "inode/directory"; |
1773 | icon = ContentType.get_icon (mimetype); |
1774 | foreach (var dir in dirs_match) |
1775 | { |
1776 | uri = @"unity-runner://$(dir)"; |
1777 | - model.append (uri, icon.to_string (), |
1778 | - category_id, mimetype, |
1779 | - dir, |
1780 | - null); |
1781 | + add_result (model, uri, icon.to_string (), |
1782 | + category_id, mimetype, dir); |
1783 | } |
1784 | - |
1785 | + |
1786 | // 3. add available exec |
1787 | foreach (var final_exec in executables_match) |
1788 | { |
1789 | // TODO: try to match to a desktop file for the icon |
1790 | uri = @"unity-runner://$(final_exec)"; |
1791 | - display_name = get_icon_uri_and_mimetype (final_exec, out icon, out uri, out mimetype); |
1792 | - |
1793 | - model.append (uri, icon.to_string (), |
1794 | - category_id, mimetype, |
1795 | - display_name, |
1796 | - null); |
1797 | + display_name = get_icon_uri_and_mimetype (final_exec, out icon, out uri, out mimetype); |
1798 | + add_result (model, uri, icon.to_string (), |
1799 | + category_id, mimetype, display_name); |
1800 | } |
1801 | - |
1802 | + |
1803 | timer.stop (); |
1804 | debug ("Entry search listed %i dir matches and %i exec matches in %fms for search: %s", |
1805 | dirs_match.size, executables_match.size, timer.elapsed ()*1000, search_string); |
1806 | - |
1807 | + |
1808 | |
1809 | search.finished (); |
1810 | } |
1811 | - |
1812 | + |
1813 | private class ExecSearcher: Object |
1814 | { |
1815 | public ExecSearcher () |
1816 | @@ -378,13 +365,13 @@ |
1817 | return matching; |
1818 | } |
1819 | } |
1820 | - |
1821 | + |
1822 | private string get_icon_uri_and_mimetype (string exec_string, out Icon? icon, out string? uri, out string? mimetype) |
1823 | { |
1824 | - |
1825 | + |
1826 | AboutEntry? entry = null; |
1827 | - |
1828 | - mimetype = "application/x-unity-run"; |
1829 | + |
1830 | + mimetype = "application/x-unity-run"; |
1831 | entry = about_entries[exec_string]; |
1832 | if (entry != null) |
1833 | { |
1834 | @@ -395,7 +382,7 @@ |
1835 | |
1836 | uri = @"unity-runner://$(exec_string)"; |
1837 | |
1838 | - |
1839 | + |
1840 | // if it's a folder, show… a folder icone! + right exec |
1841 | if (FileUtils.test (exec_string, FileTest.IS_DIR)) |
1842 | { |
1843 | @@ -404,7 +391,7 @@ |
1844 | return exec_string; |
1845 | } |
1846 | |
1847 | - var s = exec_string.delimit ("-", '_').split (" ", 0)[0]; |
1848 | + var s = exec_string.delimit ("-", '_').split (" ", 0)[0]; |
1849 | var appresults = this.daemon.appsearcher.search (@"type:Application AND exec:$s", 0, |
1850 | Unity.Package.SearchType.EXACT, |
1851 | Unity.Package.Sort.BY_NAME); |
1852 | @@ -413,19 +400,19 @@ |
1853 | |
1854 | if (pkginfo.desktop_file == null) |
1855 | continue; |
1856 | - |
1857 | + |
1858 | // pick the first one |
1859 | icon = this.daemon.find_pkg_icon (pkginfo.desktop_file, pkginfo.icon); |
1860 | return exec_string; |
1861 | - |
1862 | + |
1863 | } |
1864 | - |
1865 | + |
1866 | // if no result, default icon |
1867 | icon = new ThemedIcon ("gtk-execute"); |
1868 | return exec_string; |
1869 | - |
1870 | + |
1871 | } |
1872 | - |
1873 | + |
1874 | |
1875 | public void add_history (string last_command) |
1876 | { |
1877 | @@ -434,14 +421,14 @@ |
1878 | var new_history = new Gee.ArrayList<string> (); |
1879 | var history_store = new string [this.history.size + 1]; |
1880 | int i = 1; |
1881 | - |
1882 | + |
1883 | new_history.add (last_command); |
1884 | history_store[0] = last_command; |
1885 | for (var j = 0; (j < this.history.size) && (i < MAX_HISTORY); j++) |
1886 | { |
1887 | if (this.history[j] == last_command) |
1888 | continue; |
1889 | - |
1890 | + |
1891 | new_history.add(history[j]); |
1892 | history_store[i] = history[j]; |
1893 | i++; |
1894 | @@ -450,11 +437,11 @@ |
1895 | |
1896 | // store in gsettings |
1897 | this.gp_settings.set_strv (HISTORY_KEY, history_store); |
1898 | - |
1899 | + |
1900 | // force a search to refresh history order (TODO: be more clever in the future) |
1901 | scope.queue_search_changed (SearchType.DEFAULT); |
1902 | } |
1903 | - |
1904 | + |
1905 | private void load_history () |
1906 | { |
1907 | int i = 0; |
1908 | @@ -467,39 +454,39 @@ |
1909 | i++; |
1910 | } |
1911 | } |
1912 | - |
1913 | + |
1914 | private void load_about_entries () |
1915 | - { |
1916 | + { |
1917 | AboutEntry entry; |
1918 | string name; |
1919 | string exec; |
1920 | Icon icon; |
1921 | - |
1922 | + |
1923 | // first about:config |
1924 | name = "about:config"; |
1925 | exec = "ccsm -p unityshell"; |
1926 | try { |
1927 | - icon = Icon.new_for_string (@"$(Config.PREFIX)/share/ccsm/icons/hicolor/64x64/apps/plugin-unityshell.png"); |
1928 | + icon = Icon.new_for_string (@"$(Config.PREFIX)/share/ccsm/icons/hicolor/64x64/apps/plugin-unityshell.png"); |
1929 | } |
1930 | catch (Error err) { |
1931 | warning ("Can't find unityshell icon: %s", err.message); |
1932 | icon = new ThemedIcon ("gtk-execute"); |
1933 | - } |
1934 | + } |
1935 | entry = new AboutEntry (name, exec, icon); |
1936 | - |
1937 | + |
1938 | about_entries[name] = entry; |
1939 | about_entries[exec] = entry; |
1940 | - |
1941 | + |
1942 | // second about:robots |
1943 | name = "Robots have a plan."; |
1944 | exec = "firefox about:robots"; |
1945 | entry = new AboutEntry (name, exec, icon = new ThemedIcon ("battery")); |
1946 | - |
1947 | + |
1948 | about_entries["about:robots"] = entry; |
1949 | about_entries[exec] = entry; |
1950 | - |
1951 | + |
1952 | } |
1953 | - |
1954 | + |
1955 | } |
1956 | - |
1957 | + |
1958 | } |
1959 | |
1960 | === modified file 'src/schemas.vala' |
1961 | --- src/schemas.vala 2012-09-13 11:15:00 +0000 |
1962 | +++ src/schemas.vala 2013-05-16 21:22:23 +0000 |
1963 | @@ -37,6 +37,16 @@ |
1964 | INSTALLED, |
1965 | AVAILABLE, |
1966 | } |
1967 | + |
1968 | + public enum RemoteScopesColumn |
1969 | + { |
1970 | + SCOPE_ID, |
1971 | + NAME, |
1972 | + DESCRIPTION, |
1973 | + ICON_HINT, |
1974 | + SCREENSHOT_URL, |
1975 | + KEYWORDS |
1976 | + } |
1977 | |
1978 | public enum RunnerCategory |
1979 | { |
1980 | |
1981 | === modified file 'src/unity-package-search.cc' |
1982 | --- src/unity-package-search.cc 2013-04-15 16:32:36 +0000 |
1983 | +++ src/unity-package-search.cc 2013-05-16 21:22:23 +0000 |
1984 | @@ -59,6 +59,10 @@ |
1985 | #define XAPIAN_VALUE_EXENAME 294 |
1986 | #define XAPIAN_VALUE_CURRENCY 201 |
1987 | |
1988 | +/* this isn't a Software Center slot, but we use it to mark master |
1989 | + * scopes in the scope index. */ |
1990 | +#define XAPIAN_VALUE_MASTERSCOPE 1000 |
1991 | + |
1992 | #include "unity-package-search.h" |
1993 | #include "columbus.hh" |
1994 | |
1995 | @@ -184,6 +188,10 @@ |
1996 | query_parser->add_prefix ("pkgname", "AP"); |
1997 | query_parser->add_prefix ("exec", "XX"); |
1998 | query_parser->add_prefix ("keyword", "KW"); |
1999 | + query_parser->add_prefix ("pkg_wildcard", "XP"); |
2000 | + query_parser->add_prefix ("pkg_wildcard", "XPM"); |
2001 | + query_parser->add_prefix ("pkg_wildcard", "AP"); |
2002 | + query_parser->add_prefix ("pkg_wildcard", "APM"); |
2003 | query_parser->set_default_op (Xapian::Query::OP_AND); |
2004 | query_parser->set_database (db); |
2005 | searcher->query_parser = query_parser; |
2006 | @@ -235,6 +243,9 @@ |
2007 | if (g_app_info_get_display_name (app_info)) |
2008 | doc.add_value (XAPIAN_VALUE_APPNAME, g_app_info_get_display_name (app_info)); |
2009 | |
2010 | + if (g_app_info_get_description (app_info)) |
2011 | + doc.add_value (XAPIAN_VALUE_DESCRIPTION, g_app_info_get_description (app_info)); |
2012 | + |
2013 | if (g_app_info_get_icon (app_info)) |
2014 | { |
2015 | gchar *icon_str = g_icon_to_string (g_app_info_get_icon (app_info)); |
2016 | @@ -379,6 +390,97 @@ |
2017 | return searcher; |
2018 | } |
2019 | |
2020 | +/* Recursively traverse the set of scopes */ |
2021 | +static void |
2022 | +index_scope (Xapian::WritableDatabase *db, |
2023 | + Xapian::TermGenerator *indexer, |
2024 | + UnityProtocolScopeRegistryScopeMetadata *info) |
2025 | +{ |
2026 | + Xapian::Document doc; |
2027 | + char *dum1; |
2028 | + |
2029 | + if (info->name != NULL) |
2030 | + doc.add_value (XAPIAN_VALUE_APPNAME, info->name); |
2031 | + if (info->description != NULL) |
2032 | + doc.add_value (XAPIAN_VALUE_DESCRIPTION, info->description); |
2033 | + if (info->icon != NULL) |
2034 | + doc.add_value (XAPIAN_VALUE_ICON, info->icon); |
2035 | + if (info->id != NULL) |
2036 | + doc.add_value (XAPIAN_VALUE_DESKTOP_FILE, info->id); |
2037 | + if (info->is_master) |
2038 | + doc.add_value (XAPIAN_VALUE_MASTERSCOPE, "true"); |
2039 | + |
2040 | + indexer->set_document (doc); |
2041 | + if (info->name != NULL) |
2042 | + { |
2043 | + dum1 = unity_applications_lens_utils_preprocess_string (info->name); |
2044 | + indexer->index_text (dum1, 5); |
2045 | + g_free (dum1); |
2046 | + } |
2047 | + if (info->description != NULL) |
2048 | + { |
2049 | + dum1 = unity_applications_lens_utils_preprocess_string (info->description); |
2050 | + indexer->index_text (dum1, 5); |
2051 | + g_free (dum1); |
2052 | + } |
2053 | + for (GSList *l = info->keywords; l != NULL; l = l->next) |
2054 | + { |
2055 | + dum1 = unity_applications_lens_utils_preprocess_string ((char *)l->data); |
2056 | + indexer->index_text (dum1, 0); |
2057 | + indexer->index_text (dum1, 0, "KW"); |
2058 | + g_free (dum1); |
2059 | + } |
2060 | + |
2061 | + /* Always assume Type=Scope for scopes... */ |
2062 | + doc.add_term ("ATscope"); |
2063 | + |
2064 | + /* Index application name */ |
2065 | + dum1 = g_strconcat ("AA", info->name, NULL); |
2066 | + doc.add_term (dum1); |
2067 | + g_free (dum1); |
2068 | + |
2069 | + db->add_document (doc); |
2070 | +} |
2071 | + |
2072 | +UnityPackageSearcher* |
2073 | +unity_package_searcher_new_for_scopes (UnityProtocolScopeRegistry *scope_registry) |
2074 | +{ |
2075 | + UnityPackageSearcher *searcher; |
2076 | + Xapian::WritableDatabase *db; |
2077 | + |
2078 | + searcher = new UnityPackageSearcher; |
2079 | + db = new Xapian::WritableDatabase (); |
2080 | + searcher->db = db; |
2081 | + searcher->db->add_database (Xapian::InMemory::open ()); |
2082 | + |
2083 | + init_searcher (searcher); |
2084 | + |
2085 | + /* Index the menu recursively */ |
2086 | + searcher->db_merged = false; |
2087 | + Xapian::TermGenerator *indexer = new Xapian::TermGenerator (); |
2088 | + |
2089 | + GSList *scopes = unity_protocol_scope_registry_get_scopes (scope_registry); |
2090 | + for (GSList *l = scopes; l != NULL; l = l->next) |
2091 | + { |
2092 | + UnityProtocolScopeRegistryScopeRegistryNode *node = (UnityProtocolScopeRegistryScopeRegistryNode *)l->data; |
2093 | + index_scope (db, indexer, node->scope_info); |
2094 | + |
2095 | + // Also index any sub-scopes |
2096 | + for (GSList *sl = node->sub_scopes; sl != NULL; sl = sl->next) |
2097 | + { |
2098 | + UnityProtocolScopeRegistryScopeMetadata *info = (UnityProtocolScopeRegistryScopeMetadata *)sl->data; |
2099 | + index_scope (db, indexer, info); |
2100 | + } |
2101 | + } |
2102 | + delete indexer; |
2103 | + db->flush (); |
2104 | + |
2105 | + searcher->matcher = new Columbus::Matcher(); |
2106 | + buildMatcher(searcher); |
2107 | + |
2108 | + return searcher; |
2109 | +} |
2110 | + |
2111 | /* Create a new searcher that searches into the Xapian index |
2112 | * provided by the Software Center */ |
2113 | UnityPackageSearcher* |
2114 | @@ -448,6 +550,9 @@ |
2115 | string appname = doc.get_value (XAPIAN_VALUE_APPNAME); |
2116 | pkginfo->application_name = g_strdup (appname.c_str ()); |
2117 | |
2118 | + string description = doc.get_value (XAPIAN_VALUE_DESCRIPTION); |
2119 | + pkginfo->description = g_strdup (description.c_str ()); |
2120 | + |
2121 | string desktop_file = doc.get_value (XAPIAN_VALUE_DESKTOP_FILE); |
2122 | pkginfo->desktop_file = g_strdup (desktop_file.c_str ()); |
2123 | |
2124 | @@ -465,6 +570,9 @@ |
2125 | const string purchase_date = doc.get_value (XAPIAN_VALUE_PURCHASED_DATE); |
2126 | pkginfo->needs_purchase = purchase_date.empty (); |
2127 | |
2128 | + string is_master = doc.get_value (XAPIAN_VALUE_MASTERSCOPE); |
2129 | + pkginfo->is_master_scope = (is_master == "true"); |
2130 | + |
2131 | return pkginfo; |
2132 | } |
2133 | |
2134 | @@ -572,6 +680,7 @@ |
2135 | // Retrieve the results, note that we build the result->results |
2136 | // list in reverse order and then reverse it before we return it |
2137 | result->num_hits = matches.get_matches_estimated (); |
2138 | + result->fuzzy_search = false; |
2139 | |
2140 | for (Xapian::MSetIterator i = matches.begin(); i != matches.end(); ++i) |
2141 | { |
2142 | @@ -623,6 +732,7 @@ |
2143 | } |
2144 | |
2145 | result->results = g_slist_reverse (result->results); |
2146 | + result->fuzzy_search = true; |
2147 | return result; |
2148 | } |
2149 | |
2150 | @@ -637,11 +747,12 @@ |
2151 | g_return_val_if_fail (searcher != NULL, NULL); |
2152 | g_return_val_if_fail (search_string != NULL, NULL); |
2153 | |
2154 | - bool has_category = strstr(search_string, "category:") != NULL; |
2155 | + bool is_filtered = strstr(search_string, "category:") != NULL |
2156 | + || strstr(search_string, "pkg_wildcard:") != NULL; |
2157 | const char *col_query_str = strstr(search_string, "AND"); |
2158 | xap_result = xapian_search(searcher, search_string, max_hits, search_type, sort); |
2159 | // If Xapian does not find anything, try fuzzy matching. |
2160 | - if(g_slist_length(xap_result->results) == 0 && (!has_category && col_query_str)) { |
2161 | + if (g_slist_length(xap_result->results) == 0 && (!is_filtered && col_query_str)) { |
2162 | g_slice_free(UnityPackageSearchResult, xap_result); |
2163 | col_query_str += 3; |
2164 | UnityPackageSearchResult *res = libcolumbus_search(searcher, col_query_str); |
2165 | @@ -710,6 +821,7 @@ |
2166 | g_hash_table_unref (unique); |
2167 | |
2168 | result->num_hits = num_matches; |
2169 | + result->fuzzy_search = false; |
2170 | return result; |
2171 | } |
2172 | |
2173 | @@ -726,6 +838,7 @@ |
2174 | |
2175 | result = g_slice_new0 (UnityPackageSearchResult); |
2176 | result->num_hits = n_apps; |
2177 | + result->fuzzy_search = false; |
2178 | lastdocid = searcher->db->get_lastdocid (); |
2179 | |
2180 | /* Since we really just pick random apps we may end up with dupes */ |
2181 | @@ -867,6 +980,7 @@ |
2182 | } |
2183 | |
2184 | result->num_hits = num_matches; |
2185 | + result->fuzzy_search = false; |
2186 | return result; |
2187 | } |
2188 | |
2189 | @@ -887,14 +1001,20 @@ |
2190 | Xapian::Document doc = searcher->db->get_document (*it); |
2191 | string value = doc.get_value (XAPIAN_VALUE_DESKTOP_FILE); |
2192 | |
2193 | + bool matches = false; |
2194 | size_t sep = value.find (':'); |
2195 | if (sep != string::npos) |
2196 | { |
2197 | - if (value.compare (sep+1, value.size() - sep, query) == 0) |
2198 | - { |
2199 | - pkginfo = _pkginfo_from_document (doc); |
2200 | - return pkginfo; |
2201 | - } |
2202 | + matches = value.compare (sep+1, value.size() - sep, query) == 0; |
2203 | + } |
2204 | + else |
2205 | + { |
2206 | + matches = value == query; |
2207 | + } |
2208 | + if (matches) |
2209 | + { |
2210 | + pkginfo = _pkginfo_from_document (doc); |
2211 | + return pkginfo; |
2212 | } |
2213 | ++it; |
2214 | } |
2215 | |
2216 | === modified file 'src/unity-package-search.h' |
2217 | --- src/unity-package-search.h 2012-10-09 15:26:49 +0000 |
2218 | +++ src/unity-package-search.h 2013-05-16 21:22:23 +0000 |
2219 | @@ -19,6 +19,7 @@ |
2220 | |
2221 | #include <glib.h> |
2222 | #include <gmenu-tree.h> |
2223 | +#include <unity-protocol.h> |
2224 | |
2225 | typedef struct _UnityPackageSearcher UnityPackageSearcher; |
2226 | |
2227 | @@ -36,19 +37,22 @@ |
2228 | |
2229 | typedef struct |
2230 | { |
2231 | - GSList *results; |
2232 | - gint num_hits; |
2233 | + GSList *results; |
2234 | + gint num_hits; |
2235 | + gboolean fuzzy_search; |
2236 | } UnityPackageSearchResult; |
2237 | |
2238 | typedef struct |
2239 | { |
2240 | gchar *package_name; |
2241 | gchar *application_name; |
2242 | + gchar *description; |
2243 | gchar *desktop_file; |
2244 | gchar *icon; |
2245 | gchar *price; |
2246 | gboolean needs_purchase; |
2247 | gint relevancy; |
2248 | + gboolean is_master_scope; |
2249 | } UnityPackageInfo; |
2250 | |
2251 | typedef gboolean (*AppFilterCallback)(UnityPackageInfo *, void *); |
2252 | @@ -61,6 +65,7 @@ |
2253 | UnityPackageSearcher* unity_package_searcher_new (); |
2254 | |
2255 | UnityPackageSearcher* unity_package_searcher_new_for_menu (GMenuTree *menu); |
2256 | +UnityPackageSearcher* unity_package_searcher_new_for_scopes (UnityProtocolScopeRegistry *scope_registry); |
2257 | |
2258 | void unity_package_searcher_free (UnityPackageSearcher *searcher); |
2259 | |
2260 | |
2261 | === modified file 'src/utils.vala' |
2262 | --- src/utils.vala 2012-10-05 16:17:11 +0000 |
2263 | +++ src/utils.vala 2013-05-16 21:22:23 +0000 |
2264 | @@ -138,6 +138,99 @@ |
2265 | } |
2266 | } |
2267 | |
2268 | + public Dee.Index prepare_index (Dee.Model model, |
2269 | + uint sort_column, |
2270 | + owned Dee.ModelReaderFunc reader_func, |
2271 | + out Dee.Analyzer out_analyzer) |
2272 | + { |
2273 | + // reuse the icu_filter |
2274 | + if (icu_filter == null) |
2275 | + { |
2276 | + icu_filter = new Dee.ICUTermFilter.ascii_folder (); |
2277 | + } |
2278 | + |
2279 | + var sort_filter = Dee.Filter.new_collator (sort_column); |
2280 | + var filter_model = new Dee.FilterModel (model, sort_filter); |
2281 | + |
2282 | + var analyzer = new Dee.TextAnalyzer (); |
2283 | + analyzer.add_term_filter ((terms_in, terms_out) => |
2284 | + { |
2285 | + for (uint i = 0; i < terms_in.num_terms (); i++) |
2286 | + { |
2287 | + unowned string term = terms_in.get_term (i); |
2288 | + var folded = icu_filter.apply (term); |
2289 | + terms_out.add_term (term); |
2290 | + if (folded != term) terms_out.add_term (folded); |
2291 | + } |
2292 | + }); |
2293 | + out_analyzer = analyzer; |
2294 | + |
2295 | + var reader = Dee.ModelReader.new (reader_func); |
2296 | + return new Dee.TreeIndex (filter_model, analyzer, reader); |
2297 | + } |
2298 | + |
2299 | + public SList<Dee.ModelIter> search_index (Dee.Index index, |
2300 | + Dee.Analyzer analyzer, |
2301 | + string query) |
2302 | + { |
2303 | + if (is_search_empty (query)) |
2304 | + { |
2305 | + var model = index.get_model (); |
2306 | + var iter = model.get_first_iter (); |
2307 | + var end_iter = model.get_last_iter (); |
2308 | + |
2309 | + var result = new SList<Dee.ModelIter> (); |
2310 | + while (iter != end_iter) |
2311 | + { |
2312 | + result.prepend (iter); |
2313 | + iter = model.next (iter); |
2314 | + } |
2315 | + result.reverse (); |
2316 | + return result; |
2317 | + } |
2318 | + |
2319 | + var term_list = Object.new (typeof (Dee.TermList)) as Dee.TermList; |
2320 | + analyzer.tokenize (query, term_list); |
2321 | + var matches = new Sequence<Dee.ModelIter> (); |
2322 | + |
2323 | + uint num_terms = term_list.num_terms (); |
2324 | + for (uint i = 0; i < num_terms; i++) |
2325 | + { |
2326 | + var rs = index.lookup (term_list.get_term (i), |
2327 | + i < num_terms - 1 ? Dee.TermMatchFlag.EXACT : Dee.TermMatchFlag.PREFIX); |
2328 | + |
2329 | + bool first_pass = i == 0; |
2330 | + CompareDataFunc<Dee.ModelIter> cmp_func = (a, b) => |
2331 | + { |
2332 | + return a == b ? 0 : ((void*) a > (void*) b ? 1 : -1); |
2333 | + }; |
2334 | + // intersect the results (cause we want to AND the terms) |
2335 | + var remaining = new Sequence<Dee.ModelIter> (); |
2336 | + foreach (var item in rs) |
2337 | + { |
2338 | + if (first_pass) |
2339 | + matches.insert_sorted (item, cmp_func); |
2340 | + else if (matches.lookup (item, cmp_func) != null) |
2341 | + remaining.insert_sorted (item, cmp_func); |
2342 | + } |
2343 | + if (!first_pass) matches = (owned) remaining; |
2344 | + // final result set empty already? |
2345 | + if (matches.get_begin_iter () == matches.get_end_iter ()) break; |
2346 | + } |
2347 | + |
2348 | + var result = new SList<Dee.ModelIter> (); |
2349 | + var iter = matches.get_begin_iter (); |
2350 | + var end_iter = matches.get_end_iter (); |
2351 | + while (iter != end_iter) |
2352 | + { |
2353 | + result.prepend (iter.get ()); |
2354 | + iter = iter.next (); |
2355 | + } |
2356 | + |
2357 | + result.reverse (); |
2358 | + return result; |
2359 | + } |
2360 | + |
2361 | /* Substitute tilde character in @s by the home directory. |
2362 | * Expansion of ~username also works if 'username' is found. */ |
2363 | public string subst_tilde (string s) |
2364 | |
2365 | === modified file 'src/xapian-utils.vala' |
2366 | --- src/xapian-utils.vala 2012-10-08 13:30:44 +0000 |
2367 | +++ src/xapian-utils.vala 2013-05-16 21:22:23 +0000 |
2368 | @@ -31,6 +31,7 @@ |
2369 | "accessibility", |
2370 | "developer", |
2371 | "science-and-engineering", |
2372 | + "scopes", |
2373 | "system" |
2374 | }; |
2375 | |
2376 | @@ -58,6 +59,7 @@ |
2377 | type_queries.insert ("accessibility", "(category:Accessibility AND NOT category:Settings)"); |
2378 | type_queries.insert ("developer", "category:Development"); // FIXME emacs.desktop should be added |
2379 | type_queries.insert ("science-and-engineering", "(category:Science OR category:Engineering)"); |
2380 | + type_queries.insert ("scopes", "(pkg_wildcard:unity_scope_* OR pkg_wildcard:unity_lens_*)"); |
2381 | type_queries.insert ("system", "(category:System OR category:Security)"); |
2382 | } |
2383 | } |
2384 | @@ -107,9 +109,9 @@ |
2385 | if (Utils.is_search_empty (search_string)) |
2386 | { |
2387 | if (options == null || !options.filtering) |
2388 | - return "type:Application"; |
2389 | + return "(type:Application OR type:Scope)"; |
2390 | else |
2391 | - return "type:Application AND " + extract_type_query (options); |
2392 | + return "(type:Application OR type:Scope) AND " + extract_type_query (options); |
2393 | } |
2394 | else |
2395 | { |
2396 | @@ -125,9 +127,9 @@ |
2397 | s = s.delimit ("-", ' '); |
2398 | |
2399 | if (options == null || !options.filtering) |
2400 | - return "type:Application AND " + s; |
2401 | + return "(type:Application OR type:Scope) AND " + s; |
2402 | else |
2403 | - return "type:Application AND %s AND %s".printf (extract_type_query (options), s); |
2404 | + return "(type:Application OR type:Scope) AND %s AND %s".printf (extract_type_query (options), s); |
2405 | } |
2406 | } |
2407 | -} |
2408 | \ No newline at end of file |
2409 | +} |
2410 | |
2411 | === modified file 'tests/unit/Makefile.am' |
2412 | --- tests/unit/Makefile.am 2013-03-01 15:41:08 +0000 |
2413 | +++ tests/unit/Makefile.am 2013-05-16 21:22:23 +0000 |
2414 | @@ -30,6 +30,8 @@ |
2415 | $(test_libs) \ |
2416 | $(UNITY_PACKAGE_SEARCH_LIBS) |
2417 | |
2418 | +LDFLAGS += -rpath $(PROTOCOLPRIVATELIBDIR) |
2419 | + |
2420 | AM_CPPFLAGS = \ |
2421 | $(LENS_DAEMON_CFLAGS) \ |
2422 | -I$(srcdir) \ |
2423 | |
2424 | === modified file 'tests/unit/test-xapian-utils.vala' |
2425 | --- tests/unit/test-xapian-utils.vala 2012-10-08 08:41:45 +0000 |
2426 | +++ tests/unit/test-xapian-utils.vala 2013-05-16 21:22:23 +0000 |
2427 | @@ -43,7 +43,7 @@ |
2428 | internal static void test_empty_search_query () |
2429 | { |
2430 | var query = XapianUtils.prepare_pkg_search_string ("", null); |
2431 | - assert (query == "type:Application"); |
2432 | + assert (query == "(type:Application OR type:Scope)"); |
2433 | } |
2434 | |
2435 | internal static void test_empty_search_with_single_cat_filter () |
2436 | @@ -54,7 +54,7 @@ |
2437 | filter.add_option ("internet", "Internet", null); |
2438 | |
2439 | var query = XapianUtils.prepare_pkg_search_string ("", filter); |
2440 | - assert (query == "type:Application AND (category:AudioVideo)"); |
2441 | + assert (query == "(type:Application OR type:Scope) AND (category:AudioVideo)"); |
2442 | } |
2443 | |
2444 | internal static void test_empty_search_with_multi_cat_filter () |
2445 | @@ -65,16 +65,16 @@ |
2446 | filter.add_option ("internet", "Internet", null); |
2447 | filter.add_option ("game", "Game", null).active = true; |
2448 | var query = XapianUtils.prepare_pkg_search_string ("", filter); |
2449 | - assert (query == "type:Application AND (category:Game OR category:AudioVideo)"); |
2450 | + assert (query == "(type:Application OR type:Scope) AND (category:Game OR category:AudioVideo)"); |
2451 | } |
2452 | |
2453 | internal static void test_search_query_no_filters () |
2454 | { |
2455 | var query = XapianUtils.prepare_pkg_search_string (" foo ", null); |
2456 | - assert (query == "type:Application AND foo"); |
2457 | + assert (query == "(type:Application OR type:Scope) AND foo"); |
2458 | |
2459 | query = XapianUtils.prepare_pkg_search_string ("foo", null); |
2460 | - assert (query == "type:Application AND foo"); |
2461 | + assert (query == "(type:Application OR type:Scope) AND foo"); |
2462 | } |
2463 | |
2464 | internal static void test_search_query_with_single_cat_filter () |
2465 | @@ -84,7 +84,7 @@ |
2466 | filter.add_option ("media", "Media", null); |
2467 | filter.add_option ("internet", "Internet", null).active = true; |
2468 | var query = XapianUtils.prepare_pkg_search_string ("foo", filter); |
2469 | - assert (query == "type:Application AND (category:Network) AND foo"); |
2470 | + assert (query == "(type:Application OR type:Scope) AND (category:Network) AND foo"); |
2471 | } |
2472 | |
2473 | internal static void test_search_query_with_multi_cat_filter () |
2474 | @@ -95,7 +95,7 @@ |
2475 | filter.add_option ("internet", "Internet", null).active = true; |
2476 | filter.add_option ("game", "Game", null).active = true; |
2477 | var query = XapianUtils.prepare_pkg_search_string ("foo", filter); |
2478 | - assert (query == "type:Application AND (category:Game OR category:Network) AND foo"); |
2479 | + assert (query == "(type:Application OR type:Scope) AND (category:Game OR category:Network) AND foo"); |
2480 | } |
2481 | |
2482 | internal static void test_zg_empty_search_query () |
2483 | |
2484 | === modified file 'vapi/unity-package-search.deps' |
2485 | --- vapi/unity-package-search.deps 2012-10-18 12:36:37 +0000 |
2486 | +++ vapi/unity-package-search.deps 2013-05-16 21:22:23 +0000 |
2487 | @@ -1,2 +1,3 @@ |
2488 | glib-2.0 |
2489 | libgnome-menu-3.0 |
2490 | +unity-protocol |
2491 | |
2492 | === modified file 'vapi/unity-package-search.vapi' |
2493 | --- vapi/unity-package-search.vapi 2012-10-08 15:11:07 +0000 |
2494 | +++ vapi/unity-package-search.vapi 2013-05-16 21:22:23 +0000 |
2495 | @@ -27,6 +27,8 @@ |
2496 | public Searcher (); |
2497 | [CCode (cname = "unity_package_searcher_new_for_menu")] |
2498 | public Searcher.for_menu(GMenu.Tree menu); |
2499 | + [CCode (cname = "unity_package_searcher_new_for_scopes")] |
2500 | + public Searcher.for_scopes(Unity.Protocol.ScopeRegistry scope_registry); |
2501 | public SearchResult search (string search_string, uint max_hits, Unity.Package.SearchType search_type, Unity.Package.Sort sort); |
2502 | public SearchResult get_random_apps (string? filter_query, uint n_apps); |
2503 | public SearchResult get_apps (string? filter_query, uint n_apps, AppFilterCallback cb); |
2504 | @@ -41,6 +43,7 @@ |
2505 | public SearchResult (); |
2506 | public GLib.SList<PackageInfo> results; |
2507 | public int num_hits; |
2508 | + public bool fuzzy_search; |
2509 | } |
2510 | |
2511 | [Compact] |
2512 | @@ -49,11 +52,13 @@ |
2513 | public PackageInfo (); |
2514 | public string package_name; |
2515 | public string application_name; |
2516 | + public string description; |
2517 | public string desktop_file; |
2518 | public string icon; |
2519 | public string price; |
2520 | public bool needs_purchase; |
2521 | public int relevancy; |
2522 | + public bool is_master_scope; |
2523 | } |
2524 | } |
2525 | } |
FAILED: Continuous integration, rev:340 jenkins. qa.ubuntu. com/job/ unity-lens- applications- ci/8/ jenkins. qa.ubuntu. com/job/ unity-lens- applications- raring- amd64-ci/ 8/console jenkins. qa.ubuntu. com/job/ unity-lens- applications- raring- armhf-ci/ 8/console jenkins. qa.ubuntu. com/job/ unity-lens- applications- raring- i386-ci/ 8/console
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild: s-jenkins: 8080/job/ unity-lens- applications- ci/8/rebuild
http://