From d28114bde1a4aaab94484ef6abfe8ba3b03acf03 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Wed, 7 Sep 2016 12:46:06 +0530 Subject: [PATCH] Edit Book: A new tool to sort the rules in a CSS stylesheet. To use it add it to the toolbar for CSS editors --- resources/images/sort.png | Bin 0 -> 2012 bytes src/calibre/ebooks/oeb/polish/css.py | 35 +++++++++++++++++++ src/calibre/gui2/tweak_book/__init__.py | 2 +- src/calibre/gui2/tweak_book/editor/text.py | 10 +++++- src/calibre/gui2/tweak_book/editor/widget.py | 2 ++ 5 files changed, 47 insertions(+), 2 deletions(-) create mode 100644 resources/images/sort.png diff --git a/resources/images/sort.png b/resources/images/sort.png new file mode 100644 index 0000000000000000000000000000000000000000..26f911b7a996df6f897f9aed29edf929e2aa338f GIT binary patch literal 2012 zcmeHH`#aNn0RC)q--cxirC1oJG?$nzWEh#mr^U9B+RA5(R2QT^Kyzl$GKfJ%ZKfG6H_D9e%+hhO$XsQk6_@+ZY zDTUb71!4LM0B}>9owLM~F*EN=eHgQD}M076mMB ztD=(fw(TlARn_pj)HO5-TH3$u-lId*)i>B@XhbsJfAElrsTtYaf?`EIYIn@uf#&Gs z>UP52!_&w2)M-D)nSj8c;E>R;XeR5zB`7{2@%N(DE=Rca$pAWn3 zCgY=a97wH^;lZ6x54^-ND?A9~K*=bc>@MkK8!_z`f}F+9IxiiJP@FVl?JqYLN0g(B z=`-+#@rHdoSf+3Hc1a7_`}YTlXra;4m-&ZF=?YDFX|9vYNDhj22Q*+_}fV%Ug0vS-a0U0_PpCdXT(qAg(MpMb~;zA#&W zh(uwfXvKOj2=Sns9YdR=5tL(g%c`ZaRg-03bDudjfk(U*_{% zbp%d+!+^x!KyW8|r8|R--5k>K3#rr`U&J6FL1_AaHWv!V#wb~0`CF6pgTZ!wAmreR zc#o9KF;mxWxutTMqQwn^zTz!;+}8e1IOOilWbDKIE&0hsF5nR!35b^2twbbn&R=?1 ztiA%u%5@`=+zU|YQ*Kco9!s}oshtwkYjO+qn-g%oIV78^wggT0j-zd1LsyOPKdyMM zbDsFl+G;nG3KXmUbwFIbZjr|`Veb+ zgRO6ugQ(zh-sqgQ!|3v@pGQj1;y9w}XCHNr29vs?wq_cAvjH$(++poY4tf!z$?j%6 zOtEK2r;4v2`Xpki$REps+g_}8JbwpeY#N(;&um`Hf8bl!ILcwLI`MN1YA9%k!E{eD zlTCgg=ijKBmH6ndv?!^K_OwGOMdUkXRHG6inE+CxOBdhyBranO#OW0BoizJ|Wy?Y; z)Tq!i-HoU+Uhs@_g&Mt(3)H=}uvd&W6KMT#!A4xG3(Y4w8BtIpr$ktMSP(Z@e>Tv@ zgdr)VNiQ|CTfB7Fr%qzv`tXaqwsTHTn`8Dxd>>aNJ=i~zE>2U>6Qu12@|A)#6F{Kf p)&+bAzK4$(@Nn~N+$k--j3~J!XM!Ht*!%OJsaE!syB73>e*swZgQWlf literal 0 HcmV?d00001 diff --git a/src/calibre/ebooks/oeb/polish/css.py b/src/calibre/ebooks/oeb/polish/css.py index 6911709b77..77c1735119 100644 --- a/src/calibre/ebooks/oeb/polish/css.py +++ b/src/calibre/ebooks/oeb/polish/css.py @@ -16,6 +16,7 @@ from calibre import force_unicode from calibre.ebooks.oeb.base import OEB_STYLES, OEB_DOCS from calibre.ebooks.oeb.normalize_css import normalize_filter_css, normalizers from calibre.ebooks.oeb.polish.pretty import pretty_script_or_style +from calibre.utils.icu import numeric_sort_key from css_selectors import Select, SelectorError @@ -324,3 +325,37 @@ def remove_property_value(prop, predicate): x = x.replace(v.cssText, '').strip() prop.propertyValue.cssText = x return bool(removed_vals) + + +RULE_PRIORITIES = {t:i for i, t in enumerate((CSSRule.COMMENT, CSSRule.CHARSET_RULE, CSSRule.IMPORT_RULE, CSSRule.NAMESPACE_RULE))} + +def sort_sheet(container, sheet_or_text): + ''' Sort the rules in a stylesheet. Note that in the general case this can + change the effective styles, but for most common sheets, it should be safe. + ''' + sheet = container.parse_css(sheet_or_text) if isinstance(sheet_or_text, unicode) else sheet_or_text + + def text_sort_key(x): + return numeric_sort_key(unicode(x or '')) + + def selector_sort_key(x): + return (x.specificity, text_sort_key(x.selectorText)) + + def rule_sort_key(rule): + primary = RULE_PRIORITIES.get(rule.type, len(RULE_PRIORITIES)) + secondary = text_sort_key(getattr(rule, 'atkeyword', '') or '') + tertiary = None + if rule.type == CSSRule.STYLE_RULE: + primary += 1 + selectors = sorted(rule.selectorList, key=selector_sort_key) + tertiary = selector_sort_key(selectors[0]) + rule.selectorText = ', '.join(s.selectorText for s in selectors) + elif rule.type == CSSRule.FONT_FACE_RULE: + try: + tertiary = text_sort_key(rule.style.getPropertyValue('font-family')) + except Exception: + pass + + return primary, secondary, tertiary + sheet.cssRules.sort(key=rule_sort_key) + return sheet diff --git a/src/calibre/gui2/tweak_book/__init__.py b/src/calibre/gui2/tweak_book/__init__.py index f29fb25a72..679ff1db0e 100644 --- a/src/calibre/gui2/tweak_book/__init__.py +++ b/src/calibre/gui2/tweak_book/__init__.py @@ -58,7 +58,7 @@ d['global_tools_toolbar'] = [ ] d['global_plugins_toolbar'] = [] d['editor_common_toolbar'] = [('editor-' + x) if x else None for x in ('undo', 'redo', None, 'cut', 'copy', 'paste', 'smart-comment')] -d['editor_css_toolbar'] = ['pretty-current', 'insert-image'] +d['editor_css_toolbar'] = ['pretty-current', 'sort-css', 'insert-image'] d['editor_xml_toolbar'] = ['pretty-current', 'insert-tag'] d['editor_html_toolbar'] = ['fix-html-current', 'pretty-current', 'insert-image', 'insert-hyperlink', 'insert-tag', 'change-paragraph'] d['editor_format_toolbar'] = [('format-text-' + x) if x else x for x in ( diff --git a/src/calibre/gui2/tweak_book/editor/text.py b/src/calibre/gui2/tweak_book/editor/text.py index 83f70f7698..e101858247 100644 --- a/src/calibre/gui2/tweak_book/editor/text.py +++ b/src/calibre/gui2/tweak_book/editor/text.py @@ -17,7 +17,7 @@ from PyQt5.Qt import ( QColorDialog, QTimer, pyqtSignal) from calibre import prepare_string_for_xml -from calibre.gui2.tweak_book import tprefs, TOP +from calibre.gui2.tweak_book import tprefs, TOP, current_container from calibre.gui2.tweak_book.completion.popup import CompletionPopup from calibre.gui2.tweak_book.editor import ( SYNTAX_PROPERTY, SPELL_PROPERTY, SPELL_LOCALE_PROPERTY, store_locale, LINK_PROPERTY) @@ -332,6 +332,14 @@ class TextEdit(PlainTextEdit): from calibre.gui2.tweak_book.editor.comments import smart_comment smart_comment(self, self.syntax) + def sort_css(self): + from calibre.gui2.dialogs.confirm_delete import confirm + if confirm(_('Sorting CSS rules can in rare cases change the effective styles applied to the book.' + ' Are you sure you want to proceed?'), 'edit-book-confirm-sort-css', parent=self, config_set=tprefs): + from calibre.ebooks.oeb.polish.css import sort_sheet + text = sort_sheet(current_container(), self.toPlainText()).cssText + self.setPlainText(text) + def find(self, pat, wrap=False, marked=False, complete=False, save_match=None): if marked: return self.find_in_marked(pat, wrap=wrap, save_match=save_match) diff --git a/src/calibre/gui2/tweak_book/editor/widget.py b/src/calibre/gui2/tweak_book/editor/widget.py index 72a69dceea..5829057084 100644 --- a/src/calibre/gui2/tweak_book/editor/widget.py +++ b/src/calibre/gui2/tweak_book/editor/widget.py @@ -80,6 +80,8 @@ def register_text_editor_actions(_reg, palette): ac = reg('format-justify-fill.png', _('&Justify'), ('format_text', 'justify_justify'), 'format-text-justify-fill', (), _('Justify')) ac.setToolTip(_('

Justify

Align the paragraph to both the left and right margins')) + ac = reg('sort.png', _('&Sort style rules'), ('sort_css',), 'editor-sort-css', (), + _('Sort the style rules'), syntaxes=('css',)) ac = reg('view-image.png', _('&Insert image'), ('insert_resource', 'image'), 'insert-image', (), _('Insert an image into the text'), syntaxes=('html', 'css')) ac.setToolTip(_('

Insert image

Insert an image into the text'))