Merge lp:~stolowski/unity-lens-applications/unity-lens-applications.formatting-fixes into lp:unity-lens-applications
- unity-lens-applications.formatting-fixes
- Merge into trunk
Proposed by
Paweł Stołowski
Status: | Superseded |
---|---|
Proposed branch: | lp:~stolowski/unity-lens-applications/unity-lens-applications.formatting-fixes |
Merge into: | lp:unity-lens-applications |
Diff against target: |
2167 lines (+1039/-460) 9 files modified
configure.ac (+3/-3) src/Makefile.am (+5/-2) src/aptd-client.vala (+97/-0) src/daemon.vala (+523/-232) src/launcher-client.vala (+45/-0) src/software-center-data-provider.vala (+115/-0) src/unity-package-search.cc (+237/-213) src/unity-package-search.h (+12/-9) vapi/unity-package-search.vapi (+2/-1) |
To merge this branch: | bzr merge lp:~stolowski/unity-lens-applications/unity-lens-applications.formatting-fixes |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Michal Hruby | Pending | ||
Review via email: mp+118791@code.launchpad.net |
Commit message
Description of the change
Formatting fixes.
To post a comment you must log in.
- 313. By Paweł Stołowski
-
Merged previews branch.
- 314. By Paweł Stołowski
-
Some more formatting fixes.
- 315. By Paweł Stołowski
-
Merged trunk.
Unmerged revisions
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'configure.ac' |
2 | --- configure.ac 2012-04-27 07:39:53 +0000 |
3 | +++ configure.ac 2012-08-08 16:35:21 +0000 |
4 | @@ -103,9 +103,9 @@ |
5 | # look for dbus service dir |
6 | ############################################# |
7 | if test "x$with_localinstall" = "xyes"; then |
8 | - DBUSSERVICEDIR="${datadir}/dbus-1/services/" |
9 | + DBUSSERVICEDIR="${datadir}/dbus-1/services/" |
10 | else |
11 | - DBUSSERVICEDIR=`$PKG_CONFIG --variable=session_bus_services_dir dbus-1` |
12 | + DBUSSERVICEDIR=`$PKG_CONFIG --variable=session_bus_services_dir dbus-1` |
13 | fi |
14 | AC_SUBST(DBUSSERVICEDIR) |
15 | |
16 | @@ -140,7 +140,7 @@ |
17 | |
18 | Prefix : ${prefix} |
19 | Sysconfdir : ${sysconfdir} |
20 | - |
21 | + |
22 | Local install : ${with_localinstall} |
23 | |
24 | Extra CFlags : ${CPPFLAGS} $MAINTAINER_CFLAGS |
25 | |
26 | === modified file 'src/Makefile.am' |
27 | --- src/Makefile.am 2012-01-24 11:30:08 +0000 |
28 | +++ src/Makefile.am 2012-08-08 16:35:21 +0000 |
29 | @@ -19,7 +19,7 @@ |
30 | -I$(srcdir) \ |
31 | -g |
32 | |
33 | -# Note that we require the GLIB_2_22 flag for Valac because libzeitgeist |
34 | +# Note that we require glib 2.26 because libzeitgeist |
35 | # expects us to use g_ptr_array_unref instead of g_ptr_array_free. |
36 | unity_applications_daemon_VALAFLAGS = \ |
37 | -C \ |
38 | @@ -35,7 +35,7 @@ |
39 | --pkg libgnome-menu \ |
40 | --pkg unity-package-search \ |
41 | --pkg unity-ratings-db \ |
42 | - --define=GLIB_2_22 \ |
43 | + --target-glib=2.26 \ |
44 | $(MAINTAINER_VALAFLAGS) |
45 | |
46 | unity_package_search_libs = -lxapian -lstdc++ |
47 | @@ -54,10 +54,13 @@ |
48 | app-watcher.vala \ |
49 | config.vala \ |
50 | daemon.vala \ |
51 | + launcher-client.vala \ |
52 | main.vala \ |
53 | runner.vala \ |
54 | schemas.vala \ |
55 | utils.vala \ |
56 | + aptd-client.vala \ |
57 | + software-center-data-provider.vala \ |
58 | $(NULL) |
59 | |
60 | unity-package-search.o : $(srcdir)/unity-package-search.cc $(srcdir)/unity-package-search.h |
61 | |
62 | === added file 'src/aptd-client.vala' |
63 | --- src/aptd-client.vala 1970-01-01 00:00:00 +0000 |
64 | +++ src/aptd-client.vala 2012-08-08 16:35:21 +0000 |
65 | @@ -0,0 +1,97 @@ |
66 | +/* |
67 | + * Copyright (C) 2012 Canonical Ltd |
68 | + * |
69 | + * This program is free software: you can redistribute it and/or modify |
70 | + * it under the terms of the GNU General Public License version 3 as |
71 | + * published by the Free Software Foundation. |
72 | + * |
73 | + * This program is distributed in the hope that it will be useful, |
74 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
75 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
76 | + * GNU General Public License for more details. |
77 | + * |
78 | + * You should have received a copy of the GNU General Public License |
79 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
80 | + * |
81 | + * Authored by Pawel Stolowski <pawel.stolowski@canonical.com> |
82 | + */ |
83 | + |
84 | +namespace Unity.ApplicationsLens { |
85 | + |
86 | + static const string APTD_DBUS_NAME = "org.debian.apt"; |
87 | + static const string APTD_DBUS_PATH = "/org/debian/apt"; |
88 | + |
89 | + /** |
90 | + * Expose a subset of org.debian.apt interfaces -- only what's needed by applications lens. |
91 | + */ |
92 | + [DBus (name = "org.debian.apt")] |
93 | + public interface AptdService: GLib.Object |
94 | + { |
95 | + public abstract async string install_packages (string[] packages) throws IOError; |
96 | + public abstract async string remove_packages (string[] packages) throws IOError; |
97 | + public abstract async void quit () throws IOError; |
98 | + } |
99 | + |
100 | + [DBus (name = "org.debian.apt.transaction")] |
101 | + public interface AptdTransactionService: GLib.Object |
102 | + { |
103 | + public abstract void run () throws IOError; |
104 | + public abstract void simulate () throws IOError; |
105 | + public abstract void cancel () throws IOError; |
106 | + public signal void finished (string exit_state); |
107 | + } |
108 | + |
109 | + public class AptdProxy: GLib.Object |
110 | + { |
111 | + public void connect_to_aptd () throws IOError |
112 | + { |
113 | + _aptd_service = Bus.get_proxy_sync (BusType.SYSTEM, APTD_DBUS_NAME, APTD_DBUS_PATH); |
114 | + } |
115 | + |
116 | + public async string install_packages (string[] packages) |
117 | + { |
118 | + string res = yield _aptd_service.install_packages (packages); |
119 | + return res; |
120 | + } |
121 | + |
122 | + public async string remove_packages (string[] packages) |
123 | + { |
124 | + string res = yield _aptd_service.remove_packages (packages); |
125 | + return res; |
126 | + } |
127 | + |
128 | + public async void quit () |
129 | + { |
130 | + yield _aptd_service.quit (); |
131 | + } |
132 | + |
133 | + private AptdService _aptd_service; |
134 | + } |
135 | + |
136 | + public class AptdTransactionProxy: GLib.Object |
137 | + { |
138 | + public signal void finished (string transaction_id); |
139 | + |
140 | + public void connect_to_aptd (string transaction_id) throws IOError |
141 | + { |
142 | + _aptd_service = Bus.get_proxy_sync (BusType.SYSTEM, APTD_DBUS_NAME, transaction_id); |
143 | + _aptd_service.finished.connect ((exit_state) => |
144 | + { |
145 | + debug ("aptd transaction finished: %s\n", exit_state); |
146 | + finished (transaction_id); |
147 | + }); |
148 | + } |
149 | + |
150 | + public void simulate () |
151 | + { |
152 | + _aptd_service.simulate (); |
153 | + } |
154 | + |
155 | + public void run () |
156 | + { |
157 | + _aptd_service.run (); |
158 | + } |
159 | + |
160 | + private AptdTransactionService _aptd_service; |
161 | + } |
162 | +} |
163 | |
164 | === modified file 'src/daemon.vala' |
165 | --- src/daemon.vala 2012-04-23 13:58:42 +0000 |
166 | +++ src/daemon.vala 2012-08-08 16:35:21 +0000 |
167 | @@ -27,6 +27,7 @@ |
168 | namespace Unity.ApplicationsLens { |
169 | |
170 | const string ICON_PATH = Config.DATADIR + "/icons/unity-icon-theme/places/svg/"; |
171 | + const string ICON_APP_INSTALL_PATH = Config.DATADIR + "/app-install/icons"; |
172 | |
173 | public class Daemon : GLib.Object |
174 | { |
175 | @@ -41,13 +42,33 @@ |
176 | * the Xapian index from the Software Center */ |
177 | private Unity.Package.Searcher? pkgsearcher; |
178 | public Unity.Package.Searcher appsearcher; |
179 | - |
180 | + |
181 | /* Read the app ratings dumped by the Software Center */ |
182 | private Unity.Ratings.Database? ratings; |
183 | |
184 | private Unity.Lens lens; |
185 | private Unity.Scope scope; |
186 | - |
187 | + |
188 | + /* Support aptd dbus interface; created when application install/remove was requested by preview action */ |
189 | + private AptdProxy aptdclient; |
190 | + private AptdTransactionProxy aptd_transaction; |
191 | + |
192 | + /* Maps demangled names to mangled names expected by S-C xapian DB (e.g. kde4-KCharSelect.desktop -> kde4__KCharSelect.desktop). |
193 | + There are very few apps that need this and we only store mappings when needed, so it takes very little memory. |
194 | + */ |
195 | + private HashTable<string, string> mangled_desktop_ids; |
196 | + |
197 | + /* Used for adding launcher icon on app installation from the preview */ |
198 | + private LauncherProxy launcherservice; |
199 | + |
200 | + /* Desktop file & icon name for unity-install:// install candidate displayed in last preview; we store |
201 | + * them here to avoid extra query for app details if app install action is activated */ |
202 | + private string preview_installable_desktop_file; |
203 | + private string preview_installable_icon_file; |
204 | + |
205 | + /* SoftwareCenter data provider used for app preview details */ |
206 | + private SoftwareCenterDataProviderProxy sc_data_provider; |
207 | + |
208 | private Unity.ApplicationsLens.Runner runner; |
209 | |
210 | /* Keep references to the FilterOptions for sources */ |
211 | @@ -60,14 +81,14 @@ |
212 | |
213 | private Gee.List<string> image_extensions; |
214 | private HashTable<string,Icon> file_icon_cache; |
215 | - |
216 | + |
217 | /* Monitor the favorite apps in the launcher, so we can filter them |
218 | * out of the results for Recent Apps */ |
219 | private Unity.LauncherFavorites favorite_apps; |
220 | private AppWatcher app_watcher; |
221 | |
222 | private PtrArray zg_templates; |
223 | - |
224 | + |
225 | /* Gnome menu structure - also used to check whether apps are installed */ |
226 | private uint app_menu_changed_reindex_timeout = 0; |
227 | private GMenu.Tree app_menu = null; |
228 | @@ -95,7 +116,7 @@ |
229 | monitor.events_inserted.connect (mark_dirty); |
230 | monitor.events_deleted.connect (mark_dirty); |
231 | log.install_monitor (monitor); |
232 | - |
233 | + |
234 | popularity_map = new HashMap<string, int> (); |
235 | popularities_dirty = true; |
236 | // refresh the popularities every now and then |
237 | @@ -111,17 +132,17 @@ |
238 | |
239 | pkgsearcher = new Unity.Package.Searcher (); |
240 | if (pkgsearcher == null) |
241 | - { |
242 | - critical ("Failed to load Software Center index. 'Apps Available for Download' will not be listed"); |
243 | - } |
244 | - |
245 | + { |
246 | + critical ("Failed to load Software Center index. 'Apps Available for Download' will not be listed"); |
247 | + } |
248 | + |
249 | try { |
250 | ratings = new Unity.Ratings.Database (); |
251 | } catch (FileError e) { |
252 | warning (e.message); |
253 | ratings = null; |
254 | } |
255 | - |
256 | + |
257 | /* Image file extensions in order of popularity */ |
258 | image_extensions = new Gee.ArrayList<string> (); |
259 | image_extensions.add ("png"); |
260 | @@ -135,6 +156,7 @@ |
261 | build_app_menu_index (); |
262 | |
263 | file_icon_cache = new HashTable<string,Icon>(str_hash, str_equal); |
264 | + mangled_desktop_ids = new HashTable<string, string>(str_hash, str_equal); |
265 | |
266 | scope = new Unity.Scope ("/com/canonical/unity/scope/applications"); |
267 | //scope.icon = @"$(Config.PREFIX)/share/unity/themes/applications.png"; |
268 | @@ -158,7 +180,7 @@ |
269 | { |
270 | dispatch_search (lens_search, search_type, cancellable); |
271 | }); |
272 | - |
273 | + |
274 | /* Re-do the search if the filters changed */ |
275 | scope.filters_changed.connect (() => |
276 | { |
277 | @@ -172,13 +194,14 @@ |
278 | }); |
279 | |
280 | scope.activate_uri.connect (activate); |
281 | + scope.preview_uri.connect (preview); |
282 | |
283 | /* Listen for changes in the installed applications */ |
284 | AppInfoManager.get_default().changed.connect (mark_dirty); |
285 | - |
286 | + |
287 | /* Now start the RunEntry */ |
288 | runner = new Unity.ApplicationsLens.Runner (this); |
289 | - |
290 | + |
291 | try { |
292 | uri_regex = new Regex ("^[a-z]+:.+$"); |
293 | mountable_regex = new Regex ("((ftp|ssh|sftp|smb|dav)://).+"); |
294 | @@ -186,14 +209,16 @@ |
295 | uri_regex = null; |
296 | critical ("Failed to compile URI regex. URL launching will be disabled"); |
297 | } |
298 | - |
299 | + |
300 | favorite_apps = Unity.LauncherFavorites.get_default (); |
301 | favorite_apps.changed.connect(mark_dirty); |
302 | |
303 | app_watcher = new AppWatcher (); |
304 | app_watcher.running_applications_changed.connect (mark_dirty); |
305 | |
306 | - |
307 | + aptdclient = new AptdProxy (); |
308 | + launcherservice = new LauncherProxy (); |
309 | + |
310 | lens = new Unity.Lens ("/com/canonical/unity/lens/applications", "applications"); |
311 | lens.search_hint = _("Search Applications"); |
312 | lens.visible = true; |
313 | @@ -253,9 +278,9 @@ |
314 | var cat = new Unity.Category (_("Recently Used"), |
315 | new FileIcon (icon_dir.get_child ("group-recent.svg"))); |
316 | categories.append (cat); |
317 | - |
318 | + |
319 | cat = new Unity.Category (_("Recent Apps"), |
320 | - new FileIcon (icon_dir.get_child ("group-apps.svg"))); |
321 | + new FileIcon (icon_dir.get_child ("group-apps.svg"))); |
322 | categories.append (cat); |
323 | |
324 | cat = new Unity.Category (_("Installed"), |
325 | @@ -265,11 +290,11 @@ |
326 | cat = new Unity.Category (_("Apps Available for Download"), |
327 | new FileIcon (icon_dir.get_child ("group-downloads.svg"))); |
328 | categories.append (cat); |
329 | - |
330 | + |
331 | cat = new Unity.Category (_("Applications"), |
332 | new FileIcon (icon_dir.get_child ("group-apps.svg"))); |
333 | categories.append (cat); |
334 | - |
335 | + |
336 | lens.categories = categories; |
337 | } |
338 | |
339 | @@ -281,7 +306,7 @@ |
340 | { |
341 | var filter = new CheckOptionFilter ("type", _("Type")); |
342 | filter.sort_type = Unity.OptionsFilter.SortType.DISPLAY_NAME; |
343 | - |
344 | + |
345 | filter.add_option ("accessories", _("Accessories")); |
346 | filter.add_option ("education", _("Education")); |
347 | filter.add_option ("game", _("Games")); |
348 | @@ -321,38 +346,37 @@ |
349 | return usc_apps_option.active; |
350 | return true; |
351 | } |
352 | - |
353 | + |
354 | /* Load xdg menu info and build a Xapian index over it. |
355 | * Do throttled re-index if the menu changes */ |
356 | private bool build_app_menu_index () |
357 | - { |
358 | + { |
359 | if (app_menu == null) |
360 | - { |
361 | - debug ("Building initial application menu"); |
362 | + { |
363 | + debug ("Building initial application menu"); |
364 | |
365 | - /* We need INCLUDE_NODISPLAY to employ proper de-duping between |
366 | - * the Installed and Availabale categorys. If a NoDisplay app is installed, |
367 | - * eg. Evince, it wont otherwise be in the menu index, only in the |
368 | - * S-C index - thus show up in the Available category */ |
369 | - app_menu = GMenu.Tree.lookup ("unity-lens-applications.menu", |
370 | - GMenu.TreeFlags.INCLUDE_NODISPLAY); |
371 | - |
372 | - app_menu.add_monitor ((menu) => { |
373 | + /* We need INCLUDE_NODISPLAY to employ proper de-duping between |
374 | + * the Installed and Availabale categorys. If a NoDisplay app is installed, |
375 | + * eg. Evince, it wont otherwise be in the menu index, only in the |
376 | + * S-C index - thus show up in the Available category */ |
377 | + app_menu = GMenu.Tree.lookup ("unity-lens-applications.menu", |
378 | + GMenu.TreeFlags.INCLUDE_NODISPLAY); |
379 | + |
380 | + app_menu.add_monitor ((menu) => { |
381 | /* Reschedule the timeout if we already have one. The menu tree triggers |
382 | * many change events during app installation. This way we wait the full |
383 | * delay *after* the last change event has triggered */ |
384 | if (app_menu_changed_reindex_timeout != 0) |
385 | Source.remove (app_menu_changed_reindex_timeout); |
386 | - |
387 | - app_menu_changed_reindex_timeout = |
388 | - Timeout.add_seconds (5, build_app_menu_index_and_result_models); |
389 | + |
390 | + app_menu_changed_reindex_timeout = Timeout.add_seconds (5, build_app_menu_index_and_result_models); |
391 | }); |
392 | - } |
393 | - |
394 | + } |
395 | + |
396 | debug ("Indexing application menu"); |
397 | appsearcher = new Unity.Package.Searcher.for_menu (app_menu); |
398 | app_menu_changed_reindex_timeout = 0; |
399 | - |
400 | + |
401 | return false; |
402 | } |
403 | |
404 | @@ -363,7 +387,7 @@ |
405 | private bool build_app_menu_index_and_result_models () |
406 | { |
407 | build_app_menu_index (); |
408 | - |
409 | + |
410 | mark_dirty (); |
411 | |
412 | return false; |
413 | @@ -391,15 +415,15 @@ |
414 | OptionsFilter? options) |
415 | { |
416 | string s = search_string.strip (); |
417 | - |
418 | + |
419 | if (!s.has_suffix ("*") && s != "") |
420 | s = s + "*"; |
421 | - |
422 | + |
423 | if (s != "") |
424 | s = @"app:($s)"; |
425 | else |
426 | return extract_type_query (options); |
427 | - |
428 | + |
429 | if (options == null || !options.filtering) |
430 | return s; |
431 | else |
432 | @@ -448,13 +472,13 @@ |
433 | * to finish, to prevent flicker. */ |
434 | |
435 | debug ("Searching for: %s", search.search_string); |
436 | - |
437 | + |
438 | var filter = scope.get_filter ("type") as OptionsFilter; |
439 | |
440 | string pkg_search_string = prepare_pkg_search_string (search, filter); |
441 | |
442 | bool has_search = !Utils.is_search_empty (search); |
443 | - |
444 | + |
445 | Timer timer = new Timer (); |
446 | |
447 | var transaction = new Dee.Transaction (model); |
448 | @@ -513,8 +537,7 @@ |
449 | // no need to bother |
450 | return; |
451 | } catch (GLib.Error e) { |
452 | - warning ("Error performing search '%s': %s", |
453 | - search.search_string, e.message); |
454 | + warning ("Error performing search '%s': %s", search.search_string, e.message); |
455 | } |
456 | } |
457 | |
458 | @@ -556,7 +579,7 @@ |
459 | |
460 | search.finished (); |
461 | } |
462 | - |
463 | + |
464 | private async void update_global_search (Unity.LensSearch search, |
465 | Cancellable cancellable) |
466 | { |
467 | @@ -564,17 +587,17 @@ |
468 | * In global search, with a non-empty search string, we collate all |
469 | * hits under one Applications category |
470 | */ |
471 | - |
472 | + |
473 | if (Utils.is_search_empty (search)) |
474 | - { |
475 | - yield update_global_without_search (search, cancellable); |
476 | - return; |
477 | - } |
478 | - |
479 | + { |
480 | + yield update_global_without_search (search, cancellable); |
481 | + return; |
482 | + } |
483 | + |
484 | var model = search.results_model; |
485 | - |
486 | + |
487 | model.clear (); |
488 | - |
489 | + |
490 | var search_string = prepare_pkg_search_string (search, null); |
491 | Set<string> installed_uris = new HashSet<string> (); |
492 | Set<string> available_uris = new HashSet<string> (); |
493 | @@ -585,18 +608,18 @@ |
494 | resort_pkg_search_results (appresults); |
495 | add_pkg_search_result (appresults, installed_uris, available_uris, model, |
496 | Category.APPLICATIONS); |
497 | - |
498 | + |
499 | timer.stop (); |
500 | debug ("Global search listed %i Installed apps in %fms for query: %s", |
501 | appresults.num_hits, timer.elapsed ()*1000, search_string); |
502 | - |
503 | + |
504 | /* Allow new searches once we enter an idle again. |
505 | * We don't do it directly from here as that could mean we start |
506 | * changing the model even before we had flushed out current changes |
507 | */ |
508 | search.finished (); |
509 | } |
510 | - |
511 | + |
512 | private async void update_global_without_search (Unity.LensSearch search, |
513 | Cancellable cancellable) |
514 | { |
515 | @@ -605,7 +628,7 @@ |
516 | * Excluding apps with icons in the launcher (be they running or faves) |
517 | */ |
518 | var model = search.results_model; |
519 | - |
520 | + |
521 | Timer timer = new Timer (); |
522 | |
523 | if (local_apps_active () && display_recent_apps) |
524 | @@ -678,103 +701,122 @@ |
525 | |
526 | return result == null ? "NOT category:XYZ" : "(%s)".printf (result); |
527 | } |
528 | - |
529 | + |
530 | private string prepare_pkg_search_string (Unity.LensSearch search, |
531 | OptionsFilter? options) |
532 | { |
533 | if (Utils.is_search_empty (search)) |
534 | - { |
535 | - if (options == null || !options.filtering) |
536 | - return "type:Application"; |
537 | - else |
538 | - return "type:Application AND " + extract_type_query (options); |
539 | - } |
540 | + { |
541 | + if (options == null || !options.filtering) |
542 | + return "type:Application"; |
543 | + else |
544 | + return "type:Application AND " + extract_type_query (options); |
545 | + } |
546 | else |
547 | + { |
548 | + var s = search.search_string; |
549 | + |
550 | + s = s.strip (); |
551 | + |
552 | + /* The Xapian query parser seems to handle hyphens in a special way, |
553 | + * namely that it forces the joined tokens into a phrase query |
554 | + * no matter if it appears as the last word in a query and we have |
555 | + * the PARTIAL flag set on the query parser. This makes 'd-f' not |
556 | + * match 'd-feet' etc. */ |
557 | + s = s.delimit ("-", ' '); |
558 | + |
559 | + if (options == null || !options.filtering) |
560 | + return "type:Application AND " + s; |
561 | + else |
562 | + return "type:Application AND %s AND %s".printf (extract_type_query (options), s); |
563 | + } |
564 | + } |
565 | + |
566 | + /** |
567 | + * Find app icon in DATADIR/app-install/icons, based on package name |
568 | + * trying all supported image extensions. |
569 | + */ |
570 | + public string find_app_install_icon_path (string pkgname) |
571 | + { |
572 | + string icon = @"$ICON_APP_INSTALL_PATH/$preview_installable_icon_file."; |
573 | + string[] exts = {"png", "xpm"}; |
574 | + foreach (string ext in exts) |
575 | + { |
576 | + string path = icon + ext; |
577 | + if (FileUtils.test (path, FileTest.EXISTS)) |
578 | { |
579 | - var s = search.search_string; |
580 | - |
581 | - s = s.strip (); |
582 | - |
583 | - /* The Xapian query parser seems to handle hyphens in a special way, |
584 | - * namely that it forces the joined tokens into a phrase query |
585 | - * no matter if it appears as the last word in a query and we have |
586 | - * the PARTIAL flag set on the query parser. This makes 'd-f' not |
587 | - * match 'd-feet' etc. */ |
588 | - s = s.delimit ("-", ' '); |
589 | - |
590 | - if (options == null || !options.filtering) |
591 | - return "type:Application AND " + s; |
592 | - else |
593 | - return "type:Application AND %s AND %s".printf (extract_type_query (options), s); |
594 | + return path; |
595 | } |
596 | + } |
597 | + return ""; |
598 | } |
599 | - |
600 | + |
601 | public Icon find_pkg_icon (Unity.Package.PackageInfo pkginfo) |
602 | { |
603 | string desktop_id = Path.get_basename (pkginfo.desktop_file); |
604 | bool installed = AppInfoManager.get_default().lookup (desktop_id) != null; |
605 | - |
606 | + |
607 | /* If the app is already installed we should be able to pull the |
608 | * icon from the theme */ |
609 | if (installed) |
610 | return new ThemedIcon (pkginfo.icon); |
611 | - |
612 | + |
613 | /* App is not installed - we need to find the right icon in the bowels |
614 | * of the software center */ |
615 | if (pkginfo.icon.has_prefix ("/")) |
616 | - { |
617 | - return new FileIcon (File.new_for_path (pkginfo.icon)); |
618 | - } |
619 | + { |
620 | + return new FileIcon (File.new_for_path (pkginfo.icon)); |
621 | + } |
622 | else |
623 | - { |
624 | - Icon icon = file_icon_cache.lookup (pkginfo.icon); |
625 | - |
626 | - if (icon != null) |
627 | - return icon; |
628 | - |
629 | - /* If the icon name contains a . it probably already have a |
630 | - * type postfix - so test icon name directly */ |
631 | - string path; |
632 | - if ("." in pkginfo.icon) |
633 | - { |
634 | - path = @"$(Config.DATADIR)/app-install/icons/$(pkginfo.icon)"; |
635 | - if (FileUtils.test (path, FileTest.EXISTS)) |
636 | - { |
637 | - icon = new FileIcon (File.new_for_path (path)); |
638 | - file_icon_cache.insert (pkginfo.icon, icon); |
639 | - return icon; |
640 | - } |
641 | - /* Try also software center cache dir */ |
642 | - path = Path.build_filename (Environment.get_user_cache_dir (), |
643 | - "software-center", |
644 | - "icons", |
645 | - pkginfo.icon); |
646 | - if (FileUtils.test (path, FileTest.EXISTS)) |
647 | - { |
648 | - icon = new FileIcon (File.new_for_path (path)); |
649 | - file_icon_cache.insert (pkginfo.icon, icon); |
650 | - return icon; |
651 | - } |
652 | - } |
653 | - |
654 | - /* Now try appending all the image extensions we know */ |
655 | - foreach (var ext in image_extensions) |
656 | - { |
657 | - path = @"$(Config.DATADIR)/app-install/icons/$(pkginfo.icon).$(ext)"; |
658 | - if (FileUtils.test (path, FileTest.EXISTS)) |
659 | - { |
660 | - /* Got it! Cache the icon path and return the icon */ |
661 | - icon = new FileIcon (File.new_for_path (path)); |
662 | - file_icon_cache.insert (pkginfo.icon, icon); |
663 | - return icon; |
664 | - } |
665 | - } |
666 | - } |
667 | - |
668 | + { |
669 | + Icon icon = file_icon_cache.lookup (pkginfo.icon); |
670 | + |
671 | + if (icon != null) |
672 | + return icon; |
673 | + |
674 | + /* If the icon name contains a . it probably already have a |
675 | + * type postfix - so test icon name directly */ |
676 | + string path; |
677 | + if ("." in pkginfo.icon) |
678 | + { |
679 | + path = @"$(Config.DATADIR)/app-install/icons/$(pkginfo.icon)"; |
680 | + if (FileUtils.test (path, FileTest.EXISTS)) |
681 | + { |
682 | + icon = new FileIcon (File.new_for_path (path)); |
683 | + file_icon_cache.insert (pkginfo.icon, icon); |
684 | + return icon; |
685 | + } |
686 | + /* Try also software center cache dir */ |
687 | + path = Path.build_filename (Environment.get_user_cache_dir (), |
688 | + "software-center", |
689 | + "icons", |
690 | + pkginfo.icon); |
691 | + if (FileUtils.test (path, FileTest.EXISTS)) |
692 | + { |
693 | + icon = new FileIcon (File.new_for_path (path)); |
694 | + file_icon_cache.insert (pkginfo.icon, icon); |
695 | + return icon; |
696 | + } |
697 | + } |
698 | + |
699 | + /* Now try appending all the image extensions we know */ |
700 | + foreach (var ext in image_extensions) |
701 | + { |
702 | + path = @"$(Config.DATADIR)/app-install/icons/$(pkginfo.icon).$(ext)"; |
703 | + if (FileUtils.test (path, FileTest.EXISTS)) |
704 | + { |
705 | + /* Got it! Cache the icon path and return the icon */ |
706 | + icon = new FileIcon (File.new_for_path (path)); |
707 | + file_icon_cache.insert (pkginfo.icon, icon); |
708 | + return icon; |
709 | + } |
710 | + } |
711 | + } |
712 | + |
713 | /* Cache the fact that we couldn't find this icon */ |
714 | var icon = new ThemedIcon ("applications-other"); |
715 | file_icon_cache.insert (pkginfo.icon, icon); |
716 | - |
717 | + |
718 | return icon; |
719 | } |
720 | |
721 | @@ -791,7 +833,14 @@ |
722 | desktop_id = desktop_id[colon_pos+1:desktop_id.length]; |
723 | /* well it's still not real desktop_id, S-C converts slashes to "__" |
724 | * if the desktop file is in /usr/share/applications */ |
725 | - desktop_id = desktop_id.replace ("__", "-"); |
726 | + string demangled_desktop_id = desktop_id.replace ("__", "-"); |
727 | + |
728 | + // store demangled name -> mangled name mapping |
729 | + if (desktop_id != demangled_desktop_id) |
730 | + { |
731 | + mangled_desktop_ids.replace (demangled_desktop_id, desktop_id); |
732 | + } |
733 | + desktop_id = demangled_desktop_id; |
734 | } |
735 | |
736 | return desktop_id; |
737 | @@ -824,7 +873,7 @@ |
738 | return rel_b - rel_a; // we want higher relevancy first |
739 | }); |
740 | } |
741 | - |
742 | + |
743 | private void add_pkg_search_result (Unity.Package.SearchResult results, |
744 | Set<string> installed_uris, |
745 | Set<string> available_uris, |
746 | @@ -838,29 +887,29 @@ |
747 | |
748 | foreach (var pkginfo in results.results) |
749 | { |
750 | - if (pkginfo.desktop_file == null) |
751 | + if (pkginfo.desktop_file == null) |
752 | continue; |
753 | - |
754 | + |
755 | string desktop_id = extract_desktop_id (pkginfo.desktop_file, |
756 | - category == Category.AVAILABLE); |
757 | + category == Category.AVAILABLE); |
758 | string full_path; |
759 | |
760 | AppInfo? app = appmanager.lookup (desktop_id); |
761 | full_path = appmanager.get_path (desktop_id); |
762 | - |
763 | + |
764 | /* De-dupe by 'application://foo.desktop' URI. Also note that we need |
765 | * to de-dupe before we chuck out NoDisplay app infos, otherwise they'd |
766 | * show up from alternate sources */ |
767 | string uri = @"application://$(desktop_id)"; |
768 | if (uri in installed_uris || uri in available_uris) |
769 | continue; |
770 | - |
771 | + |
772 | /* Extract basic metadata and register de-dupe keys */ |
773 | string display_name; |
774 | string comment; |
775 | switch (category) |
776 | { |
777 | - case Category.INSTALLED: |
778 | + case Category.INSTALLED: |
779 | case Category.APPLICATIONS: |
780 | installed_uris.add (uri); |
781 | display_name = app.get_display_name (); |
782 | @@ -874,52 +923,52 @@ |
783 | default: |
784 | warning (@"Illegal category for package search $(category)"); |
785 | continue; |
786 | - } |
787 | - |
788 | + } |
789 | + |
790 | /* We can only chuck out NoDisplay and OnlyShowIn app infos after |
791 | * we have registered a de-dupe key for them - which is done in the |
792 | * switch block above) */ |
793 | if (app != null && !app.should_show ()) |
794 | continue; |
795 | - |
796 | + |
797 | if (category == Category.AVAILABLE) |
798 | + { |
799 | + /* If we have an available item, which is not a dupe, but is |
800 | + * installed anyway, we weed it out here, because it's probably |
801 | + * left out from the Installed section because of some rule in the |
802 | + * .menu file */ |
803 | + if (app != null) |
804 | + continue; |
805 | + |
806 | + /* Filter by app rating in Software Center if enabled */ |
807 | + if (ratings != null && ratings_filter.rating > 0.00001) |
808 | { |
809 | - /* If we have an available item, which is not a dupe, but is |
810 | - * installed anyway, we weed it out here, because it's probably |
811 | - * left out from the Installed section because of some rule in the |
812 | - * .menu file */ |
813 | - if (app != null) |
814 | + Unity.Ratings.Result result; |
815 | + if (ratings.query (pkginfo.package_name, out result)) |
816 | + { |
817 | + if (result.average_rating < ratings_filter.rating * 5 - 0.2) |
818 | + continue; |
819 | + } |
820 | + else |
821 | continue; |
822 | - |
823 | - /* Filter by app rating in Software Center if enabled */ |
824 | - if (ratings != null && ratings_filter.rating > 0.00001) |
825 | - { |
826 | - Unity.Ratings.Result result; |
827 | - if (ratings.query (pkginfo.package_name, out result)) |
828 | - { |
829 | - if (result.average_rating < ratings_filter.rating * 5 - 0.2) |
830 | - continue; |
831 | - } |
832 | - else |
833 | - continue; |
834 | - } |
835 | - |
836 | - /* Apps that are not installed, ie. in the Available category |
837 | - * use the 'unity-install://pkgname/Full App Name' URI scheme, |
838 | - * but only use that after we've de-duped the results. |
839 | - * But only change the URI *after* we've de-duped the results! */ |
840 | - uri = @"unity-install://$(pkginfo.package_name)/$(pkginfo.application_name)"; |
841 | - available_uris.add (uri); |
842 | } |
843 | - |
844 | + |
845 | + /* Apps that are not installed, ie. in the Available category |
846 | + * use the 'unity-install://pkgname/Full App Name' URI scheme, |
847 | + * but only use that after we've de-duped the results. |
848 | + * But only change the URI *after* we've de-duped the results! */ |
849 | + uri = @"unity-install://$(pkginfo.package_name)/$(pkginfo.application_name)"; |
850 | + available_uris.add (uri); |
851 | + } |
852 | + |
853 | Icon icon = find_pkg_icon (pkginfo); |
854 | - |
855 | + |
856 | model.append (uri, icon.to_string (), |
857 | category,"application/x-desktop", |
858 | display_name != null ? display_name : "", |
859 | comment != null ? comment : "", |
860 | - full_path != null ? "file://" + full_path : ""); |
861 | - |
862 | + full_path != null ? "file://" + full_path : ""); |
863 | + |
864 | /* Stop if we added the number of items requested */ |
865 | n_added++; |
866 | if (max_add > 0 && n_added >= max_add) |
867 | @@ -927,6 +976,248 @@ |
868 | } |
869 | } |
870 | |
871 | + private async void call_install_packages (string package_name, out string tid) |
872 | + { |
873 | + tid = yield aptdclient.install_packages ({package_name}); |
874 | + } |
875 | + |
876 | + private async void call_remove_packages (string package_name, out string tid) |
877 | + { |
878 | + tid = yield aptdclient.remove_packages ({package_name}); |
879 | + } |
880 | + |
881 | + private Unity.ActivationResponse app_preview_launch (string uri) |
882 | + { |
883 | + return activate (uri); |
884 | + } |
885 | + |
886 | + /** |
887 | + * Handler for free apps installation. |
888 | + * Triggers package installation via apt-daemon DBus service |
889 | + */ |
890 | + private Unity.ActivationResponse app_preview_install (string uri) |
891 | + { |
892 | + if (uri.has_prefix ("unity-install://")) |
893 | + { |
894 | + string app = uri.substring (16); // trim "unity-install://" |
895 | + string[] parts = app.split ("/"); |
896 | + |
897 | + if (parts.length > 1) |
898 | + { |
899 | + string pkgname = parts[0]; |
900 | + string appname = parts[1]; |
901 | + aptdclient.connect_to_aptd (); |
902 | + call_install_packages.begin (pkgname, (obj, res) => |
903 | + { |
904 | + try { |
905 | + string tid; |
906 | + call_install_packages.end (res, out tid); |
907 | + debug ("transaction started: %s, pkg: %s\n", tid, pkgname); |
908 | + aptd_transaction = new AptdTransactionProxy (); |
909 | + aptd_transaction.connect_to_aptd (tid); |
910 | + aptd_transaction.simulate (); |
911 | + aptd_transaction.run (); |
912 | + |
913 | + launcherservice.connect_to_launcher (); |
914 | + string desktop_file = preview_installable_desktop_file; |
915 | + string icon = find_app_install_icon_path (preview_installable_icon_file); |
916 | + |
917 | + launcherservice.add_launcher_item_from_position (appname, icon, 0, 0, 32, desktop_file, tid); |
918 | + } |
919 | + catch (IOError e) |
920 | + { |
921 | + warning (@"Package '$(pkgname)' installation failed: $(e.message)"); |
922 | + } |
923 | + }); |
924 | + } |
925 | + else |
926 | + { |
927 | + warning (@"Bad install uri: '%s'", uri); |
928 | + } |
929 | + } |
930 | + else |
931 | + { |
932 | + warning (@"Can't handle '%s' in app_preview_install handler", uri); |
933 | + return new Unity.ActivationResponse(Unity.HandledType.NOT_HANDLED); |
934 | + } |
935 | + return new Unity.ActivationResponse(Unity.HandledType.SHOW_DASH); |
936 | + } |
937 | + |
938 | + private Unity.ActivationResponse app_preview_install_commercial (string uri) |
939 | + { |
940 | + return activate (uri); //this will just launch Software-Center |
941 | + } |
942 | + |
943 | + private Unity.ActivationResponse app_preview_buy (string uri) |
944 | + { |
945 | + return activate (uri); //this will just launch Software-Center |
946 | + } |
947 | + |
948 | + private Unity.ActivationResponse app_preview_uninstall (string uri) |
949 | + { |
950 | + if (uri.has_prefix ("application://")) |
951 | + { |
952 | + string desktopfile = uri.substring (14); // trim "application://" |
953 | + |
954 | + // de-mangle desktop file names back to what S-C expects |
955 | + if (mangled_desktop_ids.contains (desktopfile)) |
956 | + { |
957 | + desktopfile = mangled_desktop_ids.get (desktopfile); |
958 | + } |
959 | + |
960 | + var pkginfo = pkgsearcher.get_by_desktop_file (desktopfile); |
961 | + |
962 | + if (pkginfo != null && pkginfo.package_name != null) |
963 | + { |
964 | + aptdclient.connect_to_aptd (); |
965 | + call_remove_packages.begin (pkginfo.package_name, (obj, res) => |
966 | + { |
967 | + try { |
968 | + string tid; |
969 | + call_remove_packages.end (res, out tid); |
970 | + debug ("transaction started: %s, pkg: %s\n", tid, pkginfo.package_name); |
971 | + aptd_transaction = new AptdTransactionProxy (); |
972 | + aptd_transaction.connect_to_aptd (tid); |
973 | + aptd_transaction.simulate (); |
974 | + aptd_transaction.run (); |
975 | + } |
976 | + catch (IOError e) |
977 | + { |
978 | + warning (@"Package '$(pkginfo.package_name)' removal failed: $(e.message)"); |
979 | + } |
980 | + }); |
981 | + return new Unity.ActivationResponse(Unity.HandledType.SHOW_DASH); |
982 | + } |
983 | + else |
984 | + { |
985 | + warning (@"Cannot find package info for $uri"); |
986 | + } |
987 | + } |
988 | + warning (@"Can't handle '%s' in app_preview_uninstall handler", uri); |
989 | + return new Unity.ActivationResponse(Unity.HandledType.NOT_HANDLED); |
990 | + } |
991 | + |
992 | + public Unity.Preview preview (string uri) |
993 | + { |
994 | + Unity.ApplicationPreview? preview = null; |
995 | + |
996 | + string pkgname = ""; |
997 | + string appname = ""; |
998 | + |
999 | + if (uri.has_prefix ("application://") || uri.has_prefix ("unity-install://")) |
1000 | + { |
1001 | + if (uri.has_prefix ("application://")) |
1002 | + { |
1003 | + string desktopfile = uri.substring (14); //remove "application://" prefix |
1004 | + |
1005 | + // de-mangle desktop file names back to what S-C expects |
1006 | + if (mangled_desktop_ids.contains (desktopfile)) |
1007 | + { |
1008 | + desktopfile = mangled_desktop_ids.get (desktopfile); |
1009 | + } |
1010 | + |
1011 | + Unity.Package.PackageInfo pkginfo = pkgsearcher.get_by_desktop_file (desktopfile); |
1012 | + if (pkginfo != null) |
1013 | + { |
1014 | + appname = pkginfo.application_name; |
1015 | + pkgname = pkginfo.package_name; |
1016 | + } |
1017 | + } |
1018 | + else // unity-install |
1019 | + { |
1020 | + string app = uri.substring (16); //remove "unity-install://" prefix |
1021 | + string[] parts = app.split ("/"); |
1022 | + if (parts.length > 1) |
1023 | + { |
1024 | + pkgname = parts[0]; |
1025 | + appname = parts[1]; |
1026 | + } |
1027 | + } |
1028 | + |
1029 | + if (pkgname != "") |
1030 | + { |
1031 | + try { |
1032 | + sc_data_provider = new SoftwareCenterDataProviderProxy (); |
1033 | + sc_data_provider.connect_to (); |
1034 | + |
1035 | + debug ("Requesting pkg info: %s, %s\n", pkgname, appname); |
1036 | + sc_data_provider.get_app_details (appname, pkgname); |
1037 | + |
1038 | + Icon icon = new GLib.ThemedIcon (sc_data_provider.icon); |
1039 | + Icon? screenshot = null; |
1040 | + |
1041 | + if (sc_data_provider.screenshot != null) |
1042 | + { |
1043 | + File scr_file = File.new_for_uri (sc_data_provider.screenshot); |
1044 | + screenshot = new FileIcon (scr_file); |
1045 | + } |
1046 | + |
1047 | + preview = new Unity.ApplicationPreview (sc_data_provider.name, sc_data_provider.summary, sc_data_provider.description, icon, screenshot); |
1048 | + preview.license = sc_data_provider.license; |
1049 | + |
1050 | + if (ratings !=null) |
1051 | + { |
1052 | + Unity.Ratings.Result result; |
1053 | + ratings.query (pkgname, out result); |
1054 | + preview.set_rating (result.average_rating, result.total_rating); |
1055 | + } |
1056 | + |
1057 | + preview.add_info (new InfoHint.with_variant ("size", _("Size"), null, new GLib.Variant.int64 (sc_data_provider.size))); |
1058 | + preview.add_info (new InfoHint ("hardware-requirements", _("Hardware requirements"), null, sc_data_provider.hardware_requirements)); |
1059 | + preview.add_info (new InfoHint ("version", _("Version"), null, sc_data_provider.version)); |
1060 | + preview.add_info (new InfoHint ("website", _("Website"), null, sc_data_provider.website)); |
1061 | + preview.add_info (new InfoHint ("price", _("Price"), null, sc_data_provider.price)); |
1062 | + |
1063 | + if (uri.has_prefix ("unity-install://")) // application needs to be purchased/installed |
1064 | + { |
1065 | + // uninstalled and not purchased before |
1066 | + if (sc_data_provider.pkg_state == SoftwareCenterDataProviderProxy.PackageState.NEEDS_PURCHASE) |
1067 | + { |
1068 | + var buy_action = new Unity.PreviewAction ("buy", _("Buy"), null); |
1069 | + buy_action.activated.connect (app_preview_buy); |
1070 | + preview.add_action (buy_action); |
1071 | + } |
1072 | + else // uninstalled, purchased before |
1073 | + { |
1074 | + var install_action = new Unity.PreviewAction ("install", _("Install"), null); |
1075 | + if (sc_data_provider.price != "") |
1076 | + { |
1077 | + install_action.activated.connect (app_preview_install_commercial); |
1078 | + } |
1079 | + else |
1080 | + { |
1081 | + install_action.activated.connect (app_preview_install); |
1082 | + } |
1083 | + preview.add_action (install_action); |
1084 | + } |
1085 | + } |
1086 | + else // application is already installed |
1087 | + { |
1088 | + preview.add_info (new InfoHint ("date-installed", _("Installed on"), null, sc_data_provider.installation_date)); |
1089 | + var launch_action = new Unity.PreviewAction ("launch", _("Launch"), null); |
1090 | + launch_action.activated.connect (app_preview_launch); |
1091 | + preview.add_action (launch_action); |
1092 | + var uninstall_action = new Unity.PreviewAction ("uninstall", _("Uninstall"), null); |
1093 | + uninstall_action.activated.connect (app_preview_uninstall); |
1094 | + preview.add_action (uninstall_action); |
1095 | + } |
1096 | + |
1097 | + preview_installable_desktop_file = sc_data_provider.desktop_file; |
1098 | + preview_installable_icon_file = sc_data_provider.icon; |
1099 | + } |
1100 | + catch (IOError e) |
1101 | + { |
1102 | + warning ("Failed to get package details for '%s': %s", uri, e.message); |
1103 | + } |
1104 | + } |
1105 | + else |
1106 | + { |
1107 | + warning ("pksearcher: no data for '%s'", uri); |
1108 | + } |
1109 | + } |
1110 | + return preview; |
1111 | + } |
1112 | + |
1113 | /** |
1114 | * Override of the default activation handler. The apps lens daemon |
1115 | * can handle activation of installable apps using the Software Center |
1116 | @@ -936,79 +1227,79 @@ |
1117 | string[] args; |
1118 | string exec_or_dir = null; |
1119 | if (uri.has_prefix ("unity-install://")) |
1120 | - { |
1121 | - unowned string pkg = uri.offset (16); // strip off "unity-install://" prefix |
1122 | - debug ("Installing: %s", pkg); |
1123 | - args = new string[2]; |
1124 | - args[0] = "software-center"; |
1125 | - args[1] = pkg; |
1126 | - } |
1127 | + { |
1128 | + unowned string pkg = uri.offset (16); // strip off "unity-install://" prefix |
1129 | + debug ("Installing: %s", pkg); |
1130 | + args = new string[2]; |
1131 | + args[0] = "software-center"; |
1132 | + args[1] = pkg; |
1133 | + } |
1134 | else if (uri.has_prefix ("unity-runner://")) |
1135 | - { |
1136 | - string orig; |
1137 | - orig = uri.offset (15); |
1138 | - if (orig.has_prefix("\\\\")) |
1139 | - orig = orig.replace ("\\\\","smb://"); |
1140 | - if (uri_regex != null && uri_regex.match (orig)) { |
1141 | - try { |
1142 | - /* this code ensures that a file manager will be used |
1143 | - * if uri it's a remote location that should be mounted */ |
1144 | - if (mountable_regex.match (orig)) { |
1145 | - var muris = new GLib.List<string>(); |
1146 | - muris.prepend (orig); |
1147 | - var file_manager = AppInfo.get_default_for_type("inode/directory", true); |
1148 | - file_manager.launch_uris(muris,null); |
1149 | - } else { |
1150 | + { |
1151 | + string orig; |
1152 | + orig = uri.offset (15); |
1153 | + if (orig.has_prefix("\\\\")) |
1154 | + orig = orig.replace ("\\\\","smb://"); |
1155 | + if (uri_regex != null && uri_regex.match (orig)) { |
1156 | + try { |
1157 | + /* this code ensures that a file manager will be used |
1158 | + * if uri it's a remote location that should be mounted */ |
1159 | + if (mountable_regex.match (orig)) { |
1160 | + var muris = new GLib.List<string>(); |
1161 | + muris.prepend (orig); |
1162 | + var file_manager = AppInfo.get_default_for_type("inode/directory", true); |
1163 | + file_manager.launch_uris(muris,null); |
1164 | + } else { |
1165 | AppInfo.launch_default_for_uri (orig, null); |
1166 | - } |
1167 | - } catch (GLib.Error error) { |
1168 | - warning ("Failed to launch URI %s", orig); |
1169 | - return new Unity.ActivationResponse(Unity.HandledType.NOT_HANDLED); |
1170 | } |
1171 | - return new Unity.ActivationResponse(Unity.HandledType.HIDE_DASH); |
1172 | - |
1173 | - } else { |
1174 | - exec_or_dir = Utils.subst_tilde (orig); |
1175 | - args = exec_or_dir.split (" ", 0); |
1176 | - for (int i = 0; i < args.length; i++) |
1177 | - args[i] = Utils.subst_tilde (args[i]); |
1178 | + } catch (GLib.Error error) { |
1179 | + warning ("Failed to launch URI %s", orig); |
1180 | + return new Unity.ActivationResponse(Unity.HandledType.NOT_HANDLED); |
1181 | } |
1182 | - this.runner.add_history (orig); |
1183 | + return new Unity.ActivationResponse(Unity.HandledType.HIDE_DASH); |
1184 | + |
1185 | + } else { |
1186 | + exec_or_dir = Utils.subst_tilde (orig); |
1187 | + args = exec_or_dir.split (" ", 0); |
1188 | + for (int i = 0; i < args.length; i++) |
1189 | + args[i] = Utils.subst_tilde (args[i]); |
1190 | } |
1191 | + this.runner.add_history (orig); |
1192 | + } |
1193 | else |
1194 | - { |
1195 | - /* Activation of standard application:// uris */ |
1196 | - |
1197 | - /* Make sure fresh install learns quickly */ |
1198 | - if (popularity_map.size <= 5) popularities_dirty = true; |
1199 | - |
1200 | - return new Unity.ActivationResponse(Unity.HandledType.NOT_HANDLED); |
1201 | - } |
1202 | + { |
1203 | + /* Activation of standard application:// uris */ |
1204 | + |
1205 | + /* Make sure fresh install learns quickly */ |
1206 | + if (popularity_map.size <= 5) popularities_dirty = true; |
1207 | + |
1208 | + return new Unity.ActivationResponse(Unity.HandledType.NOT_HANDLED); |
1209 | + } |
1210 | |
1211 | if ((exec_or_dir != null) && FileUtils.test (exec_or_dir, FileTest.IS_DIR)) |
1212 | { |
1213 | try { |
1214 | - AppInfo.launch_default_for_uri ("file://" + exec_or_dir, null); |
1215 | + AppInfo.launch_default_for_uri ("file://" + exec_or_dir, null); |
1216 | } catch (GLib.Error err) { |
1217 | - warning ("Failed to open current folder '%s' in file manager: %s", |
1218 | - exec_or_dir, err.message); |
1219 | - return new Unity.ActivationResponse(Unity.HandledType.NOT_HANDLED); |
1220 | + warning ("Failed to open current folder '%s' in file manager: %s", |
1221 | + exec_or_dir, err.message); |
1222 | + return new Unity.ActivationResponse(Unity.HandledType.NOT_HANDLED); |
1223 | } |
1224 | } |
1225 | else |
1226 | { |
1227 | - try { |
1228 | - unowned string home_dir = GLib.Environment.get_home_dir (); |
1229 | - Process.spawn_async (home_dir, args, null, SpawnFlags.SEARCH_PATH, null, null); |
1230 | - } catch (SpawnError e) { |
1231 | - warning ("Failed to spawn software-center or direct URI activation '%s': %s", |
1232 | - uri, e.message); |
1233 | - return new Unity.ActivationResponse(Unity.HandledType.NOT_HANDLED); |
1234 | - } |
1235 | + try { |
1236 | + unowned string home_dir = GLib.Environment.get_home_dir (); |
1237 | + Process.spawn_async (home_dir, args, null, SpawnFlags.SEARCH_PATH, null, null); |
1238 | + } catch (SpawnError e) { |
1239 | + warning ("Failed to spawn software-center or direct URI activation '%s': %s", |
1240 | + uri, e.message); |
1241 | + return new Unity.ActivationResponse(Unity.HandledType.NOT_HANDLED); |
1242 | + } |
1243 | } |
1244 | |
1245 | return new Unity.ActivationResponse(Unity.HandledType.HIDE_DASH); |
1246 | - |
1247 | + |
1248 | } |
1249 | |
1250 | /* Appends the subject URIs from a set of Zeitgeist.Events to our Dee.Model |
1251 | @@ -1026,7 +1317,7 @@ |
1252 | string? app_uri = null; |
1253 | if (ev.num_subjects () > 0) |
1254 | app_uri = ev.get_subject (0).get_uri (); |
1255 | - |
1256 | + |
1257 | if (app_uri == null) |
1258 | { |
1259 | warning ("Unexpected event without subject"); |
1260 | @@ -1035,7 +1326,7 @@ |
1261 | |
1262 | /* Assert that we indeed have a known application as actor */ |
1263 | string desktop_id = Utils.get_desktop_id_for_actor (app_uri); |
1264 | - |
1265 | + |
1266 | /* Discard Recently Used apps that are in the launcher */ |
1267 | if ((category_id == Category.RECENT || |
1268 | category_id == Category.RECENT_APPS) && |
1269 | @@ -1049,7 +1340,7 @@ |
1270 | |
1271 | if (app == null) |
1272 | continue; |
1273 | - |
1274 | + |
1275 | if (!app.should_show ()) |
1276 | continue; |
1277 | |
1278 | @@ -1073,7 +1364,7 @@ |
1279 | app.get_description (), full_uri); |
1280 | } |
1281 | } |
1282 | - |
1283 | + |
1284 | } /* END: class Daemon */ |
1285 | |
1286 | } /* namespace */ |
1287 | |
1288 | === added file 'src/launcher-client.vala' |
1289 | --- src/launcher-client.vala 1970-01-01 00:00:00 +0000 |
1290 | +++ src/launcher-client.vala 2012-08-08 16:35:21 +0000 |
1291 | @@ -0,0 +1,45 @@ |
1292 | +/* |
1293 | + * Copyright (C) 2012 Canonical Ltd |
1294 | + * |
1295 | + * This program is free software: you can redistribute it and/or modify |
1296 | + * it under the terms of the GNU General Public License version 3 as |
1297 | + * published by the Free Software Foundation. |
1298 | + * |
1299 | + * This program is distributed in the hope that it will be useful, |
1300 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1301 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1302 | + * GNU General Public License for more details. |
1303 | + * |
1304 | + * You should have received a copy of the GNU General Public License |
1305 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1306 | + * |
1307 | + * Authored by Pawel Stolowski <pawel.stolowski@canonical.com> |
1308 | + */ |
1309 | + |
1310 | +namespace Unity.ApplicationsLens { |
1311 | + |
1312 | + static const string LAUNCHER_DBUS_NAME = "com.canonical.Unity.Launcher"; |
1313 | + static const string LAUNCHER_DBUS_PATH = "/com/canonical/Unity/Launcher"; |
1314 | + |
1315 | + [DBus (name = "com.canonical.Unity.Launcher")] |
1316 | + public interface LauncherService: GLib.Object |
1317 | + { |
1318 | + public abstract async void add_launcher_item_from_position (string title, string icon, int icon_x, int icon_y, int icon_size, string desktop_file, string aptdaemon_task) throws IOError; |
1319 | + } |
1320 | + |
1321 | + public class LauncherProxy: GLib.Object |
1322 | + { |
1323 | + public void connect_to_launcher () |
1324 | + { |
1325 | + _launcher_service = Bus.get_proxy_sync (BusType.SESSION, LAUNCHER_DBUS_NAME, LAUNCHER_DBUS_PATH); |
1326 | + } |
1327 | + |
1328 | + public async void add_launcher_item_from_position (string title, string icon, int icon_x, int icon_y, int icon_size, string desktop_file, string aptdaemon_task) throws IOError |
1329 | + { |
1330 | + yield _launcher_service.add_launcher_item_from_position (title, icon, icon_x, icon_y, icon_size, desktop_file, aptdaemon_task); |
1331 | + } |
1332 | + |
1333 | + private LauncherService _launcher_service; |
1334 | + } |
1335 | + |
1336 | +} |
1337 | \ No newline at end of file |
1338 | |
1339 | === added file 'src/software-center-data-provider.vala' |
1340 | --- src/software-center-data-provider.vala 1970-01-01 00:00:00 +0000 |
1341 | +++ src/software-center-data-provider.vala 2012-08-08 16:35:21 +0000 |
1342 | @@ -0,0 +1,115 @@ |
1343 | +/* |
1344 | + * Copyright (C) 2012 Canonical Ltd |
1345 | + * |
1346 | + * This program is free software: you can redistribute it and/or modify |
1347 | + * it under the terms of the GNU General Public License version 3 as |
1348 | + * published by the Free Software Foundation. |
1349 | + * |
1350 | + * This program is distributed in the hope that it will be useful, |
1351 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1352 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1353 | + * GNU General Public License for more details. |
1354 | + * |
1355 | + * You should have received a copy of the GNU General Public License |
1356 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1357 | + * |
1358 | + * Authored by Pawel Stolowski <pawel.stolowski@canonical.com> |
1359 | + */ |
1360 | + |
1361 | +namespace Unity.ApplicationsLens { |
1362 | + |
1363 | + static const string SCDP_DBUS_NAME = "com.ubuntu.SoftwareCenterDataProvider"; |
1364 | + static const string SCDP_DBUS_PATH = "/com/ubuntu/SoftwareCenterDataProvider"; |
1365 | + |
1366 | + [DBus (name = "com.ubuntu.SoftwareCenterDataProvider")] |
1367 | + public interface SoftwareCenterDataProviderService: GLib.Object |
1368 | + { |
1369 | + public abstract HashTable<string, Variant> get_app_details (string appname, string pkgname) throws IOError; |
1370 | + } |
1371 | + |
1372 | + public class SoftwareCenterDataProviderProxy: GLib.Object |
1373 | + { |
1374 | + public enum PackageState |
1375 | + { |
1376 | + UNINSTALLED, |
1377 | + INSTALLED, |
1378 | + NEEDS_PURCHASE, |
1379 | + UNKNOWN |
1380 | + } |
1381 | + |
1382 | + public string name { get; set; } |
1383 | + public string summary { get; set; } |
1384 | + public string description { get; set; } |
1385 | + public string version { get; set; } |
1386 | + public string screenshot { get; set; } |
1387 | + public string desktop_file { get; set; } |
1388 | + public string license { get; set; } |
1389 | + public string icon { get; set; } |
1390 | + public string price { get; set; } |
1391 | + public PackageState pkg_state { get; set; } |
1392 | + public string installation_date { get; set; } |
1393 | + public string website { get; set; } |
1394 | + public int64 size { get; set; } |
1395 | + public string hardware_requirements { get; set; } |
1396 | + |
1397 | + public void connect_to () throws IOError |
1398 | + { |
1399 | + _service = Bus.get_proxy_sync (BusType.SESSION, SCDP_DBUS_NAME, SCDP_DBUS_PATH); |
1400 | + } |
1401 | + |
1402 | + public HashTable<string, Variant> get_app_details (string appname, string pkgname) |
1403 | + { |
1404 | + HashTable<string, Variant> data = _service.get_app_details (appname, pkgname); |
1405 | + |
1406 | + name = data.get ("name").get_string (); |
1407 | + summary = data.get ("summary").get_string (); |
1408 | + description = data.get ("description").get_string (); |
1409 | + version = data.get ("version").get_string (); |
1410 | + desktop_file = data.get ("desktop_file").get_string (); |
1411 | + license = data.get ("license").get_string (); |
1412 | + icon = data.get ("icon_file_name").get_string (); |
1413 | + price = data.get ("price").get_string (); |
1414 | + installation_date = data.get ("installation_date").get_string (); |
1415 | + website = data.get ("website").get_string (); |
1416 | + hardware_requirements = data.get ("hardware_requirements").get_string (); |
1417 | + size = int64.parse (data.get ("size").get_string ()); |
1418 | + |
1419 | + var state = data.get ("pkg_state").get_string (); |
1420 | + |
1421 | + if (state == "installed") |
1422 | + { |
1423 | + pkg_state = PackageState.INSTALLED; |
1424 | + } |
1425 | + else if (state == "uninstalled") |
1426 | + { |
1427 | + pkg_state = PackageState.UNINSTALLED; |
1428 | + } |
1429 | + else if (state == "needs_purchase") |
1430 | + { |
1431 | + pkg_state = PackageState.NEEDS_PURCHASE; |
1432 | + } |
1433 | + else |
1434 | + { |
1435 | + pkg_state = PackageState.UNKNOWN; |
1436 | + } |
1437 | + |
1438 | + screenshot = null; |
1439 | + |
1440 | + if (data.contains ("screenshots")) |
1441 | + { |
1442 | + var screenshot_var = data.get ("screenshots").get_child_value (0).lookup_value ("large_image_url", VariantType.STRING); |
1443 | + if (screenshot_var != null) |
1444 | + { |
1445 | + screenshot = screenshot_var.get_string (); |
1446 | + } |
1447 | + } |
1448 | + if (screenshot == null) |
1449 | + { |
1450 | + screenshot = ""; |
1451 | + } |
1452 | + return data; |
1453 | + } |
1454 | + |
1455 | + private SoftwareCenterDataProviderService _service; |
1456 | + } |
1457 | +} |
1458 | |
1459 | === modified file 'src/unity-package-search.cc' |
1460 | --- src/unity-package-search.cc 2012-03-27 10:49:37 +0000 |
1461 | +++ src/unity-package-search.cc 2012-08-08 16:35:21 +0000 |
1462 | @@ -1,6 +1,6 @@ |
1463 | /* |
1464 | * Copyright (C) 2010 Canonical Ltd |
1465 | - * |
1466 | + * |
1467 | * This program is free software: you can redistribute it and/or modify |
1468 | * it under the terms of the GNU General Public License version 3 as |
1469 | * published by the Free Software Foundation. |
1470 | @@ -50,12 +50,15 @@ |
1471 | #define XAPIAN_VALUE_SUMMARY 177 |
1472 | #define XAPIAN_VALUE_ARCHIVE_CHANNEL 178 |
1473 | #define XAPIAN_VALUE_DESKTOP_FILE 179 |
1474 | +#define XAPIAN_VALUE_SCREENSHOT_URLS 185 |
1475 | +#define XAPIAN_VALUE_DESCRIPTION 188 |
1476 | +#define XAPIAN_VALUE_VERSION_INFO 198 |
1477 | |
1478 | #include "unity-package-search.h" |
1479 | |
1480 | extern "C" |
1481 | { |
1482 | -extern gchar* unity_applications_lens_utils_preprocess_string (const gchar* input); |
1483 | + extern gchar* unity_applications_lens_utils_preprocess_string (const gchar* input); |
1484 | } |
1485 | |
1486 | struct _UnityPackageSearcher |
1487 | @@ -71,17 +74,17 @@ |
1488 | class LocaleKeyMaker : public Xapian::KeyMaker |
1489 | { |
1490 | private: |
1491 | - Xapian::valueno value; |
1492 | - |
1493 | + Xapian::valueno value; |
1494 | + |
1495 | public: |
1496 | - |
1497 | + |
1498 | LocaleKeyMaker (Xapian::valueno value) |
1499 | { |
1500 | this->value = value; |
1501 | } |
1502 | - |
1503 | + |
1504 | virtual ~LocaleKeyMaker() { } |
1505 | - |
1506 | + |
1507 | virtual std::string operator() (const Xapian::Document &doc) const |
1508 | { |
1509 | string val = doc.get_value (value); |
1510 | @@ -89,40 +92,40 @@ |
1511 | string col_key_mm = col_key_c; |
1512 | g_free (col_key_c); |
1513 | return col_key_mm; |
1514 | - } |
1515 | + } |
1516 | }; |
1517 | |
1518 | /* Do generic searcher setup */ |
1519 | static void |
1520 | init_searcher (UnityPackageSearcher *searcher) |
1521 | { |
1522 | - // Activate Xapian CJK support |
1523 | + // Activate Xapian CJK support |
1524 | setenv("XAPIAN_CJK_NGRAM", "1", 1); |
1525 | |
1526 | - Xapian::Database db = *searcher->db; |
1527 | + Xapian::Database db = *searcher->db; |
1528 | |
1529 | // Start an enquire session |
1530 | Xapian::Enquire *enquire = new Xapian::Enquire (db); |
1531 | - //enquire->set_sort_by_value (XAPIAN_VALUE_APPNAME, FALSE); |
1532 | + enquire->set_sort_by_value (XAPIAN_VALUE_APPNAME, FALSE); |
1533 | searcher->enquire = enquire; |
1534 | |
1535 | // Make sure we respect sorting rules for the current locale |
1536 | searcher->sorter = new LocaleKeyMaker (XAPIAN_VALUE_APPNAME); |
1537 | enquire->set_sort_by_key (searcher->sorter, FALSE); |
1538 | |
1539 | - // Create query parser |
1540 | - Xapian::QueryParser *query_parser = new Xapian::QueryParser (); |
1541 | - query_parser->add_prefix ("section", "AE"); |
1542 | - query_parser->add_prefix ("type", "AT"); |
1543 | - query_parser->add_prefix ("category", "AC"); |
1544 | - query_parser->add_prefix ("name", "AA"); |
1545 | - query_parser->add_prefix ("pkgname", "AP"); |
1546 | - query_parser->add_prefix ("exec", "XX"); |
1547 | - query_parser->add_prefix ("keyword", "KW"); |
1548 | - query_parser->set_default_op (Xapian::Query::OP_AND); |
1549 | - query_parser->set_database (db); |
1550 | - searcher->query_parser = query_parser; |
1551 | - |
1552 | + // Create query parser |
1553 | + Xapian::QueryParser *query_parser = new Xapian::QueryParser (); |
1554 | + query_parser->add_prefix ("section", "AE"); |
1555 | + query_parser->add_prefix ("type", "AT"); |
1556 | + query_parser->add_prefix ("category", "AC"); |
1557 | + query_parser->add_prefix ("name", "AA"); |
1558 | + query_parser->add_prefix ("pkgname", "AP"); |
1559 | + query_parser->add_prefix ("exec", "XX"); |
1560 | + query_parser->add_prefix ("keyword", "KW"); |
1561 | + query_parser->set_default_op (Xapian::Query::OP_AND); |
1562 | + query_parser->set_database (db); |
1563 | + searcher->query_parser = query_parser; |
1564 | + |
1565 | // Init random number generator from 32 lowest bits of system time |
1566 | searcher->random = g_rand_new_with_seed (g_get_monotonic_time ()); |
1567 | } |
1568 | @@ -141,110 +144,103 @@ |
1569 | gchar *dum1, *dum2, *dum3; |
1570 | gint i, len; |
1571 | |
1572 | - g_return_if_fail (db != NULL); |
1573 | - g_return_if_fail (indexer != NULL); |
1574 | - g_return_if_fail (item != NULL); |
1575 | - |
1576 | - switch (gmenu_tree_item_get_type (item)) |
1577 | - { |
1578 | - case GMENU_TREE_ITEM_INVALID: |
1579 | - return; |
1580 | - case GMENU_TREE_ITEM_DIRECTORY: |
1581 | - /* Recurse into directory */ |
1582 | - iter = gmenu_tree_directory_get_contents (GMENU_TREE_DIRECTORY (item)); |
1583 | - for (; iter != NULL; iter = iter->next) |
1584 | - { |
1585 | - index_menu_item (db, indexer, GMENU_TREE_ITEM (iter->data)); |
1586 | - } |
1587 | - break; |
1588 | - case GMENU_TREE_ITEM_ENTRY: |
1589 | - /* Add this entry to the index */ |
1590 | - entry = GMENU_TREE_ENTRY (item); |
1591 | - |
1592 | - /* Store relevant values */ |
1593 | - if (gmenu_tree_entry_get_display_name (entry)) |
1594 | - doc.add_value (XAPIAN_VALUE_APPNAME, |
1595 | - gmenu_tree_entry_get_display_name (entry)); |
1596 | - if (gmenu_tree_entry_get_icon (entry)) |
1597 | - doc.add_value (XAPIAN_VALUE_ICON, |
1598 | - gmenu_tree_entry_get_icon (entry)); |
1599 | + g_return_if_fail (db != NULL); |
1600 | + g_return_if_fail (indexer != NULL); |
1601 | + g_return_if_fail (item != NULL); |
1602 | + |
1603 | + switch (gmenu_tree_item_get_type (item)) |
1604 | + { |
1605 | + case GMENU_TREE_ITEM_INVALID: |
1606 | + return; |
1607 | + case GMENU_TREE_ITEM_DIRECTORY: |
1608 | + /* Recurse into directory */ |
1609 | + iter = gmenu_tree_directory_get_contents (GMENU_TREE_DIRECTORY (item)); |
1610 | + for (; iter != NULL; iter = iter->next) |
1611 | + { |
1612 | + index_menu_item (db, indexer, GMENU_TREE_ITEM (iter->data)); |
1613 | + } |
1614 | + break; |
1615 | + case GMENU_TREE_ITEM_ENTRY: |
1616 | + /* Add this entry to the index */ |
1617 | + entry = GMENU_TREE_ENTRY (item); |
1618 | + |
1619 | + /* Store relevant values */ |
1620 | + if (gmenu_tree_entry_get_display_name (entry)) |
1621 | + doc.add_value (XAPIAN_VALUE_APPNAME, gmenu_tree_entry_get_display_name (entry)); |
1622 | + if (gmenu_tree_entry_get_icon (entry)) |
1623 | + doc.add_value (XAPIAN_VALUE_ICON, gmenu_tree_entry_get_icon (entry)); |
1624 | if (gmenu_tree_entry_get_desktop_file_id (entry)) |
1625 | - doc.add_value (XAPIAN_VALUE_DESKTOP_FILE, |
1626 | - gmenu_tree_entry_get_desktop_file_id (entry)); |
1627 | - |
1628 | - /* Index full text data */ |
1629 | - indexer->set_document(doc); |
1630 | + doc.add_value (XAPIAN_VALUE_DESKTOP_FILE, gmenu_tree_entry_get_desktop_file_id (entry)); |
1631 | + |
1632 | + /* Index full text data */ |
1633 | + indexer->set_document(doc); |
1634 | if (gmenu_tree_entry_get_display_name (entry)) |
1635 | { |
1636 | - dum1 = unity_applications_lens_utils_preprocess_string ( |
1637 | - gmenu_tree_entry_get_display_name (entry)); |
1638 | + dum1 = unity_applications_lens_utils_preprocess_string (gmenu_tree_entry_get_display_name (entry)); |
1639 | indexer->index_text(dum1, 5); |
1640 | g_free (dum1); |
1641 | } |
1642 | if (gmenu_tree_entry_get_name (entry)) |
1643 | { |
1644 | - dum1 = unity_applications_lens_utils_preprocess_string ( |
1645 | - gmenu_tree_entry_get_name (entry)); |
1646 | + dum1 = unity_applications_lens_utils_preprocess_string (gmenu_tree_entry_get_name (entry)); |
1647 | indexer->index_text(dum1, 5); |
1648 | g_free (dum1); |
1649 | } |
1650 | if (gmenu_tree_entry_get_comment (entry)) |
1651 | { |
1652 | - dum1 = unity_applications_lens_utils_preprocess_string ( |
1653 | - gmenu_tree_entry_get_comment (entry)); |
1654 | - indexer->index_text (dum1, 0); |
1655 | - g_free (dum1); |
1656 | - } |
1657 | - |
1658 | - /* Index the XDG categories */ |
1659 | - appman = unity_app_info_manager_get_default (); |
1660 | - cats = unity_app_info_manager_get_categories (appman, // const return |
1661 | - gmenu_tree_entry_get_desktop_file_id (entry), |
1662 | - &len); |
1663 | - |
1664 | - /* Note: Wine apps and app launchers created with Alacarte commonly |
1665 | - * don't have any category metadata, so they'll only show up under |
1666 | - * All Applications */ |
1667 | - for (i = 0; i < len; i++) |
1668 | - { |
1669 | - dum1 = g_ascii_strdown (cats[i], -1); |
1670 | - dum2 = g_strconcat ("AC", dum1, NULL); |
1671 | - doc.add_term (dum2); |
1672 | - g_free (dum1); |
1673 | - g_free (dum2); |
1674 | - } |
1675 | - |
1676 | - /* Index Keywords*/ |
1677 | - keywords = unity_app_info_manager_get_keywords (appman, // const return |
1678 | - gmenu_tree_entry_get_desktop_file_id (entry), |
1679 | - &len); |
1680 | - for (i = 0; i < len; i++) |
1681 | - { |
1682 | - dum1 = unity_applications_lens_utils_preprocess_string (keywords[i]); |
1683 | - indexer->index_text (dum1, 0); |
1684 | - indexer->index_text (dum1, 0, "KW"); |
1685 | - g_free (dum1); |
1686 | - } |
1687 | - |
1688 | - |
1689 | - g_object_unref (appman); |
1690 | - |
1691 | - /* Always assume Type=Application for items in a menu... */ |
1692 | - doc.add_term ("ATapplication"); |
1693 | - |
1694 | - /* Index application names */ |
1695 | - dum1 = (gchar *) gmenu_tree_entry_get_display_name (entry); // const |
1696 | - dum2 = g_strconcat ("AA", dum1, NULL); |
1697 | + dum1 = unity_applications_lens_utils_preprocess_string (gmenu_tree_entry_get_comment (entry)); |
1698 | + indexer->index_text (dum1, 0); |
1699 | + g_free (dum1); |
1700 | + } |
1701 | + |
1702 | + /* Index the XDG categories */ |
1703 | + appman = unity_app_info_manager_get_default (); |
1704 | + cats = unity_app_info_manager_get_categories (appman, // const return |
1705 | + gmenu_tree_entry_get_desktop_file_id (entry), |
1706 | + &len); |
1707 | + |
1708 | + /* Note: Wine apps and app launchers created with Alacarte commonly |
1709 | + * don't have any category metadata, so they'll only show up under |
1710 | + * All Applications */ |
1711 | + for (i = 0; i < len; i++) |
1712 | + { |
1713 | + dum1 = g_ascii_strdown (cats[i], -1); |
1714 | + dum2 = g_strconcat ("AC", dum1, NULL); |
1715 | + doc.add_term (dum2); |
1716 | + g_free (dum1); |
1717 | + g_free (dum2); |
1718 | + } |
1719 | + |
1720 | + /* Index Keywords*/ |
1721 | + keywords = unity_app_info_manager_get_keywords (appman, // const return |
1722 | + gmenu_tree_entry_get_desktop_file_id (entry), |
1723 | + &len); |
1724 | + for (i = 0; i < len; i++) |
1725 | + { |
1726 | + dum1 = unity_applications_lens_utils_preprocess_string (keywords[i]); |
1727 | + indexer->index_text (dum1, 0); |
1728 | + indexer->index_text (dum1, 0, "KW"); |
1729 | + g_free (dum1); |
1730 | + } |
1731 | + |
1732 | + g_object_unref (appman); |
1733 | + |
1734 | + /* Always assume Type=Application for items in a menu... */ |
1735 | + doc.add_term ("ATapplication"); |
1736 | + |
1737 | + /* Index application names */ |
1738 | + dum1 = (gchar *) gmenu_tree_entry_get_display_name (entry); // const |
1739 | + dum2 = g_strconcat ("AA", dum1, NULL); |
1740 | doc.add_term (dum2); |
1741 | g_free (dum2); |
1742 | - |
1743 | + |
1744 | dum1 = (gchar *) gmenu_tree_entry_get_name (entry); // const |
1745 | - dum2 = g_strconcat ("AA", dum1, NULL); |
1746 | + dum2 = g_strconcat ("AA", dum1, NULL); |
1747 | doc.add_term (dum2); |
1748 | g_free (dum2); |
1749 | |
1750 | /* Index executable name, change - in _ for exec */ |
1751 | - dum1 = g_strdup (gmenu_tree_entry_get_exec (entry)); // alloc |
1752 | + dum1 = g_strdup (gmenu_tree_entry_get_exec (entry)); // alloc |
1753 | if (dum1) { |
1754 | dum2 = strstr (dum1, " "); // const |
1755 | dum2 == NULL ? : *dum2 = '\0'; // const |
1756 | @@ -256,25 +252,23 @@ |
1757 | doc.add_term (dum2); |
1758 | g_free (dum2); |
1759 | dum2 = g_strconcat ("XX", dum1, NULL); // alloc |
1760 | - doc.add_term (dum2); |
1761 | + doc.add_term (dum2); |
1762 | g_free (dum2); |
1763 | - g_free (dum1); |
1764 | - } |
1765 | - |
1766 | + g_free (dum1); |
1767 | + } |
1768 | + |
1769 | db->add_document(doc); |
1770 | - break; |
1771 | - case GMENU_TREE_ITEM_SEPARATOR: |
1772 | - case GMENU_TREE_ITEM_HEADER: |
1773 | - case GMENU_TREE_ITEM_ALIAS: |
1774 | - break; |
1775 | - default: |
1776 | - g_warning ("Unexpected GMenuTreeItemType %u", |
1777 | - gmenu_tree_item_get_type (item)); |
1778 | - return; |
1779 | + break; |
1780 | + case GMENU_TREE_ITEM_SEPARATOR: |
1781 | + case GMENU_TREE_ITEM_HEADER: |
1782 | + case GMENU_TREE_ITEM_ALIAS: |
1783 | + break; |
1784 | + default: |
1785 | + g_warning ("Unexpected GMenuTreeItemType %u", gmenu_tree_item_get_type (item)); |
1786 | + return; |
1787 | } |
1788 | |
1789 | // Add the document to the database. |
1790 | - |
1791 | } |
1792 | |
1793 | /* Create a searcher that searches in a menu tree. The menu tree |
1794 | @@ -289,16 +283,16 @@ |
1795 | db = new Xapian::WritableDatabase (); |
1796 | searcher->db = db; |
1797 | searcher->db->add_database (Xapian::InMemory::open ()); |
1798 | - |
1799 | + |
1800 | init_searcher (searcher); |
1801 | - |
1802 | + |
1803 | /* Index the menu recursively */ |
1804 | Xapian::TermGenerator *indexer = new Xapian::TermGenerator (); |
1805 | index_menu_item (db, indexer, |
1806 | GMENU_TREE_ITEM (gmenu_tree_get_root_directory (menu))); |
1807 | delete indexer; |
1808 | db->flush (); |
1809 | - |
1810 | + |
1811 | return searcher; |
1812 | } |
1813 | |
1814 | @@ -325,14 +319,14 @@ |
1815 | agent = g_strdup_printf("%s/software-center/software-center-agent.db", |
1816 | g_get_user_cache_dir()); |
1817 | if (g_file_test(agent, G_FILE_TEST_IS_DIR)) |
1818 | - searcher->db->add_database (Xapian::Database (agent)); |
1819 | + searcher->db->add_database (Xapian::Database (agent)); |
1820 | g_free(agent); |
1821 | } catch(const Xapian::Error &error) { |
1822 | cerr << "Error loading agent indexes: " << error.get_msg() << endl; |
1823 | } |
1824 | |
1825 | init_searcher (searcher); |
1826 | - |
1827 | + |
1828 | return searcher; |
1829 | } |
1830 | |
1831 | @@ -373,13 +367,17 @@ |
1832 | static void _free_package_info (gpointer pkg) |
1833 | { |
1834 | UnityPackageInfo *pkginfo = (UnityPackageInfo*) pkg; |
1835 | + unity_package_package_info_free (pkginfo); |
1836 | +} |
1837 | |
1838 | +void unity_package_package_info_free (UnityPackageInfo *pkginfo) |
1839 | +{ |
1840 | g_free (pkginfo->package_name); |
1841 | g_free (pkginfo->application_name); |
1842 | g_free (pkginfo->desktop_file); |
1843 | g_free (pkginfo->icon); |
1844 | |
1845 | - g_slice_free (UnityPackageInfo, pkg); |
1846 | + g_slice_free (UnityPackageInfo, pkginfo); |
1847 | } |
1848 | |
1849 | UnityPackageSearchResult* |
1850 | @@ -432,7 +430,7 @@ |
1851 | searcher->enquire->set_sort_by_relevance (); |
1852 | break; |
1853 | } |
1854 | - |
1855 | + |
1856 | result = g_slice_new0 (UnityPackageSearchResult); |
1857 | try |
1858 | { |
1859 | @@ -440,29 +438,25 @@ |
1860 | searcher->enquire->set_collapse_key(XAPIAN_VALUE_DESKTOP_FILE); |
1861 | max_hits = (max_hits != 0 ? max_hits : searcher->db->get_doccount ()); |
1862 | searcher->enquire->set_query(query); |
1863 | - Xapian::MSet matches = |
1864 | - searcher->enquire->get_mset(0, max_hits); |
1865 | + Xapian::MSet matches = searcher->enquire->get_mset(0, max_hits); |
1866 | |
1867 | // Retrieve the results, note that we build the result->results |
1868 | // list in reverse order and then reverse it before we return it |
1869 | result->num_hits = matches.get_matches_estimated (); |
1870 | - for (Xapian::MSetIterator i = matches.begin(); |
1871 | - i != matches.end(); |
1872 | - ++i) |
1873 | - { |
1874 | - try |
1875 | - { |
1876 | - Xapian::Document doc = i.get_document(); |
1877 | - UnityPackageInfo *pkginfo = _pkginfo_from_document (doc); |
1878 | - pkginfo->relevancy = i.get_percent (); |
1879 | - result->results = g_slist_prepend (result->results, pkginfo); |
1880 | - } |
1881 | - catch (Xapian::Error e) |
1882 | - { |
1883 | - g_warning ("Unable to read document from result set: %s", |
1884 | - e.get_msg().c_str()); |
1885 | - } |
1886 | - } |
1887 | + for (Xapian::MSetIterator i = matches.begin(); i != matches.end(); ++i) |
1888 | + { |
1889 | + try |
1890 | + { |
1891 | + Xapian::Document doc = i.get_document(); |
1892 | + UnityPackageInfo *pkginfo = _pkginfo_from_document (doc); |
1893 | + pkginfo->relevancy = i.get_percent (); |
1894 | + result->results = g_slist_prepend (result->results, pkginfo); |
1895 | + } |
1896 | + catch (Xapian::Error e) |
1897 | + { |
1898 | + g_warning ("Unable to read document from result set: %s", e.get_msg().c_str()); |
1899 | + } |
1900 | + } |
1901 | |
1902 | result->results = g_slist_reverse (result->results); |
1903 | } |
1904 | @@ -470,7 +464,7 @@ |
1905 | { |
1906 | g_warning ("Error running query '%s': %s", search_string, e.get_msg().c_str()); |
1907 | } |
1908 | - |
1909 | + |
1910 | return result; |
1911 | } |
1912 | |
1913 | @@ -486,79 +480,78 @@ |
1914 | g_return_val_if_fail (searcher != NULL, NULL); |
1915 | |
1916 | result = g_slice_new0 (UnityPackageSearchResult); |
1917 | - result->num_hits = n_apps; |
1918 | + result->num_hits = n_apps; |
1919 | lastdocid = searcher->db->get_lastdocid (); |
1920 | - |
1921 | + |
1922 | /* Since we really just pick random apps we may end up with dupes */ |
1923 | unique = g_hash_table_new (g_str_hash, g_str_equal); |
1924 | - |
1925 | + |
1926 | /* When looking for random apps we check up to twice the number of |
1927 | * requested apps in order to try and avoid dupes. This is a sloppy |
1928 | * check, but works well enough in practice */ |
1929 | if (filter_query == NULL) |
1930 | + { |
1931 | + g_debug ("RANDOM"); |
1932 | + for (i = 0, n_unique = 0; i < n_apps*2, n_unique < n_apps; i++) |
1933 | { |
1934 | - g_debug ("RANDOM"); |
1935 | - for (i = 0, n_unique = 0; i < n_apps*2, n_unique < n_apps; i++) |
1936 | - { |
1937 | - Xapian::Document doc; |
1938 | - try |
1939 | - { |
1940 | - doc = searcher->db->get_document ( |
1941 | - g_rand_int_range (searcher->random, 1, lastdocid)); |
1942 | - UnityPackageInfo *pkginfo = _pkginfo_from_document (doc); |
1943 | - if (g_hash_table_lookup_extended (unique, pkginfo->package_name, NULL, NULL)) |
1944 | - { |
1945 | - _free_package_info (pkginfo); |
1946 | - } |
1947 | - else |
1948 | - { |
1949 | - g_hash_table_insert (unique, pkginfo->package_name, NULL); |
1950 | - result->results = g_slist_prepend (result->results, pkginfo); |
1951 | - n_unique++; |
1952 | - } |
1953 | - } |
1954 | - catch (Xapian::Error e) |
1955 | - { |
1956 | - g_warning ("Error getting random apps: %s", e.get_msg().c_str()); |
1957 | - continue; |
1958 | - } |
1959 | - } |
1960 | + Xapian::Document doc; |
1961 | + try |
1962 | + { |
1963 | + doc = searcher->db->get_document ( |
1964 | + g_rand_int_range (searcher->random, 1, lastdocid)); |
1965 | + UnityPackageInfo *pkginfo = _pkginfo_from_document (doc); |
1966 | + if (g_hash_table_lookup_extended (unique, pkginfo->package_name, NULL, NULL)) |
1967 | + { |
1968 | + _free_package_info (pkginfo); |
1969 | + } |
1970 | + else |
1971 | + { |
1972 | + g_hash_table_insert (unique, pkginfo->package_name, NULL); |
1973 | + result->results = g_slist_prepend (result->results, pkginfo); |
1974 | + n_unique++; |
1975 | + } |
1976 | + } |
1977 | + catch (Xapian::Error e) |
1978 | + { |
1979 | + g_warning ("Error getting random apps: %s", e.get_msg().c_str()); |
1980 | + continue; |
1981 | + } |
1982 | } |
1983 | + } |
1984 | else |
1985 | - { |
1986 | - g_debug ("FILTER %s", filter_query); |
1987 | - Xapian::Query query; |
1988 | - try |
1989 | - { |
1990 | - query = searcher->query_parser->parse_query (filter_query, QUERY_PARSER_FILTER_FLAGS); |
1991 | - searcher->enquire->set_sort_by_relevance (); |
1992 | - searcher->enquire->set_query(query); |
1993 | - Xapian::MSet matches = searcher->enquire->get_mset(0, searcher->db->get_doccount ()); |
1994 | - for (i = 0, n_unique = 0; i < n_apps*4, n_unique < n_apps; i++) |
1995 | - { |
1996 | - docid = g_rand_int_range (searcher->random, 0, matches.size ()); |
1997 | - Xapian::MSetIterator iter = matches[docid]; |
1998 | - Xapian::Document doc = iter.get_document (); |
1999 | - UnityPackageInfo *pkginfo = _pkginfo_from_document (doc); |
2000 | - if (g_hash_table_lookup_extended (unique, pkginfo->package_name, NULL, NULL)) |
2001 | - { |
2002 | - _free_package_info (pkginfo); |
2003 | - } |
2004 | - else |
2005 | - { |
2006 | - g_hash_table_insert (unique, pkginfo->package_name, NULL); |
2007 | - result->results = g_slist_prepend (result->results, pkginfo); |
2008 | - n_unique++; |
2009 | - } |
2010 | - } |
2011 | - } |
2012 | - catch (Xapian::Error e) |
2013 | - { |
2014 | - g_debug ("Error getting random apps for query '%s': %s", |
2015 | - filter_query, e.get_msg().c_str()); |
2016 | - return g_slice_new0 (UnityPackageSearchResult); |
2017 | - } |
2018 | - } |
2019 | + { |
2020 | + g_debug ("FILTER %s", filter_query); |
2021 | + Xapian::Query query; |
2022 | + try |
2023 | + { |
2024 | + query = searcher->query_parser->parse_query (filter_query, QUERY_PARSER_FILTER_FLAGS); |
2025 | + searcher->enquire->set_sort_by_relevance (); |
2026 | + searcher->enquire->set_query(query); |
2027 | + Xapian::MSet matches = searcher->enquire->get_mset(0, searcher->db->get_doccount ()); |
2028 | + for (i = 0, n_unique = 0; i < n_apps*4, n_unique < n_apps; i++) |
2029 | + { |
2030 | + docid = g_rand_int_range (searcher->random, 0, matches.size ()); |
2031 | + Xapian::MSetIterator iter = matches[docid]; |
2032 | + Xapian::Document doc = iter.get_document (); |
2033 | + UnityPackageInfo *pkginfo = _pkginfo_from_document (doc); |
2034 | + if (g_hash_table_lookup_extended (unique, pkginfo->package_name, NULL, NULL)) |
2035 | + { |
2036 | + _free_package_info (pkginfo); |
2037 | + } |
2038 | + else |
2039 | + { |
2040 | + g_hash_table_insert (unique, pkginfo->package_name, NULL); |
2041 | + result->results = g_slist_prepend (result->results, pkginfo); |
2042 | + n_unique++; |
2043 | + } |
2044 | + } |
2045 | + } |
2046 | + catch (Xapian::Error e) |
2047 | + { |
2048 | + g_debug ("Error getting random apps for query '%s': %s", filter_query, e.get_msg().c_str()); |
2049 | + return g_slice_new0 (UnityPackageSearchResult); |
2050 | + } |
2051 | + } |
2052 | |
2053 | g_hash_table_unref (unique); |
2054 | |
2055 | @@ -566,6 +559,38 @@ |
2056 | return result; |
2057 | } |
2058 | |
2059 | +UnityPackageInfo * |
2060 | +unity_package_searcher_get_by_desktop_file (UnityPackageSearcher *searcher, const gchar *desktop_file) |
2061 | +{ |
2062 | + g_return_val_if_fail (searcher != NULL, NULL); |
2063 | + |
2064 | + UnityPackageInfo *pkginfo = NULL; |
2065 | + |
2066 | + Xapian::PostingIterator it = searcher->db->postlist_begin (""); |
2067 | + Xapian::PostingIterator end_it = searcher->db->postlist_end (""); |
2068 | + |
2069 | + const string query = desktop_file; |
2070 | + |
2071 | + while (it != end_it) |
2072 | + { |
2073 | + Xapian::Document doc = searcher->db->get_document (*it); |
2074 | + string value = doc.get_value (XAPIAN_VALUE_DESKTOP_FILE); |
2075 | + |
2076 | + size_t sep = value.find (':'); |
2077 | + if (sep != string::npos) |
2078 | + { |
2079 | + if (value.compare (sep+1, value.size() - sep, query) == 0) |
2080 | + { |
2081 | + pkginfo = _pkginfo_from_document (doc); |
2082 | + return pkginfo; |
2083 | + } |
2084 | + } |
2085 | + ++it; |
2086 | + } |
2087 | + |
2088 | + return pkginfo; |
2089 | +} |
2090 | + |
2091 | void |
2092 | unity_package_search_result_free (UnityPackageSearchResult *result) |
2093 | { |
2094 | @@ -574,4 +599,3 @@ |
2095 | g_slist_free_full (result->results, _free_package_info); |
2096 | g_slice_free (UnityPackageSearchResult, result); |
2097 | } |
2098 | - |
2099 | |
2100 | === modified file 'src/unity-package-search.h' |
2101 | --- src/unity-package-search.h 2012-03-09 17:44:30 +0000 |
2102 | +++ src/unity-package-search.h 2012-08-08 16:35:21 +0000 |
2103 | @@ -36,23 +36,23 @@ |
2104 | |
2105 | typedef struct |
2106 | { |
2107 | - GSList *results; |
2108 | - gint num_hits; |
2109 | + GSList *results; |
2110 | + gint num_hits; |
2111 | } UnityPackageSearchResult; |
2112 | |
2113 | typedef struct |
2114 | { |
2115 | - gchar *package_name; |
2116 | - gchar *application_name; |
2117 | - gchar *desktop_file; |
2118 | - gchar *icon; |
2119 | - gint relevancy; |
2120 | + gchar *package_name; |
2121 | + gchar *application_name; |
2122 | + gchar *desktop_file; |
2123 | + gchar *icon; |
2124 | + gint relevancy; |
2125 | } UnityPackageInfo; |
2126 | |
2127 | #ifdef __cplusplus |
2128 | extern "C" { |
2129 | #endif |
2130 | - |
2131 | + |
2132 | UnityPackageSearcher* unity_package_searcher_new (); |
2133 | |
2134 | UnityPackageSearcher* unity_package_searcher_new_for_menu (GMenuTree *menu); |
2135 | @@ -71,7 +71,10 @@ |
2136 | |
2137 | void unity_package_search_result_free (UnityPackageSearchResult *result); |
2138 | |
2139 | +void unity_package_package_info_free (UnityPackageInfo *pkginfo); |
2140 | + |
2141 | +UnityPackageInfo* unity_package_searcher_get_by_desktop_file (UnityPackageSearcher *searcher, const gchar *desktop_file); |
2142 | + |
2143 | #ifdef __cplusplus |
2144 | } |
2145 | #endif |
2146 | - |
2147 | |
2148 | === modified file 'vapi/unity-package-search.vapi' |
2149 | --- vapi/unity-package-search.vapi 2012-03-09 17:44:30 +0000 |
2150 | +++ vapi/unity-package-search.vapi 2012-08-08 16:35:21 +0000 |
2151 | @@ -27,6 +27,7 @@ |
2152 | public Searcher.for_menu(GMenu.Tree menu); |
2153 | public SearchResult search (string search_string, uint max_hits, Unity.Package.SearchType search_type, Unity.Package.Sort sort); |
2154 | public SearchResult get_random_apps (string? filter_query, uint n_apps); |
2155 | + public PackageInfo? get_by_desktop_file (string desktop_file); |
2156 | } |
2157 | |
2158 | [Compact] |
2159 | @@ -37,7 +38,7 @@ |
2160 | } |
2161 | |
2162 | [Compact] |
2163 | - [CCode (cname = "UnityPackageInfo", cheader_filename = "unity-package-search.h")] |
2164 | + [CCode (cname = "UnityPackageInfo", free_function = "unity_package_package_info_free", cheader_filename = "unity-package-search.h")] |
2165 | public class PackageInfo { |
2166 | public string package_name; |
2167 | public string application_name; |