Merge lp:~stolowski/unity-lens-applications/unity-lens-applications.previews into lp:unity-lens-applications
- unity-lens-applications.previews
- Merge into trunk
Status: | Merged |
---|---|
Approved by: | Michal Hruby |
Approved revision: | 326 |
Merged at revision: | 289 |
Proposed branch: | lp:~stolowski/unity-lens-applications/unity-lens-applications.previews |
Merge into: | lp:unity-lens-applications |
Diff against target: |
1283 lines (+802/-123) 10 files modified
configure.ac (+3/-3) src/Makefile.am (+5/-2) src/aptd-client.vala (+97/-0) src/daemon.vala (+365/-1) src/launcher-client.vala (+45/-0) src/runner.vala (+4/-4) src/software-center-data-provider.vala (+128/-0) src/unity-package-search.cc (+141/-103) 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.previews |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Michal Hruby (community) | Approve | ||
Review via email: mp+118772@code.launchpad.net |
Commit message
Implemented previews
Description of the change
Implemented previews. WARNING! Requires new Software-Center DBus Data Provider.
There are some formatting issues, they will be fixed in a separate review as I cleaned entire unity-package-
Michal Hruby (mhr3) wrote : | # |
Michal Hruby (mhr3) wrote : | # |
460 + string subtitle = _("Version %s").printf (sc_data_
Needs check for size > 0.
488 + var buy_action = new Unity.PreviewAction ("buy", _("Buy") + " " + sc_data_
Noticed that the price doesn't include currency symbol (though I guess this is for mvo?)
Michal Hruby (mhr3) wrote : | # |
701 + public abstract HashTable<string, Variant> get_app_details (string appname, string pkgname) throws IOError;
By defining dbus interfaces as throwing just IOError all other types of errors are then ignored (plus a critical is logged), we're not registering any special dbus error types, so errors from the services themselves will use IOError.
You can either use "throws IOError, DBusError" or just "throws Error" and this won't ignore anything (of course only if there will be catch (Error) {} block)
563 + catch (IOError e)
564 + {
565 + warning ("Failed to get package details for '%s': %s", uri, e.message);
566 + }
Let's set a flag here if an error occurred and use the fallback desktop file-based app preview in that case.
Michal Hruby (mhr3) wrote : | # |
Cool, let's get this in!
Unity Merger (unity-merger) wrote : | # |
There are additional revisions which have not been approved in review. Please seek review and approval of these new revisions.
Michal Hruby (mhr3) : | # |
Preview Diff
1 | === modified file 'configure.ac' |
2 | --- configure.ac 2012-08-10 09:07:03 +0000 |
3 | +++ configure.ac 2012-08-16 08:33: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-16 08:33: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-16 08:33: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) throws IOError |
117 | + { |
118 | + string res = yield _aptd_service.install_packages (packages); |
119 | + return res; |
120 | + } |
121 | + |
122 | + public async string remove_packages (string[] packages) throws IOError |
123 | + { |
124 | + string res = yield _aptd_service.remove_packages (packages); |
125 | + return res; |
126 | + } |
127 | + |
128 | + public async void quit () throws IOError |
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 () throws IOError |
151 | + { |
152 | + _aptd_service.simulate (); |
153 | + } |
154 | + |
155 | + public void run () throws IOError |
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-16 08:33: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 | @@ -48,6 +49,28 @@ |
176 | private Unity.Lens lens; |
177 | private Unity.Scope scope; |
178 | |
179 | + /* Support aptd dbus interface; created when application install/remove was requested by preview action */ |
180 | + private AptdProxy aptdclient; |
181 | + private AptdTransactionProxy aptd_transaction; |
182 | + |
183 | + /* Maps demangled names to mangled names expected by S-C xapian DB (e.g. kde4-KCharSelect.desktop -> kde4__KCharSelect.desktop). |
184 | + There are very few apps that need this and we only store mappings when needed, so it takes very little memory. |
185 | + */ |
186 | + private HashTable<string, string> mangled_desktop_ids; |
187 | + |
188 | + /* Used for adding launcher icon on app installation from the preview */ |
189 | + private LauncherProxy launcherservice; |
190 | + |
191 | + /* Desktop file & icon name for unity-install:// install candidate displayed in last preview; we store |
192 | + * them here to avoid extra query for app details if app install action is activated */ |
193 | + private string preview_installable_desktop_file; |
194 | + private string preview_installable_icon_file; |
195 | + |
196 | + private string preview_developer_website; |
197 | + |
198 | + /* SoftwareCenter data provider used for app preview details */ |
199 | + private SoftwareCenterDataProviderProxy sc_data_provider; |
200 | + |
201 | private Unity.ApplicationsLens.Runner runner; |
202 | |
203 | /* Keep references to the FilterOptions for sources */ |
204 | @@ -135,6 +158,7 @@ |
205 | build_app_menu_index (); |
206 | |
207 | file_icon_cache = new HashTable<string,Icon>(str_hash, str_equal); |
208 | + mangled_desktop_ids = new HashTable<string, string>(str_hash, str_equal); |
209 | |
210 | scope = new Unity.Scope ("/com/canonical/unity/scope/applications"); |
211 | //scope.icon = @"$(Config.PREFIX)/share/unity/themes/applications.png"; |
212 | @@ -172,6 +196,7 @@ |
213 | }); |
214 | |
215 | scope.activate_uri.connect (activate); |
216 | + scope.preview_uri.connect (preview); |
217 | |
218 | /* Listen for changes in the installed applications */ |
219 | AppInfoManager.get_default().changed.connect (mark_dirty); |
220 | @@ -193,6 +218,8 @@ |
221 | app_watcher = new AppWatcher (); |
222 | app_watcher.running_applications_changed.connect (mark_dirty); |
223 | |
224 | + aptdclient = new AptdProxy (); |
225 | + launcherservice = new LauncherProxy (); |
226 | |
227 | lens = new Unity.Lens ("/com/canonical/unity/lens/applications", "applications"); |
228 | lens.search_hint = _("Search Applications"); |
229 | @@ -709,6 +736,27 @@ |
230 | } |
231 | } |
232 | |
233 | + /** |
234 | + * Find app icon in DATADIR/app-install/icons based on preview_installable_icon_file |
235 | + * obtained from S-C data provider. |
236 | + * trying all supported image extensions. |
237 | + */ |
238 | + private string find_app_install_icon_path () |
239 | + { |
240 | + string icon = @"$ICON_APP_INSTALL_PATH/$preview_installable_icon_file."; |
241 | + |
242 | + foreach (string ext in image_extensions) |
243 | + { |
244 | + string path = icon + ext; |
245 | + if (FileUtils.test (path, FileTest.EXISTS)) |
246 | + { |
247 | + return path; |
248 | + } |
249 | + } |
250 | + var default_icon = new ThemedIcon ("applications-other"); |
251 | + return default_icon.to_string (); |
252 | + } |
253 | + |
254 | public Icon find_pkg_icon (Unity.Package.PackageInfo pkginfo) |
255 | { |
256 | string desktop_id = Path.get_basename (pkginfo.desktop_file); |
257 | @@ -791,7 +839,14 @@ |
258 | desktop_id = desktop_id[colon_pos+1:desktop_id.length]; |
259 | /* well it's still not real desktop_id, S-C converts slashes to "__" |
260 | * if the desktop file is in /usr/share/applications */ |
261 | - desktop_id = desktop_id.replace ("__", "-"); |
262 | + string demangled_desktop_id = desktop_id.replace ("__", "-"); |
263 | + |
264 | + // store demangled name -> mangled name mapping |
265 | + if (desktop_id != demangled_desktop_id) |
266 | + { |
267 | + mangled_desktop_ids.replace (demangled_desktop_id, desktop_id); |
268 | + } |
269 | + desktop_id = demangled_desktop_id; |
270 | } |
271 | |
272 | return desktop_id; |
273 | @@ -927,6 +982,315 @@ |
274 | } |
275 | } |
276 | |
277 | + private async void call_install_packages (string package_name, out string tid) throws IOError |
278 | + { |
279 | + tid = yield aptdclient.install_packages ({package_name}); |
280 | + } |
281 | + |
282 | + private async void call_remove_packages (string package_name, out string tid) throws IOError |
283 | + { |
284 | + tid = yield aptdclient.remove_packages ({package_name}); |
285 | + } |
286 | + |
287 | + /** |
288 | + * Handler for free apps installation. |
289 | + * Triggers package installation via apt-daemon DBus service |
290 | + */ |
291 | + private Unity.ActivationResponse app_preview_install (string uri) |
292 | + { |
293 | + if (uri.has_prefix ("unity-install://")) |
294 | + { |
295 | + string app = uri.substring (16); // trim "unity-install://" |
296 | + string[] parts = app.split ("/"); |
297 | + |
298 | + if (parts.length > 1) |
299 | + { |
300 | + string pkgname = parts[0]; |
301 | + string appname = parts[1]; |
302 | + try |
303 | + { |
304 | + aptdclient.connect_to_aptd (); |
305 | + } |
306 | + catch (IOError e) |
307 | + { |
308 | + warning ("Failed to connect to aptd: '%s'", e.message); |
309 | + return new Unity.ActivationResponse(Unity.HandledType.NOT_HANDLED); |
310 | + } |
311 | + call_install_packages.begin (pkgname, (obj, res) => |
312 | + { |
313 | + try { |
314 | + string tid; |
315 | + call_install_packages.end (res, out tid); |
316 | + debug ("transaction started: %s, pkg: %s\n", tid, pkgname); |
317 | + aptd_transaction = new AptdTransactionProxy (); |
318 | + aptd_transaction.connect_to_aptd (tid); |
319 | + aptd_transaction.simulate (); |
320 | + aptd_transaction.run (); |
321 | + |
322 | + launcherservice.connect_to_launcher (); |
323 | + string desktop_file = preview_installable_desktop_file; |
324 | + string icon = find_app_install_icon_path (); |
325 | + |
326 | + launcherservice.add_launcher_item_from_position (appname, icon, 0, 0, 32, desktop_file, tid); |
327 | + } |
328 | + catch (IOError e) |
329 | + { |
330 | + warning ("Package '%s' installation failed: %s", pkgname, e.message); |
331 | + } |
332 | + }); |
333 | + } |
334 | + else |
335 | + { |
336 | + warning ("Bad install uri: '%s'", uri); |
337 | + } |
338 | + } |
339 | + else |
340 | + { |
341 | + warning ("Can't handle '%s' in app_preview_install handler", uri); |
342 | + return new Unity.ActivationResponse(Unity.HandledType.NOT_HANDLED); |
343 | + } |
344 | + return new Unity.ActivationResponse(Unity.HandledType.HIDE_DASH); |
345 | + } |
346 | + |
347 | + private Unity.ActivationResponse app_preview_install_commercial (string uri) |
348 | + { |
349 | + return activate (uri); //this will just launch Software-Center |
350 | + } |
351 | + |
352 | + private Unity.ActivationResponse app_preview_buy (string uri) |
353 | + { |
354 | + return activate (uri); //this will just launch Software-Center |
355 | + } |
356 | + |
357 | + private Unity.ActivationResponse app_preview_website (string uri) |
358 | + { |
359 | + try |
360 | + { |
361 | + AppInfo.launch_default_for_uri (preview_developer_website, null); |
362 | + return new Unity.ActivationResponse(Unity.HandledType.HIDE_DASH); |
363 | + } |
364 | + catch (Error e) |
365 | + { |
366 | + warning ("Failed to launch a web browser for uri '%s': '%s'", uri, e.message); |
367 | + } |
368 | + return new Unity.ActivationResponse(Unity.HandledType.NOT_HANDLED); |
369 | + } |
370 | + |
371 | + private Unity.ActivationResponse app_preview_uninstall (string uri) |
372 | + { |
373 | + if (uri.has_prefix ("application://")) |
374 | + { |
375 | + string desktopfile = uri.substring (14); // trim "application://" |
376 | + |
377 | + // de-mangle desktop file names back to what S-C expects |
378 | + if (mangled_desktop_ids.contains (desktopfile)) |
379 | + { |
380 | + desktopfile = mangled_desktop_ids.get (desktopfile); |
381 | + } |
382 | + |
383 | + var pkginfo = pkgsearcher.get_by_desktop_file (desktopfile); |
384 | + |
385 | + if (pkginfo != null && pkginfo.package_name != null) |
386 | + { |
387 | + try |
388 | + { |
389 | + aptdclient.connect_to_aptd (); |
390 | + } |
391 | + catch (IOError e) |
392 | + { |
393 | + warning ("Failed to connect to aptd: '%s'", e.message); |
394 | + return new Unity.ActivationResponse(Unity.HandledType.NOT_HANDLED); |
395 | + } |
396 | + |
397 | + call_remove_packages.begin (pkginfo.package_name, (obj, res) => |
398 | + { |
399 | + try { |
400 | + string tid; |
401 | + call_remove_packages.end (res, out tid); |
402 | + debug ("transaction started: %s, pkg: %s\n", tid, pkginfo.package_name); |
403 | + aptd_transaction = new AptdTransactionProxy (); |
404 | + aptd_transaction.connect_to_aptd (tid); |
405 | + aptd_transaction.simulate (); |
406 | + aptd_transaction.run (); |
407 | + } |
408 | + catch (IOError e) |
409 | + { |
410 | + warning (@"Package '$(pkginfo.package_name)' removal failed: $(e.message)"); |
411 | + } |
412 | + }); |
413 | + return new Unity.ActivationResponse(Unity.HandledType.HIDE_DASH); |
414 | + } |
415 | + else |
416 | + { |
417 | + warning (@"Cannot find package info for $uri"); |
418 | + } |
419 | + } |
420 | + warning (@"Can't handle '%s' in app_preview_uninstall handler", uri); |
421 | + return new Unity.ActivationResponse(Unity.HandledType.NOT_HANDLED); |
422 | + } |
423 | + |
424 | + public Unity.Preview preview (string uri) |
425 | + { |
426 | + Unity.ApplicationPreview? preview = null; |
427 | + |
428 | + string pkgname = ""; |
429 | + string appname = ""; |
430 | + |
431 | + if (uri.has_prefix ("application://") || uri.has_prefix ("unity-install://")) |
432 | + { |
433 | + string desktopfile = null; |
434 | + if (uri.has_prefix ("application://")) |
435 | + { |
436 | + desktopfile = uri.substring (14); //remove "application://" prefix |
437 | + |
438 | + // de-mangle desktop file names back to what S-C expects |
439 | + if (mangled_desktop_ids.contains (desktopfile)) |
440 | + { |
441 | + desktopfile = mangled_desktop_ids.get (desktopfile); |
442 | + } |
443 | + |
444 | + Unity.Package.PackageInfo pkginfo = pkgsearcher.get_by_desktop_file (desktopfile); |
445 | + if (pkginfo != null) |
446 | + { |
447 | + appname = pkginfo.application_name; |
448 | + pkgname = pkginfo.package_name; |
449 | + } |
450 | + } |
451 | + else // unity-install |
452 | + { |
453 | + string app = uri.substring (16); //remove "unity-install://" prefix |
454 | + string[] parts = app.split ("/"); |
455 | + if (parts.length > 1) |
456 | + { |
457 | + pkgname = parts[0]; |
458 | + appname = parts[1]; |
459 | + } |
460 | + } |
461 | + |
462 | + if (pkgname != "") |
463 | + { |
464 | + try { |
465 | + if (sc_data_provider == null) |
466 | + { |
467 | + sc_data_provider = new SoftwareCenterDataProviderProxy (); |
468 | + sc_data_provider.connect_to (); |
469 | + } |
470 | + |
471 | + debug ("Requesting pkg info: %s, %s\n", pkgname, appname); |
472 | + sc_data_provider.get_app_details (appname, pkgname); |
473 | + |
474 | + Icon icon = new GLib.ThemedIcon (sc_data_provider.icon); |
475 | + Icon? screenshot = null; |
476 | + |
477 | + if (sc_data_provider.screenshot != null) |
478 | + { |
479 | + File scr_file = File.new_for_uri (sc_data_provider.screenshot); |
480 | + screenshot = new FileIcon (scr_file); |
481 | + } |
482 | + |
483 | + string subtitle = ""; |
484 | + if (sc_data_provider.version != "") |
485 | + subtitle = _("Version %s").printf (sc_data_provider.version); |
486 | + if (sc_data_provider.size > 0) |
487 | + { |
488 | + if (subtitle != "") |
489 | + subtitle += ", "; |
490 | + subtitle += ("Size %s").printf (GLib.format_size (sc_data_provider.size)); |
491 | + } |
492 | + preview = new Unity.ApplicationPreview (sc_data_provider.name, subtitle, sc_data_provider.description, icon, screenshot); |
493 | + preview.license = sc_data_provider.license; |
494 | + |
495 | + if (ratings !=null) |
496 | + { |
497 | + Unity.Ratings.Result result; |
498 | + ratings.query (pkgname, out result); |
499 | + preview.set_rating (result.average_rating, result.total_rating); |
500 | + } |
501 | + |
502 | + if (sc_data_provider.hardware_requirements != "") |
503 | + preview.add_info (new InfoHint ("hardware-requirements", _("Hardware requirements"), null, sc_data_provider.hardware_requirements)); |
504 | + |
505 | + if (uri.has_prefix ("unity-install://")) // application needs to be purchased/installed |
506 | + { |
507 | + if (sc_data_provider.website != null && sc_data_provider.website != "") |
508 | + { |
509 | + preview_developer_website = sc_data_provider.website; |
510 | + var website_action = new Unity.PreviewAction ("website", _("Developer Site"), null); |
511 | + website_action.activated.connect (app_preview_website); |
512 | + preview.add_action (website_action); |
513 | + } |
514 | + |
515 | + // uninstalled and not purchased before |
516 | + if (sc_data_provider.pkg_state == SoftwareCenterDataProviderProxy.PackageState.NEEDS_PURCHASE) |
517 | + { |
518 | + var buy_str = _("Buy"); |
519 | + if (sc_data_provider.price != null && sc_data_provider.price != "") |
520 | + { |
521 | + buy_str += " " + sc_data_provider.price; //FIXME: implement action hints |
522 | + } |
523 | + var buy_action = new Unity.PreviewAction ("buy", buy_str, null); |
524 | + buy_action.activated.connect (app_preview_buy); |
525 | + preview.add_action (buy_action); |
526 | + } |
527 | + else // uninstalled, purchased before |
528 | + { |
529 | + |
530 | + Unity.PreviewAction install_action = null; |
531 | + if (sc_data_provider.price == "") |
532 | + { |
533 | + install_action = new Unity.PreviewAction ("install", _("Free Download"), null); |
534 | + install_action.activated.connect (app_preview_install); |
535 | + } |
536 | + else |
537 | + { |
538 | + install_action = new Unity.PreviewAction ("install", _("Install"), null); |
539 | + install_action.activated.connect (app_preview_install_commercial); |
540 | + install_action.activated.connect (app_preview_install); |
541 | + } |
542 | + preview.add_action (install_action); |
543 | + } |
544 | + } |
545 | + else // application is already installed |
546 | + { |
547 | + preview.add_info (new InfoHint ("date-installed", _("Installed on"), null, sc_data_provider.installation_date)); |
548 | + var launch_action = new Unity.PreviewAction ("launch", _("Launch"), null); |
549 | + preview.add_action (launch_action); |
550 | + var uninstall_action = new Unity.PreviewAction ("uninstall", _("Uninstall"), null); |
551 | + uninstall_action.activated.connect (app_preview_uninstall); |
552 | + preview.add_action (uninstall_action); |
553 | + } |
554 | + |
555 | + preview_installable_desktop_file = sc_data_provider.desktop_file; |
556 | + preview_installable_icon_file = sc_data_provider.icon; |
557 | + } |
558 | + catch (Error e) |
559 | + { |
560 | + warning ("Failed to get package details for '%s': %s", uri, e.message); |
561 | + preview = null; |
562 | + } |
563 | + } |
564 | + |
565 | + // xapian db doesn't know this .desktop file or S-C dbus data provider fails, |
566 | + // fallback to DesktopAppInfo (based on installed .desktop file) if available |
567 | + if (preview == null && desktopfile != null) |
568 | + { |
569 | + var app_info = new DesktopAppInfo (desktopfile); |
570 | + if (app_info != null) |
571 | + { |
572 | + preview = new Unity.ApplicationPreview (app_info.get_display_name (), "", app_info.get_description () ?? "", app_info.get_icon (), null); |
573 | + var launch_action = new Unity.PreviewAction ("launch", _("Launch"), null); |
574 | + preview.add_action (launch_action); |
575 | + } |
576 | + } |
577 | + |
578 | + if (preview == null) |
579 | + { |
580 | + warning ("No pksearcher nor desktop app info for '%s'", uri); |
581 | + } |
582 | + } |
583 | + return preview; |
584 | + } |
585 | + |
586 | /** |
587 | * Override of the default activation handler. The apps lens daemon |
588 | * can handle activation of installable apps using the Software Center |
589 | |
590 | === added file 'src/launcher-client.vala' |
591 | --- src/launcher-client.vala 1970-01-01 00:00:00 +0000 |
592 | +++ src/launcher-client.vala 2012-08-16 08:33:21 +0000 |
593 | @@ -0,0 +1,45 @@ |
594 | +/* |
595 | + * Copyright (C) 2012 Canonical Ltd |
596 | + * |
597 | + * This program is free software: you can redistribute it and/or modify |
598 | + * it under the terms of the GNU General Public License version 3 as |
599 | + * published by the Free Software Foundation. |
600 | + * |
601 | + * This program is distributed in the hope that it will be useful, |
602 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
603 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
604 | + * GNU General Public License for more details. |
605 | + * |
606 | + * You should have received a copy of the GNU General Public License |
607 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
608 | + * |
609 | + * Authored by Pawel Stolowski <pawel.stolowski@canonical.com> |
610 | + */ |
611 | + |
612 | +namespace Unity.ApplicationsLens { |
613 | + |
614 | + static const string LAUNCHER_DBUS_NAME = "com.canonical.Unity.Launcher"; |
615 | + static const string LAUNCHER_DBUS_PATH = "/com/canonical/Unity/Launcher"; |
616 | + |
617 | + [DBus (name = "com.canonical.Unity.Launcher")] |
618 | + public interface LauncherService: GLib.Object |
619 | + { |
620 | + 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; |
621 | + } |
622 | + |
623 | + public class LauncherProxy: GLib.Object |
624 | + { |
625 | + public void connect_to_launcher () throws IOError |
626 | + { |
627 | + _launcher_service = Bus.get_proxy_sync (BusType.SESSION, LAUNCHER_DBUS_NAME, LAUNCHER_DBUS_PATH); |
628 | + } |
629 | + |
630 | + 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 |
631 | + { |
632 | + yield _launcher_service.add_launcher_item_from_position (title, icon, icon_x, icon_y, icon_size, desktop_file, aptdaemon_task); |
633 | + } |
634 | + |
635 | + private LauncherService _launcher_service; |
636 | + } |
637 | + |
638 | +} |
639 | \ No newline at end of file |
640 | |
641 | === modified file 'src/runner.vala' |
642 | --- src/runner.vala 2012-04-26 07:03:41 +0000 |
643 | +++ src/runner.vala 2012-08-16 08:33:21 +0000 |
644 | @@ -201,7 +201,7 @@ |
645 | } |
646 | |
647 | try { |
648 | - var iterator = directory.enumerate_children (FILE_ATTRIBUTE_STANDARD_NAME + "," + FILE_ATTRIBUTE_STANDARD_TYPE + "," + FILE_ATTRIBUTE_ACCESS_CAN_EXECUTE, |
649 | + var iterator = directory.enumerate_children (FileAttribute.STANDARD_NAME + "," + FileAttribute.STANDARD_TYPE + "," + FileAttribute.ACCESS_CAN_EXECUTE, |
650 | 0, null); |
651 | while (true) |
652 | { |
653 | @@ -216,7 +216,7 @@ |
654 | { |
655 | dirs_match.add (complete_path); |
656 | } |
657 | - else if (subelem_info.get_attribute_boolean (FILE_ATTRIBUTE_ACCESS_CAN_EXECUTE)) |
658 | + else if (subelem_info.get_attribute_boolean (FileAttribute.ACCESS_CAN_EXECUTE)) |
659 | { |
660 | // only include exec name if we are in the PATH |
661 | if (search_dirname_in_path) |
662 | @@ -316,7 +316,7 @@ |
663 | { |
664 | var dir = File.new_for_path (path_directory); |
665 | try { |
666 | - var e = yield dir.enumerate_children_async (FILE_ATTRIBUTE_STANDARD_NAME + "," + FILE_ATTRIBUTE_ACCESS_CAN_EXECUTE, |
667 | + var e = yield dir.enumerate_children_async (FileAttribute.STANDARD_NAME + "," + FileAttribute.ACCESS_CAN_EXECUTE, |
668 | 0, Priority.DEFAULT, null); |
669 | while (true) { |
670 | var files = yield e.next_files_async (64, Priority.DEFAULT, null); |
671 | @@ -324,7 +324,7 @@ |
672 | break; |
673 | |
674 | foreach (var info in files) { |
675 | - if (info.get_attribute_boolean (FILE_ATTRIBUTE_ACCESS_CAN_EXECUTE)) |
676 | + if (info.get_attribute_boolean (FileAttribute.ACCESS_CAN_EXECUTE)) |
677 | { |
678 | this.executables.add (info.get_name ()); |
679 | } |
680 | |
681 | === added file 'src/software-center-data-provider.vala' |
682 | --- src/software-center-data-provider.vala 1970-01-01 00:00:00 +0000 |
683 | +++ src/software-center-data-provider.vala 2012-08-16 08:33:21 +0000 |
684 | @@ -0,0 +1,128 @@ |
685 | +/* |
686 | + * Copyright (C) 2012 Canonical Ltd |
687 | + * |
688 | + * This program is free software: you can redistribute it and/or modify |
689 | + * it under the terms of the GNU General Public License version 3 as |
690 | + * published by the Free Software Foundation. |
691 | + * |
692 | + * This program is distributed in the hope that it will be useful, |
693 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
694 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
695 | + * GNU General Public License for more details. |
696 | + * |
697 | + * You should have received a copy of the GNU General Public License |
698 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
699 | + * |
700 | + * Authored by Pawel Stolowski <pawel.stolowski@canonical.com> |
701 | + */ |
702 | + |
703 | +namespace Unity.ApplicationsLens { |
704 | + |
705 | + static const string SCDP_DBUS_NAME = "com.ubuntu.SoftwareCenterDataProvider"; |
706 | + static const string SCDP_DBUS_PATH = "/com/ubuntu/SoftwareCenterDataProvider"; |
707 | + |
708 | + [DBus (name = "com.ubuntu.SoftwareCenterDataProvider")] |
709 | + public interface SoftwareCenterDataProviderService: GLib.Object |
710 | + { |
711 | + public abstract HashTable<string, Variant> get_app_details (string appname, string pkgname) throws Error; |
712 | + } |
713 | + |
714 | + public class SoftwareCenterDataProviderProxy: GLib.Object |
715 | + { |
716 | + public enum PackageState |
717 | + { |
718 | + UNINSTALLED, |
719 | + INSTALLED, |
720 | + NEEDS_PURCHASE, |
721 | + UNKNOWN |
722 | + } |
723 | + |
724 | + public string name { get; set; } |
725 | + public string summary { get; set; } |
726 | + public string description { get; set; } |
727 | + public string version { get; set; } |
728 | + public string screenshot { get; set; } |
729 | + public string desktop_file { get; set; } |
730 | + public string license { get; set; } |
731 | + public string icon { get; set; } |
732 | + public string price { get; set; } |
733 | + public PackageState pkg_state { get; set; } |
734 | + public string installation_date { get; set; } |
735 | + public string website { get; set; } |
736 | + public int64 size { get; set; } |
737 | + public string hardware_requirements { get; set; } |
738 | + |
739 | + public SoftwareCenterDataProviderProxy () |
740 | + { |
741 | + Bus.watch_name (BusType.SESSION, SCDP_DBUS_NAME, BusNameWatcherFlags.NONE, null, on_sc_dbus_name_vanished); |
742 | + } |
743 | + |
744 | + public void connect_to () throws Error |
745 | + { |
746 | + _service = Bus.get_proxy_sync (BusType.SESSION, SCDP_DBUS_NAME, SCDP_DBUS_PATH); |
747 | + } |
748 | + |
749 | + private void on_sc_dbus_name_vanished (DBusConnection conn, string name) |
750 | + { |
751 | + _service = null; |
752 | + } |
753 | + |
754 | + public HashTable<string, Variant> get_app_details (string appname, string pkgname) throws Error |
755 | + { |
756 | + if (_service == null) |
757 | + connect_to (); |
758 | + |
759 | + HashTable<string, Variant> data = _service.get_app_details (appname, pkgname); |
760 | + |
761 | + name = data["name"].get_string (); |
762 | + summary = data["summary"].get_string (); |
763 | + description = data["description"].get_string (); |
764 | + version = data["version"].get_string (); |
765 | + desktop_file = data["desktop_file"].get_string (); |
766 | + license = data["license"].get_string (); |
767 | + icon = data["icon_file_name"].get_string (); |
768 | + price = data["price"].get_string (); |
769 | + installation_date = data["installation_date"].get_string (); |
770 | + website = data["website"].get_string (); |
771 | + hardware_requirements = data["hardware_requirements"].get_string (); |
772 | + size = int64.parse (data["size"].get_string ()); |
773 | + |
774 | + var state = data["pkg_state"].get_string (); |
775 | + |
776 | + if (state == "installed") |
777 | + { |
778 | + pkg_state = PackageState.INSTALLED; |
779 | + } |
780 | + else if (state == "uninstalled") |
781 | + { |
782 | + pkg_state = PackageState.UNINSTALLED; |
783 | + } |
784 | + else if (state == "needs_purchase") |
785 | + { |
786 | + pkg_state = PackageState.NEEDS_PURCHASE; |
787 | + } |
788 | + else |
789 | + { |
790 | + pkg_state = PackageState.UNKNOWN; |
791 | + } |
792 | + |
793 | + screenshot = null; |
794 | + |
795 | + if (data.contains ("screenshots")) |
796 | + { |
797 | + var screenshot_var = data["screenshots"].get_child_value (0).lookup_value ("large_image_url", VariantType.STRING); |
798 | + if (screenshot_var != null) |
799 | + { |
800 | + screenshot = screenshot_var.get_string (); |
801 | + } |
802 | + } |
803 | + if (screenshot == null) |
804 | + { |
805 | + screenshot = ""; |
806 | + } |
807 | + return data; |
808 | + } |
809 | + |
810 | + private SoftwareCenterDataProviderService _service; |
811 | + } |
812 | +} |
813 | |
814 | === modified file 'src/unity-package-search.cc' |
815 | --- src/unity-package-search.cc 2012-03-27 10:49:37 +0000 |
816 | +++ src/unity-package-search.cc 2012-08-16 08:33:21 +0000 |
817 | @@ -50,6 +50,9 @@ |
818 | #define XAPIAN_VALUE_SUMMARY 177 |
819 | #define XAPIAN_VALUE_ARCHIVE_CHANNEL 178 |
820 | #define XAPIAN_VALUE_DESKTOP_FILE 179 |
821 | +#define XAPIAN_VALUE_SCREENSHOT_URLS 185 |
822 | +#define XAPIAN_VALUE_DESCRIPTION 188 |
823 | +#define XAPIAN_VALUE_VERSION_INFO 198 |
824 | |
825 | #include "unity-package-search.h" |
826 | |
827 | @@ -72,16 +75,16 @@ |
828 | { |
829 | private: |
830 | Xapian::valueno value; |
831 | - |
832 | + |
833 | public: |
834 | - |
835 | + |
836 | LocaleKeyMaker (Xapian::valueno value) |
837 | { |
838 | this->value = value; |
839 | } |
840 | - |
841 | + |
842 | virtual ~LocaleKeyMaker() { } |
843 | - |
844 | + |
845 | virtual std::string operator() (const Xapian::Document &doc) const |
846 | { |
847 | string val = doc.get_value (value); |
848 | @@ -89,21 +92,21 @@ |
849 | string col_key_mm = col_key_c; |
850 | g_free (col_key_c); |
851 | return col_key_mm; |
852 | - } |
853 | + } |
854 | }; |
855 | |
856 | /* Do generic searcher setup */ |
857 | static void |
858 | init_searcher (UnityPackageSearcher *searcher) |
859 | { |
860 | - // Activate Xapian CJK support |
861 | + // Activate Xapian CJK support |
862 | setenv("XAPIAN_CJK_NGRAM", "1", 1); |
863 | |
864 | - Xapian::Database db = *searcher->db; |
865 | + Xapian::Database db = *searcher->db; |
866 | |
867 | // Start an enquire session |
868 | Xapian::Enquire *enquire = new Xapian::Enquire (db); |
869 | - //enquire->set_sort_by_value (XAPIAN_VALUE_APPNAME, FALSE); |
870 | + enquire->set_sort_by_value (XAPIAN_VALUE_APPNAME, FALSE); |
871 | searcher->enquire = enquire; |
872 | |
873 | // Make sure we respect sorting rules for the current locale |
874 | @@ -122,7 +125,7 @@ |
875 | query_parser->set_default_op (Xapian::Query::OP_AND); |
876 | query_parser->set_database (db); |
877 | searcher->query_parser = query_parser; |
878 | - |
879 | + |
880 | // Init random number generator from 32 lowest bits of system time |
881 | searcher->random = g_rand_new_with_seed (g_get_monotonic_time ()); |
882 | } |
883 | @@ -141,39 +144,39 @@ |
884 | gchar *dum1, *dum2, *dum3; |
885 | gint i, len; |
886 | |
887 | - g_return_if_fail (db != NULL); |
888 | - g_return_if_fail (indexer != NULL); |
889 | - g_return_if_fail (item != NULL); |
890 | - |
891 | - switch (gmenu_tree_item_get_type (item)) |
892 | - { |
893 | - case GMENU_TREE_ITEM_INVALID: |
894 | - return; |
895 | - case GMENU_TREE_ITEM_DIRECTORY: |
896 | - /* Recurse into directory */ |
897 | - iter = gmenu_tree_directory_get_contents (GMENU_TREE_DIRECTORY (item)); |
898 | - for (; iter != NULL; iter = iter->next) |
899 | - { |
900 | - index_menu_item (db, indexer, GMENU_TREE_ITEM (iter->data)); |
901 | - } |
902 | - break; |
903 | - case GMENU_TREE_ITEM_ENTRY: |
904 | - /* Add this entry to the index */ |
905 | - entry = GMENU_TREE_ENTRY (item); |
906 | - |
907 | - /* Store relevant values */ |
908 | - if (gmenu_tree_entry_get_display_name (entry)) |
909 | - doc.add_value (XAPIAN_VALUE_APPNAME, |
910 | - gmenu_tree_entry_get_display_name (entry)); |
911 | - if (gmenu_tree_entry_get_icon (entry)) |
912 | + g_return_if_fail (db != NULL); |
913 | + g_return_if_fail (indexer != NULL); |
914 | + g_return_if_fail (item != NULL); |
915 | + |
916 | + switch (gmenu_tree_item_get_type (item)) |
917 | + { |
918 | + case GMENU_TREE_ITEM_INVALID: |
919 | + return; |
920 | + case GMENU_TREE_ITEM_DIRECTORY: |
921 | + /* Recurse into directory */ |
922 | + iter = gmenu_tree_directory_get_contents (GMENU_TREE_DIRECTORY (item)); |
923 | + for (; iter != NULL; iter = iter->next) |
924 | + { |
925 | + index_menu_item (db, indexer, GMENU_TREE_ITEM (iter->data)); |
926 | + } |
927 | + break; |
928 | + case GMENU_TREE_ITEM_ENTRY: |
929 | + /* Add this entry to the index */ |
930 | + entry = GMENU_TREE_ENTRY (item); |
931 | + |
932 | + /* Store relevant values */ |
933 | + if (gmenu_tree_entry_get_display_name (entry)) |
934 | + doc.add_value (XAPIAN_VALUE_APPNAME, |
935 | + gmenu_tree_entry_get_display_name (entry)); |
936 | + if (gmenu_tree_entry_get_icon (entry)) |
937 | doc.add_value (XAPIAN_VALUE_ICON, |
938 | gmenu_tree_entry_get_icon (entry)); |
939 | if (gmenu_tree_entry_get_desktop_file_id (entry)) |
940 | doc.add_value (XAPIAN_VALUE_DESKTOP_FILE, |
941 | gmenu_tree_entry_get_desktop_file_id (entry)); |
942 | - |
943 | - /* Index full text data */ |
944 | - indexer->set_document(doc); |
945 | + |
946 | + /* Index full text data */ |
947 | + indexer->set_document(doc); |
948 | if (gmenu_tree_entry_get_display_name (entry)) |
949 | { |
950 | dum1 = unity_applications_lens_utils_preprocess_string ( |
951 | @@ -195,56 +198,56 @@ |
952 | indexer->index_text (dum1, 0); |
953 | g_free (dum1); |
954 | } |
955 | - |
956 | - /* Index the XDG categories */ |
957 | - appman = unity_app_info_manager_get_default (); |
958 | - cats = unity_app_info_manager_get_categories (appman, // const return |
959 | - gmenu_tree_entry_get_desktop_file_id (entry), |
960 | - &len); |
961 | - |
962 | - /* Note: Wine apps and app launchers created with Alacarte commonly |
963 | - * don't have any category metadata, so they'll only show up under |
964 | - * All Applications */ |
965 | - for (i = 0; i < len; i++) |
966 | - { |
967 | - dum1 = g_ascii_strdown (cats[i], -1); |
968 | - dum2 = g_strconcat ("AC", dum1, NULL); |
969 | - doc.add_term (dum2); |
970 | - g_free (dum1); |
971 | - g_free (dum2); |
972 | - } |
973 | - |
974 | - /* Index Keywords*/ |
975 | - keywords = unity_app_info_manager_get_keywords (appman, // const return |
976 | - gmenu_tree_entry_get_desktop_file_id (entry), |
977 | - &len); |
978 | - for (i = 0; i < len; i++) |
979 | - { |
980 | + |
981 | + /* Index the XDG categories */ |
982 | + appman = unity_app_info_manager_get_default (); |
983 | + cats = unity_app_info_manager_get_categories (appman, // const return |
984 | + gmenu_tree_entry_get_desktop_file_id (entry), |
985 | + &len); |
986 | + |
987 | + /* Note: Wine apps and app launchers created with Alacarte commonly |
988 | + * don't have any category metadata, so they'll only show up under |
989 | + * All Applications */ |
990 | + for (i = 0; i < len; i++) |
991 | + { |
992 | + dum1 = g_ascii_strdown (cats[i], -1); |
993 | + dum2 = g_strconcat ("AC", dum1, NULL); |
994 | + doc.add_term (dum2); |
995 | + g_free (dum1); |
996 | + g_free (dum2); |
997 | + } |
998 | + |
999 | + /* Index Keywords*/ |
1000 | + keywords = unity_app_info_manager_get_keywords (appman, // const return |
1001 | + gmenu_tree_entry_get_desktop_file_id (entry), |
1002 | + &len); |
1003 | + for (i = 0; i < len; i++) |
1004 | + { |
1005 | dum1 = unity_applications_lens_utils_preprocess_string (keywords[i]); |
1006 | - indexer->index_text (dum1, 0); |
1007 | - indexer->index_text (dum1, 0, "KW"); |
1008 | + indexer->index_text (dum1, 0); |
1009 | + indexer->index_text (dum1, 0, "KW"); |
1010 | g_free (dum1); |
1011 | - } |
1012 | - |
1013 | - |
1014 | - g_object_unref (appman); |
1015 | - |
1016 | - /* Always assume Type=Application for items in a menu... */ |
1017 | - doc.add_term ("ATapplication"); |
1018 | - |
1019 | - /* Index application names */ |
1020 | - dum1 = (gchar *) gmenu_tree_entry_get_display_name (entry); // const |
1021 | - dum2 = g_strconcat ("AA", dum1, NULL); |
1022 | + } |
1023 | + |
1024 | + |
1025 | + g_object_unref (appman); |
1026 | + |
1027 | + /* Always assume Type=Application for items in a menu... */ |
1028 | + doc.add_term ("ATapplication"); |
1029 | + |
1030 | + /* Index application names */ |
1031 | + dum1 = (gchar *) gmenu_tree_entry_get_display_name (entry); // const |
1032 | + dum2 = g_strconcat ("AA", dum1, NULL); |
1033 | doc.add_term (dum2); |
1034 | g_free (dum2); |
1035 | - |
1036 | + |
1037 | dum1 = (gchar *) gmenu_tree_entry_get_name (entry); // const |
1038 | - dum2 = g_strconcat ("AA", dum1, NULL); |
1039 | + dum2 = g_strconcat ("AA", dum1, NULL); |
1040 | doc.add_term (dum2); |
1041 | g_free (dum2); |
1042 | |
1043 | /* Index executable name, change - in _ for exec */ |
1044 | - dum1 = g_strdup (gmenu_tree_entry_get_exec (entry)); // alloc |
1045 | + dum1 = g_strdup (gmenu_tree_entry_get_exec (entry)); // alloc |
1046 | if (dum1) { |
1047 | dum2 = strstr (dum1, " "); // const |
1048 | dum2 == NULL ? : *dum2 = '\0'; // const |
1049 | @@ -256,25 +259,25 @@ |
1050 | doc.add_term (dum2); |
1051 | g_free (dum2); |
1052 | dum2 = g_strconcat ("XX", dum1, NULL); // alloc |
1053 | - doc.add_term (dum2); |
1054 | + doc.add_term (dum2); |
1055 | g_free (dum2); |
1056 | - g_free (dum1); |
1057 | - } |
1058 | - |
1059 | + g_free (dum1); |
1060 | + } |
1061 | + |
1062 | db->add_document(doc); |
1063 | - break; |
1064 | - case GMENU_TREE_ITEM_SEPARATOR: |
1065 | - case GMENU_TREE_ITEM_HEADER: |
1066 | - case GMENU_TREE_ITEM_ALIAS: |
1067 | - break; |
1068 | - default: |
1069 | - g_warning ("Unexpected GMenuTreeItemType %u", |
1070 | - gmenu_tree_item_get_type (item)); |
1071 | - return; |
1072 | + break; |
1073 | + case GMENU_TREE_ITEM_SEPARATOR: |
1074 | + case GMENU_TREE_ITEM_HEADER: |
1075 | + case GMENU_TREE_ITEM_ALIAS: |
1076 | + break; |
1077 | + default: |
1078 | + g_warning ("Unexpected GMenuTreeItemType %u", |
1079 | + gmenu_tree_item_get_type (item)); |
1080 | + return; |
1081 | } |
1082 | |
1083 | // Add the document to the database. |
1084 | - |
1085 | + |
1086 | } |
1087 | |
1088 | /* Create a searcher that searches in a menu tree. The menu tree |
1089 | @@ -289,16 +292,16 @@ |
1090 | db = new Xapian::WritableDatabase (); |
1091 | searcher->db = db; |
1092 | searcher->db->add_database (Xapian::InMemory::open ()); |
1093 | - |
1094 | + |
1095 | init_searcher (searcher); |
1096 | - |
1097 | + |
1098 | /* Index the menu recursively */ |
1099 | Xapian::TermGenerator *indexer = new Xapian::TermGenerator (); |
1100 | index_menu_item (db, indexer, |
1101 | GMENU_TREE_ITEM (gmenu_tree_get_root_directory (menu))); |
1102 | delete indexer; |
1103 | db->flush (); |
1104 | - |
1105 | + |
1106 | return searcher; |
1107 | } |
1108 | |
1109 | @@ -373,13 +376,17 @@ |
1110 | static void _free_package_info (gpointer pkg) |
1111 | { |
1112 | UnityPackageInfo *pkginfo = (UnityPackageInfo*) pkg; |
1113 | + unity_package_package_info_free (pkginfo); |
1114 | +} |
1115 | |
1116 | +void unity_package_package_info_free (UnityPackageInfo *pkginfo) |
1117 | +{ |
1118 | g_free (pkginfo->package_name); |
1119 | g_free (pkginfo->application_name); |
1120 | g_free (pkginfo->desktop_file); |
1121 | g_free (pkginfo->icon); |
1122 | |
1123 | - g_slice_free (UnityPackageInfo, pkg); |
1124 | + g_slice_free (UnityPackageInfo, pkginfo); |
1125 | } |
1126 | |
1127 | UnityPackageSearchResult* |
1128 | @@ -432,7 +439,7 @@ |
1129 | searcher->enquire->set_sort_by_relevance (); |
1130 | break; |
1131 | } |
1132 | - |
1133 | + |
1134 | result = g_slice_new0 (UnityPackageSearchResult); |
1135 | try |
1136 | { |
1137 | @@ -470,7 +477,7 @@ |
1138 | { |
1139 | g_warning ("Error running query '%s': %s", search_string, e.get_msg().c_str()); |
1140 | } |
1141 | - |
1142 | + |
1143 | return result; |
1144 | } |
1145 | |
1146 | @@ -486,12 +493,12 @@ |
1147 | g_return_val_if_fail (searcher != NULL, NULL); |
1148 | |
1149 | result = g_slice_new0 (UnityPackageSearchResult); |
1150 | - result->num_hits = n_apps; |
1151 | + result->num_hits = n_apps; |
1152 | lastdocid = searcher->db->get_lastdocid (); |
1153 | - |
1154 | + |
1155 | /* Since we really just pick random apps we may end up with dupes */ |
1156 | unique = g_hash_table_new (g_str_hash, g_str_equal); |
1157 | - |
1158 | + |
1159 | /* When looking for random apps we check up to twice the number of |
1160 | * requested apps in order to try and avoid dupes. This is a sloppy |
1161 | * check, but works well enough in practice */ |
1162 | @@ -499,7 +506,7 @@ |
1163 | { |
1164 | g_debug ("RANDOM"); |
1165 | for (i = 0, n_unique = 0; i < n_apps*2, n_unique < n_apps; i++) |
1166 | - { |
1167 | + { |
1168 | Xapian::Document doc; |
1169 | try |
1170 | { |
1171 | @@ -566,6 +573,38 @@ |
1172 | return result; |
1173 | } |
1174 | |
1175 | +UnityPackageInfo * |
1176 | +unity_package_searcher_get_by_desktop_file (UnityPackageSearcher *searcher, const gchar *desktop_file) |
1177 | +{ |
1178 | + g_return_val_if_fail (searcher != NULL, NULL); |
1179 | + |
1180 | + UnityPackageInfo *pkginfo = NULL; |
1181 | + |
1182 | + Xapian::PostingIterator it = searcher->db->postlist_begin (""); |
1183 | + Xapian::PostingIterator end_it = searcher->db->postlist_end (""); |
1184 | + |
1185 | + const string query = desktop_file; |
1186 | + |
1187 | + while (it != end_it) |
1188 | + { |
1189 | + Xapian::Document doc = searcher->db->get_document (*it); |
1190 | + string value = doc.get_value (XAPIAN_VALUE_DESKTOP_FILE); |
1191 | + |
1192 | + size_t sep = value.find (':'); |
1193 | + if (sep != string::npos) |
1194 | + { |
1195 | + if (value.compare (sep+1, value.size() - sep, query) == 0) |
1196 | + { |
1197 | + pkginfo = _pkginfo_from_document (doc); |
1198 | + return pkginfo; |
1199 | + } |
1200 | + } |
1201 | + ++it; |
1202 | + } |
1203 | + |
1204 | + return pkginfo; |
1205 | +} |
1206 | + |
1207 | void |
1208 | unity_package_search_result_free (UnityPackageSearchResult *result) |
1209 | { |
1210 | @@ -574,4 +613,3 @@ |
1211 | g_slist_free_full (result->results, _free_package_info); |
1212 | g_slice_free (UnityPackageSearchResult, result); |
1213 | } |
1214 | - |
1215 | |
1216 | === modified file 'src/unity-package-search.h' |
1217 | --- src/unity-package-search.h 2012-03-09 17:44:30 +0000 |
1218 | +++ src/unity-package-search.h 2012-08-16 08:33:21 +0000 |
1219 | @@ -36,23 +36,23 @@ |
1220 | |
1221 | typedef struct |
1222 | { |
1223 | - GSList *results; |
1224 | - gint num_hits; |
1225 | + GSList *results; |
1226 | + gint num_hits; |
1227 | } UnityPackageSearchResult; |
1228 | |
1229 | typedef struct |
1230 | { |
1231 | - gchar *package_name; |
1232 | - gchar *application_name; |
1233 | - gchar *desktop_file; |
1234 | - gchar *icon; |
1235 | - gint relevancy; |
1236 | + gchar *package_name; |
1237 | + gchar *application_name; |
1238 | + gchar *desktop_file; |
1239 | + gchar *icon; |
1240 | + gint relevancy; |
1241 | } UnityPackageInfo; |
1242 | |
1243 | #ifdef __cplusplus |
1244 | extern "C" { |
1245 | #endif |
1246 | - |
1247 | + |
1248 | UnityPackageSearcher* unity_package_searcher_new (); |
1249 | |
1250 | UnityPackageSearcher* unity_package_searcher_new_for_menu (GMenuTree *menu); |
1251 | @@ -71,7 +71,10 @@ |
1252 | |
1253 | void unity_package_search_result_free (UnityPackageSearchResult *result); |
1254 | |
1255 | +void unity_package_package_info_free (UnityPackageInfo *pkginfo); |
1256 | + |
1257 | +UnityPackageInfo* unity_package_searcher_get_by_desktop_file (UnityPackageSearcher *searcher, const gchar *desktop_file); |
1258 | + |
1259 | #ifdef __cplusplus |
1260 | } |
1261 | #endif |
1262 | - |
1263 | |
1264 | === modified file 'vapi/unity-package-search.vapi' |
1265 | --- vapi/unity-package-search.vapi 2012-03-09 17:44:30 +0000 |
1266 | +++ vapi/unity-package-search.vapi 2012-08-16 08:33:21 +0000 |
1267 | @@ -27,6 +27,7 @@ |
1268 | public Searcher.for_menu(GMenu.Tree menu); |
1269 | public SearchResult search (string search_string, uint max_hits, Unity.Package.SearchType search_type, Unity.Package.Sort sort); |
1270 | public SearchResult get_random_apps (string? filter_query, uint n_apps); |
1271 | + public PackageInfo? get_by_desktop_file (string desktop_file); |
1272 | } |
1273 | |
1274 | [Compact] |
1275 | @@ -37,7 +38,7 @@ |
1276 | } |
1277 | |
1278 | [Compact] |
1279 | - [CCode (cname = "UnityPackageInfo", cheader_filename = "unity-package-search.h")] |
1280 | + [CCode (cname = "UnityPackageInfo", free_function = "unity_package_package_info_free", cheader_filename = "unity-package-search.h")] |
1281 | public class PackageInfo { |
1282 | public string package_name; |
1283 | public string application_name; |
434 + sc_data_provider = new SoftwareCenterD ataProviderProx y ();
Can we cache this? It's not nice that the proxy is re-created every time.
633 + public HashTable<string, Variant> get_app_details (string appname, string pkgname)
Should be propagating the error that can happen.
637 + name = data.get ("name").get_string ();
The awesome thing about vala's get method is that it's an alias for indexing - ie. `name = data["name" ].get_string ();` Doesn't that look much nicer? :)
459 + preview.add_info (new InfoHint. with_variant ("size", _("Size"), null, new GLib.Variant.int64 (sc_data_ provider. size))) ;
Shouldn't we use the same pretty printing as in files lens?
463 + preview.add_info (new InfoHint ("price", _("Price"), null, sc_data_ provider. price)) ;
I think we shouldn't add hints if they're empty.