def show_context_menu(self, point): item = self.itemAt(point) if item is None or item in set(self.categories.itervalues()): return m = QMenu(self) sel = self.selectedItems() num = len(sel) if num > 0: m.addAction(QIcon(I('trash.png')), _('&Delete selected files'), self.request_delete) ci = self.currentItem() if ci is not None: cn = unicode(ci.data(0, NAME_ROLE).toString()) mt = unicode(ci.data(0, MIME_ROLE).toString()) cat = unicode(ci.data(0, CATEGORY_ROLE).toString()) m.addAction(QIcon(I('modified.png')), _('&Rename %s') % (elided_text(self.font(), cn)), self.edit_current_item) if is_raster_image(mt): m.addAction(QIcon(I('default_cover.png')), _('Mark %s as cover image') % elided_text(self.font(), cn), partial(self.mark_as_cover, cn)) elif current_container().SUPPORTS_TITLEPAGES and mt in OEB_DOCS and cat == 'text': m.addAction(QIcon(I('default_cover.png')), _('Mark %s as title/cover page') % elided_text(self.font(), cn), partial(self.mark_as_titlepage, cn)) selected_map = defaultdict(list) for item in sel: selected_map[unicode(item.data(0, CATEGORY_ROLE).toString())].append(unicode(item.data(0, NAME_ROLE).toString())) for items in selected_map.itervalues(): items.sort(key=self.index_of_name) if len(selected_map['text']) > 1: m.addAction(QIcon(I('merge.png')), _('&Merge selected text files'), partial(self.start_merge, 'text', selected_map['text'])) if len(selected_map['styles']) > 1: m.addAction(QIcon(I('merge.png')), _('&Merge selected style files'), partial(self.start_merge, 'styles', selected_map['styles'])) if len(list(m.actions())) > 0: m.popup(self.mapToGlobal(point))
def replace(self, name): c = current_container() mt = c.mime_map[name] oext = name.rpartition(".")[-1].lower() filters = [oext] fname = _("Files") if mt in OEB_DOCS: fname = _("HTML Files") filters = "html htm xhtm xhtml shtml".split() elif is_raster_image(mt): fname = _("Images") filters = "jpeg jpg gif png".split() path = choose_files( self, "tweak_book_import_file", _("Choose file"), filters=[(fname, filters)], select_only_single_file=True ) if not path: return path = path[0] ext = path.rpartition(".")[-1].lower() force_mt = None if mt in OEB_DOCS: force_mt = c.guess_type("a.html") nname = os.path.basename(path) nname, ext = nname.rpartition(".")[0::2] nname = nname + "." + ext.lower() self.replace_requested.emit(name, path, nname, force_mt)
def run_checks(container): errors = [] # Check parsing xml_items, html_items, raster_images, stylesheets = [], [], [], [] for name, mt in container.mime_map.iteritems(): items = None if mt in XML_TYPES: items = xml_items elif mt in OEB_DOCS: items = html_items elif mt in OEB_STYLES: items = stylesheets elif is_raster_image(mt): items = raster_images if items is not None: items.append((name, mt, container.open(name, "rb").read())) errors.extend(run_checkers(check_html_size, html_items)) errors.extend(run_checkers(check_xml_parsing, xml_items)) errors.extend(run_checkers(check_xml_parsing, html_items)) errors.extend(run_checkers(check_raster_images, raster_images)) for err in errors: if err.level > WARN: return errors # cssutils is not thread safe for name, mt, raw in stylesheets: if not raw: errors.append(EmptyFile(name)) continue errors.extend(check_css_parsing(name, raw)) for name, mt, raw in html_items + xml_items: errors.extend(check_encoding_declarations(name, container)) for name, mt, raw in html_items: if not raw: continue root = container.parsed(name) for style in root.xpath('//*[local-name()="style"]'): if style.get("type", "text/css") == "text/css" and style.text: errors.extend(check_css_parsing(name, style.text, line_offset=style.sourceline - 1)) for elem in root.xpath("//*[@style]"): raw = elem.get("style") if raw: errors.extend(check_css_parsing(name, raw, line_offset=elem.sourceline - 1, is_declaration=True)) errors += check_mimetypes(container) errors += check_links(container) + check_link_destinations(container) errors += check_fonts(container) errors += check_filenames(container) errors += check_ids(container) errors += check_markup(container) errors += check_opf(container) return errors
def show_context_menu(self, point): item = self.itemAt(point) if item is None or item in set(self.categories.itervalues()): return m = QMenu(self) sel = self.selectedItems() num = len(sel) container = current_container() ci = self.currentItem() if ci is not None: cn = unicode(ci.data(0, NAME_ROLE) or '') mt = unicode(ci.data(0, MIME_ROLE) or '') cat = unicode(ci.data(0, CATEGORY_ROLE) or '') n = elided_text(cn.rpartition('/')[-1]) m.addAction(QIcon(I('save.png')), _('Export %s') % n, partial(self.export, cn)) if cn not in container.names_that_must_not_be_changed and cn not in container.names_that_must_not_be_removed and mt not in OEB_FONTS: m.addAction(_('Replace %s with file...') % n, partial(self.replace, cn)) if num > 1: m.addAction(QIcon(I('save.png')), _('Export all %d selected files') % num, self.export_selected) m.addSeparator() m.addAction(QIcon(I('modified.png')), _('&Rename %s') % n, self.edit_current_item) if is_raster_image(mt): m.addAction(QIcon(I('default_cover.png')), _('Mark %s as cover image') % n, partial(self.mark_as_cover, cn)) elif current_container().SUPPORTS_TITLEPAGES and mt in OEB_DOCS and cat == 'text': m.addAction(QIcon(I('default_cover.png')), _('Mark %s as cover page') % n, partial(self.mark_as_titlepage, cn)) m.addSeparator() if num > 0: m.addSeparator() if num > 1: m.addAction(QIcon(I('modified.png')), _('&Bulk rename the selected files'), self.request_bulk_rename) m.addAction(QIcon(I('modified.png')), _('Change the file extension for the selected files'), self.request_change_ext) m.addAction(QIcon(I('trash.png')), ngettext( '&Delete the selected file', '&Delete the {} selected files', num).format(num), self.request_delete) m.addAction(QIcon(I('edit-copy.png')), ngettext( '&Copy the selected file to another editor instance', '&Copy the {} selected files to another editor instance', num).format(num), self.copy_selected_files) m.addSeparator() selected_map = defaultdict(list) for item in sel: selected_map[unicode(item.data(0, CATEGORY_ROLE) or '')].append(unicode(item.data(0, NAME_ROLE) or '')) for items in selected_map.itervalues(): items.sort(key=self.index_of_name) if selected_map['text']: m.addAction(QIcon(I('format-text-color.png')), _('Link &stylesheets...'), partial(self.link_stylesheets, selected_map['text'])) if len(selected_map['text']) > 1: m.addAction(QIcon(I('merge.png')), _('&Merge selected text files'), partial(self.start_merge, 'text', selected_map['text'])) if len(selected_map['styles']) > 1: m.addAction(QIcon(I('merge.png')), _('&Merge selected style files'), partial(self.start_merge, 'styles', selected_map['styles'])) if len(list(m.actions())) > 0: m.popup(self.mapToGlobal(point))
def run_checks(container): errors = [] # Check parsing xml_items, html_items, raster_images, stylesheets = [], [], [], [] for name, mt in container.mime_map.iteritems(): items = None if mt in XML_TYPES: items = xml_items elif mt in OEB_DOCS: items = html_items elif mt in OEB_STYLES: items = stylesheets elif is_raster_image(mt): items = raster_images if items is not None: items.append((name, mt, container.open(name, 'rb').read())) errors.extend(run_checkers(check_html_size, html_items)) errors.extend(run_checkers(check_xml_parsing, xml_items)) errors.extend(run_checkers(check_xml_parsing, html_items)) errors.extend(run_checkers(check_raster_images, raster_images)) # cssutils is not thread safe for name, mt, raw in stylesheets: errors.extend(check_css_parsing(name, raw)) for name, mt, raw in html_items: root = container.parsed(name) for style in root.xpath('//*[local-name()="style"]'): if style.get('type', 'text/css') == 'text/css' and style.text: errors.extend(check_css_parsing(name, style.text, line_offset=style.sourceline - 1)) for elem in root.xpath('//*[@style]'): raw = elem.get('style') if raw: errors.extend(check_css_parsing(name, raw, line_offset=elem.sourceline - 1, is_declaration=True)) errors += check_mimetypes(container) errors += check_links(container) + check_link_destinations(container) errors += check_fonts(container) errors += check_filenames(container) errors += check_ids(container) errors += check_opf(container) return errors
def replace(self, name): c = current_container() mt = c.mime_map[name] oext = name.rpartition('.')[-1].lower() filters = [oext] fname = _('Files') if mt in OEB_DOCS: fname = _('HTML Files') filters = 'html htm xhtm xhtml shtml'.split() elif is_raster_image(mt): fname = _('Images') filters = 'jpeg jpg gif png'.split() path = choose_files(self, 'tweak_book_import_file', _('Choose file'), filters=[(fname, filters)], select_only_single_file=True) if not path: return path = path[0] ext = path.rpartition('.')[-1].lower() force_mt = None if mt in OEB_DOCS: force_mt = c.guess_type('a.html') nname = os.path.basename(path) nname, ext = nname.rpartition('.')[0::2] nname = nname + '.' + ext.lower() self.replace_requested.emit(name, path, nname, force_mt)
def show_context_menu(self, point): item = self.itemAt(point) if item is None or item in set(self.categories.itervalues()): return m = QMenu(self) sel = self.selectedItems() num = len(sel) container = current_container() ci = self.currentItem() if ci is not None: cn = unicode(ci.data(0, NAME_ROLE) or "") mt = unicode(ci.data(0, MIME_ROLE) or "") cat = unicode(ci.data(0, CATEGORY_ROLE) or "") n = elided_text(cn.rpartition("/")[-1]) m.addAction(QIcon(I("save.png")), _("Export %s") % n, partial(self.export, cn)) if ( cn not in container.names_that_must_not_be_changed and cn not in container.names_that_must_not_be_removed and mt not in OEB_FONTS ): m.addAction(_("Replace %s with file...") % n, partial(self.replace, cn)) m.addSeparator() m.addAction(QIcon(I("modified.png")), _("&Rename %s") % n, self.edit_current_item) if is_raster_image(mt): m.addAction( QIcon(I("default_cover.png")), _("Mark %s as cover image") % n, partial(self.mark_as_cover, cn) ) elif current_container().SUPPORTS_TITLEPAGES and mt in OEB_DOCS and cat == "text": m.addAction( QIcon(I("default_cover.png")), _("Mark %s as cover page") % n, partial(self.mark_as_titlepage, cn) ) m.addSeparator() if num > 0: m.addSeparator() if num > 1: m.addAction(QIcon(I("modified.png")), _("&Bulk rename selected files"), self.request_bulk_rename) m.addAction(QIcon(I("trash.png")), _("&Delete the %d selected file(s)") % num, self.request_delete) m.addSeparator() selected_map = defaultdict(list) for item in sel: selected_map[unicode(item.data(0, CATEGORY_ROLE) or "")].append(unicode(item.data(0, NAME_ROLE) or "")) for items in selected_map.itervalues(): items.sort(key=self.index_of_name) if selected_map["text"]: m.addAction( QIcon(I("format-text-color.png")), _("Link &stylesheets..."), partial(self.link_stylesheets, selected_map["text"]), ) if len(selected_map["text"]) > 1: m.addAction( QIcon(I("merge.png")), _("&Merge selected text files"), partial(self.start_merge, "text", selected_map["text"]), ) if len(selected_map["styles"]) > 1: m.addAction( QIcon(I("merge.png")), _("&Merge selected style files"), partial(self.start_merge, "styles", selected_map["styles"]), ) if len(list(m.actions())) > 0: m.popup(self.mapToGlobal(point))
def show_context_menu(self, point): item = self.itemAt(point) if item is None or item in tuple(itervalues(self.categories)): return m = QMenu(self) sel = self.selectedItems() num = len(sel) container = current_container() ci = self.currentItem() if ci is not None: cn = unicode_type(ci.data(0, NAME_ROLE) or '') mt = unicode_type(ci.data(0, MIME_ROLE) or '') cat = unicode_type(ci.data(0, CATEGORY_ROLE) or '') n = elided_text(cn.rpartition('/')[-1]) m.addAction(QIcon(I('save.png')), _('Export %s') % n, partial(self.export, cn)) if cn not in container.names_that_must_not_be_changed and cn not in container.names_that_must_not_be_removed and mt not in OEB_FONTS: m.addAction( _('Replace %s with file...') % n, partial(self.replace, cn)) if num > 1: m.addAction(QIcon(I('save.png')), _('Export all %d selected files') % num, self.export_selected) m.addSeparator() m.addAction(QIcon(I('modified.png')), _('&Rename %s') % n, self.edit_current_item) if is_raster_image(mt): m.addAction(QIcon(I('default_cover.png')), _('Mark %s as cover image') % n, partial(self.mark_as_cover, cn)) elif current_container( ).SUPPORTS_TITLEPAGES and mt in OEB_DOCS and cat == 'text': m.addAction(QIcon(I('default_cover.png')), _('Mark %s as cover page') % n, partial(self.mark_as_titlepage, cn)) m.addSeparator() if num > 0: m.addSeparator() if num > 1: m.addAction(QIcon(I('modified.png')), _('&Bulk rename the selected files'), self.request_bulk_rename) m.addAction(QIcon(I('modified.png')), _('Change the file extension for the selected files'), self.request_change_ext) m.addAction( QIcon(I('trash.png')), ngettext('&Delete the selected file', '&Delete the {} selected files', num).format(num), self.request_delete) m.addAction( QIcon(I('edit-copy.png')), ngettext( '&Copy the selected file to another editor instance', '&Copy the {} selected files to another editor instance', num).format(num), self.copy_selected_files) m.addSeparator() md = QApplication.instance().clipboard().mimeData() if md.hasUrls() and md.hasFormat(FILE_COPY_MIME): m.addAction(_('Paste files from other editor instance'), self.paste_from_other_instance) selected_map = defaultdict(list) for item in sel: selected_map[unicode_type( item.data(0, CATEGORY_ROLE) or '')].append(unicode_type(item.data(0, NAME_ROLE) or '')) for items in itervalues(selected_map): items.sort(key=self.index_of_name) if selected_map['text']: m.addAction(QIcon(I('format-text-color.png')), _('Link &stylesheets...'), partial(self.link_stylesheets, selected_map['text'])) if len(selected_map['text']) > 1: m.addAction( QIcon(I('merge.png')), _('&Merge selected text files'), partial(self.start_merge, 'text', selected_map['text'])) if len(selected_map['styles']) > 1: m.addAction( QIcon(I('merge.png')), _('&Merge selected style files'), partial(self.start_merge, 'styles', selected_map['styles'])) if len(list(m.actions())) > 0: m.popup(self.mapToGlobal(point))
def run_checks(container): errors = [] # Check parsing xml_items, html_items, raster_images, stylesheets = [], [], [], [] for name, mt in iteritems(container.mime_map): items = None decode = False if mt in XML_TYPES: items = xml_items elif mt in OEB_DOCS: items = html_items elif mt in OEB_STYLES: decode = True items = stylesheets elif is_raster_image(mt): items = raster_images if items is not None: items.append((name, mt, container.raw_data(name, decode=decode))) errors.extend(run_checkers(check_html_size, html_items)) errors.extend(run_checkers(check_xml_parsing, xml_items)) errors.extend(run_checkers(check_xml_parsing, html_items)) errors.extend(run_checkers(check_raster_images, raster_images)) for err in errors: if err.level > WARN: return errors # css uses its own worker pool css_checker = CSSChecker() for name, mt, raw in stylesheets: if not raw: errors.append(EmptyFile(name)) continue css_checker.create_job(name, raw) errors.extend(css_checker()) for name, mt, raw in html_items + xml_items: errors.extend(check_encoding_declarations(name, container)) css_checker = CSSChecker() for name, mt, raw in html_items: if not raw: continue root = container.parsed(name) for style in root.xpath('//*[local-name()="style"]'): if style.get('type', 'text/css') == 'text/css' and style.text: css_checker.create_job(name, style.text, line_offset=style.sourceline - 1) for elem in root.xpath('//*[@style]'): raw = elem.get('style') if raw: css_checker.create_job(name, raw, line_offset=elem.sourceline - 1, is_declaration=True) errors.extend(css_checker()) errors += check_mimetypes(container) errors += check_links(container) + check_link_destinations(container) errors += check_fonts(container) errors += check_ids(container) errors += check_filenames(container) errors += check_markup(container) errors += check_opf(container) return errors
def show_context_menu(self, point): item = self.itemAt(point) if item is None or item in set(self.categories.itervalues()): return m = QMenu(self) sel = self.selectedItems() num = len(sel) container = current_container() ci = self.currentItem() if ci is not None: cn = unicode(ci.data(0, NAME_ROLE) or '') mt = unicode(ci.data(0, MIME_ROLE) or '') cat = unicode(ci.data(0, CATEGORY_ROLE) or '') n = elided_text(cn.rpartition('/')[-1]) m.addAction(QIcon(I('save.png')), _('Export %s') % n, partial(self.export, cn)) if cn not in container.names_that_must_not_be_changed and cn not in container.names_that_must_not_be_removed and mt not in OEB_FONTS: m.addAction( _('Replace %s with file...') % n, partial(self.replace, cn)) m.addSeparator() m.addAction(QIcon(I('modified.png')), _('&Rename %s') % n, self.edit_current_item) if is_raster_image(mt): m.addAction(QIcon(I('default_cover.png')), _('Mark %s as cover image') % n, partial(self.mark_as_cover, cn)) elif current_container( ).SUPPORTS_TITLEPAGES and mt in OEB_DOCS and cat == 'text': m.addAction(QIcon(I('default_cover.png')), _('Mark %s as cover page') % n, partial(self.mark_as_titlepage, cn)) m.addSeparator() if num > 0: m.addSeparator() if num > 1: m.addAction(QIcon(I('modified.png')), _('&Bulk rename selected files'), self.request_bulk_rename) m.addAction(QIcon(I('trash.png')), _('&Delete the %d selected file(s)') % num, self.request_delete) m.addSeparator() selected_map = defaultdict(list) for item in sel: selected_map[unicode(item.data(0, CATEGORY_ROLE) or '')].append( unicode(item.data(0, NAME_ROLE) or '')) for items in selected_map.itervalues(): items.sort(key=self.index_of_name) if selected_map['text']: m.addAction(QIcon(I('format-text-color.png')), _('Link &stylesheets...'), partial(self.link_stylesheets, selected_map['text'])) if len(selected_map['text']) > 1: m.addAction( QIcon(I('merge.png')), _('&Merge selected text files'), partial(self.start_merge, 'text', selected_map['text'])) if len(selected_map['styles']) > 1: m.addAction( QIcon(I('merge.png')), _('&Merge selected style files'), partial(self.start_merge, 'styles', selected_map['styles'])) if len(list(m.actions())) > 0: m.popup(self.mapToGlobal(point))