def _download_icon_and_show_when_ready(self, url, pkgname, icon_file_name): LOG.debug("did not find the icon locally, must download %s" % icon_file_name) if url is not None: icon_file_path = os.path.join(SOFTWARE_CENTER_ICON_CACHE_DIR, icon_file_name) image_downloader = SimpleFileDownloader() image_downloader.connect('file-download-complete', self._on_image_download_complete, pkgname) image_downloader.download_file(url, icon_file_path)
def _download_icon_and_show_when_ready(self, url, pkgname, icon_file_name): LOG.debug("did not find the icon locally, must download %s" % icon_file_name) def on_image_download_complete(downloader, image_file_path, pkgname): LOG.debug("download for '%s' complete" % image_file_path) pb = GdkPixbuf.Pixbuf.new_from_file_at_size(icon_file_path, self.icon_size, self.icon_size) # replace the icon in the icon_cache now that we've got the real # one icon_file = split_icon_ext(os.path.basename(image_file_path)) self.icon_cache[icon_file] = pb self.emit("needs-refresh", pkgname) if url is not None: icon_file_path = os.path.join(SOFTWARE_CENTER_ICON_CACHE_DIR, icon_file_name) image_downloader = SimpleFileDownloader() image_downloader.connect("file-download-complete", on_image_download_complete, pkgname) image_downloader.download_file(url, icon_file_path)
def _download_icon_and_show_when_ready(self, cache, pkgname, icon_file_name): LOG.debug("did not find the icon locally, must download %s" % icon_file_name) def on_image_download_complete(downloader, image_file_path): pb = GdkPixbuf.Pixbuf.new_from_file_at_size(icon_file_path, self.icon_size, self.icon_size) # replace the icon in the icon_cache now that we've got the real one icon_file = os.path.splitext(os.path.basename(image_file_path))[0] self.icon_cache[icon_file] = pb url = get_distro().get_downloadable_icon_url(cache, pkgname, icon_file_name) if url is not None: icon_file_path = os.path.join(SOFTWARE_CENTER_ICON_CACHE_DIR, icon_file_name) image_downloader = SimpleFileDownloader() image_downloader.connect('file-download-complete', on_image_download_complete) image_downloader.download_file(url, icon_file_path)
class TestImageDownloader(unittest.TestCase): DOWNLOAD_FILENAME = "test_image_download" def setUp(self): self.downloader = SimpleFileDownloader() self.downloader.connect("file-url-reachable", self._cb_image_url_reachable) self.downloader.connect("file-download-complete", self._cb_image_download_complete) self._image_is_reachable = None self._image_downloaded_filename = None if os.path.exists(self.DOWNLOAD_FILENAME): os.unlink(self.DOWNLOAD_FILENAME) def _cb_image_url_reachable(self, downloader, is_reachable): self._image_is_reachable = is_reachable def _cb_image_download_complete(self, downloader, filename): self._image_downloaded_filename = filename def test_download_unreachable(self): self.downloader.download_file("http://examplex.com/not-there", self.DOWNLOAD_FILENAME) main_loop = GObject.main_context_default() while self._image_is_reachable is None: while main_loop.pending(): main_loop.iteration() time.sleep(0.1) self.assertNotEqual(self._image_is_reachable, None) self.assertFalse(self._image_is_reachable) self.assertTrue(not os.path.exists(self.DOWNLOAD_FILENAME)) def test_download_reachable(self): self.downloader.download_file("http://www.ubuntu.com", self.DOWNLOAD_FILENAME) main_loop = GObject.main_context_default() while self._image_downloaded_filename is None: while main_loop.pending(): main_loop.iteration() time.sleep(0.1) self.assertNotEqual(self._image_is_reachable, None) self.assertTrue(self._image_is_reachable) self.assertTrue(os.path.exists(self.DOWNLOAD_FILENAME))
def __init__(self, id_, url, cancellable, gallery): Gtk.Button.__init__(self) self.id_ = id_ def download_complete_cb(loader, path): width, height = ThumbnailGallery.THUMBNAIL_SIZE_CONTRAINTS pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_scale( path, width, height, # width, height constraints True) # respect image proportionality im = Gtk.Image.new_from_pixbuf(pixbuf) self.add(im) self.show_all() loader = SimpleFileDownloader() loader.connect("file-download-complete", download_complete_cb) loader.download_file(url, use_cache=ScreenshotGallery.USE_CACHING) self.connect("draw", self.on_draw)
def __init__(self, id_, url, cancellable, gallery): Gtk.Button.__init__(self) self.id_ = id_ def download_complete_cb(loader, path): width, height = ThumbnailGallery.THUMBNAIL_SIZE_CONTRAINTS pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_scale( path, width, height, # width, height constraints True) # respect image proportionality im = Gtk.Image.new_from_pixbuf(pixbuf) self.add(im) self.show_all() loader = SimpleFileDownloader() loader.connect("file-download-complete", download_complete_cb) loader.download_file( url, use_cache=ScreenshotGallery.USE_CACHING) self.connect("draw", self.on_draw)
def _download_icon_and_show_when_ready(self, url, pkgname, icon_file_name): LOG.debug("did not find the icon locally, must download %s" % icon_file_name) def on_image_download_complete(downloader, image_file_path, pkgname): LOG.debug("download for '%s' complete" % image_file_path) pb = GdkPixbuf.Pixbuf.new_from_file_at_size(icon_file_path, self.icon_size, self.icon_size) # replace the icon in the icon_cache now that we've got the real # one icon_file = split_icon_ext(os.path.basename(image_file_path)) self.icon_cache[icon_file] = pb self.emit("needs-refresh", pkgname) if url is not None: icon_file_path = os.path.join(SOFTWARE_CENTER_ICON_CACHE_DIR, icon_file_name) image_downloader = SimpleFileDownloader() image_downloader.connect('file-download-complete', on_image_download_complete, pkgname) image_downloader.download_file(url, icon_file_path)
class ScreenshotGallery(Gtk.VBox): """ Widget that displays screenshot availability, download progress, and eventually the screenshot itself. """ MAX_SIZE_CONSTRAINTS = 300, 250 SPINNER_SIZE = 32, 32 ZOOM_ICON = "stock_zoom-page" NOT_AVAILABLE_STRING = _('No screenshot available') USE_CACHING = True def __init__(self, distro, icons): Gtk.VBox.__init__(self) # data self.distro = distro self.icons = icons self.data = ScreenshotData() self.data.connect("screenshots-available", self._on_screenshots_available) # state tracking self.ready = False self.screenshot_pixbuf = None self.screenshot_available = False self._thumbnail_sigs = [] self._height = 0 # zoom cursor try: zoom_pb = self.icons.load_icon(self.ZOOM_ICON, 22, 0) # FIXME self._zoom_cursor = Gdk.Cursor.new_from_pixbuf( Gdk.Display.get_default(), zoom_pb, 0, 0) # x, y except: self._zoom_cursor = None # convenience class for handling the downloading (or not) of # any screenshot self.loader = SimpleFileDownloader() self.loader.connect('error', self._on_screenshot_load_error) self.loader.connect('file-url-reachable', self._on_screenshot_query_complete) self.loader.connect('file-download-complete', self._on_screenshot_download_complete) self._build_ui() # add cleanup handler to avoid signals after we are destroyed self.connect("destroy", self._on_destroy) def _on_destroy(self, widget): # we need to disconnect here otherwise gtk segfaults when it # tries to set a already destroyed gtk image self.loader.disconnect_by_func(self._on_screenshot_download_complete) self.loader.disconnect_by_func(self._on_screenshot_load_error) # overrides def do_get_preferred_width(self): if self.data.get_n_screenshots() <= 1: pb = self.button.image.get_pixbuf() if pb: width = pb.get_width() + 20 return width, width return 320, 320 def do_get_preferred_height(self): pb = self.button.image.get_pixbuf() if pb: height = pb.get_height() if self.data.get_n_screenshots() <= 1: height += 20 height = max(self._height, height) self._height = height return height, height else: height += 110 height = max(self._height, height) self._height = height return height, height self._height = max(self._height, 250) return self._height, self._height # private def _build_ui(self): self.set_border_width(3) # the frame around the screenshot (placeholder) self.screenshot = Gtk.VBox() self.pack_start(self.screenshot, True, True, 0) self.spinner = Gtk.Spinner() self.spinner.set_size_request(*self.SPINNER_SIZE) self.spinner.set_valign(Gtk.Align.CENTER) self.spinner.set_halign(Gtk.Align.CENTER) self.screenshot.add(self.spinner) # clickable screenshot button self.button = ScreenshotButton() self.screenshot.pack_start(self.button, True, False, 0) # unavailable layout self.unavailable = Gtk.Label(label=_(self.NOT_AVAILABLE_STRING)) self.unavailable.set_alignment(0.5, 0.5) # force the label state to INSENSITIVE so we get the nice # subtle etched in look self.unavailable.set_state(Gtk.StateType.INSENSITIVE) self.screenshot.add(self.unavailable) self.thumbnails = ThumbnailGallery(self) self.thumbnails.set_margin_top(5) self.thumbnails.set_halign(Gtk.Align.CENTER) self.pack_end(self.thumbnails, False, False, 0) self.thumbnails.connect("thumb-selected", self.on_thumbnail_selected) self.button.connect("clicked", self.on_clicked) self.button.connect('enter-notify-event', self._on_enter) self.button.connect('leave-notify-event', self._on_leave) self.show_all() def _on_enter(self, widget, event): if self.get_is_actionable(): self.get_window().set_cursor(self._zoom_cursor) def _on_leave(self, widget, event): self.get_window().set_cursor(None) def _on_key_press(self, widget, event): # react to spacebar, enter, numpad-enter if (event.keyval in (Gdk.KEY_space, Gdk.KEY_Return, Gdk.KEY_KP_Enter) and self.get_is_actionable()): self.set_state(Gtk.StateType.ACTIVE) def _on_key_release(self, widget, event): # react to spacebar, enter, numpad-enter if (event.keyval in (Gdk.KEY_space, Gdk.KEY_Return, Gdk.KEY_KP_Enter) and self.get_is_actionable()): self.set_state(Gtk.StateType.NORMAL) self._show_image_dialog() def _show_image_dialog(self): """ Displays the large screenshot in a seperate dialog window """ if self.data and self.screenshot_pixbuf: title = _("%s - Screenshot") % self.data.appname toplevel = self.get_toplevel() d = SimpleShowImageDialog(title, self.screenshot_pixbuf, toplevel) d.run() d.destroy() def _on_screenshots_available(self, screenshots): self.thumbnails.set_thumbnails_from_data(screenshots) def _on_screenshot_download_complete(self, loader, screenshot_path): try: self.screenshot_pixbuf = GdkPixbuf.Pixbuf.new_from_file( screenshot_path) except Exception, e: LOG.exception("Pixbuf.new_from_file() failed") self.loader.emit('error', GObject.GError, e) return False #context = self.button.get_style_context() tw, th = self.MAX_SIZE_CONSTRAINTS pb = self._downsize_pixbuf(self.screenshot_pixbuf, tw, th) self.button.image.set_from_pixbuf(pb) self.ready = True self.display_image()
class ScreenshotGallery(Gtk.VBox): """ Widget that displays screenshot availability, download progress, and eventually the screenshot itself. """ MAX_SIZE_CONSTRAINTS = 300, 250 SPINNER_SIZE = 32, 32 ZOOM_ICON = "stock_zoom-page" NOT_AVAILABLE_STRING = _('No screenshot available') USE_CACHING = True def __init__(self, distro, icons): Gtk.VBox.__init__(self) # data self.distro = distro self.icons = icons self.data = ScreenshotData() self.data.connect( "screenshots-available", self._on_screenshots_available) # state tracking self.ready = False self.screenshot_pixbuf = None self.screenshot_available = False self._thumbnail_sigs = [] self._height = 0 # zoom cursor try: zoom_pb = self.icons.load_icon(self.ZOOM_ICON, 22, 0) # FIXME self._zoom_cursor = Gdk.Cursor.new_from_pixbuf( Gdk.Display.get_default(), zoom_pb, 0, 0) # x, y except: self._zoom_cursor = None # convenience class for handling the downloading (or not) of # any screenshot self.loader = SimpleFileDownloader() self.loader.connect( 'error', self._on_screenshot_load_error) self.loader.connect( 'file-url-reachable', self._on_screenshot_query_complete) self.loader.connect( 'file-download-complete', self._on_screenshot_download_complete) self._build_ui() # add cleanup handler to avoid signals after we are destroyed self.connect("destroy", self._on_destroy) def _on_destroy(self, widget): # we need to disconnect here otherwise gtk segfaults when it # tries to set a already destroyed gtk image self.loader.disconnect_by_func( self._on_screenshot_download_complete) self.loader.disconnect_by_func( self._on_screenshot_load_error) # overrides def do_get_preferred_width(self): if self.data.get_n_screenshots() <= 1: pb = self.button.image.get_pixbuf() if pb: width = pb.get_width() + 20 return width, width return 320, 320 def do_get_preferred_height(self): pb = self.button.image.get_pixbuf() if pb: height = pb.get_height() if self.data.get_n_screenshots() <= 1: height += 20 height = max(self._height, height) self._height = height return height, height else: height += 110 height = max(self._height, height) self._height = height return height, height self._height = max(self._height, 250) return self._height, self._height # private def _build_ui(self): self.set_border_width(3) # the frame around the screenshot (placeholder) self.screenshot = Gtk.VBox() self.pack_start(self.screenshot, True, True, 0) self.spinner = Gtk.Spinner() self.spinner.set_size_request(*self.SPINNER_SIZE) self.spinner.set_valign(Gtk.Align.CENTER) self.spinner.set_halign(Gtk.Align.CENTER) self.screenshot.add(self.spinner) # clickable screenshot button self.button = ScreenshotButton() self.screenshot.pack_start(self.button, True, False, 0) # unavailable layout self.unavailable = Gtk.Label(label=self.NOT_AVAILABLE_STRING) self.unavailable.set_alignment(0.5, 0.5) # force the label state to INSENSITIVE so we get the nice # subtle etched in look self.unavailable.set_state(Gtk.StateType.INSENSITIVE) self.screenshot.add(self.unavailable) self.thumbnails = ThumbnailGallery(self) self.thumbnails.set_margin_top(5) self.thumbnails.set_halign(Gtk.Align.CENTER) self.pack_end(self.thumbnails, False, False, 0) self.thumbnails.connect( "thumb-selected", self.on_thumbnail_selected) self.button.connect("clicked", self.on_clicked) self.button.connect('enter-notify-event', self._on_enter) self.button.connect('leave-notify-event', self._on_leave) self.show_all() def _on_enter(self, widget, event): if self.get_is_actionable(): self.get_window().set_cursor(self._zoom_cursor) def _on_leave(self, widget, event): self.get_window().set_cursor(None) def _on_key_press(self, widget, event): # react to spacebar, enter, numpad-enter if (event.keyval in (Gdk.KEY_space, Gdk.KEY_Return, Gdk.KEY_KP_Enter) and self.get_is_actionable()): self.set_state(Gtk.StateType.ACTIVE) def _on_key_release(self, widget, event): # react to spacebar, enter, numpad-enter if (event.keyval in (Gdk.KEY_space, Gdk.KEY_Return, Gdk.KEY_KP_Enter) and self.get_is_actionable()): self.set_state(Gtk.StateType.NORMAL) self._show_image_dialog() def _show_image_dialog(self): """ Displays the large screenshot in a seperate dialog window """ if self.data and self.screenshot_pixbuf: title = _("%s - Screenshot") % self.data.appname toplevel = self.get_toplevel() d = SimpleShowImageDialog( title, self.screenshot_pixbuf, toplevel) d.run() d.destroy() def _on_screenshots_available(self, screenshots): self.thumbnails.set_thumbnails_from_data(screenshots) def _on_screenshot_download_complete(self, loader, screenshot_path): try: self.screenshot_pixbuf = GdkPixbuf.Pixbuf.new_from_file( screenshot_path) except Exception, e: LOG.exception("Pixbuf.new_from_file() failed") self.loader.emit('error', GObject.GError, e) return False #context = self.button.get_style_context() tw, th = self.MAX_SIZE_CONSTRAINTS pb = self._downsize_pixbuf(self.screenshot_pixbuf, tw, th) self.button.image.set_from_pixbuf(pb) self.ready = True self.display_image()
class ScreenshotThumbnail(Gtk.Alignment): """ Widget that displays screenshot availability, download prrogress, and eventually the screenshot itself. """ MAX_SIZE = 300, 300 IDLE_SIZE = 300, 150 SPINNER_SIZE = 32, 32 ZOOM_ICON = "stock_zoom-page" def __init__(self, distro, icons): Gtk.Alignment.__init__(self) self.set(0.5, 0.0, 1.0, 1.0) # data self.distro = distro self.icons = icons self.pkgname = None self.appname = None self.thumb_url = None self.large_url = None # state tracking self.ready = False self.screenshot_pixbuf = None self.screenshot_available = False self.alpha = 0.0 # zoom cursor try: zoom_pb = self.icons.load_icon(self.ZOOM_ICON, 22, 0) # FIXME self._zoom_cursor = Gdk.Cursor.new_from_pixbuf( Gdk.Display.get_default(), zoom_pb, 0, 0) # x, y except: self._zoom_cursor = None # tip stuff self._hide_after = None self.tip_alpha = 0.0 self._tip_fader = 0 self._tip_layout = self.create_pango_layout("") #m = "<small><b>%s</b></small>" #~ self._tip_layout.set_markup(m % _("Click for fullsize screenshot")) #~ self._tip_layout.set_ellipsize(Pango.EllipsizeMode.END) self._tip_xpadding = 4 self._tip_ypadding = 1 # cache the tip dimensions w, h = self._tip_layout.get_pixel_size() self._tip_size = (w+2*self._tip_xpadding, h+2*self._tip_ypadding) # convienience class for handling the downloading (or not) of any screenshot self.loader = SimpleFileDownloader() self.loader.connect('error', self._on_screenshot_load_error) self.loader.connect('file-url-reachable', self._on_screenshot_query_complete) self.loader.connect('file-download-complete', self._on_screenshot_download_complete) self._build_ui() return def _build_ui(self): self.set_redraw_on_allocate(False) # the frame around the screenshot (placeholder) self.set_border_width(3) # eventbox so we can connect to event signals event = Gtk.EventBox() event.set_visible_window(False) self.spinner_alignment = Gtk.Alignment.new(0.5, 0.5, 1.0, 0.0) self.spinner = Gtk.Spinner() self.spinner.set_size_request(*self.SPINNER_SIZE) self.spinner_alignment.add(self.spinner) # the image self.image = Gtk.Image() self.image.set_redraw_on_allocate(False) event.add(self.image) self.eventbox = event # connect the image to our custom draw func for fading in self.image.connect('draw', self._on_image_draw) # unavailable layout l = Gtk.Label(label=_('No screenshot')) # force the label state to INSENSITIVE so we get the nice subtle etched in look l.set_state(Gtk.StateType.INSENSITIVE) # center children both horizontally and vertically self.unavailable = Gtk.Alignment.new(0.5, 0.5, 1.0, 1.0) self.unavailable.add(l) # set the widget to be reactive to events self.set_property("can-focus", True) event.set_events(Gdk.EventMask.BUTTON_PRESS_MASK| Gdk.EventMask.BUTTON_RELEASE_MASK| Gdk.EventMask.KEY_RELEASE_MASK| Gdk.EventMask.KEY_PRESS_MASK| Gdk.EventMask.ENTER_NOTIFY_MASK| Gdk.EventMask.LEAVE_NOTIFY_MASK) # connect events to signal handlers event.connect('enter-notify-event', self._on_enter) event.connect('leave-notify-event', self._on_leave) event.connect('button-press-event', self._on_press) event.connect('button-release-event', self._on_release) self.connect('focus-in-event', self._on_focus_in) # self.connect('focus-out-event', self._on_focus_out) self.connect("key-press-event", self._on_key_press) self.connect("key-release-event", self._on_key_release) # signal handlers def _on_enter(self, widget, event): if not self.get_is_actionable(): return self.get_window().set_cursor(self._zoom_cursor) self.show_tip(hide_after=3000) return def _on_leave(self, widget, event): self.get_window().set_cursor(None) self.hide_tip() return def _on_press(self, widget, event): if event.button != 1 or not self.get_is_actionable(): return self.set_state(Gtk.StateType.ACTIVE) return def _on_release(self, widget, event): if event.button != 1 or not self.get_is_actionable(): return self.set_state(Gtk.StateType.NORMAL) self._show_image_dialog() return def _on_focus_in(self, widget, event): self.show_tip(hide_after=3000) return # def _on_focus_out(self, widget, event): # return def _on_key_press(self, widget, event): # react to spacebar, enter, numpad-enter if event.keyval in (Gdk.KEY_space, Gdk.KEY_Return, Gdk.KEY_KP_Enter) and self.get_is_actionable(): self.set_state(Gtk.StateType.ACTIVE) return def _on_key_release(self, widget, event): # react to spacebar, enter, numpad-enter if event.keyval in (Gdk.KEY_space, Gdk.KEY_Return, Gdk.KEY_KP_Enter) and self.get_is_actionable(): self.set_state(Gtk.StateType.NORMAL) self._show_image_dialog() return def _on_image_draw(self, widget, cr): """ If the alpha value is less than 1, we override the normal draw for the GtkImage so we can draw with transparencey. """ #~ #~ if widget.get_storage_type() != Gtk.ImageType.PIXBUF: #~ return #~ #~ pb = widget.get_pixbuf() #~ if not pb: return True #~ #~ a = widget.get_allocation() #~ cr.rectangle(a.x, a.y, a.width, a.height) #~ cr.clip() #~ #~ # draw the pixbuf with the current alpha value #~ cr.set_source_pixbuf(pb, a.x, a.y) #~ cr.paint_with_alpha(self.alpha) #~ #~ if not self.tip_alpha: return True #~ #~ tw, th = self._tip_size #~ if a.width > tw: #~ self._tip_layout.set_width(-1) #~ else: #~ # tip is image width #~ tw = a.width #~ self._tip_layout.set_width(1024*(tw-2*self._tip_xpadding)) #~ #~ tx, ty = a.x+a.width-tw, a.y+a.height-th #~ #~ rr = mkit.ShapeRoundedRectangleIrregular() #~ rr.layout(cr, tx, ty, tx+tw, ty+th, radii=(6, 0, 0, 0)) #~ #~ cr.set_source_rgba(0,0,0,0.85*self.tip_alpha) #~ cr.fill() #~ #~ cr.move_to(tx+self._tip_xpadding, ty+self._tip_ypadding) #~ cr.layout_path(self._tip_layout) #~ cr.set_source_rgba(1,1,1,self.tip_alpha) #~ cr.fill() #~ return True return def _fade_in(self): """ This callback increments the alpha value from zero to 1, stopping once 1 is reached or exceeded. """ self.alpha += 0.05 if self.alpha >= 1.0: self.alpha = 1.0 self.queue_draw() return False self.queue_draw() return True def _tip_fade_in(self): """ This callback increments the alpha value from zero to 1, stopping once 1 is reached or exceeded. """ self.tip_alpha += 0.1 #ia = self.image.get_allocation() tw, th = self._tip_size if self.tip_alpha >= 1.0: self.tip_alpha = 1.0 self.image.queue_draw() # self.image.queue_draw_area(ia.x+ia.width-tw, # ia.y+ia.height-th, # tw, th) return False self.image.queue_draw() # self.image.queue_draw_area(ia.x+ia.width-tw, # ia.y+ia.height-th, # tw, th) return True def _tip_fade_out(self): """ This callback increments the alpha value from zero to 1, stopping once 1 is reached or exceeded. """ self.tip_alpha -= 0.1 #ia = self.image.get_allocation() tw, th = self._tip_size if self.tip_alpha <= 0.0: self.tip_alpha = 0.0 # self.image.queue_draw_area(ia.x+ia.width-tw, # ia.y+ia.height-th, # tw, th) self.image.queue_draw() return False self.image.queue_draw() # self.image.queue_draw_area(ia.x+ia.width-tw, # ia.y+ia.height-th, # tw, th) return True def _show_image_dialog(self): """ Displays the large screenshot in a seperate dialog window """ if self.screenshot_pixbuf: title = _("%s - Screenshot") % self.appname toplevel = self.get_toplevel() d = SimpleShowImageDialog(title, self.screenshot_pixbuf, toplevel) d.run() d.destroy() return def _on_screenshot_load_error(self, loader, err_type, err_message): self.set_screenshot_available(False) self.ready = True return def _on_screenshot_query_complete(self, loader, reachable): self.set_screenshot_available(reachable) if not reachable: self.ready = True return def _downsize_pixbuf(self, pb, target_w, target_h): w = pb.get_width() h = pb.get_height() if w > h: sf = float(target_w) / w else: sf = float(target_h) / h sw = int(w*sf) sh = int(h*sf) return pb.scale_simple(sw, sh, GdkPixbuf.InterpType.BILINEAR) def _on_screenshot_download_complete(self, loader, screenshot_path): def setter_cb(path): try: self.screenshot_pixbuf = GdkPixbuf.Pixbuf.new_from_file(path) except Exception, e: LOG.exception("Pixbuf.new_from_file() failed") self.loader.emit('error', GObject.GError, e) return False # remove the spinner if self.spinner_alignment.get_parent(): self.spinner.stop() self.spinner.hide() self.remove(self.spinner_alignment) pb = self._downsize_pixbuf(self.screenshot_pixbuf, *self.MAX_SIZE) if not self.eventbox.get_parent(): self.add(self.eventbox) if self.get_property("visible"): self.show_all() self.image.set_size_request(-1, -1) self.image.set_from_pixbuf(pb) # queue parent redraw if height of new pb is less than idle height if pb.get_height() < self.IDLE_SIZE[1]: if self.get_parent(): self.get_parent().queue_draw() # start the fade in GObject.timeout_add(50, self._fade_in) self.ready = True return False GObject.timeout_add(500, setter_cb, screenshot_path) return
class _HtmlRenderer(Gtk.OffscreenWindow): __gsignals__ = { "render-finished": (GObject.SignalFlags.RUN_LAST, None, (), ) } def __init__(self): Gtk.OffscreenWindow.__init__(self) self.view = WebKit.WebView() settings = self.view.get_settings() settings.set_property("enable-java-applet", False) settings.set_property("enable-plugins", False) settings.set_property("enable-scripts", False) self.view.set_size_request(-1, ExhibitBanner.MAX_HEIGHT) self.add(self.view) self.show_all() self.loader = SimpleFileDownloader() self.loader.connect("file-download-complete", self.on_download_complete) self.loader.connect("error", self.on_download_error) self.exhibit = None self.view.connect("notify::load-status", self._on_load_status) def _on_load_status(self, view, prop): if view.get_property("load-status") == WebKit.LoadStatus.FINISHED: # this needs to run with a timeout because otherwise the # status is emited before the offscreen image is finihsed GObject.timeout_add(100, lambda: self.emit("render-finished")) def on_download_error(self, loader, exception, error): LOG.warn("download failed: '%s', '%s'" % (exception, error)) def on_download_complete(self, loader, path): image_name = os.path.basename(path) cache_dir = os.path.dirname(path) if hasattr(self.exhibit, "html") and self.exhibit.html: html = self.exhibit.html else: html = EXHIBIT_HTML % { 'banner_url': self.exhibit.banner_url, 'title': self.exhibit.title_translated, 'subtitle': "", } # replace the server side path with the local image name, this # assumes that the image always comes from the same server as # the html scheme, netloc, server_path, para, query, frag = urlparse( self.exhibit.banner_url) html = html.replace(server_path, image_name) self.view.load_string(html, "text/html", "UTF-8", "file:%s/" % cache_dir) def set_exhibit(self, exhibit): self.exhibit = exhibit self.loader.download_file(exhibit.banner_url, use_cache=True, simple_quoting_for_webkit=True)
class _HtmlRenderer(Gtk.OffscreenWindow): __gsignals__ = { "render-finished": ( GObject.SignalFlags.RUN_LAST, None, (), ) } def __init__(self): Gtk.OffscreenWindow.__init__(self) self.view = WebKit.WebView() settings = self.view.get_settings() settings.set_property("enable-java-applet", False) settings.set_property("enable-plugins", False) settings.set_property("enable-scripts", False) self.view.set_size_request(-1, ExhibitBanner.MAX_HEIGHT) self.add(self.view) self.show_all() self.loader = SimpleFileDownloader() self.loader.connect("file-download-complete", self.on_download_complete) self.loader.connect("error", self.on_download_error) self.exhibit = None self.view.connect("notify::load-status", self._on_load_status) def _on_load_status(self, view, prop): if view.get_property("load-status") == WebKit.LoadStatus.FINISHED: # this needs to run with a timeout because otherwise the # status is emited before the offscreen image is finihsed GObject.timeout_add(100, lambda: self.emit("render-finished")) def on_download_error(self, loader, exception, error): LOG.warn("download failed: '%s', '%s'" % (exception, error)) def on_download_complete(self, loader, path): image_name = os.path.basename(path) cache_dir = os.path.dirname(path) if hasattr(self.exhibit, "html") and self.exhibit.html: html = self.exhibit.html else: html = EXHIBIT_HTML % { 'banner_url': self.exhibit.banner_url, 'title': self.exhibit.title_translated, 'subtitle': "", } # replace the server side path with the local image name, this # assumes that the image always comes from the same server as # the html scheme, netloc, server_path, para, query, frag = urlparse( self.exhibit.banner_url) html = html.replace(server_path, image_name) self.view.load_string(html, "text/html", "UTF-8", "file:%s/" % cache_dir) def set_exhibit(self, exhibit): self.exhibit = exhibit self.loader.download_file(exhibit.banner_url, use_cache=True, simple_quoting_for_webkit=True)
class _HtmlRenderer(Gtk.OffscreenWindow): __gsignals__ = { "render-finished": (GObject.SignalFlags.RUN_LAST, None, (), ) } def __init__(self): Gtk.OffscreenWindow.__init__(self) self.view = WebKit.WebView() settings = self.view.get_settings() settings.set_property("enable-java-applet", False) settings.set_property("enable-plugins", False) settings.set_property("enable-scripts", False) self.view.set_size_request(-1, ExhibitBanner.MAX_HEIGHT) self.add(self.view) self.show_all() self.loader = SimpleFileDownloader() self.loader.connect("file-download-complete", self._on_one_download_complete) self.loader.connect("error", self._on_download_error) self.exhibit = None self._downloaded_banner_images = [] self.view.connect( "notify::load-status", self._on_internal_renderer_load_status) def set_exhibit(self, exhibit): LOG.debug("set_exhibit: '%s'" % exhibit) self._downloaded_banner_images = [] self.exhibit = exhibit self._download_next_banner_image() def _on_download_error(self, loader, exception, error): LOG.warn("download failed: '%s', '%s'" % (exception, error)) def _on_one_download_complete(self, loader, path): LOG.debug("downloading of '%s' finished" % path) self._downloaded_banner_images.append(path) if len(self._downloaded_banner_images) < len(self.exhibit.banner_urls): self._download_next_banner_image() self._on_all_banner_images_downloaded() def _on_all_banner_images_downloaded(self): LOG.debug("downloading of all banner images finished") html = self.exhibit.html cache_dir = os.path.join( softwarecenter.paths.SOFTWARE_CENTER_CACHE_DIR, "download-cache") for url, local_file in zip(self.exhibit.banner_urls, self._downloaded_banner_images): # no need to mangle local urls if url.startswith("file"): continue scheme, netloc, server_path, para, query, frag = urlparse(url) image_name = os.path.basename(local_file) # replace the server side path with the local image name, this # assumes that the image always comes from the same server as # the html html = html.replace(server_path, image_name) self.exhibit.html = html LOG.debug("mangled html: '%s'" % html) self.view.load_string(html, "text/html", "UTF-8", "file:%s/" % cache_dir) def _download_next_banner_image(self): LOG.debug("_download_next_banner_image") self.loader.download_file( self.exhibit.banner_urls[len(self._downloaded_banner_images)], use_cache=True, simple_quoting_for_webkit=True) def _on_internal_renderer_load_status(self, view, prop): """Called when the rendering of the html banner is done""" if view.get_property("load-status") == WebKit.LoadStatus.FINISHED: # this needs to run with a timeout because otherwise the # status is emitted before the offscreen image is finished GLib.timeout_add(100, lambda: self.emit("render-finished"))