def _append_sub_toprated(self): self.toprated = FlowableGrid() self.toprated.set_row_spacing(6) self.toprated.set_column_spacing(6) self.toprated_frame = FramedHeaderBox() self.toprated_frame.pack_start(self.toprated, True, True, 0) self.vbox.pack_start(self.toprated_frame, False, True, 0) return
def __init__(self, catview): FramedHeaderBox.__init__(self) # FIXME: we only need the catview for "add_titles_to_flowgrid" # and "on_category_clicked" so we should be able to # extract this to a "leaner" widget self.catview = catview self.catview.connect( "application-activated", self._on_application_activated) self.recommender_agent = RecommenderAgent()
def __init__(self, catview): FramedHeaderBox.__init__(self) # FIXME: we only need the catview for "add_titles_to_flowgrid" # and "on_category_clicked" so we should be able to # extract this to a "leaner" widget self.catview = catview self.catview.connect("application-activated", self._on_application_activated) self.recommender_agent = RecommenderAgent()
def _append_sub_top_rated(self): self.top_rated = TileGrid() self.top_rated.connect("application-activated", self.on_application_activated) self.top_rated.set_row_spacing(6) self.top_rated.set_column_spacing(6) self.top_rated_frame = FramedHeaderBox() self.top_rated_frame.pack_start(self.top_rated, True, True, 0) self.vbox.pack_start(self.top_rated_frame, False, True, 0) return
def __init__(self): FramedHeaderBox.__init__(self) self.recommender_agent = RecommenderAgent() # keep track of applications that have been viewed via a # recommendation so that we can detect when a recommended app # has been installed self.recommended_apps_viewed = set() self.backend = get_install_backend() self.backend.connect("transaction-started", self._on_transaction_started) self.backend.connect("transaction-finished", self._on_transaction_finished)
def _append_whats_new(self): self.whats_new = FlowableGrid() self.whats_new_frame = FramedHeaderBox() self.whats_new_frame.set_header_label(_(u"What\u2019s New")) self.whats_new_frame.add(self.whats_new) whats_new_cat = self._update_whats_new_content() if whats_new_cat is not None: # only add to the visible right_frame if we actually have it self.right_column.pack_start(self.whats_new_frame, True, True, 0) self.whats_new_frame.header_implements_more_button() self.whats_new_frame.more.connect('clicked', self.on_category_clicked, whats_new_cat)
def _append_top_rated(self): self.top_rated = TileGrid() self.top_rated.connect("application-activated", self.on_application_activated) #~ self.top_rated.row_spacing = StockEms.SMALL self.top_rated_frame = FramedHeaderBox() self.top_rated_frame.set_header_label(_("Top Rated")) self.top_rated_frame.add(self.top_rated) self.bottom_hbox.pack_start(self.top_rated_frame, True, True, 0) top_rated_cat = self._update_top_rated_content() # only display the 'More' LinkButton if we have top_rated content if top_rated_cat is not None: self.top_rated_frame.header_implements_more_button() self.top_rated_frame.more.connect('clicked', self.on_category_clicked, top_rated_cat)
def _append_sub_top_rated(self): self.top_rated = FlowableGrid() self.top_rated.set_row_spacing(6) self.top_rated.set_column_spacing(6) self.top_rated_frame = FramedHeaderBox() self.top_rated_frame.pack_start(self.top_rated, True, True, 0) self.vbox.pack_start(self.top_rated_frame, False, True, 0) return
def _append_whats_new(self): self.whats_new = FlowableGrid() self.whats_new_frame = FramedHeaderBox() self.whats_new_frame.set_header_label(_(u"What\u2019s New")) self.whats_new_frame.add(self.whats_new) whats_new_cat = self._update_whats_new_content() if whats_new_cat is not None: # only add to the visible right_frame if we actually have it self.right_column.pack_start(self.whats_new_frame, True, True, 0) self.whats_new_frame.header_implements_more_button() self.whats_new_frame.more.connect( 'clicked', self.on_category_clicked, whats_new_cat)
def _append_ceibal_apps(self): self.ceibal_apps = FlowableGrid() self.ceibal_apps_frame = FramedHeaderBox() self.ceibal_apps_frame.set_header_label(_(u"Ceibal Highlights")) self.ceibal_apps_frame.add(self.ceibal_apps) cat = self._update_ceibal_apps_content() if cat is not None: # only add to the visible right_frame if we actually have it self.right_column.pack_start(self.ceibal_apps_frame, True, True, 0) self.ceibal_apps_frame.header_implements_more_button() self.ceibal_apps_frame.more.connect( 'clicked', self.on_category_clicked, cat)
def _append_top_rated(self): self.toprated = FlowableGrid() #~ self.featured.row_spacing = StockEms.SMALL frame = FramedHeaderBox() frame.set_header_label(_("Top Rated")) frame.add(self.toprated) self.toprated_frame = frame self.right_column.pack_start(frame, True, True, 0) toprated_cat = self._update_toprated_content() # only display the 'More' LinkButton if we have toprated content if toprated_cat is not None: frame.header_implements_more_button() frame.more.connect('clicked', self.on_category_clicked, toprated_cat) return
def _append_top_rated(self): self.top_rated = FlowableGrid() #~ self.top_rated.row_spacing = StockEms.SMALL self.top_rated_frame = FramedHeaderBox() self.top_rated_frame.set_header_label(_("Top Rated")) self.top_rated_frame.add(self.top_rated) self.right_column.pack_start(self.top_rated_frame, True, True, 0) top_rated_cat = self._update_top_rated_content() # only display the 'More' LinkButton if we have top_rated content if top_rated_cat is not None: self.top_rated_frame.header_implements_more_button() self.top_rated_frame.more.connect('clicked', self.on_category_clicked, top_rated_cat) return
class SubCategoryView(CategoriesView): def __init__(self, cache, db, icons, apps_filter, apps_limit=0, root_category=None): CategoriesView.__init__(self, cache, db, icons, apps_filter, apps_limit) # state self._built = False # data self.root_category = root_category self.enquire = AppEnquire(self.cache, self.db) self.properties_helper = AppPropertiesHelper(self.db, self.cache, self.icons) # sections self.current_category = None self.departments = None self.top_rated = None self.recommended_for_you_in_cat = None self.appcount = None # widgetry self.vbox.set_margin_left(StockEms.MEDIUM - 2) self.vbox.set_margin_right(StockEms.MEDIUM - 2) self.vbox.set_margin_top(StockEms.MEDIUM) return def _get_sub_top_rated_content(self, category): app_filter = AppFilter(self.db, self.cache) self.enquire.set_query(category.query, limit=TOP_RATED_CAROUSEL_LIMIT, sortmode=SortMethods.BY_TOP_RATED, filter=app_filter, nonapps_visible=NonAppVisibility.ALWAYS_VISIBLE, nonblocking_load=False) return self.enquire.get_documents() @wait_for_apt_cache_ready # be consistent with new apps def _update_sub_top_rated_content(self, category): self.top_rated.remove_all() # FIXME: should this be m = "%s %s" % (_(gettext text), header text) ?? # TRANSLATORS: %s is a category name, like Internet or Development # Tools m = _('Top Rated %(category)s') % { 'category': GLib.markup_escape_text(self.header) } self.top_rated_frame.set_header_label(m) docs = self._get_sub_top_rated_content(category) self.top_rated.add_tiles(self.properties_helper, docs, TOP_RATED_CAROUSEL_LIMIT) return def _append_sub_top_rated(self): self.top_rated = TileGrid() self.top_rated.connect("application-activated", self.on_application_activated) self.top_rated.set_row_spacing(6) self.top_rated.set_column_spacing(6) self.top_rated_frame = FramedHeaderBox() self.top_rated_frame.pack_start(self.top_rated, True, True, 0) self.vbox.pack_start(self.top_rated_frame, False, True, 0) return def _update_recommended_for_you_in_cat_content(self, category): if (self.recommended_for_you_in_cat and self.recommended_for_you_in_cat.get_parent()): self.recommended_for_you_in_cat.disconnect_by_func( self.on_application_activated) self.vbox.remove(self.recommended_for_you_in_cat) self.recommended_for_you_in_cat = RecommendationsPanelCategory( self.db, self.properties_helper, category) self.recommended_for_you_in_cat.connect("application-activated", self.on_application_activated) self.recommended_for_you_in_cat.connect('more-button-clicked', self.on_category_clicked) # only show the panel in the categories view when the user # is opted in to the recommender service # FIXME: this is needed vs. a simple hide() on the widget because # we do a show_all on the view if self.recommended_for_you_in_cat.recommender_agent.is_opted_in(): self.vbox.pack_start(self.recommended_for_you_in_cat, False, False, 0) def _update_subcat_departments(self, category, num_items): self.departments.remove_all() # set the subcat header m = "<b><big>%s</big></b>" self.subcat_label.set_markup(m % GLib.markup_escape_text(self.header)) # sort Category.name's alphabetically sorted_cats = categories_sorted_by_name(self.categories) enquire = xapian.Enquire(self.db.xapiandb) app_filter = AppFilter(self.db, self.cache) distro = get_distro() supported_only = get_global_filter().supported_only for cat in sorted_cats: # add the subcategory if and only if it is non-empty if supported_only: enquire.set_query( xapian.Query(xapian.Query.OP_AND, cat.query, distro.get_supported_query())) else: enquire.set_query(cat.query) if len(enquire.get_mset(0, 1)): tile = CategoryTile(cat.name, cat.iconname) tile.connect('clicked', self.on_category_clicked, cat) self.departments.add_child(tile) # partially work around a (quite rare) corner case if num_items == 0: enquire.set_query( xapian.Query(xapian.Query.OP_AND, category.query, xapian.Query("ATapplication"))) # assuming that we only want apps is not always correct ^^^ tmp_matches = enquire.get_mset(0, len(self.db), None, app_filter) num_items = tmp_matches.get_matches_estimated() # append an additional button to show all of the items in the category all_cat = Category("All", _("All"), "category-show-all", category.query) name = GLib.markup_escape_text('%s %s' % (_("All"), num_items)) tile = CategoryTile(name, "category-show-all") tile.connect('clicked', self.on_category_clicked, all_cat) self.departments.add_child(tile) self.departments.queue_draw() return num_items def _append_subcat_departments(self): self.subcat_label = Gtk.Label() self.subcat_label.set_alignment(0, 0.5) self.departments = TileGrid(paint_grid_pattern=False) self.departments.set_row_spacing(StockEms.SMALL) self.departments.set_column_spacing(StockEms.SMALL) self.departments_frame = FramedBox(spacing=StockEms.MEDIUM, padding=StockEms.MEDIUM) # set x/y-alignment and x/y-expand self.departments_frame.set(0.5, 0.0, 1.0, 1.0) self.departments_frame.pack_start(self.subcat_label, False, False, 0) self.departments_frame.pack_start(self.departments, True, True, 0) # append the departments section to the page self.vbox.pack_start(self.departments_frame, False, True, 0) return def _update_appcount(self, appcount): text = gettext.ngettext("%(amount)s item available", "%(amount)s items available", appcount) % { 'amount': appcount } self.appcount.set_text(text) return def _append_appcount(self): self.appcount = Gtk.Label() self.appcount.set_alignment(0.5, 0.5) self.appcount.set_margin_top(1) self.appcount.set_margin_bottom(4) self.vbox.pack_end(self.appcount, False, False, 0) return def _build_subcat_view(self): # these methods add sections to the page # changing order of methods changes order that they appear in the page self._append_subcat_departments() self._append_sub_top_rated() # NOTE that the recommended for you in category view is built and added # in the _update_recommended_for_you_in_cat method (and so is not # needed here) self._append_appcount() self._built = True return def _update_subcat_view(self, category, num_items=0): num_items = self._update_subcat_departments(category, num_items) self._update_sub_top_rated_content(category) self._update_recommended_for_you_in_cat_content(category) self._update_appcount(num_items) self.show_all() return def set_subcategory(self, root_category, num_items=0): # nothing to do if (root_category is None or self.categories == root_category.subcategories): return self._set_subcategory(root_category, num_items) def _set_subcategory(self, root_category, num_items): self.current_category = root_category self.header = root_category.name self.categories = root_category.subcategories if not self._built: self._build_subcat_view() self._update_subcat_view(root_category, num_items) GLib.idle_add(self.queue_draw) return def refresh_apps(self): supported_only = get_global_filter().supported_only if (self.current_category is None or self._supported_only == supported_only): return self._supported_only = supported_only if not self._built: self._build_subcat_view() self._update_subcat_view(self.current_category) GLib.idle_add(self.queue_draw) return
class LobbyView(CategoriesView): def __init__(self, cache, db, icons, apps_filter, apps_limit=0): CategoriesView.__init__(self, cache, db, icons, apps_filter, apps_limit=0) self.top_rated = None self.exhibit_banner = None # sections self.departments = None self.appcount = None # get categories self.categories_parser = CategoriesParser(db) self.categories = self.categories_parser.parse_applications_menu() # build before connecting the signals to avoid race self.build() # ensure that on db-reopen we refresh the whats-new titles self.db.connect("reopen", self._on_db_reopen) # ensure that updates to the stats are reflected in the UI self.reviews_loader = get_review_loader(self.cache) self.reviews_loader.connect( "refresh-review-stats-finished", self._on_refresh_review_stats) def _on_db_reopen(self, db): self._update_whats_new_content() def _on_refresh_review_stats(self, reviews_loader, review_stats): self._update_top_rated_content() def _build_homepage_view(self): # these methods add sections to the page # changing order of methods changes order that they appear in the page self._append_banner_ads() self.top_hbox = Gtk.HBox(spacing=StockEms.SMALL) top_hbox_alignment = Gtk.Alignment() top_hbox_alignment.set_padding(0, 0, StockEms.MEDIUM - 2, StockEms.MEDIUM - 2) top_hbox_alignment.add(self.top_hbox) self.vbox.pack_start(top_hbox_alignment, False, False, 0) self._append_departments() self.right_column = Gtk.Box.new(Gtk.Orientation.VERTICAL, self.SPACING) self.top_hbox.pack_start(self.right_column, True, True, 0) self.bottom_hbox = Gtk.HBox(spacing=StockEms.SMALL) bottom_hbox_alignment = Gtk.Alignment() bottom_hbox_alignment.set_padding( StockEms.SMALL, 0, StockEms.MEDIUM - 2, StockEms.MEDIUM - 2) bottom_hbox_alignment.add(self.bottom_hbox) self.vbox.pack_start(bottom_hbox_alignment, False, False, 0) self._append_whats_new() self._append_top_rated() self._append_recommended_for_you() self._append_appcount() def _on_show_exhibits(self, exhibit_banner, exhibit): pkgs = exhibit.package_names.split(",") url = exhibit.click_url if url: webbrowser.open_new_tab(url) elif len(pkgs) == 1: app = Application("", pkgs[0]) self.emit("application-activated", app) else: query = self.db.get_query_for_pkgnames(pkgs) title = exhibit.title_translated untranslated_name = exhibit.package_names # create a temp query cat = Category(untranslated_name, title, None, query, flags=['nonapps-visible']) self.emit("category-selected", cat) def _filter_and_set_exhibits(self, sca_client, exhibit_list): result = [] # filter out those exhibits that are not available in this run for exhibit in exhibit_list: if not exhibit.package_names: result.append(exhibit) else: available = all(self.db.is_pkgname_known(p) for p in exhibit.package_names.split(',')) if available: result.append(exhibit) else: LOG.warn("skipping exhibit for: '%r' not available" % ( exhibit.package_names)) # its ok if result is empty, since set_exhibits() will ignore # empty lists self.exhibit_banner.set_exhibits(result) def _append_banner_ads(self): self.exhibit_banner = ExhibitBanner() self.exhibit_banner.set_exhibits([FeaturedExhibit()]) self.exhibit_banner.connect( "show-exhibits-clicked", self._on_show_exhibits) # query using the agent scagent = SoftwareCenterAgent() scagent.connect("exhibits", self._filter_and_set_exhibits) scagent.query_exhibits() a = Gtk.Alignment() a.set_padding(0, StockEms.SMALL, 0, 0) a.add(self.exhibit_banner) self.vbox.pack_start(a, False, False, 0) def _append_departments(self): # set the departments section to use the label markup we have just # defined cat_vbox = FramedBox(Gtk.Orientation.VERTICAL) self.top_hbox.pack_start(cat_vbox, False, False, 0) # sort Category.name's alphabetically sorted_cats = categories_sorted_by_name(self.categories) mrkup = "<small>%s</small>" for cat in sorted_cats: if 'carousel-only' in cat.flags: continue category_name = mrkup % GLib.markup_escape_text(cat.name) label = LabelTile(category_name, None) label.label.set_margin_left(StockEms.SMALL) label.label.set_margin_right(StockEms.SMALL) label.label.set_alignment(0.0, 0.5) label.label.set_use_markup(True) label.connect('clicked', self.on_category_clicked, cat) cat_vbox.pack_start(label, False, False, 0) return # FIXME: _update_{top_rated,whats_new,recommended_for_you}_content() # duplicates a lot of code def _update_top_rated_content(self): # remove any existing children from the grid widget self.top_rated.remove_all() # get top_rated category and docs top_rated_cat = get_category_by_name( self.categories, u"Top Rated") # untranslated name if top_rated_cat: docs = top_rated_cat.get_documents(self.db) self.top_rated.add_tiles(self.properties_helper, docs, TOP_RATED_CAROUSEL_LIMIT) self.top_rated.show_all() return top_rated_cat def _append_top_rated(self): self.top_rated = TileGrid() self.top_rated.connect("application-activated", self.on_application_activated) #~ self.top_rated.row_spacing = StockEms.SMALL self.top_rated_frame = FramedHeaderBox() self.top_rated_frame.set_header_label(_("Top Rated")) self.top_rated_frame.add(self.top_rated) self.bottom_hbox.pack_start(self.top_rated_frame, True, True, 0) top_rated_cat = self._update_top_rated_content() # only display the 'More' LinkButton if we have top_rated content if top_rated_cat is not None: self.top_rated_frame.header_implements_more_button() self.top_rated_frame.more.connect('clicked', self.on_category_clicked, top_rated_cat) def _update_whats_new_content(self): # remove any existing children from the grid widget self.whats_new.remove_all() # get top_rated category and docs whats_new_cat = get_category_by_name( self.categories, u"What\u2019s New") # untranslated name if whats_new_cat: docs = whats_new_cat.get_documents(self.db) self.whats_new.add_tiles(self.properties_helper, docs, WHATS_NEW_CAROUSEL_LIMIT) self.whats_new.show_all() return whats_new_cat def _append_whats_new(self): self.whats_new = TileGrid() self.whats_new.connect("application-activated", self.on_application_activated) self.whats_new_frame = FramedHeaderBox() self.whats_new_frame.set_header_label(_(u"What\u2019s New")) self.whats_new_frame.add(self.whats_new) whats_new_cat = self._update_whats_new_content() if whats_new_cat is not None: # only add to the visible right_frame if we actually have it self.right_column.pack_start(self.whats_new_frame, True, True, 0) self.whats_new_frame.header_implements_more_button() self.whats_new_frame.more.connect( 'clicked', self.on_category_clicked, whats_new_cat) def _update_recommended_for_you_content(self): if (self.recommended_for_you_panel and self.recommended_for_you_panel.get_parent()): # disconnect listeners self.recommended_for_you_panel.disconnect_by_func( self.on_application_activated) self.recommended_for_you_panel.disconnect_by_func( self.on_category_clicked) # and remove the panel self.right_column.remove(self.recommended_for_you_panel) self.recommended_for_you_panel = RecommendationsPanelLobby( self.db, self.properties_helper) self.recommended_for_you_panel.connect("application-activated", self.on_application_activated) self.recommended_for_you_panel.connect( 'more-button-clicked', self.on_category_clicked) # until bug #1048912 with the testcase in # tests/gtk3/test_lp1048912.py # is fixed this workaround for the drawing code in FramedHeaderBox # is needed self.recommended_for_you_panel.connect( "size-allocate", self._on_recommended_for_you_panel_size_allocate) self.right_column.pack_start(self.recommended_for_you_panel, True, True, 0) def _on_recommended_for_you_panel_size_allocate(self, rec_panel, stuff): """This workaround can go once the root cause for bug #1048912 is found, see also tests/gtk3/test_lp1048912.py """ self.queue_draw() def _append_recommended_for_you(self): # update will (re)create the widget from scratch self.recommended_for_you_panel = None self._update_recommended_for_you_content() def _update_appcount(self): enq = AppEnquire(self.cache, self.db) distro = get_distro() if get_global_filter().supported_only: query = distro.get_supported_query() else: query = xapian.Query('') length = enq.get_estimated_matches_count(query) text = gettext.ngettext("%(amount)s item", "%(amount)s items", length ) % {'amount': length} self.appcount.set_text(text) def _append_appcount(self): self.appcount = Gtk.Label() self.appcount.set_alignment(0.5, 0.5) self.appcount.set_margin_top(1) self.appcount.set_margin_bottom(4) self.vbox.pack_start(self.appcount, False, True, 0) self._update_appcount() return def build(self): self.header = _('Departments') self._build_homepage_view() self.show_all() return def refresh_apps(self): supported_only = get_global_filter().supported_only if (self._supported_only == supported_only): return self._supported_only = supported_only self._update_top_rated_content() self._update_whats_new_content() self._update_recommended_for_you_content() self._update_appcount() return
class SubCategoryViewGtk(CategoriesViewGtk): def __init__(self, datadir, desktopdir, cache, db, icons, apps_filter, apps_limit=0, root_category=None): CategoriesViewGtk.__init__(self, datadir, desktopdir, cache, db, icons, apps_filter, apps_limit) # state self._built = False # data self.root_category = root_category self.enquire = AppEnquire(self.cache, self.db) self.properties_helper = AppPropertiesHelper( self.db, self.cache, self.icons) # sections self.current_category = None self.departments = None self.top_rated = None self.recommended_for_you_in_cat = None self.appcount = None # widgetry self.vbox.set_margin_left(StockEms.MEDIUM - 2) self.vbox.set_margin_right(StockEms.MEDIUM - 2) self.vbox.set_margin_top(StockEms.MEDIUM) return def _get_sub_top_rated_content(self, category): app_filter = AppFilter(self.db, self.cache) self.enquire.set_query(category.query, limit=TOP_RATED_CAROUSEL_LIMIT, sortmode=SortMethods.BY_TOP_RATED, filter=app_filter, nonapps_visible=NonAppVisibility.ALWAYS_VISIBLE, nonblocking_load=False) return self.enquire.get_documents() @wait_for_apt_cache_ready # be consistent with new apps def _update_sub_top_rated_content(self, category): self.top_rated.remove_all() # FIXME: should this be m = "%s %s" % (_(gettext text), header text) ?? # TRANSLATORS: %s is a category name, like Internet or Development # Tools m = _('Top Rated %(category)s') % { 'category': GObject.markup_escape_text(self.header)} self.top_rated_frame.set_header_label(m) docs = self._get_sub_top_rated_content(category) self._add_tiles_to_flowgrid(docs, self.top_rated, TOP_RATED_CAROUSEL_LIMIT) return def _append_sub_top_rated(self): self.top_rated = FlowableGrid() self.top_rated.set_row_spacing(6) self.top_rated.set_column_spacing(6) self.top_rated_frame = FramedHeaderBox() self.top_rated_frame.pack_start(self.top_rated, True, True, 0) self.vbox.pack_start(self.top_rated_frame, False, True, 0) return def _update_recommended_for_you_in_cat_content(self, category): if (self.recommended_for_you_in_cat and self.recommended_for_you_in_cat.get_parent()): self.vbox.remove(self.recommended_for_you_in_cat) self.recommended_for_you_in_cat = RecommendationsPanelCategory( self, category) # only show the panel in the categories view when the user # is opted in to the recommender service # FIXME: this is needed vs. a simple hide() on the widget because # we do a show_all on the view if self.recommended_for_you_in_cat.recommender_agent.is_opted_in(): self.vbox.pack_start(self.recommended_for_you_in_cat, False, False, 0) def _update_subcat_departments(self, category, num_items): self.departments.remove_all() # set the subcat header m = "<b><big>%s</big></b>" self.subcat_label.set_markup(m % GObject.markup_escape_text( self.header)) # sort Category.name's alphabetically sorted_cats = categories_sorted_by_name(self.categories) enquire = xapian.Enquire(self.db.xapiandb) app_filter = AppFilter(self.db, self.cache) for cat in sorted_cats: # add the subcategory if and only if it is non-empty enquire.set_query(cat.query) if len(enquire.get_mset(0, 1)): tile = CategoryTile(cat.name, cat.iconname) tile.connect('clicked', self.on_category_clicked, cat) self.departments.add_child(tile) # partialy work around a (quite rare) corner case if num_items == 0: enquire.set_query(xapian.Query(xapian.Query.OP_AND, category.query, xapian.Query("ATapplication"))) # assuming that we only want apps is not always correct ^^^ tmp_matches = enquire.get_mset(0, len(self.db), None, app_filter) num_items = tmp_matches.get_matches_estimated() # append an additional button to show all of the items in the category all_cat = Category("All", _("All"), "category-show-all", category.query) name = GObject.markup_escape_text('%s %s' % (_("All"), num_items)) tile = CategoryTile(name, "category-show-all") tile.connect('clicked', self.on_category_clicked, all_cat) self.departments.add_child(tile) self.departments.queue_draw() return num_items def _append_subcat_departments(self): self.subcat_label = Gtk.Label() self.subcat_label.set_alignment(0, 0.5) self.departments = FlowableGrid(paint_grid_pattern=False) self.departments.set_row_spacing(StockEms.SMALL) self.departments.set_column_spacing(StockEms.SMALL) self.departments_frame = FramedBox(spacing=StockEms.MEDIUM, padding=StockEms.MEDIUM) # set x/y-alignment and x/y-expand self.departments_frame.set(0.5, 0.0, 1.0, 1.0) self.departments_frame.pack_start(self.subcat_label, False, False, 0) self.departments_frame.pack_start(self.departments, True, True, 0) # append the departments section to the page self.vbox.pack_start(self.departments_frame, False, True, 0) return def _update_appcount(self, appcount): text = gettext.ngettext("%(amount)s item available", "%(amount)s items available", appcount) % {'amount': appcount} self.appcount.set_text(text) return def _append_appcount(self): self.appcount = Gtk.Label() self.appcount.set_alignment(0.5, 0.5) self.appcount.set_margin_top(1) self.appcount.set_margin_bottom(4) self.vbox.pack_end(self.appcount, False, False, 0) return def _build_subcat_view(self): # these methods add sections to the page # changing order of methods changes order that they appear in the page self._append_subcat_departments() self._append_sub_top_rated() # NOTE that the recommended for you in category view is built and added # in the _update_recommended_for_you_in_cat method (and so is not # needed here) self._append_appcount() self._built = True return def _update_subcat_view(self, category, num_items=0): num_items = self._update_subcat_departments(category, num_items) self._update_sub_top_rated_content(category) self._update_recommended_for_you_in_cat_content(category) self._update_appcount(num_items) self.show_all() return def set_subcategory(self, root_category, num_items=0, block=False): # nothing to do if (root_category is None or self.categories == root_category.subcategories): return self.current_category = root_category self.header = root_category.name self.categories = root_category.subcategories if not self._built: self._build_subcat_view() self._update_subcat_view(root_category, num_items) GObject.idle_add(self.queue_draw) return def refresh_apps(self): supported_only = get_global_filter().supported_only if (self.current_category is None or self._supported_only == supported_only): return self._supported_only = supported_only if not self._built: self._build_subcat_view() self._update_subcat_view(self.current_category) GObject.idle_add(self.queue_draw) return
class LobbyViewGtk(CategoriesViewGtk): def __init__(self, datadir, desktopdir, cache, db, icons, apps_filter, apps_limit=0): CategoriesViewGtk.__init__(self, datadir, desktopdir, cache, db, icons, apps_filter, apps_limit=0) self.top_rated = None self.exhibit_banner = None # sections self.departments = None self.appcount = None # build before connecting the signals to avoid race self.build(desktopdir) # ensure that on db-reopen we refresh the whats-new titles self.db.connect("reopen", self._on_db_reopen) # ensure that updates to the stats are reflected in the UI self.reviews_loader = get_review_loader(self.cache) self.reviews_loader.connect( "refresh-review-stats-finished", self._on_refresh_review_stats) def _on_db_reopen(self, db): self._update_whats_new_content() def _on_refresh_review_stats(self, reviews_loader, review_stats): self._update_top_rated_content() def _build_homepage_view(self): # these methods add sections to the page # changing order of methods changes order that they appear in the page self._append_banner_ads() self.top_hbox = Gtk.HBox(spacing=StockEms.SMALL) top_hbox_alignment = Gtk.Alignment() top_hbox_alignment.set_padding(0, 0, StockEms.MEDIUM - 2, StockEms.MEDIUM - 2) top_hbox_alignment.add(self.top_hbox) self.vbox.pack_start(top_hbox_alignment, False, False, 0) self._append_departments() self.right_column = Gtk.Box.new(Gtk.Orientation.VERTICAL, self.SPACING) self.top_hbox.pack_start(self.right_column, True, True, 0) self._append_whats_new() self._append_top_rated() self._append_recommended_for_you() self._append_appcount() #self._append_video_clips() #self._append_top_of_the_pops #~ def _append_top_of_the_pops(self): #~ self.totp_hbox = Gtk.HBox(spacing=self.SPACING) #~ #~ alignment = Gtk.Alignment() #~ alignment.set_padding(0, 0, self.PADDING, self.PADDING) #~ alignment.add(self.totp_hbox) #~ #~ frame = FramedHeaderBox() #~ frame.header_implements_more_button() #~ frame.set_header_label(_("Most Popular")) #~ #~ label = Gtk.Label.new("Soda pop!!!") #~ label.set_name("placeholder") #~ label.set_size_request(-1, 200) #~ #~ frame.add(label) #~ self.totp_hbox.add(frame) #~ #~ frame = FramedHeaderBox() #~ frame.header_implements_more_button() #~ frame.set_header_label(_("Top Rated")) #~ #~ label = Gtk.Label.new("Demos ftw(?)") #~ label.set_name("placeholder") #~ label.set_size_request(-1, 200) #~ #~ frame.add(label) #~ self.totp_hbox.add(frame) #~ #~ self.vbox.pack_start(alignment, False, False, 0) #~ return #~ def _append_video_clips(self): #~ frame = FramedHeaderBox() #~ frame.set_header_expand(False) #~ frame.set_header_position(HeaderPosition.LEFT) #~ frame.set_header_label(_("Latest Demo Videos")) #~ #~ label = Gtk.Label.new("Videos go here") #~ label.set_name("placeholder") #~ label.set_size_request(-1, 200) #~ #~ frame.add(label) #~ #~ alignment = Gtk.Alignment() #~ alignment.set_padding(0, 0, self.PADDING, self.PADDING) #~ alignment.add(frame) #~ #~ self.vbox.pack_start(alignment, False, False, 0) #~ return def _on_show_exhibits(self, exhibit_banner, exhibit): pkgs = exhibit.package_names.split(",") if len(pkgs) == 1: app = Application("", pkgs[0]) self.emit("application-activated", app) else: query = get_query_for_pkgnames(pkgs) title = exhibit.title_translated untranslated_name = exhibit.package_names # create a temp query cat = Category(untranslated_name, title, None, query, flags=['nonapps-visible']) self.emit("category-selected", cat) def _filter_and_set_exhibits(self, sca_client, exhibit_list): result = [] # filter out those exhibits that are not available in this run for exhibit in exhibit_list: available = all(self.db.is_pkgname_known(p) for p in exhibit.package_names.split(',')) if available: result.append(exhibit) # its ok if result is empty, since set_exhibits() will ignore # empty lists self.exhibit_banner.set_exhibits(result) def _append_banner_ads(self): self.exhibit_banner = ExhibitBanner() self.exhibit_banner.set_exhibits([FeaturedExhibit()]) self.exhibit_banner.connect( "show-exhibits-clicked", self._on_show_exhibits) # query using the agent scagent = SoftwareCenterAgent() scagent.connect("exhibits", self._filter_and_set_exhibits) scagent.query_exhibits() a = Gtk.Alignment() a.set_padding(0, StockEms.SMALL, 0, 0) a.add(self.exhibit_banner) self.vbox.pack_start(a, False, False, 0) def _append_departments(self): # set the departments section to use the label markup we have just # defined cat_vbox = FramedBox(Gtk.Orientation.VERTICAL) self.top_hbox.pack_start(cat_vbox, False, False, 0) # sort Category.name's alphabetically sorted_cats = categories_sorted_by_name(self.categories) mrkup = "<small>%s</small>" for cat in sorted_cats: if 'carousel-only' in cat.flags: continue category_name = mrkup % GObject.markup_escape_text(cat.name) label = LabelTile(category_name, None) label.label.set_margin_left(StockEms.SMALL) label.label.set_margin_right(StockEms.SMALL) label.label.set_alignment(0.0, 0.5) label.label.set_use_markup(True) label.connect('clicked', self.on_category_clicked, cat) cat_vbox.pack_start(label, False, False, 0) return # FIXME: _update_{top_rated,whats_new,recommended_for_you}_content() # duplicates a lot of code def _update_top_rated_content(self): # remove any existing children from the grid widget self.top_rated.remove_all() # get top_rated category and docs top_rated_cat = get_category_by_name( self.categories, u"Top Rated") # untranslated name if top_rated_cat: docs = top_rated_cat.get_documents(self.db) self._add_tiles_to_flowgrid(docs, self.top_rated, TOP_RATED_CAROUSEL_LIMIT) self.top_rated.show_all() return top_rated_cat def _append_top_rated(self): self.top_rated = FlowableGrid() #~ self.top_rated.row_spacing = StockEms.SMALL self.top_rated_frame = FramedHeaderBox() self.top_rated_frame.set_header_label(_("Top Rated")) self.top_rated_frame.add(self.top_rated) self.right_column.pack_start(self.top_rated_frame, True, True, 0) top_rated_cat = self._update_top_rated_content() # only display the 'More' LinkButton if we have top_rated content if top_rated_cat is not None: self.top_rated_frame.header_implements_more_button() self.top_rated_frame.more.connect('clicked', self.on_category_clicked, top_rated_cat) return def _update_whats_new_content(self): # remove any existing children from the grid widget self.whats_new.remove_all() # get top_rated category and docs whats_new_cat = get_category_by_name( self.categories, u"What\u2019s New") # untranslated name if whats_new_cat: docs = whats_new_cat.get_documents(self.db) self._add_tiles_to_flowgrid(docs, self.whats_new, 8) self.whats_new.show_all() return whats_new_cat def _append_whats_new(self): self.whats_new = FlowableGrid() self.whats_new_frame = FramedHeaderBox() self.whats_new_frame.set_header_label(_(u"What\u2019s New")) self.whats_new_frame.add(self.whats_new) whats_new_cat = self._update_whats_new_content() if whats_new_cat is not None: # only add to the visible right_frame if we actually have it self.right_column.pack_start(self.whats_new_frame, True, True, 0) self.whats_new_frame.header_implements_more_button() self.whats_new_frame.more.connect( 'clicked', self.on_category_clicked, whats_new_cat) def _update_recommended_for_you_content(self): if (self.recommended_for_you_panel and self.recommended_for_you_panel.get_parent()): self.bottom_hbox.remove(self.recommended_for_you_panel) self.recommended_for_you_panel = RecommendationsPanelLobby(self) self.bottom_hbox.pack_start(self.recommended_for_you_panel, True, True, 0) def _append_recommended_for_you(self): # TODO: This space will initially contain an opt-in screen, and this # will update to the tile view of recommended apps when ready # see https://wiki.ubuntu.com/SoftwareCenter#Home_screen self.bottom_hbox = Gtk.HBox(spacing=StockEms.SMALL) bottom_hbox_alignment = Gtk.Alignment() bottom_hbox_alignment.set_padding(0, 0, StockEms.MEDIUM - 2, StockEms.MEDIUM - 2) bottom_hbox_alignment.add(self.bottom_hbox) self.vbox.pack_start(bottom_hbox_alignment, False, False, 0) # TODO: During development, place the "Recommended For You" panel # at the bottom, but swap this with the Top Rated panel once # the recommended for you pieces are done and deployed # see https://wiki.ubuntu.com/SoftwareCenter#Home_screen self.recommended_for_you_panel = RecommendationsPanelLobby(self) self.bottom_hbox.pack_start(self.recommended_for_you_panel, True, True, 0) def _update_appcount(self): enq = AppEnquire(self.cache, self.db) distro = get_distro() if get_global_filter().supported_only: query = distro.get_supported_query() else: query = xapian.Query('') length = enq.get_estimated_matches_count(query) text = gettext.ngettext("%(amount)s item", "%(amount)s items", length ) % {'amount': length} self.appcount.set_text(text) def _append_appcount(self): self.appcount = Gtk.Label() self.appcount.set_alignment(0.5, 0.5) self.appcount.set_margin_top(1) self.appcount.set_margin_bottom(4) self.vbox.pack_start(self.appcount, False, True, 0) self._update_appcount() return def build(self, desktopdir): self.categories = self.parse_applications_menu(desktopdir) self.header = _('Departments') self._build_homepage_view() self.show_all() return def refresh_apps(self): supported_only = get_global_filter().supported_only if (self._supported_only == supported_only): return self._supported_only = supported_only self._update_top_rated_content() self._update_whats_new_content() self._update_recommended_for_you_content() self._update_appcount() return # stubs for the time being, we may reuse them if we get dynamic content # again def stop_carousels(self): pass def start_carousels(self): pass
def test_visual_glitch_lp1048912(self): win = Gtk.Window() win.set_size_request(500, 300) scroll = Gtk.ScrolledWindow() win.add(scroll) viewport = Viewport() scroll.add(viewport) top_hbox = Gtk.HBox() viewport.add(top_hbox) right_column = Gtk.Box.new(Gtk.Orientation.VERTICAL, 0) top_hbox.pack_start(right_column, True, True, 0) apptiles = Gtk.VBox() apptiles_frame = FramedHeaderBox() apptiles_frame.set_name("apptiles top") apptiles_frame.set_header_label("Frame1") apptiles_frame.add(apptiles) right_column.pack_start(apptiles_frame, True, True, 0) apptiles_frame.header_implements_more_button() apptiles2 = Gtk.VBox() apptiles2_frame = FramedHeaderBox() apptiles2_frame.set_name("apptiles bottom") apptiles2_frame.set_header_label("Frame2") apptiles2_frame.add(apptiles2) right_column.pack_start(apptiles2_frame, True, True, 0) apptiles2_frame.header_implements_more_button() # this delayed adding of the tiles causes a visual glitch like # described in #1048912 on the top of the bottom frame the line # will not be drawn correctly - any subsequent redraw of the # window will fix it GLib.timeout_add(1000, add_tiles, apptiles2) # this "viewport.queue_draw()" will fix the glitch #GLib.timeout_add_seconds(2, lambda: viewport.queue_draw()) # stop the test GLib.timeout_add_seconds(3, Gtk.main_quit) win.connect("destroy", Gtk.main_quit) win.show_all() Gtk.main()
class SubCategoryViewGtk(CategoriesViewGtk): def __init__(self, datadir, desktopdir, cache, db, icons, apps_filter, apps_limit=0, root_category=None): CategoriesViewGtk.__init__(self, datadir, desktopdir, cache, db, icons, apps_filter, apps_limit) # state self._built = False # data self.root_category = root_category self.enquire = AppEnquire(self.cache, self.db) self.helper = AppPropertiesHelper(self.db, self.cache, self.icons) # sections self.current_category = None self.departments = None self.toprated = None self.appcount = None # widgetry self.vbox.set_margin_left(StockEms.MEDIUM - 2) self.vbox.set_margin_right(StockEms.MEDIUM - 2) self.vbox.set_margin_top(StockEms.MEDIUM) return def _get_sub_toprated_content(self, category): app_filter = AppFilter(self.db, self.cache) self.enquire.set_query(category.query, limit=TOP_RATED_CAROUSEL_LIMIT, sortmode=SortMethods.BY_TOP_RATED, filter=app_filter, nonapps_visible=NonAppVisibility.ALWAYS_VISIBLE, nonblocking_load=False) return self.enquire.get_documents() @wait_for_apt_cache_ready # be consistent with new apps def _update_sub_toprated_content(self, category): self.toprated.remove_all() # FIXME: should this be m = "%s %s" % (_(gettext text), header text) ?? m = _('Top Rated %s') % GObject.markup_escape_text(self.header) self.toprated_frame.set_header_label(m) docs = self._get_sub_toprated_content(category) self._add_tiles_to_flowgrid(docs, self.toprated, TOP_RATED_CAROUSEL_LIMIT) return def _append_sub_toprated(self): self.toprated = FlowableGrid() self.toprated.set_row_spacing(6) self.toprated.set_column_spacing(6) self.toprated_frame = FramedHeaderBox() self.toprated_frame.pack_start(self.toprated, True, True, 0) self.vbox.pack_start(self.toprated_frame, False, True, 0) return def _update_subcat_departments(self, category, num_items): self.departments.remove_all() # set the subcat header m = "<b><big>%s</big></b>" self.subcat_label.set_markup(m % GObject.markup_escape_text(self.header)) # sort Category.name's alphabetically sorted_cats = categories_sorted_by_name(self.categories) enquire = xapian.Enquire(self.db.xapiandb) app_filter = AppFilter(self.db, self.cache) for cat in sorted_cats: # add the subcategory if and only if it is non-empty enquire.set_query(cat.query) if len(enquire.get_mset(0, 1)): tile = CategoryTile(cat.name, cat.iconname) tile.connect('clicked', self.on_category_clicked, cat) self.departments.add_child(tile) # partialy work around a (quite rare) corner case if num_items == 0: enquire.set_query( xapian.Query(xapian.Query.OP_AND, category.query, xapian.Query("ATapplication"))) # assuming that we only want apps is not always correct ^^^ tmp_matches = enquire.get_mset(0, len(self.db), None, app_filter) num_items = tmp_matches.get_matches_estimated() # append an additional button to show all of the items in the category all_cat = Category("All", _("All"), "category-show-all", category.query) name = GObject.markup_escape_text('%s %s' % (_("All"), num_items)) tile = CategoryTile(name, "category-show-all") tile.connect('clicked', self.on_category_clicked, all_cat) self.departments.add_child(tile) self.departments.queue_draw() return num_items def _append_subcat_departments(self): self.subcat_label = Gtk.Label() self.subcat_label.set_alignment(0, 0.5) self.departments = FlowableGrid(paint_grid_pattern=False) self.departments.set_row_spacing(StockEms.SMALL) self.departments.set_column_spacing(StockEms.SMALL) frame = FramedBox(spacing=StockEms.MEDIUM, padding=StockEms.MEDIUM) # set x/y-alignment and x/y-expand frame.set(0.5, 0.0, 1.0, 1.0) frame.pack_start(self.subcat_label, False, False, 0) frame.pack_start(self.departments, True, True, 0) # append the departments section to the page self.vbox.pack_start(frame, False, True, 0) return def _update_appcount(self, appcount): text = gettext.ngettext("%(amount)s item available", "%(amount)s items available", appcount) % { 'amount': appcount, } self.appcount.set_text(text) return def _append_appcount(self): self.appcount = Gtk.Label() self.appcount.set_alignment(0.5, 0.5) self.appcount.set_margin_top(1) self.appcount.set_margin_bottom(4) self.vbox.pack_end(self.appcount, False, False, 0) return def _build_subcat_view(self): # these methods add sections to the page # changing order of methods changes order that they appear in the page self._append_subcat_departments() self._append_sub_toprated() self._append_appcount() self._built = True return def _update_subcat_view(self, category, num_items=0): num_items = self._update_subcat_departments(category, num_items) self._update_sub_toprated_content(category) self._update_appcount(num_items) self.show_all() return def set_subcategory(self, root_category, num_items=0, block=False): # nothing to do if (root_category is None or self.categories == root_category.subcategories): return self.current_category = root_category self.header = root_category.name self.categories = root_category.subcategories if not self._built: self._build_subcat_view() self._update_subcat_view(root_category, num_items) GObject.idle_add(self.queue_draw) return def refresh_apps(self): supported_only = get_global_filter().supported_only if (self.current_category is None or self._supported_only == supported_only): return self._supported_only = supported_only if not self._built: self._build_subcat_view() self._update_subcat_view(self.current_category) GObject.idle_add(self.queue_draw) return
class LobbyViewGtk(CategoriesViewGtk): def __init__(self, datadir, desktopdir, cache, db, icons, apps_filter, apps_limit=0): CategoriesViewGtk.__init__(self, datadir, desktopdir, cache, db, icons, apps_filter, apps_limit=0) self.top_rated = None self.exhibit_banner = None # sections self.departments = None self.appcount = None # build before connecting the signals to avoid race self.build(desktopdir) # ensure that on db-reopen we refresh the whats-new titles self.db.connect("reopen", self._on_db_reopen) # ensure that updates to the stats are reflected in the UI self.reviews_loader = get_review_loader(self.cache) self.reviews_loader.connect("refresh-review-stats-finished", self._on_refresh_review_stats) def _on_db_reopen(self, db): self._update_whats_new_content() def _on_refresh_review_stats(self, reviews_loader, review_stats): self._update_top_rated_content() def _build_homepage_view(self): # these methods add sections to the page # changing order of methods changes order that they appear in the page self._append_banner_ads() self.top_hbox = Gtk.HBox(spacing=StockEms.SMALL) top_hbox_alignment = Gtk.Alignment() top_hbox_alignment.set_padding(0, 0, StockEms.MEDIUM - 2, StockEms.MEDIUM - 2) top_hbox_alignment.add(self.top_hbox) self.vbox.pack_start(top_hbox_alignment, False, False, 0) self._append_departments() self.right_column = Gtk.Box.new(Gtk.Orientation.VERTICAL, self.SPACING) self.top_hbox.pack_start(self.right_column, True, True, 0) self._append_whats_new() self._append_top_rated() self._append_recommended_for_you() self._append_appcount() #self._append_video_clips() #self._append_top_of_the_pops #~ def _append_top_of_the_pops(self): #~ self.totp_hbox = Gtk.HBox(spacing=self.SPACING) #~ #~ alignment = Gtk.Alignment() #~ alignment.set_padding(0, 0, self.PADDING, self.PADDING) #~ alignment.add(self.totp_hbox) #~ #~ frame = FramedHeaderBox() #~ frame.header_implements_more_button() #~ frame.set_header_label(_("Most Popular")) #~ #~ label = Gtk.Label.new("Soda pop!!!") #~ label.set_name("placeholder") #~ label.set_size_request(-1, 200) #~ #~ frame.add(label) #~ self.totp_hbox.add(frame) #~ #~ frame = FramedHeaderBox() #~ frame.header_implements_more_button() #~ frame.set_header_label(_("Top Rated")) #~ #~ label = Gtk.Label.new("Demos ftw(?)") #~ label.set_name("placeholder") #~ label.set_size_request(-1, 200) #~ #~ frame.add(label) #~ self.totp_hbox.add(frame) #~ #~ self.vbox.pack_start(alignment, False, False, 0) #~ return #~ def _append_video_clips(self): #~ frame = FramedHeaderBox() #~ frame.set_header_expand(False) #~ frame.set_header_position(HeaderPosition.LEFT) #~ frame.set_header_label(_("Latest Demo Videos")) #~ #~ label = Gtk.Label.new("Videos go here") #~ label.set_name("placeholder") #~ label.set_size_request(-1, 200) #~ #~ frame.add(label) #~ #~ alignment = Gtk.Alignment() #~ alignment.set_padding(0, 0, self.PADDING, self.PADDING) #~ alignment.add(frame) #~ #~ self.vbox.pack_start(alignment, False, False, 0) #~ return def _on_show_exhibits(self, exhibit_banner, exhibit): pkgs = exhibit.package_names.split(",") if len(pkgs) == 1: app = Application("", pkgs[0]) self.emit("application-activated", app) else: query = get_query_for_pkgnames(pkgs) title = exhibit.title_translated untranslated_name = exhibit.package_names # create a temp query cat = Category(untranslated_name, title, None, query, flags=['nonapps-visible']) self.emit("category-selected", cat) def _filter_and_set_exhibits(self, sca_client, exhibit_list): result = [] # filter out those exhibits that are not available in this run for exhibit in exhibit_list: available = all( self.db.is_pkgname_known(p) for p in exhibit.package_names.split(',')) if available: result.append(exhibit) # its ok if result is empty, since set_exhibits() will ignore # empty lists self.exhibit_banner.set_exhibits(result) def _append_banner_ads(self): self.exhibit_banner = ExhibitBanner() self.exhibit_banner.set_exhibits([FeaturedExhibit()]) self.exhibit_banner.connect("show-exhibits-clicked", self._on_show_exhibits) # query using the agent scagent = SoftwareCenterAgent() scagent.connect("exhibits", self._filter_and_set_exhibits) scagent.query_exhibits() a = Gtk.Alignment() a.set_padding(0, StockEms.SMALL, 0, 0) a.add(self.exhibit_banner) self.vbox.pack_start(a, False, False, 0) def _append_departments(self): # set the departments section to use the label markup we have just # defined cat_vbox = FramedBox(Gtk.Orientation.VERTICAL) self.top_hbox.pack_start(cat_vbox, False, False, 0) # sort Category.name's alphabetically sorted_cats = categories_sorted_by_name(self.categories) mrkup = "<small>%s</small>" for cat in sorted_cats: if 'carousel-only' in cat.flags: continue category_name = mrkup % GObject.markup_escape_text(cat.name) label = LabelTile(category_name, None) label.label.set_margin_left(StockEms.SMALL) label.label.set_margin_right(StockEms.SMALL) label.label.set_alignment(0.0, 0.5) label.label.set_use_markup(True) label.connect('clicked', self.on_category_clicked, cat) cat_vbox.pack_start(label, False, False, 0) return # FIXME: _update_{top_rated,whats_new,recommended_for_you}_content() # duplicates a lot of code def _update_top_rated_content(self): # remove any existing children from the grid widget self.top_rated.remove_all() # get top_rated category and docs top_rated_cat = get_category_by_name(self.categories, u"Top Rated") # untranslated name if top_rated_cat: docs = top_rated_cat.get_documents(self.db) self._add_tiles_to_flowgrid(docs, self.top_rated, TOP_RATED_CAROUSEL_LIMIT) self.top_rated.show_all() return top_rated_cat def _append_top_rated(self): self.top_rated = FlowableGrid() #~ self.top_rated.row_spacing = StockEms.SMALL self.top_rated_frame = FramedHeaderBox() self.top_rated_frame.set_header_label(_("Top Rated")) self.top_rated_frame.add(self.top_rated) self.right_column.pack_start(self.top_rated_frame, True, True, 0) top_rated_cat = self._update_top_rated_content() # only display the 'More' LinkButton if we have top_rated content if top_rated_cat is not None: self.top_rated_frame.header_implements_more_button() self.top_rated_frame.more.connect('clicked', self.on_category_clicked, top_rated_cat) return def _update_whats_new_content(self): # remove any existing children from the grid widget self.whats_new.remove_all() # get top_rated category and docs whats_new_cat = get_category_by_name( self.categories, u"What\u2019s New") # untranslated name if whats_new_cat: docs = whats_new_cat.get_documents(self.db) self._add_tiles_to_flowgrid(docs, self.whats_new, 8) self.whats_new.show_all() return whats_new_cat def _append_whats_new(self): self.whats_new = FlowableGrid() self.whats_new_frame = FramedHeaderBox() self.whats_new_frame.set_header_label(_(u"What\u2019s New")) self.whats_new_frame.add(self.whats_new) whats_new_cat = self._update_whats_new_content() if whats_new_cat is not None: # only add to the visible right_frame if we actually have it self.right_column.pack_start(self.whats_new_frame, True, True, 0) self.whats_new_frame.header_implements_more_button() self.whats_new_frame.more.connect('clicked', self.on_category_clicked, whats_new_cat) def _update_recommended_for_you_content(self): if (self.recommended_for_you_panel and self.recommended_for_you_panel.get_parent()): self.bottom_hbox.remove(self.recommended_for_you_panel) self.recommended_for_you_panel = RecommendationsPanelLobby(self) self.bottom_hbox.pack_start(self.recommended_for_you_panel, True, True, 0) def _append_recommended_for_you(self): # TODO: This space will initially contain an opt-in screen, and this # will update to the tile view of recommended apps when ready # see https://wiki.ubuntu.com/SoftwareCenter#Home_screen self.bottom_hbox = Gtk.HBox(spacing=StockEms.SMALL) bottom_hbox_alignment = Gtk.Alignment() bottom_hbox_alignment.set_padding(0, 0, StockEms.MEDIUM - 2, StockEms.MEDIUM - 2) bottom_hbox_alignment.add(self.bottom_hbox) self.vbox.pack_start(bottom_hbox_alignment, False, False, 0) # TODO: During development, place the "Recommended For You" panel # at the bottom, but swap this with the Top Rated panel once # the recommended for you pieces are done and deployed # see https://wiki.ubuntu.com/SoftwareCenter#Home_screen self.recommended_for_you_panel = RecommendationsPanelLobby(self) self.bottom_hbox.pack_start(self.recommended_for_you_panel, True, True, 0) def _update_appcount(self): enq = AppEnquire(self.cache, self.db) distro = get_distro() if get_global_filter().supported_only: query = distro.get_supported_query() else: query = xapian.Query('') length = enq.get_estimated_matches_count(query) text = gettext.ngettext("%(amount)s item", "%(amount)s items", length) % { 'amount': length } self.appcount.set_text(text) def _append_appcount(self): self.appcount = Gtk.Label() self.appcount.set_alignment(0.5, 0.5) self.appcount.set_margin_top(1) self.appcount.set_margin_bottom(4) self.vbox.pack_start(self.appcount, False, True, 0) self._update_appcount() return def build(self, desktopdir): self.categories = self.parse_applications_menu(desktopdir) self.header = _('Departments') self._build_homepage_view() self.show_all() return def refresh_apps(self): supported_only = get_global_filter().supported_only if (self._supported_only == supported_only): return self._supported_only = supported_only self._update_top_rated_content() self._update_whats_new_content() self._update_recommended_for_you_content() self._update_appcount() return # stubs for the time being, we may reuse them if we get dynamic content # again def stop_carousels(self): pass def start_carousels(self): pass