Exemple #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
class RecommendationsPanelCategory(RecommendationsPanel):
    """
    Panel for use in the category view that displays recommended apps for
    the given category
    """
    def __init__(self, catview, subcategory):
        RecommendationsPanel.__init__(self, catview)
        self.subcategory = subcategory
        if self.subcategory:
            self.set_header_label(GObject.markup_escape_text(utf8(
                _("Recommended For You in %s")) % utf8(self.subcategory.name)))
        self.recommended_for_you_content = None
        if self.recommender_agent.is_opted_in():
            self._update_recommended_for_you_content()
        else:
            self._hide_recommended_for_you_panel()

    def _update_recommended_for_you_content(self):
        # destroy the old content to ensure we don't see it twice
        if self.recommended_for_you_content:
            self.recommended_for_you_content.destroy()
        # add the new stuff
        self.recommended_for_you_content = FlowableGrid()
        self.add(self.recommended_for_you_content)
        self.spinner_notebook.show_spinner(_(u"Receiving recommendations…"))
        # get the recommendations from the recommender agent
        self.recommended_for_you_cat = RecommendedForYouCategory(
                                            subcategory=self.subcategory)
        self.recommended_for_you_cat.connect(
                                    'needs-refresh',
                                    self._on_recommended_for_you_agent_refresh)
        self.recommended_for_you_cat.connect('recommender-agent-error',
                                             self._on_recommender_agent_error)

    def _on_recommended_for_you_agent_refresh(self, cat):
        self.header_implements_more_button()
        docs = cat.get_documents(self.catview.db)
        # display the recommendedations
        if len(docs) > 0:
            self.catview._add_tiles_to_flowgrid(docs,
                                        self.recommended_for_you_content, 12)
            self.recommended_for_you_content.show_all()
            self.spinner_notebook.hide_spinner()
            self.more.connect('clicked',
                              self.catview.on_category_clicked,
                              cat)
            self.header.queue_draw()
            self.show_all()
        else:
            # hide the panel if we have no recommendations to show
            self._hide_recommended_for_you_panel()
Exemple #3
0
 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
class RecommendationsPanelCategory(RecommendationsPanel):
    """
    Panel for use in the category view that displays recommended apps for
    the given category
    """
    def __init__(self, catview, subcategory):
        RecommendationsPanel.__init__(self, catview)
        self.subcategory = subcategory
        if self.subcategory:
            self.set_header_label(
                GObject.markup_escape_text(
                    utf8(_("Recommended For You in %s")) %
                    utf8(self.subcategory.name)))
        self.recommended_for_you_content = None
        if self.recommender_agent.is_opted_in():
            self._update_recommended_for_you_content()
        else:
            self._hide_recommended_for_you_panel()

    def _update_recommended_for_you_content(self):
        # destroy the old content to ensure we don't see it twice
        if self.recommended_for_you_content:
            self.recommended_for_you_content.destroy()
        # add the new stuff
        self.recommended_for_you_content = FlowableGrid()
        self.add(self.recommended_for_you_content)
        self.spinner_notebook.show_spinner(_(u"Receiving recommendations…"))
        # get the recommendations from the recommender agent
        self.recommended_for_you_cat = RecommendedForYouCategory(
            subcategory=self.subcategory)
        self.recommended_for_you_cat.connect(
            'needs-refresh', self._on_recommended_for_you_agent_refresh)
        self.recommended_for_you_cat.connect('recommender-agent-error',
                                             self._on_recommender_agent_error)

    def _on_recommended_for_you_agent_refresh(self, cat):
        self.header_implements_more_button()
        docs = cat.get_documents(self.catview.db)
        # display the recommendedations
        if len(docs) > 0:
            self.catview._add_tiles_to_flowgrid(
                docs, self.recommended_for_you_content, 12)
            self.recommended_for_you_content.show_all()
            self.spinner_notebook.hide_spinner()
            self.more.connect('clicked', self.catview.on_category_clicked, cat)
            self.header.queue_draw()
            self.show_all()
        else:
            # hide the panel if we have no recommendations to show
            self._hide_recommended_for_you_panel()
 def _update_recommended_for_you_content(self):
     # destroy the old content to ensure we don't see it twice
     if self.recommended_for_you_content:
         self.recommended_for_you_content.destroy()
     # add the new stuff
     self.recommended_for_you_content = FlowableGrid()
     self.add(self.recommended_for_you_content)
     self.spinner_notebook.show_spinner(_(u"Receiving recommendations…"))
     # get the recommendations from the recommender agent
     self.recommended_for_you_cat = RecommendedForYouCategory(
         subcategory=self.subcategory)
     self.recommended_for_you_cat.connect(
         'needs-refresh', self._on_recommended_for_you_agent_refresh)
     self.recommended_for_you_cat.connect('recommender-agent-error',
                                          self._on_recommender_agent_error)
class RecommendationsPanelDetails(RecommendationsPanel):
    """
    Panel for use in the details view to display recommendations for a given
    application
    """
    def __init__(self, catview):
        RecommendationsPanel.__init__(self, catview)
        self.set_header_label(_(u"People Also Installed"))
        self.app_recommendations_content = FlowableGrid()
        self.add(self.app_recommendations_content)

    def set_pkgname(self, pkgname):
        self.pkgname = pkgname
        self._update_app_recommendations_content()

    def _update_app_recommendations_content(self):
        if self.app_recommendations_content:
            self.app_recommendations_content.remove_all()
        self.spinner_notebook.show_spinner(_(u"Receiving recommendations…"))
        # get the recommendations from the recommender agent
        self.app_recommendations_cat = AppRecommendationsCategory(self.pkgname)
        self.app_recommendations_cat.connect(
                                    'needs-refresh',
                                    self._on_app_recommendations_agent_refresh)
        self.app_recommendations_cat.connect('recommender-agent-error',
                                             self._on_recommender_agent_error)

    def _on_app_recommendations_agent_refresh(self, cat):
        docs = cat.get_documents(self.catview.db)
        # display the recommendations
        if len(docs) > 0:
            self.catview._add_tiles_to_flowgrid(docs,
                                        self.app_recommendations_content, 3)
            self.show_all()
            self.spinner_notebook.hide_spinner()
        else:
            self._hide_app_recommendations_panel()

    def _on_recommender_agent_error(self, agent, msg):
        LOG.warn("Error while accessing the recommender agent for the "
                 "details view recommendations: %s" % msg)
        # TODO: temporary, instead we will display cached recommendations here
        self._hide_app_recommendations_panel()

    def _hide_app_recommendations_panel(self):
        # and hide the pane
        self.hide()
class RecommendationsPanelDetails(RecommendationsPanel):
    """
    Panel for use in the details view to display recommendations for a given
    application
    """
    def __init__(self, catview):
        RecommendationsPanel.__init__(self, catview)
        self.set_header_label(_(u"People Also Installed"))
        self.app_recommendations_content = FlowableGrid()
        self.add(self.app_recommendations_content)

    def set_pkgname(self, pkgname):
        self.pkgname = pkgname
        self._update_app_recommendations_content()

    def _update_app_recommendations_content(self):
        if self.app_recommendations_content:
            self.app_recommendations_content.remove_all()
        self.spinner_notebook.show_spinner(_(u"Receiving recommendations…"))
        # get the recommendations from the recommender agent
        self.app_recommendations_cat = AppRecommendationsCategory(self.pkgname)
        self.app_recommendations_cat.connect(
            'needs-refresh', self._on_app_recommendations_agent_refresh)
        self.app_recommendations_cat.connect('recommender-agent-error',
                                             self._on_recommender_agent_error)

    def _on_app_recommendations_agent_refresh(self, cat):
        docs = cat.get_documents(self.catview.db)
        # display the recommendations
        if len(docs) > 0:
            self.catview._add_tiles_to_flowgrid(
                docs, self.app_recommendations_content, 3)
            self.show_all()
            self.spinner_notebook.hide_spinner()
        else:
            self._hide_app_recommendations_panel()

    def _on_recommender_agent_error(self, agent, msg):
        LOG.warn("Error while accessing the recommender agent for the "
                 "details view recommendations: %s" % msg)
        # TODO: temporary, instead we will display cached recommendations here
        self._hide_app_recommendations_panel()

    def _hide_app_recommendations_panel(self):
        # and hide the pane
        self.hide()
 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
Exemple #9
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)
Exemple #10
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
 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_recommended_for_you_content(self):
     # destroy the old content to ensure we don't see it twice
     if self.recommended_for_you_content:
         self.recommended_for_you_content.destroy()
     # add the new stuff
     self.recommended_for_you_content = FlowableGrid()
     self.add(self.recommended_for_you_content)
     self.spinner_notebook.show_spinner(_(u"Receiving recommendations…"))
     # get the recommendations from the recommender agent
     self.recommended_for_you_cat = RecommendedForYouCategory(
                                         subcategory=self.subcategory)
     self.recommended_for_you_cat.connect(
                                 'needs-refresh',
                                 self._on_recommended_for_you_agent_refresh)
     self.recommended_for_you_cat.connect('recommender-agent-error',
                                          self._on_recommender_agent_error)
Exemple #13
0
 def _update_recommended_for_you_content(self):
     # destroy the old content to ensure we don't see it twice
     # (also removes the opt-in panel if it was there)
     if self.recommended_for_you_content:
         self.recommended_for_you_content.destroy()
     # add the new stuff
     self.header_implements_more_button()
     self.recommended_for_you_content = FlowableGrid()
     self.add(self.recommended_for_you_content)
     self.spinner_notebook.show_spinner(_(u"Receiving recommendations…"))
     # get the recommendations from the recommender agent
     self.recommended_for_you_cat = RecommendedForYouCategory()
     self.recommended_for_you_cat.connect(
                                 'needs-refresh',
                                 self._on_recommended_for_you_agent_refresh)
     self.recommended_for_you_cat.connect('recommender-agent-error',
                                          self._on_recommender_agent_error)
 def __init__(self, catview):
     RecommendationsPanel.__init__(self, catview)
     self.set_header_label(_(u"People Also Installed"))
     self.app_recommendations_content = FlowableGrid()
     self.add(self.app_recommendations_content)
Exemple #15
0
class RecommendationsPanelLobby(RecommendationsPanel):
    """
    Panel for use in the lobby view that manages the recommendations
    experience, includes the initial opt-in screen and display of
    recommendations once they have been received from the recommender agent
    """
    __gsignals__ = {
        "recommendations-opt-in": (GObject.SIGNAL_RUN_LAST,
                                   GObject.TYPE_NONE,
                                   (GObject.TYPE_STRING,),
                                  ),
        "recommendations-opt-out": (GObject.SIGNAL_RUN_LAST,
                                    GObject.TYPE_NONE,
                                    (),
                                   ),
        }

    def __init__(self, catview):
        RecommendationsPanel.__init__(self, catview)
        self.set_header_label(_(u"Recommended for You"))

        # if we already have a recommender UUID, then the user is already
        # opted-in to the recommender service
        self.recommended_for_you_content = None
        if self.recommender_agent.recommender_uuid:
            self._update_recommended_for_you_content()
        else:
            self._show_opt_in_view()

    def _show_opt_in_view(self):
        # opt in box
        vbox = Gtk.Box.new(Gtk.Orientation.VERTICAL, StockEms.MEDIUM)
        vbox.set_border_width(StockEms.LARGE)
        self.opt_in_vbox = vbox  # for tests
        self.recommended_for_you_content = vbox  # hook it up to the rest

        self.add(self.recommended_for_you_content)

        # opt in button
        button = Gtk.Button(_("Turn On Recommendations"))
        button.connect("clicked", self._on_opt_in_button_clicked)
        hbox = Gtk.Box(Gtk.Orientation.HORIZONTAL)
        hbox.pack_start(button, False, False, 0)
        vbox.pack_start(hbox, False, False, 0)
        self.opt_in_button = button  # for tests

        # opt in text
        text = _("To make recommendations, Ubuntu Software Center "
                 "will occasionally send to Canonical an anonymous list "
                 "of software currently installed.")
        label = Gtk.Label(text)
        label.set_alignment(0, 0.5)
        label.set_line_wrap(True)
        vbox.pack_start(label, False, False, 0)

    def _on_opt_in_button_clicked(self, button):
        # we upload the user profile here, and only after this is finished
        # do we fire the request for recommendations and finally display
        # them here -- a spinner is shown for this process (the spec
        # wants a progress bar, but we don't have access to real-time
        # progress info)
        self._upload_user_profile_and_get_recommendations()

    def _upload_user_profile_and_get_recommendations(self):
        # initiate upload of the user profile here
        self._upload_user_profile()

    def _upload_user_profile(self):
        self.spinner_notebook.show_spinner(_(u"Submitting inventory…"))
        self.recommender_agent.connect("submit-profile-finished",
                                  self._on_profile_submitted)
        self.recommender_agent.connect("error",
                                  self._on_profile_submitted_error)
        self.recommender_agent.post_submit_profile(self.catview.db)

    def _on_profile_submitted(self, agent, profile, recommender_uuid):
        # after the user profile data has been uploaded, make the request
        # and load the the recommended_for_you content
        LOG.debug("The recommendations profile has been successfully "
                  "submitted to the recommender agent")
        self.emit("recommendations-opt-in", recommender_uuid)
        self._update_recommended_for_you_content()

    def _on_profile_submitted_error(self, agent, msg):
        LOG.warn("Error while submitting the recommendations profile to the "
                 "recommender agent: %s" % msg)
        # TODO: handle this! display an error message in the panel
        self._hide_recommended_for_you_panel()

    def _update_recommended_for_you_content(self):
        # destroy the old content to ensure we don't see it twice
        # (also removes the opt-in panel if it was there)
        if self.recommended_for_you_content:
            self.recommended_for_you_content.destroy()
        # add the new stuff
        self.header_implements_more_button()
        self.recommended_for_you_content = FlowableGrid()
        self.add(self.recommended_for_you_content)
        self.spinner_notebook.show_spinner(_(u"Receiving recommendations…"))
        # get the recommendations from the recommender agent
        self.recommended_for_you_cat = RecommendedForYouCategory()
        self.recommended_for_you_cat.connect(
                                    'needs-refresh',
                                    self._on_recommended_for_you_agent_refresh)
        self.recommended_for_you_cat.connect('recommender-agent-error',
                                             self._on_recommender_agent_error)

    def _on_recommended_for_you_agent_refresh(self, cat):
        docs = cat.get_documents(self.catview.db)
        # display the recommendedations
        if len(docs) > 0:
            self.catview._add_tiles_to_flowgrid(docs,
                                        self.recommended_for_you_content, 8)
            self.recommended_for_you_content.show_all()
            self.spinner_notebook.hide_spinner()
            self.more.connect('clicked',
                              self.catview.on_category_clicked,
                              cat)
        else:
            # TODO: this test for zero docs is temporary and will not be
            # needed once the recommendation agent is up and running
            self._hide_recommended_for_you_panel()

    def _on_recommender_agent_error(self, agent, msg):
        LOG.warn("Error while accessing the recommender agent for the "
                 "lobby recommendations: %s" % msg)
        # TODO: temporary, instead we will display cached recommendations here
        self._hide_recommended_for_you_panel()

    def _hide_recommended_for_you_panel(self):
        # and hide the pane
        self.hide()
Exemple #16
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
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
 def __init__(self, catview):
     RecommendationsPanel.__init__(self, catview)
     self.set_header_label(_(u"People Also Installed"))
     self.app_recommendations_content = FlowableGrid()
     self.add(self.app_recommendations_content)