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
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("&", "&").replace("<", "<").replace(">", ">"), 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)
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)
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
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)
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("&", "&").replace("<", "<").replace( ">", ">"), 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)
# 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()