Merge lp:~gary-lasker/software-center/new-apps-icons into lp:software-center

Proposed by Gary Lasker
Status: Merged
Merged at revision: 995
Proposed branch: lp:~gary-lasker/software-center/new-apps-icons
Merge into: lp:software-center
Diff against target: 531 lines (+184/-94)
13 files modified
apt-xapian-index-plugin/software-center.py (+6/-2)
debian/changelog (+11/-0)
softwarecenter/app.py (+7/-0)
softwarecenter/db/application.py (+22/-1)
softwarecenter/db/database.py (+5/-1)
softwarecenter/db/update.py (+4/-0)
softwarecenter/distro/Ubuntu.py (+17/-0)
softwarecenter/enums.py (+1/-1)
softwarecenter/paths.py (+3/-2)
softwarecenter/utils.py (+44/-0)
softwarecenter/view/appdetailsview_gtk.py (+30/-81)
softwarecenter/view/appview.py (+33/-6)
test/test_appdetails.py (+1/-0)
To merge this branch: bzr merge lp:~gary-lasker/software-center/new-apps-icons
Reviewer Review Type Date Requested Status
Michael Vogt Needs Fixing
Review via email: mp+31803@code.launchpad.net

Description of the change

Hi mvo,

This branch implements the download, local caching and the display in applist and appdetails_gtk views of downloadable icons (currently from the app-review-board PPA specifically). I've tested all the code paths quite thoroughly and it seems to be working quite well.

There's a new generic image downloader in utils.py that is used for downloading the icons. When an icon needs download and is not yet in the local cache directory (or the icon_cache itself) the generic icon is displayed temporarily. The image downloader downloads the image (if available) and stores it in the local cache directory, and fires its image-download-complete event to the corresponding view (applist or appdetails) and the generic icon is updated to the new one.

As I mentioned, I also replaced appdetailsview_gtk's ScreenshotDownloader to use the new generic downloader class. Since it fires the same signals the screenshot thumbnail and full-size views in the details view work exactly as they did before.

One question I had was about where the url string for the LP PPA really ought to be. For now I put it in Ubuntu.py, but I'm not sure that's correct (see FIXME in code). I also hardcoded "app-review-board" currently, not sure if we need more flexibility there yet (esp. since we are going to move to extras.ubuntu.com anyway). So, I'd appreciate your opinion about whether we want to change these things.

Thanks!
Gary

To post a comment you must log in.
Michael Vogt (mvo) wrote :

Thanks for your work on this. Mostly good, I pushed lp:~mvo/software-center/new-apps-icons with some fixes. We need to also get rid of the hardcoded values for the app-review-board ppa url before we can merge it into main.

Note that the gtk.IconTheme will search the local download dir for us if we add it to its search path, this means we don't need some of the custom icon loading code.

review: Needs Fixing
Michael Vogt (mvo) wrote :

We can probably use something like:

>>> cache["daily-journal"].candidate.uri
'http://ppa.launchpad.net/app-review-board/ppa/ubuntu/pool/main/d/daily-journal/daily-journal_10.06.1+newapps2_all.deb'

and look for "pool" in there.

Or alternatively:
>>> pkg._pcache._list.find_index(pkg.candidate._cand.file_list[0][0]).archive_uri("")
'http://ppa.launchpad.net/app-review-board/ppa/ubuntu/'

Gary Lasker (gary-lasker) wrote :

Cool beans!! Thanks mvo, I'll do that.

P.S. I don't know why I have the sudden urge to change my IRC nick from boring old "tremolux" to:

  pkg._pcache._list.find_index(pkg.candidate._cand.file_list[0][0]).archive_uri("")

It just has such a nice...*ring* to it eh!!

:) :)

Michael Vogt (mvo) wrote :

lol

On Thu, 05 Aug 2010 15:22 +0000, "Gary Lasker"
<email address hidden> wrote:
> Cool beans!! Thanks mvo, I'll do that.
>
> P.S. I don't know why I have the sudden urge to change my IRC nick from
> boring old "tremolux" to:
>
> pkg._pcache._list.find_index(pkg.candidate._cand.file_list[0][0]).archive_uri("")
>
> It just has such a nice...*ring* to it eh!!
>
> :) :)
> --
> https://code.launchpad.net/~gary-lasker/software-center/new-apps-icons/+merge/31803
> You are reviewing the proposed merge of
> lp:~gary-lasker/software-center/new-apps-icons into lp:software-center.
>

989. By Gary Lasker on 2010-08-06

merge from lp:~mvo/software-center/new-apps-icons, many thanks

990. By Gary Lasker on 2010-08-09

make icon file downloads work again

991. By Gary Lasker on 2010-08-09

generate the url for a downloadable icon (currently support ppa's only)

992. By Gary Lasker on 2010-08-09

removed unneeded constant

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'apt-xapian-index-plugin/software-center.py'
2--- apt-xapian-index-plugin/software-center.py 2010-08-03 18:25:26 +0000
3+++ apt-xapian-index-plugin/software-center.py 2010-08-09 02:13:42 +0000
4@@ -62,12 +62,13 @@
5 AA for the Application name
6 AP for the Package name
7 AC for the categories
8- AT to "applications" for applications
9+ AT to "application" for applications
10 It sets the following xapian values from the software-center
11 enums:
12 XAPIAN_VALUE_ICON
13 XAPIAN_VALUE_ICON_NEEDS_DOWNLOAD
14 XAPIAN_VALUE_SCREENSHOT_URL
15+ XAPIAN_VALUE_THUMBNAIL_URL
16 """
17 )
18
19@@ -85,7 +86,7 @@
20 if ver is None or not CUSTOM_KEY_APPNAME in ver.record:
21 return
22 # we want to index the following custom fields:
23- # XB-AppName, XB-Icon, XB-Screenshot-Url, XB-Category
24+ # XB-AppName, XB-Icon, XB-Screenshot-Url, XB-Thumbnail-Url, XB-Category
25 if CUSTOM_KEY_APPNAME in ver.record:
26 name = ver.record[CUSTOM_KEY_APPNAME]
27 self.indexer.set_document(document)
28@@ -99,6 +100,9 @@
29 if CUSTOM_KEY_SCREENSHOT_URL in ver.record:
30 screenshot_url = ver.record[CUSTOM_KEY_SCREENSHOT_URL]
31 document.add_value(XAPIAN_VALUE_SCREENSHOT_URL, screenshot_url)
32+ if CUSTOM_KEY_THUMBNAIL_URL in ver.record:
33+ url = ver.record[CUSTOM_KEY_THUMBNAIL_URL]
34+ document.add_value(XAPIAN_VALUE_THUMBNAIL_URL, url)
35 if CUSTOM_KEY_CATEGORY in ver.record:
36 categories_str = ver.record[CUSTOM_KEY_CATEGORY]
37 for cat in categories_str.split(";"):
38
39=== modified file 'debian/changelog'
40--- debian/changelog 2010-08-06 13:39:14 +0000
41+++ debian/changelog 2010-08-09 02:13:42 +0000
42@@ -35,6 +35,17 @@
43 softwarecenter/db/update.py:
44 - implement a-x-i plugin to index custom metadata
45 for the new-apps archive
46+ * softwarecenter/utils.py:
47+ - add generic image downloader class
48+ * softwarecenter/app.py,
49+ softwarecenter/backend/paths.py,
50+ softwarecenter/db/application.py,
51+ softwarecenter/db/database.py,
52+ softwarecenter/distro/Ubuntu.py,
53+ softwarecenter/view/appdetailsview_gtk.py,
54+ softwarecenter/view/appview.py:
55+ - implement download and local caching of downloadable
56+ icons, display them in applist and appdetails views
57
58 -- Michael Vogt <michael.vogt@ubuntu.com> Fri, 06 Aug 2010 11:06:53 +0200
59
60
61=== modified file 'softwarecenter/app.py'
62--- softwarecenter/app.py 2010-08-05 13:15:01 +0000
63+++ softwarecenter/app.py 2010-08-09 02:13:42 +0000
64@@ -52,6 +52,7 @@
65
66 from backend.config import get_config
67 from backend import get_install_backend
68+from paths import SOFTWARE_CENTER_ICON_CACHE_DIR
69
70 from plugin import PluginManager
71
72@@ -323,6 +324,12 @@
73 # open plugin manager and load plugins
74 self.plugin_manager = PluginManager(self, SOFTWARE_CENTER_PLUGIN_DIR)
75 self.plugin_manager.load_plugins()
76+
77+ # make the local cache directory if it doesn't already exist
78+ icon_cache_dir = SOFTWARE_CENTER_ICON_CACHE_DIR
79+ if not os.path.exists(icon_cache_dir):
80+ os.makedirs(icon_cache_dir)
81+ self.icons.append_search_path(icon_cache_dir)
82
83 # run s-c-agent update
84 if options.enable_buy:
85
86=== modified file 'softwarecenter/db/application.py'
87--- softwarecenter/db/application.py 2010-08-05 09:57:22 +0000
88+++ softwarecenter/db/application.py 2010-08-09 02:13:42 +0000
89@@ -177,6 +177,20 @@
90 return os.path.splitext(self._db.get_iconname(self._doc))[0]
91 if not self.summary:
92 return MISSING_PKG_ICON
93+
94+ @property
95+ def icon_file_name(self):
96+ if self._doc:
97+ return self._db.get_iconname(self._doc)
98+
99+ @property
100+ def icon_needs_download(self):
101+ if self._doc:
102+ return self._db.get_icon_needs_download(self._doc)
103+
104+ @property
105+ def icon_url(self):
106+ return self._distro.get_downloadable_icon_url(self._cache, self.pkgname, self.icon_file_name)
107
108 @property
109 def installation_date(self):
110@@ -316,7 +330,7 @@
111 return self._doc.get_value(XAPIAN_VALUE_SCREENSHOT_URL)
112 # else use the default
113 return self._distro.SCREENSHOT_LARGE_URL % self.pkgname
114-
115+
116 @property
117 def summary(self):
118 if self._doc:
119@@ -324,6 +338,10 @@
120
121 @property
122 def thumbnail(self):
123+ # if there is a custom thumbnail url provided, use that
124+ if self._doc.get_value(XAPIAN_VALUE_THUMBNAIL_URL):
125+ return self._doc.get_value(XAPIAN_VALUE_THUMBNAIL_URL)
126+ # else use the default
127 return self._distro.SCREENSHOT_THUMB_URL % self.pkgname
128
129 @property
130@@ -390,6 +408,9 @@
131 details.append(" component: %s" % self.component)
132 details.append(" description: %s" % self.description)
133 details.append(" icon: %s" % self.icon)
134+ details.append(" icon_file_name: %s" % self.icon_file_name)
135+ details.append(" icon_needs_download: %s" % self.icon_needs_download)
136+ details.append(" icon_url: %s" % self.icon_url)
137 details.append(" installation_date: %s" % self.installation_date)
138 details.append(" purchase_date: %s" % self.purchase_date)
139 details.append(" license: %s" % self.license)
140
141=== modified file 'softwarecenter/db/database.py'
142--- softwarecenter/db/database.py 2010-08-02 12:56:50 +0000
143+++ softwarecenter/db/database.py 2010-08-09 02:13:42 +0000
144@@ -241,7 +241,11 @@
145 """ Return the iconname from the xapian document """
146 iconname = doc.get_value(XAPIAN_VALUE_ICON)
147 return iconname
148-
149+
150+ def get_icon_needs_download(self, doc):
151+ """ Return a value if the icon needs to be downloaded """
152+ return doc.get_value(XAPIAN_VALUE_ICON_NEEDS_DOWNLOAD)
153+
154 def get_popcon(self, doc):
155 """ Return a popcon value from a xapian document """
156 popcon_raw = doc.get_value(XAPIAN_VALUE_POPCON)
157
158=== modified file 'softwarecenter/db/update.py'
159--- softwarecenter/db/update.py 2010-08-04 16:02:36 +0000
160+++ softwarecenter/db/update.py 2010-08-09 02:13:42 +0000
161@@ -451,6 +451,10 @@
162 if parser.has_option_desktop("X-AppInstall-Screenshot-Url"):
163 url = parser.get_desktop("X-AppInstall-Screenshot-Url")
164 doc.add_value(XAPIAN_VALUE_SCREENSHOT_URL, url)
165+ # thumbnail (for third party)
166+ if parser.has_option_desktop("X-AppInstall-Thumbnail-Url"):
167+ url = parser.get_desktop("X-AppInstall-Thumbnail-Url")
168+ doc.add_value(XAPIAN_VALUE_THUMBNAIL_URL, url)
169 # price (pay stuff)
170 if parser.has_option_desktop("X-AppInstall-Price"):
171 price = parser.get_desktop("X-AppInstall-Price")
172
173=== modified file 'softwarecenter/distro/Ubuntu.py'
174--- softwarecenter/distro/Ubuntu.py 2010-08-05 13:59:02 +0000
175+++ softwarecenter/distro/Ubuntu.py 2010-08-09 02:13:42 +0000
176@@ -200,6 +200,23 @@
177 "Some updates may be provided by the "
178 "Ubuntu community.") % appname
179 return _("Application %s has an unknown maintenance status.") % appname
180+
181+ def get_downloadable_icon_url(self, cache, pkgname, icon_filename):
182+ """
183+ generates the url for a downloadable icon based on its pkgname and the icon filename itself
184+ """
185+ full_archive_url = cache[pkgname].candidate.uri
186+ split_at_pool = full_archive_url.split("pool")[0]
187+ if split_at_pool.endswith("/ppa/ubuntu/"):
188+ # it's a ppa, generate the icon_url for a ppa
189+ split_at_ppa = split_at_pool.split("/ppa/")[0]
190+ downloadable_icon_url = []
191+ downloadable_icon_url.append(split_at_ppa)
192+ downloadable_icon_url.append("/meta/ppa/")
193+ downloadable_icon_url.append(icon_filename)
194+ return "".join(downloadable_icon_url)
195+ else:
196+ raise ValueError, "we currently support downloadable icons in ppa's only"
197
198
199 if __name__ == "__main__":
200
201=== modified file 'softwarecenter/enums.py'
202--- softwarecenter/enums.py 2010-08-06 13:39:14 +0000
203+++ softwarecenter/enums.py 2010-08-09 02:13:42 +0000
204@@ -84,7 +84,7 @@
205 XAPIAN_VALUE_PURCHASED_DATE = 184
206 XAPIAN_VALUE_SCREENSHOT_URL = 185
207 XAPIAN_VALUE_ICON_NEEDS_DOWNLOAD = 186
208-
209+XAPIAN_VALUE_THUMBNAIL_URL = 187
210
211 # fake channels
212 PURCHASED_NEEDS_REINSTALL_MAGIC_CHANNEL_NAME = "for-pay-needs-reinstall"
213
214=== renamed file 'softwarecenter/backend/paths.py' => 'softwarecenter/paths.py'
215--- softwarecenter/backend/paths.py 2010-07-15 19:56:57 +0000
216+++ softwarecenter/paths.py 2010-08-09 02:13:42 +0000
217@@ -20,6 +20,7 @@
218
219 from xdg import BaseDirectory as xdg
220
221-SOFTWARE_CENTER_CONFIG_DIR = os.path.join(xdg.xdg_config_home, "softwarecenter")
222-SOFTWARE_CENTER_CACHE_DIR = os.path.join(xdg.xdg_cache_home, "softwarecenter")
223+SOFTWARE_CENTER_CONFIG_DIR = os.path.join(xdg.xdg_config_home, "software-center")
224+SOFTWARE_CENTER_CACHE_DIR = os.path.join(xdg.xdg_cache_home, "software-center")
225 SOFTWARE_CENTER_CONFIG_FILE = os.path.join(SOFTWARE_CENTER_CONFIG_DIR, "softwarecenter.cfg")
226+SOFTWARE_CENTER_ICON_CACHE_DIR = os.path.join(SOFTWARE_CENTER_CACHE_DIR, "icons")
227
228=== modified file 'softwarecenter/utils.py'
229--- softwarecenter/utils.py 2010-08-02 12:56:50 +0000
230+++ softwarecenter/utils.py 2010-08-09 02:13:42 +0000
231@@ -23,6 +23,9 @@
232 import urllib
233 import time
234 import xml.sax.saxutils
235+import gobject
236+import gio
237+import glib
238
239 from enums import USER_AGENT
240
241@@ -166,6 +169,47 @@
242 import apt_pkg
243 name = "%s.list" % apt_pkg.URItoFileName(entry.uri)
244 return name
245+
246+class ImageDownloader(gobject.GObject):
247+
248+ __gsignals__ = {
249+ "image-url-reachable" : (gobject.SIGNAL_RUN_LAST,
250+ gobject.TYPE_NONE,
251+ (bool,),),
252+
253+ "image-download-complete" : (gobject.SIGNAL_RUN_LAST,
254+ gobject.TYPE_NONE,
255+ (str,),),
256+ }
257+
258+ def download_image(self, url, dest_file_path):
259+ self.url = url
260+ self.dest_file_path = dest_file_path
261+ f = gio.File(url)
262+ # first check if the url is reachable
263+ f.query_info_async(gio.FILE_ATTRIBUTE_STANDARD_SIZE,
264+ self._check_url_reachable_cb)
265+
266+ def _check_url_reachable_cb(self, f, result):
267+ try:
268+ result = f.query_info_finish(result)
269+ self.emit('image-url-reachable', True)
270+ # url is reachable, now download the icon file
271+ f.load_contents_async(self._icon_download_complete_cb)
272+ except glib.GError, e:
273+ self.emit('image-url-reachable', False)
274+ del f
275+
276+ def _icon_download_complete_cb(self, f, result, path=None):
277+ # The result from the download is actually a tuple with three elements.
278+ # The first element is the actual content so let's grab that
279+ content = f.load_contents_finish(result)[0]
280+ outputfile = open(self.dest_file_path, "w")
281+ outputfile.write(content)
282+ outputfile.flush()
283+ outputfile.close()
284+ self.emit('image-download-complete', self.dest_file_path)
285+
286
287 if __name__ == "__main__":
288 s = decode_xml_char_reference('Search&#x2026;')
289
290=== modified file 'softwarecenter/view/appdetailsview_gtk.py'
291--- softwarecenter/view/appdetailsview_gtk.py 2010-08-05 20:32:52 +0000
292+++ softwarecenter/view/appdetailsview_gtk.py 2010-08-09 02:13:42 +0000
293@@ -35,6 +35,8 @@
294 from softwarecenter.backend import get_install_backend
295 from softwarecenter.db.application import AppDetails
296 from softwarecenter.enums import *
297+from softwarecenter.paths import SOFTWARE_CENTER_ICON_CACHE_DIR
298+from softwarecenter.utils import ImageDownloader
299
300 from appdetailsview import AppDetailsViewBase
301
302@@ -453,68 +455,7 @@
303 def set_support_status(self, support_status):
304 self.support_label.set_text(support_status)
305 return
306-
307-
308-class ScreenshotDownloader(gobject.GObject):
309-
310- __gsignals__ = {
311- "url-reachable" : (gobject.SIGNAL_RUN_LAST,
312- gobject.TYPE_NONE,
313- (bool,),),
314-
315- "download-complete" : (gobject.SIGNAL_RUN_LAST,
316- gobject.TYPE_NONE,
317- (str,),),
318- }
319-
320-
321- def __init__(self):
322- gobject.GObject.__init__(self)
323- self._tmpfile = None
324- return
325-
326- def _actually_download_screenshot(self, file, url):
327-
328- def download_complete_cb(file, result, path=None):
329- """Helper called after the file has downloaded"""
330-
331- # The result from the download is actually a tuple with three elements.
332- # The first element is the actual content so let's grab that
333- content = file.load_contents_finish(result)[0]
334-
335- # let's now save the content to the tmp dir
336- if path is None:
337- self._tmpfile = tempfile.NamedTemporaryFile(prefix="s-c-screenshot")
338- path = self._tmpfile.name
339- outputfile = open(path, "w")
340- outputfile.write(content)
341-
342- self.emit('download-complete', path)
343- return
344-
345- file.load_contents_async(download_complete_cb)
346- return
347-
348- def download_from_url(self, url):
349-
350- def query_complete_cb(file, result):
351- try:
352- result = file.query_info_finish(result)
353- self.emit('url-reachable', True)
354- self._actually_download_screenshot(file, url)
355- except glib.GError, e:
356- self.emit('url-reachable', False)
357-
358- del file
359- return
360-
361- # use gio (its so nice)
362- file=gio.File(url)
363- file.query_info_async(gio.FILE_ATTRIBUTE_STANDARD_SIZE,
364- query_complete_cb)
365- return
366-
367-gobject.type_register(ScreenshotDownloader)
368+
369
370 class ScreenshotView(gtk.Alignment):
371
372@@ -585,9 +526,9 @@
373 self.alpha = 0.0
374
375 # convienience class for handling the downloading (or not) of any screenshot
376- self.loader = ScreenshotDownloader()
377- self.loader.connect('url-reachable', self._on_screenshot_query_complete)
378- self.loader.connect('download-complete', self._on_screenshot_download_complete)
379+ self.loader = ImageDownloader()
380+ self.loader.connect('image-url-reachable', self._on_screenshot_query_complete)
381+ self.loader.connect('image-download-complete', self._on_screenshot_download_complete)
382 return
383
384 # signal handlers
385@@ -766,10 +707,11 @@
386 """ Download then displays the screenshot.
387 This actually does a query on the URL first to check if its
388 reachable, if so it downloads the thumbnail.
389- If not, it emits "url-reachable" False, then exits.
390+ If not, it emits "image-url-reachable" False, then exits.
391 """
392
393- self.loader.download_from_url(self.thumbnail_url)
394+ self.loader.download_image(self.thumbnail_url,
395+ tempfile.NamedTemporaryFile(prefix="s-c-screenshot").name)
396 return
397
398 def draw(self, cr, a, expose_area):
399@@ -1059,17 +1001,10 @@
400
401 # set app- icon, name and summary in the header
402 self.app_info.set_label(markup=markup)
403- icon = None
404- if app_details.icon:
405- if self.icons.has_icon(app_details.icon):
406- icon = app_details.icon
407- if not icon:
408- icon = MISSING_APP_ICON
409-
410+
411+ pb = self._get_icon_as_pixbuf(app_details)
412 # should we show the green tick?
413 self._show_overlay = app_details.pkg_state == PKG_STATE_INSTALLED
414-
415- pb = self.icons.load_icon(icon, 84, 0)
416 self.app_info.set_icon_from_pixbuf(pb)
417
418 # depending on pkg install state set action labels
419@@ -1282,12 +1217,26 @@
420
421 cr.restore()
422 return
423+
424+ def _get_icon_as_pixbuf(self, app_details):
425+ icon = None
426+ if app_details.icon:
427+ if self.icons.has_icon(app_details.icon):
428+ return self.icons.load_icon(app_details.icon, 84, 0)
429+ elif app_details.icon_needs_download:
430+ self._logger.debug("did not find the icon locally, must download it")
431
432- def get_icon_filename(self, iconname, iconsize):
433- iconinfo = self.icons.lookup_icon(iconname, iconsize, 0)
434- if not iconinfo:
435- iconinfo = self.icons.lookup_icon(MISSING_APP_ICON, iconsize, 0)
436- return iconinfo.get_filename()
437+ def on_image_download_complete(downloader, image_file_path):
438+ # when the download is complete, replace the icon in the view with the downloaded one
439+ pb = gtk.gdk.pixbuf_new_from_file(image_file_path)
440+ self.app_info.set_icon_from_pixbuf(pb)
441+
442+ icon_file_path = os.path.join(SOFTWARE_CENTER_ICON_CACHE_DIR, app_details.icon_file_name)
443+ image_downloader = ImageDownloader()
444+ image_downloader.connect('image-download-complete', on_image_download_complete)
445+ image_downloader.download_image(app_details.icon_url, icon_file_path)
446+
447+ return self.icons.load_icon(MISSING_APP_ICON, 84, 0)
448
449
450 if __name__ == "__main__":
451
452=== modified file 'softwarecenter/view/appview.py'
453--- softwarecenter/view/appview.py 2010-08-06 09:08:16 +0000
454+++ softwarecenter/view/appview.py 2010-08-09 02:13:42 +0000
455@@ -42,6 +42,7 @@
456 from softwarecenter.utils import *
457 from softwarecenter.db.database import StoreDatabase, Application
458 from softwarecenter.backend import get_install_backend
459+from softwarecenter.paths import SOFTWARE_CENTER_ICON_CACHE_DIR
460 from softwarecenter.distro import get_distro
461 from widgets.mkit import get_em_value
462 from gtk import gdk
463@@ -427,6 +428,23 @@
464 self._existing_apps = None
465 self._installable_apps = None
466
467+
468+ def _download_icon_and_show_when_ready(self, cache, pkgname, icon_file_name):
469+ self._logger.debug("did not find the icon locally, must download %s" % icon_file_name)
470+ def on_image_download_complete(downloader, image_file_path):
471+ pb = gtk.gdk.pixbuf_new_from_file_at_size(icon_file_path,
472+ self.icon_size,
473+ self.icon_size)
474+ # replace the icon in the icon_cache now that we've got the real one
475+ icon_file = os.path.splitext(os.path.basename(image_file_path))[0]
476+ self.icon_cache[icon_file] = pb
477+
478+ url = get_distro().get_downloadable_icon_url(cache, pkgname, icon_file_name)
479+ icon_file_path = os.path.join(SOFTWARE_CENTER_ICON_CACHE_DIR, icon_file_name)
480+ image_downloader = ImageDownloader()
481+ image_downloader.connect('image-download-complete', on_image_download_complete)
482+ image_downloader.download_image(url, icon_file_path)
483+
484 # GtkTreeModel functions
485 def on_get_flags(self):
486 return (gtk.TREE_MODEL_LIST_ONLY|
487@@ -511,17 +529,26 @@
488 return s
489 elif column == self.COL_ICON:
490 try:
491- icon_name = self.db.get_iconname(doc)
492- if icon_name:
493- icon_name = os.path.splitext(icon_name)[0]
494+ icon_file_name = self.db.get_iconname(doc)
495+ if icon_file_name:
496+ icon_name = os.path.splitext(icon_file_name)[0]
497 if icon_name in self.icon_cache:
498 return self.icon_cache[icon_name]
499 # icons.load_icon takes between 0.001 to 0.01s on my
500 # machine, this is a significant burden because get_value
501 # is called *a lot*. caching is the only option
502- icon = self.icons.load_icon(icon_name, self.icon_size, 0)
503- self.icon_cache[icon_name] = icon
504- return icon
505+
506+ # check if this is a downloadable icon
507+ if not self.db.get_icon_needs_download(doc):
508+ # load the icon from the theme
509+ icon = self.icons.load_icon(icon_name, self.icon_size, 0)
510+ self.icon_cache[icon_name] = icon
511+ return icon
512+ else:
513+ self._download_icon_and_show_when_ready(self.cache,
514+ app.pkgname,
515+ icon_file_name)
516+ return self._appicon_missing_icon
517 except glib.GError, e:
518 self._logger.debug("get_icon returned '%s'" % e)
519 self.icon_cache[icon_name] = self._appicon_missing_icon
520
521=== modified file 'test/test_appdetails.py'
522--- test/test_appdetails.py 2010-08-05 13:59:02 +0000
523+++ test/test_appdetails.py 2010-08-09 02:13:42 +0000
524@@ -63,6 +63,7 @@
525 for i in range(PKG_STATE_UNKNOWN):
526 mock_app_details.pkg_state = i
527 self.appdetails.show_app(app)
528+
529
530 if __name__ == "__main__":
531 import logging

Subscribers

People subscribed via source and target branches