def get_scrolled_window(self):
     scrolled_window = ScrolledWindow(0, 0)
     scrolled_window.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
     scrolled_window.connect("vscrollbar-state-changed",
                             self.__on_vscrollbar_state_changed)
     scrolled_window.add_child(self)
     return scrolled_window
 def get_scrolled_window(self):
     scrolled_window = ScrolledWindow(0, 0)
     scrolled_window.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
     scrolled_window.connect("vscrollbar-state-changed",
                             self.__on_vscrollbar_state_changed)
     scrolled_window.add_child(self)
     return scrolled_window
Example #3
0
class DetailPage(gtk.HBox):
    '''
    class docs
    '''

    PADDING_Y = 20

    ICON_SIZE = 64
    ICON_PADDING_X = 50

    STAR_PADDING_X = 36
    STAR_PADDING_Y = 12
    STAR_SIZE = 13

    MARK_NUMBER_SIZE = 11
    MARK_NUMBER_PADDING_X = 4
    MARK_NUMBER_PADDING_Y = 10

    INFO_RENDER_X = 10
    INFO_RENDER_Y = 140
    INFO_RENDER_HEIGHT = 18
    INFO_CATEGORY_RENDER_Y = INFO_RENDER_Y + INFO_RENDER_HEIGHT
    INFO_VERSION_RENDER_Y = INFO_RENDER_Y + INFO_RENDER_HEIGHT * 2
    INFO_SIZE_RENDER_Y = INFO_RENDER_Y + INFO_RENDER_HEIGHT * 3
    INFO_DOWNLOAD_RENDER_Y = INFO_RENDER_Y + INFO_RENDER_HEIGHT * 4
    INFO_HOMEPAGE_RENDER_Y = INFO_RENDER_Y + INFO_RENDER_HEIGHT * 5

    LEFT_INFO_PADDING_X = 18
    LEFT_INFO_PADDING_Y = 50

    LEFT_BUTTON_PADDING_Y = 50

    LEFT_INFO_WIDTH = 164

    RIGHT_INFO_PADDING_X = 30

    RIGHT_TITLE_BOX_HEIGHT = 70

    ALIAS_NAME_SIZE = 16
    ALIAS_NAME_PADDING_Y = 20

    LONG_DESC_PADDING_Y = 10
    LONG_DESC_WRAP_WIDTH = 630
    LONG_DESC_INIT_HEIGHT = 45

    MARK_SIZE = 11
    MARK_PADDING_X = 5
    MARK_PADDING_Y = -3

    def __init__(self, data_manager):
        '''
        init docs
        '''
        gtk.HBox.__init__(self)
        self.data_manager = data_manager
        self.pkg_name = None
        self.alias_name = ""
        self.pkg_pixbuf = None
        self.pkg_star_view = None

        self.left_view_box = gtk.VBox()
        self.left_view_box.set_size_request(self.LEFT_INFO_WIDTH, - 1)

        self.left_logo_box = gtk.VBox()
        self.left_logo_box.set_size_request(-1, 90)

        self.star_box = gtk.HBox()
        self.star_align = gtk.Alignment(0.4, 0.5, 0, 0)
        self.star_align.set_padding(0, 5, 0, 0)
        self.star_align.add(self.star_box)

        self.left_action_box = gtk.HBox()
        self.left_action_align = gtk.Alignment()
        self.left_action_align.set(0.5, 0.5, 0, 0)
        self.left_action_align.set_padding(0, 30, 0, 0)
        self.left_action_align.add(self.left_action_box)

        self.left_label_table = gtk.Table(4, 1)
        self.left_label_table.set_row_spacings(4)

        self.left_label_align = gtk.Alignment()
        self.left_label_align.set(0.0, 0.5, 0, 0)
        self.left_label_align.set_padding(0, 0, 14, 0)

        self.left_category_name_label = Label()
        self.left_category_label = Label(hover_color=app_theme.get_color("homepage_hover"))
        self.left_category_label.set_clickable()
        self.left_category_label_align = gtk.Alignment()
        self.left_category_label_align.set(0.0, 0.5, 0, 0)
        self.left_category_label_align.add(self.left_category_label)
        self.left_category_label_box = gtk.HBox()
        self.left_category_label_box.pack_start(self.left_category_name_label, False, False)
        self.left_category_label_box.pack_start(self.left_category_label_align, True, True)
        self.left_category_box = gtk.VBox()
        self.left_version_label = Label(label_width=136)
        show_label_tooltip(self.left_version_label)
        self.left_version_label.set_ellipsize(pango.ELLIPSIZE_END)
        self.left_download_label = Label()
        self.left_size_label = Label()

        self.left_homepage_box = gtk.HBox()
        self.left_homepage_box_align = gtk.Alignment()
        self.left_homepage_box_align.set(0.0, 0.5, 0, 0)
        self.left_homepage_box_align.add(self.left_homepage_box)

        self.left_recommend_box = gtk.VBox()
        self.left_recommend_box_align = gtk.Alignment()
        self.left_recommend_box_align.set(0.0, 0.0, 0, 0)
        self.left_recommend_box_align.set_padding(30, 0, 14, 0)
        self.left_recommend_box_align.add(self.left_recommend_box)

        self.left_recommend_label = Label(_("Popular recommendations"))

        self.right_info_box = gtk.VBox()
        self.scrolled_window = ScrolledWindow(0, 0)
        self.right_view_box = gtk.VBox()

        self.right_top_box = gtk.HBox()
        self.right_top_box.set_size_request(-1, self.RIGHT_TITLE_BOX_HEIGHT)
        self.right_desc_box = gtk.VBox()
        self.right_slide_box = gtk.VBox()
        self.right_comment_box = gtk.VBox()

        self.right_title_box = gtk.VBox()

        self.return_button = ImageButton(
            app_theme.get_pixbuf("detail/normal.png"),
            app_theme.get_pixbuf("detail/hover.png"),
            app_theme.get_pixbuf("detail/press.png"),
            )
        self.return_align = gtk.Alignment()
        self.return_align.set(0.5, 0.5, 1, 1)
        self.return_align.set_padding(self.ALIAS_NAME_PADDING_Y, 0, 0, self.RIGHT_INFO_PADDING_X)
        self.return_align.add(self.return_button)

        self.return_button.connect("clicked", lambda w: global_event.emit("switch-from-detail-page"))

        self.right_top_box.pack_start(self.right_title_box, True, True)
        self.right_top_box.pack_start(self.return_align, False, False)

        self.right_view_box.pack_start(self.right_top_box, False, False)
        self.right_view_box.pack_start(self.right_desc_box, False, False)
        self.right_view_box.pack_start(self.right_slide_box, False, False)
        self.right_view_box.pack_start(self.right_comment_box, False, False)
        self.scrolled_window.add_child(self.right_view_box)

        self.left_view_box.pack_start(self.left_logo_box, False, False)
        self.left_view_box.pack_start(self.star_align, False, False)
        self.left_view_box.pack_start(self.left_action_align, False, False)
        self.left_label_table.attach(self.left_category_box, 0, 1, 0, 1)
        self.left_label_table.attach(self.left_version_label, 0, 1, 1, 2)
        self.left_label_table.attach(self.left_size_label, 0, 1, 2, 3)
        self.left_label_table.attach(self.left_download_label, 0, 1, 3, 4)
        self.left_label_table.attach(self.left_homepage_box_align, 0, 1, 4, 5)
        self.left_label_align.add(self.left_label_table)
        self.left_view_box.pack_start(self.left_label_align, False, False)
        self.left_view_box.pack_start(self.left_recommend_box_align, False, False)
        self.right_info_box.pack_start(self.scrolled_window, True, True)
        self.pack_start(self.left_view_box, False, False)
        self.pack_start(self.right_info_box, True, True)

        self.left_view_box.connect("expose-event", self.expose_left_view)
        self.right_view_box.connect("expose-event", self.expose_right_view)
        self.left_logo_box.connect("expose-event", self.expose_left_logo_box)
        self.right_top_box.connect("expose-event", self.expose_right_top_box)
        self.right_title_box.connect("expose-event", self.expose_right_title_box)
        self.connect("hierarchy-changed", self.hierarchy_change)

        self.left_category_label.connect("button-press-event", lambda w, e: self.jump_to_category())

        global_event.register_event("download-screenshot-finish", self.download_screenshot_finish)

        self.loading_label = Label(_("Loading comments..."))
        self.loading_label_align = gtk.Alignment(0.5, 0, 0, 0)
        self.loading_label_align.add(self.loading_label)
        self.loading_label_align.set_padding(10, 0, 0, 0)

        self.update_pkg_time = 0
        self.update_pkg_interval = 0.2 # in seconds

    def hierarchy_change(self, widget, previous_toplevel):
        # When detail page remove from it's container, previous_toplevel is not None.
        if previous_toplevel != None:
            container_remove_all(self.right_slide_box) # remove slide box first, to avoid screenshot area flash
            container_remove_all(self.right_comment_box) # remove comment box first, to avoid comment area flash

    def grade_pkg(self):
        if self.pkg_star_view:
            global_event.emit("grade-pkg", (self.pkg_name, self.pkg_star_view), self.pkg_star_view.star_buffer.star_level)
            self.pkg_star_view.set_star_level(int(self.star))
            self.pkg_star_view.queue_draw()

    def jump_to_category(self):
        global_event.emit("jump-to-category", self.category[0], self.category[1])

    def expose_left_view(self, widget, event):
        # Init.
        cr = widget.window.cairo_create()
        rect = widget.allocation

        # Draw background.
        cr.set_source_rgb(*color_hex_to_cairo("#FFFFFF"))
        cr.rectangle(rect.x, rect.y, rect.width, rect.height)
        cr.fill()

        # Draw split line.
        cr.set_source_rgb(*color_hex_to_cairo("#AAAAAA"))
        cr.rectangle(rect.x + rect.width - 1, rect.y, 1, rect.height)
        cr.fill()

    def expose_right_view(self, widget, event):
        # Init.
        cr = widget.window.cairo_create()
        rect = widget.allocation

        # Draw background.
        cr.set_source_rgb(*color_hex_to_cairo("#FFFFFF"))
        cr.rectangle(rect.x, rect.y, rect.width, rect.height)
        cr.fill()

    def expose_left_logo_box(self, widget, event):
        if self.pkg_name != None:
            # Init.
            cr = widget.window.cairo_create()
            rect = widget.allocation

            # Draw pkg icon.
            self.pkg_pixbuf = gtk.gdk.pixbuf_new_from_file_at_size(
                    get_icon_pixbuf_path(
                        utils.get_origin_name(self.pkg_name)), self.ICON_SIZE, self.ICON_SIZE)
            draw_pixbuf(cr,
                        self.pkg_pixbuf,
                        rect.x + self.ICON_PADDING_X + (self.ICON_SIZE - self.pkg_pixbuf.get_width()) / 2,
                        rect.y + self.PADDING_Y)

    def expose_right_top_box(self, widget, event):
        # Init.
        cr = widget.window.cairo_create()
        rect = widget.allocation

        # Draw background.
        cr.set_source_rgb(*color_hex_to_cairo("#FFFFFF"))
        cr.rectangle(rect.x, rect.y, rect.width, rect.height)
        cr.fill()

    def expose_right_title_box(self, widget, event):
        if self.pkg_name != None:
            # Init.
            cr = widget.window.cairo_create()
            rect = widget.allocation

            # Draw alias name.
            draw_text(
                cr,
                "<b>%s</b>" % self.alias_name,
                rect.x + self.RIGHT_INFO_PADDING_X,
                rect.y + self.ALIAS_NAME_PADDING_Y,
                rect.width - self.RIGHT_INFO_PADDING_X,
                self.ALIAS_NAME_SIZE,
                text_size=self.ALIAS_NAME_SIZE)

    def expose_resizable_label_background(self, widget, event):
        if self.pkg_name != None:
            # Init.
            cr = widget.window.cairo_create()
            rect = widget.allocation

            # Draw background.
            cr.set_source_rgb(*color_hex_to_cairo("#FFFFFF"))
            cr.rectangle(rect.x, rect.y, rect.width, rect.height)
            cr.fill()

    def button_press_start_button(self, widget, event, desktops):
        pixbuf = app_theme.get_pixbuf("button/start_normal.png").get_pixbuf()
        desktop_infos = self.data_manager.get_pkg_desktop_info(desktops)
        global_event.emit("start-pkg",
                          self.alias_name,
                          desktop_infos,
                          (int(event.x), int(event.y), pixbuf.get_width() / 2, 0))

    @post_gui
    def update_some_info(self, info):
        self.star = float(info[0]['mark'].encode('utf-8').strip())
        if self.pkg_star_view:
            self.pkg_star_view.star_buffer.star_level = int(self.star)
            self.pkg_star_view.queue_draw()
        self.pkg_star_mark.update_star(self.star)
        self.pkg_star_mark.queue_draw()

        self.downlad_number = info[0]['down_nums'].encode('utf-8').strip()
        self.left_download_label.set_text(_('Download: %s') % self.downlad_number)

    def update_pkg_info(self, pkg_name):
        current_time = time.time()
        if current_time - self.update_pkg_time < self.update_pkg_interval:
            return False
        else:
            self.update_pkg_time = current_time

        FetchPackageInfo(pkg_name, self.update_some_info).start()
        self.pkg_name = pkg_name

        detail_info = self.data_manager.get_pkg_detail_info(self.pkg_name)
        self.category = detail_info['category']
        self.long_desc = detail_info['long_desc']
        self.version = detail_info['version']
        self.homepage = detail_info['homepage']
        self.alias_name = detail_info['alias_name']
        self.recommend_pkgs = detail_info['recommend_pkgs']

        self.pkg_star_view = StarView()
        self.pkg_star_view.connect("clicked", lambda w: self.grade_pkg())
        self.pkg_star_mark = StarMark(5.0, self.MARK_SIZE, self.MARK_PADDING_X, self.MARK_PADDING_Y)
        container_remove_all(self.star_box)
        self.star_box.pack_start(self.pkg_star_view, False, False)
        self.star_box.pack_start(self.pkg_star_mark, False, False)

        self.fetch_pkg_status()

        container_remove_all(self.left_category_box)
        if self.category != None:
            self.left_category_name_label.set_text(_("Category: "))
            self.left_category_label.set_text(get_category_name(self.category[1]))
            self.left_category_box.add(self.left_category_label_box)

        self.left_version_label.set_text(_("Version: %s") % self.version)
        self.left_download_label.set_text(_("Download: 0"))
        self.left_size_label.set_text(_("Size: calculating..."))

        container_remove_all(self.left_homepage_box)
        if self.homepage != "":
            homepage_label = Label(_("Visit Homepage"),
                                   text_color=app_theme.get_color("homepage"),
                                   hover_color=app_theme.get_color("homepage_hover"))
            homepage_label.set_clickable()
            homepage_label.connect("button-press-event", lambda w, e: run_command("xdg-open %s" % self.homepage))
            self.left_homepage_box.pack_start(homepage_label)

        container_remove_all(self.left_recommend_box)
        if len(self.recommend_pkgs) > 0:
            self.left_recommend_box.pack_start(self.left_recommend_label, False, False, 8)

            for (recommend_pkg_name, alias_name, star) in self.recommend_pkgs:
                self.left_recommend_box.pack_start(RecommendPkgItem(self, recommend_pkg_name, alias_name, star), False, False, 4)

        container_remove_all(self.right_desc_box)
        resizable_label = ResizableLabel(self.long_desc.replace("&", "&amp;").replace("<", "&lt;").replace(">", "&gt;"),
                                         self.LONG_DESC_WRAP_WIDTH,
                                         self.LONG_DESC_INIT_HEIGHT,
                                         3)
        resizable_align = gtk.Alignment()
        resizable_align.set(0.5, 0.5, 1, 1)
        resizable_align.set_padding(0, 0, self.RIGHT_INFO_PADDING_X, self.RIGHT_INFO_PADDING_X)
        resizable_align.add(resizable_label)
        resizable_align.connect("expose-event", self.expose_resizable_label_background)
        self.right_desc_box.pack_start(resizable_align, False, False)

        self.show_screenshot()

        self.fetch_comment()

        self.show_all()

    def handle_pkg_status(self, reply, success):
        container_remove_all(self.left_action_box)
        if success:
            install_status = str(reply)
            if install_status == "uninstalled":
                action_button = ImageButton(
                    app_theme.get_pixbuf("button/install_normal.png"),
                    app_theme.get_pixbuf("button/install_hover.png"),
                    app_theme.get_pixbuf("button/install_press.png"),
                    )
                action_button.connect("clicked", lambda w: global_event.emit("install-pkg", [self.pkg_name]))
                self.left_action_box.pack_start(action_button)
            elif install_status == "unknown":
                status_label = Label(_("Not found"))
                self.left_action_box.pack_start(status_label)
            else:
                try:
                    desktops = json.loads(install_status)
                    if not desktops:
                        status_label = Label(_("Successfully installed"))
                        self.left_action_box.pack_start(status_label)
                    else:
                        action_button = ImageButton(
                            app_theme.get_pixbuf("button/start_normal.png"),
                            app_theme.get_pixbuf("button/start_hover.png"),
                            app_theme.get_pixbuf("button/start_press.png"),
                        )
                        action_button.connect("button-press-event", lambda w, e:self.button_press_start_button(w, e, desktops))
                        self.left_action_box.pack_start(action_button)
                except:
                    logging.error("detail install status: %s = %s" % (self.pkg_name, install_status))

            self.left_action_box.show_all()
            global_event.emit('update-current-status-pkg-page', self)
        else:
            global_logger.logerror("get_pkg_installed handle_dbus_error")
            global_logger.logerror(reply)

    def handle_pkg_download_size(self, reply, success):
        # FIXME: download information display
        if success:
            if reply[0] == PKG_SIZE_OWN or reply[0] == PKG_SIZE_DOWNLOAD:
                self.left_size_label.set_text(_("Size: %s") % bit_to_human_str(reply[1]))
            elif reply[0] == PKG_SIZE_ERROR:
                self.left_size_label.set_text("")
                global_logger.logerror("Error for calculate pkg size!")
        else:
            global_logger.logerror("request_pkgs_install_status handle_dbus_error")
            global_logger.logerror(reply)

    def fetch_pkg_status(self):
        self.data_manager.get_pkg_installed(self.pkg_name, self.handle_pkg_status)
        self.data_manager.get_pkg_download_size(self.pkg_name, self.handle_pkg_download_size)

    def open_url(self, webview, frame, network_request, nav_action, policy_dec):
        webbrowser.open(network_request.get_uri())

    def webview_console_message_handler(self, webview, message, line, source_id):
        return True

    def fetch_comment(self):
        if is_network_connected():
            container_remove_all(self.right_comment_box)
            loading_label = Label(_("Loading comments..."))
            loading_label_align = gtk.Alignment(0.5, 0, 0, 0)
            loading_label_align.add(loading_label)
            loading_label_align.set_padding(10, 0, 0, 0)
            self.right_comment_box.pack_start(loading_label_align, False, False)
            web_view = WebView(os.path.join(CONFIG_DIR, "cookie.txt"))
            web_view.connect("new-window-policy-decision-requested", self.open_url)
            web_view.connect('console-message', self.webview_console_message_handler)
            web_view_align = gtk.Alignment()
            web_view_align.set(0.5, 0, 0, 0)
            web_view_align.set_padding(33, 33, 33, 33)
            web_view_align.add(web_view)
            web_settings = web_view.get_settings()
            web_settings.set_property("enable-plugins", False)
            web_settings.set_property("enable-scripts", True)
            web_view.open("%s/softcenter/v1/comment?n=%s&hl=%s" % (
                    SERVER_ADDRESS,
                    self.pkg_name,
                    LANGUAGE,
                    ))

            web_view.connect("load-finished", self.comment_load_finished_cb, web_view_align)

            create_thread(self.fetch_screenshot).start()

    def comment_load_finished_cb(self, webview, frame, web_view_align):
        self.scrolled_window.connect("vscrollbar-state-changed", lambda w, p: self.load_more_comment(p, webview))
        container_remove_all(self.right_comment_box)
        self.right_comment_box.pack_start(web_view_align, True, True)
        self.right_comment_box.show_all()

    def load_more_comment(self, postion, webview):
        if postion == "bottom":
            webview.execute_script('$("#nav_next").click();')

    def fetch_screenshot(self):
        screenshot_dir = os.path.join(SCREENSHOT_DOWNLOAD_DIR, self.pkg_name)
        screenshot_md5_path = os.path.join(screenshot_dir, "screenshot_md5.txt")
        remote_screenshot_md5_url = "%s/zh_CN/%s/screenshot_md5.txt" % (SCREENSHOT_HOST, self.pkg_name)
        remote_screenshot_zip_url = "%s/zh_CN/%s/screenshot.zip" % (SCREENSHOT_HOST, self.pkg_name)
        try:
            remote_md5 = urllib2.urlopen(remote_screenshot_md5_url).read()
            need_download = False

            if os.path.exists(screenshot_dir):
                if os.path.exists(screenshot_md5_path):
                    local_md5 = read_file(screenshot_md5_path)
                    if remote_md5 != local_md5:
                        need_download = True
                else:
                    need_download = True
            else:
                need_download = True

            if need_download:
                write_file(screenshot_md5_path, remote_md5, True)

                try:
                    urllib.urlretrieve(remote_screenshot_zip_url,
                                       os.path.join(SCREENSHOT_DOWNLOAD_DIR, self.pkg_name, "screenshot.zip")
                                       )
                    global_event.emit("download-screenshot-finish", self.pkg_name)
                except Exception, e:
                    global_logger.logerror("Download screenshot error: %s" % e)
        except Exception, e:
            global_logger.logerror("fetch_screenshot got error: %s" % e)
Example #4
0
class SecondCategoryItem(TreeItem):
    '''
    class docs
    '''
    def __init__(self, first_category_name, second_category_name,
                 data_manager):
        '''
        init docs
        '''
        TreeItem.__init__(self)
        self.first_category_name = first_category_name
        self.second_category_name = second_category_name
        self.data_manager = data_manager

    def render_name(self, cr, rect):
        text_color = "#333333"
        if self.is_select:
            cr.set_source_rgba(*color_hex_to_cairo(
                app_theme.get_color("sidebar_select").get_color()))
            cr.rectangle(rect.x, rect.y, rect.width, rect.height)
            cr.fill()

            text_color = "#FFFFFF"
        elif self.is_hover:
            cr.set_source_rgba(*color_hex_to_cairo(
                app_theme.get_color("sidebar_hover").get_color()))
            cr.rectangle(rect.x, rect.y, rect.width, rect.height)
            cr.fill()

        draw_text(
            cr,
            get_category_name(self.second_category_name),
            rect.x + SECOND_CATEGORY_PADDING_X,
            rect.y,
            rect.width,
            rect.height,
            text_size=SECOND_CATEGORY_ITEM_NAME_SIZE,
            text_color=text_color,
        )

    def get_height(self):
        return SECOND_CATEGORY_ITEM_HEIGHT

    def get_column_widths(self):
        return [CATEGORY_ITEM_NAME_WIDTH]

    def get_column_renders(self):
        return [self.render_name]

    def hover(self, column, offset_x, offset_y):
        self.is_hover = True
        if self.redraw_request_callback:
            self.redraw_request_callback(self)

    def unhover(self, column, offset_x, offset_y):
        self.is_hover = False
        if self.redraw_request_callback:
            self.redraw_request_callback(self)

    def select(self):
        self.is_select = True
        if self.redraw_request_callback:
            self.redraw_request_callback(self)

    def unselect(self):
        self.is_select = False
        if self.redraw_request_callback:
            self.redraw_request_callback(self)

    def scrolled_window_vscrollbar_handler(self, widget, state):
        if state == "bottom":
            current_item_number = len(self.pkg_icon_view.items)
            all_pkgs_number = len(self.all_pkg_names)
            start = current_item_number
            if current_item_number < all_pkgs_number and (
                    current_item_number + LOAD_ITEMS_NUMBER) < all_pkgs_number:
                end = current_item_number + LOAD_ITEMS_NUMBER
            elif current_item_number < all_pkgs_number and (
                    current_item_number +
                    LOAD_ITEMS_NUMBER) >= all_pkgs_number:
                end = all_pkgs_number
            else:
                return
            self.load_new_items(self.all_pkg_names[start:end])

    def load_new_items(self, pkg_names):
        items = []
        for pkg_name in pkg_names:
            info = self.data_manager.get_item_pkg_info(pkg_name)
            items.append(
                PkgIconItem(info[0], info[1], info[2], self.data_manager))
        self.pkg_icon_view.add_items(items)
        global_event.emit("show-pkg-view", self.page_box)

    def handle_pkg_install_status_request(self, status, items):
        for (index, state) in enumerate(status):
            items[index].is_installed = state
            items[index].emit_redraw_request()

    def button_press(self, column, offset_x, offset_y):
        # init Loading widget
        loading_box = LoadingBox()

        global_event.emit("show-pkg-view", loading_box)

        self.page_box = gtk.VBox()

        self.all_pkg_names = self.data_manager.get_second_category_packages(
            self.second_category_name)
        self.message_bar = MessageBar(18)
        self.message_bar.set_message(
            _("%s > %s : %s applications") % (
                get_category_name(self.first_category_name),
                get_category_name(self.second_category_name),
                len(self.all_pkg_names),
            ))

        self.pkg_icon_view = IconView()
        self.pkg_icon_view.connect("motion-notify-item", tooltip_aciton)
        if len(self.all_pkg_names) > LOAD_ITEMS_NUMBER:
            self.load_new_items(self.all_pkg_names[:LOAD_ITEMS_NUMBER])
        else:
            self.load_new_items(self.all_pkg_names)

        self.pkg_icon_scrolled_window = ScrolledWindow()
        self.pkg_icon_scrolled_window.connect(
            "vscrollbar-state-changed",
            self.scrolled_window_vscrollbar_handler)
        self.pkg_icon_scrolled_window.add_child(self.pkg_icon_view)
        self.pkg_icon_view.draw_mask = self.draw_mask
        self.pkg_icon_view.draw_row_mask = self.draw_row_mask

        self.page_box.pack_start(self.message_bar, False, False)
        self.page_box.pack_start(self.pkg_icon_scrolled_window, True, True)

        global_event.emit("update-current-status-pkg-page", self.pkg_icon_view)

    def draw_row_mask(self, cr, rect, row):
        if row % 2 == 1:
            cr.set_source_rgba(1, 1, 1, 0.5)
            cr.rectangle(rect.x, rect.y, rect.width, rect.height)
            cr.fill()

    def draw_mask(self, cr, x, y, w, h):
        '''
        Draw mask interface.

        @param cr: Cairo context.
        @param x: X coordiante of draw area.
        @param y: Y coordiante of draw area.
        @param w: Width of draw area.
        @param h: Height of draw area.
        '''
        draw_vlinear(cr, x, y, w, h, [
            (0, ("#FFFFFF", 0.9)),
            (1, ("#FFFFFF", 0.9)),
        ])
Example #5
0
class CategoryItem(TreeItem):
    '''
    class docs
    '''
    def __init__(self, index, first_category_name, data_manager):
        '''
        init docs
        '''
        TreeItem.__init__(self)
        self.index = index
        self.first_category_name = first_category_name
        self.data_manager = data_manager

    def render_name(self, cr, rect):
        text_color = "#333333"
        font_image_color = app_theme.get_color("sidebar_select").get_color()
        if self.is_select:
            cr.set_source_rgba(*color_hex_to_cairo(
                app_theme.get_color("sidebar_select").get_color()))
            cr.rectangle(rect.x, rect.y, rect.width, rect.height)
            cr.fill()

            text_color = "#FFFFFF"
            font_image_color = "#FFFFFF"
        elif self.is_hover:
            cr.set_source_rgba(*color_hex_to_cairo(
                app_theme.get_color("sidebar_hover").get_color()))
            cr.rectangle(rect.x, rect.y, rect.width, rect.height)
            cr.fill()

        pixbuf = app_theme.get_pixbuf("category/%s.png" %
                                      (self.index)).get_pixbuf()

        category_img_path = os.path.join(get_parent_dir(__file__, 2), "image",
                                         "category",
                                         "%s.png" % (self.index + 1, ))
        surface = cairo.ImageSurface.create_from_png(category_img_path)
        cr.set_source_rgb(*color_hex_to_cairo(font_image_color))
        cr.mask_surface(surface, rect.x + 14, rect.y + (rect.height - 24) / 2)

        draw_text(
            cr,
            get_category_name(self.first_category_name),
            rect.x + pixbuf.get_width() + 22,
            rect.y,
            rect.width,
            rect.height,
            text_size=CATEGORY_ITEM_NAME_SIZE,
            text_color=text_color,
        )

        if self.is_hover:
            if self.is_expand:
                pixbuf = app_theme.get_pixbuf("sidebar/close.png").get_pixbuf()
            else:
                pixbuf = app_theme.get_pixbuf("sidebar/open.png").get_pixbuf()

            draw_pixbuf(cr, pixbuf,
                        rect.x + rect.width - CATEGORY_ITEM_EXPAND_PADDING_X,
                        rect.y + (rect.height - pixbuf.get_height()) / 2)

    def get_height(self):
        return CATEGORY_ITEM_HEIGHT

    def get_column_widths(self):
        return [CATEGORY_ITEM_NAME_WIDTH]

    def get_column_renders(self):
        return [self.render_name]

    def hover(self, column, offset_x, offset_y):
        self.is_hover = True
        if self.redraw_request_callback:
            self.redraw_request_callback(self)

    def unhover(self, column, offset_x, offset_y):
        self.is_hover = False
        if self.redraw_request_callback:
            self.redraw_request_callback(self)

    def select(self):
        self.is_select = True
        if self.redraw_request_callback:
            self.redraw_request_callback(self)

    def unselect(self):
        self.is_select = False
        if self.redraw_request_callback:
            self.redraw_request_callback(self)

    def is_in_expand_button_area(self, column, offset_x, offset_y):
        pixbuf = app_theme.get_pixbuf("sidebar/close.png").get_pixbuf()

        return is_in_rect(
            (offset_x, offset_y),
            (CATEGORY_VIEW_WIDTH - CATEGORY_ITEM_EXPAND_PADDING_X,
             (self.get_height() - pixbuf.get_height()) / 2, pixbuf.get_width(),
             pixbuf.get_height()))

    def motion_notify(self, column, offset_x, offset_y):
        if self.is_in_expand_button_area(column, offset_x, offset_y):
            global_event.emit("set-cursor", gtk.gdk.HAND2)
        else:
            global_event.emit("set-cursor", None)

    def button_press(self, column, offset_x, offset_y):
        if self.is_in_expand_button_area(column, offset_x, offset_y):
            if self.is_expand:
                self.unexpand()
            else:
                self.expand()

    def scrolled_window_vscrollbar_handler(self, widget, state):
        if state == "bottom":
            current_item_number = len(self.pkg_icon_view.items)
            all_pkgs_number = len(self.all_pkg_names)
            start = current_item_number
            if current_item_number < all_pkgs_number and (
                    current_item_number + LOAD_ITEMS_NUMBER) < all_pkgs_number:
                end = current_item_number + LOAD_ITEMS_NUMBER
            elif current_item_number < all_pkgs_number and (
                    current_item_number +
                    LOAD_ITEMS_NUMBER) >= all_pkgs_number:
                end = all_pkgs_number
            else:
                return
            self.load_new_items(self.all_pkg_names[start:end])

    def load_new_items(self, pkg_names):
        items = []
        for pkg_name in pkg_names:
            info = self.data_manager.get_item_pkg_info(pkg_name)
            items.append(
                PkgIconItem(info[0], info[1], info[2], self.data_manager))
        self.pkg_icon_view.add_items(items)
        global_event.emit("show-pkg-view", self.page_box)

    def handle_pkg_install_status_request(self, status, items):
        for (index, state) in enumerate(status):
            items[index].is_installed = state
            items[index].emit_redraw_request()

    def single_click(self, column, offset_x, offset_y):
        # init Loading widget
        loading_box = LoadingBox()
        global_event.emit("show-pkg-view", loading_box)

        self.page_box = gtk.VBox()

        self.all_pkg_names = []
        self.all_desktop_infos = {}
        self.all_pkg_names = self.data_manager.get_first_category_packages(
            self.first_category_name)

        self.message_bar = MessageBar(18)
        self.message_bar.set_message(
            _("%s: %s applications") % (
                get_category_name(self.first_category_name),
                len(self.all_pkg_names),
            ))

        self.pkg_icon_view = IconView()
        self.pkg_icon_view.connect("motion-notify-item", tooltip_aciton)
        if len(self.all_pkg_names) > LOAD_ITEMS_NUMBER:
            self.load_new_items(self.all_pkg_names[:LOAD_ITEMS_NUMBER])
        else:
            self.load_new_items(self.all_pkg_names)

        self.pkg_icon_view.draw_mask = self.draw_mask
        self.pkg_icon_view.draw_row_mask = self.draw_row_mask
        self.pkg_icon_scrolled_window = ScrolledWindow()
        self.pkg_icon_scrolled_window.connect(
            "vscrollbar-state-changed",
            self.scrolled_window_vscrollbar_handler)
        self.pkg_icon_scrolled_window.add_child(self.pkg_icon_view)

        self.page_box.pack_start(self.message_bar, False, False)
        self.page_box.pack_start(self.pkg_icon_scrolled_window, True, True)
        global_event.emit("update-current-status-pkg-page", self.pkg_icon_view)

    def draw_row_mask(self, cr, rect, row):
        if row % 2 == 1:
            cr.set_source_rgba(1, 1, 1, 0.5)
            cr.rectangle(rect.x, rect.y, rect.width, rect.height)
            cr.fill()

    def draw_mask(self, cr, x, y, w, h):
        '''
        Draw mask interface.

        @param cr: Cairo context.
        @param x: X coordiante of draw area.
        @param y: Y coordiante of draw area.
        @param w: Width of draw area.
        @param h: Height of draw area.
        '''
        draw_vlinear(cr, x, y, w, h, [
            (0, ("#FFFFFF", 0.9)),
            (1, ("#FFFFFF", 0.9)),
        ])

    def double_click(self, column, offset_x, offset_y):
        if self.is_expand:
            self.unexpand()
        else:
            self.expand()

    def add_child_item(self):
        items = []
        second_category_names = self.data_manager.get_second_category(
            self.first_category_name)
        for second_category_name in second_category_names:
            items.append(
                SecondCategoryItem(self.first_category_name,
                                   second_category_name, self.data_manager))

        self.child_items = items
        self.add_items_callback(self.child_items, self.row_index + 1)

    def delete_chlid_item(self):
        self.delete_items_callback(self.child_items)

    def expand(self):
        self.is_expand = True

        self.add_child_item()

        if self.redraw_request_callback:
            self.redraw_request_callback(self)
        global_event.emit("category-expand", self)

    def unexpand(self):
        self.is_expand = False

        self.delete_chlid_item()

        if self.redraw_request_callback:
            self.redraw_request_callback(self)
Example #6
0
 def get_scrolled_window(self):
     scrolled_window = ScrolledWindow()
     scrolled_window.connect("vscrollbar-state-changed",
                             self.__on_vscrollbar_state_changed)
     scrolled_window.add_child(self)
     return scrolled_window
Example #7
0
        self.pixbuf = None
        return True


if __name__ == '__main__':
    gtk.gdk.threads_init()
    module_frame = ModuleFrame(
        os.path.join(get_parent_dir(__file__, 2), "config.ini"))

    scrolled_window = ScrolledWindow()
    scrolled_window.set_size_request(788, 467)
    wallpaper_view = WallpaperView()
    scrolled_window.add_child(wallpaper_view)
    module_frame.add(scrolled_window)

    scrolled_window.connect("vscrollbar-state-changed",
                            wallpaper_view.load_more_background)

    download_pool = MissionThreadPool(5)
    download_pool.start()

    def message_handler(*message):
        (message_type, message_content) = message
        if message_type == "show_again":
            module_frame.send_module_info()
        elif message_type == "exit":
            module_frame.exit()

    module_frame.module_message_handler = message_handler
    module_frame.run()
class SecondCategoryItem(TreeItem):
    '''
    class docs
    '''
	
    def __init__(self, first_category_name, second_category_name, data_manager):
        '''
        init docs
        '''
        TreeItem.__init__(self)
        self.first_category_name = first_category_name
        self.second_category_name = second_category_name
        self.data_manager = data_manager
    
    def render_name(self, cr, rect):
        text_color = "#333333"
        if self.is_select:
            cr.set_source_rgba(*color_hex_to_cairo(app_theme.get_color("sidebar_select").get_color()))
            cr.rectangle(rect.x, rect.y, rect.width, rect.height)
            cr.fill()
            
            text_color = "#FFFFFF"
        elif self.is_hover:
            cr.set_source_rgba(*color_hex_to_cairo(app_theme.get_color("sidebar_hover").get_color()))
            cr.rectangle(rect.x, rect.y, rect.width, rect.height)
            cr.fill()
        
        draw_text(cr, 
                  get_category_name(self.second_category_name),
                  rect.x + SECOND_CATEGORY_PADDING_X,
                  rect.y,
                  rect.width,
                  rect.height,
                  text_size=SECOND_CATEGORY_ITEM_NAME_SIZE,
                  text_color=text_color,
                  )
        
    def get_height(self):
        return SECOND_CATEGORY_ITEM_HEIGHT
    
    def get_column_widths(self):
        return [CATEGORY_ITEM_NAME_WIDTH]
        
    def get_column_renders(self):    
        return [self.render_name]
        
    def hover(self, column, offset_x, offset_y):
        self.is_hover = True
        if self.redraw_request_callback:
            self.redraw_request_callback(self)
        
    def unhover(self, column, offset_x, offset_y):
        self.is_hover = False
        if self.redraw_request_callback:
            self.redraw_request_callback(self)
    
    def select(self):
        self.is_select = True
        if self.redraw_request_callback:
            self.redraw_request_callback(self)
        
    def unselect(self):
        self.is_select = False
        if self.redraw_request_callback:
            self.redraw_request_callback(self)
    
    def scrolled_window_vscrollbar_handler(self, widget, state):
        if state == "bottom":
            current_item_number = len(self.pkg_icon_view.items)
            all_pkgs_number = len(self.all_pkg_names)
            start = current_item_number
            if current_item_number < all_pkgs_number and (current_item_number+LOAD_ITEMS_NUMBER) < all_pkgs_number:
                end = current_item_number+LOAD_ITEMS_NUMBER
            elif current_item_number < all_pkgs_number and (current_item_number+LOAD_ITEMS_NUMBER) >= all_pkgs_number:
                end = all_pkgs_number
            else:
                return
            self.load_new_items(self.all_pkg_names[start:end])

    def load_new_items(self, pkg_names):
        items = []
        for pkg_name in pkg_names:
            info = self.data_manager.get_item_pkg_info(pkg_name)
            items.append(PkgIconItem(info[0], info[1], info[2], self.data_manager))
        self.pkg_icon_view.add_items(items)
        global_event.emit("show-pkg-view", self.page_box)

    def handle_pkg_install_status_request(self, status, items):
        for (index, state) in enumerate(status):
            items[index].is_installed = state
            items[index].emit_redraw_request()

    def button_press(self, column, offset_x, offset_y):
        # init Loading widget
        loading_box = LoadingBox()

        global_event.emit("show-pkg-view", loading_box)

        self.page_box = gtk.VBox()    
            
        self.all_pkg_names = self.data_manager.get_second_category_packages(self.second_category_name)
        self.message_bar = MessageBar(18)
        self.message_bar.set_message(_("%s > %s : %s applications") % (
                get_category_name(self.first_category_name), 
                get_category_name(self.second_category_name), 
                len(self.all_pkg_names),
                ))
        
        self.pkg_icon_view = IconView() 
        self.pkg_icon_view.connect("motion-notify-item", tooltip_aciton)
        if len(self.all_pkg_names) > LOAD_ITEMS_NUMBER:
            self.load_new_items(self.all_pkg_names[:LOAD_ITEMS_NUMBER])
        else:
            self.load_new_items(self.all_pkg_names)

        self.pkg_icon_scrolled_window = ScrolledWindow()
        self.pkg_icon_scrolled_window.connect("vscrollbar-state-changed", self.scrolled_window_vscrollbar_handler)
        self.pkg_icon_scrolled_window.add_child(self.pkg_icon_view)
        self.pkg_icon_view.draw_mask = self.draw_mask
        self.pkg_icon_view.draw_row_mask = self.draw_row_mask
        
        self.page_box.pack_start(self.message_bar, False, False)
        self.page_box.pack_start(self.pkg_icon_scrolled_window, True, True)
        
        global_event.emit("update-current-status-pkg-page", self.pkg_icon_view)
        
    def draw_row_mask(self, cr, rect, row):
        if row % 2 == 1:
            cr.set_source_rgba(1, 1, 1, 0.5)
            cr.rectangle(rect.x, rect.y, rect.width, rect.height)
            cr.fill()
    
    def draw_mask(self, cr, x, y, w, h):
        '''
        Draw mask interface.
        
        @param cr: Cairo context.
        @param x: X coordiante of draw area.
        @param y: Y coordiante of draw area.
        @param w: Width of draw area.
        @param h: Height of draw area.
        '''
        draw_vlinear(cr, x, y, w, h,
                     [(0, ("#FFFFFF", 0.9)),
                      (1, ("#FFFFFF", 0.9)),]
                     )
class CategoryItem(TreeItem):
    '''
    class docs
    '''
	
    def __init__(self, index, first_category_name, data_manager):
        '''
        init docs
        '''
        TreeItem.__init__(self)
        self.index = index
        self.first_category_name = first_category_name
        self.data_manager = data_manager
    
    def render_name(self, cr, rect):
        text_color = "#333333"
        font_image_color = app_theme.get_color("sidebar_select").get_color()
        if self.is_select:
            cr.set_source_rgba(*color_hex_to_cairo(app_theme.get_color("sidebar_select").get_color()))
            cr.rectangle(rect.x, rect.y, rect.width, rect.height)
            cr.fill()
            
            text_color = "#FFFFFF"
            font_image_color = "#FFFFFF"
        elif self.is_hover:
            cr.set_source_rgba(*color_hex_to_cairo(app_theme.get_color("sidebar_hover").get_color()))
            cr.rectangle(rect.x, rect.y, rect.width, rect.height)
            cr.fill()
        
        pixbuf = app_theme.get_pixbuf("category/%s.png" % (self.index)).get_pixbuf()

        category_img_path = os.path.join(get_parent_dir(__file__, 2), "image", "category", "%s.png" % (self.index+1, ))
        surface = cairo.ImageSurface.create_from_png(category_img_path)
        cr.set_source_rgb(*color_hex_to_cairo(font_image_color))
        cr.mask_surface(surface, rect.x+14, rect.y+(rect.height-24)/2)

        draw_text(cr, 
                  get_category_name(self.first_category_name),
                  rect.x + pixbuf.get_width() + 22, 
                  rect.y,
                  rect.width,
                  rect.height,
                  text_size=CATEGORY_ITEM_NAME_SIZE,
                  text_color=text_color,
                  )
        
        if self.is_hover:
            if self.is_expand:
                pixbuf = app_theme.get_pixbuf("sidebar/close.png").get_pixbuf()
            else:
                pixbuf = app_theme.get_pixbuf("sidebar/open.png").get_pixbuf()
                
            draw_pixbuf(
                cr,
                pixbuf,
                rect.x + rect.width - CATEGORY_ITEM_EXPAND_PADDING_X,
                rect.y + (rect.height - pixbuf.get_height()) / 2)
        
    def get_height(self):
        return CATEGORY_ITEM_HEIGHT
    
    def get_column_widths(self):
        return [CATEGORY_ITEM_NAME_WIDTH]
        
    def get_column_renders(self):    
        return [self.render_name]
        
    def hover(self, column, offset_x, offset_y):
        self.is_hover = True
        if self.redraw_request_callback:
            self.redraw_request_callback(self)
        
    def unhover(self, column, offset_x, offset_y):
        self.is_hover = False
        if self.redraw_request_callback:
            self.redraw_request_callback(self)
    
    def select(self):
        self.is_select = True
        if self.redraw_request_callback:
            self.redraw_request_callback(self)
        
    def unselect(self):
        self.is_select = False
        if self.redraw_request_callback:
            self.redraw_request_callback(self)
    
    def is_in_expand_button_area(self, column, offset_x, offset_y):
        pixbuf = app_theme.get_pixbuf("sidebar/close.png").get_pixbuf()
        
        return is_in_rect((offset_x, offset_y),
                          (CATEGORY_VIEW_WIDTH - CATEGORY_ITEM_EXPAND_PADDING_X,
                           (self.get_height() - pixbuf.get_height()) / 2,
                           pixbuf.get_width(),
                           pixbuf.get_height()))
    
    def motion_notify(self, column, offset_x, offset_y):
        if self.is_in_expand_button_area(column, offset_x, offset_y):
            global_event.emit("set-cursor", gtk.gdk.HAND2)    
        else:
            global_event.emit("set-cursor", None)    
            
    def button_press(self, column, offset_x, offset_y):
        if self.is_in_expand_button_area(column, offset_x, offset_y):
            if self.is_expand:
                self.unexpand()
            else:
                self.expand()

    def scrolled_window_vscrollbar_handler(self, widget, state):
        if state == "bottom":
            current_item_number = len(self.pkg_icon_view.items)
            all_pkgs_number = len(self.all_pkg_names)
            start = current_item_number
            if current_item_number < all_pkgs_number and (current_item_number+LOAD_ITEMS_NUMBER) < all_pkgs_number:
                end = current_item_number+LOAD_ITEMS_NUMBER
            elif current_item_number < all_pkgs_number and (current_item_number+LOAD_ITEMS_NUMBER) >= all_pkgs_number:
                end = all_pkgs_number
            else:
                return
            self.load_new_items(self.all_pkg_names[start:end])
            
    def load_new_items(self, pkg_names):
        items = []
        for pkg_name in pkg_names:
            info = self.data_manager.get_item_pkg_info(pkg_name)
            items.append(PkgIconItem(info[0], info[1], info[2], self.data_manager))
        self.pkg_icon_view.add_items(items)
        global_event.emit("show-pkg-view", self.page_box)

    def handle_pkg_install_status_request(self, status, items):
        for (index, state) in enumerate(status):
            items[index].is_installed = state
            items[index].emit_redraw_request()

    def single_click(self, column, offset_x, offset_y):
        # init Loading widget
        loading_box = LoadingBox()
        global_event.emit("show-pkg-view", loading_box)

        self.page_box = gtk.VBox()    

        self.all_pkg_names = []
        self.all_desktop_infos = {}
        self.all_pkg_names = self.data_manager.get_first_category_packages(self.first_category_name)
            
        self.message_bar = MessageBar(18)
        self.message_bar.set_message(_("%s: %s applications") % (
                    get_category_name(self.first_category_name), 
                    len(self.all_pkg_names),
                    ))
        
        self.pkg_icon_view = IconView() 
        self.pkg_icon_view.connect("motion-notify-item", tooltip_aciton)
        if len(self.all_pkg_names) > LOAD_ITEMS_NUMBER:
            self.load_new_items(self.all_pkg_names[:LOAD_ITEMS_NUMBER])
        else:
            self.load_new_items(self.all_pkg_names)

        self.pkg_icon_view.draw_mask = self.draw_mask
        self.pkg_icon_view.draw_row_mask = self.draw_row_mask
        self.pkg_icon_scrolled_window = ScrolledWindow()
        self.pkg_icon_scrolled_window.connect("vscrollbar-state-changed", self.scrolled_window_vscrollbar_handler)
        self.pkg_icon_scrolled_window.add_child(self.pkg_icon_view)
        
        self.page_box.pack_start(self.message_bar, False, False)
        self.page_box.pack_start(self.pkg_icon_scrolled_window, True, True)
        global_event.emit("update-current-status-pkg-page", self.pkg_icon_view)
        
    def draw_row_mask(self, cr, rect, row):
        if row % 2 == 1:
            cr.set_source_rgba(1, 1, 1, 0.5)
            cr.rectangle(rect.x, rect.y, rect.width, rect.height)
            cr.fill()
    
    def draw_mask(self, cr, x, y, w, h):
        '''
        Draw mask interface.
        
        @param cr: Cairo context.
        @param x: X coordiante of draw area.
        @param y: Y coordiante of draw area.
        @param w: Width of draw area.
        @param h: Height of draw area.
        '''
        draw_vlinear(cr, x, y, w, h,
                     [(0, ("#FFFFFF", 0.9)),
                      (1, ("#FFFFFF", 0.9)),]
                     )
        
    def double_click(self, column, offset_x, offset_y):
        if self.is_expand:
            self.unexpand()
        else:
            self.expand()
        
    def add_child_item(self):
        items = []
        second_category_names = self.data_manager.get_second_category(self.first_category_name)
        for second_category_name in second_category_names:
            items.append(SecondCategoryItem(self.first_category_name, second_category_name, self.data_manager))
            
        self.child_items = items
        self.add_items_callback(self.child_items, self.row_index + 1)
        
    def delete_chlid_item(self):
        self.delete_items_callback(self.child_items)
    
    def expand(self):
        self.is_expand = True
        
        self.add_child_item()
            
        if self.redraw_request_callback:
            self.redraw_request_callback(self)
        global_event.emit("category-expand", self)
    
    def unexpand(self):
        self.is_expand = False
        
        self.delete_chlid_item()
    
        if self.redraw_request_callback:
            self.redraw_request_callback(self)
Example #10
0
class DetailPage(gtk.HBox):
    '''
    class docs
    '''

    PADDING_Y = 20

    ICON_SIZE = 64
    ICON_PADDING_X = 50

    STAR_PADDING_X = 36
    STAR_PADDING_Y = 12
    STAR_SIZE = 13

    MARK_NUMBER_SIZE = 11
    MARK_NUMBER_PADDING_X = 4
    MARK_NUMBER_PADDING_Y = 10

    INFO_RENDER_X = 10
    INFO_RENDER_Y = 140
    INFO_RENDER_HEIGHT = 18
    INFO_CATEGORY_RENDER_Y = INFO_RENDER_Y + INFO_RENDER_HEIGHT
    INFO_VERSION_RENDER_Y = INFO_RENDER_Y + INFO_RENDER_HEIGHT * 2
    INFO_SIZE_RENDER_Y = INFO_RENDER_Y + INFO_RENDER_HEIGHT * 3
    INFO_DOWNLOAD_RENDER_Y = INFO_RENDER_Y + INFO_RENDER_HEIGHT * 4
    INFO_HOMEPAGE_RENDER_Y = INFO_RENDER_Y + INFO_RENDER_HEIGHT * 5

    LEFT_INFO_PADDING_X = 18
    LEFT_INFO_PADDING_Y = 50

    LEFT_BUTTON_PADDING_Y = 50

    LEFT_INFO_WIDTH = 164

    RIGHT_INFO_PADDING_X = 30

    RIGHT_TITLE_BOX_HEIGHT = 70

    ALIAS_NAME_SIZE = 16
    ALIAS_NAME_PADDING_Y = 20

    LONG_DESC_PADDING_Y = 10
    LONG_DESC_WRAP_WIDTH = 630
    LONG_DESC_INIT_HEIGHT = 45

    MARK_SIZE = 11
    MARK_PADDING_X = 5
    MARK_PADDING_Y = -3

    def __init__(self, data_manager):
        '''
        init docs
        '''
        gtk.HBox.__init__(self)
        self.data_manager = data_manager
        self.pkg_name = None
        self.alias_name = ""
        self.pkg_pixbuf = None
        self.pkg_star_view = None

        self.left_view_box = gtk.VBox()
        self.left_view_box.set_size_request(self.LEFT_INFO_WIDTH, -1)

        self.left_logo_box = gtk.VBox()
        self.left_logo_box.set_size_request(-1, 90)

        self.star_box = gtk.HBox()
        self.star_align = gtk.Alignment(0.4, 0.5, 0, 0)
        self.star_align.set_padding(0, 5, 0, 0)
        self.star_align.add(self.star_box)

        self.left_action_box = gtk.HBox()
        self.left_action_align = gtk.Alignment()
        self.left_action_align.set(0.5, 0.5, 0, 0)
        self.left_action_align.set_padding(0, 30, 0, 0)
        self.left_action_align.add(self.left_action_box)

        self.left_label_table = gtk.Table(4, 1)
        self.left_label_table.set_row_spacings(4)

        self.left_label_align = gtk.Alignment()
        self.left_label_align.set(0.0, 0.5, 0, 0)
        self.left_label_align.set_padding(0, 0, 14, 0)

        self.left_category_name_label = Label()
        self.left_category_label = Label(
            hover_color=app_theme.get_color("homepage_hover"))
        self.left_category_label.set_clickable()
        self.left_category_label_align = gtk.Alignment()
        self.left_category_label_align.set(0.0, 0.5, 0, 0)
        self.left_category_label_align.add(self.left_category_label)
        self.left_category_label_box = gtk.HBox()
        self.left_category_label_box.pack_start(self.left_category_name_label,
                                                False, False)
        self.left_category_label_box.pack_start(self.left_category_label_align,
                                                True, True)
        self.left_category_box = gtk.VBox()
        self.left_version_label = Label(label_width=136)
        show_label_tooltip(self.left_version_label)
        self.left_version_label.set_ellipsize(pango.ELLIPSIZE_END)
        self.left_download_label = Label()
        self.left_size_label = Label()

        self.left_homepage_box = gtk.HBox()
        self.left_homepage_box_align = gtk.Alignment()
        self.left_homepage_box_align.set(0.0, 0.5, 0, 0)
        self.left_homepage_box_align.add(self.left_homepage_box)

        self.left_recommend_box = gtk.VBox()
        self.left_recommend_box_align = gtk.Alignment()
        self.left_recommend_box_align.set(0.0, 0.0, 0, 0)
        self.left_recommend_box_align.set_padding(30, 0, 14, 0)
        self.left_recommend_box_align.add(self.left_recommend_box)

        self.left_recommend_label = Label(_("Popular recommendations"))

        self.right_info_box = gtk.VBox()
        self.scrolled_window = ScrolledWindow(0, 0)
        self.right_view_box = gtk.VBox()

        self.right_top_box = gtk.HBox()
        self.right_top_box.set_size_request(-1, self.RIGHT_TITLE_BOX_HEIGHT)
        self.right_desc_box = gtk.VBox()
        self.right_slide_box = gtk.VBox()
        self.right_comment_box = gtk.VBox()

        self.right_title_box = gtk.VBox()

        self.return_button = ImageButton(
            app_theme.get_pixbuf("detail/normal.png"),
            app_theme.get_pixbuf("detail/hover.png"),
            app_theme.get_pixbuf("detail/press.png"),
        )
        self.return_align = gtk.Alignment()
        self.return_align.set(0.5, 0.5, 1, 1)
        self.return_align.set_padding(self.ALIAS_NAME_PADDING_Y, 0, 0,
                                      self.RIGHT_INFO_PADDING_X)
        self.return_align.add(self.return_button)

        self.return_button.connect(
            "clicked", lambda w: global_event.emit("switch-from-detail-page"))

        self.right_top_box.pack_start(self.right_title_box, True, True)
        self.right_top_box.pack_start(self.return_align, False, False)

        self.right_view_box.pack_start(self.right_top_box, False, False)
        self.right_view_box.pack_start(self.right_desc_box, False, False)
        self.right_view_box.pack_start(self.right_slide_box, False, False)
        self.right_view_box.pack_start(self.right_comment_box, False, False)
        self.scrolled_window.add_child(self.right_view_box)

        self.left_view_box.pack_start(self.left_logo_box, False, False)
        self.left_view_box.pack_start(self.star_align, False, False)
        self.left_view_box.pack_start(self.left_action_align, False, False)
        self.left_label_table.attach(self.left_category_box, 0, 1, 0, 1)
        self.left_label_table.attach(self.left_version_label, 0, 1, 1, 2)
        self.left_label_table.attach(self.left_size_label, 0, 1, 2, 3)
        self.left_label_table.attach(self.left_download_label, 0, 1, 3, 4)
        self.left_label_table.attach(self.left_homepage_box_align, 0, 1, 4, 5)
        self.left_label_align.add(self.left_label_table)
        self.left_view_box.pack_start(self.left_label_align, False, False)
        self.left_view_box.pack_start(self.left_recommend_box_align, False,
                                      False)
        self.right_info_box.pack_start(self.scrolled_window, True, True)
        self.pack_start(self.left_view_box, False, False)
        self.pack_start(self.right_info_box, True, True)

        self.left_view_box.connect("expose-event", self.expose_left_view)
        self.right_view_box.connect("expose-event", self.expose_right_view)
        self.left_logo_box.connect("expose-event", self.expose_left_logo_box)
        self.right_top_box.connect("expose-event", self.expose_right_top_box)
        self.right_title_box.connect("expose-event",
                                     self.expose_right_title_box)
        self.connect("hierarchy-changed", self.hierarchy_change)

        self.left_category_label.connect("button-press-event",
                                         lambda w, e: self.jump_to_category())

        global_event.register_event("download-screenshot-finish",
                                    self.download_screenshot_finish)

        self.loading_label = Label(_("Loading comments..."))
        self.loading_label_align = gtk.Alignment(0.5, 0, 0, 0)
        self.loading_label_align.add(self.loading_label)
        self.loading_label_align.set_padding(10, 0, 0, 0)

        self.update_pkg_time = 0
        self.update_pkg_interval = 0.2  # in seconds

    def hierarchy_change(self, widget, previous_toplevel):
        # When detail page remove from it's container, previous_toplevel is not None.
        if previous_toplevel != None:
            container_remove_all(
                self.right_slide_box
            )  # remove slide box first, to avoid screenshot area flash
            container_remove_all(
                self.right_comment_box
            )  # remove comment box first, to avoid comment area flash

    def grade_pkg(self):
        if self.pkg_star_view:
            global_event.emit("grade-pkg", (self.pkg_name, self.pkg_star_view),
                              self.pkg_star_view.star_buffer.star_level)
            self.pkg_star_view.set_star_level(int(self.star))
            self.pkg_star_view.queue_draw()

    def jump_to_category(self):
        global_event.emit("jump-to-category", self.category[0],
                          self.category[1])

    def expose_left_view(self, widget, event):
        # Init.
        cr = widget.window.cairo_create()
        rect = widget.allocation

        # Draw background.
        cr.set_source_rgb(*color_hex_to_cairo("#FFFFFF"))
        cr.rectangle(rect.x, rect.y, rect.width, rect.height)
        cr.fill()

        # Draw split line.
        cr.set_source_rgb(*color_hex_to_cairo("#AAAAAA"))
        cr.rectangle(rect.x + rect.width - 1, rect.y, 1, rect.height)
        cr.fill()

    def expose_right_view(self, widget, event):
        # Init.
        cr = widget.window.cairo_create()
        rect = widget.allocation

        # Draw background.
        cr.set_source_rgb(*color_hex_to_cairo("#FFFFFF"))
        cr.rectangle(rect.x, rect.y, rect.width, rect.height)
        cr.fill()

    def expose_left_logo_box(self, widget, event):
        if self.pkg_name != None:
            # Init.
            cr = widget.window.cairo_create()
            rect = widget.allocation

            # Draw pkg icon.
            self.pkg_pixbuf = gtk.gdk.pixbuf_new_from_file_at_size(
                get_icon_pixbuf_path(utils.get_origin_name(self.pkg_name)),
                self.ICON_SIZE, self.ICON_SIZE)
            draw_pixbuf(
                cr, self.pkg_pixbuf, rect.x + self.ICON_PADDING_X +
                (self.ICON_SIZE - self.pkg_pixbuf.get_width()) / 2,
                rect.y + self.PADDING_Y)

    def expose_right_top_box(self, widget, event):
        # Init.
        cr = widget.window.cairo_create()
        rect = widget.allocation

        # Draw background.
        cr.set_source_rgb(*color_hex_to_cairo("#FFFFFF"))
        cr.rectangle(rect.x, rect.y, rect.width, rect.height)
        cr.fill()

    def expose_right_title_box(self, widget, event):
        if self.pkg_name != None:
            # Init.
            cr = widget.window.cairo_create()
            rect = widget.allocation

            # Draw alias name.
            draw_text(cr,
                      "<b>%s</b>" % self.alias_name,
                      rect.x + self.RIGHT_INFO_PADDING_X,
                      rect.y + self.ALIAS_NAME_PADDING_Y,
                      rect.width - self.RIGHT_INFO_PADDING_X,
                      self.ALIAS_NAME_SIZE,
                      text_size=self.ALIAS_NAME_SIZE)

    def expose_resizable_label_background(self, widget, event):
        if self.pkg_name != None:
            # Init.
            cr = widget.window.cairo_create()
            rect = widget.allocation

            # Draw background.
            cr.set_source_rgb(*color_hex_to_cairo("#FFFFFF"))
            cr.rectangle(rect.x, rect.y, rect.width, rect.height)
            cr.fill()

    def button_press_start_button(self, widget, event, desktops):
        pixbuf = app_theme.get_pixbuf("button/start_normal.png").get_pixbuf()
        desktop_infos = self.data_manager.get_pkg_desktop_info(desktops)
        global_event.emit(
            "start-pkg", self.alias_name, desktop_infos,
            (int(event.x), int(event.y), pixbuf.get_width() / 2, 0))

    @post_gui
    def update_some_info(self, info):
        self.star = float(info[0]['mark'].encode('utf-8').strip())
        if self.pkg_star_view:
            self.pkg_star_view.star_buffer.star_level = int(self.star)
            self.pkg_star_view.queue_draw()
        self.pkg_star_mark.update_star(self.star)
        self.pkg_star_mark.queue_draw()

        self.downlad_number = info[0]['down_nums'].encode('utf-8').strip()
        self.left_download_label.set_text(
            _('Download: %s') % self.downlad_number)

    def update_pkg_info(self, pkg_name):
        current_time = time.time()
        if current_time - self.update_pkg_time < self.update_pkg_interval:
            return False
        else:
            self.update_pkg_time = current_time

        FetchPackageInfo(pkg_name, self.update_some_info).start()
        self.pkg_name = pkg_name

        detail_info = self.data_manager.get_pkg_detail_info(self.pkg_name)
        self.category = detail_info['category']
        self.long_desc = detail_info['long_desc']
        self.version = detail_info['version']
        self.homepage = detail_info['homepage']
        self.alias_name = detail_info['alias_name']
        self.recommend_pkgs = detail_info['recommend_pkgs']

        self.pkg_star_view = StarView()
        self.pkg_star_view.connect("clicked", lambda w: self.grade_pkg())
        self.pkg_star_mark = StarMark(5.0, self.MARK_SIZE, self.MARK_PADDING_X,
                                      self.MARK_PADDING_Y)
        container_remove_all(self.star_box)
        self.star_box.pack_start(self.pkg_star_view, False, False)
        self.star_box.pack_start(self.pkg_star_mark, False, False)

        self.fetch_pkg_status()

        container_remove_all(self.left_category_box)
        if self.category != None:
            self.left_category_name_label.set_text(_("Category: "))
            self.left_category_label.set_text(
                get_category_name(self.category[1]))
            self.left_category_box.add(self.left_category_label_box)

        self.left_version_label.set_text(_("Version: %s") % self.version)
        self.left_download_label.set_text(_("Download: 0"))
        self.left_size_label.set_text(_("Size: calculating..."))

        container_remove_all(self.left_homepage_box)
        if self.homepage != "":
            homepage_label = Label(
                _("Visit Homepage"),
                text_color=app_theme.get_color("homepage"),
                hover_color=app_theme.get_color("homepage_hover"))
            homepage_label.set_clickable()
            homepage_label.connect(
                "button-press-event",
                lambda w, e: run_command("xdg-open %s" % self.homepage))
            self.left_homepage_box.pack_start(homepage_label)

        container_remove_all(self.left_recommend_box)
        if len(self.recommend_pkgs) > 0:
            self.left_recommend_box.pack_start(self.left_recommend_label,
                                               False, False, 8)

            for (recommend_pkg_name, alias_name, star) in self.recommend_pkgs:
                self.left_recommend_box.pack_start(
                    RecommendPkgItem(self, recommend_pkg_name, alias_name,
                                     star), False, False, 4)

        container_remove_all(self.right_desc_box)
        resizable_label = ResizableLabel(
            self.long_desc.replace("&", "&amp;").replace("<", "&lt;").replace(
                ">", "&gt;"), self.LONG_DESC_WRAP_WIDTH,
            self.LONG_DESC_INIT_HEIGHT, 3)
        resizable_align = gtk.Alignment()
        resizable_align.set(0.5, 0.5, 1, 1)
        resizable_align.set_padding(0, 0, self.RIGHT_INFO_PADDING_X,
                                    self.RIGHT_INFO_PADDING_X)
        resizable_align.add(resizable_label)
        resizable_align.connect("expose-event",
                                self.expose_resizable_label_background)
        self.right_desc_box.pack_start(resizable_align, False, False)

        self.show_screenshot()

        self.fetch_comment()

        self.show_all()

    def handle_pkg_status(self, reply, success):
        container_remove_all(self.left_action_box)
        if success:
            install_status = str(reply)
            if install_status == "uninstalled":
                action_button = ImageButton(
                    app_theme.get_pixbuf("button/install_normal.png"),
                    app_theme.get_pixbuf("button/install_hover.png"),
                    app_theme.get_pixbuf("button/install_press.png"),
                )
                action_button.connect(
                    "clicked", lambda w: global_event.emit(
                        "install-pkg", [self.pkg_name]))
                self.left_action_box.pack_start(action_button)
            elif install_status == "unknown":
                status_label = Label(_("Not found"))
                self.left_action_box.pack_start(status_label)
            else:
                try:
                    desktops = json.loads(install_status)
                    if not desktops:
                        status_label = Label(_("Successfully installed"))
                        self.left_action_box.pack_start(status_label)
                    else:
                        action_button = ImageButton(
                            app_theme.get_pixbuf("button/start_normal.png"),
                            app_theme.get_pixbuf("button/start_hover.png"),
                            app_theme.get_pixbuf("button/start_press.png"),
                        )
                        action_button.connect(
                            "button-press-event",
                            lambda w, e: self.button_press_start_button(
                                w, e, desktops))
                        self.left_action_box.pack_start(action_button)
                except:
                    logging.error("detail install status: %s = %s" %
                                  (self.pkg_name, install_status))

            self.left_action_box.show_all()
            global_event.emit('update-current-status-pkg-page', self)
        else:
            global_logger.error("get_pkg_installed handle_dbus_error")
            global_logger.error(reply)

    def handle_pkg_download_size(self, reply, success):
        # FIXME: download information display
        if success:
            if reply[0] == PKG_SIZE_OWN or reply[0] == PKG_SIZE_DOWNLOAD:
                self.left_size_label.set_text(
                    _("Size: %s") % bit_to_human_str(reply[1]))
            elif reply[0] == PKG_SIZE_ERROR:
                self.left_size_label.set_text("")
                global_logger.error("Error for calculate pkg size!")
        else:
            global_logger.error(
                "request_pkgs_install_status handle_dbus_error")
            global_logger.error(reply)

    def fetch_pkg_status(self):
        self.data_manager.get_pkg_installed(self.pkg_name,
                                            self.handle_pkg_status)
        self.data_manager.get_pkg_download_size(self.pkg_name,
                                                self.handle_pkg_download_size)

    def open_url(self, webview, frame, network_request, nav_action,
                 policy_dec):
        webbrowser.open(network_request.get_uri())

    def webview_console_message_handler(self, webview, message, line,
                                        source_id):
        return True

    def fetch_comment(self):
        if is_network_connected():
            container_remove_all(self.right_comment_box)
            loading_label = Label(_("Loading comments..."))
            loading_label_align = gtk.Alignment(0.5, 0, 0, 0)
            loading_label_align.add(loading_label)
            loading_label_align.set_padding(10, 0, 0, 0)
            self.right_comment_box.pack_start(loading_label_align, False,
                                              False)
            web_view = WebView(os.path.join(CONFIG_DIR, "cookie.txt"))
            web_view.connect("new-window-policy-decision-requested",
                             self.open_url)
            web_view.connect('console-message',
                             self.webview_console_message_handler)
            web_view_align = gtk.Alignment()
            web_view_align.set(0.5, 0, 0, 0)
            web_view_align.set_padding(33, 33, 33, 33)
            web_view_align.add(web_view)
            web_settings = web_view.get_settings()
            web_settings.set_property("enable-plugins", False)
            web_settings.set_property("enable-scripts", True)
            web_view.open("%s/softcenter/v1/comment?n=%s&hl=%s" % (
                SERVER_ADDRESS,
                self.pkg_name,
                LANGUAGE,
            ))

            web_view.connect("load-finished", self.comment_load_finished_cb,
                             web_view_align)

            create_thread(self.fetch_screenshot).start()

    def comment_load_finished_cb(self, webview, frame, web_view_align):
        self.scrolled_window.connect(
            "vscrollbar-state-changed",
            lambda w, p: self.load_more_comment(p, webview))
        container_remove_all(self.right_comment_box)
        self.right_comment_box.pack_start(web_view_align, True, True)
        self.right_comment_box.show_all()

    def load_more_comment(self, postion, webview):
        if postion == "bottom":
            webview.execute_script('$("#nav_next").click();')

    def fetch_screenshot(self):
        screenshot_dir = os.path.join(SCREENSHOT_DOWNLOAD_DIR, self.pkg_name)
        screenshot_md5_path = os.path.join(screenshot_dir,
                                           "screenshot_md5.txt")
        remote_screenshot_md5_url = "%s/zh_CN/%s/screenshot_md5.txt" % (
            SCREENSHOT_HOST, self.pkg_name)
        remote_screenshot_zip_url = "%s/zh_CN/%s/screenshot.zip" % (
            SCREENSHOT_HOST, self.pkg_name)
        try:
            remote_md5 = urllib2.urlopen(remote_screenshot_md5_url).read()
            need_download = False

            if os.path.exists(screenshot_dir):
                if os.path.exists(screenshot_md5_path):
                    local_md5 = read_file(screenshot_md5_path)
                    if remote_md5 != local_md5:
                        need_download = True
                else:
                    need_download = True
            else:
                need_download = True

            if need_download:
                write_file(screenshot_md5_path, remote_md5, True)

                try:
                    urllib.urlretrieve(
                        remote_screenshot_zip_url,
                        os.path.join(SCREENSHOT_DOWNLOAD_DIR, self.pkg_name,
                                     "screenshot.zip"))
                    global_event.emit("download-screenshot-finish",
                                      self.pkg_name)
                except Exception, e:
                    global_logger.error("Download screenshot error: %s" % e)
        except Exception, e:
            global_logger.error("fetch_screenshot got error: %s" % e)
 def get_scrolled_window(self):
     scrolled_window = ScrolledWindow()
     scrolled_window.connect("vscrollbar-state-changed", self.__on_vscrollbar_state_changed)
     scrolled_window.add_child(self)
     return scrolled_window
        # Return True to tell IconView call gc.collect() to release memory resource.
        if self.pixbuf:
            del self.pixbuf
        self.pixbuf = None    
        return True
    
if __name__ == '__main__':
    gtk.gdk.threads_init()
    module_frame = ModuleFrame(os.path.join(get_parent_dir(__file__, 2), "config.ini"))

    scrolled_window = ScrolledWindow()
    scrolled_window.set_size_request(788, 467)
    wallpaper_view = WallpaperView()
    scrolled_window.add_child(wallpaper_view)
    module_frame.add(scrolled_window)
    
    scrolled_window.connect("vscrollbar-state-changed", wallpaper_view.load_more_background)
    
    download_pool = MissionThreadPool(5)
    download_pool.start()
    
    def message_handler(*message):
        (message_type, message_content) = message
        if message_type == "show_again":
            module_frame.send_module_info()
        elif message_type == "exit":
            module_frame.exit()

    module_frame.module_message_handler = message_handler        
    module_frame.run()