class InstallItem(TreeItem): ''' class docs ''' STATUS_READY_DOWNLOAD= 1 STATUS_PARSE_DOWNLOAD_FAILED = 2 STATUS_DOWNLOAD_FAILED = 3 STATUS_WAIT_DOWNLOAD = 4 STATUS_IN_DOWNLOAD = 5 STATUS_STOP_DOWNLOAD = 6 STATUS_WAIT_INSTALL = 7 STATUS_STOP_WAIT_INSTALL = 8 STATUS_IN_INSTALL = 9 STATUS_INSTALL_FINISH = 10 STATUS_INSTALL_FAILED = 11 STATUS_PADDING_X = 15 def __init__(self, pkg_name, pkg_version, data_manager): ''' init docs ''' TreeItem.__init__(self) self.pkg_name = pkg_name self.pkg_version = pkg_version self.data_manager = data_manager self.icon_pixbuf = None info = self.data_manager.get_item_pkg_info(self.pkg_name) self.alias_name = info[1] self.short_desc = info[2] self.star_level = get_star_level(5.0) self.star_buffer = DscStarBuffer(pkg_name) self.grade_star = 0 self.status = self.STATUS_READY_DOWNLOAD self.status_text = _("Dependencies analyzing") self.progress_buffer = ProgressBuffer() button_pixbuf = app_theme.get_pixbuf("button/start_normal.png").get_pixbuf() (self.button_width, self.button_height) = button_pixbuf.get_width(), button_pixbuf.get_height() self.button_status = BUTTON_NORMAL ### TODO: is_installed status self.install_status = json.dumps([]) self.desktops = [] def handle_pkg_status(self, status, success): if success: self.install_status= str(status) try: self.desktops = json.loads(self.install_status) self.desktops = self.data_manager.get_pkg_desktop_info(self.desktops) except: pass self.emit_redraw_request() else: utils.global_logger.logerror("%s: get_pkg_installed handle_dbus_error" % self.pkg_name) utils.global_logger.logerror(status) def render_pkg_info(self, cr, rect): if self.row_index % 2 == 1: cr.set_source_rgba(1, 1, 1, 0.5) cr.rectangle(rect.x, rect.y, rect.width, rect.height) cr.fill() if self.icon_pixbuf == None: self.icon_pixbuf = gtk.gdk.pixbuf_new_from_file(get_icon_pixbuf_path(self.pkg_name)) render_pkg_info(cr, rect, self.alias_name, self.pkg_name, self.icon_pixbuf, self.pkg_version, self.short_desc, ITEM_PKG_OFFSET_X) def render_pkg_status(self, cr, rect): if self.row_index % 2 == 1: cr.set_source_rgba(1, 1, 1, 0.5) cr.rectangle(rect.x, rect.y, rect.width, rect.height) cr.fill() if self.status == self.STATUS_READY_DOWNLOAD: draw_text( cr, self.status_text, rect.x + rect.width - ITEM_STATUS_TEXT_PADDING_RIGHT, rect.y, rect.width - ITEM_STAR_AREA_WIDTH - self.STATUS_PADDING_X, ITEM_HEIGHT, ) elif self.status == self.STATUS_WAIT_DOWNLOAD: # Draw star. self.star_buffer.render(cr, gtk.gdk.Rectangle(rect.x, rect.y, ITEM_STAR_AREA_WIDTH, ITEM_HEIGHT)) draw_text( cr, self.status_text, rect.x + rect.width - ITEM_STATUS_TEXT_PADDING_RIGHT, rect.y, rect.width - ITEM_STAR_AREA_WIDTH - self.STATUS_PADDING_X, ITEM_HEIGHT, ) pixbuf = app_theme.get_pixbuf("button/stop.png").get_pixbuf() draw_pixbuf( cr, pixbuf, rect.x + rect.width - ITEM_CANCEL_BUTTON_PADDING_RIGHT, rect.y + (rect.height - pixbuf.get_height()) / 2, ) elif self.status == self.STATUS_IN_DOWNLOAD: self.progress_buffer.render( cr, gtk.gdk.Rectangle( rect.x, rect.y + (ITEM_HEIGHT - PROGRESSBAR_HEIGHT) / 2, ITEM_STAR_AREA_WIDTH, PROGRESSBAR_HEIGHT)) draw_text( cr, self.status_text, rect.x + rect.width - ITEM_STATUS_TEXT_PADDING_RIGHT, rect.y, rect.width - ITEM_STAR_AREA_WIDTH - self.STATUS_PADDING_X, ITEM_HEIGHT, ) pixbuf = app_theme.get_pixbuf("button/stop.png").get_pixbuf() draw_pixbuf( cr, pixbuf, rect.x + rect.width - ITEM_CANCEL_BUTTON_PADDING_RIGHT, rect.y + (rect.height - pixbuf.get_height()) / 2, ) elif self.status == self.STATUS_STOP_DOWNLOAD: # Draw star. self.star_buffer.render(cr, gtk.gdk.Rectangle(rect.x, rect.y, ITEM_STAR_AREA_WIDTH, ITEM_HEIGHT)) draw_text( cr, self.status_text, rect.x + rect.width - ITEM_STATUS_TEXT_PADDING_RIGHT, rect.y, rect.width - ITEM_STAR_AREA_WIDTH - self.STATUS_PADDING_X, ITEM_HEIGHT, ) elif self.status == self.STATUS_DOWNLOAD_FAILED: # Draw star. draw_text( cr, self.status_text, rect.x, rect.y, get_content_size(self.status_text)[0], ITEM_HEIGHT, text_color="#ff0000", ) if self.button_status == BUTTON_NORMAL: status = "normal" elif self.button_status == BUTTON_HOVER: status = "hover" elif self.button_status == BUTTON_PRESS: status = "press" pixbuf = app_theme.get_pixbuf("button/install_%s.png" % (status, )).get_pixbuf() draw_pixbuf( cr, pixbuf, rect.x + rect.width - ITEM_BUTTON_PADDING_RIGHT - pixbuf.get_width(), rect.y + (rect.height - pixbuf.get_height()) / 2 ) elif self.status == self.STATUS_WAIT_INSTALL: self.progress_buffer.render( cr, gtk.gdk.Rectangle( rect.x, rect.y + (ITEM_HEIGHT - PROGRESSBAR_HEIGHT) / 2, ITEM_STAR_AREA_WIDTH, PROGRESSBAR_HEIGHT)) draw_text( cr, self.status_text, rect.x + rect.width - ITEM_STATUS_TEXT_PADDING_RIGHT, rect.y, rect.width - ITEM_STAR_AREA_WIDTH - self.STATUS_PADDING_X, ITEM_HEIGHT, ) pixbuf = app_theme.get_pixbuf("button/stop.png").get_pixbuf() draw_pixbuf( cr, pixbuf, rect.x + rect.width - ITEM_CANCEL_BUTTON_PADDING_RIGHT, rect.y + (rect.height - pixbuf.get_height()) / 2, ) elif self.status == self.STATUS_STOP_WAIT_INSTALL: # Draw star. self.star_buffer.render(cr, gtk.gdk.Rectangle(rect.x, rect.y, ITEM_STAR_AREA_WIDTH, ITEM_HEIGHT)) draw_text( cr, self.status_text, rect.x + rect.width - ITEM_STATUS_TEXT_PADDING_RIGHT, rect.y, rect.width - ITEM_STAR_AREA_WIDTH - self.STATUS_PADDING_X, ITEM_HEIGHT, ) elif self.status == self.STATUS_IN_INSTALL: self.progress_buffer.render( cr, gtk.gdk.Rectangle( rect.x, rect.y + (ITEM_HEIGHT - PROGRESSBAR_HEIGHT) / 2, ITEM_STAR_AREA_WIDTH, PROGRESSBAR_HEIGHT)) draw_text( cr, self.status_text, rect.x + rect.width - ITEM_STATUS_TEXT_PADDING_RIGHT, rect.y, rect.width - ITEM_STAR_AREA_WIDTH - self.STATUS_PADDING_X, ITEM_HEIGHT, ) elif self.status == self.STATUS_INSTALL_FINISH: # Draw star. self.star_buffer.render(cr, gtk.gdk.Rectangle(rect.x, rect.y, ITEM_STAR_AREA_WIDTH, ITEM_HEIGHT)) # Draw button. name = "" draw_str = "" if self.install_status == "uninstalled": name = "button/install" elif self.install_status == "unknown": draw_str = _("Installed") else: if self.desktops: name = "button/start" else: draw_str = _("Installed") if name: if self.button_status == BUTTON_NORMAL: status = "normal" elif self.button_status == BUTTON_HOVER: status = "hover" elif self.button_status == BUTTON_PRESS: status = "press" pixbuf = app_theme.get_pixbuf("%s_%s.png" % (name, status)).get_pixbuf() draw_pixbuf( cr, pixbuf, rect.x + rect.width - ITEM_BUTTON_PADDING_RIGHT - pixbuf.get_width(), rect.y + (ITEM_HEIGHT - self.button_height) / 2, ) else: str_width, str_height = get_content_size(draw_str, 10) draw_text( cr, draw_str, rect.x + rect.width - ITEM_BUTTON_PADDING_RIGHT - str_width, rect.y + (rect.height - str_height) / 2, str_width, str_height, alignment=pango.ALIGN_CENTER, ) elif self.status == self.STATUS_PARSE_DOWNLOAD_FAILED: # Draw star. self.star_buffer.render(cr, gtk.gdk.Rectangle(rect.x, rect.y, ITEM_STAR_AREA_WIDTH, ITEM_HEIGHT)) draw_text( cr, self.status_text, rect.x + rect.width - ITEM_STATUS_TEXT_PADDING_RIGHT, rect.y, rect.width - ITEM_STAR_AREA_WIDTH - self.STATUS_PADDING_X, ITEM_HEIGHT, ) def get_height(self): return ITEM_HEIGHT def get_column_widths(self): return [ITEM_INFO_AREA_WIDTH, ITEM_STAR_AREA_WIDTH + ITEM_BUTTON_AREA_WIDTH] def get_column_renders(self): return [self.render_pkg_info, self.render_pkg_status] def unselect(self): pass def select(self): pass def unhover(self, column, offset_x, offset_y): pass def hover(self, column, offset_x, offset_y): pass def motion_notify(self, column, offset_x, offset_y): if column == 0: if self.is_in_icon_area(column, offset_x, offset_y): global_event.emit("set-cursor", gtk.gdk.HAND2) elif self.is_in_name_area(column, offset_x, offset_y): global_event.emit("set-cursor", gtk.gdk.HAND2) else: global_event.emit("set-cursor", None) else: if self.status == self.STATUS_INSTALL_FINISH: if self.desktops: if self.is_in_button_area(column, offset_x, offset_y): self.button_status = BUTTON_HOVER if self.redraw_request_callback: self.redraw_request_callback(self) elif self.button_status != BUTTON_NORMAL: self.button_status = BUTTON_NORMAL if self.redraw_request_callback: self.redraw_request_callback(self) if self.is_in_star_area(column, offset_x, offset_y): global_event.emit("set-cursor", gtk.gdk.HAND2) times = offset_x / STAR_SIZE self.grade_star = times * 2 + 2 self.grade_star = min(self.grade_star, 10) self.star_buffer.star_level = self.grade_star if self.redraw_request_callback: self.redraw_request_callback(self) else: global_event.emit("set-cursor", None) if self.star_buffer.star_level != self.star_level: self.star_buffer.star_level = self.star_level if self.redraw_request_callback: self.redraw_request_callback(self) elif self.status == self.STATUS_DOWNLOAD_FAILED: if self.is_in_button_area(column, offset_x, offset_y): self.button_status = BUTTON_HOVER if self.redraw_request_callback: self.redraw_request_callback(self) elif self.button_status != BUTTON_NORMAL: self.button_status = BUTTON_NORMAL if self.redraw_request_callback: self.redraw_request_callback(self) elif self.status == self.STATUS_READY_DOWNLOAD: if self.is_in_star_area(column, offset_x, offset_y): global_event.emit("set-cursor", gtk.gdk.HAND2) times = offset_x / STAR_SIZE self.grade_star = times * 2 + 2 self.grade_star = min(self.grade_star, 10) self.star_buffer.star_level = self.grade_star if self.redraw_request_callback: self.redraw_request_callback(self) else: global_event.emit("set-cursor", None) if self.star_buffer.star_level != self.star_level: self.star_buffer.star_level = self.star_level if self.redraw_request_callback: self.redraw_request_callback(self) def button_press(self, column, offset_x, offset_y): if column == 0: if self.is_in_icon_area(column, offset_x, offset_y): global_event.emit("switch-to-detail-page", self.pkg_name) global_event.emit("set-cursor", None) elif self.is_in_name_area(column, offset_x, offset_y): global_event.emit("switch-to-detail-page", self.pkg_name) global_event.emit("set-cursor", None) else: if self.status == self.STATUS_WAIT_DOWNLOAD: if self.is_stop_button_can_click(column, offset_x, offset_y): self.status = self.STATUS_STOP_DOWNLOAD self.status_text = _("Download was interrupted") if self.redraw_request_callback: self.redraw_request_callback(self) global_event.emit("remove-wait-download", [self.pkg_name]) global_event.emit("request-stop-install-actions", [self.pkg_name]) elif self.is_in_star_area(column, offset_x, offset_y): global_event.emit("grade-pkg", self.pkg_name, self.grade_star) elif self.status == self.STATUS_IN_DOWNLOAD: if self.is_stop_button_can_click(column, offset_x, offset_y): self.status = self.STATUS_STOP_DOWNLOAD self.status_text = _("Download was interrupted") if self.redraw_request_callback: self.redraw_request_callback(self) global_event.emit("stop-download-pkg", [self.pkg_name]) global_event.emit("request-stop-install-actions", [self.pkg_name]) elif self.status == self.STATUS_DOWNLOAD_FAILED: if self.is_in_button_area(column, offset_x, offset_y): global_event.emit("install-pkg", [self.pkg_name]) elif self.status == self.STATUS_WAIT_INSTALL: if self.is_stop_button_can_click(column, offset_x, offset_y): self.status = self.STATUS_STOP_WAIT_INSTALL self.status_text = _("Installation was interrupted") if self.redraw_request_callback: self.redraw_request_callback(self) global_event.emit("remove-wait-action", [(self.pkg_name, ACTION_INSTALL)]) global_event.emit("request-stop-install-actions", [self.pkg_name]) elif self.status == self.STATUS_INSTALL_FINISH: if self.is_in_star_area(column, offset_x, offset_y): global_event.emit("grade-pkg", self.pkg_name, self.grade_star) elif self.is_in_button_area(column, offset_x, offset_y): if self.desktops: global_event.emit("start-pkg", self.alias_name, self.desktops, self.get_offset_with_button(offset_x, offset_y)) def get_offset_with_button(self, offset_x, offset_y): pixbuf = app_theme.get_pixbuf("button/start_normal.png").get_pixbuf() popup_x = self.get_column_widths()[1] - ITEM_BUTTON_PADDING_RIGHT - pixbuf.get_width() / 2 popup_y = (ITEM_HEIGHT - pixbuf.get_height()) / 2 return (offset_x, offset_y, popup_x, popup_y) def button_release(self, column, offset_x, offset_y): pass def single_click(self, column, offset_x, offset_y): pass def double_click(self, column, offset_x, offset_y): pass def is_in_star_area(self, column, offset_x, offset_y): return (column == 1 and is_in_rect((offset_x, offset_y), (0, (ITEM_HEIGHT - STAR_SIZE) / 2, ITEM_STAR_AREA_WIDTH, STAR_SIZE))) def is_in_button_area(self, column, offset_x, offset_y): return (column == 1 and is_in_rect((offset_x, offset_y), (self.get_column_widths()[column] - ITEM_BUTTON_PADDING_RIGHT - self.button_width, (ITEM_HEIGHT - self.button_height) / 2, self.button_width, self.button_height))) def is_stop_button_can_click(self, column, offset_x, offset_y): pixbuf = app_theme.get_pixbuf("button/stop.png").get_pixbuf() return (column == 1 and is_in_rect((offset_x, offset_y), (self.get_column_widths()[column] - ITEM_CANCEL_BUTTON_PADDING_RIGHT, (ITEM_HEIGHT - pixbuf.get_height()) / 2, pixbuf.get_width(), pixbuf.get_height()))) def download_ready(self): self.status = self.STATUS_READY_DOWNLOAD self.status_text = _("Dependencies analyzing") if self.redraw_request_callback: self.redraw_request_callback(self) def download_wait(self): self.status = self.STATUS_WAIT_DOWNLOAD self.status_text = _("Waiting for download") if self.redraw_request_callback: self.redraw_request_callback(self) def download_start(self): self.status = self.STATUS_IN_DOWNLOAD self.status_text = _("Downloading") if self.redraw_request_callback: self.redraw_request_callback(self) def download_failed(self): self.status = self.STATUS_DOWNLOAD_FAILED self.status_text = _("Download failed") if self.redraw_request_callback: self.redraw_request_callback(self) def download_update(self, percent, speed): self.status = self.STATUS_IN_DOWNLOAD self.progress_buffer.progress = percent self.status_text = "%s/s" % (format_file_size(speed)) if self.redraw_request_callback: self.redraw_request_callback(self) def download_finish(self): self.status = self.STATUS_WAIT_INSTALL self.progress_buffer.progress = 0 self.status_text = _("Waiting for installation") if self.redraw_request_callback: self.redraw_request_callback(self) def download_stop(self): pass def download_parse_failed(self): self.status = self.STATUS_PARSE_DOWNLOAD_FAILED self.status_text = _("Dependencies analysis failed") if self.redraw_request_callback: self.redraw_request_callback(self) global_event.emit("request-clear-failed-action", self.pkg_name, ACTION_INSTALL) def action_start(self): self.status = self.STATUS_IN_INSTALL self.status_text = _("Installing") if self.redraw_request_callback: self.redraw_request_callback(self) def action_update(self, percent): self.status = self.STATUS_IN_INSTALL self.status_text = _("Installing") self.progress_buffer.progress = percent if self.redraw_request_callback: self.redraw_request_callback(self) def action_finish(self): self.status = self.STATUS_INSTALL_FINISH self.progress_buffer.progress = 100 self.status_text = _("Installation completed") if self.redraw_request_callback: self.redraw_request_callback(self) self.data_manager.get_pkg_installed(self.pkg_name, self.handle_pkg_status) def is_in_name_area(self, column, offset_x, offset_y): (name_width, name_height) = get_content_size(self.alias_name, NAME_SIZE) return (column == 0 and is_in_rect((offset_x, offset_y), (ITEM_PADDING_X + ITEM_PKG_OFFSET_X + ICON_SIZE + ITEM_PADDING_MIDDLE, ITEM_PADDING_Y, name_width, NAME_SIZE))) def is_in_icon_area(self, column, offset_x, offset_y): return (column == 0 and self.icon_pixbuf != None and is_in_rect((offset_x, offset_y), (ITEM_PADDING_X + ITEM_PKG_OFFSET_X, ITEM_PADDING_Y, self.icon_pixbuf.get_width(), self.icon_pixbuf.get_height()))) def release_resource(self): ''' Release item resource. If you have pixbuf in item, you should release memory resource like below code: >>> if self.pixbuf: >>> del self.pixbuf >>> self.pixbuf = None >>> >>> return True This is TreeView interface, you should implement it. @return: Return True if do release work, otherwise return False. When this function return True, TreeView will call function gc.collect() to release object to release memory. ''' if self.icon_pixbuf: del self.icon_pixbuf self.icon_pixbuf = None return True
class UninstallItem(TreeItem): ''' class docs ''' STATUS_NORMAL = 1 STATUS_CONFIRM = 2 STATUS_WAIT_ACTION = 3 STATUS_IN_ACTION = 4 STATUS_PADDING_X = 15 def __init__(self, pkg_name, pkg_version, data_manager): ''' init docs ''' TreeItem.__init__(self) self.pkg_name = pkg_name self.pkg_version = pkg_version self.data_manager = data_manager self.icon_pixbuf = None (self.short_desc, star, self.alias_name) = data_manager.get_item_pkg_info(self.pkg_name) self.star_level = get_star_level(star) self.star_buffer = DscStarBuffer(pkg_name) self.grade_star = 0 button_pixbuf = app_theme.get_pixbuf("button/uninstall_normal.png").get_pixbuf() (self.button_width, self.button_height) = button_pixbuf.get_width(), button_pixbuf.get_height() self.button_status = BUTTON_NORMAL self.status = self.STATUS_NORMAL self.status_text = "" self.progress_buffer = ProgressBuffer() #self.action_wait() def render_pkg_info(self, cr, rect): if self.row_index % 2 == 1: cr.set_source_rgba(1, 1, 1, 0.5) cr.rectangle(rect.x, rect.y, rect.width, rect.height) cr.fill() if self.icon_pixbuf == None: self.icon_pixbuf = gtk.gdk.pixbuf_new_from_file(get_icon_pixbuf_path(self.pkg_name)) render_pkg_info(cr, rect, self.alias_name, self.pkg_name, self.icon_pixbuf, self.pkg_version, self.short_desc, ITEM_PKG_OFFSET_X) def render_pkg_status(self, cr, rect): if self.row_index % 2 == 1: cr.set_source_rgba(1, 1, 1, 0.5) cr.rectangle(rect.x, rect.y, rect.width, rect.height) cr.fill() if self.status == self.STATUS_CONFIRM: # Draw star. self.star_buffer.render(cr, gtk.gdk.Rectangle(rect.x, rect.y, ITEM_STAR_AREA_WIDTH, ITEM_HEIGHT)) confirm_pixbuf = app_theme.get_pixbuf("button/uninstall_confirm.png").get_pixbuf() cancel_pixbuf = app_theme.get_pixbuf("button/uninstall_cancel.png").get_pixbuf() draw_pixbuf( cr, confirm_pixbuf, rect.x + rect.width - ITEM_CONFIRM_BUTTON_PADDING_RIGHT, rect.y + (ITEM_HEIGHT - confirm_pixbuf.get_height()) / 2, ) draw_pixbuf( cr, cancel_pixbuf, rect.x + rect.width - ITEM_CANCEL_BUTTON_PADDING_RIGHT, rect.y + (ITEM_HEIGHT - cancel_pixbuf.get_height()) / 2, ) elif self.status == self.STATUS_IN_ACTION: self.progress_buffer.render( cr, gtk.gdk.Rectangle( rect.x, rect.y + (ITEM_HEIGHT - PROGRESSBAR_HEIGHT) / 2, ITEM_STAR_AREA_WIDTH, PROGRESSBAR_HEIGHT)) draw_text( cr, self.status_text, rect.x + rect.width - ITEM_STATUS_TEXT_PADDING_RIGHT, rect.y, rect.width - ITEM_STAR_AREA_WIDTH, ITEM_HEIGHT, ) elif self.status == self.STATUS_WAIT_ACTION: # Draw star. self.star_buffer.render(cr, gtk.gdk.Rectangle(rect.x, rect.y, ITEM_STAR_AREA_WIDTH, ITEM_HEIGHT)) draw_text( cr, self.status_text, rect.x + rect.width - ITEM_STATUS_TEXT_PADDING_RIGHT, rect.y, rect.width - ITEM_STAR_AREA_WIDTH, ITEM_HEIGHT, ) cancel_pixbuf = app_theme.get_pixbuf("button/uninstall_cancel.png").get_pixbuf() draw_pixbuf( cr, cancel_pixbuf, rect.x + rect.width - 50, rect.y + (ITEM_HEIGHT - cancel_pixbuf.get_height()) / 2, ) elif self.status == self.STATUS_NORMAL: # Draw star. self.star_buffer.render(cr, gtk.gdk.Rectangle(rect.x, rect.y, ITEM_STAR_AREA_WIDTH, ITEM_HEIGHT)) # Draw button. if self.button_status == BUTTON_NORMAL: pixbuf = app_theme.get_pixbuf("button/uninstall_normal.png").get_pixbuf() elif self.button_status == BUTTON_HOVER: pixbuf = app_theme.get_pixbuf("button/uninstall_hover.png").get_pixbuf() elif self.button_status == BUTTON_PRESS: pixbuf = app_theme.get_pixbuf("button/uninstall_press.png").get_pixbuf() draw_pixbuf( cr, pixbuf, rect.x + rect.width - ITEM_BUTTON_PADDING_RIGHT - pixbuf.get_width(), rect.y + (ITEM_HEIGHT - self.button_height) / 2, ) def get_height(self): return ITEM_HEIGHT def get_column_widths(self): return [ITEM_INFO_AREA_WIDTH, ITEM_STAR_AREA_WIDTH + ITEM_BUTTON_AREA_WIDTH] def get_column_renders(self): return [self.render_pkg_info, self.render_pkg_status] def unselect(self): pass def select(self): pass def unhover(self, column, offset_x, offset_y): pass def hover(self, column, offset_x, offset_y): pass def motion_notify(self, column, offset_x, offset_y): if column == 0: if self.is_in_icon_area(column, offset_x, offset_y): global_event.emit("set-cursor", gtk.gdk.HAND2) elif self.is_in_name_area(column, offset_x, offset_y): global_event.emit("set-cursor", gtk.gdk.HAND2) else: global_event.emit("set-cursor", None) else: if self.status == self.STATUS_NORMAL: if self.is_in_button_area(column, offset_x, offset_y): self.button_status = BUTTON_HOVER if self.redraw_request_callback: self.redraw_request_callback(self) elif self.button_status != BUTTON_NORMAL: self.button_status = BUTTON_NORMAL if self.redraw_request_callback: self.redraw_request_callback(self) if self.is_in_star_area(column, offset_x, offset_y): global_event.emit("set-cursor", gtk.gdk.HAND2) times = offset_x / STAR_SIZE self.grade_star = times * 2 + 2 self.grade_star = min(self.grade_star, 10) self.star_buffer.star_level = self.grade_star if self.redraw_request_callback: self.redraw_request_callback(self) else: global_event.emit("set-cursor", None) if self.star_buffer.star_level != self.star_level: self.star_buffer.star_level = self.star_level if self.redraw_request_callback: self.redraw_request_callback(self) def button_press(self, column, offset_x, offset_y): if column == 0: if self.is_in_icon_area(column, offset_x, offset_y): global_event.emit("switch-to-detail-page", self.pkg_name) global_event.emit("set-cursor", None) elif self.is_in_name_area(column, offset_x, offset_y): global_event.emit("switch-to-detail-page", self.pkg_name) global_event.emit("set-cursor", None) else: if self.status == self.STATUS_NORMAL: if self.is_in_button_area(column, offset_x, offset_y): self.status = self.STATUS_CONFIRM if self.redraw_request_callback: self.redraw_request_callback(self) elif self.is_in_star_area(column, offset_x, offset_y): global_event.emit("grade-pkg", self.pkg_name, self.grade_star) elif self.status == self.STATUS_CONFIRM: if self.is_confirm_button_area(column, offset_x, offset_y): self.status = self.STATUS_WAIT_ACTION self.status_text = _("Waiting for uninstall") if self.redraw_request_callback: self.redraw_request_callback(self) global_event.emit("uninstall-pkg", self.pkg_name, get_purg_flag()) elif self.is_cancel_button_area(column, offset_x, offset_y): self.status = self.STATUS_NORMAL if self.redraw_request_callback: self.redraw_request_callback(self) elif self.status == self.STATUS_WAIT_ACTION: if self.is_cancel_button_area(column, offset_x, offset_y): self.status = self.STATUS_NORMAL global_event.emit("remove-wait-action", [(str((self.pkg_name, ACTION_UNINSTALL)))]) if self.redraw_request_callback: self.redraw_request_callback(self) def button_release(self, column, offset_x, offset_y): pass def single_click(self, column, offset_x, offset_y): pass def double_click(self, column, offset_x, offset_y): pass def is_in_star_area(self, column, offset_x, offset_y): return (column == 1 and is_in_rect((offset_x, offset_y), (0, (ITEM_HEIGHT - STAR_SIZE) / 2, ITEM_STAR_AREA_WIDTH, STAR_SIZE))) def is_in_button_area(self, column, offset_x, offset_y): return (column == 1 and is_in_rect((offset_x, offset_y), (self.get_column_widths()[column] - ITEM_BUTTON_PADDING_RIGHT - self.button_width, (ITEM_HEIGHT - self.button_height) / 2, self.button_width, self.button_height))) def is_confirm_button_area(self, column, offset_x, offset_y): confirm_pixbuf = app_theme.get_pixbuf("button/uninstall_confirm.png").get_pixbuf() return (column == 1 and is_in_rect((offset_x, offset_y), (self.get_column_widths()[column] - ITEM_CONFIRM_BUTTON_PADDING_RIGHT, (ITEM_HEIGHT - confirm_pixbuf.get_height()) / 2, confirm_pixbuf.get_width(), confirm_pixbuf.get_height()))) def is_cancel_button_area(self, column, offset_x, offset_y): cancel_pixbuf = app_theme.get_pixbuf("button/uninstall_cancel.png").get_pixbuf() return (column == 1 and is_in_rect((offset_x, offset_y), (self.get_column_widths()[column] - ITEM_CANCEL_BUTTON_PADDING_RIGHT, (ITEM_HEIGHT - cancel_pixbuf.get_height()) / 2, cancel_pixbuf.get_width(), cancel_pixbuf.get_height()))) def is_in_name_area(self, column, offset_x, offset_y): (name_width, name_height) = get_content_size(self.alias_name, NAME_SIZE) return (column == 0 and is_in_rect((offset_x, offset_y), (ITEM_PADDING_X + ITEM_PKG_OFFSET_X + ICON_SIZE + ITEM_PADDING_MIDDLE, ITEM_PADDING_Y, name_width, NAME_SIZE))) def is_in_icon_area(self, column, offset_x, offset_y): return (column == 0 and self.icon_pixbuf != None and is_in_rect((offset_x, offset_y), (ITEM_PADDING_X + ITEM_PKG_OFFSET_X, ITEM_PADDING_Y, self.icon_pixbuf.get_width(), self.icon_pixbuf.get_height()))) def action_wait(self): self.status = self.STATUS_WAIT_ACTION self.status_text = _("Waiting for uninstall") if self.redraw_request_callback: self.redraw_request_callback(self) def action_start(self): self.status = self.STATUS_IN_ACTION self.status_text = _("Uninstalling") if self.redraw_request_callback: self.redraw_request_callback(self) def action_update(self, percent): self.progress_buffer.progress = percent self.status_text = _("Uninstalling") if self.redraw_request_callback: self.redraw_request_callback(self) def action_finish(self): self.progress_buffer.progress = 100 self.status_text = _("Uninstall successful") if self.redraw_request_callback: self.redraw_request_callback(self) def release_resource(self): ''' Release item resource. If you have pixbuf in item, you should release memory resource like below code: >>> if self.pixbuf: >>> del self.pixbuf >>> self.pixbuf = None >>> >>> return True This is TreeView interface, you should implement it. @return: Return True if do release work, otherwise return False. When this function return True, TreeView will call function gc.collect() to release object to release memory. ''' if self.icon_pixbuf: del self.icon_pixbuf self.icon_pixbuf = None return True
class TranscoderJob(gobject.GObject): __gsignals__ = { "end": (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, ()), "redraw-request": (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, ()), } __stop = False __pause = False __is_alive = True priority = 10 def __init__(self, trans_data): gobject.GObject.__init__(self) self.__updater_id = None # Init data. self.angle = 0 self.status_icon = app_theme.get_pixbuf( "transcoder/wait.png").get_pixbuf() self.status_icon_press = app_theme.get_pixbuf( "transcoder/wait_press.png").get_pixbuf() self.stop_icon = app_theme.get_pixbuf( "transcoder/stop.png").get_pixbuf() self.progress_ratio = 0.0 self.skip_flag = False self.trans_data = trans_data self.init_transcoder(trans_data) self.__update() self.progress_buffer = ProgressBuffer() def start(self): if self.skip_flag: self.finish_job() else: self.transcoder.start_transcode() self.__set_status_icon("working") self.__updater_id = gobject.timeout_add(500, self.update_progress) def update_progress(self): self.set_progress_ratio(self.transcoder.get_ratio()) return True def __update(self): self.title = self.trans_data["song"].get_str("title") self.status_icon_padding_x = 10 self.status_icon_padding_y = 5 self.status_icon_w, self.status_icon_h = ( self.status_icon.get_width(), self.status_icon.get_height()) self.title_padding_x = 5 self.title_padding_y = 5 self.title_w, self.title_h = get_content_size(self.title, DEFAULT_FONT_SIZE) self.progress_padding_x = 10 self.progress_padding_y = 5 self.progress_w, self.progress_h = 100, 10 self.stop_icon_padding_x = 5 self.stop_icon_padding_y = 5 self.stop_icon_w, self.stop_icon_h = (self.stop_icon.get_width(), self.stop_icon.get_height()) self.ext_padding_x = 5 self.ext_padding_y = 5 self.ext_w, self.ext_h = get_content_size(self.output_ext, DEFAULT_FONT_SIZE) def init_transcoder(self, attr): self.raw_song = attr["song"] self.output_path = attr["output"] if os.path.exists(self.output_path) and attr["prompt"]: self.exists_prompt = True else: self.exists_prompt = False if self.raw_song.get_path() == self.output_path: self.skip_flag = True self.output_ext = FORMATS[attr["format"]]["extension"] self.transcoder = Transcoder() self.transcoder.set_format(attr["format"]) self.transcoder.set_quality(attr["quality"]) if self.raw_song.get_type() == "audiocd": self.transcoder.set_cd_input(self.raw_song.get("uri")) else: self.transcoder.set_input(attr["song"].get_path()) self.transcoder.set_output(self.output_path) self.transcoder.end_cb = self.__end def __end(self): try: self.write_tags() except: pass self.finish_job() def finish_job(self): self.emit("end") self.__set_status_icon("success") self.set_progress_ratio(1.0) try: gobject.source_remove(self.__updater_id) except: pass if self.trans_data["to_playlist"]: tags = {"uri": utils.get_uri_from_path(self.output_path)} song = MediaDB.get_or_create_song(tags, "local", read_from_file=True) if song: Dispatcher.add_songs([song]) def write_tags(self): tags = deepcopy(self.raw_song) tags["uri"] = utils.get_uri_from_path(self.output_path) s = Song() s.init_from_dict(tags) s.write_to_file() @property def is_running(self): return self.transcoder.running @property def is_finish(self): return self.transcoder.is_eos def force_stop(self): try: gobject.source_remove(self.__updater_id) except: pass if self.transcoder.running: self.transcoder.pause() try: os.unlink(self.output_path) except: pass def playpause(self): if self.transcoder.running: if self.transcoder.is_pause: self.transcoder.playing() self.__updater_id = gobject.timeout_add( 500, self.update_progress) return True else: try: gobject.source_remove(self.__updater_id) except: pass self.transcoder.pause() return True return False def set_progress_ratio(self, value): self.progress_ratio = value self.emit_redraw_request() def set_index(self, index): '''Update index.''' self.index = index def get_index(self): '''Get index.''' return self.index def __set_status_icon(self, name): self.status_icon = app_theme.get_pixbuf("transcoder/%s.png" % name).get_pixbuf() self.status_icon_press = app_theme.get_pixbuf( "transcoder/%s_press.png" % name).get_pixbuf() self.emit_redraw_request() def set_error_status(self): self.__set_status_icon("error") def emit_redraw_request(self): '''Emit redraw-request signal.''' self.emit("redraw-request") def render_icon(self, cr, rect, in_select, in_highlight): icon_x = rect.x + self.status_icon_padding_x icon_y = rect.y + (rect.height - self.status_icon_h) / 2 if in_select: draw_pixbuf(cr, self.status_icon_press, icon_x, icon_y) else: draw_pixbuf(cr, self.status_icon, icon_x, icon_y) def render_title(self, cr, rect, in_select, in_highlight): rect.x += self.title_padding_x rect.width -= self.title_padding_x * 2 render_item_text2(cr, self.title, rect, in_select, in_highlight) def render_progress(self, cr, rect, in_select, in_highlight): self.progress_buffer.progress = self.progress_ratio * 100 progress_x = rect.x + self.progress_padding_x progress_y = rect.y + (rect.height - self.progress_h) / 2 progress_rect = gtk.gdk.Rectangle(progress_x, progress_y, self.progress_w, self.progress_h) self.progress_buffer.render(cr, progress_rect) def render_stop(self, cr, rect, in_select, in_highlight): icon_x = rect.x + self.stop_icon_padding_x icon_y = rect.y + (rect.height - self.stop_icon_h) / 2 draw_pixbuf(cr, self.stop_icon, icon_x, icon_y) def render_ext(self, cr, rect, in_select, in_highlight): rect.x += self.ext_padding_x rect.width -= self.ext_padding_x * 2 render_item_text2(cr, self.output_ext.upper(), rect, in_select, in_highlight) def get_ext_type(self): gio_file = gio.File(self.output_path) gio_file_info = gio_file.query_info(",".join([ gio.FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE, gio.FILE_ATTRIBUTE_STANDARD_TYPE, gio.FILE_ATTRIBUTE_STANDARD_NAME, gio.FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME, gio.FILE_ATTRIBUTE_STANDARD_SIZE, gio.FILE_ATTRIBUTE_STANDARD_ICON, gio.FILE_ATTRIBUTE_TIME_MODIFIED, gio.FILE_ATTRIBUTE_TIME_CHANGED, ])) info_attr = gio_file_info.get_attribute_as_string( gio.FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE) return gio.content_type_get_description(info_attr) def get_column_sizes(self): return [ (36, self.status_icon_h + self.status_icon_padding_y * 2), (135, self.title_h + self.title_padding_y * 2), (120, self.progress_h + self.progress_padding_y * 2), # (26, self.stop_icon_h + self.stop_icon_padding_y * 2), (50, self.ext_h + self.ext_padding_y), ] def get_renders(self): return [ self.render_icon, self.render_title, self.render_progress, self.render_ext ]
class InstallItem(TreeItem): ''' class docs ''' STATUS_READY_DOWNLOAD = 1 STATUS_PARSE_DOWNLOAD_FAILED = 2 STATUS_DOWNLOAD_FAILED = 3 STATUS_WAIT_DOWNLOAD = 4 STATUS_IN_DOWNLOAD = 5 STATUS_STOP_DOWNLOAD = 6 STATUS_WAIT_INSTALL = 7 STATUS_STOP_WAIT_INSTALL = 8 STATUS_IN_INSTALL = 9 STATUS_INSTALL_FINISH = 10 STATUS_INSTALL_FAILED = 11 STATUS_PADDING_X = 15 def __init__(self, pkg_name, pkg_version, data_manager): ''' init docs ''' TreeItem.__init__(self) self.pkg_name = pkg_name self.pkg_version = pkg_version self.data_manager = data_manager self.icon_pixbuf = None info = self.data_manager.get_item_pkg_info(self.pkg_name) self.alias_name = info[1] self.short_desc = info[2] self.star_level = get_star_level(5.0) self.star_buffer = DscStarBuffer(pkg_name) self.grade_star = 0 self.status = self.STATUS_READY_DOWNLOAD self.status_text = _("Dependencies analyzing") self.progress_buffer = ProgressBuffer() button_pixbuf = app_theme.get_pixbuf( "button/start_normal.png").get_pixbuf() (self.button_width, self.button_height ) = button_pixbuf.get_width(), button_pixbuf.get_height() self.button_status = BUTTON_NORMAL ### TODO: is_installed status self.install_status = json.dumps([]) self.desktops = [] def handle_pkg_status(self, status, success): if success: self.install_status = str(status) try: self.desktops = json.loads(self.install_status) self.desktops = self.data_manager.get_pkg_desktop_info( self.desktops) except: pass self.emit_redraw_request() else: utils.global_logger.error( "%s: get_pkg_installed handle_dbus_error" % self.pkg_name) utils.global_logger.error(status) def render_pkg_info(self, cr, rect): if self.row_index % 2 == 1: cr.set_source_rgba(1, 1, 1, 0.5) cr.rectangle(rect.x, rect.y, rect.width, rect.height) cr.fill() if self.icon_pixbuf == None: self.icon_pixbuf = gtk.gdk.pixbuf_new_from_file( get_icon_pixbuf_path(self.pkg_name)) render_pkg_info(cr, rect, self.alias_name, self.pkg_name, self.icon_pixbuf, self.pkg_version, self.short_desc, ITEM_PKG_OFFSET_X) def render_pkg_status(self, cr, rect): if self.row_index % 2 == 1: cr.set_source_rgba(1, 1, 1, 0.5) cr.rectangle(rect.x, rect.y, rect.width, rect.height) cr.fill() if self.status == self.STATUS_READY_DOWNLOAD: draw_text( cr, self.status_text, rect.x + rect.width - ITEM_STATUS_TEXT_PADDING_RIGHT, rect.y, rect.width - ITEM_STAR_AREA_WIDTH - self.STATUS_PADDING_X, ITEM_HEIGHT, ) elif self.status == self.STATUS_WAIT_DOWNLOAD: # Draw star. self.star_buffer.render( cr, gtk.gdk.Rectangle(rect.x, rect.y, ITEM_STAR_AREA_WIDTH, ITEM_HEIGHT)) draw_text( cr, self.status_text, rect.x + rect.width - ITEM_STATUS_TEXT_PADDING_RIGHT, rect.y, rect.width - ITEM_STAR_AREA_WIDTH - self.STATUS_PADDING_X, ITEM_HEIGHT, ) pixbuf = app_theme.get_pixbuf("button/stop.png").get_pixbuf() draw_pixbuf( cr, pixbuf, rect.x + rect.width - ITEM_CANCEL_BUTTON_PADDING_RIGHT, rect.y + (rect.height - pixbuf.get_height()) / 2, ) elif self.status == self.STATUS_IN_DOWNLOAD: self.progress_buffer.render( cr, gtk.gdk.Rectangle( rect.x, rect.y + (ITEM_HEIGHT - PROGRESSBAR_HEIGHT) / 2, ITEM_STAR_AREA_WIDTH, PROGRESSBAR_HEIGHT)) draw_text( cr, self.status_text, rect.x + rect.width - ITEM_STATUS_TEXT_PADDING_RIGHT, rect.y, rect.width - ITEM_STAR_AREA_WIDTH - self.STATUS_PADDING_X, ITEM_HEIGHT, ) pixbuf = app_theme.get_pixbuf("button/stop.png").get_pixbuf() draw_pixbuf( cr, pixbuf, rect.x + rect.width - ITEM_CANCEL_BUTTON_PADDING_RIGHT, rect.y + (rect.height - pixbuf.get_height()) / 2, ) elif self.status == self.STATUS_STOP_DOWNLOAD: # Draw star. self.star_buffer.render( cr, gtk.gdk.Rectangle(rect.x, rect.y, ITEM_STAR_AREA_WIDTH, ITEM_HEIGHT)) draw_text( cr, self.status_text, rect.x + rect.width - ITEM_STATUS_TEXT_PADDING_RIGHT, rect.y, rect.width - ITEM_STAR_AREA_WIDTH - self.STATUS_PADDING_X, ITEM_HEIGHT, ) elif self.status == self.STATUS_DOWNLOAD_FAILED: # Draw star. draw_text( cr, self.status_text, rect.x, rect.y, get_content_size(self.status_text)[0], ITEM_HEIGHT, text_color="#ff0000", ) if self.button_status == BUTTON_NORMAL: status = "normal" elif self.button_status == BUTTON_HOVER: status = "hover" elif self.button_status == BUTTON_PRESS: status = "press" pixbuf = app_theme.get_pixbuf("button/install_%s.png" % (status, )).get_pixbuf() draw_pixbuf( cr, pixbuf, rect.x + rect.width - ITEM_BUTTON_PADDING_RIGHT - pixbuf.get_width(), rect.y + (rect.height - pixbuf.get_height()) / 2) elif self.status == self.STATUS_WAIT_INSTALL: self.progress_buffer.render( cr, gtk.gdk.Rectangle( rect.x, rect.y + (ITEM_HEIGHT - PROGRESSBAR_HEIGHT) / 2, ITEM_STAR_AREA_WIDTH, PROGRESSBAR_HEIGHT)) draw_text( cr, self.status_text, rect.x + rect.width - ITEM_STATUS_TEXT_PADDING_RIGHT, rect.y, rect.width - ITEM_STAR_AREA_WIDTH - self.STATUS_PADDING_X, ITEM_HEIGHT, ) pixbuf = app_theme.get_pixbuf("button/stop.png").get_pixbuf() draw_pixbuf( cr, pixbuf, rect.x + rect.width - ITEM_CANCEL_BUTTON_PADDING_RIGHT, rect.y + (rect.height - pixbuf.get_height()) / 2, ) elif self.status == self.STATUS_STOP_WAIT_INSTALL: # Draw star. self.star_buffer.render( cr, gtk.gdk.Rectangle(rect.x, rect.y, ITEM_STAR_AREA_WIDTH, ITEM_HEIGHT)) draw_text( cr, self.status_text, rect.x + rect.width - ITEM_STATUS_TEXT_PADDING_RIGHT, rect.y, rect.width - ITEM_STAR_AREA_WIDTH - self.STATUS_PADDING_X, ITEM_HEIGHT, ) elif self.status == self.STATUS_IN_INSTALL: self.progress_buffer.render( cr, gtk.gdk.Rectangle( rect.x, rect.y + (ITEM_HEIGHT - PROGRESSBAR_HEIGHT) / 2, ITEM_STAR_AREA_WIDTH, PROGRESSBAR_HEIGHT)) draw_text( cr, self.status_text, rect.x + rect.width - ITEM_STATUS_TEXT_PADDING_RIGHT, rect.y, rect.width - ITEM_STAR_AREA_WIDTH - self.STATUS_PADDING_X, ITEM_HEIGHT, ) elif self.status == self.STATUS_INSTALL_FINISH: # Draw star. self.star_buffer.render( cr, gtk.gdk.Rectangle(rect.x, rect.y, ITEM_STAR_AREA_WIDTH, ITEM_HEIGHT)) # Draw button. name = "" draw_str = "" if self.install_status == "uninstalled": name = "button/install" elif self.install_status == "unknown": draw_str = _("Installed") else: if self.desktops: name = "button/start" else: draw_str = _("Installed") if name: if self.button_status == BUTTON_NORMAL: status = "normal" elif self.button_status == BUTTON_HOVER: status = "hover" elif self.button_status == BUTTON_PRESS: status = "press" pixbuf = app_theme.get_pixbuf("%s_%s.png" % (name, status)).get_pixbuf() draw_pixbuf( cr, pixbuf, rect.x + rect.width - ITEM_BUTTON_PADDING_RIGHT - pixbuf.get_width(), rect.y + (ITEM_HEIGHT - self.button_height) / 2, ) else: str_width, str_height = get_content_size(draw_str, 10) draw_text( cr, draw_str, rect.x + rect.width - ITEM_BUTTON_PADDING_RIGHT - str_width, rect.y + (rect.height - str_height) / 2, str_width, str_height, alignment=pango.ALIGN_CENTER, ) elif self.status == self.STATUS_PARSE_DOWNLOAD_FAILED: # Draw star. self.star_buffer.render( cr, gtk.gdk.Rectangle(rect.x, rect.y, ITEM_STAR_AREA_WIDTH, ITEM_HEIGHT)) draw_text( cr, self.status_text, rect.x + rect.width - ITEM_STATUS_TEXT_PADDING_RIGHT, rect.y, rect.width - ITEM_STAR_AREA_WIDTH - self.STATUS_PADDING_X, ITEM_HEIGHT, ) def get_height(self): return ITEM_HEIGHT def get_column_widths(self): return [ ITEM_INFO_AREA_WIDTH, ITEM_STAR_AREA_WIDTH + ITEM_BUTTON_AREA_WIDTH ] def get_column_renders(self): return [self.render_pkg_info, self.render_pkg_status] def unselect(self): pass def select(self): pass def unhover(self, column, offset_x, offset_y): pass def hover(self, column, offset_x, offset_y): pass def motion_notify(self, column, offset_x, offset_y): if column == 0: if self.is_in_icon_area(column, offset_x, offset_y): global_event.emit("set-cursor", gtk.gdk.HAND2) elif self.is_in_name_area(column, offset_x, offset_y): global_event.emit("set-cursor", gtk.gdk.HAND2) else: global_event.emit("set-cursor", None) else: if self.status == self.STATUS_INSTALL_FINISH: if self.desktops: if self.is_in_button_area(column, offset_x, offset_y): self.button_status = BUTTON_HOVER if self.redraw_request_callback: self.redraw_request_callback(self) elif self.button_status != BUTTON_NORMAL: self.button_status = BUTTON_NORMAL if self.redraw_request_callback: self.redraw_request_callback(self) if self.is_in_star_area(column, offset_x, offset_y): global_event.emit("set-cursor", gtk.gdk.HAND2) times = offset_x / STAR_SIZE self.grade_star = times * 2 + 2 self.grade_star = min(self.grade_star, 10) self.star_buffer.star_level = self.grade_star if self.redraw_request_callback: self.redraw_request_callback(self) else: global_event.emit("set-cursor", None) if self.star_buffer.star_level != self.star_level: self.star_buffer.star_level = self.star_level if self.redraw_request_callback: self.redraw_request_callback(self) elif self.status == self.STATUS_DOWNLOAD_FAILED: if self.is_in_button_area(column, offset_x, offset_y): self.button_status = BUTTON_HOVER if self.redraw_request_callback: self.redraw_request_callback(self) elif self.button_status != BUTTON_NORMAL: self.button_status = BUTTON_NORMAL if self.redraw_request_callback: self.redraw_request_callback(self) elif self.status == self.STATUS_READY_DOWNLOAD: if self.is_in_star_area(column, offset_x, offset_y): global_event.emit("set-cursor", gtk.gdk.HAND2) times = offset_x / STAR_SIZE self.grade_star = times * 2 + 2 self.grade_star = min(self.grade_star, 10) self.star_buffer.star_level = self.grade_star if self.redraw_request_callback: self.redraw_request_callback(self) else: global_event.emit("set-cursor", None) if self.star_buffer.star_level != self.star_level: self.star_buffer.star_level = self.star_level if self.redraw_request_callback: self.redraw_request_callback(self) def button_press(self, column, offset_x, offset_y): if column == 0: if self.is_in_icon_area(column, offset_x, offset_y): global_event.emit("switch-to-detail-page", self.pkg_name) global_event.emit("set-cursor", None) elif self.is_in_name_area(column, offset_x, offset_y): global_event.emit("switch-to-detail-page", self.pkg_name) global_event.emit("set-cursor", None) else: if self.status == self.STATUS_WAIT_DOWNLOAD: if self.is_stop_button_can_click(column, offset_x, offset_y): self.status = self.STATUS_STOP_DOWNLOAD self.status_text = _("Download was interrupted") if self.redraw_request_callback: self.redraw_request_callback(self) global_event.emit("remove-wait-download", [self.pkg_name]) global_event.emit("request-stop-install-actions", [self.pkg_name]) elif self.is_in_star_area(column, offset_x, offset_y): global_event.emit("grade-pkg", self.pkg_name, self.grade_star) elif self.status == self.STATUS_IN_DOWNLOAD: if self.is_stop_button_can_click(column, offset_x, offset_y): self.status = self.STATUS_STOP_DOWNLOAD self.status_text = _("Download was interrupted") if self.redraw_request_callback: self.redraw_request_callback(self) global_event.emit("stop-download-pkg", [self.pkg_name]) global_event.emit("request-stop-install-actions", [self.pkg_name]) elif self.status == self.STATUS_DOWNLOAD_FAILED: if self.is_in_button_area(column, offset_x, offset_y): global_event.emit("install-pkg", [self.pkg_name]) elif self.status == self.STATUS_WAIT_INSTALL: if self.is_stop_button_can_click(column, offset_x, offset_y): self.status = self.STATUS_STOP_WAIT_INSTALL self.status_text = _("Installation was interrupted") if self.redraw_request_callback: self.redraw_request_callback(self) global_event.emit("remove-wait-action", [(self.pkg_name, ACTION_INSTALL)]) global_event.emit("request-stop-install-actions", [self.pkg_name]) elif self.status == self.STATUS_INSTALL_FINISH: if self.is_in_star_area(column, offset_x, offset_y): global_event.emit("grade-pkg", self.pkg_name, self.grade_star) elif self.is_in_button_area(column, offset_x, offset_y): if self.desktops: global_event.emit( "start-pkg", self.alias_name, self.desktops, self.get_offset_with_button(offset_x, offset_y)) def get_offset_with_button(self, offset_x, offset_y): pixbuf = app_theme.get_pixbuf("button/start_normal.png").get_pixbuf() popup_x = self.get_column_widths( )[1] - ITEM_BUTTON_PADDING_RIGHT - pixbuf.get_width() / 2 popup_y = (ITEM_HEIGHT - pixbuf.get_height()) / 2 return (offset_x, offset_y, popup_x, popup_y) def button_release(self, column, offset_x, offset_y): pass def single_click(self, column, offset_x, offset_y): pass def double_click(self, column, offset_x, offset_y): pass def is_in_star_area(self, column, offset_x, offset_y): return (column == 1 and is_in_rect( (offset_x, offset_y), (0, (ITEM_HEIGHT - STAR_SIZE) / 2, ITEM_STAR_AREA_WIDTH, STAR_SIZE))) def is_in_button_area(self, column, offset_x, offset_y): return (column == 1 and is_in_rect( (offset_x, offset_y), (self.get_column_widths()[column] - ITEM_BUTTON_PADDING_RIGHT - self.button_width, (ITEM_HEIGHT - self.button_height) / 2, self.button_width, self.button_height))) def is_stop_button_can_click(self, column, offset_x, offset_y): pixbuf = app_theme.get_pixbuf("button/stop.png").get_pixbuf() return (column == 1 and is_in_rect( (offset_x, offset_y), (self.get_column_widths()[column] - ITEM_CANCEL_BUTTON_PADDING_RIGHT, (ITEM_HEIGHT - pixbuf.get_height()) / 2, pixbuf.get_width(), pixbuf.get_height()))) def download_ready(self): self.status = self.STATUS_READY_DOWNLOAD self.status_text = _("Dependencies analyzing") if self.redraw_request_callback: self.redraw_request_callback(self) def download_wait(self): self.status = self.STATUS_WAIT_DOWNLOAD self.status_text = _("Waiting for download") if self.redraw_request_callback: self.redraw_request_callback(self) def download_start(self): self.status = self.STATUS_IN_DOWNLOAD self.status_text = _("Downloading") if self.redraw_request_callback: self.redraw_request_callback(self) def download_failed(self): self.status = self.STATUS_DOWNLOAD_FAILED self.status_text = _("Download failed") if self.redraw_request_callback: self.redraw_request_callback(self) def download_update(self, percent, speed): self.status = self.STATUS_IN_DOWNLOAD self.progress_buffer.progress = percent self.status_text = "%s/s" % (format_file_size(speed)) if self.redraw_request_callback: self.redraw_request_callback(self) def download_finish(self): self.status = self.STATUS_WAIT_INSTALL self.progress_buffer.progress = 0 self.status_text = _("Waiting for installation") if self.redraw_request_callback: self.redraw_request_callback(self) def download_stop(self): pass def download_parse_failed(self): self.status = self.STATUS_PARSE_DOWNLOAD_FAILED self.status_text = _("Dependencies analysis failed") if self.redraw_request_callback: self.redraw_request_callback(self) global_event.emit("request-clear-failed-action", self.pkg_name, ACTION_INSTALL) def action_start(self): self.status = self.STATUS_IN_INSTALL self.status_text = _("Installing") if self.redraw_request_callback: self.redraw_request_callback(self) def action_update(self, percent): self.status = self.STATUS_IN_INSTALL self.status_text = _("Installing") self.progress_buffer.progress = percent if self.redraw_request_callback: self.redraw_request_callback(self) def action_finish(self): self.status = self.STATUS_INSTALL_FINISH self.progress_buffer.progress = 100 self.status_text = _("Installation completed") if self.redraw_request_callback: self.redraw_request_callback(self) self.data_manager.get_pkg_installed(self.pkg_name, self.handle_pkg_status) def is_in_name_area(self, column, offset_x, offset_y): (name_width, name_height) = get_content_size(self.alias_name, NAME_SIZE) return (column == 0 and is_in_rect( (offset_x, offset_y), (ITEM_PADDING_X + ITEM_PKG_OFFSET_X + ICON_SIZE + ITEM_PADDING_MIDDLE, ITEM_PADDING_Y, name_width, NAME_SIZE))) def is_in_icon_area(self, column, offset_x, offset_y): return (column == 0 and self.icon_pixbuf != None and is_in_rect( (offset_x, offset_y), (ITEM_PADDING_X + ITEM_PKG_OFFSET_X, ITEM_PADDING_Y, self.icon_pixbuf.get_width(), self.icon_pixbuf.get_height()))) def release_resource(self): ''' Release item resource. If you have pixbuf in item, you should release memory resource like below code: >>> if self.pixbuf: >>> del self.pixbuf >>> self.pixbuf = None >>> >>> return True This is TreeView interface, you should implement it. @return: Return True if do release work, otherwise return False. When this function return True, TreeView will call function gc.collect() to release object to release memory. ''' if self.icon_pixbuf: del self.icon_pixbuf self.icon_pixbuf = None return True
class MediaItem(gobject.GObject): '''List item.''' __gsignals__ = { "redraw-request" : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, ()), } def __init__(self): '''Init list item.''' gobject.GObject.__init__(self) self.update() self.index = None self.path = None def get_path(self): return self.path def get_name(self): return self.name def set_name(self, name): self.name = name self.emit_redraw_request() def set_text(self, text): if text == "Done Transcoding": self.set_status_icon("success") elif text == "show_error": self.set_status_icon("error") elif text == "": pass def set_fraction(self, value): if 0.0 <= value <= 1.0: self.progress_ratio = value self.emit_redraw_request() def set_format(self, _format): self.format = _format self.emit_redraw_request() def set_status_icon(self, name): if name == "wait": self.status_icon = self.wait_icon self.status_icon_press = self.wait_icon_press elif name == "stop": self.status_icon = self.stop_icon self.status_icon_press = self.stop_icon_press elif name == "success": self.status_icon = self.success_icon self.status_icon_press = self.success_icon_press elif name == "working": self.status_icon = self.working_icon self.status_icon_press = self. working_icon_press elif name == "error": self.status_icon = self.error_icon self.status_icon_press = self. error_icon_press self.emit_redraw_request() def set_index(self, index): '''Update index.''' self.index = index def get_index(self): '''Get index.''' return self.index def emit_redraw_request(self): '''Emit redraw-request signal.''' self.emit("redraw-request") def update(self, title="icon_pixbuf", name="Linux deepin", length="progress_buffer", _format="rmvb"): '''Update.''' # Update. self.title = title self.name = name self.length = length self.format = _format # Calculate item size. # self.title_padding_x = 10 # self.title_padding_y = 5 # (self.title_width, self.title_height) = get_content_size(self.title, DEFAULT_FONT_SIZE) #DEFAULT_FONT_SIZE # self.title_width = 20 self.name_padding_x = 10 self.name_padding_y = 5 (self.name_width, self.name_height) = get_content_size(self.name, DEFAULT_FONT_SIZE) #DEFAULT_FONT_SIZE self.name_width = 80 self.length_padding_x = 50 self.length_padding_y = 5 (self.length_width, self.length_height) = get_content_size(self.length, DEFAULT_FONT_SIZE) #DEFAULT_FONT_SIZE self.format_padding_x = 0 self.format_padding_y = 5 (self.format_width, self.format_height) = get_content_size(self.format, 8) #DEFAULT_FONT_SIZE # ProgressBar buffer. self.progress_ratio = 0.0 # self.progress_padding_x = 30 self.progress_padding_x = 25 self.progress_padding_y = 5 self.progress_w, self.progress_h = 100, 10 self.progress_buffer = ProgressBuffer() self.status_icon = None self.status_icon_press = None self.wait_icon = app_theme.get_pixbuf("transcoder/wait.png").get_pixbuf() self.wait_icon_press = app_theme.get_pixbuf("transcoder/wait_press.png").get_pixbuf() # stop conv. self.stop_icon = app_theme.get_pixbuf("transcoder/stop.png").get_pixbuf() self.stop_icon_press = app_theme.get_pixbuf("transcoder/stop_press.png").get_pixbuf() # conv success. self.success_icon = app_theme.get_pixbuf("transcoder/success.png").get_pixbuf() self.success_icon_press = app_theme.get_pixbuf("transcoder/success_press.png").get_pixbuf() # staring conv. self.working_icon = app_theme.get_pixbuf("transcoder/working.png").get_pixbuf() self.working_icon_press = app_theme.get_pixbuf("transcoder/working_press.png").get_pixbuf() # error . self.error_icon = app_theme.get_pixbuf("transcoder/error.png").get_pixbuf() self.error_icon_press = app_theme.get_pixbuf("transcoder/error_press.png").get_pixbuf() # Init icon state. self.set_status_icon("wait") # set icon[position]->> x and y. self.status_icon_padding_x = 5 self.status_icon_padding_y = 5 # get icon width and height . self.status_icon_w, self.status_icon_h = (self.status_icon.get_width(), self.status_icon.get_height()) def render_title(self, cr, rect, in_selection, in_highlight): '''Render title.''' rect.x += self.status_icon_padding_x # title_padding_x icon_x = rect.x + self.status_icon_padding_x # self.status_icon_padding_x icon_y = rect.y + (rect.height - self.status_icon_h) / 2 if in_selection: draw_pixbuf(cr, self.status_icon_press, icon_x, icon_y) else: draw_pixbuf(cr, self.status_icon, icon_x, icon_y) def render_name(self, cr, rect, in_selection, in_highlight): rect.x += self.name_padding_x render_item_text(cr, self.name, rect, in_selection, in_highlight) def render_length(self, cr, rect, in_selection, in_highlight): '''Render length.''' rect.width -= self.length_padding_x self.progress_buffer.progress = self.progress_ratio * 100 progress_x = rect.x + self.progress_padding_x progress_y = rect.y + (rect.height - self.progress_h) / 2 progress_rect = gtk.gdk.Rectangle(progress_x, progress_y, self.progress_w, self.progress_h) self.progress_buffer.render(cr, progress_rect) def render_format(self, cr, rect, in_selection, in_highlight): rect.x += self.format_padding_x render_item_text(cr, self.format, rect, in_selection, in_highlight) def get_column_sizes(self): '''Get sizes.''' return [(self.status_icon_w + self.status_icon_padding_x * 2, self.status_icon_h + self.status_icon_padding_y * 2), (self.name_width + self.name_padding_x * 2 + 30, self.name_height + self.name_padding_y * 2), (self.length_width + self.length_padding_x + 12, self.length_height + self.length_padding_y * 2), # (self.format_width + self.format_padding_x * 2, (self.format_width + 20, self.format_height + self.format_padding_y * 2), ] def get_renders(self): '''Get render callbacks.''' return [self.render_title, self.render_name, self.render_length, self.render_format]
class TaskItem(TreeItem): ''' class docs ''' STATUS_WAIT_DOWNLOAD = 2 STATUS_IN_DOWNLOAD = 3 STATUS_STOP = 4 STATUS_FINISH = 5 def __init__(self, image_object, finish_callback): ''' init docs ''' TreeItem.__init__(self) # Init sizes. self.item_height = 50 self.info_width = -1 self.progressbar_width = 100 self.progressbar_padding_x = 10 self.progressbar_height = 12 self.check_button_padding_x = 10 self.info_padding_x = 5 self.icon_pixbuf = None self.image_object = image_object self.button_status = BUTTON_NORMAL # Init status. self.status = self.STATUS_WAIT_DOWNLOAD self.status_text = "等待下载" # Init buffers. self.progress_buffer = ProgressBuffer() self.stop_pixbuf = app_theme.get_pixbuf( "individuation/stop.png").get_pixbuf() self.stop_pixbuf_padding_x = 5 self.block_width = 50 self.download_task = TaskObject(image_object.big_url, image_object.get_save_path(), output_temp=True) self.download_task.connect("update", self.download_update) self.download_task.connect("finish", self.download_finish) self.download_task.connect("error", self.download_failed) self.download_task.connect("start", self.download_start) self.finish_callback = finish_callback self.start_download() def start_download(self): fetch_service.add_missions([self.download_task]) def render_info(self, cr, rect): if self.is_hover: draw_single_mask(cr, rect.x, rect.y, rect.width, rect.height, "globalItemHover") if self.icon_pixbuf is None: self.icon_pixbuf = cache_manager.get_small_pixbuf( self.image_object, 37, 38) icon_width = self.icon_pixbuf.get_width() icon_height = self.icon_pixbuf.get_height() icon_x = rect.x + self.info_padding_x icon_y = rect.y + (rect.height - icon_height) / 2 # Draw shadow. drop_shadow_padding = 3 drop_shadow_radious = 3 draw_shadow(cr, icon_x, icon_y, icon_width + drop_shadow_padding, icon_height + drop_shadow_padding, drop_shadow_radious, app_theme.get_shadow_color("window_shadow")) outside_shadow_padding = 2 outside_shadow_radious = 3 draw_shadow(cr, icon_x - outside_shadow_padding, icon_y - outside_shadow_padding, icon_width + outside_shadow_padding * 2, icon_height + outside_shadow_padding * 2, outside_shadow_radious, app_theme.get_shadow_color("window_shadow")) # Draw wallpaper. draw_pixbuf(cr, self.icon_pixbuf, icon_x, icon_y) rect.x = icon_x + self.icon_pixbuf.get_width() + self.info_padding_x rect.width -= self.info_padding_x * 2 - self.icon_pixbuf.get_width() _width, _height = get_content_size( self.image_object.get_display_name()) draw_text(cr, "<b>%s</b>" % self.image_object.get_display_name(), rect.x, icon_y, rect.width, _height, text_size=10) rect.y = icon_y + icon_width - _height _width, _height = get_content_size(self.status_text) draw_text(cr, self.status_text, rect.x, rect.y, rect.width, _height) def render_progressbar(self, cr, rect): if self.is_hover: draw_single_mask(cr, rect.x, rect.y, rect.width, rect.height, "globalItemHover") self.progress_buffer.render( cr, gtk.gdk.Rectangle( rect.x + (rect.width - self.progressbar_width) / 2, rect.y + (rect.height - self.progressbar_height) / 2, self.progressbar_width, self.progressbar_height)) def render_stop(self, cr, rect): if self.is_hover: draw_single_mask(cr, rect.x, rect.y, rect.width, rect.height, "globalItemHover") icon_x = rect.x + (rect.width - self.stop_pixbuf.get_width()) / 2 icon_y = rect.y + (rect.height - self.stop_pixbuf.get_height()) / 2 draw_pixbuf(cr, self.stop_pixbuf, icon_x, icon_y) def render_block(self, cr, rect): if self.is_hover: draw_single_mask(cr, rect.x, rect.y, rect.width, rect.height, "globalItemHover") def get_column_widths(self): return [ 10, self.info_width, self.progressbar_width + self.progressbar_padding_x * 2, self.stop_pixbuf.get_width() + self.stop_pixbuf_padding_x * 2, self.block_width ] def get_column_renders(self): return [ self.render_block, self.render_info, self.render_progressbar, self.render_stop, self.render_block, ] def get_height(self): return self.item_height def emit_request_redraw(self): if self.redraw_request_callback: self.redraw_request_callback(self) def unselect(self): pass def select(self): pass def unhover(self, column, offset_x, offset_y): self.is_hover = False self.emit_request_redraw() def hover(self, column, offset_x, offset_y): self.is_hover = True self.emit_request_redraw() def motion_notify(self, column, offset_x, offset_y): if column == 0: if self.check_button_buffer.motion_button(offset_x, offset_y): self.emit_request_redraw() def button_press(self, column, offset_x, offset_y): if column == 0: if self.check_button_buffer.press_button(offset_x, offset_y): self.emit_request_redraw() def button_release(self, column, offset_x, offset_y): if column == 0 and self.check_button_buffer.release_button( offset_x, offset_y): self.emit_request_redraw() def single_click(self, column, offset_x, offset_y): pass def double_click(self, column, offset_x, offset_y): pass @post_gui def download_update(self, obj, data): self.progress_buffer.progress = data.progress speed = parse_bytes(data.speed) remaining = parse_time(data.remaining) filesize = parse_bytes(data.filesize) downloaded = parse_bytes(data.downloaded) self.status_text = "%s/s - %s, 共%s, 还有 %s " % (speed, downloaded, filesize, remaining) self.emit_request_redraw() @post_gui def download_finish(self, obj, data): event_manager.emit("download-finish", obj) self.progress_buffer.progress = 100 self.status_text = "下载完成" self.emit_request_redraw() if self.finish_callback: self.finish_callback(self) @post_gui def download_failed(self, obj, data): self.status_text = data self.emit_request_redraw() @post_gui def download_start(self, obj, data): event_manager.emit("download-start", obj) self.status_text = "开始下载" self.emit_request_redraw() def download_stop(self): pass def release_resource(self): ''' Release item resource. If you have pixbuf in item, you should release memory resource like below code: >>> if self.pixbuf: >>> del self.pixbuf >>> self.pixbuf = None >>> >>> return True This is TreeView interface, you should implement it. @return: Return True if do release work, otherwise return False. When this function return True, TreeView will call function gc.collect() to release object to release memory. ''' if self.icon_pixbuf: del self.icon_pixbuf self.icon_pixbuf = None return True
class TaskItem(TreeItem): ''' class docs ''' STATUS_WAIT_DOWNLOAD = 2 STATUS_IN_DOWNLOAD = 3 STATUS_STOP = 4 STATUS_FINISH = 5 def __init__(self, image_object, finish_callback): ''' init docs ''' TreeItem.__init__(self) # Init sizes. self.item_height = 50 self.info_width = -1 self.progressbar_width = 100 self.progressbar_padding_x = 10 self.progressbar_height = 12 self.check_button_padding_x = 10 self.info_padding_x = 5 self.icon_pixbuf = None self.image_object = image_object self.button_status = BUTTON_NORMAL # Init status. self.status = self.STATUS_WAIT_DOWNLOAD self.status_text = "等待下载" # Init buffers. self.progress_buffer = ProgressBuffer() self.stop_pixbuf = app_theme.get_pixbuf("individuation/stop.png").get_pixbuf() self.stop_pixbuf_padding_x = 5 self.block_width = 50 self.download_task = TaskObject(image_object.big_url, image_object.get_save_path(), output_temp=True) self.download_task.connect("update", self.download_update) self.download_task.connect("finish", self.download_finish) self.download_task.connect("error", self.download_failed) self.download_task.connect("start", self.download_start) self.finish_callback = finish_callback self.start_download() def start_download(self): fetch_service.add_missions([self.download_task]) def render_info(self, cr, rect): if self.is_hover: draw_single_mask(cr, rect.x, rect.y, rect.width, rect.height, "globalItemHover") if self.icon_pixbuf is None: self.icon_pixbuf = cache_manager.get_small_pixbuf(self.image_object, 37, 38) icon_width = self.icon_pixbuf.get_width() icon_height = self.icon_pixbuf.get_height() icon_x = rect.x + self.info_padding_x icon_y = rect.y + (rect.height - icon_height) / 2 # Draw shadow. drop_shadow_padding = 3 drop_shadow_radious = 3 draw_shadow( cr, icon_x, icon_y, icon_width + drop_shadow_padding, icon_height + drop_shadow_padding, drop_shadow_radious, app_theme.get_shadow_color("window_shadow") ) outside_shadow_padding = 2 outside_shadow_radious = 3 draw_shadow( cr, icon_x - outside_shadow_padding, icon_y - outside_shadow_padding, icon_width + outside_shadow_padding * 2, icon_height + outside_shadow_padding * 2, outside_shadow_radious, app_theme.get_shadow_color("window_shadow") ) # Draw wallpaper. draw_pixbuf(cr, self.icon_pixbuf, icon_x, icon_y) rect.x = icon_x + self.icon_pixbuf.get_width() + self.info_padding_x rect.width -= self.info_padding_x * 2 - self.icon_pixbuf.get_width() _width, _height = get_content_size(self.image_object.get_display_name()) draw_text(cr, "<b>%s</b>" % self.image_object.get_display_name(), rect.x, icon_y, rect.width, _height, text_size=10) rect.y = icon_y + icon_width - _height _width, _height = get_content_size(self.status_text) draw_text(cr, self.status_text, rect.x, rect.y, rect.width, _height) def render_progressbar(self, cr, rect): if self.is_hover: draw_single_mask(cr, rect.x, rect.y, rect.width, rect.height, "globalItemHover") self.progress_buffer.render(cr, gtk.gdk.Rectangle(rect.x + (rect.width - self.progressbar_width) / 2, rect.y + (rect.height - self.progressbar_height)/ 2, self.progressbar_width, self.progressbar_height)) def render_stop(self, cr, rect): if self.is_hover: draw_single_mask(cr, rect.x, rect.y, rect.width, rect.height, "globalItemHover") icon_x = rect.x + (rect.width - self.stop_pixbuf.get_width()) / 2 icon_y = rect.y + (rect.height - self.stop_pixbuf.get_height()) / 2 draw_pixbuf(cr, self.stop_pixbuf, icon_x, icon_y) def render_block(self, cr, rect): if self.is_hover: draw_single_mask(cr, rect.x, rect.y, rect.width, rect.height, "globalItemHover") def get_column_widths(self): return [ 10, self.info_width, self.progressbar_width + self.progressbar_padding_x * 2, self.stop_pixbuf.get_width() + self.stop_pixbuf_padding_x * 2, self.block_width ] def get_column_renders(self): return [ self.render_block, self.render_info, self.render_progressbar, self.render_stop, self.render_block, ] def get_height(self): return self.item_height def emit_request_redraw(self): if self.redraw_request_callback: self.redraw_request_callback(self) def unselect(self): pass def select(self): pass def unhover(self, column, offset_x, offset_y): self.is_hover = False self.emit_request_redraw() def hover(self, column, offset_x, offset_y): self.is_hover = True self.emit_request_redraw() def motion_notify(self, column, offset_x, offset_y): if column == 0: if self.check_button_buffer.motion_button(offset_x, offset_y): self.emit_request_redraw() def button_press(self, column, offset_x, offset_y): if column == 0: if self.check_button_buffer.press_button(offset_x, offset_y): self.emit_request_redraw() def button_release(self, column, offset_x, offset_y): if column == 0 and self.check_button_buffer.release_button(offset_x, offset_y): self.emit_request_redraw() def single_click(self, column, offset_x, offset_y): pass def double_click(self, column, offset_x, offset_y): pass @post_gui def download_update(self, obj, data): self.progress_buffer.progress = data.progress speed = parse_bytes(data.speed) remaining = parse_time(data.remaining) filesize = parse_bytes(data.filesize) downloaded = parse_bytes(data.downloaded) self.status_text = "%s/s - %s, 共%s, 还有 %s " % (speed, downloaded, filesize, remaining) self.emit_request_redraw() @post_gui def download_finish(self, obj, data): event_manager.emit("download-finish", obj) self.progress_buffer.progress = 100 self.status_text = "下载完成" self.emit_request_redraw() if self.finish_callback: self.finish_callback(self) @post_gui def download_failed(self, obj, data): self.status_text = data self.emit_request_redraw() @post_gui def download_start(self, obj, data): event_manager.emit("download-start", obj) self.status_text = "开始下载" self.emit_request_redraw() def download_stop(self): pass def release_resource(self): ''' Release item resource. If you have pixbuf in item, you should release memory resource like below code: >>> if self.pixbuf: >>> del self.pixbuf >>> self.pixbuf = None >>> >>> return True This is TreeView interface, you should implement it. @return: Return True if do release work, otherwise return False. When this function return True, TreeView will call function gc.collect() to release object to release memory. ''' if self.icon_pixbuf: del self.icon_pixbuf self.icon_pixbuf = None return True
class TranscoderJob(gobject.GObject): __gsignals__ = { "end" : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, ()), "redraw-request" : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, ()), } __stop = False __pause = False __is_alive = True priority = 10 def __init__(self, trans_data): gobject.GObject.__init__(self) self.__updater_id = None # Init data. self.angle = 0 self.status_icon = app_theme.get_pixbuf("transcoder/wait.png").get_pixbuf() self.status_icon_press = app_theme.get_pixbuf("transcoder/wait_press.png").get_pixbuf() self.stop_icon = app_theme.get_pixbuf("transcoder/stop.png").get_pixbuf() self.progress_ratio = 0.0 self.skip_flag = False self.trans_data = trans_data self.init_transcoder(trans_data) self.__update() self.progress_buffer = ProgressBuffer() def start(self): if self.skip_flag: self.finish_job() else: self.transcoder.start_transcode() self.__set_status_icon("working") self.__updater_id = gobject.timeout_add(500, self.update_progress) def update_progress(self): self.set_progress_ratio(self.transcoder.get_ratio()) return True def __update(self): self.title = self.trans_data["song"].get_str("title") self.status_icon_padding_x = 10 self.status_icon_padding_y = 5 self.status_icon_w, self.status_icon_h = (self.status_icon.get_width(), self.status_icon.get_height()) self.title_padding_x = 5 self.title_padding_y = 5 self.title_w, self.title_h = get_content_size(self.title, DEFAULT_FONT_SIZE) self.progress_padding_x = 10 self.progress_padding_y = 5 self.progress_w, self.progress_h = 100, 10 self.stop_icon_padding_x = 5 self.stop_icon_padding_y = 5 self.stop_icon_w, self.stop_icon_h = (self.stop_icon.get_width(), self.stop_icon.get_height()) self.ext_padding_x = 5 self.ext_padding_y = 5 self.ext_w, self.ext_h = get_content_size(self.output_ext, DEFAULT_FONT_SIZE) def init_transcoder(self, attr): self.raw_song = attr["song"] self.output_path = attr["output"] if os.path.exists(self.output_path) and attr["prompt"]: self.exists_prompt = True else: self.exists_prompt = False if self.raw_song.get_path() == self.output_path: self.skip_flag = True self.output_ext = FORMATS[attr["format"]]["extension"] self.transcoder = Transcoder() self.transcoder.set_format(attr["format"]) self.transcoder.set_quality(attr["quality"]) if self.raw_song.get_type() == "audiocd": self.transcoder.set_cd_input(self.raw_song.get("uri")) else: self.transcoder.set_input(attr["song"].get_path()) self.transcoder.set_output(self.output_path) self.transcoder.end_cb = self.__end def __end(self): try: self.write_tags() except: pass self.finish_job() def finish_job(self): self.emit("end") self.__set_status_icon("success") self.set_progress_ratio(1.0) try: gobject.source_remove(self.__updater_id) except: pass if self.trans_data["to_playlist"]: tags = {"uri" : utils.get_uri_from_path(self.output_path)} song = MediaDB.get_or_create_song(tags, "local", read_from_file=True) if song: Dispatcher.add_songs([song]) def write_tags(self): tags = deepcopy(self.raw_song) tags["uri"] = utils.get_uri_from_path(self.output_path) s = Song() s.init_from_dict(tags) s.write_to_file() @property def is_running(self): return self.transcoder.running @property def is_finish(self): return self.transcoder.is_eos def force_stop(self): try: gobject.source_remove(self.__updater_id) except: pass if self.transcoder.running: self.transcoder.pause() try: os.unlink(self.output_path) except: pass def playpause(self): if self.transcoder.running: if self.transcoder.is_pause: self.transcoder.playing() self.__updater_id = gobject.timeout_add(500, self.update_progress) return True else: try: gobject.source_remove(self.__updater_id) except: pass self.transcoder.pause() return True return False def set_progress_ratio(self, value): self.progress_ratio = value self.emit_redraw_request() def set_index(self, index): '''Update index.''' self.index = index def get_index(self): '''Get index.''' return self.index def __set_status_icon(self, name): self.status_icon = app_theme.get_pixbuf("transcoder/%s.png" % name).get_pixbuf() self.status_icon_press = app_theme.get_pixbuf("transcoder/%s_press.png" % name).get_pixbuf() self.emit_redraw_request() def set_error_status(self): self.__set_status_icon("error") def emit_redraw_request(self): '''Emit redraw-request signal.''' self.emit("redraw-request") def render_icon(self, cr, rect, in_select, in_highlight): icon_x = rect.x + self.status_icon_padding_x icon_y = rect.y + (rect.height - self.status_icon_h) / 2 if in_select: draw_pixbuf(cr, self.status_icon_press, icon_x, icon_y) else: draw_pixbuf(cr, self.status_icon, icon_x, icon_y) def render_title(self, cr, rect, in_select, in_highlight): rect.x += self.title_padding_x rect.width -= self.title_padding_x * 2 render_item_text2(cr, self.title, rect, in_select, in_highlight) def render_progress(self, cr, rect, in_select, in_highlight): self.progress_buffer.progress = self.progress_ratio * 100 progress_x = rect.x + self.progress_padding_x progress_y = rect.y + (rect.height - self.progress_h) / 2 progress_rect = gtk.gdk.Rectangle(progress_x, progress_y, self.progress_w, self.progress_h) self.progress_buffer.render(cr, progress_rect) def render_stop(self, cr, rect, in_select, in_highlight): icon_x = rect.x + self.stop_icon_padding_x icon_y = rect.y + (rect.height - self.stop_icon_h) / 2 draw_pixbuf(cr, self.stop_icon, icon_x, icon_y) def render_ext(self, cr, rect, in_select, in_highlight): rect.x += self.ext_padding_x rect.width -= self.ext_padding_x * 2 render_item_text2(cr, self.output_ext.upper(), rect, in_select, in_highlight) def get_ext_type(self): gio_file = gio.File(self.output_path) gio_file_info = gio_file.query_info(",".join([gio.FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE, gio.FILE_ATTRIBUTE_STANDARD_TYPE, gio.FILE_ATTRIBUTE_STANDARD_NAME, gio.FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME, gio.FILE_ATTRIBUTE_STANDARD_SIZE, gio.FILE_ATTRIBUTE_STANDARD_ICON, gio.FILE_ATTRIBUTE_TIME_MODIFIED, gio.FILE_ATTRIBUTE_TIME_CHANGED,])) info_attr = gio_file_info.get_attribute_as_string(gio.FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE) return gio.content_type_get_description(info_attr) def get_column_sizes(self): return [ (36, self.status_icon_h + self.status_icon_padding_y * 2), (135, self.title_h + self.title_padding_y * 2), (120, self.progress_h + self.progress_padding_y * 2), # (26, self.stop_icon_h + self.stop_icon_padding_y * 2), (50, self.ext_h + self.ext_padding_y), ] def get_renders(self): return [ self.render_icon, self.render_title, self.render_progress, self.render_ext]
class UninstallItem(TreeItem): ''' class docs ''' STATUS_NORMAL = 1 STATUS_CONFIRM = 2 STATUS_WAIT_ACTION = 3 STATUS_IN_ACTION = 4 STATUS_PADDING_X = 15 def __init__(self, pkg_name, pkg_version, data_manager): ''' init docs ''' TreeItem.__init__(self) self.pkg_name = pkg_name self.pkg_version = pkg_version self.data_manager = data_manager self.icon_pixbuf = None info = data_manager.get_item_pkg_info(self.pkg_name) self.alias_name = info[1] self.short_desc = info[2] self.star_level = get_star_level(5.0) self.star_buffer = DscStarBuffer(pkg_name) self.grade_star = 0 button_pixbuf = app_theme.get_pixbuf( "button/uninstall_normal.png").get_pixbuf() (self.button_width, self.button_height ) = button_pixbuf.get_width(), button_pixbuf.get_height() self.button_status = BUTTON_NORMAL self.status = self.STATUS_NORMAL self.status_text = "" self.progress_buffer = ProgressBuffer() #self.action_wait() def render_pkg_info(self, cr, rect): if self.row_index % 2 == 1: cr.set_source_rgba(1, 1, 1, 0.5) cr.rectangle(rect.x, rect.y, rect.width, rect.height) cr.fill() if self.icon_pixbuf == None: self.icon_pixbuf = gtk.gdk.pixbuf_new_from_file( get_icon_pixbuf_path(self.pkg_name)) render_pkg_info(cr, rect, self.alias_name, self.pkg_name, self.icon_pixbuf, self.pkg_version, self.short_desc, ITEM_PKG_OFFSET_X) def render_pkg_status(self, cr, rect): if self.row_index % 2 == 1: cr.set_source_rgba(1, 1, 1, 0.5) cr.rectangle(rect.x, rect.y, rect.width, rect.height) cr.fill() if self.status == self.STATUS_CONFIRM: # Draw star. self.star_buffer.render( cr, gtk.gdk.Rectangle(rect.x, rect.y, ITEM_STAR_AREA_WIDTH, ITEM_HEIGHT)) confirm_pixbuf = app_theme.get_pixbuf( "button/uninstall_confirm.png").get_pixbuf() cancel_pixbuf = app_theme.get_pixbuf( "button/uninstall_cancel.png").get_pixbuf() draw_pixbuf( cr, confirm_pixbuf, rect.x + rect.width - ITEM_CONFIRM_BUTTON_PADDING_RIGHT, rect.y + (ITEM_HEIGHT - confirm_pixbuf.get_height()) / 2, ) draw_pixbuf( cr, cancel_pixbuf, rect.x + rect.width - ITEM_CANCEL_BUTTON_PADDING_RIGHT, rect.y + (ITEM_HEIGHT - cancel_pixbuf.get_height()) / 2, ) elif self.status == self.STATUS_IN_ACTION: self.progress_buffer.render( cr, gtk.gdk.Rectangle( rect.x, rect.y + (ITEM_HEIGHT - PROGRESSBAR_HEIGHT) / 2, ITEM_STAR_AREA_WIDTH, PROGRESSBAR_HEIGHT)) draw_text( cr, self.status_text, rect.x + rect.width - ITEM_STATUS_TEXT_PADDING_RIGHT, rect.y, rect.width - ITEM_STAR_AREA_WIDTH, ITEM_HEIGHT, ) elif self.status == self.STATUS_WAIT_ACTION: # Draw star. self.star_buffer.render( cr, gtk.gdk.Rectangle(rect.x, rect.y, ITEM_STAR_AREA_WIDTH, ITEM_HEIGHT)) draw_text( cr, self.status_text, rect.x + rect.width - ITEM_STATUS_TEXT_PADDING_RIGHT, rect.y, rect.width - ITEM_STAR_AREA_WIDTH, ITEM_HEIGHT, ) cancel_pixbuf = app_theme.get_pixbuf( "button/uninstall_cancel.png").get_pixbuf() draw_pixbuf( cr, cancel_pixbuf, rect.x + rect.width - 50, rect.y + (ITEM_HEIGHT - cancel_pixbuf.get_height()) / 2, ) elif self.status == self.STATUS_NORMAL: # Draw star. self.star_buffer.render( cr, gtk.gdk.Rectangle(rect.x, rect.y, ITEM_STAR_AREA_WIDTH, ITEM_HEIGHT)) # Draw button. if self.button_status == BUTTON_NORMAL: pixbuf = app_theme.get_pixbuf( "button/uninstall_normal.png").get_pixbuf() elif self.button_status == BUTTON_HOVER: pixbuf = app_theme.get_pixbuf( "button/uninstall_hover.png").get_pixbuf() elif self.button_status == BUTTON_PRESS: pixbuf = app_theme.get_pixbuf( "button/uninstall_press.png").get_pixbuf() draw_pixbuf( cr, pixbuf, rect.x + rect.width - ITEM_BUTTON_PADDING_RIGHT - pixbuf.get_width(), rect.y + (ITEM_HEIGHT - self.button_height) / 2, ) def get_height(self): return ITEM_HEIGHT def get_column_widths(self): return [ ITEM_INFO_AREA_WIDTH, ITEM_STAR_AREA_WIDTH + ITEM_BUTTON_AREA_WIDTH ] def get_column_renders(self): return [self.render_pkg_info, self.render_pkg_status] def unselect(self): pass def select(self): pass def unhover(self, column, offset_x, offset_y): pass def hover(self, column, offset_x, offset_y): pass def motion_notify(self, column, offset_x, offset_y): if column == 0: if self.is_in_icon_area(column, offset_x, offset_y): global_event.emit("set-cursor", gtk.gdk.HAND2) elif self.is_in_name_area(column, offset_x, offset_y): global_event.emit("set-cursor", gtk.gdk.HAND2) else: global_event.emit("set-cursor", None) else: if self.status == self.STATUS_NORMAL: if self.is_in_button_area(column, offset_x, offset_y): self.button_status = BUTTON_HOVER if self.redraw_request_callback: self.redraw_request_callback(self) elif self.button_status != BUTTON_NORMAL: self.button_status = BUTTON_NORMAL if self.redraw_request_callback: self.redraw_request_callback(self) if self.is_in_star_area(column, offset_x, offset_y): global_event.emit("set-cursor", gtk.gdk.HAND2) times = offset_x / STAR_SIZE self.grade_star = times * 2 + 2 self.grade_star = min(self.grade_star, 10) self.star_buffer.star_level = self.grade_star if self.redraw_request_callback: self.redraw_request_callback(self) else: global_event.emit("set-cursor", None) if self.star_buffer.star_level != self.star_level: self.star_buffer.star_level = self.star_level if self.redraw_request_callback: self.redraw_request_callback(self) def button_press(self, column, offset_x, offset_y): if column == 0: if self.is_in_icon_area(column, offset_x, offset_y): global_event.emit("switch-to-detail-page", self.pkg_name) global_event.emit("set-cursor", None) elif self.is_in_name_area(column, offset_x, offset_y): global_event.emit("switch-to-detail-page", self.pkg_name) global_event.emit("set-cursor", None) else: if self.status == self.STATUS_NORMAL: if self.is_in_button_area(column, offset_x, offset_y): self.status = self.STATUS_CONFIRM if self.redraw_request_callback: self.redraw_request_callback(self) elif self.is_in_star_area(column, offset_x, offset_y): global_event.emit("grade-pkg", self.pkg_name, self.grade_star) elif self.status == self.STATUS_CONFIRM: if self.is_confirm_button_area(column, offset_x, offset_y): self.status = self.STATUS_WAIT_ACTION self.status_text = _("Waiting for uninstall") if self.redraw_request_callback: self.redraw_request_callback(self) global_event.emit("uninstall-pkg", self.pkg_name, get_purg_flag()) elif self.is_cancel_button_area(column, offset_x, offset_y): self.status = self.STATUS_NORMAL if self.redraw_request_callback: self.redraw_request_callback(self) elif self.status == self.STATUS_WAIT_ACTION: if self.is_cancel_button_area(column, offset_x, offset_y): self.status = self.STATUS_NORMAL global_event.emit("remove-wait-action", [(self.pkg_name, ACTION_UNINSTALL)]) if self.redraw_request_callback: self.redraw_request_callback(self) def button_release(self, column, offset_x, offset_y): pass def single_click(self, column, offset_x, offset_y): pass def double_click(self, column, offset_x, offset_y): pass def is_in_star_area(self, column, offset_x, offset_y): return (column == 1 and is_in_rect( (offset_x, offset_y), (0, (ITEM_HEIGHT - STAR_SIZE) / 2, ITEM_STAR_AREA_WIDTH, STAR_SIZE))) def is_in_button_area(self, column, offset_x, offset_y): return (column == 1 and is_in_rect( (offset_x, offset_y), (self.get_column_widths()[column] - ITEM_BUTTON_PADDING_RIGHT - self.button_width, (ITEM_HEIGHT - self.button_height) / 2, self.button_width, self.button_height))) def is_confirm_button_area(self, column, offset_x, offset_y): confirm_pixbuf = app_theme.get_pixbuf( "button/uninstall_confirm.png").get_pixbuf() return (column == 1 and is_in_rect( (offset_x, offset_y), (self.get_column_widths()[column] - ITEM_CONFIRM_BUTTON_PADDING_RIGHT, (ITEM_HEIGHT - confirm_pixbuf.get_height()) / 2, confirm_pixbuf.get_width(), confirm_pixbuf.get_height()))) def is_cancel_button_area(self, column, offset_x, offset_y): cancel_pixbuf = app_theme.get_pixbuf( "button/uninstall_cancel.png").get_pixbuf() return (column == 1 and is_in_rect( (offset_x, offset_y), (self.get_column_widths()[column] - ITEM_CANCEL_BUTTON_PADDING_RIGHT, (ITEM_HEIGHT - cancel_pixbuf.get_height()) / 2, cancel_pixbuf.get_width(), cancel_pixbuf.get_height()))) def is_in_name_area(self, column, offset_x, offset_y): (name_width, name_height) = get_content_size(self.alias_name, NAME_SIZE) return (column == 0 and is_in_rect( (offset_x, offset_y), (ITEM_PADDING_X + ITEM_PKG_OFFSET_X + ICON_SIZE + ITEM_PADDING_MIDDLE, ITEM_PADDING_Y, name_width, NAME_SIZE))) def is_in_icon_area(self, column, offset_x, offset_y): return (column == 0 and self.icon_pixbuf != None and is_in_rect( (offset_x, offset_y), (ITEM_PADDING_X + ITEM_PKG_OFFSET_X, ITEM_PADDING_Y, self.icon_pixbuf.get_width(), self.icon_pixbuf.get_height()))) def action_wait(self): self.status = self.STATUS_WAIT_ACTION self.status_text = _("Waiting for uninstall") if self.redraw_request_callback: self.redraw_request_callback(self) def action_start(self): self.status = self.STATUS_IN_ACTION self.status_text = _("Uninstalling") if self.redraw_request_callback: self.redraw_request_callback(self) def action_update(self, percent): self.progress_buffer.progress = percent self.status_text = _("Uninstalling") if self.redraw_request_callback: self.redraw_request_callback(self) def action_finish(self): self.progress_buffer.progress = 100 self.status_text = _("Uninstallation completed") if self.redraw_request_callback: self.redraw_request_callback(self) def release_resource(self): ''' Release item resource. If you have pixbuf in item, you should release memory resource like below code: >>> if self.pixbuf: >>> del self.pixbuf >>> self.pixbuf = None >>> >>> return True This is TreeView interface, you should implement it. @return: Return True if do release work, otherwise return False. When this function return True, TreeView will call function gc.collect() to release object to release memory. ''' if self.icon_pixbuf: del self.icon_pixbuf self.icon_pixbuf = None return True