Example #1
0
 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
Example #2
0
 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()
Example #4
0
 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
Example #5
0
 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)
Example #6
0
 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)
Example #7
0
    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)
Example #8
0
 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)
Example #9
0
 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
Example #10
0
 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
Example #11
0
    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)
Example #13
0
    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
Example #14
0
 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
Example #15
0
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
Example #16
0
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
Example #17
0
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
Example #18
0
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()
Example #20
0
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
Example #21
0
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
Example #22
0
    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()