class AppsStock(bigboard.stock.AbstractMugshotStock): STATIC_SET_SIZE = 7 DYNAMIC_SET_SIZE = 7 STATIFICATION_TIME_SEC = 60 * 60 #* 24 * 3; # 3 days __gsignals__ = { "all-apps-loaded" : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, ()) } def __init__(self, *args, **kwargs): super(AppsStock, self).__init__(*args, **kwargs) self.__box = CanvasVBox(spacing=3) self.__message = hippo.CanvasText() self.__message_link = ActionLink() self.__message_link.connect("button-press-event", lambda link, event: self.__on_message_link()) self.__message_link_url = None self.__subtitle = hippo.CanvasText(font="Bold 12px") self.__static_set = CanvasVBox() self.__dynamic_set = CanvasVBox() self.__box.append(self.__message) self.__box.append(self.__message_link) self.__box.append(self.__subtitle) self.__box.append(self.__static_set) self.__box.append(self.__dynamic_set) self.__box.set_child_visible(self.__dynamic_set, False) self.__app_browser = None self._add_more_link(self.__on_more_link) self._mugshot.connect("all-apps-loaded", lambda mugshot: self.__merge_apps()) self._mugshot.connect("global-top-apps-changed", lambda mugshot, apps: self.__sync()) self._mugshot.connect("my-top-apps-changed", lambda mugshot, apps: self.__sync()) self._mugshot.connect("pinned-apps-changed", lambda mugshot, apps: self.__sync()) self._mugshot.connect("pref-changed", lambda mugshot, key, value: self.__handle_pref_change(key, value)) self.__usage_enabled = False self.__static_set_ids = {} self.__set_message('Loading...') self.__apps = {} # mugshot app -> app # apps installed locally and not known in Mugshot self.__local_apps = {} # desktop -> app ad = apps_directory.get_app_directory() for app in ad.get_apps(): self.get_local_app(app) def __on_more_link(self): self._logger.debug("more!") if self.__app_browser is None: self.__app_browser = appbrowser.AppBrowser(self) self.__app_browser.present() def __on_message_link(self): libbig.show_url(self.__message_link_url) def __set_message(self, text, link=None): self.__box.set_child_visible(self.__message, (not text is None) and link is None) self.__box.set_child_visible(self.__message_link, not (text is None or link is None)) if text: self.__message.set_property("text", text) self.__message_link.set_property("text", text) if link: self.__message_link_url = link def __set_subtitle(self, text): self.__box.set_child_visible(self.__subtitle, not text is None) if text: self.__subtitle.set_property("text", text) def _on_mugshot_initialized(self): super(AppsStock, self)._on_mugshot_initialized() self._mugshot.get_global_top_apps() self._mugshot.request_all_apps() def _on_mugshot_ready(self): super(AppsStock, self)._on_mugshot_ready() self._mugshot.get_pinned_apps() self._mugshot.get_my_top_apps() def get_authed_content(self, size): return self.__box def get_unauthed_content(self, size): return self.__box def __set_item_size(self, item, size): if size == bigboard.stock.Stock.SIZE_BULL: item.set_property('xalign', hippo.ALIGNMENT_FILL) else: item.set_property('xalign', hippo.ALIGNMENT_CENTER) item.set_size(size) def set_size(self, size): super(AppsStock, self).set_size(size) for child in self.__static_set.get_children() + self.__dynamic_set.get_children(): self.__set_item_size(child, size) def __handle_pref_change(self, key, value): if key != 'applicationUsageEnabled': return self._logger.debug("handling %s pref change: %s", key, value) self.__sync() def __on_pinned_apps_success(self, pinned_ids): self._logger.debug("app pin set succeeded") self._mugshot.get_pinned_apps(force=True) def __set_dynamic_set(self, mugshot_apps): self.__dynamic_set.remove_all() for i, mugshot_app in enumerate(mugshot_apps or []): app = self.get_app(mugshot_app) if self.__static_set_ids.has_key(app.get_id()): continue if app.get_is_excluded(): continue if i >= self.DYNAMIC_SET_SIZE: break if not app.is_installed(): continue self._logger.debug("setting dynamic app: %s", app) display = apps_widgets.AppDisplay(app) display.connect("button-press-event", lambda display, event: display.launch()) self.__dynamic_set.append(display) if mugshot_apps: self.__box.set_child_visible(self.__dynamic_set,True) def get_app(self, mugshot_app): if not self.__apps.has_key(mugshot_app.get_id()): ad = apps_directory.get_app_directory() for desktop_name in mugshot_app.get_desktop_names().split(';'): try: target_menuitem = ad.lookup(desktop_name) except KeyError, e: continue if self.__local_apps.has_key(target_menuitem.get_name()): self._logger.debug("moving app %s from local to apps", target_menuitem.get_name()) existing_app = self.__local_apps[target_menuitem.get_name()] del self.__local_apps[target_menuitem.get_name()] existing_app.set_app(mugshot_app) self.__apps[mugshot_app.get_id()] = existing_app return existing_app self._logger.debug("creating app %s", mugshot_app.get_id()) self.__apps[mugshot_app.get_id()] = Application(mugshot_app=mugshot_app) return self.__apps[mugshot_app.get_id()]
class AppOverview(CanvasVBox): __gsignals__ = { "more-info" : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT,)), "toggle-pinned" : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT, gobject.TYPE_BOOLEAN,)), "move-up" : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT,)), "move-down" : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT,)) } def __init__(self, app=None): super(AppOverview, self).__init__(xalign=hippo.ALIGNMENT_FILL, yalign=hippo.ALIGNMENT_FILL, box_width=200, box_height=260, border=1, border_color=0xAAAAAAFF, background_color=0xFFFFFFFF, padding=5) self.__unselected = True self.__app_unselected_text = hippo.CanvasText(text="Click an application to see its description here.\n\nDouble-click to launch.", size_mode=hippo.CANVAS_SIZE_WRAP_WORD, xalign=hippo.ALIGNMENT_CENTER, yalign=hippo.ALIGNMENT_CENTER, color=0x3F3F3FFF) self.append(self.__app_unselected_text, hippo.PACK_CLEAR_RIGHT) self.__header = apps_widgets.AppDisplay(apps_widgets.AppLocation.DESCRIPTION_HEADER) self.__description = hippo.CanvasText(font="12px",size_mode=hippo.CANVAS_SIZE_WRAP_WORD) self.__controls_box = CanvasVBox(xalign=hippo.ALIGNMENT_START, yalign=hippo.ALIGNMENT_END) self.__icon_button_combo = CanvasHBox(spacing=4, padding_bottom=4) self.__action_button_image = hippo.CanvasImage(scale_width=16, scale_height=16, xalign=hippo.ALIGNMENT_CENTER, yalign=hippo.ALIGNMENT_CENTER) self.__icon_button_combo.append(self.__action_button_image) self.__action_button = Button(label_xpadding=10) self.__action_button.set_property("xalign", hippo.ALIGNMENT_START) self.__action_button.get_button().set_focus_on_click(False) self.__icon_button_combo.append(self.__action_button) self.__controls_box.append(self.__icon_button_combo) self.__more_info = IconLink(text="More Info", prelight=False, img_scale_width=16, img_scale_height=16, spacing=2, underline=pango.UNDERLINE_LOW, xalign=hippo.ALIGNMENT_START) self.__more_info.link.connect("button-press-event", lambda l,e: self.emit("more-info", self.__app)) self.__more_info.img.set_property('image-name', '/usr/share/icons/gnome/16x16/status/info.png') self.__controls_box.append(self.__more_info) self.__check_showing = CanvasCheckbox("Show in sidebar") self.__check_showing.checkbox.connect('toggled', self.__on_show_in_sidebar_toggled) self.__controls_box.append(self.__check_showing) self.__up_button = hippo.CanvasLink(text="Up", border_right=10) self.__down_button = hippo.CanvasLink(text="Down") self.__up_down_controls = hippo.CanvasBox(orientation=hippo.ORIENTATION_HORIZONTAL) self.__up_down_controls.append(self.__up_button) self.__up_down_controls.append(self.__down_button) self.__up_button.connect("activated", lambda ci: self.emit("move-up", self.__app)) self.__down_button.connect("activated", lambda ci: self.emit("move-down", self.__app)) # FIXME - don't show up-down controls until they work #self.__controls_box.append(self.__up_down_controls) self.__app = None if app: self.set_app(app) def __on_show_in_sidebar_toggled(self, checkbox): active = checkbox.get_active() _logger.debug("Checkbox toggled, active = " + str(active)) if self.__app: pinned = self.__app.get_pinned() _logger.debug("App is currently pinned = " + str(pinned)) if active != pinned: self.emit("toggle-pinned", self.__app, active) def sync_pinned_checkbox(self): _logger.debug("Syncing pinned checkbox") if self.__app: _logger.debug(str(self.__app) + " pinned: " + str(self.__app.get_pinned())) self.__controls_box.set_child_visible(self.__check_showing, not self.__app.is_local()) self.__check_showing.checkbox.set_active(self.__app.get_pinned()) def set_app(self, app): if self.__unselected: self.__unselected = False self.remove(self.__app_unselected_text) self.append(self.__header) self.append(self.__description) self.append(self.__controls_box, hippo.PACK_EXPAND) self.__app = app self.__header.set_app(app) self.__description.set_property("text", app.get_description()) self.sync_pinned_checkbox() self.__controls_box.set_child_visible(self.__more_info, not self.__app.is_local()) if app.is_installed(): self.__action_button_image.set_property("image-name", "/usr/share/icons/gnome/16x16/actions/gnome-run.png") self.__action_button.set_label_text("Run...") else: self.__action_button_image.set_property("image-name", "/usr/share/icons/gnome/16x16/apps/system-software-installer.png") self.__action_button.set_label_text("Install...") def launch(self): return self.__header.launch() def get_app(self): return self.__app def get_header(self): return self.__header def get_action_button(self): return self.__action_button
class AppDisplay(PhotoContentItem): __gsignals__ = { "title-clicked" : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, ()), } def __init__(self, app_location, app=None, **kwargs): if app_location == AppLocation.STOCK: kwargs['enable_theme'] = True PhotoContentItem.__init__(self, border_right=6, **kwargs) self.__app = None self.__description_mode = False self._logger = logging.getLogger('bigboard.AppDisplay') self.__photo = CanvasMugshotURLImage(scale_width=30, scale_height=30) self.set_photo(self.__photo) self.__box = CanvasVBox(spacing=2, border_right=4) sub_kwargs = {} if kwargs.has_key('color'): sub_kwargs['color'] = kwargs['color'] title_kwargs = dict(sub_kwargs) title_kwargs.update({'font': '14px', 'xalign': hippo.ALIGNMENT_START, 'size-mode': hippo.CANVAS_SIZE_ELLIPSIZE_END }) if app_location == AppLocation.STOCK: self.__title = ThemedLink(**title_kwargs) else: self.__title = ActionLink(**title_kwargs) self.__title.connect("activated", lambda t: self.emit("title-clicked")) subtitle_kwargs = {'font': '10px', 'xalign': hippo.ALIGNMENT_START, 'size-mode': hippo.CANVAS_SIZE_ELLIPSIZE_END } if app_location == AppLocation.STOCK: self.__subtitle = ThemedText(theme_hints=['subforeground'], **subtitle_kwargs) else: self.__subtitle = hippo.CanvasText(**subtitle_kwargs) self.__box.append(self.__title) self.__box.append(self.__subtitle) self.set_child(self.__box) self.__description = hippo.CanvasText(size_mode=hippo.CANVAS_SIZE_WRAP_WORD, **sub_kwargs) self.__box.append(self.__description) self.__photo.set_clickable(True) self.__box.set_clickable(True) self.__app_location = app_location if app: self.set_app(app) def set_description_mode(self, mode): self.__description_mode = mode self.__app_display_sync() def get_app(self): return self.__app def set_app(self, app): self.__app = app self.__app_display_sync() def __get_name(self): if self.__app is None: return "unknown" return self.__app.get_name() def __str__(self): return '<AppDisplay name="%s">' % (self.__get_name()) def __app_display_sync(self): if not self.__app: return self.__box.set_child_visible(self.__subtitle, not self.__description_mode) self.__box.set_child_visible(self.__description, self.__description_mode) self.__title.set_property("text", self.__app.get_name()) if self.__app.is_installed() or self.__app_location == AppLocation.DESCRIPTION_HEADER: self.__subtitle.set_property("text", self.__app.get_generic_name() or self.__app.get_tooltip() or self.__app.get_comment()) ## for now, install won't work if not connected elif self.__app_location == AppLocation.STOCK and globals.get_data_model().ready and globals.get_data_model().global_resource.online: self.__subtitle.set_property('text', "(Click to Install)") else: self.__subtitle.set_property('text', "(Not Installed)") self.__description.set_property("text", self.__app.get_description()) if self.__app.get_icon_url(): self.__photo.set_url(self.__app.get_icon_url()) else: pixbuf = self.__app.get_local_pixbuf() if pixbuf: self.__photo.set_property("image", hippo.cairo_surface_from_gdk_pixbuf(pixbuf)) def launch(self): self._logger.debug("launching app %s", self) self.__app.launch()
class AppDisplay(PhotoContentItem): __gsignals__ = { "title-clicked" : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, ()), } def __init__(self, app=None, **kwargs): PhotoContentItem.__init__(self, border_right=6, **kwargs) self.__app = None self.__description_mode = False self._logger = logging.getLogger('bigboard.AppDisplay') self.__photo = CanvasMugshotURLImage(scale_width=30, scale_height=30) self.set_photo(self.__photo) self.__box = CanvasVBox(spacing=2, border_right=4) sub_kwargs = {} if kwargs.has_key('color'): sub_kwargs['color'] = kwargs['color'] self.__title = ActionLink(font="14px",xalign=hippo.ALIGNMENT_START, size_mode=hippo.CANVAS_SIZE_ELLIPSIZE_END, **sub_kwargs) self.__title.connect("activated", lambda t: self.emit("title-clicked")) self.__subtitle = hippo.CanvasText(font="10px",xalign=hippo.ALIGNMENT_START, size_mode=hippo.CANVAS_SIZE_ELLIPSIZE_END) attrs = pango.AttrList() attrs.insert(pango.AttrForeground(0x6666, 0x6666, 0x6666, 0, 0xFFFF)) self.__subtitle.set_property("attributes", attrs) self.__box.append(self.__title) self.__box.append(self.__subtitle) self.set_child(self.__box) self.__description = hippo.CanvasText(size_mode=hippo.CANVAS_SIZE_WRAP_WORD, **sub_kwargs) self.__box.append(self.__description) if app: self.set_app(app) def set_description_mode(self, mode): self.__description_mode = mode self.__app_display_sync() def get_app(self): return self.__app def set_app(self, app): self.__app = app self.__app.connect("changed", lambda app: self.__app_display_sync()) self.__app_display_sync() def __get_name(self): if self.__app is None: return "unknown" return self.__app.get_name() def __str__(self): return '<AppDisplay name="%s">' % (self.__get_name()) # override def do_prelight(self): return self.__app.is_installed() def __app_display_sync(self): if not self.__app: return self.__box.set_child_visible(self.__subtitle, not self.__description_mode) self.__box.set_child_visible(self.__description, self.__description_mode) self.__photo.set_clickable(self.__app.is_installed()) self.__box.set_clickable(self.__app.is_installed()) self.__title.set_property("text", self.__app.get_name()) self.__subtitle.set_property("text", self.__app.get_generic_name() or self.__app.get_tooltip() or self.__app.get_comment()) self.__description.set_property("text", self.__app.get_description()) if self.__app.get_mugshot_app(): self.__photo.set_url(self.__app.get_mugshot_app().get_icon_url()) else: pixbuf = self.__app.get_local_pixbuf() if pixbuf: self.__photo.set_property("image", hippo.cairo_surface_from_gdk_pixbuf(pixbuf)) def launch(self): self._logger.debug("launching app %s", self) self.__app.launch()
class AppsStock(bigboard.stock.AbstractMugshotStock): STATIC_SET_SIZE = 4 DYNAMIC_SET_SIZE = 0 STATIFICATION_TIME_SEC = 60 * 60 #* 24 * 3; # 3 days __gsignals__ = { } def __init__(self, *args, **kwargs): super(AppsStock, self).__init__(*args, **kwargs) search.enable_search_provider('apps') self.__box = CanvasVBox(spacing=3) self.__message = hippo.CanvasText() self.__message_link = ActionLink() self.__message_link.connect("button-press-event", lambda link, event: self.__on_message_link()) self.__message_link_url = None self.__subtitle = hippo.CanvasText(font="Bold 12px") self.__static_set = CanvasVBox() self.__dynamic_set = CanvasVBox() self.__box.append(self.__message) self.__box.append(self.__message_link) self.__box.append(self.__subtitle) self.__box.append(self.__static_set) self.__box.append(self.__dynamic_set) self.__box.set_child_visible(self.__dynamic_set, False) self.__app_browser = None self._add_more_button(self.__on_more_button) self.__static_set_ids = {} gconf.client_get_default().notify_add(GCONF_KEY_APP_SIZE, self.__on_app_size_changed) self.__set_message('Loading...') self.__repo = apps.get_apps_repo() self.__repo.connect('enabled-changed', self.__on_usage_enabled_changed) self.__repo.connect('all-apps-loaded', self.__on_all_apps_loaded) self.__repo.connect('my-pinned-apps-changed', self.__on_my_pinned_apps_changed) self.__repo.connect('my-top-apps-changed', self.__on_my_top_apps_changed) self.__repo.connect('global-top-apps-changed', self.__on_global_top_apps_changed) self.__repo.connect('app-launched', self.__on_app_launched) self.__sync() def _on_ready(self): # When we disconnect from the server we freeze existing content, then on reconnect # we clear everything and start over. _logger.debug("Connected to data model") def __on_query_error(self, where, error_code, message): _logger.warn("Query '" + where + "' failed, code " + str(error_code) + " message: " + str(message)) def __on_usage_enabled_changed(self, repo): _logger.debug("usage enabled changed") self.__sync() def __on_all_apps_loaded(self, repo): _logger.debug("all apps are loaded") self.__sync() def __on_my_pinned_apps_changed(self, repo, pinned_apps): _logger.debug("Pinned apps changed from apps repo: " + str(pinned_apps)) self.__sync() def __on_my_top_apps_changed(self, repo, my_top_apps): _logger.debug("My top apps changed from apps repo: " + str(my_top_apps)) self.__sync() def __on_global_top_apps_changed(self, repo, global_top_apps): _logger.debug("Global top apps changed from apps repo: " + str(global_top_apps)) self.__sync() def __on_app_size_changed(self, *args): _logger.debug("app size changed") self.__sync() def __on_app_launched(self, repo, app): self._panel.action_taken() def __on_more_button(self): _logger.debug("more!") if self.__app_browser is None: self.__app_browser = appbrowser.AppBrowser() if self.__app_browser.get_property('is-active'): self.__app_browser.hide() else: self.__app_browser.present() def __on_message_link(self): libbig.show_url(self.__message_link_url) def __set_message(self, text, link=None): self.__box.set_child_visible(self.__message, (not text is None) and link is None) self.__box.set_child_visible(self.__message_link, not (text is None or link is None)) if text: self.__message.set_property("text", text) self.__message_link.set_property("text", text) if link: self.__message_link_url = link def __set_subtitle(self, text): self.__box.set_child_visible(self.__subtitle, not text is None) if text: self.__subtitle.set_property("text", text) def get_authed_content(self, size): return self.__box def get_unauthed_content(self, size): return self.__box def __set_item_size(self, item, size): if size == bigboard.stock.Stock.SIZE_BULL: item.set_property('xalign', hippo.ALIGNMENT_FILL) else: item.set_property('xalign', hippo.ALIGNMENT_CENTER) item.set_size(size) def set_size(self, size): super(AppsStock, self).set_size(size) for child in self.__static_set.get_children() + self.__dynamic_set.get_children(): self.__set_item_size(child, size) def __fill_static_set(self): self.__static_set.remove_all() self.__static_set_ids = {} usage = self.__repo.get_app_usage_enabled() pinned_apps = self.__repo.get_pinned_apps() global_top_apps = self.__repo.get_global_top_apps() local_apps = self.__repo.get_local_apps() static_size = gconf.client_get_default().get_int(GCONF_KEY_APP_SIZE) or 7 self.__set_subtitle(None) apps_in_set = [] using_local_apps = False if usage: apps_in_set = pinned_apps if len(apps_in_set) == 0: if len(global_top_apps) > 0: apps_in_set = global_top_apps self.__set_subtitle("Popular Applications") elif len(local_apps) > 0: apps_in_set = local_apps using_local_apps = True if using_local_apps: apps_in_set = filter(lambda a: POPULAR_APPS.count(a.get_app_name_from_file_name()) > 0, apps_in_set) apps_in_set.sort(lambda a, b: cmp(POPULAR_APPS.index(a.get_app_name_from_file_name()), POPULAR_APPS.index(b.get_app_name_from_file_name()))) else: ## note the "-" in front of the cmp to sort descending apps_in_set.sort(lambda a, b: - cmp(a.get_usage_count(), b.get_usage_count())) for i, app in enumerate(apps_in_set): if i >= static_size: break # don't display apps that are not installed if the user is not logged in if not self._model.self_resource and not app.is_installed(): continue display = apps_widgets.AppDisplay(apps_widgets.AppLocation.STOCK, app) display.connect("button-press-event", lambda display, event: display.launch()) #_logger.debug("setting static set app: %s", app) self.__static_set.append(display) self.__static_set_ids[app.get_id()] = True @defer_idle_func(logger=_logger) def __sync(self): #_logger.debug("doing sync") self.__set_message(None) self.__box.set_child_visible(self.__dynamic_set, False) usage = self.__repo.get_app_usage_enabled() #_logger.debug("usage: %s", usage) if usage is False and self._model.ready and self._model.global_resource.online: self.__set_message("Enable application tracking", globals.get_baseurl() + "/account") self.__fill_static_set() self.__repo.pin_stuff_if_we_have_none()